@deepseek-ai/dsh-typert-registry 0.1.6-alpha.1 → 0.1.6-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/registry/README.md
5
- README.md: c1ab98ae8ebe720a29eb4fb339f39e00ce593120
6
- README.zh.md: 7bf90ff8fd02c4fb17c4f57d1af251a7a4bd3116
5
+ README.md: 75a3d2bc495db97067818fe9c16e835e8e1f98bc
6
+ README.zh.md: b47d735c17ca4e51f41c82916a4b402ddf84e853
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: "The runtime Typert registry: stores generated package reflection, live Zod schemas, and Remote invocation descriptors, and resolves them for consumers."
2
+ description: "The runtime Typert registry: stores generated package reflection, lazy Zod schema factories, and Remote invocation descriptors, and resolves them for consumers."
3
3
  kind: "package-reference"
4
4
  ---
5
5
 
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
9
9
 
10
10
  ## Summary
11
11
 
12
- `dsh-typert-registry` makes generated Typert artifacts queryable at runtime: each package's reflection — services, events, and objects — its live Zod schemas, and Remote invocation descriptors live under stable keys that consumers can query or resolve on demand. Registrations are atomic and fiber-scoped: a contribution lands whole or not at all and is withdrawn automatically when the registering component unloads. The same service hosts the lookup and scoped-Context provider registries that Remote calls resolve through. It performs no TypeScript analysis and generates no schemas; the generator and the loader handle those.
12
+ `dsh-typert-registry` makes generated Typert artifacts queryable at runtime: each package's reflection, lazy Zod schema factories, and Remote invocation descriptors live under stable keys. A schema is materialized and cached when a consumer first requests it. Registrations are atomic and fiber-scoped: a contribution lands whole or not at all and is withdrawn automatically when the registering component unloads. The same service hosts the lookup and scoped-Context provider registries that Remote calls resolve through. It performs no TypeScript analysis and generates no schemas; the generator and the loader handle those.
13
13
 
14
14
  ## Table of Contents
15
15
 
@@ -37,7 +37,7 @@ Load the registry plugin; the Client face is installed the same way by the Clien
37
37
 
38
38
  ### Querying schemas and reflection
39
39
 
40
- Consumers read schemas with `get(key)`, `resolve(key)`, or `list(filter?)` and package reflection with `getPackage(name, face?)` or `listPackages(filter?)`. `resolve()` distinguishes a malformed key, an absent package, and a registered package that contributes no schema under that name, each with its own error. `toJSONSchema(key)` projects a live Zod schema to JSON Schema without caching.
40
+ Consumers read schemas with `get(key)`, `resolve(key)`, or `list(filter?)` and package reflection with `getPackage(name, face?)` or `listPackages(filter?)`. The first schema read materializes one process-realm instance; later reads reuse it. `resolve()` distinguishes a malformed key, an absent package, and a registered package that contributes no schema under that name, each with its own error. `toJSONSchema(key)` projects the materialized Zod schema to JSON Schema without caching the projection.
41
41
 
42
42
  ### Registering a contribution
43
43
 
@@ -72,7 +72,7 @@ Each sub-registry publishes `TypertRegistryChange` events to subscribed listener
72
72
 
73
73
  ### Identity and validation
74
74
 
75
- Keys are stable: `<package>#<face>` for reflection, `<package>#<name>` for schemas, and `<namespace>/<method>` for endpoints. Validation rejects names containing `#`, wire names outside the RPC segment grammar, duplicate keys, and lookup definitions whose wire declaration changes during the registry lifetime; strict codecs must carry a parseable schema.
75
+ Keys are stable: `<package>#<face>` for reflection, `<package>#<name>` for schemas, and `<namespace>/<method>` for endpoints. Validation rejects names containing `#`, wire names outside the RPC segment grammar, duplicate keys, and lookup definitions whose wire declaration changes during the registry lifetime; schema entries and strict codecs must carry a factory.
76
76
 
77
77
  ### Source map
78
78
 
package/README.zh.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: "运行时 Typert 注册表:保存生成的包反射、实时 Zod schema 与 Remote 调用描述符,并按需为消费方解析。"
2
+ description: "运行时 Typert 注册表:保存生成的包反射、惰性 Zod schema factory 与 Remote 调用描述符,并按需为消费方解析。"
3
3
  kind: "package-reference"
4
4
  ---
5
5
 
@@ -9,7 +9,7 @@ kind: "package-reference"
9
9
 
10
10
  ## 概述
11
11
 
