ts-procedures 8.1.0 → 8.1.1

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 (76) hide show
  1. package/README.md +14 -0
  2. package/build/client/call.test.js +1 -1
  3. package/build/client/call.test.js.map +1 -1
  4. package/build/client/errors.js +0 -1
  5. package/build/client/errors.js.map +1 -1
  6. package/build/client/hooks.test.js +1 -1
  7. package/build/client/hooks.test.js.map +1 -1
  8. package/build/client/index.js +1 -1
  9. package/build/client/index.js.map +1 -1
  10. package/build/client/typed-error-dispatch.test.js +6 -3
  11. package/build/client/typed-error-dispatch.test.js.map +1 -1
  12. package/build/codegen/bundle-size.test.js +0 -1
  13. package/build/codegen/bundle-size.test.js.map +1 -1
  14. package/build/codegen/emit-client-types.test.js +1 -0
  15. package/build/codegen/emit-client-types.test.js.map +1 -1
  16. package/build/codegen/emit-scope.js +1 -1
  17. package/build/codegen/emit-scope.js.map +1 -1
  18. package/build/codegen/test-helpers/golden.js +0 -1
  19. package/build/codegen/test-helpers/golden.js.map +1 -1
  20. package/build/create-http-stream.d.ts +2 -2
  21. package/build/create-http.d.ts +3 -3
  22. package/build/create-http.js.map +1 -1
  23. package/build/create-http.test.js +1 -1
  24. package/build/create-http.test.js.map +1 -1
  25. package/build/create-stream.d.ts +2 -2
  26. package/build/create-stream.test.js +1 -2
  27. package/build/create-stream.test.js.map +1 -1
  28. package/build/create.d.ts +2 -2
  29. package/build/create.test.js +1 -2
  30. package/build/create.test.js.map +1 -1
  31. package/build/errors.d.ts +2 -2
  32. package/build/errors.js.map +1 -1
  33. package/build/implementations/http/hono/index.d.ts +2 -1
  34. package/build/implementations/http/hono/index.js.map +1 -1
  35. package/build/implementations/types.d.ts +1 -1
  36. package/build/index.d.ts +9 -9
  37. package/build/index.js +1 -0
  38. package/build/index.js.map +1 -1
  39. package/build/index.test.js +0 -1
  40. package/build/index.test.js.map +1 -1
  41. package/build/schema/compute-schema.d.ts +3 -3
  42. package/build/schema/compute-schema.js.map +1 -1
  43. package/build/schema/extract-json-schema.d.ts +1 -1
  44. package/build/schema/parser.d.ts +1 -1
  45. package/build/schema/resolve-schema-lib.d.ts +2 -2
  46. package/build/schema/types.d.ts +2 -2
  47. package/build/stack-utils.test.js.map +1 -1
  48. package/build/types.d.ts +2 -2
  49. package/docs/decisions/2026-06-02-monorepo-split-evaluation.md +80 -0
  50. package/docs/npm-workspaces-migration-plan.md +611 -0
  51. package/package.json +2 -1
  52. package/src/client/errors.ts +1 -1
  53. package/src/client/typed-error-dispatch.test.ts +1 -2
  54. package/src/codegen/bundle-size.test.ts +1 -1
  55. package/src/codegen/test-helpers/golden.ts +1 -1
  56. package/src/create-http-stream.ts +2 -2
  57. package/src/create-http.ts +2 -3
  58. package/src/create-stream.test.ts +1 -1
  59. package/src/create-stream.ts +2 -2
  60. package/src/create.test.ts +1 -1
  61. package/src/create.ts +2 -2
  62. package/src/errors.test.ts +1 -1
  63. package/src/errors.ts +3 -2
  64. package/src/implementations/http/hono/index.ts +2 -1
  65. package/src/implementations/http/on-request-error.test.ts +1 -1
  66. package/src/implementations/http/route-errors.test.ts +1 -1
  67. package/src/implementations/types.ts +1 -1
  68. package/src/index.test.ts +1 -1
  69. package/src/index.ts +2 -2
  70. package/src/schema/compute-schema.ts +4 -3
  71. package/src/schema/extract-json-schema.ts +1 -1
  72. package/src/schema/parser.ts +1 -1
  73. package/src/schema/resolve-schema-lib.ts +2 -2
  74. package/src/schema/types.ts +2 -2
  75. package/src/stack-utils.test.ts +2 -1
  76. package/src/types.ts +2 -2
