better-call 2.0.4 → 2.0.6
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 +870 -0
- package/dist/_virtual/_rolldown/runtime.cjs +7 -13
- package/dist/adapters/node/request.cjs +3 -4
- package/dist/adapters/node/request.cjs.map +1 -1
- package/dist/adapters/node/request.d.cts +1 -6
- package/dist/adapters/node/request.d.mts +1 -6
- package/dist/adapters/node/request.mjs +1 -2
- package/dist/adapters/node/request.mjs.map +1 -1
- package/dist/client.cjs +3 -5
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +3 -4
- package/dist/client.d.mts +3 -4
- package/dist/client.mjs +1 -2
- package/dist/client.mjs.map +1 -1
- package/dist/context.cjs +6 -7
- package/dist/context.cjs.map +1 -1
- package/dist/context.d.cts +0 -1
- package/dist/context.d.mts +0 -1
- package/dist/context.mjs +1 -2
- package/dist/context.mjs.map +1 -1
- package/dist/cookies.cjs +3 -4
- package/dist/cookies.cjs.map +1 -1
- package/dist/cookies.mjs +1 -2
- package/dist/cookies.mjs.map +1 -1
- package/dist/crypto.cjs +1 -3
- package/dist/crypto.cjs.map +1 -1
- package/dist/crypto.mjs +1 -2
- package/dist/crypto.mjs.map +1 -1
- package/dist/endpoint.cjs +5 -6
- package/dist/endpoint.cjs.map +1 -1
- package/dist/endpoint.d.cts +1 -2
- package/dist/endpoint.d.mts +1 -2
- package/dist/endpoint.mjs +1 -2
- package/dist/endpoint.mjs.map +1 -1
- package/dist/error.cjs +8 -3
- package/dist/error.cjs.map +1 -1
- package/dist/error.d.cts +0 -1
- package/dist/error.d.mts +0 -1
- package/dist/error.mjs +7 -1
- package/dist/error.mjs.map +1 -1
- package/dist/helper.d.cts +5 -5
- package/dist/helper.d.mts +5 -5
- package/dist/index.cjs +9 -10
- package/dist/index.mjs +1 -2
- package/dist/middleware.cjs +4 -5
- package/dist/middleware.cjs.map +1 -1
- package/dist/middleware.d.cts +0 -1
- package/dist/middleware.d.mts +0 -1
- package/dist/middleware.mjs +1 -2
- package/dist/middleware.mjs.map +1 -1
- package/dist/node.cjs +3 -4
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +0 -1
- package/dist/node.d.mts +0 -1
- package/dist/node.mjs +1 -2
- package/dist/node.mjs.map +1 -1
- package/dist/openapi.cjs +1 -3
- package/dist/openapi.cjs.map +1 -1
- package/dist/openapi.d.cts +2 -3
- package/dist/openapi.d.mts +2 -3
- package/dist/openapi.mjs +1 -2
- package/dist/openapi.mjs.map +1 -1
- package/dist/router.cjs +15 -17
- package/dist/router.cjs.map +1 -1
- package/dist/router.d.cts +0 -1
- package/dist/router.d.mts +0 -1
- package/dist/router.mjs +11 -12
- package/dist/router.mjs.map +1 -1
- package/dist/to-response.cjs +4 -5
- package/dist/to-response.cjs.map +1 -1
- package/dist/to-response.mjs +2 -3
- package/dist/to-response.mjs.map +1 -1
- package/dist/types.d.cts +1 -2
- package/dist/types.d.mts +1 -2
- package/dist/utils.cjs +2 -3
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.mjs +1 -2
- package/dist/utils.mjs.map +1 -1
- package/dist/validator.cjs +1 -2
- package/dist/validator.cjs.map +1 -1
- package/dist/validator.mjs +1 -1
- package/dist/validator.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -6,16 +6,12 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
8
|
var __copyProps = (to, from, except, desc) => {
|
|
9
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
}
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
19
15
|
}
|
|
20
16
|
return to;
|
|
21
17
|
};
|
|
@@ -23,7 +19,5 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
19
|
value: mod,
|
|
24
20
|
enumerable: true
|
|
25
21
|
}) : target, mod));
|
|
26
|
-
|
|
27
22
|
//#endregion
|
|
28
|
-
|
|
29
|
-
exports.__toESM = __toESM;
|
|
23
|
+
exports.__toESM = __toESM;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
const require_runtime = require(
|
|
1
|
+
const require_runtime = require("../../_virtual/_rolldown/runtime.cjs");
|
|
2
2
|
let set_cookie_parser = require("set-cookie-parser");
|
|
3
|
-
set_cookie_parser = require_runtime.__toESM(set_cookie_parser);
|
|
4
|
-
|
|
3
|
+
set_cookie_parser = require_runtime.__toESM(set_cookie_parser, 1);
|
|
5
4
|
//#region src/adapters/node/request.ts
|
|
6
5
|
const getFirstHeaderValue = (header) => {
|
|
7
6
|
if (Array.isArray(header)) return header[0];
|
|
@@ -174,8 +173,8 @@ async function setResponse(res, response) {
|
|
|
174
173
|
}
|
|
175
174
|
}
|
|
176
175
|
}
|
|
177
|
-
|
|
178
176
|
//#endregion
|
|
179
177
|
exports.getRequest = getRequest;
|
|
180
178
|
exports.setResponse = setResponse;
|
|
179
|
+
|
|
181
180
|
//# sourceMappingURL=request.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request.cjs","names":[],"sources":["../../../src/adapters/node/request.ts"],"sourcesContent":["import type {\n\tIncomingHttpHeaders,\n\tIncomingMessage,\n\tServerResponse,\n} from \"node:http\";\nimport * as set_cookie_parser from \"set-cookie-parser\";\n\ntype NodeRequestWithBody = IncomingMessage & {\n\tbody?: unknown;\n};\n\nconst getFirstHeaderValue = (\n\theader: IncomingHttpHeaders[string],\n): string | undefined => {\n\tif (Array.isArray(header)) {\n\t\treturn header[0];\n\t}\n\treturn header;\n};\n\nconst hasFormUrlEncodedContentType = (\n\theaders: IncomingHttpHeaders,\n): boolean => {\n\tconst contentType = getFirstHeaderValue(headers[\"content-type\"]);\n\tif (!contentType) {\n\t\treturn false;\n\t}\n\treturn contentType\n\t\t.toLowerCase()\n\t\t.startsWith(\"application/x-www-form-urlencoded\");\n};\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === Object.prototype || prototype === null;\n};\n\nconst appendFormValue = (\n\tparams: URLSearchParams,\n\tkey: string,\n\tvalue: unknown,\n) => {\n\tif (value === undefined) {\n\t\treturn;\n\t}\n\tif (Array.isArray(value)) {\n\t\tfor (const item of value) {\n\t\t\tappendFormValue(params, key, item);\n\t\t}\n\t\treturn;\n\t}\n\tif (value === null) {\n\t\tparams.append(key, \"\");\n\t\treturn;\n\t}\n\tif (isPlainObject(value)) {\n\t\tparams.append(key, JSON.stringify(value));\n\t\treturn;\n\t}\n\tparams.append(key, `${value}`);\n};\n\nconst toFormUrlEncodedBody = (\n\tbody: Readonly<Record<string, unknown>>,\n): string => {\n\tconst params = new URLSearchParams();\n\tfor (const [key, value] of Object.entries(body)) {\n\t\tappendFormValue(params, key, value);\n\t}\n\treturn params.toString();\n};\n\nconst canReadRawBody = (request: IncomingMessage): boolean => {\n\treturn (\n\t\t!request.destroyed && request.readableEnded !== true && request.readable\n\t);\n};\n\nconst serializeParsedBody = (\n\tparsedBody: unknown,\n\tisFormUrlEncoded: boolean,\n): string => {\n\tif (typeof parsedBody === \"string\") {\n\t\treturn parsedBody;\n\t}\n\tif (parsedBody instanceof URLSearchParams) {\n\t\treturn parsedBody.toString();\n\t}\n\tif (isFormUrlEncoded && isPlainObject(parsedBody)) {\n\t\treturn toFormUrlEncodedBody(parsedBody);\n\t}\n\treturn JSON.stringify(parsedBody);\n};\n\nfunction get_raw_body(req: IncomingMessage, body_size_limit?: number) {\n\tconst h = req.headers;\n\n\tif (!h[\"content-type\"]) return null;\n\n\tconst content_length = Number(h[\"content-length\"]);\n\n\t// check if no request body\n\tif (\n\t\t(req.httpVersionMajor === 1 &&\n\t\t\tisNaN(content_length) &&\n\t\t\th[\"transfer-encoding\"] == null) ||\n\t\tcontent_length === 0\n\t) {\n\t\treturn null;\n\t}\n\n\tlet length = content_length;\n\n\tif (body_size_limit) {\n\t\tif (!length) {\n\t\t\tlength = body_size_limit;\n\t\t} else if (length > body_size_limit) {\n\t\t\tthrow Error(\n\t\t\t\t`Received content-length of ${length}, but only accept up to ${body_size_limit} bytes.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (req.destroyed) {\n\t\tconst readable = new ReadableStream();\n\t\treadable.cancel();\n\t\treturn readable;\n\t}\n\n\tlet size = 0;\n\tlet cancelled = false;\n\n\treturn new ReadableStream({\n\t\tstart(controller) {\n\t\t\treq.on(\"error\", (error) => {\n\t\t\t\tcancelled = true;\n\t\t\t\tcontroller.error(error);\n\t\t\t});\n\n\t\t\treq.on(\"end\", () => {\n\t\t\t\tif (cancelled) return;\n\t\t\t\tcontroller.close();\n\t\t\t});\n\n\t\t\treq.on(\"data\", (chunk) => {\n\t\t\t\tif (cancelled) return;\n\n\t\t\t\tsize += chunk.length;\n\n\t\t\t\tif (size > length) {\n\t\t\t\t\tcancelled = true;\n\n\t\t\t\t\tcontroller.error(\n\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t`request body size exceeded ${\n\t\t\t\t\t\t\t\tcontent_length ? \"'content-length'\" : \"BODY_SIZE_LIMIT\"\n\t\t\t\t\t\t\t} of ${length}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcontroller.enqueue(chunk);\n\n\t\t\t\tif (controller.desiredSize === null || controller.desiredSize <= 0) {\n\t\t\t\t\treq.pause();\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tpull() {\n\t\t\treq.resume();\n\t\t},\n\n\t\tcancel(reason) {\n\t\t\tcancelled = true;\n\t\t\treq.destroy(reason);\n\t\t},\n\t});\n}\n\nfunction constructRelativeUrl(\n\treq: IncomingMessage & { baseUrl?: string; originalUrl?: string },\n) {\n\tconst baseUrl = req.baseUrl;\n\tconst originalUrl = req.originalUrl;\n\n\tif (!baseUrl || !originalUrl) {\n\t\t// In express.js sub-routers `req.url` is relative to the mount\n\t\t// path (e.g., '/auth/xxx'), and `req.baseUrl` will hold the mount\n\t\t// path (e.g., '/api'). Build the full path as baseUrl + url when\n\t\t// available to preserve the full route. For application level routes\n\t\t// baseUrl will be an empty string\n\t\treturn baseUrl ? baseUrl + req.url : req.url;\n\t}\n\n\tif (baseUrl + req.url === originalUrl) {\n\t\treturn baseUrl + req.url;\n\t}\n\n\t// For certain subroutes or when mounting wildcard middlewares in express\n\t// it is possible `baseUrl + req.url` will result in a url constructed\n\t// which has a trailing forward slash the original url did not have.\n\t// Checking the `req.originalUrl` path ending can prevent this issue.\n\n\tconst originalPathEnding = originalUrl.split(\"?\")[0]!.at(-1);\n\treturn originalPathEnding === \"/\" ? baseUrl + req.url : baseUrl;\n}\n\nexport function getRequest({\n\trequest,\n\tbase,\n\tbodySizeLimit,\n}: {\n\tbase: string;\n\tbodySizeLimit?: number;\n\trequest: IncomingMessage;\n}) {\n\t// Check if body has already been parsed by Express middleware\n\tconst maybeConsumedReq = request as NodeRequestWithBody;\n\tconst isFormUrlEncoded = hasFormUrlEncodedContentType(request.headers);\n\tlet body = undefined;\n\n\tconst method = request.method;\n\t// Request with GET/HEAD method cannot have body.\n\tif (method !== \"GET\" && method !== \"HEAD\") {\n\t\t// Raw-first strategy: prefer consuming the original request stream whenever it is still readable.\n\t\tif (canReadRawBody(request)) {\n\t\t\tbody = get_raw_body(request, bodySizeLimit);\n\t\t} else if (maybeConsumedReq.body !== undefined) {\n\t\t\tconst parsedBody = maybeConsumedReq.body;\n\n\t\t\tconst bodyContent = serializeParsedBody(parsedBody, isFormUrlEncoded);\n\t\t\tbody = new ReadableStream({\n\t\t\t\tstart(controller) {\n\t\t\t\t\tcontroller.enqueue(new TextEncoder().encode(bodyContent));\n\t\t\t\t\tcontroller.close();\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\treturn new Request(base + constructRelativeUrl(request), {\n\t\t// @ts-expect-error\n\t\tduplex: \"half\",\n\t\tmethod: request.method,\n\t\tbody,\n\t\theaders: request.headers as Record<string, string>,\n\t});\n}\n\nexport async function setResponse(res: ServerResponse, response: Response) {\n\tfor (const [key, value] of response.headers as any) {\n\t\ttry {\n\t\t\tres.setHeader(\n\t\t\t\tkey,\n\t\t\t\tkey === \"set-cookie\"\n\t\t\t\t\t? set_cookie_parser.splitCookiesString(\n\t\t\t\t\t\t\tresponse.headers.get(key) as string,\n\t\t\t\t\t\t)\n\t\t\t\t\t: value,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tres.getHeaderNames().forEach((name) => res.removeHeader(name));\n\t\t\tres.writeHead(500).end(String(error));\n\t\t\treturn;\n\t\t}\n\t}\n\n\tres.statusCode = response.status;\n\tres.writeHead(response.status);\n\n\tif (!response.body) {\n\t\tres.end();\n\t\treturn;\n\t}\n\n\tif (response.body.locked) {\n\t\tres.end(\n\t\t\t\"Fatal error: Response body is locked. \" +\n\t\t\t\t\"This can happen when the response was already read (for example through 'response.json()' or 'response.text()').\",\n\t\t);\n\t\treturn;\n\t}\n\n\tconst reader = response.body.getReader();\n\n\tif (res.destroyed) {\n\t\treader.cancel();\n\t\treturn;\n\t}\n\n\tconst cancel = (error?: Error) => {\n\t\tres.off(\"close\", cancel);\n\t\tres.off(\"error\", cancel);\n\n\t\t// If the reader has already been interrupted with an error earlier,\n\t\t// then it will appear here, it is useless, but it needs to be catch.\n\t\treader.cancel(error).catch(() => {});\n\t\tif (error) res.destroy(error);\n\t};\n\n\tres.on(\"close\", cancel);\n\tres.on(\"error\", cancel);\n\n\tnext();\n\tasync function next() {\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\tconst { done, value } = await reader.read();\n\n\t\t\t\tif (done) break;\n\n\t\t\t\tconst writeResult = res.write(value);\n\t\t\t\tif (!writeResult) {\n\t\t\t\t\t// In AWS Lambda/serverless environments, drain events may not work properly\n\t\t\t\t\t// Check if we're in a Lambda-like environment and handle differently\n\t\t\t\t\tif (\n\t\t\t\t\t\tprocess.env.AWS_LAMBDA_FUNCTION_NAME ||\n\t\t\t\t\t\tprocess.env.LAMBDA_TASK_ROOT\n\t\t\t\t\t) {\n\t\t\t\t\t\t// In Lambda, continue without waiting for drain\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Standard Node.js behavior\n\t\t\t\t\t\tres.once(\"drain\", next);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tres.end();\n\t\t} catch (error) {\n\t\t\tcancel(error instanceof Error ? error : new Error(String(error)));\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"request.cjs","names":[],"sources":["../../../src/adapters/node/request.ts"],"sourcesContent":["import type {\n\tIncomingHttpHeaders,\n\tIncomingMessage,\n\tServerResponse,\n} from \"node:http\";\nimport * as set_cookie_parser from \"set-cookie-parser\";\n\ntype NodeRequestWithBody = IncomingMessage & {\n\tbody?: unknown;\n};\n\nconst getFirstHeaderValue = (\n\theader: IncomingHttpHeaders[string],\n): string | undefined => {\n\tif (Array.isArray(header)) {\n\t\treturn header[0];\n\t}\n\treturn header;\n};\n\nconst hasFormUrlEncodedContentType = (\n\theaders: IncomingHttpHeaders,\n): boolean => {\n\tconst contentType = getFirstHeaderValue(headers[\"content-type\"]);\n\tif (!contentType) {\n\t\treturn false;\n\t}\n\treturn contentType\n\t\t.toLowerCase()\n\t\t.startsWith(\"application/x-www-form-urlencoded\");\n};\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === Object.prototype || prototype === null;\n};\n\nconst appendFormValue = (\n\tparams: URLSearchParams,\n\tkey: string,\n\tvalue: unknown,\n) => {\n\tif (value === undefined) {\n\t\treturn;\n\t}\n\tif (Array.isArray(value)) {\n\t\tfor (const item of value) {\n\t\t\tappendFormValue(params, key, item);\n\t\t}\n\t\treturn;\n\t}\n\tif (value === null) {\n\t\tparams.append(key, \"\");\n\t\treturn;\n\t}\n\tif (isPlainObject(value)) {\n\t\tparams.append(key, JSON.stringify(value));\n\t\treturn;\n\t}\n\tparams.append(key, `${value}`);\n};\n\nconst toFormUrlEncodedBody = (\n\tbody: Readonly<Record<string, unknown>>,\n): string => {\n\tconst params = new URLSearchParams();\n\tfor (const [key, value] of Object.entries(body)) {\n\t\tappendFormValue(params, key, value);\n\t}\n\treturn params.toString();\n};\n\nconst canReadRawBody = (request: IncomingMessage): boolean => {\n\treturn (\n\t\t!request.destroyed && request.readableEnded !== true && request.readable\n\t);\n};\n\nconst serializeParsedBody = (\n\tparsedBody: unknown,\n\tisFormUrlEncoded: boolean,\n): string => {\n\tif (typeof parsedBody === \"string\") {\n\t\treturn parsedBody;\n\t}\n\tif (parsedBody instanceof URLSearchParams) {\n\t\treturn parsedBody.toString();\n\t}\n\tif (isFormUrlEncoded && isPlainObject(parsedBody)) {\n\t\treturn toFormUrlEncodedBody(parsedBody);\n\t}\n\treturn JSON.stringify(parsedBody);\n};\n\nfunction get_raw_body(req: IncomingMessage, body_size_limit?: number) {\n\tconst h = req.headers;\n\n\tif (!h[\"content-type\"]) return null;\n\n\tconst content_length = Number(h[\"content-length\"]);\n\n\t// check if no request body\n\tif (\n\t\t(req.httpVersionMajor === 1 &&\n\t\t\tisNaN(content_length) &&\n\t\t\th[\"transfer-encoding\"] == null) ||\n\t\tcontent_length === 0\n\t) {\n\t\treturn null;\n\t}\n\n\tlet length = content_length;\n\n\tif (body_size_limit) {\n\t\tif (!length) {\n\t\t\tlength = body_size_limit;\n\t\t} else if (length > body_size_limit) {\n\t\t\tthrow Error(\n\t\t\t\t`Received content-length of ${length}, but only accept up to ${body_size_limit} bytes.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (req.destroyed) {\n\t\tconst readable = new ReadableStream();\n\t\treadable.cancel();\n\t\treturn readable;\n\t}\n\n\tlet size = 0;\n\tlet cancelled = false;\n\n\treturn new ReadableStream({\n\t\tstart(controller) {\n\t\t\treq.on(\"error\", (error) => {\n\t\t\t\tcancelled = true;\n\t\t\t\tcontroller.error(error);\n\t\t\t});\n\n\t\t\treq.on(\"end\", () => {\n\t\t\t\tif (cancelled) return;\n\t\t\t\tcontroller.close();\n\t\t\t});\n\n\t\t\treq.on(\"data\", (chunk) => {\n\t\t\t\tif (cancelled) return;\n\n\t\t\t\tsize += chunk.length;\n\n\t\t\t\tif (size > length) {\n\t\t\t\t\tcancelled = true;\n\n\t\t\t\t\tcontroller.error(\n\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t`request body size exceeded ${\n\t\t\t\t\t\t\t\tcontent_length ? \"'content-length'\" : \"BODY_SIZE_LIMIT\"\n\t\t\t\t\t\t\t} of ${length}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcontroller.enqueue(chunk);\n\n\t\t\t\tif (controller.desiredSize === null || controller.desiredSize <= 0) {\n\t\t\t\t\treq.pause();\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tpull() {\n\t\t\treq.resume();\n\t\t},\n\n\t\tcancel(reason) {\n\t\t\tcancelled = true;\n\t\t\treq.destroy(reason);\n\t\t},\n\t});\n}\n\nfunction constructRelativeUrl(\n\treq: IncomingMessage & { baseUrl?: string; originalUrl?: string },\n) {\n\tconst baseUrl = req.baseUrl;\n\tconst originalUrl = req.originalUrl;\n\n\tif (!baseUrl || !originalUrl) {\n\t\t// In express.js sub-routers `req.url` is relative to the mount\n\t\t// path (e.g., '/auth/xxx'), and `req.baseUrl` will hold the mount\n\t\t// path (e.g., '/api'). Build the full path as baseUrl + url when\n\t\t// available to preserve the full route. For application level routes\n\t\t// baseUrl will be an empty string\n\t\treturn baseUrl ? baseUrl + req.url : req.url;\n\t}\n\n\tif (baseUrl + req.url === originalUrl) {\n\t\treturn baseUrl + req.url;\n\t}\n\n\t// For certain subroutes or when mounting wildcard middlewares in express\n\t// it is possible `baseUrl + req.url` will result in a url constructed\n\t// which has a trailing forward slash the original url did not have.\n\t// Checking the `req.originalUrl` path ending can prevent this issue.\n\n\tconst originalPathEnding = originalUrl.split(\"?\")[0]!.at(-1);\n\treturn originalPathEnding === \"/\" ? baseUrl + req.url : baseUrl;\n}\n\nexport function getRequest({\n\trequest,\n\tbase,\n\tbodySizeLimit,\n}: {\n\tbase: string;\n\tbodySizeLimit?: number;\n\trequest: IncomingMessage;\n}) {\n\t// Check if body has already been parsed by Express middleware\n\tconst maybeConsumedReq = request as NodeRequestWithBody;\n\tconst isFormUrlEncoded = hasFormUrlEncodedContentType(request.headers);\n\tlet body = undefined;\n\n\tconst method = request.method;\n\t// Request with GET/HEAD method cannot have body.\n\tif (method !== \"GET\" && method !== \"HEAD\") {\n\t\t// Raw-first strategy: prefer consuming the original request stream whenever it is still readable.\n\t\tif (canReadRawBody(request)) {\n\t\t\tbody = get_raw_body(request, bodySizeLimit);\n\t\t} else if (maybeConsumedReq.body !== undefined) {\n\t\t\tconst parsedBody = maybeConsumedReq.body;\n\n\t\t\tconst bodyContent = serializeParsedBody(parsedBody, isFormUrlEncoded);\n\t\t\tbody = new ReadableStream({\n\t\t\t\tstart(controller) {\n\t\t\t\t\tcontroller.enqueue(new TextEncoder().encode(bodyContent));\n\t\t\t\t\tcontroller.close();\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\treturn new Request(base + constructRelativeUrl(request), {\n\t\t// @ts-expect-error\n\t\tduplex: \"half\",\n\t\tmethod: request.method,\n\t\tbody,\n\t\theaders: request.headers as Record<string, string>,\n\t});\n}\n\nexport async function setResponse(res: ServerResponse, response: Response) {\n\tfor (const [key, value] of response.headers as any) {\n\t\ttry {\n\t\t\tres.setHeader(\n\t\t\t\tkey,\n\t\t\t\tkey === \"set-cookie\"\n\t\t\t\t\t? set_cookie_parser.splitCookiesString(\n\t\t\t\t\t\t\tresponse.headers.get(key) as string,\n\t\t\t\t\t\t)\n\t\t\t\t\t: value,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tres.getHeaderNames().forEach((name) => res.removeHeader(name));\n\t\t\tres.writeHead(500).end(String(error));\n\t\t\treturn;\n\t\t}\n\t}\n\n\tres.statusCode = response.status;\n\tres.writeHead(response.status);\n\n\tif (!response.body) {\n\t\tres.end();\n\t\treturn;\n\t}\n\n\tif (response.body.locked) {\n\t\tres.end(\n\t\t\t\"Fatal error: Response body is locked. \" +\n\t\t\t\t\"This can happen when the response was already read (for example through 'response.json()' or 'response.text()').\",\n\t\t);\n\t\treturn;\n\t}\n\n\tconst reader = response.body.getReader();\n\n\tif (res.destroyed) {\n\t\treader.cancel();\n\t\treturn;\n\t}\n\n\tconst cancel = (error?: Error) => {\n\t\tres.off(\"close\", cancel);\n\t\tres.off(\"error\", cancel);\n\n\t\t// If the reader has already been interrupted with an error earlier,\n\t\t// then it will appear here, it is useless, but it needs to be catch.\n\t\treader.cancel(error).catch(() => {});\n\t\tif (error) res.destroy(error);\n\t};\n\n\tres.on(\"close\", cancel);\n\tres.on(\"error\", cancel);\n\n\tnext();\n\tasync function next() {\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\tconst { done, value } = await reader.read();\n\n\t\t\t\tif (done) break;\n\n\t\t\t\tconst writeResult = res.write(value);\n\t\t\t\tif (!writeResult) {\n\t\t\t\t\t// In AWS Lambda/serverless environments, drain events may not work properly\n\t\t\t\t\t// Check if we're in a Lambda-like environment and handle differently\n\t\t\t\t\tif (\n\t\t\t\t\t\tprocess.env.AWS_LAMBDA_FUNCTION_NAME ||\n\t\t\t\t\t\tprocess.env.LAMBDA_TASK_ROOT\n\t\t\t\t\t) {\n\t\t\t\t\t\t// In Lambda, continue without waiting for drain\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Standard Node.js behavior\n\t\t\t\t\t\tres.once(\"drain\", next);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tres.end();\n\t\t} catch (error) {\n\t\t\tcancel(error instanceof Error ? error : new Error(String(error)));\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
-
|
|
3
2
|
//#region src/adapters/node/request.d.ts
|
|
4
|
-
declare function getRequest({
|
|
5
|
-
request,
|
|
6
|
-
base,
|
|
7
|
-
bodySizeLimit
|
|
8
|
-
}: {
|
|
3
|
+
declare function getRequest({ request, base, bodySizeLimit }: {
|
|
9
4
|
base: string;
|
|
10
5
|
bodySizeLimit?: number;
|
|
11
6
|
request: IncomingMessage;
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
-
|
|
3
2
|
//#region src/adapters/node/request.d.ts
|
|
4
|
-
declare function getRequest({
|
|
5
|
-
request,
|
|
6
|
-
base,
|
|
7
|
-
bodySizeLimit
|
|
8
|
-
}: {
|
|
3
|
+
declare function getRequest({ request, base, bodySizeLimit }: {
|
|
9
4
|
base: string;
|
|
10
5
|
bodySizeLimit?: number;
|
|
11
6
|
request: IncomingMessage;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import * as set_cookie_parser from "set-cookie-parser";
|
|
2
|
-
|
|
3
2
|
//#region src/adapters/node/request.ts
|
|
4
3
|
const getFirstHeaderValue = (header) => {
|
|
5
4
|
if (Array.isArray(header)) return header[0];
|
|
@@ -172,7 +171,7 @@ async function setResponse(res, response) {
|
|
|
172
171
|
}
|
|
173
172
|
}
|
|
174
173
|
}
|
|
175
|
-
|
|
176
174
|
//#endregion
|
|
177
175
|
export { getRequest, setResponse };
|
|
176
|
+
|
|
178
177
|
//# sourceMappingURL=request.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request.mjs","names":[],"sources":["../../../src/adapters/node/request.ts"],"sourcesContent":["import type {\n\tIncomingHttpHeaders,\n\tIncomingMessage,\n\tServerResponse,\n} from \"node:http\";\nimport * as set_cookie_parser from \"set-cookie-parser\";\n\ntype NodeRequestWithBody = IncomingMessage & {\n\tbody?: unknown;\n};\n\nconst getFirstHeaderValue = (\n\theader: IncomingHttpHeaders[string],\n): string | undefined => {\n\tif (Array.isArray(header)) {\n\t\treturn header[0];\n\t}\n\treturn header;\n};\n\nconst hasFormUrlEncodedContentType = (\n\theaders: IncomingHttpHeaders,\n): boolean => {\n\tconst contentType = getFirstHeaderValue(headers[\"content-type\"]);\n\tif (!contentType) {\n\t\treturn false;\n\t}\n\treturn contentType\n\t\t.toLowerCase()\n\t\t.startsWith(\"application/x-www-form-urlencoded\");\n};\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === Object.prototype || prototype === null;\n};\n\nconst appendFormValue = (\n\tparams: URLSearchParams,\n\tkey: string,\n\tvalue: unknown,\n) => {\n\tif (value === undefined) {\n\t\treturn;\n\t}\n\tif (Array.isArray(value)) {\n\t\tfor (const item of value) {\n\t\t\tappendFormValue(params, key, item);\n\t\t}\n\t\treturn;\n\t}\n\tif (value === null) {\n\t\tparams.append(key, \"\");\n\t\treturn;\n\t}\n\tif (isPlainObject(value)) {\n\t\tparams.append(key, JSON.stringify(value));\n\t\treturn;\n\t}\n\tparams.append(key, `${value}`);\n};\n\nconst toFormUrlEncodedBody = (\n\tbody: Readonly<Record<string, unknown>>,\n): string => {\n\tconst params = new URLSearchParams();\n\tfor (const [key, value] of Object.entries(body)) {\n\t\tappendFormValue(params, key, value);\n\t}\n\treturn params.toString();\n};\n\nconst canReadRawBody = (request: IncomingMessage): boolean => {\n\treturn (\n\t\t!request.destroyed && request.readableEnded !== true && request.readable\n\t);\n};\n\nconst serializeParsedBody = (\n\tparsedBody: unknown,\n\tisFormUrlEncoded: boolean,\n): string => {\n\tif (typeof parsedBody === \"string\") {\n\t\treturn parsedBody;\n\t}\n\tif (parsedBody instanceof URLSearchParams) {\n\t\treturn parsedBody.toString();\n\t}\n\tif (isFormUrlEncoded && isPlainObject(parsedBody)) {\n\t\treturn toFormUrlEncodedBody(parsedBody);\n\t}\n\treturn JSON.stringify(parsedBody);\n};\n\nfunction get_raw_body(req: IncomingMessage, body_size_limit?: number) {\n\tconst h = req.headers;\n\n\tif (!h[\"content-type\"]) return null;\n\n\tconst content_length = Number(h[\"content-length\"]);\n\n\t// check if no request body\n\tif (\n\t\t(req.httpVersionMajor === 1 &&\n\t\t\tisNaN(content_length) &&\n\t\t\th[\"transfer-encoding\"] == null) ||\n\t\tcontent_length === 0\n\t) {\n\t\treturn null;\n\t}\n\n\tlet length = content_length;\n\n\tif (body_size_limit) {\n\t\tif (!length) {\n\t\t\tlength = body_size_limit;\n\t\t} else if (length > body_size_limit) {\n\t\t\tthrow Error(\n\t\t\t\t`Received content-length of ${length}, but only accept up to ${body_size_limit} bytes.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (req.destroyed) {\n\t\tconst readable = new ReadableStream();\n\t\treadable.cancel();\n\t\treturn readable;\n\t}\n\n\tlet size = 0;\n\tlet cancelled = false;\n\n\treturn new ReadableStream({\n\t\tstart(controller) {\n\t\t\treq.on(\"error\", (error) => {\n\t\t\t\tcancelled = true;\n\t\t\t\tcontroller.error(error);\n\t\t\t});\n\n\t\t\treq.on(\"end\", () => {\n\t\t\t\tif (cancelled) return;\n\t\t\t\tcontroller.close();\n\t\t\t});\n\n\t\t\treq.on(\"data\", (chunk) => {\n\t\t\t\tif (cancelled) return;\n\n\t\t\t\tsize += chunk.length;\n\n\t\t\t\tif (size > length) {\n\t\t\t\t\tcancelled = true;\n\n\t\t\t\t\tcontroller.error(\n\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t`request body size exceeded ${\n\t\t\t\t\t\t\t\tcontent_length ? \"'content-length'\" : \"BODY_SIZE_LIMIT\"\n\t\t\t\t\t\t\t} of ${length}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcontroller.enqueue(chunk);\n\n\t\t\t\tif (controller.desiredSize === null || controller.desiredSize <= 0) {\n\t\t\t\t\treq.pause();\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tpull() {\n\t\t\treq.resume();\n\t\t},\n\n\t\tcancel(reason) {\n\t\t\tcancelled = true;\n\t\t\treq.destroy(reason);\n\t\t},\n\t});\n}\n\nfunction constructRelativeUrl(\n\treq: IncomingMessage & { baseUrl?: string; originalUrl?: string },\n) {\n\tconst baseUrl = req.baseUrl;\n\tconst originalUrl = req.originalUrl;\n\n\tif (!baseUrl || !originalUrl) {\n\t\t// In express.js sub-routers `req.url` is relative to the mount\n\t\t// path (e.g., '/auth/xxx'), and `req.baseUrl` will hold the mount\n\t\t// path (e.g., '/api'). Build the full path as baseUrl + url when\n\t\t// available to preserve the full route. For application level routes\n\t\t// baseUrl will be an empty string\n\t\treturn baseUrl ? baseUrl + req.url : req.url;\n\t}\n\n\tif (baseUrl + req.url === originalUrl) {\n\t\treturn baseUrl + req.url;\n\t}\n\n\t// For certain subroutes or when mounting wildcard middlewares in express\n\t// it is possible `baseUrl + req.url` will result in a url constructed\n\t// which has a trailing forward slash the original url did not have.\n\t// Checking the `req.originalUrl` path ending can prevent this issue.\n\n\tconst originalPathEnding = originalUrl.split(\"?\")[0]!.at(-1);\n\treturn originalPathEnding === \"/\" ? baseUrl + req.url : baseUrl;\n}\n\nexport function getRequest({\n\trequest,\n\tbase,\n\tbodySizeLimit,\n}: {\n\tbase: string;\n\tbodySizeLimit?: number;\n\trequest: IncomingMessage;\n}) {\n\t// Check if body has already been parsed by Express middleware\n\tconst maybeConsumedReq = request as NodeRequestWithBody;\n\tconst isFormUrlEncoded = hasFormUrlEncodedContentType(request.headers);\n\tlet body = undefined;\n\n\tconst method = request.method;\n\t// Request with GET/HEAD method cannot have body.\n\tif (method !== \"GET\" && method !== \"HEAD\") {\n\t\t// Raw-first strategy: prefer consuming the original request stream whenever it is still readable.\n\t\tif (canReadRawBody(request)) {\n\t\t\tbody = get_raw_body(request, bodySizeLimit);\n\t\t} else if (maybeConsumedReq.body !== undefined) {\n\t\t\tconst parsedBody = maybeConsumedReq.body;\n\n\t\t\tconst bodyContent = serializeParsedBody(parsedBody, isFormUrlEncoded);\n\t\t\tbody = new ReadableStream({\n\t\t\t\tstart(controller) {\n\t\t\t\t\tcontroller.enqueue(new TextEncoder().encode(bodyContent));\n\t\t\t\t\tcontroller.close();\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\treturn new Request(base + constructRelativeUrl(request), {\n\t\t// @ts-expect-error\n\t\tduplex: \"half\",\n\t\tmethod: request.method,\n\t\tbody,\n\t\theaders: request.headers as Record<string, string>,\n\t});\n}\n\nexport async function setResponse(res: ServerResponse, response: Response) {\n\tfor (const [key, value] of response.headers as any) {\n\t\ttry {\n\t\t\tres.setHeader(\n\t\t\t\tkey,\n\t\t\t\tkey === \"set-cookie\"\n\t\t\t\t\t? set_cookie_parser.splitCookiesString(\n\t\t\t\t\t\t\tresponse.headers.get(key) as string,\n\t\t\t\t\t\t)\n\t\t\t\t\t: value,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tres.getHeaderNames().forEach((name) => res.removeHeader(name));\n\t\t\tres.writeHead(500).end(String(error));\n\t\t\treturn;\n\t\t}\n\t}\n\n\tres.statusCode = response.status;\n\tres.writeHead(response.status);\n\n\tif (!response.body) {\n\t\tres.end();\n\t\treturn;\n\t}\n\n\tif (response.body.locked) {\n\t\tres.end(\n\t\t\t\"Fatal error: Response body is locked. \" +\n\t\t\t\t\"This can happen when the response was already read (for example through 'response.json()' or 'response.text()').\",\n\t\t);\n\t\treturn;\n\t}\n\n\tconst reader = response.body.getReader();\n\n\tif (res.destroyed) {\n\t\treader.cancel();\n\t\treturn;\n\t}\n\n\tconst cancel = (error?: Error) => {\n\t\tres.off(\"close\", cancel);\n\t\tres.off(\"error\", cancel);\n\n\t\t// If the reader has already been interrupted with an error earlier,\n\t\t// then it will appear here, it is useless, but it needs to be catch.\n\t\treader.cancel(error).catch(() => {});\n\t\tif (error) res.destroy(error);\n\t};\n\n\tres.on(\"close\", cancel);\n\tres.on(\"error\", cancel);\n\n\tnext();\n\tasync function next() {\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\tconst { done, value } = await reader.read();\n\n\t\t\t\tif (done) break;\n\n\t\t\t\tconst writeResult = res.write(value);\n\t\t\t\tif (!writeResult) {\n\t\t\t\t\t// In AWS Lambda/serverless environments, drain events may not work properly\n\t\t\t\t\t// Check if we're in a Lambda-like environment and handle differently\n\t\t\t\t\tif (\n\t\t\t\t\t\tprocess.env.AWS_LAMBDA_FUNCTION_NAME ||\n\t\t\t\t\t\tprocess.env.LAMBDA_TASK_ROOT\n\t\t\t\t\t) {\n\t\t\t\t\t\t// In Lambda, continue without waiting for drain\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Standard Node.js behavior\n\t\t\t\t\t\tres.once(\"drain\", next);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tres.end();\n\t\t} catch (error) {\n\t\t\tcancel(error instanceof Error ? error : new Error(String(error)));\n\t\t}\n\t}\n}\n"],"mappings":";;;AAWA,MAAM,uBACL,WACwB;AACxB,KAAI,MAAM,QAAQ,OAAO,CACxB,QAAO,OAAO;AAEf,QAAO;;AAGR,MAAM,gCACL,YACa;CACb,MAAM,cAAc,oBAAoB,QAAQ,gBAAgB;AAChE,KAAI,CAAC,YACJ,QAAO;AAER,QAAO,YACL,aAAa,CACb,WAAW,oCAAoC;;AAGlD,MAAM,iBAAiB,UAAqD;AAC3E,KAAI,OAAO,UAAU,YAAY,UAAU,KAC1C,QAAO;CAER,MAAM,YAAY,OAAO,eAAe,MAAM;AAC9C,QAAO,cAAc,OAAO,aAAa,cAAc;;AAGxD,MAAM,mBACL,QACA,KACA,UACI;AACJ,KAAI,UAAU,OACb;AAED,KAAI,MAAM,QAAQ,MAAM,EAAE;AACzB,OAAK,MAAM,QAAQ,MAClB,iBAAgB,QAAQ,KAAK,KAAK;AAEnC;;AAED,KAAI,UAAU,MAAM;AACnB,SAAO,OAAO,KAAK,GAAG;AACtB;;AAED,KAAI,cAAc,MAAM,EAAE;AACzB,SAAO,OAAO,KAAK,KAAK,UAAU,MAAM,CAAC;AACzC;;AAED,QAAO,OAAO,KAAK,GAAG,QAAQ;;AAG/B,MAAM,wBACL,SACY;CACZ,MAAM,SAAS,IAAI,iBAAiB;AACpC,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,CAC9C,iBAAgB,QAAQ,KAAK,MAAM;AAEpC,QAAO,OAAO,UAAU;;AAGzB,MAAM,kBAAkB,YAAsC;AAC7D,QACC,CAAC,QAAQ,aAAa,QAAQ,kBAAkB,QAAQ,QAAQ;;AAIlE,MAAM,uBACL,YACA,qBACY;AACZ,KAAI,OAAO,eAAe,SACzB,QAAO;AAER,KAAI,sBAAsB,gBACzB,QAAO,WAAW,UAAU;AAE7B,KAAI,oBAAoB,cAAc,WAAW,CAChD,QAAO,qBAAqB,WAAW;AAExC,QAAO,KAAK,UAAU,WAAW;;AAGlC,SAAS,aAAa,KAAsB,iBAA0B;CACrE,MAAM,IAAI,IAAI;AAEd,KAAI,CAAC,EAAE,gBAAiB,QAAO;CAE/B,MAAM,iBAAiB,OAAO,EAAE,kBAAkB;AAGlD,KACE,IAAI,qBAAqB,KACzB,MAAM,eAAe,IACrB,EAAE,wBAAwB,QAC3B,mBAAmB,EAEnB,QAAO;CAGR,IAAI,SAAS;AAEb,KAAI,iBACH;MAAI,CAAC,OACJ,UAAS;WACC,SAAS,gBACnB,OAAM,MACL,8BAA8B,OAAO,0BAA0B,gBAAgB,SAC/E;;AAIH,KAAI,IAAI,WAAW;EAClB,MAAM,WAAW,IAAI,gBAAgB;AACrC,WAAS,QAAQ;AACjB,SAAO;;CAGR,IAAI,OAAO;CACX,IAAI,YAAY;AAEhB,QAAO,IAAI,eAAe;EACzB,MAAM,YAAY;AACjB,OAAI,GAAG,UAAU,UAAU;AAC1B,gBAAY;AACZ,eAAW,MAAM,MAAM;KACtB;AAEF,OAAI,GAAG,aAAa;AACnB,QAAI,UAAW;AACf,eAAW,OAAO;KACjB;AAEF,OAAI,GAAG,SAAS,UAAU;AACzB,QAAI,UAAW;AAEf,YAAQ,MAAM;AAEd,QAAI,OAAO,QAAQ;AAClB,iBAAY;AAEZ,gBAAW,sBACV,IAAI,MACH,8BACC,iBAAiB,qBAAqB,kBACtC,MAAM,SACP,CACD;AACD;;AAGD,eAAW,QAAQ,MAAM;AAEzB,QAAI,WAAW,gBAAgB,QAAQ,WAAW,eAAe,EAChE,KAAI,OAAO;KAEX;;EAGH,OAAO;AACN,OAAI,QAAQ;;EAGb,OAAO,QAAQ;AACd,eAAY;AACZ,OAAI,QAAQ,OAAO;;EAEpB,CAAC;;AAGH,SAAS,qBACR,KACC;CACD,MAAM,UAAU,IAAI;CACpB,MAAM,cAAc,IAAI;AAExB,KAAI,CAAC,WAAW,CAAC,YAMhB,QAAO,UAAU,UAAU,IAAI,MAAM,IAAI;AAG1C,KAAI,UAAU,IAAI,QAAQ,YACzB,QAAO,UAAU,IAAI;AAStB,QAD2B,YAAY,MAAM,IAAI,CAAC,GAAI,GAAG,GAAG,KAC9B,MAAM,UAAU,IAAI,MAAM;;AAGzD,SAAgB,WAAW,EAC1B,SACA,MACA,iBAKE;CAEF,MAAM,mBAAmB;CACzB,MAAM,mBAAmB,6BAA6B,QAAQ,QAAQ;CACtE,IAAI,OAAO;CAEX,MAAM,SAAS,QAAQ;AAEvB,KAAI,WAAW,SAAS,WAAW,QAElC;MAAI,eAAe,QAAQ,CAC1B,QAAO,aAAa,SAAS,cAAc;WACjC,iBAAiB,SAAS,QAAW;GAC/C,MAAM,aAAa,iBAAiB;GAEpC,MAAM,cAAc,oBAAoB,YAAY,iBAAiB;AACrE,UAAO,IAAI,eAAe,EACzB,MAAM,YAAY;AACjB,eAAW,QAAQ,IAAI,aAAa,CAAC,OAAO,YAAY,CAAC;AACzD,eAAW,OAAO;MAEnB,CAAC;;;AAIJ,QAAO,IAAI,QAAQ,OAAO,qBAAqB,QAAQ,EAAE;EAExD,QAAQ;EACR,QAAQ,QAAQ;EAChB;EACA,SAAS,QAAQ;EACjB,CAAC;;AAGH,eAAsB,YAAY,KAAqB,UAAoB;AAC1E,MAAK,MAAM,CAAC,KAAK,UAAU,SAAS,QACnC,KAAI;AACH,MAAI,UACH,KACA,QAAQ,eACL,kBAAkB,mBAClB,SAAS,QAAQ,IAAI,IAAI,CACzB,GACA,MACH;UACO,OAAO;AACf,MAAI,gBAAgB,CAAC,SAAS,SAAS,IAAI,aAAa,KAAK,CAAC;AAC9D,MAAI,UAAU,IAAI,CAAC,IAAI,OAAO,MAAM,CAAC;AACrC;;AAIF,KAAI,aAAa,SAAS;AAC1B,KAAI,UAAU,SAAS,OAAO;AAE9B,KAAI,CAAC,SAAS,MAAM;AACnB,MAAI,KAAK;AACT;;AAGD,KAAI,SAAS,KAAK,QAAQ;AACzB,MAAI,IACH,yJAEA;AACD;;CAGD,MAAM,SAAS,SAAS,KAAK,WAAW;AAExC,KAAI,IAAI,WAAW;AAClB,SAAO,QAAQ;AACf;;CAGD,MAAM,UAAU,UAAkB;AACjC,MAAI,IAAI,SAAS,OAAO;AACxB,MAAI,IAAI,SAAS,OAAO;AAIxB,SAAO,OAAO,MAAM,CAAC,YAAY,GAAG;AACpC,MAAI,MAAO,KAAI,QAAQ,MAAM;;AAG9B,KAAI,GAAG,SAAS,OAAO;AACvB,KAAI,GAAG,SAAS,OAAO;AAEvB,OAAM;CACN,eAAe,OAAO;AACrB,MAAI;AACH,YAAS;IACR,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,MAAM;AAE3C,QAAI,KAAM;AAGV,QAAI,CADgB,IAAI,MAAM,MAAM,CAInC,KACC,QAAQ,IAAI,4BACZ,QAAQ,IAAI,iBAGZ;SACM;AAEN,SAAI,KAAK,SAAS,KAAK;AACvB;;;AAIH,OAAI,KAAK;WACD,OAAO;AACf,UAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"request.mjs","names":[],"sources":["../../../src/adapters/node/request.ts"],"sourcesContent":["import type {\n\tIncomingHttpHeaders,\n\tIncomingMessage,\n\tServerResponse,\n} from \"node:http\";\nimport * as set_cookie_parser from \"set-cookie-parser\";\n\ntype NodeRequestWithBody = IncomingMessage & {\n\tbody?: unknown;\n};\n\nconst getFirstHeaderValue = (\n\theader: IncomingHttpHeaders[string],\n): string | undefined => {\n\tif (Array.isArray(header)) {\n\t\treturn header[0];\n\t}\n\treturn header;\n};\n\nconst hasFormUrlEncodedContentType = (\n\theaders: IncomingHttpHeaders,\n): boolean => {\n\tconst contentType = getFirstHeaderValue(headers[\"content-type\"]);\n\tif (!contentType) {\n\t\treturn false;\n\t}\n\treturn contentType\n\t\t.toLowerCase()\n\t\t.startsWith(\"application/x-www-form-urlencoded\");\n};\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === Object.prototype || prototype === null;\n};\n\nconst appendFormValue = (\n\tparams: URLSearchParams,\n\tkey: string,\n\tvalue: unknown,\n) => {\n\tif (value === undefined) {\n\t\treturn;\n\t}\n\tif (Array.isArray(value)) {\n\t\tfor (const item of value) {\n\t\t\tappendFormValue(params, key, item);\n\t\t}\n\t\treturn;\n\t}\n\tif (value === null) {\n\t\tparams.append(key, \"\");\n\t\treturn;\n\t}\n\tif (isPlainObject(value)) {\n\t\tparams.append(key, JSON.stringify(value));\n\t\treturn;\n\t}\n\tparams.append(key, `${value}`);\n};\n\nconst toFormUrlEncodedBody = (\n\tbody: Readonly<Record<string, unknown>>,\n): string => {\n\tconst params = new URLSearchParams();\n\tfor (const [key, value] of Object.entries(body)) {\n\t\tappendFormValue(params, key, value);\n\t}\n\treturn params.toString();\n};\n\nconst canReadRawBody = (request: IncomingMessage): boolean => {\n\treturn (\n\t\t!request.destroyed && request.readableEnded !== true && request.readable\n\t);\n};\n\nconst serializeParsedBody = (\n\tparsedBody: unknown,\n\tisFormUrlEncoded: boolean,\n): string => {\n\tif (typeof parsedBody === \"string\") {\n\t\treturn parsedBody;\n\t}\n\tif (parsedBody instanceof URLSearchParams) {\n\t\treturn parsedBody.toString();\n\t}\n\tif (isFormUrlEncoded && isPlainObject(parsedBody)) {\n\t\treturn toFormUrlEncodedBody(parsedBody);\n\t}\n\treturn JSON.stringify(parsedBody);\n};\n\nfunction get_raw_body(req: IncomingMessage, body_size_limit?: number) {\n\tconst h = req.headers;\n\n\tif (!h[\"content-type\"]) return null;\n\n\tconst content_length = Number(h[\"content-length\"]);\n\n\t// check if no request body\n\tif (\n\t\t(req.httpVersionMajor === 1 &&\n\t\t\tisNaN(content_length) &&\n\t\t\th[\"transfer-encoding\"] == null) ||\n\t\tcontent_length === 0\n\t) {\n\t\treturn null;\n\t}\n\n\tlet length = content_length;\n\n\tif (body_size_limit) {\n\t\tif (!length) {\n\t\t\tlength = body_size_limit;\n\t\t} else if (length > body_size_limit) {\n\t\t\tthrow Error(\n\t\t\t\t`Received content-length of ${length}, but only accept up to ${body_size_limit} bytes.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (req.destroyed) {\n\t\tconst readable = new ReadableStream();\n\t\treadable.cancel();\n\t\treturn readable;\n\t}\n\n\tlet size = 0;\n\tlet cancelled = false;\n\n\treturn new ReadableStream({\n\t\tstart(controller) {\n\t\t\treq.on(\"error\", (error) => {\n\t\t\t\tcancelled = true;\n\t\t\t\tcontroller.error(error);\n\t\t\t});\n\n\t\t\treq.on(\"end\", () => {\n\t\t\t\tif (cancelled) return;\n\t\t\t\tcontroller.close();\n\t\t\t});\n\n\t\t\treq.on(\"data\", (chunk) => {\n\t\t\t\tif (cancelled) return;\n\n\t\t\t\tsize += chunk.length;\n\n\t\t\t\tif (size > length) {\n\t\t\t\t\tcancelled = true;\n\n\t\t\t\t\tcontroller.error(\n\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t`request body size exceeded ${\n\t\t\t\t\t\t\t\tcontent_length ? \"'content-length'\" : \"BODY_SIZE_LIMIT\"\n\t\t\t\t\t\t\t} of ${length}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcontroller.enqueue(chunk);\n\n\t\t\t\tif (controller.desiredSize === null || controller.desiredSize <= 0) {\n\t\t\t\t\treq.pause();\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\tpull() {\n\t\t\treq.resume();\n\t\t},\n\n\t\tcancel(reason) {\n\t\t\tcancelled = true;\n\t\t\treq.destroy(reason);\n\t\t},\n\t});\n}\n\nfunction constructRelativeUrl(\n\treq: IncomingMessage & { baseUrl?: string; originalUrl?: string },\n) {\n\tconst baseUrl = req.baseUrl;\n\tconst originalUrl = req.originalUrl;\n\n\tif (!baseUrl || !originalUrl) {\n\t\t// In express.js sub-routers `req.url` is relative to the mount\n\t\t// path (e.g., '/auth/xxx'), and `req.baseUrl` will hold the mount\n\t\t// path (e.g., '/api'). Build the full path as baseUrl + url when\n\t\t// available to preserve the full route. For application level routes\n\t\t// baseUrl will be an empty string\n\t\treturn baseUrl ? baseUrl + req.url : req.url;\n\t}\n\n\tif (baseUrl + req.url === originalUrl) {\n\t\treturn baseUrl + req.url;\n\t}\n\n\t// For certain subroutes or when mounting wildcard middlewares in express\n\t// it is possible `baseUrl + req.url` will result in a url constructed\n\t// which has a trailing forward slash the original url did not have.\n\t// Checking the `req.originalUrl` path ending can prevent this issue.\n\n\tconst originalPathEnding = originalUrl.split(\"?\")[0]!.at(-1);\n\treturn originalPathEnding === \"/\" ? baseUrl + req.url : baseUrl;\n}\n\nexport function getRequest({\n\trequest,\n\tbase,\n\tbodySizeLimit,\n}: {\n\tbase: string;\n\tbodySizeLimit?: number;\n\trequest: IncomingMessage;\n}) {\n\t// Check if body has already been parsed by Express middleware\n\tconst maybeConsumedReq = request as NodeRequestWithBody;\n\tconst isFormUrlEncoded = hasFormUrlEncodedContentType(request.headers);\n\tlet body = undefined;\n\n\tconst method = request.method;\n\t// Request with GET/HEAD method cannot have body.\n\tif (method !== \"GET\" && method !== \"HEAD\") {\n\t\t// Raw-first strategy: prefer consuming the original request stream whenever it is still readable.\n\t\tif (canReadRawBody(request)) {\n\t\t\tbody = get_raw_body(request, bodySizeLimit);\n\t\t} else if (maybeConsumedReq.body !== undefined) {\n\t\t\tconst parsedBody = maybeConsumedReq.body;\n\n\t\t\tconst bodyContent = serializeParsedBody(parsedBody, isFormUrlEncoded);\n\t\t\tbody = new ReadableStream({\n\t\t\t\tstart(controller) {\n\t\t\t\t\tcontroller.enqueue(new TextEncoder().encode(bodyContent));\n\t\t\t\t\tcontroller.close();\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\treturn new Request(base + constructRelativeUrl(request), {\n\t\t// @ts-expect-error\n\t\tduplex: \"half\",\n\t\tmethod: request.method,\n\t\tbody,\n\t\theaders: request.headers as Record<string, string>,\n\t});\n}\n\nexport async function setResponse(res: ServerResponse, response: Response) {\n\tfor (const [key, value] of response.headers as any) {\n\t\ttry {\n\t\t\tres.setHeader(\n\t\t\t\tkey,\n\t\t\t\tkey === \"set-cookie\"\n\t\t\t\t\t? set_cookie_parser.splitCookiesString(\n\t\t\t\t\t\t\tresponse.headers.get(key) as string,\n\t\t\t\t\t\t)\n\t\t\t\t\t: value,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tres.getHeaderNames().forEach((name) => res.removeHeader(name));\n\t\t\tres.writeHead(500).end(String(error));\n\t\t\treturn;\n\t\t}\n\t}\n\n\tres.statusCode = response.status;\n\tres.writeHead(response.status);\n\n\tif (!response.body) {\n\t\tres.end();\n\t\treturn;\n\t}\n\n\tif (response.body.locked) {\n\t\tres.end(\n\t\t\t\"Fatal error: Response body is locked. \" +\n\t\t\t\t\"This can happen when the response was already read (for example through 'response.json()' or 'response.text()').\",\n\t\t);\n\t\treturn;\n\t}\n\n\tconst reader = response.body.getReader();\n\n\tif (res.destroyed) {\n\t\treader.cancel();\n\t\treturn;\n\t}\n\n\tconst cancel = (error?: Error) => {\n\t\tres.off(\"close\", cancel);\n\t\tres.off(\"error\", cancel);\n\n\t\t// If the reader has already been interrupted with an error earlier,\n\t\t// then it will appear here, it is useless, but it needs to be catch.\n\t\treader.cancel(error).catch(() => {});\n\t\tif (error) res.destroy(error);\n\t};\n\n\tres.on(\"close\", cancel);\n\tres.on(\"error\", cancel);\n\n\tnext();\n\tasync function next() {\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\tconst { done, value } = await reader.read();\n\n\t\t\t\tif (done) break;\n\n\t\t\t\tconst writeResult = res.write(value);\n\t\t\t\tif (!writeResult) {\n\t\t\t\t\t// In AWS Lambda/serverless environments, drain events may not work properly\n\t\t\t\t\t// Check if we're in a Lambda-like environment and handle differently\n\t\t\t\t\tif (\n\t\t\t\t\t\tprocess.env.AWS_LAMBDA_FUNCTION_NAME ||\n\t\t\t\t\t\tprocess.env.LAMBDA_TASK_ROOT\n\t\t\t\t\t) {\n\t\t\t\t\t\t// In Lambda, continue without waiting for drain\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Standard Node.js behavior\n\t\t\t\t\t\tres.once(\"drain\", next);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tres.end();\n\t\t} catch (error) {\n\t\t\tcancel(error instanceof Error ? error : new Error(String(error)));\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|
package/dist/client.cjs
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value:
|
|
2
|
-
const
|
|
3
|
-
const require_error = require('./error.cjs');
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_error = require("./error.cjs");
|
|
4
3
|
let _better_fetch_fetch = require("@better-fetch/fetch");
|
|
5
|
-
|
|
6
4
|
//#region src/client.ts
|
|
7
5
|
const createClient = (options) => {
|
|
8
6
|
const fetch = (0, _better_fetch_fetch.createFetch)(options ?? {});
|
|
@@ -10,7 +8,6 @@ const createClient = (options) => {
|
|
|
10
8
|
return await fetch(path, { ...callOptions[0] });
|
|
11
9
|
};
|
|
12
10
|
};
|
|
13
|
-
|
|
14
11
|
//#endregion
|
|
15
12
|
exports.APIError = require_error.APIError;
|
|
16
13
|
exports.BetterCallError = require_error.BetterCallError;
|
|
@@ -20,4 +17,5 @@ exports.hideInternalStackFrames = require_error.hideInternalStackFrames;
|
|
|
20
17
|
exports.kAPIErrorHeaderSymbol = require_error.kAPIErrorHeaderSymbol;
|
|
21
18
|
exports.makeErrorForHideStackFrame = require_error.makeErrorForHideStackFrame;
|
|
22
19
|
exports.statusCodes = require_error.statusCodes;
|
|
20
|
+
|
|
23
21
|
//# sourceMappingURL=client.cjs.map
|
package/dist/client.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.cjs","names":[],"sources":["../src/client.ts"],"sourcesContent":["import {\n\ttype BetterFetchOption,\n\ttype BetterFetchResponse,\n\tcreateFetch,\n} from \"@better-fetch/fetch\";\nimport type { Endpoint } from \"./endpoint\";\nimport type { HasRequiredKeys, Prettify, UnionToIntersection } from \"./helper\";\nimport type { Router } from \"./router\";\n\nexport type HasRequired<T extends object> = T extends {}\n\t? false\n\t: T extends {\n\t\t\t\tbody?: any;\n\t\t\t\tquery?: any;\n\t\t\t\tparams?: any;\n\t\t\t}\n\t\t? T[\"body\"] extends object\n\t\t\t? HasRequiredKeys<T[\"body\"]> extends true\n\t\t\t\t? true\n\t\t\t\t: T[\"query\"] extends object\n\t\t\t\t\t? HasRequiredKeys<T[\"query\"]> extends true\n\t\t\t\t\t\t? true\n\t\t\t\t\t\t: T[\"params\"] extends object\n\t\t\t\t\t\t\t? HasRequiredKeys<T[\"params\"]>\n\t\t\t\t\t\t\t: false\n\t\t\t\t\t: T[\"params\"] extends object\n\t\t\t\t\t\t? HasRequiredKeys<T[\"params\"]>\n\t\t\t\t\t\t: false\n\t\t\t: T[\"query\"] extends object\n\t\t\t\t? HasRequiredKeys<T[\"query\"]> extends true\n\t\t\t\t\t? true\n\t\t\t\t\t: T[\"params\"] extends object\n\t\t\t\t\t\t? HasRequiredKeys<T[\"params\"]>\n\t\t\t\t\t\t: false\n\t\t\t\t: T[\"params\"] extends object\n\t\t\t\t\t? HasRequiredKeys<T[\"params\"]>\n\t\t\t\t\t: false\n\t\t: false;\n\ntype InferContext<T> = T extends (ctx: infer Ctx) => any\n\t? Ctx extends object\n\t\t? Ctx\n\t\t: never\n\t: never;\n\nexport interface ClientOptions extends BetterFetchOption {\n\tbaseURL?: string;\n}\n\ntype WithRequired<T, K> = T & {\n\t[P in K extends string ? K : never]-?: T[P extends keyof T ? P : never];\n};\n\n/**\n * Filter out endpoints that should not be exposed to the client.\n * Checks the typed metadata on the Endpoint's options.\n */\ntype InferClientRoutes<T extends Record<string, Endpoint>> = {\n\t[K in keyof T]: T[K] extends Endpoint<\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tinfer Meta\n\t>\n\t\t? Meta extends\n\t\t\t\t| { scope: \"http\" }\n\t\t\t\t| { scope: \"server\" }\n\t\t\t\t| { SERVER_ONLY: true }\n\t\t\t\t| { isAction: false }\n\t\t\t? never\n\t\t\t: T[K]\n\t\t: T[K];\n};\n\nexport type RequiredOptionKeys<\n\tC extends {\n\t\tbody?: any;\n\t\tquery?: any;\n\t\tparams?: any;\n\t},\n> = (undefined extends C[\"body\"]\n\t? {}\n\t: {\n\t\t\tbody: true;\n\t\t}) &\n\t(undefined extends C[\"query\"]\n\t\t? {}\n\t\t: {\n\t\t\t\tquery: true;\n\t\t\t}) &\n\t(undefined extends C[\"params\"]\n\t\t? {}\n\t\t: {\n\t\t\t\tparams: true;\n\t\t\t});\n\nexport const createClient = <\n\tR extends Router | Router[\"endpoints\"],\n\tGlobalOpts extends ClientOptions = ClientOptions,\n>(\n\toptions?: GlobalOpts,\n) => {\n\tconst fetch = createFetch(options ?? {});\n\ttype API = InferClientRoutes<\n\t\tR extends { endpoints: Record<string, Endpoint> } ? R[\"endpoints\"] : R\n\t>;\n\ttype Options = API extends {\n\t\t[key: string]: infer T;\n\t}\n\t\t? T extends Endpoint<infer P, infer M>\n\t\t\t? {\n\t\t\t\t\t[key in M extends \"GET\"\n\t\t\t\t\t\t? P\n\t\t\t\t\t\t: `@${M extends string ? Lowercase<M> : never}${P}`]: T;\n\t\t\t\t}\n\t\t\t: {}\n\t\t: {};\n\n\ttype O = Prettify<UnionToIntersection<Options>>;\n\treturn async <\n\t\tOPT extends O,\n\t\tK extends keyof OPT,\n\t\tC extends InferContext<OPT[K]>,\n\t\tCallOpts extends BetterFetchOption<C[\"body\"], C[\"query\"], C[\"params\"]>,\n\t>(\n\t\tpath: K,\n\t\t...callOptions: HasRequired<C> extends true\n\t\t\t? [\n\t\t\t\t\tWithRequired<\n\t\t\t\t\t\tBetterFetchOption<C[\"body\"], C[\"query\"], C[\"params\"]>,\n\t\t\t\t\t\tkeyof RequiredOptionKeys<C>\n\t\t\t\t\t>,\n\t\t\t\t]\n\t\t\t: [CallOpts?]\n\t): Promise<\n\t\tBetterFetchResponse<\n\t\t\tAwaited<ReturnType<OPT[K] extends Endpoint ? OPT[K] : never>>,\n\t\t\tunknown,\n\t\t\tCallOpts[\"throw\"] extends boolean\n\t\t\t\t? CallOpts[\"throw\"]\n\t\t\t\t: GlobalOpts[\"throw\"] extends true\n\t\t\t\t\t? true\n\t\t\t\t\t: false\n\t\t>\n\t> => {\n\t\treturn (await fetch(path as string, {\n\t\t\t...callOptions[0],\n\t\t})) as any;\n\t};\n};\n\nexport * from \"./error\";\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.cjs","names":[],"sources":["../src/client.ts"],"sourcesContent":["import {\n\ttype BetterFetchOption,\n\ttype BetterFetchResponse,\n\tcreateFetch,\n} from \"@better-fetch/fetch\";\nimport type { Endpoint } from \"./endpoint\";\nimport type { HasRequiredKeys, Prettify, UnionToIntersection } from \"./helper\";\nimport type { Router } from \"./router\";\n\nexport type HasRequired<T extends object> = T extends {}\n\t? false\n\t: T extends {\n\t\t\t\tbody?: any;\n\t\t\t\tquery?: any;\n\t\t\t\tparams?: any;\n\t\t\t}\n\t\t? T[\"body\"] extends object\n\t\t\t? HasRequiredKeys<T[\"body\"]> extends true\n\t\t\t\t? true\n\t\t\t\t: T[\"query\"] extends object\n\t\t\t\t\t? HasRequiredKeys<T[\"query\"]> extends true\n\t\t\t\t\t\t? true\n\t\t\t\t\t\t: T[\"params\"] extends object\n\t\t\t\t\t\t\t? HasRequiredKeys<T[\"params\"]>\n\t\t\t\t\t\t\t: false\n\t\t\t\t\t: T[\"params\"] extends object\n\t\t\t\t\t\t? HasRequiredKeys<T[\"params\"]>\n\t\t\t\t\t\t: false\n\t\t\t: T[\"query\"] extends object\n\t\t\t\t? HasRequiredKeys<T[\"query\"]> extends true\n\t\t\t\t\t? true\n\t\t\t\t\t: T[\"params\"] extends object\n\t\t\t\t\t\t? HasRequiredKeys<T[\"params\"]>\n\t\t\t\t\t\t: false\n\t\t\t\t: T[\"params\"] extends object\n\t\t\t\t\t? HasRequiredKeys<T[\"params\"]>\n\t\t\t\t\t: false\n\t\t: false;\n\ntype InferContext<T> = T extends (ctx: infer Ctx) => any\n\t? Ctx extends object\n\t\t? Ctx\n\t\t: never\n\t: never;\n\nexport interface ClientOptions extends BetterFetchOption {\n\tbaseURL?: string;\n}\n\ntype WithRequired<T, K> = T & {\n\t[P in K extends string ? K : never]-?: T[P extends keyof T ? P : never];\n};\n\n/**\n * Filter out endpoints that should not be exposed to the client.\n * Checks the typed metadata on the Endpoint's options.\n */\ntype InferClientRoutes<T extends Record<string, Endpoint>> = {\n\t[K in keyof T]: T[K] extends Endpoint<\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tinfer Meta\n\t>\n\t\t? Meta extends\n\t\t\t\t| { scope: \"http\" }\n\t\t\t\t| { scope: \"server\" }\n\t\t\t\t| { SERVER_ONLY: true }\n\t\t\t\t| { isAction: false }\n\t\t\t? never\n\t\t\t: T[K]\n\t\t: T[K];\n};\n\nexport type RequiredOptionKeys<\n\tC extends {\n\t\tbody?: any;\n\t\tquery?: any;\n\t\tparams?: any;\n\t},\n> = (undefined extends C[\"body\"]\n\t? {}\n\t: {\n\t\t\tbody: true;\n\t\t}) &\n\t(undefined extends C[\"query\"]\n\t\t? {}\n\t\t: {\n\t\t\t\tquery: true;\n\t\t\t}) &\n\t(undefined extends C[\"params\"]\n\t\t? {}\n\t\t: {\n\t\t\t\tparams: true;\n\t\t\t});\n\nexport const createClient = <\n\tR extends Router | Router[\"endpoints\"],\n\tGlobalOpts extends ClientOptions = ClientOptions,\n>(\n\toptions?: GlobalOpts,\n) => {\n\tconst fetch = createFetch(options ?? {});\n\ttype API = InferClientRoutes<\n\t\tR extends { endpoints: Record<string, Endpoint> } ? R[\"endpoints\"] : R\n\t>;\n\ttype Options = API extends {\n\t\t[key: string]: infer T;\n\t}\n\t\t? T extends Endpoint<infer P, infer M>\n\t\t\t? {\n\t\t\t\t\t[key in M extends \"GET\"\n\t\t\t\t\t\t? P\n\t\t\t\t\t\t: `@${M extends string ? Lowercase<M> : never}${P}`]: T;\n\t\t\t\t}\n\t\t\t: {}\n\t\t: {};\n\n\ttype O = Prettify<UnionToIntersection<Options>>;\n\treturn async <\n\t\tOPT extends O,\n\t\tK extends keyof OPT,\n\t\tC extends InferContext<OPT[K]>,\n\t\tCallOpts extends BetterFetchOption<C[\"body\"], C[\"query\"], C[\"params\"]>,\n\t>(\n\t\tpath: K,\n\t\t...callOptions: HasRequired<C> extends true\n\t\t\t? [\n\t\t\t\t\tWithRequired<\n\t\t\t\t\t\tBetterFetchOption<C[\"body\"], C[\"query\"], C[\"params\"]>,\n\t\t\t\t\t\tkeyof RequiredOptionKeys<C>\n\t\t\t\t\t>,\n\t\t\t\t]\n\t\t\t: [CallOpts?]\n\t): Promise<\n\t\tBetterFetchResponse<\n\t\t\tAwaited<ReturnType<OPT[K] extends Endpoint ? OPT[K] : never>>,\n\t\t\tunknown,\n\t\t\tCallOpts[\"throw\"] extends boolean\n\t\t\t\t? CallOpts[\"throw\"]\n\t\t\t\t: GlobalOpts[\"throw\"] extends true\n\t\t\t\t\t? true\n\t\t\t\t\t: false\n\t\t>\n\t> => {\n\t\treturn (await fetch(path as string, {\n\t\t\t...callOptions[0],\n\t\t})) as any;\n\t};\n};\n\nexport * from \"./error\";\n"],"mappings":";;;;AAmGA,MAAa,gBAIZ,YACI;CACJ,MAAM,SAAA,GAAA,oBAAA,YAAA,CAAoB,WAAW,CAAC,CAAC;CAiBvC,OAAO,OAMN,MACA,GAAG,gBAkBC;EACJ,OAAQ,MAAM,MAAM,MAAgB,EACnC,GAAG,YAAY,GAChB,CAAC;CACF;AACD"}
|
package/dist/client.d.cts
CHANGED
|
@@ -3,7 +3,6 @@ import { HasRequiredKeys, Prettify, UnionToIntersection } from "./helper.cjs";
|
|
|
3
3
|
import { Endpoint } from "./endpoint.cjs";
|
|
4
4
|
import { Router } from "./router.cjs";
|
|
5
5
|
import { BetterFetchOption, BetterFetchResponse } from "@better-fetch/fetch";
|
|
6
|
-
|
|
7
6
|
//#region src/client.d.ts
|
|
8
7
|
type HasRequired<T extends object> = T extends {} ? false : T extends {
|
|
9
8
|
body?: any;
|
|
@@ -14,7 +13,7 @@ type InferContext<T> = T extends ((ctx: infer Ctx) => any) ? Ctx extends object
|
|
|
14
13
|
interface ClientOptions extends BetterFetchOption {
|
|
15
14
|
baseURL?: string;
|
|
16
15
|
}
|
|
17
|
-
type WithRequired<T, K> = T & { [P in K extends string ? K : never]-?: T[P extends keyof T ? P : never] };
|
|
16
|
+
type WithRequired<T, K> = T & { [P in K extends string ? K : never]-?: T[P extends keyof T ? P : never]; };
|
|
18
17
|
/**
|
|
19
18
|
* Filter out endpoints that should not be exposed to the client.
|
|
20
19
|
* Checks the typed metadata on the Endpoint's options.
|
|
@@ -27,7 +26,7 @@ type InferClientRoutes<T extends Record<string, Endpoint>> = { [K in keyof T]: T
|
|
|
27
26
|
SERVER_ONLY: true;
|
|
28
27
|
} | {
|
|
29
28
|
isAction: false;
|
|
30
|
-
} ? never : T[K] : T[K] };
|
|
29
|
+
} ? never : T[K] : T[K]; };
|
|
31
30
|
type RequiredOptionKeys<C extends {
|
|
32
31
|
body?: any;
|
|
33
32
|
query?: any;
|
|
@@ -43,7 +42,7 @@ declare const createClient: <R extends Router | Router["endpoints"], GlobalOpts
|
|
|
43
42
|
endpoints: Record<string, Endpoint>;
|
|
44
43
|
} ? R["endpoints"] : R> extends {
|
|
45
44
|
[key: string]: infer T;
|
|
46
|
-
} ? T extends Endpoint<infer P extends string, infer M> ? { [key in M extends "GET" ? P : `@${M extends string ? Lowercase<M> : never}${P}`]: T } : {} : {}>>, K extends keyof OPT, C extends InferContext<OPT[K]>, CallOpts extends BetterFetchOption<C["body"], C["query"], C["params"]>>(path: K, ...callOptions: HasRequired<C> extends true ? [WithRequired<BetterFetchOption<C["body"], C["query"], C["params"]>, keyof RequiredOptionKeys<C>>] : [CallOpts?]) => Promise<BetterFetchResponse<Awaited<ReturnType<OPT[K] extends Endpoint ? OPT[K] : never>>, unknown, CallOpts["throw"] extends boolean ? CallOpts["throw"] : GlobalOpts["throw"] extends true ? true : false>>;
|
|
45
|
+
} ? T extends Endpoint<infer P extends string, infer M> ? { [key in M extends "GET" ? P : `@${M extends string ? Lowercase<M> : never}${P}`]: T; } : {} : {}>>, K extends keyof OPT, C extends InferContext<OPT[K]>, CallOpts extends BetterFetchOption<C["body"], C["query"], C["params"]>>(path: K, ...callOptions: HasRequired<C> extends true ? [WithRequired<BetterFetchOption<C["body"], C["query"], C["params"]>, keyof RequiredOptionKeys<C>>] : [CallOpts?]) => Promise<BetterFetchResponse<Awaited<ReturnType<OPT[K] extends Endpoint ? OPT[K] : never>>, unknown, CallOpts["throw"] extends boolean ? CallOpts["throw"] : GlobalOpts["throw"] extends true ? true : false>>;
|
|
47
46
|
//#endregion
|
|
48
47
|
export { APIError, BetterCallError, ClientOptions, HasRequired, RequiredOptionKeys, Status, ValidationError, createClient, hideInternalStackFrames, kAPIErrorHeaderSymbol, makeErrorForHideStackFrame, statusCodes };
|
|
49
48
|
//# sourceMappingURL=client.d.cts.map
|
package/dist/client.d.mts
CHANGED
|
@@ -3,7 +3,6 @@ import { HasRequiredKeys, Prettify, UnionToIntersection } from "./helper.mjs";
|
|
|
3
3
|
import { Endpoint } from "./endpoint.mjs";
|
|
4
4
|
import { Router } from "./router.mjs";
|
|
5
5
|
import { BetterFetchOption, BetterFetchResponse } from "@better-fetch/fetch";
|
|
6
|
-
|
|
7
6
|
//#region src/client.d.ts
|
|
8
7
|
type HasRequired<T extends object> = T extends {} ? false : T extends {
|
|
9
8
|
body?: any;
|
|
@@ -14,7 +13,7 @@ type InferContext<T> = T extends ((ctx: infer Ctx) => any) ? Ctx extends object
|
|
|
14
13
|
interface ClientOptions extends BetterFetchOption {
|
|
15
14
|
baseURL?: string;
|
|
16
15
|
}
|
|
17
|
-
type WithRequired<T, K> = T & { [P in K extends string ? K : never]-?: T[P extends keyof T ? P : never] };
|
|
16
|
+
type WithRequired<T, K> = T & { [P in K extends string ? K : never]-?: T[P extends keyof T ? P : never]; };
|
|
18
17
|
/**
|
|
19
18
|
* Filter out endpoints that should not be exposed to the client.
|
|
20
19
|
* Checks the typed metadata on the Endpoint's options.
|
|
@@ -27,7 +26,7 @@ type InferClientRoutes<T extends Record<string, Endpoint>> = { [K in keyof T]: T
|
|
|
27
26
|
SERVER_ONLY: true;
|
|
28
27
|
} | {
|
|
29
28
|
isAction: false;
|
|
30
|
-
} ? never : T[K] : T[K] };
|
|
29
|
+
} ? never : T[K] : T[K]; };
|
|
31
30
|
type RequiredOptionKeys<C extends {
|
|
32
31
|
body?: any;
|
|
33
32
|
query?: any;
|
|
@@ -43,7 +42,7 @@ declare const createClient: <R extends Router | Router["endpoints"], GlobalOpts
|
|
|
43
42
|
endpoints: Record<string, Endpoint>;
|
|
44
43
|
} ? R["endpoints"] : R> extends {
|
|
45
44
|
[key: string]: infer T;
|
|
46
|
-
} ? T extends Endpoint<infer P extends string, infer M> ? { [key in M extends "GET" ? P : `@${M extends string ? Lowercase<M> : never}${P}`]: T } : {} : {}>>, K extends keyof OPT, C extends InferContext<OPT[K]>, CallOpts extends BetterFetchOption<C["body"], C["query"], C["params"]>>(path: K, ...callOptions: HasRequired<C> extends true ? [WithRequired<BetterFetchOption<C["body"], C["query"], C["params"]>, keyof RequiredOptionKeys<C>>] : [CallOpts?]) => Promise<BetterFetchResponse<Awaited<ReturnType<OPT[K] extends Endpoint ? OPT[K] : never>>, unknown, CallOpts["throw"] extends boolean ? CallOpts["throw"] : GlobalOpts["throw"] extends true ? true : false>>;
|
|
45
|
+
} ? T extends Endpoint<infer P extends string, infer M> ? { [key in M extends "GET" ? P : `@${M extends string ? Lowercase<M> : never}${P}`]: T; } : {} : {}>>, K extends keyof OPT, C extends InferContext<OPT[K]>, CallOpts extends BetterFetchOption<C["body"], C["query"], C["params"]>>(path: K, ...callOptions: HasRequired<C> extends true ? [WithRequired<BetterFetchOption<C["body"], C["query"], C["params"]>, keyof RequiredOptionKeys<C>>] : [CallOpts?]) => Promise<BetterFetchResponse<Awaited<ReturnType<OPT[K] extends Endpoint ? OPT[K] : never>>, unknown, CallOpts["throw"] extends boolean ? CallOpts["throw"] : GlobalOpts["throw"] extends true ? true : false>>;
|
|
47
46
|
//#endregion
|
|
48
47
|
export { APIError, BetterCallError, ClientOptions, HasRequired, RequiredOptionKeys, Status, ValidationError, createClient, hideInternalStackFrames, kAPIErrorHeaderSymbol, makeErrorForHideStackFrame, statusCodes };
|
|
49
48
|
//# sourceMappingURL=client.d.mts.map
|
package/dist/client.mjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { APIError, BetterCallError, ValidationError, hideInternalStackFrames, kAPIErrorHeaderSymbol, makeErrorForHideStackFrame, statusCodes } from "./error.mjs";
|
|
2
2
|
import { createFetch } from "@better-fetch/fetch";
|
|
3
|
-
|
|
4
3
|
//#region src/client.ts
|
|
5
4
|
const createClient = (options) => {
|
|
6
5
|
const fetch = createFetch(options ?? {});
|
|
@@ -8,7 +7,7 @@ const createClient = (options) => {
|
|
|
8
7
|
return await fetch(path, { ...callOptions[0] });
|
|
9
8
|
};
|
|
10
9
|
};
|
|
11
|
-
|
|
12
10
|
//#endregion
|
|
13
11
|
export { APIError, BetterCallError, ValidationError, createClient, hideInternalStackFrames, kAPIErrorHeaderSymbol, makeErrorForHideStackFrame, statusCodes };
|
|
12
|
+
|
|
14
13
|
//# sourceMappingURL=client.mjs.map
|
package/dist/client.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.mjs","names":[],"sources":["../src/client.ts"],"sourcesContent":["import {\n\ttype BetterFetchOption,\n\ttype BetterFetchResponse,\n\tcreateFetch,\n} from \"@better-fetch/fetch\";\nimport type { Endpoint } from \"./endpoint\";\nimport type { HasRequiredKeys, Prettify, UnionToIntersection } from \"./helper\";\nimport type { Router } from \"./router\";\n\nexport type HasRequired<T extends object> = T extends {}\n\t? false\n\t: T extends {\n\t\t\t\tbody?: any;\n\t\t\t\tquery?: any;\n\t\t\t\tparams?: any;\n\t\t\t}\n\t\t? T[\"body\"] extends object\n\t\t\t? HasRequiredKeys<T[\"body\"]> extends true\n\t\t\t\t? true\n\t\t\t\t: T[\"query\"] extends object\n\t\t\t\t\t? HasRequiredKeys<T[\"query\"]> extends true\n\t\t\t\t\t\t? true\n\t\t\t\t\t\t: T[\"params\"] extends object\n\t\t\t\t\t\t\t? HasRequiredKeys<T[\"params\"]>\n\t\t\t\t\t\t\t: false\n\t\t\t\t\t: T[\"params\"] extends object\n\t\t\t\t\t\t? HasRequiredKeys<T[\"params\"]>\n\t\t\t\t\t\t: false\n\t\t\t: T[\"query\"] extends object\n\t\t\t\t? HasRequiredKeys<T[\"query\"]> extends true\n\t\t\t\t\t? true\n\t\t\t\t\t: T[\"params\"] extends object\n\t\t\t\t\t\t? HasRequiredKeys<T[\"params\"]>\n\t\t\t\t\t\t: false\n\t\t\t\t: T[\"params\"] extends object\n\t\t\t\t\t? HasRequiredKeys<T[\"params\"]>\n\t\t\t\t\t: false\n\t\t: false;\n\ntype InferContext<T> = T extends (ctx: infer Ctx) => any\n\t? Ctx extends object\n\t\t? Ctx\n\t\t: never\n\t: never;\n\nexport interface ClientOptions extends BetterFetchOption {\n\tbaseURL?: string;\n}\n\ntype WithRequired<T, K> = T & {\n\t[P in K extends string ? K : never]-?: T[P extends keyof T ? P : never];\n};\n\n/**\n * Filter out endpoints that should not be exposed to the client.\n * Checks the typed metadata on the Endpoint's options.\n */\ntype InferClientRoutes<T extends Record<string, Endpoint>> = {\n\t[K in keyof T]: T[K] extends Endpoint<\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tinfer Meta\n\t>\n\t\t? Meta extends\n\t\t\t\t| { scope: \"http\" }\n\t\t\t\t| { scope: \"server\" }\n\t\t\t\t| { SERVER_ONLY: true }\n\t\t\t\t| { isAction: false }\n\t\t\t? never\n\t\t\t: T[K]\n\t\t: T[K];\n};\n\nexport type RequiredOptionKeys<\n\tC extends {\n\t\tbody?: any;\n\t\tquery?: any;\n\t\tparams?: any;\n\t},\n> = (undefined extends C[\"body\"]\n\t? {}\n\t: {\n\t\t\tbody: true;\n\t\t}) &\n\t(undefined extends C[\"query\"]\n\t\t? {}\n\t\t: {\n\t\t\t\tquery: true;\n\t\t\t}) &\n\t(undefined extends C[\"params\"]\n\t\t? {}\n\t\t: {\n\t\t\t\tparams: true;\n\t\t\t});\n\nexport const createClient = <\n\tR extends Router | Router[\"endpoints\"],\n\tGlobalOpts extends ClientOptions = ClientOptions,\n>(\n\toptions?: GlobalOpts,\n) => {\n\tconst fetch = createFetch(options ?? {});\n\ttype API = InferClientRoutes<\n\t\tR extends { endpoints: Record<string, Endpoint> } ? R[\"endpoints\"] : R\n\t>;\n\ttype Options = API extends {\n\t\t[key: string]: infer T;\n\t}\n\t\t? T extends Endpoint<infer P, infer M>\n\t\t\t? {\n\t\t\t\t\t[key in M extends \"GET\"\n\t\t\t\t\t\t? P\n\t\t\t\t\t\t: `@${M extends string ? Lowercase<M> : never}${P}`]: T;\n\t\t\t\t}\n\t\t\t: {}\n\t\t: {};\n\n\ttype O = Prettify<UnionToIntersection<Options>>;\n\treturn async <\n\t\tOPT extends O,\n\t\tK extends keyof OPT,\n\t\tC extends InferContext<OPT[K]>,\n\t\tCallOpts extends BetterFetchOption<C[\"body\"], C[\"query\"], C[\"params\"]>,\n\t>(\n\t\tpath: K,\n\t\t...callOptions: HasRequired<C> extends true\n\t\t\t? [\n\t\t\t\t\tWithRequired<\n\t\t\t\t\t\tBetterFetchOption<C[\"body\"], C[\"query\"], C[\"params\"]>,\n\t\t\t\t\t\tkeyof RequiredOptionKeys<C>\n\t\t\t\t\t>,\n\t\t\t\t]\n\t\t\t: [CallOpts?]\n\t): Promise<\n\t\tBetterFetchResponse<\n\t\t\tAwaited<ReturnType<OPT[K] extends Endpoint ? OPT[K] : never>>,\n\t\t\tunknown,\n\t\t\tCallOpts[\"throw\"] extends boolean\n\t\t\t\t? CallOpts[\"throw\"]\n\t\t\t\t: GlobalOpts[\"throw\"] extends true\n\t\t\t\t\t? true\n\t\t\t\t\t: false\n\t\t>\n\t> => {\n\t\treturn (await fetch(path as string, {\n\t\t\t...callOptions[0],\n\t\t})) as any;\n\t};\n};\n\nexport * from \"./error\";\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.mjs","names":[],"sources":["../src/client.ts"],"sourcesContent":["import {\n\ttype BetterFetchOption,\n\ttype BetterFetchResponse,\n\tcreateFetch,\n} from \"@better-fetch/fetch\";\nimport type { Endpoint } from \"./endpoint\";\nimport type { HasRequiredKeys, Prettify, UnionToIntersection } from \"./helper\";\nimport type { Router } from \"./router\";\n\nexport type HasRequired<T extends object> = T extends {}\n\t? false\n\t: T extends {\n\t\t\t\tbody?: any;\n\t\t\t\tquery?: any;\n\t\t\t\tparams?: any;\n\t\t\t}\n\t\t? T[\"body\"] extends object\n\t\t\t? HasRequiredKeys<T[\"body\"]> extends true\n\t\t\t\t? true\n\t\t\t\t: T[\"query\"] extends object\n\t\t\t\t\t? HasRequiredKeys<T[\"query\"]> extends true\n\t\t\t\t\t\t? true\n\t\t\t\t\t\t: T[\"params\"] extends object\n\t\t\t\t\t\t\t? HasRequiredKeys<T[\"params\"]>\n\t\t\t\t\t\t\t: false\n\t\t\t\t\t: T[\"params\"] extends object\n\t\t\t\t\t\t? HasRequiredKeys<T[\"params\"]>\n\t\t\t\t\t\t: false\n\t\t\t: T[\"query\"] extends object\n\t\t\t\t? HasRequiredKeys<T[\"query\"]> extends true\n\t\t\t\t\t? true\n\t\t\t\t\t: T[\"params\"] extends object\n\t\t\t\t\t\t? HasRequiredKeys<T[\"params\"]>\n\t\t\t\t\t\t: false\n\t\t\t\t: T[\"params\"] extends object\n\t\t\t\t\t? HasRequiredKeys<T[\"params\"]>\n\t\t\t\t\t: false\n\t\t: false;\n\ntype InferContext<T> = T extends (ctx: infer Ctx) => any\n\t? Ctx extends object\n\t\t? Ctx\n\t\t: never\n\t: never;\n\nexport interface ClientOptions extends BetterFetchOption {\n\tbaseURL?: string;\n}\n\ntype WithRequired<T, K> = T & {\n\t[P in K extends string ? K : never]-?: T[P extends keyof T ? P : never];\n};\n\n/**\n * Filter out endpoints that should not be exposed to the client.\n * Checks the typed metadata on the Endpoint's options.\n */\ntype InferClientRoutes<T extends Record<string, Endpoint>> = {\n\t[K in keyof T]: T[K] extends Endpoint<\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tany,\n\t\tinfer Meta\n\t>\n\t\t? Meta extends\n\t\t\t\t| { scope: \"http\" }\n\t\t\t\t| { scope: \"server\" }\n\t\t\t\t| { SERVER_ONLY: true }\n\t\t\t\t| { isAction: false }\n\t\t\t? never\n\t\t\t: T[K]\n\t\t: T[K];\n};\n\nexport type RequiredOptionKeys<\n\tC extends {\n\t\tbody?: any;\n\t\tquery?: any;\n\t\tparams?: any;\n\t},\n> = (undefined extends C[\"body\"]\n\t? {}\n\t: {\n\t\t\tbody: true;\n\t\t}) &\n\t(undefined extends C[\"query\"]\n\t\t? {}\n\t\t: {\n\t\t\t\tquery: true;\n\t\t\t}) &\n\t(undefined extends C[\"params\"]\n\t\t? {}\n\t\t: {\n\t\t\t\tparams: true;\n\t\t\t});\n\nexport const createClient = <\n\tR extends Router | Router[\"endpoints\"],\n\tGlobalOpts extends ClientOptions = ClientOptions,\n>(\n\toptions?: GlobalOpts,\n) => {\n\tconst fetch = createFetch(options ?? {});\n\ttype API = InferClientRoutes<\n\t\tR extends { endpoints: Record<string, Endpoint> } ? R[\"endpoints\"] : R\n\t>;\n\ttype Options = API extends {\n\t\t[key: string]: infer T;\n\t}\n\t\t? T extends Endpoint<infer P, infer M>\n\t\t\t? {\n\t\t\t\t\t[key in M extends \"GET\"\n\t\t\t\t\t\t? P\n\t\t\t\t\t\t: `@${M extends string ? Lowercase<M> : never}${P}`]: T;\n\t\t\t\t}\n\t\t\t: {}\n\t\t: {};\n\n\ttype O = Prettify<UnionToIntersection<Options>>;\n\treturn async <\n\t\tOPT extends O,\n\t\tK extends keyof OPT,\n\t\tC extends InferContext<OPT[K]>,\n\t\tCallOpts extends BetterFetchOption<C[\"body\"], C[\"query\"], C[\"params\"]>,\n\t>(\n\t\tpath: K,\n\t\t...callOptions: HasRequired<C> extends true\n\t\t\t? [\n\t\t\t\t\tWithRequired<\n\t\t\t\t\t\tBetterFetchOption<C[\"body\"], C[\"query\"], C[\"params\"]>,\n\t\t\t\t\t\tkeyof RequiredOptionKeys<C>\n\t\t\t\t\t>,\n\t\t\t\t]\n\t\t\t: [CallOpts?]\n\t): Promise<\n\t\tBetterFetchResponse<\n\t\t\tAwaited<ReturnType<OPT[K] extends Endpoint ? OPT[K] : never>>,\n\t\t\tunknown,\n\t\t\tCallOpts[\"throw\"] extends boolean\n\t\t\t\t? CallOpts[\"throw\"]\n\t\t\t\t: GlobalOpts[\"throw\"] extends true\n\t\t\t\t\t? true\n\t\t\t\t\t: false\n\t\t>\n\t> => {\n\t\treturn (await fetch(path as string, {\n\t\t\t...callOptions[0],\n\t\t})) as any;\n\t};\n};\n\nexport * from \"./error\";\n"],"mappings":";;;AAmGA,MAAa,gBAIZ,YACI;CACJ,MAAM,QAAQ,YAAY,WAAW,CAAC,CAAC;CAiBvC,OAAO,OAMN,MACA,GAAG,gBAkBC;EACJ,OAAQ,MAAM,MAAM,MAAgB,EACnC,GAAG,YAAY,GAChB,CAAC;CACF;AACD"}
|
package/dist/context.cjs
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
const require_crypto = require(
|
|
2
|
-
const require_error = require(
|
|
3
|
-
const require_utils = require(
|
|
4
|
-
const require_cookies = require(
|
|
5
|
-
const require_validator = require(
|
|
6
|
-
|
|
1
|
+
const require_crypto = require("./crypto.cjs");
|
|
2
|
+
const require_error = require("./error.cjs");
|
|
3
|
+
const require_utils = require("./utils.cjs");
|
|
4
|
+
const require_cookies = require("./cookies.cjs");
|
|
5
|
+
const require_validator = require("./validator.cjs");
|
|
7
6
|
//#region src/context.ts
|
|
8
7
|
/**
|
|
9
8
|
* Creates the internal context for an endpoint or middleware invocation.
|
|
@@ -98,7 +97,7 @@ const createInternalContext = async (context, { options, path }) => {
|
|
|
98
97
|
}
|
|
99
98
|
return internalContext;
|
|
100
99
|
};
|
|
101
|
-
|
|
102
100
|
//#endregion
|
|
103
101
|
exports.createInternalContext = createInternalContext;
|
|
102
|
+
|
|
104
103
|
//# sourceMappingURL=context.cjs.map
|
package/dist/context.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.cjs","names":["runValidation","ValidationError","isRequest","parseCookies","getCookieKey","verifySignature","getCryptoKey","serializeCookie","serializeSignedCookie","APIError"],"sources":["../src/context.ts"],"sourcesContent":["import type { CookieOptions, CookiePrefixOptions } from \"./cookies\";\nimport {\n\tgetCookieKey,\n\tparseCookies,\n\tserializeCookie,\n\tserializeSignedCookie,\n} from \"./cookies\";\nimport { getCryptoKey, verifySignature } from \"./crypto\";\nimport {\n\tAPIError,\n\ttype Status,\n\ttype statusCodes,\n\tValidationError,\n} from \"./error\";\nimport type { Prettify } from \"./helper\";\nimport type { Middleware, MiddlewareContext } from \"./middleware\";\nimport type { StandardSchemaV1 } from \"./standard-schema\";\nimport type {\n\tInferParam,\n\tInferUse,\n\tResolveBody,\n\tResolveMethod,\n\tResolveQuery,\n} from \"./types\";\nimport { isRequest } from \"./utils\";\nimport { runValidation } from \"./validator\";\n\nexport type EndpointContext<\n\tPath extends string,\n\tM,\n\tBodySchema extends object | undefined,\n\tQuerySchema extends object | undefined,\n\tUse extends Middleware[],\n\tReqHeaders extends boolean,\n\tReqRequest extends boolean,\n\tContext = {},\n\tMeta = undefined,\n> = {\n\t/**\n\t * Method\n\t *\n\t * The request method\n\t */\n\tmethod: ResolveMethod<M>;\n\t/**\n\t * Path\n\t *\n\t * The path of the endpoint\n\t */\n\tpath: Path;\n\t/**\n\t * Body\n\t *\n\t * The body object will be the parsed JSON from the request and validated\n\t * against the body schema if it exists.\n\t */\n\tbody: ResolveBody<BodySchema, Meta>;\n\t/**\n\t * Query\n\t *\n\t * The query object will be the parsed query string from the request\n\t * and validated against the query schema if it exists\n\t */\n\tquery: ResolveQuery<QuerySchema, Meta>;\n\t/**\n\t * Params\n\t *\n\t * If the path is `/user/:id` and the request is `/user/1` then the params will\n\t * be `{ id: \"1\" }` and if the path includes a wildcard like `/user/*` then the\n\t * params will be `{ _: \"1\" }` where `_` is the wildcard key. If the wildcard\n\t * is named like `/user/**:name` then the params will be `{ name: string }`\n\t */\n\tparams: InferParam<Path>;\n\t/**\n\t * Request object\n\t *\n\t * If `requireRequest` is set to true in the endpoint options this will be\n\t * required\n\t */\n\trequest: ReqRequest extends true ? Request : Request | undefined;\n\t/**\n\t * Headers\n\t *\n\t * If `requireHeaders` is set to true in the endpoint options this will be\n\t * required\n\t */\n\theaders: ReqHeaders extends true ? Headers : Headers | undefined;\n\t/**\n\t * Set header\n\t *\n\t * If it's called outside of a request it will just be ignored.\n\t */\n\tsetHeader: (key: string, value: string) => void;\n\t/**\n\t * Set the response status code\n\t */\n\tsetStatus: (status: Status) => void;\n\t/**\n\t * Get header\n\t *\n\t * If it's called outside of a request it will just return null\n\t *\n\t * @param key - The key of the header\n\t */\n\tgetHeader: (key: string) => string | null;\n\t/**\n\t * Get a cookie value from the request\n\t *\n\t * @param key - The key of the cookie\n\t * @param prefix - The prefix of the cookie between `__Secure-` and `__Host-`\n\t * @returns The value of the cookie\n\t */\n\tgetCookie: (key: string, prefix?: CookiePrefixOptions) => string | null;\n\t/**\n\t * Get a signed cookie value from the request\n\t *\n\t * @param key - The key of the cookie\n\t * @param secret - The secret of the signed cookie\n\t * @param prefix - The prefix of the cookie between `__Secure-` and `__Host-`\n\t * @returns The value of the cookie or null if the cookie is not found or false if the signature is invalid\n\t */\n\tgetSignedCookie: (\n\t\tkey: string,\n\t\tsecret: string,\n\t\tprefix?: CookiePrefixOptions,\n\t) => Promise<string | null | false>;\n\t/**\n\t * Set a cookie value in the response\n\t *\n\t * @param key - The key of the cookie\n\t * @param value - The value to set\n\t * @param options - The options of the cookie\n\t * @returns The cookie string\n\t */\n\tsetCookie: (key: string, value: string, options?: CookieOptions) => string;\n\t/**\n\t * Set signed cookie\n\t *\n\t * @param key - The key of the cookie\n\t * @param value - The value to set\n\t * @param secret - The secret to sign the cookie with\n\t * @param options - The options of the cookie\n\t * @returns The cookie string\n\t */\n\tsetSignedCookie: (\n\t\tkey: string,\n\t\tvalue: string,\n\t\tsecret: string,\n\t\toptions?: CookieOptions,\n\t) => Promise<string>;\n\t/**\n\t * Response headers\n\t *\n\t * The live `Headers` for the response being built in the current\n\t * request. Read it to inspect what has already been queued, e.g. to\n\t * avoid emitting a `Set-Cookie` twice or to check headers set by an\n\t * earlier handler in the chain.\n\t *\n\t * @example\n\t * ```ts\n\t * const alreadySet = ctx.responseHeaders\n\t * .getSetCookie()\n\t * .some((c) => c.startsWith(\"session=\"));\n\t * ```\n\t */\n\tresponseHeaders: Headers;\n\t/**\n\t * JSON\n\t *\n\t * A helper function to create a JSON response with the correct headers\n\t * and status code. If `asResponse` is set to true in the context then\n\t * it will return a Response object instead of the JSON object.\n\t *\n\t * @param json - The JSON object to return\n\t * @param routerResponse - The response object to return if `asResponse` is\n\t * true in the context this will take precedence\n\t */\n\tjson: <R extends Record<string, any> | null>(\n\t\tjson: R,\n\t\trouterResponse?:\n\t\t\t| {\n\t\t\t\t\tstatus?: number;\n\t\t\t\t\theaders?: Record<string, string>;\n\t\t\t\t\tresponse?: Response;\n\t\t\t\t\tbody?: Record<string, any>;\n\t\t\t }\n\t\t\t| Response,\n\t) => R;\n\t/**\n\t * Middleware context\n\t */\n\tcontext: 0 extends 1 & Use\n\t\t? Prettify<Context>\n\t\t: Prettify<Context & InferUse<Use>>;\n\t/**\n\t * Redirect to a new URL\n\t */\n\tredirect: (url: string) => APIError;\n\t/**\n\t * Return error\n\t */\n\terror: (\n\t\tstatus: keyof typeof statusCodes | Status,\n\t\tbody?: {\n\t\t\tmessage?: string;\n\t\t\tcode?: string;\n\t\t} & Record<string, any>,\n\t\theaders?: HeadersInit,\n\t) => APIError;\n};\n\n/**\n * Creates the internal context for an endpoint or middleware invocation.\n * This is the runtime function that does validation, cookie handling,\n * middleware execution, etc.\n */\nexport const createInternalContext = async (\n\tcontext: Record<string, any>,\n\t{\n\t\toptions,\n\t\tpath,\n\t}: {\n\t\toptions: {\n\t\t\tmethod?: string | string[];\n\t\t\tbody?: StandardSchemaV1;\n\t\t\tquery?: StandardSchemaV1;\n\t\t\trequireHeaders?: boolean;\n\t\t\trequireRequest?: boolean;\n\t\t\tuse?: Middleware[];\n\t\t\t[key: string]: any;\n\t\t};\n\t\tpath?: string;\n\t},\n) => {\n\tconst headers = new Headers();\n\tlet responseStatus: Status | undefined;\n\n\tconst { data, error } = await runValidation(options as any, context as any);\n\tif (error) {\n\t\tthrow new ValidationError(error.message, error.issues);\n\t}\n\n\tconst requestHeaders: Headers | null =\n\t\t\"headers\" in context\n\t\t\t? context.headers instanceof Headers\n\t\t\t\t? context.headers\n\t\t\t\t: new Headers(context.headers)\n\t\t\t: \"request\" in context && isRequest(context.request)\n\t\t\t\t? context.request.headers\n\t\t\t\t: null;\n\n\tconst requestCookies = requestHeaders?.get(\"cookie\");\n\tconst parsedCookies = requestCookies\n\t\t? parseCookies(requestCookies)\n\t\t: undefined;\n\n\tconst internalContext = {\n\t\t...context,\n\t\tbody: data.body,\n\t\tquery: data.query,\n\t\tpath: context.path || path || \"virtual:\",\n\t\tcontext: \"context\" in context && context.context ? context.context : {},\n\t\theaders: context?.headers,\n\t\trequest: context?.request,\n\t\tparams: \"params\" in context ? context.params : undefined,\n\t\tmethod:\n\t\t\tcontext.method ??\n\t\t\t(Array.isArray(options.method)\n\t\t\t\t? options.method[0]\n\t\t\t\t: options.method === \"*\"\n\t\t\t\t\t? \"GET\"\n\t\t\t\t\t: options.method),\n\t\tsetHeader: (key: string, value: string) => {\n\t\t\theaders.set(key, value);\n\t\t},\n\t\tgetHeader: (key: string) => {\n\t\t\tif (!requestHeaders) return null;\n\t\t\treturn requestHeaders.get(key);\n\t\t},\n\t\tgetCookie: (key: string, prefix?: CookiePrefixOptions) => {\n\t\t\tconst finalKey = getCookieKey(key, prefix);\n\t\t\tif (!finalKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn parsedCookies?.get(finalKey) || null;\n\t\t},\n\t\tgetSignedCookie: async (\n\t\t\tkey: string,\n\t\t\tsecret: string,\n\t\t\tprefix?: CookiePrefixOptions,\n\t\t) => {\n\t\t\tconst finalKey = getCookieKey(key, prefix);\n\t\t\tif (!finalKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst value = parsedCookies?.get(finalKey);\n\t\t\tif (!value) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst signatureStartPos = value.lastIndexOf(\".\");\n\t\t\tif (signatureStartPos < 1) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst signedValue = value.substring(0, signatureStartPos);\n\t\t\tconst signature = value.substring(signatureStartPos + 1);\n\t\t\tif (signature.length !== 44 || !signature.endsWith(\"=\")) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst secretKey = await getCryptoKey(secret);\n\t\t\tconst isVerified = await verifySignature(\n\t\t\t\tsignature,\n\t\t\t\tsignedValue,\n\t\t\t\tsecretKey,\n\t\t\t);\n\t\t\treturn isVerified ? signedValue : false;\n\t\t},\n\t\tsetCookie: (key: string, value: string, options?: CookieOptions) => {\n\t\t\tconst cookie = serializeCookie(key, value, options);\n\t\t\theaders.append(\"set-cookie\", cookie);\n\t\t\treturn cookie;\n\t\t},\n\t\tsetSignedCookie: async (\n\t\t\tkey: string,\n\t\t\tvalue: string,\n\t\t\tsecret: string,\n\t\t\toptions?: CookieOptions,\n\t\t) => {\n\t\t\tconst cookie = await serializeSignedCookie(key, value, secret, options);\n\t\t\theaders.append(\"set-cookie\", cookie);\n\t\t\treturn cookie;\n\t\t},\n\t\tredirect: (url: string) => {\n\t\t\theaders.set(\"location\", url);\n\t\t\treturn new APIError(\"FOUND\", undefined, headers);\n\t\t},\n\t\terror: (\n\t\t\tstatus: keyof typeof statusCodes | Status,\n\t\t\tbody?:\n\t\t\t\t| {\n\t\t\t\t\t\tmessage?: string;\n\t\t\t\t\t\tcode?: string;\n\t\t\t\t }\n\t\t\t\t| undefined,\n\t\t\theaders?: HeadersInit,\n\t\t) => {\n\t\t\treturn new APIError(status, body, headers);\n\t\t},\n\t\tsetStatus: (status: Status) => {\n\t\t\tresponseStatus = status;\n\t\t},\n\t\tjson: <R extends Record<string, any> | null>(\n\t\t\tjson: R,\n\t\t\trouterResponse?:\n\t\t\t\t| {\n\t\t\t\t\t\tstatus?: number;\n\t\t\t\t\t\theaders?: Record<string, string>;\n\t\t\t\t\t\tresponse?: Response;\n\t\t\t\t\t\tbody?: Record<string, any>;\n\t\t\t\t }\n\t\t\t\t| Response,\n\t\t): R => {\n\t\t\tif (!context.asResponse) {\n\t\t\t\treturn json;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tbody: routerResponse?.body || json,\n\t\t\t\trouterResponse,\n\t\t\t\t_flag: \"json\",\n\t\t\t} as any;\n\t\t},\n\t\tget responseStatus() {\n\t\t\treturn responseStatus;\n\t\t},\n\t\tresponseHeaders: headers,\n\t} satisfies MiddlewareContext<any>;\n\n\t// Execute middleware chain\n\tfor (const middleware of options.use || []) {\n\t\tconst response = (await middleware({\n\t\t\t...internalContext,\n\t\t\treturnHeaders: true,\n\t\t\tasResponse: false,\n\t\t})) as {\n\t\t\tresponse?: any;\n\t\t\theaders?: Headers;\n\t\t};\n\t\tif (response.response) {\n\t\t\tObject.assign(internalContext.context, response.response);\n\t\t}\n\t\tif (response.headers) {\n\t\t\tresponse.headers.forEach((value, key) => {\n\t\t\t\tinternalContext.responseHeaders.set(key, value);\n\t\t\t});\n\t\t}\n\t}\n\n\treturn internalContext;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"context.cjs","names":["runValidation","ValidationError","isRequest","parseCookies","getCookieKey","verifySignature","getCryptoKey","serializeCookie","serializeSignedCookie","APIError"],"sources":["../src/context.ts"],"sourcesContent":["import type { CookieOptions, CookiePrefixOptions } from \"./cookies\";\nimport {\n\tgetCookieKey,\n\tparseCookies,\n\tserializeCookie,\n\tserializeSignedCookie,\n} from \"./cookies\";\nimport { getCryptoKey, verifySignature } from \"./crypto\";\nimport {\n\tAPIError,\n\ttype Status,\n\ttype statusCodes,\n\tValidationError,\n} from \"./error\";\nimport type { Prettify } from \"./helper\";\nimport type { Middleware, MiddlewareContext } from \"./middleware\";\nimport type { StandardSchemaV1 } from \"./standard-schema\";\nimport type {\n\tInferParam,\n\tInferUse,\n\tResolveBody,\n\tResolveMethod,\n\tResolveQuery,\n} from \"./types\";\nimport { isRequest } from \"./utils\";\nimport { runValidation } from \"./validator\";\n\nexport type EndpointContext<\n\tPath extends string,\n\tM,\n\tBodySchema extends object | undefined,\n\tQuerySchema extends object | undefined,\n\tUse extends Middleware[],\n\tReqHeaders extends boolean,\n\tReqRequest extends boolean,\n\tContext = {},\n\tMeta = undefined,\n> = {\n\t/**\n\t * Method\n\t *\n\t * The request method\n\t */\n\tmethod: ResolveMethod<M>;\n\t/**\n\t * Path\n\t *\n\t * The path of the endpoint\n\t */\n\tpath: Path;\n\t/**\n\t * Body\n\t *\n\t * The body object will be the parsed JSON from the request and validated\n\t * against the body schema if it exists.\n\t */\n\tbody: ResolveBody<BodySchema, Meta>;\n\t/**\n\t * Query\n\t *\n\t * The query object will be the parsed query string from the request\n\t * and validated against the query schema if it exists\n\t */\n\tquery: ResolveQuery<QuerySchema, Meta>;\n\t/**\n\t * Params\n\t *\n\t * If the path is `/user/:id` and the request is `/user/1` then the params will\n\t * be `{ id: \"1\" }` and if the path includes a wildcard like `/user/*` then the\n\t * params will be `{ _: \"1\" }` where `_` is the wildcard key. If the wildcard\n\t * is named like `/user/**:name` then the params will be `{ name: string }`\n\t */\n\tparams: InferParam<Path>;\n\t/**\n\t * Request object\n\t *\n\t * If `requireRequest` is set to true in the endpoint options this will be\n\t * required\n\t */\n\trequest: ReqRequest extends true ? Request : Request | undefined;\n\t/**\n\t * Headers\n\t *\n\t * If `requireHeaders` is set to true in the endpoint options this will be\n\t * required\n\t */\n\theaders: ReqHeaders extends true ? Headers : Headers | undefined;\n\t/**\n\t * Set header\n\t *\n\t * If it's called outside of a request it will just be ignored.\n\t */\n\tsetHeader: (key: string, value: string) => void;\n\t/**\n\t * Set the response status code\n\t */\n\tsetStatus: (status: Status) => void;\n\t/**\n\t * Get header\n\t *\n\t * If it's called outside of a request it will just return null\n\t *\n\t * @param key - The key of the header\n\t */\n\tgetHeader: (key: string) => string | null;\n\t/**\n\t * Get a cookie value from the request\n\t *\n\t * @param key - The key of the cookie\n\t * @param prefix - The prefix of the cookie between `__Secure-` and `__Host-`\n\t * @returns The value of the cookie\n\t */\n\tgetCookie: (key: string, prefix?: CookiePrefixOptions) => string | null;\n\t/**\n\t * Get a signed cookie value from the request\n\t *\n\t * @param key - The key of the cookie\n\t * @param secret - The secret of the signed cookie\n\t * @param prefix - The prefix of the cookie between `__Secure-` and `__Host-`\n\t * @returns The value of the cookie or null if the cookie is not found or false if the signature is invalid\n\t */\n\tgetSignedCookie: (\n\t\tkey: string,\n\t\tsecret: string,\n\t\tprefix?: CookiePrefixOptions,\n\t) => Promise<string | null | false>;\n\t/**\n\t * Set a cookie value in the response\n\t *\n\t * @param key - The key of the cookie\n\t * @param value - The value to set\n\t * @param options - The options of the cookie\n\t * @returns The cookie string\n\t */\n\tsetCookie: (key: string, value: string, options?: CookieOptions) => string;\n\t/**\n\t * Set signed cookie\n\t *\n\t * @param key - The key of the cookie\n\t * @param value - The value to set\n\t * @param secret - The secret to sign the cookie with\n\t * @param options - The options of the cookie\n\t * @returns The cookie string\n\t */\n\tsetSignedCookie: (\n\t\tkey: string,\n\t\tvalue: string,\n\t\tsecret: string,\n\t\toptions?: CookieOptions,\n\t) => Promise<string>;\n\t/**\n\t * Response headers\n\t *\n\t * The live `Headers` for the response being built in the current\n\t * request. Read it to inspect what has already been queued, e.g. to\n\t * avoid emitting a `Set-Cookie` twice or to check headers set by an\n\t * earlier handler in the chain.\n\t *\n\t * @example\n\t * ```ts\n\t * const alreadySet = ctx.responseHeaders\n\t * .getSetCookie()\n\t * .some((c) => c.startsWith(\"session=\"));\n\t * ```\n\t */\n\tresponseHeaders: Headers;\n\t/**\n\t * JSON\n\t *\n\t * A helper function to create a JSON response with the correct headers\n\t * and status code. If `asResponse` is set to true in the context then\n\t * it will return a Response object instead of the JSON object.\n\t *\n\t * @param json - The JSON object to return\n\t * @param routerResponse - The response object to return if `asResponse` is\n\t * true in the context this will take precedence\n\t */\n\tjson: <R extends Record<string, any> | null>(\n\t\tjson: R,\n\t\trouterResponse?:\n\t\t\t| {\n\t\t\t\t\tstatus?: number;\n\t\t\t\t\theaders?: Record<string, string>;\n\t\t\t\t\tresponse?: Response;\n\t\t\t\t\tbody?: Record<string, any>;\n\t\t\t }\n\t\t\t| Response,\n\t) => R;\n\t/**\n\t * Middleware context\n\t */\n\tcontext: 0 extends 1 & Use\n\t\t? Prettify<Context>\n\t\t: Prettify<Context & InferUse<Use>>;\n\t/**\n\t * Redirect to a new URL\n\t */\n\tredirect: (url: string) => APIError;\n\t/**\n\t * Return error\n\t */\n\terror: (\n\t\tstatus: keyof typeof statusCodes | Status,\n\t\tbody?: {\n\t\t\tmessage?: string;\n\t\t\tcode?: string;\n\t\t} & Record<string, any>,\n\t\theaders?: HeadersInit,\n\t) => APIError;\n};\n\n/**\n * Creates the internal context for an endpoint or middleware invocation.\n * This is the runtime function that does validation, cookie handling,\n * middleware execution, etc.\n */\nexport const createInternalContext = async (\n\tcontext: Record<string, any>,\n\t{\n\t\toptions,\n\t\tpath,\n\t}: {\n\t\toptions: {\n\t\t\tmethod?: string | string[];\n\t\t\tbody?: StandardSchemaV1;\n\t\t\tquery?: StandardSchemaV1;\n\t\t\trequireHeaders?: boolean;\n\t\t\trequireRequest?: boolean;\n\t\t\tuse?: Middleware[];\n\t\t\t[key: string]: any;\n\t\t};\n\t\tpath?: string;\n\t},\n) => {\n\tconst headers = new Headers();\n\tlet responseStatus: Status | undefined;\n\n\tconst { data, error } = await runValidation(options as any, context as any);\n\tif (error) {\n\t\tthrow new ValidationError(error.message, error.issues);\n\t}\n\n\tconst requestHeaders: Headers | null =\n\t\t\"headers\" in context\n\t\t\t? context.headers instanceof Headers\n\t\t\t\t? context.headers\n\t\t\t\t: new Headers(context.headers)\n\t\t\t: \"request\" in context && isRequest(context.request)\n\t\t\t\t? context.request.headers\n\t\t\t\t: null;\n\n\tconst requestCookies = requestHeaders?.get(\"cookie\");\n\tconst parsedCookies = requestCookies\n\t\t? parseCookies(requestCookies)\n\t\t: undefined;\n\n\tconst internalContext = {\n\t\t...context,\n\t\tbody: data.body,\n\t\tquery: data.query,\n\t\tpath: context.path || path || \"virtual:\",\n\t\tcontext: \"context\" in context && context.context ? context.context : {},\n\t\theaders: context?.headers,\n\t\trequest: context?.request,\n\t\tparams: \"params\" in context ? context.params : undefined,\n\t\tmethod:\n\t\t\tcontext.method ??\n\t\t\t(Array.isArray(options.method)\n\t\t\t\t? options.method[0]\n\t\t\t\t: options.method === \"*\"\n\t\t\t\t\t? \"GET\"\n\t\t\t\t\t: options.method),\n\t\tsetHeader: (key: string, value: string) => {\n\t\t\theaders.set(key, value);\n\t\t},\n\t\tgetHeader: (key: string) => {\n\t\t\tif (!requestHeaders) return null;\n\t\t\treturn requestHeaders.get(key);\n\t\t},\n\t\tgetCookie: (key: string, prefix?: CookiePrefixOptions) => {\n\t\t\tconst finalKey = getCookieKey(key, prefix);\n\t\t\tif (!finalKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn parsedCookies?.get(finalKey) || null;\n\t\t},\n\t\tgetSignedCookie: async (\n\t\t\tkey: string,\n\t\t\tsecret: string,\n\t\t\tprefix?: CookiePrefixOptions,\n\t\t) => {\n\t\t\tconst finalKey = getCookieKey(key, prefix);\n\t\t\tif (!finalKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst value = parsedCookies?.get(finalKey);\n\t\t\tif (!value) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst signatureStartPos = value.lastIndexOf(\".\");\n\t\t\tif (signatureStartPos < 1) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst signedValue = value.substring(0, signatureStartPos);\n\t\t\tconst signature = value.substring(signatureStartPos + 1);\n\t\t\tif (signature.length !== 44 || !signature.endsWith(\"=\")) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst secretKey = await getCryptoKey(secret);\n\t\t\tconst isVerified = await verifySignature(\n\t\t\t\tsignature,\n\t\t\t\tsignedValue,\n\t\t\t\tsecretKey,\n\t\t\t);\n\t\t\treturn isVerified ? signedValue : false;\n\t\t},\n\t\tsetCookie: (key: string, value: string, options?: CookieOptions) => {\n\t\t\tconst cookie = serializeCookie(key, value, options);\n\t\t\theaders.append(\"set-cookie\", cookie);\n\t\t\treturn cookie;\n\t\t},\n\t\tsetSignedCookie: async (\n\t\t\tkey: string,\n\t\t\tvalue: string,\n\t\t\tsecret: string,\n\t\t\toptions?: CookieOptions,\n\t\t) => {\n\t\t\tconst cookie = await serializeSignedCookie(key, value, secret, options);\n\t\t\theaders.append(\"set-cookie\", cookie);\n\t\t\treturn cookie;\n\t\t},\n\t\tredirect: (url: string) => {\n\t\t\theaders.set(\"location\", url);\n\t\t\treturn new APIError(\"FOUND\", undefined, headers);\n\t\t},\n\t\terror: (\n\t\t\tstatus: keyof typeof statusCodes | Status,\n\t\t\tbody?:\n\t\t\t\t| {\n\t\t\t\t\t\tmessage?: string;\n\t\t\t\t\t\tcode?: string;\n\t\t\t\t }\n\t\t\t\t| undefined,\n\t\t\theaders?: HeadersInit,\n\t\t) => {\n\t\t\treturn new APIError(status, body, headers);\n\t\t},\n\t\tsetStatus: (status: Status) => {\n\t\t\tresponseStatus = status;\n\t\t},\n\t\tjson: <R extends Record<string, any> | null>(\n\t\t\tjson: R,\n\t\t\trouterResponse?:\n\t\t\t\t| {\n\t\t\t\t\t\tstatus?: number;\n\t\t\t\t\t\theaders?: Record<string, string>;\n\t\t\t\t\t\tresponse?: Response;\n\t\t\t\t\t\tbody?: Record<string, any>;\n\t\t\t\t }\n\t\t\t\t| Response,\n\t\t): R => {\n\t\t\tif (!context.asResponse) {\n\t\t\t\treturn json;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tbody: routerResponse?.body || json,\n\t\t\t\trouterResponse,\n\t\t\t\t_flag: \"json\",\n\t\t\t} as any;\n\t\t},\n\t\tget responseStatus() {\n\t\t\treturn responseStatus;\n\t\t},\n\t\tresponseHeaders: headers,\n\t} satisfies MiddlewareContext<any>;\n\n\t// Execute middleware chain\n\tfor (const middleware of options.use || []) {\n\t\tconst response = (await middleware({\n\t\t\t...internalContext,\n\t\t\treturnHeaders: true,\n\t\t\tasResponse: false,\n\t\t})) as {\n\t\t\tresponse?: any;\n\t\t\theaders?: Headers;\n\t\t};\n\t\tif (response.response) {\n\t\t\tObject.assign(internalContext.context, response.response);\n\t\t}\n\t\tif (response.headers) {\n\t\t\tresponse.headers.forEach((value, key) => {\n\t\t\t\tinternalContext.responseHeaders.set(key, value);\n\t\t\t});\n\t\t}\n\t}\n\n\treturn internalContext;\n};\n"],"mappings":";;;;;;;;;;;AAwNA,MAAa,wBAAwB,OACpC,SACA,EACC,SACA,WAaG;CACJ,MAAM,UAAU,IAAI,QAAQ;CAC5B,IAAI;CAEJ,MAAM,EAAE,MAAM,UAAU,MAAMA,kBAAAA,cAAc,SAAgB,OAAc;CAC1E,IAAI,OACH,MAAM,IAAIC,cAAAA,gBAAgB,MAAM,SAAS,MAAM,MAAM;CAGtD,MAAM,iBACL,aAAa,UACV,QAAQ,mBAAmB,UAC1B,QAAQ,UACR,IAAI,QAAQ,QAAQ,OAAO,IAC5B,aAAa,WAAWC,cAAAA,UAAU,QAAQ,OAAO,IAChD,QAAQ,QAAQ,UAChB;CAEL,MAAM,iBAAiB,gBAAgB,IAAI,QAAQ;CACnD,MAAM,gBAAgB,iBACnBC,gBAAAA,aAAa,cAAc,IAC3B,KAAA;CAEH,MAAM,kBAAkB;EACvB,GAAG;EACH,MAAM,KAAK;EACX,OAAO,KAAK;EACZ,MAAM,QAAQ,QAAQ,QAAQ;EAC9B,SAAS,aAAa,WAAW,QAAQ,UAAU,QAAQ,UAAU,CAAC;EACtE,SAAS,SAAS;EAClB,SAAS,SAAS;EAClB,QAAQ,YAAY,UAAU,QAAQ,SAAS,KAAA;EAC/C,QACC,QAAQ,WACP,MAAM,QAAQ,QAAQ,MAAM,IAC1B,QAAQ,OAAO,KACf,QAAQ,WAAW,MAClB,QACA,QAAQ;EACb,YAAY,KAAa,UAAkB;GAC1C,QAAQ,IAAI,KAAK,KAAK;EACvB;EACA,YAAY,QAAgB;GAC3B,IAAI,CAAC,gBAAgB,OAAO;GAC5B,OAAO,eAAe,IAAI,GAAG;EAC9B;EACA,YAAY,KAAa,WAAiC;GACzD,MAAM,WAAWC,gBAAAA,aAAa,KAAK,MAAM;GACzC,IAAI,CAAC,UACJ,OAAO;GAER,OAAO,eAAe,IAAI,QAAQ,KAAK;EACxC;EACA,iBAAiB,OAChB,KACA,QACA,WACI;GACJ,MAAM,WAAWA,gBAAAA,aAAa,KAAK,MAAM;GACzC,IAAI,CAAC,UACJ,OAAO;GAER,MAAM,QAAQ,eAAe,IAAI,QAAQ;GACzC,IAAI,CAAC,OACJ,OAAO;GAER,MAAM,oBAAoB,MAAM,YAAY,GAAG;GAC/C,IAAI,oBAAoB,GACvB,OAAO;GAER,MAAM,cAAc,MAAM,UAAU,GAAG,iBAAiB;GACxD,MAAM,YAAY,MAAM,UAAU,oBAAoB,CAAC;GACvD,IAAI,UAAU,WAAW,MAAM,CAAC,UAAU,SAAS,GAAG,GACrD,OAAO;GAQR,OAAO,MALkBC,eAAAA,gBACxB,WACA,aACA,MAJuBC,eAAAA,aAAa,MAAM,CAK3C,IACoB,cAAc;EACnC;EACA,YAAY,KAAa,OAAe,YAA4B;GACnE,MAAM,SAASC,gBAAAA,gBAAgB,KAAK,OAAO,OAAO;GAClD,QAAQ,OAAO,cAAc,MAAM;GACnC,OAAO;EACR;EACA,iBAAiB,OAChB,KACA,OACA,QACA,YACI;GACJ,MAAM,SAAS,MAAMC,gBAAAA,sBAAsB,KAAK,OAAO,QAAQ,OAAO;GACtE,QAAQ,OAAO,cAAc,MAAM;GACnC,OAAO;EACR;EACA,WAAW,QAAgB;GAC1B,QAAQ,IAAI,YAAY,GAAG;GAC3B,OAAO,IAAIC,cAAAA,SAAS,SAAS,KAAA,GAAW,OAAO;EAChD;EACA,QACC,QACA,MAMA,YACI;GACJ,OAAO,IAAIA,cAAAA,SAAS,QAAQ,MAAM,OAAO;EAC1C;EACA,YAAY,WAAmB;GAC9B,iBAAiB;EAClB;EACA,OACC,MACA,mBAQO;GACP,IAAI,CAAC,QAAQ,YACZ,OAAO;GAER,OAAO;IACN,MAAM,gBAAgB,QAAQ;IAC9B;IACA,OAAO;GACR;EACD;EACA,IAAI,iBAAiB;GACpB,OAAO;EACR;EACA,iBAAiB;CAClB;CAGA,KAAK,MAAM,cAAc,QAAQ,OAAO,CAAC,GAAG;EAC3C,MAAM,WAAY,MAAM,WAAW;GAClC,GAAG;GACH,eAAe;GACf,YAAY;EACb,CAAC;EAID,IAAI,SAAS,UACZ,OAAO,OAAO,gBAAgB,SAAS,SAAS,QAAQ;EAEzD,IAAI,SAAS,SACZ,SAAS,QAAQ,SAAS,OAAO,QAAQ;GACxC,gBAAgB,gBAAgB,IAAI,KAAK,KAAK;EAC/C,CAAC;CAEH;CAEA,OAAO;AACR"}
|
package/dist/context.d.cts
CHANGED
|
@@ -3,7 +3,6 @@ import { APIError, Status, statusCodes } from "./error.cjs";
|
|
|
3
3
|
import { Prettify } from "./helper.cjs";
|
|
4
4
|
import { InferParam, InferUse, ResolveBody, ResolveMethod, ResolveQuery } from "./types.cjs";
|
|
5
5
|
import { Middleware } from "./middleware.cjs";
|
|
6
|
-
|
|
7
6
|
//#region src/context.d.ts
|
|
8
7
|
type EndpointContext<Path extends string, M, BodySchema extends object | undefined, QuerySchema extends object | undefined, Use extends Middleware[], ReqHeaders extends boolean, ReqRequest extends boolean, Context = {}, Meta = undefined> = {
|
|
9
8
|
/**
|
package/dist/context.d.mts
CHANGED
|
@@ -3,7 +3,6 @@ import { APIError, Status, statusCodes } from "./error.mjs";
|
|
|
3
3
|
import { Prettify } from "./helper.mjs";
|
|
4
4
|
import { InferParam, InferUse, ResolveBody, ResolveMethod, ResolveQuery } from "./types.mjs";
|
|
5
5
|
import { Middleware } from "./middleware.mjs";
|
|
6
|
-
|
|
7
6
|
//#region src/context.d.ts
|
|
8
7
|
type EndpointContext<Path extends string, M, BodySchema extends object | undefined, QuerySchema extends object | undefined, Use extends Middleware[], ReqHeaders extends boolean, ReqRequest extends boolean, Context = {}, Meta = undefined> = {
|
|
9
8
|
/**
|
package/dist/context.mjs
CHANGED
|
@@ -3,7 +3,6 @@ import { APIError, ValidationError } from "./error.mjs";
|
|
|
3
3
|
import { isRequest } from "./utils.mjs";
|
|
4
4
|
import { getCookieKey, parseCookies, serializeCookie, serializeSignedCookie } from "./cookies.mjs";
|
|
5
5
|
import { runValidation } from "./validator.mjs";
|
|
6
|
-
|
|
7
6
|
//#region src/context.ts
|
|
8
7
|
/**
|
|
9
8
|
* Creates the internal context for an endpoint or middleware invocation.
|
|
@@ -98,7 +97,7 @@ const createInternalContext = async (context, { options, path }) => {
|
|
|
98
97
|
}
|
|
99
98
|
return internalContext;
|
|
100
99
|
};
|
|
101
|
-
|
|
102
100
|
//#endregion
|
|
103
101
|
export { createInternalContext };
|
|
102
|
+
|
|
104
103
|
//# sourceMappingURL=context.mjs.map
|
package/dist/context.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.mjs","names":[],"sources":["../src/context.ts"],"sourcesContent":["import type { CookieOptions, CookiePrefixOptions } from \"./cookies\";\nimport {\n\tgetCookieKey,\n\tparseCookies,\n\tserializeCookie,\n\tserializeSignedCookie,\n} from \"./cookies\";\nimport { getCryptoKey, verifySignature } from \"./crypto\";\nimport {\n\tAPIError,\n\ttype Status,\n\ttype statusCodes,\n\tValidationError,\n} from \"./error\";\nimport type { Prettify } from \"./helper\";\nimport type { Middleware, MiddlewareContext } from \"./middleware\";\nimport type { StandardSchemaV1 } from \"./standard-schema\";\nimport type {\n\tInferParam,\n\tInferUse,\n\tResolveBody,\n\tResolveMethod,\n\tResolveQuery,\n} from \"./types\";\nimport { isRequest } from \"./utils\";\nimport { runValidation } from \"./validator\";\n\nexport type EndpointContext<\n\tPath extends string,\n\tM,\n\tBodySchema extends object | undefined,\n\tQuerySchema extends object | undefined,\n\tUse extends Middleware[],\n\tReqHeaders extends boolean,\n\tReqRequest extends boolean,\n\tContext = {},\n\tMeta = undefined,\n> = {\n\t/**\n\t * Method\n\t *\n\t * The request method\n\t */\n\tmethod: ResolveMethod<M>;\n\t/**\n\t * Path\n\t *\n\t * The path of the endpoint\n\t */\n\tpath: Path;\n\t/**\n\t * Body\n\t *\n\t * The body object will be the parsed JSON from the request and validated\n\t * against the body schema if it exists.\n\t */\n\tbody: ResolveBody<BodySchema, Meta>;\n\t/**\n\t * Query\n\t *\n\t * The query object will be the parsed query string from the request\n\t * and validated against the query schema if it exists\n\t */\n\tquery: ResolveQuery<QuerySchema, Meta>;\n\t/**\n\t * Params\n\t *\n\t * If the path is `/user/:id` and the request is `/user/1` then the params will\n\t * be `{ id: \"1\" }` and if the path includes a wildcard like `/user/*` then the\n\t * params will be `{ _: \"1\" }` where `_` is the wildcard key. If the wildcard\n\t * is named like `/user/**:name` then the params will be `{ name: string }`\n\t */\n\tparams: InferParam<Path>;\n\t/**\n\t * Request object\n\t *\n\t * If `requireRequest` is set to true in the endpoint options this will be\n\t * required\n\t */\n\trequest: ReqRequest extends true ? Request : Request | undefined;\n\t/**\n\t * Headers\n\t *\n\t * If `requireHeaders` is set to true in the endpoint options this will be\n\t * required\n\t */\n\theaders: ReqHeaders extends true ? Headers : Headers | undefined;\n\t/**\n\t * Set header\n\t *\n\t * If it's called outside of a request it will just be ignored.\n\t */\n\tsetHeader: (key: string, value: string) => void;\n\t/**\n\t * Set the response status code\n\t */\n\tsetStatus: (status: Status) => void;\n\t/**\n\t * Get header\n\t *\n\t * If it's called outside of a request it will just return null\n\t *\n\t * @param key - The key of the header\n\t */\n\tgetHeader: (key: string) => string | null;\n\t/**\n\t * Get a cookie value from the request\n\t *\n\t * @param key - The key of the cookie\n\t * @param prefix - The prefix of the cookie between `__Secure-` and `__Host-`\n\t * @returns The value of the cookie\n\t */\n\tgetCookie: (key: string, prefix?: CookiePrefixOptions) => string | null;\n\t/**\n\t * Get a signed cookie value from the request\n\t *\n\t * @param key - The key of the cookie\n\t * @param secret - The secret of the signed cookie\n\t * @param prefix - The prefix of the cookie between `__Secure-` and `__Host-`\n\t * @returns The value of the cookie or null if the cookie is not found or false if the signature is invalid\n\t */\n\tgetSignedCookie: (\n\t\tkey: string,\n\t\tsecret: string,\n\t\tprefix?: CookiePrefixOptions,\n\t) => Promise<string | null | false>;\n\t/**\n\t * Set a cookie value in the response\n\t *\n\t * @param key - The key of the cookie\n\t * @param value - The value to set\n\t * @param options - The options of the cookie\n\t * @returns The cookie string\n\t */\n\tsetCookie: (key: string, value: string, options?: CookieOptions) => string;\n\t/**\n\t * Set signed cookie\n\t *\n\t * @param key - The key of the cookie\n\t * @param value - The value to set\n\t * @param secret - The secret to sign the cookie with\n\t * @param options - The options of the cookie\n\t * @returns The cookie string\n\t */\n\tsetSignedCookie: (\n\t\tkey: string,\n\t\tvalue: string,\n\t\tsecret: string,\n\t\toptions?: CookieOptions,\n\t) => Promise<string>;\n\t/**\n\t * Response headers\n\t *\n\t * The live `Headers` for the response being built in the current\n\t * request. Read it to inspect what has already been queued, e.g. to\n\t * avoid emitting a `Set-Cookie` twice or to check headers set by an\n\t * earlier handler in the chain.\n\t *\n\t * @example\n\t * ```ts\n\t * const alreadySet = ctx.responseHeaders\n\t * .getSetCookie()\n\t * .some((c) => c.startsWith(\"session=\"));\n\t * ```\n\t */\n\tresponseHeaders: Headers;\n\t/**\n\t * JSON\n\t *\n\t * A helper function to create a JSON response with the correct headers\n\t * and status code. If `asResponse` is set to true in the context then\n\t * it will return a Response object instead of the JSON object.\n\t *\n\t * @param json - The JSON object to return\n\t * @param routerResponse - The response object to return if `asResponse` is\n\t * true in the context this will take precedence\n\t */\n\tjson: <R extends Record<string, any> | null>(\n\t\tjson: R,\n\t\trouterResponse?:\n\t\t\t| {\n\t\t\t\t\tstatus?: number;\n\t\t\t\t\theaders?: Record<string, string>;\n\t\t\t\t\tresponse?: Response;\n\t\t\t\t\tbody?: Record<string, any>;\n\t\t\t }\n\t\t\t| Response,\n\t) => R;\n\t/**\n\t * Middleware context\n\t */\n\tcontext: 0 extends 1 & Use\n\t\t? Prettify<Context>\n\t\t: Prettify<Context & InferUse<Use>>;\n\t/**\n\t * Redirect to a new URL\n\t */\n\tredirect: (url: string) => APIError;\n\t/**\n\t * Return error\n\t */\n\terror: (\n\t\tstatus: keyof typeof statusCodes | Status,\n\t\tbody?: {\n\t\t\tmessage?: string;\n\t\t\tcode?: string;\n\t\t} & Record<string, any>,\n\t\theaders?: HeadersInit,\n\t) => APIError;\n};\n\n/**\n * Creates the internal context for an endpoint or middleware invocation.\n * This is the runtime function that does validation, cookie handling,\n * middleware execution, etc.\n */\nexport const createInternalContext = async (\n\tcontext: Record<string, any>,\n\t{\n\t\toptions,\n\t\tpath,\n\t}: {\n\t\toptions: {\n\t\t\tmethod?: string | string[];\n\t\t\tbody?: StandardSchemaV1;\n\t\t\tquery?: StandardSchemaV1;\n\t\t\trequireHeaders?: boolean;\n\t\t\trequireRequest?: boolean;\n\t\t\tuse?: Middleware[];\n\t\t\t[key: string]: any;\n\t\t};\n\t\tpath?: string;\n\t},\n) => {\n\tconst headers = new Headers();\n\tlet responseStatus: Status | undefined;\n\n\tconst { data, error } = await runValidation(options as any, context as any);\n\tif (error) {\n\t\tthrow new ValidationError(error.message, error.issues);\n\t}\n\n\tconst requestHeaders: Headers | null =\n\t\t\"headers\" in context\n\t\t\t? context.headers instanceof Headers\n\t\t\t\t? context.headers\n\t\t\t\t: new Headers(context.headers)\n\t\t\t: \"request\" in context && isRequest(context.request)\n\t\t\t\t? context.request.headers\n\t\t\t\t: null;\n\n\tconst requestCookies = requestHeaders?.get(\"cookie\");\n\tconst parsedCookies = requestCookies\n\t\t? parseCookies(requestCookies)\n\t\t: undefined;\n\n\tconst internalContext = {\n\t\t...context,\n\t\tbody: data.body,\n\t\tquery: data.query,\n\t\tpath: context.path || path || \"virtual:\",\n\t\tcontext: \"context\" in context && context.context ? context.context : {},\n\t\theaders: context?.headers,\n\t\trequest: context?.request,\n\t\tparams: \"params\" in context ? context.params : undefined,\n\t\tmethod:\n\t\t\tcontext.method ??\n\t\t\t(Array.isArray(options.method)\n\t\t\t\t? options.method[0]\n\t\t\t\t: options.method === \"*\"\n\t\t\t\t\t? \"GET\"\n\t\t\t\t\t: options.method),\n\t\tsetHeader: (key: string, value: string) => {\n\t\t\theaders.set(key, value);\n\t\t},\n\t\tgetHeader: (key: string) => {\n\t\t\tif (!requestHeaders) return null;\n\t\t\treturn requestHeaders.get(key);\n\t\t},\n\t\tgetCookie: (key: string, prefix?: CookiePrefixOptions) => {\n\t\t\tconst finalKey = getCookieKey(key, prefix);\n\t\t\tif (!finalKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn parsedCookies?.get(finalKey) || null;\n\t\t},\n\t\tgetSignedCookie: async (\n\t\t\tkey: string,\n\t\t\tsecret: string,\n\t\t\tprefix?: CookiePrefixOptions,\n\t\t) => {\n\t\t\tconst finalKey = getCookieKey(key, prefix);\n\t\t\tif (!finalKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst value = parsedCookies?.get(finalKey);\n\t\t\tif (!value) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst signatureStartPos = value.lastIndexOf(\".\");\n\t\t\tif (signatureStartPos < 1) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst signedValue = value.substring(0, signatureStartPos);\n\t\t\tconst signature = value.substring(signatureStartPos + 1);\n\t\t\tif (signature.length !== 44 || !signature.endsWith(\"=\")) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst secretKey = await getCryptoKey(secret);\n\t\t\tconst isVerified = await verifySignature(\n\t\t\t\tsignature,\n\t\t\t\tsignedValue,\n\t\t\t\tsecretKey,\n\t\t\t);\n\t\t\treturn isVerified ? signedValue : false;\n\t\t},\n\t\tsetCookie: (key: string, value: string, options?: CookieOptions) => {\n\t\t\tconst cookie = serializeCookie(key, value, options);\n\t\t\theaders.append(\"set-cookie\", cookie);\n\t\t\treturn cookie;\n\t\t},\n\t\tsetSignedCookie: async (\n\t\t\tkey: string,\n\t\t\tvalue: string,\n\t\t\tsecret: string,\n\t\t\toptions?: CookieOptions,\n\t\t) => {\n\t\t\tconst cookie = await serializeSignedCookie(key, value, secret, options);\n\t\t\theaders.append(\"set-cookie\", cookie);\n\t\t\treturn cookie;\n\t\t},\n\t\tredirect: (url: string) => {\n\t\t\theaders.set(\"location\", url);\n\t\t\treturn new APIError(\"FOUND\", undefined, headers);\n\t\t},\n\t\terror: (\n\t\t\tstatus: keyof typeof statusCodes | Status,\n\t\t\tbody?:\n\t\t\t\t| {\n\t\t\t\t\t\tmessage?: string;\n\t\t\t\t\t\tcode?: string;\n\t\t\t\t }\n\t\t\t\t| undefined,\n\t\t\theaders?: HeadersInit,\n\t\t) => {\n\t\t\treturn new APIError(status, body, headers);\n\t\t},\n\t\tsetStatus: (status: Status) => {\n\t\t\tresponseStatus = status;\n\t\t},\n\t\tjson: <R extends Record<string, any> | null>(\n\t\t\tjson: R,\n\t\t\trouterResponse?:\n\t\t\t\t| {\n\t\t\t\t\t\tstatus?: number;\n\t\t\t\t\t\theaders?: Record<string, string>;\n\t\t\t\t\t\tresponse?: Response;\n\t\t\t\t\t\tbody?: Record<string, any>;\n\t\t\t\t }\n\t\t\t\t| Response,\n\t\t): R => {\n\t\t\tif (!context.asResponse) {\n\t\t\t\treturn json;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tbody: routerResponse?.body || json,\n\t\t\t\trouterResponse,\n\t\t\t\t_flag: \"json\",\n\t\t\t} as any;\n\t\t},\n\t\tget responseStatus() {\n\t\t\treturn responseStatus;\n\t\t},\n\t\tresponseHeaders: headers,\n\t} satisfies MiddlewareContext<any>;\n\n\t// Execute middleware chain\n\tfor (const middleware of options.use || []) {\n\t\tconst response = (await middleware({\n\t\t\t...internalContext,\n\t\t\treturnHeaders: true,\n\t\t\tasResponse: false,\n\t\t})) as {\n\t\t\tresponse?: any;\n\t\t\theaders?: Headers;\n\t\t};\n\t\tif (response.response) {\n\t\t\tObject.assign(internalContext.context, response.response);\n\t\t}\n\t\tif (response.headers) {\n\t\t\tresponse.headers.forEach((value, key) => {\n\t\t\t\tinternalContext.responseHeaders.set(key, value);\n\t\t\t});\n\t\t}\n\t}\n\n\treturn internalContext;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"context.mjs","names":[],"sources":["../src/context.ts"],"sourcesContent":["import type { CookieOptions, CookiePrefixOptions } from \"./cookies\";\nimport {\n\tgetCookieKey,\n\tparseCookies,\n\tserializeCookie,\n\tserializeSignedCookie,\n} from \"./cookies\";\nimport { getCryptoKey, verifySignature } from \"./crypto\";\nimport {\n\tAPIError,\n\ttype Status,\n\ttype statusCodes,\n\tValidationError,\n} from \"./error\";\nimport type { Prettify } from \"./helper\";\nimport type { Middleware, MiddlewareContext } from \"./middleware\";\nimport type { StandardSchemaV1 } from \"./standard-schema\";\nimport type {\n\tInferParam,\n\tInferUse,\n\tResolveBody,\n\tResolveMethod,\n\tResolveQuery,\n} from \"./types\";\nimport { isRequest } from \"./utils\";\nimport { runValidation } from \"./validator\";\n\nexport type EndpointContext<\n\tPath extends string,\n\tM,\n\tBodySchema extends object | undefined,\n\tQuerySchema extends object | undefined,\n\tUse extends Middleware[],\n\tReqHeaders extends boolean,\n\tReqRequest extends boolean,\n\tContext = {},\n\tMeta = undefined,\n> = {\n\t/**\n\t * Method\n\t *\n\t * The request method\n\t */\n\tmethod: ResolveMethod<M>;\n\t/**\n\t * Path\n\t *\n\t * The path of the endpoint\n\t */\n\tpath: Path;\n\t/**\n\t * Body\n\t *\n\t * The body object will be the parsed JSON from the request and validated\n\t * against the body schema if it exists.\n\t */\n\tbody: ResolveBody<BodySchema, Meta>;\n\t/**\n\t * Query\n\t *\n\t * The query object will be the parsed query string from the request\n\t * and validated against the query schema if it exists\n\t */\n\tquery: ResolveQuery<QuerySchema, Meta>;\n\t/**\n\t * Params\n\t *\n\t * If the path is `/user/:id` and the request is `/user/1` then the params will\n\t * be `{ id: \"1\" }` and if the path includes a wildcard like `/user/*` then the\n\t * params will be `{ _: \"1\" }` where `_` is the wildcard key. If the wildcard\n\t * is named like `/user/**:name` then the params will be `{ name: string }`\n\t */\n\tparams: InferParam<Path>;\n\t/**\n\t * Request object\n\t *\n\t * If `requireRequest` is set to true in the endpoint options this will be\n\t * required\n\t */\n\trequest: ReqRequest extends true ? Request : Request | undefined;\n\t/**\n\t * Headers\n\t *\n\t * If `requireHeaders` is set to true in the endpoint options this will be\n\t * required\n\t */\n\theaders: ReqHeaders extends true ? Headers : Headers | undefined;\n\t/**\n\t * Set header\n\t *\n\t * If it's called outside of a request it will just be ignored.\n\t */\n\tsetHeader: (key: string, value: string) => void;\n\t/**\n\t * Set the response status code\n\t */\n\tsetStatus: (status: Status) => void;\n\t/**\n\t * Get header\n\t *\n\t * If it's called outside of a request it will just return null\n\t *\n\t * @param key - The key of the header\n\t */\n\tgetHeader: (key: string) => string | null;\n\t/**\n\t * Get a cookie value from the request\n\t *\n\t * @param key - The key of the cookie\n\t * @param prefix - The prefix of the cookie between `__Secure-` and `__Host-`\n\t * @returns The value of the cookie\n\t */\n\tgetCookie: (key: string, prefix?: CookiePrefixOptions) => string | null;\n\t/**\n\t * Get a signed cookie value from the request\n\t *\n\t * @param key - The key of the cookie\n\t * @param secret - The secret of the signed cookie\n\t * @param prefix - The prefix of the cookie between `__Secure-` and `__Host-`\n\t * @returns The value of the cookie or null if the cookie is not found or false if the signature is invalid\n\t */\n\tgetSignedCookie: (\n\t\tkey: string,\n\t\tsecret: string,\n\t\tprefix?: CookiePrefixOptions,\n\t) => Promise<string | null | false>;\n\t/**\n\t * Set a cookie value in the response\n\t *\n\t * @param key - The key of the cookie\n\t * @param value - The value to set\n\t * @param options - The options of the cookie\n\t * @returns The cookie string\n\t */\n\tsetCookie: (key: string, value: string, options?: CookieOptions) => string;\n\t/**\n\t * Set signed cookie\n\t *\n\t * @param key - The key of the cookie\n\t * @param value - The value to set\n\t * @param secret - The secret to sign the cookie with\n\t * @param options - The options of the cookie\n\t * @returns The cookie string\n\t */\n\tsetSignedCookie: (\n\t\tkey: string,\n\t\tvalue: string,\n\t\tsecret: string,\n\t\toptions?: CookieOptions,\n\t) => Promise<string>;\n\t/**\n\t * Response headers\n\t *\n\t * The live `Headers` for the response being built in the current\n\t * request. Read it to inspect what has already been queued, e.g. to\n\t * avoid emitting a `Set-Cookie` twice or to check headers set by an\n\t * earlier handler in the chain.\n\t *\n\t * @example\n\t * ```ts\n\t * const alreadySet = ctx.responseHeaders\n\t * .getSetCookie()\n\t * .some((c) => c.startsWith(\"session=\"));\n\t * ```\n\t */\n\tresponseHeaders: Headers;\n\t/**\n\t * JSON\n\t *\n\t * A helper function to create a JSON response with the correct headers\n\t * and status code. If `asResponse` is set to true in the context then\n\t * it will return a Response object instead of the JSON object.\n\t *\n\t * @param json - The JSON object to return\n\t * @param routerResponse - The response object to return if `asResponse` is\n\t * true in the context this will take precedence\n\t */\n\tjson: <R extends Record<string, any> | null>(\n\t\tjson: R,\n\t\trouterResponse?:\n\t\t\t| {\n\t\t\t\t\tstatus?: number;\n\t\t\t\t\theaders?: Record<string, string>;\n\t\t\t\t\tresponse?: Response;\n\t\t\t\t\tbody?: Record<string, any>;\n\t\t\t }\n\t\t\t| Response,\n\t) => R;\n\t/**\n\t * Middleware context\n\t */\n\tcontext: 0 extends 1 & Use\n\t\t? Prettify<Context>\n\t\t: Prettify<Context & InferUse<Use>>;\n\t/**\n\t * Redirect to a new URL\n\t */\n\tredirect: (url: string) => APIError;\n\t/**\n\t * Return error\n\t */\n\terror: (\n\t\tstatus: keyof typeof statusCodes | Status,\n\t\tbody?: {\n\t\t\tmessage?: string;\n\t\t\tcode?: string;\n\t\t} & Record<string, any>,\n\t\theaders?: HeadersInit,\n\t) => APIError;\n};\n\n/**\n * Creates the internal context for an endpoint or middleware invocation.\n * This is the runtime function that does validation, cookie handling,\n * middleware execution, etc.\n */\nexport const createInternalContext = async (\n\tcontext: Record<string, any>,\n\t{\n\t\toptions,\n\t\tpath,\n\t}: {\n\t\toptions: {\n\t\t\tmethod?: string | string[];\n\t\t\tbody?: StandardSchemaV1;\n\t\t\tquery?: StandardSchemaV1;\n\t\t\trequireHeaders?: boolean;\n\t\t\trequireRequest?: boolean;\n\t\t\tuse?: Middleware[];\n\t\t\t[key: string]: any;\n\t\t};\n\t\tpath?: string;\n\t},\n) => {\n\tconst headers = new Headers();\n\tlet responseStatus: Status | undefined;\n\n\tconst { data, error } = await runValidation(options as any, context as any);\n\tif (error) {\n\t\tthrow new ValidationError(error.message, error.issues);\n\t}\n\n\tconst requestHeaders: Headers | null =\n\t\t\"headers\" in context\n\t\t\t? context.headers instanceof Headers\n\t\t\t\t? context.headers\n\t\t\t\t: new Headers(context.headers)\n\t\t\t: \"request\" in context && isRequest(context.request)\n\t\t\t\t? context.request.headers\n\t\t\t\t: null;\n\n\tconst requestCookies = requestHeaders?.get(\"cookie\");\n\tconst parsedCookies = requestCookies\n\t\t? parseCookies(requestCookies)\n\t\t: undefined;\n\n\tconst internalContext = {\n\t\t...context,\n\t\tbody: data.body,\n\t\tquery: data.query,\n\t\tpath: context.path || path || \"virtual:\",\n\t\tcontext: \"context\" in context && context.context ? context.context : {},\n\t\theaders: context?.headers,\n\t\trequest: context?.request,\n\t\tparams: \"params\" in context ? context.params : undefined,\n\t\tmethod:\n\t\t\tcontext.method ??\n\t\t\t(Array.isArray(options.method)\n\t\t\t\t? options.method[0]\n\t\t\t\t: options.method === \"*\"\n\t\t\t\t\t? \"GET\"\n\t\t\t\t\t: options.method),\n\t\tsetHeader: (key: string, value: string) => {\n\t\t\theaders.set(key, value);\n\t\t},\n\t\tgetHeader: (key: string) => {\n\t\t\tif (!requestHeaders) return null;\n\t\t\treturn requestHeaders.get(key);\n\t\t},\n\t\tgetCookie: (key: string, prefix?: CookiePrefixOptions) => {\n\t\t\tconst finalKey = getCookieKey(key, prefix);\n\t\t\tif (!finalKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn parsedCookies?.get(finalKey) || null;\n\t\t},\n\t\tgetSignedCookie: async (\n\t\t\tkey: string,\n\t\t\tsecret: string,\n\t\t\tprefix?: CookiePrefixOptions,\n\t\t) => {\n\t\t\tconst finalKey = getCookieKey(key, prefix);\n\t\t\tif (!finalKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst value = parsedCookies?.get(finalKey);\n\t\t\tif (!value) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst signatureStartPos = value.lastIndexOf(\".\");\n\t\t\tif (signatureStartPos < 1) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst signedValue = value.substring(0, signatureStartPos);\n\t\t\tconst signature = value.substring(signatureStartPos + 1);\n\t\t\tif (signature.length !== 44 || !signature.endsWith(\"=\")) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst secretKey = await getCryptoKey(secret);\n\t\t\tconst isVerified = await verifySignature(\n\t\t\t\tsignature,\n\t\t\t\tsignedValue,\n\t\t\t\tsecretKey,\n\t\t\t);\n\t\t\treturn isVerified ? signedValue : false;\n\t\t},\n\t\tsetCookie: (key: string, value: string, options?: CookieOptions) => {\n\t\t\tconst cookie = serializeCookie(key, value, options);\n\t\t\theaders.append(\"set-cookie\", cookie);\n\t\t\treturn cookie;\n\t\t},\n\t\tsetSignedCookie: async (\n\t\t\tkey: string,\n\t\t\tvalue: string,\n\t\t\tsecret: string,\n\t\t\toptions?: CookieOptions,\n\t\t) => {\n\t\t\tconst cookie = await serializeSignedCookie(key, value, secret, options);\n\t\t\theaders.append(\"set-cookie\", cookie);\n\t\t\treturn cookie;\n\t\t},\n\t\tredirect: (url: string) => {\n\t\t\theaders.set(\"location\", url);\n\t\t\treturn new APIError(\"FOUND\", undefined, headers);\n\t\t},\n\t\terror: (\n\t\t\tstatus: keyof typeof statusCodes | Status,\n\t\t\tbody?:\n\t\t\t\t| {\n\t\t\t\t\t\tmessage?: string;\n\t\t\t\t\t\tcode?: string;\n\t\t\t\t }\n\t\t\t\t| undefined,\n\t\t\theaders?: HeadersInit,\n\t\t) => {\n\t\t\treturn new APIError(status, body, headers);\n\t\t},\n\t\tsetStatus: (status: Status) => {\n\t\t\tresponseStatus = status;\n\t\t},\n\t\tjson: <R extends Record<string, any> | null>(\n\t\t\tjson: R,\n\t\t\trouterResponse?:\n\t\t\t\t| {\n\t\t\t\t\t\tstatus?: number;\n\t\t\t\t\t\theaders?: Record<string, string>;\n\t\t\t\t\t\tresponse?: Response;\n\t\t\t\t\t\tbody?: Record<string, any>;\n\t\t\t\t }\n\t\t\t\t| Response,\n\t\t): R => {\n\t\t\tif (!context.asResponse) {\n\t\t\t\treturn json;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tbody: routerResponse?.body || json,\n\t\t\t\trouterResponse,\n\t\t\t\t_flag: \"json\",\n\t\t\t} as any;\n\t\t},\n\t\tget responseStatus() {\n\t\t\treturn responseStatus;\n\t\t},\n\t\tresponseHeaders: headers,\n\t} satisfies MiddlewareContext<any>;\n\n\t// Execute middleware chain\n\tfor (const middleware of options.use || []) {\n\t\tconst response = (await middleware({\n\t\t\t...internalContext,\n\t\t\treturnHeaders: true,\n\t\t\tasResponse: false,\n\t\t})) as {\n\t\t\tresponse?: any;\n\t\t\theaders?: Headers;\n\t\t};\n\t\tif (response.response) {\n\t\t\tObject.assign(internalContext.context, response.response);\n\t\t}\n\t\tif (response.headers) {\n\t\t\tresponse.headers.forEach((value, key) => {\n\t\t\t\tinternalContext.responseHeaders.set(key, value);\n\t\t\t});\n\t\t}\n\t}\n\n\treturn internalContext;\n};\n"],"mappings":";;;;;;;;;;;AAwNA,MAAa,wBAAwB,OACpC,SACA,EACC,SACA,WAaG;CACJ,MAAM,UAAU,IAAI,QAAQ;CAC5B,IAAI;CAEJ,MAAM,EAAE,MAAM,UAAU,MAAM,cAAc,SAAgB,OAAc;CAC1E,IAAI,OACH,MAAM,IAAI,gBAAgB,MAAM,SAAS,MAAM,MAAM;CAGtD,MAAM,iBACL,aAAa,UACV,QAAQ,mBAAmB,UAC1B,QAAQ,UACR,IAAI,QAAQ,QAAQ,OAAO,IAC5B,aAAa,WAAW,UAAU,QAAQ,OAAO,IAChD,QAAQ,QAAQ,UAChB;CAEL,MAAM,iBAAiB,gBAAgB,IAAI,QAAQ;CACnD,MAAM,gBAAgB,iBACnB,aAAa,cAAc,IAC3B,KAAA;CAEH,MAAM,kBAAkB;EACvB,GAAG;EACH,MAAM,KAAK;EACX,OAAO,KAAK;EACZ,MAAM,QAAQ,QAAQ,QAAQ;EAC9B,SAAS,aAAa,WAAW,QAAQ,UAAU,QAAQ,UAAU,CAAC;EACtE,SAAS,SAAS;EAClB,SAAS,SAAS;EAClB,QAAQ,YAAY,UAAU,QAAQ,SAAS,KAAA;EAC/C,QACC,QAAQ,WACP,MAAM,QAAQ,QAAQ,MAAM,IAC1B,QAAQ,OAAO,KACf,QAAQ,WAAW,MAClB,QACA,QAAQ;EACb,YAAY,KAAa,UAAkB;GAC1C,QAAQ,IAAI,KAAK,KAAK;EACvB;EACA,YAAY,QAAgB;GAC3B,IAAI,CAAC,gBAAgB,OAAO;GAC5B,OAAO,eAAe,IAAI,GAAG;EAC9B;EACA,YAAY,KAAa,WAAiC;GACzD,MAAM,WAAW,aAAa,KAAK,MAAM;GACzC,IAAI,CAAC,UACJ,OAAO;GAER,OAAO,eAAe,IAAI,QAAQ,KAAK;EACxC;EACA,iBAAiB,OAChB,KACA,QACA,WACI;GACJ,MAAM,WAAW,aAAa,KAAK,MAAM;GACzC,IAAI,CAAC,UACJ,OAAO;GAER,MAAM,QAAQ,eAAe,IAAI,QAAQ;GACzC,IAAI,CAAC,OACJ,OAAO;GAER,MAAM,oBAAoB,MAAM,YAAY,GAAG;GAC/C,IAAI,oBAAoB,GACvB,OAAO;GAER,MAAM,cAAc,MAAM,UAAU,GAAG,iBAAiB;GACxD,MAAM,YAAY,MAAM,UAAU,oBAAoB,CAAC;GACvD,IAAI,UAAU,WAAW,MAAM,CAAC,UAAU,SAAS,GAAG,GACrD,OAAO;GAQR,OAAO,MALkB,gBACxB,WACA,aACA,MAJuB,aAAa,MAAM,CAK3C,IACoB,cAAc;EACnC;EACA,YAAY,KAAa,OAAe,YAA4B;GACnE,MAAM,SAAS,gBAAgB,KAAK,OAAO,OAAO;GAClD,QAAQ,OAAO,cAAc,MAAM;GACnC,OAAO;EACR;EACA,iBAAiB,OAChB,KACA,OACA,QACA,YACI;GACJ,MAAM,SAAS,MAAM,sBAAsB,KAAK,OAAO,QAAQ,OAAO;GACtE,QAAQ,OAAO,cAAc,MAAM;GACnC,OAAO;EACR;EACA,WAAW,QAAgB;GAC1B,QAAQ,IAAI,YAAY,GAAG;GAC3B,OAAO,IAAI,SAAS,SAAS,KAAA,GAAW,OAAO;EAChD;EACA,QACC,QACA,MAMA,YACI;GACJ,OAAO,IAAI,SAAS,QAAQ,MAAM,OAAO;EAC1C;EACA,YAAY,WAAmB;GAC9B,iBAAiB;EAClB;EACA,OACC,MACA,mBAQO;GACP,IAAI,CAAC,QAAQ,YACZ,OAAO;GAER,OAAO;IACN,MAAM,gBAAgB,QAAQ;IAC9B;IACA,OAAO;GACR;EACD;EACA,IAAI,iBAAiB;GACpB,OAAO;EACR;EACA,iBAAiB;CAClB;CAGA,KAAK,MAAM,cAAc,QAAQ,OAAO,CAAC,GAAG;EAC3C,MAAM,WAAY,MAAM,WAAW;GAClC,GAAG;GACH,eAAe;GACf,YAAY;EACb,CAAC;EAID,IAAI,SAAS,UACZ,OAAO,OAAO,gBAAgB,SAAS,SAAS,QAAQ;EAEzD,IAAI,SAAS,SACZ,SAAS,QAAQ,SAAS,OAAO,QAAQ;GACxC,gBAAgB,gBAAgB,IAAI,KAAK,KAAK;EAC/C,CAAC;CAEH;CAEA,OAAO;AACR"}
|