@deepseek-harness-tui/dsh-tui 0.8.4 → 0.8.5
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/bin/dsh-tui.js +0 -0
- package/dsh-ecosystem-spec/protocols/profile-definitions.d.ts +13 -13
- package/dsh-ecosystem-spec/protocols/profile-definitions.js +59 -59
- package/dsh-ecosystem-spec/protocols/tui-channel-http.d.ts +15 -15
- package/dsh-ecosystem-spec/protocols/tui-channel-http.js +32 -32
- package/dsh-ecosystem-spec/protocols/tui-channel.d.ts +59 -59
- package/dsh-ecosystem-spec/protocols/tui-channel.js +166 -166
- package/dsh-ecosystem-spec/protocols/tui-contributions.d.ts +42 -42
- package/dsh-ecosystem-spec/protocols/tui-contributions.js +143 -143
- package/dsh-ecosystem-spec/registry/README.md +14 -14
- package/dsh-ecosystem-spec/registry/host-descriptor.tui.example.json +56 -56
- package/dsh-ecosystem-spec/registry/permissions-0.1.json +13 -13
- package/dsh-ecosystem-spec/registry/registry-0.15.json +149 -149
- package/lib/types/activityPrefs.d.ts +10 -0
- package/lib/types/activityPrefs.d.ts.map +1 -1
- package/lib/types/activityPrefs.js +17 -0
- package/lib/types/components/MessageList.d.ts +4 -1
- package/lib/types/components/MessageList.d.ts.map +1 -1
- package/lib/types/components/MessageList.js +4 -4
- package/lib/types/components/SplitDiffView.d.ts +3 -1
- package/lib/types/components/SplitDiffView.d.ts.map +1 -1
- package/lib/types/components/SplitDiffView.js +12 -5
- package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
- package/lib/types/components/StreamingMarkdown.js +10 -2
- package/lib/types/components/activityFrames.d.ts +7 -28
- package/lib/types/components/activityFrames.d.ts.map +1 -1
- package/lib/types/components/activityFrames.js +7 -94
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantThinkingMessage.js +1 -1
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts +4 -1
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantToolUseMessage.js +14 -3
- package/lib/types/dsh-adapter/channel.d.ts +17 -0
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +161 -19
- package/lib/types/dsh-adapter/index.d.ts +5 -0
- package/lib/types/dsh-adapter/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/index.js +19 -0
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +176 -4
- package/lib/types/dsh-adapter/settings-sections.d.ts +13 -0
- package/lib/types/dsh-adapter/settings-sections.d.ts.map +1 -1
- package/lib/types/dsh-adapter/settings-sections.js +31 -6
- package/lib/types/ink/ink.d.ts +9 -0
- package/lib/types/ink/ink.d.ts.map +1 -1
- package/lib/types/ink/ink.js +24 -1
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +34 -4
- package/lib/types/screens/Settings.d.ts.map +1 -1
- package/lib/types/screens/Settings.js +109 -50
- package/lib/types/screens/StatusLine.d.ts +8 -0
- package/lib/types/screens/StatusLine.d.ts.map +1 -1
- package/lib/types/screens/StatusLine.js +62 -39
- package/lib/types/settings-sections.d.ts +1 -1
- package/lib/types/settings-sections.d.ts.map +1 -1
- package/lib/types/tips.js +2 -2
- package/lib/types/tuiDisplayPrefs.d.ts +47 -0
- package/lib/types/tuiDisplayPrefs.d.ts.map +1 -0
- package/lib/types/tuiDisplayPrefs.js +60 -0
- package/node_modules/@dsh-std/command/CHANGELOG.md +8 -8
- package/node_modules/@dsh-std/command/LICENSE +21 -21
- package/node_modules/@dsh-std/command/README.md +26 -26
- package/node_modules/@dsh-std/command/README.zh.md +28 -28
- package/node_modules/@dsh-std/command/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/command/package.json +22 -22
- package/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
- package/node_modules/@dsh-std/connection/LICENSE +21 -21
- package/node_modules/@dsh-std/connection/README.md +42 -42
- package/node_modules/@dsh-std/connection/README.zh.md +42 -42
- package/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
- package/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
- package/node_modules/@dsh-std/connection/package.json +20 -20
- package/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/node_modules/@dsh-std/core/LICENSE +21 -21
- package/node_modules/@dsh-std/core/README.md +13 -13
- package/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/core/package.json +21 -21
- package/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -9
- package/node_modules/@dsh-std/manifest/LICENSE +21 -21
- package/node_modules/@dsh-std/manifest/README.md +5 -5
- package/node_modules/@dsh-std/manifest/README.zh.md +5 -5
- package/node_modules/@dsh-std/manifest/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/manifest/package.json +20 -20
- package/node_modules/@dsh-std/manifest/schema/dsh-plugin-0.15.schema.json +144 -144
- package/node_modules/@dsh-std/messages/CHANGELOG.md +8 -8
- package/node_modules/@dsh-std/messages/LICENSE +21 -21
- package/node_modules/@dsh-std/messages/README.md +5 -5
- package/node_modules/@dsh-std/messages/README.zh.md +7 -7
- package/node_modules/@dsh-std/messages/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/messages/package.json +20 -20
- package/node_modules/@dsh-std/messages/schema/message-observer-envelope-0.15.schema.json +54 -54
- package/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -9
- package/node_modules/@dsh-std/presentation/LICENSE +21 -21
- package/node_modules/@dsh-std/presentation/README.md +27 -27
- package/node_modules/@dsh-std/presentation/README.zh.md +29 -29
- package/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -1
- package/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/presentation/package.json +25 -25
- package/node_modules/@dsh-std/storage/CHANGELOG.md +8 -8
- package/node_modules/@dsh-std/storage/LICENSE +21 -21
- package/node_modules/@dsh-std/storage/README.md +5 -5
- package/node_modules/@dsh-std/storage/README.zh.md +7 -7
- package/node_modules/@dsh-std/storage/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/storage/package.json +20 -20
- package/node_modules/@dsh-std/storage/schema/local-storage-0.15.schema.json +56 -56
- package/package.json +6 -3
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/LICENSE +21 -21
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/README.md +42 -42
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/README.zh.md +42 -42
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/package.json +20 -20
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/package.json +21 -21
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -9
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/LICENSE +21 -21
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/README.md +5 -5
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/README.zh.md +5 -5
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/package.json +20 -20
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/schema/dsh-plugin-0.15.schema.json +144 -144
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -9
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/LICENSE +21 -21
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.md +27 -27
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.zh.md +29 -29
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/package.json +25 -25
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/package.json +21 -21
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/package.json +21 -21
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/package.json +21 -21
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/LICENSE +21 -21
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/README.md +42 -42
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/README.zh.md +42 -42
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/package.json +20 -20
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/package.json +21 -21
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/package.json +21 -21
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 DSH Standard contributors
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DSH Standard contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
# @dsh-std/messages
|
|
2
|
-
|
|
3
|
-
English | [中文](README.zh.md)
|
|
4
|
-
|
|
5
|
-
This package defines the Community v0.15 `messages.dsh/v1alpha1` `MessageObserver` coordinates, negotiation definition, event types, and validators for the ContentBlock text/image subset. Event sources, subscription dispatch, and authorization interfaces are supplied by implementations.
|
|
1
|
+
# @dsh-std/messages
|
|
2
|
+
|
|
3
|
+
English | [中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
This package defines the Community v0.15 `messages.dsh/v1alpha1` `MessageObserver` coordinates, negotiation definition, event types, and validators for the ContentBlock text/image subset. Event sources, subscription dispatch, and authorization interfaces are supplied by implementations.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# @dsh-std/messages
|
|
2
|
-
|
|
3
|
-
[English](README.md) | 中文
|
|
4
|
-
|
|
5
|
-
规范见 [Message Observation](../../docs/proposals/message-observer.zh.md)。
|
|
6
|
-
|
|
7
|
-
本包定义 Community v0.15 的 `messages.dsh/v1alpha1` `MessageObserver` 协议坐标、协商 definition、事件类型和 ContentBlock text/image 子集校验器。事件来源、订阅调度与授权界面由实现提供。
|
|
1
|
+
# @dsh-std/messages
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 中文
|
|
4
|
+
|
|
5
|
+
规范见 [Message Observation](../../docs/proposals/message-observer.zh.md)。
|
|
6
|
+
|
|
7
|
+
本包定义 Community v0.15 的 `messages.dsh/v1alpha1` `MessageObserver` 协议坐标、协商 definition、事件类型和 ContentBlock text/image 子集校验器。事件来源、订阅调度与授权界面由实现提供。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type {\n ProtocolCatalog,\n ProtocolDefinition,\n ProtocolIssue,\n ProtocolSupport,\n} from '@dsh-std/core'\n\nexport const API_VERSION = 'messages.dsh/v1alpha1'\nexport const KIND = 'MessageObserver'\nexport const READ_PERMISSION = 'messages.observe.read'\nexport const EVENT_TYPE = 'messages.observe'\nexport const EVENT_VERSION = '0.15'\n\nexport type PrivacyClass = 'public' | 'internal' | 'sensitive'\nexport type MessageEventKind = 'message.created' | 'message.received' | 'message.sent'\n\nexport interface TextContentBlock {\n readonly type: 'text'\n readonly text: string\n}\n\nexport interface ImageContentBlock {\n readonly type: 'image'\n readonly data: string\n readonly mimeType: string\n}\n\nexport type MessageContentBlock = TextContentBlock | ImageContentBlock\n\nexport interface MessagePayload {\n readonly kind: MessageEventKind\n readonly messageId?: string\n readonly author?: string\n readonly content: readonly MessageContentBlock[]\n readonly truncated?: boolean\n}\n\nexport interface MessageEvent {\n readonly eventType: typeof EVENT_TYPE\n readonly eventVersion: typeof EVENT_VERSION\n readonly eventId: string\n readonly scope: string\n readonly sequence: number\n readonly privacyClass: PrivacyClass\n readonly summary: string\n readonly payload: MessagePayload\n}\n\nexport interface MessageSubscription {\n readonly scope?: string\n}\n\nexport type MessageObserverErrorCode =\n | 'PERMISSION_NOT_GRANTED'\n | 'UNKNOWN_PRIVACY_CLASS'\n | 'INVALID_EVENT_ENVELOPE'\n | 'SUBSCRIPTION_CLOSED'\n\nexport const protocol: ProtocolDefinition = Object.freeze({\n apiVersion: API_VERSION,\n kind: KIND,\n validateRequirement: emptySpec,\n validateSupport: emptySpec,\n negotiate: negotiatePublisher,\n})\n\nexport const support: ProtocolSupport = Object.freeze({\n apiVersion: API_VERSION,\n kind: KIND,\n})\n\nexport function register(catalog: ProtocolCatalog): () => void {\n return catalog.register(protocol)\n}\n\nexport function validateSubscription(value: unknown): asserts value is MessageSubscription {\n const subscription = exactRecord(value, ['scope'], [], 'MessageObserver subscription')\n if (subscription.scope !== undefined) boundedText(subscription.scope, 256, 'MessageObserver subscription.scope', false)\n}\n\nexport function validateMessageEvent(value: unknown): asserts value is MessageEvent {\n const envelope = exactRecord(\n value,\n ['eventType', 'eventVersion', 'eventId', 'scope', 'sequence', 'privacyClass', 'summary', 'payload'],\n ['eventType', 'eventVersion', 'eventId', 'scope', 'sequence', 'privacyClass', 'summary', 'payload'],\n 'MessageObserver event',\n )\n if (envelope.eventType !== EVENT_TYPE) throw new TypeError(`MessageObserver event.eventType must be ${JSON.stringify(EVENT_TYPE)}`)\n if (envelope.eventVersion !== EVENT_VERSION) throw new TypeError(`MessageObserver event.eventVersion must be ${JSON.stringify(EVENT_VERSION)}`)\n if (typeof envelope.eventId !== 'string' || !/^[A-Za-z0-9._:-]+$/u.test(envelope.eventId)) {\n throw new TypeError('MessageObserver event.eventId is invalid')\n }\n boundedText(envelope.scope, 256, 'MessageObserver event.scope', false)\n if (!Number.isSafeInteger(envelope.sequence) || (envelope.sequence as number) < 0) {\n throw new TypeError('MessageObserver event.sequence must be a non-negative safe integer')\n }\n if (envelope.privacyClass !== 'public' && envelope.privacyClass !== 'internal' && envelope.privacyClass !== 'sensitive') {\n throw new TypeError('MessageObserver event.privacyClass is invalid')\n }\n boundedText(envelope.summary, 1024, 'MessageObserver event.summary', true)\n validatePayload(envelope.payload)\n}\n\nexport function parseMessageEvent(value: unknown): MessageEvent {\n validateMessageEvent(value)\n return deepFreeze(structuredClone(value))\n}\n\nexport function validateContentBlock(value: unknown): asserts value is MessageContentBlock {\n if (!record(value)) throw new TypeError('MessageObserver content block must be an object')\n if (value.type === 'text') {\n const block = exactRecord(value, ['type', 'text'], ['type', 'text'], 'MessageObserver text block')\n if (typeof block.text !== 'string' || block.text.length > 262_144) {\n throw new TypeError('MessageObserver text block.text must be a string of at most 262144 characters')\n }\n return\n }\n if (value.type === 'image') {\n const block = exactRecord(value, ['type', 'data', 'mimeType'], ['type', 'data', 'mimeType'], 'MessageObserver image block')\n if (typeof block.data !== 'string' || !base64(block.data)) {\n throw new TypeError('MessageObserver image block.data must be a base64 string')\n }\n if (typeof block.mimeType !== 'string' || !/^[A-Za-z0-9.+-]+\\/[A-Za-z0-9.+-]+$/u.test(block.mimeType)) {\n throw new TypeError('MessageObserver image block.mimeType is invalid')\n }\n return\n }\n throw new TypeError('MessageObserver content block.type must be \"text\" or \"image\"')\n}\n\nfunction validatePayload(value: unknown): asserts value is MessagePayload {\n const payload = exactRecord(\n value,\n ['kind', 'messageId', 'author', 'content', 'truncated'],\n ['kind', 'content'],\n 'MessageObserver event.payload',\n )\n if (payload.kind !== 'message.created' && payload.kind !== 'message.received' && payload.kind !== 'message.sent') {\n throw new TypeError('MessageObserver event.payload.kind is invalid')\n }\n if (payload.messageId !== undefined) boundedText(payload.messageId, 256, 'MessageObserver event.payload.messageId', true)\n if (payload.author !== undefined) boundedText(payload.author, 256, 'MessageObserver event.payload.author', true)\n if (!Array.isArray(payload.content) || payload.content.length === 0) {\n throw new TypeError('MessageObserver event.payload.content must be a non-empty array')\n }\n for (const block of payload.content) validateContentBlock(block)\n if (payload.truncated !== undefined && typeof payload.truncated !== 'boolean') {\n throw new TypeError('MessageObserver event.payload.truncated must be boolean')\n }\n}\n\nfunction negotiatePublisher(input: Parameters<NonNullable<ProtocolDefinition['negotiate']>>[0]) {\n const issues: ProtocolIssue[] = []\n const publishers = new Map<string, string>()\n for (const row of input.requirements) {\n const candidates = input.supports.filter(candidate => candidate.participant !== row.participant)\n if (candidates.length === 0) {\n issues.push(Object.freeze({\n code: row.requirement.optional === true ? 'optional-support-missing' : 'required-support-missing',\n severity: row.requirement.optional === true ? 'warning' : 'error',\n participant: row.participant,\n message: `no participant supports ${API_VERSION} ${KIND}`,\n }))\n } else if (candidates.length > 1) {\n issues.push(Object.freeze({\n code: 'support-ambiguous',\n severity: 'error',\n participant: row.participant,\n message: `multiple participants support ${API_VERSION} ${KIND}`,\n }))\n } else {\n publishers.set(row.participant, candidates[0]!.participant)\n }\n }\n return {\n agreement: Object.freeze({\n kind: 'MessageObserverBindings',\n publishers: Object.freeze(Object.fromEntries([...publishers].sort(([left], [right]) => left.localeCompare(right)))),\n }),\n issues: Object.freeze(issues),\n }\n}\n\nfunction emptySpec(value: unknown): undefined {\n if (value !== undefined) throw new TypeError(`${KIND} does not accept spec in v1alpha1`)\n return undefined\n}\n\nfunction exactRecord(\n value: unknown,\n allowed: readonly string[],\n required: readonly string[],\n label: string,\n): Record<string, unknown> {\n if (!record(value)) throw new TypeError(`${label} must be an object`)\n const unknown = Object.keys(value).filter(name => !allowed.includes(name))\n if (unknown.length > 0) throw new TypeError(`${label} contains unknown field ${JSON.stringify(unknown[0])}`)\n for (const name of required) {\n if (!Object.hasOwn(value, name)) throw new TypeError(`${label}.${name} is required`)\n }\n return value\n}\n\nfunction boundedText(value: unknown, maximum: number, label: string, empty: boolean): asserts value is string {\n if (typeof value !== 'string' || (!empty && value.length === 0) || value.length > maximum) {\n throw new TypeError(`${label} must be ${empty ? '' : 'a non-empty '}string of at most ${maximum} characters`)\n }\n}\n\nfunction base64(value: string): boolean {\n return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/u.test(value)\n}\n\nfunction record(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction deepFreeze<T>(value: T): T {\n if (typeof value !== 'object' || value === null || Object.isFrozen(value)) return value\n Object.freeze(value)\n for (const child of Object.values(value)) deepFreeze(child)\n return value\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type {\r\n ProtocolCatalog,\r\n ProtocolDefinition,\r\n ProtocolIssue,\r\n ProtocolSupport,\r\n} from '@dsh-std/core'\r\n\r\nexport const API_VERSION = 'messages.dsh/v1alpha1'\r\nexport const KIND = 'MessageObserver'\r\nexport const READ_PERMISSION = 'messages.observe.read'\r\nexport const EVENT_TYPE = 'messages.observe'\r\nexport const EVENT_VERSION = '0.15'\r\n\r\nexport type PrivacyClass = 'public' | 'internal' | 'sensitive'\r\nexport type MessageEventKind = 'message.created' | 'message.received' | 'message.sent'\r\n\r\nexport interface TextContentBlock {\r\n readonly type: 'text'\r\n readonly text: string\r\n}\r\n\r\nexport interface ImageContentBlock {\r\n readonly type: 'image'\r\n readonly data: string\r\n readonly mimeType: string\r\n}\r\n\r\nexport type MessageContentBlock = TextContentBlock | ImageContentBlock\r\n\r\nexport interface MessagePayload {\r\n readonly kind: MessageEventKind\r\n readonly messageId?: string\r\n readonly author?: string\r\n readonly content: readonly MessageContentBlock[]\r\n readonly truncated?: boolean\r\n}\r\n\r\nexport interface MessageEvent {\r\n readonly eventType: typeof EVENT_TYPE\r\n readonly eventVersion: typeof EVENT_VERSION\r\n readonly eventId: string\r\n readonly scope: string\r\n readonly sequence: number\r\n readonly privacyClass: PrivacyClass\r\n readonly summary: string\r\n readonly payload: MessagePayload\r\n}\r\n\r\nexport interface MessageSubscription {\r\n readonly scope?: string\r\n}\r\n\r\nexport type MessageObserverErrorCode =\r\n | 'PERMISSION_NOT_GRANTED'\r\n | 'UNKNOWN_PRIVACY_CLASS'\r\n | 'INVALID_EVENT_ENVELOPE'\r\n | 'SUBSCRIPTION_CLOSED'\r\n\r\nexport const protocol: ProtocolDefinition = Object.freeze({\r\n apiVersion: API_VERSION,\r\n kind: KIND,\r\n validateRequirement: emptySpec,\r\n validateSupport: emptySpec,\r\n negotiate: negotiatePublisher,\r\n})\r\n\r\nexport const support: ProtocolSupport = Object.freeze({\r\n apiVersion: API_VERSION,\r\n kind: KIND,\r\n})\r\n\r\nexport function register(catalog: ProtocolCatalog): () => void {\r\n return catalog.register(protocol)\r\n}\r\n\r\nexport function validateSubscription(value: unknown): asserts value is MessageSubscription {\r\n const subscription = exactRecord(value, ['scope'], [], 'MessageObserver subscription')\r\n if (subscription.scope !== undefined) boundedText(subscription.scope, 256, 'MessageObserver subscription.scope', false)\r\n}\r\n\r\nexport function validateMessageEvent(value: unknown): asserts value is MessageEvent {\r\n const envelope = exactRecord(\r\n value,\r\n ['eventType', 'eventVersion', 'eventId', 'scope', 'sequence', 'privacyClass', 'summary', 'payload'],\r\n ['eventType', 'eventVersion', 'eventId', 'scope', 'sequence', 'privacyClass', 'summary', 'payload'],\r\n 'MessageObserver event',\r\n )\r\n if (envelope.eventType !== EVENT_TYPE) throw new TypeError(`MessageObserver event.eventType must be ${JSON.stringify(EVENT_TYPE)}`)\r\n if (envelope.eventVersion !== EVENT_VERSION) throw new TypeError(`MessageObserver event.eventVersion must be ${JSON.stringify(EVENT_VERSION)}`)\r\n if (typeof envelope.eventId !== 'string' || !/^[A-Za-z0-9._:-]+$/u.test(envelope.eventId)) {\r\n throw new TypeError('MessageObserver event.eventId is invalid')\r\n }\r\n boundedText(envelope.scope, 256, 'MessageObserver event.scope', false)\r\n if (!Number.isSafeInteger(envelope.sequence) || (envelope.sequence as number) < 0) {\r\n throw new TypeError('MessageObserver event.sequence must be a non-negative safe integer')\r\n }\r\n if (envelope.privacyClass !== 'public' && envelope.privacyClass !== 'internal' && envelope.privacyClass !== 'sensitive') {\r\n throw new TypeError('MessageObserver event.privacyClass is invalid')\r\n }\r\n boundedText(envelope.summary, 1024, 'MessageObserver event.summary', true)\r\n validatePayload(envelope.payload)\r\n}\r\n\r\nexport function parseMessageEvent(value: unknown): MessageEvent {\r\n validateMessageEvent(value)\r\n return deepFreeze(structuredClone(value))\r\n}\r\n\r\nexport function validateContentBlock(value: unknown): asserts value is MessageContentBlock {\r\n if (!record(value)) throw new TypeError('MessageObserver content block must be an object')\r\n if (value.type === 'text') {\r\n const block = exactRecord(value, ['type', 'text'], ['type', 'text'], 'MessageObserver text block')\r\n if (typeof block.text !== 'string' || block.text.length > 262_144) {\r\n throw new TypeError('MessageObserver text block.text must be a string of at most 262144 characters')\r\n }\r\n return\r\n }\r\n if (value.type === 'image') {\r\n const block = exactRecord(value, ['type', 'data', 'mimeType'], ['type', 'data', 'mimeType'], 'MessageObserver image block')\r\n if (typeof block.data !== 'string' || !base64(block.data)) {\r\n throw new TypeError('MessageObserver image block.data must be a base64 string')\r\n }\r\n if (typeof block.mimeType !== 'string' || !/^[A-Za-z0-9.+-]+\\/[A-Za-z0-9.+-]+$/u.test(block.mimeType)) {\r\n throw new TypeError('MessageObserver image block.mimeType is invalid')\r\n }\r\n return\r\n }\r\n throw new TypeError('MessageObserver content block.type must be \"text\" or \"image\"')\r\n}\r\n\r\nfunction validatePayload(value: unknown): asserts value is MessagePayload {\r\n const payload = exactRecord(\r\n value,\r\n ['kind', 'messageId', 'author', 'content', 'truncated'],\r\n ['kind', 'content'],\r\n 'MessageObserver event.payload',\r\n )\r\n if (payload.kind !== 'message.created' && payload.kind !== 'message.received' && payload.kind !== 'message.sent') {\r\n throw new TypeError('MessageObserver event.payload.kind is invalid')\r\n }\r\n if (payload.messageId !== undefined) boundedText(payload.messageId, 256, 'MessageObserver event.payload.messageId', true)\r\n if (payload.author !== undefined) boundedText(payload.author, 256, 'MessageObserver event.payload.author', true)\r\n if (!Array.isArray(payload.content) || payload.content.length === 0) {\r\n throw new TypeError('MessageObserver event.payload.content must be a non-empty array')\r\n }\r\n for (const block of payload.content) validateContentBlock(block)\r\n if (payload.truncated !== undefined && typeof payload.truncated !== 'boolean') {\r\n throw new TypeError('MessageObserver event.payload.truncated must be boolean')\r\n }\r\n}\r\n\r\nfunction negotiatePublisher(input: Parameters<NonNullable<ProtocolDefinition['negotiate']>>[0]) {\r\n const issues: ProtocolIssue[] = []\r\n const publishers = new Map<string, string>()\r\n for (const row of input.requirements) {\r\n const candidates = input.supports.filter(candidate => candidate.participant !== row.participant)\r\n if (candidates.length === 0) {\r\n issues.push(Object.freeze({\r\n code: row.requirement.optional === true ? 'optional-support-missing' : 'required-support-missing',\r\n severity: row.requirement.optional === true ? 'warning' : 'error',\r\n participant: row.participant,\r\n message: `no participant supports ${API_VERSION} ${KIND}`,\r\n }))\r\n } else if (candidates.length > 1) {\r\n issues.push(Object.freeze({\r\n code: 'support-ambiguous',\r\n severity: 'error',\r\n participant: row.participant,\r\n message: `multiple participants support ${API_VERSION} ${KIND}`,\r\n }))\r\n } else {\r\n publishers.set(row.participant, candidates[0]!.participant)\r\n }\r\n }\r\n return {\r\n agreement: Object.freeze({\r\n kind: 'MessageObserverBindings',\r\n publishers: Object.freeze(Object.fromEntries([...publishers].sort(([left], [right]) => left.localeCompare(right)))),\r\n }),\r\n issues: Object.freeze(issues),\r\n }\r\n}\r\n\r\nfunction emptySpec(value: unknown): undefined {\r\n if (value !== undefined) throw new TypeError(`${KIND} does not accept spec in v1alpha1`)\r\n return undefined\r\n}\r\n\r\nfunction exactRecord(\r\n value: unknown,\r\n allowed: readonly string[],\r\n required: readonly string[],\r\n label: string,\r\n): Record<string, unknown> {\r\n if (!record(value)) throw new TypeError(`${label} must be an object`)\r\n const unknown = Object.keys(value).filter(name => !allowed.includes(name))\r\n if (unknown.length > 0) throw new TypeError(`${label} contains unknown field ${JSON.stringify(unknown[0])}`)\r\n for (const name of required) {\r\n if (!Object.hasOwn(value, name)) throw new TypeError(`${label}.${name} is required`)\r\n }\r\n return value\r\n}\r\n\r\nfunction boundedText(value: unknown, maximum: number, label: string, empty: boolean): asserts value is string {\r\n if (typeof value !== 'string' || (!empty && value.length === 0) || value.length > maximum) {\r\n throw new TypeError(`${label} must be ${empty ? '' : 'a non-empty '}string of at most ${maximum} characters`)\r\n }\r\n}\r\n\r\nfunction base64(value: string): boolean {\r\n return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/u.test(value)\r\n}\r\n\r\nfunction record(value: unknown): value is Record<string, unknown> {\r\n return typeof value === 'object' && value !== null && !Array.isArray(value)\r\n}\r\n\r\nfunction deepFreeze<T>(value: T): T {\r\n if (typeof value !== 'object' || value === null || Object.isFrozen(value)) return value\r\n Object.freeze(value)\r\n for (const child of Object.values(value)) deepFreeze(child)\r\n return value\r\n}\r\n"],"mappings":"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"}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@dsh-std/messages",
|
|
3
|
-
"version": "0.1.0",
|
|
4
|
-
"license": "MIT",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "lib/index.js",
|
|
7
|
-
"types": "lib/index.d.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": { "types": "./lib/index.d.ts", "default": "./lib/index.js" },
|
|
10
|
-
"./schema/message-observer-envelope-0.15.json": "./schema/message-observer-envelope-0.15.schema.json"
|
|
11
|
-
},
|
|
12
|
-
"files": ["lib", "schema", "CHANGELOG.md"],
|
|
13
|
-
"scripts": {
|
|
14
|
-
"build": "pnpm run typecheck && tsdown",
|
|
15
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
16
|
-
"test": "vitest run --passWithNoTests"
|
|
17
|
-
},
|
|
18
|
-
"dependencies": { "@dsh-std/core": "workspace:*" },
|
|
19
|
-
"engines": { "node": "^22.19 || >=24" }
|
|
20
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@dsh-std/messages",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "lib/index.js",
|
|
7
|
+
"types": "lib/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": { "types": "./lib/index.d.ts", "default": "./lib/index.js" },
|
|
10
|
+
"./schema/message-observer-envelope-0.15.json": "./schema/message-observer-envelope-0.15.schema.json"
|
|
11
|
+
},
|
|
12
|
+
"files": ["lib", "schema", "CHANGELOG.md"],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "pnpm run typecheck && tsdown",
|
|
15
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
16
|
+
"test": "vitest run --passWithNoTests"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": { "@dsh-std/core": "workspace:*" },
|
|
19
|
+
"engines": { "node": "^22.19 || >=24" }
|
|
20
|
+
}
|
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "urn:dsh-std:messages:message-observer-envelope:0.15",
|
|
4
|
-
"title": "MessageObserver envelope v0.15",
|
|
5
|
-
"type": "object",
|
|
6
|
-
"additionalProperties": false,
|
|
7
|
-
"required": ["eventType", "eventVersion", "eventId", "scope", "sequence", "privacyClass", "summary", "payload"],
|
|
8
|
-
"properties": {
|
|
9
|
-
"eventType": { "const": "messages.observe" },
|
|
10
|
-
"eventVersion": { "const": "0.15" },
|
|
11
|
-
"eventId": { "type": "string", "pattern": "^[A-Za-z0-9._:-]+$" },
|
|
12
|
-
"scope": { "type": "string", "minLength": 1, "maxLength": 256 },
|
|
13
|
-
"sequence": { "type": "integer", "minimum": 0 },
|
|
14
|
-
"privacyClass": { "enum": ["public", "internal", "sensitive"] },
|
|
15
|
-
"summary": { "type": "string", "maxLength": 1024 },
|
|
16
|
-
"payload": {
|
|
17
|
-
"type": "object",
|
|
18
|
-
"additionalProperties": false,
|
|
19
|
-
"required": ["kind", "content"],
|
|
20
|
-
"properties": {
|
|
21
|
-
"kind": { "enum": ["message.created", "message.received", "message.sent"] },
|
|
22
|
-
"messageId": { "type": "string", "maxLength": 256 },
|
|
23
|
-
"author": { "type": "string", "maxLength": 256 },
|
|
24
|
-
"content": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/contentBlock" } },
|
|
25
|
-
"truncated": { "type": "boolean" }
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
"$defs": {
|
|
30
|
-
"contentBlock": {
|
|
31
|
-
"oneOf": [
|
|
32
|
-
{
|
|
33
|
-
"type": "object",
|
|
34
|
-
"additionalProperties": false,
|
|
35
|
-
"required": ["type", "text"],
|
|
36
|
-
"properties": {
|
|
37
|
-
"type": { "const": "text" },
|
|
38
|
-
"text": { "type": "string", "maxLength": 262144 }
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
"type": "object",
|
|
43
|
-
"additionalProperties": false,
|
|
44
|
-
"required": ["type", "data", "mimeType"],
|
|
45
|
-
"properties": {
|
|
46
|
-
"type": { "const": "image" },
|
|
47
|
-
"data": { "type": "string", "contentEncoding": "base64" },
|
|
48
|
-
"mimeType": { "type": "string", "pattern": "^[A-Za-z0-9.+-]+/[A-Za-z0-9.+-]+$" }
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
]
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "urn:dsh-std:messages:message-observer-envelope:0.15",
|
|
4
|
+
"title": "MessageObserver envelope v0.15",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["eventType", "eventVersion", "eventId", "scope", "sequence", "privacyClass", "summary", "payload"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"eventType": { "const": "messages.observe" },
|
|
10
|
+
"eventVersion": { "const": "0.15" },
|
|
11
|
+
"eventId": { "type": "string", "pattern": "^[A-Za-z0-9._:-]+$" },
|
|
12
|
+
"scope": { "type": "string", "minLength": 1, "maxLength": 256 },
|
|
13
|
+
"sequence": { "type": "integer", "minimum": 0 },
|
|
14
|
+
"privacyClass": { "enum": ["public", "internal", "sensitive"] },
|
|
15
|
+
"summary": { "type": "string", "maxLength": 1024 },
|
|
16
|
+
"payload": {
|
|
17
|
+
"type": "object",
|
|
18
|
+
"additionalProperties": false,
|
|
19
|
+
"required": ["kind", "content"],
|
|
20
|
+
"properties": {
|
|
21
|
+
"kind": { "enum": ["message.created", "message.received", "message.sent"] },
|
|
22
|
+
"messageId": { "type": "string", "maxLength": 256 },
|
|
23
|
+
"author": { "type": "string", "maxLength": 256 },
|
|
24
|
+
"content": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/contentBlock" } },
|
|
25
|
+
"truncated": { "type": "boolean" }
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"$defs": {
|
|
30
|
+
"contentBlock": {
|
|
31
|
+
"oneOf": [
|
|
32
|
+
{
|
|
33
|
+
"type": "object",
|
|
34
|
+
"additionalProperties": false,
|
|
35
|
+
"required": ["type", "text"],
|
|
36
|
+
"properties": {
|
|
37
|
+
"type": { "const": "text" },
|
|
38
|
+
"text": { "type": "string", "maxLength": 262144 }
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"type": "object",
|
|
43
|
+
"additionalProperties": false,
|
|
44
|
+
"required": ["type", "data", "mimeType"],
|
|
45
|
+
"properties": {
|
|
46
|
+
"type": { "const": "image" },
|
|
47
|
+
"data": { "type": "string", "contentEncoding": "base64" },
|
|
48
|
+
"mimeType": { "type": "string", "pattern": "^[A-Za-z0-9.+-]+/[A-Za-z0-9.+-]+$" }
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
Changes to `@dsh-std/presentation` are recorded here.
|
|
4
|
-
|
|
5
|
-
## 0.1.0 (draft)
|
|
6
|
-
|
|
7
|
-
- Defined invocation-scoped `OpenExternal`, `CopyText`, `Notification`, `UserInteraction`, and `ExternalRedirect` capabilities.
|
|
8
|
-
- Added typed question, approval, secret-input, and one-shot loopback redirect flows.
|
|
9
|
-
- Added optional exact loopback callback URIs with explicit-port validation, no-substitution semantics, and address-in-use failure reporting.
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Changes to `@dsh-std/presentation` are recorded here.
|
|
4
|
+
|
|
5
|
+
## 0.1.0 (draft)
|
|
6
|
+
|
|
7
|
+
- Defined invocation-scoped `OpenExternal`, `CopyText`, `Notification`, `UserInteraction`, and `ExternalRedirect` capabilities.
|
|
8
|
+
- Added typed question, approval, secret-input, and one-shot loopback redirect flows.
|
|
9
|
+
- Added optional exact loopback callback URIs with explicit-port validation, no-substitution semantics, and address-in-use failure reporting.
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 DSH Standard contributors
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DSH Standard contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
# @dsh-std/presentation
|
|
2
|
-
|
|
3
|
-
English | [中文](README.zh.md)
|
|
4
|
-
|
|
5
|
-
Small, invocation-scoped operations that a runtime facet may request from a connected presentation client.
|
|
6
|
-
|
|
7
|
-
## Contracts
|
|
8
|
-
|
|
9
|
-
`v1alpha1` defines five independent presentation protocols:
|
|
10
|
-
|
|
11
|
-
- `OpenExternal` asks the client to open an HTTP or HTTPS URI.
|
|
12
|
-
- `CopyText` asks the client to copy text to its clipboard.
|
|
13
|
-
- `Notification` asks the client to display informational, warning, or error text.
|
|
14
|
-
- `UserInteraction` carries structured questions, one-invocation approvals, and secret input.
|
|
15
|
-
- `ExternalRedirect` receives a one-shot HTTP redirect on the user side and may reserve an exact loopback URI requested by the consumer.
|
|
16
|
-
|
|
17
|
-
A facet declares each required operation in its manifest. A client advertises only the protocols it can perform for the current connection. The runtime admits the command only when all required presentation protocols are available, and it accepts only operations declared by that facet. Operations belong to the active invocation; they are not a global event bus or a persistent client capability.
|
|
18
|
-
|
|
19
|
-
The package provides protocol definitions, invocation-scoped typed client and implementation binders, and request/result validation. The Host binds request identity and origin when it creates a client; consumers supply only operation-specific input. It does not perform UI work. Native applications, terminals, browsers, editors, and automation clients may implement different subsets.
|
|
20
|
-
|
|
21
|
-
Simple operations are available from `@dsh-std/presentation/operations`, while interaction types are available from `@dsh-std/presentation/interaction`. A Host-provided `PresentationDescriptor` is only a projection of active agreements for the current invocation; it is not a separate Snapshot protocol.
|
|
22
|
-
|
|
23
|
-
## Known Limitations and Deferred Work
|
|
24
|
-
|
|
25
|
-
- `OpenExternal` intentionally rejects non-HTTP(S) URI schemes.
|
|
26
|
-
- Clipboard reads, arbitrary UI trees, and file pickers are not defined.
|
|
27
|
-
- Delivery acknowledgement and durable replay are outside `v1alpha1`.
|
|
1
|
+
# @dsh-std/presentation
|
|
2
|
+
|
|
3
|
+
English | [中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
Small, invocation-scoped operations that a runtime facet may request from a connected presentation client.
|
|
6
|
+
|
|
7
|
+
## Contracts
|
|
8
|
+
|
|
9
|
+
`v1alpha1` defines five independent presentation protocols:
|
|
10
|
+
|
|
11
|
+
- `OpenExternal` asks the client to open an HTTP or HTTPS URI.
|
|
12
|
+
- `CopyText` asks the client to copy text to its clipboard.
|
|
13
|
+
- `Notification` asks the client to display informational, warning, or error text.
|
|
14
|
+
- `UserInteraction` carries structured questions, one-invocation approvals, and secret input.
|
|
15
|
+
- `ExternalRedirect` receives a one-shot HTTP redirect on the user side and may reserve an exact loopback URI requested by the consumer.
|
|
16
|
+
|
|
17
|
+
A facet declares each required operation in its manifest. A client advertises only the protocols it can perform for the current connection. The runtime admits the command only when all required presentation protocols are available, and it accepts only operations declared by that facet. Operations belong to the active invocation; they are not a global event bus or a persistent client capability.
|
|
18
|
+
|
|
19
|
+
The package provides protocol definitions, invocation-scoped typed client and implementation binders, and request/result validation. The Host binds request identity and origin when it creates a client; consumers supply only operation-specific input. It does not perform UI work. Native applications, terminals, browsers, editors, and automation clients may implement different subsets.
|
|
20
|
+
|
|
21
|
+
Simple operations are available from `@dsh-std/presentation/operations`, while interaction types are available from `@dsh-std/presentation/interaction`. A Host-provided `PresentationDescriptor` is only a projection of active agreements for the current invocation; it is not a separate Snapshot protocol.
|
|
22
|
+
|
|
23
|
+
## Known Limitations and Deferred Work
|
|
24
|
+
|
|
25
|
+
- `OpenExternal` intentionally rejects non-HTTP(S) URI schemes.
|
|
26
|
+
- Clipboard reads, arbitrary UI trees, and file pickers are not defined.
|
|
27
|
+
- Delivery acknowledgement and durable replay are outside `v1alpha1`.
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
# @dsh-std/presentation
|
|
2
|
-
|
|
3
|
-
[English](README.md) | 中文
|
|
4
|
-
|
|
5
|
-
拟议设计见 [Presentation Operations](../../docs/proposals/presentation.zh.md)。
|
|
6
|
-
|
|
7
|
-
运行时插件可以向已连接表现客户端请求的小型、调用作用域内操作。
|
|
8
|
-
|
|
9
|
-
## 协议
|
|
10
|
-
|
|
11
|
-
`v1alpha1` 定义五个彼此独立的表现协议:
|
|
12
|
-
|
|
13
|
-
- `OpenExternal` 请求客户端打开 HTTP 或 HTTPS URI;
|
|
14
|
-
- `CopyText` 请求客户端把文本复制到剪贴板;
|
|
15
|
-
- `Notification` 请求客户端显示信息、警告或错误文本;
|
|
16
|
-
- `UserInteraction` 承载结构化 question、单次 approval 和 secret input。
|
|
17
|
-
- `ExternalRedirect` 在用户侧接收一次 HTTP redirect,并可按调用方要求独占精确的 loopback URI。
|
|
18
|
-
|
|
19
|
-
Facet 在清单中声明每项所需操作。客户端只为当前连接声明自己能够执行的协议。仅当全部必需表现协议可用时,运行时才接纳命令;运行时也只接受该 facet 事先声明的操作。操作属于当前调用,不是全局事件总线或持久客户端能力。
|
|
20
|
-
|
|
21
|
-
本包提供 protocol definitions、调用作用域内的类型化 client/implementation binder、请求与结果校验。Host 创建 client 时绑定 request identity 与 origin,Consumer 只提交 operation 自有输入。它不执行 UI 工作;原生应用、终端、浏览器、编辑器和自动化客户端可以实现不同子集。
|
|
22
|
-
|
|
23
|
-
普通操作可以从 `@dsh-std/presentation/operations` 导入,交互协议可以从 `@dsh-std/presentation/interaction` 导入。Host 交给领域调用的 `PresentationDescriptor` 只是当前 invocation active agreements 的投影,不是额外的 Snapshot 协议。
|
|
24
|
-
|
|
25
|
-
## 已知限制与暂缓事项
|
|
26
|
-
|
|
27
|
-
- `OpenExternal` 有意拒绝非 HTTP(S) URI scheme。
|
|
28
|
-
- 协议不定义剪贴板读取、任意 UI tree 或文件选择器。
|
|
29
|
-
- `v1alpha1` 不包含投递确认与持久回放。
|
|
1
|
+
# @dsh-std/presentation
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 中文
|
|
4
|
+
|
|
5
|
+
拟议设计见 [Presentation Operations](../../docs/proposals/presentation.zh.md)。
|
|
6
|
+
|
|
7
|
+
运行时插件可以向已连接表现客户端请求的小型、调用作用域内操作。
|
|
8
|
+
|
|
9
|
+
## 协议
|
|
10
|
+
|
|
11
|
+
`v1alpha1` 定义五个彼此独立的表现协议:
|
|
12
|
+
|
|
13
|
+
- `OpenExternal` 请求客户端打开 HTTP 或 HTTPS URI;
|
|
14
|
+
- `CopyText` 请求客户端把文本复制到剪贴板;
|
|
15
|
+
- `Notification` 请求客户端显示信息、警告或错误文本;
|
|
16
|
+
- `UserInteraction` 承载结构化 question、单次 approval 和 secret input。
|
|
17
|
+
- `ExternalRedirect` 在用户侧接收一次 HTTP redirect,并可按调用方要求独占精确的 loopback URI。
|
|
18
|
+
|
|
19
|
+
Facet 在清单中声明每项所需操作。客户端只为当前连接声明自己能够执行的协议。仅当全部必需表现协议可用时,运行时才接纳命令;运行时也只接受该 facet 事先声明的操作。操作属于当前调用,不是全局事件总线或持久客户端能力。
|
|
20
|
+
|
|
21
|
+
本包提供 protocol definitions、调用作用域内的类型化 client/implementation binder、请求与结果校验。Host 创建 client 时绑定 request identity 与 origin,Consumer 只提交 operation 自有输入。它不执行 UI 工作;原生应用、终端、浏览器、编辑器和自动化客户端可以实现不同子集。
|
|
22
|
+
|
|
23
|
+
普通操作可以从 `@dsh-std/presentation/operations` 导入,交互协议可以从 `@dsh-std/presentation/interaction` 导入。Host 交给领域调用的 `PresentationDescriptor` 只是当前 invocation active agreements 的投影,不是额外的 Snapshot 协议。
|
|
24
|
+
|
|
25
|
+
## 已知限制与暂缓事项
|
|
26
|
+
|
|
27
|
+
- `OpenExternal` 有意拒绝非 HTTP(S) URI scheme。
|
|
28
|
+
- 协议不定义剪贴板读取、任意 UI tree 或文件选择器。
|
|
29
|
+
- `v1alpha1` 不包含投递确认与持久回放。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"callback.js","names":[],"sources":["../src/callback.ts"],"sourcesContent":["import type {\n CapabilityClient,\n CapabilityHandlerContext,\n CapabilityImplementation,\n} from '@dsh-std/connection'\nimport { defineCapabilityProtocol } from '@dsh-std/connection'\nimport type { ProtocolSupport } from '@dsh-std/core'\nimport type { PresentationInvocationScope, PresentationRequestContext, PresentationResult } from './index.js'\n\nexport const EXTERNAL_REDIRECT_KIND = 'ExternalRedirect'\n\nexport interface ExternalRedirectRequest extends PresentationRequestContext {\n readonly mode: 'http-get'\n /** Exact loopback URI required by the external provider, including an explicit port. */\n readonly exactRedirectUri?: string\n}\nexport interface ExternalRedirectInput {\n readonly mode?: 'http-get'\n /** The provider must bind and announce this exact URI or report the request unavailable. */\n readonly exactRedirectUri?: string\n}\n\nexport interface ExternalRedirectReady {\n readonly type: 'ready'\n readonly redirectUri: string\n readonly expiresAt?: string\n}\n\nexport interface ExternalRedirectValue {\n readonly query: Readonly<Record<string, readonly string[]>>\n}\n\nexport interface ExternalRedirectCall {\n readonly invocationId: string\n readonly ready: Promise<ExternalRedirectReady>\n readonly result: Promise<PresentationResult<ExternalRedirectValue>>\n cancel(reason?: string): void\n}\n\nexport interface ExternalRedirectClient {\n receive(input?: ExternalRedirectInput, options?: { readonly signal?: AbortSignal }): ExternalRedirectCall\n}\n\nexport interface ExternalRedirectHandler {\n receive(\n request: ExternalRedirectRequest,\n context: CapabilityHandlerContext<ExternalRedirectReady>,\n ): PresentationResult<ExternalRedirectValue> | Promise<PresentationResult<ExternalRedirectValue>>\n}\n\nconst emptySpec = (value: unknown): undefined => {\n if (value !== undefined) throw new TypeError('ExternalRedirect does not accept spec in v1alpha1')\n return undefined\n}\n\nexport const externalRedirectProtocol = defineCapabilityProtocol({\n apiVersion: 'presentation.dsh/v1alpha1', kind: EXTERNAL_REDIRECT_KIND,\n validateRequirement: emptySpec, validateSupport: emptySpec,\n})\nexport const externalRedirectSupport: ProtocolSupport = Object.freeze({\n apiVersion: 'presentation.dsh/v1alpha1', kind: EXTERNAL_REDIRECT_KIND,\n})\n\nexport function externalRedirectClient(client: CapabilityClient, scope: PresentationInvocationScope): ExternalRedirectClient {\n validateScope(scope)\n return Object.freeze({\n receive(input: ExternalRedirectInput = {}, options?: { readonly signal?: AbortSignal }) {\n const request = Object.freeze({\n ...input,\n mode: input.mode ?? 'http-get',\n requestId: nextRequestId(scope), invocationId: scope.invocationId, origin: scope.origin,\n ...(scope.deadline === undefined ? {} : { deadline: scope.deadline }),\n })\n validateExternalRedirectRequest(request)\n const call = client.invoke<ExternalRedirectRequest, PresentationResult<ExternalRedirectValue>, ExternalRedirectReady>(\n externalRedirectSupport, 'receive', request, options,\n )\n return Object.freeze({\n invocationId: call.invocationId,\n ready: firstReady(call.progress),\n result: call.result.then(validateExternalRedirectResult),\n cancel: (reason?: string) => call.cancel(reason),\n })\n },\n })\n}\n\nexport function externalRedirectImplementation(\n participantId: string,\n handler: ExternalRedirectHandler,\n): CapabilityImplementation<ExternalRedirectRequest, PresentationResult<ExternalRedirectValue>, ExternalRedirectReady> {\n return Object.freeze({\n participantId, protocol: externalRedirectSupport,\n async handle(operation: string, input: ExternalRedirectRequest, context: CapabilityHandlerContext<ExternalRedirectReady>) {\n if (operation !== 'receive') throw new TypeError(`unsupported ExternalRedirect operation ${JSON.stringify(operation)}`)\n validateExternalRedirectRequest(input)\n let announced = false\n const guardedContext: CapabilityHandlerContext<ExternalRedirectReady> = Object.freeze({\n ...context,\n progress(value: ExternalRedirectReady) {\n if (announced) throw new TypeError('ExternalRedirect provider emitted more than one ready event')\n validateExternalRedirectReady(value)\n if (input.exactRedirectUri !== undefined && value.redirectUri !== input.exactRedirectUri) {\n throw new TypeError('ExternalRedirect provider did not announce the exact requested redirect URI')\n }\n announced = true\n context.progress(value)\n },\n })\n const result = validateExternalRedirectResult(await handler.receive(input, guardedContext))\n if (result.status === 'submitted' && !announced) {\n throw new TypeError('ExternalRedirect provider submitted a result before announcing redirectUri')\n }\n return result\n },\n })\n}\n\nexport function validateExternalRedirectRequest(value: unknown): asserts value is ExternalRedirectRequest {\n const request = exactRecord(value, ['requestId', 'invocationId', 'origin', 'deadline', 'mode', 'exactRedirectUri'], ['requestId', 'invocationId', 'origin', 'mode'], 'ExternalRedirect request')\n nonEmpty(request.requestId, 'ExternalRedirect request.requestId')\n nonEmpty(request.invocationId, 'ExternalRedirect request.invocationId')\n nonEmpty(request.origin, 'ExternalRedirect request.origin')\n if (request.mode !== 'http-get') throw new TypeError('ExternalRedirect request.mode must be \"http-get\"')\n if (request.exactRedirectUri !== undefined) validateLoopbackUri(request.exactRedirectUri, 'ExternalRedirect request.exactRedirectUri', true)\n dateTime(request.deadline, 'ExternalRedirect request.deadline')\n}\n\nexport function validateExternalRedirectReady(value: unknown): asserts value is ExternalRedirectReady {\n const ready = exactRecord(value, ['type', 'redirectUri', 'expiresAt'], ['type', 'redirectUri'], 'ExternalRedirect ready')\n if (ready.type !== 'ready') throw new TypeError('ExternalRedirect ready.type must be \"ready\"')\n validateLoopbackUri(ready.redirectUri, 'ExternalRedirect ready.redirectUri', false)\n dateTime(ready.expiresAt, 'ExternalRedirect ready.expiresAt')\n}\n\nexport function validateExternalRedirectResult(value: unknown): PresentationResult<ExternalRedirectValue> {\n if (!record(value)) throw new TypeError('ExternalRedirect result must be an object')\n if (value.status === 'submitted') {\n const result = exactRecord(value, ['status', 'value'], ['status', 'value'], 'ExternalRedirect result')\n const submitted = exactRecord(result.value, ['query'], ['query'], 'ExternalRedirect value')\n if (!record(submitted.query)) throw new TypeError('ExternalRedirect value.query must be an object')\n const query: Record<string, readonly string[]> = {}\n for (const [name, entries] of Object.entries(submitted.query)) {\n if (name === '' || !Array.isArray(entries) || entries.some(entry => typeof entry !== 'string')) {\n throw new TypeError('ExternalRedirect value.query must map non-empty names to string arrays')\n }\n query[name] = Object.freeze([...entries])\n }\n return Object.freeze({ status: 'submitted', value: Object.freeze({ query: Object.freeze(query) }) })\n }\n if (value.status === 'unavailable') {\n const result = exactRecord(value, ['status', 'reason'], ['status'], 'ExternalRedirect result')\n if (result.reason !== undefined) nonEmpty(result.reason, 'ExternalRedirect result.reason')\n return Object.freeze({ status: 'unavailable', ...(result.reason === undefined ? {} : { reason: result.reason as string }) })\n }\n if (value.status === 'cancelled' || value.status === 'expired') {\n exactRecord(value, ['status'], ['status'], 'ExternalRedirect result')\n return Object.freeze({ status: value.status })\n }\n throw new TypeError('ExternalRedirect result.status is invalid')\n}\n\nasync function firstReady(progress: AsyncIterable<ExternalRedirectReady>): Promise<ExternalRedirectReady> {\n for await (const value of progress) {\n validateExternalRedirectReady(value)\n return Object.freeze({ ...value })\n }\n throw new TypeError('ExternalRedirect provider completed without announcing redirectUri')\n}\n\nfunction validateScope(scope: PresentationInvocationScope): void {\n if (!record(scope)) throw new TypeError('Presentation invocation scope must be an object')\n nonEmpty(scope.invocationId, 'Presentation invocation scope.invocationId')\n nonEmpty(scope.origin, 'Presentation invocation scope.origin')\n dateTime(scope.deadline, 'Presentation invocation scope.deadline')\n if (typeof scope.nextRequestId !== 'function') throw new TypeError('Presentation invocation scope.nextRequestId must be a function')\n}\n\nfunction nextRequestId(scope: PresentationInvocationScope): string {\n const value = scope.nextRequestId()\n nonEmpty(value, 'Presentation requestId')\n return value\n}\n\nfunction exactRecord(value: unknown, allowed: readonly string[], required: readonly string[], label: string): Record<string, unknown> {\n if (!record(value)) throw new TypeError(`${label} must be an object`)\n const unknown = Object.keys(value).filter(key => !allowed.includes(key))\n if (unknown.length > 0) throw new TypeError(`${label} contains unknown field ${JSON.stringify(unknown[0])}`)\n for (const key of required) if (!Object.hasOwn(value, key)) throw new TypeError(`${label}.${key} is required`)\n return value\n}\nfunction record(value: unknown): value is Record<string, unknown> { return typeof value === 'object' && value !== null && !Array.isArray(value) }\nfunction nonEmpty(value: unknown, label: string): asserts value is string {\n if (typeof value !== 'string' || value.trim() === '') throw new TypeError(`${label} must be a non-empty string`)\n}\nfunction dateTime(value: unknown, label: string): void {\n if (value !== undefined && (typeof value !== 'string' || Number.isNaN(Date.parse(value)))) throw new TypeError(`${label} must be an RFC 3339 date-time`)\n}\n\nfunction validateLoopbackUri(value: unknown, label: string, requireExplicitPort: boolean): asserts value is string {\n nonEmpty(value, label)\n let uri: URL\n try {\n uri = new URL(value)\n } catch {\n throw new TypeError(`${label} must be an absolute URI`)\n }\n if (uri.protocol !== 'http:') throw new TypeError(`${label} must use HTTP`)\n if (uri.hostname !== '127.0.0.1' && uri.hostname !== '[::1]' && uri.hostname !== 'localhost') {\n throw new TypeError(`${label} must target a loopback host`)\n }\n if (uri.username !== '' || uri.password !== '') throw new TypeError(`${label} must not contain user information`)\n if (uri.hash !== '') throw new TypeError(`${label} must not contain a fragment`)\n if (requireExplicitPort) {\n const authority = value.slice(value.indexOf('//') + 2).split(/[/?#]/u, 1)[0]!\n const match = /^(?:127\\.0\\.0\\.1|localhost):(\\d+)$|^\\[::1\\]:(\\d+)$/iu.exec(authority)\n const port = Number(match?.[1] ?? match?.[2])\n if (!Number.isSafeInteger(port) || port < 1 || port > 65_535) {\n throw new TypeError(`${label} must include an explicit TCP port`)\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"callback.js","names":[],"sources":["../src/callback.ts"],"sourcesContent":["import type {\r\n CapabilityClient,\r\n CapabilityHandlerContext,\r\n CapabilityImplementation,\r\n} from '@dsh-std/connection'\r\nimport { defineCapabilityProtocol } from '@dsh-std/connection'\r\nimport type { ProtocolSupport } from '@dsh-std/core'\r\nimport type { PresentationInvocationScope, PresentationRequestContext, PresentationResult } from './index.js'\r\n\r\nexport const EXTERNAL_REDIRECT_KIND = 'ExternalRedirect'\r\n\r\nexport interface ExternalRedirectRequest extends PresentationRequestContext {\r\n readonly mode: 'http-get'\r\n /** Exact loopback URI required by the external provider, including an explicit port. */\r\n readonly exactRedirectUri?: string\r\n}\r\nexport interface ExternalRedirectInput {\r\n readonly mode?: 'http-get'\r\n /** The provider must bind and announce this exact URI or report the request unavailable. */\r\n readonly exactRedirectUri?: string\r\n}\r\n\r\nexport interface ExternalRedirectReady {\r\n readonly type: 'ready'\r\n readonly redirectUri: string\r\n readonly expiresAt?: string\r\n}\r\n\r\nexport interface ExternalRedirectValue {\r\n readonly query: Readonly<Record<string, readonly string[]>>\r\n}\r\n\r\nexport interface ExternalRedirectCall {\r\n readonly invocationId: string\r\n readonly ready: Promise<ExternalRedirectReady>\r\n readonly result: Promise<PresentationResult<ExternalRedirectValue>>\r\n cancel(reason?: string): void\r\n}\r\n\r\nexport interface ExternalRedirectClient {\r\n receive(input?: ExternalRedirectInput, options?: { readonly signal?: AbortSignal }): ExternalRedirectCall\r\n}\r\n\r\nexport interface ExternalRedirectHandler {\r\n receive(\r\n request: ExternalRedirectRequest,\r\n context: CapabilityHandlerContext<ExternalRedirectReady>,\r\n ): PresentationResult<ExternalRedirectValue> | Promise<PresentationResult<ExternalRedirectValue>>\r\n}\r\n\r\nconst emptySpec = (value: unknown): undefined => {\r\n if (value !== undefined) throw new TypeError('ExternalRedirect does not accept spec in v1alpha1')\r\n return undefined\r\n}\r\n\r\nexport const externalRedirectProtocol = defineCapabilityProtocol({\r\n apiVersion: 'presentation.dsh/v1alpha1', kind: EXTERNAL_REDIRECT_KIND,\r\n validateRequirement: emptySpec, validateSupport: emptySpec,\r\n})\r\nexport const externalRedirectSupport: ProtocolSupport = Object.freeze({\r\n apiVersion: 'presentation.dsh/v1alpha1', kind: EXTERNAL_REDIRECT_KIND,\r\n})\r\n\r\nexport function externalRedirectClient(client: CapabilityClient, scope: PresentationInvocationScope): ExternalRedirectClient {\r\n validateScope(scope)\r\n return Object.freeze({\r\n receive(input: ExternalRedirectInput = {}, options?: { readonly signal?: AbortSignal }) {\r\n const request = Object.freeze({\r\n ...input,\r\n mode: input.mode ?? 'http-get',\r\n requestId: nextRequestId(scope), invocationId: scope.invocationId, origin: scope.origin,\r\n ...(scope.deadline === undefined ? {} : { deadline: scope.deadline }),\r\n })\r\n validateExternalRedirectRequest(request)\r\n const call = client.invoke<ExternalRedirectRequest, PresentationResult<ExternalRedirectValue>, ExternalRedirectReady>(\r\n externalRedirectSupport, 'receive', request, options,\r\n )\r\n return Object.freeze({\r\n invocationId: call.invocationId,\r\n ready: firstReady(call.progress),\r\n result: call.result.then(validateExternalRedirectResult),\r\n cancel: (reason?: string) => call.cancel(reason),\r\n })\r\n },\r\n })\r\n}\r\n\r\nexport function externalRedirectImplementation(\r\n participantId: string,\r\n handler: ExternalRedirectHandler,\r\n): CapabilityImplementation<ExternalRedirectRequest, PresentationResult<ExternalRedirectValue>, ExternalRedirectReady> {\r\n return Object.freeze({\r\n participantId, protocol: externalRedirectSupport,\r\n async handle(operation: string, input: ExternalRedirectRequest, context: CapabilityHandlerContext<ExternalRedirectReady>) {\r\n if (operation !== 'receive') throw new TypeError(`unsupported ExternalRedirect operation ${JSON.stringify(operation)}`)\r\n validateExternalRedirectRequest(input)\r\n let announced = false\r\n const guardedContext: CapabilityHandlerContext<ExternalRedirectReady> = Object.freeze({\r\n ...context,\r\n progress(value: ExternalRedirectReady) {\r\n if (announced) throw new TypeError('ExternalRedirect provider emitted more than one ready event')\r\n validateExternalRedirectReady(value)\r\n if (input.exactRedirectUri !== undefined && value.redirectUri !== input.exactRedirectUri) {\r\n throw new TypeError('ExternalRedirect provider did not announce the exact requested redirect URI')\r\n }\r\n announced = true\r\n context.progress(value)\r\n },\r\n })\r\n const result = validateExternalRedirectResult(await handler.receive(input, guardedContext))\r\n if (result.status === 'submitted' && !announced) {\r\n throw new TypeError('ExternalRedirect provider submitted a result before announcing redirectUri')\r\n }\r\n return result\r\n },\r\n })\r\n}\r\n\r\nexport function validateExternalRedirectRequest(value: unknown): asserts value is ExternalRedirectRequest {\r\n const request = exactRecord(value, ['requestId', 'invocationId', 'origin', 'deadline', 'mode', 'exactRedirectUri'], ['requestId', 'invocationId', 'origin', 'mode'], 'ExternalRedirect request')\r\n nonEmpty(request.requestId, 'ExternalRedirect request.requestId')\r\n nonEmpty(request.invocationId, 'ExternalRedirect request.invocationId')\r\n nonEmpty(request.origin, 'ExternalRedirect request.origin')\r\n if (request.mode !== 'http-get') throw new TypeError('ExternalRedirect request.mode must be \"http-get\"')\r\n if (request.exactRedirectUri !== undefined) validateLoopbackUri(request.exactRedirectUri, 'ExternalRedirect request.exactRedirectUri', true)\r\n dateTime(request.deadline, 'ExternalRedirect request.deadline')\r\n}\r\n\r\nexport function validateExternalRedirectReady(value: unknown): asserts value is ExternalRedirectReady {\r\n const ready = exactRecord(value, ['type', 'redirectUri', 'expiresAt'], ['type', 'redirectUri'], 'ExternalRedirect ready')\r\n if (ready.type !== 'ready') throw new TypeError('ExternalRedirect ready.type must be \"ready\"')\r\n validateLoopbackUri(ready.redirectUri, 'ExternalRedirect ready.redirectUri', false)\r\n dateTime(ready.expiresAt, 'ExternalRedirect ready.expiresAt')\r\n}\r\n\r\nexport function validateExternalRedirectResult(value: unknown): PresentationResult<ExternalRedirectValue> {\r\n if (!record(value)) throw new TypeError('ExternalRedirect result must be an object')\r\n if (value.status === 'submitted') {\r\n const result = exactRecord(value, ['status', 'value'], ['status', 'value'], 'ExternalRedirect result')\r\n const submitted = exactRecord(result.value, ['query'], ['query'], 'ExternalRedirect value')\r\n if (!record(submitted.query)) throw new TypeError('ExternalRedirect value.query must be an object')\r\n const query: Record<string, readonly string[]> = {}\r\n for (const [name, entries] of Object.entries(submitted.query)) {\r\n if (name === '' || !Array.isArray(entries) || entries.some(entry => typeof entry !== 'string')) {\r\n throw new TypeError('ExternalRedirect value.query must map non-empty names to string arrays')\r\n }\r\n query[name] = Object.freeze([...entries])\r\n }\r\n return Object.freeze({ status: 'submitted', value: Object.freeze({ query: Object.freeze(query) }) })\r\n }\r\n if (value.status === 'unavailable') {\r\n const result = exactRecord(value, ['status', 'reason'], ['status'], 'ExternalRedirect result')\r\n if (result.reason !== undefined) nonEmpty(result.reason, 'ExternalRedirect result.reason')\r\n return Object.freeze({ status: 'unavailable', ...(result.reason === undefined ? {} : { reason: result.reason as string }) })\r\n }\r\n if (value.status === 'cancelled' || value.status === 'expired') {\r\n exactRecord(value, ['status'], ['status'], 'ExternalRedirect result')\r\n return Object.freeze({ status: value.status })\r\n }\r\n throw new TypeError('ExternalRedirect result.status is invalid')\r\n}\r\n\r\nasync function firstReady(progress: AsyncIterable<ExternalRedirectReady>): Promise<ExternalRedirectReady> {\r\n for await (const value of progress) {\r\n validateExternalRedirectReady(value)\r\n return Object.freeze({ ...value })\r\n }\r\n throw new TypeError('ExternalRedirect provider completed without announcing redirectUri')\r\n}\r\n\r\nfunction validateScope(scope: PresentationInvocationScope): void {\r\n if (!record(scope)) throw new TypeError('Presentation invocation scope must be an object')\r\n nonEmpty(scope.invocationId, 'Presentation invocation scope.invocationId')\r\n nonEmpty(scope.origin, 'Presentation invocation scope.origin')\r\n dateTime(scope.deadline, 'Presentation invocation scope.deadline')\r\n if (typeof scope.nextRequestId !== 'function') throw new TypeError('Presentation invocation scope.nextRequestId must be a function')\r\n}\r\n\r\nfunction nextRequestId(scope: PresentationInvocationScope): string {\r\n const value = scope.nextRequestId()\r\n nonEmpty(value, 'Presentation requestId')\r\n return value\r\n}\r\n\r\nfunction exactRecord(value: unknown, allowed: readonly string[], required: readonly string[], label: string): Record<string, unknown> {\r\n if (!record(value)) throw new TypeError(`${label} must be an object`)\r\n const unknown = Object.keys(value).filter(key => !allowed.includes(key))\r\n if (unknown.length > 0) throw new TypeError(`${label} contains unknown field ${JSON.stringify(unknown[0])}`)\r\n for (const key of required) if (!Object.hasOwn(value, key)) throw new TypeError(`${label}.${key} is required`)\r\n return value\r\n}\r\nfunction record(value: unknown): value is Record<string, unknown> { return typeof value === 'object' && value !== null && !Array.isArray(value) }\r\nfunction nonEmpty(value: unknown, label: string): asserts value is string {\r\n if (typeof value !== 'string' || value.trim() === '') throw new TypeError(`${label} must be a non-empty string`)\r\n}\r\nfunction dateTime(value: unknown, label: string): void {\r\n if (value !== undefined && (typeof value !== 'string' || Number.isNaN(Date.parse(value)))) throw new TypeError(`${label} must be an RFC 3339 date-time`)\r\n}\r\n\r\nfunction validateLoopbackUri(value: unknown, label: string, requireExplicitPort: boolean): asserts value is string {\r\n nonEmpty(value, label)\r\n let uri: URL\r\n try {\r\n uri = new URL(value)\r\n } catch {\r\n throw new TypeError(`${label} must be an absolute URI`)\r\n }\r\n if (uri.protocol !== 'http:') throw new TypeError(`${label} must use HTTP`)\r\n if (uri.hostname !== '127.0.0.1' && uri.hostname !== '[::1]' && uri.hostname !== 'localhost') {\r\n throw new TypeError(`${label} must target a loopback host`)\r\n }\r\n if (uri.username !== '' || uri.password !== '') throw new TypeError(`${label} must not contain user information`)\r\n if (uri.hash !== '') throw new TypeError(`${label} must not contain a fragment`)\r\n if (requireExplicitPort) {\r\n const authority = value.slice(value.indexOf('//') + 2).split(/[/?#]/u, 1)[0]!\r\n const match = /^(?:127\\.0\\.0\\.1|localhost):(\\d+)$|^\\[::1\\]:(\\d+)$/iu.exec(authority)\r\n const port = Number(match?.[1] ?? match?.[2])\r\n if (!Number.isSafeInteger(port) || port < 1 || port > 65_535) {\r\n throw new TypeError(`${label} must include an explicit TCP port`)\r\n }\r\n }\r\n}\r\n"],"mappings":"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"}
|