@deepseek-ai/dsh-typert-protocol 0.1.1-rc.2 → 0.1.2-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/typert/protocol/README.md
5
- README.md: 84f9f1b31cca35cffce5dc5fc84db1017adaad08
6
- README.zh.md: 97e4734a7292f0a305ff8ed00ff1d72d1a53b5e9
5
+ README.md: 6400cadad08c7cea634002daa15970fa5f7f6636
6
+ README.zh.md: 8efe1529e118ca2f740769b4113e7758923243a3
package/README.md CHANGED
@@ -1,38 +1,149 @@
1
+ ---
2
+ description: "The shared Typert Remote protocol: decorators, wire descriptors, codecs, and provider contracts used by business packages, generated artifacts, the Host Gateway, and the Client API."
3
+ kind: "package-library"
4
+ ---
5
+
1
6
  # @deepseek-ai/dsh-typert-protocol
2
7
 
3
8
  English | [中文](README.zh.md)
4
9
 
5
- Compiler-independent declarations shared by business packages, generated Typert artifacts, the Host Gateway, and Client API. This package owns the Remote Service base, decorators, explicit binding fallback, merge-extensible protocol maps, invocation descriptors, codecs, and provider contracts; it does not run TypeScript analysis or register a concrete Cordis service.
10
+ ## Summary
11
+
12
+ With `dsh-typert-protocol`, business packages can expose Host methods to Remote clients: mark a method with `@Remote` (or `@RemoteScope` for scoped receivers), bind the service to a wire namespace, and associate Host objects and scoped Contexts with wire identities through the merge-extensible protocol maps. Generated artifacts, the Host Gateway, and the Client API consume the same invocation descriptors, codecs, and provider contracts, so one declaration set stays in sync across every face. The package registers no Cordis service and runs no TypeScript analysis; it declares types and decorator markers only.
13
+
14
+ ## Table of Contents
15
+
16
+ - [Use this package](#use-this-package)
17
+ - [Understand the implementation](#understand-the-implementation)
18
+ - [Further Exploration](#further-exploration)
19
+ - [Model Experience](#model-experience)
20
+ - [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
21
+ - [Dev Note](#dev-note)
22
+
23
+ -----
24
+
25
+ <a id="use-this-package"></a>
26
+ ## Use this package
27
+
28
+ This package is for business-package and assembly maintainers who expose Host capabilities to Remote clients. It is a declarations library: mark methods, bind services, and let the generated pipeline and the Gateway do the rest.
29
+
30
+ ### Exposing a Host method
31
+
32
+ A business package marks a public instance method with `@Remote` (or `@RemoteScope(key)` when the receiver comes from a scoped Context), and the owning service either extends `TypertRemoteService` or declares a `typertRemote` binding through `bindTypertRemote()`:
33
+
34
+ ```text
35
+ import { Remote, TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol'
36
+
37
+ export class GoalService extends TypertRemoteService {
38
+ @Remote
39
+ async create(agentId: string, objective: string): Promise<GoalResult> {
40
+ ...
41
+ }
42
+ }
43
+ ```
44
+
45
+ Generation turns the method into a wire endpoint under the service's namespace; Clients call it as a typed method through `ctx.remote` (see the [API Gateway reference](../../../docs/api-gateway.md)). A method opts into cooperative cancellation by declaring `signal: AbortSignal` as its final parameter — the signal is injected, never a JSON parameter or lookup field.
46
+
47
+ ### Associating Host objects and Contexts with wire identities
48
+
49
+ Complex Host objects cannot cross the wire directly. A business package declares the association through the merge-extensible `TypertLookupMap` and `TypertContextMap`. Host and Client Context adapters both map `Context` to a wire identity and that identity back to `Context`; the Host adapter also owns the stable wire declaration. Host composition may override its synchronous or asynchronous resolver. A resolver that refuses on policy grounds throws `RemoteError` with its own code, which reaches the caller unchanged.
50
+
51
+ ### Reporting and reading a Remote failure
52
+
53
+ One class carries every Remote failure: `RemoteError`, holding a stable `<domain>/<reason>` code and the details typed for that code. This package declares the universal carrier codes (`gateway/bad-request`, `gateway/cancelled`, `gateway/internal`) and owns `RemoteErrorDetailsMap`, the merge-extensible table every other package extends beside its own throwing code:
54
+
55
+ ```text
56
+ declare module '@deepseek-ai/dsh-typert-protocol' {
57
+ interface RemoteErrorDetailsMap {
58
+ 'goal/not-found': { readonly goalId: string }
59
+ }
60
+ }
61
+ throw new RemoteError('goal/not-found', `goal "${id}" does not exist`, { goalId: id })
62
+ ```
63
+
64
+ An owner throws at the failure point; no package writes an error-class family or an exit-mapping function. A caller discriminates by `code` — never by `instanceof` — and a `code` branch narrows `details` with no cast, because `RemoteFailure` is the code-discriminated union of `RemoteError` instances. Infrastructure that must recognize a failure carried across a module or realm copy of the class calls `remoteErrorOf(value)`, which reads a structural marker instead of the prototype chain.
65
+
66
+ ### Receiving forwarded Host events on the Client
67
+
68
+ The Host assembly extends `TypertRemoteEventSelection` with the Cordis events it forwards to consumers, which narrows the `ctx.remote.$on` key set. `TypertForwardableEvent` accepts unscoped `void` notifications and scoped async waterfalls whose final `next()` callback returns the event's result type. `TypertClientEventListener` derives the Client listener from that same `Events` member while preserving signals, optional and readonly fields, arrays, callbacks, and result types. `TypertClientRemote` exposes only `$mount()` and `$on()`; event transport remains private to Gateway.
6
69
 
7
- ## Remote declarations
70
+ -----
8
71
 
9
- - `@Remote` marks a public instance method for direct invocation on its registered Cordis Service.
10
- - `@RemoteScope(key)` marks a method whose receiver is selected from a merge-declared scoped Context kind.
11
- - `TypertRemoteService` binds the Cordis key passed to `super(ctx, serviceKey, options?)` to the same default wire namespace.
12
- - `bindTypertRemote(this, serviceKey, options?)` provides the same visible, frozen binding for a Service that cannot inherit from `TypertRemoteService`.
13
- - `remoteMethods(service)` returns a detached declaration-order snapshot used by the Gateway's SRC fallback.
72
+ <a id="understand-the-implementation"></a>
73
+ ## Understand the implementation
14
74
 
15
- A Host method opts into cooperative cancellation by declaring `signal: AbortSignal` as its final parameter. `InvocationDescriptor.cancellation` records that reserved injection point; the signal never becomes a JSON parameter or lookup field. SRC recognizes the final parameter name, while strict generation also verifies the global `AbortSignal` type.
75
+ <details>
76
+ <summary>Implementation internals — click to expand</summary>
16
77
 
17
- Decorator initializers retain markers in a module-private `WeakMap` keyed by the Service prototype. They do not add constructor symbols, prototype properties, parameter metadata, or runtime reflection fields. A `TypertRemoteService` exposes the same public readonly `typertRemote` binding that the explicit helper returns.
78
+ This section explains how the declarations stay compiler-independent and where each contract is enforced; the programming model is covered in [Use this package](#use-this-package).
18
79
 
19
- ## Typert protocol
80
+ ### Design concept
20
81
 
21
- Business packages extend `TypertLookupMap` and `TypertContextMap` to associate Host objects or scoped Contexts with their wire identities. Generated artifacts extend `TypertRemoteMap`, `TypertRemoteScopeMap`, and `TypertRemoteNamespaceMap` so Client imports expose only selected Remote methods. `InvocationDescriptor` is the shared runtime form consumed by the registry, Gateway, and Client Remote.
82
+ The package keeps strict reflection in the compiler: decorator initializers retain minimal markers in a versioned descriptor on the Service prototype. The descriptor uses a stable string property name, so another installed copy of the protocol package can read the same markers. Full parameter, result, lookup, and schema reflection is the Typert build pipeline's job, delivered through `InvocationDescriptor`.
22
83
 
23
- The Host assembly extends `TypertRemoteEventSelection` with the Host events it forwards to consumers, which narrows the `ctx.remote.$on` key face; `TypertForwardableEvent` states the shapes a one-way delivery can carry at all, excluding Scope-bound and answered events. `TypertClientRemote` carries both roles of that surface: consumers subscribe through `$on`, and the Client half owning the host frame sink hands frames over through `$dispatch`.
84
+ ### Remote markers
24
85
 
25
- Lookup and Context packages own both sides of their contract: declaration merging supplies the static association, while runtime providers register identity resolution with `ctx.typert`. A lookup or Host Context provider supplies the stable declaration and default resolver, while Host composition may separately configure a synchronous or asynchronous resolver; policy rejections may use `TypertLookupFailure` to carry a failure value owned by the boundary adapter. Strict codecs carry generated schemas; `src-json` codecs identify the weaker source-launch path.
86
+ `@Remote` and `@RemoteScope` schedule an initializer that appends the method name, an optional export name, and the invocation mode to the prototype descriptor; `remoteMethods(service)` validates its version and returns a detached declaration-order snapshot that the Gateway's source-mode fallback reads. Markers require public, non-static instance methods with string names, and conflicting markers on one method are rejected.
26
87
 
88
+ ### Protocol maps and descriptors
89
+
90
+ The merge-extensible protocol maps keep static associations in the type system, while runtime providers register resolution with `ctx.typert`; the map names and shapes live in [`src/types.ts`](src/types.ts). `InvocationDescriptor` is the shared runtime form consumed by the registry, the Gateway, and the Client Remote, covering direct and Context receivers, JSON and lookup parameters, scope projections, cancellation, and result codecs.
91
+
92
+ ### Wire identity grammar
93
+
94
+ Every namespace, method, lookup, and Context segment must satisfy `isTypertRemoteSegment()`, so generated names cross the shared RPC carrier unchanged. Strict codecs carry generated schemas; `src-json` codecs identify the weaker source-launch path.
95
+
96
+ ### Source map
97
+
98
+ | File | Role |
99
+ |---|---|
100
+ | [`src/index.ts`](src/index.ts) | Decorators, Gateway bindings, `remoteMethods`, segment validation |
101
+ | [`src/remote-error.ts`](src/remote-error.ts) | `RemoteError` and the structural `remoteErrorOf` recognizer |
102
+ | [`src/types.ts`](src/types.ts) | Protocol maps, `RemoteErrorDetailsMap`, `RemoteResult`, `InvocationDescriptor`, codecs, provider contracts, registry interfaces, `TypertClientRemote` |
103
+ | [`src/invariant.ts`](src/invariant.ts) | Invariant companion |
104
+
105
+ </details>
106
+
107
+ -----
108
+
109
+ <a id="further-exploration"></a>
110
+ ## Further Exploration
111
+
112
+ Read these pages when the package-level contract is not enough; they move from the declarations to the runtime and the call path.
113
+
114
+ - [API Gateway reference](../../../docs/api-gateway.md) — how the declarations become running Host-to-Client calls.
115
+ - [Typert subsystem reference](../../../docs/subsystems/typert.md) — the literal public contracts recorded from protocol and Gateway types.
116
+ - [Typert registry](../registry/README.md) — where descriptors and providers are stored at runtime.
117
+ - [Typert generator](../generator/README.md) — what generates the consumer-side declarations and descriptors.
118
+ - [Remote-call Agent Note](../../../.agents/notes/implemented/architecture/2026-08-02-typert-remote-method-calls.md) — the architecture and transport decisions behind Remote calls.
119
+
120
+ -----
121
+
122
+ <a id="model-experience"></a>
27
123
  ## Model Experience
28
124
 
29
- None, as this protocol package declares application reflection and registers nothing model-facing.
125
+ None, as compiler-independent Remote protocol declarations register nothing model-facing.
30
126
 
31
127
  #### KV Cache effect
32
128
 
33
- No direct effect.
129
+ No direct effect; the declared contracts reach a request only when an assembly places them in one.
34
130
 
35
131
  ## Known Limitations and Deferred Work
36
132
 
37
- - Decorator markers contain only the method name and direct or Context invocation mode. Parameter, result, lookup, and schema reflection require the Typert build pipeline.
38
- - Remote decorators accept only public, non-static instance methods with string names. SRC execution cannot represent overloaded, destructured, defaulted, or rest-parameter signatures.
133
+ <a id="known-limitations-and-deferred-work"></a>
134
+
135
+
136
+ These limits define what the declarations can represent; they are current package constraints, not a task backlog.
137
+
138
+ - **Decorator markers are minimal** — markers contain only the method name and the direct or Context invocation mode; parameter, result, lookup, and schema reflection require the Typert build pipeline.
139
+ - **Remote signatures are restricted** — decorators accept only public, non-static instance methods with string names, and source-mode execution cannot represent overloaded, destructured, defaulted, or rest-parameter signatures.
140
+
141
+ <a id="dev-note"></a>
142
+ ### Dev Note
143
+
144
+ <details>
145
+ <summary>Working context for maintainers — click to expand</summary>
146
+
147
+ None.
148
+
149
+ </details>
package/README.zh.md CHANGED
@@ -1,38 +1,149 @@
1
+ ---
2
+ description: "共享的 Typert Remote 协议:业务包、生成产物、Host Gateway 与 Client API 使用的装饰器、wire 描述符、编解码器与提供方约定。"
3
+ kind: "package-library"
4
+ ---
5
+
1
6
  # @deepseek-ai/dsh-typert-protocol
2
7
 
3
8
  [English](README.md) | 中文
4
9
 
5
- 该包提供不依赖编译器的声明,由业务包、生成的 Typert 产物、宿主网关和客户端 API 共享。它负责 Remote 服务基类、装饰器、显式绑定回退、可通过声明合并扩展的协议映射、调用描述符、编解码器和提供方约定;它不执行 TypeScript 分析,也不注册具体 Cordis 服务。
10
+ ## 概述
11
+
12
+ 借助 `dsh-typert-protocol`,业务包可以向 Remote 客户端暴露 Host 方法:用 `@Remote`(作用域接收者用 `@RemoteScope`)标记方法,把服务绑定到 wire 命名空间,并通过可合并扩展的协议映射把 Host 对象与作用域 Context 关联到 wire identity。生成产物、Host Gateway 与 Client API 消费同一套调用描述符、编解码器与提供方约定,因此一套声明在每个 face 上保持一致。本包不注册任何 Cordis 服务,也不运行 TypeScript 分析;它只声明类型与装饰器标记。
13
+
14
+ ## 目录
15
+
16
+ - [使用本包](#use-this-package)
17
+ - [理解实现](#understand-the-implementation)
18
+ - [进一步探索](#further-exploration)
19
+ - [模型体验](#model-experience)
20
+ - [已知限制与延期工作](#known-limitations-and-deferred-work)
21
+ - [开发备注](#dev-note)
22
+
23
+ -----
24
+
25
+ <a id="use-this-package"></a>
26
+ ## 使用本包
27
+
28
+ 本包供向 Remote 客户端暴露 Host 能力的业务包与装配维护者使用。它是一个声明库:标记方法、绑定服务,其余交给生成的流水线与 Gateway。
29
+
30
+ ### 暴露 Host 方法
31
+
32
+ 业务包用 `@Remote`(当接收者来自作用域 Context 时用 `@RemoteScope(key)`)标记一个公开实例方法,所属服务要么继承 `TypertRemoteService`,要么通过 `bindTypertRemote()` 声明 `typertRemote` 绑定:
33
+
34
+ ```text
35
+ import { Remote, TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol'
36
+
37
+ export class GoalService extends TypertRemoteService {
38
+ @Remote
39
+ async create(agentId: string, objective: string): Promise<GoalResult> {
40
+ ...
41
+ }
42
+ }
43
+ ```
44
+
45
+ 生成会把方法变为服务命名空间下的 wire 端点;Client 通过 `ctx.remote` 以类型化方法调用它(见 [API Gateway 参考](../../../docs/api-gateway.zh.md))。方法把 `signal: AbortSignal` 声明为最后一个参数即可选择协作式取消——该信号是注入的,绝不会成为 JSON 参数或查找字段。
46
+
47
+ ### 把 Host 对象与 Context 关联到 wire identity
48
+
49
+ 复杂的 Host 对象不能直接跨 wire 传输。业务包通过可合并扩展的 `TypertLookupMap` 与 `TypertContextMap` 声明关联。Host 与 Client Context adapter 都把 `Context` 映射为 wire identity,也把该 identity 映射回 `Context`;Host adapter 还拥有稳定 wire 声明。Host 组合可以覆盖其同步或异步 resolver。因策略而拒绝的 resolver 抛出带自有码的 `RemoteError`,该码原样到达调用方。
50
+
51
+ ### 报告与读取 Remote 失败
52
+
53
+ 所有 Remote 失败都由一个类承载:`RemoteError`,携带稳定的 `<domain>/<reason>` 码,以及按该码定型的 details。本包声明通用载体码(`gateway/bad-request`、`gateway/cancelled`、`gateway/internal`),并拥有 `RemoteErrorDetailsMap`——可合并扩展的码表,其他每个包都在自己的抛出点旁扩展它:
54
+
55
+ ```text
56
+ declare module '@deepseek-ai/dsh-typert-protocol' {
57
+ interface RemoteErrorDetailsMap {
58
+ 'goal/not-found': { readonly goalId: string }
59
+ }
60
+ }
61
+ throw new RemoteError('goal/not-found', `goal "${id}" does not exist`, { goalId: id })
62
+ ```
63
+
64
+ 拥有方在失败点直接抛出;没有任何包再写错误类家族或出口映射函数。调用方按 `code` 判别——绝不用 `instanceof`——且 `code` 分支无需 cast 即收窄 `details`,因为 `RemoteFailure` 就是 `RemoteError` 实例按码判别的 union。需要识别跨模块或跨 realm 类副本传来的失败时,基础设施调用 `remoteErrorOf(value)`,它读结构标记而不是原型链。
65
+
66
+ ### 在 Client 侧接收转发的 Host 事件
67
+
68
+ Host 装配以转发给消费端的 Cordis 事件扩展 `TypertRemoteEventSelection`,从而收窄 `ctx.remote.$on` 的键集。`TypertForwardableEvent` 接受无作用域且返回 `void` 的通知,以及最后一个 `next()` 回调返回事件结果类型的异步作用域 waterfall。`TypertClientEventListener` 从同一条 `Events` 成员派生 Client listener,并保留 signal、可选和只读字段、数组、回调与结果类型。`TypertClientRemote` 只公开 `$mount()` 与 `$on()`;事件传输仍由 Gateway 私有持有。
6
69
 
7
- ## Remote 声明
70
+ -----
8
71
 
9
- - `@Remote` 将公开实例方法标记为可在其注册的 Cordis 服务上直接调用。
10
- - `@RemoteScope(key)` 标记接收者选自合并声明的作用域 Context 类型的方法。
11
- - `TypertRemoteService` 将传给 `super(ctx, serviceKey, options?)` 的 Cordis 键绑定到同一默认协议命名空间。
12
- - `bindTypertRemote(this, serviceKey, options?)` 为无法继承 `TypertRemoteService` 的服务提供同样可见且冻结的绑定。
13
- - `remoteMethods(service)` 返回按声明顺序排列、与内部状态分离的快照,供 Gateway 的 SRC 回退路径使用。
72
+ <a id="understand-the-implementation"></a>
73
+ ## 理解实现
14
74
 
15
- 宿主方法通过将 `signal: AbortSignal` 声明为最后一个参数来启用协作式取消。`InvocationDescriptor.cancellation` 记录这个保留的注入点;该信号绝不会成为 JSON 参数或查找字段。SRC 识别末位参数名,严格生成还会校验它是否具有全局 `AbortSignal` 类型。
75
+ <details>
76
+ <summary>实现细节——点击展开</summary>
16
77
 
17
- 装饰器初始化器将标记保存在以服务原型为键的模块私有 `WeakMap` 中。它们不会在构造函数上添加符号,也不会添加原型属性、参数元数据或运行时反射字段。`TypertRemoteService` 会暴露与显式辅助函数相同的公开只读 `typertRemote` 绑定。
78
+ 本节解释声明如何保持与编译器无关,以及每个约定在哪里执行;编程模型已在[使用本包](#use-this-package)中说明。
18
79
 
19
- ## Typert 协议
80
+ ### 设计理念
20
81
 
21
- 业务包扩展 `TypertLookupMap` `TypertContextMap`,以关联宿主对象或作用域 Context 与其协议身份。生成的产物扩展 `TypertRemoteMap`、`TypertRemoteScopeMap` `TypertRemoteNamespaceMap`,使客户端导入后仅暴露选定的 Remote 方法。`InvocationDescriptor` 是供注册表、网关和客户端 Remote 使用的共享运行时形式。
82
+ 本包把严格反射留在编译器中:装饰器初始化器把最小标记保存在 Service 原型上的带版本描述符中。描述符使用稳定的字符串属性名,因此协议包的另一个已安装副本也能读取同一组标记。完整的参数、结果、查找与 schema 反射是 Typert 构建流水线的职责,通过 `InvocationDescriptor` 交付。
22
83
 
23
- Host 装配以转发给消费端的 Host 事件扩展 `TypertRemoteEventSelection`,从而收窄 `ctx.remote.$on` 的键面;`TypertForwardableEvent` 陈述单向投递根本能承载哪些形状,把 Scope 化事件与有返回值的事件排除在外。`TypertClientRemote` 承载该面的两种角色:消费方经 `$on` 订阅,持有 Host 帧 sink 的 Client 半经 `$dispatch` 交出帧。
84
+ ### Remote 标记
24
85
 
25
- 查找包与 Context 包同时负责该约定的两侧:声明合并提供静态关联,运行时提供方则向 `ctx.typert` 注册身份解析。查找提供方或宿主 Context 提供方提供稳定声明与默认解析器,宿主组合可以另行配置同步或异步解析器;策略拒绝可用 `TypertLookupFailure` 携带由边界适配器拥有的失败值。严格编解码器携带生成的 schema;`src-json` 编解码器标识约束更弱的源码启动路径。
86
+ `@Remote` `@RemoteScope` 调度一个初始化器,把方法名、可选导出名与调用模式追加到原型描述符;`remoteMethods(service)` 校验其版本,并返回与已存描述符分离、按声明顺序排列的快照,供 Gateway 的源码模式回退读取。标记要求公开、非静态、具名字符串的实例方法,同一方法上的冲突标记会被拒绝。
26
87
 
88
+ ### 协议映射与描述符
89
+
90
+ 可合并扩展的协议映射在类型系统中保留静态关联,运行时提供方则向 `ctx.typert` 注册解析;映射的名称与形状见 [`src/types.ts`](src/types.ts)。`InvocationDescriptor` 是注册表、Gateway 与 Client Remote 共同消费的共享运行时形式,涵盖直接与 Context 接收者、JSON 与查找参数、作用域投影、取消与结果编解码器。
91
+
92
+ ### Wire 标识文法
93
+
94
+ 每个命名空间、方法、查找与 Context 段都必须满足 `isTypertRemoteSegment()`,生成的名字才能原样跨共享 RPC 载体传输。严格编解码器携带生成的 schema;`src-json` 编解码器标识约束更弱的源码启动路径。
95
+
96
+ ### 源码地图
97
+
98
+ | 文件 | 职责 |
99
+ |---|---|
100
+ | [`src/index.ts`](src/index.ts) | 装饰器、Gateway 绑定、`remoteMethods`、段校验 |
101
+ | [`src/remote-error.ts`](src/remote-error.ts) | `RemoteError` 与结构式识别函数 `remoteErrorOf` |
102
+ | [`src/types.ts`](src/types.ts) | 协议映射、`RemoteErrorDetailsMap`、`RemoteResult`、`InvocationDescriptor`、编解码器、提供方约定、注册表接口、`TypertClientRemote` |
103
+ | [`src/invariant.ts`](src/invariant.ts) | 不变式伴生插件 |
104
+
105
+ </details>
106
+
107
+ -----
108
+
109
+ <a id="further-exploration"></a>
110
+ ## 进一步探索
111
+
112
+ 当包级约定不够用时阅读以下页面;它们从声明逐步进入运行时与调用路径。
113
+
114
+ - [API Gateway 参考](../../../docs/api-gateway.zh.md)——声明如何成为实际的 Host 到 Client 调用。
115
+ - [Typert 子系统参考](../../../docs/subsystems/typert.zh.md)——从协议与 Gateway 类型记录的字面公共约定。
116
+ - [Typert 注册表](../registry/README.zh.md)——描述符与提供方在运行时存放的位置。
117
+ - [Typert 生成器](../generator/README.zh.md)——生成消费方声明与描述符的包。
118
+ - [Remote 调用 Agent Note](../../../.agents/notes/implemented/architecture/2026-08-02-typert-remote-method-calls.zh.md)——Remote 调用背后的架构与传输决策。
119
+
120
+ -----
121
+
122
+ <a id="model-experience"></a>
27
123
  ## 模型体验
28
124
 
29
- 无,因为该协议包声明应用反射,不注册任何面向模型的内容。
125
+ 无,因为与编译器无关的 Remote 协议声明不注册任何面向模型的内容。
30
126
 
31
127
  #### KV Cache 影响
32
128
 
33
- 无直接影响。
129
+ 无直接影响;声明的约定只有在装配将其放入请求时才会触及请求。
130
+
131
+ ## 已知限制与延期工作
132
+
133
+ <a id="known-limitations-and-deferred-work"></a>
134
+
135
+
136
+ 这些限制说明声明能表示什么;它们是当前包约束,不是任务积压。
137
+
138
+ - **装饰器标记是最小化的**——标记只包含方法名与直接调用或 Context 调用模式;参数、结果、查找与 schema 反射需要 Typert 构建流水线。
139
+ - **Remote 签名受限**——装饰器只接受具有字符串名称的公开、非静态实例方法,源码模式执行无法表示重载、解构、默认参数或剩余参数签名。
140
+
141
+ <a id="dev-note"></a>
142
+ ### 开发备注
143
+
144
+ <details>
145
+ <summary>维护者的工作上下文——点击展开</summary>
34
146
 
35
- ## 已知限制与暂缓事项
147
+ 无。
36
148
 
37
- - 装饰器标记仅包含方法名,以及直接调用或 Context 调用模式。参数、结果、查找和 schema 反射需要 Typert 构建流水线。
38
- - Remote 装饰器只接受具有字符串名称的公开、非静态实例方法。SRC 执行无法表示重载签名,以及包含解构参数、默认参数或剩余参数的方法签名。
149
+ </details>
package/lib/index.js CHANGED
@@ -1,8 +1,47 @@
1
1
  import { Service } from "@deepseek-ai/cordis";
2
+ //#region lib/types/remote-error.js
3
+ /** The one Remote failure class shared by owners, the Gateway, and consumers. */
4
+ /**
5
+ * One Remote call failure: a real Error carrying its stable code and typed
6
+ * details. Owners throw it at the failure point; the Host Gateway encodes it
7
+ * onto the wire unchanged; the Client face rebuilds an instance for the
8
+ * `RemoteResult` error branch, so `throw result.error` keeps throw semantics.
9
+ * Discrimination is always by `code`, never by instanceof.
10
+ */
11
+ var RemoteError = class extends Error {
12
+ code;
13
+ details;
14
+ /** Structural marker: cross-realm/bundle identification never uses instanceof. */
15
+ isDSHRemoteError = true;
16
+ /**
17
+ * @param code - stable failure code declared in {@link RemoteErrorDetailsMap}.
18
+ * @param message - human diagnostic carried across the wire.
19
+ * @param details - structured payload typed by the code.
20
+ * @param options - standard Error options (`cause` survives in-process only).
21
+ */
22
+ constructor(code, message, details, options) {
23
+ super(message, options);
24
+ this.code = code;
25
+ this.details = details;
26
+ this.name = "RemoteError";
27
+ }
28
+ };
29
+ /**
30
+ * Structurally identify a RemoteError thrown across module or realm copies of
31
+ * this class. Mechanism-internal: the Gateway and test assertions use it;
32
+ * business code receives typed failures and never needs it.
33
+ * @param value - a caught value.
34
+ * @returns the failure when the marker matches, otherwise undefined.
35
+ */
36
+ function remoteErrorOf(value) {
37
+ if (typeof value === "object" && value !== null && value.isDSHRemoteError === true && typeof value.code === "string") return value;
38
+ }
39
+ //#endregion
2
40
  //#region lib/types/index.js
3
41
  /**
4
- * Remote decorators and explicit Gateway bindings backed only by private
5
- * module state. Strict reflection remains a Typert compiler responsibility.
42
+ * Remote decorators and explicit Gateway bindings backed by versioned
43
+ * descriptors carried on decorated class prototypes. Strict reflection
44
+ * remains a Typert compiler responsibility.
6
45
  * @module @deepseek-ai/dsh-typert-protocol
7
46
  */
8
47
  const TYPERT_REMOTE_SEGMENT_PATTERN = /^[A-Za-z0-9_$.-]+$/;
@@ -14,24 +53,7 @@ const TYPERT_REMOTE_SEGMENT_PATTERN = /^[A-Za-z0-9_$.-]+$/;
14
53
  function isTypertRemoteSegment(value) {
15
54
  return value !== "." && value !== ".." && TYPERT_REMOTE_SEGMENT_PATTERN.test(value);
16
55
  }
17
- /**
18
- * A lookup policy rejection whose typed payload belongs to the active boundary adapter.
19
- * Gateway adapters preserve this payload instead of collapsing it into an infrastructure failure.
20
- */
21
- var TypertLookupFailure = class extends Error {
22
- /** Adapter-owned failure returned to the caller. */
23
- failure;
24
- /**
25
- * Wrap one adapter failure without exposing the rejected identity.
26
- * @param failure - typed failure owned by the active boundary adapter.
27
- */
28
- constructor(failure) {
29
- super("Typert lookup policy rejected the requested identity");
30
- this.name = "TypertLookupFailure";
31
- this.failure = failure;
32
- }
33
- };
34
- const markers = /* @__PURE__ */ new WeakMap();
56
+ const REMOTE_METHOD_DESCRIPTOR = "@deepseek-ai/dsh-typert-protocol/remote-methods";
35
57
  /**
36
58
  * Bind one visible Service field to a Cordis key and Remote namespace.
37
59
  * @param service - owning Service instance, normally `this`.
@@ -64,77 +86,99 @@ var TypertRemoteService = class extends Service {
64
86
  this.typertRemote = bindTypertRemote(this, this.name, options);
65
87
  }
66
88
  };
67
- function Remote(methodOrExportName, context) {
68
- if (typeof methodOrExportName === "string") {
69
- validateName("Remote export name", methodOrExportName);
70
- return function(_method, decoratorContext) {
71
- addMarkerInitializer(decoratorContext, { kind: "direct" }, methodOrExportName);
72
- };
89
+ function Remote(methodExportOrOptions, context) {
90
+ if (typeof methodExportOrOptions === "string") {
91
+ validateName("Remote export name", methodExportOrOptions);
92
+ return remoteDecorator({ kind: "direct" }, void 0, methodExportOrOptions);
93
+ }
94
+ if (typeof methodExportOrOptions === "object") {
95
+ if (remoteOptionMode(methodExportOrOptions) !== "stream" || Reflect.ownKeys(methodExportOrOptions).length !== 1) throw new TypeError("typert-protocol: Remote options must contain exactly mode: \"stream\"");
96
+ return remoteDecorator({ kind: "direct" }, "stream");
73
97
  }
74
98
  if (context === void 0) throw new TypeError("typert-protocol: Remote decorator context is missing");
75
99
  addMarkerInitializer(context, { kind: "direct" });
76
100
  }
101
+ function remoteOptionMode(options) {
102
+ return Reflect.get(options, "mode");
103
+ }
104
+ function remoteDecorator(invocation, mode, exportName) {
105
+ return function(_method, context) {
106
+ addMarkerInitializer(context, invocation, mode, exportName);
107
+ };
108
+ }
77
109
  /**
78
110
  * Create a decorator for a method resolved from one Remote Scope.
79
111
  * @param key - scope key declared through the Context map.
80
112
  * @param exportName - optional Remote export name; defaults to the method name.
81
- * @returns a standard method decorator that records only private module state.
113
+ * @returns a standard method decorator that records a versioned prototype descriptor.
82
114
  */
83
115
  function RemoteScope(key, exportName) {
84
116
  validateName("Scope key", key);
85
117
  if (exportName !== void 0) validateName("Remote export name", exportName);
86
- return function(_method, context) {
87
- addMarkerInitializer(context, {
88
- kind: "context",
89
- context: key
90
- }, exportName);
91
- };
118
+ return remoteDecorator({
119
+ kind: "context",
120
+ context: key
121
+ }, void 0, exportName);
92
122
  }
93
123
  /**
94
- * Read Remote markers attached to a live Service by decorator initializers.
95
- * The returned snapshot cannot mutate the private marker table.
124
+ * Read Remote markers attached to a live Service's class prototype.
125
+ * The returned snapshot cannot mutate the stored descriptor.
96
126
  * @param service - live Service instance.
97
127
  * @returns markers in class declaration order.
98
128
  */
99
129
  function remoteMethods(service) {
100
130
  const prototype = Object.getPrototypeOf(service);
101
131
  if (prototype === null) return [];
102
- return [...markers.get(prototype) ?? []].map(([method, marker]) => ({
103
- method,
104
- ...marker
105
- }));
132
+ return (readRemoteMethodDescriptor(prototype)?.methods ?? []).map((marker) => ({ ...marker }));
133
+ }
134
+ function readRemoteMethodDescriptor(prototype) {
135
+ const property = Object.getOwnPropertyDescriptor(prototype, REMOTE_METHOD_DESCRIPTOR);
136
+ if (property === void 0) return void 0;
137
+ const descriptor = property.value;
138
+ if (descriptor === null || typeof descriptor !== "object") throw new TypeError("typert-protocol: Remote method descriptor must be an object");
139
+ const version = Reflect.get(descriptor, "version");
140
+ if (version !== 1) throw new TypeError(`typert-protocol: unsupported Remote method descriptor version ${String(version)}`);
141
+ const methods = Reflect.get(descriptor, "methods");
142
+ if (!Array.isArray(methods)) throw new TypeError("typert-protocol: Remote method descriptor methods must be an array");
143
+ return descriptor;
106
144
  }
107
- function addMarkerInitializer(context, invocation, exportName) {
145
+ function addMarkerInitializer(context, invocation, mode, exportName) {
108
146
  if (context.private || context.static || typeof context.name !== "string") throw new TypeError("typert-protocol: Remote decorators require a public instance method with a string name");
109
147
  const method = context.name;
110
148
  context.addInitializer(function() {
111
149
  const prototype = Object.getPrototypeOf(this);
112
150
  if (prototype === null) throw new TypeError(`typert-protocol: cannot mark Remote method "${method}" on an object without a prototype`);
113
- mark(prototype, method, invocation, exportName);
151
+ mark(prototype, method, invocation, mode, exportName);
114
152
  });
115
153
  }
116
- function mark(prototype, method, invocation, exportName) {
117
- let table = markers.get(prototype);
118
- if (table === void 0) {
119
- table = /* @__PURE__ */ new Map();
120
- markers.set(prototype, table);
121
- }
122
- const marker = {
154
+ function mark(prototype, method, invocation, mode, exportName) {
155
+ const descriptor = readRemoteMethodDescriptor(prototype);
156
+ const marker = Object.freeze({
157
+ method,
123
158
  ...exportName === void 0 || exportName === method ? {} : { exportName },
159
+ ...mode === void 0 ? {} : { mode },
124
160
  invocation: Object.freeze(invocation)
125
- };
126
- const current = table.get(method);
161
+ });
162
+ const current = descriptor?.methods.find((candidate) => candidate.method === method);
127
163
  if (current !== void 0) {
128
- if (current.exportName === marker.exportName && sameInvocation(current.invocation, invocation)) return;
164
+ if (current.exportName === marker.exportName && current.mode === marker.mode && sameInvocation(current.invocation, invocation)) return;
129
165
  throw new Error(`typert-protocol: Remote method "${method}" has conflicting invocation markers`);
130
166
  }
131
- table.set(method, Object.freeze(marker));
167
+ Object.defineProperty(prototype, REMOTE_METHOD_DESCRIPTOR, {
168
+ configurable: true,
169
+ value: Object.freeze({
170
+ version: 1,
171
+ methods: Object.freeze([...descriptor?.methods ?? [], marker])
172
+ })
173
+ });
132
174
  }
133
175
  function sameInvocation(left, right) {
134
- return left.kind === right.kind && (left.kind === "direct" || right.kind === "context" && left.context === right.context);
176
+ if (left.kind === "direct") return right.kind === "direct";
177
+ if (right.kind === "direct") return false;
178
+ return left.context === right.context;
135
179
  }
136
180
  function validateName(subject, value) {
137
181
  if (!isTypertRemoteSegment(value)) throw new TypeError(`typert-protocol: ${subject} must contain only RPC endpoint segment characters`);
138
182
  }
139
183
  //#endregion
140
- export { Remote, RemoteScope, TypertLookupFailure, TypertRemoteService, bindTypertRemote, isTypertRemoteSegment, remoteMethods };
184
+ export { Remote, RemoteError, RemoteScope, TypertRemoteService, bindTypertRemote, isTypertRemoteSegment, remoteErrorOf, remoteMethods };
@@ -1,30 +1,19 @@
1
1
  /**
2
- * Remote decorators and explicit Gateway bindings backed only by private
3
- * module state. Strict reflection remains a Typert compiler responsibility.
2
+ * Remote decorators and explicit Gateway bindings backed by versioned
3
+ * descriptors carried on decorated class prototypes. Strict reflection
4
+ * remains a Typert compiler responsibility.
4
5
  * @module @deepseek-ai/dsh-typert-protocol
5
6
  */
6
7
  import { Service, type Context } from '@deepseek-ai/cordis';
7
8
  import type { TypertContextMap } from './types.ts';
9
+ export { RemoteError, remoteErrorOf } from './remote-error.ts';
8
10
  /**
9
11
  * Test one generated Remote name against the Connection endpoint grammar.
10
12
  * @param value - namespace, method, lookup, or Context segment.
11
13
  * @returns whether the value can cross the shared RPC carrier unchanged.
12
14
  */
13
15
  export declare function isTypertRemoteSegment(value: string): boolean;
14
- /**
15
- * A lookup policy rejection whose typed payload belongs to the active boundary adapter.
16
- * Gateway adapters preserve this payload instead of collapsing it into an infrastructure failure.
17
- */
18
- export declare class TypertLookupFailure<Failure = unknown> extends Error {
19
- /** Adapter-owned failure returned to the caller. */
20
- readonly failure: Failure;
21
- /**
22
- * Wrap one adapter failure without exposing the rejected identity.
23
- * @param failure - typed failure owned by the active boundary adapter.
24
- */
25
- constructor(failure: Failure);
26
- }
27
- export type { InvocationDescriptor, InvocationParameterDescriptor, InvocationSourceLocation, RemoteFailure, RemoteResult, TypertClientRemote, TypertClientContextBinder, TypertCodec, TypertContext, TypertContextMap, TypertContextRegistry, TypertContextWire, TypertDisposer, TypertForwardableEvent, TypertHostContextProvider, TypertHostContextResolver, TypertLocalRegistry, TypertLookup, TypertLookupDefinition, TypertLookupHost, TypertLookupMap, TypertLookupProvider, TypertLookupResolver, TypertLookupRegistry, TypertLookupWire, TypertRemoteScopeApi, TypertRemoteScopeMap, TypertRemoteScopeNamespace, TypertRemoteContribution, TypertRemoteEvent, TypertRemoteEventSelection, TypertRemoteMap, TypertRemoteNamespace, TypertRemoteNamespaceMap, TypertRemoteRegistry, TypertRegistryChange, TypertRegistryListener, TypertSchema, TypertRegistryContract, } from './types.ts';
16
+ export type { InvocationDescriptor, InvocationParameterDescriptor, InvocationSourceLocation, RemoteErrorCode, RemoteErrorDetailsMap, RemoteFailure, RemoteResult, TypertClientEventListener, TypertClientRemote, TypertClientContextAdapter, TypertCodec, TypertContext, TypertContextAdapter, TypertContextMap, TypertContextRegistry, TypertContextWire, TypertDisposer, TypertForwardableEvent, TypertForwardableEventEntry, TypertHostContextAdapter, TypertHostContextIdentity, TypertHostContextResolver, TypertLocalRegistry, TypertLookup, TypertLookupDefinition, TypertLookupHost, TypertLookupMap, TypertLookupProvider, TypertLookupResolver, TypertLookupRegistry, TypertLookupWire, TypertRemoteScopeApi, TypertRemoteScopeMap, TypertRemoteScopeNamespace, TypertRemoteContribution, TypertRemoteEvent, TypertRemoteEventSelection, TypertRemoteMap, TypertRemoteNamespace, TypertRemoteNamespaceMap, TypertRemoteRegistry, TypertRegistryChange, TypertRegistryListener, TypertSchema, TypertRegistryContract, } from './types.ts';
28
17
  /** Options for an explicit Service-to-Gateway binding. */
29
18
  export interface TypertGatewayBindingOptions {
30
19
  /** Wire namespace; defaults to the Cordis service key. */
@@ -49,8 +38,15 @@ export interface RemoteMethodMarker {
49
38
  readonly method: string;
50
39
  /** Endpoint method when it differs from the implementation member. */
51
40
  readonly exportName?: string;
41
+ /** Stream methods yield many independently validated result items. */
42
+ readonly mode?: 'stream';
52
43
  readonly invocation: RemoteInvocationMarker;
53
44
  }
45
+ /** Options for a non-unary Remote method. */
46
+ export interface RemoteMethodOptions {
47
+ /** Deliver each Iterable item over the shared logical-stream carrier. */
48
+ readonly mode: 'stream';
49
+ }
54
50
  type RemoteMethodDecorator = <This extends object, Args extends unknown[], Result>(method: (this: This, ...args: Args) => Result, context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Result>) => void;
55
51
  /**
56
52
  * Bind one visible Service field to a Cordis key and Remote namespace.
@@ -79,21 +75,21 @@ export declare abstract class TypertRemoteService<out T = never> extends Service
79
75
  */
80
76
  export declare function Remote<This extends object, Args extends unknown[], Result>(_method: (this: This, ...args: Args) => Result, context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Result>): void;
81
77
  /**
82
- * Mark one public instance method under a distinct exported method name.
83
- * @param exportName - Remote endpoint method, without a namespace or slash.
78
+ * Mark one public instance method under an exported name or as a logical stream.
79
+ * @param option - endpoint method name or stream delivery mode.
84
80
  * @returns a standard method decorator.
85
81
  */
86
- export declare function Remote(exportName: string): RemoteMethodDecorator;
82
+ export declare function Remote(option: string | RemoteMethodOptions): RemoteMethodDecorator;
87
83
  /**
88
84
  * Create a decorator for a method resolved from one Remote Scope.
89
85
  * @param key - scope key declared through the Context map.
90
86
  * @param exportName - optional Remote export name; defaults to the method name.
91
- * @returns a standard method decorator that records only private module state.
87
+ * @returns a standard method decorator that records a versioned prototype descriptor.
92
88
  */
93
89
  export declare function RemoteScope(key: Extract<keyof TypertContextMap, string>, exportName?: string): RemoteMethodDecorator;
94
90
  /**
95
- * Read Remote markers attached to a live Service by decorator initializers.
96
- * The returned snapshot cannot mutate the private marker table.
91
+ * Read Remote markers attached to a live Service's class prototype.
92
+ * The returned snapshot cannot mutate the stored descriptor.
97
93
  * @param service - live Service instance.
98
94
  * @returns markers in class declaration order.
99
95
  */
@@ -1,9 +1,11 @@
1
1
  /**
2
- * Remote decorators and explicit Gateway bindings backed only by private
3
- * module state. Strict reflection remains a Typert compiler responsibility.
2
+ * Remote decorators and explicit Gateway bindings backed by versioned
3
+ * descriptors carried on decorated class prototypes. Strict reflection
4
+ * remains a Typert compiler responsibility.
4
5
  * @module @deepseek-ai/dsh-typert-protocol
5
6
  */
6
7
  import { Service } from '@deepseek-ai/cordis';
8
+ export { RemoteError, remoteErrorOf } from "./remote-error.js";
7
9
  const TYPERT_REMOTE_SEGMENT_PATTERN = /^[A-Za-z0-9_$.-]+$/;
8
10
  /**
9
11
  * Test one generated Remote name against the Connection endpoint grammar.
@@ -13,24 +15,7 @@ const TYPERT_REMOTE_SEGMENT_PATTERN = /^[A-Za-z0-9_$.-]+$/;
13
15
  export function isTypertRemoteSegment(value) {
14
16
  return value !== '.' && value !== '..' && TYPERT_REMOTE_SEGMENT_PATTERN.test(value);
15
17
  }
16
- /**
17
- * A lookup policy rejection whose typed payload belongs to the active boundary adapter.
18
- * Gateway adapters preserve this payload instead of collapsing it into an infrastructure failure.
19
- */
20
- export class TypertLookupFailure extends Error {
21
- /** Adapter-owned failure returned to the caller. */
22
- failure;
23
- /**
24
- * Wrap one adapter failure without exposing the rejected identity.
25
- * @param failure - typed failure owned by the active boundary adapter.
26
- */
27
- constructor(failure) {
28
- super('Typert lookup policy rejected the requested identity');
29
- this.name = 'TypertLookupFailure';
30
- this.failure = failure;
31
- }
32
- }
33
- const markers = new WeakMap();
18
+ const REMOTE_METHOD_DESCRIPTOR = '@deepseek-ai/dsh-typert-protocol/remote-methods';
34
19
  /**
35
20
  * Bind one visible Service field to a Cordis key and Remote namespace.
36
21
  * @param service - owning Service instance, normally `this`.
@@ -59,34 +44,45 @@ export class TypertRemoteService extends Service {
59
44
  this.typertRemote = bindTypertRemote(this, this.name, options);
60
45
  }
61
46
  }
62
- export function Remote(methodOrExportName, context) {
63
- if (typeof methodOrExportName === 'string') {
64
- validateName('Remote export name', methodOrExportName);
65
- return function (_method, decoratorContext) {
66
- addMarkerInitializer(decoratorContext, { kind: 'direct' }, methodOrExportName);
67
- };
47
+ export function Remote(methodExportOrOptions, context) {
48
+ if (typeof methodExportOrOptions === 'string') {
49
+ validateName('Remote export name', methodExportOrOptions);
50
+ return remoteDecorator({ kind: 'direct' }, undefined, methodExportOrOptions);
51
+ }
52
+ if (typeof methodExportOrOptions === 'object') {
53
+ if (remoteOptionMode(methodExportOrOptions) !== 'stream'
54
+ || Reflect.ownKeys(methodExportOrOptions).length !== 1) {
55
+ throw new TypeError('typert-protocol: Remote options must contain exactly mode: "stream"');
56
+ }
57
+ return remoteDecorator({ kind: 'direct' }, 'stream');
68
58
  }
69
59
  if (context === undefined)
70
60
  throw new TypeError('typert-protocol: Remote decorator context is missing');
71
61
  addMarkerInitializer(context, { kind: 'direct' });
72
62
  }
63
+ function remoteOptionMode(options) {
64
+ return Reflect.get(options, 'mode');
65
+ }
66
+ function remoteDecorator(invocation, mode, exportName) {
67
+ return function (_method, context) {
68
+ addMarkerInitializer(context, invocation, mode, exportName);
69
+ };
70
+ }
73
71
  /**
74
72
  * Create a decorator for a method resolved from one Remote Scope.
75
73
  * @param key - scope key declared through the Context map.
76
74
  * @param exportName - optional Remote export name; defaults to the method name.
77
- * @returns a standard method decorator that records only private module state.
75
+ * @returns a standard method decorator that records a versioned prototype descriptor.
78
76
  */
79
77
  export function RemoteScope(key, exportName) {
80
78
  validateName('Scope key', key);
81
79
  if (exportName !== undefined)
82
80
  validateName('Remote export name', exportName);
83
- return function (_method, context) {
84
- addMarkerInitializer(context, { kind: 'context', context: key }, exportName);
85
- };
81
+ return remoteDecorator({ kind: 'context', context: key }, undefined, exportName);
86
82
  }
87
83
  /**
88
- * Read Remote markers attached to a live Service by decorator initializers.
89
- * The returned snapshot cannot mutate the private marker table.
84
+ * Read Remote markers attached to a live Service's class prototype.
85
+ * The returned snapshot cannot mutate the stored descriptor.
90
86
  * @param service - live Service instance.
91
87
  * @returns markers in class declaration order.
92
88
  */
@@ -94,9 +90,27 @@ export function remoteMethods(service) {
94
90
  const prototype = Object.getPrototypeOf(service);
95
91
  if (prototype === null)
96
92
  return [];
97
- return [...(markers.get(prototype) ?? [])].map(([method, marker]) => ({ method, ...marker }));
93
+ return (readRemoteMethodDescriptor(prototype)?.methods ?? []).map(marker => ({ ...marker }));
98
94
  }
99
- function addMarkerInitializer(context, invocation, exportName) {
95
+ function readRemoteMethodDescriptor(prototype) {
96
+ const property = Object.getOwnPropertyDescriptor(prototype, REMOTE_METHOD_DESCRIPTOR);
97
+ if (property === undefined)
98
+ return undefined;
99
+ const descriptor = property.value;
100
+ if (descriptor === null || typeof descriptor !== 'object') {
101
+ throw new TypeError('typert-protocol: Remote method descriptor must be an object');
102
+ }
103
+ const version = Reflect.get(descriptor, 'version');
104
+ if (version !== 1) {
105
+ throw new TypeError(`typert-protocol: unsupported Remote method descriptor version ${String(version)}`);
106
+ }
107
+ const methods = Reflect.get(descriptor, 'methods');
108
+ if (!Array.isArray(methods)) {
109
+ throw new TypeError('typert-protocol: Remote method descriptor methods must be an array');
110
+ }
111
+ return descriptor;
112
+ }
113
+ function addMarkerInitializer(context, invocation, mode, exportName) {
100
114
  if (context.private || context.static || typeof context.name !== 'string') {
101
115
  throw new TypeError('typert-protocol: Remote decorators require a public instance method with a string name');
102
116
  }
@@ -106,30 +120,39 @@ function addMarkerInitializer(context, invocation, exportName) {
106
120
  if (prototype === null) {
107
121
  throw new TypeError(`typert-protocol: cannot mark Remote method "${method}" on an object without a prototype`);
108
122
  }
109
- mark(prototype, method, invocation, exportName);
123
+ mark(prototype, method, invocation, mode, exportName);
110
124
  });
111
125
  }
112
- function mark(prototype, method, invocation, exportName) {
113
- let table = markers.get(prototype);
114
- if (table === undefined) {
115
- table = new Map();
116
- markers.set(prototype, table);
117
- }
118
- const marker = {
126
+ function mark(prototype, method, invocation, mode, exportName) {
127
+ const descriptor = readRemoteMethodDescriptor(prototype);
128
+ const marker = Object.freeze({
129
+ method,
119
130
  ...(exportName === undefined || exportName === method ? {} : { exportName }),
131
+ ...(mode === undefined ? {} : { mode }),
120
132
  invocation: Object.freeze(invocation),
121
- };
122
- const current = table.get(method);
133
+ });
134
+ const current = descriptor?.methods.find(candidate => candidate.method === method);
123
135
  if (current !== undefined) {
124
- if (current.exportName === marker.exportName && sameInvocation(current.invocation, invocation))
136
+ if (current.exportName === marker.exportName
137
+ && current.mode === marker.mode
138
+ && sameInvocation(current.invocation, invocation))
125
139
  return;
126
140
  throw new Error(`typert-protocol: Remote method "${method}" has conflicting invocation markers`);
127
141
  }
128
- table.set(method, Object.freeze(marker));
142
+ Object.defineProperty(prototype, REMOTE_METHOD_DESCRIPTOR, {
143
+ configurable: true,
144
+ value: Object.freeze({
145
+ version: 1,
146
+ methods: Object.freeze([...(descriptor?.methods ?? []), marker]),
147
+ }),
148
+ });
129
149
  }
130
150
  function sameInvocation(left, right) {
131
- return left.kind === right.kind
132
- && (left.kind === 'direct' || (right.kind === 'context' && left.context === right.context));
151
+ if (left.kind === 'direct')
152
+ return right.kind === 'direct';
153
+ if (right.kind === 'direct')
154
+ return false;
155
+ return left.context === right.context;
133
156
  }
134
157
  function validateName(subject, value) {
135
158
  if (!isTypertRemoteSegment(value)) {
@@ -0,0 +1,31 @@
1
+ /** The one Remote failure class shared by owners, the Gateway, and consumers. */
2
+ import type { RemoteErrorCode, RemoteErrorDetailsMap, RemoteFailure } from './types.ts';
3
+ /**
4
+ * One Remote call failure: a real Error carrying its stable code and typed
5
+ * details. Owners throw it at the failure point; the Host Gateway encodes it
6
+ * onto the wire unchanged; the Client face rebuilds an instance for the
7
+ * `RemoteResult` error branch, so `throw result.error` keeps throw semantics.
8
+ * Discrimination is always by `code`, never by instanceof.
9
+ */
10
+ export declare class RemoteError<Code extends RemoteErrorCode = RemoteErrorCode> extends Error {
11
+ readonly code: Code;
12
+ readonly details: RemoteErrorDetailsMap[Code];
13
+ /** Structural marker: cross-realm/bundle identification never uses instanceof. */
14
+ readonly isDSHRemoteError: true;
15
+ /**
16
+ * @param code - stable failure code declared in {@link RemoteErrorDetailsMap}.
17
+ * @param message - human diagnostic carried across the wire.
18
+ * @param details - structured payload typed by the code.
19
+ * @param options - standard Error options (`cause` survives in-process only).
20
+ */
21
+ constructor(code: Code, message: string, details: RemoteErrorDetailsMap[Code], options?: ErrorOptions);
22
+ }
23
+ /**
24
+ * Structurally identify a RemoteError thrown across module or realm copies of
25
+ * this class. Mechanism-internal: the Gateway and test assertions use it;
26
+ * business code receives typed failures and never needs it.
27
+ * @param value - a caught value.
28
+ * @returns the failure when the marker matches, otherwise undefined.
29
+ */
30
+ export declare function remoteErrorOf(value: unknown): RemoteFailure | undefined;
31
+ //# sourceMappingURL=remote-error.d.ts.map
@@ -0,0 +1,44 @@
1
+ /** The one Remote failure class shared by owners, the Gateway, and consumers. */
2
+ /**
3
+ * One Remote call failure: a real Error carrying its stable code and typed
4
+ * details. Owners throw it at the failure point; the Host Gateway encodes it
5
+ * onto the wire unchanged; the Client face rebuilds an instance for the
6
+ * `RemoteResult` error branch, so `throw result.error` keeps throw semantics.
7
+ * Discrimination is always by `code`, never by instanceof.
8
+ */
9
+ export class RemoteError extends Error {
10
+ code;
11
+ details;
12
+ /** Structural marker: cross-realm/bundle identification never uses instanceof. */
13
+ isDSHRemoteError = true;
14
+ /**
15
+ * @param code - stable failure code declared in {@link RemoteErrorDetailsMap}.
16
+ * @param message - human diagnostic carried across the wire.
17
+ * @param details - structured payload typed by the code.
18
+ * @param options - standard Error options (`cause` survives in-process only).
19
+ */
20
+ constructor(code, message, details, options) {
21
+ super(message, options);
22
+ this.code = code;
23
+ this.details = details;
24
+ this.name = 'RemoteError';
25
+ }
26
+ }
27
+ /**
28
+ * Structurally identify a RemoteError thrown across module or realm copies of
29
+ * this class. Mechanism-internal: the Gateway and test assertions use it;
30
+ * business code receives typed failures and never needs it.
31
+ * @param value - a caught value.
32
+ * @returns the failure when the marker matches, otherwise undefined.
33
+ */
34
+ export function remoteErrorOf(value) {
35
+ // Structural, not instanceof: an Error thrown in another realm (iframe, VM)
36
+ // fails instanceof Error here, so the marker plus the code field is the test.
37
+ if (typeof value === 'object' && value !== null
38
+ && value.isDSHRemoteError === true
39
+ && typeof value.code === 'string') {
40
+ return value;
41
+ }
42
+ return undefined;
43
+ }
44
+ //# sourceMappingURL=remote-error.js.map
@@ -32,20 +32,34 @@ export interface TypertContextMap {
32
32
  export interface TypertRemoteMap {
33
33
  }
34
34
  /**
35
- * One Remote call's failure as the carrier reported it. `code` stays open here:
36
- * the closed RPC code union belongs to the carrier package, which already
37
- * depends on this one, so naming it would invert that edge.
35
+ * Merge-extensible Remote failure vocabulary: this package declares the
36
+ * universal carrier codes once; the Gateway merges its infrastructure codes
37
+ * and every owner merges its domain codes next to the throwing code.
38
38
  */
39
- export interface RemoteFailure {
40
- readonly code: string;
41
- readonly message: string;
42
- readonly details: object;
39
+ export interface RemoteErrorDetailsMap {
40
+ /** Owner-side business validation refused the request; `issues` carries codec output when one produced it. */
41
+ 'gateway/bad-request': {
42
+ readonly issues?: readonly object[];
43
+ };
44
+ /** The call was cancelled by the carrier signal or the backend. */
45
+ 'gateway/cancelled': {};
46
+ /** Carrier, dispatch, or unclassified Host failure. */
47
+ 'gateway/internal': {};
43
48
  }
49
+ /** Every declared Remote failure code. */
50
+ export type RemoteErrorCode = keyof RemoteErrorDetailsMap;
51
+ /**
52
+ * One Remote call's failure: the code-discriminated union of RemoteError
53
+ * instances, so a `code` branch narrows `details` with no cast.
54
+ */
55
+ export type RemoteFailure = {
56
+ [Code in RemoteErrorCode]: import('./remote-error.ts').RemoteError<Code>;
57
+ }[RemoteErrorCode];
44
58
  /**
45
59
  * What every generated Remote method resolves to. The Remote face itself folds
46
60
  * carrier failures into the error branch, so no consumer wraps a call to
47
61
  * recover one; only assembly faults (arity, an unmounted method, a missing
48
- * Context binder) still reject.
62
+ * Context adapter) still reject.
49
63
  * @template T - the Host method's business result.
50
64
  */
51
65
  export type RemoteResult<T> = {
@@ -58,20 +72,47 @@ export type RemoteResult<T> = {
58
72
  /** Merge-extensible scoped Remote method signatures generated for consumers. */
59
73
  export interface TypertRemoteScopeMap {
60
74
  }
75
+ type TypertEventParameters<Event extends keyof Events> = Events[Event] extends (...args: infer Args) => unknown ? Args : never;
76
+ type TypertEventResult<Event extends keyof Events> = Events[Event] extends (...args: never[]) => infer Result ? Result : never;
77
+ type TypertProjectedContextKey = Extract<keyof TypertLookupMap, keyof TypertContextMap>;
78
+ type TypertProjectedContextSubject = {
79
+ [Key in TypertProjectedContextKey]: TypertLookupHost<TypertLookupMap[Key]>;
80
+ }[TypertProjectedContextKey];
81
+ type TypertAgentScopedRequest<Request> = Request extends object ? 'agent' extends keyof Request ? Exclude<Request['agent'], undefined> extends TypertProjectedContextSubject ? Request : never : never : never;
82
+ type TypertWaterfallEvent<Event extends keyof Events> = unknown extends ThisParameterType<Events[Event]> ? never : TypertEventParameters<Event> extends [infer Request, infer Next] ? Next extends () => TypertEventResult<Event> ? TypertEventResult<Event> extends Promise<unknown> ? TypertAgentScopedRequest<Request> extends never ? never : Event : never : never : never;
83
+ type TypertForwardingMode<Event extends keyof Events> = unknown extends ThisParameterType<Events[Event]> ? TypertEventResult<Event> extends void ? 'emit' : never : TypertWaterfallEvent<Event> extends never ? never : 'waterfall';
61
84
  /**
62
- * Cordis event names whose shape a one-way Remote delivery can carry: unbound
63
- * from any Scope and returning `void`. Which ones are actually forwarded is the
64
- * Host assembly's selection; this predicate only excludes shapes the carrier
65
- * cannot represent.
85
+ * Cordis event names the Remote Event carrier can preserve without a second
86
+ * signature declaration: unscoped `void` notifications and scoped async
87
+ * waterfalls whose final parameter is their same-result `next()` callback.
66
88
  */
67
89
  export type TypertForwardableEvent = {
68
- [Event in keyof Events]: unknown extends ThisParameterType<Events[Event]> ? ReturnType<Events[Event]> extends void ? Event : never : never;
90
+ [Event in keyof Events]: TypertForwardingMode<Event> extends never ? never : Event;
91
+ }[keyof Events];
92
+ /** Event and dispatch mode accepted by the Remote Event source. */
93
+ export type TypertForwardableEventEntry = {
94
+ [Event in keyof Events]: TypertForwardingMode<Event> extends infer Mode ? Mode extends 'emit' | 'waterfall' ? {
95
+ readonly event: Event;
96
+ readonly mode: Mode;
97
+ } : never : never;
69
98
  }[keyof Events];
70
99
  /** Merge-extensible forwarding selection declared once by the Host assembly. */
71
100
  export interface TypertRemoteEventSelection {
72
101
  }
73
- /** Legal `$on` keys: selected events that exist in the current compilation face. */
74
- export type TypertRemoteEvent = Extract<keyof Events, keyof TypertRemoteEventSelection>;
102
+ /** Legal `$on` keys selected from the carrier-compatible Cordis event declarations. */
103
+ export type TypertRemoteEvent = Extract<TypertForwardableEvent, keyof TypertRemoteEventSelection>;
104
+ type TypertClientAgent<Value> = Exclude<Value, undefined> extends TypertProjectedContextSubject ? Context | Extract<Value, undefined> : Value;
105
+ type TypertClientEventRequest<Request> = Request extends object ? {
106
+ [Key in keyof Request]: Key extends 'agent' ? TypertClientAgent<Request[Key]> : Request[Key];
107
+ } : never;
108
+ type TypertScopedClientEventListener<Event extends TypertRemoteEvent> = Events[Event] extends (request: infer Request, next: infer Next) => infer Result ? (this: Context, request: TypertClientEventRequest<Request>, next: Next) => Result : never;
109
+ /**
110
+ * Listener derived from one selected Cordis event declaration. Scoped Host
111
+ * subjects become the resolved Client `Context`; one-way notifications retain
112
+ * their declaration unchanged.
113
+ * @template Event - selected Remote Event name.
114
+ */
115
+ export type TypertClientEventListener<Event extends TypertRemoteEvent> = unknown extends ThisParameterType<Events[Event]> ? Events[Event] : TypertScopedClientEventListener<Event>;
75
116
  /**
76
117
  * Resolve one direct Remote namespace from the generated flat endpoint map.
77
118
  * @template Namespace - wire namespace before the endpoint slash.
@@ -148,6 +189,8 @@ export interface InvocationDescriptor {
148
189
  readonly method: string;
149
190
  /** Service member invoked when the exported method name is an alias. */
150
191
  readonly implementation?: string;
192
+ /** Absent for unary calls; stream calls validate and deliver every yielded item. */
193
+ readonly mode?: 'stream';
151
194
  /** Receiver selection mode. */
152
195
  readonly invocation: {
153
196
  readonly kind: 'direct';
@@ -159,7 +202,7 @@ export interface InvocationDescriptor {
159
202
  };
160
203
  /** Optional consuming-Context projection for one direct lookup parameter. */
161
204
  readonly scope?: {
162
- /** Context kind whose Client binder supplies the identity. */
205
+ /** Context kind whose Client adapter supplies the identity. */
163
206
  readonly context: string;
164
207
  /** Lookup parameter wire field replaced by the Context identity. */
165
208
  readonly wire: string;
@@ -171,7 +214,7 @@ export interface InvocationDescriptor {
171
214
  /** Reserved final Host method parameter. */
172
215
  readonly parameter: 'signal';
173
216
  };
174
- /** Codec for the resolved method result. */
217
+ /** Codec for the unary result or each yielded stream item. */
175
218
  readonly result: TypertCodec;
176
219
  /** Source declaration used only for diagnostics. */
177
220
  readonly sourceLocation?: InvocationSourceLocation;
@@ -192,26 +235,15 @@ export interface TypertClientRemote extends TypertRemoteNamespaceMap {
192
235
  */
193
236
  $mount(contribution: TypertRemoteContribution): Promise<TypertDisposer>;
194
237
  /**
195
- * Subscribe to one forwarded Host event; delivery is one-way, in registration
196
- * order, and isolates a throwing listener from the rest.
238
+ * Subscribe to one forwarded Host event. Notifications run in registration
239
+ * order and isolate failures; scoped waterfalls return, delegate through
240
+ * `next()`, or reject the Host dispatch.
197
241
  * @template Event - forwarded event name selected by the Host assembly.
198
242
  * @param event - forwarded Host event name, unchanged on the wire.
199
- * @param listener - receives the Host's argument list as declared by Cordis `Events`.
243
+ * @param listener - receives the Client projection of the Cordis `Events` declaration.
200
244
  * @returns disposer owned by the calling fiber.
201
245
  */
202
- $on<Event extends TypertRemoteEvent>(event: Event, listener: Events[Event]): () => void;
203
- /**
204
- * Hand one decoded forwarded frame to the subscription table. The carrier
205
- * owning the Host frame sink calls this; a consumer subscribes with
206
- * {@link TypertClientRemote.$on} and never calls it.
207
- *
208
- * `event` is a plain string because this is the wire boundary: the name is
209
- * whatever the Host assembly's allowlist selected, and one nobody subscribed
210
- * to is dropped silently.
211
- * @param event - forwarded Host event name, exactly as the Host emitted it.
212
- * @param args - the Host argument list, already JSON-decoded.
213
- */
214
- $dispatch(event: string, args: readonly unknown[]): void;
246
+ $on<Event extends TypertRemoteEvent>(event: Event, listener: TypertClientEventListener<Event>): () => void;
215
247
  }
216
248
  /**
217
249
  * Resolve one validated wire identity, synchronously or asynchronously.
@@ -249,29 +281,52 @@ export interface TypertLookupDefinition {
249
281
  /** Canonical wire type symbol used by strict generation. */
250
282
  readonly wireTypeSymbol: string;
251
283
  }
252
- /** Host resolver for one scoped Remote kind. */
253
- export interface TypertHostContextProvider<Wire = unknown> {
254
- /** Wire field carrying the Context identity. */
255
- readonly wire: string;
256
- /** Canonical wire type symbol used by strict generation. */
257
- readonly wireTypeSymbol: string;
284
+ /** Bidirectional projection between one environment's Context and its wire identity. */
285
+ export interface TypertContextAdapter<Wire = unknown> {
258
286
  /**
259
- * Resolve a wire identity to its live scoped Context.
287
+ * Read the identity represented by a live Context.
288
+ * @param ctx - Context in this adapter's environment.
289
+ * @returns the wire identity, or `undefined` when the Context has another kind.
290
+ */
291
+ identity(ctx: Context): Wire | undefined;
292
+ /**
293
+ * Resolve a wire identity to a live Context in this adapter's environment.
294
+ * An asynchronous Client resolver may wait for its owner to create the Context.
260
295
  * @param id - validated wire identity.
261
- * @returns the scoped Context, or `undefined` when unavailable.
296
+ * @returns the Context, or `undefined` when it is unavailable.
262
297
  */
263
298
  resolve(id: Wire): Context | undefined | Promise<Context | undefined>;
264
299
  }
265
- /** Composition-owned resolver replacing one Host Context provider's default lookup policy. */
300
+ /** Host Context adapter plus the wire declaration used by strict Remote methods. */
301
+ export interface TypertHostContextAdapter<Wire = unknown> extends TypertContextAdapter<Wire> {
302
+ /** Wire field carrying the Context identity. */
303
+ readonly wire: string;
304
+ /** Canonical wire type symbol used by strict generation. */
305
+ readonly wireTypeSymbol: string;
306
+ }
307
+ /** Composition-owned resolver replacing one Host Context adapter's default lookup policy. */
266
308
  export type TypertHostContextResolver<Wire = unknown> = (id: Wire) => Context | undefined | Promise<Context | undefined>;
267
- /** Client resolver for the identity carried by the calling scoped Context. */
268
- export interface TypertClientContextBinder<Wire = unknown> {
309
+ /** Client-side bidirectional Context adapter. */
310
+ export interface TypertClientContextAdapter<Wire = unknown> {
269
311
  /**
270
- * Read the Remote identity represented by a calling Context.
271
- * @param ctx - Context rebound by the Cordis service tracker.
272
- * @returns the wire identity, or `undefined` when the Context has the wrong scope.
312
+ * Read the identity represented by a live Client Context.
313
+ * @param ctx - Client Context inspected by a scoped Remote caller.
314
+ * @returns the wire identity, or `undefined` for another Context kind.
273
315
  */
274
316
  identity(ctx: Context): Wire | undefined;
317
+ /**
318
+ * Resolve a wire identity from the Client's currently materialized Contexts.
319
+ * @param id - validated wire identity.
320
+ * @returns the Client Context, or `undefined` when unavailable.
321
+ */
322
+ resolve(id: Wire): Context | undefined;
323
+ }
324
+ /** Host Context identity selected from the registered adapter set. */
325
+ export interface TypertHostContextIdentity {
326
+ /** Merge-declared Context kind whose adapter recognized the Context. */
327
+ readonly kind: string;
328
+ /** Wire identity returned by that adapter. */
329
+ readonly identity: unknown;
275
330
  }
276
331
  /** Notification emitted after a Typert runtime registry changes. */
277
332
  export interface TypertRegistryChange {
@@ -360,17 +415,17 @@ export interface TypertLookupRegistry {
360
415
  */
361
416
  subscribe(listener: TypertRegistryListener): TypertDisposer;
362
417
  }
363
- /** Runtime registry for Host Context resolvers and Client Context binders. */
418
+ /** Runtime registry for the Host and Client adapters of each Context kind. */
364
419
  export interface TypertContextRegistry {
365
420
  /**
366
- * Register a Host Context resolver.
421
+ * Register a Host Context adapter.
367
422
  * @param key - merge-declared Context key.
368
- * @param provider - owning package's Host resolver.
369
- * @returns disposer withdrawing the exact provider.
423
+ * @param adapter - owning package's bidirectional Host projection.
424
+ * @returns disposer withdrawing the exact adapter.
370
425
  */
371
- registerHost<K extends StringKeyOf<TypertContextMap>>(key: K, provider: TypertHostContextProvider<TypertContextWire<TypertContextMap[K]>>): TypertDisposer;
426
+ registerHost<K extends StringKeyOf<TypertContextMap>>(key: K, adapter: TypertHostContextAdapter<TypertContextWire<TypertContextMap[K]>>): TypertDisposer;
372
427
  /**
373
- * Override one Host Context key's identity policy for the calling fiber.
428
+ * Override one Host Context key's resolution policy for the calling fiber.
374
429
  * Configuration may precede provider registration and restores the provider's default resolver on disposal.
375
430
  * @param key - merge-declared Context key.
376
431
  * @param resolver - composition-owned resolver used by every Host Context lookup of this key.
@@ -378,26 +433,33 @@ export interface TypertContextRegistry {
378
433
  */
379
434
  configureHost<K extends StringKeyOf<TypertContextMap>>(key: K, resolver: TypertHostContextResolver<TypertContextWire<TypertContextMap[K]>>): TypertDisposer;
380
435
  /**
381
- * Register a Client Context identity binder.
436
+ * Register a Client Context adapter.
382
437
  * @param key - merge-declared Context key.
383
- * @param binder - Client scope identity resolver.
384
- * @returns disposer withdrawing the exact binder.
438
+ * @param adapter - owning package's bidirectional Client projection.
439
+ * @returns disposer withdrawing the exact adapter.
440
+ */
441
+ registerClient<K extends StringKeyOf<TypertContextMap>>(key: K, adapter: TypertClientContextAdapter<TypertContextWire<TypertContextMap[K]>>): TypertDisposer;
442
+ /**
443
+ * Identify a live Host Context through the sole registered adapter set.
444
+ * @param ctx - Context projected by a Host-to-Client scoped event.
445
+ * @returns its kind and wire identity, or `undefined` when no adapter recognizes it.
446
+ * @throws when more than one Context kind recognizes the same Context.
385
447
  */
386
- registerClient<K extends StringKeyOf<TypertContextMap>>(key: K, binder: TypertClientContextBinder<TypertContextWire<TypertContextMap[K]>>): TypertDisposer;
448
+ identifyHost(ctx: Context): TypertHostContextIdentity | undefined;
387
449
  /**
388
- * Look up a Host Context resolver.
450
+ * Look up a Host Context adapter.
389
451
  * @param key - descriptor Context key.
390
- * @returns the provider, or `undefined` when absent.
452
+ * @returns the adapter, or `undefined` when absent.
391
453
  */
392
- getHost(key: string): TypertHostContextProvider | undefined;
454
+ getHost(key: string): TypertHostContextAdapter | undefined;
393
455
  /**
394
- * Look up a Client Context binder.
456
+ * Look up a Client Context adapter.
395
457
  * @param key - descriptor Context key.
396
- * @returns the binder, or `undefined` when absent.
458
+ * @returns the adapter, or `undefined` when absent.
397
459
  */
398
- getClient(key: string): TypertClientContextBinder | undefined;
460
+ getClient(key: string): TypertClientContextAdapter | undefined;
399
461
  /**
400
- * Observe later Context provider changes.
462
+ * Observe later Context adapter changes.
401
463
  * @param listener - synchronous contained observer.
402
464
  * @returns disposer for this subscription.
403
465
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-typert-protocol",
3
3
  "description": "Compiler-independent Remote metadata and Typert provider protocols",
4
- "version": "0.1.1-rc.2",
4
+ "version": "0.1.2-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -37,11 +37,11 @@
37
37
  ],
38
38
  "license": "MIT",
39
39
  "peerDependencies": {
40
- "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
41
- "@deepseek-ai/cordis": "^4.0.1"
40
+ "@deepseek-ai/cordis": "^4.0.2",
41
+ "@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2"
42
42
  },
43
43
  "devDependencies": {
44
- "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
45
- "@deepseek-ai/cordis": "^4.0.1"
44
+ "@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2",
45
+ "@deepseek-ai/cordis": "^4.0.2"
46
46
  }
47
47
  }