orpc-file-based-router 0.1.0 → 0.1.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.
- package/README.md +46 -22
- package/dist/index.cjs +13 -1
- package/dist/index.d.cts +10 -1
- package/dist/index.d.mts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.mjs +13 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# orpc-file-based-router
|
|
2
2
|
|
|
3
|
-
A plugin for [oRPC](https://orpc.unnoq.com) that automatically
|
|
4
|
-
structure,
|
|
3
|
+
A plugin for [oRPC](https://orpc.unnoq.com) that automatically generates an oRPC router configuration based on your file
|
|
4
|
+
structure, inspired by Next.js and express-file-routing approaches.
|
|
5
5
|
|
|
6
|
-
## Highlights
|
|
6
|
+
## ✨ Highlights
|
|
7
7
|
|
|
8
|
-
- 📁 **File-based
|
|
9
|
-
- 🔄 **Zero
|
|
10
|
-
- ⚡️ **Development
|
|
11
|
-
- 🔍 **Dynamic
|
|
12
|
-
- 📑 **Index
|
|
8
|
+
- 📁 **File-based Structure**: Organize your API endpoints intuitively through your filesystem
|
|
9
|
+
- 🔄 **Zero Configuration**: Generate routes automatically based on your directory structure
|
|
10
|
+
- ⚡️ **Development Speed**: Eliminate boilerplate code and reduce maintenance overhead
|
|
11
|
+
- 🔍 **Dynamic Routing**: Support for path parameters using `{param}` syntax in file names
|
|
12
|
+
- 📑 **Index Routes**: Support for index routes via `index.ts` files
|
|
13
13
|
|
|
14
14
|
> ⚠️ **IMPORTANT:** At this time, the plugin's functionality is only guaranteed
|
|
15
15
|
> in nodejs runtime
|
|
@@ -62,21 +62,35 @@ const router = await createRouter(routesDir);
|
|
|
62
62
|
const handler = new RPCHandler(router);
|
|
63
63
|
|
|
64
64
|
```
|
|
65
|
-
> **Note:** If your environment doesn't support top-level await,
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
> startServer();
|
|
73
|
-
> ```
|
|
65
|
+
> **Note:** If your environment doesn't support top-level await, just use `cachedRouter` for example in expressjs it could be:
|
|
66
|
+
```typescript
|
|
67
|
+
import { RPCHandler } from "@orpc/server/node";
|
|
68
|
+
import { cachedRouter } from "orpc-file-based-router";
|
|
69
|
+
|
|
70
|
+
const routesDir = new URL("./routes", import.meta.url).pathname;
|
|
71
|
+
const router = cachedRouter(routesDir)
|
|
74
72
|
|
|
75
|
-
|
|
73
|
+
app.use('/rpc{/*path}', async (req, res, next) => {
|
|
76
74
|
|
|
77
|
-
|
|
75
|
+
const handler = new RPCHandler(await router.getRouter());
|
|
76
|
+
|
|
77
|
+
const { matched } = await handler.handle(req, res, {
|
|
78
|
+
prefix: '/rpc',
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
if (matched) {
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
next()
|
|
86
|
+
})
|
|
87
|
+
```
|
|
78
88
|
|
|
79
|
-
|
|
89
|
+
## 🔒 Type-Safe Client Configuration (Optional)
|
|
90
|
+
|
|
91
|
+
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.
|
|
92
|
+
|
|
93
|
+
1. Add the following code to your main server file (e.g., `server.ts` or `main.ts`). This will automatically regenerate the router configuration each time your server starts:
|
|
80
94
|
|
|
81
95
|
```typescript
|
|
82
96
|
import { generateRouter } from "orpc-file-based-router";
|
|
@@ -121,6 +135,16 @@ const client: RouterClient<typeof router> = createORPCClient(link)
|
|
|
121
135
|
|
|
122
136
|
```
|
|
123
137
|
|
|
124
|
-
##
|
|
138
|
+
## 🛠 Configuration Options
|
|
139
|
+
|
|
140
|
+
When using `generateRouter`, you can provide additional options to customize the output:
|
|
141
|
+
|
|
142
|
+
| Field | Type | Required | Default Value | Description |
|
|
143
|
+
|-------------------|----------|--------------|-----------------------|------------------------------------------------------------------------------------------------------------------------------|
|
|
144
|
+
| `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"` |
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
## 📄 License
|
|
125
149
|
|
|
126
|
-
MIT
|
|
150
|
+
MIT License - feel free to use this in your own projects!
|
package/dist/index.cjs
CHANGED
|
@@ -36,6 +36,17 @@ async function createRouter(routesDir) {
|
|
|
36
36
|
return r.exports[e].route({ path: `${r.path}` });
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
|
+
async function cachedRouter(routesDir) {
|
|
40
|
+
let router = null;
|
|
41
|
+
return {
|
|
42
|
+
getRouter: async () => {
|
|
43
|
+
if (!router) {
|
|
44
|
+
router = await createRouter(routesDir);
|
|
45
|
+
}
|
|
46
|
+
return router;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
39
50
|
async function generateRouter(routesDir, outputFile, options) {
|
|
40
51
|
const files = walkTree(
|
|
41
52
|
routesDir
|
|
@@ -43,7 +54,7 @@ async function generateRouter(routesDir, outputFile, options) {
|
|
|
43
54
|
const exports = await generateRoutes(files);
|
|
44
55
|
const importPaths = exports.map((x) => path.relative(path.dirname(outputFile), routesDir).concat(x.path));
|
|
45
56
|
const content = buildRouter(exports, (r, e) => {
|
|
46
|
-
return `${e}.route({ path: '${r.path}' })`;
|
|
57
|
+
return `${e}.route({ path: '${r.path.replace(/\/{0,1}index$/, "")}' })`;
|
|
47
58
|
});
|
|
48
59
|
let routerContent = `// This file is auto-generated
|
|
49
60
|
|
|
@@ -120,5 +131,6 @@ async function generateRoutes(files) {
|
|
|
120
131
|
return routes;
|
|
121
132
|
}
|
|
122
133
|
|
|
134
|
+
exports.cachedRouter = cachedRouter;
|
|
123
135
|
exports.createRouter = createRouter;
|
|
124
136
|
exports.generateRouter = generateRouter;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
declare function createRouter(routesDir: string): Promise<Router>;
|
|
2
|
+
declare function cachedRouter(routesDir: string): Promise<{
|
|
3
|
+
getRouter: () => Promise<Router>;
|
|
4
|
+
}>;
|
|
2
5
|
type GeneratorOptions = {
|
|
6
|
+
/**
|
|
7
|
+
* File extension to append to import statements in the generated router.
|
|
8
|
+
* Useful when your build setup requires specific extensions.
|
|
9
|
+
* @example ".js" will generate imports like: import { me } from "./routes/auth/me.js"
|
|
10
|
+
* @default "" (no extension)
|
|
11
|
+
*/
|
|
3
12
|
importExtension?: string;
|
|
4
13
|
};
|
|
5
14
|
declare function generateRouter(routesDir: string, outputFile: string, options?: GeneratorOptions): Promise<void>;
|
|
6
15
|
type Router = Record<string, any>;
|
|
7
16
|
|
|
8
|
-
export { createRouter, generateRouter };
|
|
17
|
+
export { cachedRouter, createRouter, generateRouter };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
declare function createRouter(routesDir: string): Promise<Router>;
|
|
2
|
+
declare function cachedRouter(routesDir: string): Promise<{
|
|
3
|
+
getRouter: () => Promise<Router>;
|
|
4
|
+
}>;
|
|
2
5
|
type GeneratorOptions = {
|
|
6
|
+
/**
|
|
7
|
+
* File extension to append to import statements in the generated router.
|
|
8
|
+
* Useful when your build setup requires specific extensions.
|
|
9
|
+
* @example ".js" will generate imports like: import { me } from "./routes/auth/me.js"
|
|
10
|
+
* @default "" (no extension)
|
|
11
|
+
*/
|
|
3
12
|
importExtension?: string;
|
|
4
13
|
};
|
|
5
14
|
declare function generateRouter(routesDir: string, outputFile: string, options?: GeneratorOptions): Promise<void>;
|
|
6
15
|
type Router = Record<string, any>;
|
|
7
16
|
|
|
8
|
-
export { createRouter, generateRouter };
|
|
17
|
+
export { cachedRouter, createRouter, generateRouter };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
declare function createRouter(routesDir: string): Promise<Router>;
|
|
2
|
+
declare function cachedRouter(routesDir: string): Promise<{
|
|
3
|
+
getRouter: () => Promise<Router>;
|
|
4
|
+
}>;
|
|
2
5
|
type GeneratorOptions = {
|
|
6
|
+
/**
|
|
7
|
+
* File extension to append to import statements in the generated router.
|
|
8
|
+
* Useful when your build setup requires specific extensions.
|
|
9
|
+
* @example ".js" will generate imports like: import { me } from "./routes/auth/me.js"
|
|
10
|
+
* @default "" (no extension)
|
|
11
|
+
*/
|
|
3
12
|
importExtension?: string;
|
|
4
13
|
};
|
|
5
14
|
declare function generateRouter(routesDir: string, outputFile: string, options?: GeneratorOptions): Promise<void>;
|
|
6
15
|
type Router = Record<string, any>;
|
|
7
16
|
|
|
8
|
-
export { createRouter, generateRouter };
|
|
17
|
+
export { cachedRouter, createRouter, generateRouter };
|
package/dist/index.mjs
CHANGED
|
@@ -30,6 +30,17 @@ async function createRouter(routesDir) {
|
|
|
30
30
|
return r.exports[e].route({ path: `${r.path}` });
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
|
+
async function cachedRouter(routesDir) {
|
|
34
|
+
let router = null;
|
|
35
|
+
return {
|
|
36
|
+
getRouter: async () => {
|
|
37
|
+
if (!router) {
|
|
38
|
+
router = await createRouter(routesDir);
|
|
39
|
+
}
|
|
40
|
+
return router;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
33
44
|
async function generateRouter(routesDir, outputFile, options) {
|
|
34
45
|
const files = walkTree(
|
|
35
46
|
routesDir
|
|
@@ -37,7 +48,7 @@ async function generateRouter(routesDir, outputFile, options) {
|
|
|
37
48
|
const exports = await generateRoutes(files);
|
|
38
49
|
const importPaths = exports.map((x) => relative(dirname(outputFile), routesDir).concat(x.path));
|
|
39
50
|
const content = buildRouter(exports, (r, e) => {
|
|
40
|
-
return `${e}.route({ path: '${r.path}' })`;
|
|
51
|
+
return `${e}.route({ path: '${r.path.replace(/\/{0,1}index$/, "")}' })`;
|
|
41
52
|
});
|
|
42
53
|
let routerContent = `// This file is auto-generated
|
|
43
54
|
|
|
@@ -114,4 +125,4 @@ async function generateRoutes(files) {
|
|
|
114
125
|
return routes;
|
|
115
126
|
}
|
|
116
127
|
|
|
117
|
-
export { createRouter, generateRouter };
|
|
128
|
+
export { cachedRouter, createRouter, generateRouter };
|
package/package.json
CHANGED