ts-procedures 8.3.0 → 8.4.0

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.
Files changed (124) hide show
  1. package/agent_config/claude-code/skills/ts-procedures/SKILL.md +26 -8
  2. package/agent_config/claude-code/skills/ts-procedures/templates/client.md +3 -3
  3. package/agent_config/claude-code/skills/ts-procedures/templates/hono.md +3 -3
  4. package/agent_config/claude-code/skills/ts-procedures/templates/procedure.md +3 -3
  5. package/agent_config/claude-code/skills/ts-procedures/templates/stream-procedure.md +3 -3
  6. package/build/client/call.js +1 -1
  7. package/build/client/call.js.map +1 -1
  8. package/build/client/index.d.ts +1 -1
  9. package/build/client/index.js +23 -1
  10. package/build/client/index.js.map +1 -1
  11. package/build/client/index.test.js +87 -0
  12. package/build/client/index.test.js.map +1 -1
  13. package/build/client/resolve-options.d.ts +5 -4
  14. package/build/client/resolve-options.js +18 -7
  15. package/build/client/resolve-options.js.map +1 -1
  16. package/build/client/resolve-options.test.js +53 -24
  17. package/build/client/resolve-options.test.js.map +1 -1
  18. package/build/client/stream.js +1 -1
  19. package/build/client/stream.js.map +1 -1
  20. package/build/client/types.d.ts +31 -3
  21. package/build/codegen/__fixtures__/make-envelope.d.ts +41 -0
  22. package/build/codegen/__fixtures__/make-envelope.js +38 -0
  23. package/build/codegen/__fixtures__/make-envelope.js.map +1 -0
  24. package/build/codegen/bin/cli.d.ts +11 -0
  25. package/build/codegen/bin/cli.js +30 -21
  26. package/build/codegen/bin/cli.js.map +1 -1
  27. package/build/codegen/bin/cli.test.js +36 -1
  28. package/build/codegen/bin/cli.test.js.map +1 -1
  29. package/build/codegen/bin/flag-specs.d.ts +10 -0
  30. package/build/codegen/bin/flag-specs.js +60 -0
  31. package/build/codegen/bin/flag-specs.js.map +1 -0
  32. package/build/codegen/bin/flag-specs.test.d.ts +1 -0
  33. package/build/codegen/bin/flag-specs.test.js +26 -0
  34. package/build/codegen/bin/flag-specs.test.js.map +1 -0
  35. package/build/codegen/collect-models.d.ts +37 -0
  36. package/build/codegen/collect-models.js +74 -0
  37. package/build/codegen/collect-models.js.map +1 -0
  38. package/build/codegen/collect-models.test.d.ts +1 -0
  39. package/build/codegen/collect-models.test.js +40 -0
  40. package/build/codegen/collect-models.test.js.map +1 -0
  41. package/build/codegen/emit-client-runtime.js +1 -0
  42. package/build/codegen/emit-client-runtime.js.map +1 -1
  43. package/build/codegen/emit-models.d.ts +26 -0
  44. package/build/codegen/emit-models.js +53 -0
  45. package/build/codegen/emit-models.js.map +1 -0
  46. package/build/codegen/emit-models.test.d.ts +1 -0
  47. package/build/codegen/emit-models.test.js +42 -0
  48. package/build/codegen/emit-models.test.js.map +1 -0
  49. package/build/codegen/emit-scope.d.ts +10 -0
  50. package/build/codegen/emit-scope.js +119 -34
  51. package/build/codegen/emit-scope.js.map +1 -1
  52. package/build/codegen/emit-types.d.ts +26 -1
  53. package/build/codegen/emit-types.js +27 -5
  54. package/build/codegen/emit-types.js.map +1 -1
  55. package/build/codegen/index.d.ts +5 -0
  56. package/build/codegen/index.js +2 -0
  57. package/build/codegen/index.js.map +1 -1
  58. package/build/codegen/model-refs.d.ts +27 -0
  59. package/build/codegen/model-refs.js +49 -0
  60. package/build/codegen/model-refs.js.map +1 -0
  61. package/build/codegen/model-refs.test.d.ts +1 -0
  62. package/build/codegen/model-refs.test.js +33 -0
  63. package/build/codegen/model-refs.test.js.map +1 -0
  64. package/build/codegen/pipeline.d.ts +3 -0
  65. package/build/codegen/pipeline.js +3 -1
  66. package/build/codegen/pipeline.js.map +1 -1
  67. package/build/codegen/schema-walk.d.ts +13 -0
  68. package/build/codegen/schema-walk.js +26 -0
  69. package/build/codegen/schema-walk.js.map +1 -0
  70. package/build/codegen/schema-walk.test.d.ts +1 -0
  71. package/build/codegen/schema-walk.test.js +35 -0
  72. package/build/codegen/schema-walk.test.js.map +1 -0
  73. package/build/codegen/targets/_shared/target-run.d.ts +5 -0
  74. package/build/codegen/targets/ts/run.js +28 -1
  75. package/build/codegen/targets/ts/run.js.map +1 -1
  76. package/build/codegen/targets/ts/shared-models.test.d.ts +1 -0
  77. package/build/codegen/targets/ts/shared-models.test.js +258 -0
  78. package/build/codegen/targets/ts/shared-models.test.js.map +1 -0
  79. package/build/doc-envelope.d.ts +13 -0
  80. package/build/doc-envelope.js +23 -0
  81. package/build/doc-envelope.js.map +1 -0
  82. package/build/doc-envelope.test.d.ts +1 -0
  83. package/build/doc-envelope.test.js +31 -0
  84. package/build/doc-envelope.test.js.map +1 -0
  85. package/build/exports.d.ts +2 -0
  86. package/build/exports.js +1 -0
  87. package/build/exports.js.map +1 -1
  88. package/docs/client-and-codegen.md +101 -0
  89. package/docs/handoffs/ajsc-named-type-collision.md +134 -0
  90. package/docs/handoffs/ajsc-named-type-support.md +181 -0
  91. package/docs/superpowers/plans/2026-06-05-dx-feedback-round.md +1292 -0
  92. package/docs/superpowers/specs/2026-06-05-dx-feedback-round-design.md +285 -0
  93. package/package.json +2 -2
  94. package/src/client/call.ts +1 -1
  95. package/src/client/index.test.ts +98 -0
  96. package/src/client/index.ts +32 -1
  97. package/src/client/resolve-options.test.ts +73 -26
  98. package/src/client/resolve-options.ts +23 -9
  99. package/src/client/stream.ts +1 -1
  100. package/src/client/types.ts +34 -3
  101. package/src/codegen/__fixtures__/make-envelope.ts +89 -0
  102. package/src/codegen/bin/cli.test.ts +38 -1
  103. package/src/codegen/bin/cli.ts +33 -22
  104. package/src/codegen/bin/flag-specs.test.ts +27 -0
  105. package/src/codegen/bin/flag-specs.ts +69 -0
  106. package/src/codegen/collect-models.test.ts +46 -0
  107. package/src/codegen/collect-models.ts +108 -0
  108. package/src/codegen/emit-client-runtime.ts +1 -0
  109. package/src/codegen/emit-models.test.ts +48 -0
  110. package/src/codegen/emit-models.ts +63 -0
  111. package/src/codegen/emit-scope.ts +145 -33
  112. package/src/codegen/emit-types.ts +48 -7
  113. package/src/codegen/index.ts +7 -0
  114. package/src/codegen/model-refs.test.ts +37 -0
  115. package/src/codegen/model-refs.ts +57 -0
  116. package/src/codegen/pipeline.ts +6 -1
  117. package/src/codegen/schema-walk.test.ts +37 -0
  118. package/src/codegen/schema-walk.ts +23 -0
  119. package/src/codegen/targets/_shared/target-run.ts +5 -0
  120. package/src/codegen/targets/ts/run.ts +33 -0
  121. package/src/codegen/targets/ts/shared-models.test.ts +283 -0
  122. package/src/doc-envelope.test.ts +35 -0
  123. package/src/doc-envelope.ts +30 -0
  124. package/src/exports.ts +2 -0