12
- `dsh-typert-registry` 让生成的 Typert 产物在运行时可按需查询:每个包的反射——服务、事件与对象——其实时 Zod schema 与 Remote 调用描述符都保存在稳定键下,消费方可以按需查询或解析。注册是原子且按 fiber 作用域的:贡献要么整体落地要么完全不落地,并在注册组件卸载时自动撤销。同一服务还托管 Remote 调用所经由的 lookup 与作用域 Context 提供方注册表。它不执行 TypeScript 分析,也不生成 schema;这些由生成器与 loader 负责。
12
+ `dsh-typert-registry` 让生成的 Typert 产物在运行时可按需查询:每个包的反射、惰性 Zod schema factory 与 Remote 调用描述符都保存在稳定键下。消费方首次请求 schema 时才会物化并缓存它。注册是原子且按 fiber 作用域的:贡献要么整体落地要么完全不落地,并在注册组件卸载时自动撤销。同一服务还托管 Remote 调用所经由的 lookup 与作用域 Context 提供方注册表。它不执行 TypeScript 分析,也不生成 schema;这些由生成器与 loader 负责。
13
13
 
14
14
  ## 目录
15
15
 
@@ -37,7 +37,7 @@ kind: "package-reference"
37
37
 
38
38
  ### 查询 schema 与反射
39
39
 
40
- 消费方用 `get(key)`、`resolve(key)` 或 `list(filter?)` 读取 schema,用 `getPackage(name, face?)` 或 `listPackages(filter?)` 读取包反射。`resolve()` 能区分格式错误的键、未注册的包,以及已注册但未以该名称提供 schema 的包,各自给出不同的错误。`toJSONSchema(key)` 把实时 Zod schema 投影为 JSON Schema,且不缓存结果。
40
+ 消费方用 `get(key)`、`resolve(key)` 或 `list(filter?)` 读取 schema,用 `getPackage(name, face?)` 或 `listPackages(filter?)` 读取包反射。首次读取会物化一个进程 realm 内的 schema 实例,后续读取复用该实例。`resolve()` 能区分格式错误的键、未注册的包,以及已注册但未以该名称提供 schema 的包,各自给出不同的错误。`toJSONSchema(key)` 把已物化的 Zod schema 投影为 JSON Schema,但不缓存该投影。
41
41
 
42
42
  ### 注册贡献
43
43
 
@@ -72,7 +72,7 @@ Remote 调用通过 `ctx.typert.lookups` 与 `ctx.typert.contexts` 解析 Host
72
72
 
73
73
  ### 标识与校验
74
74
 
75
- 键是稳定的:反射用 `<package>#<face>`,schema 用 `<package>#<name>`,端点用 `<namespace>/<method>`。校验会拒绝含 `#` 的名称、超出 RPC 端点段文法的 wire 名称、重复键,以及在其注册表生命周期内改变 wire 声明的 lookup 定义;严格编解码器必须携带可解析的 schema。
75
+ 键是稳定的:反射用 `<package>#<face>`,schema 用 `<package>#<name>`,端点用 `<namespace>/<method>`。校验会拒绝含 `#` 的名称、超出 RPC 端点段文法的 wire 名称、重复键,以及在其注册表生命周期内改变 wire 声明的 lookup 定义;schema 条目与严格编解码器必须携带 factory。
76
76
 
77
77
  ### 源码地图
78
78
 
package/lib/client.js CHANGED
@@ -1211,20 +1211,21 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
1211
1211
  /**
1212
1212
  * Look up one schema by `<package>#<name>`.
1213
1213
  * @param key - global schema key.
1214
- * @returns the live schema record, or `undefined` when absent.
1214
+ * @returns a record containing the cached schema, or `undefined` when absent.
1215
1215
  */
1216
1216
  get(key) {
1217
- return this.schemas.get(key);
1217
+ const record = this.schemas.get(key);
1218
+ return record === void 0 ? void 0 : materializeSchema(record);
1218
1219
  }
1219
1220
  /**
1220
1221
  * Resolve one required schema.
1221
1222
  * @param key - global schema key.
1222
- * @returns the live schema record.
1223
+ * @returns a record containing the cached schema.
1223
1224
  * @throws when the key is malformed, the package face is absent, or the schema is not contributed.
1224
1225
  */
