ts-procedures 8.3.0 → 8.5.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 (126) 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 +15 -0
  25. package/build/codegen/bin/cli.js +46 -21
  26. package/build/codegen/bin/cli.js.map +1 -1
  27. package/build/codegen/bin/cli.test.js +54 -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 +62 -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 +35 -0
  34. package/build/codegen/bin/flag-specs.test.js.map +1 -0
  35. package/build/codegen/collect-models.d.ts +48 -0
  36. package/build/codegen/collect-models.js +84 -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 +59 -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 +15 -0
  56. package/build/codegen/index.js +5 -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 +7 -0
  65. package/build/codegen/pipeline.js +6 -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 +15 -0
  74. package/build/codegen/targets/ts/run.js +37 -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 +354 -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 +163 -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/handoffs/shared-models-auto-resolve-response.md +181 -0
  92. package/docs/superpowers/plans/2026-06-05-dx-feedback-round.md +1292 -0
  93. package/docs/superpowers/plans/2026-06-06-shared-models-convention-and-diagnostics.md +659 -0
  94. package/docs/superpowers/specs/2026-06-05-dx-feedback-round-design.md +285 -0
  95. package/package.json +2 -2
  96. package/src/client/call.ts +1 -1
  97. package/src/client/index.test.ts +98 -0
  98. package/src/client/index.ts +32 -1
  99. package/src/client/resolve-options.test.ts +73 -26
  100. package/src/client/resolve-options.ts +23 -9
  101. package/src/client/stream.ts +1 -1
  102. package/src/client/types.ts +34 -3
  103. package/src/codegen/__fixtures__/make-envelope.ts +89 -0
  104. package/src/codegen/bin/cli.test.ts +65 -1
  105. package/src/codegen/bin/cli.ts +51 -22
  106. package/src/codegen/bin/flag-specs.test.ts +38 -0
  107. package/src/codegen/bin/flag-specs.ts +71 -0
  108. package/src/codegen/collect-models.test.ts +68 -0
  109. package/src/codegen/collect-models.ts +125 -0
  110. package/src/codegen/emit-client-runtime.ts +1 -0
  111. package/src/codegen/emit-models.test.ts +48 -0
  112. package/src/codegen/emit-models.ts +63 -0
  113. package/src/codegen/emit-scope.ts +145 -33
  114. package/src/codegen/emit-types.ts +48 -7
  115. package/src/codegen/index.ts +20 -0
  116. package/src/codegen/model-refs.test.ts +37 -0
  117. package/src/codegen/model-refs.ts +57 -0
  118. package/src/codegen/pipeline.ts +13 -1
  119. package/src/codegen/schema-walk.test.ts +37 -0
  120. package/src/codegen/schema-walk.ts +23 -0
  121. package/src/codegen/targets/_shared/target-run.ts +15 -0
  122. package/src/codegen/targets/ts/run.ts +50 -0
  123. package/src/codegen/targets/ts/shared-models.test.ts +391 -0
  124. package/src/doc-envelope.test.ts +35 -0
  125. package/src/doc-envelope.ts +30 -0
  126. package/src/exports.ts +2 -0
