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/node.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { Router } from "./router-DxWRTWmk.cjs";
1
+ import { Router } from "./router-BV-cToj2.cjs";
2
2
  import { IncomingMessage, ServerResponse } from "node:http";
3
3
 
4
4
  //#region src/adapters/node/request.d.ts
package/dist/node.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Router } from "./router-D1f_-c2B.js";
1
+ import { Router } from "./router-CuwMJjp1.js";
2
2
  import { IncomingMessage, ServerResponse } from "node:http";
3
3
 
4
4
  //#region src/adapters/node/request.d.ts
@@ -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-DxWRTWmk.d.cts.map
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-D1f_-c2B.d.ts.map
1293
+ //# sourceMappingURL=router-CuwMJjp1.d.ts.map
@@ -0,0 +1,3 @@
1
+ const require_utils = require('./utils-JxxvmTPm.cjs');
2
+
3
+ exports.getBody = require_utils.getBody;
@@ -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":"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"}
@@ -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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"}
@@ -0,0 +1,3 @@
1
+ import { getBody, isAPIError, tryDecode } from "./utils-Cotdrp_v.js";
2
+
3
+ export { getBody };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "better-call",
3
- "version": "1.0.27",
3
+ "version": "1.0.28-beta.1",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",