@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 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 nameParts = rpcName.split(".").map(
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 nameParts = rpcName.split(".").map(
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
- if (!responseValidator?.validate(response)) {
355
- const errors = schema.a.errors(procedure.response, response);
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, schema$1, validator) {
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) => schema.a.safeCoerce(schema$1, 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.error.errors) {
415
- const errPath = err.instancePath.split("/");
416
- errPath.shift();
417
- const propName = errPath.join(".");
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.error
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.safeParse(body);
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: `Invalid request body. Affected properties [${errorParts.join(
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
- try {
466
- if (schema.isAdaptedSchema(schema$1)) {
467
- return schema.validatorFromAdaptedSchema(schema$1);
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.serializer(item)
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.validationErrors(item);
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.serializer(data)
541
+ data: this.validator.serialize(data).value
547
542
  });
548
543
  return { success: true };
549
544
  }
550
- const errors = this.validationErrors(data);
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?.validate ?? function() {
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.safeCoerce(route.query, query);
660
+ const parsedQuery = schema.a.coerce(route.query, query);
678
661
  if (!parsedQuery.success) {
679
662
  const errParts = [];
680
- for (const err of parsedQuery.error.errors) {
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.safeParse(route.body, body);
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: `Invalid request body. Affected properties [${errorParts.join(
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, WsRpcDefinition, RpcHttpMethod, HttpRpcDefinition, SchemaFormProperties, SchemaFormDiscriminator, SchemaFormValues, AppDefinition } from '@arrirpc/codegen-utils';
2
- import { AObjectSchema, a, ValidationError, ASchema, InferType, ValueError, CompiledValidator, ADiscriminatorSchema } from '@arrirpc/schema';
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: ValidationError['errors'], prefixText?: string): H3Error;
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<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined | never = undefined>(config: Omit<EventStreamRpc<TParams, TResponse>, 'isEventStream' | 'transport'>): EventStreamRpc<TParams, TResponse>;
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: (input: unknown) => input is TData;
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 validationErrors;
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
- interface NamedWebsocketRpc<TParams extends RpcParamSchema | undefined = undefined, TResponse extends RpcParamSchema | undefined = undefined> extends WebsocketRpc<TParams, TResponse> {
146
- name: string;
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> | WebsocketRpc<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> | WebsocketRpc<any, any>): string | undefined;
234
- declare function getRpcResponseName(rpcName: string, procedure: HttpRpc<any, any, any> | WebsocketRpc<any, any>): string | undefined;
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, schema: ASchema, validator: ReturnType<typeof a.compile>): Promise<void>;
237
- declare function getSchemaValidator(rpcName: string, type: 'params' | 'response', schema: ASchema<any>): ReturnType<typeof a.compile> | undefined;
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(): (NamedWebsocketRpc<any, any> | NamedHttpRpc<any, any, any>)[];
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> | WebsocketRpc<any, any>>): ArriService;
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 NamedWebsocketRpc, type PostRouteEvent, type RequestHookContext, type RequestHookEvent, 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, type WebSocketRpcHandler, type WebsocketRpc, WsPeer, type WsPeerContext, arriError, arriErrorResponse, createAppDefinition, createHttpRpcDefinition, createWsRpcDefinition, defineError, defineEventStreamRpc, defineMiddleware, defineRoute, defineRpc, defineService, defineWebsocketRpc, errorResponseFromValidationErrors, getRpcParamName, getRpcPath, getRpcResponseName, getSchemaValidator, handleH3Error, handleRoute, isEventStreamRpc, isRpc, isRpcParamSchema, registerEventStreamRpc, registerRoute, registerRpc, registerWebsocketRpc, validateRpcRequestInput };
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 };