ts-procedures 5.10.0 → 5.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/agent_config/bin/postinstall.mjs +3 -3
  2. package/agent_config/bin/setup.mjs +22 -11
  3. package/agent_config/claude-code/agents/ts-procedures-architect.md +2 -2
  4. package/agent_config/claude-code/skills/{guide → ts-procedures}/SKILL.md +1 -1
  5. package/agent_config/claude-code/skills/{review → ts-procedures-review}/SKILL.md +3 -3
  6. package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/SKILL.md +2 -2
  7. package/agent_config/lib/install-claude.mjs +35 -87
  8. package/build/src/client/call.d.ts +14 -0
  9. package/build/src/client/call.js +47 -0
  10. package/build/src/client/call.js.map +1 -0
  11. package/build/src/client/call.test.d.ts +1 -0
  12. package/build/src/client/call.test.js +124 -0
  13. package/build/src/client/call.test.js.map +1 -0
  14. package/build/src/client/errors.d.ts +25 -0
  15. package/build/src/client/errors.js +33 -0
  16. package/build/src/client/errors.js.map +1 -0
  17. package/build/src/client/errors.test.d.ts +1 -0
  18. package/build/src/client/errors.test.js +41 -0
  19. package/build/src/client/errors.test.js.map +1 -0
  20. package/build/src/client/fetch-adapter.d.ts +12 -0
  21. package/build/src/client/fetch-adapter.js +156 -0
  22. package/build/src/client/fetch-adapter.js.map +1 -0
  23. package/build/src/client/fetch-adapter.test.d.ts +1 -0
  24. package/build/src/client/fetch-adapter.test.js +271 -0
  25. package/build/src/client/fetch-adapter.test.js.map +1 -0
  26. package/build/src/client/hooks.d.ts +17 -0
  27. package/build/src/client/hooks.js +40 -0
  28. package/build/src/client/hooks.js.map +1 -0
  29. package/build/src/client/hooks.test.d.ts +1 -0
  30. package/build/src/client/hooks.test.js +163 -0
  31. package/build/src/client/hooks.test.js.map +1 -0
  32. package/build/src/client/index.d.ts +22 -0
  33. package/build/src/client/index.js +67 -0
  34. package/build/src/client/index.js.map +1 -0
  35. package/build/src/client/index.test.d.ts +1 -0
  36. package/build/src/client/index.test.js +231 -0
  37. package/build/src/client/index.test.js.map +1 -0
  38. package/build/src/client/request-builder.d.ts +13 -0
  39. package/build/src/client/request-builder.js +53 -0
  40. package/build/src/client/request-builder.js.map +1 -0
  41. package/build/src/client/request-builder.test.d.ts +1 -0
  42. package/build/src/client/request-builder.test.js +160 -0
  43. package/build/src/client/request-builder.test.js.map +1 -0
  44. package/build/src/client/stream.d.ts +27 -0
  45. package/build/src/client/stream.js +118 -0
  46. package/build/src/client/stream.js.map +1 -0
  47. package/build/src/client/stream.test.d.ts +1 -0
  48. package/build/src/client/stream.test.js +228 -0
  49. package/build/src/client/stream.test.js.map +1 -0
  50. package/build/src/client/types.d.ts +78 -0
  51. package/build/src/client/types.js +3 -0
  52. package/build/src/client/types.js.map +1 -0
  53. package/build/src/codegen/bin/cli.d.ts +45 -0
  54. package/build/src/codegen/bin/cli.js +246 -0
  55. package/build/src/codegen/bin/cli.js.map +1 -0
  56. package/build/src/codegen/bin/cli.test.d.ts +1 -0
  57. package/build/src/codegen/bin/cli.test.js +220 -0
  58. package/build/src/codegen/bin/cli.test.js.map +1 -0
  59. package/build/src/codegen/constants.d.ts +1 -0
  60. package/build/src/codegen/constants.js +2 -0
  61. package/build/src/codegen/constants.js.map +1 -0
  62. package/build/src/codegen/e2e.test.d.ts +1 -0
  63. package/build/src/codegen/e2e.test.js +464 -0
  64. package/build/src/codegen/e2e.test.js.map +1 -0
  65. package/build/src/codegen/emit-client-runtime.d.ts +9 -0
  66. package/build/src/codegen/emit-client-runtime.js +99 -0
  67. package/build/src/codegen/emit-client-runtime.js.map +1 -0
  68. package/build/src/codegen/emit-client-runtime.test.d.ts +1 -0
  69. package/build/src/codegen/emit-client-runtime.test.js +78 -0
  70. package/build/src/codegen/emit-client-runtime.test.js.map +1 -0
  71. package/build/src/codegen/emit-client-types.d.ts +8 -0
  72. package/build/src/codegen/emit-client-types.js +25 -0
  73. package/build/src/codegen/emit-client-types.js.map +1 -0
  74. package/build/src/codegen/emit-client-types.test.d.ts +1 -0
  75. package/build/src/codegen/emit-client-types.test.js +33 -0
  76. package/build/src/codegen/emit-client-types.test.js.map +1 -0
  77. package/build/src/codegen/emit-errors.d.ts +19 -0
  78. package/build/src/codegen/emit-errors.js +59 -0
  79. package/build/src/codegen/emit-errors.js.map +1 -0
  80. package/build/src/codegen/emit-errors.test.d.ts +1 -0
  81. package/build/src/codegen/emit-errors.test.js +175 -0
  82. package/build/src/codegen/emit-errors.test.js.map +1 -0
  83. package/build/src/codegen/emit-index.d.ts +12 -0
  84. package/build/src/codegen/emit-index.js +41 -0
  85. package/build/src/codegen/emit-index.js.map +1 -0
  86. package/build/src/codegen/emit-index.test.d.ts +1 -0
  87. package/build/src/codegen/emit-index.test.js +106 -0
  88. package/build/src/codegen/emit-index.test.js.map +1 -0
  89. package/build/src/codegen/emit-scope.d.ts +15 -0
  90. package/build/src/codegen/emit-scope.js +299 -0
  91. package/build/src/codegen/emit-scope.js.map +1 -0
  92. package/build/src/codegen/emit-scope.test.d.ts +1 -0
  93. package/build/src/codegen/emit-scope.test.js +559 -0
  94. package/build/src/codegen/emit-scope.test.js.map +1 -0
  95. package/build/src/codegen/emit-types.d.ts +43 -0
  96. package/build/src/codegen/emit-types.js +111 -0
  97. package/build/src/codegen/emit-types.js.map +1 -0
  98. package/build/src/codegen/emit-types.test.d.ts +1 -0
  99. package/build/src/codegen/emit-types.test.js +184 -0
  100. package/build/src/codegen/emit-types.test.js.map +1 -0
  101. package/build/src/codegen/group-routes.d.ts +23 -0
  102. package/build/src/codegen/group-routes.js +46 -0
  103. package/build/src/codegen/group-routes.js.map +1 -0
  104. package/build/src/codegen/group-routes.test.d.ts +1 -0
  105. package/build/src/codegen/group-routes.test.js +131 -0
  106. package/build/src/codegen/group-routes.test.js.map +1 -0
  107. package/build/src/codegen/index.d.ts +15 -0
  108. package/build/src/codegen/index.js +16 -0
  109. package/build/src/codegen/index.js.map +1 -0
  110. package/build/src/codegen/naming.d.ts +7 -0
  111. package/build/src/codegen/naming.js +21 -0
  112. package/build/src/codegen/naming.js.map +1 -0
  113. package/build/src/codegen/naming.test.d.ts +1 -0
  114. package/build/src/codegen/naming.test.js +40 -0
  115. package/build/src/codegen/naming.test.js.map +1 -0
  116. package/build/src/codegen/pipeline.d.ts +17 -0
  117. package/build/src/codegen/pipeline.js +78 -0
  118. package/build/src/codegen/pipeline.js.map +1 -0
  119. package/build/src/codegen/pipeline.test.d.ts +1 -0
  120. package/build/src/codegen/pipeline.test.js +269 -0
  121. package/build/src/codegen/pipeline.test.js.map +1 -0
  122. package/build/src/codegen/resolve-envelope.d.ts +7 -0
  123. package/build/src/codegen/resolve-envelope.js +46 -0
  124. package/build/src/codegen/resolve-envelope.js.map +1 -0
  125. package/build/src/codegen/resolve-envelope.test.d.ts +1 -0
  126. package/build/src/codegen/resolve-envelope.test.js +69 -0
  127. package/build/src/codegen/resolve-envelope.test.js.map +1 -0
  128. package/build/src/errors.d.ts +33 -0
  129. package/build/src/errors.js +91 -0
  130. package/build/src/errors.js.map +1 -0
  131. package/build/src/errors.test.d.ts +1 -0
  132. package/build/src/errors.test.js +122 -0
  133. package/build/src/errors.test.js.map +1 -0
  134. package/build/src/exports.d.ts +7 -0
  135. package/build/src/exports.js +8 -0
  136. package/build/src/exports.js.map +1 -0
  137. package/build/src/implementations/http/doc-registry.d.ts +12 -0
  138. package/build/src/implementations/http/doc-registry.js +114 -0
  139. package/build/src/implementations/http/doc-registry.js.map +1 -0
  140. package/build/src/implementations/http/doc-registry.test.d.ts +1 -0
  141. package/build/src/implementations/http/doc-registry.test.js +347 -0
  142. package/build/src/implementations/http/doc-registry.test.js.map +1 -0
  143. package/build/src/implementations/http/express-rpc/index.d.ts +94 -0
  144. package/build/src/implementations/http/express-rpc/index.js +185 -0
  145. package/build/src/implementations/http/express-rpc/index.js.map +1 -0
  146. package/build/src/implementations/http/express-rpc/index.test.d.ts +1 -0
  147. package/build/src/implementations/http/express-rpc/index.test.js +684 -0
  148. package/build/src/implementations/http/express-rpc/index.test.js.map +1 -0
  149. package/build/src/implementations/http/express-rpc/types.d.ts +11 -0
  150. package/build/src/implementations/http/express-rpc/types.js +2 -0
  151. package/build/src/implementations/http/express-rpc/types.js.map +1 -0
  152. package/build/src/implementations/http/hono-api/index.d.ts +102 -0
  153. package/build/src/implementations/http/hono-api/index.js +341 -0
  154. package/build/src/implementations/http/hono-api/index.js.map +1 -0
  155. package/build/src/implementations/http/hono-api/index.test.d.ts +1 -0
  156. package/build/src/implementations/http/hono-api/index.test.js +992 -0
  157. package/build/src/implementations/http/hono-api/index.test.js.map +1 -0
  158. package/build/src/implementations/http/hono-api/types.d.ts +13 -0
  159. package/build/src/implementations/http/hono-api/types.js +2 -0
  160. package/build/src/implementations/http/hono-api/types.js.map +1 -0
  161. package/build/src/implementations/http/hono-rpc/index.d.ts +92 -0
  162. package/build/src/implementations/http/hono-rpc/index.js +161 -0
  163. package/build/src/implementations/http/hono-rpc/index.js.map +1 -0
  164. package/build/src/implementations/http/hono-rpc/index.test.d.ts +1 -0
  165. package/build/src/implementations/http/hono-rpc/index.test.js +803 -0
  166. package/build/src/implementations/http/hono-rpc/index.test.js.map +1 -0
  167. package/build/src/implementations/http/hono-rpc/types.d.ts +11 -0
  168. package/build/src/implementations/http/hono-rpc/types.js +2 -0
  169. package/build/src/implementations/http/hono-rpc/types.js.map +1 -0
  170. package/build/src/implementations/http/hono-stream/index.d.ts +120 -0
  171. package/build/src/implementations/http/hono-stream/index.js +309 -0
  172. package/build/src/implementations/http/hono-stream/index.js.map +1 -0
  173. package/build/src/implementations/http/hono-stream/index.test.d.ts +1 -0
  174. package/build/src/implementations/http/hono-stream/index.test.js +1356 -0
  175. package/build/src/implementations/http/hono-stream/index.test.js.map +1 -0
  176. package/build/src/implementations/http/hono-stream/types.d.ts +15 -0
  177. package/build/src/implementations/http/hono-stream/types.js +2 -0
  178. package/build/src/implementations/http/hono-stream/types.js.map +1 -0
  179. package/build/src/implementations/types.d.ts +142 -0
  180. package/build/src/implementations/types.js +2 -0
  181. package/build/src/implementations/types.js.map +1 -0
  182. package/build/src/index.d.ts +165 -0
  183. package/build/src/index.js +253 -0
  184. package/build/src/index.js.map +1 -0
  185. package/build/src/index.test.d.ts +1 -0
  186. package/build/src/index.test.js +890 -0
  187. package/build/src/index.test.js.map +1 -0
  188. package/build/src/schema/compute-schema.d.ts +35 -0
  189. package/build/src/schema/compute-schema.js +41 -0
  190. package/build/src/schema/compute-schema.js.map +1 -0
  191. package/build/src/schema/compute-schema.test.d.ts +1 -0
  192. package/build/src/schema/compute-schema.test.js +107 -0
  193. package/build/src/schema/compute-schema.test.js.map +1 -0
  194. package/build/src/schema/extract-json-schema.d.ts +2 -0
  195. package/build/src/schema/extract-json-schema.js +12 -0
  196. package/build/src/schema/extract-json-schema.js.map +1 -0
  197. package/build/src/schema/extract-json-schema.test.d.ts +1 -0
  198. package/build/src/schema/extract-json-schema.test.js +23 -0
  199. package/build/src/schema/extract-json-schema.test.js.map +1 -0
  200. package/build/src/schema/parser.d.ts +28 -0
  201. package/build/src/schema/parser.js +170 -0
  202. package/build/src/schema/parser.js.map +1 -0
  203. package/build/src/schema/parser.test.d.ts +1 -0
  204. package/build/src/schema/parser.test.js +120 -0
  205. package/build/src/schema/parser.test.js.map +1 -0
  206. package/build/src/schema/resolve-schema-lib.d.ts +12 -0
  207. package/build/src/schema/resolve-schema-lib.js +11 -0
  208. package/build/src/schema/resolve-schema-lib.js.map +1 -0
  209. package/build/src/schema/resolve-schema-lib.test.d.ts +1 -0
  210. package/build/src/schema/resolve-schema-lib.test.js +17 -0
  211. package/build/src/schema/resolve-schema-lib.test.js.map +1 -0
  212. package/build/src/schema/types.d.ts +8 -0
  213. package/build/src/schema/types.js +2 -0
  214. package/build/src/schema/types.js.map +1 -0
  215. package/build/src/stack-utils.d.ts +25 -0
  216. package/build/src/stack-utils.js +95 -0
  217. package/build/src/stack-utils.js.map +1 -0
  218. package/build/src/stack-utils.test.d.ts +1 -0
  219. package/build/src/stack-utils.test.js +80 -0
  220. package/build/src/stack-utils.test.js.map +1 -0
  221. package/docs/ai-agent-setup.md +7 -6
  222. package/package.json +1 -1
  223. /package/agent_config/claude-code/skills/{guide → ts-procedures}/anti-patterns.md +0 -0
  224. /package/agent_config/claude-code/skills/{guide → ts-procedures}/api-reference.md +0 -0
  225. /package/agent_config/claude-code/skills/{guide → ts-procedures}/patterns.md +0 -0
  226. /package/agent_config/claude-code/skills/{review → ts-procedures-review}/checklist.md +0 -0
  227. /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/client.md +0 -0
  228. /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/express-rpc.md +0 -0
  229. /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/hono-api.md +0 -0
  230. /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/hono-rpc.md +0 -0
  231. /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/hono-stream.md +0 -0
  232. /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/procedure.md +0 -0
  233. /package/agent_config/claude-code/skills/{scaffold → ts-procedures-scaffold}/templates/stream-procedure.md +0 -0
