"use strict"; /** * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates * SPDX-License-Identifier: MIT * * Zod-based configuration schema for the OpenClaw Lark/Feishu channel plugin. * * Provides runtime validation, sensible defaults, and cross-field refinements * so that every consuming module can rely on well-typed configuration objects. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.FEISHU_CONFIG_JSON_SCHEMA = exports.FeishuConfigSchema = exports.FeishuAccountConfigSchema = exports.FeishuGroupSchema = exports.UATConfigSchema = exports.z = void 0; const zod_1 = require("zod"); Object.defineProperty(exports, "z", { enumerable: true, get: function () { return zod_1.z; } }); // --------------------------------------------------------------------------- // Shared micro-schemas // --------------------------------------------------------------------------- const DmPolicyEnum = zod_1.z.enum(['open', 'pairing', 'allowlist', 'disabled']); const GroupPolicyEnum = zod_1.z.enum(['open', 'allowlist', 'disabled']); const ConnectionModeEnum = zod_1.z.enum(['websocket', 'webhook']); const ReplyModeValue = zod_1.z.enum(['auto', 'static', 'streaming']); const ReplyModeSchema = zod_1.z .union([ ReplyModeValue, zod_1.z.object({ default: ReplyModeValue.optional(), group: ReplyModeValue.optional(), direct: ReplyModeValue.optional(), }), ]) .optional(); const ChunkModeEnum = zod_1.z.enum(['newline', 'paragraph', 'none']); const DomainSchema = zod_1.z.union([zod_1.z.literal('feishu'), zod_1.z.literal('lark'), zod_1.z.string().regex(/^https:\/\//)]).optional(); const AllowFromSchema = zod_1.z .union([zod_1.z.string(), zod_1.z.array(zod_1.z.string())]) .optional() .transform((v) => { if (v === undefined || v == null) return undefined; return Array.isArray(v) ? v : [v]; }); const ToolPolicySchema = zod_1.z .object({ allow: zod_1.z.array(zod_1.z.string()).optional(), deny: zod_1.z.array(zod_1.z.string()).optional(), }) .optional(); const FeishuToolsFlagSchema = zod_1.z .object({ doc: zod_1.z.boolean().optional(), wiki: zod_1.z.boolean().optional(), drive: zod_1.z.boolean().optional(), perm: zod_1.z.boolean().optional(), scopes: zod_1.z.boolean().optional(), }) .optional(); const FeishuFooterSchema = zod_1.z .object({ status: zod_1.z.boolean().optional(), elapsed: zod_1.z.boolean().optional(), tokens: zod_1.z.boolean().optional(), cache: zod_1.z.boolean().optional(), context: zod_1.z.boolean().optional(), model: zod_1.z.boolean().optional(), }) .optional(); const BlockStreamingCoalesceSchema = zod_1.z .object({ minChars: zod_1.z.number().optional(), maxChars: zod_1.z.number().optional(), idleMs: zod_1.z.number().optional(), }) .optional(); const MarkdownConfigSchema = zod_1.z .object({ tables: zod_1.z.enum(['off', 'bullets', 'code']).optional(), }) .optional(); const HeartbeatSchema = zod_1.z .object({ every: zod_1.z.string().optional(), activeHours: zod_1.z .object({ start: zod_1.z.string().optional(), end: zod_1.z.string().optional(), timezone: zod_1.z.string().optional(), }) .optional(), target: zod_1.z.string().optional(), to: zod_1.z.string().optional(), prompt: zod_1.z.string().optional(), accountId: zod_1.z.string().optional(), }) .optional(); const CapabilitiesSchema = zod_1.z .object({ image: zod_1.z.boolean().optional(), audio: zod_1.z.boolean().optional(), video: zod_1.z.boolean().optional(), }) .optional(); const DedupSchema = zod_1.z .object({ ttlMs: zod_1.z.number().optional(), // default 43200000 (12h) maxEntries: zod_1.z.number().optional(), // default 5000 }) .optional(); const AllowBotsSchema = zod_1.z.union([zod_1.z.boolean(), zod_1.z.literal('mentions')]).optional(); const ReactionNotificationModeSchema = zod_1.z.enum(['off', 'own', 'all']).optional(); exports.UATConfigSchema = zod_1.z .object({ enabled: zod_1.z.boolean().optional(), allowedScopes: zod_1.z.array(zod_1.z.string()).optional(), blockedScopes: zod_1.z.array(zod_1.z.string()).optional(), }) .optional(); const DmConfigSchema = zod_1.z .object({ historyLimit: zod_1.z.number().optional(), }) .optional(); // --------------------------------------------------------------------------- // Group schema // --------------------------------------------------------------------------- exports.FeishuGroupSchema = zod_1.z.object({ groupPolicy: GroupPolicyEnum.optional(), requireMention: zod_1.z.boolean().optional(), respondToMentionAll: zod_1.z.boolean().optional(), tools: ToolPolicySchema, skills: zod_1.z.array(zod_1.z.string()).optional(), enabled: zod_1.z.boolean().optional(), allowFrom: AllowFromSchema, systemPrompt: zod_1.z.string().optional(), allowBots: AllowBotsSchema, // When true, bot-to-bot replies are allowed to stay inside a thread/topic // instead of being forced to the main chat (relaxes the #32980 guard). replyInThread: zod_1.z.boolean().optional(), }); // --------------------------------------------------------------------------- // Account config schema (same shape as top-level minus `accounts`) // --------------------------------------------------------------------------- exports.FeishuAccountConfigSchema = zod_1.z.object({ appId: zod_1.z.string().optional(), appSecret: zod_1.z.string().optional(), encryptKey: zod_1.z.string().optional(), verificationToken: zod_1.z.string().optional(), name: zod_1.z.string().optional(), enabled: zod_1.z.boolean().optional(), domain: DomainSchema, connectionMode: ConnectionModeEnum.optional(), webhookPath: zod_1.z.string().optional(), webhookPort: zod_1.z.number().optional(), dmPolicy: DmPolicyEnum.optional(), allowFrom: AllowFromSchema, groupPolicy: GroupPolicyEnum.optional(), groupAllowFrom: AllowFromSchema, requireMention: zod_1.z.boolean().optional(), respondToMentionAll: zod_1.z.boolean().optional(), groups: zod_1.z.record(zod_1.z.string(), exports.FeishuGroupSchema).optional(), historyLimit: zod_1.z.number().optional(), dmHistoryLimit: zod_1.z.number().optional(), dms: DmConfigSchema, textChunkLimit: zod_1.z.number().optional(), chunkMode: ChunkModeEnum.optional(), blockStreamingCoalesce: BlockStreamingCoalesceSchema, mediaMaxMb: zod_1.z.number().optional(), heartbeat: HeartbeatSchema, replyMode: ReplyModeSchema, streaming: zod_1.z.boolean().optional(), blockStreaming: zod_1.z.boolean().optional(), toolUseDisplay: zod_1.z .object({ showFullPaths: zod_1.z.boolean().optional(), }) .optional(), tools: FeishuToolsFlagSchema, footer: FeishuFooterSchema, markdown: MarkdownConfigSchema, configWrites: zod_1.z.boolean().optional(), capabilities: CapabilitiesSchema, dedup: DedupSchema, reactionNotifications: ReactionNotificationModeSchema, threadSession: zod_1.z.boolean().optional(), allowBots: AllowBotsSchema, // Account-level default for letting bot-to-bot replies stay in a thread // (per-group `replyInThread` overrides this). replyInThread: zod_1.z.boolean().optional(), uat: exports.UATConfigSchema, }); // --------------------------------------------------------------------------- // Top-level Feishu config schema // --------------------------------------------------------------------------- exports.FeishuConfigSchema = exports.FeishuAccountConfigSchema.extend({ accounts: zod_1.z.record(zod_1.z.string(), exports.FeishuAccountConfigSchema).optional(), }).superRefine((data, ctx) => { // When dmPolicy is "open", allowFrom must contain the wildcard "*". if (data.dmPolicy === 'open') { const list = data.allowFrom; const hasWildcard = Array.isArray(list) && list.includes('*'); if (!hasWildcard) { ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['allowFrom'], message: 'When dmPolicy is "open", allowFrom must include "*" to permit all senders.', }); } } }); // --------------------------------------------------------------------------- // Auto-generated JSON Schema (single source of truth) // --------------------------------------------------------------------------- /** * JSON Schema derived from FeishuConfigSchema. * * - `io: "input"` exposes the input type for `.transform()` schemas (e.g. AllowFromSchema). * - `unrepresentable: "any"` degrades `.superRefine()` constraints to `{}`. * - `target: "draft-07"` matches the plugin system's expected JSON Schema version. */ exports.FEISHU_CONFIG_JSON_SCHEMA = (0, zod_1.toJSONSchema)(exports.FeishuConfigSchema, { target: 'draft-07', io: 'input', unrepresentable: 'any', });