orpc-file-based-router 0.1.6 → 0.1.7
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 +15 -73
- package/dist/index.cjs +23 -20
- package/dist/index.d.cts +4 -7
- package/dist/index.d.mts +4 -7
- package/dist/index.d.ts +4 -7
- package/dist/index.mjs +23 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,97 +43,40 @@ src/routes
|
|
|
43
43
|
└── sse.ts
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
3. Each file should export an oRPC function
|
|
46
|
+
3. Each file should export an oRPC function (non-oRPC exports will be ignored)
|
|
47
47
|
|
|
48
|
-
4.
|
|
49
|
-
function:
|
|
48
|
+
4. Generate your router before starting the server using the `generateRouter` function:
|
|
50
49
|
|
|
51
50
|
```typescript
|
|
52
|
-
|
|
53
|
-
import {
|
|
54
|
-
|
|
55
|
-
const routesDir = new URL("./routes", import.meta.url).pathname;
|
|
56
|
-
const router = await createRouter(routesDir);
|
|
57
|
-
|
|
58
|
-
const handler = new RPCHandler(router);
|
|
59
|
-
|
|
60
|
-
```
|
|
61
|
-
**Note:** If your environment doesn't support top-level await, just use `lazy` for example in expressjs it could be:
|
|
62
|
-
```typescript
|
|
63
|
-
import { RPCHandler } from "@orpc/server/node";
|
|
64
|
-
import { lazy, createRouter } from "orpc-file-based-router";
|
|
51
|
+
// router-gen.ts
|
|
52
|
+
import { generateRouter } from "orpc-file-based-router";
|
|
65
53
|
|
|
66
54
|
const routesDir = new URL("./routes", import.meta.url).pathname;
|
|
55
|
+
const outputFile = new URL("./router.ts", import.meta.url).pathname;
|
|
67
56
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
app.use('/rpc{/*path}', async (req, res, next) => {
|
|
71
|
-
|
|
72
|
-
const handler = new RPCHandler(await router());
|
|
73
|
-
|
|
74
|
-
const { matched } = await handler.handle(req, res, {
|
|
75
|
-
prefix: '/rpc',
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
if (matched) {
|
|
79
|
-
return
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
next()
|
|
83
|
-
})
|
|
57
|
+
generateRouter(routesDir, outputFile);
|
|
84
58
|
```
|
|
85
59
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
For users of the [oRPC client](https://orpc.unnoq.com/docs/client/client-side), we provide automatic configuration generation for enhanced type safety and improved developer experience.
|
|
89
|
-
|
|
90
|
-
1. You can add this code either directly in your server project (e.g., in server.ts or main.ts) or put it into a separate script (e.g., router-gen.ts).
|
|
60
|
+
5. Import and use the generated router in your server:
|
|
91
61
|
|
|
92
62
|
```typescript
|
|
93
|
-
import {
|
|
63
|
+
import { RPCHandler } from "@orpc/server/node";
|
|
64
|
+
import { router } from "./router.js"; // Import the generated router
|
|
94
65
|
|
|
95
|
-
const
|
|
96
|
-
const outputFile = new URL("./router.ts", import.meta.url).pathname;
|
|
97
|
-
generateRouter(routesDir, outputFile);
|
|
66
|
+
const handler = new RPCHandler(router);
|
|
98
67
|
```
|
|
99
68
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
// router.ts
|
|
104
|
-
|
|
105
|
-
import { me as auth_me__me } from "./routes/auth/me.js"
|
|
106
|
-
import { signin as auth_signin__signin } from "./routes/auth/signin.js"
|
|
107
|
-
import { signup as auth_signup__signup } from "./routes/auth/signup.js"
|
|
108
|
-
import { createPlanet as planets_create__createPlanet } from "./routes/planets/create.js"
|
|
109
|
-
import { indexRoute as planets_index__indexRoute } from "./routes/planets/index.js"
|
|
110
|
-
import { listPlanets as planets_list__listPlanets } from "./routes/planets/list.js"
|
|
111
|
-
import { findPlanet as planets_id_find__findPlanet } from "./routes/planets/{id}/find.js"
|
|
112
|
-
import { updatePlanet as planets_id_update__updatePlanet } from "./routes/planets/{id}/update.js"
|
|
113
|
-
import { sse as sse__sse } from "./routes/sse.js"
|
|
114
|
-
|
|
115
|
-
export const router = {
|
|
116
|
-
auth: {
|
|
117
|
-
me: auth_me__me.route({ path: '/auth/me', method: 'GET' }),
|
|
118
|
-
signin: auth_signin__signin.route({ path: '/auth/signin', method: 'POST' }),
|
|
119
|
-
signup: auth_signup__signup.route({ path: '/auth/signup', method: 'POST' })
|
|
120
|
-
},
|
|
121
|
-
planets: {
|
|
122
|
-
create: planets_create__createPlanet.route({ path: '/planets/create', method: 'POST' }),
|
|
123
|
-
index: planets_index__indexRoute.route({ path: '/planets', method: 'GET' }),
|
|
124
|
-
list: planets_list__listPlanets.route({ path: '/planets/list', method: 'GET' }),
|
|
125
|
-
find: planets_id_find__findPlanet.route({ path: '/planets/{id}/find', method: 'GET' }),
|
|
126
|
-
update: planets_id_update__updatePlanet.route({ path: '/planets/{id}/update', method: 'PUT' })
|
|
127
|
-
},
|
|
128
|
-
sse: sse__sse.route({ path: '/sse', method: 'GET' })
|
|
129
|
-
}
|
|
69
|
+
## 🔒 Enhanced Type-Safe Client Configuration
|
|
130
70
|
|
|
71
|
+
After generating your router (as shown in step 4 above), you can use it in your client:
|
|
131
72
|
|
|
73
|
+
```typescript
|
|
132
74
|
// lib/orpc.ts
|
|
75
|
+
import { router } from "../router.js"; // Use the same generated router
|
|
133
76
|
const client: RouterClient<typeof router> = createORPCClient(link)
|
|
134
|
-
|
|
135
77
|
```
|
|
136
78
|
|
|
79
|
+
|
|
137
80
|
## 🛠 Configuration Options
|
|
138
81
|
|
|
139
82
|
When using `generateRouter`, you can provide additional options to customize the output:
|
|
@@ -141,7 +84,6 @@ When using `generateRouter`, you can provide additional options to customize the
|
|
|
141
84
|
| Field | Type | Required | Default Value | Description |
|
|
142
85
|
|-------------------|----------|--------------|-----------------------|------------------------------------------------------------------------------------------------------------------------------|
|
|
143
86
|
| `importExtension` | string | false | `""`(No extension) | File extension to append to import statements in the generated router. Useful when your build setup requires specific extensions. <br>Example: `.js` → `import { me } from "./routes/auth/me.js"` |
|
|
144
|
-
| `enableOpenAPI` | boolean | false | `true` | When set to true, each route will be wrapped with OpenAPI .route({ path: '...', method: '...' }) call |
|
|
145
87
|
| `additionalMethods` | string[] | false | `[]` | Additional HTTP methods to recognize from export names. |
|
|
146
88
|
|
|
147
89
|
|
package/dist/index.cjs
CHANGED
|
@@ -46,15 +46,6 @@ function walkTree(directory, tree = []) {
|
|
|
46
46
|
function mergePaths(...paths) {
|
|
47
47
|
return `/${paths.map((path2) => path2.replace(/^\/|\/$/g, "")).filter((path2) => path2 !== "").join("/")}`;
|
|
48
48
|
}
|
|
49
|
-
async function createRouter(routesDir) {
|
|
50
|
-
const files = walkTree(
|
|
51
|
-
routesDir
|
|
52
|
-
);
|
|
53
|
-
const exports = await generateRoutes(files);
|
|
54
|
-
return buildRouter(exports, (r, e) => {
|
|
55
|
-
return r.exports[e].route({ path: `${r.path}` });
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
49
|
const lazy = (create) => {
|
|
59
50
|
let cache = null;
|
|
60
51
|
const fn = () => {
|
|
@@ -68,6 +59,10 @@ const lazy = (create) => {
|
|
|
68
59
|
};
|
|
69
60
|
return fn;
|
|
70
61
|
};
|
|
62
|
+
async function createRouter(routesDir) {
|
|
63
|
+
const msg = "createRouter is deprecated. Please use generateRouter to generate router file at build time. See https://github.com/zeeeeby/orpc-file-based-router?tab=readme-ov-file#quickstart for more details.";
|
|
64
|
+
throw new Error(msg);
|
|
65
|
+
}
|
|
71
66
|
async function generateRouter(routesDir, outputFile, options) {
|
|
72
67
|
const files = walkTree(
|
|
73
68
|
routesDir
|
|
@@ -76,13 +71,10 @@ async function generateRouter(routesDir, outputFile, options) {
|
|
|
76
71
|
const importPaths = exports.map((x) => path.relative(path.dirname(outputFile), routesDir).concat(x.path));
|
|
77
72
|
const content = buildRouter(exports, (r, e) => {
|
|
78
73
|
const alias = routePathToAlias(r.path, e);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return `${alias}.route({ path: '${config.path}', method: '${config.method}' })`;
|
|
84
|
-
}
|
|
85
|
-
return alias;
|
|
74
|
+
const orpcMeta = isORPCProcedure(r.exports[e]) ? r.exports[e]["~orpc"] : void 0;
|
|
75
|
+
const method = isMethodExport(e, options?.additionalMethods || []) ? getMethodKey(e) : orpcMeta?.route?.method || "POST";
|
|
76
|
+
const config = { path: r.path.replace(/\/{0,1}index$/, ""), method };
|
|
77
|
+
return `${alias}.route({ path: '${config.path}', method: '${config.method}' })`;
|
|
86
78
|
});
|
|
87
79
|
let routerContent = `// This file is auto-generated
|
|
88
80
|
|
|
@@ -155,13 +147,24 @@ async function generateRoutes(files) {
|
|
|
155
147
|
const parsedFile = path__default.parse(file.rel);
|
|
156
148
|
const routePath = buildRoutePath(parsedFile);
|
|
157
149
|
const exports = await import(MODULE_IMPORT_PREFIX + path__default.join(file.path, file.name));
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
150
|
+
const cleanedExports = removeNonOrpcExports(exports);
|
|
151
|
+
if (Object.keys(cleanedExports).length > 0)
|
|
152
|
+
routes.push({
|
|
153
|
+
exports: cleanedExports,
|
|
154
|
+
path: routePath
|
|
155
|
+
});
|
|
162
156
|
}
|
|
163
157
|
return routes;
|
|
164
158
|
}
|
|
159
|
+
const removeNonOrpcExports = (exports) => {
|
|
160
|
+
const cleanedExports = {};
|
|
161
|
+
for (const key in exports) {
|
|
162
|
+
if (isORPCProcedure(exports[key])) {
|
|
163
|
+
cleanedExports[key] = exports[key];
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return cleanedExports;
|
|
167
|
+
};
|
|
165
168
|
|
|
166
169
|
exports.createRouter = createRouter;
|
|
167
170
|
exports.generateRouter = generateRouter;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
declare function createRouter(routesDir: string): Promise<Router>;
|
|
2
1
|
declare const lazy: <T>(create: () => Promise<T> | T) => {
|
|
3
2
|
(): Promise<T>;
|
|
4
3
|
reset(): void;
|
|
5
4
|
};
|
|
5
|
+
/**
|
|
6
|
+
* @deprecated use generateRouter instead. See https://github.com/zeeeeby/orpc-file-based-router?tab=readme-ov-file#quickstart for more details.
|
|
7
|
+
*/
|
|
8
|
+
declare function createRouter(routesDir: string): Promise<void>;
|
|
6
9
|
type GeneratorOptions = {
|
|
7
10
|
/**
|
|
8
11
|
* File extension to append to import statements in the generated router.
|
|
@@ -11,17 +14,11 @@ type GeneratorOptions = {
|
|
|
11
14
|
* @default "" (no extension)
|
|
12
15
|
*/
|
|
13
16
|
importExtension?: string;
|
|
14
|
-
/**
|
|
15
|
-
* When set to true, each route will be wrapped with OpenAPI .route({ path: '...', method: '...' }) call
|
|
16
|
-
* @default true
|
|
17
|
-
*/
|
|
18
|
-
enableOpenAPI?: boolean;
|
|
19
17
|
/**
|
|
20
18
|
* Additional HTTP methods to recognize from export names.
|
|
21
19
|
*/
|
|
22
20
|
additionalMethods?: string[];
|
|
23
21
|
};
|
|
24
22
|
declare function generateRouter(routesDir: string, outputFile: string, options?: GeneratorOptions): Promise<void>;
|
|
25
|
-
type Router = Record<string, any>;
|
|
26
23
|
|
|
27
24
|
export { createRouter, generateRouter, lazy };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
declare function createRouter(routesDir: string): Promise<Router>;
|
|
2
1
|
declare const lazy: <T>(create: () => Promise<T> | T) => {
|
|
3
2
|
(): Promise<T>;
|
|
4
3
|
reset(): void;
|
|
5
4
|
};
|
|
5
|
+
/**
|
|
6
|
+
* @deprecated use generateRouter instead. See https://github.com/zeeeeby/orpc-file-based-router?tab=readme-ov-file#quickstart for more details.
|
|
7
|
+
*/
|
|
8
|
+
declare function createRouter(routesDir: string): Promise<void>;
|
|
6
9
|
type GeneratorOptions = {
|
|
7
10
|
/**
|
|
8
11
|
* File extension to append to import statements in the generated router.
|
|
@@ -11,17 +14,11 @@ type GeneratorOptions = {
|
|
|
11
14
|
* @default "" (no extension)
|
|
12
15
|
*/
|
|
13
16
|
importExtension?: string;
|
|
14
|
-
/**
|
|
15
|
-
* When set to true, each route will be wrapped with OpenAPI .route({ path: '...', method: '...' }) call
|
|
16
|
-
* @default true
|
|
17
|
-
*/
|
|
18
|
-
enableOpenAPI?: boolean;
|
|
19
17
|
/**
|
|
20
18
|
* Additional HTTP methods to recognize from export names.
|
|
21
19
|
*/
|
|
22
20
|
additionalMethods?: string[];
|
|
23
21
|
};
|
|
24
22
|
declare function generateRouter(routesDir: string, outputFile: string, options?: GeneratorOptions): Promise<void>;
|
|
25
|
-
type Router = Record<string, any>;
|
|
26
23
|
|
|
27
24
|
export { createRouter, generateRouter, lazy };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
declare function createRouter(routesDir: string): Promise<Router>;
|
|
2
1
|
declare const lazy: <T>(create: () => Promise<T> | T) => {
|
|
3
2
|
(): Promise<T>;
|
|
4
3
|
reset(): void;
|
|
5
4
|
};
|
|
5
|
+
/**
|
|
6
|
+
* @deprecated use generateRouter instead. See https://github.com/zeeeeby/orpc-file-based-router?tab=readme-ov-file#quickstart for more details.
|
|
7
|
+
*/
|
|
8
|
+
declare function createRouter(routesDir: string): Promise<void>;
|
|
6
9
|
type GeneratorOptions = {
|
|
7
10
|
/**
|
|
8
11
|
* File extension to append to import statements in the generated router.
|
|
@@ -11,17 +14,11 @@ type GeneratorOptions = {
|
|
|
11
14
|
* @default "" (no extension)
|
|
12
15
|
*/
|
|
13
16
|
importExtension?: string;
|
|
14
|
-
/**
|
|
15
|
-
* When set to true, each route will be wrapped with OpenAPI .route({ path: '...', method: '...' }) call
|
|
16
|
-
* @default true
|
|
17
|
-
*/
|
|
18
|
-
enableOpenAPI?: boolean;
|
|
19
17
|
/**
|
|
20
18
|
* Additional HTTP methods to recognize from export names.
|
|
21
19
|
*/
|
|
22
20
|
additionalMethods?: string[];
|
|
23
21
|
};
|
|
24
22
|
declare function generateRouter(routesDir: string, outputFile: string, options?: GeneratorOptions): Promise<void>;
|
|
25
|
-
type Router = Record<string, any>;
|
|
26
23
|
|
|
27
24
|
export { createRouter, generateRouter, lazy };
|
package/dist/index.mjs
CHANGED
|
@@ -40,15 +40,6 @@ function walkTree(directory, tree = []) {
|
|
|
40
40
|
function mergePaths(...paths) {
|
|
41
41
|
return `/${paths.map((path2) => path2.replace(/^\/|\/$/g, "")).filter((path2) => path2 !== "").join("/")}`;
|
|
42
42
|
}
|
|
43
|
-
async function createRouter(routesDir) {
|
|
44
|
-
const files = walkTree(
|
|
45
|
-
routesDir
|
|
46
|
-
);
|
|
47
|
-
const exports = await generateRoutes(files);
|
|
48
|
-
return buildRouter(exports, (r, e) => {
|
|
49
|
-
return r.exports[e].route({ path: `${r.path}` });
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
43
|
const lazy = (create) => {
|
|
53
44
|
let cache = null;
|
|
54
45
|
const fn = () => {
|
|
@@ -62,6 +53,10 @@ const lazy = (create) => {
|
|
|
62
53
|
};
|
|
63
54
|
return fn;
|
|
64
55
|
};
|
|
56
|
+
async function createRouter(routesDir) {
|
|
57
|
+
const msg = "createRouter is deprecated. Please use generateRouter to generate router file at build time. See https://github.com/zeeeeby/orpc-file-based-router?tab=readme-ov-file#quickstart for more details.";
|
|
58
|
+
throw new Error(msg);
|
|
59
|
+
}
|
|
65
60
|
async function generateRouter(routesDir, outputFile, options) {
|
|
66
61
|
const files = walkTree(
|
|
67
62
|
routesDir
|
|
@@ -70,13 +65,10 @@ async function generateRouter(routesDir, outputFile, options) {
|
|
|
70
65
|
const importPaths = exports.map((x) => relative(dirname(outputFile), routesDir).concat(x.path));
|
|
71
66
|
const content = buildRouter(exports, (r, e) => {
|
|
72
67
|
const alias = routePathToAlias(r.path, e);
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return `${alias}.route({ path: '${config.path}', method: '${config.method}' })`;
|
|
78
|
-
}
|
|
79
|
-
return alias;
|
|
68
|
+
const orpcMeta = isORPCProcedure(r.exports[e]) ? r.exports[e]["~orpc"] : void 0;
|
|
69
|
+
const method = isMethodExport(e, options?.additionalMethods || []) ? getMethodKey(e) : orpcMeta?.route?.method || "POST";
|
|
70
|
+
const config = { path: r.path.replace(/\/{0,1}index$/, ""), method };
|
|
71
|
+
return `${alias}.route({ path: '${config.path}', method: '${config.method}' })`;
|
|
80
72
|
});
|
|
81
73
|
let routerContent = `// This file is auto-generated
|
|
82
74
|
|
|
@@ -149,12 +141,23 @@ async function generateRoutes(files) {
|
|
|
149
141
|
const parsedFile = path.parse(file.rel);
|
|
150
142
|
const routePath = buildRoutePath(parsedFile);
|
|
151
143
|
const exports = await import(MODULE_IMPORT_PREFIX + path.join(file.path, file.name));
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
144
|
+
const cleanedExports = removeNonOrpcExports(exports);
|
|
145
|
+
if (Object.keys(cleanedExports).length > 0)
|
|
146
|
+
routes.push({
|
|
147
|
+
exports: cleanedExports,
|
|
148
|
+
path: routePath
|
|
149
|
+
});
|
|
156
150
|
}
|
|
157
151
|
return routes;
|
|
158
152
|
}
|
|
153
|
+
const removeNonOrpcExports = (exports) => {
|
|
154
|
+
const cleanedExports = {};
|
|
155
|
+
for (const key in exports) {
|
|
156
|
+
if (isORPCProcedure(exports[key])) {
|
|
157
|
+
cleanedExports[key] = exports[key];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return cleanedExports;
|
|
161
|
+
};
|
|
159
162
|
|
|
160
163
|
export { createRouter, generateRouter, lazy };
|
package/package.json
CHANGED