@arrirpc/server 0.72.0 → 0.74.0
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 +1 -66
- package/dist/index.cjs +56 -173
- package/dist/index.d.cts +26 -80
- package/dist/index.d.mts +26 -80
- package/dist/index.d.ts +26 -80
- package/dist/index.mjs +58 -172
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -15,10 +15,9 @@ Parameters and responses are defined using [@arrirpc/schema](/languages/ts/ts-sc
|
|
|
15
15
|
- [File-Based Routing](#file-based-routing)
|
|
16
16
|
- [Manual Routing](#manual-routing)
|
|
17
17
|
- [Creating Event Stream Procedures](#creating-event-stream-procedures)
|
|
18
|
-
- [Creating Websocket Procedures](#creating-websocket-procedures-experimental)
|
|
19
|
-
- [Adding to the RPC Context](#adding-to-the-rpc-context)
|
|
20
18
|
- [Adding Non-RPC Routes](#adding-non-rpc-routes)
|
|
21
19
|
- [Adding Middleware](#adding-middleware)
|
|
20
|
+
- [Adding to the RPC Context](#adding-to-the-rpc-context)
|
|
22
21
|
- [Key Concepts](#key-concepts)
|
|
23
22
|
- [Arri Definition File](#arri-definition-file)
|
|
24
23
|
- [How Procedures Map To Endpoints](#how-procedures-map-to-endpoints)
|
|
@@ -291,70 +290,6 @@ stream.close()
|
|
|
291
290
|
stream.onClosed(cb: () => any)
|
|
292
291
|
```
|
|
293
292
|
|
|
294
|
-
### Creating Websocket Procedures (Experimental
|
|
295
|
-
|
|
296
|
-
Very experimental. Do not use in production.
|
|
297
|
-
|
|
298
|
-
```ts
|
|
299
|
-
// Websocket procedures work really well with discriminated unions
|
|
300
|
-
const IncomingMsg = a.discriminator('type', {
|
|
301
|
-
FOO: a.object({
|
|
302
|
-
message: a.string(),
|
|
303
|
-
}),
|
|
304
|
-
PING: a.object({
|
|
305
|
-
message: a.string(),
|
|
306
|
-
})
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
const OutgoingMsg = a.discriminator('type', {
|
|
310
|
-
BAR: a.object({
|
|
311
|
-
message: a.string(),
|
|
312
|
-
}),
|
|
313
|
-
PONG: a.object({
|
|
314
|
-
message: a.string()
|
|
315
|
-
})
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
export default defineWebsocketRpc(
|
|
319
|
-
params: IncomingMsg,
|
|
320
|
-
response: OutgoingMsg,
|
|
321
|
-
handler: {
|
|
322
|
-
onOpen: (peer) => {},
|
|
323
|
-
onMessage: (peer, message) => {
|
|
324
|
-
switch(message.type) {
|
|
325
|
-
case "FOO":
|
|
326
|
-
peer.send({
|
|
327
|
-
type: "BAR",
|
|
328
|
-
message: "You sent a FOO message"
|
|
329
|
-
});
|
|
330
|
-
break;
|
|
331
|
-
case "PING":
|
|
332
|
-
peer.send({
|
|
333
|
-
type: "PONG",
|
|
334
|
-
message: "You sent a PING message"
|
|
335
|
-
});
|
|
336
|
-
break;
|
|
337
|
-
}
|
|
338
|
-
},
|
|
339
|
-
onError: (peer, error) => {}
|
|
340
|
-
}
|
|
341
|
-
)
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
Under the hood Websocket RPCs use [crossws](https://crossws.unjs.io/).
|
|
345
|
-
|
|
346
|
-
The possible payloads sent by the server will look like the following:
|
|
347
|
-
|
|
348
|
-
```
|
|
349
|
-
event: message
|
|
350
|
-
data: <response serialized to json>
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
```
|
|
354
|
-
event: error
|
|
355
|
-
data: {"code": <some-err-code>, "message": <some-error-msg>}
|
|
356
|
-
```
|
|
357
|
-
|
|
358
293
|
### Adding Non-RPC Routes
|
|
359
294
|
|
|
360
295
|
You can also add generic endpoints for instances when a message-based RPC endpoint doesn't fit.
|
package/dist/index.cjs
CHANGED
|
@@ -290,20 +290,14 @@ function getRpcParamName(rpcName, procedure) {
|
|
|
290
290
|
if (!isRpcParamSchema(procedure.params)) {
|
|
291
291
|
return undefined;
|
|
292
292
|
}
|
|
293
|
-
const
|
|
294
|
-
(part) => codegenUtils.removeDisallowedChars(part, `!@#$%^&*()+=[]{}|\\;:'"<>,./?`)
|
|
295
|
-
);
|
|
296
|
-
const paramName = procedure.params.metadata.id ?? scule.pascalCase(`${nameParts.join(`_`)}_params`);
|
|
293
|
+
const paramName = getSchemaName(rpcName, "params", procedure.params);
|
|
297
294
|
return paramName;
|
|
298
295
|
}
|
|
299
296
|
function getRpcResponseName(rpcName, procedure) {
|
|
300
297
|
if (!isRpcParamSchema(procedure.response)) {
|
|
301
298
|
return undefined;
|
|
302
299
|
}
|
|
303
|
-
const
|
|
304
|
-
(part) => codegenUtils.removeDisallowedChars(part, `!@#$%^&*()+=[]{}|\\;:'"<>,./?`)
|
|
305
|
-
);
|
|
306
|
-
const responseName = procedure.response.metadata.id ?? scule.pascalCase(`${nameParts.join("_")}_response`);
|
|
300
|
+
const responseName = getSchemaName(rpcName, "response", procedure.response);
|
|
307
301
|
return responseName;
|
|
308
302
|
}
|
|
309
303
|
function getRpcResponseDefinition(rpcName, procedure) {
|
|
@@ -338,7 +332,6 @@ function registerRpc(router, path, procedure, opts) {
|
|
|
338
332
|
await validateRpcRequestInput(
|
|
339
333
|
event,
|
|
340
334
|
httpMethod,
|
|
341
|
-
procedure.params,
|
|
342
335
|
paramValidator
|
|
343
336
|
);
|
|
344
337
|
}
|
|
@@ -351,18 +344,15 @@ function registerRpc(router, path, procedure, opts) {
|
|
|
351
344
|
await opts.onBeforeResponse(event);
|
|
352
345
|
}
|
|
353
346
|
if (typeof response === "object") {
|
|
354
|
-
|
|
355
|
-
|
|
347
|
+
const payload = responseValidator?.serialize(response);
|
|
348
|
+
if (payload && payload.success !== true) {
|
|
356
349
|
throw defineError(500, {
|
|
357
350
|
message: "Failed to serialize response. Response does not match specified schema",
|
|
358
|
-
data: errors
|
|
351
|
+
data: payload?.errors
|
|
359
352
|
});
|
|
360
353
|
}
|
|
361
354
|
h3.setResponseHeader(event, "Content-Type", "application/json");
|
|
362
|
-
await h3.send(
|
|
363
|
-
event,
|
|
364
|
-
responseValidator?.serialize(response) ?? JSON.stringify(response)
|
|
365
|
-
);
|
|
355
|
+
await h3.send(event, payload?.value ?? JSON.stringify(response));
|
|
366
356
|
} else {
|
|
367
357
|
h3.setResponseHeader(event, "Content-Type", "application/json");
|
|
368
358
|
await h3.send(event, `{}`);
|
|
@@ -400,22 +390,22 @@ function registerRpc(router, path, procedure, opts) {
|
|
|
400
390
|
break;
|
|
401
391
|
}
|
|
402
392
|
}
|
|
403
|
-
async function validateRpcRequestInput(event, httpMethod,
|
|
393
|
+
async function validateRpcRequestInput(event, httpMethod, validator) {
|
|
404
394
|
switch (httpMethod) {
|
|
405
395
|
case "get": {
|
|
406
396
|
const parsedParams = await h3.getValidatedQuery(
|
|
407
397
|
event,
|
|
408
|
-
(input) =>
|
|
398
|
+
(input) => validator.coerce(input)
|
|
409
399
|
);
|
|
410
400
|
if (parsedParams.success) {
|
|
411
401
|
event.context.params = parsedParams.value;
|
|
412
402
|
} else {
|
|
413
403
|
const errParts = [];
|
|
414
|
-
for (const err of parsedParams.
|
|
415
|
-
const errPath = err.instancePath
|
|
416
|
-
errPath
|
|
417
|
-
const propName = errPath
|
|
418
|
-
if (!errParts.includes(propName)) {
|
|
404
|
+
for (const err of parsedParams.errors) {
|
|
405
|
+
const errPath = err.instancePath?.split("/");
|
|
406
|
+
errPath?.shift();
|
|
407
|
+
const propName = errPath?.join(".");
|
|
408
|
+
if (propName && !errParts.includes(propName)) {
|
|
419
409
|
errParts.push(propName);
|
|
420
410
|
}
|
|
421
411
|
}
|
|
@@ -424,7 +414,7 @@ async function validateRpcRequestInput(event, httpMethod, schema$1, validator) {
|
|
|
424
414
|
)}]`;
|
|
425
415
|
throw defineError(400, {
|
|
426
416
|
message,
|
|
427
|
-
data: parsedParams.
|
|
417
|
+
data: parsedParams.errors
|
|
428
418
|
});
|
|
429
419
|
}
|
|
430
420
|
break;
|
|
@@ -439,21 +429,11 @@ async function validateRpcRequestInput(event, httpMethod, schema$1, validator) {
|
|
|
439
429
|
message: `Invalid request body. Expected object. Got undefined.`
|
|
440
430
|
});
|
|
441
431
|
}
|
|
442
|
-
const parsedParams = validator.
|
|
432
|
+
const parsedParams = validator.parse(body);
|
|
443
433
|
if (!parsedParams?.success) {
|
|
444
|
-
const errorParts = [];
|
|
445
|
-
for (const err of parsedParams.error.errors) {
|
|
446
|
-
const errPath = err.instancePath.split("/");
|
|
447
|
-
errPath.shift();
|
|
448
|
-
if (!errorParts.includes(errPath.join("."))) {
|
|
449
|
-
errorParts.push(errPath.join("."));
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
434
|
throw defineError(400, {
|
|
453
|
-
message:
|
|
454
|
-
|
|
455
|
-
)}]`,
|
|
456
|
-
data: parsedParams.error
|
|
435
|
+
message: schema.errorMessageFromErrors(parsedParams.errors),
|
|
436
|
+
data: parsedParams.errors
|
|
457
437
|
});
|
|
458
438
|
}
|
|
459
439
|
event.context.params = parsedParams.value;
|
|
@@ -462,15 +442,31 @@ async function validateRpcRequestInput(event, httpMethod, schema$1, validator) {
|
|
|
462
442
|
}
|
|
463
443
|
}
|
|
464
444
|
function getSchemaValidator(rpcName, type, schema$1) {
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
445
|
+
if (schema.isASchema(schema$1)) {
|
|
446
|
+
try {
|
|
447
|
+
const validator = schema.a.compile(schema$1);
|
|
448
|
+
return {
|
|
449
|
+
validate: validator.validate,
|
|
450
|
+
serialize: validator.serialize,
|
|
451
|
+
parse: validator.parse,
|
|
452
|
+
coerce: validator.coerce,
|
|
453
|
+
errors: (input) => schema.a.errors(schema$1, input)
|
|
454
|
+
};
|
|
455
|
+
} catch (err) {
|
|
456
|
+
console.error(
|
|
457
|
+
`Error compiling ${type} validator for ${rpcName}. Error: ${err}`
|
|
458
|
+
);
|
|
468
459
|
}
|
|
469
|
-
return schema.a.compile(schema$1);
|
|
470
|
-
} catch (_) {
|
|
471
|
-
console.error(`Error compiling ${type} validator for ${rpcName}`);
|
|
472
|
-
return undefined;
|
|
473
460
|
}
|
|
461
|
+
return undefined;
|
|
462
|
+
}
|
|
463
|
+
function getSchemaName(rpcName, type, schema) {
|
|
464
|
+
const cleanedName = rpcName.split(".").map(
|
|
465
|
+
(part) => codegenUtils.removeDisallowedChars(part, `!@#$%^&*()+=[]{}|\\;:'"<>,./?`)
|
|
466
|
+
).join("_");
|
|
467
|
+
return schema.metadata?.id ?? scule.pascalCase(`${cleanedName}_${type}`, {
|
|
468
|
+
normalize: true
|
|
469
|
+
});
|
|
474
470
|
}
|
|
475
471
|
|
|
476
472
|
function defineEventStreamRpc(config) {
|
|
@@ -486,9 +482,7 @@ function isEventStreamRpc(input) {
|
|
|
486
482
|
}
|
|
487
483
|
class EventStreamConnection {
|
|
488
484
|
lastEventId;
|
|
489
|
-
validationErrors;
|
|
490
485
|
validator;
|
|
491
|
-
serializer;
|
|
492
486
|
// for some reason Rollup cannot output DTS when this is set to NodeJS.Timeout
|
|
493
487
|
pingInterval = undefined;
|
|
494
488
|
pingIntervalMs;
|
|
@@ -497,9 +491,7 @@ class EventStreamConnection {
|
|
|
497
491
|
this.eventStream = h3.createEventStream(event);
|
|
498
492
|
this.lastEventId = h3.getHeader(event, "Last-Event-Id");
|
|
499
493
|
this.pingIntervalMs = opts.pingInterval ?? 6e4;
|
|
500
|
-
this.serializer = opts.serializer;
|
|
501
494
|
this.validator = opts.validator;
|
|
502
|
-
this.validationErrors = opts.validationErrors;
|
|
503
495
|
this.eventStream.onClosed(() => {
|
|
504
496
|
this.cleanup();
|
|
505
497
|
});
|
|
@@ -517,20 +509,23 @@ class EventStreamConnection {
|
|
|
517
509
|
}, this.pingIntervalMs);
|
|
518
510
|
}
|
|
519
511
|
async push(data, eventId) {
|
|
512
|
+
if (!this.validator) return;
|
|
520
513
|
if (Array.isArray(data)) {
|
|
521
514
|
const results = [];
|
|
522
515
|
const events = [];
|
|
523
516
|
for (const item of data) {
|
|
524
|
-
if (this.validator(item)) {
|
|
517
|
+
if (this.validator.validate(item)) {
|
|
525
518
|
events.push({
|
|
526
519
|
id: eventId,
|
|
527
520
|
event: "message",
|
|
528
|
-
data: this.
|
|
521
|
+
data: this.validator.serialize(
|
|
522
|
+
item
|
|
523
|
+
).value
|
|
529
524
|
});
|
|
530
525
|
results.push({ success: true });
|
|
531
526
|
continue;
|
|
532
527
|
}
|
|
533
|
-
const errors2 = this.
|
|
528
|
+
const errors2 = this.validator.errors(item);
|
|
534
529
|
results.push({
|
|
535
530
|
success: false,
|
|
536
531
|
errors: errors2
|
|
@@ -539,15 +534,15 @@ class EventStreamConnection {
|
|
|
539
534
|
await this.eventStream.push(events);
|
|
540
535
|
return results;
|
|
541
536
|
}
|
|
542
|
-
if (this.validator(data)) {
|
|
537
|
+
if (this.validator.validate(data)) {
|
|
543
538
|
await this.eventStream.push({
|
|
544
539
|
id: eventId,
|
|
545
540
|
event: "message",
|
|
546
|
-
data: this.
|
|
541
|
+
data: this.validator.serialize(data).value
|
|
547
542
|
});
|
|
548
543
|
return { success: true };
|
|
549
544
|
}
|
|
550
|
-
const errors = this.
|
|
545
|
+
const errors = this.validator.errors(data);
|
|
551
546
|
return {
|
|
552
547
|
success: false,
|
|
553
548
|
errors
|
|
@@ -594,24 +589,12 @@ function registerEventStreamRpc(router, path, procedure, opts) {
|
|
|
594
589
|
await validateRpcRequestInput(
|
|
595
590
|
event,
|
|
596
591
|
httpMethod,
|
|
597
|
-
procedure.params,
|
|
598
592
|
paramValidator
|
|
599
593
|
);
|
|
600
594
|
}
|
|
601
595
|
const stream = new EventStreamConnection(event, {
|
|
602
596
|
pingInterval: procedure.pingInterval,
|
|
603
|
-
validator: responseValidator
|
|
604
|
-
return true;
|
|
605
|
-
},
|
|
606
|
-
serializer: responseValidator?.serialize ?? function(_) {
|
|
607
|
-
return "";
|
|
608
|
-
},
|
|
609
|
-
validationErrors(input) {
|
|
610
|
-
if (procedure.response) {
|
|
611
|
-
return schema.a.errors(procedure.response, input);
|
|
612
|
-
}
|
|
613
|
-
return [];
|
|
614
|
-
}
|
|
597
|
+
validator: responseValidator
|
|
615
598
|
});
|
|
616
599
|
event.context.stream = stream;
|
|
617
600
|
await procedure.handler(
|
|
@@ -674,10 +657,10 @@ function handleRoute(router, method, route, opts) {
|
|
|
674
657
|
}
|
|
675
658
|
if (route.query) {
|
|
676
659
|
const query = h3.getQuery(event);
|
|
677
|
-
const parsedQuery = schema.a.
|
|
660
|
+
const parsedQuery = schema.a.coerce(route.query, query);
|
|
678
661
|
if (!parsedQuery.success) {
|
|
679
662
|
const errParts = [];
|
|
680
|
-
for (const err of parsedQuery.
|
|
663
|
+
for (const err of parsedQuery.errors) {
|
|
681
664
|
const errPath = err.instancePath.split("/");
|
|
682
665
|
errPath.shift();
|
|
683
666
|
const propName = errPath.join(".");
|
|
@@ -702,21 +685,11 @@ function handleRoute(router, method, route, opts) {
|
|
|
702
685
|
];
|
|
703
686
|
if (route.body && !notAllowedBodyMethods.includes(event.method)) {
|
|
704
687
|
const body = await h3.readRawBody(event);
|
|
705
|
-
const parsedBody = schema.a.
|
|
688
|
+
const parsedBody = schema.a.parse(route.body, body);
|
|
706
689
|
if (!parsedBody.success) {
|
|
707
|
-
const errorParts = [];
|
|
708
|
-
for (const err of parsedBody.error.errors) {
|
|
709
|
-
const errPath = err.instancePath.split("/");
|
|
710
|
-
errPath.shift();
|
|
711
|
-
if (!errorParts.includes(errPath.join("."))) {
|
|
712
|
-
errorParts.push(errPath.join("."));
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
690
|
throw defineError(400, {
|
|
716
|
-
message:
|
|
717
|
-
|
|
718
|
-
)}]`,
|
|
719
|
-
data: parsedBody.error
|
|
691
|
+
message: schema.errorMessageFromErrors(parsedBody.errors),
|
|
692
|
+
data: parsedBody.errors
|
|
720
693
|
});
|
|
721
694
|
}
|
|
722
695
|
event.context.body = parsedBody.value;
|
|
@@ -822,88 +795,6 @@ function defineService(name, procedures) {
|
|
|
822
795
|
return service;
|
|
823
796
|
}
|
|
824
797
|
|
|
825
|
-
class WsPeer {
|
|
826
|
-
_peer;
|
|
827
|
-
_validator;
|
|
828
|
-
context;
|
|
829
|
-
url;
|
|
830
|
-
constructor(peer, opts) {
|
|
831
|
-
this._peer = peer;
|
|
832
|
-
this._validator = opts.validator;
|
|
833
|
-
this.url = peer.websocket.url ?? "";
|
|
834
|
-
this.context = opts.context;
|
|
835
|
-
}
|
|
836
|
-
send(data) {
|
|
837
|
-
if (!this._validator) {
|
|
838
|
-
return;
|
|
839
|
-
}
|
|
840
|
-
if (!this._validator.validate(data)) {
|
|
841
|
-
return;
|
|
842
|
-
}
|
|
843
|
-
const payload = this._validator.serialize(data);
|
|
844
|
-
return this._peer.send(`event: message
|
|
845
|
-
data: ${payload}`);
|
|
846
|
-
}
|
|
847
|
-
sendError(err) {
|
|
848
|
-
return this._peer.send(`event: error
|
|
849
|
-
data: ${JSON.stringify(err)}`);
|
|
850
|
-
}
|
|
851
|
-
close() {
|
|
852
|
-
throw new Error("close() is not yet implemented on WsPeer");
|
|
853
|
-
}
|
|
854
|
-
subscribe(channel) {
|
|
855
|
-
this._peer.subscribe(channel);
|
|
856
|
-
}
|
|
857
|
-
unsubscribe(channel) {
|
|
858
|
-
this._peer.unsubscribe(channel);
|
|
859
|
-
}
|
|
860
|
-
publish(channel, message) {
|
|
861
|
-
if (!this._validator) {
|
|
862
|
-
return;
|
|
863
|
-
}
|
|
864
|
-
if (!this._validator.validate(message)) {
|
|
865
|
-
const err = {
|
|
866
|
-
code: 500,
|
|
867
|
-
message: `Error serializing message on server. The payload doesn't match the specified schema.`,
|
|
868
|
-
data: {
|
|
869
|
-
payload: message
|
|
870
|
-
}
|
|
871
|
-
};
|
|
872
|
-
this.sendError(err);
|
|
873
|
-
return;
|
|
874
|
-
}
|
|
875
|
-
const payload = this._validator.serialize(message);
|
|
876
|
-
this._peer.publish(channel, payload);
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
function defineWebsocketRpc(def) {
|
|
880
|
-
def.transport = "ws";
|
|
881
|
-
return def;
|
|
882
|
-
}
|
|
883
|
-
function registerWebsocketRpc(router, path, _rpc) {
|
|
884
|
-
const handler = h3.defineWebSocketHandler({
|
|
885
|
-
upgrade(_req) {
|
|
886
|
-
},
|
|
887
|
-
open(_) {
|
|
888
|
-
},
|
|
889
|
-
message(_, __) {
|
|
890
|
-
},
|
|
891
|
-
close(_, __) {
|
|
892
|
-
}
|
|
893
|
-
});
|
|
894
|
-
router.use(path, handler);
|
|
895
|
-
}
|
|
896
|
-
function createWsRpcDefinition(rpcName, path, rpc) {
|
|
897
|
-
return {
|
|
898
|
-
transport: "ws",
|
|
899
|
-
path,
|
|
900
|
-
params: getRpcParamName(rpcName, rpc),
|
|
901
|
-
response: getRpcResponseName(rpcName, rpc),
|
|
902
|
-
isDeprecated: rpc.isDeprecated,
|
|
903
|
-
description: rpc.description
|
|
904
|
-
};
|
|
905
|
-
}
|
|
906
|
-
|
|
907
798
|
const createAppDefinition = (def) => def;
|
|
908
799
|
class ArriApp {
|
|
909
800
|
__isArri__ = true;
|
|
@@ -1014,8 +905,6 @@ class ArriApp {
|
|
|
1014
905
|
const path = p.path ?? getRpcPath(p.name, this._rpcRoutePrefix);
|
|
1015
906
|
if (p.transport === "http") {
|
|
1016
907
|
this._procedures[p.name] = createHttpRpcDefinition(p.name, path, p);
|
|
1017
|
-
} else if (p.transport === "ws") {
|
|
1018
|
-
this._procedures[p.name] = createWsRpcDefinition(p.name, path, p);
|
|
1019
908
|
}
|
|
1020
909
|
if (isRpcParamSchema(p.params)) {
|
|
1021
910
|
const paramName = getRpcParamName(p.name, p);
|
|
@@ -1051,9 +940,6 @@ class ArriApp {
|
|
|
1051
940
|
});
|
|
1052
941
|
return;
|
|
1053
942
|
}
|
|
1054
|
-
if (p.transport === "ws") {
|
|
1055
|
-
registerWebsocketRpc(this.h3Router, path);
|
|
1056
|
-
}
|
|
1057
943
|
}
|
|
1058
944
|
route(route) {
|
|
1059
945
|
registerRoute(this.h3Router, route, {
|
|
@@ -1091,23 +977,21 @@ exports.ArriApp = ArriApp;
|
|
|
1091
977
|
exports.ArriRouter = ArriRouter;
|
|
1092
978
|
exports.ArriService = ArriService;
|
|
1093
979
|
exports.EventStreamConnection = EventStreamConnection;
|
|
1094
|
-
exports.WsPeer = WsPeer;
|
|
1095
980
|
exports.arriError = arriError;
|
|
1096
981
|
exports.arriErrorResponse = arriErrorResponse;
|
|
1097
982
|
exports.createAppDefinition = createAppDefinition;
|
|
1098
983
|
exports.createHttpRpcDefinition = createHttpRpcDefinition;
|
|
1099
|
-
exports.createWsRpcDefinition = createWsRpcDefinition;
|
|
1100
984
|
exports.defineError = defineError;
|
|
1101
985
|
exports.defineEventStreamRpc = defineEventStreamRpc;
|
|
1102
986
|
exports.defineMiddleware = defineMiddleware;
|
|
1103
987
|
exports.defineRoute = defineRoute;
|
|
1104
988
|
exports.defineRpc = defineRpc;
|
|
1105
989
|
exports.defineService = defineService;
|
|
1106
|
-
exports.defineWebsocketRpc = defineWebsocketRpc;
|
|
1107
990
|
exports.errorResponseFromValidationErrors = errorResponseFromValidationErrors;
|
|
1108
991
|
exports.getRpcParamName = getRpcParamName;
|
|
1109
992
|
exports.getRpcPath = getRpcPath;
|
|
1110
993
|
exports.getRpcResponseName = getRpcResponseName;
|
|
994
|
+
exports.getSchemaName = getSchemaName;
|
|
1111
995
|
exports.getSchemaValidator = getSchemaValidator;
|
|
1112
996
|
exports.handleH3Error = handleH3Error;
|
|
1113
997
|
exports.handleRoute = handleRoute;
|
|
@@ -1117,7 +1001,6 @@ exports.isRpcParamSchema = isRpcParamSchema;
|
|
|
1117
1001
|
exports.registerEventStreamRpc = registerEventStreamRpc;
|
|
1118
1002
|
exports.registerRoute = registerRoute;
|
|
1119
1003
|
exports.registerRpc = registerRpc;
|
|
1120
|
-
exports.registerWebsocketRpc = registerWebsocketRpc;
|
|
1121
1004
|
exports.validateRpcRequestInput = validateRpcRequestInput;
|
|
1122
1005
|
Object.prototype.hasOwnProperty.call(h3, '__proto__') &&
|
|
1123
1006
|
!Object.prototype.hasOwnProperty.call(exports, '__proto__') &&
|
package/dist/index.d.cts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { HttpMethod,
|
|
2
|
-
import { AObjectSchema, a,
|
|
1
|
+
import { HttpMethod, RpcHttpMethod, HttpRpcDefinition, SchemaFormProperties, SchemaFormDiscriminator, SchemaFormValues, AppDefinition } from '@arrirpc/codegen-utils';
|
|
2
|
+
import { AObjectSchema, a, ValueError, ASchema, InferType, ADiscriminatorSchema, Result } from '@arrirpc/schema';
|
|
3
3
|
import { H3Event, StatusCode, H3Error, Router, EventStream, App } from 'h3';
|
|
4
4
|
export * from 'h3';
|
|
5
|
-
import { Peer, WSError } from 'crossws';
|
|
6
5
|
|
|
7
6
|
interface MiddlewareEvent extends H3Event {
|
|
8
7
|
context: MiddlewareEventContext;
|
|
@@ -56,7 +55,7 @@ declare const arriErrorResponse: AObjectSchema<{
|
|
|
56
55
|
}>;
|
|
57
56
|
type arriErrorResponse = a.infer<typeof arriErrorResponse>;
|
|
58
57
|
declare function defineError(statusCode: StatusCode, input?: Partial<Omit<arriErrorResponse, 'code' | 'stack'>>): arriError;
|
|
59
|
-
declare function errorResponseFromValidationErrors(errors:
|
|
58
|
+
declare function errorResponseFromValidationErrors(errors: ValueError[], prefixText?: string): H3Error;
|
|
60
59
|
declare function handleH3Error(err: unknown, event: H3Event, onError: ArriOptions['onError'], debug: boolean): Promise<void>;
|
|
61
60
|
|
|
62
61
|
interface RouteEvent<TPath extends string, TQuery extends Record<any, any> = any, TBody = any> extends H3Event {
|
|
@@ -91,7 +90,7 @@ declare class ArriRouter {
|
|
|
91
90
|
getDefinitions(): DefinitionMap;
|
|
92
91
|
}
|
|
93
92
|
|
|
94
|
-
declare function defineEventStreamRpc<
|
|
93
|
+
declare function defineEventStreamRpc<TResponse extends RpcParamSchema<any>, TParams extends RpcParamSchema<any> | undefined = undefined>(config: Omit<EventStreamRpc<TParams, TResponse>, 'isEventStream' | 'transport'>): EventStreamRpc<TParams, TResponse>;
|
|
95
94
|
declare function isEventStreamRpc(input: unknown): input is EventStreamRpc<any, any>;
|
|
96
95
|
interface EventStreamRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> extends Omit<HttpRpc<true, TParams, TResponse>, 'handler' | 'postHandler'> {
|
|
97
96
|
isEventStream: true;
|
|
@@ -102,16 +101,12 @@ interface EventStreamRpcHandlerContext<TParams = any, TResponse = any> extends R
|
|
|
102
101
|
stream: EventStreamConnection<TResponse>;
|
|
103
102
|
}
|
|
104
103
|
interface EventStreamConnectionOptions<TData> {
|
|
105
|
-
validator
|
|
106
|
-
validationErrors: (input: unknown) => ValueError[];
|
|
107
|
-
serializer: (input: TData) => string;
|
|
104
|
+
validator?: RequestValidator<TData>;
|
|
108
105
|
pingInterval?: number;
|
|
109
106
|
}
|
|
110
107
|
declare class EventStreamConnection<TData> {
|
|
111
108
|
readonly lastEventId?: string;
|
|
112
|
-
private readonly
|
|
113
|
-
private readonly validator;
|
|
114
|
-
private readonly serializer;
|
|
109
|
+
private readonly validator?;
|
|
115
110
|
private pingInterval;
|
|
116
111
|
private readonly pingIntervalMs;
|
|
117
112
|
readonly eventStream: EventStream;
|
|
@@ -142,69 +137,12 @@ declare function registerEventStreamRpc(router: Router, path: string, procedure:
|
|
|
142
137
|
name: string;
|
|
143
138
|
}, opts: RouteOptions): void;
|
|
144
139
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
interface WebsocketRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> {
|
|
149
|
-
transport: 'ws';
|
|
150
|
-
description?: string;
|
|
151
|
-
path?: string;
|
|
152
|
-
isDeprecated?: boolean;
|
|
153
|
-
params: TParams;
|
|
154
|
-
response: TResponse;
|
|
155
|
-
pingInterval?: boolean;
|
|
156
|
-
handler: WebSocketRpcHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : undefined> | (() => WebSocketRpcHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : undefined>);
|
|
157
|
-
}
|
|
158
|
-
interface WsPeerOpts<TResponse> {
|
|
159
|
-
validator?: CompiledValidator<ASchema<TResponse>>;
|
|
160
|
-
context: WsPeerContext;
|
|
161
|
-
}
|
|
162
|
-
interface WsPeerContext extends Record<string, any> {
|
|
163
|
-
rpcName: string;
|
|
164
|
-
queryParams?: Record<string, string>;
|
|
165
|
-
clientAddress?: string;
|
|
166
|
-
}
|
|
167
|
-
declare class WsPeer<TResponse> {
|
|
168
|
-
private readonly _peer;
|
|
169
|
-
private readonly _validator?;
|
|
170
|
-
context: WsPeerContext;
|
|
171
|
-
url: string;
|
|
172
|
-
constructor(peer: Peer, opts: WsPeerOpts<TResponse>);
|
|
173
|
-
send(data: TResponse): number | void;
|
|
174
|
-
sendError(err: arriErrorResponse): number | void | undefined;
|
|
175
|
-
close(): void;
|
|
176
|
-
subscribe(channel: string): void;
|
|
177
|
-
unsubscribe(channel: string): void;
|
|
178
|
-
publish(channel: string, message: TResponse): void;
|
|
179
|
-
}
|
|
180
|
-
interface WebSocketRpcHandler<TParams, TResponse> {
|
|
181
|
-
onOpen: (peer: WsPeer<TResponse>) => void;
|
|
182
|
-
onMessage: (peer: WsPeer<TResponse>, message: TParams) => void;
|
|
183
|
-
onClose: (peer: WsPeer<TResponse>, details: {
|
|
184
|
-
code?: number;
|
|
185
|
-
reason?: string;
|
|
186
|
-
}) => void;
|
|
187
|
-
onError: (peer: WsPeer<TResponse>, error: WSError) => void;
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* @experimental
|
|
191
|
-
*/
|
|
192
|
-
declare function defineWebsocketRpc<TParams extends RpcParamSchema | undefined, TResponse extends RpcParamSchema | undefined>(def: Omit<WebsocketRpc<TParams, TResponse>, 'transport'>): WebsocketRpc<TParams, TResponse>;
|
|
193
|
-
/**
|
|
194
|
-
* @experimental
|
|
195
|
-
*/
|
|
196
|
-
declare function registerWebsocketRpc(router: Router, path: string, _rpc: NamedWebsocketRpc<any, any>): void;
|
|
197
|
-
/**
|
|
198
|
-
* @experimental
|
|
199
|
-
*/
|
|
200
|
-
declare function createWsRpcDefinition(rpcName: string, path: string, rpc: NamedWebsocketRpc<any, any>): WsRpcDefinition;
|
|
201
|
-
|
|
202
|
-
type RpcParamSchema<TObjectInner = any, TDiscriminatorInner = any> = AObjectSchema<TObjectInner> | ADiscriminatorSchema<TDiscriminatorInner>;
|
|
203
|
-
declare function isRpcParamSchema(input: unknown): input is RpcParamSchema;
|
|
140
|
+
type RpcParamSchema<T = any> = AObjectSchema<T> | ADiscriminatorSchema<T>;
|
|
141
|
+
declare function isRpcParamSchema(input: unknown): input is RpcParamSchema<any>;
|
|
204
142
|
interface NamedHttpRpc<TIsEventStream extends boolean = false, TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> extends HttpRpc<TIsEventStream, TParams, TResponse> {
|
|
205
143
|
name: string;
|
|
206
144
|
}
|
|
207
|
-
type Rpc<TIsEventStream extends boolean = false, TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> = HttpRpc<TIsEventStream, TParams, TResponse
|
|
145
|
+
type Rpc<TIsEventStream extends boolean = false, TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> = HttpRpc<TIsEventStream, TParams, TResponse>;
|
|
208
146
|
interface HttpRpc<TIsEventStream extends boolean = false, TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> {
|
|
209
147
|
transport: 'http';
|
|
210
148
|
method?: RpcHttpMethod;
|
|
@@ -215,8 +153,8 @@ interface HttpRpc<TIsEventStream extends boolean = false, TParams extends RpcPar
|
|
|
215
153
|
isDeprecated?: boolean;
|
|
216
154
|
isEventStream?: TIsEventStream;
|
|
217
155
|
pingInterval?: TIsEventStream extends true ? number : undefined;
|
|
218
|
-
handler: TIsEventStream extends true ? EventStreamRpcHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : undefined> : RpcHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : void>;
|
|
219
|
-
postHandler?: TIsEventStream extends true ? undefined : RpcPostHandler<TParams extends RpcParamSchema ? InferType<TParams> : undefined, TResponse extends RpcParamSchema ? InferType<TResponse> : undefined>;
|
|
156
|
+
handler: TIsEventStream extends true ? EventStreamRpcHandler<TParams extends RpcParamSchema<any> ? InferType<TParams> : undefined, TResponse extends RpcParamSchema<any> ? InferType<TResponse> : undefined> : RpcHandler<TParams extends RpcParamSchema<any> ? InferType<TParams> : undefined, TResponse extends RpcParamSchema<any> ? InferType<TResponse> : void>;
|
|
157
|
+
postHandler?: TIsEventStream extends true ? undefined : RpcPostHandler<TParams extends RpcParamSchema<any> ? InferType<TParams> : undefined, TResponse extends RpcParamSchema<any> ? InferType<TResponse> : undefined>;
|
|
220
158
|
}
|
|
221
159
|
interface RpcEvent<TParams = undefined> extends Omit<H3Event, 'context'> {
|
|
222
160
|
context: RpcEventContext<TParams>;
|
|
@@ -230,11 +168,19 @@ declare function isRpc(input: unknown): input is HttpRpc<any, any>;
|
|
|
230
168
|
declare function defineRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined | never = undefined>(config: Omit<HttpRpc<false, TParams, TResponse>, 'transport' | 'isEventStream'>): HttpRpc<false, TParams, TResponse>;
|
|
231
169
|
declare function createHttpRpcDefinition(rpcName: string, httpPath: string, procedure: HttpRpc<any, any, any>): HttpRpcDefinition;
|
|
232
170
|
declare function getRpcPath(rpcName: string, prefix?: string): string;
|
|
233
|
-
declare function getRpcParamName(rpcName: string, procedure: HttpRpc<any, any, any>
|
|
234
|
-
declare function getRpcResponseName(rpcName: string, procedure: HttpRpc<any, any, any>
|
|
171
|
+
declare function getRpcParamName(rpcName: string, procedure: HttpRpc<any, any, any>): string | undefined;
|
|
172
|
+
declare function getRpcResponseName(rpcName: string, procedure: HttpRpc<any, any, any>): string | undefined;
|
|
235
173
|
declare function registerRpc(router: Router, path: string, procedure: NamedHttpRpc<any, any, any>, opts: RouteOptions): void;
|
|
236
|
-
declare function validateRpcRequestInput(event: H3Event, httpMethod: RpcHttpMethod,
|
|
237
|
-
|
|
174
|
+
declare function validateRpcRequestInput(event: H3Event, httpMethod: RpcHttpMethod, validator: RequestValidator): Promise<void>;
|
|
175
|
+
type RequestValidator<T = any> = {
|
|
176
|
+
validate: (input: unknown) => input is T;
|
|
177
|
+
errors: (input: unknown) => ValueError[];
|
|
178
|
+
coerce: (input: unknown) => Result<T>;
|
|
179
|
+
parse: (input: unknown) => Result<T>;
|
|
180
|
+
serialize: (input: any) => Result<string>;
|
|
181
|
+
};
|
|
182
|
+
declare function getSchemaValidator<T extends Record<string, any> = any>(rpcName: string, type: 'params' | 'response', schema: RpcParamSchema<T>): RequestValidator<T> | undefined;
|
|
183
|
+
declare function getSchemaName(rpcName: string, type: 'params' | 'response', schema: RpcParamSchema<any>): string;
|
|
238
184
|
|
|
239
185
|
declare class ArriService {
|
|
240
186
|
name: string;
|
|
@@ -243,10 +189,10 @@ declare class ArriService {
|
|
|
243
189
|
private readonly definitions;
|
|
244
190
|
rpc(name: string, procedure: Rpc<any, any, any>): void;
|
|
245
191
|
registerDefinitions(models: DefinitionMap): void;
|
|
246
|
-
getProcedures():
|
|
192
|
+
getProcedures(): NamedHttpRpc<any, any, any>[];
|
|
247
193
|
getDefinitions(): DefinitionMap;
|
|
248
194
|
}
|
|
249
|
-
declare function defineService(name: string, procedures?: Record<string, HttpRpc<any, any, any
|
|
195
|
+
declare function defineService(name: string, procedures?: Record<string, HttpRpc<any, any, any>>): ArriService;
|
|
250
196
|
|
|
251
197
|
type DefinitionMap = Record<string, SchemaFormProperties | SchemaFormDiscriminator | SchemaFormValues>;
|
|
252
198
|
declare const createAppDefinition: (def: AppDefinition) => AppDefinition;
|
|
@@ -298,4 +244,4 @@ interface RequestHookEvent extends Omit<H3Event, 'context'> {
|
|
|
298
244
|
context: RequestHookContext;
|
|
299
245
|
}
|
|
300
246
|
|
|
301
|
-
export { ArriApp, type ArriEventContext, type ArriOptions, type ArriRoute, ArriRouter, ArriService, type DefinitionMap, EventStreamConnection, type EventStreamConnectionOptions, type EventStreamRpc, type EventStreamRpcHandler, type EventStreamRpcHandlerContext, type ExtractParam, type ExtractParams, type HttpRpc, type Middleware, type MiddlewareEvent, type MiddlewareEventContext, type NamedHttpRpc, type
|
|
247
|
+
export { ArriApp, type ArriEventContext, type ArriOptions, type ArriRoute, ArriRouter, ArriService, type DefinitionMap, EventStreamConnection, type EventStreamConnectionOptions, type EventStreamRpc, type EventStreamRpcHandler, type EventStreamRpcHandlerContext, type ExtractParam, type ExtractParams, type HttpRpc, type Middleware, type MiddlewareEvent, type MiddlewareEventContext, type NamedHttpRpc, type PostRouteEvent, type RequestHookContext, type RequestHookEvent, type RequestValidator, type RouteEvent, type RouteEventContext, type RouteOptions, type RoutePostEventContext, type Rpc, type RpcEvent, type RpcEventContext, type RpcHandler, type RpcParamSchema, type RpcPostEvent, type RpcPostEventContext, type RpcPostHandler, type SsePushResult, arriError, arriErrorResponse, createAppDefinition, createHttpRpcDefinition, defineError, defineEventStreamRpc, defineMiddleware, defineRoute, defineRpc, defineService, errorResponseFromValidationErrors, getRpcParamName, getRpcPath, getRpcResponseName, getSchemaName, getSchemaValidator, handleH3Error, handleRoute, isEventStreamRpc, isRpc, isRpcParamSchema, registerEventStreamRpc, registerRoute, registerRpc, validateRpcRequestInput };
|