1225
1226
  resolve(key) {
1226
1227
  const record = this.schemas.get(key);
1227
- if (record !== void 0) return record;
1228
+ if (record !== void 0) return materializeSchema(record);
1228
1229
  const hash = key.indexOf("#");
1229
1230
  if (hash <= 0 || hash === key.length - 1) throw new Error(`typert: invalid schema key "${key}" — expected "<package>#<name>"`);
1230
1231
  const packageName = key.slice(0, hash);
@@ -1234,10 +1235,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
1234
1235
  /**
1235
1236
  * Enumerate live schemas in registration order.
1236
1237
  * @param filter - optional package and face restriction.
1237
- * @returns matching schema records.
1238
+ * @returns matching records containing the cached schemas.
1238
1239
  */
1239
1240
  list(filter = {}) {
1240
- return [...this.schemas.values()].filter((record) => matches(record, filter));
1241
+ return [...this.schemas.values()].filter((record) => matches(record, filter)).map(materializeSchema);
1241
1242
  }
1242
1243
  /**
1243
1244
  * Look up generated reflection for one package face.
@@ -1283,6 +1284,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
1283
1284
  const batch = /* @__PURE__ */ new Set();
1284
1285
  for (const schema of contribution.schemas) {
1285
1286
  validateSegment("schema name", schema.name);
1287
+ if (typeof schema.create !== "function") throw new Error(`typert: schema "${schema.name}" has no create() factory`);
1286
1288
  const key = typertKey(contribution.package, schema.name);
1287
1289
  if (batch.has(key) || this.schemas.has(key)) throw new Error(`typert: schema "${key}" is already registered`);
1288
1290
  batch.add(key);
@@ -1296,6 +1298,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
1296
1298
  return records;
1297
1299
  }
1298
1300
  };
1301
+ function materializeSchema(record) {
1302
+ const schema = record.value ??= record.create();
1303
+ return {
1304
+ name: record.name,
1305
+ schema,
1306
+ package: record.package,
1307
+ face: record.face,
1308
+ key: record.key
1309
+ };
1310
+ }
1299
1311
  function matches(record, filter) {
1300
1312
  return (filter.package === void 0 || record.package === filter.package) && (filter.face === void 0 || record.face === filter.face);
1301
1313
  }
@@ -1339,7 +1351,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
1339
1351
  function validateCodec(codec, subject) {
1340
1352
  if (codec.mode === "src-json") return;
1341
1353
  validateNonempty(`${subject} type symbol`, codec.typeSymbol);
1342
- if (typeof codec.schema.parse !== "function") throw new Error(`typert: ${subject} strict codec has no parse() method`);
1354
+ if (typeof codec.create !== "function") throw new Error(`typert: ${subject} strict codec has no create() factory`);
1343
1355
  }
