arri 0.0.44 → 0.1.0-beta.2
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/LICENSE +9 -0
- package/README.md +11 -0
- package/dist/cli.cjs +166 -19894
- package/dist/cli.mjs +130 -19856
- package/dist/codegen.cjs +4 -523
- package/dist/codegen.d.cts +2 -71
- package/dist/codegen.d.mts +2 -71
- package/dist/codegen.d.ts +2 -71
- package/dist/codegen.mjs +2 -498
- package/dist/index.cjs +26 -679
- package/dist/index.d.cts +73 -68
- package/dist/index.d.mts +73 -68
- package/dist/index.d.ts +73 -68
- package/dist/index.mjs +6 -662
- package/dist/shared/arri.406d936a.cjs +697 -0
- package/dist/shared/arri.8539c7bd.mjs +677 -0
- package/package.json +23 -13
- package/dist/chunks/index.cjs +0 -8911
- package/dist/chunks/index.mjs +0 -8889
- package/dist/shared/arri.0752aa2b.cjs +0 -192
- package/dist/shared/arri.4536bc49.d.cts +0 -77
- package/dist/shared/arri.4536bc49.d.mts +0 -77
- package/dist/shared/arri.4536bc49.d.ts +0 -77
- package/dist/shared/arri.bda2f011.cjs +0 -786
- package/dist/shared/arri.dfab1c78.mjs +0 -766
- package/dist/shared/arri.ebf86912.mjs +0 -179
|
@@ -0,0 +1,697 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const arriValidate = require('arri-validate');
|
|
4
|
+
const h3 = require('h3');
|
|
5
|
+
const arriCodegenUtils = require('arri-codegen-utils');
|
|
6
|
+
const scule = require('scule');
|
|
7
|
+
|
|
8
|
+
const ErrorResponse = arriValidate.a.object({
|
|
9
|
+
statusCode: arriValidate.a.int8(),
|
|
10
|
+
statusMessage: arriValidate.a.string(),
|
|
11
|
+
stack: arriValidate.a.array(arriValidate.a.any()),
|
|
12
|
+
data: arriValidate.a.optional(arriValidate.a.any())
|
|
13
|
+
});
|
|
14
|
+
function defineError(statusCode, input = {}) {
|
|
15
|
+
const defaultVals = errorResponseDefaults[statusCode];
|
|
16
|
+
return h3.createError({
|
|
17
|
+
statusCode,
|
|
18
|
+
statusMessage: input.statusMessage ?? defaultVals.message ?? "An unknown error occurred",
|
|
19
|
+
stack: input.stack ?? "",
|
|
20
|
+
data: input.data
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function errorResponseFromValidationErrors(errors, prefixText = `Missing or invalid parameters`) {
|
|
24
|
+
const errorParts = [];
|
|
25
|
+
for (const err of errors) {
|
|
26
|
+
const propName = err.instancePath?.split("/") ?? [];
|
|
27
|
+
if (propName.length) {
|
|
28
|
+
propName.shift();
|
|
29
|
+
}
|
|
30
|
+
if (!errorParts.includes(propName.join("."))) {
|
|
31
|
+
errorParts.push(propName.join("."));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
throw defineError(400, {
|
|
35
|
+
statusMessage: `${prefixText}: [${errorParts.join(",")}]`,
|
|
36
|
+
data: errors
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
const errorResponseDefaults = {
|
|
40
|
+
400: {
|
|
41
|
+
name: "BAD_REQUEST",
|
|
42
|
+
message: "Bad Request"
|
|
43
|
+
},
|
|
44
|
+
401: {
|
|
45
|
+
name: "UNAUTHORIZED",
|
|
46
|
+
message: "Unauthorized"
|
|
47
|
+
},
|
|
48
|
+
402: {
|
|
49
|
+
name: "PAYMENT_REQUIRED",
|
|
50
|
+
message: "Payment Required"
|
|
51
|
+
},
|
|
52
|
+
403: {
|
|
53
|
+
name: "FORBIDDEN",
|
|
54
|
+
message: "Forbidden"
|
|
55
|
+
},
|
|
56
|
+
404: {
|
|
57
|
+
name: "NOT_FOUND",
|
|
58
|
+
message: "Not Found"
|
|
59
|
+
},
|
|
60
|
+
405: {
|
|
61
|
+
name: "METHOD_NOT_ALLOWED",
|
|
62
|
+
message: "Method Not Allowed"
|
|
63
|
+
},
|
|
64
|
+
406: {
|
|
65
|
+
name: "NOT_ACCEPTABLE",
|
|
66
|
+
message: "Not Acceptable"
|
|
67
|
+
},
|
|
68
|
+
407: {
|
|
69
|
+
name: "PROXY_AUTHENTICATION_REQUIRED",
|
|
70
|
+
message: "Proxy Authentication Required"
|
|
71
|
+
},
|
|
72
|
+
408: {
|
|
73
|
+
name: "REQUEST_TIMEOUT",
|
|
74
|
+
message: "Request Timeout"
|
|
75
|
+
},
|
|
76
|
+
409: {
|
|
77
|
+
name: "CONFLICT",
|
|
78
|
+
message: "Conflict"
|
|
79
|
+
},
|
|
80
|
+
410: {
|
|
81
|
+
name: "GONE",
|
|
82
|
+
message: "Gone"
|
|
83
|
+
},
|
|
84
|
+
411: {
|
|
85
|
+
name: "LENGTH_REQUIRED",
|
|
86
|
+
message: "Length Required"
|
|
87
|
+
},
|
|
88
|
+
412: {
|
|
89
|
+
name: "PRECONDITION_FAILED",
|
|
90
|
+
message: "Precondition Failed"
|
|
91
|
+
},
|
|
92
|
+
413: {
|
|
93
|
+
name: "REQUEST_TOO_LONG",
|
|
94
|
+
message: "Request Entity Too Large"
|
|
95
|
+
},
|
|
96
|
+
414: {
|
|
97
|
+
name: "REQUEST_URI_TOO_LONG",
|
|
98
|
+
message: "Request-URI Too Long"
|
|
99
|
+
},
|
|
100
|
+
415: {
|
|
101
|
+
name: "UNSUPPORTED_MEDIA_TYPE",
|
|
102
|
+
message: "Unsupported Media Type"
|
|
103
|
+
},
|
|
104
|
+
416: {
|
|
105
|
+
name: "REQUESTED_RANGE_NOT_SATISFIABLE",
|
|
106
|
+
message: "Requested Range Not Satisfiable"
|
|
107
|
+
},
|
|
108
|
+
417: {
|
|
109
|
+
name: "EXPECTATION_FAILED",
|
|
110
|
+
message: "Expectation Failed"
|
|
111
|
+
},
|
|
112
|
+
418: {
|
|
113
|
+
name: "IM_A_TEAPOT",
|
|
114
|
+
message: "I'm a teapot"
|
|
115
|
+
},
|
|
116
|
+
419: {
|
|
117
|
+
name: "INSUFFICIENT_SPACE_ON_RESOURCE",
|
|
118
|
+
message: "Insufficient Space on Resource"
|
|
119
|
+
},
|
|
120
|
+
420: {
|
|
121
|
+
name: "METHOD_FAILURE",
|
|
122
|
+
message: "Method Failure"
|
|
123
|
+
},
|
|
124
|
+
421: {
|
|
125
|
+
name: "MISDIRECTED_REQUEST",
|
|
126
|
+
message: "Misdirected Request"
|
|
127
|
+
},
|
|
128
|
+
422: {
|
|
129
|
+
name: "UNPROCESSABLE_ENTITY",
|
|
130
|
+
message: "Unprocessable Entity"
|
|
131
|
+
},
|
|
132
|
+
423: {
|
|
133
|
+
name: "LOCKED",
|
|
134
|
+
message: "Locked"
|
|
135
|
+
},
|
|
136
|
+
424: {
|
|
137
|
+
name: "FAILED_DEPENDENCY",
|
|
138
|
+
message: "Failed Dependency"
|
|
139
|
+
},
|
|
140
|
+
428: {
|
|
141
|
+
name: "PRECONDITION_REQUIRED",
|
|
142
|
+
message: "Precondition Required"
|
|
143
|
+
},
|
|
144
|
+
429: {
|
|
145
|
+
name: "TOO_MANY_REQUESTS",
|
|
146
|
+
message: "Too Many Requests"
|
|
147
|
+
},
|
|
148
|
+
431: {
|
|
149
|
+
name: "REQUEST_HEADER_FIELDS_TOO_LARGE",
|
|
150
|
+
message: "Request Header Fields Too Large"
|
|
151
|
+
},
|
|
152
|
+
451: {
|
|
153
|
+
name: "UNAVAILABLE_FOR_LEGAL_REASONS",
|
|
154
|
+
message: "Unavailable For Legal Reasons"
|
|
155
|
+
},
|
|
156
|
+
500: {
|
|
157
|
+
name: "INTERNAL_SERVER_ERROR",
|
|
158
|
+
message: "Internal Server Error"
|
|
159
|
+
},
|
|
160
|
+
501: {
|
|
161
|
+
name: "NOT_IMPLEMENTED",
|
|
162
|
+
message: "Not Implemented"
|
|
163
|
+
},
|
|
164
|
+
502: {
|
|
165
|
+
name: "BAD_GATEWAY",
|
|
166
|
+
message: "Bad Gateway"
|
|
167
|
+
},
|
|
168
|
+
503: {
|
|
169
|
+
name: "SERVICE_UNAVAILABLE",
|
|
170
|
+
message: "Service Unavailable"
|
|
171
|
+
},
|
|
172
|
+
504: {
|
|
173
|
+
name: "GATEWAY_TIMEOUT",
|
|
174
|
+
message: "Gateway Timeout"
|
|
175
|
+
},
|
|
176
|
+
505: {
|
|
177
|
+
name: "HTTP_VERSION_NOT_SUPPORTED",
|
|
178
|
+
message: "HTTP Version Not Supported"
|
|
179
|
+
},
|
|
180
|
+
507: {
|
|
181
|
+
name: "INSUFFICIENT_STORAGE",
|
|
182
|
+
message: "Insufficient Storage"
|
|
183
|
+
},
|
|
184
|
+
511: {
|
|
185
|
+
name: "NETWORK_AUTHENTICATION_REQUIRED",
|
|
186
|
+
message: "Network Authentication Required"
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
async function handleH3Error(err, event, onError) {
|
|
190
|
+
const error = h3.isError(err) ? err : defineError(500, { data: err, stack: `${err}` });
|
|
191
|
+
h3.setResponseStatus(event, error.statusCode);
|
|
192
|
+
if (onError) {
|
|
193
|
+
await onError(error, event);
|
|
194
|
+
}
|
|
195
|
+
if (event.handled) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
await h3.send(
|
|
199
|
+
event,
|
|
200
|
+
JSON.stringify({
|
|
201
|
+
statusCode: error.statusCode,
|
|
202
|
+
statusMessage: error.statusMessage,
|
|
203
|
+
data: error.data,
|
|
204
|
+
stack: error.stack
|
|
205
|
+
})
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function isRpc(input) {
|
|
210
|
+
if (typeof input !== "object") {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
const anyInput = input;
|
|
214
|
+
if (!arriCodegenUtils.isHttpMethod(anyInput.method)) {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
if (typeof anyInput.handler !== "function") {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
function defineRpc(config) {
|
|
223
|
+
return config;
|
|
224
|
+
}
|
|
225
|
+
function createRpcDefinition(rpcName, httpPath, procedure) {
|
|
226
|
+
return {
|
|
227
|
+
description: procedure.description,
|
|
228
|
+
path: httpPath,
|
|
229
|
+
method: procedure.method ?? "post",
|
|
230
|
+
params: getRpcParamName(rpcName, procedure),
|
|
231
|
+
response: getRpcResponseDefinition(rpcName, procedure)
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function getRpcPath(rpcName, prefix = "") {
|
|
235
|
+
const path = rpcName.split(".").map(
|
|
236
|
+
(part) => arriCodegenUtils.removeDisallowedChars(
|
|
237
|
+
scule.kebabCase(part),
|
|
238
|
+
`!@#$%^&*()+=[]{}|\\;:'"<>,./?`
|
|
239
|
+
)
|
|
240
|
+
).join("/");
|
|
241
|
+
const finalPath = prefix ? `/${prefix}/${path}` : `/${path}`;
|
|
242
|
+
return finalPath;
|
|
243
|
+
}
|
|
244
|
+
function getRpcParamName(rpcName, procedure) {
|
|
245
|
+
if (!arriValidate.isAObjectSchema(procedure.params)) {
|
|
246
|
+
return void 0;
|
|
247
|
+
}
|
|
248
|
+
const nameParts = rpcName.split(".").map(
|
|
249
|
+
(part) => arriCodegenUtils.removeDisallowedChars(part, `!@#$%^&*()+=[]{}|\\;:'"<>,./?`)
|
|
250
|
+
);
|
|
251
|
+
const paramName = procedure.params.metadata.id ?? scule.pascalCase(`${nameParts.join(`_`)}_params`);
|
|
252
|
+
return paramName;
|
|
253
|
+
}
|
|
254
|
+
function getRpcResponseName(rpcName, procedure) {
|
|
255
|
+
if (!arriValidate.isAObjectSchema(procedure.response)) {
|
|
256
|
+
return void 0;
|
|
257
|
+
}
|
|
258
|
+
const nameParts = rpcName.split(".").map(
|
|
259
|
+
(part) => arriCodegenUtils.removeDisallowedChars(part, `!@#$%^&*()+=[]{}|\\;:'"<>,./?`)
|
|
260
|
+
);
|
|
261
|
+
const responseName = procedure.response.metadata.id ?? scule.pascalCase(`${nameParts.join("_")}_response`);
|
|
262
|
+
return responseName;
|
|
263
|
+
}
|
|
264
|
+
function getRpcResponseDefinition(rpcName, procedure) {
|
|
265
|
+
if (!arriValidate.isAObjectSchema(procedure.response)) {
|
|
266
|
+
return void 0;
|
|
267
|
+
}
|
|
268
|
+
const name = getRpcResponseName(rpcName, procedure);
|
|
269
|
+
if (!name) {
|
|
270
|
+
return void 0;
|
|
271
|
+
}
|
|
272
|
+
return name;
|
|
273
|
+
}
|
|
274
|
+
function registerRpc(router, path, procedure, opts) {
|
|
275
|
+
const paramValidator = procedure.params ? arriValidate.a.compile(procedure.params) : void 0;
|
|
276
|
+
const responseValidator = procedure.response ? arriValidate.a.compile(procedure.response) : void 0;
|
|
277
|
+
const httpMethod = procedure.method ?? "post";
|
|
278
|
+
const handler = h3.eventHandler(async (event) => {
|
|
279
|
+
if (h3.isPreflightRequest(event)) {
|
|
280
|
+
return "ok";
|
|
281
|
+
}
|
|
282
|
+
try {
|
|
283
|
+
if (opts.onRequest) {
|
|
284
|
+
await opts.onRequest(event);
|
|
285
|
+
}
|
|
286
|
+
if (opts.middleware.length) {
|
|
287
|
+
for (const m of opts.middleware) {
|
|
288
|
+
await m(event);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (arriValidate.isAObjectSchema(procedure.params) && paramValidator) {
|
|
292
|
+
switch (httpMethod) {
|
|
293
|
+
case "get":
|
|
294
|
+
case "head": {
|
|
295
|
+
const parsedParams = await h3.getValidatedQuery(
|
|
296
|
+
event,
|
|
297
|
+
(input) => arriValidate.a.safeCoerce(procedure.params, input)
|
|
298
|
+
);
|
|
299
|
+
if (parsedParams.success) {
|
|
300
|
+
event.context.params = parsedParams.value;
|
|
301
|
+
} else {
|
|
302
|
+
const errParts = [];
|
|
303
|
+
for (const err of parsedParams.error.errors) {
|
|
304
|
+
const errPath = err.instancePath.split("/");
|
|
305
|
+
errPath.shift();
|
|
306
|
+
const propName = errPath.join(".");
|
|
307
|
+
if (!errParts.includes(propName)) {
|
|
308
|
+
errParts.push(propName);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
const message = `Missing or invalid url query parameters: [${errParts.join(
|
|
312
|
+
", "
|
|
313
|
+
)}]`;
|
|
314
|
+
throw defineError(400, {
|
|
315
|
+
statusMessage: message,
|
|
316
|
+
data: parsedParams.error
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
case "delete":
|
|
322
|
+
case "patch":
|
|
323
|
+
case "post":
|
|
324
|
+
case "put": {
|
|
325
|
+
const body = await h3.readRawBody(event);
|
|
326
|
+
if (!body) {
|
|
327
|
+
throw defineError(400, {
|
|
328
|
+
statusMessage: `Invalid request body. Expected object. Got undefined.`
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
const parsedParams = paramValidator.safeParse(body);
|
|
332
|
+
if (!parsedParams.success) {
|
|
333
|
+
const errorParts = [];
|
|
334
|
+
for (const err of parsedParams.error.errors) {
|
|
335
|
+
const errPath = err.instancePath.split("/");
|
|
336
|
+
errPath.shift();
|
|
337
|
+
if (!errorParts.includes(errPath.join("."))) {
|
|
338
|
+
errorParts.push(errPath.join("."));
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
throw defineError(400, {
|
|
342
|
+
statusMessage: `Invalid request body. Affected properties [${errorParts.join(
|
|
343
|
+
", "
|
|
344
|
+
)}]`,
|
|
345
|
+
data: parsedParams.error
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
event.context.params = parsedParams.value;
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
default:
|
|
352
|
+
break;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
const response = await procedure.handler(
|
|
356
|
+
event.context,
|
|
357
|
+
event
|
|
358
|
+
);
|
|
359
|
+
event.context.response = response;
|
|
360
|
+
if (opts.onBeforeResponse) {
|
|
361
|
+
await opts.onBeforeResponse(event);
|
|
362
|
+
}
|
|
363
|
+
if (typeof response === "object") {
|
|
364
|
+
h3.setResponseHeader(event, "Content-Type", "application/json");
|
|
365
|
+
await h3.send(
|
|
366
|
+
event,
|
|
367
|
+
responseValidator?.serialize(response) ?? JSON.stringify(response)
|
|
368
|
+
);
|
|
369
|
+
} else {
|
|
370
|
+
await h3.send(
|
|
371
|
+
event,
|
|
372
|
+
response ?? `<!doctype html>
|
|
373
|
+
<html lang="en">
|
|
374
|
+
<head>
|
|
375
|
+
<meta charset="UTF-8" />
|
|
376
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
377
|
+
<title>Empty Response</title>
|
|
378
|
+
</head>
|
|
379
|
+
<body>
|
|
380
|
+
nothing to see here
|
|
381
|
+
</body>
|
|
382
|
+
</html>
|
|
383
|
+
`
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
if (opts.onAfterResponse) {
|
|
387
|
+
await opts.onAfterResponse(event);
|
|
388
|
+
}
|
|
389
|
+
if (procedure.postHandler) {
|
|
390
|
+
await procedure.postHandler(event.context, event);
|
|
391
|
+
}
|
|
392
|
+
} catch (err) {
|
|
393
|
+
await handleH3Error(err, event, opts.onError);
|
|
394
|
+
}
|
|
395
|
+
return "";
|
|
396
|
+
});
|
|
397
|
+
switch (httpMethod) {
|
|
398
|
+
case "get":
|
|
399
|
+
router.get(path, handler);
|
|
400
|
+
break;
|
|
401
|
+
case "head":
|
|
402
|
+
router.head(path, handler);
|
|
403
|
+
break;
|
|
404
|
+
case "delete":
|
|
405
|
+
router.delete(path, handler);
|
|
406
|
+
break;
|
|
407
|
+
case "patch":
|
|
408
|
+
router.patch(path, handler);
|
|
409
|
+
break;
|
|
410
|
+
case "put":
|
|
411
|
+
router.put(path, handler);
|
|
412
|
+
break;
|
|
413
|
+
case "post":
|
|
414
|
+
default:
|
|
415
|
+
router.post(path, handler);
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
var __defProp$1 = Object.defineProperty;
|
|
421
|
+
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
422
|
+
var __publicField$1 = (obj, key, value) => {
|
|
423
|
+
__defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
424
|
+
return value;
|
|
425
|
+
};
|
|
426
|
+
class ArriRouter {
|
|
427
|
+
constructor() {
|
|
428
|
+
__publicField$1(this, "procedures", []);
|
|
429
|
+
__publicField$1(this, "routes", []);
|
|
430
|
+
}
|
|
431
|
+
rpc(procedure) {
|
|
432
|
+
this.procedures.push(procedure);
|
|
433
|
+
}
|
|
434
|
+
route(route) {
|
|
435
|
+
this.routes.push(route);
|
|
436
|
+
}
|
|
437
|
+
getProcedures() {
|
|
438
|
+
return this.procedures;
|
|
439
|
+
}
|
|
440
|
+
getRoutes() {
|
|
441
|
+
return this.routes;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function registerRoute(router, route, opts) {
|
|
446
|
+
if (typeof route.method === "string") {
|
|
447
|
+
handleRoute(router, route.method, route, opts);
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
for (const method of route.method) {
|
|
451
|
+
handleRoute(router, method, route, opts);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
function handleRoute(router, method, route, opts) {
|
|
455
|
+
const handler = h3.defineEventHandler(async (event) => {
|
|
456
|
+
try {
|
|
457
|
+
if (opts.onRequest) {
|
|
458
|
+
await opts.onRequest(event);
|
|
459
|
+
}
|
|
460
|
+
if (opts.middleware.length) {
|
|
461
|
+
for (const m of opts.middleware) {
|
|
462
|
+
await m(event);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
const response = await route.handler(event);
|
|
466
|
+
event.context.response = response;
|
|
467
|
+
if (!event.handled) {
|
|
468
|
+
if (opts.onBeforeResponse) {
|
|
469
|
+
await opts.onBeforeResponse(event);
|
|
470
|
+
}
|
|
471
|
+
if (typeof response === "object" && response) {
|
|
472
|
+
h3.setHeader(event, "Content-Type", "application/json");
|
|
473
|
+
await h3.send(event, JSON.stringify(response));
|
|
474
|
+
} else {
|
|
475
|
+
await h3.send(event, response);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
if (opts.onAfterResponse) {
|
|
479
|
+
await opts.onAfterResponse(event);
|
|
480
|
+
}
|
|
481
|
+
if (route.postHandler) {
|
|
482
|
+
await route.postHandler(event);
|
|
483
|
+
}
|
|
484
|
+
} catch (err) {
|
|
485
|
+
await handleH3Error(err, event, opts.onError);
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
switch (method) {
|
|
489
|
+
case "get":
|
|
490
|
+
router.get(route.path, handler);
|
|
491
|
+
break;
|
|
492
|
+
case "delete":
|
|
493
|
+
router.delete(route.path, handler);
|
|
494
|
+
break;
|
|
495
|
+
case "head":
|
|
496
|
+
router.head(route.path, handler);
|
|
497
|
+
break;
|
|
498
|
+
case "patch":
|
|
499
|
+
router.patch(route.path, handler);
|
|
500
|
+
break;
|
|
501
|
+
case "post":
|
|
502
|
+
router.post(route.path, handler);
|
|
503
|
+
break;
|
|
504
|
+
case "put":
|
|
505
|
+
router.put(route.path, handler);
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
var __defProp = Object.defineProperty;
|
|
511
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
512
|
+
var __publicField = (obj, key, value) => {
|
|
513
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
514
|
+
return value;
|
|
515
|
+
};
|
|
516
|
+
const DEV_ENDPOINT_ROOT = `/__arri_dev__`;
|
|
517
|
+
const DEV_DEFINITION_ENDPOINT = `${DEV_ENDPOINT_ROOT}/__definition`;
|
|
518
|
+
class ArriApp {
|
|
519
|
+
constructor(opts = {}) {
|
|
520
|
+
__publicField(this, "__isArri__", true);
|
|
521
|
+
__publicField(this, "h3App");
|
|
522
|
+
__publicField(this, "h3Router", h3.createRouter());
|
|
523
|
+
__publicField(this, "rpcDefinitionPath");
|
|
524
|
+
__publicField(this, "rpcRoutePrefix");
|
|
525
|
+
__publicField(this, "appInfo");
|
|
526
|
+
__publicField(this, "procedures", {});
|
|
527
|
+
__publicField(this, "models", {});
|
|
528
|
+
__publicField(this, "middlewares", []);
|
|
529
|
+
__publicField(this, "onRequest");
|
|
530
|
+
__publicField(this, "onAfterResponse");
|
|
531
|
+
__publicField(this, "onBeforeResponse");
|
|
532
|
+
__publicField(this, "onError");
|
|
533
|
+
this.appInfo = opts?.appInfo;
|
|
534
|
+
this.h3App = h3.createApp({
|
|
535
|
+
debug: opts?.debug
|
|
536
|
+
});
|
|
537
|
+
this.onError = opts.onError;
|
|
538
|
+
this.onAfterResponse = opts.onAfterResponse;
|
|
539
|
+
this.onBeforeResponse = opts.onBeforeResponse;
|
|
540
|
+
this.rpcRoutePrefix = opts?.rpcRoutePrefix ?? "";
|
|
541
|
+
this.rpcDefinitionPath = opts?.rpcDefinitionPath ?? "__definition";
|
|
542
|
+
this.h3App.use(this.h3Router);
|
|
543
|
+
this.h3Router.get(
|
|
544
|
+
this.rpcRoutePrefix ? `/${this.rpcRoutePrefix}/${this.rpcDefinitionPath}`.split("//").join("/") : `/${this.rpcDefinitionPath}`,
|
|
545
|
+
h3.eventHandler(() => this.getAppDefinition())
|
|
546
|
+
);
|
|
547
|
+
if (process.env.ARRI_DEV_MODE === "true") {
|
|
548
|
+
this.h3Router.get(
|
|
549
|
+
DEV_DEFINITION_ENDPOINT,
|
|
550
|
+
h3.eventHandler(() => this.getAppDefinition())
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
this.h3Router.use(
|
|
554
|
+
"/**",
|
|
555
|
+
h3.eventHandler(async (event) => {
|
|
556
|
+
h3.setResponseStatus(event, 404);
|
|
557
|
+
const error = defineError(404);
|
|
558
|
+
try {
|
|
559
|
+
if (this.middlewares.length) {
|
|
560
|
+
for (const m of this.middlewares) {
|
|
561
|
+
await m(event);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
} catch (err) {
|
|
565
|
+
await handleH3Error(err, event, this.onError);
|
|
566
|
+
}
|
|
567
|
+
if (event.handled) {
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
if (this.onError) {
|
|
571
|
+
await this.onError(error, event);
|
|
572
|
+
}
|
|
573
|
+
if (event.handled) {
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
h3.sendError(event, error);
|
|
577
|
+
})
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
use(input) {
|
|
581
|
+
if (typeof input === "object" && input instanceof ArriRouter) {
|
|
582
|
+
for (const route of input.getRoutes()) {
|
|
583
|
+
this.route(route);
|
|
584
|
+
}
|
|
585
|
+
for (const rpc of input.getProcedures()) {
|
|
586
|
+
this.rpc(rpc);
|
|
587
|
+
}
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
this.middlewares.push(input);
|
|
591
|
+
}
|
|
592
|
+
rpc(procedure) {
|
|
593
|
+
const path = getRpcPath(procedure.name, this.rpcRoutePrefix);
|
|
594
|
+
this.procedures[procedure.name] = createRpcDefinition(
|
|
595
|
+
procedure.name,
|
|
596
|
+
path,
|
|
597
|
+
procedure
|
|
598
|
+
);
|
|
599
|
+
if (arriValidate.isAObjectSchema(procedure.params)) {
|
|
600
|
+
const paramName = getRpcParamName(procedure.name, procedure);
|
|
601
|
+
if (paramName) {
|
|
602
|
+
this.models[paramName] = procedure.params;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
if (arriValidate.isAObjectSchema(procedure.response)) {
|
|
606
|
+
const responseName = getRpcResponseName(procedure.name, procedure);
|
|
607
|
+
if (responseName) {
|
|
608
|
+
this.models[responseName] = procedure.response;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
registerRpc(this.h3Router, path, procedure, {
|
|
612
|
+
middleware: this.middlewares,
|
|
613
|
+
onError: this.onError,
|
|
614
|
+
onAfterResponse: this.onAfterResponse,
|
|
615
|
+
onBeforeResponse: this.onBeforeResponse
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
route(route) {
|
|
619
|
+
registerRoute(this.h3Router, route, {
|
|
620
|
+
middleware: this.middlewares,
|
|
621
|
+
onError: this.onError,
|
|
622
|
+
onAfterResponse: this.onAfterResponse,
|
|
623
|
+
onBeforeResponse: this.onBeforeResponse
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
getAppDefinition() {
|
|
627
|
+
const appDef = {
|
|
628
|
+
arriSchemaVersion: "0.0.2",
|
|
629
|
+
info: this.appInfo,
|
|
630
|
+
procedures: {},
|
|
631
|
+
models: this.models,
|
|
632
|
+
errors: ErrorResponse
|
|
633
|
+
};
|
|
634
|
+
for (const key of Object.keys(this.procedures)) {
|
|
635
|
+
const rpc = this.procedures[key];
|
|
636
|
+
appDef.procedures[key] = rpc;
|
|
637
|
+
}
|
|
638
|
+
return appDef;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
function isArriConfig(input) {
|
|
643
|
+
if (typeof input !== "object" || !input) {
|
|
644
|
+
return false;
|
|
645
|
+
}
|
|
646
|
+
return "port" in input && typeof input.port === "number" && !Number.isNaN(input.port) && "entry" in input && typeof input.entry === "string";
|
|
647
|
+
}
|
|
648
|
+
function isResolvedArriConfig(input) {
|
|
649
|
+
if (!isArriConfig(input)) {
|
|
650
|
+
return false;
|
|
651
|
+
}
|
|
652
|
+
return typeof input.rootDir === "string" && typeof input.srcDir === "string" && (typeof input.procedureDir === "string" || typeof input.procedureDir === "boolean") && Array.isArray(input.procedureGlobPatterns) && Array.isArray(input.clientGenerators) && typeof input.buildDir === "string" && typeof input.esbuild === "object" && input.esbuild && !Array.isArray(input.esbuild);
|
|
653
|
+
}
|
|
654
|
+
const defaultConfig = {
|
|
655
|
+
port: 3e3,
|
|
656
|
+
rootDir: ".",
|
|
657
|
+
srcDir: ".",
|
|
658
|
+
entry: "app.ts",
|
|
659
|
+
procedureDir: "procedures",
|
|
660
|
+
procedureGlobPatterns: ["**/*.rpc.ts"],
|
|
661
|
+
clientGenerators: [],
|
|
662
|
+
buildDir: ".arri",
|
|
663
|
+
esbuild: {}
|
|
664
|
+
};
|
|
665
|
+
function defineConfig(config) {
|
|
666
|
+
return {
|
|
667
|
+
port: config.port ?? defaultConfig.port,
|
|
668
|
+
rootDir: config.rootDir ?? defaultConfig.rootDir,
|
|
669
|
+
srcDir: config.srcDir ?? defaultConfig.srcDir,
|
|
670
|
+
entry: config.entry ?? defaultConfig.entry,
|
|
671
|
+
procedureDir: config.procedureDir ?? defaultConfig.procedureDir,
|
|
672
|
+
procedureGlobPatterns: config.procedureGlobPatterns ?? defaultConfig.procedureGlobPatterns,
|
|
673
|
+
clientGenerators: config.clientGenerators ?? defaultConfig.clientGenerators,
|
|
674
|
+
buildDir: config.buildDir ?? defaultConfig.buildDir,
|
|
675
|
+
esbuild: config.esbuild ?? defaultConfig.esbuild
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
exports.ArriApp = ArriApp;
|
|
680
|
+
exports.ArriRouter = ArriRouter;
|
|
681
|
+
exports.DEV_DEFINITION_ENDPOINT = DEV_DEFINITION_ENDPOINT;
|
|
682
|
+
exports.DEV_ENDPOINT_ROOT = DEV_ENDPOINT_ROOT;
|
|
683
|
+
exports.ErrorResponse = ErrorResponse;
|
|
684
|
+
exports.createRpcDefinition = createRpcDefinition;
|
|
685
|
+
exports.defaultConfig = defaultConfig;
|
|
686
|
+
exports.defineConfig = defineConfig;
|
|
687
|
+
exports.defineError = defineError;
|
|
688
|
+
exports.defineRpc = defineRpc;
|
|
689
|
+
exports.errorResponseFromValidationErrors = errorResponseFromValidationErrors;
|
|
690
|
+
exports.getRpcParamName = getRpcParamName;
|
|
691
|
+
exports.getRpcPath = getRpcPath;
|
|
692
|
+
exports.getRpcResponseName = getRpcResponseName;
|
|
693
|
+
exports.handleH3Error = handleH3Error;
|
|
694
|
+
exports.isArriConfig = isArriConfig;
|
|
695
|
+
exports.isResolvedArriConfig = isResolvedArriConfig;
|
|
696
|
+
exports.isRpc = isRpc;
|
|
697
|
+
exports.registerRpc = registerRpc;
|