@deepseek-ai/dsh-typert-loader 0.2.1-alpha.2 → 0.2.1-alpha.4

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
@@ -21,8 +21,8 @@
21
21
  en: 881670b2d7dfb04d
22
22
  zh: fbf612e945aaf066
23
23
  /deepseek-ai-dsh-typert-loader/use-this-package/what-gets-registered:
24
- en: 01318fcba39e9b0f
25
- zh: c5f6528a91b335ac
24
+ en: 73660724a51afcea
25
+ zh: 448a32bb29614c7a
26
26
  /deepseek-ai-dsh-typert-loader/use-this-package/observable-behavior-and-failures:
27
27
  en: 01494e9fbd469ec8
28
28
  zh: 3025d870c0f36e2b
@@ -33,8 +33,8 @@
33
33
  en: 03fc077e58271e18
34
34
  zh: 20f8fc02008cee5e
35
35
  /deepseek-ai-dsh-typert-loader/understand-the-implementation/manifest-validation:
36
- en: eb246aef15ea0532
37
- zh: 7a4a7bcc788b3ba3
36
+ en: c7d93c72a224e8fb
37
+ zh: 51f0e4b8a043c238
38
38
  /deepseek-ai-dsh-typert-loader/understand-the-implementation/caching-and-ownership:
39
39
  en: 38e781e052fdf44e
40
40
  zh: d8f6b4d119bf9856
@@ -51,8 +51,8 @@
51
51
  en: f8a0ad3d0fc0eb32
52
52
  zh: 7649a694b279f5f3
53
53
  /deepseek-ai-dsh-typert-loader/known-limitations-and-deferred-work:
54
- en: a7e281826b58b218
55
- zh: b4347c965151a1a9
54
+ en: 9bc795b850f7ab8a
55
+ zh: f3aea571a70bf327
56
56
  /deepseek-ai-dsh-typert-loader/known-limitations-and-deferred-work/dev-note:
57
57
  en: e67f633dc6fe7773
58
58
  zh: 3bb0c20c93f16f98
