ts-procedures 5.4.1 → 5.6.0-beta.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 (135) hide show
  1. package/README.md +171 -0
  2. package/agent_config/claude-code/skills/guide/SKILL.md +1 -0
  3. package/agent_config/claude-code/skills/guide/anti-patterns.md +37 -4
  4. package/agent_config/claude-code/skills/guide/api-reference.md +263 -0
  5. package/agent_config/claude-code/skills/guide/patterns.md +140 -0
  6. package/agent_config/claude-code/skills/review/checklist.md +2 -0
  7. package/agent_config/claude-code/skills/scaffold/templates/hono-api.md +1 -1
  8. package/agent_config/copilot/copilot-instructions.md +84 -0
  9. package/agent_config/cursor/cursorrules +84 -0
  10. package/build/client/call.d.ts +14 -0
  11. package/build/client/call.js +47 -0
  12. package/build/client/call.js.map +1 -0
  13. package/build/client/call.test.d.ts +1 -0
  14. package/build/client/call.test.js +124 -0
  15. package/build/client/call.test.js.map +1 -0
  16. package/build/client/errors.d.ts +25 -0
  17. package/build/client/errors.js +33 -0
  18. package/build/client/errors.js.map +1 -0
  19. package/build/client/errors.test.d.ts +1 -0
  20. package/build/client/errors.test.js +41 -0
  21. package/build/client/errors.test.js.map +1 -0
  22. package/build/client/fetch-adapter.d.ts +12 -0
  23. package/build/client/fetch-adapter.js +156 -0
  24. package/build/client/fetch-adapter.js.map +1 -0
  25. package/build/client/fetch-adapter.test.d.ts +1 -0
  26. package/build/client/fetch-adapter.test.js +271 -0
  27. package/build/client/fetch-adapter.test.js.map +1 -0
  28. package/build/client/hooks.d.ts +17 -0
  29. package/build/client/hooks.js +40 -0
  30. package/build/client/hooks.js.map +1 -0
  31. package/build/client/hooks.test.d.ts +1 -0
  32. package/build/client/hooks.test.js +163 -0
  33. package/build/client/hooks.test.js.map +1 -0
  34. package/build/client/index.d.ts +22 -0
  35. package/build/client/index.js +67 -0
  36. package/build/client/index.js.map +1 -0
  37. package/build/client/index.test.d.ts +1 -0
  38. package/build/client/index.test.js +231 -0
  39. package/build/client/index.test.js.map +1 -0
  40. package/build/client/request-builder.d.ts +13 -0
  41. package/build/client/request-builder.js +53 -0
  42. package/build/client/request-builder.js.map +1 -0
  43. package/build/client/request-builder.test.d.ts +1 -0
  44. package/build/client/request-builder.test.js +160 -0
  45. package/build/client/request-builder.test.js.map +1 -0
  46. package/build/client/stream.d.ts +27 -0
  47. package/build/client/stream.js +118 -0
  48. package/build/client/stream.js.map +1 -0
  49. package/build/client/stream.test.d.ts +1 -0
  50. package/build/client/stream.test.js +228 -0
  51. package/build/client/stream.test.js.map +1 -0
  52. package/build/client/types.d.ts +78 -0
  53. package/build/client/types.js +3 -0
  54. package/build/client/types.js.map +1 -0
  55. package/build/codegen/bin/cli.d.ts +17 -0
  56. package/build/codegen/bin/cli.js +148 -0
  57. package/build/codegen/bin/cli.js.map +1 -0
  58. package/build/codegen/bin/cli.test.d.ts +1 -0
  59. package/build/codegen/bin/cli.test.js +83 -0
  60. package/build/codegen/bin/cli.test.js.map +1 -0
  61. package/build/codegen/e2e.test.d.ts +1 -0
  62. package/build/codegen/e2e.test.js +321 -0
  63. package/build/codegen/e2e.test.js.map +1 -0
  64. package/build/codegen/emit-errors.d.ts +9 -0
  65. package/build/codegen/emit-errors.js +30 -0
  66. package/build/codegen/emit-errors.js.map +1 -0
  67. package/build/codegen/emit-errors.test.d.ts +1 -0
  68. package/build/codegen/emit-errors.test.js +110 -0
  69. package/build/codegen/emit-errors.test.js.map +1 -0
  70. package/build/codegen/emit-index.d.ts +6 -0
  71. package/build/codegen/emit-index.js +49 -0
  72. package/build/codegen/emit-index.js.map +1 -0
  73. package/build/codegen/emit-index.test.d.ts +1 -0
  74. package/build/codegen/emit-index.test.js +83 -0
  75. package/build/codegen/emit-index.test.js.map +1 -0
  76. package/build/codegen/emit-scope.d.ts +6 -0
  77. package/build/codegen/emit-scope.js +194 -0
  78. package/build/codegen/emit-scope.js.map +1 -0
  79. package/build/codegen/emit-scope.test.d.ts +1 -0
  80. package/build/codegen/emit-scope.test.js +276 -0
  81. package/build/codegen/emit-scope.test.js.map +1 -0
  82. package/build/codegen/emit-types.d.ts +14 -0
  83. package/build/codegen/emit-types.js +40 -0
  84. package/build/codegen/emit-types.js.map +1 -0
  85. package/build/codegen/emit-types.test.d.ts +1 -0
  86. package/build/codegen/emit-types.test.js +82 -0
  87. package/build/codegen/emit-types.test.js.map +1 -0
  88. package/build/codegen/group-routes.d.ts +23 -0
  89. package/build/codegen/group-routes.js +46 -0
  90. package/build/codegen/group-routes.js.map +1 -0
  91. package/build/codegen/group-routes.test.d.ts +1 -0
  92. package/build/codegen/group-routes.test.js +131 -0
  93. package/build/codegen/group-routes.test.js.map +1 -0
  94. package/build/codegen/index.d.ts +11 -0
  95. package/build/codegen/index.js +13 -0
  96. package/build/codegen/index.js.map +1 -0
  97. package/build/codegen/pipeline.d.ts +14 -0
  98. package/build/codegen/pipeline.js +49 -0
  99. package/build/codegen/pipeline.js.map +1 -0
  100. package/build/codegen/pipeline.test.d.ts +1 -0
  101. package/build/codegen/pipeline.test.js +151 -0
  102. package/build/codegen/pipeline.test.js.map +1 -0
  103. package/build/codegen/resolve-envelope.d.ts +7 -0
  104. package/build/codegen/resolve-envelope.js +26 -0
  105. package/build/codegen/resolve-envelope.js.map +1 -0
  106. package/build/codegen/resolve-envelope.test.d.ts +1 -0
  107. package/build/codegen/resolve-envelope.test.js +69 -0
  108. package/build/codegen/resolve-envelope.test.js.map +1 -0
  109. package/build/implementations/http/doc-registry.d.ts +12 -0
  110. package/build/implementations/http/doc-registry.js +114 -0
  111. package/build/implementations/http/doc-registry.js.map +1 -0
  112. package/build/implementations/http/doc-registry.test.d.ts +1 -0
  113. package/build/implementations/http/doc-registry.test.js +347 -0
  114. package/build/implementations/http/doc-registry.test.js.map +1 -0
  115. package/build/implementations/http/express-rpc/index.js +1 -0
  116. package/build/implementations/http/express-rpc/index.js.map +1 -1
  117. package/build/implementations/http/express-rpc/index.test.js +1 -1
  118. package/build/implementations/http/express-rpc/index.test.js.map +1 -1
  119. package/build/implementations/http/hono-api/index.js +2 -0
  120. package/build/implementations/http/hono-api/index.js.map +1 -1
  121. package/build/implementations/http/hono-api/index.test.js +9 -0
  122. package/build/implementations/http/hono-api/index.test.js.map +1 -1
  123. package/build/implementations/http/hono-rpc/index.js +1 -0
  124. package/build/implementations/http/hono-rpc/index.js.map +1 -1
  125. package/build/implementations/http/hono-rpc/index.test.js +1 -1
  126. package/build/implementations/http/hono-rpc/index.test.js.map +1 -1
  127. package/build/implementations/http/hono-stream/index.js +17 -1
  128. package/build/implementations/http/hono-stream/index.js.map +1 -1
  129. package/build/implementations/http/hono-stream/index.test.js +61 -0
  130. package/build/implementations/http/hono-stream/index.test.js.map +1 -1
  131. package/build/implementations/http/hono-stream/types.d.ts +4 -13
  132. package/build/implementations/types.d.ts +36 -0
  133. package/build/index.js +8 -1
  134. package/build/index.js.map +1 -1
  135. package/package.json +16 -2