@@ -0,0 +1,10 @@
1
+ export interface FlagSpec {
2
+ name: string;
3
+ arg?: string;
4
+ description: string;
5
+ group: 'Source' | 'Output' | 'Codegen' | 'Targets' | 'Misc';
6
+ default?: string;
7
+ }
8
+ export declare const FLAG_SPECS: readonly FlagSpec[];
9
+ export declare const KNOWN_FLAGS: readonly string[];
10
+ export declare function formatHelp(): string;
@@ -0,0 +1,60 @@
1
+ export const FLAG_SPECS = [
2
+ // Source
3
+ { name: '--url', arg: '<url>', description: 'Fetch the doc envelope from a running server', group: 'Source' },
4
+ { name: '--file', arg: '<path>', description: 'Read the doc envelope from a JSON file (see writeDocEnvelope)', group: 'Source' },
5
+ { name: '--config', arg: '<path>', description: 'Load options from a JSON config file', group: 'Source' },
6
+ // Output
7
+ { name: '--out', arg: '<dir>', description: 'Output directory for generated files', group: 'Output' },
8
+ { name: '--dry-run', description: 'Print what would be written without touching disk', group: 'Output' },
9
+ { name: '--clean-out-dir', description: 'Prune orphaned generator-owned files before writing', group: 'Output', default: 'on' },
10
+ { name: '--no-clean-out-dir', description: 'Disable orphan pruning', group: 'Output' },
11
+ { name: '--watch', description: 'Regenerate on envelope change', group: 'Output' },
12
+ { name: '--interval', arg: '<ms>', description: 'Poll interval for --watch (default 3000)', group: 'Output' },
13
+ // Codegen
14
+ { name: '--service-name', arg: '<name>', description: 'Service identifier driving generated names', group: 'Codegen', default: 'Api' },
15
+ { name: '--namespace-types', description: 'Wrap types in nested namespaces', group: 'Codegen', default: 'on' },
16
+ { name: '--no-namespace-types', description: 'Flat type names', group: 'Codegen' },
17
+ { name: '--self-contained', description: 'Bundle the client runtime into the output dir', group: 'Codegen', default: 'on' },
18
+ { name: '--no-self-contained', description: 'Import the client runtime from ts-procedures/client', group: 'Codegen' },
19
+ { name: '--client-import-path', arg: '<path>', description: 'Override the client runtime import path', group: 'Codegen' },
20
+ { name: '--share-models', description: 'Hoist $id-bearing schemas into a shared _models.ts', group: 'Codegen', default: 'on' },
21
+ { name: '--no-share-models', description: 'Inline every type per route (legacy behaviour)', group: 'Codegen' },
22
+ { name: '--jsdoc', description: 'Emit JSDoc on generated types', group: 'Codegen', default: 'on' },
23
+ { name: '--no-jsdoc', description: 'Suppress JSDoc', group: 'Codegen' },
24
+ { name: '--enum-style', arg: '<union|enum>', description: 'How to emit enums (namespace mode)', group: 'Codegen' },
25
+ { name: '--depluralize', description: 'Depluralize extracted array-item type names', group: 'Codegen' },
26
+ { name: '--array-item-naming', arg: '<name|false>', description: 'Naming for extracted array-item types', group: 'Codegen' },
27
+ { name: '--uncountable-words', arg: '<csv>', description: 'Words exempt from depluralization', group: 'Codegen' },
28
+ // Targets
29
+ { name: '--target', arg: '<ts|kotlin|swift>', description: 'Output language', group: 'Targets', default: 'ts' },
30
+ { name: '--kotlin-package', arg: '<pkg>', description: 'Package for Kotlin output (required for --target kotlin)', group: 'Targets' },
31
+ { name: '--kotlin-serializer', arg: '<kotlinx|none>', description: 'Kotlin serialization annotations', group: 'Targets', default: 'kotlinx' },
32
+ { name: '--swift-serializer', arg: '<codable|none>', description: 'Swift Codable conformance', group: 'Targets', default: 'codable' },
33
+ { name: '--swift-access-level', arg: '<public|internal>', description: 'Swift access level', group: 'Targets', default: 'public' },
34
+ { name: '--unsupported-unions', arg: '<throw|fallback>', description: 'Behaviour for untagged oneOf schemas', group: 'Targets', default: 'throw' },
35
+ ];
36
+ export const KNOWN_FLAGS = FLAG_SPECS.map((s) => s.name);
37
+ const GROUP_ORDER = ['Source', 'Output', 'Codegen', 'Targets', 'Misc'];
38
+ export function formatHelp() {
39
+ const lines = [];
40
+ lines.push('Usage: ts-procedures-codegen --out <dir> (--url <url> | --file <path>) [options]');
41
+ lines.push('');
42
+ lines.push('Generate a typed client from a ts-procedures doc envelope.');
43
+ lines.push('');
44
+ const col = Math.max(...FLAG_SPECS.map((s) => (s.name + (s.arg ? ' ' + s.arg : '')).length)) + 2;
45
+ for (const group of GROUP_ORDER) {
46
+ const specs = FLAG_SPECS.filter((s) => s.group === group);
47
+ if (specs.length === 0)
48
+ continue;
49
+ lines.push(`${group}:`);
50
+ for (const s of specs) {
51
+ const left = s.name + (s.arg ? ' ' + s.arg : '');
52
+ const def = s.default ? ` (default: ${s.default})` : '';
53
+ lines.push(` ${left.padEnd(col)}${s.description}${def}`);
54
+ }
55
+ lines.push('');
56
+ }
57
+ lines.push(' -h, --help Show this help and exit');
58
+ return lines.join('\n');
59
+ }
60
+ //# sourceMappingURL=flag-specs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flag-specs.js","sourceRoot":"","sources":["../../../src/codegen/bin/flag-specs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { FLAG_SPECS, KNOWN_FLAGS, formatHelp } from './flag-specs.js';
3
+ describe('flag-specs', () => {
4
+ it('derives KNOWN_FLAGS from the spec table', () => {
5
+ expect(KNOWN_FLAGS).toContain('--url');
6
+ expect(KNOWN_FLAGS).toContain('--service-name');
7
+ expect(KNOWN_FLAGS).toContain('--target');
8
+ for (const spec of FLAG_SPECS)
9
+ expect(KNOWN_FLAGS).toContain(spec.name);
10
+ });
11
+ it('formatHelp lists every flag with its description, grouped', () => {
12
+ const help = formatHelp();
13
+ expect(help).toMatch(/Usage: ts-procedures-codegen/);
14
+ for (const spec of FLAG_SPECS) {
15
+ expect(help).toContain(spec.name);
16
+ expect(help).toContain(spec.description);
17
+ }
18
+ expect(help).toMatch(/Source/);
19
+ expect(help).toMatch(/Targets/);
20
+ });
21
+ it('does not list --help/-h as a real codegen flag in KNOWN_FLAGS', () => {
22
+ expect(KNOWN_FLAGS).not.toContain('--help');
23
+ expect(KNOWN_FLAGS).not.toContain('-h');
24
+ });
25
+ });
26
+ //# sourceMappingURL=flag-specs.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flag-specs.test.js","sourceRoot":"","sources":["../../../src/codegen/bin/flag-specs.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAErE,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;QACtC,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAA;QAC/C,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAA;QACzC,KAAK,MAAM,IAAI,IAAI,UAAU;YAAE,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACzE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,IAAI,GAAG,UAAU,EAAE,CAAA;QACzB,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,8BAA8B,CAAC,CAAA;QACpD,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACjC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QAC1C,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;QAC9B,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IACjC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;QAC3C,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;IACzC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,37 @@
1
+ import type { AnyHttpRouteDoc } from '../implementations/types.js';
2
+ /** A schema hoisted out of per-route inlining because it carries a `$id`. */
3
+ export interface CollectedModel {
4
+ /** The schema's `$id` — the stable identity key used for dedup and import mapping. */
5
+ id: string;
6
+ /** PascalCase TypeScript identifier for the emitted model (disambiguated on collision). */
7
+ name: string;
8
+ /** The model's JSON Schema (first-seen copy). */
9
+ schema: Record<string, unknown>;
10
+ }
11
+ /** Maps a model `$id` to an external import (module + exported name). */
12
+ export interface SharedTypeImport {
13
+ module: string;
14
+ name: string;
15
+ }
16
+ /** `$id` → external import. Models with a matching entry are imported rather than generated. */
17
+ export type SharedTypesImportMap = Record<string, SharedTypeImport>;
18
+ /** A {@link CollectedModel} tagged with its external import, if one was configured. */
19
+ export interface ResolvedModel extends CollectedModel {
20
+ import?: SharedTypeImport;
21
+ }
22
+ /**
23
+ * Deep-walks every route's `jsonSchema` and collects each subschema carrying a
24
+ * string `$id` exactly once (deduped by `$id`, first-seen order preserved).
25
+ *
26
+ * - Names are derived from `title` (or the last `$id` segment), PascalCased.
27
+ * - Distinct `$id`s that derive the same name are disambiguated deterministically
28
+ * by first-seen order (`Message`, `Message2`, `Message3`, …).
29
+ * - Two nodes sharing an `$id` but differing structurally throw (the `$id` is a
30
+ * broken identity contract).
31
+ */
32
+ export declare function collectModels(routes: AnyHttpRouteDoc[]): CollectedModel[];
33
+ /**
34
+ * Tags each collected model with its external import when its `$id` is a key in
35
+ * the import map; models without a mapping keep `import` undefined (generated locally).
36
+ */
37
+ export declare function resolveModelImports(models: CollectedModel[], map?: SharedTypesImportMap): ResolvedModel[];
@@ -0,0 +1,74 @@
1
+ import { toPascalCase } from './naming.js';
2
+ import { walkSubschemas } from './schema-walk.js';
3
+ /** Produces a stable structural key for collision detection (key order does not matter). */
4
+ function structuralKey(value) {
5
+ return JSON.stringify(value, (_k, v) => {
6
+ if (v && typeof v === 'object' && !Array.isArray(v)) {
7
+ const sorted = {};
8
+ for (const k of Object.keys(v).sort()) {
9
+ sorted[k] = v[k];
10
+ }
11
+ return sorted;
12
+ }
13
+ return v;
14
+ });
15
+ }
16
+ /** Derives a base PascalCase name from a schema's `title`, falling back to the last `$id` segment. */
17
+ function deriveBaseName(schema, id) {
18
+ const title = typeof schema.title === 'string' ? schema.title : undefined;
19
+ const source = title ?? id.split(/[/:#?]+/).filter(Boolean).pop() ?? id;
20
+ const pascal = toPascalCase(source);
21
+ return pascal.length > 0 ? pascal : 'Model';
22
+ }
23
+ /**
24
+ * Deep-walks every route's `jsonSchema` and collects each subschema carrying a
25
+ * string `$id` exactly once (deduped by `$id`, first-seen order preserved).
26
+ *
27
+ * - Names are derived from `title` (or the last `$id` segment), PascalCased.
28
+ * - Distinct `$id`s that derive the same name are disambiguated deterministically
29
+ * by first-seen order (`Message`, `Message2`, `Message3`, …).
30
+ * - Two nodes sharing an `$id` but differing structurally throw (the `$id` is a
31
+ * broken identity contract).
32
+ */
33
+ export function collectModels(routes) {
34
+ const byId = new Map();
35
+ const order = [];
36
+ const visit = (obj) => {
37
+ if (typeof obj.$id === 'string') {
38
+ const id = obj.$id;
39
+ const key = structuralKey(obj);
40
+ const existing = byId.get(id);
41
+ if (existing) {
42
+ if (existing.key !== key) {
43
+ throw new Error(`[ts-procedures-codegen] Conflicting schemas share $id "${id}". A $id must identify a single structural shape; found two divergent definitions.`);
44
+ }
45
+ }
46
+ else {
47
+ byId.set(id, { schema: obj, key });
48
+ order.push(id);
49
+ }
50
+ }
51
+ };
52
+ for (const route of routes)
53
+ walkSubschemas(route.jsonSchema, visit);
54
+ const usedNames = new Map();
55
+ return order.map((id) => {
56
+ const { schema } = byId.get(id);
57
+ const base = deriveBaseName(schema, id);
58
+ const seen = usedNames.get(base) ?? 0;
59
+ usedNames.set(base, seen + 1);
60
+ const name = seen === 0 ? base : `${base}${seen + 1}`;
61
+ return { id, name, schema };
62
+ });
63
+ }
64
+ /**
65
+ * Tags each collected model with its external import when its `$id` is a key in
66
+ * the import map; models without a mapping keep `import` undefined (generated locally).
67
+ */
68
+ export function resolveModelImports(models, map = {}) {
69
+ return models.map((model) => {
70
+ const mapped = map[model.id];
71
+ return mapped ? { ...model, import: mapped } : { ...model };
72
+ });
73
+ }
74
+ //# sourceMappingURL=collect-models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collect-models.js","sourceRoot":"","sources":["../../src/codegen/collect-models.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,40 @@
1
+ import { it, expect } from 'vitest';
2
+ import { collectModels, resolveModelImports } from './collect-models.js';
3
+ const message = { type: 'object', $id: 'urn:msg', title: 'Message', properties: { id: { type: 'string' } } };
4
+ it('collects each $id subschema once, named from title', () => {
5
+ const routes = [
6
+ { jsonSchema: { response: message } },
7
+ { jsonSchema: { body: { type: 'object', properties: { msg: message } } } },
8
+ ];
9
+ const models = collectModels(routes);
10
+ expect(models.map((m) => m.name)).toEqual(['Message']);
11
+ expect(models[0]?.id).toBe('urn:msg');
12
+ });
13
+ it('throws on $id collision with divergent body', () => {
14
+ const a = { type: 'object', $id: 'urn:x', title: 'X', properties: { a: { type: 'string' } } };
15
+ const b = { type: 'object', $id: 'urn:x', title: 'X', properties: { b: { type: 'number' } } };
16
+ expect(() => collectModels([{ jsonSchema: { response: a } }, { jsonSchema: { body: b } }])).toThrow(/urn:x/);
17
+ });
18
+ it('disambiguates distinct $ids that derive the same name', () => {
19
+ const m1 = { type: 'object', $id: 'urn:a/message', title: 'Message', properties: { a: { type: 'string' } } };
20
+ const m2 = { type: 'object', $id: 'urn:b/message', title: 'Message', properties: { b: { type: 'string' } } };
21
+ const models = collectModels([{ jsonSchema: { response: m1 } }, { jsonSchema: { body: m2 } }]);
22
+ expect(models.map((m) => m.name).sort()).toEqual(['Message', 'Message2']);
23
+ });
24
+ it('ignores schemas without $id', () => {
25
+ const routes = [{ jsonSchema: { response: { type: 'object', title: 'Loose', properties: {} } } }];
26
+ expect(collectModels(routes)).toEqual([]);
27
+ });
28
+ it('does NOT throw for ordinary schemas without the reserved prefix', () => {
29
+ const routes = [
30
+ { jsonSchema: { response: { type: 'object', properties: { kind: { const: 'message' }, status: { enum: ['ok', 'error'] } } } } },
31
+ ];
32
+ expect(() => collectModels(routes)).not.toThrow();
33
+ });
34
+ it('resolveModelImports tags mapped models and leaves others generated', () => {
35
+ const models = [{ id: 'urn:msg', name: 'Message', schema: {} }];
36
+ const mapped = resolveModelImports(models, { 'urn:msg': { module: '@shared/schemas', name: 'Message' } });
37
+ expect(mapped[0]?.import).toEqual({ module: '@shared/schemas', name: 'Message' });
38
+ expect(resolveModelImports(models, {})[0]?.import).toBeUndefined();
39
+ });
40
+ //# sourceMappingURL=collect-models.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collect-models.test.js","sourceRoot":"","sources":["../../src/codegen/collect-models.test.ts"],"names":[],"mappings":"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"}
@@ -17,6 +17,7 @@ const TYPES_IMPORT = `import type {
17
17
  ClientInstance,
18
18
  ProcedureCallDefaults,
19
19
  ProcedureCallOptions,
20
+ ClientHeadersInit,
20
21
  CreateClientConfig,
21
22
  RequestMeta,
22
23
  ErrorRegistry,
@@ -1 +1 @@
1
- {"version":3,"file":"emit-client-runtime.js","sourceRoot":"","sources":["../../src/codegen/emit-client-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAE/C,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA2BH,CAAA;AAElB;;;GAGG;AACH,MAAM,YAAY,GAAG;IACnB,WAAW;IACX,mBAAmB;IACnB,mBAAmB;IACnB,oBAAoB;IACpB,oBAAoB;IACpB,UAAU;IACV,SAAS;IACT,WAAW;IACX,kBAAkB;IAClB,UAAU;CACF,CAAA;AAEV;;;;;;;GAOG;AACH,SAAS,YAAY,CAAC,OAAe;IACnC,2DAA2D;IAC3D,OAAO,OAAO,CAAC,OAAO,CAAC,mDAAmD,EAAE,EAAE,CAAC,CAAA;AACjF,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,OAAe;IACrC,mFAAmF;IACnF,OAAO,OAAO,CAAC,OAAO,CAAC,gEAAgE,EAAE,EAAE,CAAC,CAAA;AAC9F,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACjD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;IACrC,sEAAsE;IACtE,MAAM,WAAW,GAAG,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,WAAW,EAAE,YAAY,CAAC,CAAA;IAEpD,gCAAgC;IAChC,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;QACzC,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM,IAAI,KAAK,CACb,oDAAoD,IAAI,sBAAsB,QAAQ,IAAI;gBAC1F,8CAA8C,CAC/C,CAAA;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,MAAM,QAAQ,GAAa,EAAE,CAAA;IAE7B,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;QACzC,IAAI,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;QAE/C,mDAAmD;QACnD,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;QAE/B,kDAAkD;QAClD,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;YACxB,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;YACjC,0EAA0E;YAC1E,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAA;QACxD,CAAC;QAED,yCAAyC;QACzC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;QAE5C,mCAAmC;QACnC,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAA;QAExB,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACxB,CAAC;IACH,CAAC;IAED,OAAO,CAAC,cAAc,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,GAAG,QAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC3E,CAAC"}
1
+ {"version":3,"file":"emit-client-runtime.js","sourceRoot":"","sources":["../../src/codegen/emit-client-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAE/C,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA4BH,CAAA;AAElB;;;GAGG;AACH,MAAM,YAAY,GAAG;IACnB,WAAW;IACX,mBAAmB;IACnB,mBAAmB;IACnB,oBAAoB;IACpB,oBAAoB;IACpB,UAAU;IACV,SAAS;IACT,WAAW;IACX,kBAAkB;IAClB,UAAU;CACF,CAAA;AAEV;;;;;;;GAOG;AACH,SAAS,YAAY,CAAC,OAAe;IACnC,2DAA2D;IAC3D,OAAO,OAAO,CAAC,OAAO,CAAC,mDAAmD,EAAE,EAAE,CAAC,CAAA;AACjF,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,OAAe;IACrC,mFAAmF;IACnF,OAAO,OAAO,CAAC,OAAO,CAAC,gEAAgE,EAAE,EAAE,CAAC,CAAA;AAC9F,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACjD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;IACrC,sEAAsE;IACtE,MAAM,WAAW,GAAG,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,WAAW,EAAE,YAAY,CAAC,CAAA;IAEpD,gCAAgC;IAChC,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;QACzC,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM,IAAI,KAAK,CACb,oDAAoD,IAAI,sBAAsB,QAAQ,IAAI;gBAC1F,8CAA8C,CAC/C,CAAA;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,MAAM,QAAQ,GAAa,EAAE,CAAA;IAE7B,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;QACzC,IAAI,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;QAE/C,mDAAmD;QACnD,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;QAE/B,kDAAkD;QAClD,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;YACxB,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;YACjC,0EAA0E;YAC1E,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAA;QACxD,CAAC;QAED,yCAAyC;QACzC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;QAE5C,mCAAmC;QACnC,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAA;QAExB,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACxB,CAAC;IACH,CAAC;IAED,OAAO,CAAC,cAAc,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,GAAG,QAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC3E,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { type AjscOptions } from './emit-types.js';
2
+ import type { ResolvedModel } from './collect-models.js';
3
+ export interface EmitModelsOptions {
4
+ ajsc?: AjscOptions;
5
+ }
6
+ /**
7
+ * Emits the shared `_models.ts` hub: one named TypeScript type per `$id`-bearing
8
+ * schema so routes can reference a single entity type instead of inlining copies.
9
+ *
10
+ * Two kinds of model:
11
+ * - **Imported** (`model.import` set): re-exported from the user's package —
12
+ * `export { <PkgName>[ as <LocalName>] } from '<module>'`.
13
+ * - **Generated** (no `import`): converted from JSON Schema to a TS type via
14
+ * ajsc. Nested OTHER models are first rewritten to `x-named-type` nodes
15
+ * ({@link substituteModelRefs} with `skipSelfId` so the model's own root
16
+ * `$id` is not self-referenced); ajsc (≥7.3.0) then emits each nested model
17
+ * as a bare verbatim reference rather than re-inlining its shape.
18
+ *
19
+ * Declarations are kept FLAT at the top level regardless of `namespaceTypes` —
20
+ * scopes import these by bare name and TS `type` aliases permit forward
21
+ * references, so declaration order does not matter. Re-exports are emitted first,
22
+ * then generated declarations.
23
+ *
24
+ * Returns `null` when there are no models.
25
+ */
26
+ export declare function emitModelsFile(models: ResolvedModel[], opts: EmitModelsOptions): Promise<string | null>;
@@ -0,0 +1,53 @@
1
+ import { jsonSchemaToTypeBody } from './emit-types.js';
2
+ import { substituteModelRefs } from './model-refs.js';
3
+ import { CODEGEN_HEADER } from './constants.js';
4
+ /**
5
+ * Emits the shared `_models.ts` hub: one named TypeScript type per `$id`-bearing
6
+ * schema so routes can reference a single entity type instead of inlining copies.
7
+ *
8
+ * Two kinds of model:
9
+ * - **Imported** (`model.import` set): re-exported from the user's package —
10
+ * `export { <PkgName>[ as <LocalName>] } from '<module>'`.
11
+ * - **Generated** (no `import`): converted from JSON Schema to a TS type via
12
+ * ajsc. Nested OTHER models are first rewritten to `x-named-type` nodes
13
+ * ({@link substituteModelRefs} with `skipSelfId` so the model's own root
14
+ * `$id` is not self-referenced); ajsc (≥7.3.0) then emits each nested model
15
+ * as a bare verbatim reference rather than re-inlining its shape.
16
+ *
17
+ * Declarations are kept FLAT at the top level regardless of `namespaceTypes` —
18
+ * scopes import these by bare name and TS `type` aliases permit forward
19
+ * references, so declaration order does not matter. Re-exports are emitted first,
20
+ * then generated declarations.
21
+ *
22
+ * Returns `null` when there are no models.
23
+ */
24
+ export async function emitModelsFile(models, opts) {
25
+ if (models.length === 0)
26
+ return null;
27
+ const idToName = new Map(models.map((m) => [m.id, m.name]));
28
+ const reExports = [];
29
+ const declarations = [];
30
+ for (const model of models) {
31
+ if (model.import) {
32
+ const pkgName = model.import.name;
33
+ const localName = model.name;
34
+ const clause = pkgName === localName ? pkgName : `${pkgName} as ${localName}`;
35
+ reExports.push(`export { ${clause} } from '${model.import.module}'`);
36
+ continue;
37
+ }
38
+ // Generated model: rewrite nested OTHER models to `x-named-type` nodes so
39
+ // ajsc emits them as bare references, then convert to a TS body.
40
+ const substituted = substituteModelRefs(model.schema, idToName, model.id);
41
+ const body = await jsonSchemaToTypeBody(substituted.schema, opts.ajsc);
42
+ if (body == null)
43
+ continue;
44
+ declarations.push(`export type ${model.name} = ${body}`);
45
+ }
46
+ const blocks = [];
47
+ if (reExports.length > 0)
48
+ blocks.push(reExports.join('\n'));
49
+ for (const decl of declarations)
50
+ blocks.push(decl);
51
+ return [CODEGEN_HEADER, '', blocks.join('\n\n')].join('\n');
52
+ }
53
+ //# sourceMappingURL=emit-models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-models.js","sourceRoot":"","sources":["../../src/codegen/emit-models.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAoB,MAAM,iBAAiB,CAAA;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAO/C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAuB,EACvB,IAAuB;IAEvB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IAEpC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAE3D,MAAM,SAAS,GAAa,EAAE,CAAA;IAC9B,MAAM,YAAY,GAAa,EAAE,CAAA;IAEjC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAA;YACjC,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAA;YAC5B,MAAM,MAAM,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,OAAO,SAAS,EAAE,CAAA;YAC7E,SAAS,CAAC,IAAI,CAAC,YAAY,MAAM,YAAY,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAA;YACpE,SAAQ;QACV,CAAC;QAED,0EAA0E;QAC1E,iEAAiE;QACjE,MAAM,WAAW,GAAG,mBAAmB,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,CAAA;QACzE,MAAM,IAAI,GAAG,MAAM,oBAAoB,CAAC,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;QACtE,IAAI,IAAI,IAAI,IAAI;YAAE,SAAQ;QAC1B,YAAY,CAAC,IAAI,CAAC,eAAe,KAAK,CAAC,IAAI,MAAM,IAAI,EAAE,CAAC,CAAA;IAC1D,CAAC;IAED,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IAC3D,KAAK,MAAM,IAAI,IAAI,YAAY;QAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAElD,OAAO,CAAC,cAAc,EAAE,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC7D,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,42 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { emitModelsFile } from './emit-models.js';
3
+ const thread = {
4
+ id: 'urn:thread', name: 'Thread',
5
+ schema: { type: 'object', $id: 'urn:thread', title: 'Thread',
6
+ properties: { id: { type: 'string' }, author: { type: 'object', $id: 'urn:msg', title: 'Message', properties: { id: { type: 'string' } } } } },
7
+ };
8
+ const messageGenerated = {
9
+ id: 'urn:msg', name: 'Message',
10
+ schema: { type: 'object', $id: 'urn:msg', title: 'Message', properties: { id: { type: 'string' } } },
11
+ };
12
+ const messageImported = {
13
+ id: 'urn:msg', name: 'Message', schema: {},
14
+ import: { module: '@shared/schemas', name: 'Message' },
15
+ };
16
+ describe('emitModelsFile', () => {
17
+ it('returns null when there are no models', async () => {
18
+ expect(await emitModelsFile([], { ajsc: {} })).toBeNull();
19
+ });
20
+ it('declares a generated model as a named type', async () => {
21
+ const code = await emitModelsFile([messageGenerated], { ajsc: {} });
22
+ expect(code).toMatch(/export type Message =/);
23
+ });
24
+ it('re-exports a mapped model from the user package', async () => {
25
+ const code = await emitModelsFile([messageImported], { ajsc: {} });
26
+ expect(code).toContain("export { Message } from '@shared/schemas'");
27
+ });
28
+ it('aliases a re-export when local name differs from the package name', async () => {
29
+ const m = { id: 'urn:msg', name: 'ChatMessage', schema: {}, import: { module: '@shared/schemas', name: 'Message' } };
30
+ const code = await emitModelsFile([m], { ajsc: {} });
31
+ expect(code).toContain("export { Message as ChatMessage } from '@shared/schemas'");
32
+ });
33
+ it('a generated model that nests another model references it by name, not inlined', async () => {
34
+ // Thread.author is the Message model — Thread should reference Message, not inline { id }
35
+ const code = await emitModelsFile([thread, messageGenerated], { ajsc: {} });
36
+ // Thread's author property is typed as Message (the model), referenced by bare name
37
+ expect(code).toMatch(/author\??:\s*Message/);
38
+ // and there is no leftover placeholder token
39
+ expect(code).not.toContain('__MODELREF__');
40
+ });
41
+ });
42
+ //# sourceMappingURL=emit-models.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit-models.test.js","sourceRoot":"","sources":["../../src/codegen/emit-models.test.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,16 @@ export interface EmitScopeOptions {
12
12
  * so generated code never references undefined types.
13
13
  */
14
14
  errorKeys?: Set<string>;
15
+ /**
16
+ * Maps a model `$id` to its shared model type name (built by the run module
17
+ * from ALL models — generated and imported). When present and non-empty,
18
+ * `$id` subschemas are rewritten to `x-named-type` nodes before ajsc; ajsc
19
+ * emits bare references and reports them via `referencedNamedTypes`, which
20
+ * drives the `import type { … } from './_models'` line. Absent/empty →
21
+ * identical inlining behaviour (the conversion wrappers short-circuit so
22
+ * output is byte-identical for envelopes without models).
23
+ */
24
+ idToModelName?: Map<string, string>;
15
25
  }
16
26
  /**
17
27
  * Generates a complete TypeScript scope file for a ScopeGroup.