package/README.md CHANGED
@@ -44,7 +44,9 @@ The generated [configuration catalog](../../../docs/config-catalog.md#deepseek-a
44
44
 
45
45
  ### What gets registered
46
46
 
47
- Each qualifying Loader entry contributes its generated host-face reflection and schema factories to the runtime registry. Registration follows the entry lifecycle: it is withdrawn when the entry or the plugin unmounts, and an import that settles after either owner is gone is discarded.
47
+ Each qualifying Loader entry contributes its generated host-face reflection, schema factories, and `TYPERT.invocations` to the runtime registry. The ordinary artifact's getter exposes descriptors from a private Remote info instance; generated direct descriptors also provide named input and invocation helpers. Registration follows the entry lifecycle: it is withdrawn when the entry or the plugin unmounts, and an import that settles after either owner is gone is discarded.
48
+
49
+ Source compositions requiring strict Remote validation prebuild and load the ordinary `./typert` artifact. The loader registers its invocations in `ctx.typert.local`; it does not recover erased constraints, documentation, or schemas from live Services. Limited descriptor-free source fallback remains a Gateway concern, and `local.hasSeen()` prevents downgrading to it after a registered definition is withdrawn.
48
50
 
49
51
  ### Observable behavior and failures
50
52
 
@@ -66,7 +68,7 @@ The plugin is an incremental scanner mirroring the client-modules node half: eve
66
68
 
67
69
  ### Manifest validation
68
70
 
69
- `validateTypertManifest()` is the module/file boundary: the manifest crosses from a build artifact into the typed registry, so every field is checked. The manifest must name the package that exports it, carry face `host`, hold schema factories, and keep well-formed service, event, object, member, type, and documentation records; invocation descriptors must use strict codecs with factories. Every failure names the package and the defect.
71
+ `validateTypertManifest()` checks artifacts before they enter the typed registry. A manifest must name its exporting package, carry face `host`, hold schema factories, and contain well-formed reflection records; invocation descriptors require strict codecs with factories. Validation checks parameter `codec` and any supplied `strictCodec` specs and requires generated direct-method `input` and `invoke` to be callable; `result` remains the sole output codec. Documentation and JSON Schema are optional. Registration never calls the input selector, parser factories, or projection getters; validation inspects only supplied static projection data. Every failure names the package and the defect.
70
72
 
71
73
  ### Caching and ownership
72
74
 
@@ -113,6 +115,7 @@ These limits define what the loader does not discover or register; they are curr
113
115
  - **Host face only** — discovery imports only the host `./typert` artifact; client runtimes need a separate composition owner before equivalent discovery is added.
114
116
  - **Explicit entries for nested plugins** — Loader entries are discovered automatically, but plugins nested behind another entry, or not loaded by the Loader at all, need an explicit `packages` entry or direct `ctx.typert.register()` ownership.
115
117
  - **Cached verdicts never expire** — a package that gains a `./typert` export mid-process needs a restart before the loader registers it.
118
+ - **Host readiness remains composition-owned** — consumers requiring strict metadata must wait for registration before serving calls. The lazy info factory does not make asynchronous Loader registration ready; `local.hasSeen()` only protects definitions already observed.
116
119
 
117
120
  <a id="dev-note"></a>
118
121
  ### Dev Note
package/README.zh.md CHANGED
@@ -44,7 +44,9 @@ kind: "package-reference"
44
44
 
45
45
  ### 注册什么
46
46
 
47
- 每个符合条件的 Loader 配置项都会把其生成的宿主侧反射与 schema factory 贡献给运行时注册表。注册跟随配置项生命周期:配置项或本插件卸载时撤销;在配置项或本插件任一方卸载后才结束的导入操作会被丢弃。
47
+ 每个符合条件的 Loader 配置项都会把其生成的宿主侧反射、schema factory 和 `TYPERT.invocations` 贡献给运行时注册表。普通产物的 getter 暴露来自私有 Remote info 实例的描述符;生成的直接方法描述符还提供具名输入与调用辅助能力。注册跟随配置项生命周期:配置项或本插件卸载时撤销;在配置项或本插件任一方卸载后才结束的导入操作会被丢弃。
48
+
49
+ 要求严格 Remote 校验的源码组合预先构建并加载普通 `./typert` 产物。loader 将其调用定义注册到 `ctx.typert.local`;它不会从运行中的 Service 恢复已擦除的约束、文档或 schema。受限的无描述符源码回退仍由 Gateway 负责,`local.hasSeen()` 会阻止已注册定义撤销后降级到该回退。
48
50
 
49
51
  ### 可观察行为与失败
50
52
 
@@ -66,7 +68,7 @@ kind: "package-reference"
66
68
 
67
69
  ### Manifest 校验
68
70
 
69
- `validateTypertManifest()` 是模块/文件边界:manifest 从构建产物进入类型化注册表,因此每个字段都会被检查。manifest 必须指名导出它的包、携带 `host` face、持有 schema factory,并保持服务、事件、对象、成员、类型与文档记录格式正确;调用描述符必须使用带 factory 的严格编解码器。每次失败都会指名包与缺陷。
71
+ `validateTypertManifest()` 在产物进入类型化注册表前执行检查。manifest 必须指名导出它的包、携带 `host` face、持有 schema factory,并包含格式正确的反射记录;调用描述符要求带 factory 的严格 codec。校验检查参数 `codec` 及提供的 `strictCodec` spec,并要求生成直接方法的 `input` 和 `invoke` 可调用;`result` 仍是唯一输出 codec。文档和 JSON Schema 可选。注册绝不调用输入选择器、解析器 factory 或投影 getter;校验只检查已提供的静态投影数据。每次失败都会指名包与缺陷。
70
72
 
71
73
  ### 缓存与归属
72
74
 
@@ -113,6 +115,7 @@ kind: "package-reference"
113
115
  - **仅宿主侧**——发现机制只会导入宿主侧 `./typert` 产物;在为客户端运行时添加等价的发现机制之前,需要先有独立的组合所有者。
114
116
  - **嵌套插件需要显式条目**——Loader 配置项会被自动发现,但嵌套在另一配置项之下、或完全不经 Loader 加载的插件,需要显式加入 `packages`,或由其所有者直接调用 `ctx.typert.register()`。
115
117
  - **缓存结论永不过期**——进程中途新增 `./typert` 导出的包需要重启后 loader 才会注册它。
118
+ - **Host 就绪仍由组合负责**——要求严格元数据的消费方必须等待注册完成后再接受调用。惰性 info factory 不会让异步 Loader 注册自动就绪;`local.hasSeen()` 只保护已经观察到的定义。
116
119
 
117
120
  <a id="dev-note"></a>
118
121
  ### 开发备注
package/lib/index.js CHANGED
@@ -68,8 +68,9 @@ function typertExportOf(pkgName, exportsField) {
68
68
  /**
69
69
  * Narrow a dynamically imported typert module's `TYPERT` export to a
70
70
  * contribution owned by `pkgName`. This is the module/file boundary: the
71
- * manifest crosses from a build artifact into the typed registry, so every
72
- * field is checked and every failure names the package and the defect.
71
+ * manifest crosses from a build artifact into the typed registry. Dispatch
72
+ * facts and eager projection fields are checked; computed tool projections
73
+ * remain lazy until a consumer requests them. Failures name the package and defect.
73
74
  * @param pkgName - the package whose typert face was imported.
74
75
  * @param exported - the module's `TYPERT` export.
75
76
  * @returns the validated contribution.
@@ -127,6 +128,9 @@ function requireArray(pkgName, value, subject) {
127
128
  function requireString(pkgName, value, key, subject) {
128
129
  if (typeof value[key] !== "string" || value[key].length === 0) throw new Error(`typert-loader: ${pkgName} ${subject} has a missing or empty ${key}`);
129
130
  }
131
+ function requireOptionalString(pkgName, value, key, subject) {
132
+ if (value[key] !== void 0 && typeof value[key] !== "string") throw new Error(`typert-loader: ${pkgName} ${subject}.${key} must be a string`);
133
+ }
130
134
  function requireDocumentation(pkgName, value, subject) {
131
135
  requireArray(pkgName, value.tags, `${subject}.tags`);
132
136
  for (const key of [
@@ -159,6 +163,8 @@ function requireInvocation(pkgName, value) {
159
163
  "method"
160
164
  ]) requireString(pkgName, invocation, key, "invocation");
161
165
  const id = invocation.id;
166
+ requireOptionalString(pkgName, invocation, "description", `invocation "${id}"`);
167
+ if (invocation.mode !== void 0 && invocation.mode !== "stream") throw new Error(`typert-loader: ${pkgName} invocation "${id}" mode must be "stream" when present`);
162
168
  const receiver = requireObject(pkgName, invocation.invocation, `invocation "${id}" receiver`);
163
169
  if (receiver.kind === "context") {
164
170
  requireString(pkgName, receiver, "context", `invocation "${id}" Context receiver`);
@@ -172,6 +178,7 @@ function requireInvocation(pkgName, value) {
172
178
  const parameter = requireObject(pkgName, valueParameter, `invocation "${id}" parameter`);
173
179
  requireString(pkgName, parameter, "name", `invocation "${id}" parameter`);
174
180
  requireString(pkgName, parameter, "wire", `invocation "${id}" parameter`);
181
+ requireOptionalString(pkgName, parameter, "description", `invocation "${id}" parameter`);
175
182
  const wire = parameter.wire;
176
183
  if (wires.has(wire)) throw new Error(`typert-loader: ${pkgName} invocation "${id}" repeats wire field "${wire}"`);
177
184
  wires.add(wire);
@@ -183,6 +190,7 @@ function requireInvocation(pkgName, value) {
183
190
  } else throw new Error(`typert-loader: ${pkgName} invocation "${id}" parameter source must be "json" or "lookup"`);
184
191
  parameters.set(wire, parameter);
185
192
  requireStrictCodec(pkgName, parameter.codec, `invocation "${id}" parameter codec`);
193
+ if (parameter.strictCodec !== void 0) requireStrictCodec(pkgName, parameter.strictCodec, `invocation "${id}" strict input codec`);
186
194
  }
187
195
  if (invocation.cancellation !== void 0) {
188
196
  if (requireObject(pkgName, invocation.cancellation, `invocation "${id}" cancellation`).parameter !== "signal") throw new Error(`typert-loader: ${pkgName} invocation "${id}" cancellation parameter must be "signal"`);
@@ -197,18 +205,33 @@ function requireInvocation(pkgName, value) {
197
205
  }
198
206
  if (receiver.kind === "context" && wires.has(receiver.wire)) throw new Error(`typert-loader: ${pkgName} invocation "${id}" repeats Context wire field "${receiver.wire}"`);
199
207
  requireStrictCodec(pkgName, invocation.result, `invocation "${id}" result codec`);
208
+ if (invocation.input !== void 0 || invocation.invoke !== void 0) {
209
+ if (receiver.kind !== "direct") throw new Error(`typert-loader: ${pkgName} invocation "${id}" input/invoke require a direct receiver`);
210
+ if (typeof invocation.input !== "function") throw new Error(`typert-loader: ${pkgName} invocation "${id}" has no input() selector`);
211
+ if (typeof invocation.invoke !== "function") throw new Error(`typert-loader: ${pkgName} invocation "${id}" has no invoke() function`);
212
+ }
200
213
  if (invocation.sourceLocation !== void 0) {
201
214
  const location = requireObject(pkgName, invocation.sourceLocation, `invocation "${id}" sourceLocation`);
202
215
  requireString(pkgName, location, "file", `invocation "${id}" sourceLocation`);
203
216
  for (const key of ["line", "column"]) if (!Number.isInteger(location[key]) || location[key] < 1) throw new Error(`typert-loader: ${pkgName} invocation "${id}" sourceLocation.${key} must be a positive integer`);
204
217
  }
205
218
  }
219
+ function requireSchemaProjection(pkgName, value, subject) {
220
+ if (typeof value.create !== "function") throw new Error(`typert-loader: ${pkgName} ${subject} has no create() factory`);
221
+ const fields = Object.getOwnPropertyDescriptors(value);
222
+ for (const key of ["description", "jsonSchemaError"]) {
223
+ const field = fields[key]?.value;
224
+ if (field !== void 0 && typeof field !== "string") throw new Error(`typert-loader: ${pkgName} ${subject}.${key} must be a string`);
225
+ }
226
+ const schema = fields.jsonSchema?.value;
227
+ if (schema !== void 0) requireObject(pkgName, schema, `${subject}.jsonSchema`);
228
+ }
206
229
  function requireStrictCodec(pkgName, value, subject) {
207
230
  const codec = requireObject(pkgName, value, subject);
208
231
  if (codec.mode !== "strict") throw new Error(`typert-loader: ${pkgName} ${subject} must use a strict codec`);
209
232
  requireString(pkgName, codec, "typeSymbol", subject);
210
233
  for (const method of ["decode", "encode"]) if (codec[method] !== void 0 && typeof codec[method] !== "function") throw new Error(`typert-loader: ${pkgName} ${subject} ${method} must be a function`);
211
- if (typeof codec.create !== "function") throw new Error(`typert-loader: ${pkgName} ${subject} has no create() factory`);
234
+ requireSchemaProjection(pkgName, codec, subject);
212
235
  }
213
236
  /**
214
237
  * Scan current Loader entries during activation, then follow entry mounts and
@@ -43,8 +43,9 @@ export declare const Config: z<Config>;
43
43
  /**
44
44
  * Narrow a dynamically imported typert module's `TYPERT` export to a
45
45
  * contribution owned by `pkgName`. This is the module/file boundary: the
46
- * manifest crosses from a build artifact into the typed registry, so every
47
- * field is checked and every failure names the package and the defect.
46
+ * manifest crosses from a build artifact into the typed registry. Dispatch
47
+ * facts and eager projection fields are checked; computed tool projections
48
+ * remain lazy until a consumer requests them. Failures name the package and defect.
48
49
  * @param pkgName - the package whose typert face was imported.
49
50
  * @param exported - the module's `TYPERT` export.
50
51
  * @returns the validated contribution.
package/locale/en.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "meta": {
3
+ "title": "typert-loader"
4
+ }
5
+ }
package/locale/zh.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Typert 类型加载",
4
+ "description": "加载插件生成的类型信息,供运行时查询和调用。"
5
+ }
6
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-typert-loader",
3
3
  "description": "Loader integration for generated Typert package contributions",
4
- "version": "0.2.1-alpha.2",
4
+ "version": "0.2.1-alpha.4",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -19,26 +19,30 @@
19
19
  "default": "./lib/index.js"
20
20
  },
21
21
  "./src/*": "./src/*",
22
- "./package.json": "./package.json"
22
+ "./package.json": "./package.json",
23
+ "./locale/*.json": "./locale/*.json"
23
24
  },
24
25
  "files": [
26
+ "locale/*.json",
25
27
  "lib/index.js",
26
28
  "lib/types/**/*.d.ts"
27
29
  ],
28
30
  "license": "MIT",
29
31
  "peerDependencies": {
30
- "@deepseek-ai/cordis-plugin-loader": "~1.0.6-alpha.1",
31
- "@deepseek-ai/dsh-typert-registry": "0.2.1-alpha.2",
32
- "@deepseek-ai/cordis": "~4.0.5-alpha.1"
32
+ "@deepseek-ai/cordis-plugin-loader": "~1.0.6-alpha.2",
33
+ "@deepseek-ai/dsh-typert-registry": "0.2.1-alpha.4",
34
+ "@deepseek-ai/cordis": "~4.0.5-alpha.2"
33
35
  },
34
36
  "dependencies": {
35
- "@deepseek-ai/schemastery": "~3.18.5-alpha.1"
37
+ "@deepseek-ai/schemastery": "~3.18.5-alpha.2"
36
38
  },
37
39
  "devDependencies": {
38
- "@deepseek-ai/dsh-app-boot": "0.2.1-alpha.2",
39
- "@deepseek-ai/cordis-plugin-loader": "~1.0.6-alpha.1",
40
- "@deepseek-ai/dsh-typert-registry": "0.2.1-alpha.2",
41
- "@deepseek-ai/cordis": "~4.0.5-alpha.1",
42
- "zod": "^4.4.3"
40
+ "@deepseek-ai/dsh-app-boot": "0.2.1-alpha.4",
41
+ "@deepseek-ai/cordis-plugin-loader": "~1.0.6-alpha.2",
42
+ "@deepseek-ai/dsh-typert-registry": "0.2.1-alpha.4",
43
+ "@deepseek-ai/dsh-typert-protocol": "0.2.1-alpha.4",
44
+ "@deepseek-ai/cordis": "~4.0.5-alpha.2",
45
+ "typescript": "^6.0.3",
46
+ "zod": "4.4.3"
43
47
  }
44
48
  }