arri 0.43.2 → 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.
@@ -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;