@@ -0,0 +1,611 @@
1
+ # ts-procedures → npm workspaces monorepo migration plan
2
+
3
+ > **⚠️ SUPERSEDED (2026-06-02) — NOT the current direction.**
4
+ > The split was evaluated and **declined**; we stay single-package. See the
5
+ > decision record: [`docs/decisions/2026-06-02-monorepo-split-evaluation.md`](decisions/2026-06-02-monorepo-split-evaluation.md).
6
+ > This document is retained only as a starting point if the split is ever
7
+ > revived for an independent-versioning or `@ts-procedures` branding reason.
8
+ > Note two corrections the decision record carries: codegen→core must be a
9
+ > **normal** dependency (its public API leaks `DocEnvelope`), and the wire
10
+ > contract should be a named `core/contract` seam.
11
+
12
+ Status: **READY — simplified design. All prior hard blockers resolved or designed out.**
13
+ Target: split the single `ts-procedures@8.1.0` package into an npm-workspaces
14
+ monorepo of **7** scoped packages under `@ts-procedures/*`, published fresh at
15
+ `v1.0.0` in lockstep. **No meta/shim package** — `ts-procedures@8.1.0` is
16
+ deprecated in place.
17
+
18
+ This revision incorporates a line-by-line source verification (June 2026) and
19
+ four maintainer decisions that deliberately favor maintainability and DX over
20
+ cleverness:
21
+
22
+ 1. **No `@ts-procedures/http-protocol` package.** Wire-contract types live in
23
+ `@ts-procedures/core`; everyone `import type`s them. Verified: codegen's
24
+ dependency on those types is 100% type-only, so a separate runtime-free
25
+ package buys nothing. This dissolves two of the original "blockers."
26
+ 2. **No meta-package.** A `ts-procedures@9` re-export shim would carry zero real
27
+ changes. Skip it. Hard, honest import cutover instead.
28
+ 3. **`--self-contained` codegen is removed.** Generated code always imports the
29
+ now-standalone zero-dep `@ts-procedures/client`. This deletes an entire
30
+ `.ts`-regex-inlining subsystem (the single most fragile mechanism in the repo).
31
+ 4. **Scope is `@ts-procedures/*`** — self-documenting, on-brand, discoverable.
32
+
33
+ The guiding principle throughout: **no magic, no bespoke build steps, no
34
+ hand-maintained ordering.** Standard tools (`tsc -b`, Changesets,
35
+ `verbatimModuleSyntax`, a one-time codemod) do the work.
36
+
37
+ ---
38
+
39
+ ## 1. Overview & goals
40
+
41
+ **What:** convert the single ESM package (`type: module`, `tsc`-built to
42
+ `build/`) into an npm-workspaces monorepo under `packages/*`. Each export concern
43
+ becomes its own scoped package under `@ts-procedures`. All scoped packages
44
+ publish together at `1.0.0`.
45
+
46
+ **Why:**
47
+ - Independent install surface — a codegen-CLI user shouldn't pull the Hono
48
+ server runtime; an Astro-adapter user shouldn't pull `ajsc`.
49
+ - Cleaner peer-dependency story per concern (`hono` only on `@ts-procedures/hono`,
50
+ `ajsc` only on `@ts-procedures/codegen`).
51
+
52
+ **Honest trade-off:** a split improves *consumer* install surface at the cost of
53
+ *maintainer* surface (7 packages, a codemod, cross-package test devDeps). This
54
+ plan is engineered to keep that maintainer cost as low as possible — which is why
55
+ several packages, a shim, and an inlining subsystem from earlier drafts are gone.
56
+
57
+ **Constraints discovered during verification (still true, still respected):**
58
+ - `ts-procedures` is published at `8.1.0`; it is **not** republished. New work
59
+ ships under `@ts-procedures/*`. The old name is deprecated in place.
60
+ - `@ts-procedures/core` keeps `suretype`/`typebox` as **regular dependencies** —
61
+ there are unconditional top-level value imports (verified §9-B). They cannot be
62
+ optional peers.
63
+
64
+ ---
65
+
66
+ ## 2. Target package set (7 packages)
67
+
68
+ | Package | Responsibility | Owns (paths, relative to today's `src/`) | Internal deps | External deps | Peer deps |
69
+ |---|---|---|---|---|---|
70
+ | `@ts-procedures/core` | Procedures factory, `Create`/`CreateStream`/`CreateHttp`/`CreateHttpStream`, error classes, full schema pipeline, **+ all wire-contract types** (`DocEnvelope`, `AnyHttpRouteDoc` + RPC/API/Stream variants + `kind`, `ErrorDoc`, `HeaderDoc`, the `ErrorTaxonomy` *type alias*) **+ runtime-coupled config types** (`RPCConfig`, `APIConfig`, `FactoryItem`, `DocRegistryConfig` factory pieces). | `index.ts`, `create*.ts`, `errors.ts`, `stack-utils.ts`, `types.ts`, `exports.ts`, `schema/`, **+ the split of `implementations/types.ts`** (wire contract → `contract-types.ts`, runtime config → `config-types.ts`) | none | `ajv`, `ajv-formats`, `es-toolkit`, `suretype`, `typebox` | — |
71
+ | `@ts-procedures/client` | Runtime client: `createClient`, fetch adapter, call/stream/SSE, hooks, request-builder, resolve-options, six client error classes + classifier, error-dispatch/registry, `RequestMeta`/`ClientErrorMap` augmentation interfaces. | `client/` | none (**zero-dep leaf**) | none | — |
72
+ | `@ts-procedures/codegen` | Code-gen engine + `ts-procedures-codegen` bin. Loads `DocEnvelope`, groups by scope, emits TS/Kotlin/Swift. | `codegen/` (incl. `codegen/bin/cli.ts`), **minus** `emit-client-runtime.ts` / `emit-client-types.ts` (deleted with self-contained mode) | `@ts-procedures/core` (**type-only → devDependency**) | none at runtime | `ajsc` (dynamic-imported, optional) |
73
+ | `@ts-procedures/http` | Framework-agnostic HTTP layer: `DocRegistry`, error-taxonomy registry (`defineErrorTaxonomy`, `defaultErrorTaxonomy`, `resolveErrorResponse`), `dispatchPreStreamError`/`dispatchMidStreamError`. | `implementations/http/doc-registry.ts`, `error-taxonomy.ts`, `error-dispatch.ts` + a new `index.ts` barrel | `@ts-procedures/core` | none | `hono` (type-only → optional) |
74
+ | `@ts-procedures/hono` | Unified `HonoAppBuilder` (4 kinds), `toDocEnvelope()`, re-export of `defineErrorTaxonomy`. | `implementations/http/hono/` | `@ts-procedures/core`, `@ts-procedures/http` | `es-toolkit` | `hono` |
75
+ | `@ts-procedures/astro` | Astro adapter: `createHandler`/`setAstroContext`/`stripPrefix`. Prod-clean (only `import type` from hono/astro). | `implementations/http/astro/` | none in prod (core+hono are test devDeps) | none | `astro`, `hono` |
76
+ | `@ts-procedures/setup` | `ts-procedures-setup` bin + agent_config payload. **Explicit opt-in only — no `postinstall` hook.** | `agent_config/` | none | none | — |
77
+
78
+ **`@ts-procedures/core` public entry:** `.` points at the **`exports.ts`** barrel
79
+ (re-exports `index` + `errors` + `stack-utils` + schema modules + the contract
80
+ types), not bare `index.ts`. `./errors` maps to `errors.ts`.
81
+
82
+ ---
83
+
84
+ ## 3. Dependency graph (no cycles — by design, not by gymnastics)
85
+
86
+ Putting the wire-contract types in `@ts-procedures/core` and using `import type`
87
+ everywhere collapses every cycle the earlier draft fought:
88
+
89
+ - **`implementations/types.ts` line 1 `import { Procedures }`** is value-imported
90
+ but used only in `ReturnType<typeof Procedures<…>>` (verified line 22). It moves
91
+ into core and becomes `import type` — a one-line change, no refactor.
92
+ - **`error-taxonomy.ts` ↔ `types.ts`** (the old "Cycle A") dissolves: both
93
+ `ErrorDoc` and the `ErrorTaxonomy` *type* now live in core. The runtime
94
+ taxonomy helpers live in `@ts-procedures/http`, which depends on core in one
95
+ direction only.
96
+ - **codegen → wire types** is 100% `import type` (verified: all 26 imports), so
97
+ it erases at compile time under `verbatimModuleSyntax`. `@ts-procedures/core`
98
+ is therefore a **devDependency** of codegen — CLI users install zero core
99
+ runtime.
100
+
101
+ **Build order (derived automatically by `tsc -b`, never hand-maintained):**
102
+
103
+ ```
104
+ @ts-procedures/core (base: runtime + all contract types)
105
+ @ts-procedures/client (zero-dep leaf, parallel with core)
106
+
107
+ @ts-procedures/http (→ core; type-peer hono)
108
+ @ts-procedures/codegen (→ core type-only / devDep)
109
+
110
+ @ts-procedures/hono (→ core, http)
111
+
112
+ @ts-procedures/astro (prod-clean; devDeps core+hono)
113
+ @ts-procedures/setup (independent; agent_config only)
114
+ ```
115
+
116
+ ### One required source refactor before the move
117
+
118
+ Split `src/implementations/types.ts` (lands in core):
119
+ - **`contract-types.ts`** — pure wire contract: `DocEnvelope`,
120
+ `AnyHttpRouteDoc` + RPC/API/Stream variants + `kind`, `ErrorDoc`, `HeaderDoc`,
121
+ and the `ErrorTaxonomy` *type alias* (moved out of `error-taxonomy.ts`). Zero
122
+ value imports.
123
+ - **`config-types.ts`** — runtime-coupled config: `RPCConfig`, `APIConfig`,
124
+ `FactoryItem`, `ProceduresFactory`/`ProceduresContext` helpers, and the
125
+ factory-referencing parts of `DocRegistryConfig`. `import type { Procedures }`
126
+ (not a value import).
127
+
128
+ Turning on `verbatimModuleSyntax` proves `contract-types.ts` has zero value
129
+ imports at compile time.
130
+
131
+ ---
132
+
133
+ ## 4. Repository layout
134
+
135
+ ```
136
+ ts-procedures/ (workspace root, private: true)
137
+ ├── package.json workspaces: ["packages/*"], script orchestration
138
+ ├── tsconfig.base.json shared compiler options
139
+ ├── tsconfig.json solution file: references all packages
140
+ ├── eslint.config.js shared; adds no-relative-packages rule
141
+ ├── vitest.config.ts projects mode (one project per package)
142
+ ├── .prettierrc
143
+ ├── .changeset/ changesets config (fixed group) + entries
144
+ ├── .github/workflows/release.yml NEW — OIDC provenance publish
145
+ ├── scripts/ check-docs + release helpers
146
+ └── packages/
147
+ ├── core/ src/{index,create*,errors,stack-utils,types,exports,
148
+ │ contract-types,config-types}.ts + src/schema/
149
+ ├── client/ src/*.ts (former src/client/*)
150
+ ├── codegen/ src/** + src/bin/cli.ts (no client-snapshot, no self-contained emitters)
151
+ ├── http/ src/{index,doc-registry,error-taxonomy,error-dispatch}.ts
152
+ ├── hono/ src/** (former src/implementations/http/hono/*)
153
+ ├── astro/ src/** (former src/implementations/http/astro/*)
154
+ └── setup/ bin/{setup,postinstall}.mjs, lib/, claude-code/, cursor/, copilot/
155
+ ```
156
+
157
+ > `setup/` still *ships* `postinstall.mjs` (so `npx @ts-procedures/setup` and the
158
+ > existing auto-update logic remains available), but **no package wires it
159
+ > as a `scripts.postinstall`** — see §7.
160
+
161
+ ### Root `package.json`
162
+
163
+ ```jsonc
164
+ {
165
+ "name": "ts-procedures-monorepo",
166
+ "private": true,
167
+ "type": "module",
168
+ "workspaces": ["packages/*"],
169
+ "scripts": {
170
+ "build": "tsc -b",
171
+ "lint": "eslint packages/*/src --quiet",
172
+ "test": "vitest run",
173
+ "check-docs": "bash scripts/check-docs-consistency.sh",
174
+ "release": "changeset publish"
175
+ },
176
+ "devDependencies": {
177
+ "@changesets/cli": "^2.x",
178
+ "typescript": "^5.x",
179
+ "vitest": "^x",
180
+ "eslint": "^9.x",
181
+ "eslint-plugin-import": "^2.x"
182
+ }
183
+ }
184
+ ```
185
+
186
+ ### Root `tsconfig.base.json` (extended by every package)
187
+
188
+ ```jsonc
189
+ {
190
+ "compilerOptions": {
191
+ "module": "NodeNext",
192
+ "moduleResolution": "NodeNext",
193
+ "target": "ES2022",
194
+ "strict": true,
195
+ "declaration": true,
196
+ "declarationMap": true,
197
+ "composite": true,
198
+ "verbatimModuleSyntax": true,
199
+ "outDir": "dist",
200
+ "rootDir": "src"
201
+ }
202
+ }
203
+ ```
204
+
205
+ > `verbatimModuleSyntax` is **off** today. Turning it on surfaces every
206
+ > value-vs-type import mistake (e.g. the `import { Procedures }` in types.ts) at
207
+ > compile time — which is exactly what we want before the split. Every
208
+ > cross-package type-only import becomes `import type`.
209
+
210
+ ### Root `tsconfig.json` (solution / project references)
211
+
212
+ ```jsonc
213
+ {
214
+ "files": [],
215
+ "references": [
216
+ { "path": "packages/core" },
217
+ { "path": "packages/client" },
218
+ { "path": "packages/http" },
219
+ { "path": "packages/codegen" },
220
+ { "path": "packages/hono" },
221
+ { "path": "packages/astro" }
222
+ ]
223
+ }
224
+ ```
225
+
226
+ Each package's `tsconfig.json` extends the base and lists `references` mirroring
227
+ its internal deps. `setup` has no TS build (it's `.mjs` payload).
228
+
229
+ ---
230
+
231
+ ## 5. Per-package `package.json` blueprints
232
+
233
+ All scoped packages: `"version": "1.0.0"`, `"type": "module"`,
234
+ `"publishConfig": { "access": "public", "provenance": true }`,
235
+ `"repository": { "type": "git", "url": "...", "directory": "packages/<name>" }`.
236
+
237
+ ### `@ts-procedures/core`
238
+ ```jsonc
239
+ {
240
+ "name": "@ts-procedures/core", "version": "1.0.0", "type": "module",
241
+ "exports": {
242
+ ".": { "types": "./dist/exports.d.ts", "import": "./dist/exports.js" },
243
+ "./errors":{ "types": "./dist/errors.d.ts", "import": "./dist/errors.js" }
244
+ },
245
+ "files": ["dist"],
246
+ "dependencies": {
247
+ "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "es-toolkit": "^1.44.0",
248
+ "suretype": "^3.3.1", "typebox": "^1.0.30"
249
+ },
250
+ "publishConfig": { "access": "public", "provenance": true }
251
+ }
252
+ ```
253
+ > `.` points at the `exports.ts` barrel (which now also re-exports the contract
254
+ > types). `suretype`+`typebox` stay regular deps (§9-B).
255
+
256
+ ### `@ts-procedures/client`
257
+ ```jsonc
258
+ {
259
+ "name": "@ts-procedures/client", "version": "1.0.0", "type": "module",
260
+ "exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" } },
261
+ "files": ["dist"],
262
+ "dependencies": {},
263
+ "publishConfig": { "access": "public", "provenance": true }
264
+ }
265
+ ```
266
+ > Genuine zero-dep leaf. No longer ships `src` (the snapshot consumer is gone).
267
+ > The single runtime dependency that generated code now carries.
268
+
269
+ ### `@ts-procedures/codegen`
270
+ ```jsonc
271
+ {
272
+ "name": "@ts-procedures/codegen", "version": "1.0.0", "type": "module",
273
+ "bin": { "ts-procedures-codegen": "./dist/bin/cli.js" },
274
+ "exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" } },
275
+ "files": ["dist"],
276
+ "peerDependencies": { "ajsc": "*" },
277
+ "peerDependenciesMeta": { "ajsc": { "optional": true } },
278
+ "devDependencies": {
279
+ "@ts-procedures/core": "workspace:*",
280
+ "@ts-procedures/client": "workspace:*"
281
+ },
282
+ "publishConfig": { "access": "public", "provenance": true }
283
+ }
284
+ ```
285
+ > `@ts-procedures/core` is a **devDependency** — codegen's use of contract types
286
+ > is 100% `import type`, erased at build. `@ts-procedures/client` is a devDep for
287
+ > the e2e test that compiles generated output. No `prebuild` snapshot script, no
288
+ > self-contained emitters. Bin name `ts-procedures-codegen` and config filename
289
+ > `ts-procedures-codegen.config.json` unchanged; preserve the `cli.ts` shebang.
290
+
291
+ ### `@ts-procedures/http`
292
+ ```jsonc
293
+ {
294
+ "name": "@ts-procedures/http", "version": "1.0.0", "type": "module",
295
+ "exports": {
296
+ ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" },
297
+ "./docs": { "types": "./dist/doc-registry.d.ts", "import": "./dist/doc-registry.js" },
298
+ "./errors": { "types": "./dist/error-taxonomy.d.ts", "import": "./dist/error-taxonomy.js" }
299
+ },
300
+ "files": ["dist"],
301
+ "dependencies": { "@ts-procedures/core": "workspace:*" },
302
+ "peerDependencies": { "hono": "*" },
303
+ "peerDependenciesMeta": { "hono": { "optional": true } },
304
+ "publishConfig": { "access": "public", "provenance": true }
305
+ }
306
+ ```
307
+ > Author a new `src/index.ts` barrel (none exists today). `hono` is type-only
308
+ > (`error-dispatch.ts`'s `import type { Context }`) → optional peer.
309
+
310
+ ### `@ts-procedures/hono`
311
+ ```jsonc
312
+ {
313
+ "name": "@ts-procedures/hono", "version": "1.0.0", "type": "module",
314
+ "exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" } },
315
+ "files": ["dist"],
316
+ "dependencies": {
317
+ "@ts-procedures/core": "workspace:*", "@ts-procedures/http": "workspace:*",
318
+ "es-toolkit": "^1.44.0"
319
+ },
320
+ "peerDependencies": { "hono": "*" },
321
+ "publishConfig": { "access": "public", "provenance": true }
322
+ }
323
+ ```
324
+ > `es-toolkit` is a **direct** dep (`path.ts` imports `es-toolkit/string` +
325
+ > `es-toolkit/compat`). `hono` is a required peer.
326
+
327
+ ### `@ts-procedures/astro`
328
+ ```jsonc
329
+ {
330
+ "name": "@ts-procedures/astro", "version": "1.0.0", "type": "module",
331
+ "exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" } },
332
+ "files": ["dist"],
333
+ "dependencies": {},
334
+ "peerDependencies": { "astro": "*", "hono": "*" },
335
+ "devDependencies": {
336
+ "@ts-procedures/core": "workspace:*", "@ts-procedures/hono": "workspace:*"
337
+ },
338
+ "publishConfig": { "access": "public", "provenance": true }
339
+ }
340
+ ```
341
+ > Prod-clean. `astro`+`hono` required peers. core+hono are test-only devDeps.
342
+
343
+ ### `@ts-procedures/setup`
344
+ ```jsonc
345
+ {
346
+ "name": "@ts-procedures/setup", "version": "1.0.0", "type": "module",
347
+ "bin": { "ts-procedures-setup": "./bin/setup.mjs" },
348
+ "exports": { "./package.json": "./package.json" },
349
+ "files": ["bin", "lib", "claude-code", "cursor", "copilot"],
350
+ "publishConfig": { "access": "public", "provenance": true }
351
+ }
352
+ ```
353
+ > **No `scripts.postinstall`** (§7). Verify `setup.mjs`'s `resolve(__dirname, '..')`
354
+ > payload resolution still lands on `claude-code/` etc. after the move; smoke-test
355
+ > with `npm pack` + `npx -p <tarball>`.
356
+
357
+ ---
358
+
359
+ ## 6. Tooling
360
+
361
+ **TS build:** project references + `composite: true`; `tsc -b` from root derives
362
+ order. `declarationMap: true` for cross-package go-to-definition.
363
+
364
+ **Task runner:** `tsc -b` + `npm run --workspaces`. No Turborepo for v1.0.0 — add
365
+ caching later only if build time becomes a problem.
366
+
367
+ **`verbatimModuleSyntax`:** on. Forces correct `import type` everywhere.
368
+
369
+ **Import rewrites (`../*.js` → `@ts-procedures/*`):** pervasive; **do not
370
+ hand-edit.** Use a one-time ts-morph codemod with an explicit ownedPath→package
371
+ map, then enforce with `eslint-plugin-import`'s `no-relative-packages` so CI fails
372
+ on any surviving deep relative cross-package import.
373
+
374
+ **vitest:** projects mode, one project per package, each typecheck pointing at its
375
+ own `tsconfig`. The two `*.test-d.ts` files (`client/result-type.test-d.ts`,
376
+ `client/augment-error-map.test-d.ts`) live with `@ts-procedures/client`.
377
+
378
+ **Cross-package test cycles (devDep-only):**
379
+ - `client/typed-error-dispatch.test.ts` imports core + hono.
380
+ - `astro/index.test.ts` imports core + hono.
381
+ - codegen e2e (`run-tsc.ts`) shells to `node_modules/.bin/tsc` and resolves
382
+ `@ts-procedures/*` specifiers — needs them hoisted + listed as codegen devDeps.
383
+
384
+ Keep these as **devDependencies only.** CI assertion: no `@ts-procedures/*`
385
+ package may list another in `dependencies` outside its declared internal-dep set.
386
+ Verify `@ts-procedures/client`'s published `dependencies` stays empty via
387
+ `npm pack --dry-run`. Optionally relocate the two spanning tests into a private
388
+ (unpublished) `@ts-procedures/integration-tests` package.
389
+
390
+ **Declaration-merging modules:** `RequestMeta` / `ClientErrorMap` live in
391
+ `client/types.ts`. Augmentation target changes from `declare module
392
+ 'ts-procedures/client'` → `declare module '@ts-procedures/client'`. Add a
393
+ `*.test-d.ts` that augments via the new specifier and asserts the merge.
394
+
395
+ ---
396
+
397
+ ## 7. Versioning, publishing & the prior name
398
+
399
+ **Tool:** **Changesets** (`@changesets/cli`). npm workspaces has no reliable
400
+ `workspace:*`→range rewrite on publish; Changesets rewrites `workspace:*` into the
401
+ concrete just-published range and publishes in topological order atomically.
402
+
403
+ **Mode:** **fixed / lockstep** for the whole `@ts-procedures/*` set. The runtime
404
+ coupling (http→core, hono→core+http) makes independent versions drift into peer
405
+ mismatches. Lockstep also makes `workspace:*`→`^1.0.0` trivial.
406
+
407
+ **v1.0.0 cut:** all scoped packages → `1.0.0` together.
408
+
409
+ **No meta-package.** A `ts-procedures@9` re-export shim would ship zero real
410
+ changes — pointless churn. Instead:
411
+ - Publish `@ts-procedures/*` fresh.
412
+ - `npm deprecate "ts-procedures" "Moved to @ts-procedures/*. See migration guide: <url>"`
413
+ — the old `8.1.0` stays installable (no break for pinned consumers) but warns.
414
+ - Existing `ts-procedures@8` installs keep their current `postinstall`
415
+ auto-updater (frozen, harmless). New consumers opt in explicitly via
416
+ `npx @ts-procedures/setup`.
417
+
418
+ **Why no auto-postinstall on the new packages:** a `postinstall` that silently
419
+ mutates a consumer's repo is itself anti-DX/magic, and on a split it would have to
420
+ live on a deep lib everyone installs (`@ts-procedures/core`) — wrong place.
421
+ Explicit `npx @ts-procedures/setup` is the clean, predictable replacement.
422
+
423
+ **Provenance & access (both missing today):**
424
+ - Every package: `publishConfig.access: "public"` (scoped packages are private by
425
+ default — without this, publish fails 402 or publishes privately).
426
+ - Stand up `.github/workflows/release.yml` with `permissions: id-token: write` and
427
+ `npm publish --provenance` via `changesets/action`. Add `repository.directory`
428
+ per package.
429
+ - **Prereq:** claim the `@ts-procedures` npm org/scope with publish rights before
430
+ release.
431
+
432
+ **`prepublishOnly` / docs gate:** `check-docs` is a **repo-wide** invariant scan —
433
+ keep it as a single **root CI gate** before any publish. Per-package
434
+ `prepublishOnly` is at most `lint && build`.
435
+
436
+ ---
437
+
438
+ ## 8. Consumer migration & breaking changes
439
+
440
+ This is a **hard import cutover** — there is no shim. Document prominently.
441
+
442
+ ### Old import → new import
443
+
444
+ | Today | New |
445
+ |---|---|
446
+ | `ts-procedures` (`.`) | `@ts-procedures/core` |
447
+ | `ts-procedures/client` | `@ts-procedures/client` |
448
+ | `ts-procedures/codegen` | `@ts-procedures/codegen` |
449
+ | `ts-procedures/hono` | `@ts-procedures/hono` |
450
+ | `ts-procedures/astro` | `@ts-procedures/astro` |
451
+ | `ts-procedures/http` (**types-only**) | `@ts-procedures/core` (contract types now live here; still types-only at use sites via `import type`) |
452
+ | `ts-procedures/http-docs` | `@ts-procedures/http/docs` |
453
+ | `ts-procedures/http-errors` | `@ts-procedures/http/errors` |
454
+
455
+ > The codemod must use this per-subpath table, not a regex — `ts-procedures/http`
456
+ > does **not** map to `@ts-procedures/http`.
457
+
458
+ ### Codegen: `--self-contained` removed, `clientImportPath` default flips
459
+ - `--self-contained` / `--no-self-contained`, the `selfContained` option, and the
460
+ `emit-client-runtime.ts` / `emit-client-types.ts` emitters are **deleted**.
461
+ Generated code always imports `@ts-procedures/client`. Consumers add it as a
462
+ (zero-dep) dependency — documented as required.
463
+ - Default `clientImportPath` changes from `'ts-procedures/client'`
464
+ (verified: `emit-index.ts:35`, `emit-scope.ts:769`) to `'@ts-procedures/client'`.
465
+ Update the ~5 test expectations (emit-scope/emit-index/pipeline/e2e). Update
466
+ CLAUDE.md and `docs/` to drop all self-contained references.
467
+
468
+ ### Hardcoded `ts-procedures` strings that ship downstream
469
+ - **agent_config** (21 files, ~239 refs): skills, `patterns.md`,
470
+ `anti-patterns.md`, `api-reference.md`, scaffold templates,
471
+ `copilot-instructions.md`, `cursorrules`. Rewrite all to scoped names in the
472
+ migration PR.
473
+ - **docs/** (`core.md`, `http-integrations.md`, `astro-adapter.md`,
474
+ `client-and-codegen.md`, `client-error-handling.md`, `streaming.md`): sweep
475
+ alongside. (`docs/superpowers/plans|specs/*` are historical — leave them.)
476
+ - Extend `scripts/check-docs-consistency.sh` to grep agent_config + docs for bare
477
+ `ts-procedures` import strings and fail CI.
478
+
479
+ ### Bin & config names — preserved
480
+ `ts-procedures-codegen` (on `@ts-procedures/codegen`) and `ts-procedures-setup`
481
+ (on `@ts-procedures/setup`) keep their bin names; `ts-procedures-codegen.config.json`
482
+ keeps its name.
483
+
484
+ ### Expected churn
485
+ First post-upgrade regeneration produces an import-path + source-hash diff across
486
+ all generated files. Document as expected, not a regression.
487
+
488
+ ---
489
+
490
+ ## 9. Step-by-step migration sequence
491
+
492
+ Each step is verifiable. **Steps 1–3 are prerequisite refactors on the current
493
+ single package** (must land and ship working before any directory move).
494
+
495
+ **Phase 0 — De-risk in place (no split yet)**
496
+ 1. **Split `implementations/types.ts`** into `contract-types.ts` (wire contract,
497
+ incl. the `ErrorTaxonomy` type moved out of `error-taxonomy.ts`) and
498
+ `config-types.ts` (runtime-coupled). Change `import { Procedures }` →
499
+ `import type`. Turn on `verbatimModuleSyntax` locally to prove `contract-types.ts`
500
+ has zero value imports. `npm run build` green; `madge --circular src` clean.
501
+ 2. **Remove self-contained codegen:** delete `emit-client-runtime.ts` /
502
+ `emit-client-types.ts` and the `selfContained` branch; make generated code
503
+ always import from `clientImportPath` (default flips to `@ts-procedures/client`
504
+ in step 12). Update affected tests. `npm test` green.
505
+ 3. **Confirm schema-lib deps:** keep `suretype`+`typebox` as regular deps (§9-B).
506
+
507
+ **Phase 1 — Scaffold workspace**
508
+ 4. Create `packages/`, root `package.json` (`workspaces`, `private`),
509
+ `tsconfig.base.json`, solution `tsconfig.json`, `vitest.config.ts` projects
510
+ mode, eslint `no-relative-packages`.
511
+
512
+ **Phase 2 — Move files per package (in build order)**
513
+ 5. `git mv` per §4: core → client → http → codegen → hono → astro → setup.
514
+ Keep history with `git mv`.
515
+ 6. Write each package's `package.json` (§5) and `tsconfig.json`.
516
+
517
+ **Phase 3 — Rewrite imports & wire references**
518
+ 7. Run the ts-morph codemod (ownedPath→`@ts-procedures/*` map, §8 table for the
519
+ `./http` → core cases).
520
+ 8. `tsc -b` from root. Iterate until green. eslint passes.
521
+
522
+ **Phase 4 — Tests**
523
+ 9. Move test files with their packages; add test-only devDeps (client→hono/core,
524
+ astro→hono/core, codegen→client/core). `vitest run` green across all projects,
525
+ including `*.test-d.ts` typecheck and codegen e2e.
526
+ 10. Add the declaration-merge `*.test-d.ts` asserting `@ts-procedures/client`
527
+ augmentation works.
528
+
529
+ **Phase 5 — Codegen output default**
530
+ 11. Confirm default `clientImportPath` = `'@ts-procedures/client'`; update the ~5
531
+ test expectations. Build + test green.
532
+
533
+ **Phase 6 — Docs / agent_config**
534
+ 12. Rewrite all `ts-procedures` import strings in agent_config + docs to scoped
535
+ names; drop self-contained docs. Extend `check-docs-consistency.sh`;
536
+ `npm run check-docs` green.
537
+
538
+ **Phase 7 — Release engineering**
539
+ 13. `npx changeset init`; configure `fixed` group for `@ts-procedures/*`. Add the
540
+ v1.0.0 changeset.
541
+ 14. Create `.github/workflows/release.yml` (OIDC, `--provenance`,
542
+ `changesets/action`). Add `repository.directory` per package. Claim the
543
+ `@ts-procedures` npm org.
544
+ 15. Dry-run: `npm pack --dry-run` each package; assert `files` correct and no
545
+ stray `@ts-procedures/*` in published `dependencies`.
546
+
547
+ **Phase 8 — Publish & deprecate**
548
+ 16. CI runs root `lint && build && check-docs && test`, then `changeset publish`
549
+ → all `@ts-procedures/*` at 1.0.0 with `workspace:*` rewritten to `^1.0.0`,
550
+ provenance attached.
551
+ 17. `npm deprecate "ts-procedures" "Moved to @ts-procedures/*; see migration guide"`.
552
+ 18. Smoke-test a fresh consumer: install `@ts-procedures/codegen` +
553
+ `@ts-procedures/client`, run `npx ts-procedures-codegen` against a sample
554
+ envelope; assert generated imports resolve and compile.
555
+
556
+ ---
557
+
558
+ ## 10. Risks (consolidated)
559
+
560
+ The original draft's blockers 10-A (self-contained disk read), 10-C/10-D
561
+ (http-protocol cycles), 10-G (prior-version conflict), and 10-H (postinstall
562
+ reach) are **designed out** by the four decisions in the header. What remains:
563
+
564
+ ### MUST-DO before publish
565
+ - **Scoped packages are private by default + no CI/provenance exist.** Add
566
+ `publishConfig.access: public` to all packages; stand up the OIDC release
567
+ workflow; claim the `@ts-procedures` org. (was 10-E)
568
+ - **`workspace:*` has no rewrite under raw `npm publish`.** Changesets (fixed
569
+ mode) handles it. (was 10-F)
570
+
571
+ ### Keep in mind (§9-B) `@ts-procedures/core` deps
572
+ Verified unconditional top-level value imports: `extract-json-schema.ts:1`
573
+ (`extractSingleJsonSchema` from `suretype`), `resolve-schema-lib.ts:1-2`
574
+ (`CoreValidator` from `suretype`, `Type` from `typebox`), `schema/types.ts:1-2`
575
+ (both). Optional peers → `ERR_MODULE_NOT_FOUND`. **Keep both as regular
576
+ dependencies.** (Optional future: lazy `import('suretype')` inside the suretype
577
+ branch + `import type` for the type-only names, then consider dropping suretype.)
578
+
579
+ ### Lower-risk items to not forget
580
+ - `@ts-procedures/core` `.` must point at `exports.ts`, not `index.ts`.
581
+ - `@ts-procedures/http` needs a new `index.ts` barrel authored.
582
+ - `es-toolkit` must be a **direct** dep of both core and hono (deep subpaths;
583
+ don't rely on hoisting).
584
+ - `@ts-procedures/setup` bin payload resolution (`resolve(__dirname, '..')`)
585
+ re-verified after the move; payload dirs in `files`.
586
+ - `RequestMeta`/`ClientErrorMap` augmentation specifier change — silent if missed;
587
+ cover with `*.test-d.ts`.
588
+ - Preserve `cli.ts` shebang through compilation; bin path `./dist/bin/cli.js`.
589
+ - Generated-file diff churn on first regen — document as expected.
590
+
591
+ ---
592
+
593
+ ## 11. Open questions for the maintainer
594
+
595
+ Resolved by decision: meta-package (none), versioning (lockstep 1.0.0),
596
+ self-contained (removed), scope name (`@ts-procedures`), http-protocol package
597
+ (collapsed into core). Remaining:
598
+
599
+ 1. **`@ts-procedures/http` — one package vs split into `@ts-procedures/http-docs`
600
+ + `@ts-procedures/http-errors`?** Recommendation: **one package** with
601
+ `./docs`/`./errors` subpaths (doc-registry imports error-taxonomy at runtime).
602
+ Split only if a consumer wants the taxonomy without DocRegistry.
603
+ 2. **suretype's future:** keep as a regular dep of `@ts-procedures/core` for
604
+ v1.0.0 (required — §9-B), or invest in the lazy-import refactor now and consider
605
+ dropping suretype (documented as deprecated/legacy)?
606
+ 3. **Integration tests:** relocate the spanning tests
607
+ (`client/typed-error-dispatch.test.ts`, `astro/index.test.ts`) into a private
608
+ `@ts-procedures/integration-tests` package, or keep them in-package with
609
+ devDep edges?
610
+ 4. **Migration guide URL:** where does the `npm deprecate` message point — a
611
+ `MIGRATION.md` in the repo, a docs site page, or a GitHub release?
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "ts-procedures",
3
- "version": "8.1.0",
3
+ "version": "8.1.1",
4
4
  "description": "A TypeScript RPC framework that creates type-safe, schema-validated procedure calls with a single function definition. Define your procedures once and get full type inference, runtime validation, and framework integration hooks.",
5
5
  "main": "build/exports.js",
6
6
  "types": "build/exports.d.ts",
7
7
  "type": "module",
8
+ "sideEffects": false,
8
9
  "bin": {
9
10
  "ts-procedures-setup": "./agent_config/bin/setup.mjs",
10
11
  "ts-procedures-codegen": "./build/codegen/bin/cli.js"
@@ -27,7 +27,7 @@ export class ClientHttpError extends Error {
27
27
  }
28
28
 
29
29
  /** @deprecated Renamed to `ClientHttpError`. The alias is retained for one minor release after the 7.0.0 major bump and will be removed in a subsequent minor (e.g. 7.1.0). Migrate to `ClientHttpError` now. */
30
- // eslint-disable-next-line no-redeclare
30
+
31
31
  export const ClientRequestError = ClientHttpError
32
32
  /** @deprecated Renamed to `ClientHttpError`. The alias is retained for one minor release after the 7.0.0 major bump and will be removed in a subsequent minor (e.g. 7.1.0). Migrate to `ClientHttpError` now. */
33
33
  // eslint-disable-next-line no-redeclare
@@ -1,8 +1,7 @@
1
- /* eslint-disable @typescript-eslint/no-empty-object-type */
1
+
2
2
  import { describe, expect, test } from 'vitest'
3
3
  import { Type } from 'typebox'
4
4
  import { Procedures } from '../index.js'
5
- import { APIConfig } from '../implementations/types.js'
6
5
  import { HonoAppBuilder, defineErrorTaxonomy } from '../implementations/http/hono/index.js'
7
6
  import { createClient } from './index.js'
8
7
  import { ClientRequestError } from './errors.js'
@@ -69,7 +69,7 @@ describe('bundle size budget', () => {
69
69
  // This isn't a strict assertion — it surfaces the actual numbers to the
70
70
  // test output so reviewers can update PERROUTEDELTA_BASELINE in the
71
71
  // comment above without having to re-run locally.
72
- // eslint-disable-next-line no-console
72
+
73
73
  console.log(`[bundle-size] 100 routes, scope file = ${totalChars} chars stripped, per-route = ${perRouteDelta.toFixed(1)}`)
74
74
  expect(totalChars).toBeGreaterThan(0)
75
75
  })
@@ -22,7 +22,7 @@ export async function assertGoldenOrUpdate(produced: string, goldenPath: string)
22
22
  '// Source hash: <PLACEHOLDER>',
23
23
  )
24
24
  await writeFile(goldenPath, goldenContent, 'utf-8')
25
- // eslint-disable-next-line no-console
25
+
26
26
  console.log(`[golden-test] Wrote golden: ${goldenPath}`)
27
27
  return
28
28
  }