better-call 0.2.13-beta.8 → 0.2.14-beta.1
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 +378 -2
- package/dist/client.cjs +33 -8
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +3 -7
- package/dist/client.d.ts +3 -7
- package/dist/client.js +14 -0
- package/dist/client.js.map +1 -0
- package/dist/index.cjs +524 -393
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +115 -20
- package/dist/index.d.ts +115 -20
- package/dist/{index.mjs → index.js} +463 -368
- package/dist/index.js.map +1 -0
- package/dist/router-Bn7zn81P.d.cts +342 -0
- package/dist/router-Bn7zn81P.d.ts +342 -0
- package/package.json +24 -28
- package/dist/adapter/node.cjs +0 -210
- package/dist/adapter/node.d.cts +0 -19
- package/dist/adapter/node.d.mts +0 -19
- package/dist/adapter/node.d.ts +0 -19
- package/dist/adapter/node.mjs +0 -206
- package/dist/client.d.mts +0 -42
- package/dist/client.mjs +0 -12
- package/dist/index.d.mts +0 -32
- package/dist/shared/better-call.25f0dd59.d.cts +0 -677
- package/dist/shared/better-call.25f0dd59.d.mts +0 -677
- package/dist/shared/better-call.25f0dd59.d.ts +0 -677
|
@@ -1,181 +1,71 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import { createRouter as createRouter$1, addRoute, findRoute, findAllRoutes } from 'rou3';
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
data: null,
|
|
26
|
-
error: fromError(result.error)
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
request.query = result.data;
|
|
30
|
-
}
|
|
31
|
-
if (options.requireHeaders && !(context.headers instanceof Headers)) {
|
|
32
|
-
return {
|
|
33
|
-
data: null,
|
|
34
|
-
error: { message: "Validation Error: Headers are required" }
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
if (options.requireRequest && !context.request) {
|
|
38
|
-
return {
|
|
39
|
-
data: null,
|
|
40
|
-
error: { message: "Validation Error: Request is required" }
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
return {
|
|
44
|
-
data: request,
|
|
45
|
-
error: null
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
function fromError(error) {
|
|
49
|
-
const errorMessages = [];
|
|
50
|
-
for (const issue of error.issues) {
|
|
51
|
-
const path = issue.path.join(".");
|
|
52
|
-
const message = issue.message;
|
|
53
|
-
if (path) {
|
|
54
|
-
errorMessages.push(`${message} at "${path}"`);
|
|
55
|
-
} else {
|
|
56
|
-
errorMessages.push(message);
|
|
5
|
+
// src/endpoint.ts
|
|
6
|
+
import { ZodError } from "zod";
|
|
7
|
+
|
|
8
|
+
// src/error.ts
|
|
9
|
+
var APIError = class extends Error {
|
|
10
|
+
constructor(status, body, headers) {
|
|
11
|
+
super(`API Error: ${status} ${body?.message ?? ""}`, {
|
|
12
|
+
cause: body
|
|
13
|
+
});
|
|
14
|
+
__publicField(this, "status");
|
|
15
|
+
__publicField(this, "headers");
|
|
16
|
+
__publicField(this, "body");
|
|
17
|
+
this.status = status;
|
|
18
|
+
this.body = body ?? {};
|
|
19
|
+
this.stack = "";
|
|
20
|
+
this.headers = headers ?? new Headers();
|
|
21
|
+
if (!this.headers.has("Content-Type")) {
|
|
22
|
+
this.headers.set("Content-Type", "application/json");
|
|
57
23
|
}
|
|
24
|
+
this.name = "BetterCallAPIError";
|
|
58
25
|
}
|
|
59
|
-
|
|
60
|
-
message: `Validation error: ${errorMessages.join(", ")}`
|
|
61
|
-
};
|
|
62
|
-
}
|
|
26
|
+
};
|
|
63
27
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
28
|
+
// src/helper.ts
|
|
29
|
+
var json = (body, option) => {
|
|
30
|
+
return {
|
|
31
|
+
response: {
|
|
32
|
+
body: option?.body ?? body,
|
|
33
|
+
status: option?.status ?? 200,
|
|
34
|
+
statusText: option?.statusText ?? "OK",
|
|
35
|
+
headers: option?.headers
|
|
36
|
+
},
|
|
37
|
+
body,
|
|
38
|
+
_flag: "json"
|
|
72
39
|
};
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const _statusCode = {
|
|
76
|
-
OK: 200,
|
|
77
|
-
CREATED: 201,
|
|
78
|
-
ACCEPTED: 202,
|
|
79
|
-
NO_CONTENT: 204,
|
|
80
|
-
MULTIPLE_CHOICES: 300,
|
|
81
|
-
MOVED_PERMANENTLY: 301,
|
|
82
|
-
FOUND: 302,
|
|
83
|
-
SEE_OTHER: 303,
|
|
84
|
-
NOT_MODIFIED: 304,
|
|
85
|
-
TEMPORARY_REDIRECT: 307,
|
|
86
|
-
BAD_REQUEST: 400,
|
|
87
|
-
UNAUTHORIZED: 401,
|
|
88
|
-
PAYMENT_REQUIRED: 402,
|
|
89
|
-
FORBIDDEN: 403,
|
|
90
|
-
NOT_FOUND: 404,
|
|
91
|
-
METHOD_NOT_ALLOWED: 405,
|
|
92
|
-
NOT_ACCEPTABLE: 406,
|
|
93
|
-
PROXY_AUTHENTICATION_REQUIRED: 407,
|
|
94
|
-
REQUEST_TIMEOUT: 408,
|
|
95
|
-
CONFLICT: 409,
|
|
96
|
-
GONE: 410,
|
|
97
|
-
LENGTH_REQUIRED: 411,
|
|
98
|
-
PRECONDITION_FAILED: 412,
|
|
99
|
-
PAYLOAD_TOO_LARGE: 413,
|
|
100
|
-
URI_TOO_LONG: 414,
|
|
101
|
-
UNSUPPORTED_MEDIA_TYPE: 415,
|
|
102
|
-
RANGE_NOT_SATISFIABLE: 416,
|
|
103
|
-
EXPECTATION_FAILED: 417,
|
|
104
|
-
"I'M_A_TEAPOT": 418,
|
|
105
|
-
MISDIRECTED_REQUEST: 421,
|
|
106
|
-
UNPROCESSABLE_ENTITY: 422,
|
|
107
|
-
LOCKED: 423,
|
|
108
|
-
FAILED_DEPENDENCY: 424,
|
|
109
|
-
TOO_EARLY: 425,
|
|
110
|
-
UPGRADE_REQUIRED: 426,
|
|
111
|
-
PRECONDITION_REQUIRED: 428,
|
|
112
|
-
TOO_MANY_REQUESTS: 429,
|
|
113
|
-
REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
|
|
114
|
-
UNAVAILABLE_FOR_LEGAL_REASONS: 451,
|
|
115
|
-
INTERNAL_SERVER_ERROR: 500,
|
|
116
|
-
NOT_IMPLEMENTED: 501,
|
|
117
|
-
BAD_GATEWAY: 502,
|
|
118
|
-
SERVICE_UNAVAILABLE: 503,
|
|
119
|
-
GATEWAY_TIMEOUT: 504,
|
|
120
|
-
HTTP_VERSION_NOT_SUPPORTED: 505,
|
|
121
|
-
VARIANT_ALSO_NEGOTIATES: 506,
|
|
122
|
-
INSUFFICIENT_STORAGE: 507,
|
|
123
|
-
LOOP_DETECTED: 508,
|
|
124
|
-
NOT_EXTENDED: 510,
|
|
125
|
-
NETWORK_AUTHENTICATION_REQUIRED: 511
|
|
126
40
|
};
|
|
127
|
-
class APIError extends Error {
|
|
128
|
-
constructor(status = "INTERNAL_SERVER_ERROR", body = void 0, headers = {}, statusCode = _statusCode[status]) {
|
|
129
|
-
super(body?.message || status);
|
|
130
|
-
this.status = status;
|
|
131
|
-
this.body = body;
|
|
132
|
-
this.headers = headers;
|
|
133
|
-
this.statusCode = statusCode;
|
|
134
|
-
this.name = "APIError";
|
|
135
|
-
this.status = status;
|
|
136
|
-
this.headers = headers;
|
|
137
|
-
this.statusCode = statusCode;
|
|
138
|
-
this.stack = "";
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
41
|
|
|
142
|
-
|
|
143
|
-
|
|
42
|
+
// src/cookie.ts
|
|
43
|
+
import { subtle } from "uncrypto";
|
|
44
|
+
var algorithm = { name: "HMAC", hash: "SHA-256" };
|
|
45
|
+
var getCryptoKey = async (secret) => {
|
|
144
46
|
const secretBuf = typeof secret === "string" ? new TextEncoder().encode(secret) : secret;
|
|
145
|
-
return await
|
|
146
|
-
"sign",
|
|
147
|
-
"verify"
|
|
148
|
-
]);
|
|
47
|
+
return await subtle.importKey("raw", secretBuf, algorithm, false, ["sign", "verify"]);
|
|
149
48
|
};
|
|
150
|
-
|
|
49
|
+
var makeSignature = async (value, secret) => {
|
|
151
50
|
const key = await getCryptoKey(secret);
|
|
152
|
-
const signature = await
|
|
153
|
-
algorithm.name,
|
|
154
|
-
key,
|
|
155
|
-
new TextEncoder().encode(value)
|
|
156
|
-
);
|
|
51
|
+
const signature = await subtle.sign(algorithm.name, key, new TextEncoder().encode(value));
|
|
157
52
|
return btoa(String.fromCharCode(...new Uint8Array(signature)));
|
|
158
53
|
};
|
|
159
|
-
|
|
54
|
+
var verifySignature = async (base64Signature, value, secret) => {
|
|
160
55
|
try {
|
|
161
56
|
const signatureBinStr = atob(base64Signature);
|
|
162
57
|
const signature = new Uint8Array(signatureBinStr.length);
|
|
163
58
|
for (let i = 0, len = signatureBinStr.length; i < len; i++) {
|
|
164
59
|
signature[i] = signatureBinStr.charCodeAt(i);
|
|
165
60
|
}
|
|
166
|
-
return await
|
|
167
|
-
algorithm,
|
|
168
|
-
secret,
|
|
169
|
-
signature,
|
|
170
|
-
new TextEncoder().encode(value)
|
|
171
|
-
);
|
|
61
|
+
return await subtle.verify(algorithm, secret, signature, new TextEncoder().encode(value));
|
|
172
62
|
} catch (e) {
|
|
173
63
|
return false;
|
|
174
64
|
}
|
|
175
65
|
};
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
66
|
+
var validCookieNameRegEx = /^[\w!#$%&'*.^`|~+-]+$/;
|
|
67
|
+
var validCookieValueRegEx = /^[ !#-:<-[\]-~]*$/;
|
|
68
|
+
var parse = (cookie, name) => {
|
|
179
69
|
const pairs = cookie.trim().split(";");
|
|
180
70
|
return pairs.reduce((parsedCookie, pairStr) => {
|
|
181
71
|
pairStr = pairStr.trim();
|
|
@@ -197,7 +87,7 @@ const parse = (cookie, name) => {
|
|
|
197
87
|
return parsedCookie;
|
|
198
88
|
}, {});
|
|
199
89
|
};
|
|
200
|
-
|
|
90
|
+
var parseSigned = async (cookie, secret, name) => {
|
|
201
91
|
const parsedCookie = {};
|
|
202
92
|
const secretKey = await getCryptoKey(secret);
|
|
203
93
|
for (const [key, value] of Object.entries(parse(cookie, name))) {
|
|
@@ -215,7 +105,7 @@ const parseSigned = async (cookie, secret, name) => {
|
|
|
215
105
|
}
|
|
216
106
|
return parsedCookie;
|
|
217
107
|
};
|
|
218
|
-
|
|
108
|
+
var _serialize = (name, value, opt = {}) => {
|
|
219
109
|
let cookie = `${name}=${value}`;
|
|
220
110
|
if (name.startsWith("__Secure-") && !opt.secure) {
|
|
221
111
|
opt.secure = true;
|
|
@@ -270,18 +160,19 @@ const _serialize = (name, value, opt = {}) => {
|
|
|
270
160
|
}
|
|
271
161
|
return cookie;
|
|
272
162
|
};
|
|
273
|
-
|
|
163
|
+
var serialize = (name, value, opt) => {
|
|
274
164
|
value = encodeURIComponent(value);
|
|
275
165
|
return _serialize(name, value, opt);
|
|
276
166
|
};
|
|
277
|
-
|
|
167
|
+
var serializeSigned = async (name, value, secret, opt = {}) => {
|
|
278
168
|
const signature = await makeSignature(value, secret);
|
|
279
169
|
value = `${value}.${signature}`;
|
|
280
170
|
value = encodeURIComponent(value);
|
|
281
171
|
return _serialize(name, value, opt);
|
|
282
172
|
};
|
|
283
173
|
|
|
284
|
-
|
|
174
|
+
// src/cookie-utils.ts
|
|
175
|
+
var getCookie = (cookie, key, prefix) => {
|
|
285
176
|
if (!cookie) {
|
|
286
177
|
return void 0;
|
|
287
178
|
}
|
|
@@ -298,23 +189,17 @@ const getCookie = (cookie, key, prefix) => {
|
|
|
298
189
|
const obj = parse(cookie, finalKey);
|
|
299
190
|
return obj[finalKey];
|
|
300
191
|
};
|
|
301
|
-
|
|
192
|
+
var setCookie = (header, name, value, opt) => {
|
|
302
193
|
const existingCookies = header.get("Set-Cookie");
|
|
303
194
|
if (existingCookies) {
|
|
304
195
|
const cookies = existingCookies.split(", ");
|
|
305
|
-
const updatedCookies = cookies.filter(
|
|
306
|
-
(cookie2) => !cookie2.startsWith(`${name}=`)
|
|
307
|
-
);
|
|
196
|
+
const updatedCookies = cookies.filter((cookie2) => !cookie2.startsWith(`${name}=`));
|
|
308
197
|
header.delete("Set-Cookie");
|
|
309
198
|
updatedCookies.forEach((cookie2) => header.append("Set-Cookie", cookie2));
|
|
310
199
|
}
|
|
311
200
|
let cookie;
|
|
312
201
|
if (opt?.prefix === "secure") {
|
|
313
|
-
cookie = serialize("__Secure-" + name, value, {
|
|
314
|
-
path: "/",
|
|
315
|
-
...opt,
|
|
316
|
-
secure: true
|
|
317
|
-
});
|
|
202
|
+
cookie = serialize("__Secure-" + name, value, { path: "/", ...opt, secure: true });
|
|
318
203
|
} else if (opt?.prefix === "host") {
|
|
319
204
|
cookie = serialize("__Host-" + name, value, {
|
|
320
205
|
...opt,
|
|
@@ -327,7 +212,7 @@ const setCookie = (header, name, value, opt) => {
|
|
|
327
212
|
}
|
|
328
213
|
header.append("Set-Cookie", cookie);
|
|
329
214
|
};
|
|
330
|
-
|
|
215
|
+
var setSignedCookie = async (header, name, value, secret, opt) => {
|
|
331
216
|
let cookie;
|
|
332
217
|
if (opt?.prefix === "secure") {
|
|
333
218
|
cookie = await serializeSigned("__Secure-" + name, value, secret, {
|
|
@@ -347,7 +232,7 @@ const setSignedCookie = async (header, name, value, secret, opt) => {
|
|
|
347
232
|
}
|
|
348
233
|
header.append("Set-Cookie", cookie);
|
|
349
234
|
};
|
|
350
|
-
|
|
235
|
+
var getSignedCookie = async (header, secret, key, prefix) => {
|
|
351
236
|
const cookie = header.get("cookie");
|
|
352
237
|
if (!cookie) {
|
|
353
238
|
return void 0;
|
|
@@ -364,204 +249,163 @@ const getSignedCookie = async (header, secret, key, prefix) => {
|
|
|
364
249
|
return obj[finalKey];
|
|
365
250
|
};
|
|
366
251
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
zod.merge(z.object({ [param.slice(1)]: z.string() }));
|
|
373
|
-
}
|
|
374
|
-
return zod;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
extendZodWithOpenApi(z);
|
|
378
|
-
const createResponse = (handlerResponse, response) => {
|
|
379
|
-
if (handlerResponse instanceof Response) {
|
|
380
|
-
response.headers.forEach((value, key) => {
|
|
381
|
-
handlerResponse.headers.set(key, value);
|
|
382
|
-
});
|
|
383
|
-
return handlerResponse;
|
|
384
|
-
} else if (handlerResponse?._flag === "json") {
|
|
385
|
-
const responseObj = new Response(
|
|
386
|
-
JSON.stringify(
|
|
387
|
-
handlerResponse.routerResponse?.body || handlerResponse.body
|
|
388
|
-
),
|
|
252
|
+
// src/endpoint.ts
|
|
253
|
+
function createEndpointCreator(opts) {
|
|
254
|
+
return (path, options, handler) => {
|
|
255
|
+
return createEndpoint(
|
|
256
|
+
path,
|
|
389
257
|
{
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
}
|
|
393
|
-
);
|
|
394
|
-
response.headers.forEach((value, key) => {
|
|
395
|
-
responseObj.headers.set(key, value);
|
|
396
|
-
});
|
|
397
|
-
return responseObj;
|
|
398
|
-
} else {
|
|
399
|
-
const responseObj = new Response(
|
|
400
|
-
handlerResponse ? JSON.stringify(handlerResponse) : void 0
|
|
401
|
-
);
|
|
402
|
-
response.headers.forEach((value, key) => {
|
|
403
|
-
responseObj.headers.set(key, value);
|
|
404
|
-
});
|
|
405
|
-
return responseObj;
|
|
406
|
-
}
|
|
407
|
-
};
|
|
408
|
-
const runMiddleware = async (options, context) => {
|
|
409
|
-
let finalContext = {};
|
|
410
|
-
for (const middleware of options.use || []) {
|
|
411
|
-
const result = await middleware(context);
|
|
412
|
-
if (result?.context && result._flag === "context") {
|
|
413
|
-
context = { ...context, ...result.context };
|
|
414
|
-
} else {
|
|
415
|
-
finalContext = { ...result, ...finalContext };
|
|
416
|
-
context.context = finalContext;
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
return finalContext;
|
|
420
|
-
};
|
|
421
|
-
const createEndpoint = (path, options, handler) => {
|
|
422
|
-
const internalHandler = async (...inputCtx) => {
|
|
423
|
-
let response = new Response();
|
|
424
|
-
const { asResponse, ...ctx } = inputCtx[0] || {};
|
|
425
|
-
const { data, error } = runValidation(options, ctx);
|
|
426
|
-
if (error) {
|
|
427
|
-
throw new APIError("BAD_REQUEST", {
|
|
428
|
-
message: error.message
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
const context = {
|
|
432
|
-
json: (json, routerResponse) => {
|
|
433
|
-
if (!asResponse) {
|
|
434
|
-
return json;
|
|
435
|
-
}
|
|
436
|
-
return {
|
|
437
|
-
body: json,
|
|
438
|
-
routerResponse,
|
|
439
|
-
_flag: "json"
|
|
440
|
-
};
|
|
258
|
+
...options,
|
|
259
|
+
use: [...options?.use || [], ...opts?.use || []]
|
|
441
260
|
},
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
if (!requestHeaders)
|
|
453
|
-
return null;
|
|
454
|
-
return requestHeaders.get(key);
|
|
261
|
+
handler
|
|
262
|
+
);
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
function createEndpoint(path, options, handler) {
|
|
266
|
+
let responseHeader = new Headers();
|
|
267
|
+
const handle = async (...ctx) => {
|
|
268
|
+
let internalCtx = {
|
|
269
|
+
setHeader(key, value) {
|
|
270
|
+
responseHeader.set(key, value);
|
|
455
271
|
},
|
|
456
|
-
setCookie
|
|
457
|
-
setCookie(
|
|
272
|
+
setCookie(key, value, options2) {
|
|
273
|
+
setCookie(responseHeader, key, value, options2);
|
|
458
274
|
},
|
|
459
275
|
getCookie(key, prefix) {
|
|
460
|
-
const
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
return
|
|
276
|
+
const header = ctx[0]?.headers;
|
|
277
|
+
const cookieH = header?.get("cookie");
|
|
278
|
+
const cookie = getCookie(cookieH || "", key, prefix);
|
|
279
|
+
return cookie;
|
|
464
280
|
},
|
|
465
|
-
|
|
466
|
-
|
|
281
|
+
getSignedCookie(key, secret, prefix) {
|
|
282
|
+
const header = ctx[0]?.headers;
|
|
283
|
+
if (!header) {
|
|
284
|
+
throw new TypeError("Headers are required");
|
|
285
|
+
}
|
|
286
|
+
const cookie = getSignedCookie(header, secret, key, prefix);
|
|
287
|
+
return cookie;
|
|
467
288
|
},
|
|
468
|
-
async
|
|
469
|
-
|
|
470
|
-
if (!headers)
|
|
471
|
-
return void 0;
|
|
472
|
-
return getSignedCookie(headers, secret, key, prefix);
|
|
289
|
+
async setSignedCookie(key, value, secret, options2) {
|
|
290
|
+
await setSignedCookie(responseHeader, key, value, secret, options2);
|
|
473
291
|
},
|
|
474
|
-
redirect
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
...response.headers
|
|
478
|
-
});
|
|
479
|
-
return apiError;
|
|
292
|
+
redirect(url) {
|
|
293
|
+
responseHeader.set("Location", url);
|
|
294
|
+
return new APIError("FOUND");
|
|
480
295
|
},
|
|
481
|
-
|
|
296
|
+
json,
|
|
297
|
+
context: ctx[0]?.context || {},
|
|
298
|
+
_flag: ctx[0]?.asResponse ? "router" : ctx[0]?._flag,
|
|
299
|
+
responseHeader,
|
|
300
|
+
path,
|
|
301
|
+
...ctx[0] || {}
|
|
482
302
|
};
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
303
|
+
if (options.use?.length) {
|
|
304
|
+
let middlewareContexts = {};
|
|
305
|
+
let middlewareBody = {};
|
|
306
|
+
for (const middleware of options.use) {
|
|
307
|
+
if (typeof middleware !== "function") {
|
|
308
|
+
console.warn("Middleware is not a function", {
|
|
309
|
+
middleware
|
|
310
|
+
});
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
const res = await middleware(internalCtx);
|
|
314
|
+
if (res) {
|
|
315
|
+
const body = res.options?.body ? res.options.body.parse(internalCtx.body) : void 0;
|
|
316
|
+
middlewareContexts = {
|
|
317
|
+
...middlewareContexts,
|
|
318
|
+
...res
|
|
319
|
+
};
|
|
320
|
+
middlewareBody = {
|
|
321
|
+
...middlewareBody,
|
|
322
|
+
...body
|
|
323
|
+
};
|
|
490
324
|
}
|
|
491
|
-
return new Response(null, {
|
|
492
|
-
status: e.statusCode,
|
|
493
|
-
headers
|
|
494
|
-
});
|
|
495
325
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
response = createResponse(handlerResponse, response);
|
|
499
|
-
const res = asResponse ? response : handlerResponse;
|
|
500
|
-
return res;
|
|
501
|
-
};
|
|
502
|
-
internalHandler.path = path;
|
|
503
|
-
internalHandler.options = options;
|
|
504
|
-
const registry = new OpenAPIRegistry();
|
|
505
|
-
registry.registerPath({
|
|
506
|
-
path,
|
|
507
|
-
method: Array.isArray(options.method) ? options.method[0].toLowerCase() : options.method.toLowerCase(),
|
|
508
|
-
request: {
|
|
509
|
-
...options.body ? {
|
|
326
|
+
internalCtx = {
|
|
327
|
+
...internalCtx,
|
|
510
328
|
body: {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
} : {},
|
|
518
|
-
...options.query ? {
|
|
519
|
-
query: options.query
|
|
520
|
-
} : {},
|
|
521
|
-
params: paramToZod(path)
|
|
522
|
-
},
|
|
523
|
-
responses: {
|
|
524
|
-
200: {
|
|
525
|
-
description: "Successful response",
|
|
526
|
-
content: {
|
|
527
|
-
"application/json": {
|
|
528
|
-
schema: z.record(z.unknown())
|
|
529
|
-
}
|
|
329
|
+
...middlewareBody,
|
|
330
|
+
...internalCtx.body
|
|
331
|
+
},
|
|
332
|
+
context: {
|
|
333
|
+
...internalCtx.context || {},
|
|
334
|
+
...middlewareContexts
|
|
530
335
|
}
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
try {
|
|
339
|
+
const body = options.body ? options.body.parse(internalCtx.body) : internalCtx.body;
|
|
340
|
+
internalCtx = {
|
|
341
|
+
...internalCtx,
|
|
342
|
+
body: body ? {
|
|
343
|
+
...body,
|
|
344
|
+
...internalCtx.body
|
|
345
|
+
} : internalCtx.body
|
|
346
|
+
};
|
|
347
|
+
internalCtx.query = options.query ? options.query.parse(internalCtx.query) : internalCtx.query;
|
|
348
|
+
} catch (e) {
|
|
349
|
+
if (e instanceof ZodError) {
|
|
350
|
+
throw new APIError("BAD_REQUEST", {
|
|
351
|
+
message: e.message,
|
|
352
|
+
details: e.errors
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
throw e;
|
|
356
|
+
}
|
|
357
|
+
if (options.requireHeaders && !internalCtx.headers) {
|
|
358
|
+
throw new APIError("BAD_REQUEST", {
|
|
359
|
+
message: "Headers are required"
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
if (options.requireRequest && !internalCtx.request) {
|
|
363
|
+
throw new APIError("BAD_REQUEST", {
|
|
364
|
+
message: "Request is required"
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
try {
|
|
368
|
+
let res = await handler(internalCtx);
|
|
369
|
+
let actualResponse = res;
|
|
370
|
+
if (res && typeof res === "object" && "_flag" in res) {
|
|
371
|
+
if (res._flag === "json" && internalCtx._flag === "router") {
|
|
372
|
+
const h = res.response.headers;
|
|
373
|
+
Object.keys(h || {}).forEach((key) => {
|
|
374
|
+
responseHeader.set(key, h[key]);
|
|
375
|
+
});
|
|
376
|
+
responseHeader.set("Content-Type", "application/json");
|
|
377
|
+
actualResponse = new Response(JSON.stringify(res.response.body), {
|
|
378
|
+
status: res.response.status ?? 200,
|
|
379
|
+
statusText: res.response.statusText,
|
|
380
|
+
headers: responseHeader
|
|
381
|
+
});
|
|
382
|
+
} else {
|
|
383
|
+
actualResponse = res.body;
|
|
540
384
|
}
|
|
541
|
-
}
|
|
542
|
-
|
|
385
|
+
}
|
|
386
|
+
responseHeader = new Headers();
|
|
387
|
+
return actualResponse;
|
|
388
|
+
} catch (e) {
|
|
389
|
+
if (e instanceof APIError) {
|
|
390
|
+
responseHeader.set("Content-Type", "application/json");
|
|
391
|
+
e.headers = responseHeader;
|
|
392
|
+
responseHeader = new Headers();
|
|
393
|
+
throw e;
|
|
394
|
+
}
|
|
395
|
+
throw e;
|
|
543
396
|
}
|
|
544
|
-
});
|
|
545
|
-
internalHandler.openAPI = {
|
|
546
|
-
definitions: registry.definitions
|
|
547
|
-
};
|
|
548
|
-
return internalHandler;
|
|
549
|
-
};
|
|
550
|
-
function createEndpointCreator(opts) {
|
|
551
|
-
return (path, options, handler) => {
|
|
552
|
-
const res = createEndpoint(
|
|
553
|
-
path,
|
|
554
|
-
{
|
|
555
|
-
...options,
|
|
556
|
-
use: [...options?.use || [], ...opts?.use || []]
|
|
557
|
-
},
|
|
558
|
-
handler
|
|
559
|
-
);
|
|
560
|
-
return res;
|
|
561
397
|
};
|
|
398
|
+
handle.path = path;
|
|
399
|
+
handle.options = options;
|
|
400
|
+
handle.method = options.method;
|
|
401
|
+
handle.headers = responseHeader;
|
|
402
|
+
return handle;
|
|
562
403
|
}
|
|
563
|
-
createEndpoint.creator = createEndpointCreator;
|
|
564
404
|
|
|
405
|
+
// src/router.ts
|
|
406
|
+
import { createRouter as createRou3Router, addRoute, findRoute, findAllRoutes } from "rou3";
|
|
407
|
+
|
|
408
|
+
// src/utils.ts
|
|
565
409
|
async function getBody(request) {
|
|
566
410
|
const contentType = request.headers.get("content-type") || "";
|
|
567
411
|
if (!request.body) {
|
|
@@ -601,11 +445,68 @@ async function getBody(request) {
|
|
|
601
445
|
}
|
|
602
446
|
return await request.text();
|
|
603
447
|
}
|
|
448
|
+
function shouldSerialize(body) {
|
|
449
|
+
return typeof body === "object" && body !== null && !(body instanceof Blob) && !(body instanceof FormData);
|
|
450
|
+
}
|
|
451
|
+
var statusCode = {
|
|
452
|
+
OK: 200,
|
|
453
|
+
CREATED: 201,
|
|
454
|
+
ACCEPTED: 202,
|
|
455
|
+
NO_CONTENT: 204,
|
|
456
|
+
MULTIPLE_CHOICES: 300,
|
|
457
|
+
MOVED_PERMANENTLY: 301,
|
|
458
|
+
FOUND: 302,
|
|
459
|
+
SEE_OTHER: 303,
|
|
460
|
+
NOT_MODIFIED: 304,
|
|
461
|
+
TEMPORARY_REDIRECT: 307,
|
|
462
|
+
BAD_REQUEST: 400,
|
|
463
|
+
UNAUTHORIZED: 401,
|
|
464
|
+
PAYMENT_REQUIRED: 402,
|
|
465
|
+
FORBIDDEN: 403,
|
|
466
|
+
NOT_FOUND: 404,
|
|
467
|
+
METHOD_NOT_ALLOWED: 405,
|
|
468
|
+
NOT_ACCEPTABLE: 406,
|
|
469
|
+
PROXY_AUTHENTICATION_REQUIRED: 407,
|
|
470
|
+
REQUEST_TIMEOUT: 408,
|
|
471
|
+
CONFLICT: 409,
|
|
472
|
+
GONE: 410,
|
|
473
|
+
LENGTH_REQUIRED: 411,
|
|
474
|
+
PRECONDITION_FAILED: 412,
|
|
475
|
+
PAYLOAD_TOO_LARGE: 413,
|
|
476
|
+
URI_TOO_LONG: 414,
|
|
477
|
+
UNSUPPORTED_MEDIA_TYPE: 415,
|
|
478
|
+
RANGE_NOT_SATISFIABLE: 416,
|
|
479
|
+
EXPECTATION_FAILED: 417,
|
|
480
|
+
"I'M_A_TEAPOT": 418,
|
|
481
|
+
MISDIRECTED_REQUEST: 421,
|
|
482
|
+
UNPROCESSABLE_ENTITY: 422,
|
|
483
|
+
LOCKED: 423,
|
|
484
|
+
FAILED_DEPENDENCY: 424,
|
|
485
|
+
TOO_EARLY: 425,
|
|
486
|
+
UPGRADE_REQUIRED: 426,
|
|
487
|
+
PRECONDITION_REQUIRED: 428,
|
|
488
|
+
TOO_MANY_REQUESTS: 429,
|
|
489
|
+
REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
|
|
490
|
+
UNAVAILABLE_FOR_LEGAL_REASONS: 451,
|
|
491
|
+
INTERNAL_SERVER_ERROR: 500,
|
|
492
|
+
NOT_IMPLEMENTED: 501,
|
|
493
|
+
BAD_GATEWAY: 502,
|
|
494
|
+
SERVICE_UNAVAILABLE: 503,
|
|
495
|
+
GATEWAY_TIMEOUT: 504,
|
|
496
|
+
HTTP_VERSION_NOT_SUPPORTED: 505,
|
|
497
|
+
VARIANT_ALSO_NEGOTIATES: 506,
|
|
498
|
+
INSUFFICIENT_STORAGE: 507,
|
|
499
|
+
LOOP_DETECTED: 508,
|
|
500
|
+
NOT_EXTENDED: 510,
|
|
501
|
+
NETWORK_AUTHENTICATION_REQUIRED: 511
|
|
502
|
+
};
|
|
604
503
|
|
|
605
|
-
|
|
504
|
+
// src/router.ts
|
|
505
|
+
var createRouter = (endpoints, config) => {
|
|
606
506
|
const _endpoints = Object.values(endpoints);
|
|
607
|
-
const router =
|
|
507
|
+
const router = createRou3Router();
|
|
608
508
|
for (const endpoint of _endpoints) {
|
|
509
|
+
if (endpoint.options.metadata?.SERVER_ONLY) continue;
|
|
609
510
|
if (Array.isArray(endpoint.options?.method)) {
|
|
610
511
|
for (const method of endpoint.options.method) {
|
|
611
512
|
addRoute(router, method, endpoint.path, endpoint);
|
|
@@ -614,7 +515,7 @@ const createRouter = (endpoints, config) => {
|
|
|
614
515
|
addRoute(router, endpoint.options.method, endpoint.path, endpoint);
|
|
615
516
|
}
|
|
616
517
|
}
|
|
617
|
-
const middlewareRouter =
|
|
518
|
+
const middlewareRouter = createRou3Router();
|
|
618
519
|
for (const route of config?.routerMiddleware || []) {
|
|
619
520
|
addRoute(middlewareRouter, "*", route.path, route.middleware);
|
|
620
521
|
}
|
|
@@ -688,17 +589,18 @@ const createRouter = (endpoints, config) => {
|
|
|
688
589
|
request,
|
|
689
590
|
body,
|
|
690
591
|
query,
|
|
592
|
+
_flag: "router",
|
|
691
593
|
context: {
|
|
692
594
|
...middlewareContext,
|
|
693
595
|
...config?.extraContext
|
|
694
|
-
}
|
|
695
|
-
asResponse: true
|
|
596
|
+
}
|
|
696
597
|
});
|
|
697
598
|
if (handlerRes instanceof Response) {
|
|
698
599
|
return handlerRes;
|
|
699
600
|
}
|
|
700
|
-
|
|
701
|
-
|
|
601
|
+
const resBody = shouldSerialize(handlerRes) ? JSON.stringify(handlerRes) : handlerRes;
|
|
602
|
+
return new Response(resBody, {
|
|
603
|
+
headers: handler2.headers
|
|
702
604
|
});
|
|
703
605
|
} catch (e) {
|
|
704
606
|
if (config?.onError) {
|
|
@@ -709,7 +611,8 @@ const createRouter = (endpoints, config) => {
|
|
|
709
611
|
}
|
|
710
612
|
if (e instanceof APIError) {
|
|
711
613
|
return new Response(e.body ? JSON.stringify(e.body) : null, {
|
|
712
|
-
status: e.
|
|
614
|
+
status: statusCode[e.status],
|
|
615
|
+
statusText: e.status,
|
|
713
616
|
headers: e.headers
|
|
714
617
|
});
|
|
715
618
|
}
|
|
@@ -723,11 +626,24 @@ const createRouter = (endpoints, config) => {
|
|
|
723
626
|
}
|
|
724
627
|
};
|
|
725
628
|
return {
|
|
726
|
-
handler
|
|
629
|
+
handler: async (request) => {
|
|
630
|
+
const onReq = await config?.onRequest?.(request);
|
|
631
|
+
if (onReq instanceof Response) {
|
|
632
|
+
return onReq;
|
|
633
|
+
}
|
|
634
|
+
const req = onReq instanceof Request ? onReq : request;
|
|
635
|
+
const res = await handler(req);
|
|
636
|
+
const onRes = await config?.onResponse?.(res);
|
|
637
|
+
if (onRes instanceof Response) {
|
|
638
|
+
return onRes;
|
|
639
|
+
}
|
|
640
|
+
return res;
|
|
641
|
+
},
|
|
727
642
|
endpoints
|
|
728
643
|
};
|
|
729
644
|
};
|
|
730
645
|
|
|
646
|
+
// src/middleware.ts
|
|
731
647
|
function createMiddleware(optionsOrHandler, handler) {
|
|
732
648
|
if (typeof optionsOrHandler === "function") {
|
|
733
649
|
return createEndpoint(
|
|
@@ -751,18 +667,197 @@ function createMiddleware(optionsOrHandler, handler) {
|
|
|
751
667
|
);
|
|
752
668
|
return endpoint;
|
|
753
669
|
}
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
670
|
+
var createMiddlewareCreator = (opts) => {
|
|
671
|
+
function fn(optionsOrHandler, handler) {
|
|
672
|
+
if (typeof optionsOrHandler === "function") {
|
|
673
|
+
return createEndpoint(
|
|
674
|
+
"*",
|
|
675
|
+
{
|
|
676
|
+
method: "*"
|
|
677
|
+
},
|
|
678
|
+
optionsOrHandler
|
|
679
|
+
);
|
|
680
|
+
}
|
|
681
|
+
if (!handler) {
|
|
682
|
+
throw new Error("Middleware handler is required");
|
|
683
|
+
}
|
|
684
|
+
const endpoint = createEndpoint(
|
|
685
|
+
"*",
|
|
757
686
|
{
|
|
758
|
-
|
|
759
|
-
|
|
687
|
+
...optionsOrHandler,
|
|
688
|
+
method: "*"
|
|
760
689
|
},
|
|
761
690
|
handler
|
|
762
691
|
);
|
|
763
|
-
return
|
|
692
|
+
return endpoint;
|
|
693
|
+
}
|
|
694
|
+
return fn;
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
// src/types.ts
|
|
698
|
+
import "zod";
|
|
699
|
+
|
|
700
|
+
// src/adapter/request.ts
|
|
701
|
+
import * as set_cookie_parser from "set-cookie-parser";
|
|
702
|
+
function get_raw_body(req, body_size_limit) {
|
|
703
|
+
const h = req.headers;
|
|
704
|
+
if (!h["content-type"]) return null;
|
|
705
|
+
const content_length = Number(h["content-length"]);
|
|
706
|
+
if (req.httpVersionMajor === 1 && isNaN(content_length) && h["transfer-encoding"] == null || content_length === 0) {
|
|
707
|
+
return null;
|
|
708
|
+
}
|
|
709
|
+
let length = content_length;
|
|
710
|
+
if (body_size_limit) {
|
|
711
|
+
if (!length) {
|
|
712
|
+
length = body_size_limit;
|
|
713
|
+
} else if (length > body_size_limit) {
|
|
714
|
+
throw Error(
|
|
715
|
+
`Received content-length of ${length}, but only accept up to ${body_size_limit} bytes.`
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
if (req.destroyed) {
|
|
720
|
+
const readable = new ReadableStream();
|
|
721
|
+
readable.cancel();
|
|
722
|
+
return readable;
|
|
723
|
+
}
|
|
724
|
+
let size = 0;
|
|
725
|
+
let cancelled = false;
|
|
726
|
+
return new ReadableStream({
|
|
727
|
+
start(controller) {
|
|
728
|
+
req.on("error", (error) => {
|
|
729
|
+
cancelled = true;
|
|
730
|
+
controller.error(error);
|
|
731
|
+
});
|
|
732
|
+
req.on("end", () => {
|
|
733
|
+
if (cancelled) return;
|
|
734
|
+
controller.close();
|
|
735
|
+
});
|
|
736
|
+
req.on("data", (chunk) => {
|
|
737
|
+
if (cancelled) return;
|
|
738
|
+
size += chunk.length;
|
|
739
|
+
if (size > length) {
|
|
740
|
+
cancelled = true;
|
|
741
|
+
controller.error(
|
|
742
|
+
new Error(
|
|
743
|
+
`request body size exceeded ${content_length ? "'content-length'" : "BODY_SIZE_LIMIT"} of ${length}`
|
|
744
|
+
)
|
|
745
|
+
);
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
controller.enqueue(chunk);
|
|
749
|
+
if (controller.desiredSize === null || controller.desiredSize <= 0) {
|
|
750
|
+
req.pause();
|
|
751
|
+
}
|
|
752
|
+
});
|
|
753
|
+
},
|
|
754
|
+
pull() {
|
|
755
|
+
req.resume();
|
|
756
|
+
},
|
|
757
|
+
cancel(reason) {
|
|
758
|
+
cancelled = true;
|
|
759
|
+
req.destroy(reason);
|
|
760
|
+
}
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
function getRequest({
|
|
764
|
+
request,
|
|
765
|
+
base,
|
|
766
|
+
bodySizeLimit
|
|
767
|
+
}) {
|
|
768
|
+
return new Request(base + request.url, {
|
|
769
|
+
// @ts-expect-error
|
|
770
|
+
duplex: "half",
|
|
771
|
+
method: request.method,
|
|
772
|
+
body: get_raw_body(request, bodySizeLimit),
|
|
773
|
+
headers: request.headers
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
async function setResponse(res, response) {
|
|
777
|
+
for (const [key, value] of response.headers) {
|
|
778
|
+
try {
|
|
779
|
+
res.setHeader(
|
|
780
|
+
key,
|
|
781
|
+
key === "set-cookie" ? set_cookie_parser.splitCookiesString(response.headers.get(key)) : value
|
|
782
|
+
);
|
|
783
|
+
} catch (error) {
|
|
784
|
+
res.getHeaderNames().forEach((name) => res.removeHeader(name));
|
|
785
|
+
res.writeHead(500).end(String(error));
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
res.writeHead(response.status);
|
|
790
|
+
if (!response.body) {
|
|
791
|
+
res.end();
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
if (response.body.locked) {
|
|
795
|
+
res.end(
|
|
796
|
+
"Fatal error: Response body is locked. This can happen when the response was already read (for example through 'response.json()' or 'response.text()')."
|
|
797
|
+
);
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
const reader = response.body.getReader();
|
|
801
|
+
if (res.destroyed) {
|
|
802
|
+
reader.cancel();
|
|
803
|
+
return;
|
|
804
|
+
}
|
|
805
|
+
const cancel = (error) => {
|
|
806
|
+
res.off("close", cancel);
|
|
807
|
+
res.off("error", cancel);
|
|
808
|
+
reader.cancel(error).catch(() => {
|
|
809
|
+
});
|
|
810
|
+
if (error) res.destroy(error);
|
|
764
811
|
};
|
|
812
|
+
res.on("close", cancel);
|
|
813
|
+
res.on("error", cancel);
|
|
814
|
+
next();
|
|
815
|
+
async function next() {
|
|
816
|
+
try {
|
|
817
|
+
for (; ; ) {
|
|
818
|
+
const { done, value } = await reader.read();
|
|
819
|
+
if (done) break;
|
|
820
|
+
if (!res.write(value)) {
|
|
821
|
+
res.once("drain", next);
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
res.end();
|
|
826
|
+
} catch (error) {
|
|
827
|
+
cancel(error instanceof Error ? error : new Error(String(error)));
|
|
828
|
+
}
|
|
829
|
+
}
|
|
765
830
|
}
|
|
766
|
-
createMiddleware.creator = createMiddlewareCreator;
|
|
767
831
|
|
|
768
|
-
|
|
832
|
+
// src/adapter/node.ts
|
|
833
|
+
function toNodeHandler(handler) {
|
|
834
|
+
return async (req, res) => {
|
|
835
|
+
const protocol = req.connection?.encrypted ? "https" : "http";
|
|
836
|
+
const base = `${protocol}://${req.headers[":authority"] || req.headers.host}`;
|
|
837
|
+
const response = await handler(getRequest({ base, request: req }));
|
|
838
|
+
setResponse(res, response);
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
export {
|
|
842
|
+
APIError,
|
|
843
|
+
createEndpoint,
|
|
844
|
+
createEndpointCreator,
|
|
845
|
+
createMiddleware,
|
|
846
|
+
createMiddlewareCreator,
|
|
847
|
+
createRouter,
|
|
848
|
+
getBody,
|
|
849
|
+
getCookie,
|
|
850
|
+
getRequest,
|
|
851
|
+
getSignedCookie,
|
|
852
|
+
parse,
|
|
853
|
+
parseSigned,
|
|
854
|
+
serialize,
|
|
855
|
+
serializeSigned,
|
|
856
|
+
setCookie,
|
|
857
|
+
setResponse,
|
|
858
|
+
setSignedCookie,
|
|
859
|
+
shouldSerialize,
|
|
860
|
+
statusCode,
|
|
861
|
+
toNodeHandler
|
|
862
|
+
};
|
|
863
|
+
//# sourceMappingURL=index.js.map
|