ts-procedures 10.1.1 → 10.2.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 (244) hide show
  1. package/CHANGELOG.md +26 -65
  2. package/README.md +2 -0
  3. package/agent_config/claude-code/skills/ts-procedures/anti-patterns.md +8 -0
  4. package/agent_config/claude-code/skills/ts-procedures/api-reference.md +25 -22
  5. package/agent_config/claude-code/skills/ts-procedures/patterns.md +24 -13
  6. package/agent_config/copilot/copilot-instructions.md +1 -1
  7. package/agent_config/cursor/cursorrules +1 -1
  8. package/build/adapters/hono/envelope-parity.test.js +6 -17
  9. package/build/adapters/hono/envelope-parity.test.js.map +1 -1
  10. package/build/adapters/hono/handlers/http-stream.d.ts +2 -1
  11. package/build/adapters/hono/handlers/http-stream.js +9 -2
  12. package/build/adapters/hono/handlers/http-stream.js.map +1 -1
  13. package/build/adapters/hono/handlers/http.d.ts +2 -1
  14. package/build/adapters/hono/handlers/http.js +9 -2
  15. package/build/adapters/hono/handlers/http.js.map +1 -1
  16. package/build/adapters/hono/handlers/rpc.d.ts +2 -1
  17. package/build/adapters/hono/handlers/rpc.js +9 -2
  18. package/build/adapters/hono/handlers/rpc.js.map +1 -1
  19. package/build/adapters/hono/handlers/stream.d.ts +2 -1
  20. package/build/adapters/hono/handlers/stream.js +9 -2
  21. package/build/adapters/hono/handlers/stream.js.map +1 -1
  22. package/build/adapters/hono/index.d.ts +14 -7
  23. package/build/adapters/hono/index.js +45 -5
  24. package/build/adapters/hono/index.js.map +1 -1
  25. package/build/adapters/hono/index.test.js +55 -0
  26. package/build/adapters/hono/index.test.js.map +1 -1
  27. package/build/adapters/hono/request.d.ts +7 -0
  28. package/build/adapters/hono/request.js +15 -0
  29. package/build/adapters/hono/request.js.map +1 -1
  30. package/build/adapters/hono/types.d.ts +31 -0
  31. package/build/adapters/hono/types.js.map +1 -1
  32. package/build/codegen/bin/cli.js +1 -1
  33. package/build/codegen/bin/cli.js.map +1 -1
  34. package/build/codegen/constants.js +2 -2
  35. package/build/codegen/constants.js.map +1 -1
  36. package/build/codegen/emit/api-route.js +1 -1
  37. package/build/codegen/emit/api-route.js.map +1 -1
  38. package/build/codegen/emit/scope-file.js +1 -1
  39. package/build/codegen/emit/scope-file.js.map +1 -1
  40. package/build/codegen/emit-errors.integration.test.js +2 -2
  41. package/build/codegen/emit-errors.integration.test.js.map +1 -1
  42. package/build/codegen/resolve-envelope.js +1 -1
  43. package/build/codegen/resolve-envelope.js.map +1 -1
  44. package/build/codegen/test-helpers/run-tsc.js +1 -1
  45. package/build/codegen/test-helpers/run-tsc.js.map +1 -1
  46. package/build/core/create-http-stream.d.ts +3 -14
  47. package/build/core/create-http-stream.js +4 -2
  48. package/build/core/create-http-stream.js.map +1 -1
  49. package/build/core/create-http.d.ts +2 -9
  50. package/build/core/create-http.js +3 -2
  51. package/build/core/create-http.js.map +1 -1
  52. package/build/core/create-http.test-d.d.ts +1 -0
  53. package/build/core/create-http.test-d.js +104 -0
  54. package/build/core/create-http.test-d.js.map +1 -0
  55. package/build/core/create-stream.js +6 -2
  56. package/build/core/create-stream.js.map +1 -1
  57. package/build/core/create.js +5 -4
  58. package/build/core/create.js.map +1 -1
  59. package/build/core/create.test.js +63 -0
  60. package/build/core/create.test.js.map +1 -1
  61. package/build/core/internal.d.ts +16 -0
  62. package/build/core/internal.js +22 -0
  63. package/build/core/internal.js.map +1 -1
  64. package/build/core/procedures.d.ts +9 -16
  65. package/build/core/procedures.js +4 -0
  66. package/build/core/procedures.js.map +1 -1
  67. package/build/core/types.d.ts +85 -4
  68. package/build/errors.d.ts +33 -0
  69. package/build/errors.js +91 -0
  70. package/build/errors.js.map +1 -0
  71. package/build/errors.test.d.ts +1 -0
  72. package/build/errors.test.js +122 -0
  73. package/build/errors.test.js.map +1 -0
  74. package/build/exports.d.ts +1 -2
  75. package/build/exports.js +0 -4
  76. package/build/exports.js.map +1 -1
  77. package/build/implementations/http/doc-registry.d.ts +28 -0
  78. package/build/implementations/http/doc-registry.js +96 -0
  79. package/build/implementations/http/doc-registry.js.map +1 -0
  80. package/build/implementations/http/doc-registry.test.d.ts +1 -0
  81. package/build/implementations/http/doc-registry.test.js +516 -0
  82. package/build/implementations/http/doc-registry.test.js.map +1 -0
  83. package/build/implementations/http/error-taxonomy.d.ts +249 -0
  84. package/build/implementations/http/error-taxonomy.js +252 -0
  85. package/build/implementations/http/error-taxonomy.js.map +1 -0
  86. package/build/implementations/http/error-taxonomy.test.d.ts +1 -0
  87. package/build/implementations/http/error-taxonomy.test.js +399 -0
  88. package/build/implementations/http/error-taxonomy.test.js.map +1 -0
  89. package/build/implementations/http/express-rpc/error-taxonomy.test.d.ts +1 -0
  90. package/build/implementations/http/express-rpc/error-taxonomy.test.js +83 -0
  91. package/build/implementations/http/express-rpc/error-taxonomy.test.js.map +1 -0
  92. package/build/implementations/http/express-rpc/index.d.ts +125 -0
  93. package/build/implementations/http/express-rpc/index.js +216 -0
  94. package/build/implementations/http/express-rpc/index.js.map +1 -0
  95. package/build/implementations/http/express-rpc/index.test.d.ts +1 -0
  96. package/build/implementations/http/express-rpc/index.test.js +684 -0
  97. package/build/implementations/http/express-rpc/index.test.js.map +1 -0
  98. package/build/implementations/http/express-rpc/types.d.ts +11 -0
  99. package/build/implementations/http/express-rpc/types.js +2 -0
  100. package/build/implementations/http/express-rpc/types.js.map +1 -0
  101. package/build/implementations/http/hono-api/error-taxonomy.test.d.ts +1 -0
  102. package/build/implementations/http/hono-api/error-taxonomy.test.js +137 -0
  103. package/build/implementations/http/hono-api/error-taxonomy.test.js.map +1 -0
  104. package/build/implementations/http/hono-api/index.d.ts +151 -0
  105. package/build/implementations/http/hono-api/index.js +344 -0
  106. package/build/implementations/http/hono-api/index.js.map +1 -0
  107. package/build/implementations/http/hono-api/index.test.d.ts +1 -0
  108. package/build/implementations/http/hono-api/index.test.js +992 -0
  109. package/build/implementations/http/hono-api/index.test.js.map +1 -0
  110. package/build/implementations/http/hono-api/types.d.ts +13 -0
  111. package/build/implementations/http/hono-api/types.js +2 -0
  112. package/build/implementations/http/hono-api/types.js.map +1 -0
  113. package/build/implementations/http/hono-rpc/error-taxonomy.test.d.ts +1 -0
  114. package/build/implementations/http/hono-rpc/error-taxonomy.test.js +64 -0
  115. package/build/implementations/http/hono-rpc/error-taxonomy.test.js.map +1 -0
  116. package/build/implementations/http/hono-rpc/index.d.ts +130 -0
  117. package/build/implementations/http/hono-rpc/index.js +209 -0
  118. package/build/implementations/http/hono-rpc/index.js.map +1 -0
  119. package/build/implementations/http/hono-rpc/index.test.d.ts +1 -0
  120. package/build/implementations/http/hono-rpc/index.test.js +828 -0
  121. package/build/implementations/http/hono-rpc/index.test.js.map +1 -0
  122. package/build/implementations/http/hono-rpc/types.d.ts +11 -0
  123. package/build/implementations/http/hono-rpc/types.js +2 -0
  124. package/build/implementations/http/hono-rpc/types.js.map +1 -0
  125. package/build/implementations/http/hono-stream/error-taxonomy.test.d.ts +1 -0
  126. package/build/implementations/http/hono-stream/error-taxonomy.test.js +159 -0
  127. package/build/implementations/http/hono-stream/error-taxonomy.test.js.map +1 -0
  128. package/build/implementations/http/hono-stream/index.d.ts +171 -0
  129. package/build/implementations/http/hono-stream/index.js +415 -0
  130. package/build/implementations/http/hono-stream/index.js.map +1 -0
  131. package/build/implementations/http/hono-stream/index.test.d.ts +1 -0
  132. package/build/implementations/http/hono-stream/index.test.js +1383 -0
  133. package/build/implementations/http/hono-stream/index.test.js.map +1 -0
  134. package/build/implementations/http/hono-stream/types.d.ts +15 -0
  135. package/build/implementations/http/hono-stream/types.js +2 -0
  136. package/build/implementations/http/hono-stream/types.js.map +1 -0
  137. package/build/implementations/http/on-request-error.test.d.ts +1 -0
  138. package/build/implementations/http/on-request-error.test.js +173 -0
  139. package/build/implementations/http/on-request-error.test.js.map +1 -0
  140. package/build/implementations/http/route-errors.test.d.ts +1 -0
  141. package/build/implementations/http/route-errors.test.js +139 -0
  142. package/build/implementations/http/route-errors.test.js.map +1 -0
  143. package/build/implementations/types.d.ts +192 -0
  144. package/build/implementations/types.js +2 -0
  145. package/build/implementations/types.js.map +1 -0
  146. package/build/index.d.ts +165 -0
  147. package/build/index.js +258 -0
  148. package/build/index.js.map +1 -0
  149. package/build/index.test.d.ts +1 -0
  150. package/build/index.test.js +920 -0
  151. package/build/index.test.js.map +1 -0
  152. package/build/schema/extract-json-schema.d.ts +2 -0
  153. package/build/schema/extract-json-schema.js +12 -0
  154. package/build/schema/extract-json-schema.js.map +1 -0
  155. package/build/schema/extract-json-schema.test.d.ts +1 -0
  156. package/build/schema/extract-json-schema.test.js +23 -0
  157. package/build/schema/extract-json-schema.test.js.map +1 -0
  158. package/build/schema/parser.d.ts +28 -0
  159. package/build/schema/parser.js +170 -0
  160. package/build/schema/parser.js.map +1 -0
  161. package/build/schema/parser.test.d.ts +1 -0
  162. package/build/schema/parser.test.js +120 -0
  163. package/build/schema/parser.test.js.map +1 -0
  164. package/build/schema/resolve-schema-lib.d.ts +12 -0
  165. package/build/schema/resolve-schema-lib.js +11 -0
  166. package/build/schema/resolve-schema-lib.js.map +1 -0
  167. package/build/schema/resolve-schema-lib.test.d.ts +1 -0
  168. package/build/schema/resolve-schema-lib.test.js +17 -0
  169. package/build/schema/resolve-schema-lib.test.js.map +1 -0
  170. package/build/schema/typebox.d.ts +1 -1
  171. package/build/schema/typebox.js +2 -20
  172. package/build/schema/typebox.js.map +1 -1
  173. package/build/schema/typebox.test.js +0 -10
  174. package/build/schema/typebox.test.js.map +1 -1
  175. package/build/schema/types.d.ts +8 -0
  176. package/build/schema/types.js +2 -0
  177. package/build/schema/types.js.map +1 -0
  178. package/build/server/context.d.ts +12 -2
  179. package/build/server/context.js +49 -4
  180. package/build/server/context.js.map +1 -1
  181. package/build/server/context.test.js +32 -1
  182. package/build/server/context.test.js.map +1 -1
  183. package/build/server/doc-registry.js +0 -3
  184. package/build/server/doc-registry.js.map +1 -1
  185. package/build/server/doc-registry.test.js +0 -31
  186. package/build/server/doc-registry.test.js.map +1 -1
  187. package/build/server/index.d.ts +0 -1
  188. package/build/server/index.js +0 -1
  189. package/build/server/index.js.map +1 -1
  190. package/build/server/types.d.ts +6 -27
  191. package/build/stack-utils.d.ts +25 -0
  192. package/build/stack-utils.js +95 -0
  193. package/build/stack-utils.js.map +1 -0
  194. package/build/stack-utils.test.d.ts +1 -0
  195. package/build/stack-utils.test.js +80 -0
  196. package/build/stack-utils.test.js.map +1 -0
  197. package/docs/core.md +8 -0
  198. package/docs/http-integrations.md +41 -27
  199. package/package.json +8 -8
  200. package/src/adapters/astro/README.md +2 -0
  201. package/src/adapters/hono/envelope-parity.test.ts +6 -18
  202. package/src/adapters/hono/handlers/http-stream.ts +12 -3
  203. package/src/adapters/hono/handlers/http.ts +12 -3
  204. package/src/adapters/hono/handlers/rpc.ts +12 -3
  205. package/src/adapters/hono/handlers/stream.ts +12 -3
  206. package/src/adapters/hono/index.test.ts +70 -0
  207. package/src/adapters/hono/index.ts +53 -11
  208. package/src/adapters/hono/request.ts +18 -0
  209. package/src/adapters/hono/types.ts +37 -0
  210. package/src/codegen/bin/cli.ts +1 -1
  211. package/src/codegen/constants.ts +2 -2
  212. package/src/codegen/emit/api-route.ts +1 -1
  213. package/src/codegen/emit/scope-file.ts +1 -2
  214. package/src/codegen/emit-errors.integration.test.ts +2 -2
  215. package/src/codegen/resolve-envelope.ts +1 -1
  216. package/src/codegen/test-helpers/run-tsc.ts +0 -1
  217. package/src/core/create-http-stream.ts +20 -13
  218. package/src/core/create-http.test-d.ts +154 -0
  219. package/src/core/create-http.ts +19 -8
  220. package/src/core/create-stream.ts +12 -4
  221. package/src/core/create.test.ts +74 -0
  222. package/src/core/create.ts +10 -5
  223. package/src/core/internal.ts +35 -0
  224. package/src/core/procedures.ts +4 -0
  225. package/src/core/types.ts +99 -4
  226. package/src/exports.ts +6 -4
  227. package/src/schema/typebox.test.ts +0 -12
  228. package/src/schema/typebox.ts +2 -21
  229. package/src/server/context.test.ts +39 -1
  230. package/src/server/context.ts +54 -4
  231. package/src/server/doc-registry.test.ts +0 -34
  232. package/src/server/doc-registry.ts +0 -3
  233. package/src/server/index.ts +0 -1
  234. package/src/server/types.ts +8 -27
  235. package/build/server/spec-version.d.ts +0 -24
  236. package/build/server/spec-version.js +0 -26
  237. package/build/server/spec-version.js.map +0 -1
  238. package/build/version.d.ts +0 -9
  239. package/build/version.js +0 -11
  240. package/build/version.js.map +0 -1
  241. package/docs/doc-envelope-spec-v1.md +0 -296
  242. package/docs/doc-envelope-v1.schema.json +0 -253
  243. package/src/server/spec-version.ts +0 -27
  244. package/src/version.ts +0 -11
