better-call 0.0.5-beta.1 → 0.0.5-beta.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/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -6
- package/dist/index.d.ts +1 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/endpoint.ts","../src/better-call-error.ts","../src/router.ts","../src/utils.ts","../src/middleware.ts"],"sourcesContent":["export * from \"./endpoint\"\nexport * from \"./router\"\nexport * from \"./middleware\"\nexport * from \"./better-call-error\"\nexport * from \"./utils\"","import { z, ZodError, type ZodOptional, type ZodSchema } from \"zod\"\nimport type { Middleware } from \"./middleware\"\nimport { APIError } from \"./better-call-error\";\n\n\nexport type RequiredKeysOf<BaseType extends object> = Exclude<{\n [Key in keyof BaseType]: BaseType extends Record<Key, BaseType[Key]>\n ? Key\n : never\n}[keyof BaseType], undefined>;\n\nexport type HasRequiredKeys<BaseType extends object> = RequiredKeysOf<BaseType> extends never ? false : true;\n\ntype Method = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\" | \"*\"\n\nexport interface EndpointOptions {\n method: Method | Method[]\n body?: ZodSchema\n query?: ZodSchema\n params?: ZodSchema<any>\n /**\n * If true headers will be required to be passed in the context\n */\n requireHeaders?: boolean\n /**\n * If true request object will be required\n */\n requireRequest?: boolean\n}\n\ntype InferParamPath<Path> =\n Path extends `${infer _Start}:${infer Param}/${infer Rest}`\n ? { [K in Param | keyof InferParamPath<Rest>]: string }\n : Path extends `${infer _Start}:${infer Param}`\n ? { [K in Param]: string }\n : Path extends `${infer _Start}/${infer Rest}`\n ? InferParamPath<Rest>\n : undefined;\n\ntype InferParamWildCard<Path> = Path extends `${infer _Start}/*:${infer Param}/${infer Rest}` | `${infer _Start}/**:${infer Param}/${infer Rest}`\n ? { [K in Param | keyof InferParamPath<Rest>]: string }\n : Path extends `${infer _Start}/*`\n ? { [K in \"_\"]: string }\n : Path extends `${infer _Start}/${infer Rest}`\n ? InferParamPath<Rest>\n : undefined;\n\n\nexport type Prettify<T> = {\n [key in keyof T]: T[key];\n} & {};\n\ntype ContextTools = {\n setHeader: (key: string, value: string) => void\n setCookie: (key: string, value: string) => void\n getCookie: (key: string) => string | undefined\n}\n\nexport type Context<Path extends string, Opts extends EndpointOptions, Extra extends Record<string, any> = {}> = InferBody<Opts[\"body\"]> & InferParam<Path> & InferMethod<Opts['method']> & InferHeaders<Opts[\"requireHeaders\"]> & InferRequest<Opts[\"requireRequest\"]> & InferQuery<Opts[\"query\"]> & Extra\n\ntype InferMethod<M extends Method | Method[]> = M extends Array<Method> ? {\n method: M[number]\n} : {\n method?: M\n}\n\ntype InferHeaders<HeaderReq> = HeaderReq extends true ? {\n headers: Headers\n} : {\n headers?: Headers\n}\n\ntype InferRequest<RequestReq> = RequestReq extends true ? {\n request: Request\n} : {\n request?: Request\n}\n\n\ntype InferBody<Body> = Body extends ZodSchema ? Body extends ZodOptional<any> ? {\n body?: z.infer<Body>\n} : {\n body: z.infer<Body>\n} : {\n body?: undefined\n}\n\ntype InferQuery<Query> = Query extends ZodSchema ? Query extends ZodOptional<any> ? {\n query?: z.infer<Query>\n} : {\n query: z.infer<Query>\n} : {\n query?: undefined\n}\n\ntype InferParam<Path extends string, ParamPath extends InferParamPath<Path> = InferParamPath<Path>, WildCard extends InferParamWildCard<Path> = InferParamWildCard<Path>> = ParamPath extends undefined ? WildCard extends undefined ? {\n params?: undefined\n} : {\n params: WildCard\n} : {\n params: ParamPath & (WildCard extends undefined ? {} : WildCard)\n}\n\n\nexport type EndpointResponse = Record<string, any> | string | boolean | number | {\n status: string,\n body: any,\n headers: Headers | Record<string, any>\n [key: string]: any\n} | void | undefined\n\nexport type Handler<Path extends string, Opts extends EndpointOptions, R extends EndpointResponse, Extra extends Record<string, any> = Record<string, any>> = (ctx: Context<Path, Opts, Extra>) => Promise<R>\n\nexport interface EndpointConfig {\n /**\n * Throw when the response isn't in 200 range\n */\n throwOnError?: boolean\n}\n\nexport function createEndpoint<Path extends string, Opts extends EndpointOptions, R extends EndpointResponse>(path: Path, options: Opts, handler: Handler<Path, Opts, R, ContextTools>) {\n const responseHeader = new Headers()\n type Ctx = Context<Path, Opts>\n const handle = async (...ctx: HasRequiredKeys<Ctx> extends true ? [Ctx] : [Ctx?]) => {\n const internalCtx = ({\n setHeader(key, value) {\n responseHeader.set(key, value)\n },\n setCookie(key, value) {\n responseHeader.append(\"Set-Cookie\", `${key}=${value}`)\n },\n getCookie(key) {\n const header = ctx[0]?.headers\n return header?.get(\"cookie\")?.split(\";\").find(cookie => cookie.startsWith(`${key}=`))?.split(\"=\")[1]\n },\n ...(ctx[0] || {})\n }) as (Ctx & ContextTools)\n try {\n internalCtx.body = options.body ? options.body.parse(internalCtx.body) : undefined\n internalCtx.query = options.query ? options.query.parse(internalCtx.query) : undefined\n internalCtx.params = options.params ? options.params.parse(internalCtx.params) : undefined\n } catch (e) {\n if (e instanceof ZodError) {\n throw new APIError(\"Bad Request\", {\n message: e.message,\n details: e.errors\n })\n }\n throw e\n }\n if (options.requireHeaders && !internalCtx.headers) {\n throw new APIError(\"Bad Request\", {\n message: \"Headers are required\"\n })\n }\n if (options.requireRequest && !internalCtx.request) {\n throw new APIError(\"Bad Request\", {\n message: \"Request is required\"\n })\n }\n const res = await handler(internalCtx)\n return res as ReturnType<Handler<Path, Opts, R>>\n }\n handle.path = path\n handle.options = options\n handle.method = options.method\n handle.headers = responseHeader\n //for type inference\n handle.middleware = undefined as (Middleware<any> | undefined)\n\n return handle\n}\n\nexport type Endpoint = {\n path: string\n options: EndpointOptions\n middleware?: Middleware<any>\n headers?: Headers\n} & ((ctx: any) => Promise<any>)","import type { statusCode } from \"./utils\"\n\ntype Status = keyof typeof statusCode\n\nexport class APIError extends Error {\n status: Status\n body: Record<string, any>\n constructor(\n status: Status,\n body?: Record<string, any>,\n ) {\n super(\n `API Error: ${status} ${body?.message ?? \"\"}`,\n {\n cause: body,\n }\n )\n this.status = status\n this.body = body ?? {}\n this.stack = \"\";\n this.name = \"BetterCallAPIError\"\n }\n}","import type { Endpoint } from \"./endpoint\";\nimport {\n createRouter as createRou3Router,\n addRoute,\n findRoute,\n} from \"rou3\";\nimport { getBody, shouldSerialize, statusCode } from \"./utils\";\nimport { APIError } from \"./better-call-error\";\n\ninterface RouterConfig {\n /**\n * Throw error if error occurred other than APIError\n */\n throwError?: boolean\n /**\n * Handle error\n */\n onError?: (e: unknown) => void | Promise<void> | Response | Promise<Response>\n /**\n * Base path for the router\n */\n basePath?: string\n}\n\nexport const createRouter = <E extends Endpoint, Config extends RouterConfig>(endpoints: E[], config?: Config) => {\n const router = createRou3Router()\n for (const endpoint of endpoints) {\n if (Array.isArray(endpoint.options?.method)) {\n for (const method of endpoint.options.method) {\n addRoute(router, method, endpoint.path, endpoint)\n }\n } else {\n addRoute(router, endpoint.options.method, endpoint.path, endpoint)\n }\n }\n\n const handler = async (request: Request) => {\n const url = new URL(request.url);\n let path = url.pathname\n if (config?.basePath) {\n path = path.split(config.basePath)[1]\n }\n const method = request.method;\n const route = findRoute(router, method, path)\n const handler = route?.data as Endpoint\n const body = await getBody(request)\n const headers = request.headers\n\n //handler 404\n if (!handler) {\n return new Response(null, {\n status: 404,\n statusText: \"Not Found\"\n })\n }\n try {\n let middleware: Record<string, any> = {}\n if (handler.middleware) {\n middleware = await handler.middleware({\n path: path,\n method: method,\n headers,\n params: url.searchParams,\n request: request.clone(),\n body: body,\n }) || {}\n }\n const handlerRes = await handler({\n path: path,\n method: method as \"GET\",\n headers,\n params: route?.params as any,\n request: request,\n body: body,\n ...middleware?.context,\n })\n if (handlerRes instanceof Response) {\n return handlerRes\n }\n const resBody = shouldSerialize(handlerRes) ? JSON.stringify(handlerRes) : handlerRes\n return new Response(resBody as any, {\n headers: handler.headers\n })\n } catch (e) {\n if (config?.onError) {\n const onErrorRes = await config.onError(e)\n if (onErrorRes instanceof Response) {\n return onErrorRes\n }\n }\n if (e instanceof APIError) {\n return new Response(e.body ? JSON.stringify(e.body) : null, {\n status: statusCode[e.status],\n statusText: e.status,\n headers: {\n \"Content-Type\": \"application/json\",\n }\n })\n }\n if (config?.throwError) {\n throw e\n }\n return new Response(null, {\n status: 500,\n statusText: \"Internal Server Error\"\n })\n }\n }\n return { handler }\n}","export async function getBody(request: Request) {\n const contentType = request.headers.get('content-type') || '';\n\n if (!request.body) {\n return undefined\n }\n\n if (contentType.includes('application/json')) {\n return await request.json();\n }\n\n if (contentType.includes('application/x-www-form-urlencoded')) {\n const formData = await request.formData();\n const result: Record<string, string> = {};\n formData.forEach((value, key) => {\n result[key] = value.toString();\n });\n return result;\n }\n\n if (contentType.includes('multipart/form-data')) {\n const formData = await request.formData();\n const result: Record<string, any> = {};\n formData.forEach((value, key) => {\n result[key] = value;\n });\n return result;\n }\n\n if (contentType.includes('text/plain')) {\n return await request.text();\n }\n\n if (contentType.includes('application/octet-stream')) {\n return await request.arrayBuffer();\n }\n\n if (contentType.includes('application/pdf') || contentType.includes('image/') || contentType.includes('video/')) {\n const blob = await request.blob();\n return blob;\n }\n\n if (contentType.includes('application/stream') || request.body instanceof ReadableStream) {\n return request.body;\n }\n\n return await request.text();\n}\n\n\nexport function shouldSerialize(body: any) {\n return typeof body === \"object\" && body !== null && !(body instanceof Blob) && !(body instanceof FormData)\n}\n\nexport const statusCode = {\n \"OK\": 200,\n \"Created\": 201,\n \"Accepted\": 202,\n \"No Content\": 204,\n \"Multiple Choices\": 300,\n \"Moved Permanently\": 301,\n \"Found\": 302,\n \"See Other\": 303,\n \"Not Modified\": 304,\n \"Temporary Redirect\": 307,\n \"Bad Request\": 400,\n \"Unauthorized\": 401,\n \"Payment Required\": 402,\n \"Forbidden\": 403,\n \"Not Found\": 404,\n \"Method Not Allowed\": 405,\n \"Not Acceptable\": 406,\n \"Proxy Authentication Required\": 407,\n \"Request Timeout\": 408,\n \"Conflict\": 409,\n \"Gone\": 410,\n \"Length Required\": 411,\n \"Precondition Failed\": 412,\n \"Payload Too Large\": 413,\n \"URI Too Long\": 414,\n \"Unsupported Media Type\": 415,\n \"Range Not Satisfiable\": 416,\n \"Expectation Failed\": 417,\n \"I'm a teapot\": 418,\n \"Misdirected Request\": 421,\n \"Unprocessable Entity\": 422,\n \"Locked\": 423,\n \"Failed Dependency\": 424,\n \"Too Early\": 425,\n \"Upgrade Required\": 426,\n \"Precondition Required\": 428,\n \"Too Many Requests\": 429,\n \"Request Header Fields Too Large\": 431,\n \"Unavailable For Legal Reasons\": 451,\n \"Internal Server Error\": 500,\n \"Not Implemented\": 501,\n \"Bad Gateway\": 502,\n \"Service Unavailable\": 503,\n \"Gateway Timeout\": 504,\n \"HTTP Version Not Supported\": 505,\n \"Variant Also Negotiates\": 506,\n \"Insufficient Storage\": 507,\n \"Loop Detected\": 508,\n \"Not Extended\": 510,\n \"Network Authentication Required\": 511,\n}","import type { HasRequiredKeys } from \"type-fest\"\nimport { type Context, type EndpointOptions, type EndpointResponse, type Handler } from \"./endpoint\"\n\n\nexport type Middleware<E extends Record<string, string>> = (ctx: Context<string, EndpointOptions, E>) => Promise<{\n context: E\n} | void>\n\nexport const createMiddleware = <E extends Record<string, any>, M extends Middleware<E>>(middleware: M) => {\n type MiddlewareContext = Awaited<ReturnType<M>> extends {\n context: infer C\n } ? C extends Record<string, any> ? C : {} : {}\n return <Path extends string, Opts extends EndpointOptions, R extends EndpointResponse>(path: Path, options: Opts, handler: Handler<Path, Opts, R, MiddlewareContext>) => {\n type Ctx = Context<Path, Opts, MiddlewareContext>\n const handle = async (...ctx: HasRequiredKeys<Ctx> extends true ? [Ctx] : [Ctx?]) => {\n const res = await handler((ctx[0] || {}) as Ctx)\n return res as ReturnType<Handler<Path, Opts, R>>\n }\n handle.path = path\n handle.options = options\n handle.middleware = middleware\n return handle\n }\n}"],"mappings":"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","names":["src_exports","__export","APIError","createEndpoint","createMiddleware","createRouter","getBody","shouldSerialize","statusCode","__toCommonJS","import_zod","APIError","status","body","__publicField","createEndpoint","path","options","handler","responseHeader","handle","ctx","internalCtx","key","value","cookie","e","APIError","import_rou3","getBody","request","contentType","formData","result","value","key","shouldSerialize","body","statusCode","createRouter","endpoints","config","router","createRou3Router","endpoint","method","request","url","path","route","handler","body","getBody","headers","middleware","handlerRes","resBody","shouldSerialize","e","onErrorRes","APIError","statusCode","createMiddleware","middleware","path","options","handler","handle","ctx"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/endpoint.ts","../src/better-call-error.ts","../src/router.ts","../src/utils.ts","../src/middleware.ts"],"sourcesContent":["export * from \"./endpoint\"\nexport * from \"./router\"\nexport * from \"./middleware\"\nexport * from \"./better-call-error\"\nexport * from \"./utils\"","import { z, ZodError, type ZodOptional, type ZodSchema } from \"zod\"\nimport type { Middleware } from \"./middleware\"\nimport { APIError } from \"./better-call-error\";\n\n\nexport type RequiredKeysOf<BaseType extends object> = Exclude<{\n [Key in keyof BaseType]: BaseType extends Record<Key, BaseType[Key]>\n ? Key\n : never\n}[keyof BaseType], undefined>;\n\nexport type HasRequiredKeys<BaseType extends object> = RequiredKeysOf<BaseType> extends never ? false : true;\n\ntype Method = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\" | \"*\"\n\nexport interface EndpointOptions {\n method: Method | Method[]\n body?: ZodSchema\n query?: ZodSchema\n params?: ZodSchema<any>\n /**\n * If true headers will be required to be passed in the context\n */\n requireHeaders?: boolean\n /**\n * If true request object will be required\n */\n requireRequest?: boolean\n}\n\ntype InferParamPath<Path> =\n Path extends `${infer _Start}:${infer Param}/${infer Rest}`\n ? { [K in Param | keyof InferParamPath<Rest>]: string }\n : Path extends `${infer _Start}:${infer Param}`\n ? { [K in Param]: string }\n : Path extends `${infer _Start}/${infer Rest}`\n ? InferParamPath<Rest>\n : undefined;\n\ntype InferParamWildCard<Path> = Path extends `${infer _Start}/*:${infer Param}/${infer Rest}` | `${infer _Start}/**:${infer Param}/${infer Rest}`\n ? { [K in Param | keyof InferParamPath<Rest>]: string }\n : Path extends `${infer _Start}/*`\n ? { [K in \"_\"]: string }\n : Path extends `${infer _Start}/${infer Rest}`\n ? InferParamPath<Rest>\n : undefined;\n\n\nexport type Prettify<T> = {\n [key in keyof T]: T[key];\n} & {};\n\ntype ContextTools = {\n setHeader: (key: string, value: string) => void\n setCookie: (key: string, value: string) => void\n getCookie: (key: string) => string | undefined\n}\n\nexport type Context<Path extends string, Opts extends EndpointOptions, Extra extends Record<string, any> = {}> = InferBody<Opts[\"body\"]> & InferParam<Path> & InferMethod<Opts['method']> & InferHeaders<Opts[\"requireHeaders\"]> & InferRequest<Opts[\"requireRequest\"]> & InferQuery<Opts[\"query\"]> & Extra\n\ntype InferMethod<M extends Method | Method[]> = M extends Array<Method> ? {\n method: M[number]\n} : {\n method?: M\n}\n\ntype InferHeaders<HeaderReq> = HeaderReq extends true ? {\n headers: Headers\n} : {\n headers?: Headers\n}\n\ntype InferRequest<RequestReq> = RequestReq extends true ? {\n request: Request\n} : {\n request?: Request\n}\n\n\ntype InferBody<Body> = Body extends ZodSchema ? Body extends ZodOptional<any> ? {\n body?: z.infer<Body>\n} : {\n body: z.infer<Body>\n} : {\n body?: undefined\n}\n\ntype InferQuery<Query> = Query extends ZodSchema ? Query extends ZodOptional<any> ? {\n query?: z.infer<Query>\n} : {\n query: z.infer<Query>\n} : {\n query?: undefined\n}\n\ntype InferParam<Path extends string, ParamPath extends InferParamPath<Path> = InferParamPath<Path>, WildCard extends InferParamWildCard<Path> = InferParamWildCard<Path>> = ParamPath extends undefined ? WildCard extends undefined ? {\n params?: undefined\n} : {\n params: WildCard\n} : {\n params: ParamPath & (WildCard extends undefined ? {} : WildCard)\n}\n\n\nexport type EndpointResponse = Record<string, any> | string | boolean | number | void | undefined\n\nexport type Handler<Path extends string, Opts extends EndpointOptions, R extends EndpointResponse, Extra extends Record<string, any> = Record<string, any>> = (ctx: Context<Path, Opts, Extra>) => Promise<R>\n\nexport interface EndpointConfig {\n /**\n * Throw when the response isn't in 200 range\n */\n throwOnError?: boolean\n}\n\nexport function createEndpoint<Path extends string, Opts extends EndpointOptions, R extends EndpointResponse>(path: Path, options: Opts, handler: Handler<Path, Opts, R, ContextTools>) {\n const responseHeader = new Headers()\n type Ctx = Context<Path, Opts>\n const handle = async (...ctx: HasRequiredKeys<Ctx> extends true ? [Ctx] : [Ctx?]) => {\n const internalCtx = ({\n setHeader(key, value) {\n responseHeader.set(key, value)\n },\n setCookie(key, value) {\n responseHeader.append(\"Set-Cookie\", `${key}=${value}`)\n },\n getCookie(key) {\n const header = ctx[0]?.headers\n return header?.get(\"cookie\")?.split(\";\").find(cookie => cookie.startsWith(`${key}=`))?.split(\"=\")[1]\n },\n ...(ctx[0] || {})\n }) as (Ctx & ContextTools)\n try {\n internalCtx.body = options.body ? options.body.parse(internalCtx.body) : undefined\n internalCtx.query = options.query ? options.query.parse(internalCtx.query) : undefined\n internalCtx.params = options.params ? options.params.parse(internalCtx.params) : undefined\n } catch (e) {\n if (e instanceof ZodError) {\n throw new APIError(\"Bad Request\", {\n message: e.message,\n details: e.errors\n })\n }\n throw e\n }\n if (options.requireHeaders && !internalCtx.headers) {\n throw new APIError(\"Bad Request\", {\n message: \"Headers are required\"\n })\n }\n if (options.requireRequest && !internalCtx.request) {\n throw new APIError(\"Bad Request\", {\n message: \"Request is required\"\n })\n }\n const res = await handler(internalCtx)\n return res as ReturnType<Handler<Path, Opts, R>>\n }\n handle.path = path\n handle.options = options\n handle.method = options.method\n handle.headers = responseHeader\n //for type inference\n handle.middleware = undefined as (Middleware<any> | undefined)\n\n return handle\n}\n\nexport type Endpoint = {\n path: string\n options: EndpointOptions\n middleware?: Middleware<any>\n headers?: Headers\n} & ((ctx: any) => Promise<any>)","import type { statusCode } from \"./utils\"\n\ntype Status = keyof typeof statusCode\n\nexport class APIError extends Error {\n status: Status\n body: Record<string, any>\n constructor(\n status: Status,\n body?: Record<string, any>,\n ) {\n super(\n `API Error: ${status} ${body?.message ?? \"\"}`,\n {\n cause: body,\n }\n )\n this.status = status\n this.body = body ?? {}\n this.stack = \"\";\n this.name = \"BetterCallAPIError\"\n }\n}","import type { Endpoint } from \"./endpoint\";\nimport {\n createRouter as createRou3Router,\n addRoute,\n findRoute,\n} from \"rou3\";\nimport { getBody, shouldSerialize, statusCode } from \"./utils\";\nimport { APIError } from \"./better-call-error\";\n\ninterface RouterConfig {\n /**\n * Throw error if error occurred other than APIError\n */\n throwError?: boolean\n /**\n * Handle error\n */\n onError?: (e: unknown) => void | Promise<void> | Response | Promise<Response>\n /**\n * Base path for the router\n */\n basePath?: string\n}\n\nexport const createRouter = <E extends Endpoint, Config extends RouterConfig>(endpoints: E[], config?: Config) => {\n const router = createRou3Router()\n for (const endpoint of endpoints) {\n if (Array.isArray(endpoint.options?.method)) {\n for (const method of endpoint.options.method) {\n addRoute(router, method, endpoint.path, endpoint)\n }\n } else {\n addRoute(router, endpoint.options.method, endpoint.path, endpoint)\n }\n }\n\n const handler = async (request: Request) => {\n const url = new URL(request.url);\n let path = url.pathname\n if (config?.basePath) {\n path = path.split(config.basePath)[1]\n }\n const method = request.method;\n const route = findRoute(router, method, path)\n const handler = route?.data as Endpoint\n const body = await getBody(request)\n const headers = request.headers\n\n //handler 404\n if (!handler) {\n return new Response(null, {\n status: 404,\n statusText: \"Not Found\"\n })\n }\n try {\n let middleware: Record<string, any> = {}\n if (handler.middleware) {\n middleware = await handler.middleware({\n path: path,\n method: method,\n headers,\n params: url.searchParams,\n request: request.clone(),\n body: body,\n }) || {}\n }\n const handlerRes = await handler({\n path: path,\n method: method as \"GET\",\n headers,\n params: route?.params as any,\n request: request,\n body: body,\n ...middleware?.context,\n })\n if (handlerRes instanceof Response) {\n return handlerRes\n }\n const resBody = shouldSerialize(handlerRes) ? JSON.stringify(handlerRes) : handlerRes\n return new Response(resBody as any, {\n headers: handler.headers\n })\n } catch (e) {\n if (config?.onError) {\n const onErrorRes = await config.onError(e)\n if (onErrorRes instanceof Response) {\n return onErrorRes\n }\n }\n if (e instanceof APIError) {\n return new Response(e.body ? JSON.stringify(e.body) : null, {\n status: statusCode[e.status],\n statusText: e.status,\n headers: {\n \"Content-Type\": \"application/json\",\n }\n })\n }\n if (config?.throwError) {\n throw e\n }\n return new Response(null, {\n status: 500,\n statusText: \"Internal Server Error\"\n })\n }\n }\n return { handler }\n}","export async function getBody(request: Request) {\n const contentType = request.headers.get('content-type') || '';\n\n if (!request.body) {\n return undefined\n }\n\n if (contentType.includes('application/json')) {\n return await request.json();\n }\n\n if (contentType.includes('application/x-www-form-urlencoded')) {\n const formData = await request.formData();\n const result: Record<string, string> = {};\n formData.forEach((value, key) => {\n result[key] = value.toString();\n });\n return result;\n }\n\n if (contentType.includes('multipart/form-data')) {\n const formData = await request.formData();\n const result: Record<string, any> = {};\n formData.forEach((value, key) => {\n result[key] = value;\n });\n return result;\n }\n\n if (contentType.includes('text/plain')) {\n return await request.text();\n }\n\n if (contentType.includes('application/octet-stream')) {\n return await request.arrayBuffer();\n }\n\n if (contentType.includes('application/pdf') || contentType.includes('image/') || contentType.includes('video/')) {\n const blob = await request.blob();\n return blob;\n }\n\n if (contentType.includes('application/stream') || request.body instanceof ReadableStream) {\n return request.body;\n }\n\n return await request.text();\n}\n\n\nexport function shouldSerialize(body: any) {\n return typeof body === \"object\" && body !== null && !(body instanceof Blob) && !(body instanceof FormData)\n}\n\nexport const statusCode = {\n \"OK\": 200,\n \"Created\": 201,\n \"Accepted\": 202,\n \"No Content\": 204,\n \"Multiple Choices\": 300,\n \"Moved Permanently\": 301,\n \"Found\": 302,\n \"See Other\": 303,\n \"Not Modified\": 304,\n \"Temporary Redirect\": 307,\n \"Bad Request\": 400,\n \"Unauthorized\": 401,\n \"Payment Required\": 402,\n \"Forbidden\": 403,\n \"Not Found\": 404,\n \"Method Not Allowed\": 405,\n \"Not Acceptable\": 406,\n \"Proxy Authentication Required\": 407,\n \"Request Timeout\": 408,\n \"Conflict\": 409,\n \"Gone\": 410,\n \"Length Required\": 411,\n \"Precondition Failed\": 412,\n \"Payload Too Large\": 413,\n \"URI Too Long\": 414,\n \"Unsupported Media Type\": 415,\n \"Range Not Satisfiable\": 416,\n \"Expectation Failed\": 417,\n \"I'm a teapot\": 418,\n \"Misdirected Request\": 421,\n \"Unprocessable Entity\": 422,\n \"Locked\": 423,\n \"Failed Dependency\": 424,\n \"Too Early\": 425,\n \"Upgrade Required\": 426,\n \"Precondition Required\": 428,\n \"Too Many Requests\": 429,\n \"Request Header Fields Too Large\": 431,\n \"Unavailable For Legal Reasons\": 451,\n \"Internal Server Error\": 500,\n \"Not Implemented\": 501,\n \"Bad Gateway\": 502,\n \"Service Unavailable\": 503,\n \"Gateway Timeout\": 504,\n \"HTTP Version Not Supported\": 505,\n \"Variant Also Negotiates\": 506,\n \"Insufficient Storage\": 507,\n \"Loop Detected\": 508,\n \"Not Extended\": 510,\n \"Network Authentication Required\": 511,\n}","import type { HasRequiredKeys } from \"type-fest\"\nimport { type Context, type EndpointOptions, type EndpointResponse, type Handler } from \"./endpoint\"\n\n\nexport type Middleware<E extends Record<string, string>> = (ctx: Context<string, EndpointOptions, E>) => Promise<{\n context: E\n} | void>\n\nexport const createMiddleware = <E extends Record<string, any>, M extends Middleware<E>>(middleware: M) => {\n type MiddlewareContext = Awaited<ReturnType<M>> extends {\n context: infer C\n } ? C extends Record<string, any> ? C : {} : {}\n return <Path extends string, Opts extends EndpointOptions, R extends EndpointResponse>(path: Path, options: Opts, handler: Handler<Path, Opts, R, MiddlewareContext>) => {\n type Ctx = Context<Path, Opts, MiddlewareContext>\n const handle = async (...ctx: HasRequiredKeys<Ctx> extends true ? [Ctx] : [Ctx?]) => {\n const res = await handler((ctx[0] || {}) as Ctx)\n return res as ReturnType<Handler<Path, Opts, R>>\n }\n handle.path = path\n handle.options = options\n handle.middleware = middleware\n return handle\n }\n}"],"mappings":"ijBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,cAAAE,EAAA,mBAAAC,EAAA,qBAAAC,EAAA,iBAAAC,EAAA,YAAAC,EAAA,oBAAAC,EAAA,eAAAC,IAAA,eAAAC,EAAAT,GCAA,IAAAU,EAA8D,eCIvD,IAAMC,EAAN,cAAuB,KAAM,CAGhC,YACIC,EACAC,EACF,CACE,MACI,cAAcD,CAAM,IAAIC,GAAM,SAAW,EAAE,GAC3C,CACI,MAAOA,CACX,CACJ,EAXJC,EAAA,eACAA,EAAA,aAWI,KAAK,OAASF,EACd,KAAK,KAAOC,GAAQ,CAAC,EACrB,KAAK,MAAQ,GACb,KAAK,KAAO,oBAChB,CACJ,ED6FO,SAASE,EAA8FC,EAAYC,EAAeC,EAA+C,CACpL,IAAMC,EAAiB,IAAI,QAErBC,EAAS,SAAUC,IAA4D,CACjF,IAAMC,EAAe,CACjB,UAAUC,EAAKC,EAAO,CAClBL,EAAe,IAAII,EAAKC,CAAK,CACjC,EACA,UAAUD,EAAKC,EAAO,CAClBL,EAAe,OAAO,aAAc,GAAGI,CAAG,IAAIC,CAAK,EAAE,CACzD,EACA,UAAUD,EAAK,CAEX,OADeF,EAAI,CAAC,GAAG,SACR,IAAI,QAAQ,GAAG,MAAM,GAAG,EAAE,KAAKI,GAAUA,EAAO,WAAW,GAAGF,CAAG,GAAG,CAAC,GAAG,MAAM,GAAG,EAAE,CAAC,CACvG,EACA,GAAIF,EAAI,CAAC,GAAK,CAAC,CACnB,EACA,GAAI,CACAC,EAAY,KAAOL,EAAQ,KAAOA,EAAQ,KAAK,MAAMK,EAAY,IAAI,EAAI,OACzEA,EAAY,MAAQL,EAAQ,MAAQA,EAAQ,MAAM,MAAMK,EAAY,KAAK,EAAI,OAC7EA,EAAY,OAASL,EAAQ,OAASA,EAAQ,OAAO,MAAMK,EAAY,MAAM,EAAI,MACrF,OAASI,EAAG,CACR,MAAIA,aAAa,WACP,IAAIC,EAAS,cAAe,CAC9B,QAASD,EAAE,QACX,QAASA,EAAE,MACf,CAAC,EAECA,CACV,CACA,GAAIT,EAAQ,gBAAkB,CAACK,EAAY,QACvC,MAAM,IAAIK,EAAS,cAAe,CAC9B,QAAS,sBACb,CAAC,EAEL,GAAIV,EAAQ,gBAAkB,CAACK,EAAY,QACvC,MAAM,IAAIK,EAAS,cAAe,CAC9B,QAAS,qBACb,CAAC,EAGL,OADY,MAAMT,EAAQI,CAAW,CAEzC,EACA,OAAAF,EAAO,KAAOJ,EACdI,EAAO,QAAUH,EACjBG,EAAO,OAASH,EAAQ,OACxBG,EAAO,QAAUD,EAEjBC,EAAO,WAAa,OAEbA,CACX,CErKA,IAAAQ,EAIO,gBCLP,eAAsBC,EAAQC,EAAkB,CAC5C,IAAMC,EAAcD,EAAQ,QAAQ,IAAI,cAAc,GAAK,GAE3D,GAAKA,EAAQ,KAIb,IAAIC,EAAY,SAAS,kBAAkB,EACvC,OAAO,MAAMD,EAAQ,KAAK,EAG9B,GAAIC,EAAY,SAAS,mCAAmC,EAAG,CAC3D,IAAMC,EAAW,MAAMF,EAAQ,SAAS,EAClCG,EAAiC,CAAC,EACxC,OAAAD,EAAS,QAAQ,CAACE,EAAOC,IAAQ,CAC7BF,EAAOE,CAAG,EAAID,EAAM,SAAS,CACjC,CAAC,EACMD,CACX,CAEA,GAAIF,EAAY,SAAS,qBAAqB,EAAG,CAC7C,IAAMC,EAAW,MAAMF,EAAQ,SAAS,EAClCG,EAA8B,CAAC,EACrC,OAAAD,EAAS,QAAQ,CAACE,EAAOC,IAAQ,CAC7BF,EAAOE,CAAG,EAAID,CAClB,CAAC,EACMD,CACX,CAEA,OAAIF,EAAY,SAAS,YAAY,EAC1B,MAAMD,EAAQ,KAAK,EAG1BC,EAAY,SAAS,0BAA0B,EACxC,MAAMD,EAAQ,YAAY,EAGjCC,EAAY,SAAS,iBAAiB,GAAKA,EAAY,SAAS,QAAQ,GAAKA,EAAY,SAAS,QAAQ,EAC7F,MAAMD,EAAQ,KAAK,EAIhCC,EAAY,SAAS,oBAAoB,GAAKD,EAAQ,gBAAgB,eAC/DA,EAAQ,KAGZ,MAAMA,EAAQ,KAAK,EAC9B,CAGO,SAASM,EAAgBC,EAAW,CACvC,OAAO,OAAOA,GAAS,UAAYA,IAAS,MAAQ,EAAEA,aAAgB,OAAS,EAAEA,aAAgB,SACrG,CAEO,IAAMC,EAAa,CACtB,GAAM,IACN,QAAW,IACX,SAAY,IACZ,aAAc,IACd,mBAAoB,IACpB,oBAAqB,IACrB,MAAS,IACT,YAAa,IACb,eAAgB,IAChB,qBAAsB,IACtB,cAAe,IACf,aAAgB,IAChB,mBAAoB,IACpB,UAAa,IACb,YAAa,IACb,qBAAsB,IACtB,iBAAkB,IAClB,gCAAiC,IACjC,kBAAmB,IACnB,SAAY,IACZ,KAAQ,IACR,kBAAmB,IACnB,sBAAuB,IACvB,oBAAqB,IACrB,eAAgB,IAChB,yBAA0B,IAC1B,wBAAyB,IACzB,qBAAsB,IACtB,eAAgB,IAChB,sBAAuB,IACvB,uBAAwB,IACxB,OAAU,IACV,oBAAqB,IACrB,YAAa,IACb,mBAAoB,IACpB,wBAAyB,IACzB,oBAAqB,IACrB,kCAAmC,IACnC,gCAAiC,IACjC,wBAAyB,IACzB,kBAAmB,IACnB,cAAe,IACf,sBAAuB,IACvB,kBAAmB,IACnB,6BAA8B,IAC9B,0BAA2B,IAC3B,uBAAwB,IACxB,gBAAiB,IACjB,eAAgB,IAChB,kCAAmC,GACvC,EDjFO,IAAMC,EAAe,CAAkDC,EAAgBC,IAAoB,CAC9G,IAAMC,KAAS,EAAAC,cAAiB,EAChC,QAAWC,KAAYJ,EACnB,GAAI,MAAM,QAAQI,EAAS,SAAS,MAAM,EACtC,QAAWC,KAAUD,EAAS,QAAQ,UAClC,YAASF,EAAQG,EAAQD,EAAS,KAAMA,CAAQ,SAGpD,YAASF,EAAQE,EAAS,QAAQ,OAAQA,EAAS,KAAMA,CAAQ,EA4EzE,MAAO,CAAE,QAxEO,MAAOE,GAAqB,CACxC,IAAMC,EAAM,IAAI,IAAID,EAAQ,GAAG,EAC3BE,EAAOD,EAAI,SACXN,GAAQ,WACRO,EAAOA,EAAK,MAAMP,EAAO,QAAQ,EAAE,CAAC,GAExC,IAAMI,EAASC,EAAQ,OACjBG,KAAQ,aAAUP,EAAQG,EAAQG,CAAI,EACtCE,EAAUD,GAAO,KACjBE,EAAO,MAAMC,EAAQN,CAAO,EAC5BO,EAAUP,EAAQ,QAGxB,GAAI,CAACI,EACD,OAAO,IAAI,SAAS,KAAM,CACtB,OAAQ,IACR,WAAY,WAChB,CAAC,EAEL,GAAI,CACA,IAAII,EAAkC,CAAC,EACnCJ,EAAQ,aACRI,EAAa,MAAMJ,EAAQ,WAAW,CAClC,KAAMF,EACN,OAAQH,EACR,QAAAQ,EACA,OAAQN,EAAI,aACZ,QAASD,EAAQ,MAAM,EACvB,KAAMK,CACV,CAAC,GAAK,CAAC,GAEX,IAAMI,EAAa,MAAML,EAAQ,CAC7B,KAAMF,EACN,OAAQH,EACR,QAAAQ,EACA,OAAQJ,GAAO,OACf,QAASH,EACT,KAAMK,EACN,GAAGG,GAAY,OACnB,CAAC,EACD,GAAIC,aAAsB,SACtB,OAAOA,EAEX,IAAMC,EAAUC,EAAgBF,CAAU,EAAI,KAAK,UAAUA,CAAU,EAAIA,EAC3E,OAAO,IAAI,SAASC,EAAgB,CAChC,QAASN,EAAQ,OACrB,CAAC,CACL,OAASQ,EAAG,CACR,GAAIjB,GAAQ,QAAS,CACjB,IAAMkB,EAAa,MAAMlB,EAAO,QAAQiB,CAAC,EACzC,GAAIC,aAAsB,SACtB,OAAOA,CAEf,CACA,GAAID,aAAaE,EACb,OAAO,IAAI,SAASF,EAAE,KAAO,KAAK,UAAUA,EAAE,IAAI,EAAI,KAAM,CACxD,OAAQG,EAAWH,EAAE,MAAM,EAC3B,WAAYA,EAAE,OACd,QAAS,CACL,eAAgB,kBACpB,CACJ,CAAC,EAEL,GAAIjB,GAAQ,WACR,MAAMiB,EAEV,OAAO,IAAI,SAAS,KAAM,CACtB,OAAQ,IACR,WAAY,uBAChB,CAAC,CACL,CACJ,CACiB,CACrB,EErGO,IAAMI,EAA4EC,GAI9E,CAAgFC,EAAYC,EAAeC,IAAuD,CAErK,IAAMC,EAAS,SAAUC,IACT,MAAMF,EAASE,EAAI,CAAC,GAAK,CAAC,CAAS,EAGnD,OAAAD,EAAO,KAAOH,EACdG,EAAO,QAAUF,EACjBE,EAAO,WAAaJ,EACbI,CACX","names":["src_exports","__export","APIError","createEndpoint","createMiddleware","createRouter","getBody","shouldSerialize","statusCode","__toCommonJS","import_zod","APIError","status","body","__publicField","createEndpoint","path","options","handler","responseHeader","handle","ctx","internalCtx","key","value","cookie","e","APIError","import_rou3","getBody","request","contentType","formData","result","value","key","shouldSerialize","body","statusCode","createRouter","endpoints","config","router","createRou3Router","endpoint","method","request","url","path","route","handler","body","getBody","headers","middleware","handlerRes","resBody","shouldSerialize","e","onErrorRes","APIError","statusCode","createMiddleware","middleware","path","options","handler","handle","ctx"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -93,12 +93,7 @@ type InferParam<Path extends string, ParamPath extends InferParamPath<Path> = In
|
|
|
93
93
|
} : {
|
|
94
94
|
params: ParamPath & (WildCard extends undefined ? {} : WildCard);
|
|
95
95
|
};
|
|
96
|
-
type EndpointResponse = Record<string, any> | string | boolean | number |
|
|
97
|
-
status: string;
|
|
98
|
-
body: any;
|
|
99
|
-
headers: Headers | Record<string, any>;
|
|
100
|
-
[key: string]: any;
|
|
101
|
-
} | void | undefined;
|
|
96
|
+
type EndpointResponse = Record<string, any> | string | boolean | number | void | undefined;
|
|
102
97
|
type Handler<Path extends string, Opts extends EndpointOptions, R extends EndpointResponse, Extra extends Record<string, any> = Record<string, any>> = (ctx: Context<Path, Opts, Extra>) => Promise<R>;
|
|
103
98
|
interface EndpointConfig {
|
|
104
99
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -93,12 +93,7 @@ type InferParam<Path extends string, ParamPath extends InferParamPath<Path> = In
|
|
|
93
93
|
} : {
|
|
94
94
|
params: ParamPath & (WildCard extends undefined ? {} : WildCard);
|
|
95
95
|
};
|
|
96
|
-
type EndpointResponse = Record<string, any> | string | boolean | number |
|
|
97
|
-
status: string;
|
|
98
|
-
body: any;
|
|
99
|
-
headers: Headers | Record<string, any>;
|
|
100
|
-
[key: string]: any;
|
|
101
|
-
} | void | undefined;
|
|
96
|
+
type EndpointResponse = Record<string, any> | string | boolean | number | void | undefined;
|
|
102
97
|
type Handler<Path extends string, Opts extends EndpointOptions, R extends EndpointResponse, Extra extends Record<string, any> = Record<string, any>> = (ctx: Context<Path, Opts, Extra>) => Promise<R>;
|
|
103
98
|
interface EndpointConfig {
|
|
104
99
|
/**
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/endpoint.ts","../src/better-call-error.ts","../src/router.ts","../src/utils.ts","../src/middleware.ts"],"sourcesContent":["import { z, ZodError, type ZodOptional, type ZodSchema } from \"zod\"\nimport type { Middleware } from \"./middleware\"\nimport { APIError } from \"./better-call-error\";\n\n\nexport type RequiredKeysOf<BaseType extends object> = Exclude<{\n [Key in keyof BaseType]: BaseType extends Record<Key, BaseType[Key]>\n ? Key\n : never\n}[keyof BaseType], undefined>;\n\nexport type HasRequiredKeys<BaseType extends object> = RequiredKeysOf<BaseType> extends never ? false : true;\n\ntype Method = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\" | \"*\"\n\nexport interface EndpointOptions {\n method: Method | Method[]\n body?: ZodSchema\n query?: ZodSchema\n params?: ZodSchema<any>\n /**\n * If true headers will be required to be passed in the context\n */\n requireHeaders?: boolean\n /**\n * If true request object will be required\n */\n requireRequest?: boolean\n}\n\ntype InferParamPath<Path> =\n Path extends `${infer _Start}:${infer Param}/${infer Rest}`\n ? { [K in Param | keyof InferParamPath<Rest>]: string }\n : Path extends `${infer _Start}:${infer Param}`\n ? { [K in Param]: string }\n : Path extends `${infer _Start}/${infer Rest}`\n ? InferParamPath<Rest>\n : undefined;\n\ntype InferParamWildCard<Path> = Path extends `${infer _Start}/*:${infer Param}/${infer Rest}` | `${infer _Start}/**:${infer Param}/${infer Rest}`\n ? { [K in Param | keyof InferParamPath<Rest>]: string }\n : Path extends `${infer _Start}/*`\n ? { [K in \"_\"]: string }\n : Path extends `${infer _Start}/${infer Rest}`\n ? InferParamPath<Rest>\n : undefined;\n\n\nexport type Prettify<T> = {\n [key in keyof T]: T[key];\n} & {};\n\ntype ContextTools = {\n setHeader: (key: string, value: string) => void\n setCookie: (key: string, value: string) => void\n getCookie: (key: string) => string | undefined\n}\n\nexport type Context<Path extends string, Opts extends EndpointOptions, Extra extends Record<string, any> = {}> = InferBody<Opts[\"body\"]> & InferParam<Path> & InferMethod<Opts['method']> & InferHeaders<Opts[\"requireHeaders\"]> & InferRequest<Opts[\"requireRequest\"]> & InferQuery<Opts[\"query\"]> & Extra\n\ntype InferMethod<M extends Method | Method[]> = M extends Array<Method> ? {\n method: M[number]\n} : {\n method?: M\n}\n\ntype InferHeaders<HeaderReq> = HeaderReq extends true ? {\n headers: Headers\n} : {\n headers?: Headers\n}\n\ntype InferRequest<RequestReq> = RequestReq extends true ? {\n request: Request\n} : {\n request?: Request\n}\n\n\ntype InferBody<Body> = Body extends ZodSchema ? Body extends ZodOptional<any> ? {\n body?: z.infer<Body>\n} : {\n body: z.infer<Body>\n} : {\n body?: undefined\n}\n\ntype InferQuery<Query> = Query extends ZodSchema ? Query extends ZodOptional<any> ? {\n query?: z.infer<Query>\n} : {\n query: z.infer<Query>\n} : {\n query?: undefined\n}\n\ntype InferParam<Path extends string, ParamPath extends InferParamPath<Path> = InferParamPath<Path>, WildCard extends InferParamWildCard<Path> = InferParamWildCard<Path>> = ParamPath extends undefined ? WildCard extends undefined ? {\n params?: undefined\n} : {\n params: WildCard\n} : {\n params: ParamPath & (WildCard extends undefined ? {} : WildCard)\n}\n\n\nexport type EndpointResponse = Record<string, any> | string | boolean | number | {\n status: string,\n body: any,\n headers: Headers | Record<string, any>\n [key: string]: any\n} | void | undefined\n\nexport type Handler<Path extends string, Opts extends EndpointOptions, R extends EndpointResponse, Extra extends Record<string, any> = Record<string, any>> = (ctx: Context<Path, Opts, Extra>) => Promise<R>\n\nexport interface EndpointConfig {\n /**\n * Throw when the response isn't in 200 range\n */\n throwOnError?: boolean\n}\n\nexport function createEndpoint<Path extends string, Opts extends EndpointOptions, R extends EndpointResponse>(path: Path, options: Opts, handler: Handler<Path, Opts, R, ContextTools>) {\n const responseHeader = new Headers()\n type Ctx = Context<Path, Opts>\n const handle = async (...ctx: HasRequiredKeys<Ctx> extends true ? [Ctx] : [Ctx?]) => {\n const internalCtx = ({\n setHeader(key, value) {\n responseHeader.set(key, value)\n },\n setCookie(key, value) {\n responseHeader.append(\"Set-Cookie\", `${key}=${value}`)\n },\n getCookie(key) {\n const header = ctx[0]?.headers\n return header?.get(\"cookie\")?.split(\";\").find(cookie => cookie.startsWith(`${key}=`))?.split(\"=\")[1]\n },\n ...(ctx[0] || {})\n }) as (Ctx & ContextTools)\n try {\n internalCtx.body = options.body ? options.body.parse(internalCtx.body) : undefined\n internalCtx.query = options.query ? options.query.parse(internalCtx.query) : undefined\n internalCtx.params = options.params ? options.params.parse(internalCtx.params) : undefined\n } catch (e) {\n if (e instanceof ZodError) {\n throw new APIError(\"Bad Request\", {\n message: e.message,\n details: e.errors\n })\n }\n throw e\n }\n if (options.requireHeaders && !internalCtx.headers) {\n throw new APIError(\"Bad Request\", {\n message: \"Headers are required\"\n })\n }\n if (options.requireRequest && !internalCtx.request) {\n throw new APIError(\"Bad Request\", {\n message: \"Request is required\"\n })\n }\n const res = await handler(internalCtx)\n return res as ReturnType<Handler<Path, Opts, R>>\n }\n handle.path = path\n handle.options = options\n handle.method = options.method\n handle.headers = responseHeader\n //for type inference\n handle.middleware = undefined as (Middleware<any> | undefined)\n\n return handle\n}\n\nexport type Endpoint = {\n path: string\n options: EndpointOptions\n middleware?: Middleware<any>\n headers?: Headers\n} & ((ctx: any) => Promise<any>)","import type { statusCode } from \"./utils\"\n\ntype Status = keyof typeof statusCode\n\nexport class APIError extends Error {\n status: Status\n body: Record<string, any>\n constructor(\n status: Status,\n body?: Record<string, any>,\n ) {\n super(\n `API Error: ${status} ${body?.message ?? \"\"}`,\n {\n cause: body,\n }\n )\n this.status = status\n this.body = body ?? {}\n this.stack = \"\";\n this.name = \"BetterCallAPIError\"\n }\n}","import type { Endpoint } from \"./endpoint\";\nimport {\n createRouter as createRou3Router,\n addRoute,\n findRoute,\n} from \"rou3\";\nimport { getBody, shouldSerialize, statusCode } from \"./utils\";\nimport { APIError } from \"./better-call-error\";\n\ninterface RouterConfig {\n /**\n * Throw error if error occurred other than APIError\n */\n throwError?: boolean\n /**\n * Handle error\n */\n onError?: (e: unknown) => void | Promise<void> | Response | Promise<Response>\n /**\n * Base path for the router\n */\n basePath?: string\n}\n\nexport const createRouter = <E extends Endpoint, Config extends RouterConfig>(endpoints: E[], config?: Config) => {\n const router = createRou3Router()\n for (const endpoint of endpoints) {\n if (Array.isArray(endpoint.options?.method)) {\n for (const method of endpoint.options.method) {\n addRoute(router, method, endpoint.path, endpoint)\n }\n } else {\n addRoute(router, endpoint.options.method, endpoint.path, endpoint)\n }\n }\n\n const handler = async (request: Request) => {\n const url = new URL(request.url);\n let path = url.pathname\n if (config?.basePath) {\n path = path.split(config.basePath)[1]\n }\n const method = request.method;\n const route = findRoute(router, method, path)\n const handler = route?.data as Endpoint\n const body = await getBody(request)\n const headers = request.headers\n\n //handler 404\n if (!handler) {\n return new Response(null, {\n status: 404,\n statusText: \"Not Found\"\n })\n }\n try {\n let middleware: Record<string, any> = {}\n if (handler.middleware) {\n middleware = await handler.middleware({\n path: path,\n method: method,\n headers,\n params: url.searchParams,\n request: request.clone(),\n body: body,\n }) || {}\n }\n const handlerRes = await handler({\n path: path,\n method: method as \"GET\",\n headers,\n params: route?.params as any,\n request: request,\n body: body,\n ...middleware?.context,\n })\n if (handlerRes instanceof Response) {\n return handlerRes\n }\n const resBody = shouldSerialize(handlerRes) ? JSON.stringify(handlerRes) : handlerRes\n return new Response(resBody as any, {\n headers: handler.headers\n })\n } catch (e) {\n if (config?.onError) {\n const onErrorRes = await config.onError(e)\n if (onErrorRes instanceof Response) {\n return onErrorRes\n }\n }\n if (e instanceof APIError) {\n return new Response(e.body ? JSON.stringify(e.body) : null, {\n status: statusCode[e.status],\n statusText: e.status,\n headers: {\n \"Content-Type\": \"application/json\",\n }\n })\n }\n if (config?.throwError) {\n throw e\n }\n return new Response(null, {\n status: 500,\n statusText: \"Internal Server Error\"\n })\n }\n }\n return { handler }\n}","export async function getBody(request: Request) {\n const contentType = request.headers.get('content-type') || '';\n\n if (!request.body) {\n return undefined\n }\n\n if (contentType.includes('application/json')) {\n return await request.json();\n }\n\n if (contentType.includes('application/x-www-form-urlencoded')) {\n const formData = await request.formData();\n const result: Record<string, string> = {};\n formData.forEach((value, key) => {\n result[key] = value.toString();\n });\n return result;\n }\n\n if (contentType.includes('multipart/form-data')) {\n const formData = await request.formData();\n const result: Record<string, any> = {};\n formData.forEach((value, key) => {\n result[key] = value;\n });\n return result;\n }\n\n if (contentType.includes('text/plain')) {\n return await request.text();\n }\n\n if (contentType.includes('application/octet-stream')) {\n return await request.arrayBuffer();\n }\n\n if (contentType.includes('application/pdf') || contentType.includes('image/') || contentType.includes('video/')) {\n const blob = await request.blob();\n return blob;\n }\n\n if (contentType.includes('application/stream') || request.body instanceof ReadableStream) {\n return request.body;\n }\n\n return await request.text();\n}\n\n\nexport function shouldSerialize(body: any) {\n return typeof body === \"object\" && body !== null && !(body instanceof Blob) && !(body instanceof FormData)\n}\n\nexport const statusCode = {\n \"OK\": 200,\n \"Created\": 201,\n \"Accepted\": 202,\n \"No Content\": 204,\n \"Multiple Choices\": 300,\n \"Moved Permanently\": 301,\n \"Found\": 302,\n \"See Other\": 303,\n \"Not Modified\": 304,\n \"Temporary Redirect\": 307,\n \"Bad Request\": 400,\n \"Unauthorized\": 401,\n \"Payment Required\": 402,\n \"Forbidden\": 403,\n \"Not Found\": 404,\n \"Method Not Allowed\": 405,\n \"Not Acceptable\": 406,\n \"Proxy Authentication Required\": 407,\n \"Request Timeout\": 408,\n \"Conflict\": 409,\n \"Gone\": 410,\n \"Length Required\": 411,\n \"Precondition Failed\": 412,\n \"Payload Too Large\": 413,\n \"URI Too Long\": 414,\n \"Unsupported Media Type\": 415,\n \"Range Not Satisfiable\": 416,\n \"Expectation Failed\": 417,\n \"I'm a teapot\": 418,\n \"Misdirected Request\": 421,\n \"Unprocessable Entity\": 422,\n \"Locked\": 423,\n \"Failed Dependency\": 424,\n \"Too Early\": 425,\n \"Upgrade Required\": 426,\n \"Precondition Required\": 428,\n \"Too Many Requests\": 429,\n \"Request Header Fields Too Large\": 431,\n \"Unavailable For Legal Reasons\": 451,\n \"Internal Server Error\": 500,\n \"Not Implemented\": 501,\n \"Bad Gateway\": 502,\n \"Service Unavailable\": 503,\n \"Gateway Timeout\": 504,\n \"HTTP Version Not Supported\": 505,\n \"Variant Also Negotiates\": 506,\n \"Insufficient Storage\": 507,\n \"Loop Detected\": 508,\n \"Not Extended\": 510,\n \"Network Authentication Required\": 511,\n}","import type { HasRequiredKeys } from \"type-fest\"\nimport { type Context, type EndpointOptions, type EndpointResponse, type Handler } from \"./endpoint\"\n\n\nexport type Middleware<E extends Record<string, string>> = (ctx: Context<string, EndpointOptions, E>) => Promise<{\n context: E\n} | void>\n\nexport const createMiddleware = <E extends Record<string, any>, M extends Middleware<E>>(middleware: M) => {\n type MiddlewareContext = Awaited<ReturnType<M>> extends {\n context: infer C\n } ? C extends Record<string, any> ? C : {} : {}\n return <Path extends string, Opts extends EndpointOptions, R extends EndpointResponse>(path: Path, options: Opts, handler: Handler<Path, Opts, R, MiddlewareContext>) => {\n type Ctx = Context<Path, Opts, MiddlewareContext>\n const handle = async (...ctx: HasRequiredKeys<Ctx> extends true ? [Ctx] : [Ctx?]) => {\n const res = await handler((ctx[0] || {}) as Ctx)\n return res as ReturnType<Handler<Path, Opts, R>>\n }\n handle.path = path\n handle.options = options\n handle.middleware = middleware\n return handle\n }\n}"],"mappings":"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","names":["ZodError","APIError","status","body","__publicField","createEndpoint","path","options","handler","responseHeader","handle","ctx","internalCtx","key","value","cookie","e","ZodError","APIError","createRou3Router","addRoute","findRoute","getBody","request","contentType","formData","result","value","key","shouldSerialize","body","statusCode","createRouter","endpoints","config","router","createRou3Router","endpoint","method","addRoute","request","url","path","route","findRoute","handler","body","getBody","headers","middleware","handlerRes","resBody","shouldSerialize","e","onErrorRes","APIError","statusCode","createMiddleware","middleware","path","options","handler","handle","ctx"]}
|
|
1
|
+
{"version":3,"sources":["../src/endpoint.ts","../src/better-call-error.ts","../src/router.ts","../src/utils.ts","../src/middleware.ts"],"sourcesContent":["import { z, ZodError, type ZodOptional, type ZodSchema } from \"zod\"\nimport type { Middleware } from \"./middleware\"\nimport { APIError } from \"./better-call-error\";\n\n\nexport type RequiredKeysOf<BaseType extends object> = Exclude<{\n [Key in keyof BaseType]: BaseType extends Record<Key, BaseType[Key]>\n ? Key\n : never\n}[keyof BaseType], undefined>;\n\nexport type HasRequiredKeys<BaseType extends object> = RequiredKeysOf<BaseType> extends never ? false : true;\n\ntype Method = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\" | \"*\"\n\nexport interface EndpointOptions {\n method: Method | Method[]\n body?: ZodSchema\n query?: ZodSchema\n params?: ZodSchema<any>\n /**\n * If true headers will be required to be passed in the context\n */\n requireHeaders?: boolean\n /**\n * If true request object will be required\n */\n requireRequest?: boolean\n}\n\ntype InferParamPath<Path> =\n Path extends `${infer _Start}:${infer Param}/${infer Rest}`\n ? { [K in Param | keyof InferParamPath<Rest>]: string }\n : Path extends `${infer _Start}:${infer Param}`\n ? { [K in Param]: string }\n : Path extends `${infer _Start}/${infer Rest}`\n ? InferParamPath<Rest>\n : undefined;\n\ntype InferParamWildCard<Path> = Path extends `${infer _Start}/*:${infer Param}/${infer Rest}` | `${infer _Start}/**:${infer Param}/${infer Rest}`\n ? { [K in Param | keyof InferParamPath<Rest>]: string }\n : Path extends `${infer _Start}/*`\n ? { [K in \"_\"]: string }\n : Path extends `${infer _Start}/${infer Rest}`\n ? InferParamPath<Rest>\n : undefined;\n\n\nexport type Prettify<T> = {\n [key in keyof T]: T[key];\n} & {};\n\ntype ContextTools = {\n setHeader: (key: string, value: string) => void\n setCookie: (key: string, value: string) => void\n getCookie: (key: string) => string | undefined\n}\n\nexport type Context<Path extends string, Opts extends EndpointOptions, Extra extends Record<string, any> = {}> = InferBody<Opts[\"body\"]> & InferParam<Path> & InferMethod<Opts['method']> & InferHeaders<Opts[\"requireHeaders\"]> & InferRequest<Opts[\"requireRequest\"]> & InferQuery<Opts[\"query\"]> & Extra\n\ntype InferMethod<M extends Method | Method[]> = M extends Array<Method> ? {\n method: M[number]\n} : {\n method?: M\n}\n\ntype InferHeaders<HeaderReq> = HeaderReq extends true ? {\n headers: Headers\n} : {\n headers?: Headers\n}\n\ntype InferRequest<RequestReq> = RequestReq extends true ? {\n request: Request\n} : {\n request?: Request\n}\n\n\ntype InferBody<Body> = Body extends ZodSchema ? Body extends ZodOptional<any> ? {\n body?: z.infer<Body>\n} : {\n body: z.infer<Body>\n} : {\n body?: undefined\n}\n\ntype InferQuery<Query> = Query extends ZodSchema ? Query extends ZodOptional<any> ? {\n query?: z.infer<Query>\n} : {\n query: z.infer<Query>\n} : {\n query?: undefined\n}\n\ntype InferParam<Path extends string, ParamPath extends InferParamPath<Path> = InferParamPath<Path>, WildCard extends InferParamWildCard<Path> = InferParamWildCard<Path>> = ParamPath extends undefined ? WildCard extends undefined ? {\n params?: undefined\n} : {\n params: WildCard\n} : {\n params: ParamPath & (WildCard extends undefined ? {} : WildCard)\n}\n\n\nexport type EndpointResponse = Record<string, any> | string | boolean | number | void | undefined\n\nexport type Handler<Path extends string, Opts extends EndpointOptions, R extends EndpointResponse, Extra extends Record<string, any> = Record<string, any>> = (ctx: Context<Path, Opts, Extra>) => Promise<R>\n\nexport interface EndpointConfig {\n /**\n * Throw when the response isn't in 200 range\n */\n throwOnError?: boolean\n}\n\nexport function createEndpoint<Path extends string, Opts extends EndpointOptions, R extends EndpointResponse>(path: Path, options: Opts, handler: Handler<Path, Opts, R, ContextTools>) {\n const responseHeader = new Headers()\n type Ctx = Context<Path, Opts>\n const handle = async (...ctx: HasRequiredKeys<Ctx> extends true ? [Ctx] : [Ctx?]) => {\n const internalCtx = ({\n setHeader(key, value) {\n responseHeader.set(key, value)\n },\n setCookie(key, value) {\n responseHeader.append(\"Set-Cookie\", `${key}=${value}`)\n },\n getCookie(key) {\n const header = ctx[0]?.headers\n return header?.get(\"cookie\")?.split(\";\").find(cookie => cookie.startsWith(`${key}=`))?.split(\"=\")[1]\n },\n ...(ctx[0] || {})\n }) as (Ctx & ContextTools)\n try {\n internalCtx.body = options.body ? options.body.parse(internalCtx.body) : undefined\n internalCtx.query = options.query ? options.query.parse(internalCtx.query) : undefined\n internalCtx.params = options.params ? options.params.parse(internalCtx.params) : undefined\n } catch (e) {\n if (e instanceof ZodError) {\n throw new APIError(\"Bad Request\", {\n message: e.message,\n details: e.errors\n })\n }\n throw e\n }\n if (options.requireHeaders && !internalCtx.headers) {\n throw new APIError(\"Bad Request\", {\n message: \"Headers are required\"\n })\n }\n if (options.requireRequest && !internalCtx.request) {\n throw new APIError(\"Bad Request\", {\n message: \"Request is required\"\n })\n }\n const res = await handler(internalCtx)\n return res as ReturnType<Handler<Path, Opts, R>>\n }\n handle.path = path\n handle.options = options\n handle.method = options.method\n handle.headers = responseHeader\n //for type inference\n handle.middleware = undefined as (Middleware<any> | undefined)\n\n return handle\n}\n\nexport type Endpoint = {\n path: string\n options: EndpointOptions\n middleware?: Middleware<any>\n headers?: Headers\n} & ((ctx: any) => Promise<any>)","import type { statusCode } from \"./utils\"\n\ntype Status = keyof typeof statusCode\n\nexport class APIError extends Error {\n status: Status\n body: Record<string, any>\n constructor(\n status: Status,\n body?: Record<string, any>,\n ) {\n super(\n `API Error: ${status} ${body?.message ?? \"\"}`,\n {\n cause: body,\n }\n )\n this.status = status\n this.body = body ?? {}\n this.stack = \"\";\n this.name = \"BetterCallAPIError\"\n }\n}","import type { Endpoint } from \"./endpoint\";\nimport {\n createRouter as createRou3Router,\n addRoute,\n findRoute,\n} from \"rou3\";\nimport { getBody, shouldSerialize, statusCode } from \"./utils\";\nimport { APIError } from \"./better-call-error\";\n\ninterface RouterConfig {\n /**\n * Throw error if error occurred other than APIError\n */\n throwError?: boolean\n /**\n * Handle error\n */\n onError?: (e: unknown) => void | Promise<void> | Response | Promise<Response>\n /**\n * Base path for the router\n */\n basePath?: string\n}\n\nexport const createRouter = <E extends Endpoint, Config extends RouterConfig>(endpoints: E[], config?: Config) => {\n const router = createRou3Router()\n for (const endpoint of endpoints) {\n if (Array.isArray(endpoint.options?.method)) {\n for (const method of endpoint.options.method) {\n addRoute(router, method, endpoint.path, endpoint)\n }\n } else {\n addRoute(router, endpoint.options.method, endpoint.path, endpoint)\n }\n }\n\n const handler = async (request: Request) => {\n const url = new URL(request.url);\n let path = url.pathname\n if (config?.basePath) {\n path = path.split(config.basePath)[1]\n }\n const method = request.method;\n const route = findRoute(router, method, path)\n const handler = route?.data as Endpoint\n const body = await getBody(request)\n const headers = request.headers\n\n //handler 404\n if (!handler) {\n return new Response(null, {\n status: 404,\n statusText: \"Not Found\"\n })\n }\n try {\n let middleware: Record<string, any> = {}\n if (handler.middleware) {\n middleware = await handler.middleware({\n path: path,\n method: method,\n headers,\n params: url.searchParams,\n request: request.clone(),\n body: body,\n }) || {}\n }\n const handlerRes = await handler({\n path: path,\n method: method as \"GET\",\n headers,\n params: route?.params as any,\n request: request,\n body: body,\n ...middleware?.context,\n })\n if (handlerRes instanceof Response) {\n return handlerRes\n }\n const resBody = shouldSerialize(handlerRes) ? JSON.stringify(handlerRes) : handlerRes\n return new Response(resBody as any, {\n headers: handler.headers\n })\n } catch (e) {\n if (config?.onError) {\n const onErrorRes = await config.onError(e)\n if (onErrorRes instanceof Response) {\n return onErrorRes\n }\n }\n if (e instanceof APIError) {\n return new Response(e.body ? JSON.stringify(e.body) : null, {\n status: statusCode[e.status],\n statusText: e.status,\n headers: {\n \"Content-Type\": \"application/json\",\n }\n })\n }\n if (config?.throwError) {\n throw e\n }\n return new Response(null, {\n status: 500,\n statusText: \"Internal Server Error\"\n })\n }\n }\n return { handler }\n}","export async function getBody(request: Request) {\n const contentType = request.headers.get('content-type') || '';\n\n if (!request.body) {\n return undefined\n }\n\n if (contentType.includes('application/json')) {\n return await request.json();\n }\n\n if (contentType.includes('application/x-www-form-urlencoded')) {\n const formData = await request.formData();\n const result: Record<string, string> = {};\n formData.forEach((value, key) => {\n result[key] = value.toString();\n });\n return result;\n }\n\n if (contentType.includes('multipart/form-data')) {\n const formData = await request.formData();\n const result: Record<string, any> = {};\n formData.forEach((value, key) => {\n result[key] = value;\n });\n return result;\n }\n\n if (contentType.includes('text/plain')) {\n return await request.text();\n }\n\n if (contentType.includes('application/octet-stream')) {\n return await request.arrayBuffer();\n }\n\n if (contentType.includes('application/pdf') || contentType.includes('image/') || contentType.includes('video/')) {\n const blob = await request.blob();\n return blob;\n }\n\n if (contentType.includes('application/stream') || request.body instanceof ReadableStream) {\n return request.body;\n }\n\n return await request.text();\n}\n\n\nexport function shouldSerialize(body: any) {\n return typeof body === \"object\" && body !== null && !(body instanceof Blob) && !(body instanceof FormData)\n}\n\nexport const statusCode = {\n \"OK\": 200,\n \"Created\": 201,\n \"Accepted\": 202,\n \"No Content\": 204,\n \"Multiple Choices\": 300,\n \"Moved Permanently\": 301,\n \"Found\": 302,\n \"See Other\": 303,\n \"Not Modified\": 304,\n \"Temporary Redirect\": 307,\n \"Bad Request\": 400,\n \"Unauthorized\": 401,\n \"Payment Required\": 402,\n \"Forbidden\": 403,\n \"Not Found\": 404,\n \"Method Not Allowed\": 405,\n \"Not Acceptable\": 406,\n \"Proxy Authentication Required\": 407,\n \"Request Timeout\": 408,\n \"Conflict\": 409,\n \"Gone\": 410,\n \"Length Required\": 411,\n \"Precondition Failed\": 412,\n \"Payload Too Large\": 413,\n \"URI Too Long\": 414,\n \"Unsupported Media Type\": 415,\n \"Range Not Satisfiable\": 416,\n \"Expectation Failed\": 417,\n \"I'm a teapot\": 418,\n \"Misdirected Request\": 421,\n \"Unprocessable Entity\": 422,\n \"Locked\": 423,\n \"Failed Dependency\": 424,\n \"Too Early\": 425,\n \"Upgrade Required\": 426,\n \"Precondition Required\": 428,\n \"Too Many Requests\": 429,\n \"Request Header Fields Too Large\": 431,\n \"Unavailable For Legal Reasons\": 451,\n \"Internal Server Error\": 500,\n \"Not Implemented\": 501,\n \"Bad Gateway\": 502,\n \"Service Unavailable\": 503,\n \"Gateway Timeout\": 504,\n \"HTTP Version Not Supported\": 505,\n \"Variant Also Negotiates\": 506,\n \"Insufficient Storage\": 507,\n \"Loop Detected\": 508,\n \"Not Extended\": 510,\n \"Network Authentication Required\": 511,\n}","import type { HasRequiredKeys } from \"type-fest\"\nimport { type Context, type EndpointOptions, type EndpointResponse, type Handler } from \"./endpoint\"\n\n\nexport type Middleware<E extends Record<string, string>> = (ctx: Context<string, EndpointOptions, E>) => Promise<{\n context: E\n} | void>\n\nexport const createMiddleware = <E extends Record<string, any>, M extends Middleware<E>>(middleware: M) => {\n type MiddlewareContext = Awaited<ReturnType<M>> extends {\n context: infer C\n } ? C extends Record<string, any> ? C : {} : {}\n return <Path extends string, Opts extends EndpointOptions, R extends EndpointResponse>(path: Path, options: Opts, handler: Handler<Path, Opts, R, MiddlewareContext>) => {\n type Ctx = Context<Path, Opts, MiddlewareContext>\n const handle = async (...ctx: HasRequiredKeys<Ctx> extends true ? [Ctx] : [Ctx?]) => {\n const res = await handler((ctx[0] || {}) as Ctx)\n return res as ReturnType<Handler<Path, Opts, R>>\n }\n handle.path = path\n handle.options = options\n handle.middleware = middleware\n return handle\n }\n}"],"mappings":"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","names":["ZodError","APIError","status","body","__publicField","createEndpoint","path","options","handler","responseHeader","handle","ctx","internalCtx","key","value","cookie","e","ZodError","APIError","createRou3Router","addRoute","findRoute","getBody","request","contentType","formData","result","value","key","shouldSerialize","body","statusCode","createRouter","endpoints","config","router","createRou3Router","endpoint","method","addRoute","request","url","path","route","findRoute","handler","body","getBody","headers","middleware","handlerRes","resBody","shouldSerialize","e","onErrorRes","APIError","statusCode","createMiddleware","middleware","path","options","handler","handle","ctx"]}
|