better-call 1.4.1 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/context.cjs CHANGED
@@ -9,7 +9,7 @@ const createInternalContext = async (context, { options, path }) => {
9
9
  let responseStatus = void 0;
10
10
  const { data, error } = await require_validator.runValidation(options, context);
11
11
  if (error) throw new require_error.ValidationError(error.message, error.issues);
12
- const requestHeaders = "headers" in context ? context.headers instanceof Headers ? context.headers : new Headers(context.headers) : "request" in context && require_utils.isRequest(context.request) ? context.request.headers : null;
12
+ const requestHeaders = context.headers !== void 0 ? context.headers instanceof Headers ? context.headers : new Headers(context.headers) : "request" in context && require_utils.isRequest(context.request) ? context.request.headers : null;
13
13
  const requestCookies = requestHeaders?.get("cookie");
14
14
  const parsedCookies = requestCookies ? require_cookies.parseCookies(requestCookies) : void 0;
15
15
  const internalContext = {
@@ -1 +1 @@
1
- {"version":3,"file":"context.cjs","names":["runValidation","ValidationError","isRequest","parseCookies","getCookieKey","verifySignature","getCryptoKey","serializeCookie","serializeSignedCookie","APIError"],"sources":["../src/context.ts"],"sourcesContent":["import type { InferRouteParams } from \"rou3\";\nimport type { CookieOptions, CookiePrefixOptions } from \"./cookies\";\nimport {\n\tgetCookieKey,\n\tparseCookies,\n\tserializeCookie,\n\tserializeSignedCookie,\n} from \"./cookies\";\nimport { getCryptoKey, verifySignature } from \"./crypto\";\nimport type { EndpointOptions } from \"./endpoint\";\nimport type { Status, statusCodes } from \"./error\";\nimport { APIError, ValidationError } from \"./error\";\nimport type { IsEmptyObject, Prettify, UnionToIntersection } from \"./helper\";\nimport type { MiddlewareHandler, MiddlewareOptions } from \"./middleware\";\nimport type { StandardSchemaV1 } from \"./standard-schema\";\nimport { isRequest } from \"./utils\";\nimport { runValidation } from \"./validator\";\n\nexport type HTTPMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\nexport type Method = HTTPMethod | \"*\";\n\nexport type InferBodyInput<\n\tOptions extends EndpointOptions | MiddlewareOptions,\n\tBody = Options[\"metadata\"] extends {\n\t\t$Infer: {\n\t\t\tbody: infer B;\n\t\t};\n\t}\n\t\t? B\n\t\t: Options[\"body\"] extends StandardSchemaV1\n\t\t\t? StandardSchemaV1.InferInput<Options[\"body\"]>\n\t\t\t: undefined,\n> = undefined extends Body\n\t? {\n\t\t\tbody?: Body;\n\t\t}\n\t: {\n\t\t\tbody: Body;\n\t\t};\n\nexport type InferBody<Options extends EndpointOptions | MiddlewareOptions> =\n\tOptions[\"metadata\"] extends {\n\t\t$Infer: {\n\t\t\tbody: infer Body;\n\t\t};\n\t}\n\t\t? Body\n\t\t: Options[\"body\"] extends StandardSchemaV1\n\t\t\t? StandardSchemaV1.InferOutput<Options[\"body\"]>\n\t\t\t: any;\n\nexport type InferQueryInput<\n\tOptions extends EndpointOptions | MiddlewareOptions,\n\tQuery = Options[\"metadata\"] extends {\n\t\t$Infer: {\n\t\t\tquery: infer Query;\n\t\t};\n\t}\n\t\t? Query\n\t\t: Options[\"query\"] extends StandardSchemaV1\n\t\t\t? StandardSchemaV1.InferInput<Options[\"query\"]>\n\t\t\t: Record<string, any> | undefined,\n> = undefined extends Query\n\t? {\n\t\t\tquery?: Query;\n\t\t}\n\t: {\n\t\t\tquery: Query;\n\t\t};\n\nexport type InferQuery<Options extends EndpointOptions | MiddlewareOptions> =\n\tOptions[\"metadata\"] extends {\n\t\t$Infer: {\n\t\t\tquery: infer Query;\n\t\t};\n\t}\n\t\t? Query\n\t\t: Options[\"query\"] extends StandardSchemaV1\n\t\t\t? StandardSchemaV1.InferOutput<Options[\"query\"]>\n\t\t\t: Record<string, any> | undefined;\n\nexport type InferMethod<Options extends EndpointOptions> =\n\tOptions[\"method\"] extends Array<Method>\n\t\t? Options[\"method\"][number]\n\t\t: Options[\"method\"] extends \"*\"\n\t\t\t? HTTPMethod\n\t\t\t: Options[\"method\"];\n\nexport type InferInputMethod<\n\tOptions extends EndpointOptions,\n\tMethod = Options[\"method\"] extends Array<any>\n\t\t? Options[\"method\"][number] | undefined\n\t\t: Options[\"method\"] extends \"*\"\n\t\t\t? HTTPMethod\n\t\t\t: Options[\"method\"] | undefined,\n> = undefined extends Method\n\t? {\n\t\t\tmethod?: Method;\n\t\t}\n\t: {\n\t\t\tmethod: Method;\n\t\t};\n\ntype TrailingWildcardKey<Path extends string> =\n\tPath extends `${infer Prefix}/*${\"\" | \"/\"}`\n\t\t? Exclude<keyof InferRouteParams<Path>, keyof InferRouteParams<Prefix>>\n\t\t: never;\n\ntype RouteParams<Path extends string> = {\n\t[Key in keyof InferRouteParams<Path>]: Key extends TrailingWildcardKey<Path>\n\t\t? InferRouteParams<Path>[Key] | undefined\n\t\t: InferRouteParams<Path>[Key];\n};\n\nexport type InferParam<Path extends string> = string extends Path\n\t? Record<string, string | undefined> | undefined\n\t: [Path] extends [never]\n\t\t? Record<string, string | undefined> | undefined\n\t\t: IsEmptyObject<RouteParams<Path>> extends true\n\t\t\t? Record<string, string | undefined> | undefined\n\t\t\t: Prettify<RouteParams<Path>>;\n\nexport type InferParamInput<Path extends string> = string extends Path\n\t? { params?: Record<string, string | undefined> }\n\t: [Path] extends [never]\n\t\t? { params?: Record<string, string | undefined> }\n\t\t: IsEmptyObject<RouteParams<Path>> extends true\n\t\t\t? {\n\t\t\t\t\tparams?: Record<string, string | undefined>;\n\t\t\t\t}\n\t\t\t: {\n\t\t\t\t\tparams: Prettify<RouteParams<Path>>;\n\t\t\t\t};\n\nexport type InferRequest<Option extends EndpointOptions | MiddlewareOptions> =\n\tOption[\"requireRequest\"] extends true ? Request : Request | undefined;\n\nexport type InferRequestInput<\n\tOption extends EndpointOptions | MiddlewareOptions,\n> = Option[\"requireRequest\"] extends true\n\t? {\n\t\t\trequest: Request;\n\t\t}\n\t: {\n\t\t\trequest?: Request;\n\t\t};\n\nexport type InferHeaders<Option extends EndpointOptions | MiddlewareOptions> =\n\tOption[\"requireHeaders\"] extends true ? Headers : Headers | undefined;\n\nexport type InferHeadersInput<\n\tOption extends EndpointOptions | MiddlewareOptions,\n> = Option[\"requireHeaders\"] extends true\n\t? {\n\t\t\theaders: HeadersInit;\n\t\t}\n\t: {\n\t\t\theaders?: HeadersInit;\n\t\t};\n\ntype InferMiddlewareContext<T> = T extends (...args: never[]) => infer Result\n\t? unknown extends Awaited<Result>\n\t\t? never\n\t\t: Extract<Awaited<Result>, object>\n\t: never;\n\ntype InferMiddlewareContexts<Opts extends EndpointOptions[\"use\"]> =\n\tOpts extends MiddlewareHandler[]\n\t\t? InferMiddlewareContext<Opts[number]>\n\t\t: never;\n\nexport type InferUse<Opts extends EndpointOptions[\"use\"]> = [\n\tInferMiddlewareContexts<Opts>,\n] extends [never]\n\t? object\n\t: UnionToIntersection<InferMiddlewareContexts<Opts>>;\n\nexport type InferMiddlewareBody<Options extends MiddlewareOptions> =\n\tOptions[\"body\"] extends StandardSchemaV1<infer T> ? T : any;\n\nexport type InferMiddlewareQuery<Options extends MiddlewareOptions> =\n\tOptions[\"query\"] extends StandardSchemaV1<infer T>\n\t\t? T\n\t\t: Record<string, any> | undefined;\n\nexport type InputContext<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n> = InferBodyInput<Options> &\n\tInferInputMethod<Options> &\n\tInferQueryInput<Options> &\n\tInferParamInput<Path> &\n\tInferRequestInput<Options> &\n\tInferHeadersInput<Options> & {\n\t\tasResponse?: boolean;\n\t\treturnHeaders?: boolean;\n\t\treturnStatus?: boolean;\n\t\tuse?: MiddlewareHandler[];\n\t\tpath?: string;\n\t\tcontext?: Record<string, any>;\n\t};\n\nexport const createInternalContext = async (\n\tcontext: InputContext<any, any>,\n\t{\n\t\toptions,\n\t\tpath,\n\t}: {\n\t\toptions: EndpointOptions;\n\t\tpath?: string;\n\t},\n) => {\n\tconst headers = new Headers();\n\tlet responseStatus: Status | undefined = undefined;\n\n\tconst { data, error } = await runValidation(options, context);\n\tif (error) {\n\t\tthrow new ValidationError(error.message, error.issues);\n\t}\n\tconst requestHeaders: Headers | null =\n\t\t\"headers\" in context\n\t\t\t? context.headers instanceof Headers\n\t\t\t\t? context.headers\n\t\t\t\t: new Headers(context.headers)\n\t\t\t: \"request\" in context && isRequest(context.request)\n\t\t\t\t? context.request.headers\n\t\t\t\t: null;\n\tconst requestCookies = requestHeaders?.get(\"cookie\");\n\tconst parsedCookies = requestCookies\n\t\t? parseCookies(requestCookies)\n\t\t: undefined;\n\n\tconst internalContext = {\n\t\t...context,\n\t\tbody: data.body,\n\t\tquery: data.query,\n\t\tpath: context.path || path || \"virtual:\",\n\t\tcontext: \"context\" in context && context.context ? context.context : {},\n\t\treturned: undefined as any,\n\t\theaders: context?.headers,\n\t\trequest: context?.request,\n\t\tparams: \"params\" in context ? context.params : undefined,\n\t\tmethod:\n\t\t\tcontext.method ??\n\t\t\t(Array.isArray(options.method)\n\t\t\t\t? options.method[0]\n\t\t\t\t: options.method === \"*\"\n\t\t\t\t\t? \"GET\"\n\t\t\t\t\t: options.method),\n\t\tsetHeader: (key: string, value: string) => {\n\t\t\theaders.set(key, value);\n\t\t},\n\t\tgetHeader: (key: string) => {\n\t\t\tif (!requestHeaders) return null;\n\t\t\treturn requestHeaders.get(key);\n\t\t},\n\t\tgetCookie: (key: string, prefix?: CookiePrefixOptions) => {\n\t\t\tconst finalKey = getCookieKey(key, prefix);\n\t\t\tif (!finalKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn parsedCookies?.get(finalKey) || null;\n\t\t},\n\t\tgetSignedCookie: async (\n\t\t\tkey: string,\n\t\t\tsecret: string,\n\t\t\tprefix?: CookiePrefixOptions,\n\t\t) => {\n\t\t\tconst finalKey = getCookieKey(key, prefix);\n\t\t\tif (!finalKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst value = parsedCookies?.get(finalKey);\n\t\t\tif (!value) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst signatureStartPos = value.lastIndexOf(\".\");\n\t\t\tif (signatureStartPos < 1) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst signedValue = value.substring(0, signatureStartPos);\n\t\t\tconst signature = value.substring(signatureStartPos + 1);\n\t\t\tif (signature.length !== 44 || !signature.endsWith(\"=\")) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst secretKey = await getCryptoKey(secret);\n\t\t\tconst isVerified = await verifySignature(\n\t\t\t\tsignature,\n\t\t\t\tsignedValue,\n\t\t\t\tsecretKey,\n\t\t\t);\n\t\t\treturn isVerified ? signedValue : false;\n\t\t},\n\t\tsetCookie: (key: string, value: string, options?: CookieOptions) => {\n\t\t\tconst cookie = serializeCookie(key, value, options);\n\t\t\theaders.append(\"set-cookie\", cookie);\n\t\t\treturn cookie;\n\t\t},\n\t\tsetSignedCookie: async (\n\t\t\tkey: string,\n\t\t\tvalue: string,\n\t\t\tsecret: string,\n\t\t\toptions?: CookieOptions,\n\t\t) => {\n\t\t\tconst cookie = await serializeSignedCookie(key, value, secret, options);\n\t\t\theaders.append(\"set-cookie\", cookie);\n\t\t\treturn cookie;\n\t\t},\n\t\tredirect: (url: string) => {\n\t\t\theaders.set(\"location\", url);\n\t\t\treturn new APIError(\"FOUND\", undefined, headers);\n\t\t},\n\t\terror: (\n\t\t\tstatus: keyof typeof statusCodes | Status,\n\t\t\tbody?:\n\t\t\t\t| {\n\t\t\t\t\t\tmessage?: string;\n\t\t\t\t\t\tcode?: string;\n\t\t\t\t }\n\t\t\t\t| undefined,\n\t\t\theaders?: HeadersInit,\n\t\t) => {\n\t\t\treturn new APIError(status, body, headers);\n\t\t},\n\t\tsetStatus: (status: Status) => {\n\t\t\tresponseStatus = status;\n\t\t},\n\t\tjson: (\n\t\t\tjson: Record<string, any>,\n\t\t\trouterResponse?:\n\t\t\t\t| {\n\t\t\t\t\t\tstatus?: number;\n\t\t\t\t\t\theaders?: Record<string, string>;\n\t\t\t\t\t\tresponse?: Response;\n\t\t\t\t\t\tbody?: Record<string, any>;\n\t\t\t\t }\n\t\t\t\t| Response,\n\t\t) => {\n\t\t\tif (!context.asResponse) {\n\t\t\t\treturn json;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tbody: routerResponse?.body || json,\n\t\t\t\trouterResponse,\n\t\t\t\t_flag: \"json\",\n\t\t\t};\n\t\t},\n\t\tresponseHeaders: headers,\n\t\tget responseStatus() {\n\t\t\treturn responseStatus;\n\t\t},\n\t};\n\t//if context was shimmed through the input we want to apply it\n\tfor (const middleware of options.use || []) {\n\t\tconst response = (await middleware({\n\t\t\t...internalContext,\n\t\t\treturnHeaders: true,\n\t\t\tasResponse: false,\n\t\t})) as {\n\t\t\tresponse?: any;\n\t\t\theaders?: Headers;\n\t\t};\n\t\tif (response.response) {\n\t\t\tObject.assign(internalContext.context, response.response);\n\t\t}\n\t\t/**\n\t\t * Apply headers from the middleware to the endpoint headers\n\t\t */\n\t\tif (response.headers) {\n\t\t\tresponse.headers.forEach((value, key) => {\n\t\t\t\tinternalContext.responseHeaders.set(key, value);\n\t\t\t});\n\t\t}\n\t}\n\treturn internalContext;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"context.cjs","names":["runValidation","ValidationError","isRequest","parseCookies","getCookieKey","verifySignature","getCryptoKey","serializeCookie","serializeSignedCookie","APIError"],"sources":["../src/context.ts"],"sourcesContent":["import type { InferRouteParams } from \"rou3\";\nimport type { CookieOptions, CookiePrefixOptions } from \"./cookies\";\nimport {\n\tgetCookieKey,\n\tparseCookies,\n\tserializeCookie,\n\tserializeSignedCookie,\n} from \"./cookies\";\nimport { getCryptoKey, verifySignature } from \"./crypto\";\nimport type { EndpointOptions } from \"./endpoint\";\nimport type { Status, statusCodes } from \"./error\";\nimport { APIError, ValidationError } from \"./error\";\nimport type { IsEmptyObject, Prettify, UnionToIntersection } from \"./helper\";\nimport type { MiddlewareHandler, MiddlewareOptions } from \"./middleware\";\nimport type { StandardSchemaV1 } from \"./standard-schema\";\nimport { isRequest } from \"./utils\";\nimport { runValidation } from \"./validator\";\n\nexport type HTTPMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\nexport type Method = HTTPMethod | \"*\";\n\nexport type InferBodyInput<\n\tOptions extends EndpointOptions | MiddlewareOptions,\n\tBody = Options[\"metadata\"] extends {\n\t\t$Infer: {\n\t\t\tbody: infer B;\n\t\t};\n\t}\n\t\t? B\n\t\t: Options[\"body\"] extends StandardSchemaV1\n\t\t\t? StandardSchemaV1.InferInput<Options[\"body\"]>\n\t\t\t: undefined,\n> = undefined extends Body\n\t? {\n\t\t\tbody?: Body;\n\t\t}\n\t: {\n\t\t\tbody: Body;\n\t\t};\n\nexport type InferBody<Options extends EndpointOptions | MiddlewareOptions> =\n\tOptions[\"metadata\"] extends {\n\t\t$Infer: {\n\t\t\tbody: infer Body;\n\t\t};\n\t}\n\t\t? Body\n\t\t: Options[\"body\"] extends StandardSchemaV1\n\t\t\t? StandardSchemaV1.InferOutput<Options[\"body\"]>\n\t\t\t: any;\n\nexport type InferQueryInput<\n\tOptions extends EndpointOptions | MiddlewareOptions,\n\tQuery = Options[\"metadata\"] extends {\n\t\t$Infer: {\n\t\t\tquery: infer Query;\n\t\t};\n\t}\n\t\t? Query\n\t\t: Options[\"query\"] extends StandardSchemaV1\n\t\t\t? StandardSchemaV1.InferInput<Options[\"query\"]>\n\t\t\t: Record<string, any> | undefined,\n> = undefined extends Query\n\t? {\n\t\t\tquery?: Query;\n\t\t}\n\t: {\n\t\t\tquery: Query;\n\t\t};\n\nexport type InferQuery<Options extends EndpointOptions | MiddlewareOptions> =\n\tOptions[\"metadata\"] extends {\n\t\t$Infer: {\n\t\t\tquery: infer Query;\n\t\t};\n\t}\n\t\t? Query\n\t\t: Options[\"query\"] extends StandardSchemaV1\n\t\t\t? StandardSchemaV1.InferOutput<Options[\"query\"]>\n\t\t\t: Record<string, any> | undefined;\n\nexport type InferMethod<Options extends EndpointOptions> =\n\tOptions[\"method\"] extends Array<Method>\n\t\t? Options[\"method\"][number]\n\t\t: Options[\"method\"] extends \"*\"\n\t\t\t? HTTPMethod\n\t\t\t: Options[\"method\"];\n\nexport type InferInputMethod<\n\tOptions extends EndpointOptions,\n\tMethod = Options[\"method\"] extends Array<any>\n\t\t? Options[\"method\"][number] | undefined\n\t\t: Options[\"method\"] extends \"*\"\n\t\t\t? HTTPMethod\n\t\t\t: Options[\"method\"] | undefined,\n> = undefined extends Method\n\t? {\n\t\t\tmethod?: Method;\n\t\t}\n\t: {\n\t\t\tmethod: Method;\n\t\t};\n\ntype TrailingWildcardKey<Path extends string> =\n\tPath extends `${infer Prefix}/*${\"\" | \"/\"}`\n\t\t? Exclude<keyof InferRouteParams<Path>, keyof InferRouteParams<Prefix>>\n\t\t: never;\n\ntype RouteParams<Path extends string> = {\n\t[Key in keyof InferRouteParams<Path>]: Key extends TrailingWildcardKey<Path>\n\t\t? InferRouteParams<Path>[Key] | undefined\n\t\t: InferRouteParams<Path>[Key];\n};\n\nexport type InferParam<Path extends string> = string extends Path\n\t? Record<string, string | undefined> | undefined\n\t: [Path] extends [never]\n\t\t? Record<string, string | undefined> | undefined\n\t\t: IsEmptyObject<RouteParams<Path>> extends true\n\t\t\t? Record<string, string | undefined> | undefined\n\t\t\t: Prettify<RouteParams<Path>>;\n\nexport type InferParamInput<Path extends string> = string extends Path\n\t? { params?: Record<string, string | undefined> }\n\t: [Path] extends [never]\n\t\t? { params?: Record<string, string | undefined> }\n\t\t: IsEmptyObject<RouteParams<Path>> extends true\n\t\t\t? {\n\t\t\t\t\tparams?: Record<string, string | undefined>;\n\t\t\t\t}\n\t\t\t: {\n\t\t\t\t\tparams: Prettify<RouteParams<Path>>;\n\t\t\t\t};\n\nexport type InferRequest<Option extends EndpointOptions | MiddlewareOptions> =\n\tOption[\"requireRequest\"] extends true ? Request : Request | undefined;\n\nexport type InferRequestInput<\n\tOption extends EndpointOptions | MiddlewareOptions,\n> = Option[\"requireRequest\"] extends true\n\t? {\n\t\t\trequest: Request;\n\t\t}\n\t: {\n\t\t\trequest?: Request | undefined;\n\t\t};\n\nexport type InferHeaders<Option extends EndpointOptions | MiddlewareOptions> =\n\tOption[\"requireHeaders\"] extends true ? Headers : Headers | undefined;\n\nexport type InferHeadersInput<\n\tOption extends EndpointOptions | MiddlewareOptions,\n> = Option[\"requireHeaders\"] extends true\n\t? {\n\t\t\theaders: HeadersInit;\n\t\t}\n\t: {\n\t\t\theaders?: HeadersInit | undefined;\n\t\t};\n\ntype InferMiddlewareContext<T> = T extends (...args: never[]) => infer Result\n\t? unknown extends Awaited<Result>\n\t\t? never\n\t\t: Extract<Awaited<Result>, object>\n\t: never;\n\ntype InferMiddlewareContexts<Opts extends EndpointOptions[\"use\"]> =\n\tOpts extends MiddlewareHandler[]\n\t\t? InferMiddlewareContext<Opts[number]>\n\t\t: never;\n\nexport type InferUse<Opts extends EndpointOptions[\"use\"]> = [\n\tInferMiddlewareContexts<Opts>,\n] extends [never]\n\t? object\n\t: UnionToIntersection<InferMiddlewareContexts<Opts>>;\n\nexport type InferMiddlewareBody<Options extends MiddlewareOptions> =\n\tOptions[\"body\"] extends StandardSchemaV1<infer T> ? T : any;\n\nexport type InferMiddlewareQuery<Options extends MiddlewareOptions> =\n\tOptions[\"query\"] extends StandardSchemaV1<infer T>\n\t\t? T\n\t\t: Record<string, any> | undefined;\n\nexport type InputContext<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n> = InferBodyInput<Options> &\n\tInferInputMethod<Options> &\n\tInferQueryInput<Options> &\n\tInferParamInput<Path> &\n\tInferRequestInput<Options> &\n\tInferHeadersInput<Options> & {\n\t\tasResponse?: boolean;\n\t\treturnHeaders?: boolean;\n\t\treturnStatus?: boolean;\n\t\tuse?: MiddlewareHandler[];\n\t\tpath?: string;\n\t\tcontext?: Record<string, any>;\n\t};\n\nexport const createInternalContext = async (\n\tcontext: InputContext<any, any>,\n\t{\n\t\toptions,\n\t\tpath,\n\t}: {\n\t\toptions: EndpointOptions;\n\t\tpath?: string | undefined;\n\t},\n) => {\n\tconst headers = new Headers();\n\tlet responseStatus: Status | undefined = undefined;\n\n\tconst { data, error } = await runValidation(options, context);\n\tif (error) {\n\t\tthrow new ValidationError(error.message, error.issues);\n\t}\n\tconst requestHeaders: Headers | null =\n\t\tcontext.headers !== undefined\n\t\t\t? context.headers instanceof Headers\n\t\t\t\t? context.headers\n\t\t\t\t: new Headers(context.headers)\n\t\t\t: \"request\" in context && isRequest(context.request)\n\t\t\t\t? context.request.headers\n\t\t\t\t: null;\n\tconst requestCookies = requestHeaders?.get(\"cookie\");\n\tconst parsedCookies = requestCookies\n\t\t? parseCookies(requestCookies)\n\t\t: undefined;\n\n\tconst internalContext = {\n\t\t...context,\n\t\tbody: data.body,\n\t\tquery: data.query,\n\t\tpath: context.path || path || \"virtual:\",\n\t\tcontext: \"context\" in context && context.context ? context.context : {},\n\t\treturned: undefined as any,\n\t\theaders: context?.headers,\n\t\trequest: context?.request,\n\t\tparams: \"params\" in context ? context.params : undefined,\n\t\tmethod:\n\t\t\tcontext.method ??\n\t\t\t(Array.isArray(options.method)\n\t\t\t\t? options.method[0]\n\t\t\t\t: options.method === \"*\"\n\t\t\t\t\t? \"GET\"\n\t\t\t\t\t: options.method),\n\t\tsetHeader: (key: string, value: string) => {\n\t\t\theaders.set(key, value);\n\t\t},\n\t\tgetHeader: (key: string) => {\n\t\t\tif (!requestHeaders) return null;\n\t\t\treturn requestHeaders.get(key);\n\t\t},\n\t\tgetCookie: (key: string, prefix?: CookiePrefixOptions) => {\n\t\t\tconst finalKey = getCookieKey(key, prefix);\n\t\t\tif (!finalKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn parsedCookies?.get(finalKey) || null;\n\t\t},\n\t\tgetSignedCookie: async (\n\t\t\tkey: string,\n\t\t\tsecret: string,\n\t\t\tprefix?: CookiePrefixOptions,\n\t\t) => {\n\t\t\tconst finalKey = getCookieKey(key, prefix);\n\t\t\tif (!finalKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst value = parsedCookies?.get(finalKey);\n\t\t\tif (!value) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst signatureStartPos = value.lastIndexOf(\".\");\n\t\t\tif (signatureStartPos < 1) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst signedValue = value.substring(0, signatureStartPos);\n\t\t\tconst signature = value.substring(signatureStartPos + 1);\n\t\t\tif (signature.length !== 44 || !signature.endsWith(\"=\")) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst secretKey = await getCryptoKey(secret);\n\t\t\tconst isVerified = await verifySignature(\n\t\t\t\tsignature,\n\t\t\t\tsignedValue,\n\t\t\t\tsecretKey,\n\t\t\t);\n\t\t\treturn isVerified ? signedValue : false;\n\t\t},\n\t\tsetCookie: (key: string, value: string, options?: CookieOptions) => {\n\t\t\tconst cookie = serializeCookie(key, value, options);\n\t\t\theaders.append(\"set-cookie\", cookie);\n\t\t\treturn cookie;\n\t\t},\n\t\tsetSignedCookie: async (\n\t\t\tkey: string,\n\t\t\tvalue: string,\n\t\t\tsecret: string,\n\t\t\toptions?: CookieOptions,\n\t\t) => {\n\t\t\tconst cookie = await serializeSignedCookie(key, value, secret, options);\n\t\t\theaders.append(\"set-cookie\", cookie);\n\t\t\treturn cookie;\n\t\t},\n\t\tredirect: (url: string) => {\n\t\t\theaders.set(\"location\", url);\n\t\t\treturn new APIError(\"FOUND\", undefined, headers);\n\t\t},\n\t\terror: (\n\t\t\tstatus: keyof typeof statusCodes | Status,\n\t\t\tbody?:\n\t\t\t\t| {\n\t\t\t\t\t\tmessage?: string;\n\t\t\t\t\t\tcode?: string;\n\t\t\t\t }\n\t\t\t\t| undefined,\n\t\t\theaders?: HeadersInit,\n\t\t) => {\n\t\t\treturn new APIError(status, body, headers);\n\t\t},\n\t\tsetStatus: (status: Status) => {\n\t\t\tresponseStatus = status;\n\t\t},\n\t\tjson: (\n\t\t\tjson: Record<string, any>,\n\t\t\trouterResponse?:\n\t\t\t\t| {\n\t\t\t\t\t\tstatus?: number;\n\t\t\t\t\t\theaders?: Record<string, string>;\n\t\t\t\t\t\tresponse?: Response;\n\t\t\t\t\t\tbody?: Record<string, any>;\n\t\t\t\t }\n\t\t\t\t| Response,\n\t\t) => {\n\t\t\tif (!context.asResponse) {\n\t\t\t\treturn json;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tbody: routerResponse?.body || json,\n\t\t\t\trouterResponse,\n\t\t\t\t_flag: \"json\",\n\t\t\t};\n\t\t},\n\t\tresponseHeaders: headers,\n\t\tget responseStatus() {\n\t\t\treturn responseStatus;\n\t\t},\n\t};\n\t//if context was shimmed through the input we want to apply it\n\tfor (const middleware of options.use || []) {\n\t\tconst response = (await middleware({\n\t\t\t...internalContext,\n\t\t\treturnHeaders: true,\n\t\t\tasResponse: false,\n\t\t})) as {\n\t\t\tresponse?: any;\n\t\t\theaders?: Headers;\n\t\t};\n\t\tif (response.response) {\n\t\t\tObject.assign(internalContext.context, response.response);\n\t\t}\n\t\t/**\n\t\t * Apply headers from the middleware to the endpoint headers\n\t\t */\n\t\tif (response.headers) {\n\t\t\tresponse.headers.forEach((value, key) => {\n\t\t\t\tinternalContext.responseHeaders.set(key, value);\n\t\t\t});\n\t\t}\n\t}\n\treturn internalContext;\n};\n"],"mappings":"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"}
@@ -58,13 +58,13 @@ type InferRequest<Option extends EndpointOptions | MiddlewareOptions> = Option["
58
58
  type InferRequestInput<Option extends EndpointOptions | MiddlewareOptions> = Option["requireRequest"] extends true ? {
59
59
  request: Request;
60
60
  } : {
61
- request?: Request;
61
+ request?: Request | undefined;
62
62
  };
63
63
  type InferHeaders<Option extends EndpointOptions | MiddlewareOptions> = Option["requireHeaders"] extends true ? Headers : Headers | undefined;
64
64
  type InferHeadersInput<Option extends EndpointOptions | MiddlewareOptions> = Option["requireHeaders"] extends true ? {
65
65
  headers: HeadersInit;
66
66
  } : {
67
- headers?: HeadersInit;
67
+ headers?: HeadersInit | undefined;
68
68
  };
69
69
  type InferMiddlewareContext<T> = T extends ((...args: never[]) => infer Result) ? unknown extends Awaited<Result> ? never : Extract<Awaited<Result>, object> : never;
70
70
  type InferMiddlewareContexts<Opts extends EndpointOptions["use"]> = Opts extends MiddlewareHandler[] ? InferMiddlewareContext<Opts[number]> : never;
@@ -81,7 +81,7 @@ type InputContext<Path extends string, Options extends EndpointOptions> = InferB
81
81
  };
82
82
  declare const createInternalContext: (context: InputContext<any, any>, { options, path }: {
83
83
  options: EndpointOptions;
84
- path?: string;
84
+ path?: string | undefined;
85
85
  }) => Promise<{
86
86
  body: any;
87
87
  query: any;
@@ -58,13 +58,13 @@ type InferRequest<Option extends EndpointOptions | MiddlewareOptions> = Option["
58
58
  type InferRequestInput<Option extends EndpointOptions | MiddlewareOptions> = Option["requireRequest"] extends true ? {
59
59
  request: Request;
60
60
  } : {
61
- request?: Request;
61
+ request?: Request | undefined;
62
62
  };
63
63
  type InferHeaders<Option extends EndpointOptions | MiddlewareOptions> = Option["requireHeaders"] extends true ? Headers : Headers | undefined;
64
64
  type InferHeadersInput<Option extends EndpointOptions | MiddlewareOptions> = Option["requireHeaders"] extends true ? {
65
65
  headers: HeadersInit;
66
66
  } : {
67
- headers?: HeadersInit;
67
+ headers?: HeadersInit | undefined;
68
68
  };
69
69
  type InferMiddlewareContext<T> = T extends ((...args: never[]) => infer Result) ? unknown extends Awaited<Result> ? never : Extract<Awaited<Result>, object> : never;
70
70
  type InferMiddlewareContexts<Opts extends EndpointOptions["use"]> = Opts extends MiddlewareHandler[] ? InferMiddlewareContext<Opts[number]> : never;
@@ -81,7 +81,7 @@ type InputContext<Path extends string, Options extends EndpointOptions> = InferB
81
81
  };
82
82
  declare const createInternalContext: (context: InputContext<any, any>, { options, path }: {
83
83
  options: EndpointOptions;
84
- path?: string;
84
+ path?: string | undefined;
85
85
  }) => Promise<{
86
86
  body: any;
87
87
  query: any;
package/dist/context.mjs CHANGED
@@ -9,7 +9,7 @@ const createInternalContext = async (context, { options, path }) => {
9
9
  let responseStatus = void 0;
10
10
  const { data, error } = await runValidation(options, context);
11
11
  if (error) throw new ValidationError(error.message, error.issues);
12
- const requestHeaders = "headers" in context ? context.headers instanceof Headers ? context.headers : new Headers(context.headers) : "request" in context && isRequest(context.request) ? context.request.headers : null;
12
+ const requestHeaders = context.headers !== void 0 ? context.headers instanceof Headers ? context.headers : new Headers(context.headers) : "request" in context && isRequest(context.request) ? context.request.headers : null;
13
13
  const requestCookies = requestHeaders?.get("cookie");
14
14
  const parsedCookies = requestCookies ? parseCookies(requestCookies) : void 0;
15
15
  const internalContext = {
@@ -1 +1 @@
1
- {"version":3,"file":"context.mjs","names":[],"sources":["../src/context.ts"],"sourcesContent":["import type { InferRouteParams } from \"rou3\";\nimport type { CookieOptions, CookiePrefixOptions } from \"./cookies\";\nimport {\n\tgetCookieKey,\n\tparseCookies,\n\tserializeCookie,\n\tserializeSignedCookie,\n} from \"./cookies\";\nimport { getCryptoKey, verifySignature } from \"./crypto\";\nimport type { EndpointOptions } from \"./endpoint\";\nimport type { Status, statusCodes } from \"./error\";\nimport { APIError, ValidationError } from \"./error\";\nimport type { IsEmptyObject, Prettify, UnionToIntersection } from \"./helper\";\nimport type { MiddlewareHandler, MiddlewareOptions } from \"./middleware\";\nimport type { StandardSchemaV1 } from \"./standard-schema\";\nimport { isRequest } from \"./utils\";\nimport { runValidation } from \"./validator\";\n\nexport type HTTPMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\nexport type Method = HTTPMethod | \"*\";\n\nexport type InferBodyInput<\n\tOptions extends EndpointOptions | MiddlewareOptions,\n\tBody = Options[\"metadata\"] extends {\n\t\t$Infer: {\n\t\t\tbody: infer B;\n\t\t};\n\t}\n\t\t? B\n\t\t: Options[\"body\"] extends StandardSchemaV1\n\t\t\t? StandardSchemaV1.InferInput<Options[\"body\"]>\n\t\t\t: undefined,\n> = undefined extends Body\n\t? {\n\t\t\tbody?: Body;\n\t\t}\n\t: {\n\t\t\tbody: Body;\n\t\t};\n\nexport type InferBody<Options extends EndpointOptions | MiddlewareOptions> =\n\tOptions[\"metadata\"] extends {\n\t\t$Infer: {\n\t\t\tbody: infer Body;\n\t\t};\n\t}\n\t\t? Body\n\t\t: Options[\"body\"] extends StandardSchemaV1\n\t\t\t? StandardSchemaV1.InferOutput<Options[\"body\"]>\n\t\t\t: any;\n\nexport type InferQueryInput<\n\tOptions extends EndpointOptions | MiddlewareOptions,\n\tQuery = Options[\"metadata\"] extends {\n\t\t$Infer: {\n\t\t\tquery: infer Query;\n\t\t};\n\t}\n\t\t? Query\n\t\t: Options[\"query\"] extends StandardSchemaV1\n\t\t\t? StandardSchemaV1.InferInput<Options[\"query\"]>\n\t\t\t: Record<string, any> | undefined,\n> = undefined extends Query\n\t? {\n\t\t\tquery?: Query;\n\t\t}\n\t: {\n\t\t\tquery: Query;\n\t\t};\n\nexport type InferQuery<Options extends EndpointOptions | MiddlewareOptions> =\n\tOptions[\"metadata\"] extends {\n\t\t$Infer: {\n\t\t\tquery: infer Query;\n\t\t};\n\t}\n\t\t? Query\n\t\t: Options[\"query\"] extends StandardSchemaV1\n\t\t\t? StandardSchemaV1.InferOutput<Options[\"query\"]>\n\t\t\t: Record<string, any> | undefined;\n\nexport type InferMethod<Options extends EndpointOptions> =\n\tOptions[\"method\"] extends Array<Method>\n\t\t? Options[\"method\"][number]\n\t\t: Options[\"method\"] extends \"*\"\n\t\t\t? HTTPMethod\n\t\t\t: Options[\"method\"];\n\nexport type InferInputMethod<\n\tOptions extends EndpointOptions,\n\tMethod = Options[\"method\"] extends Array<any>\n\t\t? Options[\"method\"][number] | undefined\n\t\t: Options[\"method\"] extends \"*\"\n\t\t\t? HTTPMethod\n\t\t\t: Options[\"method\"] | undefined,\n> = undefined extends Method\n\t? {\n\t\t\tmethod?: Method;\n\t\t}\n\t: {\n\t\t\tmethod: Method;\n\t\t};\n\ntype TrailingWildcardKey<Path extends string> =\n\tPath extends `${infer Prefix}/*${\"\" | \"/\"}`\n\t\t? Exclude<keyof InferRouteParams<Path>, keyof InferRouteParams<Prefix>>\n\t\t: never;\n\ntype RouteParams<Path extends string> = {\n\t[Key in keyof InferRouteParams<Path>]: Key extends TrailingWildcardKey<Path>\n\t\t? InferRouteParams<Path>[Key] | undefined\n\t\t: InferRouteParams<Path>[Key];\n};\n\nexport type InferParam<Path extends string> = string extends Path\n\t? Record<string, string | undefined> | undefined\n\t: [Path] extends [never]\n\t\t? Record<string, string | undefined> | undefined\n\t\t: IsEmptyObject<RouteParams<Path>> extends true\n\t\t\t? Record<string, string | undefined> | undefined\n\t\t\t: Prettify<RouteParams<Path>>;\n\nexport type InferParamInput<Path extends string> = string extends Path\n\t? { params?: Record<string, string | undefined> }\n\t: [Path] extends [never]\n\t\t? { params?: Record<string, string | undefined> }\n\t\t: IsEmptyObject<RouteParams<Path>> extends true\n\t\t\t? {\n\t\t\t\t\tparams?: Record<string, string | undefined>;\n\t\t\t\t}\n\t\t\t: {\n\t\t\t\t\tparams: Prettify<RouteParams<Path>>;\n\t\t\t\t};\n\nexport type InferRequest<Option extends EndpointOptions | MiddlewareOptions> =\n\tOption[\"requireRequest\"] extends true ? Request : Request | undefined;\n\nexport type InferRequestInput<\n\tOption extends EndpointOptions | MiddlewareOptions,\n> = Option[\"requireRequest\"] extends true\n\t? {\n\t\t\trequest: Request;\n\t\t}\n\t: {\n\t\t\trequest?: Request;\n\t\t};\n\nexport type InferHeaders<Option extends EndpointOptions | MiddlewareOptions> =\n\tOption[\"requireHeaders\"] extends true ? Headers : Headers | undefined;\n\nexport type InferHeadersInput<\n\tOption extends EndpointOptions | MiddlewareOptions,\n> = Option[\"requireHeaders\"] extends true\n\t? {\n\t\t\theaders: HeadersInit;\n\t\t}\n\t: {\n\t\t\theaders?: HeadersInit;\n\t\t};\n\ntype InferMiddlewareContext<T> = T extends (...args: never[]) => infer Result\n\t? unknown extends Awaited<Result>\n\t\t? never\n\t\t: Extract<Awaited<Result>, object>\n\t: never;\n\ntype InferMiddlewareContexts<Opts extends EndpointOptions[\"use\"]> =\n\tOpts extends MiddlewareHandler[]\n\t\t? InferMiddlewareContext<Opts[number]>\n\t\t: never;\n\nexport type InferUse<Opts extends EndpointOptions[\"use\"]> = [\n\tInferMiddlewareContexts<Opts>,\n] extends [never]\n\t? object\n\t: UnionToIntersection<InferMiddlewareContexts<Opts>>;\n\nexport type InferMiddlewareBody<Options extends MiddlewareOptions> =\n\tOptions[\"body\"] extends StandardSchemaV1<infer T> ? T : any;\n\nexport type InferMiddlewareQuery<Options extends MiddlewareOptions> =\n\tOptions[\"query\"] extends StandardSchemaV1<infer T>\n\t\t? T\n\t\t: Record<string, any> | undefined;\n\nexport type InputContext<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n> = InferBodyInput<Options> &\n\tInferInputMethod<Options> &\n\tInferQueryInput<Options> &\n\tInferParamInput<Path> &\n\tInferRequestInput<Options> &\n\tInferHeadersInput<Options> & {\n\t\tasResponse?: boolean;\n\t\treturnHeaders?: boolean;\n\t\treturnStatus?: boolean;\n\t\tuse?: MiddlewareHandler[];\n\t\tpath?: string;\n\t\tcontext?: Record<string, any>;\n\t};\n\nexport const createInternalContext = async (\n\tcontext: InputContext<any, any>,\n\t{\n\t\toptions,\n\t\tpath,\n\t}: {\n\t\toptions: EndpointOptions;\n\t\tpath?: string;\n\t},\n) => {\n\tconst headers = new Headers();\n\tlet responseStatus: Status | undefined = undefined;\n\n\tconst { data, error } = await runValidation(options, context);\n\tif (error) {\n\t\tthrow new ValidationError(error.message, error.issues);\n\t}\n\tconst requestHeaders: Headers | null =\n\t\t\"headers\" in context\n\t\t\t? context.headers instanceof Headers\n\t\t\t\t? context.headers\n\t\t\t\t: new Headers(context.headers)\n\t\t\t: \"request\" in context && isRequest(context.request)\n\t\t\t\t? context.request.headers\n\t\t\t\t: null;\n\tconst requestCookies = requestHeaders?.get(\"cookie\");\n\tconst parsedCookies = requestCookies\n\t\t? parseCookies(requestCookies)\n\t\t: undefined;\n\n\tconst internalContext = {\n\t\t...context,\n\t\tbody: data.body,\n\t\tquery: data.query,\n\t\tpath: context.path || path || \"virtual:\",\n\t\tcontext: \"context\" in context && context.context ? context.context : {},\n\t\treturned: undefined as any,\n\t\theaders: context?.headers,\n\t\trequest: context?.request,\n\t\tparams: \"params\" in context ? context.params : undefined,\n\t\tmethod:\n\t\t\tcontext.method ??\n\t\t\t(Array.isArray(options.method)\n\t\t\t\t? options.method[0]\n\t\t\t\t: options.method === \"*\"\n\t\t\t\t\t? \"GET\"\n\t\t\t\t\t: options.method),\n\t\tsetHeader: (key: string, value: string) => {\n\t\t\theaders.set(key, value);\n\t\t},\n\t\tgetHeader: (key: string) => {\n\t\t\tif (!requestHeaders) return null;\n\t\t\treturn requestHeaders.get(key);\n\t\t},\n\t\tgetCookie: (key: string, prefix?: CookiePrefixOptions) => {\n\t\t\tconst finalKey = getCookieKey(key, prefix);\n\t\t\tif (!finalKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn parsedCookies?.get(finalKey) || null;\n\t\t},\n\t\tgetSignedCookie: async (\n\t\t\tkey: string,\n\t\t\tsecret: string,\n\t\t\tprefix?: CookiePrefixOptions,\n\t\t) => {\n\t\t\tconst finalKey = getCookieKey(key, prefix);\n\t\t\tif (!finalKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst value = parsedCookies?.get(finalKey);\n\t\t\tif (!value) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst signatureStartPos = value.lastIndexOf(\".\");\n\t\t\tif (signatureStartPos < 1) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst signedValue = value.substring(0, signatureStartPos);\n\t\t\tconst signature = value.substring(signatureStartPos + 1);\n\t\t\tif (signature.length !== 44 || !signature.endsWith(\"=\")) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst secretKey = await getCryptoKey(secret);\n\t\t\tconst isVerified = await verifySignature(\n\t\t\t\tsignature,\n\t\t\t\tsignedValue,\n\t\t\t\tsecretKey,\n\t\t\t);\n\t\t\treturn isVerified ? signedValue : false;\n\t\t},\n\t\tsetCookie: (key: string, value: string, options?: CookieOptions) => {\n\t\t\tconst cookie = serializeCookie(key, value, options);\n\t\t\theaders.append(\"set-cookie\", cookie);\n\t\t\treturn cookie;\n\t\t},\n\t\tsetSignedCookie: async (\n\t\t\tkey: string,\n\t\t\tvalue: string,\n\t\t\tsecret: string,\n\t\t\toptions?: CookieOptions,\n\t\t) => {\n\t\t\tconst cookie = await serializeSignedCookie(key, value, secret, options);\n\t\t\theaders.append(\"set-cookie\", cookie);\n\t\t\treturn cookie;\n\t\t},\n\t\tredirect: (url: string) => {\n\t\t\theaders.set(\"location\", url);\n\t\t\treturn new APIError(\"FOUND\", undefined, headers);\n\t\t},\n\t\terror: (\n\t\t\tstatus: keyof typeof statusCodes | Status,\n\t\t\tbody?:\n\t\t\t\t| {\n\t\t\t\t\t\tmessage?: string;\n\t\t\t\t\t\tcode?: string;\n\t\t\t\t }\n\t\t\t\t| undefined,\n\t\t\theaders?: HeadersInit,\n\t\t) => {\n\t\t\treturn new APIError(status, body, headers);\n\t\t},\n\t\tsetStatus: (status: Status) => {\n\t\t\tresponseStatus = status;\n\t\t},\n\t\tjson: (\n\t\t\tjson: Record<string, any>,\n\t\t\trouterResponse?:\n\t\t\t\t| {\n\t\t\t\t\t\tstatus?: number;\n\t\t\t\t\t\theaders?: Record<string, string>;\n\t\t\t\t\t\tresponse?: Response;\n\t\t\t\t\t\tbody?: Record<string, any>;\n\t\t\t\t }\n\t\t\t\t| Response,\n\t\t) => {\n\t\t\tif (!context.asResponse) {\n\t\t\t\treturn json;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tbody: routerResponse?.body || json,\n\t\t\t\trouterResponse,\n\t\t\t\t_flag: \"json\",\n\t\t\t};\n\t\t},\n\t\tresponseHeaders: headers,\n\t\tget responseStatus() {\n\t\t\treturn responseStatus;\n\t\t},\n\t};\n\t//if context was shimmed through the input we want to apply it\n\tfor (const middleware of options.use || []) {\n\t\tconst response = (await middleware({\n\t\t\t...internalContext,\n\t\t\treturnHeaders: true,\n\t\t\tasResponse: false,\n\t\t})) as {\n\t\t\tresponse?: any;\n\t\t\theaders?: Headers;\n\t\t};\n\t\tif (response.response) {\n\t\t\tObject.assign(internalContext.context, response.response);\n\t\t}\n\t\t/**\n\t\t * Apply headers from the middleware to the endpoint headers\n\t\t */\n\t\tif (response.headers) {\n\t\t\tresponse.headers.forEach((value, key) => {\n\t\t\t\tinternalContext.responseHeaders.set(key, value);\n\t\t\t});\n\t\t}\n\t}\n\treturn internalContext;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"context.mjs","names":[],"sources":["../src/context.ts"],"sourcesContent":["import type { InferRouteParams } from \"rou3\";\nimport type { CookieOptions, CookiePrefixOptions } from \"./cookies\";\nimport {\n\tgetCookieKey,\n\tparseCookies,\n\tserializeCookie,\n\tserializeSignedCookie,\n} from \"./cookies\";\nimport { getCryptoKey, verifySignature } from \"./crypto\";\nimport type { EndpointOptions } from \"./endpoint\";\nimport type { Status, statusCodes } from \"./error\";\nimport { APIError, ValidationError } from \"./error\";\nimport type { IsEmptyObject, Prettify, UnionToIntersection } from \"./helper\";\nimport type { MiddlewareHandler, MiddlewareOptions } from \"./middleware\";\nimport type { StandardSchemaV1 } from \"./standard-schema\";\nimport { isRequest } from \"./utils\";\nimport { runValidation } from \"./validator\";\n\nexport type HTTPMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\nexport type Method = HTTPMethod | \"*\";\n\nexport type InferBodyInput<\n\tOptions extends EndpointOptions | MiddlewareOptions,\n\tBody = Options[\"metadata\"] extends {\n\t\t$Infer: {\n\t\t\tbody: infer B;\n\t\t};\n\t}\n\t\t? B\n\t\t: Options[\"body\"] extends StandardSchemaV1\n\t\t\t? StandardSchemaV1.InferInput<Options[\"body\"]>\n\t\t\t: undefined,\n> = undefined extends Body\n\t? {\n\t\t\tbody?: Body;\n\t\t}\n\t: {\n\t\t\tbody: Body;\n\t\t};\n\nexport type InferBody<Options extends EndpointOptions | MiddlewareOptions> =\n\tOptions[\"metadata\"] extends {\n\t\t$Infer: {\n\t\t\tbody: infer Body;\n\t\t};\n\t}\n\t\t? Body\n\t\t: Options[\"body\"] extends StandardSchemaV1\n\t\t\t? StandardSchemaV1.InferOutput<Options[\"body\"]>\n\t\t\t: any;\n\nexport type InferQueryInput<\n\tOptions extends EndpointOptions | MiddlewareOptions,\n\tQuery = Options[\"metadata\"] extends {\n\t\t$Infer: {\n\t\t\tquery: infer Query;\n\t\t};\n\t}\n\t\t? Query\n\t\t: Options[\"query\"] extends StandardSchemaV1\n\t\t\t? StandardSchemaV1.InferInput<Options[\"query\"]>\n\t\t\t: Record<string, any> | undefined,\n> = undefined extends Query\n\t? {\n\t\t\tquery?: Query;\n\t\t}\n\t: {\n\t\t\tquery: Query;\n\t\t};\n\nexport type InferQuery<Options extends EndpointOptions | MiddlewareOptions> =\n\tOptions[\"metadata\"] extends {\n\t\t$Infer: {\n\t\t\tquery: infer Query;\n\t\t};\n\t}\n\t\t? Query\n\t\t: Options[\"query\"] extends StandardSchemaV1\n\t\t\t? StandardSchemaV1.InferOutput<Options[\"query\"]>\n\t\t\t: Record<string, any> | undefined;\n\nexport type InferMethod<Options extends EndpointOptions> =\n\tOptions[\"method\"] extends Array<Method>\n\t\t? Options[\"method\"][number]\n\t\t: Options[\"method\"] extends \"*\"\n\t\t\t? HTTPMethod\n\t\t\t: Options[\"method\"];\n\nexport type InferInputMethod<\n\tOptions extends EndpointOptions,\n\tMethod = Options[\"method\"] extends Array<any>\n\t\t? Options[\"method\"][number] | undefined\n\t\t: Options[\"method\"] extends \"*\"\n\t\t\t? HTTPMethod\n\t\t\t: Options[\"method\"] | undefined,\n> = undefined extends Method\n\t? {\n\t\t\tmethod?: Method;\n\t\t}\n\t: {\n\t\t\tmethod: Method;\n\t\t};\n\ntype TrailingWildcardKey<Path extends string> =\n\tPath extends `${infer Prefix}/*${\"\" | \"/\"}`\n\t\t? Exclude<keyof InferRouteParams<Path>, keyof InferRouteParams<Prefix>>\n\t\t: never;\n\ntype RouteParams<Path extends string> = {\n\t[Key in keyof InferRouteParams<Path>]: Key extends TrailingWildcardKey<Path>\n\t\t? InferRouteParams<Path>[Key] | undefined\n\t\t: InferRouteParams<Path>[Key];\n};\n\nexport type InferParam<Path extends string> = string extends Path\n\t? Record<string, string | undefined> | undefined\n\t: [Path] extends [never]\n\t\t? Record<string, string | undefined> | undefined\n\t\t: IsEmptyObject<RouteParams<Path>> extends true\n\t\t\t? Record<string, string | undefined> | undefined\n\t\t\t: Prettify<RouteParams<Path>>;\n\nexport type InferParamInput<Path extends string> = string extends Path\n\t? { params?: Record<string, string | undefined> }\n\t: [Path] extends [never]\n\t\t? { params?: Record<string, string | undefined> }\n\t\t: IsEmptyObject<RouteParams<Path>> extends true\n\t\t\t? {\n\t\t\t\t\tparams?: Record<string, string | undefined>;\n\t\t\t\t}\n\t\t\t: {\n\t\t\t\t\tparams: Prettify<RouteParams<Path>>;\n\t\t\t\t};\n\nexport type InferRequest<Option extends EndpointOptions | MiddlewareOptions> =\n\tOption[\"requireRequest\"] extends true ? Request : Request | undefined;\n\nexport type InferRequestInput<\n\tOption extends EndpointOptions | MiddlewareOptions,\n> = Option[\"requireRequest\"] extends true\n\t? {\n\t\t\trequest: Request;\n\t\t}\n\t: {\n\t\t\trequest?: Request | undefined;\n\t\t};\n\nexport type InferHeaders<Option extends EndpointOptions | MiddlewareOptions> =\n\tOption[\"requireHeaders\"] extends true ? Headers : Headers | undefined;\n\nexport type InferHeadersInput<\n\tOption extends EndpointOptions | MiddlewareOptions,\n> = Option[\"requireHeaders\"] extends true\n\t? {\n\t\t\theaders: HeadersInit;\n\t\t}\n\t: {\n\t\t\theaders?: HeadersInit | undefined;\n\t\t};\n\ntype InferMiddlewareContext<T> = T extends (...args: never[]) => infer Result\n\t? unknown extends Awaited<Result>\n\t\t? never\n\t\t: Extract<Awaited<Result>, object>\n\t: never;\n\ntype InferMiddlewareContexts<Opts extends EndpointOptions[\"use\"]> =\n\tOpts extends MiddlewareHandler[]\n\t\t? InferMiddlewareContext<Opts[number]>\n\t\t: never;\n\nexport type InferUse<Opts extends EndpointOptions[\"use\"]> = [\n\tInferMiddlewareContexts<Opts>,\n] extends [never]\n\t? object\n\t: UnionToIntersection<InferMiddlewareContexts<Opts>>;\n\nexport type InferMiddlewareBody<Options extends MiddlewareOptions> =\n\tOptions[\"body\"] extends StandardSchemaV1<infer T> ? T : any;\n\nexport type InferMiddlewareQuery<Options extends MiddlewareOptions> =\n\tOptions[\"query\"] extends StandardSchemaV1<infer T>\n\t\t? T\n\t\t: Record<string, any> | undefined;\n\nexport type InputContext<\n\tPath extends string,\n\tOptions extends EndpointOptions,\n> = InferBodyInput<Options> &\n\tInferInputMethod<Options> &\n\tInferQueryInput<Options> &\n\tInferParamInput<Path> &\n\tInferRequestInput<Options> &\n\tInferHeadersInput<Options> & {\n\t\tasResponse?: boolean;\n\t\treturnHeaders?: boolean;\n\t\treturnStatus?: boolean;\n\t\tuse?: MiddlewareHandler[];\n\t\tpath?: string;\n\t\tcontext?: Record<string, any>;\n\t};\n\nexport const createInternalContext = async (\n\tcontext: InputContext<any, any>,\n\t{\n\t\toptions,\n\t\tpath,\n\t}: {\n\t\toptions: EndpointOptions;\n\t\tpath?: string | undefined;\n\t},\n) => {\n\tconst headers = new Headers();\n\tlet responseStatus: Status | undefined = undefined;\n\n\tconst { data, error } = await runValidation(options, context);\n\tif (error) {\n\t\tthrow new ValidationError(error.message, error.issues);\n\t}\n\tconst requestHeaders: Headers | null =\n\t\tcontext.headers !== undefined\n\t\t\t? context.headers instanceof Headers\n\t\t\t\t? context.headers\n\t\t\t\t: new Headers(context.headers)\n\t\t\t: \"request\" in context && isRequest(context.request)\n\t\t\t\t? context.request.headers\n\t\t\t\t: null;\n\tconst requestCookies = requestHeaders?.get(\"cookie\");\n\tconst parsedCookies = requestCookies\n\t\t? parseCookies(requestCookies)\n\t\t: undefined;\n\n\tconst internalContext = {\n\t\t...context,\n\t\tbody: data.body,\n\t\tquery: data.query,\n\t\tpath: context.path || path || \"virtual:\",\n\t\tcontext: \"context\" in context && context.context ? context.context : {},\n\t\treturned: undefined as any,\n\t\theaders: context?.headers,\n\t\trequest: context?.request,\n\t\tparams: \"params\" in context ? context.params : undefined,\n\t\tmethod:\n\t\t\tcontext.method ??\n\t\t\t(Array.isArray(options.method)\n\t\t\t\t? options.method[0]\n\t\t\t\t: options.method === \"*\"\n\t\t\t\t\t? \"GET\"\n\t\t\t\t\t: options.method),\n\t\tsetHeader: (key: string, value: string) => {\n\t\t\theaders.set(key, value);\n\t\t},\n\t\tgetHeader: (key: string) => {\n\t\t\tif (!requestHeaders) return null;\n\t\t\treturn requestHeaders.get(key);\n\t\t},\n\t\tgetCookie: (key: string, prefix?: CookiePrefixOptions) => {\n\t\t\tconst finalKey = getCookieKey(key, prefix);\n\t\t\tif (!finalKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn parsedCookies?.get(finalKey) || null;\n\t\t},\n\t\tgetSignedCookie: async (\n\t\t\tkey: string,\n\t\t\tsecret: string,\n\t\t\tprefix?: CookiePrefixOptions,\n\t\t) => {\n\t\t\tconst finalKey = getCookieKey(key, prefix);\n\t\t\tif (!finalKey) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst value = parsedCookies?.get(finalKey);\n\t\t\tif (!value) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst signatureStartPos = value.lastIndexOf(\".\");\n\t\t\tif (signatureStartPos < 1) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst signedValue = value.substring(0, signatureStartPos);\n\t\t\tconst signature = value.substring(signatureStartPos + 1);\n\t\t\tif (signature.length !== 44 || !signature.endsWith(\"=\")) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst secretKey = await getCryptoKey(secret);\n\t\t\tconst isVerified = await verifySignature(\n\t\t\t\tsignature,\n\t\t\t\tsignedValue,\n\t\t\t\tsecretKey,\n\t\t\t);\n\t\t\treturn isVerified ? signedValue : false;\n\t\t},\n\t\tsetCookie: (key: string, value: string, options?: CookieOptions) => {\n\t\t\tconst cookie = serializeCookie(key, value, options);\n\t\t\theaders.append(\"set-cookie\", cookie);\n\t\t\treturn cookie;\n\t\t},\n\t\tsetSignedCookie: async (\n\t\t\tkey: string,\n\t\t\tvalue: string,\n\t\t\tsecret: string,\n\t\t\toptions?: CookieOptions,\n\t\t) => {\n\t\t\tconst cookie = await serializeSignedCookie(key, value, secret, options);\n\t\t\theaders.append(\"set-cookie\", cookie);\n\t\t\treturn cookie;\n\t\t},\n\t\tredirect: (url: string) => {\n\t\t\theaders.set(\"location\", url);\n\t\t\treturn new APIError(\"FOUND\", undefined, headers);\n\t\t},\n\t\terror: (\n\t\t\tstatus: keyof typeof statusCodes | Status,\n\t\t\tbody?:\n\t\t\t\t| {\n\t\t\t\t\t\tmessage?: string;\n\t\t\t\t\t\tcode?: string;\n\t\t\t\t }\n\t\t\t\t| undefined,\n\t\t\theaders?: HeadersInit,\n\t\t) => {\n\t\t\treturn new APIError(status, body, headers);\n\t\t},\n\t\tsetStatus: (status: Status) => {\n\t\t\tresponseStatus = status;\n\t\t},\n\t\tjson: (\n\t\t\tjson: Record<string, any>,\n\t\t\trouterResponse?:\n\t\t\t\t| {\n\t\t\t\t\t\tstatus?: number;\n\t\t\t\t\t\theaders?: Record<string, string>;\n\t\t\t\t\t\tresponse?: Response;\n\t\t\t\t\t\tbody?: Record<string, any>;\n\t\t\t\t }\n\t\t\t\t| Response,\n\t\t) => {\n\t\t\tif (!context.asResponse) {\n\t\t\t\treturn json;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tbody: routerResponse?.body || json,\n\t\t\t\trouterResponse,\n\t\t\t\t_flag: \"json\",\n\t\t\t};\n\t\t},\n\t\tresponseHeaders: headers,\n\t\tget responseStatus() {\n\t\t\treturn responseStatus;\n\t\t},\n\t};\n\t//if context was shimmed through the input we want to apply it\n\tfor (const middleware of options.use || []) {\n\t\tconst response = (await middleware({\n\t\t\t...internalContext,\n\t\t\treturnHeaders: true,\n\t\t\tasResponse: false,\n\t\t})) as {\n\t\t\tresponse?: any;\n\t\t\theaders?: Headers;\n\t\t};\n\t\tif (response.response) {\n\t\t\tObject.assign(internalContext.context, response.response);\n\t\t}\n\t\t/**\n\t\t * Apply headers from the middleware to the endpoint headers\n\t\t */\n\t\tif (response.headers) {\n\t\t\tresponse.headers.forEach((value, key) => {\n\t\t\t\tinternalContext.responseHeaders.set(key, value);\n\t\t\t});\n\t\t}\n\t}\n\treturn internalContext;\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"cookies.cjs","names":["tryDecode","signCookieValue"],"sources":["../src/cookies.ts"],"sourcesContent":["import { signCookieValue } from \"./crypto\";\nimport { tryDecode } from \"./utils\";\n\nexport type CookiePrefixOptions = \"host\" | \"secure\";\n\nconst COOKIE_PREFIXES = {\n\tsecure: \"__Secure-\",\n\thost: \"__Host-\",\n} as const satisfies Record<CookiePrefixOptions, string>;\n\nexport type CookieOptions = {\n\t/**\n\t * Domain of the cookie\n\t *\n\t * The Domain attribute specifies which server can receive a cookie. If specified, cookies are\n\t * available on the specified server and its subdomains. If the it is not\n\t * specified, the cookies are available on the server that sets it but not on\n\t * its subdomains.\n\t *\n\t * @example\n\t * `domain: \"example.com\"`\n\t */\n\tdomain?: string;\n\t/**\n\t * A lifetime of a cookie. Permanent cookies are deleted after the date specified in the\n\t * Expires attribute:\n\t *\n\t * Expires has been available for longer than Max-Age, however Max-Age is less error-prone, and\n\t * takes precedence when both are set. The rationale behind this is that when you set an\n\t * Expires date and time, they're relative to the client the cookie is being set on. If the\n\t * server is set to a different time, this could cause errors\n\t */\n\texpires?: Date;\n\t/**\n\t * Forbids JavaScript from accessing the cookie, for example, through the Document.cookie\n\t * property. Note that a cookie that has been created with HttpOnly will still be sent with\n\t * JavaScript-initiated requests, for example, when calling XMLHttpRequest.send() or fetch().\n\t * This mitigates attacks against cross-site scripting\n\t */\n\thttpOnly?: boolean;\n\t/**\n\t * Indicates the number of seconds until the cookie expires. A zero or negative number will\n\t * expire the cookie immediately. If both Expires and Max-Age are set, Max-Age has precedence.\n\t *\n\t * @example 604800 - 7 days\n\t */\n\tmaxAge?: number;\n\t/**\n\t * Indicates the path that must exist in the requested URL for the browser to send the Cookie\n\t * header.\n\t *\n\t * @example\n\t * \"/docs\"\n\t * // -> the request paths /docs, /docs/, /docs/Web/, and /docs/Web/HTTP will all match. the request paths /, /fr/docs will not match.\n\t */\n\tpath?: string;\n\t/**\n\t * Indicates that the cookie is sent to the server only when a request is made with the https:\n\t * scheme (except on localhost), and therefore, is more resistant to man-in-the-middle attacks.\n\t */\n\tsecure?: boolean;\n\t/**\n\t * Controls whether or not a cookie is sent with cross-site requests, providing some protection\n\t * against cross-site request forgery attacks (CSRF).\n\t *\n\t * Strict - Means that the browser sends the cookie only for same-site requests, that is,\n\t * requests originating from the same site that set the cookie. If a request originates from a\n\t * different domain or scheme (even with the same domain), no cookies with the SameSite=Strict\n\t * attribute are sent.\n\t *\n\t * Lax - Means that the cookie is not sent on cross-site requests, such as on requests to load\n\t * images or frames, but is sent when a user is navigating to the origin site from an external\n\t * site (for example, when following a link). This is the default behavior if the SameSite\n\t * attribute is not specified.\n\t *\n\t * None - Means that the browser sends the cookie with both cross-site and same-site requests.\n\t * The Secure attribute must also be set when setting this value.\n\t */\n\tsameSite?: \"Strict\" | \"Lax\" | \"None\" | \"strict\" | \"lax\" | \"none\";\n\t/**\n\t * Indicates that the cookie should be stored using partitioned storage. Note that if this is\n\t * set, the Secure directive must also be set.\n\t *\n\t * @see https://developer.mozilla.org/en-US/docs/Web/Privacy/Privacy_sandbox/Partitioned_cookies\n\t */\n\tpartitioned?: boolean;\n\t/**\n\t * Cooke Prefix\n\t *\n\t * - secure: `__Secure-` -> `__Secure-cookie-name`\n\t * - host: `__Host-` -> `__Host-cookie-name`\n\t *\n\t * Required Secure, Path, and Domain attributes are applied automatically.\n\t */\n\tprefix?: CookiePrefixOptions;\n};\n\ntype Cookie = {\n\tname: string;\n\tvalue: string;\n\toptions: CookieOptions;\n};\n\nexport const getCookieKey = (key: string, prefix?: CookiePrefixOptions) => {\n\tif (!prefix) return key;\n\tif (prefix !== \"secure\" && prefix !== \"host\") return undefined;\n\treturn COOKIE_PREFIXES[prefix] + key;\n};\n\n/**\n * Parse an HTTP Cookie header string and returning an object of all cookie\n * name-value pairs.\n *\n * Inspired by https://github.com/unjs/cookie-es/blob/main/src/cookie/parse.ts\n *\n * @param str the string representing a `Cookie` header value\n */\nexport function parseCookies(str: string) {\n\tif (typeof str !== \"string\") {\n\t\tthrow new TypeError(\"argument str must be a string\");\n\t}\n\n\tconst cookies: Map<string, string> = new Map();\n\n\tlet index = 0;\n\twhile (index < str.length) {\n\t\tconst eqIdx = str.indexOf(\"=\", index);\n\n\t\tif (eqIdx === -1) {\n\t\t\tbreak;\n\t\t}\n\n\t\tlet endIdx = str.indexOf(\";\", index);\n\n\t\tif (endIdx === -1) {\n\t\t\tendIdx = str.length;\n\t\t} else if (endIdx < eqIdx) {\n\t\t\tindex = str.lastIndexOf(\";\", eqIdx - 1) + 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst key = str.slice(index, eqIdx).trim();\n\t\tif (!cookies.has(key)) {\n\t\t\tlet val = str.slice(eqIdx + 1, endIdx).trim();\n\t\t\tif (val.codePointAt(0) === 0x22) {\n\t\t\t\tval = val.slice(1, -1);\n\t\t\t}\n\t\t\tcookies.set(key, tryDecode(val));\n\t\t}\n\n\t\tindex = endIdx + 1;\n\t}\n\n\treturn cookies;\n}\n\nfunction resolveCookie(\n\tname: string,\n\tvalue: string,\n\toptions: CookieOptions = {},\n): Cookie {\n\tconst resolvedName = getCookieKey(name, options.prefix) ?? name;\n\tconst resolvedOptions = { ...options };\n\n\tconst lowerName = resolvedName.toLowerCase();\n\tif (lowerName.startsWith(\"__host-\")) {\n\t\tresolvedOptions.secure = true;\n\t\tresolvedOptions.path = \"/\";\n\t\tresolvedOptions.domain = undefined;\n\t} else if (lowerName.startsWith(\"__secure-\")) {\n\t\tresolvedOptions.secure = true;\n\t}\n\tif (\n\t\tresolvedOptions.partitioned === true ||\n\t\tresolvedOptions.sameSite?.toLowerCase() === \"none\"\n\t) {\n\t\tresolvedOptions.secure = true;\n\t}\n\n\treturn { name: resolvedName, value, options: resolvedOptions };\n}\n\nfunction serializeCookieValue({ name, value, options }: Cookie) {\n\tlet cookie = `${name}=${value}`;\n\tif (typeof options.maxAge === \"number\" && options.maxAge >= 0) {\n\t\tif (options.maxAge > 34560000) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Cookies Max-Age SHOULD NOT be greater than 400 days (34560000 seconds) in duration.\",\n\t\t\t);\n\t\t}\n\t\tcookie += `; Max-Age=${Math.floor(options.maxAge)}`;\n\t}\n\n\tif (options.domain) {\n\t\tcookie += `; Domain=${options.domain}`;\n\t}\n\n\tif (options.path) {\n\t\tcookie += `; Path=${options.path}`;\n\t}\n\n\tif (options.expires) {\n\t\tif (options.expires.getTime() - Date.now() > 34560000_000) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Cookies Expires SHOULD NOT be greater than 400 days (34560000 seconds) in the future.\",\n\t\t\t);\n\t\t}\n\t\tcookie += `; Expires=${options.expires.toUTCString()}`;\n\t}\n\n\tif (options.httpOnly) {\n\t\tcookie += \"; HttpOnly\";\n\t}\n\n\tif (options.secure) {\n\t\tcookie += \"; Secure\";\n\t}\n\n\tif (options.sameSite) {\n\t\tcookie += `; SameSite=${options.sameSite.charAt(0).toUpperCase() + options.sameSite.slice(1)}`;\n\t}\n\n\tif (options.partitioned) {\n\t\tcookie += \"; Partitioned\";\n\t}\n\n\treturn cookie;\n}\n\nexport const serializeCookie = (\n\tkey: string,\n\tvalue: string,\n\topt?: CookieOptions,\n) => {\n\tvalue = encodeURIComponent(value);\n\treturn serializeCookieValue(resolveCookie(key, value, opt));\n};\n\nexport const serializeSignedCookie = async (\n\tkey: string,\n\tvalue: string,\n\tsecret: string,\n\topt?: CookieOptions,\n) => {\n\tvalue = await signCookieValue(value, secret);\n\treturn serializeCookieValue(resolveCookie(key, value, opt));\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"cookies.cjs","names":["tryDecode","signCookieValue"],"sources":["../src/cookies.ts"],"sourcesContent":["import { signCookieValue } from \"./crypto\";\nimport { tryDecode } from \"./utils\";\n\nexport type CookiePrefixOptions = \"host\" | \"secure\";\n\nconst COOKIE_PREFIXES = {\n\tsecure: \"__Secure-\",\n\thost: \"__Host-\",\n} as const satisfies Record<CookiePrefixOptions, string>;\n\nexport type CookieOptions = {\n\t/**\n\t * Domain of the cookie\n\t *\n\t * The Domain attribute specifies which server can receive a cookie. If specified, cookies are\n\t * available on the specified server and its subdomains. If the it is not\n\t * specified, the cookies are available on the server that sets it but not on\n\t * its subdomains.\n\t *\n\t * @example\n\t * `domain: \"example.com\"`\n\t */\n\tdomain?: string | undefined;\n\t/**\n\t * A lifetime of a cookie. Permanent cookies are deleted after the date specified in the\n\t * Expires attribute:\n\t *\n\t * Expires has been available for longer than Max-Age, however Max-Age is less error-prone, and\n\t * takes precedence when both are set. The rationale behind this is that when you set an\n\t * Expires date and time, they're relative to the client the cookie is being set on. If the\n\t * server is set to a different time, this could cause errors\n\t */\n\texpires?: Date;\n\t/**\n\t * Forbids JavaScript from accessing the cookie, for example, through the Document.cookie\n\t * property. Note that a cookie that has been created with HttpOnly will still be sent with\n\t * JavaScript-initiated requests, for example, when calling XMLHttpRequest.send() or fetch().\n\t * This mitigates attacks against cross-site scripting\n\t */\n\thttpOnly?: boolean;\n\t/**\n\t * Indicates the number of seconds until the cookie expires. A zero or negative number will\n\t * expire the cookie immediately. If both Expires and Max-Age are set, Max-Age has precedence.\n\t *\n\t * @example 604800 - 7 days\n\t */\n\tmaxAge?: number;\n\t/**\n\t * Indicates the path that must exist in the requested URL for the browser to send the Cookie\n\t * header.\n\t *\n\t * @example\n\t * \"/docs\"\n\t * // -> the request paths /docs, /docs/, /docs/Web/, and /docs/Web/HTTP will all match. the request paths /, /fr/docs will not match.\n\t */\n\tpath?: string;\n\t/**\n\t * Indicates that the cookie is sent to the server only when a request is made with the https:\n\t * scheme (except on localhost), and therefore, is more resistant to man-in-the-middle attacks.\n\t */\n\tsecure?: boolean;\n\t/**\n\t * Controls whether or not a cookie is sent with cross-site requests, providing some protection\n\t * against cross-site request forgery attacks (CSRF).\n\t *\n\t * Strict - Means that the browser sends the cookie only for same-site requests, that is,\n\t * requests originating from the same site that set the cookie. If a request originates from a\n\t * different domain or scheme (even with the same domain), no cookies with the SameSite=Strict\n\t * attribute are sent.\n\t *\n\t * Lax - Means that the cookie is not sent on cross-site requests, such as on requests to load\n\t * images or frames, but is sent when a user is navigating to the origin site from an external\n\t * site (for example, when following a link). This is the default behavior if the SameSite\n\t * attribute is not specified.\n\t *\n\t * None - Means that the browser sends the cookie with both cross-site and same-site requests.\n\t * The Secure attribute must also be set when setting this value.\n\t */\n\tsameSite?: \"Strict\" | \"Lax\" | \"None\" | \"strict\" | \"lax\" | \"none\";\n\t/**\n\t * Indicates that the cookie should be stored using partitioned storage. Note that if this is\n\t * set, the Secure directive must also be set.\n\t *\n\t * @see https://developer.mozilla.org/en-US/docs/Web/Privacy/Privacy_sandbox/Partitioned_cookies\n\t */\n\tpartitioned?: boolean;\n\t/**\n\t * Cooke Prefix\n\t *\n\t * - secure: `__Secure-` -> `__Secure-cookie-name`\n\t * - host: `__Host-` -> `__Host-cookie-name`\n\t *\n\t * Required Secure, Path, and Domain attributes are applied automatically.\n\t */\n\tprefix?: CookiePrefixOptions;\n};\n\ntype Cookie = {\n\tname: string;\n\tvalue: string;\n\toptions: CookieOptions;\n};\n\nexport const getCookieKey = (key: string, prefix?: CookiePrefixOptions) => {\n\tif (!prefix) return key;\n\tif (prefix !== \"secure\" && prefix !== \"host\") return undefined;\n\treturn COOKIE_PREFIXES[prefix] + key;\n};\n\n/**\n * Parse an HTTP Cookie header string and returning an object of all cookie\n * name-value pairs.\n *\n * Inspired by https://github.com/unjs/cookie-es/blob/main/src/cookie/parse.ts\n *\n * @param str the string representing a `Cookie` header value\n */\nexport function parseCookies(str: string) {\n\tif (typeof str !== \"string\") {\n\t\tthrow new TypeError(\"argument str must be a string\");\n\t}\n\n\tconst cookies: Map<string, string> = new Map();\n\n\tlet index = 0;\n\twhile (index < str.length) {\n\t\tconst eqIdx = str.indexOf(\"=\", index);\n\n\t\tif (eqIdx === -1) {\n\t\t\tbreak;\n\t\t}\n\n\t\tlet endIdx = str.indexOf(\";\", index);\n\n\t\tif (endIdx === -1) {\n\t\t\tendIdx = str.length;\n\t\t} else if (endIdx < eqIdx) {\n\t\t\tindex = str.lastIndexOf(\";\", eqIdx - 1) + 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst key = str.slice(index, eqIdx).trim();\n\t\tif (!cookies.has(key)) {\n\t\t\tlet val = str.slice(eqIdx + 1, endIdx).trim();\n\t\t\tif (val.codePointAt(0) === 0x22) {\n\t\t\t\tval = val.slice(1, -1);\n\t\t\t}\n\t\t\tcookies.set(key, tryDecode(val));\n\t\t}\n\n\t\tindex = endIdx + 1;\n\t}\n\n\treturn cookies;\n}\n\nfunction resolveCookie(\n\tname: string,\n\tvalue: string,\n\toptions: CookieOptions = {},\n): Cookie {\n\tconst resolvedName = getCookieKey(name, options.prefix) ?? name;\n\tconst resolvedOptions = { ...options };\n\n\tconst lowerName = resolvedName.toLowerCase();\n\tif (lowerName.startsWith(\"__host-\")) {\n\t\tresolvedOptions.secure = true;\n\t\tresolvedOptions.path = \"/\";\n\t\tresolvedOptions.domain = undefined;\n\t} else if (lowerName.startsWith(\"__secure-\")) {\n\t\tresolvedOptions.secure = true;\n\t}\n\tif (\n\t\tresolvedOptions.partitioned === true ||\n\t\tresolvedOptions.sameSite?.toLowerCase() === \"none\"\n\t) {\n\t\tresolvedOptions.secure = true;\n\t}\n\n\treturn { name: resolvedName, value, options: resolvedOptions };\n}\n\nfunction serializeCookieValue({ name, value, options }: Cookie) {\n\tlet cookie = `${name}=${value}`;\n\tif (typeof options.maxAge === \"number\" && options.maxAge >= 0) {\n\t\tif (options.maxAge > 34560000) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Cookies Max-Age SHOULD NOT be greater than 400 days (34560000 seconds) in duration.\",\n\t\t\t);\n\t\t}\n\t\tcookie += `; Max-Age=${Math.floor(options.maxAge)}`;\n\t}\n\n\tif (options.domain) {\n\t\tcookie += `; Domain=${options.domain}`;\n\t}\n\n\tif (options.path) {\n\t\tcookie += `; Path=${options.path}`;\n\t}\n\n\tif (options.expires) {\n\t\tif (options.expires.getTime() - Date.now() > 34560000_000) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Cookies Expires SHOULD NOT be greater than 400 days (34560000 seconds) in the future.\",\n\t\t\t);\n\t\t}\n\t\tcookie += `; Expires=${options.expires.toUTCString()}`;\n\t}\n\n\tif (options.httpOnly) {\n\t\tcookie += \"; HttpOnly\";\n\t}\n\n\tif (options.secure) {\n\t\tcookie += \"; Secure\";\n\t}\n\n\tif (options.sameSite) {\n\t\tcookie += `; SameSite=${options.sameSite.charAt(0).toUpperCase() + options.sameSite.slice(1)}`;\n\t}\n\n\tif (options.partitioned) {\n\t\tcookie += \"; Partitioned\";\n\t}\n\n\treturn cookie;\n}\n\nexport const serializeCookie = (\n\tkey: string,\n\tvalue: string,\n\topt?: CookieOptions,\n) => {\n\tvalue = encodeURIComponent(value);\n\treturn serializeCookieValue(resolveCookie(key, value, opt));\n};\n\nexport const serializeSignedCookie = async (\n\tkey: string,\n\tvalue: string,\n\tsecret: string,\n\topt?: CookieOptions,\n) => {\n\tvalue = await signCookieValue(value, secret);\n\treturn serializeCookieValue(resolveCookie(key, value, opt));\n};\n"],"mappings":"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"}
@@ -12,7 +12,7 @@ type CookieOptions = {
12
12
  * @example
13
13
  * `domain: "example.com"`
14
14
  */
15
- domain?: string;
15
+ domain?: string | undefined;
16
16
  /**
17
17
  * A lifetime of a cookie. Permanent cookies are deleted after the date specified in the
18
18
  * Expires attribute:
@@ -12,7 +12,7 @@ type CookieOptions = {
12
12
  * @example
13
13
  * `domain: "example.com"`
14
14
  */
15
- domain?: string;
15
+ domain?: string | undefined;
16
16
  /**
17
17
  * A lifetime of a cookie. Permanent cookies are deleted after the date specified in the
18
18
  * Expires attribute:
@@ -1 +1 @@
1
- {"version":3,"file":"cookies.mjs","names":[],"sources":["../src/cookies.ts"],"sourcesContent":["import { signCookieValue } from \"./crypto\";\nimport { tryDecode } from \"./utils\";\n\nexport type CookiePrefixOptions = \"host\" | \"secure\";\n\nconst COOKIE_PREFIXES = {\n\tsecure: \"__Secure-\",\n\thost: \"__Host-\",\n} as const satisfies Record<CookiePrefixOptions, string>;\n\nexport type CookieOptions = {\n\t/**\n\t * Domain of the cookie\n\t *\n\t * The Domain attribute specifies which server can receive a cookie. If specified, cookies are\n\t * available on the specified server and its subdomains. If the it is not\n\t * specified, the cookies are available on the server that sets it but not on\n\t * its subdomains.\n\t *\n\t * @example\n\t * `domain: \"example.com\"`\n\t */\n\tdomain?: string;\n\t/**\n\t * A lifetime of a cookie. Permanent cookies are deleted after the date specified in the\n\t * Expires attribute:\n\t *\n\t * Expires has been available for longer than Max-Age, however Max-Age is less error-prone, and\n\t * takes precedence when both are set. The rationale behind this is that when you set an\n\t * Expires date and time, they're relative to the client the cookie is being set on. If the\n\t * server is set to a different time, this could cause errors\n\t */\n\texpires?: Date;\n\t/**\n\t * Forbids JavaScript from accessing the cookie, for example, through the Document.cookie\n\t * property. Note that a cookie that has been created with HttpOnly will still be sent with\n\t * JavaScript-initiated requests, for example, when calling XMLHttpRequest.send() or fetch().\n\t * This mitigates attacks against cross-site scripting\n\t */\n\thttpOnly?: boolean;\n\t/**\n\t * Indicates the number of seconds until the cookie expires. A zero or negative number will\n\t * expire the cookie immediately. If both Expires and Max-Age are set, Max-Age has precedence.\n\t *\n\t * @example 604800 - 7 days\n\t */\n\tmaxAge?: number;\n\t/**\n\t * Indicates the path that must exist in the requested URL for the browser to send the Cookie\n\t * header.\n\t *\n\t * @example\n\t * \"/docs\"\n\t * // -> the request paths /docs, /docs/, /docs/Web/, and /docs/Web/HTTP will all match. the request paths /, /fr/docs will not match.\n\t */\n\tpath?: string;\n\t/**\n\t * Indicates that the cookie is sent to the server only when a request is made with the https:\n\t * scheme (except on localhost), and therefore, is more resistant to man-in-the-middle attacks.\n\t */\n\tsecure?: boolean;\n\t/**\n\t * Controls whether or not a cookie is sent with cross-site requests, providing some protection\n\t * against cross-site request forgery attacks (CSRF).\n\t *\n\t * Strict - Means that the browser sends the cookie only for same-site requests, that is,\n\t * requests originating from the same site that set the cookie. If a request originates from a\n\t * different domain or scheme (even with the same domain), no cookies with the SameSite=Strict\n\t * attribute are sent.\n\t *\n\t * Lax - Means that the cookie is not sent on cross-site requests, such as on requests to load\n\t * images or frames, but is sent when a user is navigating to the origin site from an external\n\t * site (for example, when following a link). This is the default behavior if the SameSite\n\t * attribute is not specified.\n\t *\n\t * None - Means that the browser sends the cookie with both cross-site and same-site requests.\n\t * The Secure attribute must also be set when setting this value.\n\t */\n\tsameSite?: \"Strict\" | \"Lax\" | \"None\" | \"strict\" | \"lax\" | \"none\";\n\t/**\n\t * Indicates that the cookie should be stored using partitioned storage. Note that if this is\n\t * set, the Secure directive must also be set.\n\t *\n\t * @see https://developer.mozilla.org/en-US/docs/Web/Privacy/Privacy_sandbox/Partitioned_cookies\n\t */\n\tpartitioned?: boolean;\n\t/**\n\t * Cooke Prefix\n\t *\n\t * - secure: `__Secure-` -> `__Secure-cookie-name`\n\t * - host: `__Host-` -> `__Host-cookie-name`\n\t *\n\t * Required Secure, Path, and Domain attributes are applied automatically.\n\t */\n\tprefix?: CookiePrefixOptions;\n};\n\ntype Cookie = {\n\tname: string;\n\tvalue: string;\n\toptions: CookieOptions;\n};\n\nexport const getCookieKey = (key: string, prefix?: CookiePrefixOptions) => {\n\tif (!prefix) return key;\n\tif (prefix !== \"secure\" && prefix !== \"host\") return undefined;\n\treturn COOKIE_PREFIXES[prefix] + key;\n};\n\n/**\n * Parse an HTTP Cookie header string and returning an object of all cookie\n * name-value pairs.\n *\n * Inspired by https://github.com/unjs/cookie-es/blob/main/src/cookie/parse.ts\n *\n * @param str the string representing a `Cookie` header value\n */\nexport function parseCookies(str: string) {\n\tif (typeof str !== \"string\") {\n\t\tthrow new TypeError(\"argument str must be a string\");\n\t}\n\n\tconst cookies: Map<string, string> = new Map();\n\n\tlet index = 0;\n\twhile (index < str.length) {\n\t\tconst eqIdx = str.indexOf(\"=\", index);\n\n\t\tif (eqIdx === -1) {\n\t\t\tbreak;\n\t\t}\n\n\t\tlet endIdx = str.indexOf(\";\", index);\n\n\t\tif (endIdx === -1) {\n\t\t\tendIdx = str.length;\n\t\t} else if (endIdx < eqIdx) {\n\t\t\tindex = str.lastIndexOf(\";\", eqIdx - 1) + 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst key = str.slice(index, eqIdx).trim();\n\t\tif (!cookies.has(key)) {\n\t\t\tlet val = str.slice(eqIdx + 1, endIdx).trim();\n\t\t\tif (val.codePointAt(0) === 0x22) {\n\t\t\t\tval = val.slice(1, -1);\n\t\t\t}\n\t\t\tcookies.set(key, tryDecode(val));\n\t\t}\n\n\t\tindex = endIdx + 1;\n\t}\n\n\treturn cookies;\n}\n\nfunction resolveCookie(\n\tname: string,\n\tvalue: string,\n\toptions: CookieOptions = {},\n): Cookie {\n\tconst resolvedName = getCookieKey(name, options.prefix) ?? name;\n\tconst resolvedOptions = { ...options };\n\n\tconst lowerName = resolvedName.toLowerCase();\n\tif (lowerName.startsWith(\"__host-\")) {\n\t\tresolvedOptions.secure = true;\n\t\tresolvedOptions.path = \"/\";\n\t\tresolvedOptions.domain = undefined;\n\t} else if (lowerName.startsWith(\"__secure-\")) {\n\t\tresolvedOptions.secure = true;\n\t}\n\tif (\n\t\tresolvedOptions.partitioned === true ||\n\t\tresolvedOptions.sameSite?.toLowerCase() === \"none\"\n\t) {\n\t\tresolvedOptions.secure = true;\n\t}\n\n\treturn { name: resolvedName, value, options: resolvedOptions };\n}\n\nfunction serializeCookieValue({ name, value, options }: Cookie) {\n\tlet cookie = `${name}=${value}`;\n\tif (typeof options.maxAge === \"number\" && options.maxAge >= 0) {\n\t\tif (options.maxAge > 34560000) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Cookies Max-Age SHOULD NOT be greater than 400 days (34560000 seconds) in duration.\",\n\t\t\t);\n\t\t}\n\t\tcookie += `; Max-Age=${Math.floor(options.maxAge)}`;\n\t}\n\n\tif (options.domain) {\n\t\tcookie += `; Domain=${options.domain}`;\n\t}\n\n\tif (options.path) {\n\t\tcookie += `; Path=${options.path}`;\n\t}\n\n\tif (options.expires) {\n\t\tif (options.expires.getTime() - Date.now() > 34560000_000) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Cookies Expires SHOULD NOT be greater than 400 days (34560000 seconds) in the future.\",\n\t\t\t);\n\t\t}\n\t\tcookie += `; Expires=${options.expires.toUTCString()}`;\n\t}\n\n\tif (options.httpOnly) {\n\t\tcookie += \"; HttpOnly\";\n\t}\n\n\tif (options.secure) {\n\t\tcookie += \"; Secure\";\n\t}\n\n\tif (options.sameSite) {\n\t\tcookie += `; SameSite=${options.sameSite.charAt(0).toUpperCase() + options.sameSite.slice(1)}`;\n\t}\n\n\tif (options.partitioned) {\n\t\tcookie += \"; Partitioned\";\n\t}\n\n\treturn cookie;\n}\n\nexport const serializeCookie = (\n\tkey: string,\n\tvalue: string,\n\topt?: CookieOptions,\n) => {\n\tvalue = encodeURIComponent(value);\n\treturn serializeCookieValue(resolveCookie(key, value, opt));\n};\n\nexport const serializeSignedCookie = async (\n\tkey: string,\n\tvalue: string,\n\tsecret: string,\n\topt?: CookieOptions,\n) => {\n\tvalue = await signCookieValue(value, secret);\n\treturn serializeCookieValue(resolveCookie(key, value, opt));\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"cookies.mjs","names":[],"sources":["../src/cookies.ts"],"sourcesContent":["import { signCookieValue } from \"./crypto\";\nimport { tryDecode } from \"./utils\";\n\nexport type CookiePrefixOptions = \"host\" | \"secure\";\n\nconst COOKIE_PREFIXES = {\n\tsecure: \"__Secure-\",\n\thost: \"__Host-\",\n} as const satisfies Record<CookiePrefixOptions, string>;\n\nexport type CookieOptions = {\n\t/**\n\t * Domain of the cookie\n\t *\n\t * The Domain attribute specifies which server can receive a cookie. If specified, cookies are\n\t * available on the specified server and its subdomains. If the it is not\n\t * specified, the cookies are available on the server that sets it but not on\n\t * its subdomains.\n\t *\n\t * @example\n\t * `domain: \"example.com\"`\n\t */\n\tdomain?: string | undefined;\n\t/**\n\t * A lifetime of a cookie. Permanent cookies are deleted after the date specified in the\n\t * Expires attribute:\n\t *\n\t * Expires has been available for longer than Max-Age, however Max-Age is less error-prone, and\n\t * takes precedence when both are set. The rationale behind this is that when you set an\n\t * Expires date and time, they're relative to the client the cookie is being set on. If the\n\t * server is set to a different time, this could cause errors\n\t */\n\texpires?: Date;\n\t/**\n\t * Forbids JavaScript from accessing the cookie, for example, through the Document.cookie\n\t * property. Note that a cookie that has been created with HttpOnly will still be sent with\n\t * JavaScript-initiated requests, for example, when calling XMLHttpRequest.send() or fetch().\n\t * This mitigates attacks against cross-site scripting\n\t */\n\thttpOnly?: boolean;\n\t/**\n\t * Indicates the number of seconds until the cookie expires. A zero or negative number will\n\t * expire the cookie immediately. If both Expires and Max-Age are set, Max-Age has precedence.\n\t *\n\t * @example 604800 - 7 days\n\t */\n\tmaxAge?: number;\n\t/**\n\t * Indicates the path that must exist in the requested URL for the browser to send the Cookie\n\t * header.\n\t *\n\t * @example\n\t * \"/docs\"\n\t * // -> the request paths /docs, /docs/, /docs/Web/, and /docs/Web/HTTP will all match. the request paths /, /fr/docs will not match.\n\t */\n\tpath?: string;\n\t/**\n\t * Indicates that the cookie is sent to the server only when a request is made with the https:\n\t * scheme (except on localhost), and therefore, is more resistant to man-in-the-middle attacks.\n\t */\n\tsecure?: boolean;\n\t/**\n\t * Controls whether or not a cookie is sent with cross-site requests, providing some protection\n\t * against cross-site request forgery attacks (CSRF).\n\t *\n\t * Strict - Means that the browser sends the cookie only for same-site requests, that is,\n\t * requests originating from the same site that set the cookie. If a request originates from a\n\t * different domain or scheme (even with the same domain), no cookies with the SameSite=Strict\n\t * attribute are sent.\n\t *\n\t * Lax - Means that the cookie is not sent on cross-site requests, such as on requests to load\n\t * images or frames, but is sent when a user is navigating to the origin site from an external\n\t * site (for example, when following a link). This is the default behavior if the SameSite\n\t * attribute is not specified.\n\t *\n\t * None - Means that the browser sends the cookie with both cross-site and same-site requests.\n\t * The Secure attribute must also be set when setting this value.\n\t */\n\tsameSite?: \"Strict\" | \"Lax\" | \"None\" | \"strict\" | \"lax\" | \"none\";\n\t/**\n\t * Indicates that the cookie should be stored using partitioned storage. Note that if this is\n\t * set, the Secure directive must also be set.\n\t *\n\t * @see https://developer.mozilla.org/en-US/docs/Web/Privacy/Privacy_sandbox/Partitioned_cookies\n\t */\n\tpartitioned?: boolean;\n\t/**\n\t * Cooke Prefix\n\t *\n\t * - secure: `__Secure-` -> `__Secure-cookie-name`\n\t * - host: `__Host-` -> `__Host-cookie-name`\n\t *\n\t * Required Secure, Path, and Domain attributes are applied automatically.\n\t */\n\tprefix?: CookiePrefixOptions;\n};\n\ntype Cookie = {\n\tname: string;\n\tvalue: string;\n\toptions: CookieOptions;\n};\n\nexport const getCookieKey = (key: string, prefix?: CookiePrefixOptions) => {\n\tif (!prefix) return key;\n\tif (prefix !== \"secure\" && prefix !== \"host\") return undefined;\n\treturn COOKIE_PREFIXES[prefix] + key;\n};\n\n/**\n * Parse an HTTP Cookie header string and returning an object of all cookie\n * name-value pairs.\n *\n * Inspired by https://github.com/unjs/cookie-es/blob/main/src/cookie/parse.ts\n *\n * @param str the string representing a `Cookie` header value\n */\nexport function parseCookies(str: string) {\n\tif (typeof str !== \"string\") {\n\t\tthrow new TypeError(\"argument str must be a string\");\n\t}\n\n\tconst cookies: Map<string, string> = new Map();\n\n\tlet index = 0;\n\twhile (index < str.length) {\n\t\tconst eqIdx = str.indexOf(\"=\", index);\n\n\t\tif (eqIdx === -1) {\n\t\t\tbreak;\n\t\t}\n\n\t\tlet endIdx = str.indexOf(\";\", index);\n\n\t\tif (endIdx === -1) {\n\t\t\tendIdx = str.length;\n\t\t} else if (endIdx < eqIdx) {\n\t\t\tindex = str.lastIndexOf(\";\", eqIdx - 1) + 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst key = str.slice(index, eqIdx).trim();\n\t\tif (!cookies.has(key)) {\n\t\t\tlet val = str.slice(eqIdx + 1, endIdx).trim();\n\t\t\tif (val.codePointAt(0) === 0x22) {\n\t\t\t\tval = val.slice(1, -1);\n\t\t\t}\n\t\t\tcookies.set(key, tryDecode(val));\n\t\t}\n\n\t\tindex = endIdx + 1;\n\t}\n\n\treturn cookies;\n}\n\nfunction resolveCookie(\n\tname: string,\n\tvalue: string,\n\toptions: CookieOptions = {},\n): Cookie {\n\tconst resolvedName = getCookieKey(name, options.prefix) ?? name;\n\tconst resolvedOptions = { ...options };\n\n\tconst lowerName = resolvedName.toLowerCase();\n\tif (lowerName.startsWith(\"__host-\")) {\n\t\tresolvedOptions.secure = true;\n\t\tresolvedOptions.path = \"/\";\n\t\tresolvedOptions.domain = undefined;\n\t} else if (lowerName.startsWith(\"__secure-\")) {\n\t\tresolvedOptions.secure = true;\n\t}\n\tif (\n\t\tresolvedOptions.partitioned === true ||\n\t\tresolvedOptions.sameSite?.toLowerCase() === \"none\"\n\t) {\n\t\tresolvedOptions.secure = true;\n\t}\n\n\treturn { name: resolvedName, value, options: resolvedOptions };\n}\n\nfunction serializeCookieValue({ name, value, options }: Cookie) {\n\tlet cookie = `${name}=${value}`;\n\tif (typeof options.maxAge === \"number\" && options.maxAge >= 0) {\n\t\tif (options.maxAge > 34560000) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Cookies Max-Age SHOULD NOT be greater than 400 days (34560000 seconds) in duration.\",\n\t\t\t);\n\t\t}\n\t\tcookie += `; Max-Age=${Math.floor(options.maxAge)}`;\n\t}\n\n\tif (options.domain) {\n\t\tcookie += `; Domain=${options.domain}`;\n\t}\n\n\tif (options.path) {\n\t\tcookie += `; Path=${options.path}`;\n\t}\n\n\tif (options.expires) {\n\t\tif (options.expires.getTime() - Date.now() > 34560000_000) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Cookies Expires SHOULD NOT be greater than 400 days (34560000 seconds) in the future.\",\n\t\t\t);\n\t\t}\n\t\tcookie += `; Expires=${options.expires.toUTCString()}`;\n\t}\n\n\tif (options.httpOnly) {\n\t\tcookie += \"; HttpOnly\";\n\t}\n\n\tif (options.secure) {\n\t\tcookie += \"; Secure\";\n\t}\n\n\tif (options.sameSite) {\n\t\tcookie += `; SameSite=${options.sameSite.charAt(0).toUpperCase() + options.sameSite.slice(1)}`;\n\t}\n\n\tif (options.partitioned) {\n\t\tcookie += \"; Partitioned\";\n\t}\n\n\treturn cookie;\n}\n\nexport const serializeCookie = (\n\tkey: string,\n\tvalue: string,\n\topt?: CookieOptions,\n) => {\n\tvalue = encodeURIComponent(value);\n\treturn serializeCookieValue(resolveCookie(key, value, opt));\n};\n\nexport const serializeSignedCookie = async (\n\tkey: string,\n\tvalue: string,\n\tsecret: string,\n\topt?: CookieOptions,\n) => {\n\tvalue = await signCookieValue(value, secret);\n\treturn serializeCookieValue(resolveCookie(key, value, opt));\n};\n"],"mappings":"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"}
package/dist/endpoint.cjs CHANGED
@@ -36,7 +36,7 @@ function createEndpoint(pathOrOptions, handlerOrOptions, handlerOrNever) {
36
36
  });
37
37
  const headers = internalContext.responseHeaders;
38
38
  const status = internalContext.responseStatus;
39
- return context.asResponse ? require_to_response.toResponse(response, {
39
+ return context.asResponse ? require_to_response.toResponse(response, status === void 0 ? { headers } : {
40
40
  headers,
41
41
  status
42
42
  }) : context.returnHeaders ? context.returnStatus ? {
@@ -1 +1 @@
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"}
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\t| {\n\t\t\t\t\tsummary?: string | undefined;\n\t\t\t\t\tdescription?: string | undefined;\n\t\t\t\t\ttags?: string[] | undefined;\n\t\t\t\t\toperationId?: string | undefined;\n\t\t\t\t\tparameters?: OpenAPIParameter[] | undefined;\n\t\t\t\t\trequestBody?:\n\t\t\t\t\t\t| {\n\t\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\t\ttype?: OpenAPISchemaType | undefined;\n\t\t\t\t\t\t\t\t\t\t\tproperties?: Record<string, any> | undefined;\n\t\t\t\t\t\t\t\t\t\t\trequired?: string[] | undefined;\n\t\t\t\t\t\t\t\t\t\t\t$ref?: string | undefined;\n\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t }\n\t\t\t\t\t\t| undefined;\n\t\t\t\t\tresponses?:\n\t\t\t\t\t\t| {\n\t\t\t\t\t\t\t\t[status: string]: {\n\t\t\t\t\t\t\t\t\tdescription: string;\n\t\t\t\t\t\t\t\t\tcontent?:\n\t\t\t\t\t\t\t\t\t\t| {\n\t\t\t\t\t\t\t\t\t\t\t\t\"application/json\"?:\n\t\t\t\t\t\t\t\t\t\t\t\t\t| {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype?: OpenAPISchemaType | undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tproperties?: Record<string, any> | undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trequired?: string[] | undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t$ref?: string | undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t\t\t\t\t }\n\t\t\t\t\t\t\t\t\t\t\t\t\t| undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\"text/plain\"?:\n\t\t\t\t\t\t\t\t\t\t\t\t\t| {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tschema?:\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t| {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype?: OpenAPISchemaType | undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tproperties?:\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t| Record<string, any>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t| undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trequired?: string[] | undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t$ref?: string | undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t }\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t| undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\t }\n\t\t\t\t\t\t\t\t\t\t\t\t\t| undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\"text/html\"?:\n\t\t\t\t\t\t\t\t\t\t\t\t\t| {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tschema?:\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t| {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype?: OpenAPISchemaType | undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tproperties?:\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t| Record<string, any>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t| undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trequired?: string[] | undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t$ref?: string | undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t }\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t| undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\t }\n\t\t\t\t\t\t\t\t\t\t\t\t\t| undefined;\n\t\t\t\t\t\t\t\t\t\t }\n\t\t\t\t\t\t\t\t\t\t| undefined;\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t }\n\t\t\t\t\t\t| undefined;\n\t\t\t }\n\t\t\t| undefined;\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[] | undefined;\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(\n\t\t\t\t\t\tresponse,\n\t\t\t\t\t\tstatus === undefined ? { headers } : { headers, status },\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":";;;;;AAqiBA,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,WACA,UACA,WAAW,KAAA,IAAY,EAAE,QAAQ,IAAI;GAAE;GAAS;EAAO,CACxD,IACC,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"}
@@ -39,55 +39,55 @@ interface EndpointBaseOptions {
39
39
  * Open API definition
40
40
  */
41
41
  openapi?: {
42
- summary?: string;
43
- description?: string;
44
- tags?: string[];
45
- operationId?: string;
46
- parameters?: OpenAPIParameter[];
42
+ summary?: string | undefined;
43
+ description?: string | undefined;
44
+ tags?: string[] | undefined;
45
+ operationId?: string | undefined;
46
+ parameters?: OpenAPIParameter[] | undefined;
47
47
  requestBody?: {
48
48
  content: {
49
49
  "application/json": {
50
50
  schema: {
51
- type?: OpenAPISchemaType;
52
- properties?: Record<string, any>;
53
- required?: string[];
54
- $ref?: string;
51
+ type?: OpenAPISchemaType | undefined;
52
+ properties?: Record<string, any> | undefined;
53
+ required?: string[] | undefined;
54
+ $ref?: string | undefined;
55
55
  };
56
56
  };
57
57
  };
58
- };
58
+ } | undefined;
59
59
  responses?: {
60
60
  [status: string]: {
61
61
  description: string;
62
62
  content?: {
63
63
  "application/json"?: {
64
64
  schema: {
65
- type?: OpenAPISchemaType;
66
- properties?: Record<string, any>;
67
- required?: string[];
68
- $ref?: string;
65
+ type?: OpenAPISchemaType | undefined;
66
+ properties?: Record<string, any> | undefined;
67
+ required?: string[] | undefined;
68
+ $ref?: string | undefined;
69
69
  };
70
- };
70
+ } | undefined;
71
71
  "text/plain"?: {
72
72
  schema?: {
73
- type?: OpenAPISchemaType;
74
- properties?: Record<string, any>;
75
- required?: string[];
76
- $ref?: string;
77
- };
78
- };
73
+ type?: OpenAPISchemaType | undefined;
74
+ properties?: Record<string, any> | undefined;
75
+ required?: string[] | undefined;
76
+ $ref?: string | undefined;
77
+ } | undefined;
78
+ } | undefined;
79
79
  "text/html"?: {
80
80
  schema?: {
81
- type?: OpenAPISchemaType;
82
- properties?: Record<string, any>;
83
- required?: string[];
84
- $ref?: string;
85
- };
86
- };
87
- };
81
+ type?: OpenAPISchemaType | undefined;
82
+ properties?: Record<string, any> | undefined;
83
+ required?: string[] | undefined;
84
+ $ref?: string | undefined;
85
+ } | undefined;
86
+ } | undefined;
87
+ } | undefined;
88
88
  };
89
- };
90
- };
89
+ } | undefined;
90
+ } | undefined;
91
91
  /**
92
92
  * Infer body and query type from ts interface
93
93
  *
@@ -162,7 +162,7 @@ interface EndpointBaseOptions {
162
162
  /**
163
163
  * List of middlewares to use
164
164
  */
165
- use?: MiddlewareHandler[];
165
+ use?: MiddlewareHandler[] | undefined;
166
166
  /**
167
167
  * A callback to run before any API error is throw or returned
168
168
  *