@@ -38,6 +38,10 @@ import { HonoStreamAppBuilder, sse } from 'ts-procedures/hono-stream'
38
38
  // Hono API (REST-style)
39
39
  import { HonoAPIAppBuilder } from 'ts-procedures/hono-api'
40
40
  import type { APIConfig, APIInput } from 'ts-procedures/hono-api'
41
+
42
+ // Doc Registry — compose route docs from multiple builders
43
+ import { DocRegistry } from 'ts-procedures/http-docs'
44
+ import type { DocEnvelope, HeaderDoc, ErrorDoc } from 'ts-procedures/http-docs'
41
45
  ```
42
46
 
43
47
  ## Architecture Rules
@@ -288,3 +292,83 @@ describe('GetUser', () => {
288
292
  - `scope` can be string or string[] (joined as path segments)
289
293
  - Procedure name auto-converted to kebab-case
290
294
  - Stream routes support both GET (query params) and POST (JSON body)
295
+
296
+ ## Client Code Generation
297
+
298
+ Generate type-safe client SDKs from a running DocRegistry endpoint.
299
+
300
+ ### Imports
301
+
302
+ ```typescript
303
+ // Client Runtime
304
+ import { createClient, createFetchAdapter } from 'ts-procedures/client'
305
+ import type { ClientAdapter, ClientHooks, TypedStream, ClientInstance } from 'ts-procedures/client'
306
+
307
+ // Code Generation (build-time only)
308
+ import { generateClient } from 'ts-procedures/codegen'
309
+ ```
310
+
311
+ ### CLI
312
+
313
+ ```bash
314
+ npx ts-procedures-codegen --url http://localhost:3000/docs --out ./src/generated/api
315
+ ```
316
+
317
+ Generates one `.ts` file per scope plus a root `index.ts` exporting `createScopeBindings`.
318
+
319
+ ### createClient Example
320
+
321
+ ```typescript
322
+ import { createClient, createFetchAdapter } from 'ts-procedures/client'
323
+ import { createScopeBindings } from './generated/api'
324
+
325
+ const client = createClient({
326
+ adapter: createFetchAdapter(),
327
+ basePath: 'http://localhost:3000',
328
+ scopes: createScopeBindings,
329
+ hooks: {
330
+ onBeforeRequest(ctx) {
331
+ ctx.request.headers = { ...ctx.request.headers, Authorization: `Bearer ${getToken()}` }
332
+ return ctx
333
+ },
334
+ onAfterResponse(ctx) {
335
+ if (ctx.response.status === 401) redirect('/login')
336
+ },
337
+ },
338
+ })
339
+
340
+ // Fully typed — params and response inferred from server schemas
341
+ const user = await client.users.GetUser({ pathParams: { id: '123' } })
342
+
343
+ // Per-call hook override
344
+ await client.users.GetUser({ pathParams: { id: '123' } }, {
345
+ onAfterResponse(ctx) {
346
+ console.log(ctx.response.headers['x-rate-limit-remaining'])
347
+ },
348
+ })
349
+ ```
350
+
351
+ ### Hook Types
352
+
353
+ ```typescript
354
+ interface ClientHooks {
355
+ onBeforeRequest?: (ctx: { request: ClientRequest }) => { request: ClientRequest } | void
356
+ onAfterResponse?: (ctx: { request: ClientRequest; response: ClientResponse }) => void
357
+ }
358
+ ```
359
+
360
+ ### TypedStream Usage
361
+
362
+ ```typescript
363
+ const stream = client.events.WatchNotifications({ filter: 'all' })
364
+
365
+ for await (const event of stream) {
366
+ console.log(event) // Typed as WatchNotificationsYield
367
+ }
368
+
369
+ const result = await stream.result // Typed as WatchNotificationsReturn
370
+ ```
371
+
372
+ - `TypedStream<TYield, TReturn>` extends `AsyncIterable<TYield>`
373
+ - `stream.result` resolves with the final return value sent as `event: 'return'` SSE message
374
+ - Stream procedures that return `void` have `result` resolve to `undefined`
@@ -38,6 +38,10 @@ import { HonoStreamAppBuilder, sse } from 'ts-procedures/hono-stream'
38
38
  // Hono API (REST-style)
39
39
  import { HonoAPIAppBuilder } from 'ts-procedures/hono-api'
40
40
  import type { APIConfig, APIInput } from 'ts-procedures/hono-api'
41
+
42
+ // Doc Registry — compose route docs from multiple builders
43
+ import { DocRegistry } from 'ts-procedures/http-docs'
44
+ import type { DocEnvelope, HeaderDoc, ErrorDoc } from 'ts-procedures/http-docs'
41
45
  ```
