orpc-file-based-router 0.0.7 → 0.0.9
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 +61 -61
- package/dist/index.cjs +15 -10
- package/dist/index.d.cts +3 -2
- package/dist/index.d.mts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.mjs +15 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
# orpc-file-based-router
|
|
2
2
|
|
|
3
|
-
A plugin for [oRPC](https://orpc.unnoq.com) that automatically creates an oRPC
|
|
3
|
+
A plugin for [oRPC](https://orpc.unnoq.com) that automatically creates an oRPC
|
|
4
|
+
router configuration based on your file structure.
|
|
4
5
|
|
|
5
|
-
> ⚠️ **IMPORTANT:** At this time, the plugin's functionality is only guaranteed
|
|
6
|
+
> ⚠️ **IMPORTANT:** At this time, the plugin's functionality is only guaranteed
|
|
7
|
+
> in nodejs runtime
|
|
6
8
|
|
|
7
|
-
##
|
|
9
|
+
## Get started
|
|
10
|
+
|
|
11
|
+
1. Install package
|
|
8
12
|
|
|
9
13
|
```bash
|
|
10
14
|
npm install orpc-file-based-router
|
|
@@ -12,45 +16,9 @@ npm install orpc-file-based-router
|
|
|
12
16
|
yarn add orpc-file-based-router
|
|
13
17
|
```
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
```typescript
|
|
18
|
-
import { RPCHandler } from '@orpc/server/node'
|
|
19
|
-
import { generateRouter } from 'orpc-file-based-router'
|
|
20
|
-
|
|
21
|
-
const routesDir = new URL('./routes', import.meta.url).pathname
|
|
22
|
-
const outputFile = new URL('./router.ts', import.meta.url).pathname
|
|
23
|
-
const router = await generateRouter(routesDir, outputFile)
|
|
19
|
+
2. Create a routes directory structure (for example):
|
|
24
20
|
|
|
25
|
-
const handler = new RPCHandler(router)
|
|
26
21
|
```
|
|
27
|
-
|
|
28
|
-
Alternative approach for environments without top-level await support:
|
|
29
|
-
|
|
30
|
-
```typescript
|
|
31
|
-
import { RPCHandler } from '@orpc/server/node'
|
|
32
|
-
import { generateRouter } from 'orpc-file-based-router'
|
|
33
|
-
|
|
34
|
-
async function setupRouter() {
|
|
35
|
-
const routesDir = new URL('./routes', import.meta.url).pathname
|
|
36
|
-
const outputFile = new URL('./router.ts', import.meta.url).pathname
|
|
37
|
-
const router = await generateRouter(routesDir, outputFile)
|
|
38
|
-
|
|
39
|
-
return new RPCHandler(router)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Initialize the router
|
|
43
|
-
setupRouter().then(handler => {
|
|
44
|
-
// Your application code here
|
|
45
|
-
console.log('Router initialized and ready to use')
|
|
46
|
-
}).catch(error => {
|
|
47
|
-
console.error('Failed to initialize router:', error)
|
|
48
|
-
})
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### File Structure Example
|
|
52
|
-
|
|
53
|
-
```
|
|
54
22
|
src/routes
|
|
55
23
|
├── auth
|
|
56
24
|
│ ├── me.ts
|
|
@@ -66,37 +34,69 @@ src/routes
|
|
|
66
34
|
│ ├── index.ts
|
|
67
35
|
│ └── list.ts
|
|
68
36
|
│
|
|
69
|
-
└── sse.ts
|
|
37
|
+
└── sse.ts
|
|
70
38
|
```
|
|
71
39
|
|
|
72
|
-
|
|
40
|
+
3. Each file should export a oRPC handler function
|
|
41
|
+
|
|
42
|
+
4. Simply replace router in your handlers with the result of the `createRouter`
|
|
43
|
+
function:
|
|
73
44
|
|
|
74
45
|
```typescript
|
|
75
|
-
import {
|
|
76
|
-
import {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
46
|
+
import { RPCHandler } from "@orpc/server/node";
|
|
47
|
+
import { createRouter } from "orpc-file-based-router";
|
|
48
|
+
|
|
49
|
+
const routesDir = new URL("./routes", import.meta.url).pathname;
|
|
50
|
+
const router = await createRouter(routesDir);
|
|
51
|
+
|
|
52
|
+
const handler = new RPCHandler(router);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## How to generate configuration file
|
|
56
|
+
|
|
57
|
+
1. Call `generateRouter`
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import { generateRouter } from "orpc-file-based-router";
|
|
61
|
+
|
|
62
|
+
const routesDir = new URL("./routes", import.meta.url).pathname;
|
|
63
|
+
const outputFile = new URL("./router.ts", import.meta.url).pathname;
|
|
64
|
+
generateRouter(routesDir, outputFile);
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
2. Generated configuration is ready to use in router client:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
// router.ts
|
|
71
|
+
import { me } from "./routes/auth/me";
|
|
72
|
+
import { signin } from "./routes/auth/signin";
|
|
73
|
+
import { signup } from "./routes/auth/signup";
|
|
74
|
+
import { createPlanet } from "./routes/planets/create";
|
|
75
|
+
import { indexRoute } from "./routes/planets";
|
|
76
|
+
import { listPlanets } from "./routes/planets/list";
|
|
77
|
+
import { findPlanet } from "./routes/planets/{id}/find";
|
|
78
|
+
import { updatePlanet } from "./routes/planets/{id}/update";
|
|
79
|
+
import { sse } from "./routes/sse";
|
|
84
80
|
|
|
85
81
|
export const router = {
|
|
86
82
|
auth: {
|
|
87
|
-
me: me.route({ path:
|
|
88
|
-
signin: signin.route({ path:
|
|
89
|
-
signup: signup.route({ path:
|
|
83
|
+
me: me.route({ path: "/auth/me" }),
|
|
84
|
+
signin: signin.route({ path: "/auth/signin" }),
|
|
85
|
+
signup: signup.route({ path: "/auth/signup" }),
|
|
90
86
|
},
|
|
91
87
|
planets: {
|
|
92
|
-
create: createPlanet.route({ path:
|
|
93
|
-
indexRoute: indexRoute.route({ path:
|
|
94
|
-
list: listPlanets.route({ path:
|
|
95
|
-
find: findPlanet.route({ path:
|
|
96
|
-
update: updatePlanet.route({ path:
|
|
88
|
+
create: createPlanet.route({ path: "/planets/create" }),
|
|
89
|
+
indexRoute: indexRoute.route({ path: "/planets" }),
|
|
90
|
+
list: listPlanets.route({ path: "/planets/list" }),
|
|
91
|
+
find: findPlanet.route({ path: "/planets/{id}/find" }),
|
|
92
|
+
update: updatePlanet.route({ path: "/planets/{id}/update" }),
|
|
97
93
|
},
|
|
98
|
-
sse: sse.route({ path:
|
|
99
|
-
}
|
|
94
|
+
sse: sse.route({ path: "/sse" }),
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// lib/orpc.ts
|
|
98
|
+
const client: RouterClient<typeof router> = createORPCClient(link)
|
|
99
|
+
|
|
100
100
|
```
|
|
101
101
|
|
|
102
102
|
## License
|
package/dist/index.cjs
CHANGED
|
@@ -27,6 +27,15 @@ function walkTree(directory, tree = []) {
|
|
|
27
27
|
function mergePaths(...paths) {
|
|
28
28
|
return `/${paths.map((path2) => path2.replace(/^\/|\/$/g, "")).filter((path2) => path2 !== "").join("/")}`;
|
|
29
29
|
}
|
|
30
|
+
async function createRouter(routesDir) {
|
|
31
|
+
const files = walkTree(
|
|
32
|
+
routesDir
|
|
33
|
+
);
|
|
34
|
+
const exports = await generateRoutes(files);
|
|
35
|
+
return buildRouter(exports, (r, e) => {
|
|
36
|
+
return r.exports[e].route({ path: `${r.path}` });
|
|
37
|
+
});
|
|
38
|
+
}
|
|
30
39
|
async function generateRouter(routesDir, outputFile) {
|
|
31
40
|
const files = walkTree(
|
|
32
41
|
routesDir
|
|
@@ -43,10 +52,6 @@ async function generateRouter(routesDir, outputFile) {
|
|
|
43
52
|
routerContent += "\n\nexport const router = ";
|
|
44
53
|
routerContent += JSON.stringify(content, null, 2).replace(/"/g, "");
|
|
45
54
|
node_fs.writeFileSync(path.join(outputFile), routerContent);
|
|
46
|
-
const router = buildRouter(exports, (r, e) => {
|
|
47
|
-
return r.exports[e].route({ path: `${r.path}` });
|
|
48
|
-
});
|
|
49
|
-
return router;
|
|
50
55
|
}
|
|
51
56
|
function buildRoutePath(parsedFile) {
|
|
52
57
|
const directory = parsedFile.dir === parsedFile.root ? "" : parsedFile.dir;
|
|
@@ -78,12 +83,11 @@ function simplifyRouter(router) {
|
|
|
78
83
|
for (const key in router) {
|
|
79
84
|
if (isLeaf(router[key])) {
|
|
80
85
|
simplifiedRouter[key] = router[key];
|
|
86
|
+
} else if (hasSingleLeaf(router[key])) {
|
|
87
|
+
const childKey = Object.keys(router[key])[0];
|
|
88
|
+
simplifiedRouter[key] = router[key][childKey];
|
|
81
89
|
} else {
|
|
82
90
|
simplifiedRouter[key] = simplifyRouter(router[key]);
|
|
83
|
-
if (isSingleChild(simplifiedRouter[key])) {
|
|
84
|
-
const childKey = Object.keys(simplifiedRouter[key])[0];
|
|
85
|
-
simplifiedRouter[key] = simplifiedRouter[key][childKey];
|
|
86
|
-
}
|
|
87
91
|
}
|
|
88
92
|
}
|
|
89
93
|
return simplifiedRouter;
|
|
@@ -94,9 +98,9 @@ function isORPCProcedure(obj) {
|
|
|
94
98
|
function isLeaf(obj) {
|
|
95
99
|
return typeof obj === "string" || isORPCProcedure(obj);
|
|
96
100
|
}
|
|
97
|
-
function
|
|
101
|
+
function hasSingleLeaf(obj) {
|
|
98
102
|
const keys = Object.keys(obj);
|
|
99
|
-
return keys.length === 1;
|
|
103
|
+
return keys.length === 1 && isLeaf(obj[keys[0]]);
|
|
100
104
|
}
|
|
101
105
|
const isCjs = () => typeof module !== "undefined" && !!module?.exports;
|
|
102
106
|
const IS_ESM = !isCjs();
|
|
@@ -115,4 +119,5 @@ async function generateRoutes(files) {
|
|
|
115
119
|
return routes;
|
|
116
120
|
}
|
|
117
121
|
|
|
122
|
+
exports.createRouter = createRouter;
|
|
118
123
|
exports.generateRouter = generateRouter;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
declare function
|
|
1
|
+
declare function createRouter(routesDir: string): Promise<Router>;
|
|
2
|
+
declare function generateRouter(routesDir: string, outputFile: string): Promise<void>;
|
|
2
3
|
type Router = Record<string, any>;
|
|
3
4
|
|
|
4
|
-
export { generateRouter };
|
|
5
|
+
export { createRouter, generateRouter };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
declare function
|
|
1
|
+
declare function createRouter(routesDir: string): Promise<Router>;
|
|
2
|
+
declare function generateRouter(routesDir: string, outputFile: string): Promise<void>;
|
|
2
3
|
type Router = Record<string, any>;
|
|
3
4
|
|
|
4
|
-
export { generateRouter };
|
|
5
|
+
export { createRouter, generateRouter };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
declare function
|
|
1
|
+
declare function createRouter(routesDir: string): Promise<Router>;
|
|
2
|
+
declare function generateRouter(routesDir: string, outputFile: string): Promise<void>;
|
|
2
3
|
type Router = Record<string, any>;
|
|
3
4
|
|
|
4
|
-
export { generateRouter };
|
|
5
|
+
export { createRouter, generateRouter };
|
package/dist/index.mjs
CHANGED
|
@@ -21,6 +21,15 @@ function walkTree(directory, tree = []) {
|
|
|
21
21
|
function mergePaths(...paths) {
|
|
22
22
|
return `/${paths.map((path2) => path2.replace(/^\/|\/$/g, "")).filter((path2) => path2 !== "").join("/")}`;
|
|
23
23
|
}
|
|
24
|
+
async function createRouter(routesDir) {
|
|
25
|
+
const files = walkTree(
|
|
26
|
+
routesDir
|
|
27
|
+
);
|
|
28
|
+
const exports = await generateRoutes(files);
|
|
29
|
+
return buildRouter(exports, (r, e) => {
|
|
30
|
+
return r.exports[e].route({ path: `${r.path}` });
|
|
31
|
+
});
|
|
32
|
+
}
|
|
24
33
|
async function generateRouter(routesDir, outputFile) {
|
|
25
34
|
const files = walkTree(
|
|
26
35
|
routesDir
|
|
@@ -37,10 +46,6 @@ async function generateRouter(routesDir, outputFile) {
|
|
|
37
46
|
routerContent += "\n\nexport const router = ";
|
|
38
47
|
routerContent += JSON.stringify(content, null, 2).replace(/"/g, "");
|
|
39
48
|
writeFileSync(join(outputFile), routerContent);
|
|
40
|
-
const router = buildRouter(exports, (r, e) => {
|
|
41
|
-
return r.exports[e].route({ path: `${r.path}` });
|
|
42
|
-
});
|
|
43
|
-
return router;
|
|
44
49
|
}
|
|
45
50
|
function buildRoutePath(parsedFile) {
|
|
46
51
|
const directory = parsedFile.dir === parsedFile.root ? "" : parsedFile.dir;
|
|
@@ -72,12 +77,11 @@ function simplifyRouter(router) {
|
|
|
72
77
|
for (const key in router) {
|
|
73
78
|
if (isLeaf(router[key])) {
|
|
74
79
|
simplifiedRouter[key] = router[key];
|
|
80
|
+
} else if (hasSingleLeaf(router[key])) {
|
|
81
|
+
const childKey = Object.keys(router[key])[0];
|
|
82
|
+
simplifiedRouter[key] = router[key][childKey];
|
|
75
83
|
} else {
|
|
76
84
|
simplifiedRouter[key] = simplifyRouter(router[key]);
|
|
77
|
-
if (isSingleChild(simplifiedRouter[key])) {
|
|
78
|
-
const childKey = Object.keys(simplifiedRouter[key])[0];
|
|
79
|
-
simplifiedRouter[key] = simplifiedRouter[key][childKey];
|
|
80
|
-
}
|
|
81
85
|
}
|
|
82
86
|
}
|
|
83
87
|
return simplifiedRouter;
|
|
@@ -88,9 +92,9 @@ function isORPCProcedure(obj) {
|
|
|
88
92
|
function isLeaf(obj) {
|
|
89
93
|
return typeof obj === "string" || isORPCProcedure(obj);
|
|
90
94
|
}
|
|
91
|
-
function
|
|
95
|
+
function hasSingleLeaf(obj) {
|
|
92
96
|
const keys = Object.keys(obj);
|
|
93
|
-
return keys.length === 1;
|
|
97
|
+
return keys.length === 1 && isLeaf(obj[keys[0]]);
|
|
94
98
|
}
|
|
95
99
|
const isCjs = () => typeof module !== "undefined" && !!module?.exports;
|
|
96
100
|
const IS_ESM = !isCjs();
|
|
@@ -109,4 +113,4 @@ async function generateRoutes(files) {
|
|
|
109
113
|
return routes;
|
|
110
114
|
}
|
|
111
115
|
|
|
112
|
-
export { generateRouter };
|
|
116
|
+
export { createRouter, generateRouter };
|
package/package.json
CHANGED