arri 0.44.0 → 0.45.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 +66 -542
- package/dist/cli.cjs +51 -393
- package/dist/cli.mjs +6 -336
- package/dist/index.cjs +25 -44
- package/dist/index.d.cts +8 -278
- package/dist/index.d.mts +8 -278
- package/dist/index.d.ts +8 -278
- package/dist/index.mjs +15 -9
- package/dist/shared/arri.547ce62e.cjs +436 -0
- package/dist/shared/arri.e5993636.mjs +403 -0
- package/package.json +17 -27
- package/dist/codegen.cjs +0 -13
- package/dist/codegen.d.cts +0 -4
- package/dist/codegen.d.mts +0 -4
- package/dist/codegen.d.ts +0 -4
- package/dist/codegen.mjs +0 -4
- package/dist/shared/arri.0628c07d.cjs +0 -1285
- package/dist/shared/arri.c3a553fc.mjs +0 -1250
|
@@ -1,1285 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const arriCodegenUtils = require('arri-codegen-utils');
|
|
4
|
-
const h3 = require('h3');
|
|
5
|
-
const arriValidate = require('arri-validate');
|
|
6
|
-
const h3Sse = require('h3-sse');
|
|
7
|
-
const scule = require('scule');
|
|
8
|
-
|
|
9
|
-
var __defProp$4 = Object.defineProperty;
|
|
10
|
-
var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
11
|
-
var __publicField$4 = (obj, key, value) => {
|
|
12
|
-
__defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
13
|
-
return value;
|
|
14
|
-
};
|
|
15
|
-
class ArriServerError extends Error {
|
|
16
|
-
constructor(err) {
|
|
17
|
-
super(err.message);
|
|
18
|
-
__publicField$4(this, "code");
|
|
19
|
-
__publicField$4(this, "data");
|
|
20
|
-
this.code = err.code;
|
|
21
|
-
this.data = err.data;
|
|
22
|
-
if (err.stack) {
|
|
23
|
-
this.stack = err.stack;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
const ArriServerErrorResponse = arriValidate.a.object({
|
|
28
|
-
code: arriValidate.a.int16(),
|
|
29
|
-
message: arriValidate.a.string(),
|
|
30
|
-
stack: arriValidate.a.optional(arriValidate.a.array(arriValidate.a.string())),
|
|
31
|
-
data: arriValidate.a.optional(arriValidate.a.any())
|
|
32
|
-
});
|
|
33
|
-
function defineError(statusCode, input = {}) {
|
|
34
|
-
const defaultVals = errorResponseDefaults[statusCode];
|
|
35
|
-
return new ArriServerError({
|
|
36
|
-
code: statusCode,
|
|
37
|
-
message: input.message ?? defaultVals?.message ?? "An unknown error occurred",
|
|
38
|
-
data: input.data
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
function errorResponseFromValidationErrors(errors, prefixText = `Missing or invalid parameters`) {
|
|
42
|
-
const errorParts = [];
|
|
43
|
-
for (const err of errors) {
|
|
44
|
-
const propName = err.instancePath?.split("/") ?? [];
|
|
45
|
-
if (propName.length > 0) {
|
|
46
|
-
propName.shift();
|
|
47
|
-
}
|
|
48
|
-
if (!errorParts.includes(propName.join("."))) {
|
|
49
|
-
errorParts.push(propName.join("."));
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
throw defineError(400, {
|
|
53
|
-
message: `${prefixText}: [${errorParts.join(",")}]`,
|
|
54
|
-
data: errors
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
const errorResponseDefaults = {
|
|
58
|
-
400: {
|
|
59
|
-
name: "BAD_REQUEST",
|
|
60
|
-
message: "Bad Request"
|
|
61
|
-
},
|
|
62
|
-
401: {
|
|
63
|
-
name: "UNAUTHORIZED",
|
|
64
|
-
message: "Unauthorized"
|
|
65
|
-
},
|
|
66
|
-
402: {
|
|
67
|
-
name: "PAYMENT_REQUIRED",
|
|
68
|
-
message: "Payment Required"
|
|
69
|
-
},
|
|
70
|
-
403: {
|
|
71
|
-
name: "FORBIDDEN",
|
|
72
|
-
message: "Forbidden"
|
|
73
|
-
},
|
|
74
|
-
404: {
|
|
75
|
-
name: "NOT_FOUND",
|
|
76
|
-
message: "Not Found"
|
|
77
|
-
},
|
|
78
|
-
405: {
|
|
79
|
-
name: "METHOD_NOT_ALLOWED",
|
|
80
|
-
message: "Method Not Allowed"
|
|
81
|
-
},
|
|
82
|
-
406: {
|
|
83
|
-
name: "NOT_ACCEPTABLE",
|
|
84
|
-
message: "Not Acceptable"
|
|
85
|
-
},
|
|
86
|
-
407: {
|
|
87
|
-
name: "PROXY_AUTHENTICATION_REQUIRED",
|
|
88
|
-
message: "Proxy Authentication Required"
|
|
89
|
-
},
|
|
90
|
-
408: {
|
|
91
|
-
name: "REQUEST_TIMEOUT",
|
|
92
|
-
message: "Request Timeout"
|
|
93
|
-
},
|
|
94
|
-
409: {
|
|
95
|
-
name: "CONFLICT",
|
|
96
|
-
message: "Conflict"
|
|
97
|
-
},
|
|
98
|
-
410: {
|
|
99
|
-
name: "GONE",
|
|
100
|
-
message: "Gone"
|
|
101
|
-
},
|
|
102
|
-
411: {
|
|
103
|
-
name: "LENGTH_REQUIRED",
|
|
104
|
-
message: "Length Required"
|
|
105
|
-
},
|
|
106
|
-
412: {
|
|
107
|
-
name: "PRECONDITION_FAILED",
|
|
108
|
-
message: "Precondition Failed"
|
|
109
|
-
},
|
|
110
|
-
413: {
|
|
111
|
-
name: "REQUEST_TOO_LONG",
|
|
112
|
-
message: "Request Entity Too Large"
|
|
113
|
-
},
|
|
114
|
-
414: {
|
|
115
|
-
name: "REQUEST_URI_TOO_LONG",
|
|
116
|
-
message: "Request-URI Too Long"
|
|
117
|
-
},
|
|
118
|
-
415: {
|
|
119
|
-
name: "UNSUPPORTED_MEDIA_TYPE",
|
|
120
|
-
message: "Unsupported Media Type"
|
|
121
|
-
},
|
|
122
|
-
416: {
|
|
123
|
-
name: "REQUESTED_RANGE_NOT_SATISFIABLE",
|
|
124
|
-
message: "Requested Range Not Satisfiable"
|
|
125
|
-
},
|
|
126
|
-
417: {
|
|
127
|
-
name: "EXPECTATION_FAILED",
|
|
128
|
-
message: "Expectation Failed"
|
|
129
|
-
},
|
|
130
|
-
418: {
|
|
131
|
-
name: "IM_A_TEAPOT",
|
|
132
|
-
message: "I'm a teapot"
|
|
133
|
-
},
|
|
134
|
-
419: {
|
|
135
|
-
name: "INSUFFICIENT_SPACE_ON_RESOURCE",
|
|
136
|
-
message: "Insufficient Space on Resource"
|
|
137
|
-
},
|
|
138
|
-
420: {
|
|
139
|
-
name: "METHOD_FAILURE",
|
|
140
|
-
message: "Method Failure"
|
|
141
|
-
},
|
|
142
|
-
421: {
|
|
143
|
-
name: "MISDIRECTED_REQUEST",
|
|
144
|
-
message: "Misdirected Request"
|
|
145
|
-
},
|
|
146
|
-
422: {
|
|
147
|
-
name: "UNPROCESSABLE_ENTITY",
|
|
148
|
-
message: "Unprocessable Entity"
|
|
149
|
-
},
|
|
150
|
-
423: {
|
|
151
|
-
name: "LOCKED",
|
|
152
|
-
message: "Locked"
|
|
153
|
-
},
|
|
154
|
-
424: {
|
|
155
|
-
name: "FAILED_DEPENDENCY",
|
|
156
|
-
message: "Failed Dependency"
|
|
157
|
-
},
|
|
158
|
-
428: {
|
|
159
|
-
name: "PRECONDITION_REQUIRED",
|
|
160
|
-
message: "Precondition Required"
|
|
161
|
-
},
|
|
162
|
-
429: {
|
|
163
|
-
name: "TOO_MANY_REQUESTS",
|
|
164
|
-
message: "Too Many Requests"
|
|
165
|
-
},
|
|
166
|
-
431: {
|
|
167
|
-
name: "REQUEST_HEADER_FIELDS_TOO_LARGE",
|
|
168
|
-
message: "Request Header Fields Too Large"
|
|
169
|
-
},
|
|
170
|
-
451: {
|
|
171
|
-
name: "UNAVAILABLE_FOR_LEGAL_REASONS",
|
|
172
|
-
message: "Unavailable For Legal Reasons"
|
|
173
|
-
},
|
|
174
|
-
500: {
|
|
175
|
-
name: "INTERNAL_SERVER_ERROR",
|
|
176
|
-
message: "Internal Server Error"
|
|
177
|
-
},
|
|
178
|
-
501: {
|
|
179
|
-
name: "NOT_IMPLEMENTED",
|
|
180
|
-
message: "Not Implemented"
|
|
181
|
-
},
|
|
182
|
-
502: {
|
|
183
|
-
name: "BAD_GATEWAY",
|
|
184
|
-
message: "Bad Gateway"
|
|
185
|
-
},
|
|
186
|
-
503: {
|
|
187
|
-
name: "SERVICE_UNAVAILABLE",
|
|
188
|
-
message: "Service Unavailable"
|
|
189
|
-
},
|
|
190
|
-
504: {
|
|
191
|
-
name: "GATEWAY_TIMEOUT",
|
|
192
|
-
message: "Gateway Timeout"
|
|
193
|
-
},
|
|
194
|
-
505: {
|
|
195
|
-
name: "HTTP_VERSION_NOT_SUPPORTED",
|
|
196
|
-
message: "HTTP Version Not Supported"
|
|
197
|
-
},
|
|
198
|
-
507: {
|
|
199
|
-
name: "INSUFFICIENT_STORAGE",
|
|
200
|
-
message: "Insufficient Storage"
|
|
201
|
-
},
|
|
202
|
-
511: {
|
|
203
|
-
name: "NETWORK_AUTHENTICATION_REQUIRED",
|
|
204
|
-
message: "Network Authentication Required"
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
async function handleH3Error(err, event, onError, debug) {
|
|
208
|
-
let arriErr;
|
|
209
|
-
if (err instanceof ArriServerError) {
|
|
210
|
-
arriErr = err;
|
|
211
|
-
} else if (h3.isError(err)) {
|
|
212
|
-
arriErr = new ArriServerError({
|
|
213
|
-
code: err.statusCode,
|
|
214
|
-
message: err.message,
|
|
215
|
-
stack: err.stack,
|
|
216
|
-
data: err.data
|
|
217
|
-
});
|
|
218
|
-
} else if (err instanceof Error) {
|
|
219
|
-
arriErr = new ArriServerError({
|
|
220
|
-
code: 500,
|
|
221
|
-
message: err.message,
|
|
222
|
-
data: err,
|
|
223
|
-
stack: err.stack
|
|
224
|
-
});
|
|
225
|
-
} else {
|
|
226
|
-
arriErr = new ArriServerError({
|
|
227
|
-
code: 500,
|
|
228
|
-
message: `An unknown error occurred`,
|
|
229
|
-
data: err
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
if (!arriErr) {
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
h3.setResponseStatus(event, arriErr.code);
|
|
236
|
-
if (onError) {
|
|
237
|
-
await onError(arriErr, event);
|
|
238
|
-
}
|
|
239
|
-
if (event.handled) {
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
return sendArriError(event, arriErr, debug);
|
|
243
|
-
}
|
|
244
|
-
async function sendArriError(event, error, debug) {
|
|
245
|
-
const payload = {
|
|
246
|
-
code: error.code,
|
|
247
|
-
message: error.message,
|
|
248
|
-
data: error.data
|
|
249
|
-
};
|
|
250
|
-
if (debug) {
|
|
251
|
-
payload.stack = error.stack?.split("\n").map((l) => l.trim());
|
|
252
|
-
}
|
|
253
|
-
h3.setResponseHeader(event, "Content-Type", "application/json");
|
|
254
|
-
h3.setResponseStatus(event, error.code);
|
|
255
|
-
return h3.send(event, JSON.stringify(payload));
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
function isRpcParamSchema(input) {
|
|
259
|
-
return arriValidate.isAObjectSchema(input) || arriValidate.isADiscriminatorSchema(input);
|
|
260
|
-
}
|
|
261
|
-
function isRpc(input) {
|
|
262
|
-
return typeof input === "object" && input !== null && "method" in input && arriCodegenUtils.isRpcHttpMethod(input.method) && "handler" in input && typeof input.handler === "function";
|
|
263
|
-
}
|
|
264
|
-
function defineRpc(config) {
|
|
265
|
-
config.transport = "http";
|
|
266
|
-
return config;
|
|
267
|
-
}
|
|
268
|
-
function createHttpRpcDefinition(rpcName, httpPath, procedure) {
|
|
269
|
-
let method;
|
|
270
|
-
if (procedure.isEventStream === true) {
|
|
271
|
-
method = procedure.method ?? "get";
|
|
272
|
-
} else {
|
|
273
|
-
method = procedure.method ?? "post";
|
|
274
|
-
}
|
|
275
|
-
return {
|
|
276
|
-
transport: "http",
|
|
277
|
-
description: procedure.description,
|
|
278
|
-
path: httpPath,
|
|
279
|
-
method,
|
|
280
|
-
params: getRpcParamName(rpcName, procedure),
|
|
281
|
-
response: getRpcResponseDefinition(rpcName, procedure),
|
|
282
|
-
isDeprecated: procedure.isDeprecated,
|
|
283
|
-
isEventStream: procedure.isEventStream === true ? true : void 0
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
function getRpcPath(rpcName, prefix = "") {
|
|
287
|
-
const path = rpcName.split(".").map(
|
|
288
|
-
(part) => arriCodegenUtils.removeDisallowedChars(
|
|
289
|
-
scule.kebabCase(part),
|
|
290
|
-
`!@#$%^&*()+=[]{}|\\;:'"<>,./?`
|
|
291
|
-
)
|
|
292
|
-
).join("/");
|
|
293
|
-
const finalPath = prefix ? `/${prefix}/${path}` : `/${path}`;
|
|
294
|
-
return finalPath;
|
|
295
|
-
}
|
|
296
|
-
function getRpcParamName(rpcName, procedure) {
|
|
297
|
-
if (!isRpcParamSchema(procedure.params)) {
|
|
298
|
-
return void 0;
|
|
299
|
-
}
|
|
300
|
-
const nameParts = rpcName.split(".").map(
|
|
301
|
-
(part) => arriCodegenUtils.removeDisallowedChars(part, `!@#$%^&*()+=[]{}|\\;:'"<>,./?`)
|
|
302
|
-
);
|
|
303
|
-
const paramName = procedure.params.metadata.id ?? scule.pascalCase(`${nameParts.join(`_`)}_params`);
|
|
304
|
-
return paramName;
|
|
305
|
-
}
|
|
306
|
-
function getRpcResponseName(rpcName, procedure) {
|
|
307
|
-
if (!isRpcParamSchema(procedure.response)) {
|
|
308
|
-
return void 0;
|
|
309
|
-
}
|
|
310
|
-
const nameParts = rpcName.split(".").map(
|
|
311
|
-
(part) => arriCodegenUtils.removeDisallowedChars(part, `!@#$%^&*()+=[]{}|\\;:'"<>,./?`)
|
|
312
|
-
);
|
|
313
|
-
const responseName = procedure.response.metadata.id ?? scule.pascalCase(`${nameParts.join("_")}_response`);
|
|
314
|
-
return responseName;
|
|
315
|
-
}
|
|
316
|
-
function getRpcResponseDefinition(rpcName, procedure) {
|
|
317
|
-
if (!isRpcParamSchema(procedure.response)) {
|
|
318
|
-
return void 0;
|
|
319
|
-
}
|
|
320
|
-
const name = getRpcResponseName(rpcName, procedure);
|
|
321
|
-
if (!name) {
|
|
322
|
-
return void 0;
|
|
323
|
-
}
|
|
324
|
-
return name;
|
|
325
|
-
}
|
|
326
|
-
function registerRpc(router, path, procedure, opts) {
|
|
327
|
-
let responseValidator;
|
|
328
|
-
try {
|
|
329
|
-
responseValidator = procedure.response ? arriValidate.a.compile(procedure.response) : void 0;
|
|
330
|
-
} catch (err) {
|
|
331
|
-
console.error("ERROR COMPILING VALIDATOR", err);
|
|
332
|
-
}
|
|
333
|
-
const httpMethod = procedure.method ?? "post";
|
|
334
|
-
const handler = h3.eventHandler(async (event) => {
|
|
335
|
-
event.context.rpcName = procedure.name;
|
|
336
|
-
if (h3.isPreflightRequest(event)) {
|
|
337
|
-
return "ok";
|
|
338
|
-
}
|
|
339
|
-
try {
|
|
340
|
-
if (opts.onRequest) {
|
|
341
|
-
await opts.onRequest(event);
|
|
342
|
-
}
|
|
343
|
-
if (opts.middleware.length) {
|
|
344
|
-
for (const m of opts.middleware) {
|
|
345
|
-
await m(event);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
if (isRpcParamSchema(procedure.params)) {
|
|
349
|
-
await validateRpcRequestInput(
|
|
350
|
-
event,
|
|
351
|
-
httpMethod,
|
|
352
|
-
procedure.params
|
|
353
|
-
);
|
|
354
|
-
}
|
|
355
|
-
const response = await procedure.handler(
|
|
356
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
357
|
-
event.context,
|
|
358
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
359
|
-
event
|
|
360
|
-
);
|
|
361
|
-
event.context.response = response;
|
|
362
|
-
if (opts.onBeforeResponse) {
|
|
363
|
-
await opts.onBeforeResponse(event);
|
|
364
|
-
}
|
|
365
|
-
if (typeof response === "object") {
|
|
366
|
-
if (!responseValidator?.validate(response)) {
|
|
367
|
-
const errors = arriValidate.a.errors(procedure.response, response);
|
|
368
|
-
throw defineError(500, {
|
|
369
|
-
message: "Failed to serialize response. Response does not match specified schema",
|
|
370
|
-
data: errors
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
h3.setResponseHeader(event, "Content-Type", "application/json");
|
|
374
|
-
await h3.send(
|
|
375
|
-
event,
|
|
376
|
-
responseValidator?.serialize(response) ?? JSON.stringify(response)
|
|
377
|
-
);
|
|
378
|
-
} else {
|
|
379
|
-
h3.setResponseHeader(event, "Content-Type", "application/json");
|
|
380
|
-
await h3.send(event, `{}`);
|
|
381
|
-
}
|
|
382
|
-
if (opts.onAfterResponse) {
|
|
383
|
-
await opts.onAfterResponse(event);
|
|
384
|
-
}
|
|
385
|
-
if (procedure.postHandler) {
|
|
386
|
-
await procedure.postHandler(
|
|
387
|
-
event.context,
|
|
388
|
-
event
|
|
389
|
-
);
|
|
390
|
-
}
|
|
391
|
-
} catch (err) {
|
|
392
|
-
await handleH3Error(err, event, opts.onError, opts.debug ?? false);
|
|
393
|
-
}
|
|
394
|
-
return "";
|
|
395
|
-
});
|
|
396
|
-
switch (httpMethod) {
|
|
397
|
-
case "get":
|
|
398
|
-
router.get(path, handler);
|
|
399
|
-
break;
|
|
400
|
-
case "delete":
|
|
401
|
-
router.delete(path, handler);
|
|
402
|
-
break;
|
|
403
|
-
case "patch":
|
|
404
|
-
router.patch(path, handler);
|
|
405
|
-
break;
|
|
406
|
-
case "put":
|
|
407
|
-
router.put(path, handler);
|
|
408
|
-
break;
|
|
409
|
-
case "post":
|
|
410
|
-
default:
|
|
411
|
-
router.post(path, handler);
|
|
412
|
-
break;
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
async function validateRpcRequestInput(event, httpMethod, schema) {
|
|
416
|
-
switch (httpMethod) {
|
|
417
|
-
case "get": {
|
|
418
|
-
const parsedParams = await h3.getValidatedQuery(
|
|
419
|
-
event,
|
|
420
|
-
(input) => arriValidate.a.safeCoerce(schema, input)
|
|
421
|
-
);
|
|
422
|
-
if (parsedParams.success) {
|
|
423
|
-
event.context.params = parsedParams.value;
|
|
424
|
-
} else {
|
|
425
|
-
const errParts = [];
|
|
426
|
-
for (const err of parsedParams.error.errors) {
|
|
427
|
-
const errPath = err.instancePath.split("/");
|
|
428
|
-
errPath.shift();
|
|
429
|
-
const propName = errPath.join(".");
|
|
430
|
-
if (!errParts.includes(propName)) {
|
|
431
|
-
errParts.push(propName);
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
const message = `Missing or invalid url query parameters: [${errParts.join(
|
|
435
|
-
", "
|
|
436
|
-
)}]`;
|
|
437
|
-
throw defineError(400, {
|
|
438
|
-
message,
|
|
439
|
-
data: parsedParams.error
|
|
440
|
-
});
|
|
441
|
-
}
|
|
442
|
-
break;
|
|
443
|
-
}
|
|
444
|
-
case "delete":
|
|
445
|
-
case "patch":
|
|
446
|
-
case "post":
|
|
447
|
-
case "put": {
|
|
448
|
-
const body = await h3.readRawBody(event);
|
|
449
|
-
if (!body) {
|
|
450
|
-
throw defineError(400, {
|
|
451
|
-
message: `Invalid request body. Expected object. Got undefined.`
|
|
452
|
-
});
|
|
453
|
-
}
|
|
454
|
-
const parsedParams = arriValidate.a.safeParse(schema, body);
|
|
455
|
-
if (!parsedParams.success) {
|
|
456
|
-
const errorParts = [];
|
|
457
|
-
for (const err of parsedParams.error.errors) {
|
|
458
|
-
const errPath = err.instancePath.split("/");
|
|
459
|
-
errPath.shift();
|
|
460
|
-
if (!errorParts.includes(errPath.join("."))) {
|
|
461
|
-
errorParts.push(errPath.join("."));
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
throw defineError(400, {
|
|
465
|
-
message: `Invalid request body. Affected properties [${errorParts.join(
|
|
466
|
-
", "
|
|
467
|
-
)}]`,
|
|
468
|
-
data: parsedParams.error
|
|
469
|
-
});
|
|
470
|
-
}
|
|
471
|
-
event.context.params = parsedParams.value;
|
|
472
|
-
break;
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
var __defProp$3 = Object.defineProperty;
|
|
478
|
-
var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
479
|
-
var __publicField$3 = (obj, key, value) => {
|
|
480
|
-
__defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
481
|
-
return value;
|
|
482
|
-
};
|
|
483
|
-
function defineEventStreamRpc(config) {
|
|
484
|
-
return {
|
|
485
|
-
...config,
|
|
486
|
-
method: config.method ?? "get",
|
|
487
|
-
isEventStream: true,
|
|
488
|
-
transport: "http"
|
|
489
|
-
};
|
|
490
|
-
}
|
|
491
|
-
function isEventStreamRpc(input) {
|
|
492
|
-
return isRpc(input) && "isEventStream" in input && input.isEventStream === true;
|
|
493
|
-
}
|
|
494
|
-
class EventStreamConnection {
|
|
495
|
-
constructor(event, opts) {
|
|
496
|
-
__publicField$3(this, "lastEventId");
|
|
497
|
-
__publicField$3(this, "validationErrors");
|
|
498
|
-
__publicField$3(this, "validator");
|
|
499
|
-
__publicField$3(this, "serializer");
|
|
500
|
-
// for some reason Rollup cannot output DTS when this is set to NodeJS.Timeout
|
|
501
|
-
__publicField$3(this, "pingInterval");
|
|
502
|
-
__publicField$3(this, "pingIntervalMs");
|
|
503
|
-
__publicField$3(this, "eventStream");
|
|
504
|
-
this.eventStream = h3Sse.createEventStream(event);
|
|
505
|
-
this.lastEventId = this.eventStream.lastEventId;
|
|
506
|
-
this.pingIntervalMs = opts.pingInterval ?? 6e4;
|
|
507
|
-
this.serializer = opts.serializer;
|
|
508
|
-
this.validator = opts.validator;
|
|
509
|
-
this.validationErrors = opts.validationErrors;
|
|
510
|
-
this.eventStream.onClose(() => {
|
|
511
|
-
this.cleanup();
|
|
512
|
-
});
|
|
513
|
-
}
|
|
514
|
-
/**
|
|
515
|
-
* Send the stream to the client. This must be called before sending any events.
|
|
516
|
-
*/
|
|
517
|
-
send() {
|
|
518
|
-
void this.eventStream.send();
|
|
519
|
-
this.pingInterval = setInterval(async () => {
|
|
520
|
-
await this.eventStream.push({
|
|
521
|
-
event: "ping",
|
|
522
|
-
data: ""
|
|
523
|
-
});
|
|
524
|
-
}, this.pingIntervalMs);
|
|
525
|
-
}
|
|
526
|
-
async push(data, eventId) {
|
|
527
|
-
if (Array.isArray(data)) {
|
|
528
|
-
const events = [];
|
|
529
|
-
for (const item of data) {
|
|
530
|
-
if (this.validator(item)) {
|
|
531
|
-
events.push({
|
|
532
|
-
id: eventId,
|
|
533
|
-
event: "message",
|
|
534
|
-
data: this.serializer(item)
|
|
535
|
-
});
|
|
536
|
-
continue;
|
|
537
|
-
}
|
|
538
|
-
const errors2 = this.validationErrors(item);
|
|
539
|
-
const errorResponse2 = defineError(500, {
|
|
540
|
-
message: "Failed to serialize response. Response does not match specified schema.",
|
|
541
|
-
data: errors2
|
|
542
|
-
});
|
|
543
|
-
events.push({
|
|
544
|
-
id: eventId,
|
|
545
|
-
event: "error",
|
|
546
|
-
data: JSON.stringify(errorResponse2)
|
|
547
|
-
});
|
|
548
|
-
}
|
|
549
|
-
await this.eventStream.push(events);
|
|
550
|
-
return;
|
|
551
|
-
}
|
|
552
|
-
if (this.validator(data)) {
|
|
553
|
-
await this.eventStream.push({
|
|
554
|
-
id: eventId,
|
|
555
|
-
event: "message",
|
|
556
|
-
data: this.serializer(data)
|
|
557
|
-
});
|
|
558
|
-
return;
|
|
559
|
-
}
|
|
560
|
-
const errors = this.validationErrors(data);
|
|
561
|
-
const errorResponse = defineError(500, {
|
|
562
|
-
message: "Failed to serialize response. Response does not match specified schema.",
|
|
563
|
-
data: errors
|
|
564
|
-
});
|
|
565
|
-
await this.eventStream.push({
|
|
566
|
-
id: eventId,
|
|
567
|
-
event: "error",
|
|
568
|
-
data: JSON.stringify(errorResponse)
|
|
569
|
-
});
|
|
570
|
-
}
|
|
571
|
-
// /**
|
|
572
|
-
// * Push a custom event. These events will need to be parsed manually using the `onEvent` hooks of any generated clients.
|
|
573
|
-
// * Note events with the name "error" or "message" cannot be used for custom events.
|
|
574
|
-
// */
|
|
575
|
-
// async pushCustomEvent(event: SseEvent): Promise<void> {
|
|
576
|
-
// if (event.event === "message") {
|
|
577
|
-
// throw new Error(
|
|
578
|
-
// `Event type "message" is the default event type. Therefore it cannot be used when pushing custom events.`,
|
|
579
|
-
// );
|
|
580
|
-
// }
|
|
581
|
-
// if (event.event === "error") {
|
|
582
|
-
// throw new Error(
|
|
583
|
-
// `Event type "error" is reserved for the pushError() method. Therefore it cannot be used when pushing custom events.`,
|
|
584
|
-
// );
|
|
585
|
-
// }
|
|
586
|
-
// }
|
|
587
|
-
/**
|
|
588
|
-
* Publish an error event. This will trigger the `onError` hooks of any connected clients.
|
|
589
|
-
*/
|
|
590
|
-
async pushError(error, eventId) {
|
|
591
|
-
await this.eventStream.push({
|
|
592
|
-
id: eventId,
|
|
593
|
-
event: "error",
|
|
594
|
-
data: JSON.stringify(error)
|
|
595
|
-
});
|
|
596
|
-
}
|
|
597
|
-
cleanup() {
|
|
598
|
-
if (this.pingInterval) {
|
|
599
|
-
clearInterval(this.pingInterval);
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
/**
|
|
603
|
-
* Tell clients that the stream has ended and close the connection.
|
|
604
|
-
*/
|
|
605
|
-
async close() {
|
|
606
|
-
await this.eventStream.push({
|
|
607
|
-
event: "done",
|
|
608
|
-
data: "this stream has ended"
|
|
609
|
-
}).catch();
|
|
610
|
-
await this.eventStream.close();
|
|
611
|
-
}
|
|
612
|
-
onClose(cb) {
|
|
613
|
-
this.eventStream.onClose(cb);
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
function registerEventStreamRpc(router, path, procedure, opts) {
|
|
617
|
-
let responseValidator;
|
|
618
|
-
try {
|
|
619
|
-
responseValidator = procedure.response ? arriValidate.a.compile(procedure.response) : void 0;
|
|
620
|
-
} catch (err) {
|
|
621
|
-
console.error("ERROR COMPILING VALIDATOR", err);
|
|
622
|
-
}
|
|
623
|
-
const httpMethod = procedure.method ?? "get";
|
|
624
|
-
const handler = h3.eventHandler(async (event) => {
|
|
625
|
-
event.context.rpcName = procedure.name;
|
|
626
|
-
if (h3.isPreflightRequest(event)) {
|
|
627
|
-
return "ok";
|
|
628
|
-
}
|
|
629
|
-
try {
|
|
630
|
-
if (opts.onRequest) {
|
|
631
|
-
await opts.onRequest(event);
|
|
632
|
-
}
|
|
633
|
-
if (opts.middleware.length) {
|
|
634
|
-
for (const m of opts.middleware) {
|
|
635
|
-
await m(event);
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
if (isRpcParamSchema(procedure.params)) {
|
|
639
|
-
await validateRpcRequestInput(
|
|
640
|
-
event,
|
|
641
|
-
httpMethod,
|
|
642
|
-
procedure.params
|
|
643
|
-
);
|
|
644
|
-
}
|
|
645
|
-
const stream = new EventStreamConnection(event, {
|
|
646
|
-
pingInterval: procedure.pingInterval,
|
|
647
|
-
validator: responseValidator?.validate ?? function() {
|
|
648
|
-
return true;
|
|
649
|
-
},
|
|
650
|
-
serializer: (
|
|
651
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
652
|
-
responseValidator?.serialize ?? function(_) {
|
|
653
|
-
return "";
|
|
654
|
-
}
|
|
655
|
-
),
|
|
656
|
-
validationErrors(input) {
|
|
657
|
-
if (procedure.response) {
|
|
658
|
-
return arriValidate.a.errors(procedure.response, input);
|
|
659
|
-
}
|
|
660
|
-
return [];
|
|
661
|
-
}
|
|
662
|
-
});
|
|
663
|
-
event.context.stream = stream;
|
|
664
|
-
await procedure.handler(
|
|
665
|
-
event.context,
|
|
666
|
-
event
|
|
667
|
-
);
|
|
668
|
-
if (!event.handled && !stream.eventStream._handled) {
|
|
669
|
-
stream.send();
|
|
670
|
-
}
|
|
671
|
-
} catch (err) {
|
|
672
|
-
await handleH3Error(err, event, opts.onError, opts.debug ?? false);
|
|
673
|
-
}
|
|
674
|
-
return "";
|
|
675
|
-
});
|
|
676
|
-
switch (httpMethod) {
|
|
677
|
-
case "get":
|
|
678
|
-
router.get(path, handler);
|
|
679
|
-
break;
|
|
680
|
-
case "delete":
|
|
681
|
-
router.delete(path, handler);
|
|
682
|
-
break;
|
|
683
|
-
case "patch":
|
|
684
|
-
router.patch(path, handler);
|
|
685
|
-
break;
|
|
686
|
-
case "put":
|
|
687
|
-
router.put(path, handler);
|
|
688
|
-
break;
|
|
689
|
-
case "post":
|
|
690
|
-
default:
|
|
691
|
-
router.post(path, handler);
|
|
692
|
-
break;
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
function defineRoute(route) {
|
|
697
|
-
return route;
|
|
698
|
-
}
|
|
699
|
-
function registerRoute(router, route, opts) {
|
|
700
|
-
if (typeof route.method === "string") {
|
|
701
|
-
handleRoute(router, route.method, route, opts);
|
|
702
|
-
return;
|
|
703
|
-
}
|
|
704
|
-
for (const method of route.method) {
|
|
705
|
-
handleRoute(router, method, route, opts);
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
function handleRoute(router, method, route, opts) {
|
|
709
|
-
const handler = h3.defineEventHandler(async (event) => {
|
|
710
|
-
if (h3.isPreflightRequest(event)) {
|
|
711
|
-
return "ok";
|
|
712
|
-
}
|
|
713
|
-
try {
|
|
714
|
-
if (opts.onRequest) {
|
|
715
|
-
await opts.onRequest(event);
|
|
716
|
-
}
|
|
717
|
-
if (opts.middleware.length) {
|
|
718
|
-
for (const m of opts.middleware) {
|
|
719
|
-
await m(event);
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
if (route.query) {
|
|
723
|
-
const query = h3.getQuery(event);
|
|
724
|
-
const parsedQuery = arriValidate.a.safeCoerce(route.query, query);
|
|
725
|
-
if (!parsedQuery.success) {
|
|
726
|
-
const errParts = [];
|
|
727
|
-
for (const err of parsedQuery.error.errors) {
|
|
728
|
-
const errPath = err.instancePath.split("/");
|
|
729
|
-
errPath.shift();
|
|
730
|
-
const propName = errPath.join(".");
|
|
731
|
-
if (!errParts.includes(propName)) {
|
|
732
|
-
errParts.push(propName);
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
const message = `Missing or invalid url query parameters: [${errParts.join(
|
|
736
|
-
", "
|
|
737
|
-
)}]`;
|
|
738
|
-
throw defineError(400, {
|
|
739
|
-
message
|
|
740
|
-
});
|
|
741
|
-
}
|
|
742
|
-
event.context.query = parsedQuery.value;
|
|
743
|
-
}
|
|
744
|
-
const notAllowedBodyMethods = [
|
|
745
|
-
"GET",
|
|
746
|
-
"HEAD",
|
|
747
|
-
"CONNECT",
|
|
748
|
-
"OPTIONS"
|
|
749
|
-
];
|
|
750
|
-
if (route.body && !notAllowedBodyMethods.includes(event.method)) {
|
|
751
|
-
const body = await h3.readRawBody(event);
|
|
752
|
-
const parsedBody = arriValidate.a.safeParse(route.body, body);
|
|
753
|
-
if (!parsedBody.success) {
|
|
754
|
-
const errorParts = [];
|
|
755
|
-
for (const err of parsedBody.error.errors) {
|
|
756
|
-
const errPath = err.instancePath.split("/");
|
|
757
|
-
errPath.shift();
|
|
758
|
-
if (!errorParts.includes(errPath.join("."))) {
|
|
759
|
-
errorParts.push(errPath.join("."));
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
throw defineError(400, {
|
|
763
|
-
message: `Invalid request body. Affected properties [${errorParts.join(
|
|
764
|
-
", "
|
|
765
|
-
)}]`,
|
|
766
|
-
data: parsedBody.error
|
|
767
|
-
});
|
|
768
|
-
}
|
|
769
|
-
event.context.body = parsedBody.value;
|
|
770
|
-
}
|
|
771
|
-
const response = await route.handler(event);
|
|
772
|
-
event.context.response = response;
|
|
773
|
-
if (!event.handled) {
|
|
774
|
-
if (opts.onBeforeResponse) {
|
|
775
|
-
await opts.onBeforeResponse(event);
|
|
776
|
-
}
|
|
777
|
-
if (typeof response === "object" && response) {
|
|
778
|
-
h3.setHeader(event, "Content-Type", "application/json");
|
|
779
|
-
await h3.send(event, JSON.stringify(response));
|
|
780
|
-
} else {
|
|
781
|
-
await h3.send(event, response);
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
|
-
if (opts.onAfterResponse) {
|
|
785
|
-
await opts.onAfterResponse(event);
|
|
786
|
-
}
|
|
787
|
-
if (route.postHandler) {
|
|
788
|
-
await route.postHandler(event);
|
|
789
|
-
}
|
|
790
|
-
} catch (err) {
|
|
791
|
-
await handleH3Error(err, event, opts.onError, opts.debug ?? false);
|
|
792
|
-
}
|
|
793
|
-
return "";
|
|
794
|
-
});
|
|
795
|
-
switch (method) {
|
|
796
|
-
case "head":
|
|
797
|
-
router.head(route.path, handler);
|
|
798
|
-
break;
|
|
799
|
-
case "get":
|
|
800
|
-
router.get(route.path, handler);
|
|
801
|
-
break;
|
|
802
|
-
case "delete":
|
|
803
|
-
router.delete(route.path, handler);
|
|
804
|
-
break;
|
|
805
|
-
case "patch":
|
|
806
|
-
router.patch(route.path, handler);
|
|
807
|
-
break;
|
|
808
|
-
case "post":
|
|
809
|
-
router.post(route.path, handler);
|
|
810
|
-
break;
|
|
811
|
-
case "put":
|
|
812
|
-
router.put(route.path, handler);
|
|
813
|
-
break;
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
var __defProp$2 = Object.defineProperty;
|
|
818
|
-
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
819
|
-
var __publicField$2 = (obj, key, value) => {
|
|
820
|
-
__defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
821
|
-
return value;
|
|
822
|
-
};
|
|
823
|
-
class ArriRouter {
|
|
824
|
-
constructor() {
|
|
825
|
-
__publicField$2(this, "procedures", []);
|
|
826
|
-
__publicField$2(this, "routes", []);
|
|
827
|
-
__publicField$2(this, "models", {});
|
|
828
|
-
}
|
|
829
|
-
rpc(procedure) {
|
|
830
|
-
procedure.transport = "http";
|
|
831
|
-
this.procedures.push(procedure);
|
|
832
|
-
}
|
|
833
|
-
wsRpc(procedure) {
|
|
834
|
-
procedure.transport = "ws";
|
|
835
|
-
this.procedures.push(procedure);
|
|
836
|
-
}
|
|
837
|
-
route(route) {
|
|
838
|
-
this.routes.push(route);
|
|
839
|
-
}
|
|
840
|
-
registerModels(models) {
|
|
841
|
-
for (const key of Object.keys(models)) {
|
|
842
|
-
this.models[key] = models[key];
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
getProcedures() {
|
|
846
|
-
return this.procedures;
|
|
847
|
-
}
|
|
848
|
-
getRoutes() {
|
|
849
|
-
return this.routes;
|
|
850
|
-
}
|
|
851
|
-
getModels() {
|
|
852
|
-
return this.models;
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
var __defProp$1 = Object.defineProperty;
|
|
857
|
-
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
858
|
-
var __publicField$1 = (obj, key, value) => {
|
|
859
|
-
__defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
860
|
-
return value;
|
|
861
|
-
};
|
|
862
|
-
class WsPeer {
|
|
863
|
-
constructor(peer, opts) {
|
|
864
|
-
__publicField$1(this, "_peer");
|
|
865
|
-
__publicField$1(this, "_validator");
|
|
866
|
-
__publicField$1(this, "context");
|
|
867
|
-
__publicField$1(this, "url");
|
|
868
|
-
this._peer = peer;
|
|
869
|
-
this._validator = opts.validator;
|
|
870
|
-
this.url = peer.url;
|
|
871
|
-
this.context = opts.context;
|
|
872
|
-
}
|
|
873
|
-
send(data) {
|
|
874
|
-
if (!this._validator) {
|
|
875
|
-
return;
|
|
876
|
-
}
|
|
877
|
-
if (!this._validator.validate(data)) {
|
|
878
|
-
return;
|
|
879
|
-
}
|
|
880
|
-
const payload = this._validator.serialize(data);
|
|
881
|
-
return this._peer.send(`event: message
|
|
882
|
-
data: ${payload}`);
|
|
883
|
-
}
|
|
884
|
-
sendError(err) {
|
|
885
|
-
return this._peer.send(`event: error
|
|
886
|
-
data: ${JSON.stringify(err)}`);
|
|
887
|
-
}
|
|
888
|
-
close() {
|
|
889
|
-
throw new Error("close() is not yet implemented on WsPeer");
|
|
890
|
-
}
|
|
891
|
-
subscribe(channel) {
|
|
892
|
-
this._peer.subscribe(channel);
|
|
893
|
-
}
|
|
894
|
-
unsubscribe(channel) {
|
|
895
|
-
this._peer.unsubscribe(channel);
|
|
896
|
-
}
|
|
897
|
-
publish(channel, message) {
|
|
898
|
-
if (!this._validator) {
|
|
899
|
-
return;
|
|
900
|
-
}
|
|
901
|
-
if (!this._validator.validate(message)) {
|
|
902
|
-
const err = {
|
|
903
|
-
code: 500,
|
|
904
|
-
message: `Error serializing message on server. The payload doesn't match the specified schema.`,
|
|
905
|
-
data: {
|
|
906
|
-
payload: message
|
|
907
|
-
}
|
|
908
|
-
};
|
|
909
|
-
this.sendError(err);
|
|
910
|
-
return;
|
|
911
|
-
}
|
|
912
|
-
const payload = this._validator.serialize(message);
|
|
913
|
-
this._peer.publish(channel, payload);
|
|
914
|
-
}
|
|
915
|
-
readyState() {
|
|
916
|
-
return this._peer.readyState;
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
function defineWebsocketRpc(def) {
|
|
920
|
-
def.transport = "ws";
|
|
921
|
-
return def;
|
|
922
|
-
}
|
|
923
|
-
function registerWebsocketRpc(router, path, rpc) {
|
|
924
|
-
let responseValidator;
|
|
925
|
-
let paramValidator;
|
|
926
|
-
try {
|
|
927
|
-
responseValidator = rpc.response ? arriValidate.a.compile(rpc.response) : void 0;
|
|
928
|
-
} catch (err) {
|
|
929
|
-
console.error("ERROR COMPILING VALIDATOR", err);
|
|
930
|
-
}
|
|
931
|
-
try {
|
|
932
|
-
paramValidator = rpc.params ? arriValidate.a.compile(rpc.params) : void 0;
|
|
933
|
-
} catch (err) {
|
|
934
|
-
console.error("ERROR COMPILING PARAMS", err);
|
|
935
|
-
}
|
|
936
|
-
const rpcHandler = typeof rpc.handler === "function" ? rpc.handler() : rpc.handler;
|
|
937
|
-
const handler = h3.defineWebSocketHandler({
|
|
938
|
-
upgrade(req) {
|
|
939
|
-
},
|
|
940
|
-
open(peer) {
|
|
941
|
-
const urlParts = peer.url.split("?");
|
|
942
|
-
const context = {
|
|
943
|
-
rpcName: rpc.name,
|
|
944
|
-
clientAddress: peer.addr
|
|
945
|
-
};
|
|
946
|
-
if (urlParts.length > 1) {
|
|
947
|
-
urlParts.shift();
|
|
948
|
-
const queryStr = new URLSearchParams(urlParts.join("?"));
|
|
949
|
-
const query = {};
|
|
950
|
-
for (const [key, val] of queryStr.entries()) {
|
|
951
|
-
query[key] = val;
|
|
952
|
-
}
|
|
953
|
-
context.queryParams = query;
|
|
954
|
-
}
|
|
955
|
-
const wsPeer = new WsPeer(peer, {
|
|
956
|
-
validator: responseValidator,
|
|
957
|
-
context
|
|
958
|
-
});
|
|
959
|
-
peer.ctx.__wsPeer = wsPeer;
|
|
960
|
-
rpcHandler.onOpen(peer.ctx.__wsPeer);
|
|
961
|
-
},
|
|
962
|
-
message(peer, message) {
|
|
963
|
-
if (!paramValidator) {
|
|
964
|
-
return;
|
|
965
|
-
}
|
|
966
|
-
const data = paramValidator.safeParse(message.text());
|
|
967
|
-
if (!data.success) {
|
|
968
|
-
const errorResponse = {
|
|
969
|
-
code: 400,
|
|
970
|
-
message: data.error.message,
|
|
971
|
-
data: data.error.errors,
|
|
972
|
-
stack: data.error.stack?.split("\n")
|
|
973
|
-
};
|
|
974
|
-
peer.ctx.__wsPeer.sendError(errorResponse);
|
|
975
|
-
return;
|
|
976
|
-
}
|
|
977
|
-
rpcHandler.onMessage(peer.ctx.__wsPeer, data.value);
|
|
978
|
-
},
|
|
979
|
-
close(peer, details) {
|
|
980
|
-
rpcHandler.onClose(peer.ctx.__wsPeer, details);
|
|
981
|
-
}
|
|
982
|
-
});
|
|
983
|
-
router.use(path, handler);
|
|
984
|
-
}
|
|
985
|
-
function createWsRpcDefinition(rpcName, path, rpc) {
|
|
986
|
-
return {
|
|
987
|
-
transport: "ws",
|
|
988
|
-
path,
|
|
989
|
-
params: getRpcParamName(rpcName, rpc),
|
|
990
|
-
response: getRpcResponseName(rpcName, rpc),
|
|
991
|
-
isDeprecated: rpc.isDeprecated,
|
|
992
|
-
description: rpc.description
|
|
993
|
-
};
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
var __defProp = Object.defineProperty;
|
|
997
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
998
|
-
var __publicField = (obj, key, value) => {
|
|
999
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1000
|
-
return value;
|
|
1001
|
-
};
|
|
1002
|
-
const DEV_ENDPOINT_ROOT = `/__arri_dev__`;
|
|
1003
|
-
const DEV_DEFINITION_ENDPOINT = `${DEV_ENDPOINT_ROOT}/__definition`;
|
|
1004
|
-
const createAppDefinition = (def) => def;
|
|
1005
|
-
class ArriApp {
|
|
1006
|
-
constructor(opts = {}) {
|
|
1007
|
-
__publicField(this, "__isArri__", true);
|
|
1008
|
-
__publicField(this, "h3App");
|
|
1009
|
-
__publicField(this, "h3Router", h3.createRouter());
|
|
1010
|
-
__publicField(this, "_rpcDefinitionPath");
|
|
1011
|
-
__publicField(this, "_rpcRoutePrefix");
|
|
1012
|
-
__publicField(this, "appInfo");
|
|
1013
|
-
__publicField(this, "_procedures", {});
|
|
1014
|
-
__publicField(this, "_models", {});
|
|
1015
|
-
__publicField(this, "_middlewares", []);
|
|
1016
|
-
__publicField(this, "_onRequest");
|
|
1017
|
-
__publicField(this, "_onAfterResponse");
|
|
1018
|
-
__publicField(this, "_onBeforeResponse");
|
|
1019
|
-
__publicField(this, "_onError");
|
|
1020
|
-
__publicField(this, "_debug");
|
|
1021
|
-
__publicField(this, "definitionPath");
|
|
1022
|
-
this.appInfo = opts?.appInfo;
|
|
1023
|
-
this.h3App = h3.createApp({
|
|
1024
|
-
debug: opts?.debug
|
|
1025
|
-
});
|
|
1026
|
-
this._debug = opts.debug ?? false;
|
|
1027
|
-
this._onRequest = opts.onRequest;
|
|
1028
|
-
this._onError = opts.onError;
|
|
1029
|
-
this._onAfterResponse = opts.onAfterResponse;
|
|
1030
|
-
this._onBeforeResponse = opts.onBeforeResponse;
|
|
1031
|
-
this._rpcRoutePrefix = opts?.rpcRoutePrefix ?? "";
|
|
1032
|
-
this._rpcDefinitionPath = opts?.rpcDefinitionPath ?? "__definition";
|
|
1033
|
-
this.h3App.use(this.h3Router);
|
|
1034
|
-
this.definitionPath = this._rpcRoutePrefix ? `/${this._rpcRoutePrefix}/${this._rpcDefinitionPath}`.split("//").join("/") : `/${this._rpcDefinitionPath}`;
|
|
1035
|
-
this.h3Router.get(
|
|
1036
|
-
this.definitionPath,
|
|
1037
|
-
h3.eventHandler(() => this.getAppDefinition())
|
|
1038
|
-
);
|
|
1039
|
-
if (!opts.disableDefaultRoute) {
|
|
1040
|
-
this.route({
|
|
1041
|
-
method: ["get", "head"],
|
|
1042
|
-
path: "/",
|
|
1043
|
-
handler: (_) => {
|
|
1044
|
-
let schemaPath;
|
|
1045
|
-
if (this._rpcRoutePrefix) {
|
|
1046
|
-
schemaPath = `/${this._rpcRoutePrefix}/${this._rpcDefinitionPath}`;
|
|
1047
|
-
} else {
|
|
1048
|
-
schemaPath = `/${this._rpcDefinitionPath}`;
|
|
1049
|
-
}
|
|
1050
|
-
return {
|
|
1051
|
-
title: this.appInfo?.title ?? "Arri-RPC Server",
|
|
1052
|
-
description: this.appInfo?.description ?? "This server utilizes Arri-RPC. Visit the schema path to see all of the available procedures.",
|
|
1053
|
-
schemaPath,
|
|
1054
|
-
...this.appInfo
|
|
1055
|
-
};
|
|
1056
|
-
}
|
|
1057
|
-
});
|
|
1058
|
-
}
|
|
1059
|
-
if (process.env.ARRI_DEV_MODE === "true") {
|
|
1060
|
-
this.h3Router.get(
|
|
1061
|
-
DEV_DEFINITION_ENDPOINT,
|
|
1062
|
-
h3.eventHandler(() => this.getAppDefinition())
|
|
1063
|
-
);
|
|
1064
|
-
}
|
|
1065
|
-
this.h3Router.use(
|
|
1066
|
-
"/**",
|
|
1067
|
-
h3.eventHandler(async (event) => {
|
|
1068
|
-
h3.setResponseStatus(event, 404);
|
|
1069
|
-
const error = defineError(404);
|
|
1070
|
-
try {
|
|
1071
|
-
if (this._onRequest) {
|
|
1072
|
-
await this._onRequest(event);
|
|
1073
|
-
}
|
|
1074
|
-
} catch (err) {
|
|
1075
|
-
await handleH3Error(err, event, this._onError, this._debug);
|
|
1076
|
-
}
|
|
1077
|
-
if (event.handled) {
|
|
1078
|
-
return;
|
|
1079
|
-
}
|
|
1080
|
-
return handleH3Error(error, event, this._onError, this._debug);
|
|
1081
|
-
})
|
|
1082
|
-
);
|
|
1083
|
-
}
|
|
1084
|
-
use(input) {
|
|
1085
|
-
if (typeof input === "object" && input instanceof ArriRouter) {
|
|
1086
|
-
for (const route of input.getRoutes()) {
|
|
1087
|
-
this.route(route);
|
|
1088
|
-
}
|
|
1089
|
-
for (const rpc of input.getProcedures()) {
|
|
1090
|
-
if (rpc.transport === "http") {
|
|
1091
|
-
this.rpc(rpc);
|
|
1092
|
-
} else {
|
|
1093
|
-
this.wsRpc(rpc);
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1096
|
-
this.registerModels(input.getModels());
|
|
1097
|
-
return;
|
|
1098
|
-
}
|
|
1099
|
-
this._middlewares.push(input);
|
|
1100
|
-
}
|
|
1101
|
-
rpc(procedure) {
|
|
1102
|
-
procedure.transport = "http";
|
|
1103
|
-
const p = procedure;
|
|
1104
|
-
const path = p.path ?? getRpcPath(p.name, this._rpcRoutePrefix);
|
|
1105
|
-
this._procedures[p.name] = createHttpRpcDefinition(p.name, path, p);
|
|
1106
|
-
if (isRpcParamSchema(p.params)) {
|
|
1107
|
-
const paramName = getRpcParamName(p.name, p);
|
|
1108
|
-
if (paramName) {
|
|
1109
|
-
this._models[paramName] = p.params;
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
if (isRpcParamSchema(p.response)) {
|
|
1113
|
-
const responseName = getRpcResponseName(p.name, p);
|
|
1114
|
-
if (responseName) {
|
|
1115
|
-
this._models[responseName] = p.response;
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
if (isEventStreamRpc(p)) {
|
|
1119
|
-
registerEventStreamRpc(this.h3Router, path, p, {
|
|
1120
|
-
middleware: this._middlewares,
|
|
1121
|
-
onRequest: this._onRequest,
|
|
1122
|
-
onError: this._onError,
|
|
1123
|
-
onAfterResponse: this._onAfterResponse,
|
|
1124
|
-
onBeforeResponse: this._onBeforeResponse,
|
|
1125
|
-
debug: this._debug
|
|
1126
|
-
});
|
|
1127
|
-
return;
|
|
1128
|
-
}
|
|
1129
|
-
registerRpc(this.h3Router, path, p, {
|
|
1130
|
-
middleware: this._middlewares,
|
|
1131
|
-
onRequest: this._onRequest,
|
|
1132
|
-
onError: this._onError,
|
|
1133
|
-
onAfterResponse: this._onAfterResponse,
|
|
1134
|
-
onBeforeResponse: this._onBeforeResponse,
|
|
1135
|
-
debug: this._debug
|
|
1136
|
-
});
|
|
1137
|
-
}
|
|
1138
|
-
wsRpc(procedure) {
|
|
1139
|
-
procedure.transport = "ws";
|
|
1140
|
-
const p = procedure;
|
|
1141
|
-
const path = procedure.path ?? getRpcPath(procedure.name, this._rpcRoutePrefix);
|
|
1142
|
-
this._procedures[procedure.name] = createWsRpcDefinition(
|
|
1143
|
-
procedure.name,
|
|
1144
|
-
path,
|
|
1145
|
-
p
|
|
1146
|
-
);
|
|
1147
|
-
if (isRpcParamSchema(procedure.params)) {
|
|
1148
|
-
const paramName = getRpcParamName(procedure.name, p);
|
|
1149
|
-
if (paramName) {
|
|
1150
|
-
this._models[paramName] = procedure.params;
|
|
1151
|
-
}
|
|
1152
|
-
}
|
|
1153
|
-
if (isRpcParamSchema(procedure.response)) {
|
|
1154
|
-
const responseName = getRpcResponseName(procedure.name, p);
|
|
1155
|
-
if (responseName) {
|
|
1156
|
-
this._models[responseName] = procedure.response;
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
registerWebsocketRpc(this.h3Router, path, p);
|
|
1160
|
-
}
|
|
1161
|
-
route(route) {
|
|
1162
|
-
registerRoute(this.h3Router, route, {
|
|
1163
|
-
middleware: this._middlewares,
|
|
1164
|
-
onRequest: this._onRequest,
|
|
1165
|
-
onError: this._onError,
|
|
1166
|
-
onAfterResponse: this._onAfterResponse,
|
|
1167
|
-
onBeforeResponse: this._onBeforeResponse,
|
|
1168
|
-
debug: this._debug
|
|
1169
|
-
});
|
|
1170
|
-
}
|
|
1171
|
-
registerModels(models) {
|
|
1172
|
-
for (const key of Object.keys(models)) {
|
|
1173
|
-
this._models[key] = models[key];
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
getAppDefinition() {
|
|
1177
|
-
const appDef = {
|
|
1178
|
-
arriSchemaVersion: arriCodegenUtils.SCHEMA_VERSION,
|
|
1179
|
-
info: this.appInfo,
|
|
1180
|
-
procedures: {},
|
|
1181
|
-
models: this._models
|
|
1182
|
-
};
|
|
1183
|
-
for (const key of Object.keys(this._procedures)) {
|
|
1184
|
-
const rpc = this._procedures[key];
|
|
1185
|
-
appDef.procedures[key] = rpc;
|
|
1186
|
-
}
|
|
1187
|
-
return appDef;
|
|
1188
|
-
}
|
|
1189
|
-
}
|
|
1190
|
-
|
|
1191
|
-
function isArriConfig(input) {
|
|
1192
|
-
if (typeof input !== "object" || input === null) {
|
|
1193
|
-
return false;
|
|
1194
|
-
}
|
|
1195
|
-
if ("generators" in input) {
|
|
1196
|
-
if (!Array.isArray(input.generators)) {
|
|
1197
|
-
return false;
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
if ("port" in input) {
|
|
1201
|
-
if (typeof input.port !== "number") {
|
|
1202
|
-
return false;
|
|
1203
|
-
}
|
|
1204
|
-
if (Number.isNaN(input.port)) {
|
|
1205
|
-
return false;
|
|
1206
|
-
}
|
|
1207
|
-
}
|
|
1208
|
-
if ("entry" in input && typeof input.entry !== "string") {
|
|
1209
|
-
return false;
|
|
1210
|
-
}
|
|
1211
|
-
return true;
|
|
1212
|
-
}
|
|
1213
|
-
function isResolvedArriConfig(input) {
|
|
1214
|
-
if (!isArriConfig(input)) {
|
|
1215
|
-
return false;
|
|
1216
|
-
}
|
|
1217
|
-
return typeof input.rootDir === "string" && typeof input.srcDir === "string" && (typeof input.procedureDir === "string" || typeof input.procedureDir === "boolean") && Array.isArray(input.procedureGlobPatterns) && Array.isArray(input.generators);
|
|
1218
|
-
}
|
|
1219
|
-
const defaultConfig = {
|
|
1220
|
-
port: 3e3,
|
|
1221
|
-
rootDir: ".",
|
|
1222
|
-
srcDir: "src",
|
|
1223
|
-
entry: "app.ts",
|
|
1224
|
-
serverEntry: "",
|
|
1225
|
-
procedureDir: "procedures",
|
|
1226
|
-
procedureGlobPatterns: ["**/*.rpc.ts"],
|
|
1227
|
-
generators: [],
|
|
1228
|
-
buildDir: ".arri",
|
|
1229
|
-
esbuild: {},
|
|
1230
|
-
https: false,
|
|
1231
|
-
http2: false,
|
|
1232
|
-
devServer: {}
|
|
1233
|
-
};
|
|
1234
|
-
function defineConfig(config) {
|
|
1235
|
-
return {
|
|
1236
|
-
port: config.port ?? defaultConfig.port,
|
|
1237
|
-
rootDir: config.rootDir ?? defaultConfig.rootDir,
|
|
1238
|
-
srcDir: config.srcDir ?? defaultConfig.srcDir,
|
|
1239
|
-
entry: config.entry ?? defaultConfig.entry,
|
|
1240
|
-
procedureDir: config.procedureDir ?? defaultConfig.procedureDir,
|
|
1241
|
-
procedureGlobPatterns: config.procedureGlobPatterns ?? defaultConfig.procedureGlobPatterns,
|
|
1242
|
-
generators: config.generators ?? defaultConfig.generators,
|
|
1243
|
-
buildDir: config.buildDir ?? defaultConfig.buildDir,
|
|
1244
|
-
esbuild: config.esbuild ?? defaultConfig.esbuild,
|
|
1245
|
-
serverEntry: config.serverEntry ?? "",
|
|
1246
|
-
https: config.https ?? false,
|
|
1247
|
-
http2: config.http2 ?? false,
|
|
1248
|
-
devServer: config.devServer ?? {}
|
|
1249
|
-
};
|
|
1250
|
-
}
|
|
1251
|
-
|
|
1252
|
-
exports.ArriApp = ArriApp;
|
|
1253
|
-
exports.ArriRouter = ArriRouter;
|
|
1254
|
-
exports.ArriServerError = ArriServerError;
|
|
1255
|
-
exports.ArriServerErrorResponse = ArriServerErrorResponse;
|
|
1256
|
-
exports.DEV_DEFINITION_ENDPOINT = DEV_DEFINITION_ENDPOINT;
|
|
1257
|
-
exports.DEV_ENDPOINT_ROOT = DEV_ENDPOINT_ROOT;
|
|
1258
|
-
exports.EventStreamConnection = EventStreamConnection;
|
|
1259
|
-
exports.WsPeer = WsPeer;
|
|
1260
|
-
exports.createAppDefinition = createAppDefinition;
|
|
1261
|
-
exports.createHttpRpcDefinition = createHttpRpcDefinition;
|
|
1262
|
-
exports.createWsRpcDefinition = createWsRpcDefinition;
|
|
1263
|
-
exports.defaultConfig = defaultConfig;
|
|
1264
|
-
exports.defineConfig = defineConfig;
|
|
1265
|
-
exports.defineError = defineError;
|
|
1266
|
-
exports.defineEventStreamRpc = defineEventStreamRpc;
|
|
1267
|
-
exports.defineRoute = defineRoute;
|
|
1268
|
-
exports.defineRpc = defineRpc;
|
|
1269
|
-
exports.defineWebsocketRpc = defineWebsocketRpc;
|
|
1270
|
-
exports.errorResponseFromValidationErrors = errorResponseFromValidationErrors;
|
|
1271
|
-
exports.getRpcParamName = getRpcParamName;
|
|
1272
|
-
exports.getRpcPath = getRpcPath;
|
|
1273
|
-
exports.getRpcResponseName = getRpcResponseName;
|
|
1274
|
-
exports.handleH3Error = handleH3Error;
|
|
1275
|
-
exports.handleRoute = handleRoute;
|
|
1276
|
-
exports.isArriConfig = isArriConfig;
|
|
1277
|
-
exports.isEventStreamRpc = isEventStreamRpc;
|
|
1278
|
-
exports.isResolvedArriConfig = isResolvedArriConfig;
|
|
1279
|
-
exports.isRpc = isRpc;
|
|
1280
|
-
exports.isRpcParamSchema = isRpcParamSchema;
|
|
1281
|
-
exports.registerEventStreamRpc = registerEventStreamRpc;
|
|
1282
|
-
exports.registerRoute = registerRoute;
|
|
1283
|
-
exports.registerRpc = registerRpc;
|
|
1284
|
-
exports.registerWebsocketRpc = registerWebsocketRpc;
|
|
1285
|
-
exports.validateRpcRequestInput = validateRpcRequestInput;
|