better-call 1.3.7 → 1.4.0
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 +862 -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 +5 -6
- package/dist/client.d.mts +5 -6
- 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 +32 -29
- package/dist/context.d.mts +32 -29
- package/dist/context.mjs +3 -4
- package/dist/context.mjs.map +1 -1
- package/dist/cookies.cjs +3 -4
- package/dist/cookies.cjs.map +1 -1
- package/dist/cookies.mjs +2 -3
- package/dist/cookies.mjs.map +1 -1
- package/dist/crypto.cjs +2 -4
- package/dist/crypto.cjs.map +1 -1
- package/dist/crypto.mjs +2 -3
- package/dist/crypto.mjs.map +1 -1
- package/dist/endpoint.cjs +21 -10
- package/dist/endpoint.cjs.map +1 -1
- package/dist/endpoint.d.cts +22 -20
- package/dist/endpoint.d.mts +22 -20
- package/dist/endpoint.mjs +18 -7
- 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 +4 -4
- package/dist/helper.d.mts +4 -4
- package/dist/index.cjs +10 -11
- package/dist/index.d.cts +4 -4
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +2 -3
- package/dist/middleware.cjs +4 -6
- package/dist/middleware.cjs.map +1 -1
- package/dist/middleware.d.cts +10 -21
- package/dist/middleware.d.mts +10 -21
- package/dist/middleware.mjs +1 -3
- 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 +1 -2
- package/dist/node.d.mts +1 -2
- 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 +7 -9
- package/dist/router.cjs.map +1 -1
- package/dist/router.d.cts +2 -3
- package/dist/router.d.mts +2 -3
- package/dist/router.mjs +3 -4
- package/dist/router.mjs.map +1 -1
- package/dist/to-response.cjs +3 -5
- package/dist/to-response.cjs.map +1 -1
- package/dist/to-response.mjs +2 -4
- package/dist/to-response.mjs.map +1 -1
- 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 +2 -3
- package/dist/validator.cjs.map +1 -1
- package/dist/validator.mjs +2 -2
- package/dist/validator.mjs.map +1 -1
- package/package.json +10 -11
package/dist/crypto.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto.cjs","names":[],"sources":["../src/crypto.ts"],"sourcesContent":["import { getWebcryptoSubtle } from \"@better-auth/utils\";\nconst algorithm = { name: \"HMAC\", hash: \"SHA-256\" };\n\nexport const getCryptoKey = async (secret: string | BufferSource) => {\n\tconst secretBuf =\n\t\ttypeof secret === \"string\" ? new TextEncoder().encode(secret) : secret;\n\treturn await getWebcryptoSubtle().importKey(\n\t\t\"raw\",\n\t\tsecretBuf,\n\t\talgorithm,\n\t\tfalse,\n\t\t[\"sign\", \"verify\"],\n\t);\n};\n\nexport const verifySignature = async (\n\tbase64Signature: string,\n\tvalue: string,\n\tsecret: CryptoKey,\n): Promise<boolean> => {\n\ttry {\n\t\tconst signatureBinStr = atob(base64Signature);\n\t\tconst signature = new Uint8Array(signatureBinStr.length);\n\t\tfor (let i = 0, len = signatureBinStr.length; i < len; i++) {\n\t\t\tsignature[i] = signatureBinStr.charCodeAt(i);\n\t\t}\n\t\treturn await getWebcryptoSubtle().verify(\n\t\t\talgorithm,\n\t\t\tsecret,\n\t\t\tsignature,\n\t\t\tnew TextEncoder().encode(value),\n\t\t);\n\t} catch
|
|
1
|
+
{"version":3,"file":"crypto.cjs","names":[],"sources":["../src/crypto.ts"],"sourcesContent":["import { getWebcryptoSubtle } from \"@better-auth/utils\";\n\nconst algorithm = { name: \"HMAC\", hash: \"SHA-256\" };\n\nexport const getCryptoKey = async (secret: string | BufferSource) => {\n\tconst secretBuf =\n\t\ttypeof secret === \"string\" ? new TextEncoder().encode(secret) : secret;\n\treturn await getWebcryptoSubtle().importKey(\n\t\t\"raw\",\n\t\tsecretBuf,\n\t\talgorithm,\n\t\tfalse,\n\t\t[\"sign\", \"verify\"],\n\t);\n};\n\nexport const verifySignature = async (\n\tbase64Signature: string,\n\tvalue: string,\n\tsecret: CryptoKey,\n): Promise<boolean> => {\n\ttry {\n\t\tconst signatureBinStr = atob(base64Signature);\n\t\tconst signature = new Uint8Array(signatureBinStr.length);\n\t\tfor (let i = 0, len = signatureBinStr.length; i < len; i++) {\n\t\t\tsignature[i] = signatureBinStr.charCodeAt(i);\n\t\t}\n\t\treturn await getWebcryptoSubtle().verify(\n\t\t\talgorithm,\n\t\t\tsecret,\n\t\t\tsignature,\n\t\t\tnew TextEncoder().encode(value),\n\t\t);\n\t} catch {\n\t\treturn false;\n\t}\n};\n\nconst makeSignature = async (\n\tvalue: string,\n\tsecret: string | BufferSource,\n): Promise<string> => {\n\tconst key = await getCryptoKey(secret);\n\tconst signature = await getWebcryptoSubtle().sign(\n\t\talgorithm.name,\n\t\tkey,\n\t\tnew TextEncoder().encode(value),\n\t);\n\t// the returned base64 encoded signature will always be 44 characters long and end with one or two equal signs\n\treturn btoa(String.fromCharCode(...new Uint8Array(signature)));\n};\n\nexport const signCookieValue = async (\n\tvalue: string,\n\tsecret: string | BufferSource,\n) => {\n\tconst signature = await makeSignature(value, secret);\n\tvalue = `${value}.${signature}`;\n\tvalue = encodeURIComponent(value);\n\treturn value;\n};\n"],"mappings":";;AAEA,MAAM,YAAY;CAAE,MAAM;CAAQ,MAAM;AAAU;AAElD,MAAa,eAAe,OAAO,WAAkC;CACpE,MAAM,YACL,OAAO,WAAW,WAAW,IAAI,YAAY,CAAC,CAAC,OAAO,MAAM,IAAI;CACjE,OAAO,OAAA,GAAA,mBAAA,mBAAA,CAAyB,CAAC,CAAC,UACjC,OACA,WACA,WACA,OACA,CAAC,QAAQ,QAAQ,CAClB;AACD;AAEA,MAAa,kBAAkB,OAC9B,iBACA,OACA,WACsB;CACtB,IAAI;EACH,MAAM,kBAAkB,KAAK,eAAe;EAC5C,MAAM,YAAY,IAAI,WAAW,gBAAgB,MAAM;EACvD,KAAK,IAAI,IAAI,GAAG,MAAM,gBAAgB,QAAQ,IAAI,KAAK,KACtD,UAAU,KAAK,gBAAgB,WAAW,CAAC;EAE5C,OAAO,OAAA,GAAA,mBAAA,mBAAA,CAAyB,CAAC,CAAC,OACjC,WACA,QACA,WACA,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK,CAC/B;CACD,QAAQ;EACP,OAAO;CACR;AACD;AAEA,MAAM,gBAAgB,OACrB,OACA,WACqB;CACrB,MAAM,MAAM,MAAM,aAAa,MAAM;CACrC,MAAM,YAAY,OAAA,GAAA,mBAAA,mBAAA,CAAyB,CAAC,CAAC,KAC5C,UAAU,MACV,KACA,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK,CAC/B;CAEA,OAAO,KAAK,OAAO,aAAa,GAAG,IAAI,WAAW,SAAS,CAAC,CAAC;AAC9D;AAEA,MAAa,kBAAkB,OAC9B,OACA,WACI;CACJ,MAAM,YAAY,MAAM,cAAc,OAAO,MAAM;CACnD,QAAQ,GAAG,MAAM,GAAG;CACpB,QAAQ,mBAAmB,KAAK;CAChC,OAAO;AACR"}
|
package/dist/crypto.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { getWebcryptoSubtle } from "@better-auth/utils";
|
|
2
|
-
|
|
3
2
|
//#region src/crypto.ts
|
|
4
3
|
const algorithm = {
|
|
5
4
|
name: "HMAC",
|
|
@@ -15,7 +14,7 @@ const verifySignature = async (base64Signature, value, secret) => {
|
|
|
15
14
|
const signature = new Uint8Array(signatureBinStr.length);
|
|
16
15
|
for (let i = 0, len = signatureBinStr.length; i < len; i++) signature[i] = signatureBinStr.charCodeAt(i);
|
|
17
16
|
return await getWebcryptoSubtle().verify(algorithm, secret, signature, new TextEncoder().encode(value));
|
|
18
|
-
} catch
|
|
17
|
+
} catch {
|
|
19
18
|
return false;
|
|
20
19
|
}
|
|
21
20
|
};
|
|
@@ -30,7 +29,7 @@ const signCookieValue = async (value, secret) => {
|
|
|
30
29
|
value = encodeURIComponent(value);
|
|
31
30
|
return value;
|
|
32
31
|
};
|
|
33
|
-
|
|
34
32
|
//#endregion
|
|
35
33
|
export { getCryptoKey, signCookieValue, verifySignature };
|
|
34
|
+
|
|
36
35
|
//# sourceMappingURL=crypto.mjs.map
|
package/dist/crypto.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto.mjs","names":[],"sources":["../src/crypto.ts"],"sourcesContent":["import { getWebcryptoSubtle } from \"@better-auth/utils\";\nconst algorithm = { name: \"HMAC\", hash: \"SHA-256\" };\n\nexport const getCryptoKey = async (secret: string | BufferSource) => {\n\tconst secretBuf =\n\t\ttypeof secret === \"string\" ? new TextEncoder().encode(secret) : secret;\n\treturn await getWebcryptoSubtle().importKey(\n\t\t\"raw\",\n\t\tsecretBuf,\n\t\talgorithm,\n\t\tfalse,\n\t\t[\"sign\", \"verify\"],\n\t);\n};\n\nexport const verifySignature = async (\n\tbase64Signature: string,\n\tvalue: string,\n\tsecret: CryptoKey,\n): Promise<boolean> => {\n\ttry {\n\t\tconst signatureBinStr = atob(base64Signature);\n\t\tconst signature = new Uint8Array(signatureBinStr.length);\n\t\tfor (let i = 0, len = signatureBinStr.length; i < len; i++) {\n\t\t\tsignature[i] = signatureBinStr.charCodeAt(i);\n\t\t}\n\t\treturn await getWebcryptoSubtle().verify(\n\t\t\talgorithm,\n\t\t\tsecret,\n\t\t\tsignature,\n\t\t\tnew TextEncoder().encode(value),\n\t\t);\n\t} catch
|
|
1
|
+
{"version":3,"file":"crypto.mjs","names":[],"sources":["../src/crypto.ts"],"sourcesContent":["import { getWebcryptoSubtle } from \"@better-auth/utils\";\n\nconst algorithm = { name: \"HMAC\", hash: \"SHA-256\" };\n\nexport const getCryptoKey = async (secret: string | BufferSource) => {\n\tconst secretBuf =\n\t\ttypeof secret === \"string\" ? new TextEncoder().encode(secret) : secret;\n\treturn await getWebcryptoSubtle().importKey(\n\t\t\"raw\",\n\t\tsecretBuf,\n\t\talgorithm,\n\t\tfalse,\n\t\t[\"sign\", \"verify\"],\n\t);\n};\n\nexport const verifySignature = async (\n\tbase64Signature: string,\n\tvalue: string,\n\tsecret: CryptoKey,\n): Promise<boolean> => {\n\ttry {\n\t\tconst signatureBinStr = atob(base64Signature);\n\t\tconst signature = new Uint8Array(signatureBinStr.length);\n\t\tfor (let i = 0, len = signatureBinStr.length; i < len; i++) {\n\t\t\tsignature[i] = signatureBinStr.charCodeAt(i);\n\t\t}\n\t\treturn await getWebcryptoSubtle().verify(\n\t\t\talgorithm,\n\t\t\tsecret,\n\t\t\tsignature,\n\t\t\tnew TextEncoder().encode(value),\n\t\t);\n\t} catch {\n\t\treturn false;\n\t}\n};\n\nconst makeSignature = async (\n\tvalue: string,\n\tsecret: string | BufferSource,\n): Promise<string> => {\n\tconst key = await getCryptoKey(secret);\n\tconst signature = await getWebcryptoSubtle().sign(\n\t\talgorithm.name,\n\t\tkey,\n\t\tnew TextEncoder().encode(value),\n\t);\n\t// the returned base64 encoded signature will always be 44 characters long and end with one or two equal signs\n\treturn btoa(String.fromCharCode(...new Uint8Array(signature)));\n};\n\nexport const signCookieValue = async (\n\tvalue: string,\n\tsecret: string | BufferSource,\n) => {\n\tconst signature = await makeSignature(value, secret);\n\tvalue = `${value}.${signature}`;\n\tvalue = encodeURIComponent(value);\n\treturn value;\n};\n"],"mappings":";;AAEA,MAAM,YAAY;CAAE,MAAM;CAAQ,MAAM;AAAU;AAElD,MAAa,eAAe,OAAO,WAAkC;CACpE,MAAM,YACL,OAAO,WAAW,WAAW,IAAI,YAAY,CAAC,CAAC,OAAO,MAAM,IAAI;CACjE,OAAO,MAAM,mBAAmB,CAAC,CAAC,UACjC,OACA,WACA,WACA,OACA,CAAC,QAAQ,QAAQ,CAClB;AACD;AAEA,MAAa,kBAAkB,OAC9B,iBACA,OACA,WACsB;CACtB,IAAI;EACH,MAAM,kBAAkB,KAAK,eAAe;EAC5C,MAAM,YAAY,IAAI,WAAW,gBAAgB,MAAM;EACvD,KAAK,IAAI,IAAI,GAAG,MAAM,gBAAgB,QAAQ,IAAI,KAAK,KACtD,UAAU,KAAK,gBAAgB,WAAW,CAAC;EAE5C,OAAO,MAAM,mBAAmB,CAAC,CAAC,OACjC,WACA,QACA,WACA,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK,CAC/B;CACD,QAAQ;EACP,OAAO;CACR;AACD;AAEA,MAAM,gBAAgB,OACrB,OACA,WACqB;CACrB,MAAM,MAAM,MAAM,aAAa,MAAM;CACrC,MAAM,YAAY,MAAM,mBAAmB,CAAC,CAAC,KAC5C,UAAU,MACV,KACA,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK,CAC/B;CAEA,OAAO,KAAK,OAAO,aAAa,GAAG,IAAI,WAAW,SAAS,CAAC,CAAC;AAC9D;AAEA,MAAa,kBAAkB,OAC9B,OACA,WACI;CACJ,MAAM,YAAY,MAAM,cAAc,OAAO,MAAM;CACnD,QAAQ,GAAG,MAAM,GAAG;CACpB,QAAQ,mBAAmB,KAAK;CAChC,OAAO;AACR"}
|
package/dist/endpoint.cjs
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
const require_error = require(
|
|
2
|
-
const require_utils = require(
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
|
|
1
|
+
const require_error = require("./error.cjs");
|
|
2
|
+
const require_utils = require("./utils.cjs");
|
|
3
|
+
const require_context = require("./context.cjs");
|
|
4
|
+
const require_to_response = require("./to-response.cjs");
|
|
6
5
|
//#region src/endpoint.ts
|
|
7
6
|
function createEndpoint(pathOrOptions, handlerOrOptions, handlerOrNever) {
|
|
8
7
|
const path = typeof pathOrOptions === "string" ? pathOrOptions : void 0;
|
|
@@ -56,15 +55,27 @@ function createEndpoint(pathOrOptions, handlerOrOptions, handlerOrNever) {
|
|
|
56
55
|
internalHandler.path = path;
|
|
57
56
|
return internalHandler;
|
|
58
57
|
}
|
|
58
|
+
function combineMiddleware(local, configured) {
|
|
59
|
+
return [...local ?? [], ...configured ?? []];
|
|
60
|
+
}
|
|
59
61
|
createEndpoint.create = (opts) => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
function createConfiguredEndpoint(...args) {
|
|
63
|
+
if (args.length === 3) {
|
|
64
|
+
const [path, options, handler] = args;
|
|
65
|
+
return createEndpoint(path, {
|
|
66
|
+
...options,
|
|
67
|
+
use: combineMiddleware(options.use, opts?.use)
|
|
68
|
+
}, handler);
|
|
69
|
+
}
|
|
70
|
+
const [options, handler] = args;
|
|
71
|
+
return createEndpoint({
|
|
62
72
|
...options,
|
|
63
|
-
use:
|
|
73
|
+
use: combineMiddleware(options.use, opts?.use)
|
|
64
74
|
}, handler);
|
|
65
|
-
}
|
|
75
|
+
}
|
|
76
|
+
return createConfiguredEndpoint;
|
|
66
77
|
};
|
|
67
|
-
|
|
68
78
|
//#endregion
|
|
69
79
|
exports.createEndpoint = createEndpoint;
|
|
80
|
+
|
|
70
81
|
//# sourceMappingURL=endpoint.cjs.map
|
package/dist/endpoint.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"endpoint.cjs","names":["BetterCallError","tryCatch","createInternalContext","ValidationError","APIError","isAPIError","toResponse"],"sources":["../src/endpoint.ts"],"sourcesContent":["import type { HasRequiredKeys, Prettify } from \"./helper\";\nimport { toResponse } from \"./to-response\";\nimport type { Middleware } from \"./middleware\";\nimport {\n\tcreateInternalContext,\n\ttype InferBody,\n\ttype InferHeaders,\n\ttype InferMethod,\n\ttype InferParam,\n\ttype InferQuery,\n\ttype InferRequest,\n\ttype InferUse,\n\ttype InputContext,\n\ttype Method,\n} from \"./context\";\nimport type { CookieOptions, CookiePrefixOptions } from \"./cookies\";\nimport {\n\tAPIError,\n\tValidationError,\n\ttype statusCodes,\n\ttype Status,\n\tBetterCallError,\n} from \"./error\";\nimport type { OpenAPIParameter, OpenAPISchemaType } from \"./openapi\";\nimport type { StandardSchemaV1 } from \"./standard-schema\";\nimport { isAPIError, tryCatch } from \"./utils\";\n\nexport interface EndpointBaseOptions {\n\t/**\n\t * Query Schema\n\t */\n\tquery?: StandardSchemaV1;\n\t/**\n\t * Error Schema\n\t */\n\terror?: StandardSchemaV1;\n\t/**\n\t * If true headers will be required to be passed in the context\n\t */\n\trequireHeaders?: boolean;\n\t/**\n\t * If true request object will be required\n\t */\n\trequireRequest?: boolean;\n\t/**\n\t * Clone the request object from the router\n\t */\n\tcloneRequest?: boolean;\n\t/**\n\t * If true the body will be undefined\n\t */\n\tdisableBody?: boolean;\n\t/**\n\t * Endpoint metadata\n\t */\n\tmetadata?: {\n\t\t/**\n\t\t * Open API definition\n\t\t */\n\t\topenapi?: {\n\t\t\tsummary?: string;\n\t\t\tdescription?: string;\n\t\t\ttags?: string[];\n\t\t\toperationId?: string;\n\t\t\tparameters?: OpenAPIParameter[];\n\t\t\trequestBody?: {\n\t\t\t\tcontent: {\n\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\ttype?: OpenAPISchemaType;\n\t\t\t\t\t\t\tproperties?: Record<string, any>;\n\t\t\t\t\t\t\trequired?: string[];\n\t\t\t\t\t\t\t$ref?: string;\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tresponses?: {\n\t\t\t\t[status: string]: {\n\t\t\t\t\tdescription: string;\n\t\t\t\t\tcontent?: {\n\t\t\t\t\t\t\"application/json\"?: {\n\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\ttype?: OpenAPISchemaType;\n\t\t\t\t\t\t\t\tproperties?: Record<string, any>;\n\t\t\t\t\t\t\t\trequired?: string[];\n\t\t\t\t\t\t\t\t$ref?: string;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t\t\"text/plain\"?: {\n\t\t\t\t\t\t\tschema?: {\n\t\t\t\t\t\t\t\ttype?: OpenAPISchemaType;\n\t\t\t\t\t\t\t\tproperties?: Record<string, any>;\n\t\t\t\t\t\t\t\trequired?: string[];\n\t\t\t\t\t\t\t\t$ref?: string;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t\t\"text/html\"?: {\n\t\t\t\t\t\t\tschema?: {\n\t\t\t\t\t\t\t\ttype?: OpenAPISchemaType;\n\t\t\t\t\t\t\t\tproperties?: Record<string, any>;\n\t\t\t\t\t\t\t\trequired?: string[];\n\t\t\t\t\t\t\t\t$ref?: string;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t};\n\t\t/**\n\t\t * Infer body and query type from ts interface\n\t\t *\n\t\t * useful for generic and dynamic types\n\t\t *\n\t\t * @example\n\t\t * ```ts\n\t\t * const endpoint = createEndpoint(\"/path\", {\n\t\t * \t\tmethod: \"POST\",\n\t\t * \t\tbody: z.record(z.string()),\n\t\t * \t\t$Infer: {\n\t\t * \t\t\tbody: {} as {\n\t\t * \t\t\t\ttype: InferTypeFromOptions<Option> // custom type inference\n\t\t * \t\t\t}\n\t\t * \t\t}\n\t\t * \t}, async(ctx)=>{\n\t\t * \t\tconst body = ctx.body\n\t\t * \t})\n\t\t * ```\n\t\t */\n\t\t$Infer?: {\n\t\t\t/**\n\t\t\t * Body\n\t\t\t */\n\t\t\tbody?: any;\n\t\t\t/**\n\t\t\t * Query\n\t\t\t */\n\t\t\tquery?: Record<string, any>;\n\t\t};\n\t\t/**\n\t\t * If enabled, endpoint won't be exposed over a router\n\t\t * @deprecated Use path-less endpoints instead\n\t\t */\n\t\tSERVER_ONLY?: boolean;\n\t\t/**\n\t\t * If enabled, endpoint won't be exposed as an action to the client\n\t\t * @deprecated Use path-less endpoints instead\n\t\t */\n\t\tisAction?: boolean;\n\t\t/**\n\t\t * Defines the places where the endpoint will be available\n\t\t *\n\t\t * Possible options:\n\t\t * - `rpc` - the endpoint is exposed to the router, can be invoked directly and is available to the client\n\t\t * - `server` - the endpoint is exposed to the router, can be invoked directly, but is not available to the client\n\t\t * - `http` - the endpoint is only exposed to the router\n\t\t * @default \"rpc\"\n\t\t */\n\t\tscope?: \"rpc\" | \"server\" | \"http\";\n\t\t/**\n\t\t * List of allowed media types (MIME types) for the endpoint\n\t\t *\n\t\t * if provided, only the media types in the list will be allowed to be passed in the body\n\t\t *\n\t\t * @example\n\t\t * ```ts\n\t\t * const endpoint = createEndpoint(\"/path\", {\n\t\t * \t\tmethod: \"POST\",\n\t\t * \t\tallowedMediaTypes: [\"application/json\", \"application/x-www-form-urlencoded\"],\n\t\t * \t}, async(ctx)=>{\n\t\t * \t\tconst body = ctx.body\n\t\t * \t})\n\t\t * ```\n\t\t */\n\t\tallowedMediaTypes?: string[];\n\t\t/**\n\t\t * Extra metadata\n\t\t */\n\t\t[key: string]: any;\n\t};\n\t/**\n\t * List of middlewares to use\n\t */\n\tuse?: Middleware[];\n\t/**\n\t * A callback to run before any API error is throw or returned\n\t *\n\t * @param e - The API error\n\t * @returns - The response to return\n\t */\n\tonAPIError?: (e: APIError) => void | Promise<void>;\n\t/**\n\t * A callback to run before a validation error is thrown\n\t * You can customize the validation error message by throwing your own APIError\n\t */\n\tonValidationError?: ({\n\t\tissues,\n\t\tmessage,\n\t}: {\n\t\tmessage: string;\n\t\tissues: readonly StandardSchemaV1.Issue[];\n\t}) => void | Promise<void>;\n}\n\nexport type EndpointBodyMethodOptions =\n\t| {\n\t\t\t/**\n\t\t\t * Request Method\n\t\t\t */\n\t\t\tmethod:\n\t\t\t\t| \"POST\"\n\t\t\t\t| \"PUT\"\n\t\t\t\t| \"DELETE\"\n\t\t\t\t| \"PATCH\"\n\t\t\t\t| (\"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\")[];\n\t\t\t/**\n\t\t\t * Body Schema\n\t\t\t */\n\t\t\tbody?: StandardSchemaV1;\n\t }\n\t| {\n\t\t\t/**\n\t\t\t * Request Method\n\t\t\t */\n\t\t\tmethod: \"GET\" | \"HEAD\" | (\"GET\" | \"HEAD\")[];\n\t\t\t/**\n\t\t\t * Body Schema\n\t\t\t */\n\t\t\tbody?: never;\n\t }\n\t| {\n\t\t\t/**\n\t\t\t * Request Method\n\t\t\t */\n\t\t\tmethod: \"*\";\n\t\t\t/**\n\t\t\t * Body Schema\n\t\t\t */\n\t\t\tbody?: StandardSchemaV1;\n\t }\n\t| {\n\t\t\t/**\n\t\t\t * Request Method\n\t\t\t */\n\t\t\tmethod: (\"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\" | \"GET\" | \"HEAD\")[];\n\t\t\t/**\n\t\t\t * Body Schema\n\t\t\t */\n\t\t\tbody?: StandardSchemaV1;\n\t };\n\nexport type EndpointOptions = EndpointBaseOptions & EndpointBodyMethodOptions;\n\nexport type EndpointContext<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n\tContext = {},\n> = {\n\t/**\n\t * Method\n\t *\n\t * The request method\n\t */\n\tmethod: InferMethod<Options>;\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: InferBody<Options>;\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: InferQuery<Options>;\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: InferRequest<Options>;\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: InferHeaders<Options>;\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 * @returns\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\n\t * the correct headers\n\t * and status code. If `asResponse` is set to true in\n\t * the context then\n\t * it will return a Response object instead of the\n\t * JSON object.\n\t *\n\t * @param json - The JSON object to return\n\t * @param routerResponse - The response object to\n\t * 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, string>;\n\t\t\t }\n\t\t\t| Response,\n\t) => Promise<R>;\n\t/**\n\t * Middleware context\n\t */\n\tcontext: Prettify<Context & InferUse<Options[\"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\ntype ExtractBody<E extends EndpointBodyMethodOptions> = E extends {\n\tmethod: (\"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\" | \"GET\" | \"HEAD\")[];\n\tbody?: StandardSchemaV1<infer B>;\n}\n\t? E extends {\n\t\t\tmethod: infer M;\n\t\t\tbody?: StandardSchemaV1<B>;\n\t\t}\n\t\t? { method: M; body: StandardSchemaV1<B> }\n\t\t: never\n\t: E extends {\n\t\t\t\tmethod:\n\t\t\t\t\t| \"POST\"\n\t\t\t\t\t| \"PUT\"\n\t\t\t\t\t| \"DELETE\"\n\t\t\t\t\t| \"PATCH\"\n\t\t\t\t\t| (\"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\")[];\n\t\t\t\tbody?: StandardSchemaV1<infer B>;\n\t\t\t}\n\t\t? E extends {\n\t\t\t\tmethod: infer M;\n\t\t\t\tbody?: StandardSchemaV1<B>;\n\t\t\t}\n\t\t\t? { method: M; body: StandardSchemaV1<B> }\n\t\t\t: never\n\t\t: E extends {\n\t\t\t\t\tmethod: \"*\";\n\t\t\t\t\tbody?: StandardSchemaV1<infer B>;\n\t\t\t\t}\n\t\t\t? {\n\t\t\t\t\tmethod: \"*\";\n\t\t\t\t\tbody?: StandardSchemaV1<B>;\n\t\t\t\t}\n\t\t\t: E extends {\n\t\t\t\t\t\tmethod: \"GET\" | \"HEAD\" | (\"GET\" | \"HEAD\")[];\n\t\t\t\t\t\tbody?: never;\n\t\t\t\t\t}\n\t\t\t\t? E extends { method: infer M }\n\t\t\t\t\t? { method: M }\n\t\t\t\t\t: never\n\t\t\t\t: never;\ntype ExtractError<E extends EndpointOptions> = E extends {\n\terror?: StandardSchemaV1<infer Err>;\n}\n\t? {\n\t\t\terror: StandardSchemaV1<Err>;\n\t\t}\n\t: {};\ntype ExtractQuery<E extends EndpointOptions> = E extends {\n\tquery?: StandardSchemaV1<infer Q>;\n}\n\t? {\n\t\t\tquery: StandardSchemaV1<Q>;\n\t\t}\n\t: {};\n\ntype ExtractOthers<E extends EndpointOptions> = Pick<\n\tE,\n\tExclude<keyof E, \"method\" | \"body\" | \"query\" | \"error\">\n>;\n\n/**\n * DO NOT EXPORT THIS TYPE\n */\ntype ExtractStandSchema<E extends EndpointOptions> = ExtractOthers<E> &\n\tExtractBody<E> &\n\tExtractQuery<E> &\n\tExtractError<E>;\n\nexport type EndpointHandler<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n\tR,\n> = (context: EndpointContext<Path, Options>) => Promise<R>;\n\nexport function createEndpoint<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n\tR,\n>(\n\tpath: Path,\n\toptions: Options,\n\thandler: EndpointHandler<Path, Options, R>,\n): StrictEndpoint<Path, ExtractStandSchema<Options>, R>;\n\nexport function createEndpoint<Options extends EndpointOptions, R>(\n\toptions: Options,\n\thandler: EndpointHandler<never, Options, R>,\n): StrictEndpoint<never, ExtractStandSchema<Options>, R>;\n\nexport function createEndpoint<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n\tR,\n>(\n\tpathOrOptions: Path | Options,\n\thandlerOrOptions: EndpointHandler<Path, Options, R> | Options,\n\thandlerOrNever?: any,\n): StrictEndpoint<Path, ExtractStandSchema<Options>, R> {\n\tconst path: string | undefined =\n\t\ttypeof pathOrOptions === \"string\" ? pathOrOptions : undefined;\n\tconst options: Options =\n\t\ttypeof handlerOrOptions === \"object\"\n\t\t\t? handlerOrOptions\n\t\t\t: (pathOrOptions as Options);\n\tconst handler: EndpointHandler<Path, Options, R> =\n\t\ttypeof handlerOrOptions === \"function\" ? handlerOrOptions : handlerOrNever;\n\n\tif ((options.method === \"GET\" || options.method === \"HEAD\") && options.body) {\n\t\tthrow new BetterCallError(\"Body is not allowed with GET or HEAD methods\");\n\t}\n\n\tif (path && /\\/{2,}/.test(path)) {\n\t\tthrow new BetterCallError(\"Path cannot contain consecutive slashes\");\n\t}\n\ttype Context = InputContext<Path, Options>;\n\n\ttype ResultType<\n\t\tAsResponse extends boolean,\n\t\tReturnHeaders extends boolean,\n\t\tReturnStatus extends boolean,\n\t> = AsResponse extends true\n\t\t? Response\n\t\t: ReturnHeaders extends true\n\t\t\t? ReturnStatus extends true\n\t\t\t\t? {\n\t\t\t\t\t\theaders: Headers;\n\t\t\t\t\t\tstatus: number;\n\t\t\t\t\t\tresponse: Awaited<R>;\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\theaders: Headers;\n\t\t\t\t\t\tresponse: Awaited<R>;\n\t\t\t\t\t}\n\t\t\t: ReturnStatus extends true\n\t\t\t\t? {\n\t\t\t\t\t\tstatus: number;\n\t\t\t\t\t\tresponse: Awaited<R>;\n\t\t\t\t\t}\n\t\t\t\t: Awaited<R>;\n\n\tconst internalHandler = async <\n\t\tAsResponse extends boolean = false,\n\t\tReturnHeaders extends boolean = false,\n\t\tReturnStatus extends boolean = false,\n\t>(\n\t\t...inputCtx: HasRequiredKeys<Context> extends true\n\t\t\t? [\n\t\t\t\t\tContext & {\n\t\t\t\t\t\tasResponse?: AsResponse;\n\t\t\t\t\t\treturnHeaders?: ReturnHeaders;\n\t\t\t\t\t\treturnStatus?: ReturnStatus;\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t: [\n\t\t\t\t\t(Context & {\n\t\t\t\t\t\tasResponse?: AsResponse;\n\t\t\t\t\t\treturnHeaders?: ReturnHeaders;\n\t\t\t\t\t\treturnStatus?: ReturnStatus;\n\t\t\t\t\t})?,\n\t\t\t\t]\n\t): Promise<ResultType<AsResponse, ReturnHeaders, ReturnStatus>> => {\n\t\tconst context = (inputCtx[0] || {}) as InputContext<any, any>;\n\t\tconst { data: internalContext, error: validationError } = await tryCatch(\n\t\t\tcreateInternalContext(context, {\n\t\t\t\toptions,\n\t\t\t\tpath,\n\t\t\t}),\n\t\t);\n\n\t\tif (validationError) {\n\t\t\t// If it's not a validation error, we throw it\n\t\t\tif (!(validationError instanceof ValidationError)) throw validationError;\n\n\t\t\t// Check if the endpoint has a custom onValidationError callback\n\t\t\tif (options.onValidationError) {\n\t\t\t\t// This can possibly throw an APIError in order to customize the validation error message\n\t\t\t\tawait options.onValidationError({\n\t\t\t\t\tmessage: validationError.message,\n\t\t\t\t\tissues: validationError.issues,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tthrow new APIError(400, {\n\t\t\t\tmessage: validationError.message,\n\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t});\n\t\t}\n\t\tconst response = await handler(internalContext as any).catch(async (e) => {\n\t\t\tif (isAPIError(e)) {\n\t\t\t\tconst onAPIError = options.onAPIError;\n\t\t\t\tif (onAPIError) {\n\t\t\t\t\tawait onAPIError(e);\n\t\t\t\t}\n\t\t\t\tif (context.asResponse) {\n\t\t\t\t\treturn e;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow e;\n\t\t});\n\t\tconst headers = internalContext.responseHeaders;\n\t\tconst status = internalContext.responseStatus;\n\n\t\treturn (\n\t\t\tcontext.asResponse\n\t\t\t\t? toResponse(response, {\n\t\t\t\t\t\theaders,\n\t\t\t\t\t\tstatus,\n\t\t\t\t\t})\n\t\t\t\t: context.returnHeaders\n\t\t\t\t\t? context.returnStatus\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\theaders,\n\t\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t\t\tstatus,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\theaders,\n\t\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t: context.returnStatus\n\t\t\t\t\t\t? { response, status }\n\t\t\t\t\t\t: response\n\t\t) as ResultType<AsResponse, ReturnHeaders, ReturnStatus>;\n\t};\n\tinternalHandler.options = options;\n\tinternalHandler.path = path;\n\treturn internalHandler as unknown as StrictEndpoint<\n\t\tPath,\n\t\tExtractStandSchema<Options>,\n\t\tR\n\t>;\n}\n\ncreateEndpoint.create = <E extends { use?: Middleware[] }>(opts?: E) => {\n\treturn <\n\t\tPath extends string,\n\t\tOpts extends EndpointOptions,\n\t\tR extends Promise<any>,\n\t>(\n\t\tpath: Path,\n\t\toptions: Opts,\n\t\thandler: (ctx: EndpointContext<Path, Opts, InferUse<E[\"use\"]>>) => R,\n\t) => {\n\t\treturn createEndpoint(\n\t\t\tpath,\n\t\t\t{\n\t\t\t\t...options,\n\t\t\t\tuse: [...(options?.use || []), ...(opts?.use || [])],\n\t\t\t},\n\t\t\thandler,\n\t\t);\n\t};\n};\n\nexport type StrictEndpoint<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n\tR = any,\n> = {\n\t// asResponse cases\n\t(\n\t\tcontext: InputContext<Path, Options> & { asResponse: true },\n\t): Promise<Response>;\n\n\t// returnHeaders & returnStatus cases\n\t(\n\t\tcontext: InputContext<Path, Options> & {\n\t\t\treturnHeaders: true;\n\t\t\treturnStatus: true;\n\t\t},\n\t): Promise<{ headers: Headers; status: number; response: Awaited<R> }>;\n\t(\n\t\tcontext: InputContext<Path, Options> & {\n\t\t\treturnHeaders: true;\n\t\t\treturnStatus: false;\n\t\t},\n\t): Promise<{ headers: Headers; response: Awaited<R> }>;\n\t(\n\t\tcontext: InputContext<Path, Options> & {\n\t\t\treturnHeaders: false;\n\t\t\treturnStatus: true;\n\t\t},\n\t): Promise<{ status: number; response: Awaited<R> }>;\n\t(\n\t\tcontext: InputContext<Path, Options> & {\n\t\t\treturnHeaders: false;\n\t\t\treturnStatus: false;\n\t\t},\n\t): Promise<R>;\n\n\t// individual flag cases\n\t(\n\t\tcontext: InputContext<Path, Options> & { returnHeaders: true },\n\t): Promise<{ headers: Headers; response: Awaited<R> }>;\n\t(\n\t\tcontext: InputContext<Path, Options> & { returnStatus: true },\n\t): Promise<{ status: number; response: Awaited<R> }>;\n\n\t// default case\n\t(context?: InputContext<Path, Options>): Promise<R>;\n\n\toptions: Options;\n\tpath: Path;\n};\n\nexport type Endpoint<\n\tPath extends string = string,\n\tOptions extends EndpointOptions = EndpointOptions,\n\tHandler extends (inputCtx: any) => Promise<any> = (\n\t\tinputCtx: any,\n\t) => Promise<any>,\n> = Handler & {\n\toptions: Options;\n\tpath: Path;\n};\n"],"mappings":";;;;;;AA4gBA,SAAgB,eAKf,eACA,kBACA,gBACuD;CACvD,MAAM,OACL,OAAO,kBAAkB,WAAW,gBAAgB;CACrD,MAAM,UACL,OAAO,qBAAqB,WACzB,mBACC;CACL,MAAM,UACL,OAAO,qBAAqB,aAAa,mBAAmB;AAE7D,MAAK,QAAQ,WAAW,SAAS,QAAQ,WAAW,WAAW,QAAQ,KACtE,OAAM,IAAIA,8BAAgB,+CAA+C;AAG1E,KAAI,QAAQ,SAAS,KAAK,KAAK,CAC9B,OAAM,IAAIA,8BAAgB,0CAA0C;CA4BrE,MAAM,kBAAkB,OAKvB,GAAG,aAe+D;EAClE,MAAM,UAAW,SAAS,MAAM,EAAE;EAClC,MAAM,EAAE,MAAM,iBAAiB,OAAO,oBAAoB,MAAMC,uBAC/DC,sCAAsB,SAAS;GAC9B;GACA;GACA,CAAC,CACF;AAED,MAAI,iBAAiB;AAEpB,OAAI,EAAE,2BAA2BC,+BAAkB,OAAM;AAGzD,OAAI,QAAQ,kBAEX,OAAM,QAAQ,kBAAkB;IAC/B,SAAS,gBAAgB;IACzB,QAAQ,gBAAgB;IACxB,CAAC;AAGH,SAAM,IAAIC,uBAAS,KAAK;IACvB,SAAS,gBAAgB;IACzB,MAAM;IACN,CAAC;;EAEH,MAAM,WAAW,MAAM,QAAQ,gBAAuB,CAAC,MAAM,OAAO,MAAM;AACzE,OAAIC,yBAAW,EAAE,EAAE;IAClB,MAAM,aAAa,QAAQ;AAC3B,QAAI,WACH,OAAM,WAAW,EAAE;AAEpB,QAAI,QAAQ,WACX,QAAO;;AAGT,SAAM;IACL;EACF,MAAM,UAAU,gBAAgB;EAChC,MAAM,SAAS,gBAAgB;AAE/B,SACC,QAAQ,aACLC,+BAAW,UAAU;GACrB;GACA;GACA,CAAC,GACD,QAAQ,gBACP,QAAQ,eACP;GACA;GACA;GACA;GACA,GACA;GACA;GACA;GACA,GACD,QAAQ,eACP;GAAE;GAAU;GAAQ,GACpB;;AAGP,iBAAgB,UAAU;AAC1B,iBAAgB,OAAO;AACvB,QAAO;;AAOR,eAAe,UAA4C,SAAa;AACvE,SAKC,MACA,SACA,YACI;AACJ,SAAO,eACN,MACA;GACC,GAAG;GACH,KAAK,CAAC,GAAI,SAAS,OAAO,EAAE,EAAG,GAAI,MAAM,OAAO,EAAE,CAAE;GACpD,EACD,QACA"}
|
|
1
|
+
{"version":3,"file":"endpoint.cjs","names":["BetterCallError","tryCatch","createInternalContext","ValidationError","APIError","isAPIError","toResponse"],"sources":["../src/endpoint.ts"],"sourcesContent":["import type {\n\tInferBody,\n\tInferHeaders,\n\tInferMethod,\n\tInferParam,\n\tInferQuery,\n\tInferRequest,\n\tInferUse,\n\tInputContext,\n} from \"./context\";\nimport { createInternalContext } from \"./context\";\nimport type { CookieOptions, CookiePrefixOptions } from \"./cookies\";\nimport type { Status, statusCodes } from \"./error\";\nimport { APIError, BetterCallError, ValidationError } from \"./error\";\nimport type { HasRequiredKeys, Prettify } from \"./helper\";\nimport type { MiddlewareHandler } from \"./middleware\";\nimport type { OpenAPIParameter, OpenAPISchemaType } from \"./openapi\";\nimport type { StandardSchemaV1 } from \"./standard-schema\";\nimport { toResponse } from \"./to-response\";\nimport { isAPIError, tryCatch } from \"./utils\";\n\nexport interface EndpointBaseOptions {\n\t/**\n\t * Query Schema\n\t */\n\tquery?: StandardSchemaV1;\n\t/**\n\t * Error Schema\n\t */\n\terror?: StandardSchemaV1;\n\t/**\n\t * If true headers will be required to be passed in the context\n\t */\n\trequireHeaders?: boolean;\n\t/**\n\t * If true request object will be required\n\t */\n\trequireRequest?: boolean;\n\t/**\n\t * Clone the request object from the router\n\t */\n\tcloneRequest?: boolean;\n\t/**\n\t * If true the body will be undefined\n\t */\n\tdisableBody?: boolean;\n\t/**\n\t * Endpoint metadata\n\t */\n\tmetadata?: {\n\t\t/**\n\t\t * Open API definition\n\t\t */\n\t\topenapi?: {\n\t\t\tsummary?: string;\n\t\t\tdescription?: string;\n\t\t\ttags?: string[];\n\t\t\toperationId?: string;\n\t\t\tparameters?: OpenAPIParameter[];\n\t\t\trequestBody?: {\n\t\t\t\tcontent: {\n\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\ttype?: OpenAPISchemaType;\n\t\t\t\t\t\t\tproperties?: Record<string, any>;\n\t\t\t\t\t\t\trequired?: string[];\n\t\t\t\t\t\t\t$ref?: string;\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tresponses?: {\n\t\t\t\t[status: string]: {\n\t\t\t\t\tdescription: string;\n\t\t\t\t\tcontent?: {\n\t\t\t\t\t\t\"application/json\"?: {\n\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\ttype?: OpenAPISchemaType;\n\t\t\t\t\t\t\t\tproperties?: Record<string, any>;\n\t\t\t\t\t\t\t\trequired?: string[];\n\t\t\t\t\t\t\t\t$ref?: string;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t\t\"text/plain\"?: {\n\t\t\t\t\t\t\tschema?: {\n\t\t\t\t\t\t\t\ttype?: OpenAPISchemaType;\n\t\t\t\t\t\t\t\tproperties?: Record<string, any>;\n\t\t\t\t\t\t\t\trequired?: string[];\n\t\t\t\t\t\t\t\t$ref?: string;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t\t\"text/html\"?: {\n\t\t\t\t\t\t\tschema?: {\n\t\t\t\t\t\t\t\ttype?: OpenAPISchemaType;\n\t\t\t\t\t\t\t\tproperties?: Record<string, any>;\n\t\t\t\t\t\t\t\trequired?: string[];\n\t\t\t\t\t\t\t\t$ref?: string;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t};\n\t\t/**\n\t\t * Infer body and query type from ts interface\n\t\t *\n\t\t * useful for generic and dynamic types\n\t\t *\n\t\t * @example\n\t\t * ```ts\n\t\t * const endpoint = createEndpoint(\"/path\", {\n\t\t * \t\tmethod: \"POST\",\n\t\t * \t\tbody: z.record(z.string()),\n\t\t * \t\t$Infer: {\n\t\t * \t\t\tbody: {} as {\n\t\t * \t\t\t\ttype: InferTypeFromOptions<Option> // custom type inference\n\t\t * \t\t\t}\n\t\t * \t\t}\n\t\t * \t}, async(ctx)=>{\n\t\t * \t\tconst body = ctx.body\n\t\t * \t})\n\t\t * ```\n\t\t */\n\t\t$Infer?: {\n\t\t\t/**\n\t\t\t * Body\n\t\t\t */\n\t\t\tbody?: any;\n\t\t\t/**\n\t\t\t * Query\n\t\t\t */\n\t\t\tquery?: Record<string, any>;\n\t\t};\n\t\t/**\n\t\t * If enabled, endpoint won't be exposed over a router\n\t\t * @deprecated Use path-less endpoints instead\n\t\t */\n\t\tSERVER_ONLY?: boolean;\n\t\t/**\n\t\t * If enabled, endpoint won't be exposed as an action to the client\n\t\t * @deprecated Use path-less endpoints instead\n\t\t */\n\t\tisAction?: boolean;\n\t\t/**\n\t\t * Defines the places where the endpoint will be available\n\t\t *\n\t\t * Possible options:\n\t\t * - `rpc` - the endpoint is exposed to the router, can be invoked directly and is available to the client\n\t\t * - `server` - the endpoint is exposed to the router, can be invoked directly, but is not available to the client\n\t\t * - `http` - the endpoint is only exposed to the router\n\t\t * @default \"rpc\"\n\t\t */\n\t\tscope?: \"rpc\" | \"server\" | \"http\";\n\t\t/**\n\t\t * List of allowed media types (MIME types) for the endpoint\n\t\t *\n\t\t * if provided, only the media types in the list will be allowed to be passed in the body\n\t\t *\n\t\t * @example\n\t\t * ```ts\n\t\t * const endpoint = createEndpoint(\"/path\", {\n\t\t * \t\tmethod: \"POST\",\n\t\t * \t\tallowedMediaTypes: [\"application/json\", \"application/x-www-form-urlencoded\"],\n\t\t * \t}, async(ctx)=>{\n\t\t * \t\tconst body = ctx.body\n\t\t * \t})\n\t\t * ```\n\t\t */\n\t\tallowedMediaTypes?: string[];\n\t\t/**\n\t\t * Extra metadata\n\t\t */\n\t\t[key: string]: any;\n\t};\n\t/**\n\t * List of middlewares to use\n\t */\n\tuse?: MiddlewareHandler[];\n\t/**\n\t * A callback to run before any API error is throw or returned\n\t *\n\t * @param e - The API error\n\t * @returns - The response to return\n\t */\n\tonAPIError?: (e: APIError) => void | Promise<void>;\n\t/**\n\t * A callback to run before a validation error is thrown\n\t * You can customize the validation error message by throwing your own APIError\n\t */\n\tonValidationError?: ({\n\t\tissues,\n\t\tmessage,\n\t}: {\n\t\tmessage: string;\n\t\tissues: readonly StandardSchemaV1.Issue[];\n\t}) => void | Promise<void>;\n}\n\nexport type EndpointBodyMethodOptions =\n\t| {\n\t\t\t/**\n\t\t\t * Request Method\n\t\t\t */\n\t\t\tmethod:\n\t\t\t\t| \"POST\"\n\t\t\t\t| \"PUT\"\n\t\t\t\t| \"DELETE\"\n\t\t\t\t| \"PATCH\"\n\t\t\t\t| (\"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\")[];\n\t\t\t/**\n\t\t\t * Body Schema\n\t\t\t */\n\t\t\tbody?: StandardSchemaV1;\n\t }\n\t| {\n\t\t\t/**\n\t\t\t * Request Method\n\t\t\t */\n\t\t\tmethod: \"GET\" | \"HEAD\" | (\"GET\" | \"HEAD\")[];\n\t\t\t/**\n\t\t\t * Body Schema\n\t\t\t */\n\t\t\tbody?: never;\n\t }\n\t| {\n\t\t\t/**\n\t\t\t * Request Method\n\t\t\t */\n\t\t\tmethod: \"*\";\n\t\t\t/**\n\t\t\t * Body Schema\n\t\t\t */\n\t\t\tbody?: StandardSchemaV1;\n\t }\n\t| {\n\t\t\t/**\n\t\t\t * Request Method\n\t\t\t */\n\t\t\tmethod: (\"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\" | \"GET\" | \"HEAD\")[];\n\t\t\t/**\n\t\t\t * Body Schema\n\t\t\t */\n\t\t\tbody?: StandardSchemaV1;\n\t };\n\nexport type EndpointOptions = EndpointBaseOptions & EndpointBodyMethodOptions;\n\ntype EndpointParams = Record<string, string | undefined> | undefined;\n\nexport type EndpointContext<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n\tContext extends object = object,\n\tResolvedParams extends EndpointParams = InferParam<Path>,\n> = {\n\t/**\n\t * Method\n\t *\n\t * The request method\n\t */\n\tmethod: InferMethod<Options>;\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: InferBody<Options>;\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: InferQuery<Options>;\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\" }`. An unnamed wildcard like `/user/*` uses a numeric key,\n\t * while a named catch-all like `/user/**:path` uses its declared name.\n\t */\n\tparams: ResolvedParams;\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: InferRequest<Options>;\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: InferHeaders<Options>;\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 * @returns\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\n\t * the correct headers\n\t * and status code. If `asResponse` is set to true in\n\t * the context then\n\t * it will return a Response object instead of the\n\t * JSON object.\n\t *\n\t * @param json - The JSON object to return\n\t * @param routerResponse - The response object to\n\t * 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, string>;\n\t\t\t }\n\t\t\t| Response,\n\t) => Promise<R>;\n\t/**\n\t * Middleware context\n\t */\n\tcontext: Prettify<Context & InferUse<Options[\"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\ntype ExtractBody<E extends EndpointBodyMethodOptions> = E extends {\n\tmethod: (\"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\" | \"GET\" | \"HEAD\")[];\n\tbody?: StandardSchemaV1<infer B>;\n}\n\t? E extends {\n\t\t\tmethod: infer M;\n\t\t\tbody?: StandardSchemaV1<B>;\n\t\t}\n\t\t? { method: M; body: StandardSchemaV1<B> }\n\t\t: never\n\t: E extends {\n\t\t\t\tmethod:\n\t\t\t\t\t| \"POST\"\n\t\t\t\t\t| \"PUT\"\n\t\t\t\t\t| \"DELETE\"\n\t\t\t\t\t| \"PATCH\"\n\t\t\t\t\t| (\"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\")[];\n\t\t\t\tbody?: StandardSchemaV1<infer B>;\n\t\t\t}\n\t\t? E extends {\n\t\t\t\tmethod: infer M;\n\t\t\t\tbody?: StandardSchemaV1<B>;\n\t\t\t}\n\t\t\t? { method: M; body: StandardSchemaV1<B> }\n\t\t\t: never\n\t\t: E extends {\n\t\t\t\t\tmethod: \"*\";\n\t\t\t\t\tbody?: StandardSchemaV1<infer B>;\n\t\t\t\t}\n\t\t\t? {\n\t\t\t\t\tmethod: \"*\";\n\t\t\t\t\tbody?: StandardSchemaV1<B>;\n\t\t\t\t}\n\t\t\t: E extends {\n\t\t\t\t\t\tmethod: \"GET\" | \"HEAD\" | (\"GET\" | \"HEAD\")[];\n\t\t\t\t\t\tbody?: never;\n\t\t\t\t\t}\n\t\t\t\t? E extends { method: infer M }\n\t\t\t\t\t? { method: M }\n\t\t\t\t\t: never\n\t\t\t\t: never;\ntype ExtractError<E extends EndpointOptions> = E extends {\n\terror?: StandardSchemaV1<infer Err>;\n}\n\t? {\n\t\t\terror: StandardSchemaV1<Err>;\n\t\t}\n\t: {};\ntype ExtractQuery<E extends EndpointOptions> = E extends {\n\tquery?: StandardSchemaV1<infer Q>;\n}\n\t? {\n\t\t\tquery: StandardSchemaV1<Q>;\n\t\t}\n\t: {};\n\ntype ExtractOthers<E extends EndpointOptions> = Pick<\n\tE,\n\tExclude<keyof E, \"method\" | \"body\" | \"query\" | \"error\">\n>;\n\n/**\n * DO NOT EXPORT THIS TYPE\n */\ntype ExtractStandSchema<E extends EndpointOptions> = ExtractOthers<E> &\n\tExtractBody<E> &\n\tExtractQuery<E> &\n\tExtractError<E>;\n\nexport type EndpointHandler<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n\tR,\n\tContext extends object = object,\n> = (context: EndpointContext<Path, Options, Context>) => Promise<R>;\n\ntype PathlessEndpointHandler<\n\tOptions extends EndpointOptions,\n\tR,\n\tContext extends object = object,\n> = EndpointHandler<string, Options, R, Context>;\n\nexport function createEndpoint<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n\tR,\n>(\n\tpath: Path,\n\toptions: Options,\n\thandler: EndpointHandler<Path, Options, R>,\n): StrictEndpoint<Path, ExtractStandSchema<Options>, R>;\n\nexport function createEndpoint<Options extends EndpointOptions, R>(\n\toptions: Options,\n\thandler: PathlessEndpointHandler<Options, R>,\n): StrictEndpoint<never, ExtractStandSchema<Options>, R>;\n\nexport function createEndpoint<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n\tR,\n>(\n\tpathOrOptions: Path | Options,\n\thandlerOrOptions: EndpointHandler<Path, Options, R> | Options,\n\thandlerOrNever?: any,\n): StrictEndpoint<Path, ExtractStandSchema<Options>, R> {\n\tconst path: string | undefined =\n\t\ttypeof pathOrOptions === \"string\" ? pathOrOptions : undefined;\n\tconst options: Options =\n\t\ttypeof handlerOrOptions === \"object\"\n\t\t\t? handlerOrOptions\n\t\t\t: (pathOrOptions as Options);\n\tconst handler: EndpointHandler<Path, Options, R> =\n\t\ttypeof handlerOrOptions === \"function\" ? handlerOrOptions : handlerOrNever;\n\n\tif ((options.method === \"GET\" || options.method === \"HEAD\") && options.body) {\n\t\tthrow new BetterCallError(\"Body is not allowed with GET or HEAD methods\");\n\t}\n\n\tif (path && /\\/{2,}/.test(path)) {\n\t\tthrow new BetterCallError(\"Path cannot contain consecutive slashes\");\n\t}\n\ttype Context = InputContext<Path, Options>;\n\n\ttype ResultType<\n\t\tAsResponse extends boolean,\n\t\tReturnHeaders extends boolean,\n\t\tReturnStatus extends boolean,\n\t> = AsResponse extends true\n\t\t? Response\n\t\t: ReturnHeaders extends true\n\t\t\t? ReturnStatus extends true\n\t\t\t\t? {\n\t\t\t\t\t\theaders: Headers;\n\t\t\t\t\t\tstatus: number;\n\t\t\t\t\t\tresponse: Awaited<R>;\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\theaders: Headers;\n\t\t\t\t\t\tresponse: Awaited<R>;\n\t\t\t\t\t}\n\t\t\t: ReturnStatus extends true\n\t\t\t\t? {\n\t\t\t\t\t\tstatus: number;\n\t\t\t\t\t\tresponse: Awaited<R>;\n\t\t\t\t\t}\n\t\t\t\t: Awaited<R>;\n\n\tconst internalHandler = async <\n\t\tAsResponse extends boolean = false,\n\t\tReturnHeaders extends boolean = false,\n\t\tReturnStatus extends boolean = false,\n\t>(\n\t\t...inputCtx: HasRequiredKeys<Context> extends true\n\t\t\t? [\n\t\t\t\t\tContext & {\n\t\t\t\t\t\tasResponse?: AsResponse;\n\t\t\t\t\t\treturnHeaders?: ReturnHeaders;\n\t\t\t\t\t\treturnStatus?: ReturnStatus;\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t: [\n\t\t\t\t\t(Context & {\n\t\t\t\t\t\tasResponse?: AsResponse;\n\t\t\t\t\t\treturnHeaders?: ReturnHeaders;\n\t\t\t\t\t\treturnStatus?: ReturnStatus;\n\t\t\t\t\t})?,\n\t\t\t\t]\n\t): Promise<ResultType<AsResponse, ReturnHeaders, ReturnStatus>> => {\n\t\tconst context = (inputCtx[0] || {}) as InputContext<any, any>;\n\t\tconst { data: internalContext, error: validationError } = await tryCatch(\n\t\t\tcreateInternalContext(context, {\n\t\t\t\toptions,\n\t\t\t\tpath,\n\t\t\t}),\n\t\t);\n\n\t\tif (validationError) {\n\t\t\t// If it's not a validation error, we throw it\n\t\t\tif (!(validationError instanceof ValidationError)) throw validationError;\n\n\t\t\t// Check if the endpoint has a custom onValidationError callback\n\t\t\tif (options.onValidationError) {\n\t\t\t\t// This can possibly throw an APIError in order to customize the validation error message\n\t\t\t\tawait options.onValidationError({\n\t\t\t\t\tmessage: validationError.message,\n\t\t\t\t\tissues: validationError.issues,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tthrow new APIError(400, {\n\t\t\t\tmessage: validationError.message,\n\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t});\n\t\t}\n\t\tconst response = await handler(internalContext as any).catch(async (e) => {\n\t\t\tif (isAPIError(e)) {\n\t\t\t\tconst onAPIError = options.onAPIError;\n\t\t\t\tif (onAPIError) {\n\t\t\t\t\tawait onAPIError(e);\n\t\t\t\t}\n\t\t\t\tif (context.asResponse) {\n\t\t\t\t\treturn e;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow e;\n\t\t});\n\t\tconst headers = internalContext.responseHeaders;\n\t\tconst status = internalContext.responseStatus;\n\n\t\treturn (\n\t\t\tcontext.asResponse\n\t\t\t\t? toResponse(response, {\n\t\t\t\t\t\theaders,\n\t\t\t\t\t\tstatus,\n\t\t\t\t\t})\n\t\t\t\t: context.returnHeaders\n\t\t\t\t\t? context.returnStatus\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\theaders,\n\t\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t\t\tstatus,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\theaders,\n\t\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t: context.returnStatus\n\t\t\t\t\t\t? { response, status }\n\t\t\t\t\t\t: response\n\t\t) as ResultType<AsResponse, ReturnHeaders, ReturnStatus>;\n\t};\n\tinternalHandler.options = options;\n\tinternalHandler.path = path;\n\treturn internalHandler as unknown as StrictEndpoint<\n\t\tPath,\n\t\tExtractStandSchema<Options>,\n\t\tR\n\t>;\n}\n\nfunction combineMiddleware(\n\tlocal: MiddlewareHandler[] | undefined,\n\tconfigured: MiddlewareHandler[] | undefined,\n): MiddlewareHandler[] {\n\treturn [...(local ?? []), ...(configured ?? [])];\n}\n\ncreateEndpoint.create = <E extends { use?: MiddlewareHandler[] }>(opts?: E) => {\n\tfunction createConfiguredEndpoint<\n\t\tPath extends string,\n\t\tOpts extends EndpointOptions,\n\t\tR,\n\t>(\n\t\tpath: Path,\n\t\toptions: Opts,\n\t\thandler: EndpointHandler<Path, Opts, R, InferUse<E[\"use\"]>>,\n\t): StrictEndpoint<\n\t\tPath,\n\t\tExtractStandSchema<Opts & { use: MiddlewareHandler[] }>,\n\t\tR\n\t>;\n\n\tfunction createConfiguredEndpoint<Opts extends EndpointOptions, R>(\n\t\toptions: Opts,\n\t\thandler: PathlessEndpointHandler<Opts, R, InferUse<E[\"use\"]>>,\n\t): StrictEndpoint<\n\t\tnever,\n\t\tExtractStandSchema<Opts & { use: MiddlewareHandler[] }>,\n\t\tR\n\t>;\n\n\tfunction createConfiguredEndpoint<\n\t\tPath extends string,\n\t\tOpts extends EndpointOptions,\n\t\tR,\n\t>(\n\t\t...args:\n\t\t\t| [\n\t\t\t\t\tpath: Path,\n\t\t\t\t\toptions: Opts,\n\t\t\t\t\thandler: EndpointHandler<Path, Opts, R, InferUse<E[\"use\"]>>,\n\t\t\t ]\n\t\t\t| [\n\t\t\t\t\toptions: Opts,\n\t\t\t\t\thandler: PathlessEndpointHandler<Opts, R, InferUse<E[\"use\"]>>,\n\t\t\t ]\n\t) {\n\t\tif (args.length === 3) {\n\t\t\tconst [path, options, handler] = args;\n\t\t\treturn createEndpoint(\n\t\t\t\tpath,\n\t\t\t\t{\n\t\t\t\t\t...options,\n\t\t\t\t\tuse: combineMiddleware(options.use, opts?.use),\n\t\t\t\t},\n\t\t\t\thandler,\n\t\t\t);\n\t\t}\n\n\t\tconst [options, handler] = args;\n\t\treturn createEndpoint(\n\t\t\t{\n\t\t\t\t...options,\n\t\t\t\tuse: combineMiddleware(options.use, opts?.use),\n\t\t\t},\n\t\t\thandler,\n\t\t);\n\t}\n\n\treturn createConfiguredEndpoint;\n};\n\nexport type StrictEndpoint<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n\tR = any,\n> = {\n\t// asResponse cases\n\t(\n\t\tcontext: InputContext<Path, Options> & { asResponse: true },\n\t): Promise<Response>;\n\n\t// returnHeaders & returnStatus cases\n\t(\n\t\tcontext: InputContext<Path, Options> & {\n\t\t\treturnHeaders: true;\n\t\t\treturnStatus: true;\n\t\t},\n\t): Promise<{ headers: Headers; status: number; response: Awaited<R> }>;\n\t(\n\t\tcontext: InputContext<Path, Options> & {\n\t\t\treturnHeaders: true;\n\t\t\treturnStatus: false;\n\t\t},\n\t): Promise<{ headers: Headers; response: Awaited<R> }>;\n\t(\n\t\tcontext: InputContext<Path, Options> & {\n\t\t\treturnHeaders: false;\n\t\t\treturnStatus: true;\n\t\t},\n\t): Promise<{ status: number; response: Awaited<R> }>;\n\t(\n\t\tcontext: InputContext<Path, Options> & {\n\t\t\treturnHeaders: false;\n\t\t\treturnStatus: false;\n\t\t},\n\t): Promise<R>;\n\n\t// individual flag cases\n\t(\n\t\tcontext: InputContext<Path, Options> & { returnHeaders: true },\n\t): Promise<{ headers: Headers; response: Awaited<R> }>;\n\t(\n\t\tcontext: InputContext<Path, Options> & { returnStatus: true },\n\t): Promise<{ status: number; response: Awaited<R> }>;\n\n\t// default case\n\t(context?: InputContext<Path, Options>): Promise<R>;\n\n\toptions: Options;\n\tpath: Path;\n};\n\nexport type Endpoint<\n\tPath extends string = string,\n\tOptions extends EndpointOptions = EndpointOptions,\n\tHandler extends (inputCtx: any) => Promise<any> = (\n\t\tinputCtx: any,\n\t) => Promise<any>,\n> = Handler & {\n\toptions: Options;\n\tpath: Path;\n};\n"],"mappings":";;;;;AA+gBA,SAAgB,eAKf,eACA,kBACA,gBACuD;CACvD,MAAM,OACL,OAAO,kBAAkB,WAAW,gBAAgB,KAAA;CACrD,MAAM,UACL,OAAO,qBAAqB,WACzB,mBACC;CACL,MAAM,UACL,OAAO,qBAAqB,aAAa,mBAAmB;CAE7D,KAAK,QAAQ,WAAW,SAAS,QAAQ,WAAW,WAAW,QAAQ,MACtE,MAAM,IAAIA,cAAAA,gBAAgB,8CAA8C;CAGzE,IAAI,QAAQ,SAAS,KAAK,IAAI,GAC7B,MAAM,IAAIA,cAAAA,gBAAgB,yCAAyC;CA4BpE,MAAM,kBAAkB,OAKvB,GAAG,aAe+D;EAClE,MAAM,UAAW,SAAS,MAAM,CAAC;EACjC,MAAM,EAAE,MAAM,iBAAiB,OAAO,oBAAoB,MAAMC,cAAAA,SAC/DC,gBAAAA,sBAAsB,SAAS;GAC9B;GACA;EACD,CAAC,CACF;EAEA,IAAI,iBAAiB;GAEpB,IAAI,EAAE,2BAA2BC,cAAAA,kBAAkB,MAAM;GAGzD,IAAI,QAAQ,mBAEX,MAAM,QAAQ,kBAAkB;IAC/B,SAAS,gBAAgB;IACzB,QAAQ,gBAAgB;GACzB,CAAC;GAGF,MAAM,IAAIC,cAAAA,SAAS,KAAK;IACvB,SAAS,gBAAgB;IACzB,MAAM;GACP,CAAC;EACF;EACA,MAAM,WAAW,MAAM,QAAQ,eAAsB,CAAC,CAAC,MAAM,OAAO,MAAM;GACzE,IAAIC,cAAAA,WAAW,CAAC,GAAG;IAClB,MAAM,aAAa,QAAQ;IAC3B,IAAI,YACH,MAAM,WAAW,CAAC;IAEnB,IAAI,QAAQ,YACX,OAAO;GAET;GACA,MAAM;EACP,CAAC;EACD,MAAM,UAAU,gBAAgB;EAChC,MAAM,SAAS,gBAAgB;EAE/B,OACC,QAAQ,aACLC,oBAAAA,WAAW,UAAU;GACrB;GACA;EACD,CAAC,IACA,QAAQ,gBACP,QAAQ,eACP;GACA;GACA;GACA;EACD,IACC;GACA;GACA;EACD,IACA,QAAQ,eACP;GAAE;GAAU;EAAO,IACnB;CAEP;CACA,gBAAgB,UAAU;CAC1B,gBAAgB,OAAO;CACvB,OAAO;AAKR;AAEA,SAAS,kBACR,OACA,YACsB;CACtB,OAAO,CAAC,GAAI,SAAS,CAAC,GAAI,GAAI,cAAc,CAAC,CAAE;AAChD;AAEA,eAAe,UAAmD,SAAa;CAwB9E,SAAS,yBAKR,GAAG,MAUF;EACD,IAAI,KAAK,WAAW,GAAG;GACtB,MAAM,CAAC,MAAM,SAAS,WAAW;GACjC,OAAO,eACN,MACA;IACC,GAAG;IACH,KAAK,kBAAkB,QAAQ,KAAK,MAAM,GAAG;GAC9C,GACA,OACD;EACD;EAEA,MAAM,CAAC,SAAS,WAAW;EAC3B,OAAO,eACN;GACC,GAAG;GACH,KAAK,kBAAkB,QAAQ,KAAK,MAAM,GAAG;EAC9C,GACA,OACD;CACD;CAEA,OAAO;AACR"}
|
package/dist/endpoint.d.cts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CookieOptions, CookiePrefixOptions } from "./cookies.cjs";
|
|
2
2
|
import { StandardSchemaV1 } from "./standard-schema.cjs";
|
|
3
3
|
import { APIError, Status, statusCodes } from "./error.cjs";
|
|
4
|
-
import {
|
|
4
|
+
import { Prettify } from "./helper.cjs";
|
|
5
|
+
import { MiddlewareHandler } from "./middleware.cjs";
|
|
5
6
|
import { InferBody, InferHeaders, InferMethod, InferParam, InferQuery, InferRequest, InferUse, InputContext } from "./context.cjs";
|
|
6
|
-
import { Middleware } from "./middleware.cjs";
|
|
7
7
|
import { OpenAPIParameter, OpenAPISchemaType } from "./openapi.cjs";
|
|
8
|
-
|
|
9
8
|
//#region src/endpoint.d.ts
|
|
10
9
|
interface EndpointBaseOptions {
|
|
11
10
|
/**
|
|
@@ -163,7 +162,7 @@ interface EndpointBaseOptions {
|
|
|
163
162
|
/**
|
|
164
163
|
* List of middlewares to use
|
|
165
164
|
*/
|
|
166
|
-
use?:
|
|
165
|
+
use?: MiddlewareHandler[];
|
|
167
166
|
/**
|
|
168
167
|
* A callback to run before any API error is throw or returned
|
|
169
168
|
*
|
|
@@ -175,10 +174,7 @@ interface EndpointBaseOptions {
|
|
|
175
174
|
* A callback to run before a validation error is thrown
|
|
176
175
|
* You can customize the validation error message by throwing your own APIError
|
|
177
176
|
*/
|
|
178
|
-
onValidationError?: ({
|
|
179
|
-
issues,
|
|
180
|
-
message
|
|
181
|
-
}: {
|
|
177
|
+
onValidationError?: ({ issues, message }: {
|
|
182
178
|
message: string;
|
|
183
179
|
issues: readonly StandardSchemaV1.Issue[];
|
|
184
180
|
}) => void | Promise<void>;
|
|
@@ -221,7 +217,8 @@ type EndpointBodyMethodOptions = {
|
|
|
221
217
|
body?: StandardSchemaV1;
|
|
222
218
|
};
|
|
223
219
|
type EndpointOptions = EndpointBaseOptions & EndpointBodyMethodOptions;
|
|
224
|
-
type
|
|
220
|
+
type EndpointParams = Record<string, string | undefined> | undefined;
|
|
221
|
+
type EndpointContext<Path extends string, Options extends EndpointOptions, Context extends object = object, ResolvedParams extends EndpointParams = InferParam<Path>> = {
|
|
225
222
|
/**
|
|
226
223
|
* Method
|
|
227
224
|
*
|
|
@@ -252,11 +249,10 @@ type EndpointContext<Path extends string, Options extends EndpointOptions, Conte
|
|
|
252
249
|
* Params
|
|
253
250
|
*
|
|
254
251
|
* If the path is `/user/:id` and the request is `/user/1` then the params will
|
|
255
|
-
* be `{ id: "1" }
|
|
256
|
-
*
|
|
257
|
-
* is named like `/user/**:name` then the params will be `{ name: string }`
|
|
252
|
+
* be `{ id: "1" }`. An unnamed wildcard like `/user/*` uses a numeric key,
|
|
253
|
+
* while a named catch-all like `/user/**:path` uses its declared name.
|
|
258
254
|
*/
|
|
259
|
-
params:
|
|
255
|
+
params: ResolvedParams;
|
|
260
256
|
/**
|
|
261
257
|
* Request object
|
|
262
258
|
*
|
|
@@ -426,15 +422,21 @@ type ExtractOthers<E extends EndpointOptions> = Pick<E, Exclude<keyof E, "method
|
|
|
426
422
|
* DO NOT EXPORT THIS TYPE
|
|
427
423
|
*/
|
|
428
424
|
type ExtractStandSchema<E extends EndpointOptions> = ExtractOthers<E> & ExtractBody<E> & ExtractQuery<E> & ExtractError<E>;
|
|
429
|
-
type EndpointHandler<Path extends string, Options extends EndpointOptions, R> = (context: EndpointContext<Path, Options>) => Promise<R>;
|
|
425
|
+
type EndpointHandler<Path extends string, Options extends EndpointOptions, R, Context extends object = object> = (context: EndpointContext<Path, Options, Context>) => Promise<R>;
|
|
426
|
+
type PathlessEndpointHandler<Options extends EndpointOptions, R, Context extends object = object> = EndpointHandler<string, Options, R, Context>;
|
|
430
427
|
declare function createEndpoint<Path extends string, Options extends EndpointOptions, R>(path: Path, options: Options, handler: EndpointHandler<Path, Options, R>): StrictEndpoint<Path, ExtractStandSchema<Options>, R>;
|
|
431
|
-
declare function createEndpoint<Options extends EndpointOptions, R>(options: Options, handler:
|
|
428
|
+
declare function createEndpoint<Options extends EndpointOptions, R>(options: Options, handler: PathlessEndpointHandler<Options, R>): StrictEndpoint<never, ExtractStandSchema<Options>, R>;
|
|
432
429
|
declare namespace createEndpoint {
|
|
433
430
|
var create: <E extends {
|
|
434
|
-
use?:
|
|
435
|
-
}>(opts?: E) =>
|
|
436
|
-
|
|
437
|
-
|
|
431
|
+
use?: MiddlewareHandler[];
|
|
432
|
+
}>(opts?: E) => {
|
|
433
|
+
<Path extends string, Opts extends EndpointOptions, R>(path: Path, options: Opts, handler: EndpointHandler<Path, Opts, R, InferUse<E["use"]>>): StrictEndpoint<Path, ExtractStandSchema<Opts & {
|
|
434
|
+
use: MiddlewareHandler[];
|
|
435
|
+
}>, R>;
|
|
436
|
+
<Opts_1 extends EndpointOptions, R_1>(options: Opts_1, handler: PathlessEndpointHandler<Opts_1, R_1, InferUse<E["use"]>>): StrictEndpoint<never, ExtractStandSchema<Opts_1 & {
|
|
437
|
+
use: MiddlewareHandler[];
|
|
438
|
+
}>, R_1>;
|
|
439
|
+
};
|
|
438
440
|
}
|
|
439
441
|
type StrictEndpoint<Path extends string, Options extends EndpointOptions, R = any> = {
|
|
440
442
|
(context: InputContext<Path, Options> & {
|
package/dist/endpoint.d.mts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CookieOptions, CookiePrefixOptions } from "./cookies.mjs";
|
|
2
2
|
import { StandardSchemaV1 } from "./standard-schema.mjs";
|
|
3
3
|
import { APIError, Status, statusCodes } from "./error.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { Prettify } from "./helper.mjs";
|
|
5
|
+
import { MiddlewareHandler } from "./middleware.mjs";
|
|
5
6
|
import { InferBody, InferHeaders, InferMethod, InferParam, InferQuery, InferRequest, InferUse, InputContext } from "./context.mjs";
|
|
6
|
-
import { Middleware } from "./middleware.mjs";
|
|
7
7
|
import { OpenAPIParameter, OpenAPISchemaType } from "./openapi.mjs";
|
|
8
|
-
|
|
9
8
|
//#region src/endpoint.d.ts
|
|
10
9
|
interface EndpointBaseOptions {
|
|
11
10
|
/**
|
|
@@ -163,7 +162,7 @@ interface EndpointBaseOptions {
|
|
|
163
162
|
/**
|
|
164
163
|
* List of middlewares to use
|
|
165
164
|
*/
|
|
166
|
-
use?:
|
|
165
|
+
use?: MiddlewareHandler[];
|
|
167
166
|
/**
|
|
168
167
|
* A callback to run before any API error is throw or returned
|
|
169
168
|
*
|
|
@@ -175,10 +174,7 @@ interface EndpointBaseOptions {
|
|
|
175
174
|
* A callback to run before a validation error is thrown
|
|
176
175
|
* You can customize the validation error message by throwing your own APIError
|
|
177
176
|
*/
|
|
178
|
-
onValidationError?: ({
|
|
179
|
-
issues,
|
|
180
|
-
message
|
|
181
|
-
}: {
|
|
177
|
+
onValidationError?: ({ issues, message }: {
|
|
182
178
|
message: string;
|
|
183
179
|
issues: readonly StandardSchemaV1.Issue[];
|
|
184
180
|
}) => void | Promise<void>;
|
|
@@ -221,7 +217,8 @@ type EndpointBodyMethodOptions = {
|
|
|
221
217
|
body?: StandardSchemaV1;
|
|
222
218
|
};
|
|
223
219
|
type EndpointOptions = EndpointBaseOptions & EndpointBodyMethodOptions;
|
|
224
|
-
type
|
|
220
|
+
type EndpointParams = Record<string, string | undefined> | undefined;
|
|
221
|
+
type EndpointContext<Path extends string, Options extends EndpointOptions, Context extends object = object, ResolvedParams extends EndpointParams = InferParam<Path>> = {
|
|
225
222
|
/**
|
|
226
223
|
* Method
|
|
227
224
|
*
|
|
@@ -252,11 +249,10 @@ type EndpointContext<Path extends string, Options extends EndpointOptions, Conte
|
|
|
252
249
|
* Params
|
|
253
250
|
*
|
|
254
251
|
* If the path is `/user/:id` and the request is `/user/1` then the params will
|
|
255
|
-
* be `{ id: "1" }
|
|
256
|
-
*
|
|
257
|
-
* is named like `/user/**:name` then the params will be `{ name: string }`
|
|
252
|
+
* be `{ id: "1" }`. An unnamed wildcard like `/user/*` uses a numeric key,
|
|
253
|
+
* while a named catch-all like `/user/**:path` uses its declared name.
|
|
258
254
|
*/
|
|
259
|
-
params:
|
|
255
|
+
params: ResolvedParams;
|
|
260
256
|
/**
|
|
261
257
|
* Request object
|
|
262
258
|
*
|
|
@@ -426,15 +422,21 @@ type ExtractOthers<E extends EndpointOptions> = Pick<E, Exclude<keyof E, "method
|
|
|
426
422
|
* DO NOT EXPORT THIS TYPE
|
|
427
423
|
*/
|
|
428
424
|
type ExtractStandSchema<E extends EndpointOptions> = ExtractOthers<E> & ExtractBody<E> & ExtractQuery<E> & ExtractError<E>;
|
|
429
|
-
type EndpointHandler<Path extends string, Options extends EndpointOptions, R> = (context: EndpointContext<Path, Options>) => Promise<R>;
|
|
425
|
+
type EndpointHandler<Path extends string, Options extends EndpointOptions, R, Context extends object = object> = (context: EndpointContext<Path, Options, Context>) => Promise<R>;
|
|
426
|
+
type PathlessEndpointHandler<Options extends EndpointOptions, R, Context extends object = object> = EndpointHandler<string, Options, R, Context>;
|
|
430
427
|
declare function createEndpoint<Path extends string, Options extends EndpointOptions, R>(path: Path, options: Options, handler: EndpointHandler<Path, Options, R>): StrictEndpoint<Path, ExtractStandSchema<Options>, R>;
|
|
431
|
-
declare function createEndpoint<Options extends EndpointOptions, R>(options: Options, handler:
|
|
428
|
+
declare function createEndpoint<Options extends EndpointOptions, R>(options: Options, handler: PathlessEndpointHandler<Options, R>): StrictEndpoint<never, ExtractStandSchema<Options>, R>;
|
|
432
429
|
declare namespace createEndpoint {
|
|
433
430
|
var create: <E extends {
|
|
434
|
-
use?:
|
|
435
|
-
}>(opts?: E) =>
|
|
436
|
-
|
|
437
|
-
|
|
431
|
+
use?: MiddlewareHandler[];
|
|
432
|
+
}>(opts?: E) => {
|
|
433
|
+
<Path extends string, Opts extends EndpointOptions, R>(path: Path, options: Opts, handler: EndpointHandler<Path, Opts, R, InferUse<E["use"]>>): StrictEndpoint<Path, ExtractStandSchema<Opts & {
|
|
434
|
+
use: MiddlewareHandler[];
|
|
435
|
+
}>, R>;
|
|
436
|
+
<Opts_1 extends EndpointOptions, R_1>(options: Opts_1, handler: PathlessEndpointHandler<Opts_1, R_1, InferUse<E["use"]>>): StrictEndpoint<never, ExtractStandSchema<Opts_1 & {
|
|
437
|
+
use: MiddlewareHandler[];
|
|
438
|
+
}>, R_1>;
|
|
439
|
+
};
|
|
438
440
|
}
|
|
439
441
|
type StrictEndpoint<Path extends string, Options extends EndpointOptions, R = any> = {
|
|
440
442
|
(context: InputContext<Path, Options> & {
|
package/dist/endpoint.mjs
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { APIError, BetterCallError, ValidationError } from "./error.mjs";
|
|
2
2
|
import { isAPIError, tryCatch } from "./utils.mjs";
|
|
3
|
-
import { toResponse } from "./to-response.mjs";
|
|
4
3
|
import { createInternalContext } from "./context.mjs";
|
|
5
|
-
|
|
4
|
+
import { toResponse } from "./to-response.mjs";
|
|
6
5
|
//#region src/endpoint.ts
|
|
7
6
|
function createEndpoint(pathOrOptions, handlerOrOptions, handlerOrNever) {
|
|
8
7
|
const path = typeof pathOrOptions === "string" ? pathOrOptions : void 0;
|
|
@@ -56,15 +55,27 @@ function createEndpoint(pathOrOptions, handlerOrOptions, handlerOrNever) {
|
|
|
56
55
|
internalHandler.path = path;
|
|
57
56
|
return internalHandler;
|
|
58
57
|
}
|
|
58
|
+
function combineMiddleware(local, configured) {
|
|
59
|
+
return [...local ?? [], ...configured ?? []];
|
|
60
|
+
}
|
|
59
61
|
createEndpoint.create = (opts) => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
function createConfiguredEndpoint(...args) {
|
|
63
|
+
if (args.length === 3) {
|
|
64
|
+
const [path, options, handler] = args;
|
|
65
|
+
return createEndpoint(path, {
|
|
66
|
+
...options,
|
|
67
|
+
use: combineMiddleware(options.use, opts?.use)
|
|
68
|
+
}, handler);
|
|
69
|
+
}
|
|
70
|
+
const [options, handler] = args;
|
|
71
|
+
return createEndpoint({
|
|
62
72
|
...options,
|
|
63
|
-
use:
|
|
73
|
+
use: combineMiddleware(options.use, opts?.use)
|
|
64
74
|
}, handler);
|
|
65
|
-
}
|
|
75
|
+
}
|
|
76
|
+
return createConfiguredEndpoint;
|
|
66
77
|
};
|
|
67
|
-
|
|
68
78
|
//#endregion
|
|
69
79
|
export { createEndpoint };
|
|
80
|
+
|
|
70
81
|
//# sourceMappingURL=endpoint.mjs.map
|
package/dist/endpoint.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"endpoint.mjs","names":[],"sources":["../src/endpoint.ts"],"sourcesContent":["import type { HasRequiredKeys, Prettify } from \"./helper\";\nimport { toResponse } from \"./to-response\";\nimport type { Middleware } from \"./middleware\";\nimport {\n\tcreateInternalContext,\n\ttype InferBody,\n\ttype InferHeaders,\n\ttype InferMethod,\n\ttype InferParam,\n\ttype InferQuery,\n\ttype InferRequest,\n\ttype InferUse,\n\ttype InputContext,\n\ttype Method,\n} from \"./context\";\nimport type { CookieOptions, CookiePrefixOptions } from \"./cookies\";\nimport {\n\tAPIError,\n\tValidationError,\n\ttype statusCodes,\n\ttype Status,\n\tBetterCallError,\n} from \"./error\";\nimport type { OpenAPIParameter, OpenAPISchemaType } from \"./openapi\";\nimport type { StandardSchemaV1 } from \"./standard-schema\";\nimport { isAPIError, tryCatch } from \"./utils\";\n\nexport interface EndpointBaseOptions {\n\t/**\n\t * Query Schema\n\t */\n\tquery?: StandardSchemaV1;\n\t/**\n\t * Error Schema\n\t */\n\terror?: StandardSchemaV1;\n\t/**\n\t * If true headers will be required to be passed in the context\n\t */\n\trequireHeaders?: boolean;\n\t/**\n\t * If true request object will be required\n\t */\n\trequireRequest?: boolean;\n\t/**\n\t * Clone the request object from the router\n\t */\n\tcloneRequest?: boolean;\n\t/**\n\t * If true the body will be undefined\n\t */\n\tdisableBody?: boolean;\n\t/**\n\t * Endpoint metadata\n\t */\n\tmetadata?: {\n\t\t/**\n\t\t * Open API definition\n\t\t */\n\t\topenapi?: {\n\t\t\tsummary?: string;\n\t\t\tdescription?: string;\n\t\t\ttags?: string[];\n\t\t\toperationId?: string;\n\t\t\tparameters?: OpenAPIParameter[];\n\t\t\trequestBody?: {\n\t\t\t\tcontent: {\n\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\ttype?: OpenAPISchemaType;\n\t\t\t\t\t\t\tproperties?: Record<string, any>;\n\t\t\t\t\t\t\trequired?: string[];\n\t\t\t\t\t\t\t$ref?: string;\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tresponses?: {\n\t\t\t\t[status: string]: {\n\t\t\t\t\tdescription: string;\n\t\t\t\t\tcontent?: {\n\t\t\t\t\t\t\"application/json\"?: {\n\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\ttype?: OpenAPISchemaType;\n\t\t\t\t\t\t\t\tproperties?: Record<string, any>;\n\t\t\t\t\t\t\t\trequired?: string[];\n\t\t\t\t\t\t\t\t$ref?: string;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t\t\"text/plain\"?: {\n\t\t\t\t\t\t\tschema?: {\n\t\t\t\t\t\t\t\ttype?: OpenAPISchemaType;\n\t\t\t\t\t\t\t\tproperties?: Record<string, any>;\n\t\t\t\t\t\t\t\trequired?: string[];\n\t\t\t\t\t\t\t\t$ref?: string;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t\t\"text/html\"?: {\n\t\t\t\t\t\t\tschema?: {\n\t\t\t\t\t\t\t\ttype?: OpenAPISchemaType;\n\t\t\t\t\t\t\t\tproperties?: Record<string, any>;\n\t\t\t\t\t\t\t\trequired?: string[];\n\t\t\t\t\t\t\t\t$ref?: string;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t};\n\t\t/**\n\t\t * Infer body and query type from ts interface\n\t\t *\n\t\t * useful for generic and dynamic types\n\t\t *\n\t\t * @example\n\t\t * ```ts\n\t\t * const endpoint = createEndpoint(\"/path\", {\n\t\t * \t\tmethod: \"POST\",\n\t\t * \t\tbody: z.record(z.string()),\n\t\t * \t\t$Infer: {\n\t\t * \t\t\tbody: {} as {\n\t\t * \t\t\t\ttype: InferTypeFromOptions<Option> // custom type inference\n\t\t * \t\t\t}\n\t\t * \t\t}\n\t\t * \t}, async(ctx)=>{\n\t\t * \t\tconst body = ctx.body\n\t\t * \t})\n\t\t * ```\n\t\t */\n\t\t$Infer?: {\n\t\t\t/**\n\t\t\t * Body\n\t\t\t */\n\t\t\tbody?: any;\n\t\t\t/**\n\t\t\t * Query\n\t\t\t */\n\t\t\tquery?: Record<string, any>;\n\t\t};\n\t\t/**\n\t\t * If enabled, endpoint won't be exposed over a router\n\t\t * @deprecated Use path-less endpoints instead\n\t\t */\n\t\tSERVER_ONLY?: boolean;\n\t\t/**\n\t\t * If enabled, endpoint won't be exposed as an action to the client\n\t\t * @deprecated Use path-less endpoints instead\n\t\t */\n\t\tisAction?: boolean;\n\t\t/**\n\t\t * Defines the places where the endpoint will be available\n\t\t *\n\t\t * Possible options:\n\t\t * - `rpc` - the endpoint is exposed to the router, can be invoked directly and is available to the client\n\t\t * - `server` - the endpoint is exposed to the router, can be invoked directly, but is not available to the client\n\t\t * - `http` - the endpoint is only exposed to the router\n\t\t * @default \"rpc\"\n\t\t */\n\t\tscope?: \"rpc\" | \"server\" | \"http\";\n\t\t/**\n\t\t * List of allowed media types (MIME types) for the endpoint\n\t\t *\n\t\t * if provided, only the media types in the list will be allowed to be passed in the body\n\t\t *\n\t\t * @example\n\t\t * ```ts\n\t\t * const endpoint = createEndpoint(\"/path\", {\n\t\t * \t\tmethod: \"POST\",\n\t\t * \t\tallowedMediaTypes: [\"application/json\", \"application/x-www-form-urlencoded\"],\n\t\t * \t}, async(ctx)=>{\n\t\t * \t\tconst body = ctx.body\n\t\t * \t})\n\t\t * ```\n\t\t */\n\t\tallowedMediaTypes?: string[];\n\t\t/**\n\t\t * Extra metadata\n\t\t */\n\t\t[key: string]: any;\n\t};\n\t/**\n\t * List of middlewares to use\n\t */\n\tuse?: Middleware[];\n\t/**\n\t * A callback to run before any API error is throw or returned\n\t *\n\t * @param e - The API error\n\t * @returns - The response to return\n\t */\n\tonAPIError?: (e: APIError) => void | Promise<void>;\n\t/**\n\t * A callback to run before a validation error is thrown\n\t * You can customize the validation error message by throwing your own APIError\n\t */\n\tonValidationError?: ({\n\t\tissues,\n\t\tmessage,\n\t}: {\n\t\tmessage: string;\n\t\tissues: readonly StandardSchemaV1.Issue[];\n\t}) => void | Promise<void>;\n}\n\nexport type EndpointBodyMethodOptions =\n\t| {\n\t\t\t/**\n\t\t\t * Request Method\n\t\t\t */\n\t\t\tmethod:\n\t\t\t\t| \"POST\"\n\t\t\t\t| \"PUT\"\n\t\t\t\t| \"DELETE\"\n\t\t\t\t| \"PATCH\"\n\t\t\t\t| (\"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\")[];\n\t\t\t/**\n\t\t\t * Body Schema\n\t\t\t */\n\t\t\tbody?: StandardSchemaV1;\n\t }\n\t| {\n\t\t\t/**\n\t\t\t * Request Method\n\t\t\t */\n\t\t\tmethod: \"GET\" | \"HEAD\" | (\"GET\" | \"HEAD\")[];\n\t\t\t/**\n\t\t\t * Body Schema\n\t\t\t */\n\t\t\tbody?: never;\n\t }\n\t| {\n\t\t\t/**\n\t\t\t * Request Method\n\t\t\t */\n\t\t\tmethod: \"*\";\n\t\t\t/**\n\t\t\t * Body Schema\n\t\t\t */\n\t\t\tbody?: StandardSchemaV1;\n\t }\n\t| {\n\t\t\t/**\n\t\t\t * Request Method\n\t\t\t */\n\t\t\tmethod: (\"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\" | \"GET\" | \"HEAD\")[];\n\t\t\t/**\n\t\t\t * Body Schema\n\t\t\t */\n\t\t\tbody?: StandardSchemaV1;\n\t };\n\nexport type EndpointOptions = EndpointBaseOptions & EndpointBodyMethodOptions;\n\nexport type EndpointContext<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n\tContext = {},\n> = {\n\t/**\n\t * Method\n\t *\n\t * The request method\n\t */\n\tmethod: InferMethod<Options>;\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: InferBody<Options>;\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: InferQuery<Options>;\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: InferRequest<Options>;\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: InferHeaders<Options>;\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 * @returns\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\n\t * the correct headers\n\t * and status code. If `asResponse` is set to true in\n\t * the context then\n\t * it will return a Response object instead of the\n\t * JSON object.\n\t *\n\t * @param json - The JSON object to return\n\t * @param routerResponse - The response object to\n\t * 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, string>;\n\t\t\t }\n\t\t\t| Response,\n\t) => Promise<R>;\n\t/**\n\t * Middleware context\n\t */\n\tcontext: Prettify<Context & InferUse<Options[\"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\ntype ExtractBody<E extends EndpointBodyMethodOptions> = E extends {\n\tmethod: (\"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\" | \"GET\" | \"HEAD\")[];\n\tbody?: StandardSchemaV1<infer B>;\n}\n\t? E extends {\n\t\t\tmethod: infer M;\n\t\t\tbody?: StandardSchemaV1<B>;\n\t\t}\n\t\t? { method: M; body: StandardSchemaV1<B> }\n\t\t: never\n\t: E extends {\n\t\t\t\tmethod:\n\t\t\t\t\t| \"POST\"\n\t\t\t\t\t| \"PUT\"\n\t\t\t\t\t| \"DELETE\"\n\t\t\t\t\t| \"PATCH\"\n\t\t\t\t\t| (\"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\")[];\n\t\t\t\tbody?: StandardSchemaV1<infer B>;\n\t\t\t}\n\t\t? E extends {\n\t\t\t\tmethod: infer M;\n\t\t\t\tbody?: StandardSchemaV1<B>;\n\t\t\t}\n\t\t\t? { method: M; body: StandardSchemaV1<B> }\n\t\t\t: never\n\t\t: E extends {\n\t\t\t\t\tmethod: \"*\";\n\t\t\t\t\tbody?: StandardSchemaV1<infer B>;\n\t\t\t\t}\n\t\t\t? {\n\t\t\t\t\tmethod: \"*\";\n\t\t\t\t\tbody?: StandardSchemaV1<B>;\n\t\t\t\t}\n\t\t\t: E extends {\n\t\t\t\t\t\tmethod: \"GET\" | \"HEAD\" | (\"GET\" | \"HEAD\")[];\n\t\t\t\t\t\tbody?: never;\n\t\t\t\t\t}\n\t\t\t\t? E extends { method: infer M }\n\t\t\t\t\t? { method: M }\n\t\t\t\t\t: never\n\t\t\t\t: never;\ntype ExtractError<E extends EndpointOptions> = E extends {\n\terror?: StandardSchemaV1<infer Err>;\n}\n\t? {\n\t\t\terror: StandardSchemaV1<Err>;\n\t\t}\n\t: {};\ntype ExtractQuery<E extends EndpointOptions> = E extends {\n\tquery?: StandardSchemaV1<infer Q>;\n}\n\t? {\n\t\t\tquery: StandardSchemaV1<Q>;\n\t\t}\n\t: {};\n\ntype ExtractOthers<E extends EndpointOptions> = Pick<\n\tE,\n\tExclude<keyof E, \"method\" | \"body\" | \"query\" | \"error\">\n>;\n\n/**\n * DO NOT EXPORT THIS TYPE\n */\ntype ExtractStandSchema<E extends EndpointOptions> = ExtractOthers<E> &\n\tExtractBody<E> &\n\tExtractQuery<E> &\n\tExtractError<E>;\n\nexport type EndpointHandler<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n\tR,\n> = (context: EndpointContext<Path, Options>) => Promise<R>;\n\nexport function createEndpoint<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n\tR,\n>(\n\tpath: Path,\n\toptions: Options,\n\thandler: EndpointHandler<Path, Options, R>,\n): StrictEndpoint<Path, ExtractStandSchema<Options>, R>;\n\nexport function createEndpoint<Options extends EndpointOptions, R>(\n\toptions: Options,\n\thandler: EndpointHandler<never, Options, R>,\n): StrictEndpoint<never, ExtractStandSchema<Options>, R>;\n\nexport function createEndpoint<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n\tR,\n>(\n\tpathOrOptions: Path | Options,\n\thandlerOrOptions: EndpointHandler<Path, Options, R> | Options,\n\thandlerOrNever?: any,\n): StrictEndpoint<Path, ExtractStandSchema<Options>, R> {\n\tconst path: string | undefined =\n\t\ttypeof pathOrOptions === \"string\" ? pathOrOptions : undefined;\n\tconst options: Options =\n\t\ttypeof handlerOrOptions === \"object\"\n\t\t\t? handlerOrOptions\n\t\t\t: (pathOrOptions as Options);\n\tconst handler: EndpointHandler<Path, Options, R> =\n\t\ttypeof handlerOrOptions === \"function\" ? handlerOrOptions : handlerOrNever;\n\n\tif ((options.method === \"GET\" || options.method === \"HEAD\") && options.body) {\n\t\tthrow new BetterCallError(\"Body is not allowed with GET or HEAD methods\");\n\t}\n\n\tif (path && /\\/{2,}/.test(path)) {\n\t\tthrow new BetterCallError(\"Path cannot contain consecutive slashes\");\n\t}\n\ttype Context = InputContext<Path, Options>;\n\n\ttype ResultType<\n\t\tAsResponse extends boolean,\n\t\tReturnHeaders extends boolean,\n\t\tReturnStatus extends boolean,\n\t> = AsResponse extends true\n\t\t? Response\n\t\t: ReturnHeaders extends true\n\t\t\t? ReturnStatus extends true\n\t\t\t\t? {\n\t\t\t\t\t\theaders: Headers;\n\t\t\t\t\t\tstatus: number;\n\t\t\t\t\t\tresponse: Awaited<R>;\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\theaders: Headers;\n\t\t\t\t\t\tresponse: Awaited<R>;\n\t\t\t\t\t}\n\t\t\t: ReturnStatus extends true\n\t\t\t\t? {\n\t\t\t\t\t\tstatus: number;\n\t\t\t\t\t\tresponse: Awaited<R>;\n\t\t\t\t\t}\n\t\t\t\t: Awaited<R>;\n\n\tconst internalHandler = async <\n\t\tAsResponse extends boolean = false,\n\t\tReturnHeaders extends boolean = false,\n\t\tReturnStatus extends boolean = false,\n\t>(\n\t\t...inputCtx: HasRequiredKeys<Context> extends true\n\t\t\t? [\n\t\t\t\t\tContext & {\n\t\t\t\t\t\tasResponse?: AsResponse;\n\t\t\t\t\t\treturnHeaders?: ReturnHeaders;\n\t\t\t\t\t\treturnStatus?: ReturnStatus;\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t: [\n\t\t\t\t\t(Context & {\n\t\t\t\t\t\tasResponse?: AsResponse;\n\t\t\t\t\t\treturnHeaders?: ReturnHeaders;\n\t\t\t\t\t\treturnStatus?: ReturnStatus;\n\t\t\t\t\t})?,\n\t\t\t\t]\n\t): Promise<ResultType<AsResponse, ReturnHeaders, ReturnStatus>> => {\n\t\tconst context = (inputCtx[0] || {}) as InputContext<any, any>;\n\t\tconst { data: internalContext, error: validationError } = await tryCatch(\n\t\t\tcreateInternalContext(context, {\n\t\t\t\toptions,\n\t\t\t\tpath,\n\t\t\t}),\n\t\t);\n\n\t\tif (validationError) {\n\t\t\t// If it's not a validation error, we throw it\n\t\t\tif (!(validationError instanceof ValidationError)) throw validationError;\n\n\t\t\t// Check if the endpoint has a custom onValidationError callback\n\t\t\tif (options.onValidationError) {\n\t\t\t\t// This can possibly throw an APIError in order to customize the validation error message\n\t\t\t\tawait options.onValidationError({\n\t\t\t\t\tmessage: validationError.message,\n\t\t\t\t\tissues: validationError.issues,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tthrow new APIError(400, {\n\t\t\t\tmessage: validationError.message,\n\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t});\n\t\t}\n\t\tconst response = await handler(internalContext as any).catch(async (e) => {\n\t\t\tif (isAPIError(e)) {\n\t\t\t\tconst onAPIError = options.onAPIError;\n\t\t\t\tif (onAPIError) {\n\t\t\t\t\tawait onAPIError(e);\n\t\t\t\t}\n\t\t\t\tif (context.asResponse) {\n\t\t\t\t\treturn e;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow e;\n\t\t});\n\t\tconst headers = internalContext.responseHeaders;\n\t\tconst status = internalContext.responseStatus;\n\n\t\treturn (\n\t\t\tcontext.asResponse\n\t\t\t\t? toResponse(response, {\n\t\t\t\t\t\theaders,\n\t\t\t\t\t\tstatus,\n\t\t\t\t\t})\n\t\t\t\t: context.returnHeaders\n\t\t\t\t\t? context.returnStatus\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\theaders,\n\t\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t\t\tstatus,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\theaders,\n\t\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t: context.returnStatus\n\t\t\t\t\t\t? { response, status }\n\t\t\t\t\t\t: response\n\t\t) as ResultType<AsResponse, ReturnHeaders, ReturnStatus>;\n\t};\n\tinternalHandler.options = options;\n\tinternalHandler.path = path;\n\treturn internalHandler as unknown as StrictEndpoint<\n\t\tPath,\n\t\tExtractStandSchema<Options>,\n\t\tR\n\t>;\n}\n\ncreateEndpoint.create = <E extends { use?: Middleware[] }>(opts?: E) => {\n\treturn <\n\t\tPath extends string,\n\t\tOpts extends EndpointOptions,\n\t\tR extends Promise<any>,\n\t>(\n\t\tpath: Path,\n\t\toptions: Opts,\n\t\thandler: (ctx: EndpointContext<Path, Opts, InferUse<E[\"use\"]>>) => R,\n\t) => {\n\t\treturn createEndpoint(\n\t\t\tpath,\n\t\t\t{\n\t\t\t\t...options,\n\t\t\t\tuse: [...(options?.use || []), ...(opts?.use || [])],\n\t\t\t},\n\t\t\thandler,\n\t\t);\n\t};\n};\n\nexport type StrictEndpoint<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n\tR = any,\n> = {\n\t// asResponse cases\n\t(\n\t\tcontext: InputContext<Path, Options> & { asResponse: true },\n\t): Promise<Response>;\n\n\t// returnHeaders & returnStatus cases\n\t(\n\t\tcontext: InputContext<Path, Options> & {\n\t\t\treturnHeaders: true;\n\t\t\treturnStatus: true;\n\t\t},\n\t): Promise<{ headers: Headers; status: number; response: Awaited<R> }>;\n\t(\n\t\tcontext: InputContext<Path, Options> & {\n\t\t\treturnHeaders: true;\n\t\t\treturnStatus: false;\n\t\t},\n\t): Promise<{ headers: Headers; response: Awaited<R> }>;\n\t(\n\t\tcontext: InputContext<Path, Options> & {\n\t\t\treturnHeaders: false;\n\t\t\treturnStatus: true;\n\t\t},\n\t): Promise<{ status: number; response: Awaited<R> }>;\n\t(\n\t\tcontext: InputContext<Path, Options> & {\n\t\t\treturnHeaders: false;\n\t\t\treturnStatus: false;\n\t\t},\n\t): Promise<R>;\n\n\t// individual flag cases\n\t(\n\t\tcontext: InputContext<Path, Options> & { returnHeaders: true },\n\t): Promise<{ headers: Headers; response: Awaited<R> }>;\n\t(\n\t\tcontext: InputContext<Path, Options> & { returnStatus: true },\n\t): Promise<{ status: number; response: Awaited<R> }>;\n\n\t// default case\n\t(context?: InputContext<Path, Options>): Promise<R>;\n\n\toptions: Options;\n\tpath: Path;\n};\n\nexport type Endpoint<\n\tPath extends string = string,\n\tOptions extends EndpointOptions = EndpointOptions,\n\tHandler extends (inputCtx: any) => Promise<any> = (\n\t\tinputCtx: any,\n\t) => Promise<any>,\n> = Handler & {\n\toptions: Options;\n\tpath: Path;\n};\n"],"mappings":";;;;;;AA4gBA,SAAgB,eAKf,eACA,kBACA,gBACuD;CACvD,MAAM,OACL,OAAO,kBAAkB,WAAW,gBAAgB;CACrD,MAAM,UACL,OAAO,qBAAqB,WACzB,mBACC;CACL,MAAM,UACL,OAAO,qBAAqB,aAAa,mBAAmB;AAE7D,MAAK,QAAQ,WAAW,SAAS,QAAQ,WAAW,WAAW,QAAQ,KACtE,OAAM,IAAI,gBAAgB,+CAA+C;AAG1E,KAAI,QAAQ,SAAS,KAAK,KAAK,CAC9B,OAAM,IAAI,gBAAgB,0CAA0C;CA4BrE,MAAM,kBAAkB,OAKvB,GAAG,aAe+D;EAClE,MAAM,UAAW,SAAS,MAAM,EAAE;EAClC,MAAM,EAAE,MAAM,iBAAiB,OAAO,oBAAoB,MAAM,SAC/D,sBAAsB,SAAS;GAC9B;GACA;GACA,CAAC,CACF;AAED,MAAI,iBAAiB;AAEpB,OAAI,EAAE,2BAA2B,iBAAkB,OAAM;AAGzD,OAAI,QAAQ,kBAEX,OAAM,QAAQ,kBAAkB;IAC/B,SAAS,gBAAgB;IACzB,QAAQ,gBAAgB;IACxB,CAAC;AAGH,SAAM,IAAI,SAAS,KAAK;IACvB,SAAS,gBAAgB;IACzB,MAAM;IACN,CAAC;;EAEH,MAAM,WAAW,MAAM,QAAQ,gBAAuB,CAAC,MAAM,OAAO,MAAM;AACzE,OAAI,WAAW,EAAE,EAAE;IAClB,MAAM,aAAa,QAAQ;AAC3B,QAAI,WACH,OAAM,WAAW,EAAE;AAEpB,QAAI,QAAQ,WACX,QAAO;;AAGT,SAAM;IACL;EACF,MAAM,UAAU,gBAAgB;EAChC,MAAM,SAAS,gBAAgB;AAE/B,SACC,QAAQ,aACL,WAAW,UAAU;GACrB;GACA;GACA,CAAC,GACD,QAAQ,gBACP,QAAQ,eACP;GACA;GACA;GACA;GACA,GACA;GACA;GACA;GACA,GACD,QAAQ,eACP;GAAE;GAAU;GAAQ,GACpB;;AAGP,iBAAgB,UAAU;AAC1B,iBAAgB,OAAO;AACvB,QAAO;;AAOR,eAAe,UAA4C,SAAa;AACvE,SAKC,MACA,SACA,YACI;AACJ,SAAO,eACN,MACA;GACC,GAAG;GACH,KAAK,CAAC,GAAI,SAAS,OAAO,EAAE,EAAG,GAAI,MAAM,OAAO,EAAE,CAAE;GACpD,EACD,QACA"}
|
|
1
|
+
{"version":3,"file":"endpoint.mjs","names":[],"sources":["../src/endpoint.ts"],"sourcesContent":["import type {\n\tInferBody,\n\tInferHeaders,\n\tInferMethod,\n\tInferParam,\n\tInferQuery,\n\tInferRequest,\n\tInferUse,\n\tInputContext,\n} from \"./context\";\nimport { createInternalContext } from \"./context\";\nimport type { CookieOptions, CookiePrefixOptions } from \"./cookies\";\nimport type { Status, statusCodes } from \"./error\";\nimport { APIError, BetterCallError, ValidationError } from \"./error\";\nimport type { HasRequiredKeys, Prettify } from \"./helper\";\nimport type { MiddlewareHandler } from \"./middleware\";\nimport type { OpenAPIParameter, OpenAPISchemaType } from \"./openapi\";\nimport type { StandardSchemaV1 } from \"./standard-schema\";\nimport { toResponse } from \"./to-response\";\nimport { isAPIError, tryCatch } from \"./utils\";\n\nexport interface EndpointBaseOptions {\n\t/**\n\t * Query Schema\n\t */\n\tquery?: StandardSchemaV1;\n\t/**\n\t * Error Schema\n\t */\n\terror?: StandardSchemaV1;\n\t/**\n\t * If true headers will be required to be passed in the context\n\t */\n\trequireHeaders?: boolean;\n\t/**\n\t * If true request object will be required\n\t */\n\trequireRequest?: boolean;\n\t/**\n\t * Clone the request object from the router\n\t */\n\tcloneRequest?: boolean;\n\t/**\n\t * If true the body will be undefined\n\t */\n\tdisableBody?: boolean;\n\t/**\n\t * Endpoint metadata\n\t */\n\tmetadata?: {\n\t\t/**\n\t\t * Open API definition\n\t\t */\n\t\topenapi?: {\n\t\t\tsummary?: string;\n\t\t\tdescription?: string;\n\t\t\ttags?: string[];\n\t\t\toperationId?: string;\n\t\t\tparameters?: OpenAPIParameter[];\n\t\t\trequestBody?: {\n\t\t\t\tcontent: {\n\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\ttype?: OpenAPISchemaType;\n\t\t\t\t\t\t\tproperties?: Record<string, any>;\n\t\t\t\t\t\t\trequired?: string[];\n\t\t\t\t\t\t\t$ref?: string;\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tresponses?: {\n\t\t\t\t[status: string]: {\n\t\t\t\t\tdescription: string;\n\t\t\t\t\tcontent?: {\n\t\t\t\t\t\t\"application/json\"?: {\n\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\ttype?: OpenAPISchemaType;\n\t\t\t\t\t\t\t\tproperties?: Record<string, any>;\n\t\t\t\t\t\t\t\trequired?: string[];\n\t\t\t\t\t\t\t\t$ref?: string;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t\t\"text/plain\"?: {\n\t\t\t\t\t\t\tschema?: {\n\t\t\t\t\t\t\t\ttype?: OpenAPISchemaType;\n\t\t\t\t\t\t\t\tproperties?: Record<string, any>;\n\t\t\t\t\t\t\t\trequired?: string[];\n\t\t\t\t\t\t\t\t$ref?: string;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t\t\"text/html\"?: {\n\t\t\t\t\t\t\tschema?: {\n\t\t\t\t\t\t\t\ttype?: OpenAPISchemaType;\n\t\t\t\t\t\t\t\tproperties?: Record<string, any>;\n\t\t\t\t\t\t\t\trequired?: string[];\n\t\t\t\t\t\t\t\t$ref?: string;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t};\n\t\t/**\n\t\t * Infer body and query type from ts interface\n\t\t *\n\t\t * useful for generic and dynamic types\n\t\t *\n\t\t * @example\n\t\t * ```ts\n\t\t * const endpoint = createEndpoint(\"/path\", {\n\t\t * \t\tmethod: \"POST\",\n\t\t * \t\tbody: z.record(z.string()),\n\t\t * \t\t$Infer: {\n\t\t * \t\t\tbody: {} as {\n\t\t * \t\t\t\ttype: InferTypeFromOptions<Option> // custom type inference\n\t\t * \t\t\t}\n\t\t * \t\t}\n\t\t * \t}, async(ctx)=>{\n\t\t * \t\tconst body = ctx.body\n\t\t * \t})\n\t\t * ```\n\t\t */\n\t\t$Infer?: {\n\t\t\t/**\n\t\t\t * Body\n\t\t\t */\n\t\t\tbody?: any;\n\t\t\t/**\n\t\t\t * Query\n\t\t\t */\n\t\t\tquery?: Record<string, any>;\n\t\t};\n\t\t/**\n\t\t * If enabled, endpoint won't be exposed over a router\n\t\t * @deprecated Use path-less endpoints instead\n\t\t */\n\t\tSERVER_ONLY?: boolean;\n\t\t/**\n\t\t * If enabled, endpoint won't be exposed as an action to the client\n\t\t * @deprecated Use path-less endpoints instead\n\t\t */\n\t\tisAction?: boolean;\n\t\t/**\n\t\t * Defines the places where the endpoint will be available\n\t\t *\n\t\t * Possible options:\n\t\t * - `rpc` - the endpoint is exposed to the router, can be invoked directly and is available to the client\n\t\t * - `server` - the endpoint is exposed to the router, can be invoked directly, but is not available to the client\n\t\t * - `http` - the endpoint is only exposed to the router\n\t\t * @default \"rpc\"\n\t\t */\n\t\tscope?: \"rpc\" | \"server\" | \"http\";\n\t\t/**\n\t\t * List of allowed media types (MIME types) for the endpoint\n\t\t *\n\t\t * if provided, only the media types in the list will be allowed to be passed in the body\n\t\t *\n\t\t * @example\n\t\t * ```ts\n\t\t * const endpoint = createEndpoint(\"/path\", {\n\t\t * \t\tmethod: \"POST\",\n\t\t * \t\tallowedMediaTypes: [\"application/json\", \"application/x-www-form-urlencoded\"],\n\t\t * \t}, async(ctx)=>{\n\t\t * \t\tconst body = ctx.body\n\t\t * \t})\n\t\t * ```\n\t\t */\n\t\tallowedMediaTypes?: string[];\n\t\t/**\n\t\t * Extra metadata\n\t\t */\n\t\t[key: string]: any;\n\t};\n\t/**\n\t * List of middlewares to use\n\t */\n\tuse?: MiddlewareHandler[];\n\t/**\n\t * A callback to run before any API error is throw or returned\n\t *\n\t * @param e - The API error\n\t * @returns - The response to return\n\t */\n\tonAPIError?: (e: APIError) => void | Promise<void>;\n\t/**\n\t * A callback to run before a validation error is thrown\n\t * You can customize the validation error message by throwing your own APIError\n\t */\n\tonValidationError?: ({\n\t\tissues,\n\t\tmessage,\n\t}: {\n\t\tmessage: string;\n\t\tissues: readonly StandardSchemaV1.Issue[];\n\t}) => void | Promise<void>;\n}\n\nexport type EndpointBodyMethodOptions =\n\t| {\n\t\t\t/**\n\t\t\t * Request Method\n\t\t\t */\n\t\t\tmethod:\n\t\t\t\t| \"POST\"\n\t\t\t\t| \"PUT\"\n\t\t\t\t| \"DELETE\"\n\t\t\t\t| \"PATCH\"\n\t\t\t\t| (\"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\")[];\n\t\t\t/**\n\t\t\t * Body Schema\n\t\t\t */\n\t\t\tbody?: StandardSchemaV1;\n\t }\n\t| {\n\t\t\t/**\n\t\t\t * Request Method\n\t\t\t */\n\t\t\tmethod: \"GET\" | \"HEAD\" | (\"GET\" | \"HEAD\")[];\n\t\t\t/**\n\t\t\t * Body Schema\n\t\t\t */\n\t\t\tbody?: never;\n\t }\n\t| {\n\t\t\t/**\n\t\t\t * Request Method\n\t\t\t */\n\t\t\tmethod: \"*\";\n\t\t\t/**\n\t\t\t * Body Schema\n\t\t\t */\n\t\t\tbody?: StandardSchemaV1;\n\t }\n\t| {\n\t\t\t/**\n\t\t\t * Request Method\n\t\t\t */\n\t\t\tmethod: (\"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\" | \"GET\" | \"HEAD\")[];\n\t\t\t/**\n\t\t\t * Body Schema\n\t\t\t */\n\t\t\tbody?: StandardSchemaV1;\n\t };\n\nexport type EndpointOptions = EndpointBaseOptions & EndpointBodyMethodOptions;\n\ntype EndpointParams = Record<string, string | undefined> | undefined;\n\nexport type EndpointContext<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n\tContext extends object = object,\n\tResolvedParams extends EndpointParams = InferParam<Path>,\n> = {\n\t/**\n\t * Method\n\t *\n\t * The request method\n\t */\n\tmethod: InferMethod<Options>;\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: InferBody<Options>;\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: InferQuery<Options>;\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\" }`. An unnamed wildcard like `/user/*` uses a numeric key,\n\t * while a named catch-all like `/user/**:path` uses its declared name.\n\t */\n\tparams: ResolvedParams;\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: InferRequest<Options>;\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: InferHeaders<Options>;\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 * @returns\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\n\t * the correct headers\n\t * and status code. If `asResponse` is set to true in\n\t * the context then\n\t * it will return a Response object instead of the\n\t * JSON object.\n\t *\n\t * @param json - The JSON object to return\n\t * @param routerResponse - The response object to\n\t * 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, string>;\n\t\t\t }\n\t\t\t| Response,\n\t) => Promise<R>;\n\t/**\n\t * Middleware context\n\t */\n\tcontext: Prettify<Context & InferUse<Options[\"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\ntype ExtractBody<E extends EndpointBodyMethodOptions> = E extends {\n\tmethod: (\"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\" | \"GET\" | \"HEAD\")[];\n\tbody?: StandardSchemaV1<infer B>;\n}\n\t? E extends {\n\t\t\tmethod: infer M;\n\t\t\tbody?: StandardSchemaV1<B>;\n\t\t}\n\t\t? { method: M; body: StandardSchemaV1<B> }\n\t\t: never\n\t: E extends {\n\t\t\t\tmethod:\n\t\t\t\t\t| \"POST\"\n\t\t\t\t\t| \"PUT\"\n\t\t\t\t\t| \"DELETE\"\n\t\t\t\t\t| \"PATCH\"\n\t\t\t\t\t| (\"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\")[];\n\t\t\t\tbody?: StandardSchemaV1<infer B>;\n\t\t\t}\n\t\t? E extends {\n\t\t\t\tmethod: infer M;\n\t\t\t\tbody?: StandardSchemaV1<B>;\n\t\t\t}\n\t\t\t? { method: M; body: StandardSchemaV1<B> }\n\t\t\t: never\n\t\t: E extends {\n\t\t\t\t\tmethod: \"*\";\n\t\t\t\t\tbody?: StandardSchemaV1<infer B>;\n\t\t\t\t}\n\t\t\t? {\n\t\t\t\t\tmethod: \"*\";\n\t\t\t\t\tbody?: StandardSchemaV1<B>;\n\t\t\t\t}\n\t\t\t: E extends {\n\t\t\t\t\t\tmethod: \"GET\" | \"HEAD\" | (\"GET\" | \"HEAD\")[];\n\t\t\t\t\t\tbody?: never;\n\t\t\t\t\t}\n\t\t\t\t? E extends { method: infer M }\n\t\t\t\t\t? { method: M }\n\t\t\t\t\t: never\n\t\t\t\t: never;\ntype ExtractError<E extends EndpointOptions> = E extends {\n\terror?: StandardSchemaV1<infer Err>;\n}\n\t? {\n\t\t\terror: StandardSchemaV1<Err>;\n\t\t}\n\t: {};\ntype ExtractQuery<E extends EndpointOptions> = E extends {\n\tquery?: StandardSchemaV1<infer Q>;\n}\n\t? {\n\t\t\tquery: StandardSchemaV1<Q>;\n\t\t}\n\t: {};\n\ntype ExtractOthers<E extends EndpointOptions> = Pick<\n\tE,\n\tExclude<keyof E, \"method\" | \"body\" | \"query\" | \"error\">\n>;\n\n/**\n * DO NOT EXPORT THIS TYPE\n */\ntype ExtractStandSchema<E extends EndpointOptions> = ExtractOthers<E> &\n\tExtractBody<E> &\n\tExtractQuery<E> &\n\tExtractError<E>;\n\nexport type EndpointHandler<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n\tR,\n\tContext extends object = object,\n> = (context: EndpointContext<Path, Options, Context>) => Promise<R>;\n\ntype PathlessEndpointHandler<\n\tOptions extends EndpointOptions,\n\tR,\n\tContext extends object = object,\n> = EndpointHandler<string, Options, R, Context>;\n\nexport function createEndpoint<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n\tR,\n>(\n\tpath: Path,\n\toptions: Options,\n\thandler: EndpointHandler<Path, Options, R>,\n): StrictEndpoint<Path, ExtractStandSchema<Options>, R>;\n\nexport function createEndpoint<Options extends EndpointOptions, R>(\n\toptions: Options,\n\thandler: PathlessEndpointHandler<Options, R>,\n): StrictEndpoint<never, ExtractStandSchema<Options>, R>;\n\nexport function createEndpoint<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n\tR,\n>(\n\tpathOrOptions: Path | Options,\n\thandlerOrOptions: EndpointHandler<Path, Options, R> | Options,\n\thandlerOrNever?: any,\n): StrictEndpoint<Path, ExtractStandSchema<Options>, R> {\n\tconst path: string | undefined =\n\t\ttypeof pathOrOptions === \"string\" ? pathOrOptions : undefined;\n\tconst options: Options =\n\t\ttypeof handlerOrOptions === \"object\"\n\t\t\t? handlerOrOptions\n\t\t\t: (pathOrOptions as Options);\n\tconst handler: EndpointHandler<Path, Options, R> =\n\t\ttypeof handlerOrOptions === \"function\" ? handlerOrOptions : handlerOrNever;\n\n\tif ((options.method === \"GET\" || options.method === \"HEAD\") && options.body) {\n\t\tthrow new BetterCallError(\"Body is not allowed with GET or HEAD methods\");\n\t}\n\n\tif (path && /\\/{2,}/.test(path)) {\n\t\tthrow new BetterCallError(\"Path cannot contain consecutive slashes\");\n\t}\n\ttype Context = InputContext<Path, Options>;\n\n\ttype ResultType<\n\t\tAsResponse extends boolean,\n\t\tReturnHeaders extends boolean,\n\t\tReturnStatus extends boolean,\n\t> = AsResponse extends true\n\t\t? Response\n\t\t: ReturnHeaders extends true\n\t\t\t? ReturnStatus extends true\n\t\t\t\t? {\n\t\t\t\t\t\theaders: Headers;\n\t\t\t\t\t\tstatus: number;\n\t\t\t\t\t\tresponse: Awaited<R>;\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\theaders: Headers;\n\t\t\t\t\t\tresponse: Awaited<R>;\n\t\t\t\t\t}\n\t\t\t: ReturnStatus extends true\n\t\t\t\t? {\n\t\t\t\t\t\tstatus: number;\n\t\t\t\t\t\tresponse: Awaited<R>;\n\t\t\t\t\t}\n\t\t\t\t: Awaited<R>;\n\n\tconst internalHandler = async <\n\t\tAsResponse extends boolean = false,\n\t\tReturnHeaders extends boolean = false,\n\t\tReturnStatus extends boolean = false,\n\t>(\n\t\t...inputCtx: HasRequiredKeys<Context> extends true\n\t\t\t? [\n\t\t\t\t\tContext & {\n\t\t\t\t\t\tasResponse?: AsResponse;\n\t\t\t\t\t\treturnHeaders?: ReturnHeaders;\n\t\t\t\t\t\treturnStatus?: ReturnStatus;\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t: [\n\t\t\t\t\t(Context & {\n\t\t\t\t\t\tasResponse?: AsResponse;\n\t\t\t\t\t\treturnHeaders?: ReturnHeaders;\n\t\t\t\t\t\treturnStatus?: ReturnStatus;\n\t\t\t\t\t})?,\n\t\t\t\t]\n\t): Promise<ResultType<AsResponse, ReturnHeaders, ReturnStatus>> => {\n\t\tconst context = (inputCtx[0] || {}) as InputContext<any, any>;\n\t\tconst { data: internalContext, error: validationError } = await tryCatch(\n\t\t\tcreateInternalContext(context, {\n\t\t\t\toptions,\n\t\t\t\tpath,\n\t\t\t}),\n\t\t);\n\n\t\tif (validationError) {\n\t\t\t// If it's not a validation error, we throw it\n\t\t\tif (!(validationError instanceof ValidationError)) throw validationError;\n\n\t\t\t// Check if the endpoint has a custom onValidationError callback\n\t\t\tif (options.onValidationError) {\n\t\t\t\t// This can possibly throw an APIError in order to customize the validation error message\n\t\t\t\tawait options.onValidationError({\n\t\t\t\t\tmessage: validationError.message,\n\t\t\t\t\tissues: validationError.issues,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tthrow new APIError(400, {\n\t\t\t\tmessage: validationError.message,\n\t\t\t\tcode: \"VALIDATION_ERROR\",\n\t\t\t});\n\t\t}\n\t\tconst response = await handler(internalContext as any).catch(async (e) => {\n\t\t\tif (isAPIError(e)) {\n\t\t\t\tconst onAPIError = options.onAPIError;\n\t\t\t\tif (onAPIError) {\n\t\t\t\t\tawait onAPIError(e);\n\t\t\t\t}\n\t\t\t\tif (context.asResponse) {\n\t\t\t\t\treturn e;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow e;\n\t\t});\n\t\tconst headers = internalContext.responseHeaders;\n\t\tconst status = internalContext.responseStatus;\n\n\t\treturn (\n\t\t\tcontext.asResponse\n\t\t\t\t? toResponse(response, {\n\t\t\t\t\t\theaders,\n\t\t\t\t\t\tstatus,\n\t\t\t\t\t})\n\t\t\t\t: context.returnHeaders\n\t\t\t\t\t? context.returnStatus\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\theaders,\n\t\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t\t\tstatus,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\theaders,\n\t\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t: context.returnStatus\n\t\t\t\t\t\t? { response, status }\n\t\t\t\t\t\t: response\n\t\t) as ResultType<AsResponse, ReturnHeaders, ReturnStatus>;\n\t};\n\tinternalHandler.options = options;\n\tinternalHandler.path = path;\n\treturn internalHandler as unknown as StrictEndpoint<\n\t\tPath,\n\t\tExtractStandSchema<Options>,\n\t\tR\n\t>;\n}\n\nfunction combineMiddleware(\n\tlocal: MiddlewareHandler[] | undefined,\n\tconfigured: MiddlewareHandler[] | undefined,\n): MiddlewareHandler[] {\n\treturn [...(local ?? []), ...(configured ?? [])];\n}\n\ncreateEndpoint.create = <E extends { use?: MiddlewareHandler[] }>(opts?: E) => {\n\tfunction createConfiguredEndpoint<\n\t\tPath extends string,\n\t\tOpts extends EndpointOptions,\n\t\tR,\n\t>(\n\t\tpath: Path,\n\t\toptions: Opts,\n\t\thandler: EndpointHandler<Path, Opts, R, InferUse<E[\"use\"]>>,\n\t): StrictEndpoint<\n\t\tPath,\n\t\tExtractStandSchema<Opts & { use: MiddlewareHandler[] }>,\n\t\tR\n\t>;\n\n\tfunction createConfiguredEndpoint<Opts extends EndpointOptions, R>(\n\t\toptions: Opts,\n\t\thandler: PathlessEndpointHandler<Opts, R, InferUse<E[\"use\"]>>,\n\t): StrictEndpoint<\n\t\tnever,\n\t\tExtractStandSchema<Opts & { use: MiddlewareHandler[] }>,\n\t\tR\n\t>;\n\n\tfunction createConfiguredEndpoint<\n\t\tPath extends string,\n\t\tOpts extends EndpointOptions,\n\t\tR,\n\t>(\n\t\t...args:\n\t\t\t| [\n\t\t\t\t\tpath: Path,\n\t\t\t\t\toptions: Opts,\n\t\t\t\t\thandler: EndpointHandler<Path, Opts, R, InferUse<E[\"use\"]>>,\n\t\t\t ]\n\t\t\t| [\n\t\t\t\t\toptions: Opts,\n\t\t\t\t\thandler: PathlessEndpointHandler<Opts, R, InferUse<E[\"use\"]>>,\n\t\t\t ]\n\t) {\n\t\tif (args.length === 3) {\n\t\t\tconst [path, options, handler] = args;\n\t\t\treturn createEndpoint(\n\t\t\t\tpath,\n\t\t\t\t{\n\t\t\t\t\t...options,\n\t\t\t\t\tuse: combineMiddleware(options.use, opts?.use),\n\t\t\t\t},\n\t\t\t\thandler,\n\t\t\t);\n\t\t}\n\n\t\tconst [options, handler] = args;\n\t\treturn createEndpoint(\n\t\t\t{\n\t\t\t\t...options,\n\t\t\t\tuse: combineMiddleware(options.use, opts?.use),\n\t\t\t},\n\t\t\thandler,\n\t\t);\n\t}\n\n\treturn createConfiguredEndpoint;\n};\n\nexport type StrictEndpoint<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n\tR = any,\n> = {\n\t// asResponse cases\n\t(\n\t\tcontext: InputContext<Path, Options> & { asResponse: true },\n\t): Promise<Response>;\n\n\t// returnHeaders & returnStatus cases\n\t(\n\t\tcontext: InputContext<Path, Options> & {\n\t\t\treturnHeaders: true;\n\t\t\treturnStatus: true;\n\t\t},\n\t): Promise<{ headers: Headers; status: number; response: Awaited<R> }>;\n\t(\n\t\tcontext: InputContext<Path, Options> & {\n\t\t\treturnHeaders: true;\n\t\t\treturnStatus: false;\n\t\t},\n\t): Promise<{ headers: Headers; response: Awaited<R> }>;\n\t(\n\t\tcontext: InputContext<Path, Options> & {\n\t\t\treturnHeaders: false;\n\t\t\treturnStatus: true;\n\t\t},\n\t): Promise<{ status: number; response: Awaited<R> }>;\n\t(\n\t\tcontext: InputContext<Path, Options> & {\n\t\t\treturnHeaders: false;\n\t\t\treturnStatus: false;\n\t\t},\n\t): Promise<R>;\n\n\t// individual flag cases\n\t(\n\t\tcontext: InputContext<Path, Options> & { returnHeaders: true },\n\t): Promise<{ headers: Headers; response: Awaited<R> }>;\n\t(\n\t\tcontext: InputContext<Path, Options> & { returnStatus: true },\n\t): Promise<{ status: number; response: Awaited<R> }>;\n\n\t// default case\n\t(context?: InputContext<Path, Options>): Promise<R>;\n\n\toptions: Options;\n\tpath: Path;\n};\n\nexport type Endpoint<\n\tPath extends string = string,\n\tOptions extends EndpointOptions = EndpointOptions,\n\tHandler extends (inputCtx: any) => Promise<any> = (\n\t\tinputCtx: any,\n\t) => Promise<any>,\n> = Handler & {\n\toptions: Options;\n\tpath: Path;\n};\n"],"mappings":";;;;;AA+gBA,SAAgB,eAKf,eACA,kBACA,gBACuD;CACvD,MAAM,OACL,OAAO,kBAAkB,WAAW,gBAAgB,KAAA;CACrD,MAAM,UACL,OAAO,qBAAqB,WACzB,mBACC;CACL,MAAM,UACL,OAAO,qBAAqB,aAAa,mBAAmB;CAE7D,KAAK,QAAQ,WAAW,SAAS,QAAQ,WAAW,WAAW,QAAQ,MACtE,MAAM,IAAI,gBAAgB,8CAA8C;CAGzE,IAAI,QAAQ,SAAS,KAAK,IAAI,GAC7B,MAAM,IAAI,gBAAgB,yCAAyC;CA4BpE,MAAM,kBAAkB,OAKvB,GAAG,aAe+D;EAClE,MAAM,UAAW,SAAS,MAAM,CAAC;EACjC,MAAM,EAAE,MAAM,iBAAiB,OAAO,oBAAoB,MAAM,SAC/D,sBAAsB,SAAS;GAC9B;GACA;EACD,CAAC,CACF;EAEA,IAAI,iBAAiB;GAEpB,IAAI,EAAE,2BAA2B,kBAAkB,MAAM;GAGzD,IAAI,QAAQ,mBAEX,MAAM,QAAQ,kBAAkB;IAC/B,SAAS,gBAAgB;IACzB,QAAQ,gBAAgB;GACzB,CAAC;GAGF,MAAM,IAAI,SAAS,KAAK;IACvB,SAAS,gBAAgB;IACzB,MAAM;GACP,CAAC;EACF;EACA,MAAM,WAAW,MAAM,QAAQ,eAAsB,CAAC,CAAC,MAAM,OAAO,MAAM;GACzE,IAAI,WAAW,CAAC,GAAG;IAClB,MAAM,aAAa,QAAQ;IAC3B,IAAI,YACH,MAAM,WAAW,CAAC;IAEnB,IAAI,QAAQ,YACX,OAAO;GAET;GACA,MAAM;EACP,CAAC;EACD,MAAM,UAAU,gBAAgB;EAChC,MAAM,SAAS,gBAAgB;EAE/B,OACC,QAAQ,aACL,WAAW,UAAU;GACrB;GACA;EACD,CAAC,IACA,QAAQ,gBACP,QAAQ,eACP;GACA;GACA;GACA;EACD,IACC;GACA;GACA;EACD,IACA,QAAQ,eACP;GAAE;GAAU;EAAO,IACnB;CAEP;CACA,gBAAgB,UAAU;CAC1B,gBAAgB,OAAO;CACvB,OAAO;AAKR;AAEA,SAAS,kBACR,OACA,YACsB;CACtB,OAAO,CAAC,GAAI,SAAS,CAAC,GAAI,GAAI,cAAc,CAAC,CAAE;AAChD;AAEA,eAAe,UAAmD,SAAa;CAwB9E,SAAS,yBAKR,GAAG,MAUF;EACD,IAAI,KAAK,WAAW,GAAG;GACtB,MAAM,CAAC,MAAM,SAAS,WAAW;GACjC,OAAO,eACN,MACA;IACC,GAAG;IACH,KAAK,kBAAkB,QAAQ,KAAK,MAAM,GAAG;GAC9C,GACA,OACD;EACD;EAEA,MAAM,CAAC,SAAS,WAAW;EAC3B,OAAO,eACN;GACC,GAAG;GACH,KAAK,kBAAkB,QAAQ,KAAK,MAAM,GAAG;EAC9C,GACA,OACD;CACD;CAEA,OAAO;AACR"}
|
package/dist/error.cjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value:
|
|
2
|
-
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
2
|
//#region src/error.ts
|
|
4
3
|
function isErrorStackTraceLimitWritable() {
|
|
5
4
|
const desc = Object.getOwnPropertyDescriptor(Error, "stackTraceLimit");
|
|
@@ -97,6 +96,10 @@ const statusCodes = {
|
|
|
97
96
|
NETWORK_AUTHENTICATION_REQUIRED: 511
|
|
98
97
|
};
|
|
99
98
|
var InternalAPIError = class extends Error {
|
|
99
|
+
status;
|
|
100
|
+
body;
|
|
101
|
+
headers;
|
|
102
|
+
statusCode;
|
|
100
103
|
constructor(status = "INTERNAL_SERVER_ERROR", body = void 0, headers = {}, statusCode = typeof status === "number" ? status : statusCodes[status]) {
|
|
101
104
|
super(body?.message, body?.cause ? { cause: body.cause } : void 0);
|
|
102
105
|
this.status = status;
|
|
@@ -111,6 +114,8 @@ var InternalAPIError = class extends Error {
|
|
|
111
114
|
}
|
|
112
115
|
};
|
|
113
116
|
var ValidationError = class extends InternalAPIError {
|
|
117
|
+
message;
|
|
118
|
+
issues;
|
|
114
119
|
constructor(message, issues) {
|
|
115
120
|
super(400, {
|
|
116
121
|
message,
|
|
@@ -129,7 +134,6 @@ var BetterCallError = class extends Error {
|
|
|
129
134
|
};
|
|
130
135
|
const kAPIErrorHeaderSymbol = Symbol.for("better-call:api-error-headers");
|
|
131
136
|
const APIError = makeErrorForHideStackFrame(InternalAPIError, Error);
|
|
132
|
-
|
|
133
137
|
//#endregion
|
|
134
138
|
exports.APIError = APIError;
|
|
135
139
|
exports.BetterCallError = BetterCallError;
|
|
@@ -138,4 +142,5 @@ exports.hideInternalStackFrames = hideInternalStackFrames;
|
|
|
138
142
|
exports.kAPIErrorHeaderSymbol = kAPIErrorHeaderSymbol;
|
|
139
143
|
exports.makeErrorForHideStackFrame = makeErrorForHideStackFrame;
|
|
140
144
|
exports.statusCodes = statusCodes;
|
|
145
|
+
|
|
141
146
|
//# sourceMappingURL=error.cjs.map
|