arri 0.36.0 → 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,20 +1,21 @@
1
1
  import { isRpcHttpMethod, removeDisallowedChars, SCHEMA_VERSION } from 'arri-codegen-utils';
2
- import { isError, setResponseStatus, setResponseHeader, send, eventHandler, isPreflightRequest, readRawBody, getValidatedQuery, defineEventHandler, getQuery, setHeader, createRouter, createApp } from 'h3';
2
+ import consola from 'consola';
3
+ import { isError, setResponseStatus, setResponseHeader, send, eventHandler, isPreflightRequest, readRawBody, getValidatedQuery, defineEventHandler, getQuery, setHeader, defineWebSocketHandler, createRouter, createApp } from 'h3';
3
4
  import { a, isAObjectSchema, isADiscriminatorSchema } from 'arri-validate';
4
5
  import { createEventStream } from 'h3-sse';
5
6
  import { kebabCase, pascalCase } from 'scule';
6
7
 
7
- var __defProp$3 = Object.defineProperty;
8
- var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
- var __publicField$3 = (obj, key, value) => {
10
- __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);
11
12
  return value;
12
13
  };
13
14
  class ArriServerError extends Error {
14
15
  constructor(err) {
15
16
  super(err.message);
16
- __publicField$3(this, "code");
17
- __publicField$3(this, "data");
17
+ __publicField$4(this, "code");
18
+ __publicField$4(this, "data");
18
19
  this.code = err.code;
19
20
  this.data = err.data;
20
21
  if (err.stack) {
@@ -260,6 +261,7 @@ function isRpc(input) {
260
261
  return typeof input === "object" && input !== null && "method" in input && isRpcHttpMethod(input.method) && "handler" in input && typeof input.handler === "function";
261
262
  }
262
263
  function defineRpc(config) {
264
+ config.transport = "http";
263
265
  return config;
264
266
  }
265
267
  function createHttpRpcDefinition(rpcName, httpPath, procedure) {
@@ -471,17 +473,18 @@ async function validateRpcRequestInput(event, httpMethod, schema) {
471
473
  }
472
474
  }
473
475
 
474
- var __defProp$2 = Object.defineProperty;
475
- var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
476
- var __publicField$2 = (obj, key, value) => {
477
- __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);
478
480
  return value;
479
481
  };
480
482
  function defineEventStreamRpc(config) {
481
483
  return {
482
484
  ...config,
483
485
  method: config.method ?? "get",
484
- isEventStream: true
486
+ isEventStream: true,
487
+ transport: "http"
485
488
  };
486
489
  }
487
490
  function isEventStreamRpc(input) {
@@ -489,14 +492,14 @@ function isEventStreamRpc(input) {
489
492
  }
490
493
  class EventStreamConnection {
491
494
  constructor(event, opts) {
492
- __publicField$2(this, "lastEventId");
493
- __publicField$2(this, "validationErrors");
494
- __publicField$2(this, "validator");
495
- __publicField$2(this, "serializer");
495
+ __publicField$3(this, "lastEventId");
496
+ __publicField$3(this, "validationErrors");
497
+ __publicField$3(this, "validator");
498
+ __publicField$3(this, "serializer");
496
499
  // for some reason Rollup cannot output DTS when this is set to NodeJS.Timeout
497
- __publicField$2(this, "pingInterval");
498
- __publicField$2(this, "pingIntervalMs");
499
- __publicField$2(this, "eventStream");
500
+ __publicField$3(this, "pingInterval");
501
+ __publicField$3(this, "pingIntervalMs");
502
+ __publicField$3(this, "eventStream");
500
503
  this.eventStream = createEventStream(event);
501
504
  this.lastEventId = this.eventStream.lastEventId;
502
505
  this.pingIntervalMs = opts.pingInterval ?? 6e4;
@@ -810,19 +813,24 @@ function handleRoute(router, method, route, opts) {
810
813
  }
811
814
  }
812
815
 
813
- var __defProp$1 = Object.defineProperty;
814
- var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
815
- var __publicField$1 = (obj, key, value) => {
816
- __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);
817
820
  return value;
818
821
  };
819
822
  class ArriRouter {
820
823
  constructor() {
821
- __publicField$1(this, "procedures", []);
822
- __publicField$1(this, "routes", []);
823
- __publicField$1(this, "models", {});
824
+ __publicField$2(this, "procedures", []);
825
+ __publicField$2(this, "routes", []);
826
+ __publicField$2(this, "models", {});
824
827
  }
825
828
  rpc(procedure) {
829
+ procedure.transport = "http";
830
+ this.procedures.push(procedure);
831
+ }
832
+ wsRpc(procedure) {
833
+ procedure.transport = "ws";
826
834
  this.procedures.push(procedure);
827
835
  }
828
836
  route(route) {
@@ -844,6 +852,145 @@ class ArriRouter {
844
852
  }
845
853
  }
846
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
+
847
994
  var __defProp = Object.defineProperty;
848
995
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
849
996
  var __publicField = (obj, key, value) => {
@@ -869,6 +1016,7 @@ class ArriApp {
869
1016
  __publicField(this, "_onBeforeResponse");
870
1017
  __publicField(this, "_onError");
871
1018
  __publicField(this, "_debug");
1019
+ __publicField(this, "definitionPath");
872
1020
  this.appInfo = opts?.appInfo;
873
1021
  this.h3App = createApp({
874
1022
  debug: opts?.debug
@@ -881,11 +1029,15 @@ class ArriApp {
881
1029
  this._rpcRoutePrefix = opts?.rpcRoutePrefix ?? "";
882
1030
  this._rpcDefinitionPath = opts?.rpcDefinitionPath ?? "__definition";
883
1031
  this.h3App.use(this.h3Router);
1032
+ this.definitionPath = this._rpcRoutePrefix ? `/${this._rpcRoutePrefix}/${this._rpcDefinitionPath}`.split("//").join("/") : `/${this._rpcDefinitionPath}`;
884
1033
  this.h3Router.get(
885
- this._rpcRoutePrefix ? `/${this._rpcRoutePrefix}/${this._rpcDefinitionPath}`.split("//").join("/") : `/${this._rpcDefinitionPath}`,
1034
+ this.definitionPath,
886
1035
  eventHandler(() => this.getAppDefinition())
887
1036
  );
888
1037
  if (process.env.ARRI_DEV_MODE === "true") {
1038
+ consola.info(
1039
+ `Arri definition available at \`http://<host>${this.definitionPath}\``
1040
+ );
889
1041
  this.h3Router.get(
890
1042
  DEV_DEFINITION_ENDPOINT,
891
1043
  eventHandler(() => this.getAppDefinition())
@@ -916,7 +1068,11 @@ class ArriApp {
916
1068
  this.route(route);
917
1069
  }
918
1070
  for (const rpc of input.getProcedures()) {
919
- this.rpc(rpc);
1071
+ if (rpc.transport === "http") {
1072
+ this.rpc(rpc);
1073
+ } else {
1074
+ this.wsRpc(rpc);
1075
+ }
920
1076
  }
921
1077
  this.registerModels(input.getModels());
922
1078
  return;
@@ -924,26 +1080,24 @@ class ArriApp {
924
1080
  this._middlewares.push(input);
925
1081
  }
926
1082
  rpc(procedure) {
927
- const path = procedure.path ?? getRpcPath(procedure.name, this._rpcRoutePrefix);
928
- this._procedures[procedure.name] = createHttpRpcDefinition(
929
- procedure.name,
930
- path,
931
- procedure
932
- );
933
- if (isRpcParamSchema(procedure.params)) {
934
- 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);
935
1089
  if (paramName) {
936
- this._models[paramName] = procedure.params;
1090
+ this._models[paramName] = p.params;
937
1091
  }
938
1092
  }
939
- if (isRpcParamSchema(procedure.response)) {
940
- const responseName = getRpcResponseName(procedure.name, procedure);
1093
+ if (isRpcParamSchema(p.response)) {
1094
+ const responseName = getRpcResponseName(p.name, p);
941
1095
  if (responseName) {
942
- this._models[responseName] = procedure.response;
1096
+ this._models[responseName] = p.response;
943
1097
  }
944
1098
  }
945
- if (isEventStreamRpc(procedure)) {
946
- registerEventStreamRpc(this.h3Router, path, procedure, {
1099
+ if (isEventStreamRpc(p)) {
1100
+ registerEventStreamRpc(this.h3Router, path, p, {
947
1101
  middleware: this._middlewares,
948
1102
  onRequest: this._onRequest,
949
1103
  onError: this._onError,
@@ -953,7 +1107,7 @@ class ArriApp {
953
1107
  });
954
1108
  return;
955
1109
  }
956
- registerRpc(this.h3Router, path, procedure, {
1110
+ registerRpc(this.h3Router, path, p, {
957
1111
  middleware: this._middlewares,
958
1112
  onRequest: this._onRequest,
959
1113
  onError: this._onError,
@@ -962,6 +1116,29 @@ class ArriApp {
962
1116
  debug: this._debug
963
1117
  });
964
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
+ }
965
1142
  route(route) {
966
1143
  registerRoute(this.h3Router, route, {
967
1144
  middleware: this._middlewares,
@@ -1051,4 +1228,4 @@ function defineConfig(config) {
1051
1228
  };
1052
1229
  }
1053
1230
 
1054
- 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.0",
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-dart": "0.36.0",
47
- "arri-codegen-ts": "0.36.0",
48
- "arri-codegen-utils": "0.36.0",
49
- "arri-validate": "0.36.0"
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",