better-call 2.0.1 → 2.0.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.
@@ -1 +1 @@
1
- {"version":3,"file":"endpoint.cjs","names":["BetterCallError","tryCatch","createInternalContext","ValidationError","APIError","isAPIError","toResponse"],"sources":["../src/endpoint.ts"],"sourcesContent":["import { createInternalContext, type EndpointContext } from \"./context\";\nimport type { CookieOptions, CookiePrefixOptions } from \"./cookies\";\nimport {\n\tAPIError,\n\tBetterCallError,\n\ttype Status,\n\ttype statusCodes,\n\tValidationError,\n} from \"./error\";\nimport type { HasRequiredKeys, Prettify } from \"./helper\";\nimport type { Middleware } from \"./middleware\";\nimport type { OpenAPIParameter, OpenAPISchemaType } from \"./openapi\";\nimport type { StandardSchemaV1 } from \"./standard-schema\";\nimport { toResponse } from \"./to-response\";\nimport type {\n\tBodyOption,\n\tHasRequiredInputKeys,\n\tHTTPMethod,\n\tInferUse,\n\tInputContext,\n\tResolveBodyInput,\n\tResolveErrorInput,\n\tResolveMetaInput,\n\tResolveQueryInput,\n} from \"./types\";\nimport { isAPIError, tryCatch } from \"./utils\";\n\nexport type { EndpointContext } from \"./context\";\n\nexport interface EndpointMetadata {\n\t/**\n\t * Open API definition\n\t */\n\topenapi?: {\n\t\tsummary?: string;\n\t\tdescription?: string;\n\t\ttags?: string[];\n\t\toperationId?: string;\n\t\tparameters?: OpenAPIParameter[];\n\t\trequestBody?: {\n\t\t\tcontent: {\n\t\t\t\t\"application/json\": {\n\t\t\t\t\tschema: {\n\t\t\t\t\t\ttype?: OpenAPISchemaType;\n\t\t\t\t\t\tproperties?: Record<string, any>;\n\t\t\t\t\t\trequired?: string[];\n\t\t\t\t\t\t$ref?: string;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t};\n\t\tresponses?: {\n\t\t\t[status: string]: {\n\t\t\t\tdescription: string;\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\t\"text/plain\"?: {\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\t\"text/html\"?: {\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};\n\t};\n\t/**\n\t * Infer body and query type from ts interface\n\t *\n\t * useful for generic and dynamic types\n\t *\n\t * @example\n\t * ```ts\n\t * const endpoint = createEndpoint(\"/path\", {\n\t * \t\tmethod: \"POST\",\n\t * \t\tbody: z.record(z.string()),\n\t * \t\t$Infer: {\n\t * \t\t\tbody: {} as {\n\t * \t\t\t\ttype: InferTypeFromOptions<Option> // custom type inference\n\t * \t\t\t}\n\t * \t\t}\n\t * \t}, async(ctx)=>{\n\t * \t\tconst body = ctx.body\n\t * \t})\n\t * ```\n\t */\n\t$Infer?: {\n\t\t/**\n\t\t * Body\n\t\t */\n\t\tbody?: any;\n\t\t/**\n\t\t * Query\n\t\t */\n\t\tquery?: Record<string, any>;\n\t\t/**\n\t\t * Error\n\t\t */\n\t\terror?: any;\n\t};\n\t/**\n\t * If enabled, endpoint won't be exposed over a router\n\t * @deprecated Use path-less endpoints instead\n\t */\n\tSERVER_ONLY?: boolean;\n\t/**\n\t * If enabled, endpoint won't be exposed as an action to the client\n\t * @deprecated Use path-less endpoints instead\n\t */\n\tisAction?: boolean;\n\t/**\n\t * Defines the places where the endpoint will be available\n\t *\n\t * Possible options:\n\t * - `rpc` - the endpoint is exposed to the router, can be invoked directly and is available to the client\n\t * - `server` - the endpoint is exposed to the router, can be invoked directly, but is not available to the client\n\t * - `http` - the endpoint is only exposed to the router\n\t * @default \"rpc\"\n\t */\n\tscope?: \"rpc\" | \"server\" | \"http\";\n\t/**\n\t * List of allowed media types (MIME types) for the endpoint\n\t *\n\t * if provided, only the media types in the list will be allowed to be passed in the body\n\t *\n\t * @example\n\t * ```ts\n\t * const endpoint = createEndpoint(\"/path\", {\n\t * \t\tmethod: \"POST\",\n\t * \t\tallowedMediaTypes: [\"application/json\", \"application/x-www-form-urlencoded\"],\n\t * \t}, async(ctx)=>{\n\t * \t\tconst body = ctx.body\n\t * \t})\n\t * ```\n\t */\n\tallowedMediaTypes?: string[];\n\t/**\n\t * Extra metadata\n\t */\n\t[key: string]: any;\n}\n\nexport interface EndpointRuntimeOptions {\n\tmethod: string | string[];\n\tbody?: StandardSchemaV1;\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?: EndpointMetadata;\n\t/**\n\t * List of middlewares to use\n\t */\n\tuse?: Middleware[];\n\t/**\n\t * A callback to run before any API error is thrown or returned\n\t *\n\t * @param e - The API error\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?: (info: {\n\t\tmessage: string;\n\t\tissues: readonly StandardSchemaV1.Issue[];\n\t}) => void | Promise<void>;\n}\n\nexport type Endpoint<\n\tPath extends string = string,\n\tMethod = any,\n\tBody = any,\n\tQuery = any,\n\tUse extends Middleware[] = any,\n\tR = any,\n\tMeta extends EndpointMetadata | undefined = EndpointMetadata | undefined,\n\tError = any,\n> = {\n\t(\n\t\tcontext: InputContext<Path, Method, Body, Query, false, false> & {\n\t\t\tasResponse: true;\n\t\t},\n\t): Promise<Response>;\n\t(\n\t\tcontext: InputContext<Path, Method, Body, Query, false, false> & {\n\t\t\treturnHeaders: true;\n\t\t\treturnStatus: true;\n\t\t},\n\t): Promise<{\n\t\theaders: Headers;\n\t\tstatus: number;\n\t\tresponse: Awaited<R>;\n\t}>;\n\t(\n\t\tcontext: InputContext<Path, Method, Body, Query, false, false> & {\n\t\t\treturnHeaders: true;\n\t\t},\n\t): Promise<{\n\t\theaders: Headers;\n\t\tresponse: Awaited<R>;\n\t}>;\n\t(\n\t\tcontext: InputContext<Path, Method, Body, Query, false, false> & {\n\t\t\treturnStatus: true;\n\t\t},\n\t): Promise<{\n\t\tstatus: number;\n\t\tresponse: Awaited<R>;\n\t}>;\n\t(\n\t\tcontext?: InputContext<Path, Method, Body, Query, false, false>,\n\t): Promise<Awaited<R>>;\n\toptions: EndpointRuntimeOptions & {\n\t\tmethod: Method;\n\t\tmetadata?: Meta;\n\t};\n\tpath: Path;\n};\n\n// Path + options + handler overload\nexport function createEndpoint<\n\tPath extends string,\n\tMethod extends HTTPMethod | HTTPMethod[] | \"*\",\n\tBodySchema extends object | undefined = undefined,\n\tQuerySchema extends object | undefined = undefined,\n\tUse extends Middleware[] = [],\n\tReqHeaders extends boolean = false,\n\tReqRequest extends boolean = false,\n\tR = unknown,\n\tMeta extends EndpointMetadata | undefined = undefined,\n\tErrorSchema extends StandardSchemaV1 | undefined = undefined,\n>(\n\tpath: Path,\n\toptions: { method: Method } & BodyOption<Method, BodySchema> & {\n\t\t\tquery?: QuerySchema;\n\t\t\tuse?: [...Use];\n\t\t\trequireHeaders?: ReqHeaders;\n\t\t\trequireRequest?: ReqRequest;\n\t\t\terror?: ErrorSchema;\n\t\t\tcloneRequest?: boolean;\n\t\t\tdisableBody?: boolean;\n\t\t\tmetadata?: Meta;\n\t\t\tonAPIError?: (e: APIError) => void | Promise<void>;\n\t\t\tonValidationError?: (info: {\n\t\t\t\tmessage: string;\n\t\t\t\tissues: readonly StandardSchemaV1.Issue[];\n\t\t\t}) => void | Promise<void>;\n\t\t\t[key: string]: any;\n\t\t},\n\thandler: (\n\t\tctx: EndpointContext<\n\t\t\tPath,\n\t\t\tMethod,\n\t\t\tBodySchema,\n\t\t\tQuerySchema,\n\t\t\tUse,\n\t\t\tReqHeaders,\n\t\t\tReqRequest,\n\t\t\tInferUse<Use>,\n\t\t\tMeta\n\t\t>,\n\t) => Promise<R>,\n): Endpoint<\n\tPath,\n\tMethod,\n\tResolveBodyInput<BodySchema, Meta>,\n\tResolveQueryInput<QuerySchema, Meta>,\n\tUse,\n\tR,\n\tResolveMetaInput<Meta>,\n\tResolveErrorInput<ErrorSchema, Meta>\n>;\n\n// Options-only (virtual/path-less) overload\nexport function createEndpoint<\n\tMethod extends HTTPMethod | HTTPMethod[] | \"*\",\n\tBodySchema extends object | undefined = undefined,\n\tQuerySchema extends object | undefined = undefined,\n\tUse extends Middleware[] = [],\n\tReqHeaders extends boolean = false,\n\tReqRequest extends boolean = false,\n\tR = unknown,\n\tMeta extends EndpointMetadata | undefined = undefined,\n\tErrorSchema extends StandardSchemaV1 | undefined = undefined,\n>(\n\toptions: { method: Method } & BodyOption<Method, BodySchema> & {\n\t\t\tpath?: never;\n\t\t\tquery?: QuerySchema;\n\t\t\tuse?: [...Use];\n\t\t\trequireHeaders?: ReqHeaders;\n\t\t\trequireRequest?: ReqRequest;\n\t\t\terror?: ErrorSchema;\n\t\t\tcloneRequest?: boolean;\n\t\t\tdisableBody?: boolean;\n\t\t\tmetadata?: Meta;\n\t\t\tonAPIError?: (e: APIError) => void | Promise<void>;\n\t\t\tonValidationError?: (info: {\n\t\t\t\tmessage: string;\n\t\t\t\tissues: readonly StandardSchemaV1.Issue[];\n\t\t\t}) => void | Promise<void>;\n\t\t\t[key: string]: any;\n\t\t},\n\thandler: (\n\t\tctx: EndpointContext<\n\t\t\tnever,\n\t\t\tMethod,\n\t\t\tBodySchema,\n\t\t\tQuerySchema,\n\t\t\tUse,\n\t\t\tReqHeaders,\n\t\t\tReqRequest,\n\t\t\tInferUse<Use>,\n\t\t\tMeta\n\t\t>,\n\t) => Promise<R>,\n): Endpoint<\n\tnever,\n\tMethod,\n\tResolveBodyInput<BodySchema, Meta>,\n\tResolveQueryInput<QuerySchema, Meta>,\n\tUse,\n\tR,\n\tResolveMetaInput<Meta>,\n\tResolveErrorInput<ErrorSchema, Meta>\n>;\n\n// Implementation\nexport function createEndpoint(\n\tpathOrOptions: any,\n\thandlerOrOptions: any,\n\thandlerOrNever?: any,\n): any {\n\tconst path: string | undefined =\n\t\ttypeof pathOrOptions === \"string\" ? pathOrOptions : undefined;\n\tconst options: any =\n\t\ttypeof handlerOrOptions === \"object\" ? handlerOrOptions : pathOrOptions;\n\tconst handler: any =\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\n\tconst runtimeOptions: EndpointRuntimeOptions = {\n\t\tmethod: options.method,\n\t\tbody: options.body,\n\t\tquery: options.query,\n\t\terror: options.error,\n\t\trequireHeaders: options.requireHeaders,\n\t\trequireRequest: options.requireRequest,\n\t\tcloneRequest: options.cloneRequest,\n\t\tdisableBody: options.disableBody,\n\t\tmetadata: options.metadata,\n\t\tuse: options.use,\n\t\tonAPIError: options.onAPIError,\n\t\tonValidationError: options.onValidationError,\n\t};\n\n\tconst internalHandler = async (...inputCtx: any[]): Promise<any> => {\n\t\tconst context = (inputCtx[0] || {}) as Record<string, any>;\n\t\tconst { data: internalContext, error: validationError } = await tryCatch(\n\t\t\tcreateInternalContext(context, {\n\t\t\t\toptions: runtimeOptions,\n\t\t\t\tpath,\n\t\t\t}),\n\t\t);\n\n\t\tif (validationError) {\n\t\t\tif (!(validationError instanceof ValidationError)) throw validationError;\n\n\t\t\tif (options.onValidationError) {\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\n\t\tconst response = await handler(internalContext as any).catch(\n\t\t\tasync (e: any) => {\n\t\t\t\tif (isAPIError(e)) {\n\t\t\t\t\tconst onAPIError = options.onAPIError;\n\t\t\t\t\tif (onAPIError) {\n\t\t\t\t\t\tawait onAPIError(e);\n\t\t\t\t\t}\n\t\t\t\t\tif (context.asResponse) {\n\t\t\t\t\t\treturn e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthrow e;\n\t\t\t},\n\t\t);\n\n\t\tconst responseHeaders = internalContext.responseHeaders;\n\t\tconst status = internalContext.responseStatus;\n\n\t\treturn context.asResponse\n\t\t\t? toResponse(response, {\n\t\t\t\t\theaders: responseHeaders,\n\t\t\t\t\tstatus,\n\t\t\t\t})\n\t\t\t: context.returnHeaders\n\t\t\t\t? context.returnStatus\n\t\t\t\t\t? {\n\t\t\t\t\t\t\theaders: responseHeaders,\n\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t\tstatus,\n\t\t\t\t\t\t}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\theaders: responseHeaders,\n\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t}\n\t\t\t\t: context.returnStatus\n\t\t\t\t\t? { response, status }\n\t\t\t\t\t: response;\n\t};\n\n\tinternalHandler.options = runtimeOptions;\n\tinternalHandler.path = path;\n\treturn internalHandler as any;\n}\n\ncreateEndpoint.create = <E extends { use?: Middleware[] }>(opts?: E) => {\n\treturn <\n\t\tPath extends string,\n\t\tMethod extends HTTPMethod | HTTPMethod[] | \"*\",\n\t\tBodySchema extends object | undefined = undefined,\n\t\tQuerySchema extends object | undefined = undefined,\n\t\tUse extends Middleware[] = [],\n\t\tReqHeaders extends boolean = false,\n\t\tReqRequest extends boolean = false,\n\t\tR = unknown,\n\t\tMeta extends EndpointMetadata | undefined = undefined,\n\t\tErrorSchema extends StandardSchemaV1 | undefined = undefined,\n\t>(\n\t\tpath: Path,\n\t\toptions: { method: Method } & BodyOption<Method, BodySchema> & {\n\t\t\t\tquery?: QuerySchema;\n\t\t\t\tuse?: [...Use];\n\t\t\t\trequireHeaders?: ReqHeaders;\n\t\t\t\trequireRequest?: ReqRequest;\n\t\t\t\terror?: ErrorSchema;\n\t\t\t\tcloneRequest?: boolean;\n\t\t\t\tdisableBody?: boolean;\n\t\t\t\tmetadata?: Meta;\n\t\t\t\tonAPIError?: (e: APIError) => void | Promise<void>;\n\t\t\t\tonValidationError?: (info: {\n\t\t\t\t\tmessage: string;\n\t\t\t\t\tissues: readonly StandardSchemaV1.Issue[];\n\t\t\t\t}) => void | Promise<void>;\n\t\t\t\t[key: string]: any;\n\t\t\t},\n\t\thandler: (\n\t\t\tctx: EndpointContext<\n\t\t\t\tPath,\n\t\t\t\tMethod,\n\t\t\t\tBodySchema,\n\t\t\t\tQuerySchema,\n\t\t\t\tUse,\n\t\t\t\tReqHeaders,\n\t\t\t\tReqRequest,\n\t\t\t\tInferUse<E[\"use\"]>,\n\t\t\t\tMeta\n\t\t\t>,\n\t\t) => Promise<R>,\n\t): Endpoint<\n\t\tPath,\n\t\tMethod,\n\t\tResolveBodyInput<BodySchema, Meta>,\n\t\tResolveQueryInput<QuerySchema, Meta>,\n\t\tUse,\n\t\tAwaited<R>,\n\t\tResolveMetaInput<Meta>,\n\t\tResolveErrorInput<ErrorSchema, Meta>\n\t> => {\n\t\treturn createEndpoint(\n\t\t\tpath,\n\t\t\t{\n\t\t\t\t...options,\n\t\t\t\tuse: [...(options?.use || []), ...(opts?.use || [])],\n\t\t\t} as any,\n\t\t\thandler as any,\n\t\t) as any;\n\t};\n};\n"],"mappings":";;;;;;AAiXA,SAAgB,eACf,eACA,kBACA,gBACM;CACN,MAAM,OACL,OAAO,kBAAkB,WAAW,gBAAgB;CACrD,MAAM,UACL,OAAO,qBAAqB,WAAW,mBAAmB;CAC3D,MAAM,UACL,OAAO,qBAAqB,aAAa,mBAAmB;AAE7D,MAAK,QAAQ,WAAW,SAAS,QAAQ,WAAW,WAAW,QAAQ,KACtE,OAAM,IAAIA,8BAAgB,+CAA+C;AAG1E,KAAI,QAAQ,SAAS,KAAK,KAAK,CAC9B,OAAM,IAAIA,8BAAgB,0CAA0C;CAGrE,MAAM,iBAAyC;EAC9C,QAAQ,QAAQ;EAChB,MAAM,QAAQ;EACd,OAAO,QAAQ;EACf,OAAO,QAAQ;EACf,gBAAgB,QAAQ;EACxB,gBAAgB,QAAQ;EACxB,cAAc,QAAQ;EACtB,aAAa,QAAQ;EACrB,UAAU,QAAQ;EAClB,KAAK,QAAQ;EACb,YAAY,QAAQ;EACpB,mBAAmB,QAAQ;EAC3B;CAED,MAAM,kBAAkB,OAAO,GAAG,aAAkC;EACnE,MAAM,UAAW,SAAS,MAAM,EAAE;EAClC,MAAM,EAAE,MAAM,iBAAiB,OAAO,oBAAoB,MAAMC,uBAC/DC,sCAAsB,SAAS;GAC9B,SAAS;GACT;GACA,CAAC,CACF;AAED,MAAI,iBAAiB;AACpB,OAAI,EAAE,2BAA2BC,+BAAkB,OAAM;AAEzD,OAAI,QAAQ,kBACX,OAAM,QAAQ,kBAAkB;IAC/B,SAAS,gBAAgB;IACzB,QAAQ,gBAAgB;IACxB,CAAC;AAGH,SAAM,IAAIC,uBAAS,KAAK;IACvB,SAAS,gBAAgB;IACzB,MAAM;IACN,CAAC;;EAGH,MAAM,WAAW,MAAM,QAAQ,gBAAuB,CAAC,MACtD,OAAO,MAAW;AACjB,OAAIC,yBAAW,EAAE,EAAE;IAClB,MAAM,aAAa,QAAQ;AAC3B,QAAI,WACH,OAAM,WAAW,EAAE;AAEpB,QAAI,QAAQ,WACX,QAAO;;AAGT,SAAM;IAEP;EAED,MAAM,kBAAkB,gBAAgB;EACxC,MAAM,SAAS,gBAAgB;AAE/B,SAAO,QAAQ,aACZC,+BAAW,UAAU;GACrB,SAAS;GACT;GACA,CAAC,GACD,QAAQ,gBACP,QAAQ,eACP;GACA,SAAS;GACT;GACA;GACA,GACA;GACA,SAAS;GACT;GACA,GACD,QAAQ,eACP;GAAE;GAAU;GAAQ,GACpB;;AAGN,iBAAgB,UAAU;AAC1B,iBAAgB,OAAO;AACvB,QAAO;;AAGR,eAAe,UAA4C,SAAa;AACvE,SAYC,MACA,SAgBA,YAsBI;AACJ,SAAO,eACN,MACA;GACC,GAAG;GACH,KAAK,CAAC,GAAI,SAAS,OAAO,EAAE,EAAG,GAAI,MAAM,OAAO,EAAE,CAAE;GACpD,EACD,QACA"}
1
+ {"version":3,"file":"endpoint.cjs","names":["BetterCallError","tryCatch","createInternalContext","ValidationError","APIError","isAPIError","toResponse"],"sources":["../src/endpoint.ts"],"sourcesContent":["import { createInternalContext, type EndpointContext } from \"./context\";\nimport type { CookieOptions, CookiePrefixOptions } from \"./cookies\";\nimport {\n\tAPIError,\n\tBetterCallError,\n\ttype Status,\n\ttype statusCodes,\n\tValidationError,\n} from \"./error\";\nimport type { HasRequiredKeys, Prettify } from \"./helper\";\nimport type { Middleware } from \"./middleware\";\nimport type { OpenAPIParameter, OpenAPISchemaType } from \"./openapi\";\nimport type { StandardSchemaV1 } from \"./standard-schema\";\nimport { toResponse } from \"./to-response\";\nimport type {\n\tBodyOption,\n\tHasRequiredInputKeys,\n\tHTTPMethod,\n\tInferUse,\n\tInputContext,\n\tResolveBodyInput,\n\tResolveErrorInput,\n\tResolveMetaInput,\n\tResolveQueryInput,\n} from \"./types\";\nimport { isAPIError, tryCatch } from \"./utils\";\n\nexport type { EndpointContext } from \"./context\";\n\nexport interface EndpointMetadata {\n\t/**\n\t * Open API definition\n\t */\n\topenapi?: {\n\t\tsummary?: string;\n\t\tdescription?: string;\n\t\ttags?: string[];\n\t\toperationId?: string;\n\t\tparameters?: OpenAPIParameter[];\n\t\trequestBody?: {\n\t\t\tcontent: {\n\t\t\t\t\"application/json\": {\n\t\t\t\t\tschema: {\n\t\t\t\t\t\ttype?: OpenAPISchemaType;\n\t\t\t\t\t\tproperties?: Record<string, any>;\n\t\t\t\t\t\trequired?: string[];\n\t\t\t\t\t\t$ref?: string;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t};\n\t\tresponses?: {\n\t\t\t[status: string]: {\n\t\t\t\tdescription: string;\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\t\"text/plain\"?: {\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\t\"text/html\"?: {\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};\n\t};\n\t/**\n\t * Infer body and query type from ts interface\n\t *\n\t * useful for generic and dynamic types\n\t *\n\t * @example\n\t * ```ts\n\t * const endpoint = createEndpoint(\"/path\", {\n\t * \t\tmethod: \"POST\",\n\t * \t\tbody: z.record(z.string()),\n\t * \t\t$Infer: {\n\t * \t\t\tbody: {} as {\n\t * \t\t\t\ttype: InferTypeFromOptions<Option> // custom type inference\n\t * \t\t\t}\n\t * \t\t}\n\t * \t}, async(ctx)=>{\n\t * \t\tconst body = ctx.body\n\t * \t})\n\t * ```\n\t */\n\t$Infer?: {\n\t\t/**\n\t\t * Body\n\t\t */\n\t\tbody?: any;\n\t\t/**\n\t\t * Query\n\t\t */\n\t\tquery?: Record<string, any>;\n\t\t/**\n\t\t * Error\n\t\t */\n\t\terror?: any;\n\t};\n\t/**\n\t * If enabled, endpoint won't be exposed over a router\n\t * @deprecated Use path-less endpoints instead\n\t */\n\tSERVER_ONLY?: boolean;\n\t/**\n\t * If enabled, endpoint won't be exposed as an action to the client\n\t * @deprecated Use path-less endpoints instead\n\t */\n\tisAction?: boolean;\n\t/**\n\t * Defines the places where the endpoint will be available\n\t *\n\t * Possible options:\n\t * - `rpc` - the endpoint is exposed to the router, can be invoked directly and is available to the client\n\t * - `server` - the endpoint is exposed to the router, can be invoked directly, but is not available to the client\n\t * - `http` - the endpoint is only exposed to the router\n\t * @default \"rpc\"\n\t */\n\tscope?: \"rpc\" | \"server\" | \"http\";\n\t/**\n\t * List of allowed media types (MIME types) for the endpoint\n\t *\n\t * if provided, only the media types in the list will be allowed to be passed in the body\n\t *\n\t * @example\n\t * ```ts\n\t * const endpoint = createEndpoint(\"/path\", {\n\t * \t\tmethod: \"POST\",\n\t * \t\tallowedMediaTypes: [\"application/json\", \"application/x-www-form-urlencoded\"],\n\t * \t}, async(ctx)=>{\n\t * \t\tconst body = ctx.body\n\t * \t})\n\t * ```\n\t */\n\tallowedMediaTypes?: string[];\n\t/**\n\t * Extra metadata\n\t */\n\t[key: string]: any;\n}\n\nexport interface EndpointRuntimeOptions {\n\tmethod: string | string[];\n\tbody?: StandardSchemaV1;\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?: EndpointMetadata;\n\t/**\n\t * List of middlewares to use\n\t */\n\tuse?: Middleware[];\n\t/**\n\t * A callback to run before any API error is thrown or returned\n\t *\n\t * @param e - The API error\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?: (info: {\n\t\tmessage: string;\n\t\tissues: readonly StandardSchemaV1.Issue[];\n\t}) => void | Promise<void>;\n}\n\nexport type Endpoint<\n\tPath extends string = string,\n\tMethod = any,\n\tBody = any,\n\tQuery = any,\n\tUse extends Middleware[] = any,\n\tR = any,\n\tMeta extends EndpointMetadata | undefined = EndpointMetadata | undefined,\n\tError = any,\n> = {\n\t(\n\t\tcontext: InputContext<Path, Method, Body, Query, false, false> & {\n\t\t\tasResponse: true;\n\t\t},\n\t): Promise<Response>;\n\t(\n\t\tcontext: InputContext<Path, Method, Body, Query, false, false> & {\n\t\t\treturnHeaders: true;\n\t\t\treturnStatus: true;\n\t\t},\n\t): Promise<{\n\t\theaders: Headers;\n\t\tstatus: number;\n\t\tresponse: Awaited<R>;\n\t}>;\n\t(\n\t\tcontext: InputContext<Path, Method, Body, Query, false, false> & {\n\t\t\treturnHeaders: true;\n\t\t},\n\t): Promise<{\n\t\theaders: Headers;\n\t\tresponse: Awaited<R>;\n\t}>;\n\t(\n\t\tcontext: InputContext<Path, Method, Body, Query, false, false> & {\n\t\t\treturnStatus: true;\n\t\t},\n\t): Promise<{\n\t\tstatus: number;\n\t\tresponse: Awaited<R>;\n\t}>;\n\t(\n\t\tcontext?: InputContext<Path, Method, Body, Query, false, false>,\n\t): Promise<Awaited<R>>;\n\toptions: Omit<EndpointRuntimeOptions, \"method\" | \"metadata\"> & {\n\t\tmethod: Method;\n\t\tmetadata?: Meta;\n\t};\n\tpath: Path;\n};\n\n// Path + options + handler overload\nexport function createEndpoint<\n\tPath extends string,\n\tMethod extends HTTPMethod | HTTPMethod[] | \"*\",\n\tBodySchema extends object | undefined = undefined,\n\tQuerySchema extends object | undefined = undefined,\n\tUse extends Middleware[] = [],\n\tReqHeaders extends boolean = false,\n\tReqRequest extends boolean = false,\n\tR = unknown,\n\tMeta extends EndpointMetadata | undefined = undefined,\n\tErrorSchema extends StandardSchemaV1 | undefined = undefined,\n>(\n\tpath: Path,\n\toptions: { method: Method } & BodyOption<Method, BodySchema> & {\n\t\t\tquery?: QuerySchema;\n\t\t\tuse?: [...Use];\n\t\t\trequireHeaders?: ReqHeaders;\n\t\t\trequireRequest?: ReqRequest;\n\t\t\terror?: ErrorSchema;\n\t\t\tcloneRequest?: boolean;\n\t\t\tdisableBody?: boolean;\n\t\t\tmetadata?: Meta;\n\t\t\tonAPIError?: (e: APIError) => void | Promise<void>;\n\t\t\tonValidationError?: (info: {\n\t\t\t\tmessage: string;\n\t\t\t\tissues: readonly StandardSchemaV1.Issue[];\n\t\t\t}) => void | Promise<void>;\n\t\t\t[key: string]: any;\n\t\t},\n\thandler: (\n\t\tctx: EndpointContext<\n\t\t\tPath,\n\t\t\tMethod,\n\t\t\tBodySchema,\n\t\t\tQuerySchema,\n\t\t\tUse,\n\t\t\tReqHeaders,\n\t\t\tReqRequest,\n\t\t\tInferUse<Use>,\n\t\t\tMeta\n\t\t>,\n\t) => Promise<R>,\n): Endpoint<\n\tPath,\n\tMethod,\n\tResolveBodyInput<BodySchema, Meta>,\n\tResolveQueryInput<QuerySchema, Meta>,\n\tUse,\n\tR,\n\tResolveMetaInput<Meta>,\n\tResolveErrorInput<ErrorSchema, Meta>\n>;\n\n// Options-only (virtual/path-less) overload\nexport function createEndpoint<\n\tMethod extends HTTPMethod | HTTPMethod[] | \"*\",\n\tBodySchema extends object | undefined = undefined,\n\tQuerySchema extends object | undefined = undefined,\n\tUse extends Middleware[] = [],\n\tReqHeaders extends boolean = false,\n\tReqRequest extends boolean = false,\n\tR = unknown,\n\tMeta extends EndpointMetadata | undefined = undefined,\n\tErrorSchema extends StandardSchemaV1 | undefined = undefined,\n>(\n\toptions: { method: Method } & BodyOption<Method, BodySchema> & {\n\t\t\tpath?: never;\n\t\t\tquery?: QuerySchema;\n\t\t\tuse?: [...Use];\n\t\t\trequireHeaders?: ReqHeaders;\n\t\t\trequireRequest?: ReqRequest;\n\t\t\terror?: ErrorSchema;\n\t\t\tcloneRequest?: boolean;\n\t\t\tdisableBody?: boolean;\n\t\t\tmetadata?: Meta;\n\t\t\tonAPIError?: (e: APIError) => void | Promise<void>;\n\t\t\tonValidationError?: (info: {\n\t\t\t\tmessage: string;\n\t\t\t\tissues: readonly StandardSchemaV1.Issue[];\n\t\t\t}) => void | Promise<void>;\n\t\t\t[key: string]: any;\n\t\t},\n\thandler: (\n\t\tctx: EndpointContext<\n\t\t\tnever,\n\t\t\tMethod,\n\t\t\tBodySchema,\n\t\t\tQuerySchema,\n\t\t\tUse,\n\t\t\tReqHeaders,\n\t\t\tReqRequest,\n\t\t\tInferUse<Use>,\n\t\t\tMeta\n\t\t>,\n\t) => Promise<R>,\n): Endpoint<\n\tnever,\n\tMethod,\n\tResolveBodyInput<BodySchema, Meta>,\n\tResolveQueryInput<QuerySchema, Meta>,\n\tUse,\n\tR,\n\tResolveMetaInput<Meta>,\n\tResolveErrorInput<ErrorSchema, Meta>\n>;\n\n// Implementation\nexport function createEndpoint(\n\tpathOrOptions: any,\n\thandlerOrOptions: any,\n\thandlerOrNever?: any,\n): any {\n\tconst path: string | undefined =\n\t\ttypeof pathOrOptions === \"string\" ? pathOrOptions : undefined;\n\tconst options: any =\n\t\ttypeof handlerOrOptions === \"object\" ? handlerOrOptions : pathOrOptions;\n\tconst handler: any =\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\n\tconst runtimeOptions: EndpointRuntimeOptions = {\n\t\tmethod: options.method,\n\t\tbody: options.body,\n\t\tquery: options.query,\n\t\terror: options.error,\n\t\trequireHeaders: options.requireHeaders,\n\t\trequireRequest: options.requireRequest,\n\t\tcloneRequest: options.cloneRequest,\n\t\tdisableBody: options.disableBody,\n\t\tmetadata: options.metadata,\n\t\tuse: options.use,\n\t\tonAPIError: options.onAPIError,\n\t\tonValidationError: options.onValidationError,\n\t};\n\n\tconst internalHandler = async (...inputCtx: any[]): Promise<any> => {\n\t\tconst context = (inputCtx[0] || {}) as Record<string, any>;\n\t\tconst { data: internalContext, error: validationError } = await tryCatch(\n\t\t\tcreateInternalContext(context, {\n\t\t\t\toptions: runtimeOptions,\n\t\t\t\tpath,\n\t\t\t}),\n\t\t);\n\n\t\tif (validationError) {\n\t\t\tif (!(validationError instanceof ValidationError)) throw validationError;\n\n\t\t\tif (options.onValidationError) {\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\n\t\tconst response = await handler(internalContext as any).catch(\n\t\t\tasync (e: any) => {\n\t\t\t\tif (isAPIError(e)) {\n\t\t\t\t\tconst onAPIError = options.onAPIError;\n\t\t\t\t\tif (onAPIError) {\n\t\t\t\t\t\tawait onAPIError(e);\n\t\t\t\t\t}\n\t\t\t\t\tif (context.asResponse) {\n\t\t\t\t\t\treturn e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthrow e;\n\t\t\t},\n\t\t);\n\n\t\tconst responseHeaders = internalContext.responseHeaders;\n\t\tconst status = internalContext.responseStatus;\n\n\t\treturn context.asResponse\n\t\t\t? toResponse(response, {\n\t\t\t\t\theaders: responseHeaders,\n\t\t\t\t\tstatus,\n\t\t\t\t})\n\t\t\t: context.returnHeaders\n\t\t\t\t? context.returnStatus\n\t\t\t\t\t? {\n\t\t\t\t\t\t\theaders: responseHeaders,\n\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t\tstatus,\n\t\t\t\t\t\t}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\theaders: responseHeaders,\n\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t}\n\t\t\t\t: context.returnStatus\n\t\t\t\t\t? { response, status }\n\t\t\t\t\t: response;\n\t};\n\n\tinternalHandler.options = runtimeOptions;\n\tinternalHandler.path = path;\n\treturn internalHandler as any;\n}\n\ncreateEndpoint.create = <E extends { use?: Middleware[] }>(opts?: E) => {\n\treturn <\n\t\tPath extends string,\n\t\tMethod extends HTTPMethod | HTTPMethod[] | \"*\",\n\t\tBodySchema extends object | undefined = undefined,\n\t\tQuerySchema extends object | undefined = undefined,\n\t\tUse extends Middleware[] = [],\n\t\tReqHeaders extends boolean = false,\n\t\tReqRequest extends boolean = false,\n\t\tR = unknown,\n\t\tMeta extends EndpointMetadata | undefined = undefined,\n\t\tErrorSchema extends StandardSchemaV1 | undefined = undefined,\n\t>(\n\t\tpath: Path,\n\t\toptions: { method: Method } & BodyOption<Method, BodySchema> & {\n\t\t\t\tquery?: QuerySchema;\n\t\t\t\tuse?: [...Use];\n\t\t\t\trequireHeaders?: ReqHeaders;\n\t\t\t\trequireRequest?: ReqRequest;\n\t\t\t\terror?: ErrorSchema;\n\t\t\t\tcloneRequest?: boolean;\n\t\t\t\tdisableBody?: boolean;\n\t\t\t\tmetadata?: Meta;\n\t\t\t\tonAPIError?: (e: APIError) => void | Promise<void>;\n\t\t\t\tonValidationError?: (info: {\n\t\t\t\t\tmessage: string;\n\t\t\t\t\tissues: readonly StandardSchemaV1.Issue[];\n\t\t\t\t}) => void | Promise<void>;\n\t\t\t\t[key: string]: any;\n\t\t\t},\n\t\thandler: (\n\t\t\tctx: EndpointContext<\n\t\t\t\tPath,\n\t\t\t\tMethod,\n\t\t\t\tBodySchema,\n\t\t\t\tQuerySchema,\n\t\t\t\tUse,\n\t\t\t\tReqHeaders,\n\t\t\t\tReqRequest,\n\t\t\t\tInferUse<E[\"use\"]>,\n\t\t\t\tMeta\n\t\t\t>,\n\t\t) => Promise<R>,\n\t): Endpoint<\n\t\tPath,\n\t\tMethod,\n\t\tResolveBodyInput<BodySchema, Meta>,\n\t\tResolveQueryInput<QuerySchema, Meta>,\n\t\tUse,\n\t\tAwaited<R>,\n\t\tResolveMetaInput<Meta>,\n\t\tResolveErrorInput<ErrorSchema, Meta>\n\t> => {\n\t\treturn createEndpoint(\n\t\t\tpath,\n\t\t\t{\n\t\t\t\t...options,\n\t\t\t\tuse: [...(options?.use || []), ...(opts?.use || [])],\n\t\t\t} as any,\n\t\t\thandler as any,\n\t\t) as any;\n\t};\n};\n"],"mappings":";;;;;;AAiXA,SAAgB,eACf,eACA,kBACA,gBACM;CACN,MAAM,OACL,OAAO,kBAAkB,WAAW,gBAAgB;CACrD,MAAM,UACL,OAAO,qBAAqB,WAAW,mBAAmB;CAC3D,MAAM,UACL,OAAO,qBAAqB,aAAa,mBAAmB;AAE7D,MAAK,QAAQ,WAAW,SAAS,QAAQ,WAAW,WAAW,QAAQ,KACtE,OAAM,IAAIA,8BAAgB,+CAA+C;AAG1E,KAAI,QAAQ,SAAS,KAAK,KAAK,CAC9B,OAAM,IAAIA,8BAAgB,0CAA0C;CAGrE,MAAM,iBAAyC;EAC9C,QAAQ,QAAQ;EAChB,MAAM,QAAQ;EACd,OAAO,QAAQ;EACf,OAAO,QAAQ;EACf,gBAAgB,QAAQ;EACxB,gBAAgB,QAAQ;EACxB,cAAc,QAAQ;EACtB,aAAa,QAAQ;EACrB,UAAU,QAAQ;EAClB,KAAK,QAAQ;EACb,YAAY,QAAQ;EACpB,mBAAmB,QAAQ;EAC3B;CAED,MAAM,kBAAkB,OAAO,GAAG,aAAkC;EACnE,MAAM,UAAW,SAAS,MAAM,EAAE;EAClC,MAAM,EAAE,MAAM,iBAAiB,OAAO,oBAAoB,MAAMC,uBAC/DC,sCAAsB,SAAS;GAC9B,SAAS;GACT;GACA,CAAC,CACF;AAED,MAAI,iBAAiB;AACpB,OAAI,EAAE,2BAA2BC,+BAAkB,OAAM;AAEzD,OAAI,QAAQ,kBACX,OAAM,QAAQ,kBAAkB;IAC/B,SAAS,gBAAgB;IACzB,QAAQ,gBAAgB;IACxB,CAAC;AAGH,SAAM,IAAIC,uBAAS,KAAK;IACvB,SAAS,gBAAgB;IACzB,MAAM;IACN,CAAC;;EAGH,MAAM,WAAW,MAAM,QAAQ,gBAAuB,CAAC,MACtD,OAAO,MAAW;AACjB,OAAIC,yBAAW,EAAE,EAAE;IAClB,MAAM,aAAa,QAAQ;AAC3B,QAAI,WACH,OAAM,WAAW,EAAE;AAEpB,QAAI,QAAQ,WACX,QAAO;;AAGT,SAAM;IAEP;EAED,MAAM,kBAAkB,gBAAgB;EACxC,MAAM,SAAS,gBAAgB;AAE/B,SAAO,QAAQ,aACZC,+BAAW,UAAU;GACrB,SAAS;GACT;GACA,CAAC,GACD,QAAQ,gBACP,QAAQ,eACP;GACA,SAAS;GACT;GACA;GACA,GACA;GACA,SAAS;GACT;GACA,GACD,QAAQ,eACP;GAAE;GAAU;GAAQ,GACpB;;AAGN,iBAAgB,UAAU;AAC1B,iBAAgB,OAAO;AACvB,QAAO;;AAGR,eAAe,UAA4C,SAAa;AACvE,SAYC,MACA,SAgBA,YAsBI;AACJ,SAAO,eACN,MACA;GACC,GAAG;GACH,KAAK,CAAC,GAAI,SAAS,OAAO,EAAE,EAAG,GAAI,MAAM,OAAO,EAAE,CAAE;GACpD,EACD,QACA"}
@@ -210,7 +210,7 @@ type Endpoint<Path extends string = string, Method = any, Body = any, Query = an
210
210
  response: Awaited<R>;
