@lowerdeck/rpc-server 1.0.0 → 1.0.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/.turbo/turbo-build.log +16 -9
- package/CHANGELOG.md +16 -0
- package/README.md +48 -0
- package/package.json +3 -3
- package/src/rpcMux.ts +48 -26
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
|
|
2
2
|
[0m[2m[35m$[0m [2m[1mmicrobundle[0m
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
No name was provided for external module '@lowerdeck/error' in output.globals – guessing 'error'
|
|
4
|
+
No name was provided for external module '@lowerdeck/execution-context' in output.globals – guessing 'executionContext'
|
|
5
|
+
No name was provided for external module '@lowerdeck/id' in output.globals – guessing 'id'
|
|
6
|
+
No name was provided for external module '@lowerdeck/memo' in output.globals – guessing 'memo'
|
|
7
|
+
No name was provided for external module '@lowerdeck/sentry' in output.globals – guessing 'sentry'
|
|
8
|
+
No name was provided for external module '@lowerdeck/serialize' in output.globals – guessing 'serialize'
|
|
9
|
+
No name was provided for external module '@lowerdeck/validation' in output.globals – guessing 'validation$1'
|
|
10
|
+
[34mBuild "@lowerdeck/rpc-server" to dist:[39m
|
|
11
|
+
[32m4.14 kB[39m: [37mindex.cjs[39m.gz
|
|
12
|
+
[32m3.72 kB[39m: [37mindex.cjs[39m.br
|
|
13
|
+
[32m2.8 kB[39m: [37mindex.module.js[39m.gz
|
|
14
|
+
[32m2.51 kB[39m: [37mindex.module.js[39m.br
|
|
15
|
+
[32m4.06 kB[39m: [37mindex.module.js[39m.gz
|
|
16
|
+
[32m3.65 kB[39m: [37mindex.module.js[39m.br
|
|
17
|
+
[32m4.24 kB[39m: [37mindex.umd.js[39m.gz
|
|
18
|
+
[32m3.83 kB[39m: [37mindex.umd.js[39m.br
|
package/CHANGELOG.md
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# `@lowerdeck/rpc-server`
|
|
2
|
+
|
|
3
|
+
Type-safe RPC server for handling remote procedure calls. Provides automatic validation, error handling, execution context tracking, and Sentry integration.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @lowerdeck/rpc-server
|
|
9
|
+
yarn add @lowerdeck/rpc-server
|
|
10
|
+
bun add @lowerdeck/rpc-server
|
|
11
|
+
pnpm add @lowerdeck/rpc-server
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { createRpcServer } from '@lowerdeck/rpc-server';
|
|
18
|
+
|
|
19
|
+
// Define your API implementation
|
|
20
|
+
const api = {
|
|
21
|
+
getUser: async (id: string) => {
|
|
22
|
+
return { name: 'John Doe', email: 'john@example.com' };
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
createPost: async (data: { title: string; content: string }) => {
|
|
26
|
+
return { id: 'post_123' };
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Create the RPC server
|
|
31
|
+
const server = createRpcServer({
|
|
32
|
+
controllers: { api },
|
|
33
|
+
context: async (req) => ({
|
|
34
|
+
userId: req.headers.get('user-id')
|
|
35
|
+
})
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Use with your HTTP framework
|
|
39
|
+
app.post('/rpc', server.handler);
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## License
|
|
43
|
+
|
|
44
|
+
This project is licensed under the Apache License 2.0.
|
|
45
|
+
|
|
46
|
+
<div align="center">
|
|
47
|
+
<sub>Built with ❤️ by <a href="https://metorial.com">Metorial</a></sub>
|
|
48
|
+
</div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lowerdeck/rpc-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@lowerdeck/error": "^1.0.5",
|
|
34
|
-
"@lowerdeck/execution-context": "^1.0.
|
|
34
|
+
"@lowerdeck/execution-context": "^1.0.1",
|
|
35
35
|
"@lowerdeck/id": "^1.0.2",
|
|
36
36
|
"@lowerdeck/memo": "^1.0.1",
|
|
37
|
-
"@lowerdeck/sentry": "^1.0.
|
|
37
|
+
"@lowerdeck/sentry": "^1.0.1",
|
|
38
38
|
"@lowerdeck/serialize": "^1.0.1",
|
|
39
39
|
"@lowerdeck/validation": "^1.0.1",
|
|
40
40
|
"cookie": "^1.1.1"
|
package/src/rpcMux.ts
CHANGED
|
@@ -207,19 +207,6 @@ export let rpcMux = (
|
|
|
207
207
|
contentType: 'application/json'
|
|
208
208
|
});
|
|
209
209
|
|
|
210
|
-
let valRes = validation.validate(body);
|
|
211
|
-
if (!valRes.success) {
|
|
212
|
-
return new Response(
|
|
213
|
-
JSON.stringify(
|
|
214
|
-
validationError({
|
|
215
|
-
errors: valRes.errors,
|
|
216
|
-
entity: 'request_data'
|
|
217
|
-
}).toResponse()
|
|
218
|
-
),
|
|
219
|
-
{ status: 406, headers }
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
210
|
return provideExecutionContext(
|
|
224
211
|
createExecutionContext({
|
|
225
212
|
type: 'request',
|
|
@@ -233,8 +220,20 @@ export let rpcMux = (
|
|
|
233
220
|
{ id: string; name: string; payload: any }[]
|
|
234
221
|
>();
|
|
235
222
|
|
|
236
|
-
|
|
237
|
-
|
|
223
|
+
let resRef = {
|
|
224
|
+
body: {
|
|
225
|
+
__typename: 'rpc.response',
|
|
226
|
+
calls: [] as any[]
|
|
227
|
+
},
|
|
228
|
+
status: 200
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
let pathParts = url.pathname.split('/').filter(Boolean);
|
|
232
|
+
let lastPart = pathParts[pathParts.length - 1];
|
|
233
|
+
|
|
234
|
+
if (lastPart[0] == '$') {
|
|
235
|
+
let id = lastPart.slice(1);
|
|
236
|
+
let rpcIndex = handlerNameToRpcMap.get(id);
|
|
238
237
|
if (rpcIndex == undefined) {
|
|
239
238
|
return new Response(
|
|
240
239
|
JSON.stringify(
|
|
@@ -245,19 +244,42 @@ export let rpcMux = (
|
|
|
245
244
|
}
|
|
246
245
|
|
|
247
246
|
let calls = callsByRpc.get(rpcIndex) ?? [];
|
|
248
|
-
calls.push(
|
|
247
|
+
calls.push({
|
|
248
|
+
id: generateCustomId('call_'),
|
|
249
|
+
name: id,
|
|
250
|
+
payload: body
|
|
251
|
+
});
|
|
249
252
|
callsByRpc.set(rpcIndex, calls);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
+
} else {
|
|
254
|
+
let valRes = validation.validate(body);
|
|
255
|
+
if (!valRes.success) {
|
|
256
|
+
return new Response(
|
|
257
|
+
JSON.stringify(
|
|
258
|
+
validationError({
|
|
259
|
+
errors: valRes.errors,
|
|
260
|
+
entity: 'request_data'
|
|
261
|
+
}).toResponse()
|
|
262
|
+
),
|
|
263
|
+
{ status: 406, headers }
|
|
264
|
+
);
|
|
265
|
+
}
|
|
253
266
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
267
|
+
for (let call of valRes.value.calls) {
|
|
268
|
+
let rpcIndex = handlerNameToRpcMap.get(call.name);
|
|
269
|
+
if (rpcIndex == undefined) {
|
|
270
|
+
return new Response(
|
|
271
|
+
JSON.stringify(
|
|
272
|
+
notFoundError({ entity: 'handler' }).toResponse()
|
|
273
|
+
),
|
|
274
|
+
{ status: 404, headers }
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
let calls = callsByRpc.get(rpcIndex) ?? [];
|
|
279
|
+
calls.push(call as any);
|
|
280
|
+
callsByRpc.set(rpcIndex, calls);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
261
283
|
|
|
262
284
|
await Promise.all(
|
|
263
285
|
Array.from(callsByRpc.entries()).map(async ([rpcIndex, calls]) => {
|