@lucidcms/core
Version:
The core of the Lucid CMS. It's responsible for spinning up the API and serving the CMS.
1 lines • 5.39 kB
Source Map (JSON)
{"version":3,"file":"register-custom-routes.mjs","names":[],"sources":["../../../../src/libs/http/utils/register-custom-routes.ts"],"sourcesContent":["import type { Handler, Hono, ValidationTargets } from \"hono\";\nimport { type DescribeRouteOptions, describeRoute } from \"hono-openapi\";\nimport z from \"zod\";\nimport type {\n\tLucidHonoContext,\n\tLucidHonoGeneric,\n} from \"../../../types/hono.js\";\nimport validate from \"../middleware/validate.js\";\nimport openAPI from \"../openapi/index.js\";\nimport type { LucidRouteDefinition, LucidRouteInput } from \"../types.js\";\nimport buildFormattedQuery from \"./build-formatted-query.js\";\nimport createServiceContext from \"./create-service-context.js\";\n\ntype ValidatedRequest = {\n\tvalid: (target: keyof ValidationTargets) => unknown;\n};\n\nconst getValidatedValue = <T>(\n\thono: LucidHonoContext,\n\ttarget: keyof ValidationTargets,\n): T => (hono.req as unknown as ValidatedRequest).valid(target) as T;\n\n/**\n * Builds route docs from schema defaults while letting explicit OpenAPI fields\n * win, so custom routes stay documented without hiding escape hatches.\n */\nconst buildOpenAPIOptions = (\n\troute: LucidRouteDefinition,\n): DescribeRouteOptions => {\n\tconst schema = route.schema;\n\tconst openAPIOptions = route.openAPI ?? {};\n\tconst parameters = openAPI.parameters({\n\t\tparams: schema?.params,\n\t\tquery: schema?.query?.string,\n\t});\n\n\treturn {\n\t\t...openAPIOptions,\n\t\t...(openAPIOptions.parameters === undefined && parameters.length > 0\n\t\t\t? { parameters }\n\t\t\t: {}),\n\t\t...(openAPIOptions.requestBody === undefined && schema?.body\n\t\t\t? { requestBody: openAPI.requestBody(schema.body) }\n\t\t\t: {}),\n\t\t...(openAPIOptions.responses === undefined\n\t\t\t? {\n\t\t\t\t\tresponses: openAPI.responses(\n\t\t\t\t\t\tschema?.response\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tschema: z.toJSONSchema(schema.response),\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t),\n\t\t\t\t}\n\t\t\t: {}),\n\t};\n};\n\n/**\n * Creates the handler input after validators have run, using formatted query\n * output when a route defines one.\n */\nconst buildInput = async (\n\thono: LucidHonoContext,\n\troute: LucidRouteDefinition,\n): Promise<LucidRouteInput<typeof route.schema>> => {\n\tconst schema = route.schema;\n\n\treturn {\n\t\tbody: schema?.body ? getValidatedValue(hono, \"json\") : undefined,\n\t\tparams: schema?.params ? getValidatedValue(hono, \"param\") : undefined,\n\t\tquery: schema?.query?.formatted\n\t\t\t? await buildFormattedQuery(hono, schema.query.formatted)\n\t\t\t: schema?.query?.string\n\t\t\t\t? getValidatedValue(hono, \"query\")\n\t\t\t\t: undefined,\n\t} as LucidRouteInput<typeof route.schema>;\n};\n\n/**\n * Keeps custom routes on the same pipeline: document, run route middleware,\n * validate request parts, then call the Lucid handler.\n */\nconst buildRouteHandlers = (\n\troute: LucidRouteDefinition,\n): Handler<LucidHonoGeneric>[] => [\n\tdescribeRoute(buildOpenAPIOptions(route)),\n\t...(route.middleware ?? []),\n\t...(route.schema?.params ? [validate(\"param\", route.schema.params)] : []),\n\t...(route.schema?.query?.string\n\t\t? [validate(\"query\", route.schema.query.string)]\n\t\t: []),\n\t...(route.schema?.body ? [validate(\"json\", route.schema.body)] : []),\n\tasync (hono) =>\n\t\troute.handler({\n\t\t\thono,\n\t\t\tcontext: createServiceContext(hono),\n\t\t\tinput: await buildInput(hono, route),\n\t\t}),\n];\n\n/**\n * Registers custom routes with exact user-defined paths. Lucid does not apply\n * an API prefix here because plugins and apps may expose their own public paths.\n */\nconst registerCustomRoutes = (\n\tapp: Hono<LucidHonoGeneric>,\n\troutes: LucidRouteDefinition[],\n) => {\n\tfor (const route of routes) {\n\t\tconst handlers = buildRouteHandlers(route);\n\t\tconst register = app[route.method].bind(app) as (\n\t\t\tpath: string,\n\t\t\t...handlers: Handler<LucidHonoGeneric>[]\n\t\t) => void;\n\n\t\tregister(route.path, ...handlers);\n\t}\n};\n\nexport default registerCustomRoutes;\n"],"mappings":"qOAiBA,MAAM,GACL,EACA,IACQ,EAAK,IAAoC,MAAM,CAAM,EAMxD,EACL,GAC0B,CAC1B,IAAM,EAAS,EAAM,OACf,EAAiB,EAAM,SAAW,CAAC,EACnC,EAAa,EAAQ,WAAW,CACrC,OAAQ,GAAQ,OAChB,MAAO,GAAQ,OAAO,MACvB,CAAC,EAED,MAAO,CACN,GAAG,EACH,GAAI,EAAe,aAAe,IAAA,IAAa,EAAW,OAAS,EAChE,CAAE,YAAW,EACb,CAAC,EACJ,GAAI,EAAe,cAAgB,IAAA,IAAa,GAAQ,KACrD,CAAE,YAAa,EAAQ,YAAY,EAAO,IAAI,CAAE,EAChD,CAAC,EACJ,GAAI,EAAe,YAAc,IAAA,GAC9B,CACA,UAAW,EAAQ,UAClB,GAAQ,SACL,CACA,OAAQ,EAAE,aAAa,EAAO,QAAQ,CACvC,EACC,IAAA,EACJ,CACD,EACC,CAAC,CACL,CACD,EAMM,EAAa,MAClB,EACA,IACmD,CACnD,IAAM,EAAS,EAAM,OAErB,MAAO,CACN,KAAM,GAAQ,KAAO,EAAkB,EAAM,MAAM,EAAI,IAAA,GACvD,OAAQ,GAAQ,OAAS,EAAkB,EAAM,OAAO,EAAI,IAAA,GAC5D,MAAO,GAAQ,OAAO,UACnB,MAAM,EAAoB,EAAM,EAAO,MAAM,SAAS,EACtD,GAAQ,OAAO,OACd,EAAkB,EAAM,OAAO,EAC/B,IAAA,EACL,CACD,EAMM,EACL,GACiC,CACjC,EAAc,EAAoB,CAAK,CAAC,EACxC,GAAI,EAAM,YAAc,CAAC,EACzB,GAAI,EAAM,QAAQ,OAAS,CAAC,EAAS,QAAS,EAAM,OAAO,MAAM,CAAC,EAAI,CAAC,EACvE,GAAI,EAAM,QAAQ,OAAO,OACtB,CAAC,EAAS,QAAS,EAAM,OAAO,MAAM,MAAM,CAAC,EAC7C,CAAC,EACJ,GAAI,EAAM,QAAQ,KAAO,CAAC,EAAS,OAAQ,EAAM,OAAO,IAAI,CAAC,EAAI,CAAC,EAClE,KAAO,IACN,EAAM,QAAQ,CACb,OACA,QAAS,EAAqB,CAAI,EAClC,MAAO,MAAM,EAAW,EAAM,CAAK,CACpC,CAAC,CACH,EAMM,GACL,EACA,IACI,CACJ,IAAK,IAAM,KAAS,EAAQ,CAC3B,IAAM,EAAW,EAAmB,CAAK,EAMzC,EALqB,EAAM,OAAO,CAAC,KAAK,CAKjC,CAAC,CAAC,EAAM,KAAM,GAAG,CAAQ,CACjC,CACD"}