better-call 1.0.27 → 1.0.28-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/dist/client.d.cts +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/index.cjs +48 -187
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +34 -173
- package/dist/index.js.map +1 -1
- package/dist/node.d.cts +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/{router-DxWRTWmk.d.cts → router-BV-cToj2.d.cts} +31 -1
- package/dist/{router-D1f_-c2B.d.ts → router-CuwMJjp1.d.ts} +31 -1
- package/dist/utils-C1kQcShE.cjs +3 -0
- package/dist/utils-Cotdrp_v.js +174 -0
- package/dist/utils-Cotdrp_v.js.map +1 -0
- package/dist/utils-JxxvmTPm.cjs +222 -0
- package/dist/utils-JxxvmTPm.cjs.map +1 -0
- package/dist/utils-yiQwA3Vf.js +3 -0
- package/package.json +1 -1
package/dist/node.d.cts
CHANGED
package/dist/node.d.ts
CHANGED
|
@@ -931,6 +931,22 @@ interface EndpointBaseOptions {
|
|
|
931
931
|
* If enabled, endpoint won't be exposed over a router
|
|
932
932
|
*/
|
|
933
933
|
SERVER_ONLY?: boolean;
|
|
934
|
+
/**
|
|
935
|
+
* List of allowed content types for the endpoint
|
|
936
|
+
*
|
|
937
|
+
* if provided, only the content types in the list will be allowed to be passed in the body
|
|
938
|
+
*
|
|
939
|
+
* @example
|
|
940
|
+
* ```ts
|
|
941
|
+
* const endpoint = createEndpoint("/path", {
|
|
942
|
+
* method: "POST",
|
|
943
|
+
* allowedContentTypes: ["application/json", "application/x-www-form-urlencoded"],
|
|
944
|
+
* }, async(ctx)=>{
|
|
945
|
+
* const body = ctx.body
|
|
946
|
+
* })
|
|
947
|
+
* ```
|
|
948
|
+
*/
|
|
949
|
+
allowedContentTypes?: string[];
|
|
934
950
|
/**
|
|
935
951
|
* Extra metadata
|
|
936
952
|
*/
|
|
@@ -1210,6 +1226,20 @@ interface RouterConfig {
|
|
|
1210
1226
|
* A callback to run before any request
|
|
1211
1227
|
*/
|
|
1212
1228
|
onRequest?: (req: Request) => any | Promise<any>;
|
|
1229
|
+
/**
|
|
1230
|
+
* List of allowed content types for the router
|
|
1231
|
+
*
|
|
1232
|
+
* if provided, only the content types in the list will be allowed to be passed in the body.
|
|
1233
|
+
*
|
|
1234
|
+
* If an endpoint has an allowed content types, it will override the router's allowed content types.
|
|
1235
|
+
*
|
|
1236
|
+
* @example
|
|
1237
|
+
* ```ts
|
|
1238
|
+
* const router = createRouter({
|
|
1239
|
+
* allowedContentTypes: ["application/json", "application/x-www-form-urlencoded"],
|
|
1240
|
+
* })
|
|
1241
|
+
*/
|
|
1242
|
+
allowedContentTypes?: string[];
|
|
1213
1243
|
/**
|
|
1214
1244
|
* Open API route configuration
|
|
1215
1245
|
*/
|
|
@@ -1260,4 +1290,4 @@ declare const createRouter: <E extends Record<string, Endpoint>, Config extends
|
|
|
1260
1290
|
type Router = ReturnType<typeof createRouter>;
|
|
1261
1291
|
//#endregion
|
|
1262
1292
|
export { APIError, BetterCallError, CookieOptions, CookiePrefixOptions, Endpoint, EndpointBaseOptions, EndpointBodyMethodOptions, EndpointContext, EndpointOptions, HTTPMethod, HasRequiredKeys, InferBody, InferBodyInput, InferHeaders, InferHeadersInput, InferInputMethod, InferMethod, InferMiddlewareBody, InferMiddlewareQuery, InferParam, InferParamInput, InferParamPath, InferParamWildCard, InferQuery, InferQueryInput, InferRequest, InferRequestInput, InferUse, InputContext, IsEmptyObject, MergeObject, Method, Middleware, MiddlewareContext, MiddlewareInputContext, MiddlewareOptions, MiddlewareResponse, OpenAPIParameter, OpenAPISchemaType, Path$1 as Path, Prettify, RequiredKeysOf, Router, RouterConfig, StandardSchemaV1, Status, StrictEndpoint, UnionToIntersection, createEndpoint, createInternalContext, createMiddleware, createRouter, generator, getCookieKey, getHTML, hideInternalStackFrames, makeErrorForHideStackFrame, parseCookies, serializeCookie, serializeSignedCookie, statusCodes };
|
|
1263
|
-
//# sourceMappingURL=router-
|
|
1293
|
+
//# sourceMappingURL=router-BV-cToj2.d.cts.map
|
|
@@ -931,6 +931,22 @@ interface EndpointBaseOptions {
|
|
|
931
931
|
* If enabled, endpoint won't be exposed over a router
|
|
932
932
|
*/
|
|
933
933
|
SERVER_ONLY?: boolean;
|
|
934
|
+
/**
|
|
935
|
+
* List of allowed content types for the endpoint
|
|
936
|
+
*
|
|
937
|
+
* if provided, only the content types in the list will be allowed to be passed in the body
|
|
938
|
+
*
|
|
939
|
+
* @example
|
|
940
|
+
* ```ts
|
|
941
|
+
* const endpoint = createEndpoint("/path", {
|
|
942
|
+
* method: "POST",
|
|
943
|
+
* allowedContentTypes: ["application/json", "application/x-www-form-urlencoded"],
|
|
944
|
+
* }, async(ctx)=>{
|
|
945
|
+
* const body = ctx.body
|
|
946
|
+
* })
|
|
947
|
+
* ```
|
|
948
|
+
*/
|
|
949
|
+
allowedContentTypes?: string[];
|
|
934
950
|
/**
|
|
935
951
|
* Extra metadata
|
|
936
952
|
*/
|
|
@@ -1210,6 +1226,20 @@ interface RouterConfig {
|
|
|
1210
1226
|
* A callback to run before any request
|
|
1211
1227
|
*/
|
|
1212
1228
|
onRequest?: (req: Request) => any | Promise<any>;
|
|
1229
|
+
/**
|
|
1230
|
+
* List of allowed content types for the router
|
|
1231
|
+
*
|
|
1232
|
+
* if provided, only the content types in the list will be allowed to be passed in the body.
|
|
1233
|
+
*
|
|
1234
|
+
* If an endpoint has an allowed content types, it will override the router's allowed content types.
|
|
1235
|
+
*
|
|
1236
|
+
* @example
|
|
1237
|
+
* ```ts
|
|
1238
|
+
* const router = createRouter({
|
|
1239
|
+
* allowedContentTypes: ["application/json", "application/x-www-form-urlencoded"],
|
|
1240
|
+
* })
|
|
1241
|
+
*/
|
|
1242
|
+
allowedContentTypes?: string[];
|
|
1213
1243
|
/**
|
|
1214
1244
|
* Open API route configuration
|
|
1215
1245
|
*/
|
|
@@ -1260,4 +1290,4 @@ declare const createRouter: <E extends Record<string, Endpoint>, Config extends
|
|
|
1260
1290
|
type Router = ReturnType<typeof createRouter>;
|
|
1261
1291
|
//#endregion
|
|
1262
1292
|
export { APIError, BetterCallError, CookieOptions, CookiePrefixOptions, Endpoint, EndpointBaseOptions, EndpointBodyMethodOptions, EndpointContext, EndpointOptions, HTTPMethod, HasRequiredKeys, InferBody, InferBodyInput, InferHeaders, InferHeadersInput, InferInputMethod, InferMethod, InferMiddlewareBody, InferMiddlewareQuery, InferParam, InferParamInput, InferParamPath, InferParamWildCard, InferQuery, InferQueryInput, InferRequest, InferRequestInput, InferUse, InputContext, IsEmptyObject, MergeObject, Method, Middleware, MiddlewareContext, MiddlewareInputContext, MiddlewareOptions, MiddlewareResponse, OpenAPIParameter, OpenAPISchemaType, Path$1 as Path, Prettify, RequiredKeysOf, Router, RouterConfig, StandardSchemaV1, Status, StrictEndpoint, UnionToIntersection, createEndpoint, createInternalContext, createMiddleware, createRouter, generator, getCookieKey, getHTML, hideInternalStackFrames, makeErrorForHideStackFrame, parseCookies, serializeCookie, serializeSignedCookie, statusCodes };
|
|
1263
|
-
//# sourceMappingURL=router-
|
|
1293
|
+
//# sourceMappingURL=router-CuwMJjp1.d.ts.map
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
//#region src/error.ts
|
|
2
|
+
function isErrorStackTraceLimitWritable() {
|
|
3
|
+
const desc = Object.getOwnPropertyDescriptor(Error, "stackTraceLimit");
|
|
4
|
+
if (desc === void 0) return Object.isExtensible(Error);
|
|
5
|
+
return Object.prototype.hasOwnProperty.call(desc, "writable") ? desc.writable : desc.set !== void 0;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Hide internal stack frames from the error stack trace.
|
|
9
|
+
*/
|
|
10
|
+
function hideInternalStackFrames(stack) {
|
|
11
|
+
const lines = stack.split("\n at ");
|
|
12
|
+
if (lines.length <= 1) return stack;
|
|
13
|
+
lines.splice(1, 1);
|
|
14
|
+
return lines.join("\n at ");
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Creates a custom error class that hides stack frames.
|
|
18
|
+
*/
|
|
19
|
+
function makeErrorForHideStackFrame(Base, clazz) {
|
|
20
|
+
class HideStackFramesError extends Base {
|
|
21
|
+
#hiddenStack;
|
|
22
|
+
constructor(...args) {
|
|
23
|
+
if (isErrorStackTraceLimitWritable()) {
|
|
24
|
+
const limit = Error.stackTraceLimit;
|
|
25
|
+
Error.stackTraceLimit = 0;
|
|
26
|
+
super(...args);
|
|
27
|
+
Error.stackTraceLimit = limit;
|
|
28
|
+
} else super(...args);
|
|
29
|
+
const stack = (/* @__PURE__ */ new Error()).stack;
|
|
30
|
+
if (stack) this.#hiddenStack = hideInternalStackFrames(stack.replace(/^Error/, this.name));
|
|
31
|
+
}
|
|
32
|
+
get errorStack() {
|
|
33
|
+
return this.#hiddenStack;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
Object.defineProperty(HideStackFramesError.prototype, "constructor", {
|
|
37
|
+
get() {
|
|
38
|
+
return clazz;
|
|
39
|
+
},
|
|
40
|
+
enumerable: false,
|
|
41
|
+
configurable: true
|
|
42
|
+
});
|
|
43
|
+
return HideStackFramesError;
|
|
44
|
+
}
|
|
45
|
+
const statusCodes = {
|
|
46
|
+
OK: 200,
|
|
47
|
+
CREATED: 201,
|
|
48
|
+
ACCEPTED: 202,
|
|
49
|
+
NO_CONTENT: 204,
|
|
50
|
+
MULTIPLE_CHOICES: 300,
|
|
51
|
+
MOVED_PERMANENTLY: 301,
|
|
52
|
+
FOUND: 302,
|
|
53
|
+
SEE_OTHER: 303,
|
|
54
|
+
NOT_MODIFIED: 304,
|
|
55
|
+
TEMPORARY_REDIRECT: 307,
|
|
56
|
+
BAD_REQUEST: 400,
|
|
57
|
+
UNAUTHORIZED: 401,
|
|
58
|
+
PAYMENT_REQUIRED: 402,
|
|
59
|
+
FORBIDDEN: 403,
|
|
60
|
+
NOT_FOUND: 404,
|
|
61
|
+
METHOD_NOT_ALLOWED: 405,
|
|
62
|
+
NOT_ACCEPTABLE: 406,
|
|
63
|
+
PROXY_AUTHENTICATION_REQUIRED: 407,
|
|
64
|
+
REQUEST_TIMEOUT: 408,
|
|
65
|
+
CONFLICT: 409,
|
|
66
|
+
GONE: 410,
|
|
67
|
+
LENGTH_REQUIRED: 411,
|
|
68
|
+
PRECONDITION_FAILED: 412,
|
|
69
|
+
PAYLOAD_TOO_LARGE: 413,
|
|
70
|
+
URI_TOO_LONG: 414,
|
|
71
|
+
UNSUPPORTED_MEDIA_TYPE: 415,
|
|
72
|
+
RANGE_NOT_SATISFIABLE: 416,
|
|
73
|
+
EXPECTATION_FAILED: 417,
|
|
74
|
+
"I'M_A_TEAPOT": 418,
|
|
75
|
+
MISDIRECTED_REQUEST: 421,
|
|
76
|
+
UNPROCESSABLE_ENTITY: 422,
|
|
77
|
+
LOCKED: 423,
|
|
78
|
+
FAILED_DEPENDENCY: 424,
|
|
79
|
+
TOO_EARLY: 425,
|
|
80
|
+
UPGRADE_REQUIRED: 426,
|
|
81
|
+
PRECONDITION_REQUIRED: 428,
|
|
82
|
+
TOO_MANY_REQUESTS: 429,
|
|
83
|
+
REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
|
|
84
|
+
UNAVAILABLE_FOR_LEGAL_REASONS: 451,
|
|
85
|
+
INTERNAL_SERVER_ERROR: 500,
|
|
86
|
+
NOT_IMPLEMENTED: 501,
|
|
87
|
+
BAD_GATEWAY: 502,
|
|
88
|
+
SERVICE_UNAVAILABLE: 503,
|
|
89
|
+
GATEWAY_TIMEOUT: 504,
|
|
90
|
+
HTTP_VERSION_NOT_SUPPORTED: 505,
|
|
91
|
+
VARIANT_ALSO_NEGOTIATES: 506,
|
|
92
|
+
INSUFFICIENT_STORAGE: 507,
|
|
93
|
+
LOOP_DETECTED: 508,
|
|
94
|
+
NOT_EXTENDED: 510,
|
|
95
|
+
NETWORK_AUTHENTICATION_REQUIRED: 511
|
|
96
|
+
};
|
|
97
|
+
var InternalAPIError = class extends Error {
|
|
98
|
+
constructor(status = "INTERNAL_SERVER_ERROR", body = void 0, headers = {}, statusCode = typeof status === "number" ? status : statusCodes[status]) {
|
|
99
|
+
super(body?.message, body?.cause ? { cause: body.cause } : void 0);
|
|
100
|
+
this.status = status;
|
|
101
|
+
this.body = body;
|
|
102
|
+
this.headers = headers;
|
|
103
|
+
this.statusCode = statusCode;
|
|
104
|
+
this.name = "APIError";
|
|
105
|
+
this.status = status;
|
|
106
|
+
this.headers = headers;
|
|
107
|
+
this.statusCode = statusCode;
|
|
108
|
+
this.body = body ? {
|
|
109
|
+
code: body?.message?.toUpperCase().replace(/ /g, "_").replace(/[^A-Z0-9_]/g, ""),
|
|
110
|
+
...body
|
|
111
|
+
} : void 0;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
var BetterCallError = class extends Error {
|
|
115
|
+
constructor(message) {
|
|
116
|
+
super(message);
|
|
117
|
+
this.name = "BetterCallError";
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
const APIError = makeErrorForHideStackFrame(InternalAPIError, Error);
|
|
121
|
+
|
|
122
|
+
//#endregion
|
|
123
|
+
//#region src/utils.ts
|
|
124
|
+
async function getBody(request, allowedContentTypes) {
|
|
125
|
+
const contentType = request.headers.get("content-type") || "";
|
|
126
|
+
const normalizedContentType = contentType.toLowerCase();
|
|
127
|
+
if (!request.body) return;
|
|
128
|
+
if (allowedContentTypes && allowedContentTypes.length > 0) {
|
|
129
|
+
if (!allowedContentTypes.some((allowed) => {
|
|
130
|
+
const normalizedContentTypeBase = normalizedContentType.split(";")[0].trim();
|
|
131
|
+
const normalizedAllowed = allowed.toLowerCase().trim();
|
|
132
|
+
return normalizedContentTypeBase === normalizedAllowed || normalizedContentTypeBase.includes(normalizedAllowed);
|
|
133
|
+
})) throw new APIError(415, {
|
|
134
|
+
message: `Content-Type "${contentType}" is not allowed. Allowed types: ${allowedContentTypes.join(", ")}`,
|
|
135
|
+
code: "UNSUPPORTED_MEDIA_TYPE"
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
if (normalizedContentType.includes("application/json")) return await request.json();
|
|
139
|
+
if (normalizedContentType.includes("application/x-www-form-urlencoded")) {
|
|
140
|
+
const formData = await request.formData();
|
|
141
|
+
const result = {};
|
|
142
|
+
formData.forEach((value, key) => {
|
|
143
|
+
result[key] = value.toString();
|
|
144
|
+
});
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
if (normalizedContentType.includes("multipart/form-data")) {
|
|
148
|
+
const formData = await request.formData();
|
|
149
|
+
const result = {};
|
|
150
|
+
formData.forEach((value, key) => {
|
|
151
|
+
result[key] = value;
|
|
152
|
+
});
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
if (normalizedContentType.includes("text/plain")) return await request.text();
|
|
156
|
+
if (normalizedContentType.includes("application/octet-stream")) return await request.arrayBuffer();
|
|
157
|
+
if (normalizedContentType.includes("application/pdf") || normalizedContentType.includes("image/") || normalizedContentType.includes("video/")) return await request.blob();
|
|
158
|
+
if (normalizedContentType.includes("application/stream") || request.body instanceof ReadableStream) return request.body;
|
|
159
|
+
return await request.text();
|
|
160
|
+
}
|
|
161
|
+
function isAPIError(error) {
|
|
162
|
+
return error instanceof APIError || error?.name === "APIError";
|
|
163
|
+
}
|
|
164
|
+
function tryDecode(str) {
|
|
165
|
+
try {
|
|
166
|
+
return str.includes("%") ? decodeURIComponent(str) : str;
|
|
167
|
+
} catch {
|
|
168
|
+
return str;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
//#endregion
|
|
173
|
+
export { APIError, BetterCallError, getBody, hideInternalStackFrames, isAPIError, makeErrorForHideStackFrame, statusCodes, tryDecode };
|
|
174
|
+
//# sourceMappingURL=utils-Cotdrp_v.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils-Cotdrp_v.js","names":["#hiddenStack","status: keyof typeof statusCodes | Status","body:\n\t\t\t| ({\n\t\t\t\t\tmessage?: string;\n\t\t\t\t\tcode?: string;\n\t\t\t\t\tcause?: unknown;\n\t\t\t } & Record<string, any>)\n\t\t\t| undefined","headers: HeadersInit","result: Record<string, string>","result: Record<string, any>"],"sources":["../src/error.ts","../src/utils.ts"],"sourcesContent":["// https://github.com/nodejs/node/blob/360f7cc7867b43344aac00564286b895e15f21d7/lib/internal/errors.js#L246C1-L261C2\nfunction isErrorStackTraceLimitWritable() {\n\tconst desc = Object.getOwnPropertyDescriptor(Error, \"stackTraceLimit\");\n\tif (desc === undefined) {\n\t\treturn Object.isExtensible(Error);\n\t}\n\n\treturn Object.prototype.hasOwnProperty.call(desc, \"writable\")\n\t\t? desc.writable\n\t\t: desc.set !== undefined;\n}\n\n/**\n * Hide internal stack frames from the error stack trace.\n */\nexport function hideInternalStackFrames(stack: string): string {\n\tconst lines = stack.split(\"\\n at \");\n\tif (lines.length <= 1) {\n\t\treturn stack;\n\t}\n\tlines.splice(1, 1);\n\treturn lines.join(\"\\n at \");\n}\n\n// https://github.com/nodejs/node/blob/360f7cc7867b43344aac00564286b895e15f21d7/lib/internal/errors.js#L411-L432\n/**\n * Creates a custom error class that hides stack frames.\n */\nexport function makeErrorForHideStackFrame<B extends new (...args: any[]) => Error>(\n\tBase: B,\n\tclazz: any,\n): {\n\tnew (...args: ConstructorParameters<B>): InstanceType<B> & { errorStack: string | undefined };\n} {\n\tclass HideStackFramesError extends Base {\n\t\t#hiddenStack: string | undefined;\n\n\t\tconstructor(...args: any[]) {\n\t\t\tif (isErrorStackTraceLimitWritable()) {\n\t\t\t\tconst limit = Error.stackTraceLimit;\n\t\t\t\tError.stackTraceLimit = 0;\n\t\t\t\tsuper(...args);\n\t\t\t\tError.stackTraceLimit = limit;\n\t\t\t} else {\n\t\t\t\tsuper(...args);\n\t\t\t}\n\t\t\tconst stack = new Error().stack;\n\t\t\tif (stack) {\n\t\t\t\tthis.#hiddenStack = hideInternalStackFrames(stack.replace(/^Error/, this.name));\n\t\t\t}\n\t\t}\n\n\t\t// use `getter` here to avoid the stack trace being captured by loggers\n\t\tget errorStack() {\n\t\t\treturn this.#hiddenStack;\n\t\t}\n\t}\n\n\t// This is a workaround for wpt tests that expect that the error\n\t// constructor has a `name` property of the base class.\n\tObject.defineProperty(HideStackFramesError.prototype, \"constructor\", {\n\t\tget() {\n\t\t\treturn clazz;\n\t\t},\n\t\tenumerable: false,\n\t\tconfigurable: true,\n\t});\n\n\treturn HideStackFramesError as any;\n}\n\nexport const statusCodes = {\n\tOK: 200,\n\tCREATED: 201,\n\tACCEPTED: 202,\n\tNO_CONTENT: 204,\n\tMULTIPLE_CHOICES: 300,\n\tMOVED_PERMANENTLY: 301,\n\tFOUND: 302,\n\tSEE_OTHER: 303,\n\tNOT_MODIFIED: 304,\n\tTEMPORARY_REDIRECT: 307,\n\tBAD_REQUEST: 400,\n\tUNAUTHORIZED: 401,\n\tPAYMENT_REQUIRED: 402,\n\tFORBIDDEN: 403,\n\tNOT_FOUND: 404,\n\tMETHOD_NOT_ALLOWED: 405,\n\tNOT_ACCEPTABLE: 406,\n\tPROXY_AUTHENTICATION_REQUIRED: 407,\n\tREQUEST_TIMEOUT: 408,\n\tCONFLICT: 409,\n\tGONE: 410,\n\tLENGTH_REQUIRED: 411,\n\tPRECONDITION_FAILED: 412,\n\tPAYLOAD_TOO_LARGE: 413,\n\tURI_TOO_LONG: 414,\n\tUNSUPPORTED_MEDIA_TYPE: 415,\n\tRANGE_NOT_SATISFIABLE: 416,\n\tEXPECTATION_FAILED: 417,\n\t\"I'M_A_TEAPOT\": 418,\n\tMISDIRECTED_REQUEST: 421,\n\tUNPROCESSABLE_ENTITY: 422,\n\tLOCKED: 423,\n\tFAILED_DEPENDENCY: 424,\n\tTOO_EARLY: 425,\n\tUPGRADE_REQUIRED: 426,\n\tPRECONDITION_REQUIRED: 428,\n\tTOO_MANY_REQUESTS: 429,\n\tREQUEST_HEADER_FIELDS_TOO_LARGE: 431,\n\tUNAVAILABLE_FOR_LEGAL_REASONS: 451,\n\tINTERNAL_SERVER_ERROR: 500,\n\tNOT_IMPLEMENTED: 501,\n\tBAD_GATEWAY: 502,\n\tSERVICE_UNAVAILABLE: 503,\n\tGATEWAY_TIMEOUT: 504,\n\tHTTP_VERSION_NOT_SUPPORTED: 505,\n\tVARIANT_ALSO_NEGOTIATES: 506,\n\tINSUFFICIENT_STORAGE: 507,\n\tLOOP_DETECTED: 508,\n\tNOT_EXTENDED: 510,\n\tNETWORK_AUTHENTICATION_REQUIRED: 511,\n};\n\nexport type Status =\n\t| 100\n\t| 101\n\t| 102\n\t| 103\n\t| 200\n\t| 201\n\t| 202\n\t| 203\n\t| 204\n\t| 205\n\t| 206\n\t| 207\n\t| 208\n\t| 226\n\t| 300\n\t| 301\n\t| 302\n\t| 303\n\t| 304\n\t| 305\n\t| 306\n\t| 307\n\t| 308\n\t| 400\n\t| 401\n\t| 402\n\t| 403\n\t| 404\n\t| 405\n\t| 406\n\t| 407\n\t| 408\n\t| 409\n\t| 410\n\t| 411\n\t| 412\n\t| 413\n\t| 414\n\t| 415\n\t| 416\n\t| 417\n\t| 418\n\t| 421\n\t| 422\n\t| 423\n\t| 424\n\t| 425\n\t| 426\n\t| 428\n\t| 429\n\t| 431\n\t| 451\n\t| 500\n\t| 501\n\t| 502\n\t| 503\n\t| 504\n\t| 505\n\t| 506\n\t| 507\n\t| 508\n\t| 510\n\t| 511;\n\nclass InternalAPIError extends Error {\n\tconstructor(\n\t\tpublic status: keyof typeof statusCodes | Status = \"INTERNAL_SERVER_ERROR\",\n\t\tpublic body:\n\t\t\t| ({\n\t\t\t\t\tmessage?: string;\n\t\t\t\t\tcode?: string;\n\t\t\t\t\tcause?: unknown;\n\t\t\t } & Record<string, any>)\n\t\t\t| undefined = undefined,\n\t\tpublic headers: HeadersInit = {},\n\t\tpublic statusCode = typeof status === \"number\" ? status : statusCodes[status],\n\t) {\n\t\tsuper(\n\t\t\tbody?.message,\n\t\t\tbody?.cause\n\t\t\t\t? {\n\t\t\t\t\t\tcause: body.cause,\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t);\n\t\tthis.name = \"APIError\";\n\t\tthis.status = status;\n\t\tthis.headers = headers;\n\t\tthis.statusCode = statusCode;\n\t\tthis.body = body\n\t\t\t? {\n\t\t\t\t\tcode: body?.message\n\t\t\t\t\t\t?.toUpperCase()\n\t\t\t\t\t\t.replace(/ /g, \"_\")\n\t\t\t\t\t\t.replace(/[^A-Z0-9_]/g, \"\"),\n\t\t\t\t\t...body,\n\t\t\t\t}\n\t\t\t: undefined;\n\t}\n}\n\nexport class BetterCallError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"BetterCallError\";\n\t}\n}\n\nexport type APIError = InstanceType<typeof InternalAPIError>;\nexport const APIError = makeErrorForHideStackFrame(InternalAPIError, Error);\n","import { APIError } from \"./error\";\n\nexport async function getBody(request: Request, allowedContentTypes?: string[]) {\n\tconst contentType = request.headers.get(\"content-type\") || \"\";\n\tconst normalizedContentType = contentType.toLowerCase();\n\n\tif (!request.body) {\n\t\treturn undefined;\n\t}\n\n\t// Validate content-type if allowedContentTypes is provided\n\tif (allowedContentTypes && allowedContentTypes.length > 0) {\n\t\tconst isAllowed = allowedContentTypes.some((allowed) => {\n\t\t\t// Normalize both content types for comparison\n\t\t\tconst normalizedContentTypeBase = normalizedContentType.split(\";\")[0].trim();\n\t\t\tconst normalizedAllowed = allowed.toLowerCase().trim();\n\t\t\treturn (\n\t\t\t\tnormalizedContentTypeBase === normalizedAllowed ||\n\t\t\t\tnormalizedContentTypeBase.includes(normalizedAllowed)\n\t\t\t);\n\t\t});\n\n\t\tif (!isAllowed) {\n\t\t\tthrow new APIError(415, {\n\t\t\t\tmessage: `Content-Type \"${contentType}\" is not allowed. Allowed types: ${allowedContentTypes.join(\", \")}`,\n\t\t\t\tcode: \"UNSUPPORTED_MEDIA_TYPE\",\n\t\t\t});\n\t\t}\n\t}\n\n\tif (normalizedContentType.includes(\"application/json\")) {\n\t\treturn await request.json();\n\t}\n\n\tif (normalizedContentType.includes(\"application/x-www-form-urlencoded\")) {\n\t\tconst formData = await request.formData();\n\t\tconst result: Record<string, string> = {};\n\t\tformData.forEach((value, key) => {\n\t\t\tresult[key] = value.toString();\n\t\t});\n\t\treturn result;\n\t}\n\n\tif (normalizedContentType.includes(\"multipart/form-data\")) {\n\t\tconst formData = await request.formData();\n\t\tconst result: Record<string, any> = {};\n\t\tformData.forEach((value, key) => {\n\t\t\tresult[key] = value;\n\t\t});\n\t\treturn result;\n\t}\n\n\tif (normalizedContentType.includes(\"text/plain\")) {\n\t\treturn await request.text();\n\t}\n\n\tif (normalizedContentType.includes(\"application/octet-stream\")) {\n\t\treturn await request.arrayBuffer();\n\t}\n\n\tif (\n\t\tnormalizedContentType.includes(\"application/pdf\") ||\n\t\tnormalizedContentType.includes(\"image/\") ||\n\t\tnormalizedContentType.includes(\"video/\")\n\t) {\n\t\tconst blob = await request.blob();\n\t\treturn blob;\n\t}\n\n\tif (normalizedContentType.includes(\"application/stream\") || request.body instanceof ReadableStream) {\n\t\treturn request.body;\n\t}\n\n\treturn await request.text();\n}\n\nexport function isAPIError(error: any): error is APIError {\n\treturn error instanceof APIError || error?.name === \"APIError\";\n}\n\nexport function tryDecode(str: string) {\n\ttry {\n\t\treturn str.includes(\"%\") ? decodeURIComponent(str) : str;\n\t} catch {\n\t\treturn str;\n\t}\n}\n"],"mappings":";AACA,SAAS,iCAAiC;CACzC,MAAM,OAAO,OAAO,yBAAyB,OAAO,kBAAkB;AACtE,KAAI,SAAS,OACZ,QAAO,OAAO,aAAa,MAAM;AAGlC,QAAO,OAAO,UAAU,eAAe,KAAK,MAAM,WAAW,GAC1D,KAAK,WACL,KAAK,QAAQ;;;;;AAMjB,SAAgB,wBAAwB,OAAuB;CAC9D,MAAM,QAAQ,MAAM,MAAM,YAAY;AACtC,KAAI,MAAM,UAAU,EACnB,QAAO;AAER,OAAM,OAAO,GAAG,EAAE;AAClB,QAAO,MAAM,KAAK,YAAY;;;;;AAO/B,SAAgB,2BACf,MACA,OAGC;CACD,MAAM,6BAA6B,KAAK;EACvC;EAEA,YAAY,GAAG,MAAa;AAC3B,OAAI,gCAAgC,EAAE;IACrC,MAAM,QAAQ,MAAM;AACpB,UAAM,kBAAkB;AACxB,UAAM,GAAG,KAAK;AACd,UAAM,kBAAkB;SAExB,OAAM,GAAG,KAAK;GAEf,MAAM,yBAAQ,IAAI,OAAO,EAAC;AAC1B,OAAI,MACH,OAAKA,cAAe,wBAAwB,MAAM,QAAQ,UAAU,KAAK,KAAK,CAAC;;EAKjF,IAAI,aAAa;AAChB,UAAO,MAAKA;;;AAMd,QAAO,eAAe,qBAAqB,WAAW,eAAe;EACpE,MAAM;AACL,UAAO;;EAER,YAAY;EACZ,cAAc;EACd,CAAC;AAEF,QAAO;;AAGR,MAAa,cAAc;CAC1B,IAAI;CACJ,SAAS;CACT,UAAU;CACV,YAAY;CACZ,kBAAkB;CAClB,mBAAmB;CACnB,OAAO;CACP,WAAW;CACX,cAAc;CACd,oBAAoB;CACpB,aAAa;CACb,cAAc;CACd,kBAAkB;CAClB,WAAW;CACX,WAAW;CACX,oBAAoB;CACpB,gBAAgB;CAChB,+BAA+B;CAC/B,iBAAiB;CACjB,UAAU;CACV,MAAM;CACN,iBAAiB;CACjB,qBAAqB;CACrB,mBAAmB;CACnB,cAAc;CACd,wBAAwB;CACxB,uBAAuB;CACvB,oBAAoB;CACpB,gBAAgB;CAChB,qBAAqB;CACrB,sBAAsB;CACtB,QAAQ;CACR,mBAAmB;CACnB,WAAW;CACX,kBAAkB;CAClB,uBAAuB;CACvB,mBAAmB;CACnB,iCAAiC;CACjC,+BAA+B;CAC/B,uBAAuB;CACvB,iBAAiB;CACjB,aAAa;CACb,qBAAqB;CACrB,iBAAiB;CACjB,4BAA4B;CAC5B,yBAAyB;CACzB,sBAAsB;CACtB,eAAe;CACf,cAAc;CACd,iCAAiC;CACjC;AAmED,IAAM,mBAAN,cAA+B,MAAM;CACpC,YACC,AAAOC,SAA4C,yBACnD,AAAOC,OAMQ,QACf,AAAOC,UAAuB,EAAE,EAChC,AAAO,aAAa,OAAO,WAAW,WAAW,SAAS,YAAY,SACrE;AACD,QACC,MAAM,SACN,MAAM,QACH,EACA,OAAO,KAAK,OACZ,GACA,OACH;EAlBM;EACA;EAOA;EACA;AAUP,OAAK,OAAO;AACZ,OAAK,SAAS;AACd,OAAK,UAAU;AACf,OAAK,aAAa;AAClB,OAAK,OAAO,OACT;GACA,MAAM,MAAM,SACT,aAAa,CACd,QAAQ,MAAM,IAAI,CAClB,QAAQ,eAAe,GAAG;GAC5B,GAAG;GACH,GACA;;;AAIL,IAAa,kBAAb,cAAqC,MAAM;CAC1C,YAAY,SAAiB;AAC5B,QAAM,QAAQ;AACd,OAAK,OAAO;;;AAKd,MAAa,WAAW,2BAA2B,kBAAkB,MAAM;;;;ACxO3E,eAAsB,QAAQ,SAAkB,qBAAgC;CAC/E,MAAM,cAAc,QAAQ,QAAQ,IAAI,eAAe,IAAI;CAC3D,MAAM,wBAAwB,YAAY,aAAa;AAEvD,KAAI,CAAC,QAAQ,KACZ;AAID,KAAI,uBAAuB,oBAAoB,SAAS,GAWvD;MAAI,CAVc,oBAAoB,MAAM,YAAY;GAEvD,MAAM,4BAA4B,sBAAsB,MAAM,IAAI,CAAC,GAAG,MAAM;GAC5E,MAAM,oBAAoB,QAAQ,aAAa,CAAC,MAAM;AACtD,UACC,8BAA8B,qBAC9B,0BAA0B,SAAS,kBAAkB;IAErD,CAGD,OAAM,IAAI,SAAS,KAAK;GACvB,SAAS,iBAAiB,YAAY,mCAAmC,oBAAoB,KAAK,KAAK;GACvG,MAAM;GACN,CAAC;;AAIJ,KAAI,sBAAsB,SAAS,mBAAmB,CACrD,QAAO,MAAM,QAAQ,MAAM;AAG5B,KAAI,sBAAsB,SAAS,oCAAoC,EAAE;EACxE,MAAM,WAAW,MAAM,QAAQ,UAAU;EACzC,MAAMC,SAAiC,EAAE;AACzC,WAAS,SAAS,OAAO,QAAQ;AAChC,UAAO,OAAO,MAAM,UAAU;IAC7B;AACF,SAAO;;AAGR,KAAI,sBAAsB,SAAS,sBAAsB,EAAE;EAC1D,MAAM,WAAW,MAAM,QAAQ,UAAU;EACzC,MAAMC,SAA8B,EAAE;AACtC,WAAS,SAAS,OAAO,QAAQ;AAChC,UAAO,OAAO;IACb;AACF,SAAO;;AAGR,KAAI,sBAAsB,SAAS,aAAa,CAC/C,QAAO,MAAM,QAAQ,MAAM;AAG5B,KAAI,sBAAsB,SAAS,2BAA2B,CAC7D,QAAO,MAAM,QAAQ,aAAa;AAGnC,KACC,sBAAsB,SAAS,kBAAkB,IACjD,sBAAsB,SAAS,SAAS,IACxC,sBAAsB,SAAS,SAAS,CAGxC,QADa,MAAM,QAAQ,MAAM;AAIlC,KAAI,sBAAsB,SAAS,qBAAqB,IAAI,QAAQ,gBAAgB,eACnF,QAAO,QAAQ;AAGhB,QAAO,MAAM,QAAQ,MAAM;;AAG5B,SAAgB,WAAW,OAA+B;AACzD,QAAO,iBAAiB,YAAY,OAAO,SAAS;;AAGrD,SAAgB,UAAU,KAAa;AACtC,KAAI;AACH,SAAO,IAAI,SAAS,IAAI,GAAG,mBAAmB,IAAI,GAAG;SAC9C;AACP,SAAO"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/error.ts
|
|
3
|
+
function isErrorStackTraceLimitWritable() {
|
|
4
|
+
const desc = Object.getOwnPropertyDescriptor(Error, "stackTraceLimit");
|
|
5
|
+
if (desc === void 0) return Object.isExtensible(Error);
|
|
6
|
+
return Object.prototype.hasOwnProperty.call(desc, "writable") ? desc.writable : desc.set !== void 0;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Hide internal stack frames from the error stack trace.
|
|
10
|
+
*/
|
|
11
|
+
function hideInternalStackFrames(stack) {
|
|
12
|
+
const lines = stack.split("\n at ");
|
|
13
|
+
if (lines.length <= 1) return stack;
|
|
14
|
+
lines.splice(1, 1);
|
|
15
|
+
return lines.join("\n at ");
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Creates a custom error class that hides stack frames.
|
|
19
|
+
*/
|
|
20
|
+
function makeErrorForHideStackFrame(Base, clazz) {
|
|
21
|
+
class HideStackFramesError extends Base {
|
|
22
|
+
#hiddenStack;
|
|
23
|
+
constructor(...args) {
|
|
24
|
+
if (isErrorStackTraceLimitWritable()) {
|
|
25
|
+
const limit = Error.stackTraceLimit;
|
|
26
|
+
Error.stackTraceLimit = 0;
|
|
27
|
+
super(...args);
|
|
28
|
+
Error.stackTraceLimit = limit;
|
|
29
|
+
} else super(...args);
|
|
30
|
+
const stack = (/* @__PURE__ */ new Error()).stack;
|
|
31
|
+
if (stack) this.#hiddenStack = hideInternalStackFrames(stack.replace(/^Error/, this.name));
|
|
32
|
+
}
|
|
33
|
+
get errorStack() {
|
|
34
|
+
return this.#hiddenStack;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
Object.defineProperty(HideStackFramesError.prototype, "constructor", {
|
|
38
|
+
get() {
|
|
39
|
+
return clazz;
|
|
40
|
+
},
|
|
41
|
+
enumerable: false,
|
|
42
|
+
configurable: true
|
|
43
|
+
});
|
|
44
|
+
return HideStackFramesError;
|
|
45
|
+
}
|
|
46
|
+
const statusCodes = {
|
|
47
|
+
OK: 200,
|
|
48
|
+
CREATED: 201,
|
|
49
|
+
ACCEPTED: 202,
|
|
50
|
+
NO_CONTENT: 204,
|
|
51
|
+
MULTIPLE_CHOICES: 300,
|
|
52
|
+
MOVED_PERMANENTLY: 301,
|
|
53
|
+
FOUND: 302,
|
|
54
|
+
SEE_OTHER: 303,
|
|
55
|
+
NOT_MODIFIED: 304,
|
|
56
|
+
TEMPORARY_REDIRECT: 307,
|
|
57
|
+
BAD_REQUEST: 400,
|
|
58
|
+
UNAUTHORIZED: 401,
|
|
59
|
+
PAYMENT_REQUIRED: 402,
|
|
60
|
+
FORBIDDEN: 403,
|
|
61
|
+
NOT_FOUND: 404,
|
|
62
|
+
METHOD_NOT_ALLOWED: 405,
|
|
63
|
+
NOT_ACCEPTABLE: 406,
|
|
64
|
+
PROXY_AUTHENTICATION_REQUIRED: 407,
|
|
65
|
+
REQUEST_TIMEOUT: 408,
|
|
66
|
+
CONFLICT: 409,
|
|
67
|
+
GONE: 410,
|
|
68
|
+
LENGTH_REQUIRED: 411,
|
|
69
|
+
PRECONDITION_FAILED: 412,
|
|
70
|
+
PAYLOAD_TOO_LARGE: 413,
|
|
71
|
+
URI_TOO_LONG: 414,
|
|
72
|
+
UNSUPPORTED_MEDIA_TYPE: 415,
|
|
73
|
+
RANGE_NOT_SATISFIABLE: 416,
|
|
74
|
+
EXPECTATION_FAILED: 417,
|
|
75
|
+
"I'M_A_TEAPOT": 418,
|
|
76
|
+
MISDIRECTED_REQUEST: 421,
|
|
77
|
+
UNPROCESSABLE_ENTITY: 422,
|
|
78
|
+
LOCKED: 423,
|
|
79
|
+
FAILED_DEPENDENCY: 424,
|
|
80
|
+
TOO_EARLY: 425,
|
|
81
|
+
UPGRADE_REQUIRED: 426,
|
|
82
|
+
PRECONDITION_REQUIRED: 428,
|
|
83
|
+
TOO_MANY_REQUESTS: 429,
|
|
84
|
+
REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
|
|
85
|
+
UNAVAILABLE_FOR_LEGAL_REASONS: 451,
|
|
86
|
+
INTERNAL_SERVER_ERROR: 500,
|
|
87
|
+
NOT_IMPLEMENTED: 501,
|
|
88
|
+
BAD_GATEWAY: 502,
|
|
89
|
+
SERVICE_UNAVAILABLE: 503,
|
|
90
|
+
GATEWAY_TIMEOUT: 504,
|
|
91
|
+
HTTP_VERSION_NOT_SUPPORTED: 505,
|
|
92
|
+
VARIANT_ALSO_NEGOTIATES: 506,
|
|
93
|
+
INSUFFICIENT_STORAGE: 507,
|
|
94
|
+
LOOP_DETECTED: 508,
|
|
95
|
+
NOT_EXTENDED: 510,
|
|
96
|
+
NETWORK_AUTHENTICATION_REQUIRED: 511
|
|
97
|
+
};
|
|
98
|
+
var InternalAPIError = class extends Error {
|
|
99
|
+
constructor(status = "INTERNAL_SERVER_ERROR", body = void 0, headers = {}, statusCode = typeof status === "number" ? status : statusCodes[status]) {
|
|
100
|
+
super(body?.message, body?.cause ? { cause: body.cause } : void 0);
|
|
101
|
+
this.status = status;
|
|
102
|
+
this.body = body;
|
|
103
|
+
this.headers = headers;
|
|
104
|
+
this.statusCode = statusCode;
|
|
105
|
+
this.name = "APIError";
|
|
106
|
+
this.status = status;
|
|
107
|
+
this.headers = headers;
|
|
108
|
+
this.statusCode = statusCode;
|
|
109
|
+
this.body = body ? {
|
|
110
|
+
code: body?.message?.toUpperCase().replace(/ /g, "_").replace(/[^A-Z0-9_]/g, ""),
|
|
111
|
+
...body
|
|
112
|
+
} : void 0;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
var BetterCallError = class extends Error {
|
|
116
|
+
constructor(message) {
|
|
117
|
+
super(message);
|
|
118
|
+
this.name = "BetterCallError";
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
const APIError = makeErrorForHideStackFrame(InternalAPIError, Error);
|
|
122
|
+
|
|
123
|
+
//#endregion
|
|
124
|
+
//#region src/utils.ts
|
|
125
|
+
async function getBody(request, allowedContentTypes) {
|
|
126
|
+
const contentType = request.headers.get("content-type") || "";
|
|
127
|
+
const normalizedContentType = contentType.toLowerCase();
|
|
128
|
+
if (!request.body) return;
|
|
129
|
+
if (allowedContentTypes && allowedContentTypes.length > 0) {
|
|
130
|
+
if (!allowedContentTypes.some((allowed) => {
|
|
131
|
+
const normalizedContentTypeBase = normalizedContentType.split(";")[0].trim();
|
|
132
|
+
const normalizedAllowed = allowed.toLowerCase().trim();
|
|
133
|
+
return normalizedContentTypeBase === normalizedAllowed || normalizedContentTypeBase.includes(normalizedAllowed);
|
|
134
|
+
})) throw new APIError(415, {
|
|
135
|
+
message: `Content-Type "${contentType}" is not allowed. Allowed types: ${allowedContentTypes.join(", ")}`,
|
|
136
|
+
code: "UNSUPPORTED_MEDIA_TYPE"
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
if (normalizedContentType.includes("application/json")) return await request.json();
|
|
140
|
+
if (normalizedContentType.includes("application/x-www-form-urlencoded")) {
|
|
141
|
+
const formData = await request.formData();
|
|
142
|
+
const result = {};
|
|
143
|
+
formData.forEach((value, key) => {
|
|
144
|
+
result[key] = value.toString();
|
|
145
|
+
});
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
if (normalizedContentType.includes("multipart/form-data")) {
|
|
149
|
+
const formData = await request.formData();
|
|
150
|
+
const result = {};
|
|
151
|
+
formData.forEach((value, key) => {
|
|
152
|
+
result[key] = value;
|
|
153
|
+
});
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
156
|
+
if (normalizedContentType.includes("text/plain")) return await request.text();
|
|
157
|
+
if (normalizedContentType.includes("application/octet-stream")) return await request.arrayBuffer();
|
|
158
|
+
if (normalizedContentType.includes("application/pdf") || normalizedContentType.includes("image/") || normalizedContentType.includes("video/")) return await request.blob();
|
|
159
|
+
if (normalizedContentType.includes("application/stream") || request.body instanceof ReadableStream) return request.body;
|
|
160
|
+
return await request.text();
|
|
161
|
+
}
|
|
162
|
+
function isAPIError(error) {
|
|
163
|
+
return error instanceof APIError || error?.name === "APIError";
|
|
164
|
+
}
|
|
165
|
+
function tryDecode(str) {
|
|
166
|
+
try {
|
|
167
|
+
return str.includes("%") ? decodeURIComponent(str) : str;
|
|
168
|
+
} catch {
|
|
169
|
+
return str;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
//#endregion
|
|
174
|
+
Object.defineProperty(exports, 'APIError', {
|
|
175
|
+
enumerable: true,
|
|
176
|
+
get: function () {
|
|
177
|
+
return APIError;
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
Object.defineProperty(exports, 'BetterCallError', {
|
|
181
|
+
enumerable: true,
|
|
182
|
+
get: function () {
|
|
183
|
+
return BetterCallError;
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
Object.defineProperty(exports, 'getBody', {
|
|
187
|
+
enumerable: true,
|
|
188
|
+
get: function () {
|
|
189
|
+
return getBody;
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
Object.defineProperty(exports, 'hideInternalStackFrames', {
|
|
193
|
+
enumerable: true,
|
|
194
|
+
get: function () {
|
|
195
|
+
return hideInternalStackFrames;
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
Object.defineProperty(exports, 'isAPIError', {
|
|
199
|
+
enumerable: true,
|
|
200
|
+
get: function () {
|
|
201
|
+
return isAPIError;
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
Object.defineProperty(exports, 'makeErrorForHideStackFrame', {
|
|
205
|
+
enumerable: true,
|
|
206
|
+
get: function () {
|
|
207
|
+
return makeErrorForHideStackFrame;
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
Object.defineProperty(exports, 'statusCodes', {
|
|
211
|
+
enumerable: true,
|
|
212
|
+
get: function () {
|
|
213
|
+
return statusCodes;
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
Object.defineProperty(exports, 'tryDecode', {
|
|
217
|
+
enumerable: true,
|
|
218
|
+
get: function () {
|
|
219
|
+
return tryDecode;
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
//# sourceMappingURL=utils-JxxvmTPm.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils-JxxvmTPm.cjs","names":["#hiddenStack","status: keyof typeof statusCodes | Status","body:\n\t\t\t| ({\n\t\t\t\t\tmessage?: string;\n\t\t\t\t\tcode?: string;\n\t\t\t\t\tcause?: unknown;\n\t\t\t } & Record<string, any>)\n\t\t\t| undefined","headers: HeadersInit","result: Record<string, string>","result: Record<string, any>"],"sources":["../src/error.ts","../src/utils.ts"],"sourcesContent":["// https://github.com/nodejs/node/blob/360f7cc7867b43344aac00564286b895e15f21d7/lib/internal/errors.js#L246C1-L261C2\nfunction isErrorStackTraceLimitWritable() {\n\tconst desc = Object.getOwnPropertyDescriptor(Error, \"stackTraceLimit\");\n\tif (desc === undefined) {\n\t\treturn Object.isExtensible(Error);\n\t}\n\n\treturn Object.prototype.hasOwnProperty.call(desc, \"writable\")\n\t\t? desc.writable\n\t\t: desc.set !== undefined;\n}\n\n/**\n * Hide internal stack frames from the error stack trace.\n */\nexport function hideInternalStackFrames(stack: string): string {\n\tconst lines = stack.split(\"\\n at \");\n\tif (lines.length <= 1) {\n\t\treturn stack;\n\t}\n\tlines.splice(1, 1);\n\treturn lines.join(\"\\n at \");\n}\n\n// https://github.com/nodejs/node/blob/360f7cc7867b43344aac00564286b895e15f21d7/lib/internal/errors.js#L411-L432\n/**\n * Creates a custom error class that hides stack frames.\n */\nexport function makeErrorForHideStackFrame<B extends new (...args: any[]) => Error>(\n\tBase: B,\n\tclazz: any,\n): {\n\tnew (...args: ConstructorParameters<B>): InstanceType<B> & { errorStack: string | undefined };\n} {\n\tclass HideStackFramesError extends Base {\n\t\t#hiddenStack: string | undefined;\n\n\t\tconstructor(...args: any[]) {\n\t\t\tif (isErrorStackTraceLimitWritable()) {\n\t\t\t\tconst limit = Error.stackTraceLimit;\n\t\t\t\tError.stackTraceLimit = 0;\n\t\t\t\tsuper(...args);\n\t\t\t\tError.stackTraceLimit = limit;\n\t\t\t} else {\n\t\t\t\tsuper(...args);\n\t\t\t}\n\t\t\tconst stack = new Error().stack;\n\t\t\tif (stack) {\n\t\t\t\tthis.#hiddenStack = hideInternalStackFrames(stack.replace(/^Error/, this.name));\n\t\t\t}\n\t\t}\n\n\t\t// use `getter` here to avoid the stack trace being captured by loggers\n\t\tget errorStack() {\n\t\t\treturn this.#hiddenStack;\n\t\t}\n\t}\n\n\t// This is a workaround for wpt tests that expect that the error\n\t// constructor has a `name` property of the base class.\n\tObject.defineProperty(HideStackFramesError.prototype, \"constructor\", {\n\t\tget() {\n\t\t\treturn clazz;\n\t\t},\n\t\tenumerable: false,\n\t\tconfigurable: true,\n\t});\n\n\treturn HideStackFramesError as any;\n}\n\nexport const statusCodes = {\n\tOK: 200,\n\tCREATED: 201,\n\tACCEPTED: 202,\n\tNO_CONTENT: 204,\n\tMULTIPLE_CHOICES: 300,\n\tMOVED_PERMANENTLY: 301,\n\tFOUND: 302,\n\tSEE_OTHER: 303,\n\tNOT_MODIFIED: 304,\n\tTEMPORARY_REDIRECT: 307,\n\tBAD_REQUEST: 400,\n\tUNAUTHORIZED: 401,\n\tPAYMENT_REQUIRED: 402,\n\tFORBIDDEN: 403,\n\tNOT_FOUND: 404,\n\tMETHOD_NOT_ALLOWED: 405,\n\tNOT_ACCEPTABLE: 406,\n\tPROXY_AUTHENTICATION_REQUIRED: 407,\n\tREQUEST_TIMEOUT: 408,\n\tCONFLICT: 409,\n\tGONE: 410,\n\tLENGTH_REQUIRED: 411,\n\tPRECONDITION_FAILED: 412,\n\tPAYLOAD_TOO_LARGE: 413,\n\tURI_TOO_LONG: 414,\n\tUNSUPPORTED_MEDIA_TYPE: 415,\n\tRANGE_NOT_SATISFIABLE: 416,\n\tEXPECTATION_FAILED: 417,\n\t\"I'M_A_TEAPOT\": 418,\n\tMISDIRECTED_REQUEST: 421,\n\tUNPROCESSABLE_ENTITY: 422,\n\tLOCKED: 423,\n\tFAILED_DEPENDENCY: 424,\n\tTOO_EARLY: 425,\n\tUPGRADE_REQUIRED: 426,\n\tPRECONDITION_REQUIRED: 428,\n\tTOO_MANY_REQUESTS: 429,\n\tREQUEST_HEADER_FIELDS_TOO_LARGE: 431,\n\tUNAVAILABLE_FOR_LEGAL_REASONS: 451,\n\tINTERNAL_SERVER_ERROR: 500,\n\tNOT_IMPLEMENTED: 501,\n\tBAD_GATEWAY: 502,\n\tSERVICE_UNAVAILABLE: 503,\n\tGATEWAY_TIMEOUT: 504,\n\tHTTP_VERSION_NOT_SUPPORTED: 505,\n\tVARIANT_ALSO_NEGOTIATES: 506,\n\tINSUFFICIENT_STORAGE: 507,\n\tLOOP_DETECTED: 508,\n\tNOT_EXTENDED: 510,\n\tNETWORK_AUTHENTICATION_REQUIRED: 511,\n};\n\nexport type Status =\n\t| 100\n\t| 101\n\t| 102\n\t| 103\n\t| 200\n\t| 201\n\t| 202\n\t| 203\n\t| 204\n\t| 205\n\t| 206\n\t| 207\n\t| 208\n\t| 226\n\t| 300\n\t| 301\n\t| 302\n\t| 303\n\t| 304\n\t| 305\n\t| 306\n\t| 307\n\t| 308\n\t| 400\n\t| 401\n\t| 402\n\t| 403\n\t| 404\n\t| 405\n\t| 406\n\t| 407\n\t| 408\n\t| 409\n\t| 410\n\t| 411\n\t| 412\n\t| 413\n\t| 414\n\t| 415\n\t| 416\n\t| 417\n\t| 418\n\t| 421\n\t| 422\n\t| 423\n\t| 424\n\t| 425\n\t| 426\n\t| 428\n\t| 429\n\t| 431\n\t| 451\n\t| 500\n\t| 501\n\t| 502\n\t| 503\n\t| 504\n\t| 505\n\t| 506\n\t| 507\n\t| 508\n\t| 510\n\t| 511;\n\nclass InternalAPIError extends Error {\n\tconstructor(\n\t\tpublic status: keyof typeof statusCodes | Status = \"INTERNAL_SERVER_ERROR\",\n\t\tpublic body:\n\t\t\t| ({\n\t\t\t\t\tmessage?: string;\n\t\t\t\t\tcode?: string;\n\t\t\t\t\tcause?: unknown;\n\t\t\t } & Record<string, any>)\n\t\t\t| undefined = undefined,\n\t\tpublic headers: HeadersInit = {},\n\t\tpublic statusCode = typeof status === \"number\" ? status : statusCodes[status],\n\t) {\n\t\tsuper(\n\t\t\tbody?.message,\n\t\t\tbody?.cause\n\t\t\t\t? {\n\t\t\t\t\t\tcause: body.cause,\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t);\n\t\tthis.name = \"APIError\";\n\t\tthis.status = status;\n\t\tthis.headers = headers;\n\t\tthis.statusCode = statusCode;\n\t\tthis.body = body\n\t\t\t? {\n\t\t\t\t\tcode: body?.message\n\t\t\t\t\t\t?.toUpperCase()\n\t\t\t\t\t\t.replace(/ /g, \"_\")\n\t\t\t\t\t\t.replace(/[^A-Z0-9_]/g, \"\"),\n\t\t\t\t\t...body,\n\t\t\t\t}\n\t\t\t: undefined;\n\t}\n}\n\nexport class BetterCallError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"BetterCallError\";\n\t}\n}\n\nexport type APIError = InstanceType<typeof InternalAPIError>;\nexport const APIError = makeErrorForHideStackFrame(InternalAPIError, Error);\n","import { APIError } from \"./error\";\n\nexport async function getBody(request: Request, allowedContentTypes?: string[]) {\n\tconst contentType = request.headers.get(\"content-type\") || \"\";\n\tconst normalizedContentType = contentType.toLowerCase();\n\n\tif (!request.body) {\n\t\treturn undefined;\n\t}\n\n\t// Validate content-type if allowedContentTypes is provided\n\tif (allowedContentTypes && allowedContentTypes.length > 0) {\n\t\tconst isAllowed = allowedContentTypes.some((allowed) => {\n\t\t\t// Normalize both content types for comparison\n\t\t\tconst normalizedContentTypeBase = normalizedContentType.split(\";\")[0].trim();\n\t\t\tconst normalizedAllowed = allowed.toLowerCase().trim();\n\t\t\treturn (\n\t\t\t\tnormalizedContentTypeBase === normalizedAllowed ||\n\t\t\t\tnormalizedContentTypeBase.includes(normalizedAllowed)\n\t\t\t);\n\t\t});\n\n\t\tif (!isAllowed) {\n\t\t\tthrow new APIError(415, {\n\t\t\t\tmessage: `Content-Type \"${contentType}\" is not allowed. Allowed types: ${allowedContentTypes.join(\", \")}`,\n\t\t\t\tcode: \"UNSUPPORTED_MEDIA_TYPE\",\n\t\t\t});\n\t\t}\n\t}\n\n\tif (normalizedContentType.includes(\"application/json\")) {\n\t\treturn await request.json();\n\t}\n\n\tif (normalizedContentType.includes(\"application/x-www-form-urlencoded\")) {\n\t\tconst formData = await request.formData();\n\t\tconst result: Record<string, string> = {};\n\t\tformData.forEach((value, key) => {\n\t\t\tresult[key] = value.toString();\n\t\t});\n\t\treturn result;\n\t}\n\n\tif (normalizedContentType.includes(\"multipart/form-data\")) {\n\t\tconst formData = await request.formData();\n\t\tconst result: Record<string, any> = {};\n\t\tformData.forEach((value, key) => {\n\t\t\tresult[key] = value;\n\t\t});\n\t\treturn result;\n\t}\n\n\tif (normalizedContentType.includes(\"text/plain\")) {\n\t\treturn await request.text();\n\t}\n\n\tif (normalizedContentType.includes(\"application/octet-stream\")) {\n\t\treturn await request.arrayBuffer();\n\t}\n\n\tif (\n\t\tnormalizedContentType.includes(\"application/pdf\") ||\n\t\tnormalizedContentType.includes(\"image/\") ||\n\t\tnormalizedContentType.includes(\"video/\")\n\t) {\n\t\tconst blob = await request.blob();\n\t\treturn blob;\n\t}\n\n\tif (normalizedContentType.includes(\"application/stream\") || request.body instanceof ReadableStream) {\n\t\treturn request.body;\n\t}\n\n\treturn await request.text();\n}\n\nexport function isAPIError(error: any): error is APIError {\n\treturn error instanceof APIError || error?.name === \"APIError\";\n}\n\nexport function tryDecode(str: string) {\n\ttry {\n\t\treturn str.includes(\"%\") ? decodeURIComponent(str) : str;\n\t} catch {\n\t\treturn str;\n\t}\n}\n"],"mappings":"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"}
|