ts-procedures 5.4.1 → 5.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -727,6 +727,27 @@ for (const config of procedures) {
727
727
  }
728
728
  ```
729
729
 
730
+ ### DocRegistry — Composing Docs from Multiple Builders
731
+
732
+ Use `DocRegistry` to compose route documentation from any combination of HTTP builders into a typed envelope:
733
+
734
+ ```typescript
735
+ import { DocRegistry } from 'ts-procedures/http-docs'
736
+
737
+ const docs = new DocRegistry({
738
+ basePath: '/api',
739
+ headers: [{ name: 'Authorization', description: 'Bearer token', required: false }],
740
+ errors: DocRegistry.defaultErrors(),
741
+ })
742
+ .from(rpcBuilder)
743
+ .from(apiBuilder)
744
+ .from(streamBuilder)
745
+
746
+ app.get('/docs', (c) => c.json(docs.toJSON()))
747
+ ```
748
+
749
+ `from()` stores a reference — routes are read lazily at `toJSON()` time, so builders can be registered before or after `.build()`. Supports optional `filter` and `transform` options for customizing output.
750
+
730
751
  ## Testing
731
752
 
732
753
  Procedures return handlers that can be called directly in tests:
@@ -82,6 +82,7 @@ All errors include `definedAt` (file:line:column) and enhanced stack traces poin
82
82
  | `ExpressRPCAppBuilder` | `ts-procedures/express-rpc` | POST JSON |
83
83
  | `HonoRPCAppBuilder` | `ts-procedures/hono-rpc` | POST JSON |
84
84
  | `HonoStreamAppBuilder` | `ts-procedures/hono-stream` | SSE or newline-delimited JSON |
85
+ | `DocRegistry` | `ts-procedures/http-docs` | Compose route docs from multiple builders |
85
86
 
86
87
  ### Route Path Format
87
88
 
@@ -451,7 +451,40 @@ console.log(builder.docs)
451
451
 
452
452
  ---
453
453
 
454
- ## 16. Using Async Context Factory Without Error Handling
454
+ ## 16. Manually Wiring a /docs Endpoint Instead of Using DocRegistry
455
+
456
+ **Problem:** Building the docs JSON envelope by hand in every app — duplicating basePath, headers, errors, and route assembly.
457
+
458
+ ```typescript
459
+ // BAD — repeated boilerplate in every app
460
+ app.get('/docs', (c) => c.json({
461
+ basePath: '/api',
462
+ headers: [{ name: 'Authorization', description: 'Bearer token' }],
463
+ errors: [],
464
+ routes: [...rpcBuilder.docs, ...apiBuilder.docs, ...streamBuilder.docs],
465
+ }))
466
+ ```
467
+
468
+ **Fix:** Use `DocRegistry` to compose docs from builders.
469
+
470
+ ```typescript
471
+ // GOOD — declarative, composable, typed
472
+ import { DocRegistry } from 'ts-procedures/http-docs'
473
+
474
+ const docs = new DocRegistry({
475
+ basePath: '/api',
476
+ headers: [{ name: 'Authorization', description: 'Bearer token' }],
477
+ errors: DocRegistry.defaultErrors(),
478
+ }).from(rpcBuilder).from(apiBuilder).from(streamBuilder)
479
+
480
+ app.get('/docs', (c) => c.json(docs.toJSON()))
481
+ ```
482
+
483
+ **Why:** `DocRegistry` provides a typed `DocEnvelope`, includes `defaultErrors()` with JSON Schemas for all 4 procedure error types, reads docs lazily (order-independent), and supports filtering and transformation via `toJSON()` options.
484
+
485
+ ---
486
+
487
+ ## 17. Using Async Context Factory Without Error Handling
455
488
 
456
489
  **Problem:** Async context factories that throw unhandled errors, crashing the request.
457
490
 
@@ -480,7 +513,7 @@ new ExpressRPCAppBuilder({
480
513
 
481
514
  ---
482
515
 
483
- ## 17. Using Both schema.params and schema.input
516
+ ## 18. Using Both schema.params and schema.input
484
517
 
485
518
  **Problem:** Defining both `schema.params` and `schema.input` on the same procedure.
486
519
 
@@ -523,7 +556,7 @@ Create('GetUser', {
523
556
 
524
557
  ---
525
558
 
526
- ## 18. Mismatched Path Param Names in schema.input
559
+ ## 19. Mismatched Path Param Names in schema.input
527
560
 
528
561
  **Problem:** Path template param names don't match `schema.input.pathParams` property names.
529
562
 
@@ -559,7 +592,7 @@ Create('GetUser', {
559
592
 
560
593
  ---
561
594
 
562
- ## 19. Forgetting build() is Async on HonoAPIAppBuilder
595
+ ## 20. Forgetting build() is Async on HonoAPIAppBuilder
563
596
 
564
597
  **Problem:** Not awaiting `build()` on `HonoAPIAppBuilder`.
565
598
 
@@ -665,6 +665,92 @@ type HttpMethod = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head'
665
665
 
666
666
  ---
667
667
 
668
+ ## DocRegistry
669
+
670
+ Composes route documentation from any number of HTTP builders into a typed envelope. Eliminates boilerplate `/docs` endpoint wiring.
671
+
672
+ ```typescript
673
+ import { DocRegistry } from 'ts-procedures/http-docs'
674
+ import type { DocEnvelope, DocRegistryConfig, DocRegistryOutputOptions, HeaderDoc, ErrorDoc, DocSource } from 'ts-procedures/http-docs'
675
+ ```
676
+
677
+ ```typescript
678
+ class DocRegistry {
679
+ constructor(config?: {
680
+ basePath?: string
681
+ headers?: HeaderDoc[]
682
+ errors?: ErrorDoc[]
683
+ })
684
+
685
+ from(source: DocSource<AnyHttpRouteDoc>): this
686
+
687
+ toJSON<T = DocEnvelope>(options?: {
688
+ filter?: (route: AnyHttpRouteDoc) => boolean
689
+ transform?: (envelope: DocEnvelope) => T
690
+ }): T
691
+
692
+ static defaultErrors(): ErrorDoc[]
693
+ }
694
+ ```
695
+
696
+ ### DocSource
697
+
698
+ Any object with a `readonly docs` array. All four HTTP builders (`HonoRPCAppBuilder`, `HonoAPIAppBuilder`, `HonoStreamAppBuilder`, `ExpressRPCAppBuilder`) satisfy this interface.
699
+
700
+ ```typescript
701
+ interface DocSource<T = AnyHttpRouteDoc> {
702
+ readonly docs: T[]
703
+ }
704
+ ```
705
+
706
+ ### HeaderDoc
707
+
708
+ ```typescript
709
+ interface HeaderDoc {
710
+ name: string
711
+ description?: string
712
+ required?: boolean
713
+ example?: string
714
+ }
715
+ ```
716
+
717
+ ### ErrorDoc
718
+
719
+ ```typescript
720
+ interface ErrorDoc {
721
+ name: string
722
+ statusCode: number
723
+ description: string
724
+ schema?: Record<string, unknown>
725
+ }
726
+ ```
727
+
728
+ ### DocEnvelope
729
+
730
+ ```typescript
731
+ interface DocEnvelope {
732
+ basePath: string
733
+ headers: HeaderDoc[]
734
+ errors: ErrorDoc[]
735
+ routes: AnyHttpRouteDoc[]
736
+ }
737
+ ```
738
+
739
+ ### AnyHttpRouteDoc
740
+
741
+ ```typescript
742
+ type AnyHttpRouteDoc = RPCHttpRouteDoc | APIHttpRouteDoc | StreamHttpRouteDoc
743
+ ```
744
+
745
+ ### Key Behaviors
746
+
747
+ - `from()` stores a **reference** to the builder — routes are read lazily at `toJSON()` time, so builders can be registered before or after `.build()`
748
+ - `toJSON()` collects routes via `flatMap(source => source.docs)`, applies optional `filter`, builds envelope, then applies optional `transform`
749
+ - `defaultErrors()` returns 4 `ErrorDoc` entries describing `ProcedureError` (500), `ProcedureValidationError` (400), `ProcedureYieldValidationError` (500), `ProcedureRegistrationError` (500) — each with a JSON Schema for the error response body shape
750
+ - `JSON.stringify(registry)` works directly (calls `toJSON()` implicitly)
751
+
752
+ ---
753
+
668
754
  ## Stack Utilities
669
755
 
670
756
  ### captureDefinitionInfo()
@@ -640,6 +640,39 @@ const openApiPaths = app.docs.map(doc => ({
640
640
 
641
641
  ---
642
642
 
643
+ ## DocRegistry — Composing Docs from Multiple Builders
644
+
645
+ ```typescript
646
+ import { DocRegistry } from 'ts-procedures/http-docs'
647
+
648
+ // Compose docs from any combination of builders
649
+ const docs = new DocRegistry({
650
+ basePath: '/api',
651
+ headers: [{ name: 'Authorization', description: 'Bearer token', required: false }],
652
+ errors: DocRegistry.defaultErrors(),
653
+ })
654
+ .from(rpcBuilder)
655
+ .from(apiBuilder)
656
+ .from(streamBuilder)
657
+
658
+ // Serve as a /docs endpoint
659
+ app.get('/docs', (c) => c.json(docs.toJSON()))
660
+
661
+ // With filtering and transformation
662
+ app.get('/docs', (c) => c.json(docs.toJSON({
663
+ filter: (route) => route.name !== 'InternalHealthCheck',
664
+ transform: (envelope) => ({ ...envelope, generatedAt: new Date().toISOString() }),
665
+ })))
666
+ ```
667
+
668
+ **Key points:**
669
+ - `from()` stores a reference — register builders before or after `.build()`
670
+ - `toJSON()` reads docs lazily, so late-registered procedures are included
671
+ - `DocRegistry.defaultErrors()` provides error schemas for all 4 procedure error types
672
+ - Accepts any object satisfying `{ readonly docs: AnyHttpRouteDoc[] }` — not limited to built-in builders
673
+
674
+ ---
675
+
643
676
  ## Testing Procedures
644
677
 
645
678
  ```typescript
