arri 0.36.1 → 0.37.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.
@@ -1,21 +1,21 @@
1
1
  import { isRpcHttpMethod, removeDisallowedChars, SCHEMA_VERSION } from 'arri-codegen-utils';
2
2
  import consola from 'consola';
3
- import { isError, setResponseStatus, setResponseHeader, send, eventHandler, isPreflightRequest, readRawBody, getValidatedQuery, defineEventHandler, getQuery, setHeader, createRouter, createApp } from 'h3';
3
+ import { isError, setResponseStatus, setResponseHeader, send, eventHandler, isPreflightRequest, readRawBody, getValidatedQuery, defineEventHandler, getQuery, setHeader, defineWebSocketHandler, createRouter, createApp } from 'h3';
4
4
  import { a, isAObjectSchema, isADiscriminatorSchema } from 'arri-validate';
5
5
  import { createEventStream } from 'h3-sse';
6
6
  import { kebabCase, pascalCase } from 'scule';
7
7
 
8
- var __defProp$3 = Object.defineProperty;
9
- var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
10
- var __publicField$3 = (obj, key, value) => {
11
- __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
8
+ var __defProp$4 = Object.defineProperty;
9
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
10
+ var __publicField$4 = (obj, key, value) => {
11
+ __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
12
12
  return value;
13
13
  };
14
14
  class ArriServerError extends Error {
15
15
  constructor(err) {
16
16
  super(err.message);
17
- __publicField$3(this, "code");
18
- __publicField$3(this, "data");
17
+ __publicField$4(this, "code");
18
+ __publicField$4(this, "data");
19
19
  this.code = err.code;
20
20
  this.data = err.data;
21
21
  if (err.stack) {
@@ -261,6 +261,7 @@ function isRpc(input) {
261
261
  return typeof input === "object" && input !== null && "method" in input && isRpcHttpMethod(input.method) && "handler" in input && typeof input.handler === "function";
262
262
  }
263
263
  function defineRpc(config) {
264
+ config.transport = "http";
264
265
  return config;
265
266
  }
266
267
  function createHttpRpcDefinition(rpcName, httpPath, procedure) {
@@ -472,17 +473,18 @@ async function validateRpcRequestInput(event, httpMethod, schema) {
472
473
  }
473
474
  }
474
475
 
475
- var __defProp$2 = Object.defineProperty;
476
- var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
477
- var __publicField$2 = (obj, key, value) => {
478
- __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
476
+ var __defProp$3 = Object.defineProperty;
477
+ var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
478
+ var __publicField$3 = (obj, key, value) => {
479
+ __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
479
480
  return value;
480
481
  };
481
482
  function defineEventStreamRpc(config) {
482
483
  return {
483
484
  ...config,
484
485
  method: config.method ?? "get",
485
- isEventStream: true
486
+ isEventStream: true,
487
+ transport: "http"
486
488
  };
487
489
  }
488
490
  function isEventStreamRpc(input) {
@@ -490,14 +492,14 @@ function isEventStreamRpc(input) {
490
492
  }
491
493
  class EventStreamConnection {
492
494
  constructor(event, opts) {
493
- __publicField$2(this, "lastEventId");
494
- __publicField$2(this, "validationErrors");
495
- __publicField$2(this, "validator");
496
- __publicField$2(this, "serializer");
495
+ __publicField$3(this, "lastEventId");
496
+ __publicField$3(this, "validationErrors");
497
+ __publicField$3(this, "validator");
498
+ __publicField$3(this, "serializer");
497
499
  // for some reason Rollup cannot output DTS when this is set to NodeJS.Timeout
498
- __publicField$2(this, "pingInterval");
499
- __publicField$2(this, "pingIntervalMs");
500
- __publicField$2(this, "eventStream");
500
+ __publicField$3(this, "pingInterval");
501
+ __publicField$3(this, "pingIntervalMs");
502
+ __publicField$3(this, "eventStream");
501
503
  this.eventStream = createEventStream(event);
502
504
  this.lastEventId = this.eventStream.lastEventId;
503
505
  this.pingIntervalMs = opts.pingInterval ?? 6e4;
@@ -811,19 +813,24 @@ function handleRoute(router, method, route, opts) {
811
813
  }
812
814
  }
813
815
 
814
- var __defProp$1 = Object.defineProperty;
815
- var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
816
- var __publicField$1 = (obj, key, value) => {
817
- __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
816
+ var __defProp$2 = Object.defineProperty;
817
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
818
+ var __publicField$2 = (obj, key, value) => {
819
+ __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
818
820
  return value;
819
821
  };
820
822
  class ArriRouter {
821
823
  constructor() {
822
- __publicField$1(this, "procedures", []);
823
- __publicField$1(this, "routes", []);
824
- __publicField$1(this, "models", {});
824
+ __publicField$2(this, "procedures", []);
825
+ __publicField$2(this, "routes", []);
826
+ __publicField$2(this, "models", {});
825
827
  }
826
828
  rpc(procedure) {
829
+ procedure.transport = "http";
830
+ this.procedures.push(procedure);
831
+ }
832
+ wsRpc(procedure) {
833
+ procedure.transport = "ws";
827
834
  this.procedures.push(procedure);
828
835
  }
829
836
  route(route) {
@@ -845,6 +852,145 @@ class ArriRouter {
845
852
  }
846
853
  }
847
854
 
855
+ var __defProp$1 = Object.defineProperty;
856
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
857
+ var __publicField$1 = (obj, key, value) => {
858
+ __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
859
+ return value;
860
+ };
861
+ class WsPeer {
862
+ constructor(peer, opts) {
863
+ __publicField$1(this, "_peer");
864
+ __publicField$1(this, "_validator");
865
+ __publicField$1(this, "context");
866
+ __publicField$1(this, "url");
867
+ this._peer = peer;
868
+ this._validator = opts.validator;
869
+ this.url = peer.url;
870
+ this.context = opts.context;
871
+ }
872
+ send(data) {
873
+ if (!this._validator) {
874
+ return;
875
+ }
876
+ if (!this._validator.validate(data)) {
877
+ return;
878
+ }
879
+ const payload = this._validator.serialize(data);
880
+ return this._peer.send(`type: message
881
+ data: ${payload}`);
882
+ }
883
+ sendError(err) {
884
+ return this._peer.send(`type: error
885
+ data: ${JSON.stringify(err)}`);
886
+ }
887
+ close() {
888
+ throw new Error("close() is not yet implemented on WsPeer");
889
+ }
890
+ subscribe(channel) {
891
+ this._peer.subscribe(channel);
892
+ }
893
+ unsubscribe(channel) {
894
+ this._peer.unsubscribe(channel);
895
+ }
896
+ publish(channel, message) {
897
+ if (!this._validator) {
898
+ return;
899
+ }
900
+ if (!this._validator.validate(message)) {
901
+ const err = {
902
+ code: 500,
903
+ message: `Error serializing message on server. The payload doesn't match the specified schema.`,
904
+ data: {
905
+ payload: message
906
+ }
907
+ };
908
+ this.sendError(err);
909
+ return;
910
+ }
911
+ const payload = this._validator.serialize(message);
912
+ this._peer.publish(channel, payload);
913
+ }
914
+ readyState() {
915
+ return this._peer.readyState;
916
+ }
917
+ }
918
+ function defineWebsocketRpc(def) {
919
+ def.transport = "ws";
920
+ return def;
921
+ }
922
+ function registerWebsocketRpc(router, path, rpc) {
923
+ let responseValidator;
924
+ let paramValidator;
925
+ try {
926
+ responseValidator = rpc.response ? a.compile(rpc.response) : void 0;
927
+ } catch (err) {
928
+ console.error("ERROR COMPILING VALIDATOR", err);
929
+ }
930
+ try {
931
+ paramValidator = rpc.params ? a.compile(rpc.params) : void 0;
932
+ } catch (err) {
933
+ console.error("ERROR COMPILING PARAMS", err);
934
+ }
935
+ const handler = defineWebSocketHandler({
936
+ upgrade(req) {
937
+ },
938
+ open(peer) {
939
+ const urlParts = peer.url.split("?");
940
+ const context = {
941
+ rpcName: rpc.name,
942
+ clientAddress: peer.addr
943
+ };
944
+ if (urlParts.length > 1) {
945
+ urlParts.shift();
946
+ const queryStr = new URLSearchParams(urlParts.join("?"));
947
+ const query = {};
948
+ for (const [key, val] of queryStr.entries()) {
949
+ query[key] = val;
950
+ }
951
+ context.queryParams = query;
952
+ }
953
+ const wsPeer = new WsPeer(peer, {
954
+ validator: responseValidator,
955
+ context
956
+ });
957
+ peer.ctx.__wsPeer = wsPeer;
958
+ rpc.handler.onOpen(peer.ctx.__wsPeer);
959
+ },
960
+ message(peer, message) {
961
+ if (!paramValidator) {
962
+ return;
963
+ }
964
+ const data = paramValidator.safeParse(message.text());
965
+ if (!data.success) {
966
+ const errorResponse = {
967
+ code: 400,
968
+ message: data.error.message,
969
+ data: data.error.errors,
970
+ stack: data.error.stack?.split("\n")
971
+ };
972
+ peer.ctx.__wsPeer.sendError(errorResponse);
973
+ return;
974
+ }
975
+ rpc.handler.onMessage(peer.ctx.__wsPeer, data.value);
976
+ },
977
+ close(peer, details) {
978
+ rpc.handler.onClose(peer.ctx.__wsPeer, details);
979
+ }
980
+ });
981
+ router.use(path, handler);
982
+ }
983
+ function createWsRpcDefinition(rpcName, path, rpc) {
984
+ return {
985
+ transport: "ws",
986
+ path,
987
+ params: getRpcParamName(rpcName, rpc),
988
+ response: getRpcResponseName(rpcName, rpc),
989
+ isDeprecated: rpc.isDeprecated,
990
+ description: rpc.description
991
+ };
992
+ }
993
+
848
994
  var __defProp = Object.defineProperty;
849
995
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
850
996
  var __publicField = (obj, key, value) => {
@@ -922,7 +1068,11 @@ class ArriApp {
922
1068
  this.route(route);
923
1069
  }
924
1070
  for (const rpc of input.getProcedures()) {
925
- this.rpc(rpc);
1071
+ if (rpc.transport === "http") {
1072
+ this.rpc(rpc);
1073
+ } else {
1074
+ this.wsRpc(rpc);
1075
+ }
926
1076
  }
927
1077
  this.registerModels(input.getModels());
928
1078
  return;
@@ -930,26 +1080,24 @@ class ArriApp {
930
1080
  this._middlewares.push(input);
931
1081
  }
932
1082
  rpc(procedure) {
933
- const path = procedure.path ?? getRpcPath(procedure.name, this._rpcRoutePrefix);
934
- this._procedures[procedure.name] = createHttpRpcDefinition(
935
- procedure.name,
936
- path,
937
- procedure
938
- );
939
- if (isRpcParamSchema(procedure.params)) {
940
- const paramName = getRpcParamName(procedure.name, procedure);
1083
+ procedure.transport = "http";
1084
+ const p = procedure;
1085
+ const path = p.path ?? getRpcPath(p.name, this._rpcRoutePrefix);
1086
+ this._procedures[p.name] = createHttpRpcDefinition(p.name, path, p);
1087
+ if (isRpcParamSchema(p.params)) {
1088
+ const paramName = getRpcParamName(p.name, p);
941
1089
  if (paramName) {
942
- this._models[paramName] = procedure.params;
1090
+ this._models[paramName] = p.params;
943
1091
  }
944
1092
  }
945
- if (isRpcParamSchema(procedure.response)) {
946
- const responseName = getRpcResponseName(procedure.name, procedure);
1093
+ if (isRpcParamSchema(p.response)) {
1094
+ const responseName = getRpcResponseName(p.name, p);
947
1095
  if (responseName) {
948
- this._models[responseName] = procedure.response;
1096
+ this._models[responseName] = p.response;
949
1097
  }
950
1098
  }
951
- if (isEventStreamRpc(procedure)) {
952
- registerEventStreamRpc(this.h3Router, path, procedure, {
1099
+ if (isEventStreamRpc(p)) {
1100
+ registerEventStreamRpc(this.h3Router, path, p, {
953
1101
  middleware: this._middlewares,
954
1102
  onRequest: this._onRequest,
955
1103
  onError: this._onError,
@@ -959,7 +1107,7 @@ class ArriApp {
959
1107
  });
960
1108
  return;
961
1109
  }
962
- registerRpc(this.h3Router, path, procedure, {
1110
+ registerRpc(this.h3Router, path, p, {
963
1111
  middleware: this._middlewares,
964
1112
  onRequest: this._onRequest,
965
1113
  onError: this._onError,
@@ -968,6 +1116,29 @@ class ArriApp {
968
1116
  debug: this._debug
969
1117
  });
970
1118
  }
1119
+ wsRpc(procedure) {
1120
+ procedure.transport = "ws";
1121
+ const p = procedure;
1122
+ const path = procedure.path ?? getRpcPath(procedure.name, this._rpcRoutePrefix);
1123
+ this._procedures[procedure.name] = createWsRpcDefinition(
1124
+ procedure.name,
1125
+ path,
1126
+ p
1127
+ );
1128
+ if (isRpcParamSchema(procedure.params)) {
1129
+ const paramName = getRpcParamName(procedure.name, p);
1130
+ if (paramName) {
1131
+ this._models[paramName] = procedure.params;
1132
+ }
1133
+ }
1134
+ if (isRpcParamSchema(procedure.response)) {
1135
+ const responseName = getRpcResponseName(procedure.name, p);
1136
+ if (responseName) {
1137
+ this._models[responseName] = procedure.response;
1138
+ }
1139
+ }
1140
+ registerWebsocketRpc(this.h3Router, path, p);
1141
+ }
971
1142
  route(route) {
972
1143
  registerRoute(this.h3Router, route, {
973
1144
  middleware: this._middlewares,
@@ -1057,4 +1228,4 @@ function defineConfig(config) {
1057
1228
  };
1058
1229
  }
1059
1230
 
1060
- export { ArriApp as A, registerEventStreamRpc as B, DEV_ENDPOINT_ROOT as D, EventStreamConnection as E, DEV_DEFINITION_ENDPOINT as a, isRpc as b, createAppDefinition as c, defineRpc as d, createHttpRpcDefinition as e, getRpcParamName as f, getRpcPath as g, getRpcResponseName as h, isRpcParamSchema as i, ArriServerError as j, ArriServerErrorResponse as k, defineError as l, errorResponseFromValidationErrors as m, handleH3Error as n, isArriConfig as o, isResolvedArriConfig as p, defaultConfig as q, registerRpc as r, defineConfig as s, ArriRouter as t, defineRoute as u, validateRpcRequestInput as v, registerRoute as w, handleRoute as x, defineEventStreamRpc as y, isEventStreamRpc as z };
1231
+ export { ArriApp as A, registerEventStreamRpc as B, defineWebsocketRpc as C, DEV_ENDPOINT_ROOT as D, EventStreamConnection as E, registerWebsocketRpc as F, createWsRpcDefinition as G, WsPeer as W, DEV_DEFINITION_ENDPOINT as a, isRpc as b, createAppDefinition as c, defineRpc as d, createHttpRpcDefinition as e, getRpcParamName as f, getRpcPath as g, getRpcResponseName as h, isRpcParamSchema as i, ArriServerError as j, ArriServerErrorResponse as k, defineError as l, errorResponseFromValidationErrors as m, handleH3Error as n, isArriConfig as o, isResolvedArriConfig as p, defaultConfig as q, registerRpc as r, defineConfig as s, ArriRouter as t, defineRoute as u, validateRpcRequestInput as v, registerRoute as w, handleRoute as x, defineEventStreamRpc as y, isEventStreamRpc as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arri",
3
- "version": "0.36.1",
3
+ "version": "0.37.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -30,6 +30,7 @@
30
30
  "chokidar": "^3.6.0",
31
31
  "citty": "^0.1.6",
32
32
  "consola": "^3.2.3",
33
+ "crossws": "^0.2.4",
33
34
  "degit": "^2.8.4",
34
35
  "enquirer": "^2.4.1",
35
36
  "esbuild": "^0.20.2",
@@ -43,10 +44,10 @@
43
44
  "prettier": "^3.2.5",
44
45
  "scule": "^1.3.0",
45
46
  "uncrypto": "^0.1.3",
46
- "arri-codegen-utils": "0.36.1",
47
- "arri-validate": "0.36.1",
48
- "arri-codegen-ts": "0.36.1",
49
- "arri-codegen-dart": "0.36.1"
47
+ "arri-codegen-dart": "0.37.0",
48
+ "arri-codegen-utils": "0.37.0",
49
+ "arri-validate": "0.37.0",
50
+ "arri-codegen-ts": "0.37.0"
50
51
  },
51
52
  "devDependencies": {
52
53
  "@types/degit": "^2.8.6",