@@ -0,0 +1,347 @@
1
+ import { describe, expect, it, test } from 'vitest';
2
+ import { v } from 'suretype';
3
+ import { Procedures } from '../../index.js';
4
+ import { HonoRPCAppBuilder } from './hono-rpc/index.js';
5
+ import { DocRegistry } from './doc-registry.js';
6
+ // ---------------------------------------------------------------------------
7
+ // Helpers — minimal doc fixtures
8
+ // ---------------------------------------------------------------------------
9
+ const rpcDoc = {
10
+ kind: 'rpc',
11
+ name: 'Echo',
12
+ path: '/echo/1',
13
+ method: 'post',
14
+ scope: 'echo',
15
+ version: 1,
16
+ jsonSchema: { body: { type: 'object' } },
17
+ };
18
+ const apiDoc = {
19
+ kind: 'api',
20
+ name: 'GetUser',
21
+ path: '/users/:id',
22
+ method: 'get',
23
+ fullPath: '/api/users/:id',
24
+ jsonSchema: { pathParams: { type: 'object' } },
25
+ };
26
+ const streamDoc = {
27
+ kind: 'stream',
28
+ name: 'Feed',
29
+ path: '/feed/1',
30
+ methods: ['get'],
31
+ streamMode: 'sse',
32
+ scope: 'feed',
33
+ version: 1,
34
+ jsonSchema: { yieldType: { type: 'object' } },
35
+ };
36
+ function makeSource(docs) {
37
+ return { docs };
38
+ }
39
+ // ---------------------------------------------------------------------------
40
+ // Tests
41
+ // ---------------------------------------------------------------------------
42
+ describe('DocRegistry', () => {
43
+ // --------------------------------------------------------------------------
44
+ // Constructor
45
+ // --------------------------------------------------------------------------
46
+ describe('constructor', () => {
47
+ test('uses defaults when no config provided', () => {
48
+ const registry = new DocRegistry();
49
+ const out = registry.toJSON();
50
+ expect(out.basePath).toBe('');
51
+ expect(out.headers).toEqual([]);
52
+ expect(out.errors).toEqual([]);
53
+ });
54
+ test('accepts partial config', () => {
55
+ const registry = new DocRegistry({ basePath: '/v1' });
56
+ const out = registry.toJSON();
57
+ expect(out.basePath).toBe('/v1');
58
+ expect(out.headers).toEqual([]);
59
+ expect(out.errors).toEqual([]);
60
+ });
61
+ test('accepts full config', () => {
62
+ const headers = [{ name: 'Authorization', description: 'Bearer token', required: true }];
63
+ const errors = [{ name: 'Unauthorized', statusCode: 401, description: 'Missing token' }];
64
+ const registry = new DocRegistry({ basePath: '/api', headers, errors });
65
+ const out = registry.toJSON();
66
+ expect(out.basePath).toBe('/api');
67
+ expect(out.headers).toEqual(headers);
68
+ expect(out.errors).toEqual(errors);
69
+ });
70
+ });
71
+ // --------------------------------------------------------------------------
72
+ // from()
73
+ // --------------------------------------------------------------------------
74
+ describe('from()', () => {
75
+ test('returns this for chaining', () => {
76
+ const registry = new DocRegistry();
77
+ const result = registry.from(makeSource([rpcDoc]));
78
+ expect(result).toBe(registry);
79
+ });
80
+ test('accepts RPC builder source', () => {
81
+ const registry = new DocRegistry().from(makeSource([rpcDoc]));
82
+ expect(registry.toJSON().routes).toEqual([rpcDoc]);
83
+ });
84
+ test('accepts API builder source', () => {
85
+ const registry = new DocRegistry().from(makeSource([apiDoc]));
86
+ expect(registry.toJSON().routes).toEqual([apiDoc]);
87
+ });
88
+ test('accepts Stream builder source', () => {
89
+ const registry = new DocRegistry().from(makeSource([streamDoc]));
90
+ expect(registry.toJSON().routes).toEqual([streamDoc]);
91
+ });
92
+ test('accepts plain { docs } object', () => {
93
+ const plain = { docs: [rpcDoc, apiDoc] };
94
+ const registry = new DocRegistry().from(plain);
95
+ expect(registry.toJSON().routes).toHaveLength(2);
96
+ });
97
+ test('builder not yet built returns empty routes', () => {
98
+ const emptySource = makeSource([]);
99
+ const registry = new DocRegistry().from(emptySource);
100
+ expect(registry.toJSON().routes).toEqual([]);
101
+ });
102
+ test('same builder twice duplicates routes', () => {
103
+ const source = makeSource([rpcDoc]);
104
+ const registry = new DocRegistry().from(source).from(source);
105
+ expect(registry.toJSON().routes).toHaveLength(2);
106
+ expect(registry.toJSON().routes[0]).toEqual(registry.toJSON().routes[1]);
107
+ });
108
+ test('reads docs lazily at toJSON() time', () => {
109
+ const mutableDocs = [];
110
+ const source = { get docs() { return mutableDocs; } };
111
+ const registry = new DocRegistry().from(source);
112
+ expect(registry.toJSON().routes).toHaveLength(0);
113
+ mutableDocs.push(rpcDoc);
114
+ expect(registry.toJSON().routes).toHaveLength(1);
115
+ });
116
+ });
117
+ // --------------------------------------------------------------------------
118
+ // toJSON()
119
+ // --------------------------------------------------------------------------
120
+ describe('toJSON()', () => {
121
+ test('returns correct DocEnvelope shape', () => {
122
+ const registry = new DocRegistry({ basePath: '/api' });
123
+ const out = registry.toJSON();
124
+ expect(out).toHaveProperty('basePath');
125
+ expect(out).toHaveProperty('headers');
126
+ expect(out).toHaveProperty('errors');
127
+ expect(out).toHaveProperty('routes');
128
+ });
129
+ test('collects routes from all sources', () => {
130
+ const registry = new DocRegistry()
131
+ .from(makeSource([rpcDoc]))
132
+ .from(makeSource([apiDoc]))
133
+ .from(makeSource([streamDoc]));
134
+ const out = registry.toJSON();
135
+ expect(out.routes).toHaveLength(3);
136
+ expect(out.routes).toEqual([rpcDoc, apiDoc, streamDoc]);
137
+ });
138
+ test('empty when no sources', () => {
139
+ const out = new DocRegistry().toJSON();
140
+ expect(out.routes).toEqual([]);
141
+ });
142
+ test('headers and errors are copies', () => {
143
+ const headers = [{ name: 'X-Custom' }];
144
+ const errors = [{ name: 'E', statusCode: 500, description: 'd' }];
145
+ const registry = new DocRegistry({ headers, errors });
146
+ const out = registry.toJSON();
147
+ expect(out.headers).toEqual(headers);
148
+ expect(out.headers).not.toBe(headers);
149
+ expect(out.errors).toEqual(errors);
150
+ expect(out.errors).not.toBe(errors);
151
+ });
152
+ });
153
+ // --------------------------------------------------------------------------
154
+ // toJSON() filter
155
+ // --------------------------------------------------------------------------
156
+ describe('toJSON() filter', () => {
157
+ test('excludes routes by name', () => {
158
+ const registry = new DocRegistry()
159
+ .from(makeSource([rpcDoc]))
160
+ .from(makeSource([apiDoc]));
161
+ const out = registry.toJSON({ filter: (r) => r.name !== 'Echo' });
162
+ expect(out.routes).toHaveLength(1);
163
+ expect(out.routes[0].name).toBe('GetUser');
164
+ });
165
+ test('excludes routes by type field', () => {
166
+ const registry = new DocRegistry()
167
+ .from(makeSource([rpcDoc]))
168
+ .from(makeSource([apiDoc]));
169
+ const out = registry.toJSON({
170
+ filter: (r) => 'method' in r && r.method === 'post' && 'scope' in r,
171
+ });
172
+ expect(out.routes).toHaveLength(1);
173
+ expect(out.routes[0].name).toBe('Echo');
174
+ });
175
+ test('all filtered returns empty routes array', () => {
176
+ const registry = new DocRegistry().from(makeSource([rpcDoc]));
177
+ const out = registry.toJSON({ filter: () => false });
178
+ expect(out.routes).toEqual([]);
179
+ });
180
+ });
181
+ // --------------------------------------------------------------------------
182
+ // toJSON() transform
183
+ // --------------------------------------------------------------------------
184
+ describe('toJSON() transform', () => {
185
+ test('adds fields', () => {
186
+ const registry = new DocRegistry({ basePath: '/api' }).from(makeSource([rpcDoc]));
187
+ const out = registry.toJSON({
188
+ transform: (envelope) => ({ ...envelope, version: '2.0' }),
189
+ });
190
+ expect(out.version).toBe('2.0');
191
+ expect(out.basePath).toBe('/api');
192
+ });
193
+ test('reshapes envelope', () => {
194
+ const registry = new DocRegistry().from(makeSource([rpcDoc]));
195
+ const out = registry.toJSON({
196
+ transform: (envelope) => ({ count: envelope.routes.length }),
197
+ });
198
+ expect(out).toEqual({ count: 1 });
199
+ });
200
+ test('runs after filter', () => {
201
+ const registry = new DocRegistry()
202
+ .from(makeSource([rpcDoc]))
203
+ .from(makeSource([apiDoc]));
204
+ const out = registry.toJSON({
205
+ filter: (r) => r.name === 'Echo',
206
+ transform: (envelope) => ({ ...envelope, filteredCount: envelope.routes.length }),
207
+ });
208
+ expect(out.filteredCount).toBe(1);
209
+ expect(out.routes).toHaveLength(1);
210
+ });
211
+ });
212
+ // --------------------------------------------------------------------------
213
+ // defaultErrors()
214
+ // --------------------------------------------------------------------------
215
+ describe('defaultErrors()', () => {
216
+ test('returns 4 entries', () => {
217
+ const errors = DocRegistry.defaultErrors();
218
+ expect(errors).toHaveLength(4);
219
+ });
220
+ test('has correct error names', () => {
221
+ const names = DocRegistry.defaultErrors().map((e) => e.name);
222
+ expect(names).toEqual([
223
+ 'ProcedureError',
224
+ 'ProcedureValidationError',
225
+ 'ProcedureYieldValidationError',
226
+ 'ProcedureRegistrationError',
227
+ ]);
228
+ });
229
+ test('has correct status codes', () => {
230
+ const errors = DocRegistry.defaultErrors();
231
+ expect(errors[0].statusCode).toBe(500); // ProcedureError
232
+ expect(errors[1].statusCode).toBe(400); // ProcedureValidationError
233
+ expect(errors[2].statusCode).toBe(500); // ProcedureYieldValidationError
234
+ expect(errors[3].statusCode).toBe(500); // ProcedureRegistrationError
235
+ });
236
+ test('each entry has schema', () => {
237
+ for (const err of DocRegistry.defaultErrors()) {
238
+ expect(err.schema).toBeDefined();
239
+ expect(err.schema.type).toBe('object');
240
+ }
241
+ });
242
+ test('returns a new array each call', () => {
243
+ const a = DocRegistry.defaultErrors();
244
+ const b = DocRegistry.defaultErrors();
245
+ expect(a).not.toBe(b);
246
+ expect(a).toEqual(b);
247
+ });
248
+ });
249
+ // --------------------------------------------------------------------------
250
+ // kind discriminant
251
+ // --------------------------------------------------------------------------
252
+ describe('kind discriminant', () => {
253
+ it('rpcDoc fixture requires kind field', () => {
254
+ const doc = rpcDoc;
255
+ expect(doc.kind).toBe('rpc');
256
+ });
257
+ it('apiDoc fixture requires kind field', () => {
258
+ const doc = apiDoc;
259
+ expect(doc.kind).toBe('api');
260
+ });
261
+ it('streamDoc fixture requires kind field', () => {
262
+ const doc = streamDoc;
263
+ expect(doc.kind).toBe('stream');
264
+ });
265
+ it('narrows AnyHttpRouteDoc union via kind', () => {
266
+ const routes = [rpcDoc, apiDoc, streamDoc];
267
+ for (const route of routes) {
268
+ expect(route.kind).toBeDefined();
269
+ }
270
+ });
271
+ });
272
+ // --------------------------------------------------------------------------
273
+ // Integration
274
+ // --------------------------------------------------------------------------
275
+ describe('integration', () => {
276
+ test('multiple builder types composed', () => {
277
+ const registry = new DocRegistry({
278
+ basePath: '/api',
279
+ headers: [{ name: 'Authorization', description: 'Bearer token', required: false }],
280
+ errors: DocRegistry.defaultErrors(),
281
+ })
282
+ .from(makeSource([rpcDoc]))
283
+ .from(makeSource([apiDoc]))
284
+ .from(makeSource([streamDoc]));
285
+ const out = registry.toJSON();
286
+ expect(out.basePath).toBe('/api');
287
+ expect(out.headers).toHaveLength(1);
288
+ expect(out.errors).toHaveLength(4);
289
+ expect(out.routes).toHaveLength(3);
290
+ });
291
+ test('filter + transform combined', () => {
292
+ const registry = new DocRegistry({
293
+ basePath: '/api',
294
+ errors: DocRegistry.defaultErrors(),
295
+ })
296
+ .from(makeSource([rpcDoc]))
297
+ .from(makeSource([apiDoc]))
298
+ .from(makeSource([streamDoc]));
299
+ const out = registry.toJSON({
300
+ filter: (r) => r.name !== 'Feed',
301
+ transform: (envelope) => ({
302
+ ...envelope,
303
+ generatedAt: '2026-01-01',
304
+ }),
305
+ });
306
+ expect(out.routes).toHaveLength(2);
307
+ expect(out.routes.map((r) => r.name)).toEqual(['Echo', 'GetUser']);
308
+ expect(out.generatedAt).toBe('2026-01-01');
309
+ });
310
+ test('output is JSON.stringify-safe', () => {
311
+ const registry = new DocRegistry({
312
+ basePath: '/api',
313
+ headers: [{ name: 'X-Request-Id', example: 'abc-123' }],
314
+ errors: DocRegistry.defaultErrors(),
315
+ })
316
+ .from(makeSource([rpcDoc]))
317
+ .from(makeSource([apiDoc]));
318
+ const out = registry.toJSON();
319
+ const str = JSON.stringify(out);
320
+ expect(() => JSON.parse(str)).not.toThrow();
321
+ expect(JSON.parse(str)).toEqual(out);
322
+ });
323
+ test('JSON.stringify(registry) produces default envelope', () => {
324
+ const registry = new DocRegistry({ basePath: '/api' })
325
+ .from(makeSource([rpcDoc]));
326
+ const str = JSON.stringify(registry);
327
+ const parsed = JSON.parse(str);
328
+ expect(parsed.basePath).toBe('/api');
329
+ expect(parsed.routes).toHaveLength(1);
330
+ expect(parsed.routes[0].name).toBe('Echo');
331
+ });
332
+ test('accepts a real HonoRPCAppBuilder as source', () => {
333
+ const RPC = Procedures();
334
+ RPC.Create('Ping', { scope: 'ping', version: 1, schema: { params: v.object({ msg: v.string() }) } }, async (_ctx, params) => params);
335
+ const builder = new HonoRPCAppBuilder();
336
+ builder.register(RPC, () => ({ userId: '123' }));
337
+ builder.build();
338
+ const registry = new DocRegistry({ basePath: '/rpc' }).from(builder);
339
+ const out = registry.toJSON();
340
+ expect(out.basePath).toBe('/rpc');
341
+ expect(out.routes).toHaveLength(1);
342
+ expect(out.routes[0].name).toBe('Ping');
343
+ expect(out.routes[0]).toHaveProperty('jsonSchema');
344
+ });
345
+ });
346
+ });
347
+ //# sourceMappingURL=doc-registry.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doc-registry.test.js","sourceRoot":"","sources":["../../../../src/implementations/http/doc-registry.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ import express from 'express';
2
+ import { TProcedureRegistration } from '../../../index.js';
3
+ import { ExtractConfig, ExtractContext, ProceduresFactory, RPCConfig, RPCHttpRouteDoc } from '../../types.js';
4
+ export type { RPCConfig, RPCHttpRouteDoc };
5
+ export type ExpressRPCAppBuilderConfig = {
6
+ /**
7
+ * An existing Express application instance to use.
8
+ * When provided, ensure to set up necessary middleware (e.g., json/body parser) beforehand.
9
+ * If not provided, a new instance will be created.
10
+ */
11
+ app?: express.Express;
12
+ /** Optional path prefix for all RPC routes. */
13
+ pathPrefix?: string;
14
+ onRequestStart?: (req: express.Request) => void;
15
+ onRequestEnd?: (req: express.Request, res: express.Response) => void;
16
+ onSuccess?: (procedure: TProcedureRegistration, req: express.Request, res: express.Response) => void;
17
+ /**
18
+ * Error handler called when a procedure throws an error.
19
+ * @param procedure
20
+ * @param req
21
+ * @param res
22
+ * @param error
23
+ */
24
+ onError?: (procedure: TProcedureRegistration, req: express.Request, res: express.Response, error: Error) => void;
25
+ };
26
+ /**
27
+ * Builder class for creating an Express application with RPC routes.
28
+ *
29
+ * Usage:
30
+ * const PublicRPC = Procedures<PublicRPCContext, RPCConfig>()
31
+ * const ProtectedRPC = Procedures<ProtectedRPCContext, RPCConfig>()
32
+ *
33
+ * const rpcApp = new ExpressRPCAppBuilder()
34
+ * .register(PublicRPC, (req): Promise<PublicRPCContext> => { /* context resolution logic * / })
35
+ * .register(ProtectedRPC, (req): Promise<ProtectedRPCContext> => { /* context resolution logic * / })
36
+ * .build();
37
+ *
38
+ * const app = rpcApp.app; // Express application
39
+ * const docs = rpcApp.docs; // RPC route documentation
40
+ */
41
+ export declare class ExpressRPCAppBuilder {
42
+ readonly config?: ExpressRPCAppBuilderConfig | undefined;
43
+ /**
44
+ * Constructor for ExpressRPCAppBuilder.
45
+ *
46
+ * @param config
47
+ */
48
+ constructor(config?: ExpressRPCAppBuilderConfig | undefined);
49
+ /**
50
+ * Generates the RPC route path based on the RPC configuration.
51
+ * The RPCConfig name can be a string or an array of strings to form nested paths.
52
+ *
53
+ * Example
54
+ * name: ['string', 'string-string', 'string']
55
+ * path: /string/string-string/string/version
56
+ * @param config
57
+ */
58
+ static makeRPCHttpRoutePath({ name, config, prefix, }: {
59
+ name: string;
60
+ prefix?: string;
61
+ config: RPCConfig;
62
+ }): string;
63
+ /**
64
+ * Instance method wrapper for makeRPCHttpRoutePath that uses the builder's pathPrefix.
65
+ * @param config - The RPC configuration
66
+ */
67
+ makeRPCHttpRoutePath(name: string, config: RPCConfig): string;
68
+ private factories;
69
+ private _app;
70
+ private _docs;
71
+ get app(): express.Express;
72
+ get docs(): RPCHttpRouteDoc[];
73
+ /**
74
+ * Registers a procedure factory with its context.
75
+ * @param factory - The procedure factory created by Procedures<Context, RPCConfig>()
76
+ * @param factoryContext - The context for procedure handlers. Can be a direct value,
77
+ * a sync function (req) => Context, or an async function (req) => Promise<Context>
78
+ * @param extendProcedureDoc - A custom function to extend the generated RPC route documentation for each procedure.
79
+ */
80
+ register<TFactory extends ProceduresFactory>(factory: TFactory, factoryContext: ExtractContext<TFactory> | ((req: express.Request) => ExtractContext<TFactory> | Promise<ExtractContext<TFactory>>), extendProcedureDoc?: (params: {
81
+ base: RPCHttpRouteDoc;
82
+ procedure: TProcedureRegistration<any, ExtractConfig<TFactory>>;
83
+ }) => Record<string, any>): this;
84
+ /**
85
+ * Builds and returns the Express application with registered RPC routes.
86
+ * @return express.Application
87
+ */
88
+ build(): express.Application;
89
+ /**
90
+ * Generates the RPC HTTP route for the given procedure.
91
+ * @param procedure
92
+ */
93
+ private buildRpcHttpRouteDoc;
94
+ }
@@ -0,0 +1,185 @@
1
+ import express from 'express';
2
+ import { kebabCase } from 'es-toolkit/string';
3
+ import { castArray } from 'es-toolkit/compat';
4
+ /**
5
+ * Builder class for creating an Express application with RPC routes.
6
+ *
7
+ * Usage:
8
+ * const PublicRPC = Procedures<PublicRPCContext, RPCConfig>()
9
+ * const ProtectedRPC = Procedures<ProtectedRPCContext, RPCConfig>()
10
+ *
11
+ * const rpcApp = new ExpressRPCAppBuilder()
12
+ * .register(PublicRPC, (req): Promise<PublicRPCContext> => { /* context resolution logic * / })
13
+ * .register(ProtectedRPC, (req): Promise<ProtectedRPCContext> => { /* context resolution logic * / })
14
+ * .build();
15
+ *
16
+ * const app = rpcApp.app; // Express application
17
+ * const docs = rpcApp.docs; // RPC route documentation
18
+ */
19
+ export class ExpressRPCAppBuilder {
20
+ config;
21
+ /**
22
+ * Constructor for ExpressRPCAppBuilder.
23
+ *
24
+ * @param config
25
+ */
26
+ constructor(config) {
27
+ this.config = config;
28
+ if (config?.app) {
29
+ this._app = config.app;
30
+ }
31
+ else {
32
+ // Default middleware if no app is provided
33
+ this._app.use(express.json());
34
+ }
35
+ if (config?.onRequestStart) {
36
+ this._app.use((req, res, next) => {
37
+ config.onRequestStart(req);
38
+ next();
39
+ });
40
+ }
41
+ if (config?.onRequestEnd) {
42
+ this._app.use((req, res, next) => {
43
+ res.on('finish', () => {
44
+ config.onRequestEnd(req, res);
45
+ });
46
+ next();
47
+ });
48
+ }
49
+ }
50
+ /**
51
+ * Generates the RPC route path based on the RPC configuration.
52
+ * The RPCConfig name can be a string or an array of strings to form nested paths.
53
+ *
54
+ * Example
55
+ * name: ['string', 'string-string', 'string']
56
+ * path: /string/string-string/string/version
57
+ * @param config
58
+ */
59
+ static makeRPCHttpRoutePath({ name, config, prefix, }) {
60
+ const normalizedPrefix = prefix ? (prefix.startsWith('/') ? prefix : `/${prefix}`) : '';
61
+ return `${normalizedPrefix}/${castArray(config.scope).map(kebabCase).join('/')}/${kebabCase(name)}/${String(config.version).trim()}`;
62
+ }
63
+ /**
64
+ * Instance method wrapper for makeRPCHttpRoutePath that uses the builder's pathPrefix.
65
+ * @param config - The RPC configuration
66
+ */
67
+ makeRPCHttpRoutePath(name, config) {
68
+ return ExpressRPCAppBuilder.makeRPCHttpRoutePath({
69
+ name,
70
+ config,
71
+ prefix: this.config?.pathPrefix,
72
+ });
73
+ }
74
+ factories = [];
75
+ _app = express();
76
+ _docs = [];
77
+ get app() {
78
+ return this._app;
79
+ }
80
+ get docs() {
81
+ return this._docs;
82
+ }
83
+ /**
84
+ * Registers a procedure factory with its context.
85
+ * @param factory - The procedure factory created by Procedures<Context, RPCConfig>()
86
+ * @param factoryContext - The context for procedure handlers. Can be a direct value,
87
+ * a sync function (req) => Context, or an async function (req) => Promise<Context>
88
+ * @param extendProcedureDoc - A custom function to extend the generated RPC route documentation for each procedure.
89
+ */
90
+ register(factory, factoryContext, extendProcedureDoc) {
91
+ this.factories.push({ factory, factoryContext, extendProcedureDoc });
92
+ return this;
93
+ }
94
+ /**
95
+ * Builds and returns the Express application with registered RPC routes.
96
+ * @return express.Application
97
+ */
98
+ build() {
99
+ this.factories.forEach(({ factory, factoryContext, extendProcedureDoc }) => {
100
+ factory.getProcedures().map((procedure) => {
101
+ const route = this.buildRpcHttpRouteDoc(procedure, extendProcedureDoc);
102
+ this._docs.push(route);
103
+ this._app[route.method](route.path, async (req, res) => {
104
+ try {
105
+ const context = typeof factoryContext === 'function'
106
+ ? await factoryContext(req)
107
+ : factoryContext;
108
+ let ac;
109
+ const ctxWithSignal = Object.defineProperty({ ...context }, 'signal', {
110
+ get() {
111
+ if (!ac) {
112
+ ac = new AbortController();
113
+ req.on('close', () => { if (!res.writableFinished)
114
+ ac.abort(); });
115
+ }
116
+ return ac.signal;
117
+ },
118
+ enumerable: true,
119
+ });
120
+ res.json(await procedure.handler(ctxWithSignal, req.body));
121
+ if (this.config?.onSuccess) {
122
+ this.config.onSuccess(procedure, req, res);
123
+ }
124
+ // if status not set, set to 200
125
+ if (!res.status) {
126
+ res.status(200);
127
+ }
128
+ }
129
+ catch (error) {
130
+ if (this.config?.onError) {
131
+ this.config.onError(procedure, req, res, error);
132
+ return;
133
+ }
134
+ if (!res.status) {
135
+ res.status(500);
136
+ }
137
+ // if no res.json set, set default error message
138
+ if (!res.headersSent) {
139
+ res.json({ error: error.message });
140
+ }
141
+ }
142
+ });
143
+ });
144
+ });
145
+ return this._app;
146
+ }
147
+ /**
148
+ * Generates the RPC HTTP route for the given procedure.
149
+ * @param procedure
150
+ */
151
+ buildRpcHttpRouteDoc(procedure, extendProcedureDoc) {
152
+ const { config } = procedure;
153
+ const path = ExpressRPCAppBuilder.makeRPCHttpRoutePath({
154
+ name: procedure.name,
155
+ config,
156
+ prefix: this.config?.pathPrefix,
157
+ });
158
+ const method = 'post'; // RPCs use POST method
159
+ const jsonSchema = {};
160
+ if (config.schema?.params) {
161
+ jsonSchema.body = config.schema.params;
162
+ }
163
+ if (config.schema?.returnType) {
164
+ jsonSchema.response = config.schema.returnType;
165
+ }
166
+ const base = {
167
+ kind: 'rpc',
168
+ name: procedure.name,
169
+ version: config.version,
170
+ scope: config.scope,
171
+ path,
172
+ method,
173
+ jsonSchema,
174
+ };
175
+ let extendedDoc = {};
176
+ if (extendProcedureDoc) {
177
+ extendedDoc = extendProcedureDoc({ base, procedure });
178
+ }
179
+ return {
180
+ ...extendedDoc,
181
+ ...base,
182
+ };
183
+ }
184
+ }
185
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/implementations/http/express-rpc/index.ts"],"names":[],"mappings":"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"}