42
46
 
43
47
  ## Architecture Rules
@@ -288,3 +292,83 @@ describe('GetUser', () => {
288
292
  - `scope` can be string or string[] (joined as path segments)
289
293
  - Procedure name auto-converted to kebab-case
290
294
  - Stream routes support both GET (query params) and POST (JSON body)
295
+
296
+ ## Client Code Generation
297
+
298
+ Generate type-safe client SDKs from a running DocRegistry endpoint.
299
+
300
+ ### Imports
301
+
302
+ ```typescript
303
+ // Client Runtime
304
+ import { createClient, createFetchAdapter } from 'ts-procedures/client'
305
+ import type { ClientAdapter, ClientHooks, TypedStream, ClientInstance } from 'ts-procedures/client'
306
+
307
+ // Code Generation (build-time only)
308
+ import { generateClient } from 'ts-procedures/codegen'
309
+ ```
310
+
311
+ ### CLI
312
+
313
+ ```bash
314
+ npx ts-procedures-codegen --url http://localhost:3000/docs --out ./src/generated/api
315
+ ```
316
+
317
+ Generates one `.ts` file per scope plus a root `index.ts` exporting `createScopeBindings`.
318
+
319
+ ### createClient Example
320
+
321
+ ```typescript
322
+ import { createClient, createFetchAdapter } from 'ts-procedures/client'
323
+ import { createScopeBindings } from './generated/api'
324
+
325
+ const client = createClient({
326
+ adapter: createFetchAdapter(),
327
+ basePath: 'http://localhost:3000',
328
+ scopes: createScopeBindings,
329
+ hooks: {
330
+ onBeforeRequest(ctx) {
331
+ ctx.request.headers = { ...ctx.request.headers, Authorization: `Bearer ${getToken()}` }
332
+ return ctx
333
+ },
334
+ onAfterResponse(ctx) {
335
+ if (ctx.response.status === 401) redirect('/login')
336
+ },
337
+ },
338
+ })
339
+
340
+ // Fully typed — params and response inferred from server schemas
341
+ const user = await client.users.GetUser({ pathParams: { id: '123' } })
342
+
343
+ // Per-call hook override
344
+ await client.users.GetUser({ pathParams: { id: '123' } }, {
345
+ onAfterResponse(ctx) {
346
+ console.log(ctx.response.headers['x-rate-limit-remaining'])
347
+ },
348
+ })
349
+ ```
350
+
351
+ ### Hook Types
352
+
353
+ ```typescript
354
+ interface ClientHooks {
355
+ onBeforeRequest?: (ctx: { request: ClientRequest }) => { request: ClientRequest } | void
356
+ onAfterResponse?: (ctx: { request: ClientRequest; response: ClientResponse }) => void
357
+ }
358
+ ```
359
+
360
+ ### TypedStream Usage
361
+
362
+ ```typescript
363
+ const stream = client.events.WatchNotifications({ filter: 'all' })
364
+
365
+ for await (const event of stream) {
366
+ console.log(event) // Typed as WatchNotificationsYield
367
+ }
368
+
369
+ const result = await stream.result // Typed as WatchNotificationsReturn
370
+ ```
371
+
372
+ - `TypedStream<TYield, TReturn>` extends `AsyncIterable<TYield>`
373
+ - `stream.result` resolves with the final return value sent as `event: 'return'` SSE message
374
+ - Stream procedures that return `void` have `result` resolve to `undefined`
@@ -0,0 +1,14 @@
1
+ import type { ClientAdapter, ClientHooks, CallDescriptor } from './types.js';
2
+ /**
3
+ * Executes a single procedure call through the adapter.
4
+ *
5
+ * Flow:
6
+ * 1. Build AdapterRequest from descriptor
7
+ * 2. Run onBeforeRequest hooks (global then local)
8
+ * 3. Call adapter.request()
9
+ * 4. On adapter error: run onError hooks, re-throw
10
+ * 5. Run onAfterResponse hooks (hooks may mutate response.status)
11
+ * 6. If response status is non-2xx: throw ClientRequestError
12
+ * 7. Return response.body as TResponse
13
+ */
14
+ export declare function executeCall<TResponse>(descriptor: CallDescriptor, basePath: string, adapter: ClientAdapter, globalHooks: ClientHooks, localHooks: ClientHooks | undefined): Promise<TResponse>;
@@ -0,0 +1,47 @@
1
+ import { buildAdapterRequest } from './request-builder.js';
2
+ import { runBeforeRequest, runAfterResponse, runOnError } from './hooks.js';
3
+ import { ClientRequestError } from './errors.js';
4
+ /**
5
+ * Executes a single procedure call through the adapter.
6
+ *
7
+ * Flow:
8
+ * 1. Build AdapterRequest from descriptor
9
+ * 2. Run onBeforeRequest hooks (global then local)
10
+ * 3. Call adapter.request()
11
+ * 4. On adapter error: run onError hooks, re-throw
12
+ * 5. Run onAfterResponse hooks (hooks may mutate response.status)
13
+ * 6. If response status is non-2xx: throw ClientRequestError
14
+ * 7. Return response.body as TResponse
15
+ */
16
+ export async function executeCall(descriptor, basePath, adapter, globalHooks, localHooks) {
17
+ // 1. Build the initial request
18
+ let request = buildAdapterRequest(descriptor, basePath);
19
+ // 2. Run before-request hooks — they may mutate the request
20
+ const beforeCtx = await runBeforeRequest({ procedureName: descriptor.name, scope: descriptor.scope, request }, globalHooks, localHooks);
21
+ request = beforeCtx.request;
22
+ // 3. Call the adapter
23
+ let response;
24
+ try {
25
+ response = await adapter.request(request);
26
+ }
27
+ catch (err) {
28
+ // 4. On adapter error: run error hooks, re-throw
29
+ await runOnError({ procedureName: descriptor.name, scope: descriptor.scope, request, error: err }, globalHooks, localHooks);
30
+ throw err;
31
+ }
32
+ // 5. Run after-response hooks — they may mutate response.status to swallow errors
33
+ await runAfterResponse({ procedureName: descriptor.name, scope: descriptor.scope, request, response }, globalHooks, localHooks);
34
+ // 6. Check status AFTER hooks (hooks may have swallowed the error by mutating status)
35
+ if (response.status < 200 || response.status >= 300) {
36
+ throw new ClientRequestError({
37
+ status: response.status,
38
+ headers: response.headers,
39
+ body: response.body,
40
+ procedureName: descriptor.name,
41
+ scope: descriptor.scope,
42
+ });
43
+ }
44
+ // 7. Return the body
45
+ return response.body;
46
+ }
47
+ //# sourceMappingURL=call.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"call.js","sourceRoot":"","sources":["../../src/client/call.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAOhD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,UAA0B,EAC1B,QAAgB,EAChB,OAAsB,EACtB,WAAwB,EACxB,UAAmC;IAEnC,+BAA+B;IAC/B,IAAI,OAAO,GAAG,mBAAmB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;IAEvD,4DAA4D;IAC5D,MAAM,SAAS,GAAG,MAAM,gBAAgB,CACtC,EAAE,aAAa,EAAE,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,EACpE,WAAW,EACX,UAAU,CACX,CAAA;IACD,OAAO,GAAG,SAAS,CAAC,OAAO,CAAA;IAE3B,sBAAsB;IACtB,IAAI,QAAQ,CAAA;IACZ,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAC3C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,iDAAiD;QACjD,MAAM,UAAU,CACd,EAAE,aAAa,EAAE,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAChF,WAAW,EACX,UAAU,CACX,CAAA;QACD,MAAM,GAAG,CAAA;IACX,CAAC;IAED,kFAAkF;IAClF,MAAM,gBAAgB,CACpB,EAAE,aAAa,EAAE,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,EAC9E,WAAW,EACX,UAAU,CACX,CAAA;IAED,sFAAsF;IACtF,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;QACpD,MAAM,IAAI,kBAAkB,CAAC;YAC3B,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,OAAO,EAAE,QAAQ,CAAC,OAAO;YACzB,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,aAAa,EAAE,UAAU,CAAC,IAAI;YAC9B,KAAK,EAAE,UAAU,CAAC,KAAK;SACxB,CAAC,CAAA;IACJ,CAAC;IAED,qBAAqB;IACrB,OAAO,QAAQ,CAAC,IAAiB,CAAA;AACnC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,124 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { executeCall } from './call.js';
3
+ import { ClientRequestError } from './errors.js';
4
+ // ── helpers ───────────────────────────────────────────────
5
+ function makeDescriptor(overrides) {
6
+ return {
7
+ name: 'GetUser',
8
+ scope: 'users',
9
+ path: '/users',
10
+ method: 'GET',
11
+ kind: 'rpc',
12
+ params: { id: '42' },
13
+ ...overrides,
14
+ };
15
+ }
16
+ function makeAdapter(response) {
17
+ return {
18
+ request: vi.fn(async (_req) => ({
19
+ status: 200,
20
+ headers: {},
21
+ body: { id: '42', name: 'Alice' },
22
+ ...response,
23
+ })),
24
+ stream: vi.fn(async () => {
25
+ throw new Error('stream not expected in call tests');
26
+ }),
27
+ };
28
+ }
29
+ // ── executeCall ───────────────────────────────────────────
30
+ describe('executeCall', () => {
31
+ it('calls adapter.request and returns body', async () => {
32
+ const adapter = makeAdapter({ body: { id: '1', name: 'Bob' } });
33
+ const result = await executeCall(makeDescriptor(), 'https://api.example.com', adapter, {}, undefined);
34
+ expect(adapter.request).toHaveBeenCalledOnce();
35
+ expect(result).toEqual({ id: '1', name: 'Bob' });
36
+ });
37
+ it('throws ClientRequestError on 4xx response', async () => {
38
+ const adapter = makeAdapter({ status: 404, body: { message: 'Not Found' } });
39
+ await expect(executeCall(makeDescriptor(), 'https://api.example.com', adapter, {}, undefined)).rejects.toThrow(ClientRequestError);
40
+ });
41
+ it('throws ClientRequestError on 5xx response', async () => {
42
+ const adapter = makeAdapter({ status: 500, body: { message: 'Server Error' } });
43
+ await expect(executeCall(makeDescriptor(), 'https://api.example.com', adapter, {}, undefined)).rejects.toThrow(ClientRequestError);
44
+ });
45
+ it('throws ClientRequestError on 199 response (below 200)', async () => {
46
+ const adapter = makeAdapter({ status: 199, body: null });
47
+ await expect(executeCall(makeDescriptor(), 'https://api.example.com', adapter, {}, undefined)).rejects.toThrow(ClientRequestError);
48
+ });
49
+ it('does not throw on 2xx boundary responses (200, 201, 299)', async () => {
50
+ for (const status of [200, 201, 204, 299]) {
51
+ const adapter = makeAdapter({ status, body: null });
52
+ await expect(executeCall(makeDescriptor(), 'https://api.example.com', adapter, {}, undefined)).resolves.not.toThrow();
53
+ }
54
+ });
55
+ it('runs onBeforeRequest before calling adapter (headers are modified)', async () => {
56
+ const capturedHeaders = [];
57
+ const adapter = {
58
+ request: vi.fn(async (req) => {
59
+ capturedHeaders.push(req.headers ?? {});
60
+ return { status: 200, headers: {}, body: {} };
61
+ }),
62
+ stream: vi.fn(async () => { throw new Error('not expected'); }),
63
+ };
64
+ const globalHooks = {
65
+ onBeforeRequest: (ctx) => ({
66
+ ...ctx,
67
+ request: {
68
+ ...ctx.request,
69
+ headers: { ...ctx.request.headers, 'x-auth': 'token-123' },
70
+ },
71
+ }),
72
+ };
73
+ await executeCall(makeDescriptor(), 'https://api.example.com', adapter, globalHooks, undefined);
74
+ expect(capturedHeaders[0]?.['x-auth']).toBe('token-123');
75
+ });
76
+ it('runs onAfterResponse after adapter returns', async () => {
77
+ const order = [];
78
+ const adapter = {
79
+ request: vi.fn(async () => {
80
+ order.push('adapter');
81
+ return { status: 200, headers: {}, body: {} };
82
+ }),
83
+ stream: vi.fn(async () => { throw new Error('not expected'); }),
84
+ };
85
+ const globalHooks = {
86
+ onAfterResponse: () => { order.push('afterResponse'); },
87
+ };
88
+ await executeCall(makeDescriptor(), 'https://api.example.com', adapter, globalHooks, undefined);
89
+ expect(order).toEqual(['adapter', 'afterResponse']);
90
+ });
91
+ it('does not throw when onAfterResponse swallows non-2xx by mutating status', async () => {
92
+ const adapter = makeAdapter({ status: 401, body: { message: 'Unauthorized' } });
93
+ const globalHooks = {
94
+ onAfterResponse: (ctx) => {
95
+ // Swallow the error by setting status to 200
96
+ ctx.response.status = 200;
97
+ },
98
+ };
99
+ await expect(executeCall(makeDescriptor(), 'https://api.example.com', adapter, globalHooks, undefined)).resolves.not.toThrow();
100
+ });
101
+ it('runs onError on adapter failure and re-throws', async () => {
102
+ const adapterError = new Error('Network failure');
103
+ const adapter = {
104
+ request: vi.fn(async () => { throw adapterError; }),
105
+ stream: vi.fn(async () => { throw new Error('not expected'); }),
106
+ };
107
+ const receivedErrors = [];
108
+ const globalHooks = {
109
+ onError: (ctx) => { receivedErrors.push(ctx.error); },
110
+ };
111
+ await expect(executeCall(makeDescriptor(), 'https://api.example.com', adapter, globalHooks, undefined)).rejects.toThrow('Network failure');
112
+ expect(receivedErrors[0]).toBe(adapterError);
113
+ });
114
+ it('passes per-procedure hooks as local hooks', async () => {
115
+ const adapter = makeAdapter();
116
+ const localOrder = [];
117
+ const localHooks = {
118
+ onBeforeRequest: (ctx) => { localOrder.push('local-before'); return ctx; },
119
+ };
120
+ await executeCall(makeDescriptor(), 'https://api.example.com', adapter, {}, localHooks);
121
+ expect(localOrder).toContain('local-before');
122
+ });
123
+ });
124
+ //# sourceMappingURL=call.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"call.test.js","sourceRoot":"","sources":["../../src/client/call.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ export declare class ClientRequestError extends Error {
2
+ readonly name = "ClientRequestError";
3
+ readonly status: number;
4
+ readonly headers: Record<string, string>;
5
+ readonly body: unknown;
6
+ readonly procedureName: string;
7
+ readonly scope: string;
8
+ constructor(opts: {
9
+ status: number;
10
+ headers: Record<string, string>;
11
+ body: unknown;
12
+ procedureName: string;
13
+ scope: string;
14
+ });
15
+ }
16
+ export declare class ClientPathParamError extends Error {
17
+ readonly name = "ClientPathParamError";
18
+ constructor(param: string, path: string, procedureName: string);
19
+ }
20
+ export declare class ClientStreamError extends Error {
21
+ readonly name = "ClientStreamError";
22
+ readonly procedureName: string;
23
+ readonly scope: string;
24
+ constructor(message: string, procedureName: string, scope: string);
25
+ }
@@ -0,0 +1,33 @@
1
+ export class ClientRequestError extends Error {
2
+ name = 'ClientRequestError';
3
+ status;
4
+ headers;
5
+ body;
6
+ procedureName;
7
+ scope;
8
+ constructor(opts) {
9
+ super(`${opts.procedureName} (${opts.scope}) failed with status ${opts.status}`);
10
+ this.status = opts.status;
11
+ this.headers = opts.headers;
12
+ this.body = opts.body;
13
+ this.procedureName = opts.procedureName;
14
+ this.scope = opts.scope;
15
+ }
16
+ }
17
+ export class ClientPathParamError extends Error {
18
+ name = 'ClientPathParamError';
19
+ constructor(param, path, procedureName) {
20
+ super(`Missing path parameter "${param}" in "${path}" for procedure ${procedureName}`);
21
+ }
22
+ }
23
+ export class ClientStreamError extends Error {
24
+ name = 'ClientStreamError';
25
+ procedureName;
26
+ scope;
27
+ constructor(message, procedureName, scope) {
28
+ super(message);
29
+ this.procedureName = procedureName;
30
+ this.scope = scope;
31
+ }
32
+ }
33
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/client/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAClC,IAAI,GAAG,oBAAoB,CAAA;IAC3B,MAAM,CAAQ;IACd,OAAO,CAAwB;IAC/B,IAAI,CAAS;IACb,aAAa,CAAQ;IACrB,KAAK,CAAQ;IAEtB,YAAY,IAMX;QACC,KAAK,CAAC,GAAG,IAAI,CAAC,aAAa,KAAK,IAAI,CAAC,KAAK,wBAAwB,IAAI,CAAC,MAAM,EAAE,CAAC,CAAA;QAChF,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;QACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAA;QAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;QACrB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAA;QACvC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;IACzB,CAAC;CACF;AAED,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IACpC,IAAI,GAAG,sBAAsB,CAAA;IAEtC,YAAY,KAAa,EAAE,IAAY,EAAE,aAAqB;QAC5D,KAAK,CAAC,2BAA2B,KAAK,SAAS,IAAI,mBAAmB,aAAa,EAAE,CAAC,CAAA;IACxF,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACjC,IAAI,GAAG,mBAAmB,CAAA;IAC1B,aAAa,CAAQ;IACrB,KAAK,CAAQ;IAEtB,YAAY,OAAe,EAAE,aAAqB,EAAE,KAAa;QAC/D,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,aAAa,GAAG,aAAa,CAAA;QAClC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;IACpB,CAAC;CACF"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,41 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { ClientRequestError, ClientPathParamError, ClientStreamError } from './errors.js';
3
+ describe('ClientRequestError', () => {
4
+ it('includes status, headers, and body', () => {
5
+ const err = new ClientRequestError({
6
+ status: 401,
7
+ headers: { 'x-request-id': 'abc' },
8
+ body: { message: 'Unauthorized' },
9
+ procedureName: 'GetUser',
10
+ scope: 'users',
11
+ });
12
+ expect(err).toBeInstanceOf(Error);
13
+ expect(err.name).toBe('ClientRequestError');
14
+ expect(err.status).toBe(401);
15
+ expect(err.headers['x-request-id']).toBe('abc');
16
+ expect(err.body).toEqual({ message: 'Unauthorized' });
17
+ expect(err.procedureName).toBe('GetUser');
18
+ expect(err.scope).toBe('users');
19
+ expect(err.message).toBe('GetUser (users) failed with status 401');
20
+ });
21
+ });
22
+ describe('ClientPathParamError', () => {
23
+ it('reports missing param', () => {
24
+ const err = new ClientPathParamError('id', '/users/:id', 'GetUser');
25
+ expect(err).toBeInstanceOf(Error);
26
+ expect(err.name).toBe('ClientPathParamError');
27
+ expect(err.message).toContain('id');
28
+ expect(err.message).toContain('/users/:id');
29
+ });
30
+ });
31
+ describe('ClientStreamError', () => {
32
+ it('includes procedure context', () => {
33
+ const err = new ClientStreamError('stream interrupted', 'Watch', 'events');
34
+ expect(err).toBeInstanceOf(Error);
35
+ expect(err.name).toBe('ClientStreamError');
36
+ expect(err.procedureName).toBe('Watch');
37
+ expect(err.scope).toBe('events');
38
+ expect(err.message).toBe('stream interrupted');
39
+ });
40
+ });
41
+ //# sourceMappingURL=errors.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.test.js","sourceRoot":"","sources":["../../src/client/errors.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAEzF,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,GAAG,GAAG,IAAI,kBAAkB,CAAC;YACjC,MAAM,EAAE,GAAG;YACX,OAAO,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE;YAClC,IAAI,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE;YACjC,aAAa,EAAE,SAAS;YACxB,KAAK,EAAE,OAAO;SACf,CAAC,CAAA;QACF,MAAM,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAA;QACjC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;QAC3C,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAC5B,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC/C,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAA;QACrD,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACzC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAC/B,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAA;IACpE,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,GAAG,GAAG,IAAI,oBAAoB,CAAC,IAAI,EAAE,YAAY,EAAE,SAAS,CAAC,CAAA;QACnE,MAAM,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAA;QACjC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAA;QAC7C,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;QACnC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAA;IAC7C,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,GAAG,GAAG,IAAI,iBAAiB,CAAC,oBAAoB,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAA;QAC1E,MAAM,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAA;QACjC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAA;QAC1C,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACvC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAChC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;IAChD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,12 @@
1
+ import type { ClientAdapter } from './types.js';
2
+ export interface FetchAdapterConfig {
3
+ headers?: Record<string, string>;
4
+ }
5
+ /**
6
+ * Creates a fetch-based ClientAdapter.
7
+ *
8
+ * - `config.headers` are default headers applied to every request.
9
+ * - Per-request headers override config headers (spread order).
10
+ * - Works in Node.js 18+ and browsers (uses standard fetch + ReadableStream).
11
+ */
12
+ export declare function createFetchAdapter(config?: FetchAdapterConfig): ClientAdapter;