@@ -1,24 +0,0 @@
1
- /**
2
- * Spec version of the {@link DocEnvelope} wire format.
3
- *
4
- * Bump this ONLY when the envelope shape changes in a way downstream parsers
5
- * must react to — field renames, nesting changes, or semantic changes. Do NOT
6
- * bump it on ordinary package releases (dependency upgrades, bug fixes, new
7
- * optional fields that older parsers can safely ignore). It is decoupled from
8
- * the npm package version on purpose, so consumers get a small monotonic
9
- * integer to branch on instead of having to interpret semver.
10
- *
11
- * Consumer contract: an envelope with no `specVersion` field predates this
12
- * field and MUST be treated as spec version 1.
13
- */
14
- export declare const DOC_ENVELOPE_SPEC_VERSION = 1;
15
- /**
16
- * The ts-procedures package version that produced an envelope (e.g. `"10.0.0"`).
17
- * Populates the envelope's `generatorVersion` field.
18
- *
19
- * Informational only — for telemetry, debugging, and "which release served
20
- * this?" questions. Do NOT use it to decide parse compatibility; it churns on
21
- * every release regardless of whether the envelope format changed. Use
22
- * {@link DOC_ENVELOPE_SPEC_VERSION} for compatibility decisions.
23
- */
24
- export declare const DOC_ENVELOPE_GENERATOR_VERSION: string;
@@ -1,26 +0,0 @@
1
- import { PACKAGE_VERSION } from '../version.js';
2
- /**
3
- * Spec version of the {@link DocEnvelope} wire format.
4
- *
5
- * Bump this ONLY when the envelope shape changes in a way downstream parsers
6
- * must react to — field renames, nesting changes, or semantic changes. Do NOT
7
- * bump it on ordinary package releases (dependency upgrades, bug fixes, new
8
- * optional fields that older parsers can safely ignore). It is decoupled from
9
- * the npm package version on purpose, so consumers get a small monotonic
10
- * integer to branch on instead of having to interpret semver.
11
- *
12
- * Consumer contract: an envelope with no `specVersion` field predates this
13
- * field and MUST be treated as spec version 1.
14
- */
15
- export const DOC_ENVELOPE_SPEC_VERSION = 1;
16
- /**
17
- * The ts-procedures package version that produced an envelope (e.g. `"10.0.0"`).
18
- * Populates the envelope's `generatorVersion` field.
19
- *
20
- * Informational only — for telemetry, debugging, and "which release served
21
- * this?" questions. Do NOT use it to decide parse compatibility; it churns on
22
- * every release regardless of whether the envelope format changed. Use
23
- * {@link DOC_ENVELOPE_SPEC_VERSION} for compatibility decisions.
24
- */
25
- export const DOC_ENVELOPE_GENERATOR_VERSION = PACKAGE_VERSION;
26
- //# sourceMappingURL=spec-version.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"spec-version.js","sourceRoot":"","sources":["../../src/server/spec-version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAE/C;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAA;AAE1C;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAW,eAAe,CAAA"}
@@ -1,9 +0,0 @@
1
- /**
2
- * The ts-procedures package version (e.g. `"10.0.0"`), read from `package.json`.
3
- *
4
- * Single source of truth for "which version is this build?" — consumed by the
5
- * codegen file header and the doc-envelope `generatorVersion`. Import this
6
- * rather than re-importing `package.json`, so there's one place the version
7
- * enters the source tree.
8
- */
9
- export declare const PACKAGE_VERSION: string;
package/build/version.js DELETED
@@ -1,11 +0,0 @@
1
- import pkg from '../package.json' with { type: 'json' };
2
- /**
3
- * The ts-procedures package version (e.g. `"10.0.0"`), read from `package.json`.
4
- *
5
- * Single source of truth for "which version is this build?" — consumed by the
6
- * codegen file header and the doc-envelope `generatorVersion`. Import this
7
- * rather than re-importing `package.json`, so there's one place the version
8
- * enters the source tree.
9
- */
10
- export const PACKAGE_VERSION = pkg.version;
11
- //# sourceMappingURL=version.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AAEvD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,eAAe,GAAW,GAAG,CAAC,OAAO,CAAA"}
@@ -1,296 +0,0 @@
1
- # ts-procedures DocEnvelope — Consumer Spec (`specVersion: 1`)
2
-
3
- > **This document describes DocEnvelope `specVersion: 1`.** The filename is
4
- > pinned to the spec version (`-v1`) so future format changes land as a sibling
5
- > (`doc-envelope-spec-v2.md`) and the differences stay diffable. Check the
6
- > envelope's `specVersion` field (absent ⇒ `1`) to know which spec applies.
7
-
8
- A spec for a GUI that fetches a `DocEnvelope` JSON document from a ts-procedures
9
- server URL and renders it. This is the **stable wire contract** between a
10
- ts-procedures server and any documentation/codegen consumer. It is a *frozen*
11
- contract in the framework (changing field names/nesting breaks codegen goldens),
12
- so you can build against it confidently.
13
-
14
- Companion file: `doc-envelope-v1.schema.json` (JSON Schema Draft-07) — validate
15
- fetched documents against it.
16
-
17
- ---
18
-
19
- ## 1. How you get the document
20
-
21
- There is **no built-in endpoint**. A server author calls
22
- `builder.toDocEnvelope()` (or `DocRegistry.toJSON()`) and exposes the resulting
23
- JSON at a route of their choosing (e.g. `GET /api/docs`, `/openapi`, a static
24
- `.json` file, etc.).
25
-
26
- So your website's "paste a URL" flow should:
27
-
28
- 1. `fetch(url)` the user-supplied URL.
29
- 2. Expect `Content-Type` ~ JSON; `JSON.parse` the body.
30
- 3. Validate that it is an object with a `routes` **array**. That single check is
31
- what the official codegen uses as its "is this an envelope?" gate. If
32
- `routes` is missing/not-an-array, show a clear "not a ts-procedures docs
33
- document" error.
34
- 4. Optionally validate fully against `doc-envelope-v1.schema.json`.
35
-
36
- CORS: the server must allow your origin, or you'll need a proxy. Worth surfacing
37
- as a distinct error from "bad JSON".
38
-
39
- ---
40
-
41
- ## 2. Top-level shape
42
-
43
- ```ts
44
- interface DocEnvelope {
45
- specVersion?: number // envelope wire-format version; absent ⇒ treat as 1
46
- generatorVersion?: string // producing ts-procedures version, e.g. "10.0.0" (informational)
47
- basePath: string // e.g. "/api" (may be "")
48
- headers: HeaderDoc[] // global headers (often [])
49
- errors: ErrorDoc[] // the error catalog
50
- routes: AnyRouteDoc[] // every procedure/route
51
- }
52
- ```
53
-
54
- The authoritative producer (`DocRegistry.toJSON`) emits these six keys.
55
- Resilience notes:
56
-
57
- - **`specVersion`** is your compatibility signal — a small monotonic integer
58
- that increments **only** when the envelope format changes (never on routine
59
- package releases). **Branch your parser on this.** Treat a **missing**
60
- `specVersion` as `1` (documents predating the field). Refuse / warn on a
61
- `specVersion` higher than your GUI knows about. Current value: `1`.
62
- - **`generatorVersion`** is the producing ts-procedures package version (e.g.
63
- `"10.0.0"`). **Informational only** — show it in a footer/tooltip, but do
64
- **not** use it to decide how to parse; it changes every release regardless of
65
- format. (Note: one internal codegen *input* fixture carries an unrelated
66
- top-level `"version"` string and uppercase methods — that's a loose
67
- hand-authored fixture, not server output; ignore `version` if you ever see it.)
68
- - Be tolerant of **extra top-level keys** — treat unknown keys as opaque.
69
- - `headers` and `errors` are commonly empty arrays. Render gracefully.
70
-
71
- ---
72
-
73
- ## 3. The error catalog (`errors`)
74
-
75
- ```ts
76
- interface ErrorDoc {
77
- name: string // unique; routes reference it by this name
78
- statusCode: number // HTTP status, e.g. 400, 404, 418, 500
79
- description: string
80
- schema?: Record<string, unknown> // JSON Schema of the error body (optional)
81
- }
82
- ```
83
-
84
- Framework defaults are auto-merged and always present unless opted out:
85
- `ProcedureValidationError` (400), `ProcedureYieldValidationError` (500),
86
- `ProcedureError` (500), `ProcedureRegistrationError` (500). User taxonomy errors
87
- (e.g. `NotFound` 404, `Teapot` 418) appear alongside them.
88
-
89
- **GUI tip:** build a `Map<name, ErrorDoc>`. Each route's `errors: string[]` is a
90
- list of these names — render them as links/badges that resolve to the catalog
91
- entry (status code + description + body schema).
92
-
93
- ---
94
-
95
- ## 4. Global headers (`headers`)
96
-
97
- ```ts
98
- interface HeaderDoc {
99
- name: string
100
- description?: string
101
- required?: boolean
102
- example?: string
103
- }
104
- ```
105
-
106
- Simple list; render as a small table. Often empty.
107
-
108
- ---
109
-
110
- ## 5. Routes — discriminated union on `kind`
111
-
112
- `routes[]` mixes four kinds. **Always switch on `route.kind`.** Every route has a
113
- `name` and a `jsonSchema` object; the rest varies by kind.
114
-
115
- | `kind` | Transport | Path field(s) | Method field | Payload schema keys |
116
- |-----------------|----------------------|----------------------|---------------------|----------------------------------------------|
117
- | `rpc` | JSON-RPC (POST) | `path` | `method: "post"` | `body`, `response` |
118
- | `stream` | RPC stream (SSE/text)| `path` | `methods: string[]` | `params`, `yieldType`, `returnType` |
119
- | `api` | REST | `path?`, `fullPath` | `method` | `req.{pathParams,query,body,headers}`, `res.{body,headers}` |
120
- | `http-stream` | REST stream (SSE) | `path?`, `fullPath` | `method` | `req.{...}`, `res.{headers}`, `yield`, `returnType` |
121
-
122
- Common fields: `name` (string), `errors?` (string[] → catalog names),
123
- `scope` (grouping; `string | string[]` for rpc/stream, `string` for api/http-stream).
124
-
125
- > **No per-route `description`.** A `description` passed at procedure-definition
126
- > time is **not** carried into the route doc. Don't build UI that depends on it.
127
-
128
- ### 5.1 `rpc`
129
-
130
- ```jsonc
131
- {
132
- "kind": "rpc",
133
- "name": "GetUser",
134
- "version": 1,
135
- "scope": "users",
136
- "path": "/api/users/get-user/1", // full path; embeds scope + version
137
- "method": "post",
138
- "jsonSchema": {
139
- "body": { "type": "object", "required": ["id"], "properties": { "id": { "type": "string" } } },
140
- "response": { "type": "object", "required": ["id","name"], "properties": { "id":{"type":"string"}, "name":{"type":"string"} } }
141
- },
142
- "errors": ["Teapot"]
143
- }
144
- ```
145
-
146
- - `jsonSchema.body` = request input (runtime-validated).
147
- - `jsonSchema.response` = response shape (documentation only).
148
- - Both are optional (a no-arg/no-return procedure yields `jsonSchema: {}`).
149
-
150
- ### 5.2 `stream` (RPC stream)
151
-
152
- ```jsonc
153
- {
154
- "kind": "stream",
155
- "name": "WatchUser",
156
- "version": 2,
157
- "scope": ["users", "live"],
158
- "path": "/api/users/live/watch-user/2",
159
- "methods": ["post", "get"],
160
- "streamMode": "sse", // "sse" | "text"
161
- "jsonSchema": {
162
- "params": { "type": "object", "required": ["id"], "properties": { "id": { "type": "string" } } },
163
- "yieldType": { /* see note */ },
164
- "returnType": { "type": "object", "required": ["total"], "properties": { "total": { "type": "number" } } }
165
- }
166
- }
167
- ```
168
-
169
- - `params` = input (query params for GET, body for POST).
170
- - **`yieldType` in `sse` mode is the SSE envelope**, not the bare value:
171
- ```jsonc
172
- {
173
- "type": "object",
174
- "description": "SSE message envelope. The data field contains the procedure yield value.",
175
- "required": ["data", "event", "id"],
176
- "properties": {
177
- "data": { /* the actual per-yield value schema */ },
178
- "event": { "type": "string" },
179
- "id": { "type": "string" },
180
- "retry": { "type": "number" }
181
- }
182
- }
183
- ```
184
- In `text` mode `yieldType` is the bare value schema. **GUI tip:** to show "what
185
- each event carries", detect the SSE envelope (object with `data`/`event`/`id`)
186
- and surface `properties.data`; otherwise show `yieldType` directly.
187
- - `returnType` = value delivered on stream completion (carried by the `return`
188
- SSE event). Optional.
189
- - `errors` here are pre-stream errors only.
190
-
191
- ### 5.3 `api` (REST)
192
-
193
- ```jsonc
194
- {
195
- "kind": "api",
196
- "name": "UpdateUser",
197
- "scope": "users",
198
- "path": "/users/:id", // as registered (may have :params)
199
- "method": "put",
200
- "fullPath": "/api/users/:id", // resolved, incl. basePath — prefer this for display
201
- "successStatus": 200, // optional; defaults POST→201, DELETE→204, else 200
202
- "jsonSchema": {
203
- "req": {
204
- "pathParams": { "type":"object", "required":["id"], "properties":{"id":{"type":"string"}} },
205
- "query": { "type":"object", "properties":{"dryRun":{"type":"boolean"}} },
206
- "body": { "type":"object", "required":["name"], "properties":{"name":{"type":"string"}} }
207
- // "headers" also possible
208
- },
209
- "res": {
210
- "body": { "type":"object", "required":["id","name"], "properties":{"id":{"type":"string"},"name":{"type":"string"}} },
211
- "headers": { "type":"object", "required":["x-rev"], "properties":{"x-rev":{"type":"string"}} }
212
- }
213
- },
214
- "errors": ["Teapot"]
215
- }
216
- ```
217
-
218
- - `req` channels: any of `pathParams`, `query`, `body`, `headers` (all optional).
219
- - `res` channels: `body`, `headers` (both optional).
220
- - `jsonSchema.req`/`res` may be `{}` or absent for trivial endpoints.
221
- - Prefer `fullPath` for the displayed URL; `path` may be omitted in some
222
- envelopes.
223
-
224
- ### 5.4 `http-stream` (REST stream)
225
-
226
- ```jsonc
227
- {
228
- "kind": "http-stream",
229
- "name": "TailUser",
230
- "scope": "users",
231
- "path": "/users/:id/tail",
232
- "method": "get",
233
- "fullPath": "/api/users/:id/tail",
234
- "streamMode": "sse",
235
- "jsonSchema": {
236
- "req": { "pathParams": { "type":"object", "required":["id"], "properties":{"id":{"type":"string"}} } },
237
- "res": { "headers": { /* optional response headers schema */ } },
238
- "yield": { "type":"object", "required":["line"], "properties":{"line":{"type":"string"}} },
239
- "returnType": { "type":"object", "required":["lines"], "properties":{"lines":{"type":"number"}} }
240
- }
241
- }
242
- ```
243
-
244
- - Same `req` channels as `api`.
245
- - `res` has **`headers` only** (no `body` — streaming responses have no single body).
246
- - `yield` = per-event value schema, **raw** (NOT wrapped in an SSE envelope,
247
- unlike `kind: "stream"`).
248
- - `returnType` = completion value. Optional.
249
-
250
- ---
251
-
252
- ## 6. Embedded payload schemas
253
-
254
- Every `jsonSchema.*` leaf (`body`, `response`, `params`, `yield`, `req.query`,
255
- error `schema`, …) is a plain **JSON Schema (Draft-07)** object as produced by
256
- the server's schema layer (TypeBox → JSON Schema). Expect standard keywords:
257
- `type`, `properties`, `required`, `items`, `enum`, `const`, `format`, `oneOf`,
258
- nested objects/arrays, etc.
259
-
260
- **Render these with a generic JSON-Schema viewer.** Don't hard-code field lists.
261
- Useful libraries: `@apidevtools/json-schema-ref-parser` (deref `$ref` if any),
262
- or any JSON-Schema-to-table/form renderer. They are validation-grade schemas, so
263
- you can also drive a "try it" form or example generator from them.
264
-
265
- ---
266
-
267
- ## 7. Suggested rendering model
268
-
269
- 1. **Header:** `basePath`, route count, kind breakdown.
270
- 2. **Sidebar:** group routes by `scope` (join array scopes with `/`), then by
271
- `kind`. Label each with `name` + method/path.
272
- 3. **Route detail:**
273
- - Title: `name`; badge: `kind`; method(s); display path (`fullPath` ?? `path`).
274
- - For `rpc`/`stream`: also show `version`.
275
- - **Request** section from `body`/`params`/`req.*`.
276
- - **Response** section from `response`/`res.*`; for streams, a **Stream**
277
- section from `yield`/`yieldType` (+ `returnType`).
278
- - **Errors** section: resolve each `errors[]` name against the catalog and
279
- show status + description + body schema.
280
- 4. **Errors page:** full `errors[]` catalog.
281
- 5. **Headers page:** `headers[]` table.
282
-
283
- ---
284
-
285
- ## 8. Defensive checklist for the GUI
286
-
287
- - Validate `routes` is an array before anything else; otherwise it's not an envelope.
288
- - Switch on `kind`; render unknown `kind` values generically (future-proofing).
289
- - Treat HTTP methods case-insensitively (canonical output is lowercase, but
290
- normalize anyway).
291
- - Tolerate empty/absent `headers`, `errors`, `jsonSchema`, `req`, `res`.
292
- - Tolerate extra/unknown properties at every level.
293
- - Read `specVersion` first (default 1 if absent) and branch parsing on it; warn on unknown-higher.
294
- - Don't expect a per-route `description`. `generatorVersion` is display-only, never a parse signal.
295
- - Prefer `fullPath` over `path` for `api`/`http-stream` display.
296
- - Unwrap the SSE envelope for `stream` `yieldType.data` when showing "event payload".
@@ -1,253 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-07/schema#",
3
- "$id": "https://ts-procedures.dev/schemas/doc-envelope-v1.schema.json",
4
- "title": "ts-procedures DocEnvelope (specVersion 1)",
5
- "description": "The JSON document a ts-procedures server exposes (via builder.toDocEnvelope() / DocRegistry.toJSON()). Describes every procedure/route the server serves, the global error catalog, and global headers. Payload schemas embedded under each route's `jsonSchema` are arbitrary JSON Schema (Draft-07) objects and are intentionally left unconstrained here.",
6
- "type": "object",
7
- "required": ["basePath", "headers", "errors", "routes"],
8
- "properties": {
9
- "specVersion": {
10
- "type": "integer",
11
- "minimum": 1,
12
- "description": "Wire-format version of the envelope. A small monotonic integer, bumped ONLY when the envelope shape changes — not on every package release. Branch on this to pick a parser. ABSENT means treat as 1 (envelopes predating this field). Emitted by ts-procedures servers; optional here so older/hand-built documents still validate."
13
- },
14
- "generatorVersion": {
15
- "type": "string",
16
- "description": "ts-procedures package version that produced the envelope, e.g. \"10.0.0\". Informational only (telemetry/debugging) — do NOT use it for parse-compatibility decisions; use specVersion."
17
- },
18
- "basePath": {
19
- "type": "string",
20
- "description": "Path prefix shared by all routes, e.g. \"/api\". May be the empty string."
21
- },
22
- "headers": {
23
- "type": "array",
24
- "description": "Global HTTP headers documented for the whole API.",
25
- "items": { "$ref": "#/definitions/HeaderDoc" }
26
- },
27
- "errors": {
28
- "type": "array",
29
- "description": "Catalog of every error the API may return (framework defaults + user-defined taxonomy). Routes reference these by name via their `errors` array.",
30
- "items": { "$ref": "#/definitions/ErrorDoc" }
31
- },
32
- "routes": {
33
- "type": "array",
34
- "description": "All procedures/routes. Discriminated union on `kind`.",
35
- "items": { "$ref": "#/definitions/AnyRouteDoc" }
36
- }
37
- },
38
- "additionalProperties": true,
39
- "definitions": {
40
- "JsonSchema": {
41
- "description": "An embedded JSON Schema (Draft-07) object describing a payload. Left unconstrained on purpose — render it generically.",
42
- "type": "object",
43
- "additionalProperties": true
44
- },
45
- "HeaderDoc": {
46
- "type": "object",
47
- "required": ["name"],
48
- "properties": {
49
- "name": { "type": "string" },
50
- "description": { "type": "string" },
51
- "required": { "type": "boolean" },
52
- "example": { "type": "string" }
53
- },
54
- "additionalProperties": true
55
- },
56
- "ErrorDoc": {
57
- "type": "object",
58
- "required": ["name", "statusCode", "description"],
59
- "properties": {
60
- "name": {
61
- "type": "string",
62
- "description": "Unique error name. Routes link to it via their `errors` array."
63
- },
64
- "statusCode": {
65
- "type": "integer",
66
- "description": "HTTP status code returned for this error.",
67
- "minimum": 100,
68
- "maximum": 599
69
- },
70
- "description": { "type": "string" },
71
- "schema": {
72
- "$ref": "#/definitions/JsonSchema",
73
- "description": "JSON Schema of the error response body. Optional."
74
- }
75
- },
76
- "additionalProperties": true
77
- },
78
-
79
- "AnyRouteDoc": {
80
- "oneOf": [
81
- { "$ref": "#/definitions/RPCRouteDoc" },
82
- { "$ref": "#/definitions/StreamRouteDoc" },
83
- { "$ref": "#/definitions/APIRouteDoc" },
84
- { "$ref": "#/definitions/HttpStreamRouteDoc" }
85
- ]
86
- },
87
-
88
- "HttpMethod": {
89
- "description": "HTTP method. Canonical wire form is lowercase; treat case-insensitively when rendering.",
90
- "type": "string",
91
- "enum": ["get", "post", "put", "delete", "patch", "head", "GET", "POST", "PUT", "DELETE", "PATCH", "HEAD"]
92
- },
93
-
94
- "StreamMode": {
95
- "type": "string",
96
- "enum": ["sse", "text"],
97
- "description": "Stream transport. `sse` = Server-Sent Events; `text` = raw text chunks."
98
- },
99
-
100
- "Scope": {
101
- "description": "Logical grouping. A single segment or an array of segments.",
102
- "oneOf": [
103
- { "type": "string" },
104
- { "type": "array", "items": { "type": "string" } }
105
- ]
106
- },
107
-
108
- "RPCRouteDoc": {
109
- "title": "RPC route (kind = rpc)",
110
- "description": "JSON-RPC-style procedure. Always POST. Path embeds scope + version.",
111
- "type": "object",
112
- "required": ["kind", "name", "path", "method", "scope", "version", "jsonSchema"],
113
- "properties": {
114
- "kind": { "const": "rpc" },
115
- "name": { "type": "string" },
116
- "path": { "type": "string", "description": "Full path incl. basePath + version, e.g. /api/users/get-user/1" },
117
- "method": { "const": "post" },
118
- "scope": { "$ref": "#/definitions/Scope" },
119
- "version": { "type": "number" },
120
- "errors": { "type": "array", "items": { "type": "string" } },
121
- "jsonSchema": {
122
- "type": "object",
123
- "properties": {
124
- "body": { "$ref": "#/definitions/JsonSchema", "description": "Request body schema (validated)." },
125
- "response": { "$ref": "#/definitions/JsonSchema", "description": "Response body schema (doc only)." }
126
- },
127
- "additionalProperties": true
128
- }
129
- },
130
- "additionalProperties": true
131
- },
132
-
133
- "StreamRouteDoc": {
134
- "title": "RPC stream route (kind = stream)",
135
- "description": "Streaming RPC procedure. Served over both POST and GET. Path embeds scope + version.",
136
- "type": "object",
137
- "required": ["kind", "name", "path", "methods", "streamMode", "scope", "version", "jsonSchema"],
138
- "properties": {
139
- "kind": { "const": "stream" },
140
- "name": { "type": "string" },
141
- "path": { "type": "string" },
142
- "methods": {
143
- "type": "array",
144
- "description": "Allowed methods, conventionally [\"post\", \"get\"].",
145
- "items": { "type": "string", "enum": ["get", "post"] }
146
- },
147
- "streamMode": { "$ref": "#/definitions/StreamMode" },
148
- "scope": { "$ref": "#/definitions/Scope" },
149
- "version": { "type": "number" },
150
- "errors": { "type": "array", "items": { "type": "string" }, "description": "Pre-stream errors only." },
151
- "jsonSchema": {
152
- "type": "object",
153
- "properties": {
154
- "params": { "$ref": "#/definitions/JsonSchema", "description": "Query params (GET) or body (POST)." },
155
- "yieldType": {
156
- "$ref": "#/definitions/JsonSchema",
157
- "description": "Schema for each streamed value. In `sse` mode this is the SSE envelope { data, event, id, retry } whose `data` holds the user's yield schema; in `text` mode it is the raw yield schema."
158
- },
159
- "returnType": { "$ref": "#/definitions/JsonSchema", "description": "Final return value schema." }
160
- },
161
- "additionalProperties": true
162
- }
163
- },
164
- "additionalProperties": true
165
- },
166
-
167
- "APIRouteDoc": {
168
- "title": "REST route (kind = api)",
169
- "description": "REST-style HTTP endpoint with explicit method + path.",
170
- "type": "object",
171
- "required": ["kind", "name", "method", "fullPath", "jsonSchema"],
172
- "properties": {
173
- "kind": { "const": "api" },
174
- "name": { "type": "string" },
175
- "scope": { "type": "string" },
176
- "path": { "type": "string", "description": "Path as registered (may include :params), e.g. /users/:id. May be omitted in some envelopes; prefer fullPath." },
177
- "method": { "$ref": "#/definitions/HttpMethod" },
178
- "fullPath": { "type": "string", "description": "Resolved path incl. basePath prefix, e.g. /api/users/:id." },
179
- "successStatus": { "type": "integer", "description": "Status on success. Defaults: POST→201, DELETE→204, else 200." },
180
- "errors": { "type": "array", "items": { "type": "string" } },
181
- "jsonSchema": {
182
- "type": "object",
183
- "properties": {
184
- "req": {
185
- "type": "object",
186
- "properties": {
187
- "pathParams": { "$ref": "#/definitions/JsonSchema" },
188
- "query": { "$ref": "#/definitions/JsonSchema" },
189
- "body": { "$ref": "#/definitions/JsonSchema" },
190
- "headers": { "$ref": "#/definitions/JsonSchema" }
191
- },
192
- "additionalProperties": true
193
- },
194
- "res": {
195
- "type": "object",
196
- "properties": {
197
- "body": { "$ref": "#/definitions/JsonSchema" },
198
- "headers": { "$ref": "#/definitions/JsonSchema" }
199
- },
200
- "additionalProperties": true
201
- }
202
- },
203
- "additionalProperties": true
204
- }
205
- },
206
- "additionalProperties": true
207
- },
208
-
209
- "HttpStreamRouteDoc": {
210
- "title": "REST stream route (kind = http-stream)",
211
- "description": "REST-style streaming endpoint. Response has no single body; values arrive via `yield`. Currently always SSE.",
212
- "type": "object",
213
- "required": ["kind", "name", "method", "fullPath", "streamMode", "jsonSchema"],
214
- "properties": {
215
- "kind": { "const": "http-stream" },
216
- "name": { "type": "string" },
217
- "scope": { "type": "string" },
218
- "path": { "type": "string" },
219
- "method": { "$ref": "#/definitions/HttpMethod" },
220
- "fullPath": { "type": "string" },
221
- "streamMode": { "$ref": "#/definitions/StreamMode" },
222
- "errors": { "type": "array", "items": { "type": "string" } },
223
- "jsonSchema": {
224
- "type": "object",
225
- "properties": {
226
- "req": {
227
- "type": "object",
228
- "properties": {
229
- "pathParams": { "$ref": "#/definitions/JsonSchema" },
230
- "query": { "$ref": "#/definitions/JsonSchema" },
231
- "body": { "$ref": "#/definitions/JsonSchema" },
232
- "headers": { "$ref": "#/definitions/JsonSchema" }
233
- },
234
- "additionalProperties": true
235
- },
236
- "res": {
237
- "type": "object",
238
- "description": "Response headers only — streaming responses have no single body.",
239
- "properties": {
240
- "headers": { "$ref": "#/definitions/JsonSchema" }
241
- },
242
- "additionalProperties": true
243
- },
244
- "yield": { "$ref": "#/definitions/JsonSchema", "description": "Schema for each streamed value. NOT wrapped in an SSE envelope (unlike kind=stream)." },
245
- "returnType": { "$ref": "#/definitions/JsonSchema", "description": "Final return value schema." }
246
- },
247
- "additionalProperties": true
248
- }
249
- },
250
- "additionalProperties": true
251
- }
252
- }
253
- }
@@ -1,27 +0,0 @@
1
- import { PACKAGE_VERSION } from '../version.js'
2
-
3
- /**
4
- * Spec version of the {@link DocEnvelope} wire format.
5
- *
6
- * Bump this ONLY when the envelope shape changes in a way downstream parsers
7
- * must react to — field renames, nesting changes, or semantic changes. Do NOT
8
- * bump it on ordinary package releases (dependency upgrades, bug fixes, new
9
- * optional fields that older parsers can safely ignore). It is decoupled from
10
- * the npm package version on purpose, so consumers get a small monotonic
11
- * integer to branch on instead of having to interpret semver.
12
- *
13
- * Consumer contract: an envelope with no `specVersion` field predates this
14
- * field and MUST be treated as spec version 1.
15
- */
16
- export const DOC_ENVELOPE_SPEC_VERSION = 1
17
-
18
- /**
19
- * The ts-procedures package version that produced an envelope (e.g. `"10.0.0"`).
20
- * Populates the envelope's `generatorVersion` field.
21
- *
22
- * Informational only — for telemetry, debugging, and "which release served
23
- * this?" questions. Do NOT use it to decide parse compatibility; it churns on
24
- * every release regardless of whether the envelope format changed. Use
25
- * {@link DOC_ENVELOPE_SPEC_VERSION} for compatibility decisions.
26
- */
27
- export const DOC_ENVELOPE_GENERATOR_VERSION: string = PACKAGE_VERSION