Skip to content

Commit c6b6e1d

Browse files
committed
feat: restructure RouteMeta type and update documentation metadata format
1 parent f25fc43 commit c6b6e1d

17 files changed

Lines changed: 95 additions & 63 deletions

CHANGELOG.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,43 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
66
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.6.0] - 2026-02-25
9+
10+
### Breaking Changes
11+
12+
- **`RouteMeta` type restructured** — The `docs` metadata fields (`description`, `tags`,
13+
`deprecated`, `auth`, `roles`) must now be nested under a `docs` sub-object. The previous flat
14+
shape was inconsistent with how the HTML generator read the metadata, meaning those fields were
15+
silently ignored in the generated documentation.
16+
17+
**Before (broken — fields were silently ignored):**
18+
19+
```ts
20+
t.procedure.meta({
21+
name: 'Get User',
22+
description: 'Fetch a user by ID', // ❌ never rendered
23+
tags: ['Users'], // ❌ never rendered
24+
auth: true // ❌ never rendered
25+
});
26+
```
27+
28+
**After (correct):**
29+
30+
```ts
31+
t.procedure.meta({
32+
name: 'Get User',
33+
docs: {
34+
description: 'Fetch a user by ID', //
35+
tags: ['Users'], //
36+
auth: true //
37+
}
38+
});
39+
```
40+
41+
`name` remains at the top level of `RouteMeta`. All other documentation fields move under `docs`.
42+
43+
---
44+
845
## [0.5.2] - 2026-02-24
946

1047
### Fixed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ type RouteMeta = {
418418
auth?: boolean;
419419
/** Roles allowed to access this route */
420420
roles?: string[];
421-
}
421+
};
422422
};
423423
```
424424

@@ -453,7 +453,7 @@ export const appRouter = t.router({
453453
list: t.procedure
454454
.meta({
455455
name: 'List Users',
456-
docs: {
456+
docs: {
457457
description: 'Get a paginated list of users',
458458
tags: ['Users'],
459459
auth: true,

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "trpc-docs-generator",
3-
"version": "0.5.2",
3+
"version": "0.6.0",
44
"author": "Lior Cohen",
55
"homepage": "https://github.com/liorcodev/trpc-docs-generator#readme",
66
"repository": {

src/generate-html.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,21 +104,21 @@ export function generateDocsHtml(routes: RouteInfo[], options: DocsGeneratorOpti
104104
<div class="stat-label">Total Endpoints</div>
105105
</div>
106106
<div class="stat">
107-
<div class="stat-value">${routes.filter(r => !(r.meta?.docs as RouteMeta)?.auth).length}</div>
107+
<div class="stat-value">${routes.filter(r => !(r.meta?.docs as RouteMeta['docs'])?.auth).length}</div>
108108
<div class="stat-label">Public Endpoints</div>
109109
<div class="stat-breakdown">
110-
<span>${routes.filter(r => !(r.meta?.docs as RouteMeta)?.auth && r.type === 'query').length} Queries</span>
110+
<span>${routes.filter(r => !(r.meta?.docs as RouteMeta['docs'])?.auth && r.type === 'query').length} Queries</span>
111111
<span>•</span>
112-
<span>${routes.filter(r => !(r.meta?.docs as RouteMeta)?.auth && r.type === 'mutation').length} Mutations</span>
112+
<span>${routes.filter(r => !(r.meta?.docs as RouteMeta['docs'])?.auth && r.type === 'mutation').length} Mutations</span>
113113
</div>
114114
</div>
115115
<div class="stat">
116-
<div class="stat-value">${routes.filter(r => (r.meta?.docs as RouteMeta)?.auth).length}</div>
116+
<div class="stat-value">${routes.filter(r => (r.meta?.docs as RouteMeta['docs'])?.auth).length}</div>
117117
<div class="stat-label">Protected Endpoints</div>
118118
<div class="stat-breakdown">
119-
<span>${routes.filter(r => (r.meta?.docs as RouteMeta)?.auth && r.type === 'query').length} Queries</span>
119+
<span>${routes.filter(r => (r.meta?.docs as RouteMeta['docs'])?.auth && r.type === 'query').length} Queries</span>
120120
<span>•</span>
121-
<span>${routes.filter(r => (r.meta?.docs as RouteMeta)?.auth && r.type === 'mutation').length} Mutations</span>
121+
<span>${routes.filter(r => (r.meta?.docs as RouteMeta['docs'])?.auth && r.type === 'mutation').length} Mutations</span>
122122
</div>
123123
</div>
124124
</div>
@@ -179,7 +179,7 @@ function formatGroupName(group: string): string {
179179
}
180180

181181
function generateRouteCard(route: RouteInfo): string {
182-
const docs = route.meta?.docs as RouteMeta | undefined;
182+
const docs = route.meta?.docs as RouteMeta['docs'];
183183
const routeId = route.path.replace(/\./g, '-');
184184

185185
return `

