Files
goodbuddy/src/shared/channel-settings-contracts.ts
T
lofyer b8fc7bc86e
Cross-platform packages / Validate source (push) Waiting to run
Cross-platform packages / ${{ matrix.platform }} ${{ matrix.arch }} (arm64, macos, macos-15) (push) Blocked by required conditions
Cross-platform packages / ${{ matrix.platform }} ${{ matrix.arch }} (arm64, windows, windows-2025) (push) Blocked by required conditions
Cross-platform packages / ${{ matrix.platform }} ${{ matrix.arch }} (x64, linux, ubuntu-24.04) (push) Blocked by required conditions
Cross-platform packages / ${{ matrix.platform }} ${{ matrix.arch }} (x64, macos, macos-15-intel) (push) Blocked by required conditions
Cross-platform packages / ${{ matrix.platform }} ${{ matrix.arch }} (x64, windows, windows-2025) (push) Blocked by required conditions
Cross-platform packages / Publish GitHub Release (push) Blocked by required conditions
Cross-platform packages / ${{ matrix.platform }} ${{ matrix.arch }} (arm64, linux, ubuntu-24.04-arm) (push) Blocked by required conditions
chore: prepare GoodBuddy 0.8.2
2026-08-06 22:47:13 +08:00

197 lines
4.7 KiB
TypeScript

import { z } from 'zod'
export const CHANNEL_SETTINGS_LIMITS = {
maximumIdentifierLength: 256,
maximumSecretLength: 4_096,
maximumAllowedSenders: 100,
maximumStatusMessageLength: 500,
maximumWarningLength: 500
} as const
export const managedChannelSchema = z.enum(['wecom', 'dingtalk'])
export type ManagedChannel = z.infer<typeof managedChannelSchema>
const identifierSchema = z
.string()
.trim()
.max(CHANNEL_SETTINGS_LIMITS.maximumIdentifierLength)
const senderIdentifierSchema = identifierSchema.min(1)
export const allowedSenderIdsSchema = z
.array(senderIdentifierSchema)
.max(CHANNEL_SETTINGS_LIMITS.maximumAllowedSenders)
.transform((values) => [...new Set(values)])
export const channelSecretUpdateSchema = z.discriminatedUnion('action', [
z.object({ action: z.literal('keep') }).strict(),
z
.object({
action: z.literal('replace'),
value: z
.string()
.trim()
.min(1)
.max(CHANNEL_SETTINGS_LIMITS.maximumSecretLength)
})
.strict(),
z.object({ action: z.literal('clear') }).strict()
])
export type ChannelSecretUpdate = z.infer<
typeof channelSecretUpdateSchema
>
const editableChannelFields = {
enabled: z.boolean(),
secret: channelSecretUpdateSchema,
allowedSenderIds: allowedSenderIdsSchema,
allowGroupMessages: z.boolean()
} as const
export const weComChannelSettingsInputSchema = z
.object({
...editableChannelFields,
botId: identifierSchema
})
.strict()
export type WeComChannelSettingsInput = z.infer<
typeof weComChannelSettingsInputSchema
>
export const dingTalkChannelSettingsInputSchema = z
.object({
...editableChannelFields,
clientId: identifierSchema
})
.strict()
export type DingTalkChannelSettingsInput = z.infer<
typeof dingTalkChannelSettingsInputSchema
>
export const channelSettingsApplySchema = z
.object({
wecom: weComChannelSettingsInputSchema.optional(),
dingtalk: dingTalkChannelSettingsInputSchema.optional()
})
.strict()
.refine(
(input) => input.wecom !== undefined || input.dingtalk !== undefined,
'至少需要提供一个通道设置'
)
export type ChannelSettingsApply = z.infer<
typeof channelSettingsApplySchema
>
export const channelCredentialSourceSchema = z.enum([
'none',
'encrypted',
'environment'
])
export type ChannelCredentialSource = z.infer<
typeof channelCredentialSourceSchema
>
export const channelRuntimeStateSchema = z.enum([
'disabled',
'stopped',
'starting',
'running',
'error'
])
export type ChannelRuntimeState = z.infer<
typeof channelRuntimeStateSchema
>
export const channelRuntimeStatusSchema = z
.object({
state: channelRuntimeStateSchema,
lastError: z
.string()
.trim()
.min(1)
.max(CHANNEL_SETTINGS_LIMITS.maximumStatusMessageLength)
.optional()
})
.strict()
export type ChannelRuntimeStatus = z.infer<
typeof channelRuntimeStatusSchema
>
const publicChannelFields = {
enabled: z.boolean(),
secretConfigured: z.boolean(),
source: channelCredentialSourceSchema,
readOnly: z.boolean(),
allowedSenderIds: allowedSenderIdsSchema,
allowGroupMessages: z.boolean(),
status: channelRuntimeStatusSchema
} as const
export const weComChannelSettingsSchema = z
.object({
...publicChannelFields,
botId: identifierSchema
})
.strict()
export type WeComChannelSettings = z.infer<
typeof weComChannelSettingsSchema
>
export const dingTalkChannelSettingsSchema = z
.object({
...publicChannelFields,
clientId: identifierSchema
})
.strict()
export type DingTalkChannelSettings = z.infer<
typeof dingTalkChannelSettingsSchema
>
export const channelSettingsSnapshotSchema = z
.object({
wecom: weComChannelSettingsSchema,
dingtalk: dingTalkChannelSettingsSchema,
warning: z
.string()
.trim()
.min(1)
.max(CHANNEL_SETTINGS_LIMITS.maximumWarningLength)
.optional()
})
.strict()
export type ChannelSettingsSnapshot = z.infer<
typeof channelSettingsSnapshotSchema
>
export const channelConnectionTestResultSchema = z
.object({
channel: managedChannelSchema,
ok: z.boolean(),
error: z
.string()
.trim()
.min(1)
.max(CHANNEL_SETTINGS_LIMITS.maximumStatusMessageLength)
.optional()
})
.strict()
.superRefine((result, context) => {
if (result.ok && result.error !== undefined) {
context.addIssue({
code: 'custom',
path: ['error'],
message: '成功结果不能包含错误'
})
}
if (!result.ok && result.error === undefined) {
context.addIssue({
code: 'custom',
path: ['error'],
message: '失败结果必须包含错误'
})
}
})
export type ChannelConnectionTestResult = z.infer<
typeof channelConnectionTestResultSchema
>