211
211
  }>;
212
212
  (context?: InputContext<Path, Method, Body, Query, false, false>): Promise<Awaited<R>>;
213
- options: EndpointRuntimeOptions & {
213
+ options: Omit<EndpointRuntimeOptions, "method" | "metadata"> & {
214
214
  method: Method;
215
215
  metadata?: Meta;
216
216
  };
@@ -210,7 +210,7 @@ type Endpoint<Path extends string = string, Method = any, Body = any, Query = an
210
210
  response: Awaited<R>;
211
211
  }>;
212
212
  (context?: InputContext<Path, Method, Body, Query, false, false>): Promise<Awaited<R>>;
213
- options: EndpointRuntimeOptions & {
213
+ options: Omit<EndpointRuntimeOptions, "method" | "metadata"> & {
214
214
  method: Method;
215
215
  metadata?: Meta;
216
216
  };
@@ -1 +1 @@
1
- {"version":3,"file":"endpoint.mjs","names":[],"sources":["../src/endpoint.ts"],"sourcesContent":["import { createInternalContext, type EndpointContext } from \"./context\";\nimport type { CookieOptions, CookiePrefixOptions } from \"./cookies\";\nimport {\n\tAPIError,\n\tBetterCallError,\n\ttype Status,\n\ttype statusCodes,\n\tValidationError,\n} from \"./error\";\nimport type { HasRequiredKeys, Prettify } from \"./helper\";\nimport type { Middleware } from \"./middleware\";\nimport type { OpenAPIParameter, OpenAPISchemaType } from \"./openapi\";\nimport type { StandardSchemaV1 } from \"./standard-schema\";\nimport { toResponse } from \"./to-response\";\nimport type {\n\tBodyOption,\n\tHasRequiredInputKeys,\n\tHTTPMethod,\n\tInferUse,\n\tInputContext,\n\tResolveBodyInput,\n\tResolveErrorInput,\n\tResolveMetaInput,\n\tResolveQueryInput,\n} from \"./types\";\nimport { isAPIError, tryCatch } from \"./utils\";\n\nexport type { EndpointContext } from \"./context\";\n\nexport interface EndpointMetadata {\n\t/**\n\t * Open API definition\n\t */\n\topenapi?: {\n\t\tsummary?: string;\n\t\tdescription?: string;\n\t\ttags?: string[];\n\t\toperationId?: string;\n\t\tparameters?: OpenAPIParameter[];\n\t\trequestBody?: {\n\t\t\tcontent: {\n\t\t\t\t\"application/json\": {\n\t\t\t\t\tschema: {\n\t\t\t\t\t\ttype?: OpenAPISchemaType;\n\t\t\t\t\t\tproperties?: Record<string, any>;\n\t\t\t\t\t\trequired?: string[];\n\t\t\t\t\t\t$ref?: string;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t};\n\t\tresponses?: {\n\t\t\t[status: string]: {\n\t\t\t\tdescription: string;\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\t\"text/plain\"?: {\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\t\"text/html\"?: {\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};\n\t};\n\t/**\n\t * Infer body and query type from ts interface\n\t *\n\t * useful for generic and dynamic types\n\t *\n\t * @example\n\t * ```ts\n\t * const endpoint = createEndpoint(\"/path\", {\n\t * \t\tmethod: \"POST\",\n\t * \t\tbody: z.record(z.string()),\n\t * \t\t$Infer: {\n\t * \t\t\tbody: {} as {\n\t * \t\t\t\ttype: InferTypeFromOptions<Option> // custom type inference\n\t * \t\t\t}\n\t * \t\t}\n\t * \t}, async(ctx)=>{\n\t * \t\tconst body = ctx.body\n\t * \t})\n\t * ```\n\t */\n\t$Infer?: {\n\t\t/**\n\t\t * Body\n\t\t */\n\t\tbody?: any;\n\t\t/**\n\t\t * Query\n\t\t */\n\t\tquery?: Record<string, any>;\n\t\t/**\n\t\t * Error\n\t\t */\n\t\terror?: any;\n\t};\n\t/**\n\t * If enabled, endpoint won't be exposed over a router\n\t * @deprecated Use path-less endpoints instead\n\t */\n\tSERVER_ONLY?: boolean;\n\t/**\n\t * If enabled, endpoint won't be exposed as an action to the client\n\t * @deprecated Use path-less endpoints instead\n\t */\n\tisAction?: boolean;\n\t/**\n\t * Defines the places where the endpoint will be available\n\t *\n\t * Possible options:\n\t * - `rpc` - the endpoint is exposed to the router, can be invoked directly and is available to the client\n\t * - `server` - the endpoint is exposed to the router, can be invoked directly, but is not available to the client\n\t * - `http` - the endpoint is only exposed to the router\n\t * @default \"rpc\"\n\t */\n\tscope?: \"rpc\" | \"server\" | \"http\";\n\t/**\n\t * List of allowed media types (MIME types) for the endpoint\n\t *\n\t * if provided, only the media types in the list will be allowed to be passed in the body\n\t *\n\t * @example\n\t * ```ts\n\t * const endpoint = createEndpoint(\"/path\", {\n\t * \t\tmethod: \"POST\",\n\t * \t\tallowedMediaTypes: [\"application/json\", \"application/x-www-form-urlencoded\"],\n\t * \t}, async(ctx)=>{\n\t * \t\tconst body = ctx.body\n\t * \t})\n\t * ```\n\t */\n\tallowedMediaTypes?: string[];\n\t/**\n\t * Extra metadata\n\t */\n\t[key: string]: any;\n}\n\nexport interface EndpointRuntimeOptions {\n\tmethod: string | string[];\n\tbody?: StandardSchemaV1;\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?: EndpointMetadata;\n\t/**\n\t * List of middlewares to use\n\t */\n\tuse?: Middleware[];\n\t/**\n\t * A callback to run before any API error is thrown or returned\n\t *\n\t * @param e - The API error\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?: (info: {\n\t\tmessage: string;\n\t\tissues: readonly StandardSchemaV1.Issue[];\n\t}) => void | Promise<void>;\n}\n\nexport type Endpoint<\n\tPath extends string = string,\n\tMethod = any,\n\tBody = any,\n\tQuery = any,\n\tUse extends Middleware[] = any,\n\tR = any,\n\tMeta extends EndpointMetadata | undefined = EndpointMetadata | undefined,\n\tError = any,\n> = {\n\t(\n\t\tcontext: InputContext<Path, Method, Body, Query, false, false> & {\n\t\t\tasResponse: true;\n\t\t},\n\t): Promise<Response>;\n\t(\n\t\tcontext: InputContext<Path, Method, Body, Query, false, false> & {\n\t\t\treturnHeaders: true;\n\t\t\treturnStatus: true;\n\t\t},\n\t): Promise<{\n\t\theaders: Headers;\n\t\tstatus: number;\n\t\tresponse: Awaited<R>;\n\t}>;\n\t(\n\t\tcontext: InputContext<Path, Method, Body, Query, false, false> & {\n\t\t\treturnHeaders: true;\n\t\t},\n\t): Promise<{\n\t\theaders: Headers;\n\t\tresponse: Awaited<R>;\n\t}>;\n\t(\n\t\tcontext: InputContext<Path, Method, Body, Query, false, false> & {\n\t\t\treturnStatus: true;\n\t\t},\n\t): Promise<{\n\t\tstatus: number;\n\t\tresponse: Awaited<R>;\n\t}>;\n\t(\n\t\tcontext?: InputContext<Path, Method, Body, Query, false, false>,\n\t): Promise<Awaited<R>>;\n\toptions: EndpointRuntimeOptions & {\n\t\tmethod: Method;\n\t\tmetadata?: Meta;\n\t};\n\tpath: Path;\n};\n\n// Path + options + handler overload\nexport function createEndpoint<\n\tPath extends string,\n\tMethod extends HTTPMethod | HTTPMethod[] | \"*\",\n\tBodySchema extends object | undefined = undefined,\n\tQuerySchema extends object | undefined = undefined,\n\tUse extends Middleware[] = [],\n\tReqHeaders extends boolean = false,\n\tReqRequest extends boolean = false,\n\tR = unknown,\n\tMeta extends EndpointMetadata | undefined = undefined,\n\tErrorSchema extends StandardSchemaV1 | undefined = undefined,\n>(\n\tpath: Path,\n\toptions: { method: Method } & BodyOption<Method, BodySchema> & {\n\t\t\tquery?: QuerySchema;\n\t\t\tuse?: [...Use];\n\t\t\trequireHeaders?: ReqHeaders;\n\t\t\trequireRequest?: ReqRequest;\n\t\t\terror?: ErrorSchema;\n\t\t\tcloneRequest?: boolean;\n\t\t\tdisableBody?: boolean;\n\t\t\tmetadata?: Meta;\n\t\t\tonAPIError?: (e: APIError) => void | Promise<void>;\n\t\t\tonValidationError?: (info: {\n\t\t\t\tmessage: string;\n\t\t\t\tissues: readonly StandardSchemaV1.Issue[];\n\t\t\t}) => void | Promise<void>;\n\t\t\t[key: string]: any;\n\t\t},\n\thandler: (\n\t\tctx: EndpointContext<\n\t\t\tPath,\n\t\t\tMethod,\n\t\t\tBodySchema,\n\t\t\tQuerySchema,\n\t\t\tUse,\n\t\t\tReqHeaders,\n\t\t\tReqRequest,\n\t\t\tInferUse<Use>,\n\t\t\tMeta\n\t\t>,\n\t) => Promise<R>,\n): Endpoint<\n\tPath,\n\tMethod,\n\tResolveBodyInput<BodySchema, Meta>,\n\tResolveQueryInput<QuerySchema, Meta>,\n\tUse,\n\tR,\n\tResolveMetaInput<Meta>,\n\tResolveErrorInput<ErrorSchema, Meta>\n>;\n\n// Options-only (virtual/path-less) overload\nexport function createEndpoint<\n\tMethod extends HTTPMethod | HTTPMethod[] | \"*\",\n\tBodySchema extends object | undefined = undefined,\n\tQuerySchema extends object | undefined = undefined,\n\tUse extends Middleware[] = [],\n\tReqHeaders extends boolean = false,\n\tReqRequest extends boolean = false,\n\tR = unknown,\n\tMeta extends EndpointMetadata | undefined = undefined,\n\tErrorSchema extends StandardSchemaV1 | undefined = undefined,\n>(\n\toptions: { method: Method } & BodyOption<Method, BodySchema> & {\n\t\t\tpath?: never;\n\t\t\tquery?: QuerySchema;\n\t\t\tuse?: [...Use];\n\t\t\trequireHeaders?: ReqHeaders;\n\t\t\trequireRequest?: ReqRequest;\n\t\t\terror?: ErrorSchema;\n\t\t\tcloneRequest?: boolean;\n\t\t\tdisableBody?: boolean;\n\t\t\tmetadata?: Meta;\n\t\t\tonAPIError?: (e: APIError) => void | Promise<void>;\n\t\t\tonValidationError?: (info: {\n\t\t\t\tmessage: string;\n\t\t\t\tissues: readonly StandardSchemaV1.Issue[];\n\t\t\t}) => void | Promise<void>;\n\t\t\t[key: string]: any;\n\t\t},\n\thandler: (\n\t\tctx: EndpointContext<\n\t\t\tnever,\n\t\t\tMethod,\n\t\t\tBodySchema,\n\t\t\tQuerySchema,\n\t\t\tUse,\n\t\t\tReqHeaders,\n\t\t\tReqRequest,\n\t\t\tInferUse<Use>,\n\t\t\tMeta\n\t\t>,\n\t) => Promise<R>,\n): Endpoint<\n\tnever,\n\tMethod,\n\tResolveBodyInput<BodySchema, Meta>,\n\tResolveQueryInput<QuerySchema, Meta>,\n\tUse,\n\tR,\n\tResolveMetaInput<Meta>,\n\tResolveErrorInput<ErrorSchema, Meta>\n>;\n\n// Implementation\nexport function createEndpoint(\n\tpathOrOptions: any,\n\thandlerOrOptions: any,\n\thandlerOrNever?: any,\n): any {\n\tconst path: string | undefined =\n\t\ttypeof pathOrOptions === \"string\" ? pathOrOptions : undefined;\n\tconst options: any =\n\t\ttypeof handlerOrOptions === \"object\" ? handlerOrOptions : pathOrOptions;\n\tconst handler: any =\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\n\tconst runtimeOptions: EndpointRuntimeOptions = {\n\t\tmethod: options.method,\n\t\tbody: options.body,\n\t\tquery: options.query,\n\t\terror: options.error,\n\t\trequireHeaders: options.requireHeaders,\n\t\trequireRequest: options.requireRequest,\n\t\tcloneRequest: options.cloneRequest,\n\t\tdisableBody: options.disableBody,\n\t\tmetadata: options.metadata,\n\t\tuse: options.use,\n\t\tonAPIError: options.onAPIError,\n\t\tonValidationError: options.onValidationError,\n\t};\n\n\tconst internalHandler = async (...inputCtx: any[]): Promise<any> => {\n\t\tconst context = (inputCtx[0] || {}) as Record<string, any>;\n\t\tconst { data: internalContext, error: validationError } = await tryCatch(\n\t\t\tcreateInternalContext(context, {\n\t\t\t\toptions: runtimeOptions,\n\t\t\t\tpath,\n\t\t\t}),\n\t\t);\n\n\t\tif (validationError) {\n\t\t\tif (!(validationError instanceof ValidationError)) throw validationError;\n\n\t\t\tif (options.onValidationError) {\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\n\t\tconst response = await handler(internalContext as any).catch(\n\t\t\tasync (e: any) => {\n\t\t\t\tif (isAPIError(e)) {\n\t\t\t\t\tconst onAPIError = options.onAPIError;\n\t\t\t\t\tif (onAPIError) {\n\t\t\t\t\t\tawait onAPIError(e);\n\t\t\t\t\t}\n\t\t\t\t\tif (context.asResponse) {\n\t\t\t\t\t\treturn e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthrow e;\n\t\t\t},\n\t\t);\n\n\t\tconst responseHeaders = internalContext.responseHeaders;\n\t\tconst status = internalContext.responseStatus;\n\n\t\treturn context.asResponse\n\t\t\t? toResponse(response, {\n\t\t\t\t\theaders: responseHeaders,\n\t\t\t\t\tstatus,\n\t\t\t\t})\n\t\t\t: context.returnHeaders\n\t\t\t\t? context.returnStatus\n\t\t\t\t\t? {\n\t\t\t\t\t\t\theaders: responseHeaders,\n\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t\tstatus,\n\t\t\t\t\t\t}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\theaders: responseHeaders,\n\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t}\n\t\t\t\t: context.returnStatus\n\t\t\t\t\t? { response, status }\n\t\t\t\t\t: response;\n\t};\n\n\tinternalHandler.options = runtimeOptions;\n\tinternalHandler.path = path;\n\treturn internalHandler as any;\n}\n\ncreateEndpoint.create = <E extends { use?: Middleware[] }>(opts?: E) => {\n\treturn <\n\t\tPath extends string,\n\t\tMethod extends HTTPMethod | HTTPMethod[] | \"*\",\n\t\tBodySchema extends object | undefined = undefined,\n\t\tQuerySchema extends object | undefined = undefined,\n\t\tUse extends Middleware[] = [],\n\t\tReqHeaders extends boolean = false,\n\t\tReqRequest extends boolean = false,\n\t\tR = unknown,\n\t\tMeta extends EndpointMetadata | undefined = undefined,\n\t\tErrorSchema extends StandardSchemaV1 | undefined = undefined,\n\t>(\n\t\tpath: Path,\n\t\toptions: { method: Method } & BodyOption<Method, BodySchema> & {\n\t\t\t\tquery?: QuerySchema;\n\t\t\t\tuse?: [...Use];\n\t\t\t\trequireHeaders?: ReqHeaders;\n\t\t\t\trequireRequest?: ReqRequest;\n\t\t\t\terror?: ErrorSchema;\n\t\t\t\tcloneRequest?: boolean;\n\t\t\t\tdisableBody?: boolean;\n\t\t\t\tmetadata?: Meta;\n\t\t\t\tonAPIError?: (e: APIError) => void | Promise<void>;\n\t\t\t\tonValidationError?: (info: {\n\t\t\t\t\tmessage: string;\n\t\t\t\t\tissues: readonly StandardSchemaV1.Issue[];\n\t\t\t\t}) => void | Promise<void>;\n\t\t\t\t[key: string]: any;\n\t\t\t},\n\t\thandler: (\n\t\t\tctx: EndpointContext<\n\t\t\t\tPath,\n\t\t\t\tMethod,\n\t\t\t\tBodySchema,\n\t\t\t\tQuerySchema,\n\t\t\t\tUse,\n\t\t\t\tReqHeaders,\n\t\t\t\tReqRequest,\n\t\t\t\tInferUse<E[\"use\"]>,\n\t\t\t\tMeta\n\t\t\t>,\n\t\t) => Promise<R>,\n\t): Endpoint<\n\t\tPath,\n\t\tMethod,\n\t\tResolveBodyInput<BodySchema, Meta>,\n\t\tResolveQueryInput<QuerySchema, Meta>,\n\t\tUse,\n\t\tAwaited<R>,\n\t\tResolveMetaInput<Meta>,\n\t\tResolveErrorInput<ErrorSchema, Meta>\n\t> => {\n\t\treturn createEndpoint(\n\t\t\tpath,\n\t\t\t{\n\t\t\t\t...options,\n\t\t\t\tuse: [...(options?.use || []), ...(opts?.use || [])],\n\t\t\t} as any,\n\t\t\thandler as any,\n\t\t) as any;\n\t};\n};\n"],"mappings":";;;;;;AAiXA,SAAgB,eACf,eACA,kBACA,gBACM;CACN,MAAM,OACL,OAAO,kBAAkB,WAAW,gBAAgB;CACrD,MAAM,UACL,OAAO,qBAAqB,WAAW,mBAAmB;CAC3D,MAAM,UACL,OAAO,qBAAqB,aAAa,mBAAmB;AAE7D,MAAK,QAAQ,WAAW,SAAS,QAAQ,WAAW,WAAW,QAAQ,KACtE,OAAM,IAAI,gBAAgB,+CAA+C;AAG1E,KAAI,QAAQ,SAAS,KAAK,KAAK,CAC9B,OAAM,IAAI,gBAAgB,0CAA0C;CAGrE,MAAM,iBAAyC;EAC9C,QAAQ,QAAQ;EAChB,MAAM,QAAQ;EACd,OAAO,QAAQ;EACf,OAAO,QAAQ;EACf,gBAAgB,QAAQ;EACxB,gBAAgB,QAAQ;EACxB,cAAc,QAAQ;EACtB,aAAa,QAAQ;EACrB,UAAU,QAAQ;EAClB,KAAK,QAAQ;EACb,YAAY,QAAQ;EACpB,mBAAmB,QAAQ;EAC3B;CAED,MAAM,kBAAkB,OAAO,GAAG,aAAkC;EACnE,MAAM,UAAW,SAAS,MAAM,EAAE;EAClC,MAAM,EAAE,MAAM,iBAAiB,OAAO,oBAAoB,MAAM,SAC/D,sBAAsB,SAAS;GAC9B,SAAS;GACT;GACA,CAAC,CACF;AAED,MAAI,iBAAiB;AACpB,OAAI,EAAE,2BAA2B,iBAAkB,OAAM;AAEzD,OAAI,QAAQ,kBACX,OAAM,QAAQ,kBAAkB;IAC/B,SAAS,gBAAgB;IACzB,QAAQ,gBAAgB;IACxB,CAAC;AAGH,SAAM,IAAI,SAAS,KAAK;IACvB,SAAS,gBAAgB;IACzB,MAAM;IACN,CAAC;;EAGH,MAAM,WAAW,MAAM,QAAQ,gBAAuB,CAAC,MACtD,OAAO,MAAW;AACjB,OAAI,WAAW,EAAE,EAAE;IAClB,MAAM,aAAa,QAAQ;AAC3B,QAAI,WACH,OAAM,WAAW,EAAE;AAEpB,QAAI,QAAQ,WACX,QAAO;;AAGT,SAAM;IAEP;EAED,MAAM,kBAAkB,gBAAgB;EACxC,MAAM,SAAS,gBAAgB;AAE/B,SAAO,QAAQ,aACZ,WAAW,UAAU;GACrB,SAAS;GACT;GACA,CAAC,GACD,QAAQ,gBACP,QAAQ,eACP;GACA,SAAS;GACT;GACA;GACA,GACA;GACA,SAAS;GACT;GACA,GACD,QAAQ,eACP;GAAE;GAAU;GAAQ,GACpB;;AAGN,iBAAgB,UAAU;AAC1B,iBAAgB,OAAO;AACvB,QAAO;;AAGR,eAAe,UAA4C,SAAa;AACvE,SAYC,MACA,SAgBA,YAsBI;AACJ,SAAO,eACN,MACA;GACC,GAAG;GACH,KAAK,CAAC,GAAI,SAAS,OAAO,EAAE,EAAG,GAAI,MAAM,OAAO,EAAE,CAAE;GACpD,EACD,QACA"}
1
+ {"version":3,"file":"endpoint.mjs","names":[],"sources":["../src/endpoint.ts"],"sourcesContent":["import { createInternalContext, type EndpointContext } from \"./context\";\nimport type { CookieOptions, CookiePrefixOptions } from \"./cookies\";\nimport {\n\tAPIError,\n\tBetterCallError,\n\ttype Status,\n\ttype statusCodes,\n\tValidationError,\n} from \"./error\";\nimport type { HasRequiredKeys, Prettify } from \"./helper\";\nimport type { Middleware } from \"./middleware\";\nimport type { OpenAPIParameter, OpenAPISchemaType } from \"./openapi\";\nimport type { StandardSchemaV1 } from \"./standard-schema\";\nimport { toResponse } from \"./to-response\";\nimport type {\n\tBodyOption,\n\tHasRequiredInputKeys,\n\tHTTPMethod,\n\tInferUse,\n\tInputContext,\n\tResolveBodyInput,\n\tResolveErrorInput,\n\tResolveMetaInput,\n\tResolveQueryInput,\n} from \"./types\";\nimport { isAPIError, tryCatch } from \"./utils\";\n\nexport type { EndpointContext } from \"./context\";\n\nexport interface EndpointMetadata {\n\t/**\n\t * Open API definition\n\t */\n\topenapi?: {\n\t\tsummary?: string;\n\t\tdescription?: string;\n\t\ttags?: string[];\n\t\toperationId?: string;\n\t\tparameters?: OpenAPIParameter[];\n\t\trequestBody?: {\n\t\t\tcontent: {\n\t\t\t\t\"application/json\": {\n\t\t\t\t\tschema: {\n\t\t\t\t\t\ttype?: OpenAPISchemaType;\n\t\t\t\t\t\tproperties?: Record<string, any>;\n\t\t\t\t\t\trequired?: string[];\n\t\t\t\t\t\t$ref?: string;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t};\n\t\tresponses?: {\n\t\t\t[status: string]: {\n\t\t\t\tdescription: string;\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\t\"text/plain\"?: {\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\t\"text/html\"?: {\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};\n\t};\n\t/**\n\t * Infer body and query type from ts interface\n\t *\n\t * useful for generic and dynamic types\n\t *\n\t * @example\n\t * ```ts\n\t * const endpoint = createEndpoint(\"/path\", {\n\t * \t\tmethod: \"POST\",\n\t * \t\tbody: z.record(z.string()),\n\t * \t\t$Infer: {\n\t * \t\t\tbody: {} as {\n\t * \t\t\t\ttype: InferTypeFromOptions<Option> // custom type inference\n\t * \t\t\t}\n\t * \t\t}\n\t * \t}, async(ctx)=>{\n\t * \t\tconst body = ctx.body\n\t * \t})\n\t * ```\n\t */\n\t$Infer?: {\n\t\t/**\n\t\t * Body\n\t\t */\n\t\tbody?: any;\n\t\t/**\n\t\t * Query\n\t\t */\n\t\tquery?: Record<string, any>;\n\t\t/**\n\t\t * Error\n\t\t */\n\t\terror?: any;\n\t};\n\t/**\n\t * If enabled, endpoint won't be exposed over a router\n\t * @deprecated Use path-less endpoints instead\n\t */\n\tSERVER_ONLY?: boolean;\n\t/**\n\t * If enabled, endpoint won't be exposed as an action to the client\n\t * @deprecated Use path-less endpoints instead\n\t */\n\tisAction?: boolean;\n\t/**\n\t * Defines the places where the endpoint will be available\n\t *\n\t * Possible options:\n\t * - `rpc` - the endpoint is exposed to the router, can be invoked directly and is available to the client\n\t * - `server` - the endpoint is exposed to the router, can be invoked directly, but is not available to the client\n\t * - `http` - the endpoint is only exposed to the router\n\t * @default \"rpc\"\n\t */\n\tscope?: \"rpc\" | \"server\" | \"http\";\n\t/**\n\t * List of allowed media types (MIME types) for the endpoint\n\t *\n\t * if provided, only the media types in the list will be allowed to be passed in the body\n\t *\n\t * @example\n\t * ```ts\n\t * const endpoint = createEndpoint(\"/path\", {\n\t * \t\tmethod: \"POST\",\n\t * \t\tallowedMediaTypes: [\"application/json\", \"application/x-www-form-urlencoded\"],\n\t * \t}, async(ctx)=>{\n\t * \t\tconst body = ctx.body\n\t * \t})\n\t * ```\n\t */\n\tallowedMediaTypes?: string[];\n\t/**\n\t * Extra metadata\n\t */\n\t[key: string]: any;\n}\n\nexport interface EndpointRuntimeOptions {\n\tmethod: string | string[];\n\tbody?: StandardSchemaV1;\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?: EndpointMetadata;\n\t/**\n\t * List of middlewares to use\n\t */\n\tuse?: Middleware[];\n\t/**\n\t * A callback to run before any API error is thrown or returned\n\t *\n\t * @param e - The API error\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?: (info: {\n\t\tmessage: string;\n\t\tissues: readonly StandardSchemaV1.Issue[];\n\t}) => void | Promise<void>;\n}\n\nexport type Endpoint<\n\tPath extends string = string,\n\tMethod = any,\n\tBody = any,\n\tQuery = any,\n\tUse extends Middleware[] = any,\n\tR = any,\n\tMeta extends EndpointMetadata | undefined = EndpointMetadata | undefined,\n\tError = any,\n> = {\n\t(\n\t\tcontext: InputContext<Path, Method, Body, Query, false, false> & {\n\t\t\tasResponse: true;\n\t\t},\n\t): Promise<Response>;\n\t(\n\t\tcontext: InputContext<Path, Method, Body, Query, false, false> & {\n\t\t\treturnHeaders: true;\n\t\t\treturnStatus: true;\n\t\t},\n\t): Promise<{\n\t\theaders: Headers;\n\t\tstatus: number;\n\t\tresponse: Awaited<R>;\n\t}>;\n\t(\n\t\tcontext: InputContext<Path, Method, Body, Query, false, false> & {\n\t\t\treturnHeaders: true;\n\t\t},\n\t): Promise<{\n\t\theaders: Headers;\n\t\tresponse: Awaited<R>;\n\t}>;\n\t(\n\t\tcontext: InputContext<Path, Method, Body, Query, false, false> & {\n\t\t\treturnStatus: true;\n\t\t},\n\t): Promise<{\n\t\tstatus: number;\n\t\tresponse: Awaited<R>;\n\t}>;\n\t(\n\t\tcontext?: InputContext<Path, Method, Body, Query, false, false>,\n\t): Promise<Awaited<R>>;\n\toptions: Omit<EndpointRuntimeOptions, \"method\" | \"metadata\"> & {\n\t\tmethod: Method;\n\t\tmetadata?: Meta;\n\t};\n\tpath: Path;\n};\n\n// Path + options + handler overload\nexport function createEndpoint<\n\tPath extends string,\n\tMethod extends HTTPMethod | HTTPMethod[] | \"*\",\n\tBodySchema extends object | undefined = undefined,\n\tQuerySchema extends object | undefined = undefined,\n\tUse extends Middleware[] = [],\n\tReqHeaders extends boolean = false,\n\tReqRequest extends boolean = false,\n\tR = unknown,\n\tMeta extends EndpointMetadata | undefined = undefined,\n\tErrorSchema extends StandardSchemaV1 | undefined = undefined,\n>(\n\tpath: Path,\n\toptions: { method: Method } & BodyOption<Method, BodySchema> & {\n\t\t\tquery?: QuerySchema;\n\t\t\tuse?: [...Use];\n\t\t\trequireHeaders?: ReqHeaders;\n\t\t\trequireRequest?: ReqRequest;\n\t\t\terror?: ErrorSchema;\n\t\t\tcloneRequest?: boolean;\n\t\t\tdisableBody?: boolean;\n\t\t\tmetadata?: Meta;\n\t\t\tonAPIError?: (e: APIError) => void | Promise<void>;\n\t\t\tonValidationError?: (info: {\n\t\t\t\tmessage: string;\n\t\t\t\tissues: readonly StandardSchemaV1.Issue[];\n\t\t\t}) => void | Promise<void>;\n\t\t\t[key: string]: any;\n\t\t},\n\thandler: (\n\t\tctx: EndpointContext<\n\t\t\tPath,\n\t\t\tMethod,\n\t\t\tBodySchema,\n\t\t\tQuerySchema,\n\t\t\tUse,\n\t\t\tReqHeaders,\n\t\t\tReqRequest,\n\t\t\tInferUse<Use>,\n\t\t\tMeta\n\t\t>,\n\t) => Promise<R>,\n): Endpoint<\n\tPath,\n\tMethod,\n\tResolveBodyInput<BodySchema, Meta>,\n\tResolveQueryInput<QuerySchema, Meta>,\n\tUse,\n\tR,\n\tResolveMetaInput<Meta>,\n\tResolveErrorInput<ErrorSchema, Meta>\n>;\n\n// Options-only (virtual/path-less) overload\nexport function createEndpoint<\n\tMethod extends HTTPMethod | HTTPMethod[] | \"*\",\n\tBodySchema extends object | undefined = undefined,\n\tQuerySchema extends object | undefined = undefined,\n\tUse extends Middleware[] = [],\n\tReqHeaders extends boolean = false,\n\tReqRequest extends boolean = false,\n\tR = unknown,\n\tMeta extends EndpointMetadata | undefined = undefined,\n\tErrorSchema extends StandardSchemaV1 | undefined = undefined,\n>(\n\toptions: { method: Method } & BodyOption<Method, BodySchema> & {\n\t\t\tpath?: never;\n\t\t\tquery?: QuerySchema;\n\t\t\tuse?: [...Use];\n\t\t\trequireHeaders?: ReqHeaders;\n\t\t\trequireRequest?: ReqRequest;\n\t\t\terror?: ErrorSchema;\n\t\t\tcloneRequest?: boolean;\n\t\t\tdisableBody?: boolean;\n\t\t\tmetadata?: Meta;\n\t\t\tonAPIError?: (e: APIError) => void | Promise<void>;\n\t\t\tonValidationError?: (info: {\n\t\t\t\tmessage: string;\n\t\t\t\tissues: readonly StandardSchemaV1.Issue[];\n\t\t\t}) => void | Promise<void>;\n\t\t\t[key: string]: any;\n\t\t},\n\thandler: (\n\t\tctx: EndpointContext<\n\t\t\tnever,\n\t\t\tMethod,\n\t\t\tBodySchema,\n\t\t\tQuerySchema,\n\t\t\tUse,\n\t\t\tReqHeaders,\n\t\t\tReqRequest,\n\t\t\tInferUse<Use>,\n\t\t\tMeta\n\t\t>,\n\t) => Promise<R>,\n): Endpoint<\n\tnever,\n\tMethod,\n\tResolveBodyInput<BodySchema, Meta>,\n\tResolveQueryInput<QuerySchema, Meta>,\n\tUse,\n\tR,\n\tResolveMetaInput<Meta>,\n\tResolveErrorInput<ErrorSchema, Meta>\n>;\n\n// Implementation\nexport function createEndpoint(\n\tpathOrOptions: any,\n\thandlerOrOptions: any,\n\thandlerOrNever?: any,\n): any {\n\tconst path: string | undefined =\n\t\ttypeof pathOrOptions === \"string\" ? pathOrOptions : undefined;\n\tconst options: any =\n\t\ttypeof handlerOrOptions === \"object\" ? handlerOrOptions : pathOrOptions;\n\tconst handler: any =\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\n\tconst runtimeOptions: EndpointRuntimeOptions = {\n\t\tmethod: options.method,\n\t\tbody: options.body,\n\t\tquery: options.query,\n\t\terror: options.error,\n\t\trequireHeaders: options.requireHeaders,\n\t\trequireRequest: options.requireRequest,\n\t\tcloneRequest: options.cloneRequest,\n\t\tdisableBody: options.disableBody,\n\t\tmetadata: options.metadata,\n\t\tuse: options.use,\n\t\tonAPIError: options.onAPIError,\n\t\tonValidationError: options.onValidationError,\n\t};\n\n\tconst internalHandler = async (...inputCtx: any[]): Promise<any> => {\n\t\tconst context = (inputCtx[0] || {}) as Record<string, any>;\n\t\tconst { data: internalContext, error: validationError } = await tryCatch(\n\t\t\tcreateInternalContext(context, {\n\t\t\t\toptions: runtimeOptions,\n\t\t\t\tpath,\n\t\t\t}),\n\t\t);\n\n\t\tif (validationError) {\n\t\t\tif (!(validationError instanceof ValidationError)) throw validationError;\n\n\t\t\tif (options.onValidationError) {\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\n\t\tconst response = await handler(internalContext as any).catch(\n\t\t\tasync (e: any) => {\n\t\t\t\tif (isAPIError(e)) {\n\t\t\t\t\tconst onAPIError = options.onAPIError;\n\t\t\t\t\tif (onAPIError) {\n\t\t\t\t\t\tawait onAPIError(e);\n\t\t\t\t\t}\n\t\t\t\t\tif (context.asResponse) {\n\t\t\t\t\t\treturn e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthrow e;\n\t\t\t},\n\t\t);\n\n\t\tconst responseHeaders = internalContext.responseHeaders;\n\t\tconst status = internalContext.responseStatus;\n\n\t\treturn context.asResponse\n\t\t\t? toResponse(response, {\n\t\t\t\t\theaders: responseHeaders,\n\t\t\t\t\tstatus,\n\t\t\t\t})\n\t\t\t: context.returnHeaders\n\t\t\t\t? context.returnStatus\n\t\t\t\t\t? {\n\t\t\t\t\t\t\theaders: responseHeaders,\n\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t\tstatus,\n\t\t\t\t\t\t}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\theaders: responseHeaders,\n\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t}\n\t\t\t\t: context.returnStatus\n\t\t\t\t\t? { response, status }\n\t\t\t\t\t: response;\n\t};\n\n\tinternalHandler.options = runtimeOptions;\n\tinternalHandler.path = path;\n\treturn internalHandler as any;\n}\n\ncreateEndpoint.create = <E extends { use?: Middleware[] }>(opts?: E) => {\n\treturn <\n\t\tPath extends string,\n\t\tMethod extends HTTPMethod | HTTPMethod[] | \"*\",\n\t\tBodySchema extends object | undefined = undefined,\n\t\tQuerySchema extends object | undefined = undefined,\n\t\tUse extends Middleware[] = [],\n\t\tReqHeaders extends boolean = false,\n\t\tReqRequest extends boolean = false,\n\t\tR = unknown,\n\t\tMeta extends EndpointMetadata | undefined = undefined,\n\t\tErrorSchema extends StandardSchemaV1 | undefined = undefined,\n\t>(\n\t\tpath: Path,\n\t\toptions: { method: Method } & BodyOption<Method, BodySchema> & {\n\t\t\t\tquery?: QuerySchema;\n\t\t\t\tuse?: [...Use];\n\t\t\t\trequireHeaders?: ReqHeaders;\n\t\t\t\trequireRequest?: ReqRequest;\n\t\t\t\terror?: ErrorSchema;\n\t\t\t\tcloneRequest?: boolean;\n\t\t\t\tdisableBody?: boolean;\n\t\t\t\tmetadata?: Meta;\n\t\t\t\tonAPIError?: (e: APIError) => void | Promise<void>;\n\t\t\t\tonValidationError?: (info: {\n\t\t\t\t\tmessage: string;\n\t\t\t\t\tissues: readonly StandardSchemaV1.Issue[];\n\t\t\t\t}) => void | Promise<void>;\n\t\t\t\t[key: string]: any;\n\t\t\t},\n\t\thandler: (\n\t\t\tctx: EndpointContext<\n\t\t\t\tPath,\n\t\t\t\tMethod,\n\t\t\t\tBodySchema,\n\t\t\t\tQuerySchema,\n\t\t\t\tUse,\n\t\t\t\tReqHeaders,\n\t\t\t\tReqRequest,\n\t\t\t\tInferUse<E[\"use\"]>,\n\t\t\t\tMeta\n\t\t\t>,\n\t\t) => Promise<R>,\n\t): Endpoint<\n\t\tPath,\n\t\tMethod,\n\t\tResolveBodyInput<BodySchema, Meta>,\n\t\tResolveQueryInput<QuerySchema, Meta>,\n\t\tUse,\n\t\tAwaited<R>,\n\t\tResolveMetaInput<Meta>,\n\t\tResolveErrorInput<ErrorSchema, Meta>\n\t> => {\n\t\treturn createEndpoint(\n\t\t\tpath,\n\t\t\t{\n\t\t\t\t...options,\n\t\t\t\tuse: [...(options?.use || []), ...(opts?.use || [])],\n\t\t\t} as any,\n\t\t\thandler as any,\n\t\t) as any;\n\t};\n};\n"],"mappings":";;;;;;AAiXA,SAAgB,eACf,eACA,kBACA,gBACM;CACN,MAAM,OACL,OAAO,kBAAkB,WAAW,gBAAgB;CACrD,MAAM,UACL,OAAO,qBAAqB,WAAW,mBAAmB;CAC3D,MAAM,UACL,OAAO,qBAAqB,aAAa,mBAAmB;AAE7D,MAAK,QAAQ,WAAW,SAAS,QAAQ,WAAW,WAAW,QAAQ,KACtE,OAAM,IAAI,gBAAgB,+CAA+C;AAG1E,KAAI,QAAQ,SAAS,KAAK,KAAK,CAC9B,OAAM,IAAI,gBAAgB,0CAA0C;CAGrE,MAAM,iBAAyC;EAC9C,QAAQ,QAAQ;EAChB,MAAM,QAAQ;EACd,OAAO,QAAQ;EACf,OAAO,QAAQ;EACf,gBAAgB,QAAQ;EACxB,gBAAgB,QAAQ;EACxB,cAAc,QAAQ;EACtB,aAAa,QAAQ;EACrB,UAAU,QAAQ;EAClB,KAAK,QAAQ;EACb,YAAY,QAAQ;EACpB,mBAAmB,QAAQ;EAC3B;CAED,MAAM,kBAAkB,OAAO,GAAG,aAAkC;EACnE,MAAM,UAAW,SAAS,MAAM,EAAE;EAClC,MAAM,EAAE,MAAM,iBAAiB,OAAO,oBAAoB,MAAM,SAC/D,sBAAsB,SAAS;GAC9B,SAAS;GACT;GACA,CAAC,CACF;AAED,MAAI,iBAAiB;AACpB,OAAI,EAAE,2BAA2B,iBAAkB,OAAM;AAEzD,OAAI,QAAQ,kBACX,OAAM,QAAQ,kBAAkB;IAC/B,SAAS,gBAAgB;IACzB,QAAQ,gBAAgB;IACxB,CAAC;AAGH,SAAM,IAAI,SAAS,KAAK;IACvB,SAAS,gBAAgB;IACzB,MAAM;IACN,CAAC;;EAGH,MAAM,WAAW,MAAM,QAAQ,gBAAuB,CAAC,MACtD,OAAO,MAAW;AACjB,OAAI,WAAW,EAAE,EAAE;IAClB,MAAM,aAAa,QAAQ;AAC3B,QAAI,WACH,OAAM,WAAW,EAAE;AAEpB,QAAI,QAAQ,WACX,QAAO;;AAGT,SAAM;IAEP;EAED,MAAM,kBAAkB,gBAAgB;EACxC,MAAM,SAAS,gBAAgB;AAE/B,SAAO,QAAQ,aACZ,WAAW,UAAU;GACrB,SAAS;GACT;GACA,CAAC,GACD,QAAQ,gBACP,QAAQ,eACP;GACA,SAAS;GACT;GACA;GACA,GACA;GACA,SAAS;GACT;GACA,GACD,QAAQ,eACP;GAAE;GAAU;GAAQ,GACpB;;AAGN,iBAAgB,UAAU;AAC1B,iBAAgB,OAAO;AACvB,QAAO;;AAGR,eAAe,UAA4C,SAAa;AACvE,SAYC,MACA,SAgBA,YAsBI;AACJ,SAAO,eACN,MACA;GACC,GAAG;GACH,KAAK,CAAC,GAAI,SAAS,OAAO,EAAE,EAAG,GAAI,MAAM,OAAO,EAAE,CAAE;GACpD,EACD,QACA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "better-call",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",