src/types.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,19 @@
55
export type RouteMeta = {
66
/** Human-readable name for the route */
77
name?: string;
8-
/** Description of what the route does */
9-
description?: string;
10-
/** Tags for grouping routes */
11-
tags?: string[];
12-
/** Whether this route is deprecated */
13-
deprecated?: boolean;
14-
/** Whether this route requires authentication */
15-
auth?: boolean;
16-
/** Roles allowed to access this route */
17-
roles?: string[];
8+
/** Documentation metadata */
9+
docs?: {
10+
/** Description of what the route does */
11+
description?: string;
12+
/** Tags for grouping routes */
13+
tags?: string[];
14+
/** Whether this route is deprecated */
15+
deprecated?: boolean;
16+
/** Whether this route requires authentication */
17+
auth?: boolean;
18+
/** Roles allowed to access this route */
19+
roles?: string[];
20+
};
1821
};
1922

2023
/**

tests/arrays.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const router = t.router({
1111
numArr: t.procedure.input(z.object({ ids: z.array(z.number()) })).query(() => ''),
1212
objArr: t.procedure
1313
.input(z.object({ items: z.array(z.object({ id: z.number(), name: z.string() })) }))
14-
.query(() => ''),
14+
.query(() => '')
1515
});
1616

1717
describe('array types', () => {

tests/edge-cases.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ const router = t.router({
1313
z.object({
1414
filter: z.union([
1515
z.object({ type: z.literal('id'), value: z.number() }),
16-
z.object({ type: z.literal('name'), value: z.string() }),
17-
]),
16+
z.object({ type: z.literal('name'), value: z.string() })
17+
])
1818
})
1919
)
2020
.query(() => ''),
@@ -25,7 +25,7 @@ const router = t.router({
2525
.query(() => ''),
2626

2727
// Nullable date
28-
nullableDate: t.procedure.input(z.object({ at: z.date().nullable() })).query(() => ''),
28+
nullableDate: t.procedure.input(z.object({ at: z.date().nullable() })).query(() => '')
2929
});
3030

3131
describe('edge cases', () => {

tests/enums.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const t = initTRPC.create();
99
const router = t.router({
1010
byStatus: t.procedure
1111
.input(z.object({ status: z.enum(['active', 'inactive', 'pending']) }))
12-
.query(() => ''),
12+
.query(() => '')
1313
});
1414

1515
describe('enums', () => {
@@ -21,7 +21,7 @@ describe('enums', () => {
2121
expect(inputSchema(collectRoutes(router), 'byStatus').properties.status.enum).toEqual([
2222
'active',
2323
'inactive',
24-
'pending',
24+
'pending'
2525
]);
2626
});
2727

tests/intersections.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const Base = z.object({ id: z.number() });
1010
const Extra = z.object({ name: z.string() });
1111

1212
const router = t.router({
13-
merged: t.procedure.input(Base.and(Extra)).query(() => ''),
13+
merged: t.procedure.input(Base.and(Extra)).query(() => '')
1414
});
1515

1616
describe('intersection types', () => {

tests/literals.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const t = initTRPC.create();
99
const router = t.router({
1010
strLit: t.procedure.input(z.object({ v: z.literal('hello') })).query(() => ''),
1111
numLit: t.procedure.input(z.object({ v: z.literal(42) })).query(() => 0),
12-
boolLit: t.procedure.input(z.object({ v: z.literal(true) })).query(() => false),
12+
boolLit: t.procedure.input(z.object({ v: z.literal(true) })).query(() => false)
1313
});
1414

1515
describe('literals', () => {

0 commit comments

Comments
 (0)