@@ -72,6 +72,7 @@
72
72
 
73
73
  ### SUGGESTION
74
74
  - [ ] Route documentation accessed via `builder.docs` for OpenAPI generation
75
+ - [ ] Uses `DocRegistry` to compose docs from multiple builders instead of manual envelope assembly
75
76
  - [ ] Lifecycle hooks used for observability (logging, metrics)
76
77
 
77
78
  ---
@@ -110,6 +111,7 @@
110
111
 
111
112
  ### SUGGESTION
112
113
  - [ ] Route documentation accessed via `builder.docs` for OpenAPI generation
114
+ - [ ] Uses `DocRegistry` to compose docs across builders instead of manual assembly
113
115
  - [ ] Custom `queryParser` provided if complex query string formats needed
114
116
  - [ ] Lifecycle hooks used for observability (logging, metrics)
115
117
 
@@ -113,7 +113,7 @@ export const {{name}}App = await new HonoAPIAppBuilder({
113
113
  // POST /api/{{name}} → 201
114
114
  // DELETE /api/{{name}}/:id → 204
115
115
 
116
- // Documentation: builder.docs (access before .build() resolves)
116
+ // Documentation: builder.docs or compose with DocRegistry from 'ts-procedures/http-docs'
117
117
  ```
118
118
 
119
119
  ## Test — `{{Name}}.api.test.ts`
@@ -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
@@ -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
@@ -0,0 +1,12 @@
1
+ import type { AnyHttpRouteDoc, DocEnvelope, DocRegistryConfig, DocRegistryOutputOptions, DocSource, ErrorDoc } from '../types.js';
2
+ export type { AnyHttpRouteDoc, DocEnvelope, DocRegistryConfig, DocRegistryOutputOptions, DocSource, ErrorDoc, HeaderDoc, } from '../types.js';
3
+ export declare class DocRegistry {
4
+ private readonly basePath;
5
+ private readonly headers;
6
+ private readonly errors;
7
+ private readonly sources;
8
+ constructor(config?: DocRegistryConfig);
9
+ from(source: DocSource<AnyHttpRouteDoc>): this;
10
+ toJSON<T = DocEnvelope>(options?: DocRegistryOutputOptions<T>): T;
11
+ static defaultErrors(): ErrorDoc[];
12
+ }
@@ -0,0 +1,114 @@
1
+ export class DocRegistry {
2
+ basePath;
3
+ headers;
4
+ errors;
5
+ sources = [];
6
+ constructor(config) {
7
+ this.basePath = config?.basePath ?? '';
8
+ this.headers = config?.headers ?? [];
9
+ this.errors = config?.errors ?? [];
10
+ }
11
+ from(source) {
12
+ this.sources.push(source);
13
+ return this;
14
+ }
15
+ toJSON(options) {
16
+ let routes = this.sources.flatMap((source) => source.docs);
17
+ if (options?.filter) {
18
+ routes = routes.filter(options.filter);
19
+ }
20
+ const envelope = {
21
+ basePath: this.basePath,
22
+ headers: [...this.headers],
23
+ errors: [...this.errors],
24
+ routes,
25
+ };
26
+ if (options?.transform) {
27
+ return options.transform(envelope);
28
+ }
29
+ return envelope;
30
+ }
31
+ // Keep in sync with src/errors.ts
32
+ static defaultErrors() {
33
+ return [
34
+ {
35
+ name: 'ProcedureError',
36
+ statusCode: 500,
37
+ description: 'An error thrown from within a procedure handler via ctx.error().',
38
+ schema: {
39
+ type: 'object',
40
+ properties: {
41
+ name: { type: 'string', const: 'ProcedureError' },
42
+ procedureName: { type: 'string' },
43
+ message: { type: 'string' },
44
+ meta: { type: 'object' },
45
+ },
46
+ required: ['name', 'procedureName', 'message'],
47
+ },
48
+ },
49
+ {
50
+ name: 'ProcedureValidationError',
51
+ statusCode: 400,
52
+ description: 'Schema validation failed for the procedure input parameters.',
53
+ schema: {
54
+ type: 'object',
55
+ properties: {
56
+ name: { type: 'string', const: 'ProcedureValidationError' },
57
+ procedureName: { type: 'string' },
58
+ message: { type: 'string' },
59
+ errors: {
60
+ type: 'array',
61
+ items: {
62
+ type: 'object',
63
+ properties: {
64
+ instancePath: { type: 'string' },
65
+ message: { type: 'string' },
66
+ },
67
+ },
68
+ },
69
+ },
70
+ required: ['name', 'procedureName', 'message'],
71
+ },
72
+ },
73
+ {
74
+ name: 'ProcedureYieldValidationError',
75
+ statusCode: 500,
76
+ description: 'Schema validation failed for a yielded value in a streaming procedure.',
77
+ schema: {
78
+ type: 'object',
79
+ properties: {
80
+ name: { type: 'string', const: 'ProcedureYieldValidationError' },
81
+ procedureName: { type: 'string' },
82
+ message: { type: 'string' },
83
+ errors: {
84
+ type: 'array',
85
+ items: {
86
+ type: 'object',
87
+ properties: {
88
+ instancePath: { type: 'string' },
89
+ message: { type: 'string' },
90
+ },
91
+ },
92
+ },
93
+ },
94
+ required: ['name', 'procedureName', 'message'],
95
+ },
96
+ },
97
+ {
98
+ name: 'ProcedureRegistrationError',
99
+ statusCode: 500,
100
+ description: 'An invalid schema or configuration was detected at procedure registration time.',
101
+ schema: {
102
+ type: 'object',
103
+ properties: {
104
+ name: { type: 'string', const: 'ProcedureRegistrationError' },
105
+ procedureName: { type: 'string' },
106
+ message: { type: 'string' },
107
+ },
108
+ required: ['name', 'procedureName', 'message'],
109
+ },
110
+ },
111
+ ];
112
+ }
113
+ }
114
+ //# sourceMappingURL=doc-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doc-registry.js","sourceRoot":"","sources":["../../../src/implementations/http/doc-registry.ts"],"names":[],"mappings":"AAoBA,MAAM,OAAO,WAAW;IACL,QAAQ,CAAQ;IAChB,OAAO,CAAa;IACpB,MAAM,CAAY;IAClB,OAAO,GAAiC,EAAE,CAAA;IAE3D,YAAY,MAA0B;QACpC,IAAI,CAAC,QAAQ,GAAG,MAAM,EAAE,QAAQ,IAAI,EAAE,CAAA;QACtC,IAAI,CAAC,OAAO,GAAG,MAAM,EAAE,OAAO,IAAI,EAAE,CAAA;QACpC,IAAI,CAAC,MAAM,GAAG,MAAM,EAAE,MAAM,IAAI,EAAE,CAAA;IACpC,CAAC;IAED,IAAI,CAAC,MAAkC;QACrC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACzB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,MAAM,CAAkB,OAAqC;QAC3D,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QAE1D,IAAI,OAAO,EAAE,MAAM,EAAE,CAAC;YACpB,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;QACxC,CAAC;QAED,MAAM,QAAQ,GAAgB;YAC5B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;YAC1B,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;YACxB,MAAM;SACP,CAAA;QAED,IAAI,OAAO,EAAE,SAAS,EAAE,CAAC;YACvB,OAAO,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;QACpC,CAAC;QAED,OAAO,QAAa,CAAA;IACtB,CAAC;IAED,kCAAkC;IAClC,MAAM,CAAC,aAAa;QAClB,OAAO;YACL;gBACE,IAAI,EAAE,gBAAgB;gBACtB,UAAU,EAAE,GAAG;gBACf,WAAW,EAAE,kEAAkE;gBAC/E,MAAM,EAAE;oBACN,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,gBAAgB,EAAE;wBACjD,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBACjC,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBAC3B,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;qBACzB;oBACD,QAAQ,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,SAAS,CAAC;iBAC/C;aACF;YACD;gBACE,IAAI,EAAE,0BAA0B;gBAChC,UAAU,EAAE,GAAG;gBACf,WAAW,EAAE,8DAA8D;gBAC3E,MAAM,EAAE;oBACN,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,0BAA0B,EAAE;wBAC3D,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBACjC,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBAC3B,MAAM,EAAE;4BACN,IAAI,EAAE,OAAO;4BACb,KAAK,EAAE;gCACL,IAAI,EAAE,QAAQ;gCACd,UAAU,EAAE;oCACV,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oCAChC,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;iCAC5B;6BACF;yBACF;qBACF;oBACD,QAAQ,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,SAAS,CAAC;iBAC/C;aACF;YACD;gBACE,IAAI,EAAE,+BAA+B;gBACrC,UAAU,EAAE,GAAG;gBACf,WAAW,EACT,wEAAwE;gBAC1E,MAAM,EAAE;oBACN,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,+BAA+B,EAAE;wBAChE,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBACjC,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBAC3B,MAAM,EAAE;4BACN,IAAI,EAAE,OAAO;4BACb,KAAK,EAAE;gCACL,IAAI,EAAE,QAAQ;gCACd,UAAU,EAAE;oCACV,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oCAChC,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;iCAC5B;6BACF;yBACF;qBACF;oBACD,QAAQ,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,SAAS,CAAC;iBAC/C;aACF;YACD;gBACE,IAAI,EAAE,4BAA4B;gBAClC,UAAU,EAAE,GAAG;gBACf,WAAW,EACT,iFAAiF;gBACnF,MAAM,EAAE;oBACN,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,4BAA4B,EAAE;wBAC7D,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBACjC,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;qBAC5B;oBACD,QAAQ,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,SAAS,CAAC;iBAC/C;aACF;SACF,CAAA;IACH,CAAC;CACF"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,321 @@
1
+ import { describe, expect, 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
+ name: 'Echo',
11
+ path: '/echo/1',
12
+ method: 'post',
13
+ scope: 'echo',
14
+ version: 1,
15
+ jsonSchema: { body: { type: 'object' } },
16
+ };
17
+ const apiDoc = {
18
+ name: 'GetUser',
19
+ path: '/users/:id',
20
+ method: 'get',
21
+ fullPath: '/api/users/:id',
22
+ jsonSchema: { pathParams: { type: 'object' } },
23
+ };
24
+ const streamDoc = {
25
+ name: 'Feed',
26
+ path: '/feed/1',
27
+ methods: ['get'],
28
+ streamMode: 'sse',
29
+ scope: 'feed',
30
+ version: 1,
31
+ jsonSchema: { yieldType: { type: 'object' } },
32
+ };
33
+ function makeSource(docs) {
34
+ return { docs };
35
+ }
36
+ // ---------------------------------------------------------------------------
37
+ // Tests
38
+ // ---------------------------------------------------------------------------
39
+ describe('DocRegistry', () => {
40
+ // --------------------------------------------------------------------------
41
+ // Constructor
42
+ // --------------------------------------------------------------------------
43
+ describe('constructor', () => {
44
+ test('uses defaults when no config provided', () => {
45
+ const registry = new DocRegistry();
46
+ const out = registry.toJSON();
47
+ expect(out.basePath).toBe('');
48
+ expect(out.headers).toEqual([]);
49
+ expect(out.errors).toEqual([]);
50
+ });
51
+ test('accepts partial config', () => {
52
+ const registry = new DocRegistry({ basePath: '/v1' });
53
+ const out = registry.toJSON();
54
+ expect(out.basePath).toBe('/v1');
55
+ expect(out.headers).toEqual([]);
56
+ expect(out.errors).toEqual([]);
57
+ });
58
+ test('accepts full config', () => {
59
+ const headers = [{ name: 'Authorization', description: 'Bearer token', required: true }];
60
+ const errors = [{ name: 'Unauthorized', statusCode: 401, description: 'Missing token' }];
61
+ const registry = new DocRegistry({ basePath: '/api', headers, errors });
62
+ const out = registry.toJSON();
63
+ expect(out.basePath).toBe('/api');
64
+ expect(out.headers).toEqual(headers);
65
+ expect(out.errors).toEqual(errors);
66
+ });
67
+ });
68
+ // --------------------------------------------------------------------------
69
+ // from()
70
+ // --------------------------------------------------------------------------
71
+ describe('from()', () => {
72
+ test('returns this for chaining', () => {
73
+ const registry = new DocRegistry();
74
+ const result = registry.from(makeSource([rpcDoc]));
75
+ expect(result).toBe(registry);
76
+ });
77
+ test('accepts RPC builder source', () => {
78
+ const registry = new DocRegistry().from(makeSource([rpcDoc]));
79
+ expect(registry.toJSON().routes).toEqual([rpcDoc]);
80
+ });
81
+ test('accepts API builder source', () => {
82
+ const registry = new DocRegistry().from(makeSource([apiDoc]));
83
+ expect(registry.toJSON().routes).toEqual([apiDoc]);
84
+ });
85
+ test('accepts Stream builder source', () => {
86
+ const registry = new DocRegistry().from(makeSource([streamDoc]));
87
+ expect(registry.toJSON().routes).toEqual([streamDoc]);
88
+ });
89
+ test('accepts plain { docs } object', () => {
90
+ const plain = { docs: [rpcDoc, apiDoc] };
91
+ const registry = new DocRegistry().from(plain);
92
+ expect(registry.toJSON().routes).toHaveLength(2);
93
+ });
94
+ test('builder not yet built returns empty routes', () => {
95
+ const emptySource = makeSource([]);
96
+ const registry = new DocRegistry().from(emptySource);
97
+ expect(registry.toJSON().routes).toEqual([]);
98
+ });
99
+ test('same builder twice duplicates routes', () => {
100
+ const source = makeSource([rpcDoc]);
101
+ const registry = new DocRegistry().from(source).from(source);
102
+ expect(registry.toJSON().routes).toHaveLength(2);
103
+ expect(registry.toJSON().routes[0]).toEqual(registry.toJSON().routes[1]);
104
+ });
105
+ test('reads docs lazily at toJSON() time', () => {
106
+ const mutableDocs = [];
107
+ const source = { get docs() { return mutableDocs; } };
108
+ const registry = new DocRegistry().from(source);
109
+ expect(registry.toJSON().routes).toHaveLength(0);
110
+ mutableDocs.push(rpcDoc);
111
+ expect(registry.toJSON().routes).toHaveLength(1);
112
+ });
113
+ });
114
+ // --------------------------------------------------------------------------
115
+ // toJSON()
116
+ // --------------------------------------------------------------------------
117
+ describe('toJSON()', () => {
118
+ test('returns correct DocEnvelope shape', () => {
119
+ const registry = new DocRegistry({ basePath: '/api' });
120
+ const out = registry.toJSON();
121
+ expect(out).toHaveProperty('basePath');
122
+ expect(out).toHaveProperty('headers');
123
+ expect(out).toHaveProperty('errors');
124
+ expect(out).toHaveProperty('routes');
125
+ });
126
+ test('collects routes from all sources', () => {
127
+ const registry = new DocRegistry()
128
+ .from(makeSource([rpcDoc]))
129
+ .from(makeSource([apiDoc]))
130
+ .from(makeSource([streamDoc]));
131
+ const out = registry.toJSON();
132
+ expect(out.routes).toHaveLength(3);
133
+ expect(out.routes).toEqual([rpcDoc, apiDoc, streamDoc]);
134
+ });
135
+ test('empty when no sources', () => {
136
+ const out = new DocRegistry().toJSON();
137
+ expect(out.routes).toEqual([]);
138
+ });
139
+ test('headers and errors are copies', () => {
140
+ const headers = [{ name: 'X-Custom' }];
141
+ const errors = [{ name: 'E', statusCode: 500, description: 'd' }];
142
+ const registry = new DocRegistry({ headers, errors });
143
+ const out = registry.toJSON();
144
+ expect(out.headers).toEqual(headers);
145
+ expect(out.headers).not.toBe(headers);
146
+ expect(out.errors).toEqual(errors);
147
+ expect(out.errors).not.toBe(errors);
148
+ });
149
+ });
150
+ // --------------------------------------------------------------------------
151
+ // toJSON() filter
152
+ // --------------------------------------------------------------------------
153
+ describe('toJSON() filter', () => {
154
+ test('excludes routes by name', () => {
155
+ const registry = new DocRegistry()
156
+ .from(makeSource([rpcDoc]))
157
+ .from(makeSource([apiDoc]));
158
+ const out = registry.toJSON({ filter: (r) => r.name !== 'Echo' });
159
+ expect(out.routes).toHaveLength(1);
160
+ expect(out.routes[0].name).toBe('GetUser');
161
+ });
162
+ test('excludes routes by type field', () => {
163
+ const registry = new DocRegistry()
164
+ .from(makeSource([rpcDoc]))
165
+ .from(makeSource([apiDoc]));
166
+ const out = registry.toJSON({
167
+ filter: (r) => 'method' in r && r.method === 'post' && 'scope' in r,
168
+ });
169
+ expect(out.routes).toHaveLength(1);
170
+ expect(out.routes[0].name).toBe('Echo');
171
+ });
172
+ test('all filtered returns empty routes array', () => {
173
+ const registry = new DocRegistry().from(makeSource([rpcDoc]));
174
+ const out = registry.toJSON({ filter: () => false });
175
+ expect(out.routes).toEqual([]);
176
+ });
177
+ });
178
+ // --------------------------------------------------------------------------
179
+ // toJSON() transform
180
+ // --------------------------------------------------------------------------
181
+ describe('toJSON() transform', () => {
182
+ test('adds fields', () => {
183
+ const registry = new DocRegistry({ basePath: '/api' }).from(makeSource([rpcDoc]));
184
+ const out = registry.toJSON({
185
+ transform: (envelope) => ({ ...envelope, version: '2.0' }),
186
+ });
187
+ expect(out.version).toBe('2.0');
188
+ expect(out.basePath).toBe('/api');
189
+ });
190
+ test('reshapes envelope', () => {
191
+ const registry = new DocRegistry().from(makeSource([rpcDoc]));
192
+ const out = registry.toJSON({
193
+ transform: (envelope) => ({ count: envelope.routes.length }),
194
+ });
195
+ expect(out).toEqual({ count: 1 });
196
+ });
197
+ test('runs after filter', () => {
198
+ const registry = new DocRegistry()
199
+ .from(makeSource([rpcDoc]))
200
+ .from(makeSource([apiDoc]));
201
+ const out = registry.toJSON({
202
+ filter: (r) => r.name === 'Echo',
203
+ transform: (envelope) => ({ ...envelope, filteredCount: envelope.routes.length }),
204
+ });
205
+ expect(out.filteredCount).toBe(1);
206
+ expect(out.routes).toHaveLength(1);
207
+ });
208
+ });
209
+ // --------------------------------------------------------------------------
210
+ // defaultErrors()
211
+ // --------------------------------------------------------------------------
212
+ describe('defaultErrors()', () => {
213
+ test('returns 4 entries', () => {
214
+ const errors = DocRegistry.defaultErrors();
215
+ expect(errors).toHaveLength(4);
216
+ });
217
+ test('has correct error names', () => {
218
+ const names = DocRegistry.defaultErrors().map((e) => e.name);
219
+ expect(names).toEqual([
220
+ 'ProcedureError',
221
+ 'ProcedureValidationError',
222
+ 'ProcedureYieldValidationError',
223
+ 'ProcedureRegistrationError',
224
+ ]);
225
+ });
226
+ test('has correct status codes', () => {
227
+ const errors = DocRegistry.defaultErrors();
228
+ expect(errors[0].statusCode).toBe(500); // ProcedureError
229
+ expect(errors[1].statusCode).toBe(400); // ProcedureValidationError
230
+ expect(errors[2].statusCode).toBe(500); // ProcedureYieldValidationError
231
+ expect(errors[3].statusCode).toBe(500); // ProcedureRegistrationError
232
+ });
233
+ test('each entry has schema', () => {
234
+ for (const err of DocRegistry.defaultErrors()) {
235
+ expect(err.schema).toBeDefined();
236
+ expect(err.schema.type).toBe('object');
237
+ }
238
+ });
239
+ test('returns a new array each call', () => {
240
+ const a = DocRegistry.defaultErrors();
241
+ const b = DocRegistry.defaultErrors();
242
+ expect(a).not.toBe(b);
243
+ expect(a).toEqual(b);
244
+ });
245
+ });
246
+ // --------------------------------------------------------------------------
247
+ // Integration
248
+ // --------------------------------------------------------------------------
249
+ describe('integration', () => {
250
+ test('multiple builder types composed', () => {
251
+ const registry = new DocRegistry({
252
+ basePath: '/api',
253
+ headers: [{ name: 'Authorization', description: 'Bearer token', required: false }],
254
+ errors: DocRegistry.defaultErrors(),
255
+ })
256
+ .from(makeSource([rpcDoc]))
257
+ .from(makeSource([apiDoc]))
258
+ .from(makeSource([streamDoc]));
259
+ const out = registry.toJSON();
260
+ expect(out.basePath).toBe('/api');
261
+ expect(out.headers).toHaveLength(1);
262
+ expect(out.errors).toHaveLength(4);
263
+ expect(out.routes).toHaveLength(3);
264
+ });
265
+ test('filter + transform combined', () => {
266
+ const registry = new DocRegistry({
267
+ basePath: '/api',
268
+ errors: DocRegistry.defaultErrors(),
269
+ })
270
+ .from(makeSource([rpcDoc]))
271
+ .from(makeSource([apiDoc]))
272
+ .from(makeSource([streamDoc]));
273
+ const out = registry.toJSON({
274
+ filter: (r) => r.name !== 'Feed',
275
+ transform: (envelope) => ({
276
+ ...envelope,
277
+ generatedAt: '2026-01-01',
278
+ }),
279
+ });
280
+ expect(out.routes).toHaveLength(2);
281
+ expect(out.routes.map((r) => r.name)).toEqual(['Echo', 'GetUser']);
282
+ expect(out.generatedAt).toBe('2026-01-01');
283
+ });
284
+ test('output is JSON.stringify-safe', () => {
285
+ const registry = new DocRegistry({
286
+ basePath: '/api',
287
+ headers: [{ name: 'X-Request-Id', example: 'abc-123' }],
288
+ errors: DocRegistry.defaultErrors(),
289
+ })
290
+ .from(makeSource([rpcDoc]))
291
+ .from(makeSource([apiDoc]));
292
+ const out = registry.toJSON();
293
+ const str = JSON.stringify(out);
294
+ expect(() => JSON.parse(str)).not.toThrow();
295
+ expect(JSON.parse(str)).toEqual(out);
296
+ });
297
+ test('JSON.stringify(registry) produces default envelope', () => {
298
+ const registry = new DocRegistry({ basePath: '/api' })
299
+ .from(makeSource([rpcDoc]));
300
+ const str = JSON.stringify(registry);
301
+ const parsed = JSON.parse(str);
302
+ expect(parsed.basePath).toBe('/api');
303
+ expect(parsed.routes).toHaveLength(1);
304
+ expect(parsed.routes[0].name).toBe('Echo');
305
+ });
306
+ test('accepts a real HonoRPCAppBuilder as source', () => {
307
+ const RPC = Procedures();
308
+ RPC.Create('Ping', { scope: 'ping', version: 1, schema: { params: v.object({ msg: v.string() }) } }, async (_ctx, params) => params);
309
+ const builder = new HonoRPCAppBuilder();
310
+ builder.register(RPC, () => ({ userId: '123' }));
311
+ builder.build();
312
+ const registry = new DocRegistry({ basePath: '/rpc' }).from(builder);
313
+ const out = registry.toJSON();
314
+ expect(out.basePath).toBe('/rpc');
315
+ expect(out.routes).toHaveLength(1);
316
+ expect(out.routes[0].name).toBe('Ping');
317
+ expect(out.routes[0]).toHaveProperty('jsonSchema');
318
+ });
319
+ });
320
+ });
321
+ //# 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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"}
@@ -104,3 +104,34 @@ export type ProceduresFactory = {
104
104
  Create: (...args: any[]) => any;
105
105
  CreateStream?: (...args: any[]) => any;
106
106
  };
107
+ export type AnyHttpRouteDoc = RPCHttpRouteDoc | APIHttpRouteDoc | StreamHttpRouteDoc;
108
+ export interface DocSource<T = AnyHttpRouteDoc> {
109
+ readonly docs: T[];
110
+ }
111
+ export interface HeaderDoc {
112
+ name: string;
113
+ description?: string;
114
+ required?: boolean;
115
+ example?: string;
116
+ }
117
+ export interface ErrorDoc {
118
+ name: string;
119
+ statusCode: number;
120
+ description: string;
121
+ schema?: Record<string, unknown>;
122
+ }
123
+ export interface DocRegistryConfig {
124
+ basePath?: string;
125
+ headers?: HeaderDoc[];
126
+ errors?: ErrorDoc[];
127
+ }
128
+ export interface DocRegistryOutputOptions<TEnvelope = DocEnvelope> {
129
+ filter?: (route: AnyHttpRouteDoc) => boolean;
130
+ transform?: (envelope: DocEnvelope) => TEnvelope;
131
+ }
132
+ export interface DocEnvelope {
133
+ basePath: string;
134
+ headers: HeaderDoc[];
135
+ errors: ErrorDoc[];
136
+ routes: AnyHttpRouteDoc[];
137
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-procedures",
3
- "version": "5.4.1",
3
+ "version": "5.5.0",
4
4
  "description": "A TypeScript RPC framework that creates type-safe, schema-validated procedure calls with a single function definition. Define your procedures once and get full type inference, runtime validation, and framework integration hooks.",
5
5
  "main": "build/exports.js",
6
6
  "types": "build/exports.d.ts",
@@ -39,6 +39,10 @@
39
39
  "./hono-api": {
40
40
  "types": "./build/implementations/http/hono-api/index.d.ts",
41
41
  "import": "./build/implementations/http/hono-api/index.js"
42
+ },
43
+ "./http-docs": {
44
+ "types": "./build/implementations/http/doc-registry.d.ts",
45
+ "import": "./build/implementations/http/doc-registry.js"
42
46
  }
43
47
  },
44
48
  "author": "coryrobinson42@gmail.com",