better-call 2.0.0-beta.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/endpoint.cjs.map +1 -1
- package/dist/endpoint.d.cts +4 -4
- package/dist/endpoint.d.mts +4 -4
- package/dist/endpoint.mjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/types.d.cts +8 -1
- package/dist/types.d.mts +8 -1
- package/package.json +1 -1
package/dist/endpoint.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"endpoint.cjs","names":["BetterCallError","tryCatch","createInternalContext","ValidationError","APIError","isAPIError","toResponse"],"sources":["../src/endpoint.ts"],"sourcesContent":["import { 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\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\tMeta,\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\tMeta,\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\tMeta,\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":";;;;;;AAgXA,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: 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"}
|
package/dist/endpoint.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StandardSchemaV1 } from "./standard-schema.cjs";
|
|
2
2
|
import { APIError } from "./error.cjs";
|
|
3
|
-
import { BodyOption, HTTPMethod, InferUse, InputContext, ResolveBodyInput, ResolveErrorInput, ResolveQueryInput } from "./types.cjs";
|
|
3
|
+
import { BodyOption, HTTPMethod, InferUse, InputContext, ResolveBodyInput, ResolveErrorInput, ResolveMetaInput, ResolveQueryInput } from "./types.cjs";
|
|
4
4
|
import { Middleware } from "./middleware.cjs";
|
|
5
5
|
import { EndpointContext } from "./context.cjs";
|
|
6
6
|
import { OpenAPIParameter, OpenAPISchemaType } from "./openapi.cjs";
|
|
@@ -233,7 +233,7 @@ declare function createEndpoint<Path extends string, Method extends HTTPMethod |
|
|
|
233
233
|
issues: readonly StandardSchemaV1.Issue[];
|
|
234
234
|
}) => void | Promise<void>;
|
|
235
235
|
[key: string]: any;
|
|
236
|
-
}, handler: (ctx: EndpointContext<Path, Method, BodySchema, QuerySchema, Use, ReqHeaders, ReqRequest, InferUse<Use>, Meta>) => Promise<R>): Endpoint<Path, Method, ResolveBodyInput<BodySchema, Meta>, ResolveQueryInput<QuerySchema, Meta>, Use, R, Meta
|
|
236
|
+
}, handler: (ctx: EndpointContext<Path, Method, BodySchema, QuerySchema, Use, ReqHeaders, ReqRequest, InferUse<Use>, Meta>) => Promise<R>): Endpoint<Path, Method, ResolveBodyInput<BodySchema, Meta>, ResolveQueryInput<QuerySchema, Meta>, Use, R, ResolveMetaInput<Meta>, ResolveErrorInput<ErrorSchema, Meta>>;
|
|
237
237
|
declare function createEndpoint<Method extends HTTPMethod | HTTPMethod[] | "*", BodySchema extends object | undefined = undefined, QuerySchema extends object | undefined = undefined, Use extends Middleware[] = [], ReqHeaders extends boolean = false, ReqRequest extends boolean = false, R = unknown, Meta extends EndpointMetadata | undefined = undefined, ErrorSchema extends StandardSchemaV1 | undefined = undefined>(options: {
|
|
238
238
|
method: Method;
|
|
239
239
|
} & BodyOption<Method, BodySchema> & {
|
|
@@ -252,7 +252,7 @@ declare function createEndpoint<Method extends HTTPMethod | HTTPMethod[] | "*",
|
|
|
252
252
|
issues: readonly StandardSchemaV1.Issue[];
|
|
253
253
|
}) => void | Promise<void>;
|
|
254
254
|
[key: string]: any;
|
|
255
|
-
}, handler: (ctx: EndpointContext<never, Method, BodySchema, QuerySchema, Use, ReqHeaders, ReqRequest, InferUse<Use>, Meta>) => Promise<R>): Endpoint<never, Method, ResolveBodyInput<BodySchema, Meta>, ResolveQueryInput<QuerySchema, Meta>, Use, R, Meta
|
|
255
|
+
}, handler: (ctx: EndpointContext<never, Method, BodySchema, QuerySchema, Use, ReqHeaders, ReqRequest, InferUse<Use>, Meta>) => Promise<R>): Endpoint<never, Method, ResolveBodyInput<BodySchema, Meta>, ResolveQueryInput<QuerySchema, Meta>, Use, R, ResolveMetaInput<Meta>, ResolveErrorInput<ErrorSchema, Meta>>;
|
|
256
256
|
declare namespace createEndpoint {
|
|
257
257
|
var create: <E extends {
|
|
258
258
|
use?: Middleware[];
|
|
@@ -273,7 +273,7 @@ declare namespace createEndpoint {
|
|
|
273
273
|
issues: readonly StandardSchemaV1.Issue[];
|
|
274
274
|
}) => void | Promise<void>;
|
|
275
275
|
[key: string]: any;
|
|
276
|
-
}, handler: (ctx: EndpointContext<Path, Method, BodySchema, QuerySchema, Use, ReqHeaders, ReqRequest, InferUse<E["use"]>, Meta>) => Promise<R>) => Endpoint<Path, Method, ResolveBodyInput<BodySchema, Meta>, ResolveQueryInput<QuerySchema, Meta>, Use, Awaited<R>, Meta
|
|
276
|
+
}, handler: (ctx: EndpointContext<Path, Method, BodySchema, QuerySchema, Use, ReqHeaders, ReqRequest, InferUse<E["use"]>, Meta>) => Promise<R>) => Endpoint<Path, Method, ResolveBodyInput<BodySchema, Meta>, ResolveQueryInput<QuerySchema, Meta>, Use, Awaited<R>, ResolveMetaInput<Meta>, ResolveErrorInput<ErrorSchema, Meta>>;
|
|
277
277
|
}
|
|
278
278
|
//#endregion
|
|
279
279
|
export { Endpoint, EndpointMetadata, EndpointRuntimeOptions, createEndpoint };
|
package/dist/endpoint.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StandardSchemaV1 } from "./standard-schema.mjs";
|
|
2
2
|
import { APIError } from "./error.mjs";
|
|
3
|
-
import { BodyOption, HTTPMethod, InferUse, InputContext, ResolveBodyInput, ResolveErrorInput, ResolveQueryInput } from "./types.mjs";
|
|
3
|
+
import { BodyOption, HTTPMethod, InferUse, InputContext, ResolveBodyInput, ResolveErrorInput, ResolveMetaInput, ResolveQueryInput } from "./types.mjs";
|
|
4
4
|
import { Middleware } from "./middleware.mjs";
|
|
5
5
|
import { EndpointContext } from "./context.mjs";
|
|
6
6
|
import { OpenAPIParameter, OpenAPISchemaType } from "./openapi.mjs";
|
|
@@ -233,7 +233,7 @@ declare function createEndpoint<Path extends string, Method extends HTTPMethod |
|
|
|
233
233
|
issues: readonly StandardSchemaV1.Issue[];
|
|
234
234
|
}) => void | Promise<void>;
|
|
235
235
|
[key: string]: any;
|
|
236
|
-
}, handler: (ctx: EndpointContext<Path, Method, BodySchema, QuerySchema, Use, ReqHeaders, ReqRequest, InferUse<Use>, Meta>) => Promise<R>): Endpoint<Path, Method, ResolveBodyInput<BodySchema, Meta>, ResolveQueryInput<QuerySchema, Meta>, Use, R, Meta
|
|
236
|
+
}, handler: (ctx: EndpointContext<Path, Method, BodySchema, QuerySchema, Use, ReqHeaders, ReqRequest, InferUse<Use>, Meta>) => Promise<R>): Endpoint<Path, Method, ResolveBodyInput<BodySchema, Meta>, ResolveQueryInput<QuerySchema, Meta>, Use, R, ResolveMetaInput<Meta>, ResolveErrorInput<ErrorSchema, Meta>>;
|
|
237
237
|
declare function createEndpoint<Method extends HTTPMethod | HTTPMethod[] | "*", BodySchema extends object | undefined = undefined, QuerySchema extends object | undefined = undefined, Use extends Middleware[] = [], ReqHeaders extends boolean = false, ReqRequest extends boolean = false, R = unknown, Meta extends EndpointMetadata | undefined = undefined, ErrorSchema extends StandardSchemaV1 | undefined = undefined>(options: {
|
|
238
238
|
method: Method;
|
|
239
239
|
} & BodyOption<Method, BodySchema> & {
|
|
@@ -252,7 +252,7 @@ declare function createEndpoint<Method extends HTTPMethod | HTTPMethod[] | "*",
|
|
|
252
252
|
issues: readonly StandardSchemaV1.Issue[];
|
|
253
253
|
}) => void | Promise<void>;
|
|
254
254
|
[key: string]: any;
|
|
255
|
-
}, handler: (ctx: EndpointContext<never, Method, BodySchema, QuerySchema, Use, ReqHeaders, ReqRequest, InferUse<Use>, Meta>) => Promise<R>): Endpoint<never, Method, ResolveBodyInput<BodySchema, Meta>, ResolveQueryInput<QuerySchema, Meta>, Use, R, Meta
|
|
255
|
+
}, handler: (ctx: EndpointContext<never, Method, BodySchema, QuerySchema, Use, ReqHeaders, ReqRequest, InferUse<Use>, Meta>) => Promise<R>): Endpoint<never, Method, ResolveBodyInput<BodySchema, Meta>, ResolveQueryInput<QuerySchema, Meta>, Use, R, ResolveMetaInput<Meta>, ResolveErrorInput<ErrorSchema, Meta>>;
|
|
256
256
|
declare namespace createEndpoint {
|
|
257
257
|
var create: <E extends {
|
|
258
258
|
use?: Middleware[];
|
|
@@ -273,7 +273,7 @@ declare namespace createEndpoint {
|
|
|
273
273
|
issues: readonly StandardSchemaV1.Issue[];
|
|
274
274
|
}) => void | Promise<void>;
|
|
275
275
|
[key: string]: any;
|
|
276
|
-
}, handler: (ctx: EndpointContext<Path, Method, BodySchema, QuerySchema, Use, ReqHeaders, ReqRequest, InferUse<E["use"]>, Meta>) => Promise<R>) => Endpoint<Path, Method, ResolveBodyInput<BodySchema, Meta>, ResolveQueryInput<QuerySchema, Meta>, Use, Awaited<R>, Meta
|
|
276
|
+
}, handler: (ctx: EndpointContext<Path, Method, BodySchema, QuerySchema, Use, ReqHeaders, ReqRequest, InferUse<E["use"]>, Meta>) => Promise<R>) => Endpoint<Path, Method, ResolveBodyInput<BodySchema, Meta>, ResolveQueryInput<QuerySchema, Meta>, Use, Awaited<R>, ResolveMetaInput<Meta>, ResolveErrorInput<ErrorSchema, Meta>>;
|
|
277
277
|
}
|
|
278
278
|
//#endregion
|
|
279
279
|
export { Endpoint, EndpointMetadata, EndpointRuntimeOptions, createEndpoint };
|
package/dist/endpoint.mjs.map
CHANGED
|
@@ -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\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\tMeta,\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\tMeta,\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\tMeta,\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":";;;;;;AAgXA,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: 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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -2,11 +2,11 @@ import { CookieOptions, CookiePrefixOptions, serializeSignedCookie } from "./coo
|
|
|
2
2
|
import { StandardSchemaV1 } from "./standard-schema.cjs";
|
|
3
3
|
import { APIError, BetterCallError, Status, ValidationError, kAPIErrorHeaderSymbol, statusCodes } from "./error.cjs";
|
|
4
4
|
import { Prettify } from "./helper.cjs";
|
|
5
|
-
import { HTTPMethod, InputContext, ResolveBodyInput, ResolveErrorInput, ResolveQueryInput } from "./types.cjs";
|
|
5
|
+
import { HTTPMethod, InputContext, ResolveBodyInput, ResolveErrorInput, ResolveMetaInput, ResolveQueryInput } from "./types.cjs";
|
|
6
6
|
import { Middleware, MiddlewareContext, createMiddleware } from "./middleware.cjs";
|
|
7
7
|
import { EndpointContext } from "./context.cjs";
|
|
8
8
|
import { OpenAPIParameter, OpenAPISchemaType, generator, getHTML } from "./openapi.cjs";
|
|
9
9
|
import { Endpoint, EndpointMetadata, EndpointRuntimeOptions, createEndpoint } from "./endpoint.cjs";
|
|
10
10
|
import { Router, RouterConfig, createRouter } from "./router.cjs";
|
|
11
11
|
import { JSONResponse, toResponse } from "./to-response.cjs";
|
|
12
|
-
export { APIError, BetterCallError, type CookieOptions, type CookiePrefixOptions, type Endpoint, type EndpointContext, type EndpointMetadata, type EndpointRuntimeOptions, type HTTPMethod, type InputContext, type JSONResponse, type Middleware, type MiddlewareContext, type OpenAPIParameter, type OpenAPISchemaType, type Prettify, type ResolveBodyInput, type ResolveErrorInput, type ResolveQueryInput, type Router, type RouterConfig, type StandardSchemaV1, type Status, ValidationError, createEndpoint, createMiddleware, createRouter, generator as generateOpenAPI, getHTML as getOpenAPIHTML, kAPIErrorHeaderSymbol, serializeSignedCookie, statusCodes, toResponse };
|
|
12
|
+
export { APIError, BetterCallError, type CookieOptions, type CookiePrefixOptions, type Endpoint, type EndpointContext, type EndpointMetadata, type EndpointRuntimeOptions, type HTTPMethod, type InputContext, type JSONResponse, type Middleware, type MiddlewareContext, type OpenAPIParameter, type OpenAPISchemaType, type Prettify, type ResolveBodyInput, type ResolveErrorInput, type ResolveMetaInput, type ResolveQueryInput, type Router, type RouterConfig, type StandardSchemaV1, type Status, ValidationError, createEndpoint, createMiddleware, createRouter, generator as generateOpenAPI, getHTML as getOpenAPIHTML, kAPIErrorHeaderSymbol, serializeSignedCookie, statusCodes, toResponse };
|
package/dist/index.d.mts
CHANGED
|
@@ -2,11 +2,11 @@ import { CookieOptions, CookiePrefixOptions, serializeSignedCookie } from "./coo
|
|
|
2
2
|
import { StandardSchemaV1 } from "./standard-schema.mjs";
|
|
3
3
|
import { APIError, BetterCallError, Status, ValidationError, kAPIErrorHeaderSymbol, statusCodes } from "./error.mjs";
|
|
4
4
|
import { Prettify } from "./helper.mjs";
|
|
5
|
-
import { HTTPMethod, InputContext, ResolveBodyInput, ResolveErrorInput, ResolveQueryInput } from "./types.mjs";
|
|
5
|
+
import { HTTPMethod, InputContext, ResolveBodyInput, ResolveErrorInput, ResolveMetaInput, ResolveQueryInput } from "./types.mjs";
|
|
6
6
|
import { Middleware, MiddlewareContext, createMiddleware } from "./middleware.mjs";
|
|
7
7
|
import { EndpointContext } from "./context.mjs";
|
|
8
8
|
import { OpenAPIParameter, OpenAPISchemaType, generator, getHTML } from "./openapi.mjs";
|
|
9
9
|
import { Endpoint, EndpointMetadata, EndpointRuntimeOptions, createEndpoint } from "./endpoint.mjs";
|
|
10
10
|
import { Router, RouterConfig, createRouter } from "./router.mjs";
|
|
11
11
|
import { JSONResponse, toResponse } from "./to-response.mjs";
|
|
12
|
-
export { APIError, BetterCallError, type CookieOptions, type CookiePrefixOptions, type Endpoint, type EndpointContext, type EndpointMetadata, type EndpointRuntimeOptions, type HTTPMethod, type InputContext, type JSONResponse, type Middleware, type MiddlewareContext, type OpenAPIParameter, type OpenAPISchemaType, type Prettify, type ResolveBodyInput, type ResolveErrorInput, type ResolveQueryInput, type Router, type RouterConfig, type StandardSchemaV1, type Status, ValidationError, createEndpoint, createMiddleware, createRouter, generator as generateOpenAPI, getHTML as getOpenAPIHTML, kAPIErrorHeaderSymbol, serializeSignedCookie, statusCodes, toResponse };
|
|
12
|
+
export { APIError, BetterCallError, type CookieOptions, type CookiePrefixOptions, type Endpoint, type EndpointContext, type EndpointMetadata, type EndpointRuntimeOptions, type HTTPMethod, type InputContext, type JSONResponse, type Middleware, type MiddlewareContext, type OpenAPIParameter, type OpenAPISchemaType, type Prettify, type ResolveBodyInput, type ResolveErrorInput, type ResolveMetaInput, type ResolveQueryInput, type Router, type RouterConfig, type StandardSchemaV1, type Status, ValidationError, createEndpoint, createMiddleware, createRouter, generator as generateOpenAPI, getHTML as getOpenAPIHTML, kAPIErrorHeaderSymbol, serializeSignedCookie, statusCodes, toResponse };
|
package/dist/types.d.cts
CHANGED
|
@@ -54,6 +54,13 @@ type ResolveErrorInput<S, Meta = undefined> = Meta extends {
|
|
|
54
54
|
error: infer E;
|
|
55
55
|
};
|
|
56
56
|
} ? ResolveInferValueInput<E> : S extends StandardSchemaV1 ? StandardSchemaV1.InferInput<S> : undefined;
|
|
57
|
+
/**
|
|
58
|
+
* Resolves metadata by resolving any StandardSchemaV1 schemas inside $Infer to their input types.
|
|
59
|
+
* Uses mapped type instead of Omit to avoid preserving the original schema types in declaration emit.
|
|
60
|
+
*/
|
|
61
|
+
type ResolveMetaInput<Meta> = Meta extends {
|
|
62
|
+
$Infer: infer I;
|
|
63
|
+
} ? { [K in keyof Meta]: K extends "$Infer" ? { [J in keyof I]: ResolveInferValueInput<I[J]> } : Meta[K] } : Meta;
|
|
57
64
|
/**
|
|
58
65
|
* Constraint: body is `never` for GET/HEAD methods.
|
|
59
66
|
*/
|
|
@@ -144,5 +151,5 @@ type InputContext<Path extends string, M, Body, Query, ReqHeaders extends boolea
|
|
|
144
151
|
context?: Record<string, any>;
|
|
145
152
|
};
|
|
146
153
|
//#endregion
|
|
147
|
-
export { BodyOption, HTTPMethod, InferParam, InferUse, InputContext, ResolveBody, ResolveBodyInput, ResolveErrorInput, ResolveMethod, ResolveQuery, ResolveQueryInput };
|
|
154
|
+
export { BodyOption, HTTPMethod, InferParam, InferUse, InputContext, ResolveBody, ResolveBodyInput, ResolveErrorInput, ResolveMetaInput, ResolveMethod, ResolveQuery, ResolveQueryInput };
|
|
148
155
|
//# sourceMappingURL=types.d.cts.map
|
package/dist/types.d.mts
CHANGED
|
@@ -54,6 +54,13 @@ type ResolveErrorInput<S, Meta = undefined> = Meta extends {
|
|
|
54
54
|
error: infer E;
|
|
55
55
|
};
|
|
56
56
|
} ? ResolveInferValueInput<E> : S extends StandardSchemaV1 ? StandardSchemaV1.InferInput<S> : undefined;
|
|
57
|
+
/**
|
|
58
|
+
* Resolves metadata by resolving any StandardSchemaV1 schemas inside $Infer to their input types.
|
|
59
|
+
* Uses mapped type instead of Omit to avoid preserving the original schema types in declaration emit.
|
|
60
|
+
*/
|
|
61
|
+
type ResolveMetaInput<Meta> = Meta extends {
|
|
62
|
+
$Infer: infer I;
|
|
63
|
+
} ? { [K in keyof Meta]: K extends "$Infer" ? { [J in keyof I]: ResolveInferValueInput<I[J]> } : Meta[K] } : Meta;
|
|
57
64
|
/**
|
|
58
65
|
* Constraint: body is `never` for GET/HEAD methods.
|
|
59
66
|
*/
|
|
@@ -144,5 +151,5 @@ type InputContext<Path extends string, M, Body, Query, ReqHeaders extends boolea
|
|
|
144
151
|
context?: Record<string, any>;
|
|
145
152
|
};
|
|
146
153
|
//#endregion
|
|
147
|
-
export { BodyOption, HTTPMethod, InferParam, InferUse, InputContext, ResolveBody, ResolveBodyInput, ResolveErrorInput, ResolveMethod, ResolveQuery, ResolveQueryInput };
|
|
154
|
+
export { BodyOption, HTTPMethod, InferParam, InferUse, InputContext, ResolveBody, ResolveBodyInput, ResolveErrorInput, ResolveMetaInput, ResolveMethod, ResolveQuery, ResolveQueryInput };
|
|
148
155
|
//# sourceMappingURL=types.d.mts.map
|