@@ -0,0 +1,181 @@
1
+ # Response: shared-models auto-resolve (re: `--shared-types-from` request)
2
+
3
+ > **STATUS: SHIPPED (v8.5.0).** Three targeted improvements shipped in place of source-file scanning. See below for what landed and why the requested mechanism was declined.
4
+
5
+ **To:** downstream developer
6
+ **From:** ts-procedures codegen maintainers
7
+ **Date:** 2026-06-06
8
+ **Reference:** feedback on `sharedTypesImport` DX — pain points 1–3
9
+
10
+ ---
11
+
12
+ ## TL;DR
13
+
14
+ The goal — "define it once, no second table, no silent drift" — was right. We shipped three targeted fixes that deliver those ergonomics from the DocEnvelope side rather than by scanning TypeScript source files, which would introduce a worse class of silent failure. The per-`$id` `sharedTypesImport` map is unchanged and remains available as a precision escape hatch.
15
+
16
+ ---
17
+
18
+ ## What shipped
19
+
20
+ ### 1. `sharedModelsModule` — one line replaces the entire map
21
+
22
+ A single module path tells codegen: *"re-export every `$id` model from this module under its derived name."*
23
+
24
+ ```jsonc
25
+ // ts-procedures-codegen.config.json
26
+ { "sharedModelsModule": "@app/schemas" }
27
+ ```
28
+
29
+ ```bash
30
+ # CLI
31
+ npx ts-procedures-codegen --url http://localhost:3000/doc --out ./generated --shared-models-module @app/schemas
32
+ ```
33
+
34
+ ```ts
35
+ // generateClient() API
36
+ await generateClient({ url, outDir, sharedModelsModule: '@app/schemas' })
37
+ ```
38
+
39
+ Convention: the derived name is the model's `$id`/`title` (PascalCase), which is the same identifier your schema file already exports. If the names align — they usually do — the entire `sharedTypesImport` map collapses to this single value.
40
+
41
+ Precedence: explicit `sharedTypesImport[$id]` entry → `sharedModelsModule` convention → generate locally. The map remains available to override individual entries (rename, different package, multi-consumer split).
42
+
43
+ ### 2. Summary log (CLI)
44
+
45
+ Every CLI run that finds `$id`-bearing models now prints:
46
+
47
+ ```
48
+ [ts-procedures-codegen] Shared models: 15 total — 15 re-exported, 0 generated locally.
49
+ ```
50
+
51
+ This makes silent generated-twin drift visible without requiring any additional flags or contract tests. (Calling `generateClient` programmatically is silent by default — pass `logger: console.log` to opt in — so the summary never leaks into your own build-script output.)
52
+
53
+ ### 3. `--strict-shared-models` — hard-fail on local twins
54
+
55
+ Fails the run and lists every `$id` that would be generated as a local structural twin instead of re-exported:
56
+
57
+ ```bash
58
+ npx ts-procedures-codegen ... --strict-shared-models
59
+ ```
60
+
61
+ ```jsonc
62
+ { "strictSharedModels": true }
63
+ ```
64
+
65
+ ```ts
66
+ await generateClient({ url, outDir, sharedModelsModule: '@app/schemas', strictSharedModels: true })
67
+ ```
68
+
69
+ This is a **CI flag, not a development default** — run it in your pipeline and codegen becomes the drift gate. It replaces a hand-written `toEqualTypeOf` contract test.
70
+
71
+ ---
72
+
73
+ ## How this maps to your three pain points
74
+
75
+ ### Pain 1: Two places to keep in lockstep (`$id` and the map entry)
76
+
77
+ `sharedModelsModule` derives the import from the model's own `$id`/`title` — you define the convention once and it applies to every model. There is no second table to maintain.
78
+
79
+ ### Pain 2: Silent fallback — a generated structural twin that typechecks but isn't the real type
80
+
81
+ Two layers now make this visible:
82
+
83
+ - The CLI summary log surfaces the "generated locally" count on every codegen run.
84
+ - `--strict-shared-models` promotes that to a hard failure, listing the specific `$id`s. Add it to your CI pipeline and the generated-twin state becomes impossible to ship.
85
+
86
+ This replaces your hand-written `toEqualTypeOf` contract test with a single flag — the codegen itself owns the invariant.
87
+
88
+ ### Pain 3: The map is redundant — `module` is "where the schema lives" and `name` is usually the `$id`
89
+
90
+ `sharedModelsModule` makes that redundancy disappear. `name` is derived from the model's `$id`/`title`; `module` is supplied once for all models. The 15-entry map becomes one line.
91
+
92
+ ---
93
+
94
+ ## Why `--shared-types-from <dir|glob>` was declined
95
+
96
+ The goal was right. The mechanism is what we changed.
97
+
98
+ ts-procedures codegen has one explicit input contract: a **DocEnvelope** obtained via `--url`, `--file`, or a passed object. The envelope is a self-contained JSON document — it contains schemas, routes, and error shapes. Codegen never reads the consumer's TypeScript source tree. That decoupling is what makes codegen work against a live remote server, a serialized offline file, or a published package with no local source.
99
+
100
+ Source-file scanning would break that contract in four concrete ways:
101
+
102
+ **(a) Silent desync in `--url` / offline `--file` cases.** The live server's envelope and the local source tree can disagree at any point in time — a schema field renamed in the server but not yet deployed, an `$id` changed in source but not rebuilt. Source scanning would produce a "shared" reference that names a type the server actually never returns. The result typechecks and the single-source-of-truth claim is restored, but the types are silently WRONG — a worse outcome than today's duplicate-but-correct structural twin.
103
+
104
+ **(b) Fails for published-package consumers.** If `@app/schemas` lives in `node_modules`, there is no TypeScript source tree to scan — only compiled `.d.ts` files (if any) or nothing. The scan would silently skip models that are genuinely shared from a published package and generate local twins for them anyway, with no signal.
105
+
106
+ **(c) Requires a TS parser, glob runner, and export-resolution heuristics in codegen.** This is a substantial dependency and surface area. It introduces failure modes (barrel re-exports, `export * from`, conditional exports, `.d.ts` vs. `.ts`) whose edge cases are hard to exhaustively enumerate and maintain. The DocEnvelope contract specifically exists to avoid this category of tooling dependency.
107
+
108
+ **(d) Does not solve module-path correctness.** A file path discovered by glob scanning (`src/schemas/message.ts`) is not a valid TypeScript import specifier for a consumer who imports `@app/schemas`. Path-to-module-alias resolution requires TypeScript's full compiler configuration. Without it, any path the scan produces must be corrected by hand — which brings back a second table.
109
+
110
+ The `sharedModelsModule` convention solves the same "define once, no second table" problem. The module specifier (`@app/schemas`) is typed once; names are derived from the model's own `$id`/`title`. It works in all deployment topologies: live server, offline file, published package.
111
+
112
+ ---
113
+
114
+ ## Escape hatch: `sharedTypesImport` unchanged
115
+
116
+ The per-`$id` map is unchanged and remains available for cases where `sharedModelsModule` is not enough:
117
+
118
+ - A model whose TypeScript name differs from its `$id` (rename case).
119
+ - Different models imported from different packages (`@app/schemas` and `@app/internal-schemas`).
120
+ - Multi-consumer split where a subset of models come from a shared package and others are generated locally.
121
+
122
+ ```jsonc
123
+ {
124
+ "sharedModelsModule": "@app/schemas",
125
+ "sharedTypesImport": {
126
+ "urn:internal-msg": { "module": "@app/internal-schemas", "name": "InternalMessage" }
127
+ }
128
+ }
129
+ ```
130
+
131
+ `sharedTypesImport` entries take precedence over `sharedModelsModule`, so you can cover the general case with the convention and override individual outliers explicitly.
132
+
133
+ ---
134
+
135
+ ## Migration example
136
+
137
+ **Before (v8.3 and earlier) — 15-entry hand-maintained map + contract test:**
138
+
139
+ ```jsonc
140
+ // ts-procedures-codegen.config.json
141
+ {
142
+ "shareModels": true,
143
+ "sharedTypesImport": {
144
+ "urn:message": { "module": "@app/schemas", "name": "Message" },
145
+ "urn:user": { "module": "@app/schemas", "name": "User" },
146
+ "urn:thread": { "module": "@app/schemas", "name": "Thread" },
147
+ "urn:attachment": { "module": "@app/schemas", "name": "Attachment" },
148
+ "urn:reaction": { "module": "@app/schemas", "name": "Reaction" },
149
+ "urn:channel": { "module": "@app/schemas", "name": "Channel" },
150
+ "urn:workspace": { "module": "@app/schemas", "name": "Workspace" },
151
+ "urn:notification": { "module": "@app/schemas", "name": "Notification" },
152
+ "urn:role": { "module": "@app/schemas", "name": "Role" },
153
+ "urn:permission": { "module": "@app/schemas", "name": "Permission" },
154
+ "urn:bot": { "module": "@app/schemas", "name": "Bot" },
155
+ "urn:webhook": { "module": "@app/schemas", "name": "Webhook" },
156
+ "urn:app": { "module": "@app/schemas", "name": "App" },
157
+ "urn:token": { "module": "@app/schemas", "name": "Token" },
158
+ "urn:audit-log": { "module": "@app/schemas", "name": "AuditLog" }
159
+ }
160
+ }
161
+ ```
162
+
163
+ ```ts
164
+ // contract test to catch silent twins
165
+ expect(generatedMessage).toEqualTypeOf<Message>()
166
+ expect(generatedUser).toEqualTypeOf<User>()
167
+ // ... × 15
168
+ ```
169
+
170
+ **After (v8.5.0) — one config line + one CI flag:**
171
+
172
+ ```jsonc
173
+ // ts-procedures-codegen.config.json
174
+ {
175
+ "shareModels": true,
176
+ "sharedModelsModule": "@app/schemas",
177
+ "strictSharedModels": true
178
+ }
179
+ ```
180
+
181
+ No map. No contract tests. `--strict-shared-models` (or `"strictSharedModels": true`) in CI is the drift gate: codegen fails and names the offender if any `$id` model would silently generate as a local twin.