@larksuite/openclaw-lark 2025.7.15-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +76 -0
- package/bin/openclaw-lark.js +39 -0
- package/index.d.ts +36 -0
- package/index.js +188 -0
- package/openclaw.plugin.json +64 -0
- package/package.json +63 -0
- package/secret-contract-api.d.ts +15 -0
- package/secret-contract-api.js +78 -0
- package/skills/feishu-bitable/SKILL.md +248 -0
- package/skills/feishu-bitable/references/examples.md +813 -0
- package/skills/feishu-bitable/references/field-properties.md +763 -0
- package/skills/feishu-bitable/references/record-values.md +911 -0
- package/skills/feishu-calendar/SKILL.md +242 -0
- package/skills/feishu-channel-rules/SKILL.md +18 -0
- package/skills/feishu-channel-rules/references/markdown-syntax.md +138 -0
- package/skills/feishu-create-doc/SKILL.md +719 -0
- package/skills/feishu-fetch-doc/SKILL.md +93 -0
- package/skills/feishu-im-read/SKILL.md +163 -0
- package/skills/feishu-task/SKILL.md +340 -0
- package/skills/feishu-troubleshoot/SKILL.md +70 -0
- package/skills/feishu-update-doc/SKILL.md +285 -0
- package/src/card/builder.d.ts +152 -0
- package/src/card/builder.js +794 -0
- package/src/card/card-error.d.ts +91 -0
- package/src/card/card-error.js +206 -0
- package/src/card/cardkit.d.ts +90 -0
- package/src/card/cardkit.js +203 -0
- package/src/card/flush-controller.d.ts +45 -0
- package/src/card/flush-controller.js +138 -0
- package/src/card/image-resolver.d.ts +45 -0
- package/src/card/image-resolver.js +116 -0
- package/src/card/markdown-style.d.ts +16 -0
- package/src/card/markdown-style.js +106 -0
- package/src/card/reasoning-utils.d.ts +14 -0
- package/src/card/reasoning-utils.js +64 -0
- package/src/card/reply-dispatcher-types.d.ts +132 -0
- package/src/card/reply-dispatcher-types.js +61 -0
- package/src/card/reply-dispatcher.d.ts +15 -0
- package/src/card/reply-dispatcher.js +447 -0
- package/src/card/reply-mode.d.ts +41 -0
- package/src/card/reply-mode.js +70 -0
- package/src/card/streaming-card-controller.d.ts +118 -0
- package/src/card/streaming-card-controller.js +1045 -0
- package/src/card/tool-use-config.d.ts +26 -0
- package/src/card/tool-use-config.js +76 -0
- package/src/card/tool-use-display.d.ts +37 -0
- package/src/card/tool-use-display.js +476 -0
- package/src/card/tool-use-trace-store.d.ts +51 -0
- package/src/card/tool-use-trace-store.js +271 -0
- package/src/card/unavailable-guard.d.ts +35 -0
- package/src/card/unavailable-guard.js +87 -0
- package/src/channel/abort-detect.d.ts +47 -0
- package/src/channel/abort-detect.js +219 -0
- package/src/channel/chat-queue.d.ts +41 -0
- package/src/channel/chat-queue.js +68 -0
- package/src/channel/config-adapter.d.ts +23 -0
- package/src/channel/config-adapter.js +107 -0
- package/src/channel/directory.d.ts +57 -0
- package/src/channel/directory.js +197 -0
- package/src/channel/event-handlers.d.ts +17 -0
- package/src/channel/event-handlers.js +380 -0
- package/src/channel/interactive-dispatch.d.ts +59 -0
- package/src/channel/interactive-dispatch.js +195 -0
- package/src/channel/monitor.d.ts +17 -0
- package/src/channel/monitor.js +140 -0
- package/src/channel/onboarding-config.d.ts +18 -0
- package/src/channel/onboarding-config.js +96 -0
- package/src/channel/onboarding-migrate.d.ts +25 -0
- package/src/channel/onboarding-migrate.js +70 -0
- package/src/channel/onboarding.d.ts +12 -0
- package/src/channel/onboarding.js +300 -0
- package/src/channel/plugin.d.ts +13 -0
- package/src/channel/plugin.js +310 -0
- package/src/channel/probe.d.ts +14 -0
- package/src/channel/probe.js +24 -0
- package/src/channel/types.d.ts +37 -0
- package/src/channel/types.js +8 -0
- package/src/commands/auth.d.ts +21 -0
- package/src/commands/auth.js +165 -0
- package/src/commands/diagnose.d.ts +69 -0
- package/src/commands/diagnose.js +848 -0
- package/src/commands/doctor.d.ts +27 -0
- package/src/commands/doctor.js +588 -0
- package/src/commands/index.d.ts +25 -0
- package/src/commands/index.js +219 -0
- package/src/commands/locale.d.ts +7 -0
- package/src/commands/locale.js +8 -0
- package/src/core/accounts.d.ts +51 -0
- package/src/core/accounts.js +219 -0
- package/src/core/agent-config.d.ts +100 -0
- package/src/core/agent-config.js +148 -0
- package/src/core/api-error.d.ts +48 -0
- package/src/core/api-error.js +117 -0
- package/src/core/app-owner-fallback.d.ts +22 -0
- package/src/core/app-owner-fallback.js +39 -0
- package/src/core/app-scope-checker.d.ts +87 -0
- package/src/core/app-scope-checker.js +198 -0
- package/src/core/auth-errors.d.ts +144 -0
- package/src/core/auth-errors.js +160 -0
- package/src/core/card-action-operator.d.ts +33 -0
- package/src/core/card-action-operator.js +30 -0
- package/src/core/chat-info-cache.d.ts +67 -0
- package/src/core/chat-info-cache.js +165 -0
- package/src/core/comment-target.d.ts +65 -0
- package/src/core/comment-target.js +100 -0
- package/src/core/config-schema.d.ts +490 -0
- package/src/core/config-schema.js +223 -0
- package/src/core/device-flow.d.ts +77 -0
- package/src/core/device-flow.js +217 -0
- package/src/core/domains.d.ts +18 -0
- package/src/core/domains.js +34 -0
- package/src/core/feishu-fetch.d.ts +18 -0
- package/src/core/feishu-fetch.js +28 -0
- package/src/core/footer-config.d.ts +24 -0
- package/src/core/footer-config.js +51 -0
- package/src/core/lark-client.d.ts +125 -0
- package/src/core/lark-client.js +468 -0
- package/src/core/lark-logger.d.ts +23 -0
- package/src/core/lark-logger.js +160 -0
- package/src/core/lark-ticket.d.ts +29 -0
- package/src/core/lark-ticket.js +40 -0
- package/src/core/message-unavailable.d.ts +53 -0
- package/src/core/message-unavailable.js +142 -0
- package/src/core/owner-policy.d.ts +32 -0
- package/src/core/owner-policy.js +55 -0
- package/src/core/permission-url.d.ts +22 -0
- package/src/core/permission-url.js +76 -0
- package/src/core/raw-request.d.ts +27 -0
- package/src/core/raw-request.js +90 -0
- package/src/core/runtime-store.d.ts +13 -0
- package/src/core/runtime-store.js +29 -0
- package/src/core/scope-manager.d.ts +168 -0
- package/src/core/scope-manager.js +224 -0
- package/src/core/sdk-compat.d.ts +20 -0
- package/src/core/sdk-compat.js +28 -0
- package/src/core/security-check.d.ts +72 -0
- package/src/core/security-check.js +184 -0
- package/src/core/shutdown-hooks.d.ts +22 -0
- package/src/core/shutdown-hooks.js +61 -0
- package/src/core/synthetic-target.d.ts +33 -0
- package/src/core/synthetic-target.js +40 -0
- package/src/core/targets.d.ts +60 -0
- package/src/core/targets.js +173 -0
- package/src/core/token-store.d.ts +54 -0
- package/src/core/token-store.js +326 -0
- package/src/core/tool-client.d.ts +176 -0
- package/src/core/tool-client.js +426 -0
- package/src/core/tool-scopes.d.ts +156 -0
- package/src/core/tool-scopes.js +344 -0
- package/src/core/tools-config.d.ts +55 -0
- package/src/core/tools-config.js +143 -0
- package/src/core/types.d.ts +91 -0
- package/src/core/types.js +12 -0
- package/src/core/uat-client.d.ts +46 -0
- package/src/core/uat-client.js +192 -0
- package/src/core/version.d.ts +31 -0
- package/src/core/version.js +69 -0
- package/src/messaging/converters/audio.d.ts +8 -0
- package/src/messaging/converters/audio.js +24 -0
- package/src/messaging/converters/calendar.d.ts +13 -0
- package/src/messaging/converters/calendar.js +56 -0
- package/src/messaging/converters/content-converter-helpers.d.ts +30 -0
- package/src/messaging/converters/content-converter-helpers.js +82 -0
- package/src/messaging/converters/content-converter.d.ts +24 -0
- package/src/messaging/converters/content-converter.js +40 -0
- package/src/messaging/converters/file.d.ts +8 -0
- package/src/messaging/converters/file.js +24 -0
- package/src/messaging/converters/folder.d.ts +8 -0
- package/src/messaging/converters/folder.js +24 -0
- package/src/messaging/converters/hongbao.d.ts +8 -0
- package/src/messaging/converters/hongbao.js +20 -0
- package/src/messaging/converters/image.d.ts +8 -0
- package/src/messaging/converters/image.js +22 -0
- package/src/messaging/converters/index.d.ts +8 -0
- package/src/messaging/converters/index.js +53 -0
- package/src/messaging/converters/interactive/card-converter.d.ts +76 -0
- package/src/messaging/converters/interactive/card-converter.js +1177 -0
- package/src/messaging/converters/interactive/card-utils.d.ts +9 -0
- package/src/messaging/converters/interactive/card-utils.js +47 -0
- package/src/messaging/converters/interactive/index.d.ts +8 -0
- package/src/messaging/converters/interactive/index.js +25 -0
- package/src/messaging/converters/interactive/legacy.d.ts +11 -0
- package/src/messaging/converters/interactive/legacy.js +60 -0
- package/src/messaging/converters/interactive/types.d.ts +23 -0
- package/src/messaging/converters/interactive/types.js +27 -0
- package/src/messaging/converters/location.d.ts +8 -0
- package/src/messaging/converters/location.js +23 -0
- package/src/messaging/converters/merge-forward.d.ts +32 -0
- package/src/messaging/converters/merge-forward.js +235 -0
- package/src/messaging/converters/post.d.ts +11 -0
- package/src/messaging/converters/post.js +235 -0
- package/src/messaging/converters/share.d.ts +9 -0
- package/src/messaging/converters/share.js +28 -0
- package/src/messaging/converters/sticker.d.ts +8 -0
- package/src/messaging/converters/sticker.js +22 -0
- package/src/messaging/converters/system.d.ts +12 -0
- package/src/messaging/converters/system.js +36 -0
- package/src/messaging/converters/text.d.ts +8 -0
- package/src/messaging/converters/text.js +18 -0
- package/src/messaging/converters/todo.d.ts +8 -0
- package/src/messaging/converters/todo.js +45 -0
- package/src/messaging/converters/types.d.ts +114 -0
- package/src/messaging/converters/types.js +8 -0
- package/src/messaging/converters/unknown.d.ts +8 -0
- package/src/messaging/converters/unknown.js +20 -0
- package/src/messaging/converters/utils.d.ts +22 -0
- package/src/messaging/converters/utils.js +57 -0
- package/src/messaging/converters/video-chat.d.ts +8 -0
- package/src/messaging/converters/video-chat.js +31 -0
- package/src/messaging/converters/video.d.ts +8 -0
- package/src/messaging/converters/video.js +35 -0
- package/src/messaging/converters/vote.d.ts +8 -0
- package/src/messaging/converters/vote.js +28 -0
- package/src/messaging/inbound/bot-content.d.ts +84 -0
- package/src/messaging/inbound/bot-content.js +117 -0
- package/src/messaging/inbound/bot-loop-guard.d.ts +48 -0
- package/src/messaging/inbound/bot-loop-guard.js +89 -0
- package/src/messaging/inbound/comment-context.d.ts +82 -0
- package/src/messaging/inbound/comment-context.js +353 -0
- package/src/messaging/inbound/comment-handler.d.ts +30 -0
- package/src/messaging/inbound/comment-handler.js +269 -0
- package/src/messaging/inbound/dedup.d.ts +59 -0
- package/src/messaging/inbound/dedup.js +121 -0
- package/src/messaging/inbound/dispatch-builders.d.ts +104 -0
- package/src/messaging/inbound/dispatch-builders.js +241 -0
- package/src/messaging/inbound/dispatch-commands.d.ts +22 -0
- package/src/messaging/inbound/dispatch-commands.js +131 -0
- package/src/messaging/inbound/dispatch-context.d.ts +67 -0
- package/src/messaging/inbound/dispatch-context.js +153 -0
- package/src/messaging/inbound/dispatch.d.ts +50 -0
- package/src/messaging/inbound/dispatch.js +477 -0
- package/src/messaging/inbound/enrich.d.ts +102 -0
- package/src/messaging/inbound/enrich.js +236 -0
- package/src/messaging/inbound/gate-effects.d.ts +23 -0
- package/src/messaging/inbound/gate-effects.js +46 -0
- package/src/messaging/inbound/gate.d.ts +91 -0
- package/src/messaging/inbound/gate.js +342 -0
- package/src/messaging/inbound/handler-registry.d.ts +25 -0
- package/src/messaging/inbound/handler-registry.js +23 -0
- package/src/messaging/inbound/handler.d.ts +37 -0
- package/src/messaging/inbound/handler.js +286 -0
- package/src/messaging/inbound/media-resolver.d.ts +32 -0
- package/src/messaging/inbound/media-resolver.js +91 -0
- package/src/messaging/inbound/mention-registry.d.ts +59 -0
- package/src/messaging/inbound/mention-registry.js +115 -0
- package/src/messaging/inbound/mention.d.ts +48 -0
- package/src/messaging/inbound/mention.js +102 -0
- package/src/messaging/inbound/parse-io.d.ts +50 -0
- package/src/messaging/inbound/parse-io.js +86 -0
- package/src/messaging/inbound/parse.d.ts +28 -0
- package/src/messaging/inbound/parse.js +128 -0
- package/src/messaging/inbound/permission.d.ts +17 -0
- package/src/messaging/inbound/permission.js +44 -0
- package/src/messaging/inbound/policy.d.ts +95 -0
- package/src/messaging/inbound/policy.js +168 -0
- package/src/messaging/inbound/reaction-handler.d.ts +62 -0
- package/src/messaging/inbound/reaction-handler.js +259 -0
- package/src/messaging/inbound/sentinel-store.d.ts +37 -0
- package/src/messaging/inbound/sentinel-store.js +98 -0
- package/src/messaging/inbound/synthetic-message.d.ts +26 -0
- package/src/messaging/inbound/synthetic-message.js +59 -0
- package/src/messaging/inbound/user-name-cache-store.d.ts +62 -0
- package/src/messaging/inbound/user-name-cache-store.js +236 -0
- package/src/messaging/inbound/user-name-cache.d.ts +78 -0
- package/src/messaging/inbound/user-name-cache.js +306 -0
- package/src/messaging/inbound/vc-meeting-invited-handler.d.ts +20 -0
- package/src/messaging/inbound/vc-meeting-invited-handler.js +236 -0
- package/src/messaging/inbound/vc-sender.d.ts +41 -0
- package/src/messaging/inbound/vc-sender.js +53 -0
- package/src/messaging/outbound/actions.d.ts +16 -0
- package/src/messaging/outbound/actions.js +329 -0
- package/src/messaging/outbound/bot-peer-context.d.ts +42 -0
- package/src/messaging/outbound/bot-peer-context.js +40 -0
- package/src/messaging/outbound/chat-manage.d.ts +64 -0
- package/src/messaging/outbound/chat-manage.js +117 -0
- package/src/messaging/outbound/deliver.d.ts +186 -0
- package/src/messaging/outbound/deliver.js +410 -0
- package/src/messaging/outbound/fetch.d.ts +12 -0
- package/src/messaging/outbound/fetch.js +17 -0
- package/src/messaging/outbound/forward.d.ts +26 -0
- package/src/messaging/outbound/forward.js +51 -0
- package/src/messaging/outbound/media-url-utils.d.ts +29 -0
- package/src/messaging/outbound/media-url-utils.js +172 -0
- package/src/messaging/outbound/media.d.ts +260 -0
- package/src/messaging/outbound/media.js +865 -0
- package/src/messaging/outbound/normalize-mentions.d.ts +50 -0
- package/src/messaging/outbound/normalize-mentions.js +166 -0
- package/src/messaging/outbound/outbound-mention.d.ts +41 -0
- package/src/messaging/outbound/outbound-mention.js +112 -0
- package/src/messaging/outbound/outbound.d.ts +79 -0
- package/src/messaging/outbound/outbound.js +195 -0
- package/src/messaging/outbound/reactions.d.ts +124 -0
- package/src/messaging/outbound/reactions.js +384 -0
- package/src/messaging/outbound/send.d.ts +153 -0
- package/src/messaging/outbound/send.js +417 -0
- package/src/messaging/outbound/typing.d.ts +60 -0
- package/src/messaging/outbound/typing.js +139 -0
- package/src/messaging/shared/message-lookup.d.ts +54 -0
- package/src/messaging/shared/message-lookup.js +120 -0
- package/src/messaging/types.d.ts +316 -0
- package/src/messaging/types.js +11 -0
- package/src/tools/ask-user-question.d.ts +32 -0
- package/src/tools/ask-user-question.js +922 -0
- package/src/tools/auto-auth.d.ts +57 -0
- package/src/tools/auto-auth.js +904 -0
- package/src/tools/helpers.d.ts +264 -0
- package/src/tools/helpers.js +389 -0
- package/src/tools/mcp/doc/create.d.ts +12 -0
- package/src/tools/mcp/doc/create.js +47 -0
- package/src/tools/mcp/doc/fetch.d.ts +12 -0
- package/src/tools/mcp/doc/fetch.js +39 -0
- package/src/tools/mcp/doc/index.d.ts +12 -0
- package/src/tools/mcp/doc/index.js +50 -0
- package/src/tools/mcp/doc/update.d.ts +12 -0
- package/src/tools/mcp/doc/update.js +64 -0
- package/src/tools/mcp/shared.d.ts +59 -0
- package/src/tools/mcp/shared.js +239 -0
- package/src/tools/oapi/bitable/app-table-field.d.ts +16 -0
- package/src/tools/oapi/bitable/app-table-field.js +225 -0
- package/src/tools/oapi/bitable/app-table-record.d.ts +20 -0
- package/src/tools/oapi/bitable/app-table-record.js +439 -0
- package/src/tools/oapi/bitable/app-table-view.d.ts +16 -0
- package/src/tools/oapi/bitable/app-table-view.js +172 -0
- package/src/tools/oapi/bitable/app-table.d.ts +17 -0
- package/src/tools/oapi/bitable/app-table.js +195 -0
- package/src/tools/oapi/bitable/app.d.ts +18 -0
- package/src/tools/oapi/bitable/app.js +189 -0
- package/src/tools/oapi/bitable/index.d.ts +9 -0
- package/src/tools/oapi/bitable/index.js +17 -0
- package/src/tools/oapi/calendar/calendar.d.ts +15 -0
- package/src/tools/oapi/calendar/calendar.js +125 -0
- package/src/tools/oapi/calendar/event-attendee.d.ts +14 -0
- package/src/tools/oapi/calendar/event-attendee.js +161 -0
- package/src/tools/oapi/calendar/event.d.ts +16 -0
- package/src/tools/oapi/calendar/event.js +712 -0
- package/src/tools/oapi/calendar/freebusy.d.ts +13 -0
- package/src/tools/oapi/calendar/freebusy.js +114 -0
- package/src/tools/oapi/calendar/index.d.ts +8 -0
- package/src/tools/oapi/calendar/index.js +15 -0
- package/src/tools/oapi/chat/chat.d.ts +16 -0
- package/src/tools/oapi/chat/chat.js +127 -0
- package/src/tools/oapi/chat/index.d.ts +10 -0
- package/src/tools/oapi/chat/index.js +23 -0
- package/src/tools/oapi/chat/members.d.ts +11 -0
- package/src/tools/oapi/chat/members.js +84 -0
- package/src/tools/oapi/common/get-user.d.ts +12 -0
- package/src/tools/oapi/common/get-user.js +109 -0
- package/src/tools/oapi/common/index.d.ts +6 -0
- package/src/tools/oapi/common/index.js +11 -0
- package/src/tools/oapi/common/search-user.d.ts +11 -0
- package/src/tools/oapi/common/search-user.js +76 -0
- package/src/tools/oapi/drive/doc-comments.d.ts +15 -0
- package/src/tools/oapi/drive/doc-comments.js +351 -0
- package/src/tools/oapi/drive/doc-media.d.ts +19 -0
- package/src/tools/oapi/drive/doc-media.js +371 -0
- package/src/tools/oapi/drive/file.d.ts +19 -0
- package/src/tools/oapi/drive/file.js +519 -0
- package/src/tools/oapi/drive/index.d.ts +12 -0
- package/src/tools/oapi/drive/index.js +45 -0
- package/src/tools/oapi/helpers.d.ts +183 -0
- package/src/tools/oapi/helpers.js +385 -0
- package/src/tools/oapi/im/format-messages.d.ts +50 -0
- package/src/tools/oapi/im/format-messages.js +169 -0
- package/src/tools/oapi/im/index.d.ts +10 -0
- package/src/tools/oapi/im/index.js +25 -0
- package/src/tools/oapi/im/message-read.d.ts +13 -0
- package/src/tools/oapi/im/message-read.js +419 -0
- package/src/tools/oapi/im/message.d.ts +16 -0
- package/src/tools/oapi/im/message.js +152 -0
- package/src/tools/oapi/im/resource.d.ts +13 -0
- package/src/tools/oapi/im/resource.js +186 -0
- package/src/tools/oapi/im/time-utils.d.ts +46 -0
- package/src/tools/oapi/im/time-utils.js +212 -0
- package/src/tools/oapi/im/user-name-uat.d.ts +26 -0
- package/src/tools/oapi/im/user-name-uat.js +143 -0
- package/src/tools/oapi/index.d.ts +11 -0
- package/src/tools/oapi/index.js +64 -0
- package/src/tools/oapi/sdk-types.d.ts +96 -0
- package/src/tools/oapi/sdk-types.js +13 -0
- package/src/tools/oapi/search/doc-search.d.ts +13 -0
- package/src/tools/oapi/search/doc-search.js +194 -0
- package/src/tools/oapi/search/index.d.ts +12 -0
- package/src/tools/oapi/search/index.js +37 -0
- package/src/tools/oapi/sheets/index.d.ts +12 -0
- package/src/tools/oapi/sheets/index.js +35 -0
- package/src/tools/oapi/sheets/sheet.d.ts +16 -0
- package/src/tools/oapi/sheets/sheet.js +688 -0
- package/src/tools/oapi/task/attachment.d.ts +18 -0
- package/src/tools/oapi/task/attachment.js +107 -0
- package/src/tools/oapi/task/comment.d.ts +15 -0
- package/src/tools/oapi/task/comment.js +149 -0
- package/src/tools/oapi/task/index.d.ts +11 -0
- package/src/tools/oapi/task/index.js +21 -0
- package/src/tools/oapi/task/section.d.ts +17 -0
- package/src/tools/oapi/task/section.js +293 -0
- package/src/tools/oapi/task/subtask.d.ts +14 -0
- package/src/tools/oapi/task/subtask.js +171 -0
- package/src/tools/oapi/task/task.d.ts +19 -0
- package/src/tools/oapi/task/task.js +512 -0
- package/src/tools/oapi/task/task_agent.d.ts +14 -0
- package/src/tools/oapi/task/task_agent.js +108 -0
- package/src/tools/oapi/task/tasklist.d.ts +19 -0
- package/src/tools/oapi/task/tasklist.js +276 -0
- package/src/tools/oapi/wiki/index.d.ts +12 -0
- package/src/tools/oapi/wiki/index.js +42 -0
- package/src/tools/oapi/wiki/space-node.d.ts +17 -0
- package/src/tools/oapi/wiki/space-node.js +233 -0
- package/src/tools/oapi/wiki/space.d.ts +15 -0
- package/src/tools/oapi/wiki/space.js +133 -0
- package/src/tools/oauth-batch-auth.d.ts +11 -0
- package/src/tools/oauth-batch-auth.js +150 -0
- package/src/tools/oauth-cards.d.ts +39 -0
- package/src/tools/oauth-cards.js +324 -0
- package/src/tools/oauth.d.ts +47 -0
- package/src/tools/oauth.js +592 -0
- package/src/tools/onboarding-auth.d.ts +27 -0
- package/src/tools/onboarding-auth.js +133 -0
- package/src/tools/tat/im/index.d.ts +15 -0
- package/src/tools/tat/im/index.js +22 -0
- package/src/tools/tat/im/resource.d.ts +15 -0
- package/src/tools/tat/im/resource.js +192 -0
- package/tsdown.config.d.ts +2 -0
- package/tsdown.config.js +25 -0
- package/vitest.config.d.ts +2 -0
- package/vitest.config.js +12 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
/**
|
|
4
|
+
* Agent configuration helpers for the Lark/Feishu channel plugin.
|
|
5
|
+
*
|
|
6
|
+
* Reads agent-level configuration (identity, skills, tools, subagents)
|
|
7
|
+
* from the top-level `agents.list` in OpenClawConfig. These helpers
|
|
8
|
+
* bridge the gap between the SDK's agent infrastructure and the Feishu
|
|
9
|
+
* plugin's dispatch/reply layers.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.listConfiguredAgents = listConfiguredAgents;
|
|
13
|
+
exports.resolveAgentEntry = resolveAgentEntry;
|
|
14
|
+
exports.getAgentDisplayName = getAgentDisplayName;
|
|
15
|
+
exports.getAgentSkillsFilter = getAgentSkillsFilter;
|
|
16
|
+
exports.getAgentToolsPolicy = getAgentToolsPolicy;
|
|
17
|
+
exports.mergeSkillFilters = mergeSkillFilters;
|
|
18
|
+
exports.isToolAllowedByPolicy = isToolAllowedByPolicy;
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Helpers
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
/**
|
|
23
|
+
* Retrieve the full list of configured agents from config.
|
|
24
|
+
*
|
|
25
|
+
* @param cfg - The top-level application config.
|
|
26
|
+
* @returns Array of agent entries, or empty array if none configured.
|
|
27
|
+
*/
|
|
28
|
+
function listConfiguredAgents(cfg) {
|
|
29
|
+
const agents = cfg.agents;
|
|
30
|
+
return agents?.list ?? [];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Look up a specific agent's configuration by its ID.
|
|
34
|
+
*
|
|
35
|
+
* @param cfg - The top-level application config.
|
|
36
|
+
* @param agentId - The agent ID to search for.
|
|
37
|
+
* @returns The matching agent entry, or `undefined` if not found.
|
|
38
|
+
*/
|
|
39
|
+
function resolveAgentEntry(cfg, agentId) {
|
|
40
|
+
return listConfiguredAgents(cfg).find((a) => a.id === agentId);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Resolve a human-readable display name for an agent.
|
|
44
|
+
*
|
|
45
|
+
* Priority: `identity.name` > `name` > `undefined`.
|
|
46
|
+
*
|
|
47
|
+
* @param cfg - The top-level application config.
|
|
48
|
+
* @param agentId - The agent ID.
|
|
49
|
+
* @returns The display name, or `undefined` if none configured.
|
|
50
|
+
*/
|
|
51
|
+
function getAgentDisplayName(cfg, agentId) {
|
|
52
|
+
const entry = resolveAgentEntry(cfg, agentId);
|
|
53
|
+
if (!entry)
|
|
54
|
+
return undefined;
|
|
55
|
+
return entry.identity?.name ?? entry.name;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Resolve the per-agent skills filter.
|
|
59
|
+
*
|
|
60
|
+
* @param cfg - The top-level application config.
|
|
61
|
+
* @param agentId - The agent ID.
|
|
62
|
+
* @returns Skill allowlist, or `undefined` if no agent-level filter.
|
|
63
|
+
*/
|
|
64
|
+
function getAgentSkillsFilter(cfg, agentId) {
|
|
65
|
+
return resolveAgentEntry(cfg, agentId)?.skills;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Resolve the per-agent tools policy (allow/deny lists).
|
|
69
|
+
*
|
|
70
|
+
* @param cfg - The top-level application config.
|
|
71
|
+
* @param agentId - The agent ID.
|
|
72
|
+
* @returns Tools policy object, or `undefined` if none configured.
|
|
73
|
+
*/
|
|
74
|
+
function getAgentToolsPolicy(cfg, agentId) {
|
|
75
|
+
const entry = resolveAgentEntry(cfg, agentId);
|
|
76
|
+
if (!entry?.tools)
|
|
77
|
+
return undefined;
|
|
78
|
+
const { allow, deny } = entry.tools;
|
|
79
|
+
if (!allow && !deny)
|
|
80
|
+
return undefined;
|
|
81
|
+
return { allow, deny };
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Merge agent-level and group-level skill filters.
|
|
85
|
+
*
|
|
86
|
+
* When both are present, the effective filter is the intersection:
|
|
87
|
+
* a skill must appear in both lists to be included. When only one
|
|
88
|
+
* is present, that list is used as-is.
|
|
89
|
+
*
|
|
90
|
+
* @param agentSkills - Per-agent skill allowlist (from AgentConfig.skills).
|
|
91
|
+
* @param groupSkills - Per-group skill allowlist (from FeishuGroupConfig.skills).
|
|
92
|
+
* @returns Merged skill filter, or `undefined` if neither is set.
|
|
93
|
+
*/
|
|
94
|
+
function mergeSkillFilters(agentSkills, groupSkills) {
|
|
95
|
+
if (!agentSkills && !groupSkills)
|
|
96
|
+
return undefined;
|
|
97
|
+
if (!agentSkills)
|
|
98
|
+
return groupSkills;
|
|
99
|
+
if (!groupSkills)
|
|
100
|
+
return agentSkills;
|
|
101
|
+
// Intersection: group filter narrows the agent filter.
|
|
102
|
+
const agentSet = new Set(agentSkills);
|
|
103
|
+
return groupSkills.filter((s) => agentSet.has(s));
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Check whether a tool name is permitted by an agent's tool policy.
|
|
107
|
+
*
|
|
108
|
+
* Evaluation order:
|
|
109
|
+
* 1. If `deny` list exists and tool matches → denied.
|
|
110
|
+
* 2. If `allow` list exists and tool does NOT match → denied.
|
|
111
|
+
* 3. Otherwise → allowed.
|
|
112
|
+
*
|
|
113
|
+
* Supports glob-like patterns with trailing `*` (e.g. `feishu_calendar_*`).
|
|
114
|
+
*
|
|
115
|
+
* @param toolName - The tool name being invoked.
|
|
116
|
+
* @param policy - The agent's tool policy.
|
|
117
|
+
* @returns `true` if the tool is allowed, `false` if denied.
|
|
118
|
+
*/
|
|
119
|
+
function isToolAllowedByPolicy(toolName, policy) {
|
|
120
|
+
if (!policy)
|
|
121
|
+
return true;
|
|
122
|
+
if (policy.deny && policy.deny.length > 0) {
|
|
123
|
+
if (matchesAnyPattern(toolName, policy.deny))
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
if (policy.allow && policy.allow.length > 0) {
|
|
127
|
+
return matchesAnyPattern(toolName, policy.allow);
|
|
128
|
+
}
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Check whether a string matches any of the given patterns.
|
|
133
|
+
* Supports trailing `*` as a simple wildcard.
|
|
134
|
+
*/
|
|
135
|
+
function matchesAnyPattern(value, patterns) {
|
|
136
|
+
for (const pattern of patterns) {
|
|
137
|
+
if (pattern === '*')
|
|
138
|
+
return true;
|
|
139
|
+
if (pattern.endsWith('*')) {
|
|
140
|
+
if (value.startsWith(pattern.slice(0, -1)))
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
else if (value === pattern) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* Shared Lark API error handling utilities.
|
|
6
|
+
*
|
|
7
|
+
* Provides unified error handling for two distinct error paths:
|
|
8
|
+
*
|
|
9
|
+
* 1. **Response-level errors** — The SDK returns a response object with a
|
|
10
|
+
* non-zero `code`. Handled by {@link assertLarkOk}.
|
|
11
|
+
*
|
|
12
|
+
* 2. **Thrown exceptions** — The SDK throws an Axios-style error (HTTP 4xx)
|
|
13
|
+
* whose properties include the Feishu error `code` and `msg`.
|
|
14
|
+
* Handled by {@link formatLarkError}.
|
|
15
|
+
*
|
|
16
|
+
* Both paths intercept well-known codes (e.g. LARK_ERROR.APP_SCOPE_MISSING (99991672) — missing API scopes)
|
|
17
|
+
* and produce user-friendly messages with actionable authorization links.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* 从 Lark SDK 抛错对象中提取飞书 API code。
|
|
21
|
+
*
|
|
22
|
+
* 支持三种常见结构:
|
|
23
|
+
* - `{ code }` — SDK 直接挂载
|
|
24
|
+
* - `{ data: { code } }` — 响应体嵌套
|
|
25
|
+
* - `{ response: { data: { code } } }` — Axios 风格
|
|
26
|
+
*/
|
|
27
|
+
export declare function extractLarkApiCode(err: unknown): number | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Assert that a Lark SDK response is successful (code === 0).
|
|
30
|
+
*
|
|
31
|
+
* For permission errors (code LARK_ERROR.APP_SCOPE_MISSING (99991672)), the thrown error includes the
|
|
32
|
+
* required scope names and a direct authorization URL so the AI can
|
|
33
|
+
* present it to the end user.
|
|
34
|
+
*/
|
|
35
|
+
export declare function assertLarkOk(res: {
|
|
36
|
+
code?: number;
|
|
37
|
+
msg?: string;
|
|
38
|
+
}): void;
|
|
39
|
+
/**
|
|
40
|
+
* Extract a meaningful error message from a thrown Lark SDK / Axios error.
|
|
41
|
+
*
|
|
42
|
+
* The Lark SDK throws Axios errors whose object carries Feishu-specific
|
|
43
|
+
* fields (`code`, `msg`) alongside the standard `message`. For permission
|
|
44
|
+
* errors (LARK_ERROR.APP_SCOPE_MISSING (99991672)) we format a user-friendly string with scopes + auth URL.
|
|
45
|
+
* For all other errors we try `err.msg` first (the Feishu detail) and fall
|
|
46
|
+
* back to `err.message` (the generic Axios text).
|
|
47
|
+
*/
|
|
48
|
+
export declare function formatLarkError(err: unknown): string;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* Shared Lark API error handling utilities.
|
|
7
|
+
*
|
|
8
|
+
* Provides unified error handling for two distinct error paths:
|
|
9
|
+
*
|
|
10
|
+
* 1. **Response-level errors** — The SDK returns a response object with a
|
|
11
|
+
* non-zero `code`. Handled by {@link assertLarkOk}.
|
|
12
|
+
*
|
|
13
|
+
* 2. **Thrown exceptions** — The SDK throws an Axios-style error (HTTP 4xx)
|
|
14
|
+
* whose properties include the Feishu error `code` and `msg`.
|
|
15
|
+
* Handled by {@link formatLarkError}.
|
|
16
|
+
*
|
|
17
|
+
* Both paths intercept well-known codes (e.g. LARK_ERROR.APP_SCOPE_MISSING (99991672) — missing API scopes)
|
|
18
|
+
* and produce user-friendly messages with actionable authorization links.
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.extractLarkApiCode = extractLarkApiCode;
|
|
22
|
+
exports.assertLarkOk = assertLarkOk;
|
|
23
|
+
exports.formatLarkError = formatLarkError;
|
|
24
|
+
const permission_url_1 = require("./permission-url.js");
|
|
25
|
+
const auth_errors_1 = require("./auth-errors.js");
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Helpers
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
/**
|
|
30
|
+
* Given a Feishu error code and msg, format a user-friendly permission
|
|
31
|
+
* error string if the code is LARK_ERROR.APP_SCOPE_MISSING (99991672). Returns `null` for other codes.
|
|
32
|
+
*/
|
|
33
|
+
function formatPermissionError(code, msg) {
|
|
34
|
+
if (code !== auth_errors_1.LARK_ERROR.APP_SCOPE_MISSING)
|
|
35
|
+
return null;
|
|
36
|
+
const authUrl = (0, permission_url_1.extractPermissionGrantUrl)(msg);
|
|
37
|
+
const scopes = (0, permission_url_1.extractPermissionScopes)(msg);
|
|
38
|
+
return `权限不足:应用缺少 [${scopes}] 权限。\n` + `请管理员点击以下链接申请并开通权限:\n${authUrl}`;
|
|
39
|
+
}
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Code extraction
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
function coerceCode(value) {
|
|
44
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
if (typeof value === 'string') {
|
|
48
|
+
const parsed = Number(value);
|
|
49
|
+
if (Number.isFinite(parsed))
|
|
50
|
+
return parsed;
|
|
51
|
+
}
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 从 Lark SDK 抛错对象中提取飞书 API code。
|
|
56
|
+
*
|
|
57
|
+
* 支持三种常见结构:
|
|
58
|
+
* - `{ code }` — SDK 直接挂载
|
|
59
|
+
* - `{ data: { code } }` — 响应体嵌套
|
|
60
|
+
* - `{ response: { data: { code } } }` — Axios 风格
|
|
61
|
+
*/
|
|
62
|
+
function extractLarkApiCode(err) {
|
|
63
|
+
if (!err || typeof err !== 'object')
|
|
64
|
+
return undefined;
|
|
65
|
+
const e = err;
|
|
66
|
+
return coerceCode(e.code) ?? coerceCode(e.data?.code) ?? coerceCode(e.response?.data?.code);
|
|
67
|
+
}
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Public API
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
/**
|
|
72
|
+
* Assert that a Lark SDK response is successful (code === 0).
|
|
73
|
+
*
|
|
74
|
+
* For permission errors (code LARK_ERROR.APP_SCOPE_MISSING (99991672)), the thrown error includes the
|
|
75
|
+
* required scope names and a direct authorization URL so the AI can
|
|
76
|
+
* present it to the end user.
|
|
77
|
+
*/
|
|
78
|
+
function assertLarkOk(res) {
|
|
79
|
+
if (!res.code || res.code === 0)
|
|
80
|
+
return;
|
|
81
|
+
const permMsg = formatPermissionError(res.code, res.msg ?? '');
|
|
82
|
+
if (permMsg)
|
|
83
|
+
throw new Error(permMsg);
|
|
84
|
+
throw new Error(res.msg ?? `Feishu API error (code: ${res.code})`);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Extract a meaningful error message from a thrown Lark SDK / Axios error.
|
|
88
|
+
*
|
|
89
|
+
* The Lark SDK throws Axios errors whose object carries Feishu-specific
|
|
90
|
+
* fields (`code`, `msg`) alongside the standard `message`. For permission
|
|
91
|
+
* errors (LARK_ERROR.APP_SCOPE_MISSING (99991672)) we format a user-friendly string with scopes + auth URL.
|
|
92
|
+
* For all other errors we try `err.msg` first (the Feishu detail) and fall
|
|
93
|
+
* back to `err.message` (the generic Axios text).
|
|
94
|
+
*/
|
|
95
|
+
function formatLarkError(err) {
|
|
96
|
+
if (!err || typeof err !== 'object') {
|
|
97
|
+
return String(err);
|
|
98
|
+
}
|
|
99
|
+
const e = err;
|
|
100
|
+
// Path 1: Lark SDK merges Feishu fields onto the thrown error object.
|
|
101
|
+
if (typeof e.code === 'number' && e.msg) {
|
|
102
|
+
const permMsg = formatPermissionError(e.code, e.msg);
|
|
103
|
+
if (permMsg)
|
|
104
|
+
return permMsg;
|
|
105
|
+
return e.msg;
|
|
106
|
+
}
|
|
107
|
+
// Path 2: Standard Axios error — dig into response.data.
|
|
108
|
+
const data = e.response?.data;
|
|
109
|
+
if (data && typeof data.code === 'number' && data.msg) {
|
|
110
|
+
const permMsg = formatPermissionError(data.code, data.msg);
|
|
111
|
+
if (permMsg)
|
|
112
|
+
return permMsg;
|
|
113
|
+
return data.msg;
|
|
114
|
+
}
|
|
115
|
+
// Fallback.
|
|
116
|
+
return e.message ?? String(err);
|
|
117
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* 应用所有者查询 — 复用 app-scope-checker 的 API 调用和统一 owner 定义。
|
|
6
|
+
*
|
|
7
|
+
* 所有 owner 判定统一使用 {@link getAppInfo} 返回的 `effectiveOwnerOpenId`。
|
|
8
|
+
* 不维护独立缓存,完全依赖 app-scope-checker 的 30s 缓存。
|
|
9
|
+
*/
|
|
10
|
+
import type * as Lark from '@larksuiteoapi/node-sdk';
|
|
11
|
+
import type { ConfiguredLarkAccount } from './types';
|
|
12
|
+
/**
|
|
13
|
+
* 获取应用的 effectiveOwnerOpenId。
|
|
14
|
+
*
|
|
15
|
+
* 复用 app-scope-checker 的 API 调用、缓存和统一 owner 定义(effectiveOwnerOpenId)。
|
|
16
|
+
* 查询失败时返回 undefined(fail-open)。
|
|
17
|
+
*
|
|
18
|
+
* @param account - 已配置的飞书账号信息
|
|
19
|
+
* @param sdk - 飞书 SDK 实例(必须已初始化 TAT)
|
|
20
|
+
* @returns 应用所有者的 open_id,如果查询失败则返回 undefined
|
|
21
|
+
*/
|
|
22
|
+
export declare function getAppOwnerFallback(account: ConfiguredLarkAccount, sdk: Lark.Client): Promise<string | undefined>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* 应用所有者查询 — 复用 app-scope-checker 的 API 调用和统一 owner 定义。
|
|
7
|
+
*
|
|
8
|
+
* 所有 owner 判定统一使用 {@link getAppInfo} 返回的 `effectiveOwnerOpenId`。
|
|
9
|
+
* 不维护独立缓存,完全依赖 app-scope-checker 的 30s 缓存。
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.getAppOwnerFallback = getAppOwnerFallback;
|
|
13
|
+
const app_scope_checker_1 = require("./app-scope-checker.js");
|
|
14
|
+
const lark_logger_1 = require("./lark-logger.js");
|
|
15
|
+
const log = (0, lark_logger_1.larkLogger)('core/app-owner-fallback');
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Public API
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
/**
|
|
20
|
+
* 获取应用的 effectiveOwnerOpenId。
|
|
21
|
+
*
|
|
22
|
+
* 复用 app-scope-checker 的 API 调用、缓存和统一 owner 定义(effectiveOwnerOpenId)。
|
|
23
|
+
* 查询失败时返回 undefined(fail-open)。
|
|
24
|
+
*
|
|
25
|
+
* @param account - 已配置的飞书账号信息
|
|
26
|
+
* @param sdk - 飞书 SDK 实例(必须已初始化 TAT)
|
|
27
|
+
* @returns 应用所有者的 open_id,如果查询失败则返回 undefined
|
|
28
|
+
*/
|
|
29
|
+
async function getAppOwnerFallback(account, sdk) {
|
|
30
|
+
const { appId } = account;
|
|
31
|
+
try {
|
|
32
|
+
const appInfo = await (0, app_scope_checker_1.getAppInfo)(sdk, appId);
|
|
33
|
+
return appInfo.effectiveOwnerOpenId;
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
log.warn(`failed to get owner for ${appId}: ${err instanceof Error ? err.message : err}`);
|
|
37
|
+
return undefined; // fail-open: 获取失败不阻塞业务
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* App Scope Checker — 查询应用已开通的 scope 列表。
|
|
6
|
+
*
|
|
7
|
+
* 通过 `GET /open-apis/application/v6/applications/:app_id` (TAT) 获取
|
|
8
|
+
* 应用信息,从 `app.scopes` 中提取已开通的 scope 字符串列表。
|
|
9
|
+
*
|
|
10
|
+
* 结果带 30 秒内存缓存,避免每次 invoke() 都调远程 API。
|
|
11
|
+
* scope 检查失败后可调 {@link invalidateAppScopeCache} 清缓存重查。
|
|
12
|
+
*/
|
|
13
|
+
import type * as Lark from '@larksuiteoapi/node-sdk';
|
|
14
|
+
export interface AppInfo {
|
|
15
|
+
appId: string;
|
|
16
|
+
creatorId?: string;
|
|
17
|
+
ownerOpenId?: string;
|
|
18
|
+
ownerType?: number;
|
|
19
|
+
/**
|
|
20
|
+
* 统一的 owner 判定结果。所有需要判定"谁是应用 owner"的场景都应使用此字段。
|
|
21
|
+
*
|
|
22
|
+
* 规则:owner_type=2(企业内成员)时取 owner_id,否则回退 creator_id。
|
|
23
|
+
* 兼容 owner.owner_type 和 owner.type 两种字段名。
|
|
24
|
+
*/
|
|
25
|
+
effectiveOwnerOpenId?: string;
|
|
26
|
+
scopes: Array<{
|
|
27
|
+
scope: string;
|
|
28
|
+
token_types?: string[];
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
/** 清除指定 appId 的缓存。 */
|
|
32
|
+
export declare function invalidateAppScopeCache(appId: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* 获取应用已开通的 scope 列表。
|
|
35
|
+
*
|
|
36
|
+
* 需要应用自身有 `application:application:self_manage` 权限。
|
|
37
|
+
* `appId` 可传 `"me"` 查自己。
|
|
38
|
+
*
|
|
39
|
+
* @param sdk - Lark SDK 实例
|
|
40
|
+
* @param appId - 应用 ID
|
|
41
|
+
* @param tokenType - token 类型,用于过滤只支持特定 token 类型的 scope
|
|
42
|
+
* @returns scope 字符串数组,如 `["calendar:calendar", "task:task:write"]`
|
|
43
|
+
*/
|
|
44
|
+
export declare function getAppGrantedScopes(sdk: Lark.Client, appId: string, tokenType?: 'user' | 'tenant'): Promise<string[]>;
|
|
45
|
+
/**
|
|
46
|
+
* 获取应用信息,包括 owner 信息。
|
|
47
|
+
*
|
|
48
|
+
* 复用 getAppGrantedScopes 的 API 调用和缓存。
|
|
49
|
+
* 如果缓存中已有数据且未过期,直接从缓存提取。
|
|
50
|
+
*
|
|
51
|
+
* @param sdk - Lark SDK 实例
|
|
52
|
+
* @param appId - 应用 ID(可传 "me")
|
|
53
|
+
*/
|
|
54
|
+
export declare function getAppInfo(sdk: Lark.Client, appId: string): Promise<AppInfo>;
|
|
55
|
+
/**
|
|
56
|
+
* 计算 APP 已有 ∩ OAPI 需要 的交集。
|
|
57
|
+
*
|
|
58
|
+
* 用于传给 OAuth 的 scope 参数 — 只请求 APP 已开通且 API 需要的 scope。
|
|
59
|
+
*
|
|
60
|
+
* @param appGranted - 应用已开通的 scope 列表
|
|
61
|
+
* @param apiRequired - OAPI 要求的 scope 列表
|
|
62
|
+
* @returns 交集 scope 列表
|
|
63
|
+
*/
|
|
64
|
+
export declare function intersectScopes(appGranted: string[], apiRequired: string[]): string[];
|
|
65
|
+
/**
|
|
66
|
+
* 计算 OAPI 需要但 APP 未开通的 scope(差集)。
|
|
67
|
+
*
|
|
68
|
+
* 用于 AppScopeMissingError 的 missingScopes。
|
|
69
|
+
*
|
|
70
|
+
* @param appGranted - 应用已开通的 scope 列表
|
|
71
|
+
* @param apiRequired - OAPI 要求的 scope 列表
|
|
72
|
+
* @returns 缺失的 scope 列表
|
|
73
|
+
*/
|
|
74
|
+
export declare function missingScopes(appGranted: string[], apiRequired: string[]): string[];
|
|
75
|
+
/**
|
|
76
|
+
* 校验应用已开通的 scope 是否满足要求。
|
|
77
|
+
*
|
|
78
|
+
* 与 tool-client.ts invoke() 的 scope 校验逻辑完全一致,作为唯一真值来源:
|
|
79
|
+
* - `scopeNeedType === "all"`: appScopes 必须包含 requiredScopes 的全部项
|
|
80
|
+
* - 其他(默认 "one"): appScopes 与 requiredScopes 的交集非空即可
|
|
81
|
+
* - appScopes 为空: 视为满足(API 查询失败,退回服务端判断)
|
|
82
|
+
*
|
|
83
|
+
* @param appScopes - 应用已开通的 scope 列表(由 getAppGrantedScopes 返回)
|
|
84
|
+
* @param requiredScopes - 需要的 scope 列表
|
|
85
|
+
* @param scopeNeedType - "all" 表示全部必须,undefined/"one" 表示任一即可
|
|
86
|
+
*/
|
|
87
|
+
export declare function isAppScopeSatisfied(appScopes: string[], requiredScopes: string[], scopeNeedType?: 'one' | 'all'): boolean;
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* App Scope Checker — 查询应用已开通的 scope 列表。
|
|
7
|
+
*
|
|
8
|
+
* 通过 `GET /open-apis/application/v6/applications/:app_id` (TAT) 获取
|
|
9
|
+
* 应用信息,从 `app.scopes` 中提取已开通的 scope 字符串列表。
|
|
10
|
+
*
|
|
11
|
+
* 结果带 30 秒内存缓存,避免每次 invoke() 都调远程 API。
|
|
12
|
+
* scope 检查失败后可调 {@link invalidateAppScopeCache} 清缓存重查。
|
|
13
|
+
*/
|
|
14
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.invalidateAppScopeCache = invalidateAppScopeCache;
|
|
17
|
+
exports.getAppGrantedScopes = getAppGrantedScopes;
|
|
18
|
+
exports.getAppInfo = getAppInfo;
|
|
19
|
+
exports.intersectScopes = intersectScopes;
|
|
20
|
+
exports.missingScopes = missingScopes;
|
|
21
|
+
exports.isAppScopeSatisfied = isAppScopeSatisfied;
|
|
22
|
+
const lark_logger_1 = require("./lark-logger.js");
|
|
23
|
+
const log = (0, lark_logger_1.larkLogger)('core/app-scope-checker');
|
|
24
|
+
const auth_errors_1 = require("./auth-errors.js");
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Cache
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
const cache = new Map();
|
|
29
|
+
const CACHE_TTL_MS = 30 * 1000; // 30 秒
|
|
30
|
+
/** 清除指定 appId 的缓存。 */
|
|
31
|
+
function invalidateAppScopeCache(appId) {
|
|
32
|
+
cache.delete(appId);
|
|
33
|
+
}
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Fetch
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
/**
|
|
38
|
+
* 获取应用已开通的 scope 列表。
|
|
39
|
+
*
|
|
40
|
+
* 需要应用自身有 `application:application:self_manage` 权限。
|
|
41
|
+
* `appId` 可传 `"me"` 查自己。
|
|
42
|
+
*
|
|
43
|
+
* @param sdk - Lark SDK 实例
|
|
44
|
+
* @param appId - 应用 ID
|
|
45
|
+
* @param tokenType - token 类型,用于过滤只支持特定 token 类型的 scope
|
|
46
|
+
* @returns scope 字符串数组,如 `["calendar:calendar", "task:task:write"]`
|
|
47
|
+
*/
|
|
48
|
+
async function getAppGrantedScopes(sdk, appId, tokenType) {
|
|
49
|
+
// 1. 检查缓存
|
|
50
|
+
const cached = cache.get(appId);
|
|
51
|
+
if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
|
|
52
|
+
// 从缓存中过滤出支持当前 token 类型的 scope
|
|
53
|
+
return cached.rawScopes
|
|
54
|
+
.filter((s) => {
|
|
55
|
+
if (tokenType && s.token_types && Array.isArray(s.token_types)) {
|
|
56
|
+
return s.token_types.includes(tokenType);
|
|
57
|
+
}
|
|
58
|
+
return true;
|
|
59
|
+
})
|
|
60
|
+
.map((s) => s.scope);
|
|
61
|
+
}
|
|
62
|
+
// 2. 调用 API
|
|
63
|
+
try {
|
|
64
|
+
const res = await sdk.request({
|
|
65
|
+
method: 'GET',
|
|
66
|
+
url: `/open-apis/application/v6/applications/${appId}`,
|
|
67
|
+
params: { lang: 'zh_cn' },
|
|
68
|
+
});
|
|
69
|
+
if (res.code !== 0) {
|
|
70
|
+
// 任何 API 错误都认为是应用缺少 application:application:self_manage 权限
|
|
71
|
+
throw new auth_errors_1.AppScopeCheckFailedError(appId);
|
|
72
|
+
}
|
|
73
|
+
// 响应结构: res.data.app.scopes → [{ scope: "xxx", description, level, token_types?: string[] }]
|
|
74
|
+
// 或者从 app_version 中获取 scopes
|
|
75
|
+
const app = res.data?.app ?? res.app ?? res.data;
|
|
76
|
+
const rawScopes = app?.scopes ?? app?.online_version?.scopes ?? [];
|
|
77
|
+
// 提取并验证 scope 字符串
|
|
78
|
+
const validScopes = rawScopes
|
|
79
|
+
.filter((s) => typeof s.scope === 'string' && s.scope.length > 0)
|
|
80
|
+
.map((s) => ({ scope: s.scope, token_types: s.token_types }));
|
|
81
|
+
// 3. 写缓存(缓存完整数据,包含 token_types 和原始 app 对象)
|
|
82
|
+
cache.set(appId, { rawScopes: validScopes, rawApp: app, fetchedAt: Date.now() });
|
|
83
|
+
log.info(`fetched ${validScopes.length} scopes for app ${appId}`);
|
|
84
|
+
// 4. 根据 tokenType 过滤
|
|
85
|
+
const scopes = validScopes
|
|
86
|
+
.filter((s) => {
|
|
87
|
+
if (tokenType && s.token_types && Array.isArray(s.token_types)) {
|
|
88
|
+
return s.token_types.includes(tokenType);
|
|
89
|
+
}
|
|
90
|
+
return true;
|
|
91
|
+
})
|
|
92
|
+
.map((s) => s.scope);
|
|
93
|
+
log.info(`returning ${scopes.length} scopes${tokenType ? ` for ${tokenType} token` : ''}`);
|
|
94
|
+
return scopes;
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
// 如果是 AppScopeCheckFailedError,重新抛出(不吞掉)
|
|
98
|
+
if (err instanceof auth_errors_1.AppScopeCheckFailedError) {
|
|
99
|
+
throw err;
|
|
100
|
+
}
|
|
101
|
+
// 检查是否是权限相关的 HTTP 错误(400/403)
|
|
102
|
+
// axios/SDK 异常对象通常包含 response.status 或 status 字段
|
|
103
|
+
const statusCode = err?.response?.status || err?.status || err?.statusCode;
|
|
104
|
+
const isPermissionError = statusCode === 400 ||
|
|
105
|
+
statusCode === 403 ||
|
|
106
|
+
(err instanceof Error && (err.message.includes('status code 400') || err.message.includes('status code 403')));
|
|
107
|
+
if (isPermissionError) {
|
|
108
|
+
throw new auth_errors_1.AppScopeCheckFailedError(appId);
|
|
109
|
+
}
|
|
110
|
+
log.warn(`failed to fetch scopes for ${appId}: ${err instanceof Error ? err.message : err}`);
|
|
111
|
+
// 其他查询失败不阻塞调用,返回空数组(后续 API 调用如果缺 scope 会被服务端拒绝)
|
|
112
|
+
return [];
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
// App info
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
/**
|
|
119
|
+
* 获取应用信息,包括 owner 信息。
|
|
120
|
+
*
|
|
121
|
+
* 复用 getAppGrantedScopes 的 API 调用和缓存。
|
|
122
|
+
* 如果缓存中已有数据且未过期,直接从缓存提取。
|
|
123
|
+
*
|
|
124
|
+
* @param sdk - Lark SDK 实例
|
|
125
|
+
* @param appId - 应用 ID(可传 "me")
|
|
126
|
+
*/
|
|
127
|
+
async function getAppInfo(sdk, appId) {
|
|
128
|
+
// 先确保缓存已填充(调一次 getAppGrantedScopes 来触发 API + 缓存)
|
|
129
|
+
await getAppGrantedScopes(sdk, appId);
|
|
130
|
+
const cached = cache.get(appId);
|
|
131
|
+
const rawApp = cached?.rawApp;
|
|
132
|
+
// 提取 owner 信息
|
|
133
|
+
const owner = rawApp?.owner;
|
|
134
|
+
const creatorId = rawApp?.creator_id;
|
|
135
|
+
// 统一 owner 定义:type=2(企业内成员)用 owner_id,否则回退 creator_id
|
|
136
|
+
// 兼容两种字段名(owner_type 和 type)
|
|
137
|
+
const ownerTypeValue = owner?.owner_type ?? owner?.type;
|
|
138
|
+
const effectiveOwnerOpenId = ownerTypeValue === 2 && owner?.owner_id ? owner.owner_id : (creatorId ?? owner?.owner_id);
|
|
139
|
+
return {
|
|
140
|
+
appId,
|
|
141
|
+
creatorId,
|
|
142
|
+
ownerOpenId: owner?.owner_id,
|
|
143
|
+
ownerType: owner?.owner_type,
|
|
144
|
+
effectiveOwnerOpenId,
|
|
145
|
+
scopes: cached?.rawScopes ?? [],
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
// Scope intersection
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
/**
|
|
152
|
+
* 计算 APP 已有 ∩ OAPI 需要 的交集。
|
|
153
|
+
*
|
|
154
|
+
* 用于传给 OAuth 的 scope 参数 — 只请求 APP 已开通且 API 需要的 scope。
|
|
155
|
+
*
|
|
156
|
+
* @param appGranted - 应用已开通的 scope 列表
|
|
157
|
+
* @param apiRequired - OAPI 要求的 scope 列表
|
|
158
|
+
* @returns 交集 scope 列表
|
|
159
|
+
*/
|
|
160
|
+
function intersectScopes(appGranted, apiRequired) {
|
|
161
|
+
const grantedSet = new Set(appGranted);
|
|
162
|
+
return apiRequired.filter((s) => grantedSet.has(s));
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* 计算 OAPI 需要但 APP 未开通的 scope(差集)。
|
|
166
|
+
*
|
|
167
|
+
* 用于 AppScopeMissingError 的 missingScopes。
|
|
168
|
+
*
|
|
169
|
+
* @param appGranted - 应用已开通的 scope 列表
|
|
170
|
+
* @param apiRequired - OAPI 要求的 scope 列表
|
|
171
|
+
* @returns 缺失的 scope 列表
|
|
172
|
+
*/
|
|
173
|
+
function missingScopes(appGranted, apiRequired) {
|
|
174
|
+
const grantedSet = new Set(appGranted);
|
|
175
|
+
return apiRequired.filter((s) => !grantedSet.has(s));
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* 校验应用已开通的 scope 是否满足要求。
|
|
179
|
+
*
|
|
180
|
+
* 与 tool-client.ts invoke() 的 scope 校验逻辑完全一致,作为唯一真值来源:
|
|
181
|
+
* - `scopeNeedType === "all"`: appScopes 必须包含 requiredScopes 的全部项
|
|
182
|
+
* - 其他(默认 "one"): appScopes 与 requiredScopes 的交集非空即可
|
|
183
|
+
* - appScopes 为空: 视为满足(API 查询失败,退回服务端判断)
|
|
184
|
+
*
|
|
185
|
+
* @param appScopes - 应用已开通的 scope 列表(由 getAppGrantedScopes 返回)
|
|
186
|
+
* @param requiredScopes - 需要的 scope 列表
|
|
187
|
+
* @param scopeNeedType - "all" 表示全部必须,undefined/"one" 表示任一即可
|
|
188
|
+
*/
|
|
189
|
+
function isAppScopeSatisfied(appScopes, requiredScopes, scopeNeedType) {
|
|
190
|
+
if (appScopes.length === 0)
|
|
191
|
+
return true; // API 查询失败 → 退回服务端判断
|
|
192
|
+
if (requiredScopes.length === 0)
|
|
193
|
+
return true;
|
|
194
|
+
if (scopeNeedType === 'all') {
|
|
195
|
+
return missingScopes(appScopes, requiredScopes).length === 0;
|
|
196
|
+
}
|
|
197
|
+
return intersectScopes(appScopes, requiredScopes).length > 0;
|
|
198
|
+
}
|