@zhin.js/core 1.1.34 → 1.1.35
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/README.md +121 -65
- package/lib/adapter.d.ts +72 -23
- package/lib/adapter.js +222 -62
- package/lib/built/adapter-process.d.ts +20 -5
- package/lib/built/adapter-process.js +54 -7
- package/lib/built/agent-preset.d.ts +1 -2
- package/lib/built/agent-preset.js +1 -2
- package/lib/built/ai-access.d.ts +36 -0
- package/lib/built/ai-access.js +46 -0
- package/lib/built/ai-outbound/adapter-access.d.ts +3 -0
- package/lib/built/ai-outbound/adapter-access.js +9 -0
- package/lib/built/ai-outbound/extensions/onebot-keyboard.d.ts +2 -0
- package/lib/built/ai-outbound/extensions/onebot-keyboard.js +67 -0
- package/lib/built/ai-outbound/extensions/qq-message.d.ts +3 -0
- package/lib/built/ai-outbound/extensions/qq-message.js +23 -0
- package/lib/built/ai-outbound/index.d.ts +9 -0
- package/lib/built/ai-outbound/index.js +9 -0
- package/lib/built/ai-outbound/parse.d.ts +13 -0
- package/lib/built/ai-outbound/parse.js +104 -0
- package/lib/built/ai-outbound/plain-mention-rewrite.d.ts +6 -0
- package/lib/built/ai-outbound/plain-mention-rewrite.js +37 -0
- package/lib/built/ai-outbound/prompt.d.ts +11 -0
- package/lib/built/ai-outbound/prompt.js +44 -0
- package/lib/built/ai-outbound/resolve.d.ts +4 -0
- package/lib/built/ai-outbound/resolve.js +64 -0
- package/lib/built/ai-outbound/structured-detect.d.ts +3 -0
- package/lib/built/ai-outbound/structured-detect.js +6 -0
- package/lib/built/ai-outbound/types.d.ts +58 -0
- package/lib/built/ai-outbound/types.js +5 -0
- package/lib/built/ai-trigger.d.ts +17 -17
- package/lib/built/ai-trigger.js +65 -70
- package/lib/built/authorization.d.ts +10 -0
- package/lib/built/authorization.js +76 -0
- package/lib/built/command.d.ts +9 -5
- package/lib/built/command.js +20 -7
- package/lib/built/common-adapter-tools.d.ts +35 -29
- package/lib/built/common-adapter-tools.js +83 -67
- package/lib/built/component.d.ts +1 -3
- package/lib/built/component.js +2 -4
- package/lib/built/config.d.ts +4 -5
- package/lib/built/config.js +26 -9
- package/lib/built/connect-endpoint-instance.d.ts +17 -0
- package/lib/built/connect-endpoint-instance.js +42 -0
- package/lib/built/database.d.ts +5 -3
- package/lib/built/database.js +10 -4
- package/lib/built/dispatcher.d.ts +10 -8
- package/lib/built/dispatcher.js +31 -9
- package/lib/built/endpoint-commands.d.ts +3 -0
- package/lib/built/endpoint-commands.js +99 -0
- package/lib/built/endpoint-lifecycle-service.d.ts +28 -0
- package/lib/built/endpoint-lifecycle-service.js +242 -0
- package/lib/built/endpoint-lifecycle.d.ts +27 -0
- package/lib/built/endpoint-lifecycle.js +36 -0
- package/lib/built/endpoint-manager.d.ts +34 -0
- package/lib/built/endpoint-manager.js +1 -0
- package/lib/built/generated-qrcode.d.ts +24 -0
- package/lib/built/generated-qrcode.js +45 -0
- package/lib/built/generic-segment-mapper.d.ts +4 -0
- package/lib/built/generic-segment-mapper.js +190 -0
- package/lib/built/html-renderer-loader.d.ts +13 -0
- package/lib/built/html-renderer-loader.js +33 -0
- package/lib/built/html-segment-fallback.d.ts +2 -2
- package/lib/built/html-segment-fallback.js +0 -1
- package/lib/built/html-to-text.d.ts +0 -1
- package/lib/built/html-to-text.js +15 -15
- package/lib/built/inbound-pipeline.d.ts +37 -0
- package/lib/built/inbound-pipeline.js +63 -0
- package/lib/built/inbound-runner.d.ts +0 -1
- package/lib/built/inbound-runner.js +0 -3
- package/lib/built/interactive-segment-contract.d.ts +6 -0
- package/lib/built/interactive-segment-contract.js +9 -0
- package/lib/built/interactive-segments/action.d.ts +17 -0
- package/lib/built/interactive-segments/action.js +69 -0
- package/lib/built/interactive-segments/button-spec.d.ts +10 -0
- package/lib/built/interactive-segments/button-spec.js +21 -0
- package/lib/built/interactive-segments/fallback-store.d.ts +29 -0
- package/lib/built/interactive-segments/fallback-store.js +63 -0
- package/lib/built/interactive-segments/handlers.d.ts +16 -0
- package/lib/built/interactive-segments/handlers.js +74 -0
- package/lib/built/interactive-segments/index.d.ts +8 -0
- package/lib/built/interactive-segments/index.js +8 -0
- package/lib/built/interactive-segments/keyboard-segment.d.ts +11 -0
- package/lib/built/interactive-segments/keyboard-segment.js +12 -0
- package/lib/built/interactive-segments/onebot-keyboard.d.ts +7 -0
- package/lib/built/interactive-segments/onebot-keyboard.js +51 -0
- package/lib/built/interactive-segments/resolve.d.ts +15 -0
- package/lib/built/interactive-segments/resolve.js +110 -0
- package/lib/built/interactive-segments/types.d.ts +50 -0
- package/lib/built/interactive-segments/types.js +9 -0
- package/lib/built/introspection-format.d.ts +10 -0
- package/lib/built/introspection-format.js +28 -0
- package/lib/built/login-assist.d.ts +43 -9
- package/lib/built/login-assist.js +113 -11
- package/lib/built/management-command-guard.d.ts +15 -0
- package/lib/built/management-command-guard.js +25 -0
- package/lib/built/message-enrich.d.ts +38 -0
- package/lib/built/message-enrich.js +75 -0
- package/lib/built/message-filter.d.ts +4 -5
- package/lib/built/message-filter.js +5 -7
- package/lib/built/optional-peer-import.d.ts +3 -0
- package/lib/built/optional-peer-import.js +33 -0
- package/lib/built/outbound-media-contract.d.ts +22 -0
- package/lib/built/outbound-media-contract.js +10 -0
- package/lib/built/outbound-media-utils.d.ts +9 -0
- package/lib/built/outbound-media-utils.js +62 -0
- package/lib/built/permission.d.ts +3 -7
- package/lib/built/permission.js +39 -52
- package/lib/built/permit-check.d.ts +7 -0
- package/lib/built/permit-check.js +35 -0
- package/lib/built/permit-parse.d.ts +16 -0
- package/lib/built/permit-parse.js +32 -0
- package/lib/built/platform-permit.d.ts +20 -0
- package/lib/built/platform-permit.js +91 -0
- package/lib/built/queue-im-field-contract.d.ts +7 -2
- package/lib/built/queue-im-field-contract.js +13 -4
- package/lib/built/rich-segments/adapter-policies.d.ts +9 -0
- package/lib/built/rich-segments/adapter-policies.js +27 -0
- package/lib/built/rich-segments/base.d.ts +11 -0
- package/lib/built/rich-segments/base.js +24 -0
- package/lib/built/rich-segments/builtins.d.ts +4 -0
- package/lib/built/rich-segments/builtins.js +40 -0
- package/lib/built/rich-segments/capabilities.d.ts +6 -0
- package/lib/built/rich-segments/capabilities.js +38 -0
- package/lib/built/rich-segments/html-segment.d.ts +15 -0
- package/lib/built/rich-segments/html-segment.js +62 -0
- package/lib/built/rich-segments/index.d.ts +13 -0
- package/lib/built/rich-segments/index.js +13 -0
- package/lib/built/rich-segments/markdown-segment.d.ts +14 -0
- package/lib/built/rich-segments/markdown-segment.js +58 -0
- package/lib/built/rich-segments/markdown-to-text.d.ts +3 -0
- package/lib/built/rich-segments/markdown-to-text.js +27 -0
- package/lib/built/rich-segments/qrcode-segment.d.ts +18 -0
- package/lib/built/rich-segments/qrcode-segment.js +73 -0
- package/lib/built/rich-segments/registry.d.ts +16 -0
- package/lib/built/rich-segments/registry.js +52 -0
- package/lib/built/rich-segments/resolve.d.ts +5 -0
- package/lib/built/rich-segments/resolve.js +87 -0
- package/lib/built/rich-segments/tts-segment.d.ts +13 -0
- package/lib/built/rich-segments/tts-segment.js +51 -0
- package/lib/built/rich-segments/types.d.ts +79 -0
- package/lib/built/rich-segments/types.js +17 -0
- package/lib/built/roles.d.ts +4 -5
- package/lib/built/roles.js +4 -5
- package/lib/built/runtime-io.d.ts +0 -1
- package/lib/built/runtime-io.js +0 -1
- package/lib/built/schedule.d.ts +54 -0
- package/lib/built/schedule.js +112 -0
- package/lib/built/schema-endpoint-manager.d.ts +17 -0
- package/lib/built/schema-endpoint-manager.js +73 -0
- package/lib/built/schema-feature.d.ts +0 -1
- package/lib/built/schema-feature.js +1 -3
- package/lib/built/segment-contract/assert.d.ts +7 -0
- package/lib/built/segment-contract/assert.js +39 -0
- package/lib/built/segment-contract/delivery.d.ts +5 -0
- package/lib/built/segment-contract/delivery.js +40 -0
- package/lib/built/segment-contract/image.d.ts +5 -0
- package/lib/built/segment-contract/image.js +10 -0
- package/lib/built/segment-contract/index.d.ts +10 -0
- package/lib/built/segment-contract/index.js +9 -0
- package/lib/built/segment-contract/json-schema.d.ts +28 -0
- package/lib/built/segment-contract/json-schema.js +128 -0
- package/lib/built/segment-contract/media.d.ts +12 -0
- package/lib/built/segment-contract/media.js +22 -0
- package/lib/built/segment-contract/mention.d.ts +10 -0
- package/lib/built/segment-contract/mention.js +26 -0
- package/lib/built/segment-contract/preview.d.ts +3 -0
- package/lib/built/segment-contract/preview.js +159 -0
- package/lib/built/segment-contract/text.d.ts +7 -0
- package/lib/built/segment-contract/text.js +34 -0
- package/lib/built/segment-contract/types.d.ts +58 -0
- package/lib/built/segment-contract/types.js +1 -0
- package/lib/built/segment-contract/validate.d.ts +229 -0
- package/lib/built/segment-contract/validate.js +174 -0
- package/lib/built/skill.d.ts +0 -1
- package/lib/built/skill.js +0 -1
- package/lib/built/speech-loader.d.ts +14 -0
- package/lib/built/speech-loader.js +32 -0
- package/lib/built/tool.d.ts +14 -13
- package/lib/built/tool.js +30 -25
- package/lib/built/user-interaction.d.ts +30 -0
- package/lib/built/user-interaction.js +248 -0
- package/lib/command.d.ts +19 -11
- package/lib/command.js +42 -11
- package/lib/component.d.ts +0 -1
- package/lib/component.js +30 -14
- package/lib/endpoint-capabilities.d.ts +46 -0
- package/lib/endpoint-capabilities.js +55 -0
- package/lib/endpoint.d.ts +19 -0
- package/lib/endpoint.js +3 -0
- package/lib/errors.d.ts +2 -3
- package/lib/errors.js +4 -5
- package/lib/feature/adapter.d.ts +2 -0
- package/lib/feature/adapter.js +2 -0
- package/lib/feature/command.d.ts +2 -0
- package/lib/feature/command.js +2 -0
- package/lib/feature/component.d.ts +2 -0
- package/lib/feature/component.js +2 -0
- package/lib/feature/handler.d.ts +52 -0
- package/lib/feature/handler.js +26 -0
- package/lib/feature/middleware.d.ts +2 -0
- package/lib/feature/middleware.js +2 -0
- package/lib/host-plugin-registry.d.ts +8 -0
- package/lib/host-plugin-registry.js +12 -0
- package/lib/im-scene.d.ts +29 -0
- package/lib/im-scene.js +75 -0
- package/lib/im-session-id.d.ts +39 -0
- package/lib/im-session-id.js +47 -0
- package/lib/index.d.ts +59 -25
- package/lib/index.js +53 -31
- package/lib/jsx-dev-runtime.d.ts +0 -1
- package/lib/jsx-dev-runtime.js +0 -1
- package/lib/jsx-runtime.d.ts +1 -1
- package/lib/jsx-runtime.js +0 -1
- package/lib/jsx.d.ts +19 -22
- package/lib/jsx.js +0 -1
- package/lib/message.d.ts +16 -10
- package/lib/message.js +16 -13
- package/lib/models/system-log.d.ts +0 -1
- package/lib/models/system-log.js +0 -1
- package/lib/models/user.d.ts +0 -1
- package/lib/models/user.js +0 -1
- package/lib/notice.d.ts +16 -59
- package/lib/notice.js +1 -4
- package/lib/plugin-context.d.ts +27 -0
- package/lib/plugin-context.js +64 -0
- package/lib/plugin-runtime/im/contracts.d.ts +191 -0
- package/lib/plugin-runtime/im/contracts.js +169 -0
- package/lib/plugin-runtime/im/im-runtime.d.ts +177 -0
- package/lib/plugin-runtime/im/im-runtime.js +1204 -0
- package/lib/plugin-runtime/im/index.d.ts +9 -0
- package/lib/plugin-runtime/im/index.js +9 -0
- package/lib/plugin-runtime/im/interactive.d.ts +26 -0
- package/lib/plugin-runtime/im/interactive.js +46 -0
- package/lib/plugin-runtime/im/login-assist-host.d.ts +6 -0
- package/lib/plugin-runtime/im/login-assist-host.js +6 -0
- package/lib/plugin-runtime/im/message-bus.d.ts +38 -0
- package/lib/plugin-runtime/im/message-bus.js +40 -0
- package/lib/plugin-runtime/im/message-dispatcher.d.ts +18 -0
- package/lib/plugin-runtime/im/message-dispatcher.js +107 -0
- package/lib/plugin-runtime/im/outbound-renderer.d.ts +7 -0
- package/lib/plugin-runtime/im/outbound-renderer.js +70 -0
- package/lib/plugin-runtime/im/outbound-segments.d.ts +72 -0
- package/lib/plugin-runtime/im/outbound-segments.js +220 -0
- package/lib/plugin-runtime/im/public-api.d.ts +6 -0
- package/lib/plugin-runtime/im/public-api.js +6 -0
- package/lib/plugin-runtime/im/service-tokens.d.ts +18 -0
- package/lib/plugin-runtime/im/service-tokens.js +13 -0
- package/lib/plugin.d.ts +34 -24
- package/lib/plugin.js +119 -224
- package/lib/request.d.ts +17 -61
- package/lib/request.js +0 -4
- package/lib/{prompt.d.ts → schema-interaction.d.ts} +6 -7
- package/lib/{prompt.js → schema-interaction.js} +20 -17
- package/lib/side-event/base.d.ts +52 -0
- package/lib/side-event/base.js +30 -0
- package/lib/side-event/dispatch.d.ts +15 -0
- package/lib/side-event/dispatch.js +140 -0
- package/lib/side-event/index.d.ts +4 -0
- package/lib/side-event/index.js +4 -0
- package/lib/side-event/normalize.d.ts +42 -0
- package/lib/side-event/normalize.js +121 -0
- package/lib/side-event/types.d.ts +23 -0
- package/lib/side-event/types.js +55 -0
- package/lib/system-event.d.ts +15 -0
- package/lib/system-event.js +7 -0
- package/lib/tool-zod.d.ts +18 -3
- package/lib/tool-zod.js +140 -54
- package/lib/types.d.ts +44 -95
- package/lib/types.js +0 -1
- package/lib/utils.d.ts +61 -13
- package/lib/utils.js +66 -25
- package/package.json +98 -10
- package/lib/adapter.d.ts.map +0 -1
- package/lib/adapter.js.map +0 -1
- package/lib/agent-prompt.d.ts +0 -37
- package/lib/agent-prompt.d.ts.map +0 -1
- package/lib/agent-prompt.js +0 -2
- package/lib/agent-prompt.js.map +0 -1
- package/lib/bot.d.ts +0 -38
- package/lib/bot.d.ts.map +0 -1
- package/lib/bot.js +0 -2
- package/lib/bot.js.map +0 -1
- package/lib/built/adapter-process.d.ts.map +0 -1
- package/lib/built/adapter-process.js.map +0 -1
- package/lib/built/agent-preset.d.ts.map +0 -1
- package/lib/built/agent-preset.js.map +0 -1
- package/lib/built/ai-trigger.d.ts.map +0 -1
- package/lib/built/ai-trigger.js.map +0 -1
- package/lib/built/command.d.ts.map +0 -1
- package/lib/built/command.js.map +0 -1
- package/lib/built/common-adapter-tools.d.ts.map +0 -1
- package/lib/built/common-adapter-tools.js.map +0 -1
- package/lib/built/component.d.ts.map +0 -1
- package/lib/built/component.js.map +0 -1
- package/lib/built/config.d.ts.map +0 -1
- package/lib/built/config.js.map +0 -1
- package/lib/built/cron.d.ts +0 -75
- package/lib/built/cron.d.ts.map +0 -1
- package/lib/built/cron.js +0 -122
- package/lib/built/cron.js.map +0 -1
- package/lib/built/database.d.ts.map +0 -1
- package/lib/built/database.js.map +0 -1
- package/lib/built/dispatcher.d.ts.map +0 -1
- package/lib/built/dispatcher.js.map +0 -1
- package/lib/built/html-segment-fallback.d.ts.map +0 -1
- package/lib/built/html-segment-fallback.js.map +0 -1
- package/lib/built/html-to-text.d.ts.map +0 -1
- package/lib/built/html-to-text.js.map +0 -1
- package/lib/built/inbound-runner.d.ts.map +0 -1
- package/lib/built/inbound-runner.js.map +0 -1
- package/lib/built/login-assist.d.ts.map +0 -1
- package/lib/built/login-assist.js.map +0 -1
- package/lib/built/mcp-mesh-registrar.d.ts +0 -9
- package/lib/built/mcp-mesh-registrar.d.ts.map +0 -1
- package/lib/built/mcp-mesh-registrar.js +0 -17
- package/lib/built/mcp-mesh-registrar.js.map +0 -1
- package/lib/built/message-filter.d.ts.map +0 -1
- package/lib/built/message-filter.js.map +0 -1
- package/lib/built/permission.d.ts.map +0 -1
- package/lib/built/permission.js.map +0 -1
- package/lib/built/prepend-quote-context.d.ts +0 -35
- package/lib/built/prepend-quote-context.d.ts.map +0 -1
- package/lib/built/prepend-quote-context.js +0 -131
- package/lib/built/prepend-quote-context.js.map +0 -1
- package/lib/built/queue-im-field-contract.d.ts.map +0 -1
- package/lib/built/queue-im-field-contract.js.map +0 -1
- package/lib/built/roles.d.ts.map +0 -1
- package/lib/built/roles.js.map +0 -1
- package/lib/built/runtime-io.d.ts.map +0 -1
- package/lib/built/runtime-io.js.map +0 -1
- package/lib/built/schema-feature.d.ts.map +0 -1
- package/lib/built/schema-feature.js.map +0 -1
- package/lib/built/skill.d.ts.map +0 -1
- package/lib/built/skill.js.map +0 -1
- package/lib/built/tool.d.ts.map +0 -1
- package/lib/built/tool.js.map +0 -1
- package/lib/command.d.ts.map +0 -1
- package/lib/command.js.map +0 -1
- package/lib/component.d.ts.map +0 -1
- package/lib/component.js.map +0 -1
- package/lib/errors.d.ts.map +0 -1
- package/lib/errors.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/jsx-dev-runtime.d.ts.map +0 -1
- package/lib/jsx-dev-runtime.js.map +0 -1
- package/lib/jsx-runtime.d.ts.map +0 -1
- package/lib/jsx-runtime.js.map +0 -1
- package/lib/jsx.d.ts.map +0 -1
- package/lib/jsx.js.map +0 -1
- package/lib/message-quote.d.ts +0 -11
- package/lib/message-quote.d.ts.map +0 -1
- package/lib/message-quote.js +0 -91
- package/lib/message-quote.js.map +0 -1
- package/lib/message.d.ts.map +0 -1
- package/lib/message.js.map +0 -1
- package/lib/models/system-log.d.ts.map +0 -1
- package/lib/models/system-log.js.map +0 -1
- package/lib/models/user.d.ts.map +0 -1
- package/lib/models/user.js.map +0 -1
- package/lib/notice.d.ts.map +0 -1
- package/lib/notice.js.map +0 -1
- package/lib/plugin.d.ts.map +0 -1
- package/lib/plugin.js.map +0 -1
- package/lib/prompt.d.ts.map +0 -1
- package/lib/prompt.js.map +0 -1
- package/lib/request.d.ts.map +0 -1
- package/lib/request.js.map +0 -1
- package/lib/scheduler/scheduler.d.ts +0 -49
- package/lib/scheduler/scheduler.d.ts.map +0 -1
- package/lib/scheduler/scheduler.js +0 -352
- package/lib/scheduler/scheduler.js.map +0 -1
- package/lib/scheduler/types.d.ts +0 -71
- package/lib/scheduler/types.d.ts.map +0 -1
- package/lib/scheduler/types.js +0 -8
- package/lib/scheduler/types.js.map +0 -1
- package/lib/tool-zod.d.ts.map +0 -1
- package/lib/tool-zod.js.map +0 -1
- package/lib/types-generator.d.ts +0 -6
- package/lib/types-generator.d.ts.map +0 -1
- package/lib/types-generator.js +0 -72
- package/lib/types-generator.js.map +0 -1
- package/lib/types.d.ts.map +0 -1
- package/lib/types.js.map +0 -1
- package/lib/utils.d.ts.map +0 -1
- package/lib/utils.js.map +0 -1
package/lib/built/permission.js
CHANGED
|
@@ -3,67 +3,59 @@
|
|
|
3
3
|
* 权限管理服务,继承自 Feature 抽象类
|
|
4
4
|
*/
|
|
5
5
|
import { Feature } from "@zhin.js/kernel";
|
|
6
|
-
import {
|
|
6
|
+
import logger, { formatCompact } from "@zhin.js/logger";
|
|
7
|
+
import { isBuiltinPermit, parsePermitName } from "./permit-parse.js";
|
|
8
|
+
import { checkBuiltinPermit } from "./permit-check.js";
|
|
9
|
+
import { senderRolesFromMessage } from "./message-enrich.js";
|
|
10
|
+
function rolesForPermitCheck(message) {
|
|
11
|
+
return senderRolesFromMessage(message);
|
|
12
|
+
}
|
|
13
|
+
function auditPermitDenied(permit, message, reason) {
|
|
14
|
+
logger.debug(formatCompact({
|
|
15
|
+
op: 'permit_denied',
|
|
16
|
+
permit,
|
|
17
|
+
reason,
|
|
18
|
+
senderId: message.$sender.id,
|
|
19
|
+
adapter: message.$adapter,
|
|
20
|
+
endpoint: message.$endpoint,
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
7
23
|
export class PermissionFeature extends Feature {
|
|
8
24
|
name = 'permission';
|
|
9
25
|
icon = 'Shield';
|
|
10
26
|
desc = '权限';
|
|
11
27
|
constructor() {
|
|
12
28
|
super();
|
|
13
|
-
|
|
14
|
-
this.add(Permissions.define(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return false;
|
|
21
|
-
const id = match[1];
|
|
22
|
-
if (message.$channel.type !== 'group')
|
|
23
|
-
return false;
|
|
24
|
-
if (id === '' || id === '*')
|
|
25
|
-
return true;
|
|
26
|
-
return message.$channel.id === id;
|
|
27
|
-
}), '__built-in__');
|
|
28
|
-
this.add(Permissions.define(/^private\([^)]+\)$/, (name, message) => {
|
|
29
|
-
const match = name.match(/^private\(([^)]+)\)$/);
|
|
30
|
-
if (!match)
|
|
31
|
-
return false;
|
|
32
|
-
const id = match[1];
|
|
33
|
-
if (message.$channel.type !== 'private')
|
|
34
|
-
return false;
|
|
35
|
-
if (id === '' || id === '*')
|
|
36
|
-
return true;
|
|
37
|
-
return message.$channel.id === id;
|
|
38
|
-
}), '__built-in__');
|
|
39
|
-
this.add(Permissions.define(/^channel\([^)]+\)$/, (name, message) => {
|
|
40
|
-
const match = name.match(/^channel\(([^)]+)\)$/);
|
|
41
|
-
if (!match)
|
|
42
|
-
return false;
|
|
43
|
-
const id = match[1];
|
|
44
|
-
if (message.$channel.type !== 'channel')
|
|
45
|
-
return false;
|
|
46
|
-
if (id === '' || id === '*')
|
|
47
|
-
return true;
|
|
48
|
-
return message.$channel.id === id;
|
|
49
|
-
}), '__built-in__');
|
|
50
|
-
this.add(Permissions.define(/^user\([^)]+\)$/, (name, message) => {
|
|
51
|
-
const match = name.match(/^user\(([^)]+)\)$/);
|
|
52
|
-
if (!match)
|
|
53
|
-
return false;
|
|
54
|
-
const id = match[1];
|
|
55
|
-
return message.$sender.id === id;
|
|
29
|
+
const builtinRe = /^(adapter|group|private|channel|user|role)\([^)]*\)$/;
|
|
30
|
+
this.add(Permissions.define(builtinRe, (name, message) => {
|
|
31
|
+
const parsed = parsePermitName(name);
|
|
32
|
+
if (parsed && parsed.kind !== 'role') {
|
|
33
|
+
return checkBuiltinPermit(name, message, ['user']);
|
|
34
|
+
}
|
|
35
|
+
return checkBuiltinPermit(name, message, rolesForPermitCheck(message));
|
|
56
36
|
}), '__built-in__');
|
|
57
37
|
}
|
|
58
38
|
/**
|
|
59
|
-
*
|
|
39
|
+
* 检查权限(subject 为 Message 通讯上下文)
|
|
60
40
|
*/
|
|
61
|
-
async check(name,
|
|
41
|
+
async check(name, subject) {
|
|
42
|
+
const message = subject;
|
|
43
|
+
if (isBuiltinPermit(name)) {
|
|
44
|
+
const parsed = parsePermitName(name);
|
|
45
|
+
if (parsed && parsed.kind !== 'role') {
|
|
46
|
+
if (checkBuiltinPermit(name, message, ['user']))
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
else if (checkBuiltinPermit(name, message, rolesForPermitCheck(message))) {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
62
53
|
for (const permission of this.items) {
|
|
63
54
|
const passed = await permission.check(name, message);
|
|
64
55
|
if (passed)
|
|
65
56
|
return true;
|
|
66
57
|
}
|
|
58
|
+
auditPermitDenied(name, message);
|
|
67
59
|
return false;
|
|
68
60
|
}
|
|
69
61
|
/**
|
|
@@ -88,7 +80,7 @@ export class PermissionFeature extends Feature {
|
|
|
88
80
|
const feature = this;
|
|
89
81
|
return {
|
|
90
82
|
addPermission(permission) {
|
|
91
|
-
const plugin =
|
|
83
|
+
const plugin = this;
|
|
92
84
|
const dispose = feature.add(permission, plugin.name);
|
|
93
85
|
const permName = permission.name instanceof RegExp ? permission.name.source : permission.name;
|
|
94
86
|
plugin.recordFeatureContribution(feature.name, permName);
|
|
@@ -105,8 +97,3 @@ export var Permissions;
|
|
|
105
97
|
}
|
|
106
98
|
Permissions.define = define;
|
|
107
99
|
})(Permissions || (Permissions = {}));
|
|
108
|
-
/**
|
|
109
|
-
* @deprecated Use PermissionFeature instead
|
|
110
|
-
*/
|
|
111
|
-
export const PermissionService = PermissionFeature;
|
|
112
|
-
//# sourceMappingURL=permission.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 内置 permit 同步校验(adapter/group/private/channel/user/role)
|
|
3
|
+
*/
|
|
4
|
+
import type { Message } from '../message.js';
|
|
5
|
+
import { type SenderRole } from './roles.js';
|
|
6
|
+
export declare function checkBuiltinPermit(name: string, message: Message<any>, roles: readonly SenderRole[]): boolean;
|
|
7
|
+
export declare function checkBuiltinPermitList(permits: readonly string[], message: Message<any>, roles: readonly SenderRole[]): boolean;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { isFrameworkSenderRole, roleSatisfies } from './roles.js';
|
|
2
|
+
import { parsePermitName } from './permit-parse.js';
|
|
3
|
+
function channelIdMatches(id, channelId) {
|
|
4
|
+
return id === '' || id === '*' || channelId === id;
|
|
5
|
+
}
|
|
6
|
+
export function checkBuiltinPermit(name, message, roles) {
|
|
7
|
+
const parsed = parsePermitName(name);
|
|
8
|
+
if (!parsed)
|
|
9
|
+
return false;
|
|
10
|
+
switch (parsed.kind) {
|
|
11
|
+
case 'adapter':
|
|
12
|
+
return parsed.values.some((v) => message.$adapter === v);
|
|
13
|
+
case 'group':
|
|
14
|
+
if (message.$channel?.type !== 'group')
|
|
15
|
+
return false;
|
|
16
|
+
return parsed.values.some((id) => channelIdMatches(id, String(message.$channel.id)));
|
|
17
|
+
case 'private':
|
|
18
|
+
if (message.$channel?.type !== 'private')
|
|
19
|
+
return false;
|
|
20
|
+
return parsed.values.some((id) => channelIdMatches(id, String(message.$channel.id)));
|
|
21
|
+
case 'channel':
|
|
22
|
+
if (message.$channel?.type !== 'channel')
|
|
23
|
+
return false;
|
|
24
|
+
return parsed.values.some((id) => channelIdMatches(id, String(message.$channel.id)));
|
|
25
|
+
case 'user':
|
|
26
|
+
return parsed.values.some((id) => String(message.$sender.id) === id);
|
|
27
|
+
case 'role':
|
|
28
|
+
return parsed.values.some((req) => isFrameworkSenderRole(req) && roleSatisfies(roles, [req]));
|
|
29
|
+
default:
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function checkBuiltinPermitList(permits, message, roles) {
|
|
34
|
+
return permits.every((p) => checkBuiltinPermit(p, message, roles));
|
|
35
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permit 语法解析:type(a,b,c) 括号内逗号为 OR;链式 .permit().permit() 为 AND(由调用方保证)。
|
|
3
|
+
*/
|
|
4
|
+
export type PermitKind = 'adapter' | 'group' | 'private' | 'channel' | 'user' | 'role';
|
|
5
|
+
export interface ParsedPermit {
|
|
6
|
+
kind: PermitKind;
|
|
7
|
+
values: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare function parsePermitName(name: string): ParsedPermit | null;
|
|
10
|
+
export declare function isBuiltinPermit(name: string): boolean;
|
|
11
|
+
export interface ParsedPlatformPermit {
|
|
12
|
+
adapter: string;
|
|
13
|
+
perm: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function parsePlatformPermitName(name: string): ParsedPlatformPermit | null;
|
|
16
|
+
export declare function isPlatformPermit(name: string): boolean;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permit 语法解析:type(a,b,c) 括号内逗号为 OR;链式 .permit().permit() 为 AND(由调用方保证)。
|
|
3
|
+
*/
|
|
4
|
+
const PERMIT_RE = /^(adapter|group|private|channel|user|role)\(([^)]*)\)$/;
|
|
5
|
+
export function parsePermitName(name) {
|
|
6
|
+
const m = name.match(PERMIT_RE);
|
|
7
|
+
if (!m)
|
|
8
|
+
return null;
|
|
9
|
+
const kind = m[1];
|
|
10
|
+
const inner = m[2].trim();
|
|
11
|
+
if (!inner)
|
|
12
|
+
return { kind, values: [''] };
|
|
13
|
+
const values = inner.split(',').map((v) => v.trim()).filter((v) => v.length > 0);
|
|
14
|
+
return { kind, values: values.length > 0 ? values : [''] };
|
|
15
|
+
}
|
|
16
|
+
export function isBuiltinPermit(name) {
|
|
17
|
+
return PERMIT_RE.test(name);
|
|
18
|
+
}
|
|
19
|
+
const PLATFORM_PERMIT_RE = /^platform\(([^,)]+),([^)]*)\)$/;
|
|
20
|
+
export function parsePlatformPermitName(name) {
|
|
21
|
+
const m = name.match(PLATFORM_PERMIT_RE);
|
|
22
|
+
if (!m)
|
|
23
|
+
return null;
|
|
24
|
+
const adapter = m[1].trim();
|
|
25
|
+
const perm = m[2].trim();
|
|
26
|
+
if (!adapter || !perm)
|
|
27
|
+
return null;
|
|
28
|
+
return { adapter, perm };
|
|
29
|
+
}
|
|
30
|
+
export function isPlatformPermit(name) {
|
|
31
|
+
return PLATFORM_PERMIT_RE.test(name);
|
|
32
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform permit — 适配器注册的平台级权限校验(场景治理、频道身份等)
|
|
3
|
+
*/
|
|
4
|
+
import type { Message } from '../message.js';
|
|
5
|
+
export type PlatformPermitChecker = (perm: string, message: Message<any>) => boolean;
|
|
6
|
+
export declare function registerPlatformPermitChecker(adapter: string, checker: PlatformPermitChecker): () => void;
|
|
7
|
+
export declare function clearPlatformPermitCheckers(): void;
|
|
8
|
+
export declare function checkPlatformPermit(name: string, message: Message<any>): boolean;
|
|
9
|
+
export declare function checkPlatformPermitList(permits: readonly string[], message: Message<any>): boolean;
|
|
10
|
+
/** OneBot / QQ 系 sender.role 归一化 */
|
|
11
|
+
export declare function normalizeQqSenderRole(role?: string): 'owner' | 'admin' | undefined;
|
|
12
|
+
/** 从 OneBot sender 对象写入 MessageSender.role / permissions */
|
|
13
|
+
export declare function applyQqSenderRoleToMessageSender(sender: {
|
|
14
|
+
role?: string;
|
|
15
|
+
permissions?: string[];
|
|
16
|
+
}, role?: string): void;
|
|
17
|
+
/** 常见 IM 平台场景身份:$sender.role 为 owner / admin */
|
|
18
|
+
export declare function createSceneRolePlatformChecker(): PlatformPermitChecker;
|
|
19
|
+
/** 为适配器注册默认场景治理 platform checker(幂等) */
|
|
20
|
+
export declare function registerDefaultScenePlatformPermitChecker(adapter: string): () => void;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { parsePlatformPermitName, isPlatformPermit } from './permit-parse.js';
|
|
2
|
+
const checkers = new Map();
|
|
3
|
+
const defaultSceneRegistrations = new Map();
|
|
4
|
+
export function registerPlatformPermitChecker(adapter, checker) {
|
|
5
|
+
const key = String(adapter);
|
|
6
|
+
const registrations = checkers.get(key) ?? [];
|
|
7
|
+
registrations.push(checker);
|
|
8
|
+
checkers.set(key, registrations);
|
|
9
|
+
return () => {
|
|
10
|
+
const current = checkers.get(key);
|
|
11
|
+
if (!current)
|
|
12
|
+
return;
|
|
13
|
+
const index = current.lastIndexOf(checker);
|
|
14
|
+
if (index >= 0)
|
|
15
|
+
current.splice(index, 1);
|
|
16
|
+
if (current.length === 0)
|
|
17
|
+
checkers.delete(key);
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function clearPlatformPermitCheckers() {
|
|
21
|
+
checkers.clear();
|
|
22
|
+
defaultSceneRegistrations.clear();
|
|
23
|
+
}
|
|
24
|
+
export function checkPlatformPermit(name, message) {
|
|
25
|
+
const parsed = parsePlatformPermitName(name);
|
|
26
|
+
if (!parsed)
|
|
27
|
+
return false;
|
|
28
|
+
if (String(message.$adapter) !== parsed.adapter)
|
|
29
|
+
return false;
|
|
30
|
+
const registrations = checkers.get(parsed.adapter);
|
|
31
|
+
const checker = registrations?.[registrations.length - 1];
|
|
32
|
+
if (!checker)
|
|
33
|
+
return false;
|
|
34
|
+
return checker(parsed.perm, message);
|
|
35
|
+
}
|
|
36
|
+
export function checkPlatformPermitList(permits, message) {
|
|
37
|
+
return permits.every((p) => isPlatformPermit(p) && checkPlatformPermit(p, message));
|
|
38
|
+
}
|
|
39
|
+
/** OneBot / QQ 系 sender.role 归一化 */
|
|
40
|
+
export function normalizeQqSenderRole(role) {
|
|
41
|
+
if (!role || role === 'member')
|
|
42
|
+
return undefined;
|
|
43
|
+
if (role === 'owner' || role === 'admin')
|
|
44
|
+
return role;
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
/** 从 OneBot sender 对象写入 MessageSender.role / permissions */
|
|
48
|
+
export function applyQqSenderRoleToMessageSender(sender, role) {
|
|
49
|
+
const normalized = normalizeQqSenderRole(role);
|
|
50
|
+
if (!normalized)
|
|
51
|
+
return;
|
|
52
|
+
sender.role = normalized;
|
|
53
|
+
sender.permissions = [normalized];
|
|
54
|
+
}
|
|
55
|
+
/** 常见 IM 平台场景身份:$sender.role 为 owner / admin */
|
|
56
|
+
export function createSceneRolePlatformChecker() {
|
|
57
|
+
return (perm, message) => {
|
|
58
|
+
const role = message.$sender?.role;
|
|
59
|
+
if (perm === 'scene_admin')
|
|
60
|
+
return role === 'admin' || role === 'owner';
|
|
61
|
+
if (perm === 'scene_owner')
|
|
62
|
+
return role === 'owner';
|
|
63
|
+
return false;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/** 为适配器注册默认场景治理 platform checker(幂等) */
|
|
67
|
+
export function registerDefaultScenePlatformPermitChecker(adapter) {
|
|
68
|
+
const key = String(adapter);
|
|
69
|
+
const existing = defaultSceneRegistrations.get(key);
|
|
70
|
+
if (existing) {
|
|
71
|
+
existing.references += 1;
|
|
72
|
+
return () => releaseDefaultSceneChecker(key, existing);
|
|
73
|
+
}
|
|
74
|
+
const checker = createSceneRolePlatformChecker();
|
|
75
|
+
const registration = {
|
|
76
|
+
checker,
|
|
77
|
+
dispose: registerPlatformPermitChecker(key, checker),
|
|
78
|
+
references: 1,
|
|
79
|
+
};
|
|
80
|
+
defaultSceneRegistrations.set(key, registration);
|
|
81
|
+
return () => releaseDefaultSceneChecker(key, registration);
|
|
82
|
+
}
|
|
83
|
+
function releaseDefaultSceneChecker(key, registration) {
|
|
84
|
+
if (defaultSceneRegistrations.get(key) !== registration)
|
|
85
|
+
return;
|
|
86
|
+
registration.references -= 1;
|
|
87
|
+
if (registration.references > 0)
|
|
88
|
+
return;
|
|
89
|
+
defaultSceneRegistrations.delete(key);
|
|
90
|
+
registration.dispose();
|
|
91
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { MessageType } from '../message.js';
|
|
2
2
|
import type { SendContent, SendOptions } from '../types.js';
|
|
3
|
+
import { type IMDeliveryTarget } from '../im-scene.js';
|
|
3
4
|
export interface QueueEnvelope<TDetail extends Record<string, unknown> = Record<string, unknown>> {
|
|
4
5
|
kind: string;
|
|
5
6
|
type: string;
|
|
@@ -8,7 +9,7 @@ export interface QueueEnvelope<TDetail extends Record<string, unknown> = Record<
|
|
|
8
9
|
}
|
|
9
10
|
export interface NormalizedQueueOutboundDetail {
|
|
10
11
|
context: string;
|
|
11
|
-
|
|
12
|
+
endpoint: string;
|
|
12
13
|
channelId: string;
|
|
13
14
|
channelType: MessageType;
|
|
14
15
|
content: SendContent;
|
|
@@ -23,5 +24,9 @@ export declare function isMessageType(value: unknown): value is MessageType;
|
|
|
23
24
|
/** Normalize queue outbound detail into the canonical queue-IM shape. */
|
|
24
25
|
export declare function normalizeQueueOutboundDetail(record: Record<string, unknown>): NormalizedQueueOutboundDetail;
|
|
25
26
|
export declare function toSendOptions(detail: NormalizedQueueOutboundDetail): SendOptions;
|
|
27
|
+
export interface QueueIMSceneTargetDetail {
|
|
28
|
+
target: IMDeliveryTarget;
|
|
29
|
+
content: SendContent;
|
|
30
|
+
}
|
|
31
|
+
export declare function sceneTargetToSendOptions(detail: QueueIMSceneTargetDetail): SendOptions;
|
|
26
32
|
export declare function normalizeRecordToSendOptions(record: Record<string, unknown>): SendOptions;
|
|
27
|
-
//# sourceMappingURL=queue-im-field-contract.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sceneRefToSendOptions } from '../im-scene.js';
|
|
1
2
|
export class QueueIMFieldContractError extends Error {
|
|
2
3
|
code;
|
|
3
4
|
field;
|
|
@@ -26,7 +27,7 @@ function requireContent(value) {
|
|
|
26
27
|
/** Normalize queue outbound detail into the canonical queue-IM shape. */
|
|
27
28
|
export function normalizeQueueOutboundDetail(record) {
|
|
28
29
|
const context = requireString(record.context, 'context');
|
|
29
|
-
const
|
|
30
|
+
const endpoint = requireString(record.endpoint, 'endpoint');
|
|
30
31
|
const channelId = requireString(record.channelId, 'channelId');
|
|
31
32
|
const channelTypeValue = record.channelType;
|
|
32
33
|
if (!isMessageType(channelTypeValue)) {
|
|
@@ -34,7 +35,7 @@ export function normalizeQueueOutboundDetail(record) {
|
|
|
34
35
|
}
|
|
35
36
|
const normalized = {
|
|
36
37
|
context,
|
|
37
|
-
|
|
38
|
+
endpoint,
|
|
38
39
|
channelId,
|
|
39
40
|
channelType: channelTypeValue,
|
|
40
41
|
content: requireContent(record.content),
|
|
@@ -46,13 +47,21 @@ export function normalizeQueueOutboundDetail(record) {
|
|
|
46
47
|
export function toSendOptions(detail) {
|
|
47
48
|
return {
|
|
48
49
|
context: detail.context,
|
|
49
|
-
|
|
50
|
+
endpoint: detail.endpoint,
|
|
50
51
|
id: detail.channelId,
|
|
51
52
|
type: detail.channelType,
|
|
52
53
|
content: detail.content,
|
|
53
54
|
};
|
|
54
55
|
}
|
|
56
|
+
export function sceneTargetToSendOptions(detail) {
|
|
57
|
+
return sceneRefToSendOptions(detail.target, detail.content);
|
|
58
|
+
}
|
|
55
59
|
export function normalizeRecordToSendOptions(record) {
|
|
60
|
+
if (record.target && typeof record.target === 'object') {
|
|
61
|
+
return sceneTargetToSendOptions({
|
|
62
|
+
target: record.target,
|
|
63
|
+
content: requireContent(record.content),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
56
66
|
return toSendOptions(normalizeQueueOutboundDetail(record));
|
|
57
67
|
}
|
|
58
|
-
//# sourceMappingURL=queue-im-field-contract.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type OutboundRichSegmentPolicy } from './types.js';
|
|
2
|
+
/** 全功能 IM:html/markdown/qrcode→image,tts→audio */
|
|
3
|
+
export declare const OUTBOUND_RICH_SEGMENT_POLICY_IM_FULL: OutboundRichSegmentPolicy;
|
|
4
|
+
/** 仅文本降级(无富媒体出站能力) */
|
|
5
|
+
export declare const OUTBOUND_RICH_SEGMENT_POLICY_TEXT_ONLY: OutboundRichSegmentPolicy;
|
|
6
|
+
/** 默认 registry 等价(html/markdown 文本,qrcode 图片,tts 音频) */
|
|
7
|
+
export declare const OUTBOUND_RICH_SEGMENT_POLICY_IM_DEFAULT: OutboundRichSegmentPolicy;
|
|
8
|
+
/** 无音频出站(tts 降级 text) */
|
|
9
|
+
export declare const OUTBOUND_RICH_SEGMENT_POLICY_NO_AUDIO: OutboundRichSegmentPolicy;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { BUILTIN_RICH_SEGMENT_KINDS, RICH_SEGMENT_MODE } from './types.js';
|
|
2
|
+
/** 全功能 IM:html/markdown/qrcode→image,tts→audio */
|
|
3
|
+
export const OUTBOUND_RICH_SEGMENT_POLICY_IM_FULL = {
|
|
4
|
+
[BUILTIN_RICH_SEGMENT_KINDS.QRCODE]: RICH_SEGMENT_MODE.IMAGE,
|
|
5
|
+
[BUILTIN_RICH_SEGMENT_KINDS.HTML]: RICH_SEGMENT_MODE.IMAGE,
|
|
6
|
+
[BUILTIN_RICH_SEGMENT_KINDS.MARKDOWN]: RICH_SEGMENT_MODE.IMAGE,
|
|
7
|
+
[BUILTIN_RICH_SEGMENT_KINDS.TTS]: RICH_SEGMENT_MODE.AUDIO,
|
|
8
|
+
};
|
|
9
|
+
/** 仅文本降级(无富媒体出站能力) */
|
|
10
|
+
export const OUTBOUND_RICH_SEGMENT_POLICY_TEXT_ONLY = {
|
|
11
|
+
[BUILTIN_RICH_SEGMENT_KINDS.QRCODE]: RICH_SEGMENT_MODE.TEXT,
|
|
12
|
+
[BUILTIN_RICH_SEGMENT_KINDS.HTML]: RICH_SEGMENT_MODE.TEXT,
|
|
13
|
+
[BUILTIN_RICH_SEGMENT_KINDS.MARKDOWN]: RICH_SEGMENT_MODE.TEXT,
|
|
14
|
+
[BUILTIN_RICH_SEGMENT_KINDS.TTS]: RICH_SEGMENT_MODE.TEXT,
|
|
15
|
+
};
|
|
16
|
+
/** 默认 registry 等价(html/markdown 文本,qrcode 图片,tts 音频) */
|
|
17
|
+
export const OUTBOUND_RICH_SEGMENT_POLICY_IM_DEFAULT = {
|
|
18
|
+
[BUILTIN_RICH_SEGMENT_KINDS.QRCODE]: RICH_SEGMENT_MODE.IMAGE,
|
|
19
|
+
[BUILTIN_RICH_SEGMENT_KINDS.HTML]: RICH_SEGMENT_MODE.TEXT,
|
|
20
|
+
[BUILTIN_RICH_SEGMENT_KINDS.MARKDOWN]: RICH_SEGMENT_MODE.TEXT,
|
|
21
|
+
[BUILTIN_RICH_SEGMENT_KINDS.TTS]: RICH_SEGMENT_MODE.AUDIO,
|
|
22
|
+
};
|
|
23
|
+
/** 无音频出站(tts 降级 text) */
|
|
24
|
+
export const OUTBOUND_RICH_SEGMENT_POLICY_NO_AUDIO = {
|
|
25
|
+
...OUTBOUND_RICH_SEGMENT_POLICY_IM_FULL,
|
|
26
|
+
[BUILTIN_RICH_SEGMENT_KINDS.TTS]: RICH_SEGMENT_MODE.TEXT,
|
|
27
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { MessageElement } from '../../types.js';
|
|
2
|
+
import type { RichSegmentRenderContext, RichSegmentRenderResult } from './types.js';
|
|
3
|
+
export declare abstract class RichSegment<TData> {
|
|
4
|
+
readonly data: TData;
|
|
5
|
+
abstract readonly segmentType: string;
|
|
6
|
+
constructor(data: TData);
|
|
7
|
+
abstract render(mode: string, ctx?: RichSegmentRenderContext): Promise<RichSegmentRenderResult>;
|
|
8
|
+
toJSON(): MessageElement;
|
|
9
|
+
}
|
|
10
|
+
export declare function isRichSegment(item: unknown): item is RichSegment<unknown>;
|
|
11
|
+
export declare function richSegmentKind(item: MessageElement | string): string | null;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { richSegmentRegistry } from './registry.js';
|
|
2
|
+
export class RichSegment {
|
|
3
|
+
data;
|
|
4
|
+
constructor(data) {
|
|
5
|
+
this.data = data;
|
|
6
|
+
}
|
|
7
|
+
toJSON() {
|
|
8
|
+
return { type: this.segmentType, data: this.data };
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function isRichSegment(item) {
|
|
12
|
+
return item instanceof RichSegment;
|
|
13
|
+
}
|
|
14
|
+
export function richSegmentKind(item) {
|
|
15
|
+
if (typeof item === 'string')
|
|
16
|
+
return null;
|
|
17
|
+
const type = item.type;
|
|
18
|
+
if (typeof type !== 'string')
|
|
19
|
+
return null;
|
|
20
|
+
if (richSegmentRegistry.has(type)) {
|
|
21
|
+
return type;
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { registerRichSegmentKind, richSegmentRegistry } from './registry.js';
|
|
2
|
+
import { wrapQrcodeSegment } from './qrcode-segment.js';
|
|
3
|
+
import { wrapHtmlSegment } from './html-segment.js';
|
|
4
|
+
import { wrapMarkdownSegment } from './markdown-segment.js';
|
|
5
|
+
import { wrapTtsSegment } from './tts-segment.js';
|
|
6
|
+
import { BUILTIN_RICH_SEGMENT_KINDS, RICH_SEGMENT_MODE } from './types.js';
|
|
7
|
+
function registerBuiltinRichSegmentKinds() {
|
|
8
|
+
registerRichSegmentKind({
|
|
9
|
+
kind: BUILTIN_RICH_SEGMENT_KINDS.QRCODE,
|
|
10
|
+
defaultMode: RICH_SEGMENT_MODE.IMAGE,
|
|
11
|
+
modes: [RICH_SEGMENT_MODE.IMAGE, RICH_SEGMENT_MODE.TEXT, RICH_SEGMENT_MODE.ORIGIN],
|
|
12
|
+
wrap: wrapQrcodeSegment,
|
|
13
|
+
});
|
|
14
|
+
registerRichSegmentKind({
|
|
15
|
+
kind: BUILTIN_RICH_SEGMENT_KINDS.HTML,
|
|
16
|
+
defaultMode: RICH_SEGMENT_MODE.TEXT,
|
|
17
|
+
modes: [RICH_SEGMENT_MODE.IMAGE, RICH_SEGMENT_MODE.TEXT, RICH_SEGMENT_MODE.ORIGIN],
|
|
18
|
+
wrap: wrapHtmlSegment,
|
|
19
|
+
});
|
|
20
|
+
registerRichSegmentKind({
|
|
21
|
+
kind: BUILTIN_RICH_SEGMENT_KINDS.MARKDOWN,
|
|
22
|
+
defaultMode: RICH_SEGMENT_MODE.TEXT,
|
|
23
|
+
modes: [RICH_SEGMENT_MODE.IMAGE, RICH_SEGMENT_MODE.TEXT, RICH_SEGMENT_MODE.ORIGIN],
|
|
24
|
+
wrap: wrapMarkdownSegment,
|
|
25
|
+
});
|
|
26
|
+
registerRichSegmentKind({
|
|
27
|
+
kind: BUILTIN_RICH_SEGMENT_KINDS.TTS,
|
|
28
|
+
defaultMode: RICH_SEGMENT_MODE.AUDIO,
|
|
29
|
+
modes: [RICH_SEGMENT_MODE.ORIGIN, RICH_SEGMENT_MODE.AUDIO, RICH_SEGMENT_MODE.TEXT],
|
|
30
|
+
wrap: wrapTtsSegment,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
registerBuiltinRichSegmentKinds();
|
|
34
|
+
/** 内置 kind 的默认出站 policy(由 registry 生成,增 kind 时自动包含) */
|
|
35
|
+
export const DEFAULT_OUTBOUND_RICH_SEGMENT_POLICY = richSegmentRegistry.buildDefaultPolicy();
|
|
36
|
+
/** 测试:清空 registry 后重新注册内置 kind */
|
|
37
|
+
export function resetBuiltinRichSegmentKindsForTests() {
|
|
38
|
+
richSegmentRegistry.clearForTests();
|
|
39
|
+
registerBuiltinRichSegmentKinds();
|
|
40
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { RichSegmentCapabilityLoader, RichSegmentCapabilityLoaderOptions, RichSegmentRenderContext } from './types.js';
|
|
2
|
+
/** 注册 optional 包能力(如 html-renderer、未来 media-pipeline) */
|
|
3
|
+
export declare function registerRichSegmentCapabilityLoader(id: string, loader: RichSegmentCapabilityLoader): void;
|
|
4
|
+
/** 测试隔离 */
|
|
5
|
+
export declare function resetRichSegmentCapabilityLoadersForTests(): void;
|
|
6
|
+
export declare function createRichSegmentRenderContext(options?: RichSegmentCapabilityLoaderOptions): RichSegmentRenderContext;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { loadHtmlRenderer } from '../html-renderer-loader.js';
|
|
2
|
+
import { loadSpeechPipeline } from '../speech-loader.js';
|
|
3
|
+
const capabilityLoaders = new Map();
|
|
4
|
+
/** 注册 optional 包能力(如 html-renderer、未来 media-pipeline) */
|
|
5
|
+
export function registerRichSegmentCapabilityLoader(id, loader) {
|
|
6
|
+
capabilityLoaders.set(id, loader);
|
|
7
|
+
}
|
|
8
|
+
/** 测试隔离 */
|
|
9
|
+
export function resetRichSegmentCapabilityLoadersForTests() {
|
|
10
|
+
capabilityLoaders.clear();
|
|
11
|
+
registerCoreRichSegmentCapabilityLoaders();
|
|
12
|
+
}
|
|
13
|
+
function registerCoreRichSegmentCapabilityLoaders() {
|
|
14
|
+
registerRichSegmentCapabilityLoader('html-renderer', async (options) => loadHtmlRenderer({
|
|
15
|
+
getConfig: options.getConfig,
|
|
16
|
+
warn: options.warn,
|
|
17
|
+
}));
|
|
18
|
+
registerRichSegmentCapabilityLoader('speech', async (options) => loadSpeechPipeline({
|
|
19
|
+
getConfig: options.getConfig,
|
|
20
|
+
warn: options.warn,
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
registerCoreRichSegmentCapabilityLoaders();
|
|
24
|
+
export function createRichSegmentRenderContext(options = {}) {
|
|
25
|
+
const cache = new Map();
|
|
26
|
+
const resolveCapability = async (id) => {
|
|
27
|
+
if (!cache.has(id)) {
|
|
28
|
+
const loader = capabilityLoaders.get(id);
|
|
29
|
+
cache.set(id, loader ? loader(options) : Promise.resolve(undefined));
|
|
30
|
+
}
|
|
31
|
+
return cache.get(id);
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
resolveCapability,
|
|
35
|
+
warn: options.warn,
|
|
36
|
+
logContentChain: options.logContentChain,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { RichSegment } from './base.js';
|
|
2
|
+
import { type RichSegmentRenderContext, type RichSegmentRenderResult } from './types.js';
|
|
3
|
+
export interface HtmlSegmentData {
|
|
4
|
+
html: string;
|
|
5
|
+
text?: string;
|
|
6
|
+
width?: number;
|
|
7
|
+
backgroundColor?: string;
|
|
8
|
+
fileName?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare class HtmlSegment extends RichSegment<HtmlSegmentData> {
|
|
11
|
+
readonly segmentType: "html";
|
|
12
|
+
readonly type: "html";
|
|
13
|
+
render(mode: string, ctx?: RichSegmentRenderContext): Promise<RichSegmentRenderResult>;
|
|
14
|
+
}
|
|
15
|
+
export declare function wrapHtmlSegment(data: Record<string, unknown>): HtmlSegment;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { segment } from '../../utils.js';
|
|
2
|
+
import { htmlToFallbackText } from '../html-to-text.js';
|
|
3
|
+
import { RichSegment } from './base.js';
|
|
4
|
+
import { RICH_SEGMENT_MODE } from './types.js';
|
|
5
|
+
async function resolveHtmlRenderer(ctx) {
|
|
6
|
+
if (!ctx)
|
|
7
|
+
return undefined;
|
|
8
|
+
return ctx.resolveCapability('html-renderer');
|
|
9
|
+
}
|
|
10
|
+
export class HtmlSegment extends RichSegment {
|
|
11
|
+
segmentType = 'html';
|
|
12
|
+
type = 'html';
|
|
13
|
+
async render(mode, ctx) {
|
|
14
|
+
if (mode === RICH_SEGMENT_MODE.ORIGIN) {
|
|
15
|
+
return this.toJSON();
|
|
16
|
+
}
|
|
17
|
+
if (mode === RICH_SEGMENT_MODE.TEXT) {
|
|
18
|
+
if (typeof this.data.text === 'string' && this.data.text.length > 0) {
|
|
19
|
+
return segment.text(this.data.text);
|
|
20
|
+
}
|
|
21
|
+
const html = typeof this.data.html === 'string' ? this.data.html : '';
|
|
22
|
+
return segment.text(html ? htmlToFallbackText(html) : '');
|
|
23
|
+
}
|
|
24
|
+
if (mode === RICH_SEGMENT_MODE.IMAGE) {
|
|
25
|
+
const html = typeof this.data.html === 'string' ? this.data.html : '';
|
|
26
|
+
if (!html) {
|
|
27
|
+
return segment.text('');
|
|
28
|
+
}
|
|
29
|
+
const renderer = await resolveHtmlRenderer(ctx);
|
|
30
|
+
if (!renderer) {
|
|
31
|
+
return this.render(RICH_SEGMENT_MODE.TEXT, ctx);
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const result = await renderer.render(html, {
|
|
35
|
+
width: typeof this.data.width === 'number' ? this.data.width : 540,
|
|
36
|
+
format: 'png',
|
|
37
|
+
backgroundColor: typeof this.data.backgroundColor === 'string' ? this.data.backgroundColor : '#d8dce3',
|
|
38
|
+
});
|
|
39
|
+
if (result.format !== 'png' || typeof result.data !== 'object') {
|
|
40
|
+
return this.render(RICH_SEGMENT_MODE.TEXT, ctx);
|
|
41
|
+
}
|
|
42
|
+
const base64 = Buffer.from(result.data).toString('base64');
|
|
43
|
+
const fileName = typeof this.data.fileName === 'string' ? this.data.fileName : 'card.png';
|
|
44
|
+
return segment('image', { url: `base64://${base64}`, name: fileName });
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return this.render(RICH_SEGMENT_MODE.TEXT, ctx);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return this.render(RICH_SEGMENT_MODE.TEXT, ctx);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export function wrapHtmlSegment(data) {
|
|
54
|
+
const html = typeof data.html === 'string' ? data.html : '';
|
|
55
|
+
return new HtmlSegment({
|
|
56
|
+
html,
|
|
57
|
+
text: typeof data.text === 'string' ? data.text : undefined,
|
|
58
|
+
width: typeof data.width === 'number' ? data.width : undefined,
|
|
59
|
+
backgroundColor: typeof data.backgroundColor === 'string' ? data.backgroundColor : undefined,
|
|
60
|
+
fileName: typeof data.fileName === 'string' ? data.fileName : undefined,
|
|
61
|
+
});
|
|
62
|
+
}
|