1344
1356
  function validateWireName(subject, value) {
1345
1357
  if (value === "." || value === ".." || !/^[A-Za-z0-9_$.-]+$/.test(value)) throw new Error(`typert: invalid ${subject} "${value}" — must contain only RPC endpoint segment characters`);
package/lib/index.js CHANGED
@@ -419,20 +419,21 @@ var TypertRegistry = class extends Service {
419
419
  /**
420
420
  * Look up one schema by `<package>#<name>`.
421
421
  * @param key - global schema key.
422
- * @returns the live schema record, or `undefined` when absent.
422
+ * @returns a record containing the cached schema, or `undefined` when absent.
423
423
  */
424
424
  get(key) {
425
- return this.schemas.get(key);
425
+ const record = this.schemas.get(key);
426
+ return record === void 0 ? void 0 : materializeSchema(record);
426
427
  }
427
428
  /**
428
429
  * Resolve one required schema.
429
430
  * @param key - global schema key.
430
- * @returns the live schema record.
431
+ * @returns a record containing the cached schema.
431
432
  * @throws when the key is malformed, the package face is absent, or the schema is not contributed.
432
433
  */
433
434
  resolve(key) {
434
435
  const record = this.schemas.get(key);
435
- if (record !== void 0) return record;
436
+ if (record !== void 0) return materializeSchema(record);
436
437
  const hash = key.indexOf("#");
437
438
  if (hash <= 0 || hash === key.length - 1) throw new Error(`typert: invalid schema key "${key}" — expected "<package>#<name>"`);
438
439
  const packageName = key.slice(0, hash);
@@ -442,10 +443,10 @@ var TypertRegistry = class extends Service {
442
443
  /**
443
444
  * Enumerate live schemas in registration order.
444
445
  * @param filter - optional package and face restriction.
445
- * @returns matching schema records.
446
+ * @returns matching records containing the cached schemas.
446
447
  */
447
448
  list(filter = {}) {
448
- return [...this.schemas.values()].filter((record) => matches(record, filter));
449
+ return [...this.schemas.values()].filter((record) => matches(record, filter)).map(materializeSchema);
449
450
  }
450
451
  /**
451
452
  * Look up generated reflection for one package face.
@@ -491,6 +492,7 @@ var TypertRegistry = class extends Service {
491
492
  const batch = /* @__PURE__ */ new Set();
492
493
  for (const schema of contribution.schemas) {
493
494
  validateSegment("schema name", schema.name);
495
+ if (typeof schema.create !== "function") throw new Error(`typert: schema "${schema.name}" has no create() factory`);
494
496
  const key = typertKey(contribution.package, schema.name);
495
497
  if (batch.has(key) || this.schemas.has(key)) throw new Error(`typert: schema "${key}" is already registered`);
496
498
  batch.add(key);
@@ -504,6 +506,16 @@ var TypertRegistry = class extends Service {
504
506
  return records;
505
507
  }
506
508
  };
509
+ function materializeSchema(record) {
510
+ const schema = record.value ??= record.create();
511
+ return {
512
+ name: record.name,
513
+ schema,
514
+ package: record.package,
515
+ face: record.face,
516
+ key: record.key
517
+ };
518
+ }
507
519
  function matches(record, filter) {
508
520
  return (filter.package === void 0 || record.package === filter.package) && (filter.face === void 0 || record.face === filter.face);
509
521
  }
@@ -547,7 +559,7 @@ function validateInvocation(descriptor) {
547
559
  function validateCodec(codec, subject) {
548
560
  if (codec.mode === "src-json") return;
549
561
  validateNonempty(`${subject} type symbol`, codec.typeSymbol);
550
- if (typeof codec.schema.parse !== "function") throw new Error(`typert: ${subject} strict codec has no parse() method`);
562
+ if (typeof codec.create !== "function") throw new Error(`typert: ${subject} strict codec has no create() factory`);
551
563
  }
552
564
  function validateWireName(subject, value) {
553
565
  if (value === "." || value === ".." || !/^[A-Za-z0-9_$.-]+$/.test(value)) throw new Error(`typert: invalid ${subject} "${value}" — must contain only RPC endpoint segment characters`);
@@ -60,20 +60,20 @@ export declare class TypertRegistry extends Service implements TypertRegistryCon
60
60
  /**
61
61
  * Look up one schema by `<package>#<name>`.
62
62
  * @param key - global schema key.
63
- * @returns the live schema record, or `undefined` when absent.
63
+ * @returns a record containing the cached schema, or `undefined` when absent.
64
64
  */
65
65
  get(key: string): TypertSchemaRecord | undefined;
66
66
  /**
67
67
  * Resolve one required schema.
68
68
  * @param key - global schema key.
69
- * @returns the live schema record.
69
+ * @returns a record containing the cached schema.
70
70
  * @throws when the key is malformed, the package face is absent, or the schema is not contributed.
71
71
  */
72
72
  resolve(key: string): TypertSchemaRecord;
73
73
  /**
74
74
  * Enumerate live schemas in registration order.
75
75
  * @param filter - optional package and face restriction.
76
- * @returns matching schema records.
76
+ * @returns matching records containing the cached schemas.
77
77
  */
78
78
  list(filter?: TypertSchemaFilter): TypertSchemaRecord[];
79
79
  /**
@@ -417,21 +417,22 @@ export class TypertRegistry extends Service {
417
417
  /**
418
418
  * Look up one schema by `<package>#<name>`.
419
419
  * @param key - global schema key.
420
- * @returns the live schema record, or `undefined` when absent.
420
+ * @returns a record containing the cached schema, or `undefined` when absent.
421
421
  */
422
422
  get(key) {
423
- return this.schemas.get(key);
423
+ const record = this.schemas.get(key);
424
+ return record === undefined ? undefined : materializeSchema(record);
424
425
  }
425
426
  /**
426
427
  * Resolve one required schema.
427
428
  * @param key - global schema key.
428
- * @returns the live schema record.
429
+ * @returns a record containing the cached schema.
429
430
  * @throws when the key is malformed, the package face is absent, or the schema is not contributed.
430
431
  */
431
432
  resolve(key) {
432
433
  const record = this.schemas.get(key);
433
434
  if (record !== undefined)
434
- return record;
435
+ return materializeSchema(record);
435
436
  const hash = key.indexOf('#');
436
437
  if (hash <= 0 || hash === key.length - 1) {
437
438
  throw new Error(`typert: invalid schema key "${key}" — expected "<package>#<name>"`);
@@ -445,10 +446,10 @@ export class TypertRegistry extends Service {
445
446
  /**
446
447
  * Enumerate live schemas in registration order.
447
448
  * @param filter - optional package and face restriction.
448
- * @returns matching schema records.
449
+ * @returns matching records containing the cached schemas.
449
450
  */
450
451
  list(filter = {}) {
451
- return [...this.schemas.values()].filter(record => matches(record, filter));
452
+ return [...this.schemas.values()].filter(record => matches(record, filter)).map(materializeSchema);
452
453
  }
453
454
  /**
454
455
  * Look up generated reflection for one package face.
@@ -498,6 +499,9 @@ export class TypertRegistry extends Service {
498
499
  const batch = new Set();
499
500
  for (const schema of contribution.schemas) {
500
501
  validateSegment('schema name', schema.name);
502
+ if (typeof schema.create !== 'function') {
503
+ throw new Error(`typert: schema "${schema.name}" has no create() factory`);
504
+ }
501
505
  const key = typertKey(contribution.package, schema.name);
502
506
  if (batch.has(key) || this.schemas.has(key)) {
503
507
  throw new Error(`typert: schema "${key}" is already registered`);
@@ -513,6 +517,16 @@ export class TypertRegistry extends Service {
513
517
  return records;
514
518
  }
515
519
  }
520
+ function materializeSchema(record) {
521
+ const schema = record.value ??= record.create();
522
+ return {
523
+ name: record.name,
524
+ schema,
525
+ package: record.package,
526
+ face: record.face,
527
+ key: record.key,
528
+ };
529
+ }
516
530
  function matches(record, filter) {
517
531
  return (filter.package === undefined || record.package === filter.package)
518
532
  && (filter.face === undefined || record.face === filter.face);
@@ -578,8 +592,8 @@ function validateCodec(codec, subject) {
578
592
  if (codec.mode === 'src-json')
579
593
  return;
580
594
  validateNonempty(`${subject} type symbol`, codec.typeSymbol);
581
- if (typeof codec.schema.parse !== 'function') {
582
- throw new Error(`typert: ${subject} strict codec has no parse() method`);
595
+ if (typeof codec.create !== 'function') {
596
+ throw new Error(`typert: ${subject} strict codec has no create() factory`);
583
597
  }
584
598
  }
585
599
  function validateWireName(subject, value) {
@@ -60,22 +60,25 @@ export interface TypertPackageModel {
60
60
  readonly events: readonly TypertEventModel[];
61
61
  readonly objects: readonly TypertObjectModel[];
62
62
  }
63
- /** One generated live Zod schema. */
64
- export interface TypertSchema {
63
+ /** One generated Zod schema factory. */
64
+ export interface TypertSchemaFactory {
65
65
  readonly name: string;
66
- readonly schema: z.ZodType;
66
+ /** Materialize and return the process-realm schema on first use. */
67
+ readonly create: () => z.ZodType;
67
68
  }
68
69
  /** One generated package contribution registered and withdrawn atomically. */
69
70
  export interface TypertContribution {
70
71
  readonly package: string;
71
72
  readonly face: TypertFace;
72
- readonly schemas: readonly TypertSchema[];
73
+ readonly schemas: readonly TypertSchemaFactory[];
73
74
  readonly model: TypertPackageModel;
74
75
  /** Host invocation definitions, empty when the package exports no Remote methods. */
75
76
  readonly invocations: readonly InvocationDescriptor[];
76
77
  }
77
78
  /** A live schema plus its contribution identity. */
78
- export interface TypertSchemaRecord extends TypertSchema {
79
+ export interface TypertSchemaRecord {
80
+ readonly name: string;
81
+ readonly schema: z.ZodType;
79
82
  readonly package: string;
80
83
  readonly face: TypertFace;
81
84
  readonly key: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-typert-registry",
3
3
  "description": "Runtime registry for generated package reflection and Zod schemas",
4
- "version": "0.1.6-alpha.1",
4
+ "version": "0.1.6-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -50,8 +50,8 @@
50
50
  "@deepseek-ai/cordis": "^4.0.2"
51
51
  },
52
52
  "devDependencies": {
53
- "@deepseek-ai/dsh-typert-protocol": "^0.1.6-alpha.1",
54
- "@deepseek-ai/cordis": "^4.0.2"
53
+ "@deepseek-ai/cordis": "^4.0.2",
54
+ "@deepseek-ai/dsh-typert-protocol": "^0.1.6-alpha.2"
55
55
  },
56
56
  "scripts": {
57
57
  "bundle": "tsdown",