@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,42 +1,42 @@
|
|
|
1
|
-
# @dsh-std/connection
|
|
2
|
-
|
|
3
|
-
English | [中文](README.zh.md)
|
|
4
|
-
|
|
5
|
-
The proposed design is documented in [Endpoint Connection](../../docs/proposals/endpoint-connection.zh.md). It separates the application-facing `ConnectionService` from the Connection Host provider SPI. The remainder of this page describes the current reference implementation, which does not yet complete that split.
|
|
6
|
-
|
|
7
|
-
Host-provided communication service, two-endpoint capability negotiation, and implementation-neutral invocation for the DSH Standard.
|
|
8
|
-
|
|
9
|
-
## Endpoint offers
|
|
10
|
-
|
|
11
|
-
An endpoint offer contains an endpoint identity, a revision, and the live participant declarations admitted by endpoint policy. It carries no component manifests, installation inventory, or plugin registry.
|
|
12
|
-
|
|
13
|
-
`resolveConnection()` passes both sets of declarations to a caller-owned `ProtocolCatalog`. Each protocol definition owns its negotiation and may place invocation bindings in its agreement; connection does not impose consumer/provider semantics on every protocol. `defineCapabilityProtocol()` is an explicit helper for domain protocols that do use RPC-shaped bindings.
|
|
14
|
-
|
|
15
|
-
Each invocation binding is participant-scoped and plan-revision-scoped. A client for one participant cannot discover or invoke bindings granted to another participant.
|
|
16
|
-
|
|
17
|
-
## Current reference API
|
|
18
|
-
|
|
19
|
-
`StandardConnection` exposes endpoint identities, the active plan, consumer-scoped clients, plan-change observation, and close. `CapabilityClient.invoke()` returns an invocation id, a result promise, an asynchronous progress stream, and cancellation. Domain protocol packages own operation names and input, output, and progress values.
|
|
20
|
-
|
|
21
|
-
`ConnectionBroker` selects one registered `ConnectionConnector` for an implementation-neutral target URI. Zero matches and multiple matches are both explicit errors. The broker does not expose the selected connector type through `StandardConnection`.
|
|
22
|
-
|
|
23
|
-
These types are an early reference implementation. They do not require a TUI, Web UI, GUI, or business plugin to register and operate its own connector. The protocol direction places the broker, connector/provider registry, carrier, and wire behind a Connection Host's `ConnectionService`. A consumer submits a target and uses scoped typed clients for the negotiated protocols.
|
|
24
|
-
|
|
25
|
-
A Connection Host may install or discover a remote service, own authentication, ports, forwarding and reconnection, and produce the `StandardConnection`. An SSH target facet contributes resolution and bootstrap integration while system OpenSSH or another provider may supply the physical SSH implementation. Applications do not observe the selected provider, ports, credentials, or wire.
|
|
26
|
-
|
|
27
|
-
## Lifecycle
|
|
28
|
-
|
|
29
|
-
Renegotiation creates a complete new plan revision and publishes it atomically. An invocation admitted under the old revision retains its binding until settlement; later invocations use the new revision. Closing a connection cancels active work and rejects new work with `connection-closed`.
|
|
30
|
-
|
|
31
|
-
Transport implementations must preserve invocation isolation, progress order, cancellation, and the error classification exposed by `ConnectionInvocationError`. They are also responsible for authenticating the peer and preventing one connection from reusing another connection's grants.
|
|
32
|
-
|
|
33
|
-
## Reference implementation
|
|
34
|
-
|
|
35
|
-
The `@dsh-std/connection/memory` export provides a process-local implementation for tests, adapters, and conformance experiments. It demonstrates symmetric calls, progress, cancellation, isolation, and renegotiation. It is not a required carrier or a wire-format specification.
|
|
36
|
-
|
|
37
|
-
## Known Limitations and Deferred Work
|
|
38
|
-
|
|
39
|
-
- The consumer-facing `ConnectionService` and Host provider SPI are not implemented in the current code yet.
|
|
40
|
-
- The package does not yet standardize discovery, authentication, encryption, reconnect policy, framing, or serialization.
|
|
41
|
-
- A connection has exactly two endpoints in `v1alpha1`; multi-party routing is composed from separate connections.
|
|
42
|
-
- The capability helper requires one peer provider by default. Protocols that allow multiple providers must opt into and define that behavior explicitly.
|
|
1
|
+
# @dsh-std/connection
|
|
2
|
+
|
|
3
|
+
English | [中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
The proposed design is documented in [Endpoint Connection](../../docs/proposals/endpoint-connection.zh.md). It separates the application-facing `ConnectionService` from the Connection Host provider SPI. The remainder of this page describes the current reference implementation, which does not yet complete that split.
|
|
6
|
+
|
|
7
|
+
Host-provided communication service, two-endpoint capability negotiation, and implementation-neutral invocation for the DSH Standard.
|
|
8
|
+
|
|
9
|
+
## Endpoint offers
|
|
10
|
+
|
|
11
|
+
An endpoint offer contains an endpoint identity, a revision, and the live participant declarations admitted by endpoint policy. It carries no component manifests, installation inventory, or plugin registry.
|
|
12
|
+
|
|
13
|
+
`resolveConnection()` passes both sets of declarations to a caller-owned `ProtocolCatalog`. Each protocol definition owns its negotiation and may place invocation bindings in its agreement; connection does not impose consumer/provider semantics on every protocol. `defineCapabilityProtocol()` is an explicit helper for domain protocols that do use RPC-shaped bindings.
|
|
14
|
+
|
|
15
|
+
Each invocation binding is participant-scoped and plan-revision-scoped. A client for one participant cannot discover or invoke bindings granted to another participant.
|
|
16
|
+
|
|
17
|
+
## Current reference API
|
|
18
|
+
|
|
19
|
+
`StandardConnection` exposes endpoint identities, the active plan, consumer-scoped clients, plan-change observation, and close. `CapabilityClient.invoke()` returns an invocation id, a result promise, an asynchronous progress stream, and cancellation. Domain protocol packages own operation names and input, output, and progress values.
|
|
20
|
+
|
|
21
|
+
`ConnectionBroker` selects one registered `ConnectionConnector` for an implementation-neutral target URI. Zero matches and multiple matches are both explicit errors. The broker does not expose the selected connector type through `StandardConnection`.
|
|
22
|
+
|
|
23
|
+
These types are an early reference implementation. They do not require a TUI, Web UI, GUI, or business plugin to register and operate its own connector. The protocol direction places the broker, connector/provider registry, carrier, and wire behind a Connection Host's `ConnectionService`. A consumer submits a target and uses scoped typed clients for the negotiated protocols.
|
|
24
|
+
|
|
25
|
+
A Connection Host may install or discover a remote service, own authentication, ports, forwarding and reconnection, and produce the `StandardConnection`. An SSH target facet contributes resolution and bootstrap integration while system OpenSSH or another provider may supply the physical SSH implementation. Applications do not observe the selected provider, ports, credentials, or wire.
|
|
26
|
+
|
|
27
|
+
## Lifecycle
|
|
28
|
+
|
|
29
|
+
Renegotiation creates a complete new plan revision and publishes it atomically. An invocation admitted under the old revision retains its binding until settlement; later invocations use the new revision. Closing a connection cancels active work and rejects new work with `connection-closed`.
|
|
30
|
+
|
|
31
|
+
Transport implementations must preserve invocation isolation, progress order, cancellation, and the error classification exposed by `ConnectionInvocationError`. They are also responsible for authenticating the peer and preventing one connection from reusing another connection's grants.
|
|
32
|
+
|
|
33
|
+
## Reference implementation
|
|
34
|
+
|
|
35
|
+
The `@dsh-std/connection/memory` export provides a process-local implementation for tests, adapters, and conformance experiments. It demonstrates symmetric calls, progress, cancellation, isolation, and renegotiation. It is not a required carrier or a wire-format specification.
|
|
36
|
+
|
|
37
|
+
## Known Limitations and Deferred Work
|
|
38
|
+
|
|
39
|
+
- The consumer-facing `ConnectionService` and Host provider SPI are not implemented in the current code yet.
|
|
40
|
+
- The package does not yet standardize discovery, authentication, encryption, reconnect policy, framing, or serialization.
|
|
41
|
+
- A connection has exactly two endpoints in `v1alpha1`; multi-party routing is composed from separate connections.
|
|
42
|
+
- The capability helper requires one peer provider by default. Protocols that allow multiple providers must opt into and define that behavior explicitly.
|
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
# @dsh-std/connection
|
|
2
|
-
|
|
3
|
-
[English](README.md) | 中文
|
|
4
|
-
|
|
5
|
-
拟议设计见 [Endpoint Connection](../../docs/proposals/endpoint-connection.zh.md)。规范把普通应用使用的 `ConnectionService` 与 Connection Host 的 provider SPI 分开;本页其余内容描述尚未完成该分层的当前参考实现。
|
|
6
|
-
|
|
7
|
-
DSH Standard 的宿主通信 service、双端点能力协商与实现无关调用。
|
|
8
|
-
|
|
9
|
-
## 端点提议
|
|
10
|
-
|
|
11
|
-
端点提议包含端点身份、修订号,以及经端点 policy 裁剪后的 live participant declarations。它不携带 component manifests、安装记录或插件注册表。
|
|
12
|
-
|
|
13
|
-
`resolveConnection()` 把两端 declarations 交给调用方提供的 `ProtocolCatalog`。每份协议 definition 决定如何协商,并可在 agreement 中产生调用绑定;connection 不为所有协议预设 consumer/provider 语义。内置的 `defineCapabilityProtocol()` 是需要 RPC 绑定的领域协议可显式采用的辅助定义。
|
|
14
|
-
|
|
15
|
-
每项调用绑定都限定于消费 participant 和方案修订版。一个 participant 的客户端不能发现或调用授予另一 participant 的绑定。
|
|
16
|
-
|
|
17
|
-
## 当前参考 API
|
|
18
|
-
|
|
19
|
-
`StandardConnection` 暴露端点身份、当前方案、按消费方隔离的客户端、方案变更观察与关闭操作。`CapabilityClient.invoke()` 返回调用 id、结果 Promise、异步进度流与取消操作。领域协议包拥有操作名称以及输入、输出和进度值的语义。
|
|
20
|
-
|
|
21
|
-
`ConnectionBroker` 根据与实现无关的目标 URI,从已注册 `ConnectionConnector` 中选择唯一实现。零个匹配与多个匹配都是明确错误。broker 不会通过 `StandardConnection` 暴露选中的 connector 类型。
|
|
22
|
-
|
|
23
|
-
这些类型是早期参考实现,不表示 TUI、Web、GUI 或业务插件应自行注册 connector。规范方向是由 Connection Host 把 broker、connector/provider、carrier 和 wire 封装为 `ConnectionService`;consumer 只提交 target,并通过 scoped typed client 使用已协商协议。
|
|
24
|
-
|
|
25
|
-
Connection Host 负责安装或发现远端服务、认证、端口与转发、重连和 `StandardConnection`。SSH target facet 可以贡献解析与 bootstrap 集成,物理 SSH 则可由系统 OpenSSH 或独立 provider 完成。应用不会看到所选 provider、端口、凭据或 wire。
|
|
26
|
-
|
|
27
|
-
## 生命周期
|
|
28
|
-
|
|
29
|
-
重新协商会生成完整的新方案修订版,并原子发布。旧修订版已经接纳的调用保留其绑定直至结束;后续调用使用新修订版。关闭连接会取消活跃工作,并以 `connection-closed` 拒绝新工作。
|
|
30
|
-
|
|
31
|
-
传输实现必须保持调用隔离、进度顺序、取消语义和 `ConnectionInvocationError` 暴露的错误分类。实现还负责认证对端,并阻止一条连接复用另一条连接的授权。
|
|
32
|
-
|
|
33
|
-
## 参考实现
|
|
34
|
-
|
|
35
|
-
`@dsh-std/connection/memory` 导出用于测试、适配器和一致性实验的进程内实现。它演示双向调用、进度、取消、隔离和重新协商,但不是强制承载方式或线协议规范。
|
|
36
|
-
|
|
37
|
-
## 已知限制与暂缓事项
|
|
38
|
-
|
|
39
|
-
- consumer-facing `ConnectionService` 与 Host provider SPI 尚未在当前代码中实现。
|
|
40
|
-
- 本包尚未标准化发现、认证、加密、重连策略、封帧或序列化。
|
|
41
|
-
- `v1alpha1` 的一条连接恰好包含两个端点;多方路由由多条独立连接组合。
|
|
42
|
-
- Capability helper 默认要求唯一对端提供方;需要多提供方的协议必须明确选择其规则。
|
|
1
|
+
# @dsh-std/connection
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 中文
|
|
4
|
+
|
|
5
|
+
拟议设计见 [Endpoint Connection](../../docs/proposals/endpoint-connection.zh.md)。规范把普通应用使用的 `ConnectionService` 与 Connection Host 的 provider SPI 分开;本页其余内容描述尚未完成该分层的当前参考实现。
|
|
6
|
+
|
|
7
|
+
DSH Standard 的宿主通信 service、双端点能力协商与实现无关调用。
|
|
8
|
+
|
|
9
|
+
## 端点提议
|
|
10
|
+
|
|
11
|
+
端点提议包含端点身份、修订号,以及经端点 policy 裁剪后的 live participant declarations。它不携带 component manifests、安装记录或插件注册表。
|
|
12
|
+
|
|
13
|
+
`resolveConnection()` 把两端 declarations 交给调用方提供的 `ProtocolCatalog`。每份协议 definition 决定如何协商,并可在 agreement 中产生调用绑定;connection 不为所有协议预设 consumer/provider 语义。内置的 `defineCapabilityProtocol()` 是需要 RPC 绑定的领域协议可显式采用的辅助定义。
|
|
14
|
+
|
|
15
|
+
每项调用绑定都限定于消费 participant 和方案修订版。一个 participant 的客户端不能发现或调用授予另一 participant 的绑定。
|
|
16
|
+
|
|
17
|
+
## 当前参考 API
|
|
18
|
+
|
|
19
|
+
`StandardConnection` 暴露端点身份、当前方案、按消费方隔离的客户端、方案变更观察与关闭操作。`CapabilityClient.invoke()` 返回调用 id、结果 Promise、异步进度流与取消操作。领域协议包拥有操作名称以及输入、输出和进度值的语义。
|
|
20
|
+
|
|
21
|
+
`ConnectionBroker` 根据与实现无关的目标 URI,从已注册 `ConnectionConnector` 中选择唯一实现。零个匹配与多个匹配都是明确错误。broker 不会通过 `StandardConnection` 暴露选中的 connector 类型。
|
|
22
|
+
|
|
23
|
+
这些类型是早期参考实现,不表示 TUI、Web、GUI 或业务插件应自行注册 connector。规范方向是由 Connection Host 把 broker、connector/provider、carrier 和 wire 封装为 `ConnectionService`;consumer 只提交 target,并通过 scoped typed client 使用已协商协议。
|
|
24
|
+
|
|
25
|
+
Connection Host 负责安装或发现远端服务、认证、端口与转发、重连和 `StandardConnection`。SSH target facet 可以贡献解析与 bootstrap 集成,物理 SSH 则可由系统 OpenSSH 或独立 provider 完成。应用不会看到所选 provider、端口、凭据或 wire。
|
|
26
|
+
|
|
27
|
+
## 生命周期
|
|
28
|
+
|
|
29
|
+
重新协商会生成完整的新方案修订版,并原子发布。旧修订版已经接纳的调用保留其绑定直至结束;后续调用使用新修订版。关闭连接会取消活跃工作,并以 `connection-closed` 拒绝新工作。
|
|
30
|
+
|
|
31
|
+
传输实现必须保持调用隔离、进度顺序、取消语义和 `ConnectionInvocationError` 暴露的错误分类。实现还负责认证对端,并阻止一条连接复用另一条连接的授权。
|
|
32
|
+
|
|
33
|
+
## 参考实现
|
|
34
|
+
|
|
35
|
+
`@dsh-std/connection/memory` 导出用于测试、适配器和一致性实验的进程内实现。它演示双向调用、进度、取消、隔离和重新协商,但不是强制承载方式或线协议规范。
|
|
36
|
+
|
|
37
|
+
## 已知限制与暂缓事项
|
|
38
|
+
|
|
39
|
+
- consumer-facing `ConnectionService` 与 Host provider SPI 尚未在当前代码中实现。
|
|
40
|
+
- 本包尚未标准化发现、认证、加密、重连策略、封帧或序列化。
|
|
41
|
+
- `v1alpha1` 的一条连接恰好包含两个端点;多方路由由多条独立连接组合。
|
|
42
|
+
- Capability helper 默认要求唯一对端提供方;需要多提供方的协议必须明确选择其规则。
|
package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/broker.ts","../src/endpoint.ts"],"sourcesContent":["import { validateEndpointOffer } from './model.js'\nimport type { ConnectionEndpoint, StandardConnection } from './connection.js'\n\nexport interface ConnectionTarget {\n /** Implementation-neutral target. Its URI scheme is interpreted by registered connectors. */\n readonly uri: string\n readonly metadata?: Readonly<Record<string, string>>\n}\n\nexport interface ConnectRequest {\n readonly target: ConnectionTarget\n /** Live endpoint, including the dispatcher used for peer-to-local calls. */\n readonly local: ConnectionEndpoint\n readonly signal?: AbortSignal\n}\n\n/** Client half of one concrete connection implementation. */\nexport interface ConnectionConnector {\n /** Namespaced implementation identity, not a transport or product name exposed to domain consumers. */\n readonly id: string\n supports(target: ConnectionTarget): boolean\n connect(request: ConnectRequest): Promise<StandardConnection>\n}\n\nexport class ConnectionSelectionError extends Error {\n constructor(\n readonly code: 'implementation-unavailable' | 'implementation-ambiguous',\n message: string,\n readonly implementations: readonly string[],\n ) {\n super(message)\n this.name = 'ConnectionSelectionError'\n }\n}\n\n/**\n * Implementation registry used by an adapter or application composition root.\n * Domain consumers request a connection; they never import the selected implementation.\n */\nexport class ConnectionBroker {\n private readonly connectors = new Map<string, ConnectionConnector>()\n\n register(connector: ConnectionConnector): () => void {\n namespaced(connector.id, 'connection connector id')\n if (this.connectors.has(connector.id)) throw new Error(`connection connector ${JSON.stringify(connector.id)} is already registered`)\n this.connectors.set(connector.id, connector)\n return () => { if (this.connectors.get(connector.id) === connector) this.connectors.delete(connector.id) }\n }\n\n implementations(target?: ConnectionTarget): readonly string[] {\n if (target !== undefined) validateTarget(target)\n return Object.freeze([...this.connectors.values()]\n .filter(connector => target === undefined || safelySupports(connector, target))\n .map(connector => connector.id)\n .sort())\n }\n\n async connect(request: ConnectRequest): Promise<StandardConnection> {\n validateTarget(request.target)\n validateEndpointOffer(request.local.offer)\n request.signal?.throwIfAborted()\n const matches = [...this.connectors.values()]\n .filter(connector => safelySupports(connector, request.target))\n .sort((left, right) => left.id.localeCompare(right.id))\n if (matches.length === 0) {\n throw new ConnectionSelectionError(\n 'implementation-unavailable',\n `no connection implementation supports ${JSON.stringify(request.target.uri)}`,\n [],\n )\n }\n if (matches.length > 1) {\n const ids = Object.freeze(matches.map(connector => connector.id))\n throw new ConnectionSelectionError(\n 'implementation-ambiguous',\n `multiple connection implementations support ${JSON.stringify(request.target.uri)}: ${ids.join(', ')}`,\n ids,\n )\n }\n return matches[0]!.connect(request)\n }\n}\n\nfunction safelySupports(connector: ConnectionConnector, target: ConnectionTarget): boolean {\n try { return connector.supports(target) } catch { return false }\n}\n\nfunction validateTarget(target: ConnectionTarget): void {\n if (typeof target.uri !== 'string' || target.uri.trim() === '') throw new TypeError('connection target uri must be non-empty')\n if (target.metadata !== undefined) {\n for (const [key, value] of Object.entries(target.metadata)) {\n if (key.trim() === '' || typeof value !== 'string') throw new TypeError('connection target metadata must contain string pairs')\n }\n }\n}\n\nfunction namespaced(value: string, label: string): void {\n if (!/^[a-z][a-z0-9]*(?:[.-][a-z0-9][a-z0-9-]*)+$/u.test(value)) throw new TypeError(`${label} must be namespaced`)\n}\n","import {\n defineProtocolDeclaration,\n sameProtocol,\n type ProtocolDeclaration,\n type ProtocolSupport,\n} from '@dsh-std/core'\nimport {\n ConnectionInvocationError,\n type CapabilityDispatch,\n type CapabilityImplementation,\n type ConnectionEndpoint,\n} from './connection.js'\nimport { createEndpointOffer, type EndpointIdentity, type EndpointOffer } from './model.js'\n\nexport interface EndpointPublication {\n readonly declaration: ProtocolDeclaration\n readonly implementations?: readonly CapabilityImplementation[]\n}\n\nexport interface EndpointRuntimeOptions extends EndpointIdentity {\n readonly revision?: number\n}\n\nexport class StandardEndpointRuntime implements ConnectionEndpoint {\n private readonly declarations = new Map<string, ProtocolDeclaration>()\n private readonly implementations: CapabilityImplementation[] = []\n private readonly listeners = new Set<(offer: EndpointOffer) => void>()\n private readonly identity: EndpointIdentity\n private revision: number\n private currentOffer: EndpointOffer\n\n constructor(options: EndpointRuntimeOptions) {\n this.identity = Object.freeze({ id: options.id, instanceId: options.instanceId })\n this.revision = options.revision ?? 0\n this.currentOffer = this.createOffer()\n }\n\n get offer(): EndpointOffer { return this.currentOffer }\n\n register(publication: EndpointPublication): () => void {\n const declaration = defineProtocolDeclaration(publication.declaration)\n const participantId = declaration.participant.id\n if (this.declarations.has(participantId)) throw new Error(`participant ${JSON.stringify(participantId)} is already registered`)\n const implementations = [...(publication.implementations ?? [])]\n const implemented = new Set<string>()\n for (const implementation of implementations) {\n if (implementation.participantId !== participantId) throw new TypeError(`implementation participantId must be ${JSON.stringify(participantId)}`)\n if (!(declaration.supports ?? []).some(support => sameProtocol(support, implementation.protocol))) {\n throw new TypeError(`participant implementation ${implementation.protocol.apiVersion} ${implementation.protocol.kind} is not declared live`)\n }\n const key = `${implementation.protocol.apiVersion}\\0${implementation.protocol.kind}`\n if (implemented.has(key)) throw new TypeError(`participant has multiple implementations for ${implementation.protocol.apiVersion} ${implementation.protocol.kind}`)\n implemented.add(key)\n }\n const stored = implementations.map(implementation => Object.freeze({\n ...implementation, protocol: Object.freeze({ ...implementation.protocol }),\n handle: implementation.handle as CapabilityImplementation['handle'],\n }))\n this.declarations.set(participantId, declaration)\n this.implementations.push(...stored)\n this.publishOffer()\n let active = true\n return () => {\n if (!active) return\n active = false\n if (this.declarations.get(participantId) === declaration) this.declarations.delete(participantId)\n for (const implementation of stored) {\n const index = this.implementations.indexOf(implementation)\n if (index >= 0) this.implementations.splice(index, 1)\n }\n this.publishOffer()\n }\n }\n\n async dispatch<TInput = unknown, TOutput = unknown, TProgress = unknown>(invocation: CapabilityDispatch<TInput, TProgress>): Promise<TOutput> {\n validateDispatch(invocation, this.currentOffer)\n const implementation = this.implementations.find(candidate =>\n candidate.participantId === invocation.binding.provider.participantId\n && sameProtocol(candidate.protocol, invocation.binding.support))\n if (implementation === undefined) throw new ConnectionInvocationError('handler-missing', `binding ${JSON.stringify(invocation.binding.bindingId)} has no live implementation`)\n try {\n return await implementation.handle(invocation.operation, invocation.input, Object.freeze({\n connectionId: invocation.connectionId,\n planRevision: invocation.planRevision,\n invocationId: invocation.invocationId,\n binding: invocation.binding,\n signal: invocation.signal,\n progress: invocation.progress,\n })) as TOutput\n } catch (error) {\n if (error instanceof ConnectionInvocationError) throw error\n throw new ConnectionInvocationError('handler-failed', error instanceof Error ? error.message : String(error), { cause: error })\n }\n }\n\n onOfferChange(listener: (offer: EndpointOffer) => void): () => void {\n this.listeners.add(listener)\n return () => { this.listeners.delete(listener) }\n }\n\n private createOffer(): EndpointOffer {\n return createEndpointOffer(this.identity, this.revision, [...this.declarations.values()])\n }\n\n private publishOffer(): void {\n this.revision += 1\n this.currentOffer = this.createOffer()\n for (const listener of this.listeners) listener(this.currentOffer)\n }\n}\n\nfunction validateDispatch(invocation: CapabilityDispatch, offer: EndpointOffer): void {\n if (invocation.connectionId.trim() === '') throw new TypeError('connectionId must be non-empty')\n if (!Number.isSafeInteger(invocation.planRevision) || invocation.planRevision < 1) throw new TypeError('planRevision must be positive')\n if (invocation.binding.planRevision !== invocation.planRevision) throw new ConnectionInvocationError('capability-unbound', 'binding belongs to another plan revision')\n if (invocation.binding.provider.endpoint.instanceId !== offer.endpoint.instanceId) throw new ConnectionInvocationError('capability-unbound', 'binding provider belongs to another endpoint')\n if (invocation.invocationId.trim() === '' || invocation.operation.trim() === '') throw new TypeError('invocationId and operation must be non-empty')\n invocation.signal.throwIfAborted()\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/broker.ts","../src/endpoint.ts"],"sourcesContent":["import { validateEndpointOffer } from './model.js'\r\nimport type { ConnectionEndpoint, StandardConnection } from './connection.js'\r\n\r\nexport interface ConnectionTarget {\r\n /** Implementation-neutral target. Its URI scheme is interpreted by registered connectors. */\r\n readonly uri: string\r\n readonly metadata?: Readonly<Record<string, string>>\r\n}\r\n\r\nexport interface ConnectRequest {\r\n readonly target: ConnectionTarget\r\n /** Live endpoint, including the dispatcher used for peer-to-local calls. */\r\n readonly local: ConnectionEndpoint\r\n readonly signal?: AbortSignal\r\n}\r\n\r\n/** Client half of one concrete connection implementation. */\r\nexport interface ConnectionConnector {\r\n /** Namespaced implementation identity, not a transport or product name exposed to domain consumers. */\r\n readonly id: string\r\n supports(target: ConnectionTarget): boolean\r\n connect(request: ConnectRequest): Promise<StandardConnection>\r\n}\r\n\r\nexport class ConnectionSelectionError extends Error {\r\n constructor(\r\n readonly code: 'implementation-unavailable' | 'implementation-ambiguous',\r\n message: string,\r\n readonly implementations: readonly string[],\r\n ) {\r\n super(message)\r\n this.name = 'ConnectionSelectionError'\r\n }\r\n}\r\n\r\n/**\r\n * Implementation registry used by an adapter or application composition root.\r\n * Domain consumers request a connection; they never import the selected implementation.\r\n */\r\nexport class ConnectionBroker {\r\n private readonly connectors = new Map<string, ConnectionConnector>()\r\n\r\n register(connector: ConnectionConnector): () => void {\r\n namespaced(connector.id, 'connection connector id')\r\n if (this.connectors.has(connector.id)) throw new Error(`connection connector ${JSON.stringify(connector.id)} is already registered`)\r\n this.connectors.set(connector.id, connector)\r\n return () => { if (this.connectors.get(connector.id) === connector) this.connectors.delete(connector.id) }\r\n }\r\n\r\n implementations(target?: ConnectionTarget): readonly string[] {\r\n if (target !== undefined) validateTarget(target)\r\n return Object.freeze([...this.connectors.values()]\r\n .filter(connector => target === undefined || safelySupports(connector, target))\r\n .map(connector => connector.id)\r\n .sort())\r\n }\r\n\r\n async connect(request: ConnectRequest): Promise<StandardConnection> {\r\n validateTarget(request.target)\r\n validateEndpointOffer(request.local.offer)\r\n request.signal?.throwIfAborted()\r\n const matches = [...this.connectors.values()]\r\n .filter(connector => safelySupports(connector, request.target))\r\n .sort((left, right) => left.id.localeCompare(right.id))\r\n if (matches.length === 0) {\r\n throw new ConnectionSelectionError(\r\n 'implementation-unavailable',\r\n `no connection implementation supports ${JSON.stringify(request.target.uri)}`,\r\n [],\r\n )\r\n }\r\n if (matches.length > 1) {\r\n const ids = Object.freeze(matches.map(connector => connector.id))\r\n throw new ConnectionSelectionError(\r\n 'implementation-ambiguous',\r\n `multiple connection implementations support ${JSON.stringify(request.target.uri)}: ${ids.join(', ')}`,\r\n ids,\r\n )\r\n }\r\n return matches[0]!.connect(request)\r\n }\r\n}\r\n\r\nfunction safelySupports(connector: ConnectionConnector, target: ConnectionTarget): boolean {\r\n try { return connector.supports(target) } catch { return false }\r\n}\r\n\r\nfunction validateTarget(target: ConnectionTarget): void {\r\n if (typeof target.uri !== 'string' || target.uri.trim() === '') throw new TypeError('connection target uri must be non-empty')\r\n if (target.metadata !== undefined) {\r\n for (const [key, value] of Object.entries(target.metadata)) {\r\n if (key.trim() === '' || typeof value !== 'string') throw new TypeError('connection target metadata must contain string pairs')\r\n }\r\n }\r\n}\r\n\r\nfunction namespaced(value: string, label: string): void {\r\n if (!/^[a-z][a-z0-9]*(?:[.-][a-z0-9][a-z0-9-]*)+$/u.test(value)) throw new TypeError(`${label} must be namespaced`)\r\n}\r\n","import {\r\n defineProtocolDeclaration,\r\n sameProtocol,\r\n type ProtocolDeclaration,\r\n type ProtocolSupport,\r\n} from '@dsh-std/core'\r\nimport {\r\n ConnectionInvocationError,\r\n type CapabilityDispatch,\r\n type CapabilityImplementation,\r\n type ConnectionEndpoint,\r\n} from './connection.js'\r\nimport { createEndpointOffer, type EndpointIdentity, type EndpointOffer } from './model.js'\r\n\r\nexport interface EndpointPublication {\r\n readonly declaration: ProtocolDeclaration\r\n readonly implementations?: readonly CapabilityImplementation[]\r\n}\r\n\r\nexport interface EndpointRuntimeOptions extends EndpointIdentity {\r\n readonly revision?: number\r\n}\r\n\r\nexport class StandardEndpointRuntime implements ConnectionEndpoint {\r\n private readonly declarations = new Map<string, ProtocolDeclaration>()\r\n private readonly implementations: CapabilityImplementation[] = []\r\n private readonly listeners = new Set<(offer: EndpointOffer) => void>()\r\n private readonly identity: EndpointIdentity\r\n private revision: number\r\n private currentOffer: EndpointOffer\r\n\r\n constructor(options: EndpointRuntimeOptions) {\r\n this.identity = Object.freeze({ id: options.id, instanceId: options.instanceId })\r\n this.revision = options.revision ?? 0\r\n this.currentOffer = this.createOffer()\r\n }\r\n\r\n get offer(): EndpointOffer { return this.currentOffer }\r\n\r\n register(publication: EndpointPublication): () => void {\r\n const declaration = defineProtocolDeclaration(publication.declaration)\r\n const participantId = declaration.participant.id\r\n if (this.declarations.has(participantId)) throw new Error(`participant ${JSON.stringify(participantId)} is already registered`)\r\n const implementations = [...(publication.implementations ?? [])]\r\n const implemented = new Set<string>()\r\n for (const implementation of implementations) {\r\n if (implementation.participantId !== participantId) throw new TypeError(`implementation participantId must be ${JSON.stringify(participantId)}`)\r\n if (!(declaration.supports ?? []).some(support => sameProtocol(support, implementation.protocol))) {\r\n throw new TypeError(`participant implementation ${implementation.protocol.apiVersion} ${implementation.protocol.kind} is not declared live`)\r\n }\r\n const key = `${implementation.protocol.apiVersion}\\0${implementation.protocol.kind}`\r\n if (implemented.has(key)) throw new TypeError(`participant has multiple implementations for ${implementation.protocol.apiVersion} ${implementation.protocol.kind}`)\r\n implemented.add(key)\r\n }\r\n const stored = implementations.map(implementation => Object.freeze({\r\n ...implementation, protocol: Object.freeze({ ...implementation.protocol }),\r\n handle: implementation.handle as CapabilityImplementation['handle'],\r\n }))\r\n this.declarations.set(participantId, declaration)\r\n this.implementations.push(...stored)\r\n this.publishOffer()\r\n let active = true\r\n return () => {\r\n if (!active) return\r\n active = false\r\n if (this.declarations.get(participantId) === declaration) this.declarations.delete(participantId)\r\n for (const implementation of stored) {\r\n const index = this.implementations.indexOf(implementation)\r\n if (index >= 0) this.implementations.splice(index, 1)\r\n }\r\n this.publishOffer()\r\n }\r\n }\r\n\r\n async dispatch<TInput = unknown, TOutput = unknown, TProgress = unknown>(invocation: CapabilityDispatch<TInput, TProgress>): Promise<TOutput> {\r\n validateDispatch(invocation, this.currentOffer)\r\n const implementation = this.implementations.find(candidate =>\r\n candidate.participantId === invocation.binding.provider.participantId\r\n && sameProtocol(candidate.protocol, invocation.binding.support))\r\n if (implementation === undefined) throw new ConnectionInvocationError('handler-missing', `binding ${JSON.stringify(invocation.binding.bindingId)} has no live implementation`)\r\n try {\r\n return await implementation.handle(invocation.operation, invocation.input, Object.freeze({\r\n connectionId: invocation.connectionId,\r\n planRevision: invocation.planRevision,\r\n invocationId: invocation.invocationId,\r\n binding: invocation.binding,\r\n signal: invocation.signal,\r\n progress: invocation.progress,\r\n })) as TOutput\r\n } catch (error) {\r\n if (error instanceof ConnectionInvocationError) throw error\r\n throw new ConnectionInvocationError('handler-failed', error instanceof Error ? error.message : String(error), { cause: error })\r\n }\r\n }\r\n\r\n onOfferChange(listener: (offer: EndpointOffer) => void): () => void {\r\n this.listeners.add(listener)\r\n return () => { this.listeners.delete(listener) }\r\n }\r\n\r\n private createOffer(): EndpointOffer {\r\n return createEndpointOffer(this.identity, this.revision, [...this.declarations.values()])\r\n }\r\n\r\n private publishOffer(): void {\r\n this.revision += 1\r\n this.currentOffer = this.createOffer()\r\n for (const listener of this.listeners) listener(this.currentOffer)\r\n }\r\n}\r\n\r\nfunction validateDispatch(invocation: CapabilityDispatch, offer: EndpointOffer): void {\r\n if (invocation.connectionId.trim() === '') throw new TypeError('connectionId must be non-empty')\r\n if (!Number.isSafeInteger(invocation.planRevision) || invocation.planRevision < 1) throw new TypeError('planRevision must be positive')\r\n if (invocation.binding.planRevision !== invocation.planRevision) throw new ConnectionInvocationError('capability-unbound', 'binding belongs to another plan revision')\r\n if (invocation.binding.provider.endpoint.instanceId !== offer.endpoint.instanceId) throw new ConnectionInvocationError('capability-unbound', 'binding provider belongs to another endpoint')\r\n if (invocation.invocationId.trim() === '' || invocation.operation.trim() === '') throw new TypeError('invocationId and operation must be non-empty')\r\n invocation.signal.throwIfAborted()\r\n}\r\n"],"mappings":"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"}
|
package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.js","names":[],"sources":["../src/memory.ts"],"sourcesContent":["import { sameProtocol, type ApiReference } from '@dsh-std/core'\nimport {\n ConnectionInvocationError,\n type CapabilityCall,\n type CapabilityClient,\n type CapabilityDispatch,\n type CapabilityImplementation,\n type ConnectionEndpoint,\n type StandardConnection,\n} from './connection.js'\nimport {\n validateEndpointOffer,\n type CapabilityBinding,\n type ConnectionPlan,\n type EndpointOffer,\n type ResolveConnectionOptions,\n} from './model.js'\nimport { resolveConnection } from './resolve.js'\n\nexport class MemoryConnectionEndpoint implements ConnectionEndpoint {\n private currentOffer: EndpointOffer\n private readonly implementations: CapabilityImplementation[] = []\n private readonly offerListeners = new Set<(offer: EndpointOffer) => void>()\n\n constructor(offer: EndpointOffer) {\n validateEndpointOffer(offer)\n this.currentOffer = offer\n }\n\n get offer(): EndpointOffer { return this.currentOffer }\n\n replaceOffer(offer: EndpointOffer): void {\n validateEndpointOffer(offer)\n if (offer.endpoint.instanceId !== this.currentOffer.endpoint.instanceId) throw new TypeError('replacement offer belongs to another endpoint')\n if (offer.revision <= this.currentOffer.revision) throw new TypeError('replacement offer must increase revision')\n this.currentOffer = offer\n for (const listener of this.offerListeners) listener(offer)\n }\n\n register(implementation: CapabilityImplementation): () => void {\n const declaration = this.currentOffer.declarations.find(row => row.participant.id === implementation.participantId)\n if (declaration === undefined || !(declaration.supports ?? []).some(row => sameProtocol(row, implementation.protocol))) {\n throw new TypeError('implementation is not backed by a live endpoint declaration')\n }\n if (this.implementations.some(row => row.participantId === implementation.participantId && sameProtocol(row.protocol, implementation.protocol))) {\n throw new TypeError('capability implementation is already registered')\n }\n const stored = Object.freeze({ ...implementation, protocol: Object.freeze({ ...implementation.protocol }) })\n this.implementations.push(stored)\n return () => {\n const index = this.implementations.indexOf(stored)\n if (index >= 0) this.implementations.splice(index, 1)\n }\n }\n\n async dispatch<TInput = unknown, TOutput = unknown, TProgress = unknown>(invocation: CapabilityDispatch<TInput, TProgress>): Promise<TOutput> {\n const implementation = this.implementations.find(row =>\n row.participantId === invocation.binding.provider.participantId\n && sameProtocol(row.protocol, invocation.binding.support))\n if (implementation === undefined) throw new ConnectionInvocationError('handler-missing', 'binding has no live implementation')\n return await implementation.handle(invocation.operation, invocation.input, Object.freeze({\n connectionId: invocation.connectionId,\n planRevision: invocation.planRevision,\n invocationId: invocation.invocationId,\n binding: invocation.binding,\n signal: invocation.signal,\n progress: invocation.progress,\n })) as TOutput\n }\n\n onOfferChange(listener: (offer: EndpointOffer) => void): () => void {\n this.offerListeners.add(listener)\n return () => { this.offerListeners.delete(listener) }\n }\n}\n\nexport interface MemoryConnectionPair {\n readonly left: StandardConnection\n readonly right: StandardConnection\n readonly plan: ConnectionPlan\n renegotiate(options: ResolveConnectionOptions): ConnectionPlan\n close(reason?: string): void\n}\n\nexport function createMemoryConnectionPair(\n left: ConnectionEndpoint, right: ConnectionEndpoint, options: ResolveConnectionOptions,\n): MemoryConnectionPair {\n return new MemoryPair(left, right, options)\n}\n\nclass MemoryPair implements MemoryConnectionPair {\n private currentPlan: ConnectionPlan\n private closed = false\n private invocationSequence = 0\n private readonly listeners = new Set<(plan: ConnectionPlan) => void>()\n private readonly active = new Map<string, (reason?: string, code?: 'cancelled' | 'connection-closed') => void>()\n readonly left: StandardConnection\n readonly right: StandardConnection\n\n constructor(\n private readonly leftEndpoint: ConnectionEndpoint,\n private readonly rightEndpoint: ConnectionEndpoint,\n options: ResolveConnectionOptions,\n ) {\n this.currentPlan = resolveConnection(leftEndpoint.offer, rightEndpoint.offer, options)\n this.left = new MemoryConnectionView(this, leftEndpoint, rightEndpoint)\n this.right = new MemoryConnectionView(this, rightEndpoint, leftEndpoint)\n }\n\n get plan(): ConnectionPlan { return this.currentPlan }\n\n renegotiate(options: ResolveConnectionOptions): ConnectionPlan {\n this.assertOpen()\n if (options.connectionId !== this.currentPlan.connectionId || options.revision <= this.currentPlan.revision) {\n throw new TypeError('renegotiation must retain connectionId and increase revision')\n }\n this.currentPlan = resolveConnection(this.leftEndpoint.offer, this.rightEndpoint.offer, options)\n for (const listener of this.listeners) listener(this.currentPlan)\n return this.currentPlan\n }\n\n subscribe(listener: (plan: ConnectionPlan) => void): () => void {\n this.listeners.add(listener)\n return () => { this.listeners.delete(listener) }\n }\n\n binding(local: ConnectionEndpoint, participantId: string, reference: ApiReference): CapabilityBinding | undefined {\n if (this.closed) return undefined\n return this.currentPlan.bindings.find(binding =>\n binding.consumer.endpoint.instanceId === local.offer.endpoint.instanceId\n && binding.consumer.participantId === participantId\n && sameProtocol(binding.requirement, reference))\n }\n\n invoke<TInput, TOutput, TProgress>(\n local: ConnectionEndpoint,\n participantId: string,\n reference: ApiReference,\n operation: string,\n input: TInput,\n signal?: AbortSignal,\n ): CapabilityCall<TOutput, TProgress> {\n this.assertOpen()\n signal?.throwIfAborted()\n const binding = this.binding(local, participantId, reference)\n if (binding === undefined) throw new ConnectionInvocationError('capability-unbound', `participant ${JSON.stringify(participantId)} has no binding`)\n const target = binding.provider.endpoint.instanceId === this.leftEndpoint.offer.endpoint.instanceId\n ? this.leftEndpoint\n : binding.provider.endpoint.instanceId === this.rightEndpoint.offer.endpoint.instanceId ? this.rightEndpoint : undefined\n if (target === undefined) throw new ConnectionInvocationError('handler-missing', 'binding provider endpoint is unavailable')\n const invocationId = `${local.offer.endpoint.instanceId}:${String(++this.invocationSequence)}`\n const controller = new AbortController()\n const progress = new AsyncProgress<TProgress>()\n let settled = false\n let resolveResult!: (value: TOutput | PromiseLike<TOutput>) => void\n let rejectResult!: (reason?: unknown) => void\n const result = new Promise<TOutput>((resolve, reject) => { resolveResult = resolve; rejectResult = reject })\n const finish = () => { settled = true; this.active.delete(invocationId); progress.close() }\n const cancel = (reason = 'capability invocation cancelled', code: 'cancelled' | 'connection-closed' = 'cancelled') => {\n if (settled) return\n controller.abort(reason)\n finish()\n rejectResult(new ConnectionInvocationError(code, reason))\n }\n this.active.set(invocationId, cancel)\n if (signal !== undefined) signal.addEventListener('abort', () => cancel(abortMessage(signal)), { once: true })\n queueMicrotask(() => {\n if (settled) return\n Promise.resolve(target.dispatch<TInput, TOutput, TProgress>({\n connectionId: this.currentPlan.connectionId,\n planRevision: binding.planRevision,\n invocationId,\n binding,\n operation,\n input,\n signal: controller.signal,\n progress: value => { if (!settled) progress.push(value) },\n })).then(value => { if (!settled) { finish(); resolveResult(value) } }, error => {\n if (!settled) { finish(); rejectResult(error) }\n })\n })\n return Object.freeze({ invocationId, result, progress, cancel })\n }\n\n close(reason = 'connection closed'): void {\n if (this.closed) return\n this.closed = true\n for (const cancel of this.active.values()) cancel(reason, 'connection-closed')\n this.active.clear()\n this.listeners.clear()\n }\n\n private assertOpen(): void {\n if (this.closed) throw new ConnectionInvocationError('connection-closed', 'connection is closed')\n }\n\n}\n\nclass MemoryConnectionView implements StandardConnection {\n constructor(\n private readonly pair: MemoryPair,\n private readonly localEndpoint: ConnectionEndpoint,\n private readonly remoteEndpoint: ConnectionEndpoint,\n ) {}\n\n get id(): string { return this.pair.plan.connectionId }\n get local() { return this.localEndpoint.offer.endpoint }\n get remote() { return this.remoteEndpoint.offer.endpoint }\n get plan() { return this.pair.plan }\n\n client(participantId: string): CapabilityClient {\n nonEmpty(participantId, 'participantId')\n return Object.freeze({\n participantId,\n binding: (reference: ApiReference) => this.pair.binding(this.localEndpoint, participantId, reference),\n invoke: <TInput, TOutput, TProgress>(\n reference: ApiReference, operation: string, input: TInput, options?: { readonly signal?: AbortSignal },\n ) => this.pair.invoke<TInput, TOutput, TProgress>(this.localEndpoint, participantId, reference, operation, input, options?.signal),\n })\n }\n\n onPlanChange(listener: (plan: ConnectionPlan) => void): () => void { return this.pair.subscribe(listener) }\n close(reason?: string): void { this.pair.close(reason) }\n}\n\nclass AsyncProgress<T> implements AsyncIterableIterator<T> {\n private readonly values: T[] = []\n private readonly waiters: Array<(result: IteratorResult<T>) => void> = []\n private done = false\n push(value: T): void {\n if (this.done) return\n const waiter = this.waiters.shift()\n if (waiter === undefined) this.values.push(value)\n else waiter({ done: false, value })\n }\n close(): void {\n if (this.done) return\n this.done = true\n for (const waiter of this.waiters.splice(0)) waiter({ done: true, value: undefined })\n }\n next(): Promise<IteratorResult<T>> {\n if (this.values.length > 0) return Promise.resolve({ done: false, value: this.values.shift() as T })\n if (this.done) return Promise.resolve({ done: true, value: undefined })\n return new Promise(resolve => { this.waiters.push(resolve) })\n }\n return(): Promise<IteratorResult<T>> { this.close(); return Promise.resolve({ done: true, value: undefined }) }\n [Symbol.asyncIterator](): AsyncIterableIterator<T> { return this }\n}\n\nfunction abortMessage(signal: AbortSignal): string {\n return signal.reason instanceof Error ? signal.reason.message : typeof signal.reason === 'string' ? signal.reason : 'capability invocation cancelled'\n}\n\nfunction nonEmpty(value: string, label: string): void {\n if (typeof value !== 'string' || value.trim() === '') throw new TypeError(`${label} must be non-empty`)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"memory.js","names":[],"sources":["../src/memory.ts"],"sourcesContent":["import { sameProtocol, type ApiReference } from '@dsh-std/core'\r\nimport {\r\n ConnectionInvocationError,\r\n type CapabilityCall,\r\n type CapabilityClient,\r\n type CapabilityDispatch,\r\n type CapabilityImplementation,\r\n type ConnectionEndpoint,\r\n type StandardConnection,\r\n} from './connection.js'\r\nimport {\r\n validateEndpointOffer,\r\n type CapabilityBinding,\r\n type ConnectionPlan,\r\n type EndpointOffer,\r\n type ResolveConnectionOptions,\r\n} from './model.js'\r\nimport { resolveConnection } from './resolve.js'\r\n\r\nexport class MemoryConnectionEndpoint implements ConnectionEndpoint {\r\n private currentOffer: EndpointOffer\r\n private readonly implementations: CapabilityImplementation[] = []\r\n private readonly offerListeners = new Set<(offer: EndpointOffer) => void>()\r\n\r\n constructor(offer: EndpointOffer) {\r\n validateEndpointOffer(offer)\r\n this.currentOffer = offer\r\n }\r\n\r\n get offer(): EndpointOffer { return this.currentOffer }\r\n\r\n replaceOffer(offer: EndpointOffer): void {\r\n validateEndpointOffer(offer)\r\n if (offer.endpoint.instanceId !== this.currentOffer.endpoint.instanceId) throw new TypeError('replacement offer belongs to another endpoint')\r\n if (offer.revision <= this.currentOffer.revision) throw new TypeError('replacement offer must increase revision')\r\n this.currentOffer = offer\r\n for (const listener of this.offerListeners) listener(offer)\r\n }\r\n\r\n register(implementation: CapabilityImplementation): () => void {\r\n const declaration = this.currentOffer.declarations.find(row => row.participant.id === implementation.participantId)\r\n if (declaration === undefined || !(declaration.supports ?? []).some(row => sameProtocol(row, implementation.protocol))) {\r\n throw new TypeError('implementation is not backed by a live endpoint declaration')\r\n }\r\n if (this.implementations.some(row => row.participantId === implementation.participantId && sameProtocol(row.protocol, implementation.protocol))) {\r\n throw new TypeError('capability implementation is already registered')\r\n }\r\n const stored = Object.freeze({ ...implementation, protocol: Object.freeze({ ...implementation.protocol }) })\r\n this.implementations.push(stored)\r\n return () => {\r\n const index = this.implementations.indexOf(stored)\r\n if (index >= 0) this.implementations.splice(index, 1)\r\n }\r\n }\r\n\r\n async dispatch<TInput = unknown, TOutput = unknown, TProgress = unknown>(invocation: CapabilityDispatch<TInput, TProgress>): Promise<TOutput> {\r\n const implementation = this.implementations.find(row =>\r\n row.participantId === invocation.binding.provider.participantId\r\n && sameProtocol(row.protocol, invocation.binding.support))\r\n if (implementation === undefined) throw new ConnectionInvocationError('handler-missing', 'binding has no live implementation')\r\n return await implementation.handle(invocation.operation, invocation.input, Object.freeze({\r\n connectionId: invocation.connectionId,\r\n planRevision: invocation.planRevision,\r\n invocationId: invocation.invocationId,\r\n binding: invocation.binding,\r\n signal: invocation.signal,\r\n progress: invocation.progress,\r\n })) as TOutput\r\n }\r\n\r\n onOfferChange(listener: (offer: EndpointOffer) => void): () => void {\r\n this.offerListeners.add(listener)\r\n return () => { this.offerListeners.delete(listener) }\r\n }\r\n}\r\n\r\nexport interface MemoryConnectionPair {\r\n readonly left: StandardConnection\r\n readonly right: StandardConnection\r\n readonly plan: ConnectionPlan\r\n renegotiate(options: ResolveConnectionOptions): ConnectionPlan\r\n close(reason?: string): void\r\n}\r\n\r\nexport function createMemoryConnectionPair(\r\n left: ConnectionEndpoint, right: ConnectionEndpoint, options: ResolveConnectionOptions,\r\n): MemoryConnectionPair {\r\n return new MemoryPair(left, right, options)\r\n}\r\n\r\nclass MemoryPair implements MemoryConnectionPair {\r\n private currentPlan: ConnectionPlan\r\n private closed = false\r\n private invocationSequence = 0\r\n private readonly listeners = new Set<(plan: ConnectionPlan) => void>()\r\n private readonly active = new Map<string, (reason?: string, code?: 'cancelled' | 'connection-closed') => void>()\r\n readonly left: StandardConnection\r\n readonly right: StandardConnection\r\n\r\n constructor(\r\n private readonly leftEndpoint: ConnectionEndpoint,\r\n private readonly rightEndpoint: ConnectionEndpoint,\r\n options: ResolveConnectionOptions,\r\n ) {\r\n this.currentPlan = resolveConnection(leftEndpoint.offer, rightEndpoint.offer, options)\r\n this.left = new MemoryConnectionView(this, leftEndpoint, rightEndpoint)\r\n this.right = new MemoryConnectionView(this, rightEndpoint, leftEndpoint)\r\n }\r\n\r\n get plan(): ConnectionPlan { return this.currentPlan }\r\n\r\n renegotiate(options: ResolveConnectionOptions): ConnectionPlan {\r\n this.assertOpen()\r\n if (options.connectionId !== this.currentPlan.connectionId || options.revision <= this.currentPlan.revision) {\r\n throw new TypeError('renegotiation must retain connectionId and increase revision')\r\n }\r\n this.currentPlan = resolveConnection(this.leftEndpoint.offer, this.rightEndpoint.offer, options)\r\n for (const listener of this.listeners) listener(this.currentPlan)\r\n return this.currentPlan\r\n }\r\n\r\n subscribe(listener: (plan: ConnectionPlan) => void): () => void {\r\n this.listeners.add(listener)\r\n return () => { this.listeners.delete(listener) }\r\n }\r\n\r\n binding(local: ConnectionEndpoint, participantId: string, reference: ApiReference): CapabilityBinding | undefined {\r\n if (this.closed) return undefined\r\n return this.currentPlan.bindings.find(binding =>\r\n binding.consumer.endpoint.instanceId === local.offer.endpoint.instanceId\r\n && binding.consumer.participantId === participantId\r\n && sameProtocol(binding.requirement, reference))\r\n }\r\n\r\n invoke<TInput, TOutput, TProgress>(\r\n local: ConnectionEndpoint,\r\n participantId: string,\r\n reference: ApiReference,\r\n operation: string,\r\n input: TInput,\r\n signal?: AbortSignal,\r\n ): CapabilityCall<TOutput, TProgress> {\r\n this.assertOpen()\r\n signal?.throwIfAborted()\r\n const binding = this.binding(local, participantId, reference)\r\n if (binding === undefined) throw new ConnectionInvocationError('capability-unbound', `participant ${JSON.stringify(participantId)} has no binding`)\r\n const target = binding.provider.endpoint.instanceId === this.leftEndpoint.offer.endpoint.instanceId\r\n ? this.leftEndpoint\r\n : binding.provider.endpoint.instanceId === this.rightEndpoint.offer.endpoint.instanceId ? this.rightEndpoint : undefined\r\n if (target === undefined) throw new ConnectionInvocationError('handler-missing', 'binding provider endpoint is unavailable')\r\n const invocationId = `${local.offer.endpoint.instanceId}:${String(++this.invocationSequence)}`\r\n const controller = new AbortController()\r\n const progress = new AsyncProgress<TProgress>()\r\n let settled = false\r\n let resolveResult!: (value: TOutput | PromiseLike<TOutput>) => void\r\n let rejectResult!: (reason?: unknown) => void\r\n const result = new Promise<TOutput>((resolve, reject) => { resolveResult = resolve; rejectResult = reject })\r\n const finish = () => { settled = true; this.active.delete(invocationId); progress.close() }\r\n const cancel = (reason = 'capability invocation cancelled', code: 'cancelled' | 'connection-closed' = 'cancelled') => {\r\n if (settled) return\r\n controller.abort(reason)\r\n finish()\r\n rejectResult(new ConnectionInvocationError(code, reason))\r\n }\r\n this.active.set(invocationId, cancel)\r\n if (signal !== undefined) signal.addEventListener('abort', () => cancel(abortMessage(signal)), { once: true })\r\n queueMicrotask(() => {\r\n if (settled) return\r\n Promise.resolve(target.dispatch<TInput, TOutput, TProgress>({\r\n connectionId: this.currentPlan.connectionId,\r\n planRevision: binding.planRevision,\r\n invocationId,\r\n binding,\r\n operation,\r\n input,\r\n signal: controller.signal,\r\n progress: value => { if (!settled) progress.push(value) },\r\n })).then(value => { if (!settled) { finish(); resolveResult(value) } }, error => {\r\n if (!settled) { finish(); rejectResult(error) }\r\n })\r\n })\r\n return Object.freeze({ invocationId, result, progress, cancel })\r\n }\r\n\r\n close(reason = 'connection closed'): void {\r\n if (this.closed) return\r\n this.closed = true\r\n for (const cancel of this.active.values()) cancel(reason, 'connection-closed')\r\n this.active.clear()\r\n this.listeners.clear()\r\n }\r\n\r\n private assertOpen(): void {\r\n if (this.closed) throw new ConnectionInvocationError('connection-closed', 'connection is closed')\r\n }\r\n\r\n}\r\n\r\nclass MemoryConnectionView implements StandardConnection {\r\n constructor(\r\n private readonly pair: MemoryPair,\r\n private readonly localEndpoint: ConnectionEndpoint,\r\n private readonly remoteEndpoint: ConnectionEndpoint,\r\n ) {}\r\n\r\n get id(): string { return this.pair.plan.connectionId }\r\n get local() { return this.localEndpoint.offer.endpoint }\r\n get remote() { return this.remoteEndpoint.offer.endpoint }\r\n get plan() { return this.pair.plan }\r\n\r\n client(participantId: string): CapabilityClient {\r\n nonEmpty(participantId, 'participantId')\r\n return Object.freeze({\r\n participantId,\r\n binding: (reference: ApiReference) => this.pair.binding(this.localEndpoint, participantId, reference),\r\n invoke: <TInput, TOutput, TProgress>(\r\n reference: ApiReference, operation: string, input: TInput, options?: { readonly signal?: AbortSignal },\r\n ) => this.pair.invoke<TInput, TOutput, TProgress>(this.localEndpoint, participantId, reference, operation, input, options?.signal),\r\n })\r\n }\r\n\r\n onPlanChange(listener: (plan: ConnectionPlan) => void): () => void { return this.pair.subscribe(listener) }\r\n close(reason?: string): void { this.pair.close(reason) }\r\n}\r\n\r\nclass AsyncProgress<T> implements AsyncIterableIterator<T> {\r\n private readonly values: T[] = []\r\n private readonly waiters: Array<(result: IteratorResult<T>) => void> = []\r\n private done = false\r\n push(value: T): void {\r\n if (this.done) return\r\n const waiter = this.waiters.shift()\r\n if (waiter === undefined) this.values.push(value)\r\n else waiter({ done: false, value })\r\n }\r\n close(): void {\r\n if (this.done) return\r\n this.done = true\r\n for (const waiter of this.waiters.splice(0)) waiter({ done: true, value: undefined })\r\n }\r\n next(): Promise<IteratorResult<T>> {\r\n if (this.values.length > 0) return Promise.resolve({ done: false, value: this.values.shift() as T })\r\n if (this.done) return Promise.resolve({ done: true, value: undefined })\r\n return new Promise(resolve => { this.waiters.push(resolve) })\r\n }\r\n return(): Promise<IteratorResult<T>> { this.close(); return Promise.resolve({ done: true, value: undefined }) }\r\n [Symbol.asyncIterator](): AsyncIterableIterator<T> { return this }\r\n}\r\n\r\nfunction abortMessage(signal: AbortSignal): string {\r\n return signal.reason instanceof Error ? signal.reason.message : typeof signal.reason === 'string' ? signal.reason : 'capability invocation cancelled'\r\n}\r\n\r\nfunction nonEmpty(value: string, label: string): void {\r\n if (typeof value !== 'string' || value.trim() === '') throw new TypeError(`${label} must be non-empty`)\r\n}\r\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-3X6ausgz.js","names":[],"sources":["../src/model.ts","../src/connection.ts","../src/rpc.ts","../src/resolve.ts"],"sourcesContent":["import type {\n NegotiatedProtocol,\n ProtocolDeclaration,\n ProtocolRequirement,\n ProtocolSupport,\n} from '@dsh-std/core'\nimport type { ProtocolCatalog } from '@dsh-std/core'\nimport { defineProtocolDeclaration, validateProtocolDeclaration } from '@dsh-std/core'\n\nexport const CONNECTION_API_VERSION = 'connection.dsh/v1alpha1'\n\nexport interface EndpointIdentity {\n readonly id: string\n readonly instanceId: string\n}\n\nexport interface EndpointOffer {\n readonly apiVersion: typeof CONNECTION_API_VERSION\n readonly kind: 'ConnectionOffer'\n readonly endpoint: EndpointIdentity\n readonly revision: number\n readonly declarations: readonly ProtocolDeclaration[]\n}\n\nexport interface ConnectionEndpointReference extends EndpointIdentity {}\n\nexport interface CapabilityParticipant {\n readonly endpoint: ConnectionEndpointReference\n readonly participantId: string\n}\n\nexport interface CapabilityBinding {\n readonly bindingId: string\n readonly agreementId: string\n readonly planRevision: number\n readonly consumer: CapabilityParticipant\n readonly provider: CapabilityParticipant\n readonly requirement: ProtocolRequirement\n readonly support: ProtocolSupport\n}\n\nexport interface ConnectionIssue {\n readonly severity: 'error' | 'warning'\n readonly code: string\n readonly participant?: CapabilityParticipant\n readonly path?: string\n readonly message: string\n}\n\nexport interface ConnectionPlan {\n readonly apiVersion: typeof CONNECTION_API_VERSION\n readonly kind: 'ConnectionAgreement'\n readonly connectionId: string\n readonly revision: number\n readonly digest: string\n readonly offers: readonly {\n readonly endpoint: ConnectionEndpointReference\n readonly revision: number\n }[]\n readonly compatible: boolean\n readonly protocols: readonly NegotiatedProtocol[]\n readonly bindings: readonly CapabilityBinding[]\n readonly issues: readonly ConnectionIssue[]\n}\n\nexport interface ResolveConnectionOptions {\n readonly connectionId: string\n readonly revision: number\n readonly protocols: ProtocolCatalog\n readonly policy?: unknown\n}\n\n/** Policy envelope supplied to definitions while evaluating a pair of endpoint offers. */\nexport interface ConnectionNegotiationPolicy {\n readonly endpointByParticipant: Readonly<Record<string, string>>\n readonly protocol?: unknown\n}\n\nexport function createEndpointOffer(\n endpoint: EndpointIdentity,\n revision: number,\n declarations: readonly ProtocolDeclaration[],\n): EndpointOffer {\n validateEndpoint(endpoint)\n validateOfferRevision(revision)\n const seen = new Set<string>()\n const normalized = declarations.map(declaration => defineProtocolDeclaration(declaration))\n for (const declaration of normalized) {\n if (seen.has(declaration.participant.id)) throw new TypeError(`duplicate endpoint participant ${JSON.stringify(declaration.participant.id)}`)\n seen.add(declaration.participant.id)\n }\n return Object.freeze({\n apiVersion: CONNECTION_API_VERSION,\n kind: 'ConnectionOffer',\n endpoint: freezeEndpoint(endpoint),\n revision,\n declarations: Object.freeze(normalized),\n })\n}\n\nexport function validateEndpointOffer(offer: EndpointOffer): void {\n if (offer.apiVersion !== CONNECTION_API_VERSION || offer.kind !== 'ConnectionOffer') throw new TypeError('endpoint offer version or kind is unsupported')\n validateEndpoint(offer.endpoint)\n validateOfferRevision(offer.revision)\n if (!Array.isArray(offer.declarations)) throw new TypeError('endpoint offer declarations must be an array')\n const seen = new Set<string>()\n for (const declaration of offer.declarations) {\n validateProtocolDeclaration(declaration)\n if (seen.has(declaration.participant.id)) throw new TypeError(`duplicate endpoint participant ${JSON.stringify(declaration.participant.id)}`)\n seen.add(declaration.participant.id)\n }\n}\n\nexport function freezeEndpoint(endpoint: EndpointIdentity): ConnectionEndpointReference {\n return Object.freeze({ id: endpoint.id, instanceId: endpoint.instanceId })\n}\n\nexport function validatePlanCoordinates(connectionId: string, revision: number): void {\n nonEmpty(connectionId, 'connectionId')\n if (!Number.isSafeInteger(revision) || revision < 1) throw new TypeError('connection revision must be a positive safe integer')\n}\n\nfunction validateEndpoint(endpoint: EndpointIdentity): void {\n nonEmpty(endpoint.id, 'endpoint.id')\n nonEmpty(endpoint.instanceId, 'endpoint.instanceId')\n}\n\nfunction validateOfferRevision(revision: number): void {\n if (!Number.isSafeInteger(revision) || revision < 0) throw new TypeError('offer revision must be a non-negative safe integer')\n}\n\nfunction nonEmpty(value: string, label: string): void {\n if (typeof value !== 'string' || value.trim() === '') throw new TypeError(`${label} must be a non-empty string`)\n}\n","import type { ApiReference, ProtocolSupport } from '@dsh-std/core'\nimport type { CapabilityBinding, ConnectionEndpointReference, ConnectionPlan, EndpointOffer } from './model.js'\n\nexport interface CapabilityHandlerContext<TProgress = unknown> {\n readonly connectionId: string\n readonly planRevision: number\n readonly invocationId: string\n readonly binding: CapabilityBinding\n readonly signal: AbortSignal\n progress(value: TProgress): void\n}\n\nexport type CapabilityHandler<TInput = unknown, TOutput = unknown, TProgress = unknown> = (\n operation: string, input: TInput, context: CapabilityHandlerContext<TProgress>,\n) => TOutput | Promise<TOutput>\n\nexport interface CapabilityImplementation<TInput = unknown, TOutput = unknown, TProgress = unknown> {\n readonly participantId: string\n readonly protocol: ProtocolSupport\n readonly handle: CapabilityHandler<TInput, TOutput, TProgress>\n}\n\nexport interface CapabilityDispatch<TInput = unknown, TProgress = unknown> {\n readonly connectionId: string\n readonly planRevision: number\n readonly invocationId: string\n readonly binding: CapabilityBinding\n readonly operation: string\n readonly input: TInput\n readonly signal: AbortSignal\n progress(value: TProgress): void\n}\n\nexport interface ConnectionEndpoint {\n readonly offer: EndpointOffer\n dispatch<TInput = unknown, TOutput = unknown, TProgress = unknown>(invocation: CapabilityDispatch<TInput, TProgress>): Promise<TOutput>\n onOfferChange(listener: (offer: EndpointOffer) => void): () => void\n}\n\nexport interface CapabilityCall<TOutput = unknown, TProgress = unknown> {\n readonly invocationId: string\n readonly result: Promise<TOutput>\n readonly progress: AsyncIterable<TProgress>\n cancel(reason?: string): void\n}\n\nexport interface CapabilityClient {\n readonly participantId: string\n binding(reference: ApiReference): CapabilityBinding | undefined\n invoke<TInput = unknown, TOutput = unknown, TProgress = unknown>(\n reference: ApiReference,\n operation: string,\n input: TInput,\n options?: { readonly signal?: AbortSignal },\n ): CapabilityCall<TOutput, TProgress>\n}\n\nexport interface StandardConnection {\n readonly id: string\n readonly local: ConnectionEndpointReference\n readonly remote: ConnectionEndpointReference\n readonly plan: ConnectionPlan\n client(participantId: string): CapabilityClient\n onPlanChange(listener: (plan: ConnectionPlan) => void): () => void\n close(reason?: string): void | Promise<void>\n}\n\nexport class ConnectionInvocationError extends Error {\n constructor(\n readonly code: 'connection-closed' | 'capability-unbound' | 'handler-missing' | 'cancelled' | 'handler-failed',\n message: string,\n options?: ErrorOptions,\n ) {\n super(message, options)\n this.name = 'ConnectionInvocationError'\n }\n}\n","import type {\n ProtocolDefinition,\n ProtocolIssue,\n ProtocolRequirement,\n ProtocolSupport,\n} from '@dsh-std/core'\nimport type { ConnectionNegotiationPolicy } from './model.js'\n\nexport interface CapabilityBindingDraft {\n readonly consumer: string\n readonly provider: string\n readonly requirement: ProtocolRequirement\n readonly support: ProtocolSupport\n}\n\nexport interface CapabilityAgreement {\n readonly kind: 'CapabilityBindings'\n readonly bindings: readonly CapabilityBindingDraft[]\n}\n\nexport interface CapabilityProtocolOptions {\n readonly apiVersion: string\n readonly kind: string\n readonly accepts?: readonly string[]\n readonly multipleProviders?: boolean\n validateRequirement?(spec: unknown): unknown\n validateSupport?(spec: unknown): unknown\n}\n\n/** Reusable RPC-shaped protocol definition. Domain packages opt into these semantics explicitly. */\nexport function defineCapabilityProtocol(options: CapabilityProtocolOptions): ProtocolDefinition {\n const definition: ProtocolDefinition = {\n apiVersion: options.apiVersion,\n kind: options.kind,\n ...(options.accepts === undefined ? {} : { accepts: Object.freeze([...options.accepts]) }),\n validateRequirement: options.validateRequirement ?? ((value: unknown) => value),\n validateSupport: options.validateSupport ?? ((value: unknown) => value),\n negotiate(input) {\n const issues: ProtocolIssue[] = []\n const bindings: CapabilityBindingDraft[] = []\n const connectionPolicy = isConnectionPolicy(input.policy) ? input.policy : undefined\n for (const row of input.requirements) {\n const consumerEndpoint = connectionPolicy?.endpointByParticipant[row.participant]\n const providers = input.supports.filter(candidate =>\n candidate.participant !== row.participant\n && (consumerEndpoint === undefined\n || connectionPolicy?.endpointByParticipant[candidate.participant] !== consumerEndpoint),\n )\n if (providers.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 ${row.requirement.apiVersion} ${row.requirement.kind}`,\n }))\n continue\n }\n if (providers.length > 1 && options.multipleProviders !== true) {\n issues.push(Object.freeze({\n code: 'support-ambiguous', severity: 'error', participant: row.participant,\n message: `multiple participants support ${row.requirement.apiVersion} ${row.requirement.kind}`,\n }))\n continue\n }\n for (const provider of options.multipleProviders === true ? providers : providers.slice(0, 1)) {\n bindings.push(Object.freeze({\n consumer: row.participant,\n provider: provider.participant,\n requirement: row.requirement,\n support: provider.support,\n }))\n }\n }\n return {\n agreement: Object.freeze({ kind: 'CapabilityBindings' as const, bindings: Object.freeze(bindings) }),\n issues: Object.freeze(issues),\n }\n },\n }\n return Object.freeze(definition)\n}\n\nfunction isConnectionPolicy(value: unknown): value is ConnectionNegotiationPolicy {\n return typeof value === 'object' && value !== null\n && typeof (value as { endpointByParticipant?: unknown }).endpointByParticipant === 'object'\n && (value as { endpointByParticipant?: unknown }).endpointByParticipant !== null\n}\n\nexport function isCapabilityAgreement(value: unknown): value is CapabilityAgreement {\n return typeof value === 'object' && value !== null\n && (value as { kind?: unknown }).kind === 'CapabilityBindings'\n && Array.isArray((value as { bindings?: unknown }).bindings)\n}\n","import type { ProtocolIssue } from '@dsh-std/core'\nimport {\n CONNECTION_API_VERSION,\n freezeEndpoint,\n validateEndpointOffer,\n validatePlanCoordinates,\n type CapabilityBinding,\n type CapabilityParticipant,\n type ConnectionIssue,\n type ConnectionPlan,\n type ConnectionNegotiationPolicy,\n type EndpointOffer,\n type ResolveConnectionOptions,\n} from './model.js'\nimport { isCapabilityAgreement } from './rpc.js'\n\nexport function resolveConnection(left: EndpointOffer, right: EndpointOffer, options: ResolveConnectionOptions): ConnectionPlan {\n validateEndpointOffer(left)\n validateEndpointOffer(right)\n validatePlanCoordinates(options.connectionId, options.revision)\n if (left.endpoint.instanceId === right.endpoint.instanceId) throw new TypeError('connection endpoints must have distinct instanceId values')\n\n const owner = participantOwners(left, right)\n const endpointByParticipant = Object.freeze(Object.fromEntries(\n [...owner.entries()].map(([participant, row]) => [participant, row.endpoint.instanceId]),\n ))\n const policy: ConnectionNegotiationPolicy = Object.freeze({\n endpointByParticipant,\n ...(options.policy === undefined ? {} : { protocol: options.policy }),\n })\n const report = options.protocols.negotiate([...left.declarations, ...right.declarations], policy)\n const bindings: CapabilityBinding[] = []\n for (const protocol of report.protocols) {\n if (!isCapabilityAgreement(protocol.agreement)) continue\n for (const draft of protocol.agreement.bindings) {\n const consumer = owner.get(draft.consumer)\n const provider = owner.get(draft.provider)\n if (consumer === undefined || provider === undefined) continue\n bindings.push(Object.freeze({\n bindingId: '', agreementId: `${protocol.apiVersion}:${protocol.kind}`,\n planRevision: options.revision,\n consumer, provider,\n requirement: Object.freeze({ ...draft.requirement }),\n support: Object.freeze({ ...draft.support }),\n }))\n }\n }\n bindings.sort((a, b) => a.consumer.participantId.localeCompare(b.consumer.participantId)\n || a.requirement.apiVersion.localeCompare(b.requirement.apiVersion)\n || a.requirement.kind.localeCompare(b.requirement.kind)\n || a.provider.participantId.localeCompare(b.provider.participantId))\n const numbered = bindings.map((binding, index) => Object.freeze({ ...binding, bindingId: `binding-${String(index + 1)}` }))\n const issues = Object.freeze(report.issues.map(row => connectionIssue(row, owner)))\n const coordinates = Object.freeze([\n Object.freeze({ endpoint: freezeEndpoint(left.endpoint), revision: left.revision }),\n Object.freeze({ endpoint: freezeEndpoint(right.endpoint), revision: right.revision }),\n ])\n const digest = planDigest({ connectionId: options.connectionId, revision: options.revision, offers: coordinates, protocols: report.protocols })\n return Object.freeze({\n apiVersion: CONNECTION_API_VERSION,\n kind: 'ConnectionAgreement',\n connectionId: options.connectionId,\n revision: options.revision,\n digest,\n offers: coordinates,\n compatible: report.compatible,\n protocols: report.protocols,\n bindings: Object.freeze(numbered),\n issues,\n })\n}\n\nfunction planDigest(value: unknown): string {\n const input = canonical(value)\n let hash = 2166136261\n for (let index = 0; index < input.length; index += 1) hash = Math.imul(hash ^ input.charCodeAt(index), 16777619)\n return `fnv1a32:${(hash >>> 0).toString(16).padStart(8, '0')}`\n}\n\nfunction canonical(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(canonical).join(',')}]`\n if (typeof value === 'object' && value !== null) {\n return `{${Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, item]) => `${JSON.stringify(key)}:${canonical(item)}`).join(',')}}`\n }\n return JSON.stringify(value)\n}\n\nfunction participantOwners(left: EndpointOffer, right: EndpointOffer): Map<string, CapabilityParticipant> {\n const owners = new Map<string, CapabilityParticipant>()\n for (const offer of [left, right]) {\n for (const declaration of offer.declarations) {\n if (owners.has(declaration.participant.id)) throw new TypeError(`participant ${JSON.stringify(declaration.participant.id)} appears in both endpoint offers`)\n owners.set(declaration.participant.id, Object.freeze({\n endpoint: freezeEndpoint(offer.endpoint), participantId: declaration.participant.id,\n }))\n }\n }\n return owners\n}\n\nfunction connectionIssue(issue: ProtocolIssue, owners: ReadonlyMap<string, CapabilityParticipant>): ConnectionIssue {\n return Object.freeze({\n severity: issue.severity,\n code: issue.code,\n ...(issue.participant === undefined ? {} : {\n participant: owners.get(issue.participant) ?? Object.freeze({\n endpoint: Object.freeze({ id: 'unknown', instanceId: 'unknown' }), participantId: issue.participant,\n }),\n }),\n ...(issue.path === undefined ? {} : { path: issue.path }),\n message: issue.message,\n })\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"resolve-3X6ausgz.js","names":[],"sources":["../src/model.ts","../src/connection.ts","../src/rpc.ts","../src/resolve.ts"],"sourcesContent":["import type {\r\n NegotiatedProtocol,\r\n ProtocolDeclaration,\r\n ProtocolRequirement,\r\n ProtocolSupport,\r\n} from '@dsh-std/core'\r\nimport type { ProtocolCatalog } from '@dsh-std/core'\r\nimport { defineProtocolDeclaration, validateProtocolDeclaration } from '@dsh-std/core'\r\n\r\nexport const CONNECTION_API_VERSION = 'connection.dsh/v1alpha1'\r\n\r\nexport interface EndpointIdentity {\r\n readonly id: string\r\n readonly instanceId: string\r\n}\r\n\r\nexport interface EndpointOffer {\r\n readonly apiVersion: typeof CONNECTION_API_VERSION\r\n readonly kind: 'ConnectionOffer'\r\n readonly endpoint: EndpointIdentity\r\n readonly revision: number\r\n readonly declarations: readonly ProtocolDeclaration[]\r\n}\r\n\r\nexport interface ConnectionEndpointReference extends EndpointIdentity {}\r\n\r\nexport interface CapabilityParticipant {\r\n readonly endpoint: ConnectionEndpointReference\r\n readonly participantId: string\r\n}\r\n\r\nexport interface CapabilityBinding {\r\n readonly bindingId: string\r\n readonly agreementId: string\r\n readonly planRevision: number\r\n readonly consumer: CapabilityParticipant\r\n readonly provider: CapabilityParticipant\r\n readonly requirement: ProtocolRequirement\r\n readonly support: ProtocolSupport\r\n}\r\n\r\nexport interface ConnectionIssue {\r\n readonly severity: 'error' | 'warning'\r\n readonly code: string\r\n readonly participant?: CapabilityParticipant\r\n readonly path?: string\r\n readonly message: string\r\n}\r\n\r\nexport interface ConnectionPlan {\r\n readonly apiVersion: typeof CONNECTION_API_VERSION\r\n readonly kind: 'ConnectionAgreement'\r\n readonly connectionId: string\r\n readonly revision: number\r\n readonly digest: string\r\n readonly offers: readonly {\r\n readonly endpoint: ConnectionEndpointReference\r\n readonly revision: number\r\n }[]\r\n readonly compatible: boolean\r\n readonly protocols: readonly NegotiatedProtocol[]\r\n readonly bindings: readonly CapabilityBinding[]\r\n readonly issues: readonly ConnectionIssue[]\r\n}\r\n\r\nexport interface ResolveConnectionOptions {\r\n readonly connectionId: string\r\n readonly revision: number\r\n readonly protocols: ProtocolCatalog\r\n readonly policy?: unknown\r\n}\r\n\r\n/** Policy envelope supplied to definitions while evaluating a pair of endpoint offers. */\r\nexport interface ConnectionNegotiationPolicy {\r\n readonly endpointByParticipant: Readonly<Record<string, string>>\r\n readonly protocol?: unknown\r\n}\r\n\r\nexport function createEndpointOffer(\r\n endpoint: EndpointIdentity,\r\n revision: number,\r\n declarations: readonly ProtocolDeclaration[],\r\n): EndpointOffer {\r\n validateEndpoint(endpoint)\r\n validateOfferRevision(revision)\r\n const seen = new Set<string>()\r\n const normalized = declarations.map(declaration => defineProtocolDeclaration(declaration))\r\n for (const declaration of normalized) {\r\n if (seen.has(declaration.participant.id)) throw new TypeError(`duplicate endpoint participant ${JSON.stringify(declaration.participant.id)}`)\r\n seen.add(declaration.participant.id)\r\n }\r\n return Object.freeze({\r\n apiVersion: CONNECTION_API_VERSION,\r\n kind: 'ConnectionOffer',\r\n endpoint: freezeEndpoint(endpoint),\r\n revision,\r\n declarations: Object.freeze(normalized),\r\n })\r\n}\r\n\r\nexport function validateEndpointOffer(offer: EndpointOffer): void {\r\n if (offer.apiVersion !== CONNECTION_API_VERSION || offer.kind !== 'ConnectionOffer') throw new TypeError('endpoint offer version or kind is unsupported')\r\n validateEndpoint(offer.endpoint)\r\n validateOfferRevision(offer.revision)\r\n if (!Array.isArray(offer.declarations)) throw new TypeError('endpoint offer declarations must be an array')\r\n const seen = new Set<string>()\r\n for (const declaration of offer.declarations) {\r\n validateProtocolDeclaration(declaration)\r\n if (seen.has(declaration.participant.id)) throw new TypeError(`duplicate endpoint participant ${JSON.stringify(declaration.participant.id)}`)\r\n seen.add(declaration.participant.id)\r\n }\r\n}\r\n\r\nexport function freezeEndpoint(endpoint: EndpointIdentity): ConnectionEndpointReference {\r\n return Object.freeze({ id: endpoint.id, instanceId: endpoint.instanceId })\r\n}\r\n\r\nexport function validatePlanCoordinates(connectionId: string, revision: number): void {\r\n nonEmpty(connectionId, 'connectionId')\r\n if (!Number.isSafeInteger(revision) || revision < 1) throw new TypeError('connection revision must be a positive safe integer')\r\n}\r\n\r\nfunction validateEndpoint(endpoint: EndpointIdentity): void {\r\n nonEmpty(endpoint.id, 'endpoint.id')\r\n nonEmpty(endpoint.instanceId, 'endpoint.instanceId')\r\n}\r\n\r\nfunction validateOfferRevision(revision: number): void {\r\n if (!Number.isSafeInteger(revision) || revision < 0) throw new TypeError('offer revision must be a non-negative safe integer')\r\n}\r\n\r\nfunction nonEmpty(value: string, label: string): void {\r\n if (typeof value !== 'string' || value.trim() === '') throw new TypeError(`${label} must be a non-empty string`)\r\n}\r\n","import type { ApiReference, ProtocolSupport } from '@dsh-std/core'\r\nimport type { CapabilityBinding, ConnectionEndpointReference, ConnectionPlan, EndpointOffer } from './model.js'\r\n\r\nexport interface CapabilityHandlerContext<TProgress = unknown> {\r\n readonly connectionId: string\r\n readonly planRevision: number\r\n readonly invocationId: string\r\n readonly binding: CapabilityBinding\r\n readonly signal: AbortSignal\r\n progress(value: TProgress): void\r\n}\r\n\r\nexport type CapabilityHandler<TInput = unknown, TOutput = unknown, TProgress = unknown> = (\r\n operation: string, input: TInput, context: CapabilityHandlerContext<TProgress>,\r\n) => TOutput | Promise<TOutput>\r\n\r\nexport interface CapabilityImplementation<TInput = unknown, TOutput = unknown, TProgress = unknown> {\r\n readonly participantId: string\r\n readonly protocol: ProtocolSupport\r\n readonly handle: CapabilityHandler<TInput, TOutput, TProgress>\r\n}\r\n\r\nexport interface CapabilityDispatch<TInput = unknown, TProgress = unknown> {\r\n readonly connectionId: string\r\n readonly planRevision: number\r\n readonly invocationId: string\r\n readonly binding: CapabilityBinding\r\n readonly operation: string\r\n readonly input: TInput\r\n readonly signal: AbortSignal\r\n progress(value: TProgress): void\r\n}\r\n\r\nexport interface ConnectionEndpoint {\r\n readonly offer: EndpointOffer\r\n dispatch<TInput = unknown, TOutput = unknown, TProgress = unknown>(invocation: CapabilityDispatch<TInput, TProgress>): Promise<TOutput>\r\n onOfferChange(listener: (offer: EndpointOffer) => void): () => void\r\n}\r\n\r\nexport interface CapabilityCall<TOutput = unknown, TProgress = unknown> {\r\n readonly invocationId: string\r\n readonly result: Promise<TOutput>\r\n readonly progress: AsyncIterable<TProgress>\r\n cancel(reason?: string): void\r\n}\r\n\r\nexport interface CapabilityClient {\r\n readonly participantId: string\r\n binding(reference: ApiReference): CapabilityBinding | undefined\r\n invoke<TInput = unknown, TOutput = unknown, TProgress = unknown>(\r\n reference: ApiReference,\r\n operation: string,\r\n input: TInput,\r\n options?: { readonly signal?: AbortSignal },\r\n ): CapabilityCall<TOutput, TProgress>\r\n}\r\n\r\nexport interface StandardConnection {\r\n readonly id: string\r\n readonly local: ConnectionEndpointReference\r\n readonly remote: ConnectionEndpointReference\r\n readonly plan: ConnectionPlan\r\n client(participantId: string): CapabilityClient\r\n onPlanChange(listener: (plan: ConnectionPlan) => void): () => void\r\n close(reason?: string): void | Promise<void>\r\n}\r\n\r\nexport class ConnectionInvocationError extends Error {\r\n constructor(\r\n readonly code: 'connection-closed' | 'capability-unbound' | 'handler-missing' | 'cancelled' | 'handler-failed',\r\n message: string,\r\n options?: ErrorOptions,\r\n ) {\r\n super(message, options)\r\n this.name = 'ConnectionInvocationError'\r\n }\r\n}\r\n","import type {\r\n ProtocolDefinition,\r\n ProtocolIssue,\r\n ProtocolRequirement,\r\n ProtocolSupport,\r\n} from '@dsh-std/core'\r\nimport type { ConnectionNegotiationPolicy } from './model.js'\r\n\r\nexport interface CapabilityBindingDraft {\r\n readonly consumer: string\r\n readonly provider: string\r\n readonly requirement: ProtocolRequirement\r\n readonly support: ProtocolSupport\r\n}\r\n\r\nexport interface CapabilityAgreement {\r\n readonly kind: 'CapabilityBindings'\r\n readonly bindings: readonly CapabilityBindingDraft[]\r\n}\r\n\r\nexport interface CapabilityProtocolOptions {\r\n readonly apiVersion: string\r\n readonly kind: string\r\n readonly accepts?: readonly string[]\r\n readonly multipleProviders?: boolean\r\n validateRequirement?(spec: unknown): unknown\r\n validateSupport?(spec: unknown): unknown\r\n}\r\n\r\n/** Reusable RPC-shaped protocol definition. Domain packages opt into these semantics explicitly. */\r\nexport function defineCapabilityProtocol(options: CapabilityProtocolOptions): ProtocolDefinition {\r\n const definition: ProtocolDefinition = {\r\n apiVersion: options.apiVersion,\r\n kind: options.kind,\r\n ...(options.accepts === undefined ? {} : { accepts: Object.freeze([...options.accepts]) }),\r\n validateRequirement: options.validateRequirement ?? ((value: unknown) => value),\r\n validateSupport: options.validateSupport ?? ((value: unknown) => value),\r\n negotiate(input) {\r\n const issues: ProtocolIssue[] = []\r\n const bindings: CapabilityBindingDraft[] = []\r\n const connectionPolicy = isConnectionPolicy(input.policy) ? input.policy : undefined\r\n for (const row of input.requirements) {\r\n const consumerEndpoint = connectionPolicy?.endpointByParticipant[row.participant]\r\n const providers = input.supports.filter(candidate =>\r\n candidate.participant !== row.participant\r\n && (consumerEndpoint === undefined\r\n || connectionPolicy?.endpointByParticipant[candidate.participant] !== consumerEndpoint),\r\n )\r\n if (providers.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 ${row.requirement.apiVersion} ${row.requirement.kind}`,\r\n }))\r\n continue\r\n }\r\n if (providers.length > 1 && options.multipleProviders !== true) {\r\n issues.push(Object.freeze({\r\n code: 'support-ambiguous', severity: 'error', participant: row.participant,\r\n message: `multiple participants support ${row.requirement.apiVersion} ${row.requirement.kind}`,\r\n }))\r\n continue\r\n }\r\n for (const provider of options.multipleProviders === true ? providers : providers.slice(0, 1)) {\r\n bindings.push(Object.freeze({\r\n consumer: row.participant,\r\n provider: provider.participant,\r\n requirement: row.requirement,\r\n support: provider.support,\r\n }))\r\n }\r\n }\r\n return {\r\n agreement: Object.freeze({ kind: 'CapabilityBindings' as const, bindings: Object.freeze(bindings) }),\r\n issues: Object.freeze(issues),\r\n }\r\n },\r\n }\r\n return Object.freeze(definition)\r\n}\r\n\r\nfunction isConnectionPolicy(value: unknown): value is ConnectionNegotiationPolicy {\r\n return typeof value === 'object' && value !== null\r\n && typeof (value as { endpointByParticipant?: unknown }).endpointByParticipant === 'object'\r\n && (value as { endpointByParticipant?: unknown }).endpointByParticipant !== null\r\n}\r\n\r\nexport function isCapabilityAgreement(value: unknown): value is CapabilityAgreement {\r\n return typeof value === 'object' && value !== null\r\n && (value as { kind?: unknown }).kind === 'CapabilityBindings'\r\n && Array.isArray((value as { bindings?: unknown }).bindings)\r\n}\r\n","import type { ProtocolIssue } from '@dsh-std/core'\r\nimport {\r\n CONNECTION_API_VERSION,\r\n freezeEndpoint,\r\n validateEndpointOffer,\r\n validatePlanCoordinates,\r\n type CapabilityBinding,\r\n type CapabilityParticipant,\r\n type ConnectionIssue,\r\n type ConnectionPlan,\r\n type ConnectionNegotiationPolicy,\r\n type EndpointOffer,\r\n type ResolveConnectionOptions,\r\n} from './model.js'\r\nimport { isCapabilityAgreement } from './rpc.js'\r\n\r\nexport function resolveConnection(left: EndpointOffer, right: EndpointOffer, options: ResolveConnectionOptions): ConnectionPlan {\r\n validateEndpointOffer(left)\r\n validateEndpointOffer(right)\r\n validatePlanCoordinates(options.connectionId, options.revision)\r\n if (left.endpoint.instanceId === right.endpoint.instanceId) throw new TypeError('connection endpoints must have distinct instanceId values')\r\n\r\n const owner = participantOwners(left, right)\r\n const endpointByParticipant = Object.freeze(Object.fromEntries(\r\n [...owner.entries()].map(([participant, row]) => [participant, row.endpoint.instanceId]),\r\n ))\r\n const policy: ConnectionNegotiationPolicy = Object.freeze({\r\n endpointByParticipant,\r\n ...(options.policy === undefined ? {} : { protocol: options.policy }),\r\n })\r\n const report = options.protocols.negotiate([...left.declarations, ...right.declarations], policy)\r\n const bindings: CapabilityBinding[] = []\r\n for (const protocol of report.protocols) {\r\n if (!isCapabilityAgreement(protocol.agreement)) continue\r\n for (const draft of protocol.agreement.bindings) {\r\n const consumer = owner.get(draft.consumer)\r\n const provider = owner.get(draft.provider)\r\n if (consumer === undefined || provider === undefined) continue\r\n bindings.push(Object.freeze({\r\n bindingId: '', agreementId: `${protocol.apiVersion}:${protocol.kind}`,\r\n planRevision: options.revision,\r\n consumer, provider,\r\n requirement: Object.freeze({ ...draft.requirement }),\r\n support: Object.freeze({ ...draft.support }),\r\n }))\r\n }\r\n }\r\n bindings.sort((a, b) => a.consumer.participantId.localeCompare(b.consumer.participantId)\r\n || a.requirement.apiVersion.localeCompare(b.requirement.apiVersion)\r\n || a.requirement.kind.localeCompare(b.requirement.kind)\r\n || a.provider.participantId.localeCompare(b.provider.participantId))\r\n const numbered = bindings.map((binding, index) => Object.freeze({ ...binding, bindingId: `binding-${String(index + 1)}` }))\r\n const issues = Object.freeze(report.issues.map(row => connectionIssue(row, owner)))\r\n const coordinates = Object.freeze([\r\n Object.freeze({ endpoint: freezeEndpoint(left.endpoint), revision: left.revision }),\r\n Object.freeze({ endpoint: freezeEndpoint(right.endpoint), revision: right.revision }),\r\n ])\r\n const digest = planDigest({ connectionId: options.connectionId, revision: options.revision, offers: coordinates, protocols: report.protocols })\r\n return Object.freeze({\r\n apiVersion: CONNECTION_API_VERSION,\r\n kind: 'ConnectionAgreement',\r\n connectionId: options.connectionId,\r\n revision: options.revision,\r\n digest,\r\n offers: coordinates,\r\n compatible: report.compatible,\r\n protocols: report.protocols,\r\n bindings: Object.freeze(numbered),\r\n issues,\r\n })\r\n}\r\n\r\nfunction planDigest(value: unknown): string {\r\n const input = canonical(value)\r\n let hash = 2166136261\r\n for (let index = 0; index < input.length; index += 1) hash = Math.imul(hash ^ input.charCodeAt(index), 16777619)\r\n return `fnv1a32:${(hash >>> 0).toString(16).padStart(8, '0')}`\r\n}\r\n\r\nfunction canonical(value: unknown): string {\r\n if (Array.isArray(value)) return `[${value.map(canonical).join(',')}]`\r\n if (typeof value === 'object' && value !== null) {\r\n return `{${Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, item]) => `${JSON.stringify(key)}:${canonical(item)}`).join(',')}}`\r\n }\r\n return JSON.stringify(value)\r\n}\r\n\r\nfunction participantOwners(left: EndpointOffer, right: EndpointOffer): Map<string, CapabilityParticipant> {\r\n const owners = new Map<string, CapabilityParticipant>()\r\n for (const offer of [left, right]) {\r\n for (const declaration of offer.declarations) {\r\n if (owners.has(declaration.participant.id)) throw new TypeError(`participant ${JSON.stringify(declaration.participant.id)} appears in both endpoint offers`)\r\n owners.set(declaration.participant.id, Object.freeze({\r\n endpoint: freezeEndpoint(offer.endpoint), participantId: declaration.participant.id,\r\n }))\r\n }\r\n }\r\n return owners\r\n}\r\n\r\nfunction connectionIssue(issue: ProtocolIssue, owners: ReadonlyMap<string, CapabilityParticipant>): ConnectionIssue {\r\n return Object.freeze({\r\n severity: issue.severity,\r\n code: issue.code,\r\n ...(issue.participant === undefined ? {} : {\r\n participant: owners.get(issue.participant) ?? Object.freeze({\r\n endpoint: Object.freeze({ id: 'unknown', instanceId: 'unknown' }), participantId: issue.participant,\r\n }),\r\n }),\r\n ...(issue.path === undefined ? {} : { path: issue.path }),\r\n message: issue.message,\r\n })\r\n}\r\n"],"mappings":"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"}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@dsh-std/connection",
|
|
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
|
-
"./memory": { "types": "./lib/memory.d.ts", "default": "./lib/memory.js" }
|
|
11
|
-
},
|
|
12
|
-
"files": ["lib", "CHANGELOG.md"],
|
|
13
|
-
"scripts": {
|
|
14
|
-
"build": "pnpm run typecheck && tsdown",
|
|
15
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
16
|
-
"test": "vitest run"
|
|
17
|
-
},
|
|
18
|
-
"dependencies": { "@dsh-std/core": "workspace:*" },
|
|
19
|
-
"engines": { "node": "^22.19 || >=24" }
|
|
20
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@dsh-std/connection",
|
|
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
|
+
"./memory": { "types": "./lib/memory.d.ts", "default": "./lib/memory.js" }
|
|
11
|
+
},
|
|
12
|
+
"files": ["lib", "CHANGELOG.md"],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "pnpm run typecheck && tsdown",
|
|
15
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
16
|
+
"test": "vitest run"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": { "@dsh-std/core": "workspace:*" },
|
|
19
|
+
"engines": { "node": "^22.19 || >=24" }
|
|
20
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
Changes to `@dsh-std/core` are recorded here.
|
|
4
|
-
|
|
5
|
-
## 0.1.0 (draft)
|
|
6
|
-
|
|
7
|
-
- Defined protocol coordinates, participant declarations, definition catalogs, and negotiation reports.
|
|
8
|
-
- Separated evaluator knowledge, requirements, potential support, and live support.
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Changes to `@dsh-std/core` are recorded here.
|
|
4
|
+
|
|
5
|
+
## 0.1.0 (draft)
|
|
6
|
+
|
|
7
|
+
- Defined protocol coordinates, participant declarations, definition catalogs, and negotiation reports.
|
|
8
|
+
- Separated evaluator knowledge, requirements, potential support, and live support.
|
|
@@ -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.
|