/** * All non-VC events (application identity) that the botmux dispatcher consumes. * `card.action.trigger` is intentionally NOT here: the Open Platform treats it * as a "callback" configured via `/developers/v1/callback/*`, see * BOT_BASELINE_CALLBACKS. */ export declare const BOT_BASELINE_APP_EVENTS: readonly ["im.message.receive_v1", "im.chat.member.bot.added_v1", "im.chat.member.bot.deleted_v1", "drive.notice.comment_add_v1", "im.message.reaction.created_v1", "im.message.reaction.deleted_v1"]; /** * Best-effort app events: subscribed alongside the baseline but NEVER part of * the fail-closed verification (missingBaselineEvents / MANAGED_VERIFIED_EVENT_COUNT). * Used for enhancements that degrade gracefully when unsubscribed — membership * change events only drive chatStatsCache invalidation, whose 5-min TTL is the * documented fallback. Some tenants cannot grant the underlying member-read * scopes for user events; hard-requiring them would block bot onboarding. */ export declare const BOT_OPTIONAL_APP_EVENTS: readonly ["im.chat.member.user.added_v1", "im.chat.member.user.deleted_v1"]; /** 缺了它 daemon 完全收不到消息——回读确认失败时整个自动配置 fail-closed。 */ export declare const BOT_CRITICAL_APP_EVENTS: readonly ["im.message.receive_v1"]; /** 卡片交互回调。缺了它卡片按钮点击无响应,同样 fail-closed。 */ export declare const BOT_BASELINE_CALLBACKS: readonly ["card.action.trigger"]; /** 开放平台「使用长连接接收事件/回调」对应的 mode 值。 */ export declare const LONG_CONNECTION_EVENT_MODE = 4; export declare const VC_MEETING_APP_EVENTS: ("vc.bot.meeting_invited_v1" | "vc.bot.meeting_activity_v1" | "vc.bot.meeting_ended_v1" | "vc.meeting.participant_meeting_joined_v1")[]; export declare const VC_MEETING_USER_EVENTS: ("vc.bot.meeting_invited_v1" | "vc.bot.meeting_activity_v1" | "vc.bot.meeting_ended_v1" | "vc.meeting.participant_meeting_joined_v1")[]; export declare const BOTMUX_REDIRECT_URL = "http://127.0.0.1:9768/callback"; export interface StoredCookie { name: string; value: string; domain: string; path: string; secure: boolean; httpOnly: boolean; hostOnly: boolean; expiresAt?: number; sameSite?: string; } /** 当前开放平台 Web session 对应的人与企业。创建前用它防止复用错租户。 */ export interface FeishuWebSessionIdentity { userId: string; userName: string; email?: string; tenantId: string; tenantName: string; } export interface ScopeManifest { scopes?: { tenant?: string[]; user?: string[]; }; } export interface OpenPlatformScopeEntry { id: string; name: string; bucket?: 'tenant' | 'user'; } export interface MappedScopeIds { tenantScopeIds: string[]; userScopeIds: string[]; missingTenantScopes: string[]; missingUserScopes: string[]; } export type OpenPlatformAutomationResult = { ok: true; sessionFile: string; sessionSource: FeishuWebSessionSource; cookieCount: number; scopeCount: number; skippedScopeCount: number; scopeWarning?: string; subscribedEventCount: number; eventWarning?: string; /** 回读后仍缺失的 VC 会议事件。普通建 bot 不阻断,VC listener 保存前必须为空。 */ missingVcEvents: string[]; /** 回读确认事件接收方式已是长连接(ok:true 时恒为 true,显式带回供门函数统一判定)。 */ eventModeReady: boolean; /** Managed onboarding only: exact same-session event mode readback. */ eventMode?: number; /** Managed onboarding only: exact baseline event + callback count read back before session cleanup. */ verifiedEventCount?: number; versionId?: string; } | { ok: false; reason: 'unsupported_brand' | 'missing_session' | 'invalid_session' | 'login_failed' | 'qr_expired' | 'timeout' | 'missing_csrf' | 'owner_session_mismatch' | 'scope_mapping_failed' | 'event_verification_failed' | 'version_verification_failed' | 'visibility_unreadable' | 'network' | 'api_error'; message: string; sessionFile?: string; /** Number of events successfully subscribed (0 when event update failed before downstream error). */ subscribedEventCount?: number; /** Warning from event subscription attempt, if any. */ eventWarning?: string; /** 回读后仍缺失的 VC 会议事件(走到订阅阶段才有)。 */ missingVcEvents?: string[]; /** 事件接收方式是否回读确认为长连接(走到订阅阶段才有;早期失败为 undefined)。 */ eventModeReady?: boolean; /** Managed onboarding exact event-mode ACK, preserved across later scope propagation failure. */ eventMode?: number; /** Managed onboarding exact baseline count ACK, preserved across later scope propagation failure. */ verifiedEventCount?: number; /** Exact published version ACK, preserved across later scope propagation failure. */ versionId?: string; }; export interface OpenPlatformAutomationOptions { appId: string; brand?: 'feishu' | 'lark'; sessionFilePath?: string; bytedcliFallbackSessionFilePath?: string; disableBytedcliFallback?: boolean; /** Ignore any shared cached account and require the exact App owner to scan. */ forceQrLogin?: boolean; /** Reuse a valid cache or fail instead of presenting another QR. */ disableQrLogin?: boolean; /** Require all baseline events/callbacks and a published version to be proven before managed activation. */ requireVerifiedEvents?: boolean; fetchImpl?: typeof fetch; scopeManifest?: ScopeManifest; pollIntervalMs?: number; maxWaitMs?: number; onQrCode?: (info: { qrText: string; qrPayload: string; }) => void | Promise; /** Emitted once only after Feishu reports this exact QR as scanned. */ onQrScanConfirmed?: (info: { confirmedAt: number; }) => void | Promise; onStatus?: (message: string) => void | Promise; } export type FeishuWebSessionSource = 'botmux_cache' | 'qr_login' | 'bytedcli_fallback'; export type FeishuWebSessionFailureReason = 'login_failed' | 'qr_expired' | 'timeout' | 'network' | 'invalid_session'; export type FeishuWebSessionPrepareResult = { ok: true; sessionFile: string; source: FeishuWebSessionSource; cookies: StoredCookie[]; cookieCount: number; } | { ok: false; reason: FeishuWebSessionFailureReason; message: string; sessionFile: string; fallbackSessionFile?: string; }; export interface FeishuWebSessionOptions { sessionFilePath?: string; bytedcliFallbackSessionFilePath?: string; disableBytedcliFallback?: boolean; /** * Ignore cached sessions and require a fresh QR login. Dashboard onboarding * uses this so the user always sees which account is authorizing the new app; * the resulting session is still cached for the remaining setup steps. */ forceQrLogin?: boolean; /** Reuse a valid cache or fail; never present another QR code. */ disableQrLogin?: boolean; fetchImpl?: typeof fetch; pollIntervalMs?: number; maxWaitMs?: number; onQrCode?: (info: { qrText: string; qrPayload: string; }) => void | Promise; /** Emitted once only after polling observes Feishu status=2 for this QR. */ onQrScanConfirmed?: (info: { confirmedAt: number; }) => void | Promise; onStatus?: (message: string) => void | Promise; } export type FeishuOpenPlatformSessionInspectionResult = { ok: true; source: FeishuWebSessionSource; identity: FeishuWebSessionIdentity; sessionFile: string; } | { ok: false; reason: FeishuWebSessionFailureReason | 'missing_csrf' | 'identity_unavailable' | 'network'; message: string; sessionFile?: string; }; export declare function parseSetupOpenPlatformAutoFlag(argv: string[]): boolean; export declare function botmuxFeishuSessionFilePath(configDir?: string): string; export declare function bytedcliFeishuSessionFilePath(homeDir?: string): string; export declare function readStoredCookiesFromSessionFile(filePath: string): StoredCookie[] | null; export declare function readStoredCookiesFromBytedcliSession(filePath: string): StoredCookie[] | null; export declare function writeStoredCookiesToSessionFile(filePath: string, cookies: StoredCookie[]): void; export declare function getCookieHeader(cookies: StoredCookie[], requestUrl: string): string; export declare function extractOpenPlatformCsrfToken(html: string): string | null; /** * 开发者后台把当前登录人写入 `window.user = {...}`。只提取创建前需要展示和 * 比对的稳定字段,不把头像、功能开关等整段页面状态带进 Dashboard API。 */ export declare function extractOpenPlatformSessionIdentity(html: string): FeishuWebSessionIdentity | null; export declare function extractOpenPlatformScopeEntries(payload: unknown): OpenPlatformScopeEntry[]; export declare function mapManifestScopesToOpenPlatformIds(manifest: ScopeManifest, catalog: OpenPlatformScopeEntry[]): MappedScopeIds; export declare function buildScopeUpdatePayload(appId: string, mapped: Pick): { clientId: string; appScopeIDs: string[]; userScopeIDs: string[]; scopeIds: never[]; operation: string; isDeveloperPanel: boolean; }; export declare function buildSafeSettingPayload(appId: string, extraRedirectUrls?: string[]): { clientId: string; redirectURL: string[]; }; /** * Build the incremental event-subscription payload used by the developer * console (`updateEvent` in the console frontend bundle): * `{clientId, operation:'add', events, appEvents, userEvents, eventMode}`。 * eventMode 必须回填读接口返回的当前值,事件按接收身份分桶(应用/用户)。 */ export declare function buildEventSubscriptionPayload(appId: string, eventMode: number, appEvents: string[], userEvents: string[], events?: string[]): { clientId: string; operation: string; events: string[]; appEvents: string[]; userEvents: string[]; eventMode: number; }; /** 同款增量契约的回调版(console frontend `updateCallback`)。 */ export declare function buildCallbackSubscriptionPayload(appId: string, callbackMode: number, callbacks: string[]): { clientId: string; operation: string; callbacks: string[]; callbackMode: number; }; export interface OpenPlatformEventState { eventMode?: number; /** 所有已订阅事件(顶层 events + 应用/用户身份分组的并集)。 */ events: string[]; appEvents: string[]; userEvents: string[]; } export interface OpenPlatformCallbackState { callbackMode?: number; callbacks: string[]; } /** Extract the event mode and subscribed event ids from `/developers/v1/event/:clientId`. */ export declare function extractOpenPlatformEventState(payload: unknown): OpenPlatformEventState; /** Extract the callback mode and subscribed callback ids from `/developers/v1/callback/:clientId`. */ export declare function extractOpenPlatformCallbackState(payload: unknown): OpenPlatformCallbackState; /** * 应用版本创建 payload,与 console launcher「一键创建智能体」同款极简结构 * (CDP 抓包确认)。⚠️不要重新加回 applyReasonConfig / isAutoAudit:false —— * 那会让版本进入人工审核、发布后应用停在「未上架/未启用」(tenantAppStatus=0), * 事件配置进了草稿也无法在企业内生效。visibleSuggest.members 必须含创建者, * 否则同样不会自动上架启用。 * * ⚠️ **visibleSuggest 是全量覆写语义**:这里给什么,新版本的可见范围就是什么, * 没给的集合会被清空而不是保持原样。因此**只有全新应用的首次发布**能用这个 * 默认的空 departments/groups + isAll:0 —— 对已有应用发版,调用方必须先用 * {@link parseOnlineVisibility} 读回线上可见范围并整块覆盖 visibleSuggest / * blackVisibleSuggest(见 automateOpenPlatformSetup 与 open-platform-rename)。 * 曾经漏掉这一步,导致每次权限自愈自动发版都把「全员可见 / 部门 / 用户组」 * 静默清空。 */ export declare function buildAppVersionCreatePayload(appVersion: string, visibleMemberIds?: string[]): { appVersion: string; mobileDefaultAbility: string; pcDefaultAbility: string; changeLog: string; visibleSuggest: { departments: never[]; members: string[]; groups: never[]; isAll: number; }; blackVisibleSuggest: { departments: never[]; members: never[]; groups: never[]; isAll: number; }; }; export declare function buildFeishuQrPayload(token: string): string; export declare function mapFeishuQrPollingStatus(status: number | null): string; export declare function prepareFeishuWebSession(options?: FeishuWebSessionOptions): Promise; export declare function automateOpenPlatformSetup(options: OpenPlatformAutomationOptions): Promise; /** * dashboard 保存 VC 会议监听 bot 前的事件订阅门。普通建 bot 允许 VC 事件缺失 * (只记 warning),但 listener 缺 VC 事件=会议邀请黑洞,必须阻断保存。 * 只看 subscribedEventCount 总数无法区分「缺的是不是 VC」,所以要看 * missingVcEvents。返回错误描述;可保存时返回 null。 */ export declare function vcListenerEventGateError(result: { eventWarning?: string; subscribedEventCount?: number; missingVcEvents?: string[]; eventModeReady?: boolean; }): string | null; export interface OpenPlatformAppSummary { clientId: string; name: string; /** 应用描述(接口给什么用什么,仅展示)。 */ description?: string; } export interface OpenPlatformApiClient { apiOrigin: string; postJson(path: string, body?: unknown): Promise; postForm(path: string, body: FormData): Promise; } export type OpenPlatformClientResult = { ok: true; client: OpenPlatformApiClient; identity?: FeishuWebSessionIdentity; } | { ok: false; reason: 'missing_csrf' | 'network'; message: string; }; /** * 用已就绪的 Web session cookies 构造开放平台 console API 客户端:加载 console * 页面提取 `window.csrfToken` 与最终 origin(部分租户会把控制台重定向到 * open.larkoffice.com),返回可调 `/developers/v1/*` 的 postJson。 */ export declare function createOpenPlatformApiClient(cookies: StoredCookie[], opts?: { fetchImpl?: typeof fetch; }): Promise; /** * 只检查现有缓存,不展示二维码。Dashboard 打开添加表单时调用;返回的账号/企业 * 会显示给用户,并在真正创建前再次比对,避免旧 cookie 把应用建到错误租户。 */ export declare function inspectCachedFeishuOpenPlatformSession(options?: Pick): Promise; export type CreateFeishuOpenPlatformAppResult = { ok: true; appId: string; appSecret: string; brand: 'feishu'; sessionFile: string; sessionSource: FeishuWebSessionSource; sessionIdentity: FeishuWebSessionIdentity; } | { ok: false; reason: FeishuWebSessionFailureReason | 'missing_csrf' | 'missing_icon' | 'identity_unavailable' | 'session_changed' | 'api_error'; message: string; /** 应用已经建成但读取 Secret 失败时返回,调用方不得再创建一个重复应用。 */ appId?: string; sessionFile?: string; }; export interface CreateFeishuOpenPlatformAppOptions extends FeishuWebSessionOptions { name: string; description?: string; /** 测试/定制图标;默认复用 botmux dashboard 的 512x512 favicon。 */ iconFilePath?: string; /** Dashboard 表单打开时显示过的缓存身份;创建前必须仍是同一人、同一企业。 */ expectedIdentity?: Pick; /** 已拿到并验证账号/企业、但尚未创建应用时触发。 */ onSessionReady?: (info: { source: FeishuWebSessionSource; identity: FeishuWebSessionIdentity; }) => void | Promise; } /** 「一键创建智能体」(backend_oneclick launcher) 使用的应用清单模板 ID。 */ export declare const ONECLICK_APP_MANIFEST_TEMPLATE_ID = "developer_console"; /** * Build the payload for `POST /developers/v1/manifest/upsert_by_template` — * the console launcher's one-click agent creation endpoint (CDP 抓包确认)。 * 该模板建出的应用开箱自带 bot 能力、长连接事件/回调模式、基础事件订阅与 * card.action.trigger 回调,正是「正常申请默认带的权限」。 */ export declare function buildManifestTemplateCreatePayload(name: string, description: string, avatar: string, cid: string): { appManifestTemplateID: string; createAppUserCustomField: { i18n: { zh_cn: { name: string; description: string; }; }; avatar: string; primaryLang: string; }; cid: string; HTTPHead: {}; }; /** * 用已经登录的开放平台 Web session 创建一个企业自建应用并读取凭证。 * * 首选 console launcher 的「一键创建智能体」模板接口 * (manifest/upsert_by_template):模板应用出生即带 bot 能力、长连接、基础 * 事件与卡片回调,新建 bot 不再依赖后续订阅补齐。模板 ID 属内部契约,被 * 服务端明确拒绝时自动回退旧 app/create(裸自建应用,事件/回调由 * automateOpenPlatformSetup 增量补齐并 fail-closed 兜底);创建结果未知时 * 不回退(见 isDefiniteTemplateRejection)。Secret 只存在返回值中,不打印、 * 不写日志。 */ export declare function createOpenPlatformAppWithClient(client: OpenPlatformApiClient, options: { name: string; description?: string; iconFilePath?: string; creatorUserId: string; }): Promise<{ appId: string; appSecret: string; }>; /** * Read-only probe: are this app's VC meeting events (vc.bot.meeting_* + * participant_meeting_joined) subscribed, and is event mode the long connection? * Uses ONLY the cached Feishu Web session (disableQrLogin) and never publishes a * version — so it is safe to call at daemon startup. The caller decides whether * to run the full (publishing) automateOpenPlatformSetup based on the result: * only when events are actually missing / mode is wrong. */ export type VcMeetingEventProbeResult = { ok: true; missingVcEvents: string[]; eventModeReady: boolean; sessionFile?: string; } | { ok: false; reason: string; message: string; sessionFile?: string; }; export declare function probeVcMeetingEventSubscription(appId: string, options?: Pick): Promise; /** * 单次飞书 Web 扫码完成应用创建。session 会写入 ~/.botmux,后续 * automateOpenPlatformSetup 会直接复用,因此权限/redirect/发版不再二次扫码。 */ export declare function createFeishuOpenPlatformApp(options: CreateFeishuOpenPlatformAppOptions): Promise; /** * 列出当前登录人可见的自建应用(console `getAppList` 同款: * POST /developers/v1/app/list,body {Count, Cursor, QueryFilter},响应 * data.apps + totalCount,分页拉全)。console 是内部接口,item 字段名做 * 宽松解析,取不到 cli_ 开头 clientId 的条目丢弃。失败抛错(含 API 错误)。 */ export declare function listOpenPlatformApps(client: OpenPlatformApiClient, opts?: { pageSize?: number; maxApps?: number; }): Promise; /** * 读取指定应用的 App Secret(console `getAppSecret` 同款: * POST /developers/v1/secret/:clientId,响应含 secret 字段)。 * 只读接口——绝不触碰 /v1/secret/reset/*(会轮换 secret、打断在跑的 bot)。 */ export declare function fetchOpenPlatformAppSecret(client: OpenPlatformApiClient, clientId: string): Promise; export declare class OpenPlatformApiError extends Error { readonly payload: unknown; readonly status: number; constructor(message: string, payload: unknown, status: number); } /** 从 app_version/list 响应算下一个版本号(最新已发布 +1,无发布版 → 0.0.1)。 */ export declare function nextAppVersion(payload: unknown): string; /** 从 app_version/create 响应提取 versionId(多种响应形态兼容)。 */ export declare function extractVersionId(payload: unknown): string | undefined; export declare function safeErrorMessage(err: unknown): string; //# sourceMappingURL=open-platform-automation.d.ts.map