UNPKG

@lucidcms/core

Version:

The core of the Lucid CMS. It's responsible for spinning up the API and serving the CMS.

1,713 lines (1,673 loc) 607 kB
import { build_response_default, route_default, swaggerRegisterRefs, swagger_headers_default, swagger_refs_default, swagger_response_default } from "./chunk-JNP7DCNX.js"; import { build_table_name_default, choose_accept_header_format_default, collectionTableParts, formatters_default, generate_process_key_default, get_unique_locale_codes_default, merge_translation_groups_default, should_update_translations_default } from "./chunk-5BJFGYMM.js"; import "./chunk-K5KJEV2Z.js"; import { prefix_generated_column_name_default } from "./chunk-FRZBD5RL.js"; import { permissions_default, service_wrapper_default } from "./chunk-HLKZRFCZ.js"; import { decode_error_default, logger_default, logging_default, lucid_api_error_default, lucid_error_default, tidy_zod_errors_default } from "./chunk-7SRFYA4B.js"; import { constants_default, permission_groups_default, translations_default } from "./chunk-7XW7FQ7W.js"; // src/libs/fastify/server.ts import Fastify from "fastify"; // src/libs/fastify/plugins/lucid.ts import fs8 from "node:fs"; import path5 from "node:path"; import fastifyCookie from "@fastify/cookie"; import cors from "@fastify/cors"; import fastifyHelmet from "@fastify/helmet"; import fastifyRateLimit from "@fastify/rate-limit"; import fastifyStatic2 from "@fastify/static"; import fastifySwagger from "@fastify/swagger"; import fp2 from "fastify-plugin"; // package.json var package_default = { name: "@lucidcms/core", version: "0.11.0-alpha.0", description: "The core of the Lucid CMS. It's responsible for spinning up the API and serving the CMS.", type: "module", types: "./dist/index.d.ts", module: "dist/index.js", exports: { ".": { import: "./dist/index.js", types: "./dist/index.d.ts" }, "./api": { types: "./dist/api.d.ts", default: "./dist/api.js" }, "./builders": { types: "./dist/builders.d.ts", default: "./dist/builders.js" }, "./middleware": { types: "./dist/middleware.d.ts", default: "./dist/middleware.js" }, "./helpers": { types: "./dist/helpers.d.ts", default: "./dist/helpers.js" }, "./types": { types: "./dist/types.d.ts", default: "./dist/types.js" }, "./package.json": "./package.json" }, scripts: { build: "tsc && tsup", dev: "tsup --watch", format: "biome format ./src", "format:fix": "biome format --write ./src", lint: "biome lint ./src", "lint:fix": "biome lint --apply ./src" }, files: ["dist", "cms", "templates", "assets"], author: "Proto Digital", repository: { type: "git", url: "git+https://github.com/ProtoDigitalUK/lucid_cms.git", directory: "packages/core" }, keywords: [ "CMS", "Headless", "Node.js", "Typescript", "ESM", "Fastify", "Kysely" ], devDependencies: { "@biomejs/biome": "^1.9.4", "@lucidcms/admin": "*", "@lucidcms/config": "*", "@types/jsonwebtoken": "^9.0.9", "@types/lodash.merge": "^4.6.9", "@types/mime-types": "^2.1.4", "@types/mjml": "^4.7.4", "@types/node": "^22.15.2", "@types/node-cron": "^3.0.11", "@types/sanitize-html": "^2.15.0", "@types/semver": "^7.7.0", "@types/slug": "^5.0.9", tsup: "^8.4.0", typescript: "^5.8.3" }, dependencies: { "@fastify/cookie": "^11.0.2", "@fastify/cors": "^11.0.1", "@fastify/helmet": "^13.0.1", "@fastify/rate-limit": "^10.2.2", "@fastify/static": "^8.1.1", "@fastify/swagger": "^9.5.0", "@lucidcms/admin": "0.11.0-alpha.0", "@scalar/fastify-api-reference": "^1.28.26", "@tailwindcss/vite": "^4.1.4", argon2: "^0.43.0", blurhash: "^2.0.5", "date-fns": "^4.1.0", "fast-average-color-node": "^3.1.0", fastify: "^5.3.2", "fastify-plugin": "^5.0.1", handlebars: "^4.7.8", jiti: "^2.4.2", jsonwebtoken: "^9.0.2", kysely: "0.27.4", "lodash.merge": "^4.6.2", "mime-types": "^3.0.1", mjml: "^5.0.0-alpha.6", "node-cron": "^3.0.3", "sanitize-html": "^2.16.0", semver: "^7.7.1", sharp: "^0.33.5", slug: "^10.0.0", "solid-js": "^1.9.5", tailwindcss: "^4.1.4", vite: "^6.3.5", "vite-plugin-solid": "^2.11.6", winston: "^3.17.0", zod: "^4.0.0-beta" }, volta: { node: "22.15.0" }, engines: { node: ">=22.0.0 <23.0.0" }, license: "BSL-1.0" }; // src/actions/register-cron-jobs.ts import cron from "node-cron"; var registerCronJobs = async (service) => { try { cron.schedule(constants_default.cronSchedule, async () => { logging_default("info", { message: translations_default("running_cron_jobs"), scope: constants_default.logScopes.cron }); await Promise.allSettled([ service_wrapper_default(service.services.crons.clearExpiredLocales, { transaction: true, logError: true, defaultError: { type: "cron", name: translations_default("cron_job_error_name"), message: translations_default("an_error_occurred_clearing_expired_locales") } })(service), service_wrapper_default(service.services.crons.clearExpiredCollections, { transaction: true, logError: true, defaultError: { type: "cron", name: translations_default("cron_job_error_name"), message: translations_default("an_error_occurred_clearing_expired_collections") } })(service), service_wrapper_default(service.services.crons.clearExpiredTokens, { transaction: true, logError: true, defaultError: { type: "cron", name: translations_default("cron_job_error_name"), message: translations_default("an_error_occurred_clearing_expired_tokens") } })(service), service_wrapper_default(service.services.crons.updateMediaStorage, { transaction: true, logError: true, defaultError: { type: "cron", name: translations_default("cron_job_error_name"), message: translations_default("an_error_occurred_updating_media_storage") } })(service), service_wrapper_default(service.services.crons.deleteExpiredMedia, { transaction: true, logError: true, defaultError: { type: "cron", name: translations_default("cron_job_error_name"), message: translations_default("an_error_occurred_deleting_expired_media") } })(service) ]); }); } catch (error) { logging_default("error", { message: translations_default("cron_job_error_message"), scope: constants_default.logScopes.cron }); } }; var register_cron_jobs_default = registerCronJobs; // src/actions/execute-start-tasks.ts var executeStartTasks = async (service) => { await service.config.db.migrateToLatest(); await Promise.all([ service_wrapper_default(service.services.start.executeSeeds, { transaction: true, logError: true, defaultError: { name: translations_default("seed_error_name") } })(service), service_wrapper_default(service.services.start.syncLocales, { transaction: true, logError: true, defaultError: { name: translations_default("start_error_name"), message: translations_default("locale_error_occured_saving_default") } })(service), service_wrapper_default(service.services.start.syncCollections, { transaction: true, logError: true, defaultError: { name: translations_default("start_error_name"), message: translations_default("collection_error_occured_saving_default") } })(service) ]); await service_wrapper_default( service.services.collection.migrator.migrateCollections, { transaction: true, logError: true, defaultError: { name: translations_default("collection_migrator_error_name") } } )(service); register_cron_jobs_default(service); }; var execute_start_tasks_default = executeStartTasks; // src/libs/config/get-config-path.ts import path from "node:path"; import fs from "node:fs"; var getConfigPath = (cwd, filename) => { let configPath = void 0; const root = path.parse(cwd).root; const configFileName = filename ?? "lucid.config"; const configExtensions = [".ts", ".js", ".mjs", ".mts"]; const search = (cwd2) => { const files = fs.readdirSync(cwd2); const configFiles = files.filter((file) => { const { name, ext } = path.parse(file); return name === configFileName && configExtensions.includes(ext); }); if (configFiles.length > 0 && configFiles[0]) { configPath = path.resolve(cwd2, configFiles[0]); return; } const parent = path.resolve(cwd2, ".."); if (parent === cwd2 || parent === root) { return; } search(parent); }; search(cwd); if (!configPath) { throw new Error(translations_default("cannot_find_config_path")); } return configPath; }; var get_config_path_default = getConfigPath; // src/libs/config/get-config.ts import path2 from "node:path"; import { pathToFileURL } from "node:url"; import { createJiti } from "jiti"; var jiti = createJiti(import.meta.url); var config = void 0; var getConfig = async (props) => { if (props?.config) { config = props.config; return config; } if (config) { return config; } const configPath = props?.path ? props.path : get_config_path_default(process.cwd()); const importPath = pathToFileURL(path2.resolve(configPath)).href; if (props?.dynamicImport) { const configModule = await import(importPath); config = configModule.default; } else { const configModule = await jiti.import(importPath, { default: true }); config = configModule; } return config; }; var get_config_default = getConfig; // src/libs/fastify/controllers/auth/get-csrf.ts import z2 from "zod"; // src/schemas/auth.ts import z from "zod"; var controllerSchemas = { getCSRF: { body: void 0, query: { string: void 0, formatted: void 0 }, params: void 0, response: z.object({ _csrf: z.string().meta({ description: "Store this value and use it for the _csrf header on required endpoints.", example: "55b26b90b9715d0e9cc425e8f1ba565cad5157e3d56ae8380d8c832a5fb3fcb7" }) }) }, login: { body: z.object({ usernameOrEmail: z.string().meta({ description: "Username or email address", example: "admin" }), password: z.string().meta({ description: "User password", example: "password" }) }).meta({ description: "User credentials for login" }), query: { string: void 0, formatted: void 0 }, params: void 0, response: void 0 }, token: { body: void 0, query: { string: void 0, formatted: void 0 }, params: void 0, response: void 0 }, logout: { body: void 0, query: { string: void 0, formatted: void 0 }, params: void 0, response: void 0 } }; // src/libs/fastify/controllers/auth/get-csrf.ts var getCSRFController = async (request, reply) => { const tokenRes = await request.server.services.auth.csrf.generateToken( request, reply ); if (tokenRes.error) throw new lucid_api_error_default(tokenRes.error); reply.status(200).send( build_response_default(request, { data: { _csrf: tokenRes.data } }) ); }; var get_csrf_default = { controller: getCSRFController, zodSchema: controllerSchemas.getCSRF, swaggerSchema: { description: "This endpoint returns a CSRF token in the response body as well as setting a _csrf httpOnly cookie. Some endpoints require this value to be passed via a _csrf header.", tags: ["auth"], summary: "CSRF Token", response: swagger_response_default({ schema: z2.toJSONSchema(controllerSchemas.getCSRF.response) }) } }; // src/libs/fastify/controllers/auth/login.ts import z3 from "zod"; var loginController = async (request, reply) => { const userRes = await service_wrapper_default(request.server.services.auth.login, { transaction: false, defaultError: { type: "basic", code: "login", name: translations_default("route_login_error_name"), message: translations_default("route_login_error_message") } })( { db: request.server.config.db.client, config: request.server.config, services: request.server.services }, { usernameOrEmail: request.body.usernameOrEmail, password: request.body.password } ); if (userRes.error) throw new lucid_api_error_default(userRes.error); const [refreshRes, accessRes] = await Promise.all([ request.server.services.auth.refreshToken.generateToken( reply, request, userRes.data.id ), request.server.services.auth.accessToken.generateToken( reply, request, userRes.data.id ) ]); if (refreshRes.error) throw new lucid_api_error_default(refreshRes.error); if (accessRes.error) throw new lucid_api_error_default(accessRes.error); reply.status(204).send(); }; var login_default = { controller: loginController, zodSchema: controllerSchemas.login, swaggerSchema: { description: "Authenticates a user and sets a refresh and access token as httpOnly cookies.", tags: ["auth"], summary: "Login", headers: swagger_headers_default({ csrf: true }), body: z3.toJSONSchema(controllerSchemas.login.body), response: swagger_response_default({ noProperties: true }) } }; // src/libs/fastify/controllers/auth/token.ts var tokenController = async (request, reply) => { const payloadRes = await request.server.services.auth.refreshToken.verifyToken(request, reply); if (payloadRes.error) throw new lucid_api_error_default(payloadRes.error); const [refreshRes, accessRes] = await Promise.all([ request.server.services.auth.refreshToken.generateToken( reply, request, payloadRes.data.user_id ), request.server.services.auth.accessToken.generateToken( reply, request, payloadRes.data.user_id ) ]); if (refreshRes.error) throw new lucid_api_error_default(refreshRes.error); if (accessRes.error) throw new lucid_api_error_default(accessRes.error); reply.status(204).send(); }; var token_default = { controller: tokenController, zodSchema: controllerSchemas.token, swaggerSchema: { description: "Verifies the refresh token and issues a new access and refresh token.", tags: ["auth"], summary: "Refresh Token", headers: swagger_headers_default({ csrf: true }), response: swagger_response_default({ noProperties: true }) } }; // src/libs/fastify/controllers/auth/logout.ts var logoutController = async (request, reply) => { const [clearRefreshRes, clearAccessRes, clearCSRFRes] = await Promise.all([ request.server.services.auth.refreshToken.clearToken(request, reply), request.server.services.auth.accessToken.clearToken(reply), request.server.services.auth.csrf.clearToken(reply) ]); if (clearRefreshRes.error) throw new lucid_api_error_default(clearRefreshRes.error); if (clearAccessRes.error) throw new lucid_api_error_default(clearAccessRes.error); if (clearCSRFRes.error) throw new lucid_api_error_default(clearCSRFRes.error); reply.status(204).send(); }; var logout_default = { controller: logoutController, zodSchema: controllerSchemas.logout, swaggerSchema: { description: "Logs out a user by clearing the refresh token and access token, it also clears the CSRF token.", tags: ["auth"], summary: "Logout", headers: swagger_headers_default({ csrf: true }), response: swagger_response_default({ noProperties: true }) } }; // src/libs/fastify/controllers/auth/index.ts var controllers = { getCSRF: get_csrf_default, login: login_default, token: token_default, logout: logout_default }; var auth_default = controllers; // src/libs/fastify/routes/v1/api/auth.routes.ts var authRoutes = async (fastify2) => { route_default(fastify2, { method: "get", url: "/csrf", zodSchema: auth_default.getCSRF.zodSchema, swaggerSchema: auth_default.getCSRF.swaggerSchema, controller: auth_default.getCSRF.controller }); route_default(fastify2, { method: "post", url: "/login", middleware: { validateCSRF: true }, zodSchema: auth_default.login.zodSchema, swaggerSchema: auth_default.login.swaggerSchema, controller: auth_default.login.controller }); route_default(fastify2, { method: "post", url: "/token", middleware: { validateCSRF: true // Does have the authenticate middleware because all it does it checks if the access token is valid // and if it is it will return the user data, this handles authorisatio itsself via the refresh token. }, zodSchema: auth_default.token.zodSchema, swaggerSchema: auth_default.token.swaggerSchema, controller: auth_default.token.controller }); route_default(fastify2, { method: "post", url: "/logout", middleware: { authenticate: true, validateCSRF: true }, zodSchema: auth_default.logout.zodSchema, swaggerSchema: auth_default.logout.swaggerSchema, controller: auth_default.logout.controller }); }; var auth_routes_default = authRoutes; // src/libs/fastify/controllers/permissions/get-all.ts import z5 from "zod"; // src/schemas/permissions.ts import z4 from "zod"; var permissionResponseSchema = z4.object({ key: z4.string().meta({ description: "The permission's group key", example: "users_permissions" }), permissions: z4.array(z4.string()).meta({ description: "The permissions for this permission group", example: ["create_user", "update_user", "delete_user"] }) }); var controllerSchemas2 = { getAll: { body: void 0, query: { string: void 0, formatted: void 0 }, params: void 0, response: z4.array(permissionResponseSchema) } }; // src/libs/fastify/controllers/permissions/get-all.ts var getAllController = async (request, reply) => { const PermissionsFormatter = formatters_default.get("permissions"); reply.status(200).send( build_response_default(request, { data: PermissionsFormatter.formatMultiple({ permissions: permission_groups_default }) }) ); }; var get_all_default = { controller: getAllController, zodSchema: controllerSchemas2.getAll, swaggerSchema: { description: "Returns a list of all permissions available for users.", tags: ["permissions"], summary: "Get All Permissions", response: swagger_response_default({ schema: z5.toJSONSchema(controllerSchemas2.getAll.response) }) } }; // src/libs/fastify/controllers/permissions/index.ts var controllers2 = { getAll: get_all_default }; var permissions_default2 = controllers2; // src/libs/fastify/routes/v1/api/permissions.routes.ts var permissionRoutes = async (fastify2) => { route_default(fastify2, { method: "get", url: "", middleware: { authenticate: true }, swaggerSchema: permissions_default2.getAll.swaggerSchema, zodSchema: permissions_default2.getAll.zodSchema, controller: permissions_default2.getAll.controller }); }; var permissions_routes_default = permissionRoutes; // src/libs/fastify/controllers/roles/create-single.ts import z8 from "zod"; // src/schemas/roles.ts import z7 from "zod"; // src/schemas/helpers/querystring.ts import z6 from "zod"; var filterOperators = z6.enum(["=", "%", "like", "ilike", "in", "not in", "<>", "is not", "is", "!="]).optional(); var queryString = { schema: { filter: (multiple = false, example, description) => z6.string().meta({ description: multiple ? description || "Accepts multiple values separated by commas." : description || "Accepts a single value only.", example }).optional(), sort: (example) => z6.string().meta({ description: "Orders results using comma-separated field names. Prefix with - for descending order.", example }).optional(), include: (example) => z6.string().meta({ description: "Specifies related resources to include in response as comma-separated values", example }).optional(), exclude: (example) => z6.string().meta({ description: "Defines fields to exclude from response as comma-separated values", example }).optional(), page: z6.string().regex(/^[1-9][0-9]*$/).describe( "Specifies the page number for pagination (must be a positive integer)" ).optional(), perPage: z6.string().regex(/^([1-9][0-9]*|-1)$/).describe( "Sets the number of items per page (use positive integer or -1 for all items)" ).optional() }, meta: { patternProperties: { "^filter\\[([^\\]:]+):?([^\\]]*)\\]$": { type: ["string", "null"], description: "Dynamic filter parameter in format filter[fieldName:operator]. Supported operators include: '=', '%', 'like', 'ilike', 'in', 'not in', '<>', 'is not', 'is' and '!='." } }, additionalProperties: false } }; var queryFormatted = { schema: { filters: { single: z6.object({ value: z6.union([z6.string(), z6.number()]), operator: filterOperators }), union: z6.object({ value: z6.union([ z6.string(), z6.array(z6.string()), z6.number(), z6.array(z6.number()) ]), operator: filterOperators }) }, page: z6.number(), perPage: z6.number() } }; // src/schemas/roles.ts var roleResponseSchema = z7.interface({ id: z7.number().meta({ description: "The role ID", example: 1 }), name: z7.string().meta({ description: "The role's name", example: "Editors" }), description: z7.string().nullable().meta({ description: "The role's description", example: "Editor's can edit documents from any collection" }), "permissions?": z7.array( z7.object({ id: z7.number().meta({ description: "The permission ID", example: 1 }), permission: z7.string().meta({ description: "The permission key", example: "create_user" }) }) ).meta({ description: "A list of all of the roles permissions" }), createdAt: z7.string().meta({ description: "Creation timestamp", example: "2022-01-01T00:00:00Z" }), updatedAt: z7.string().meta({ description: "Last update timestamp", example: "2022-01-01T00:00:00Z" }) }); var controllerSchemas3 = { createSingle: { body: z7.object({ name: z7.string().min(2).meta({ description: "The role's name", example: "Editor" }), description: z7.string().meta({ description: "A description for the role", example: "Editor's can edit documents from any collection" }).optional(), permissions: z7.array(z7.string()).meta({ description: "A lit of permissions", example: ["create_user", "update_user"] }) }), query: { string: void 0, formatted: void 0 }, params: void 0, response: roleResponseSchema }, updateSingle: { body: z7.object({ name: z7.string().min(2).meta({ description: "The role's name", example: "Editor" }).optional(), description: z7.string().meta({ description: "A description for the role", example: "Editor's can edit documents from any collection" }).optional(), permissions: z7.array(z7.string()).meta({ description: "A lit of permissions", example: ["create_user", "update_user"] }).optional() }), query: { string: void 0, formatted: void 0 }, params: z7.object({ id: z7.string().meta({ description: "The role's ID", example: 1 }) }), response: void 0 }, deleteSingle: { body: void 0, query: { string: void 0, formatted: void 0 }, params: z7.object({ id: z7.string().meta({ description: "The role's ID", example: 1 }) }), response: void 0 }, getMultiple: { body: void 0, query: { string: z7.object({ "filter[name]": queryString.schema.filter(false, "Editor"), "filter[roleIds]": queryString.schema.filter(true, "1,2"), sort: queryString.schema.sort("createdAt,name"), include: queryString.schema.include("permissions"), page: queryString.schema.page, perPage: queryString.schema.perPage }).meta(queryString.meta), formatted: z7.object({ filter: z7.object({ name: queryFormatted.schema.filters.single.optional(), roleIds: queryFormatted.schema.filters.union.optional() }).optional(), sort: z7.array( z7.object({ key: z7.enum(["createdAt", "name"]), value: z7.enum(["asc", "desc"]) }) ).optional(), include: z7.array(z7.enum(["permissions"])).optional(), page: queryFormatted.schema.page, perPage: queryFormatted.schema.perPage }) }, params: void 0, response: z7.array(roleResponseSchema) }, getSingle: { body: void 0, query: { string: void 0, formatted: void 0 }, params: z7.object({ id: z7.string().meta({ description: "The role's ID", example: 1 }) }), response: roleResponseSchema } }; // src/libs/fastify/controllers/roles/create-single.ts var createSingleController = async (request, reply) => { const roleId = await service_wrapper_default( request.server.services.role.createSingle, { transaction: true, defaultError: { type: "basic", name: translations_default("route_roles_create_error_name"), message: translations_default("route_roles_create_error_message") } } )( { db: request.server.config.db.client, config: request.server.config, services: request.server.services }, { name: request.body.name, description: request.body.description, permissions: request.body.permissions } ); if (roleId.error) throw new lucid_api_error_default(roleId.error); const role = await service_wrapper_default(request.server.services.role.getSingle, { transaction: false, defaultError: { type: "basic", name: translations_default("route_roles_fetch_error_name"), message: translations_default("route_roles_fetch_error_message") } })( { db: request.server.config.db.client, config: request.server.config, services: request.server.services }, { id: roleId.data } ); if (role.error) throw new lucid_api_error_default(role.error); reply.status(200).send( build_response_default(request, { data: role.data }) ); }; var create_single_default = { controller: createSingleController, zodSchema: controllerSchemas3.createSingle, swaggerSchema: { description: "Create a single role with the given name and permission groups.", tags: ["roles"], summary: "Create Role", headers: swagger_headers_default({ csrf: true }), body: z8.toJSONSchema(controllerSchemas3.createSingle.body), response: swagger_response_default({ schema: z8.toJSONSchema(controllerSchemas3.createSingle.response) }) } }; // src/libs/fastify/controllers/roles/get-single.ts import z9 from "zod"; var getSingleController = async (request, reply) => { const role = await service_wrapper_default(request.server.services.role.getSingle, { transaction: false, defaultError: { type: "basic", name: translations_default("route_roles_fetch_error_name"), message: translations_default("route_roles_fetch_error_message") } })( { db: request.server.config.db.client, config: request.server.config, services: request.server.services }, { id: Number.parseInt(request.params.id, 10) } ); if (role.error) throw new lucid_api_error_default(role.error); reply.status(200).send( build_response_default(request, { data: role.data }) ); }; var get_single_default = { controller: getSingleController, zodSchema: controllerSchemas3.getSingle, swaggerSchema: { description: "Returns a single role based on the given ID.", tags: ["roles"], summary: "Get Role", params: z9.toJSONSchema(controllerSchemas3.getSingle.params), response: swagger_response_default({ schema: z9.toJSONSchema(controllerSchemas3.getSingle.response) }) } }; // src/libs/fastify/controllers/roles/get-multiple.ts import z10 from "zod"; var getMultipleController = async (request, reply) => { const role = await service_wrapper_default(request.server.services.role.getMultiple, { transaction: false, defaultError: { type: "basic", name: translations_default("route_roles_fetch_error_name"), message: translations_default("route_roles_fetch_error_message") } })( { db: request.server.config.db.client, config: request.server.config, services: request.server.services }, { query: request.formattedQuery } ); if (role.error) throw new lucid_api_error_default(role.error); reply.status(200).send( build_response_default(request, { data: role.data.data, pagination: { count: role.data.count, page: request.formattedQuery.page, perPage: request.formattedQuery.perPage } }) ); }; var get_multiple_default = { controller: getMultipleController, zodSchema: controllerSchemas3.getMultiple, swaggerSchema: { description: "Returns multiple roles based on the query parameters.", tags: ["roles"], summary: "Get Multiple Roles", querystring: z10.toJSONSchema(controllerSchemas3.getMultiple.query.string), response: swagger_response_default({ schema: z10.toJSONSchema(controllerSchemas3.getMultiple.response), paginated: true }) } }; // src/libs/fastify/controllers/roles/delete-single.ts import z11 from "zod"; var deleteSingleController = async (request, reply) => { const deleteSingle7 = await service_wrapper_default( request.server.services.role.deleteSingle, { transaction: true, defaultError: { type: "basic", name: translations_default("route_roles_delete_error_name"), message: translations_default("route_roles_delete_error_message") } } )( { db: request.server.config.db.client, config: request.server.config, services: request.server.services }, { id: Number.parseInt(request.params.id) } ); if (deleteSingle7.error) throw new lucid_api_error_default(deleteSingle7.error); reply.status(204).send(); }; var delete_single_default = { controller: deleteSingleController, zodSchema: controllerSchemas3.deleteSingle, swaggerSchema: { description: "Delete a single role based on the given role ID.", tags: ["roles"], summary: "Delete Role", headers: swagger_headers_default({ csrf: true }), params: z11.toJSONSchema(controllerSchemas3.deleteSingle.params), response: swagger_response_default({ noProperties: true }) } }; // src/libs/fastify/controllers/roles/update-single.ts import z12 from "zod"; var updateSingleController = async (request, reply) => { const updateSingel = await service_wrapper_default( request.server.services.role.updateSingle, { transaction: true, defaultError: { type: "basic", name: translations_default("route_roles_update_error_name"), message: translations_default("route_roles_update_error_message") } } )( { db: request.server.config.db.client, config: request.server.config, services: request.server.services }, { id: Number.parseInt(request.params.id), name: request.body.name, description: request.body.description, permissions: request.body.permissions } ); if (updateSingel.error) throw new lucid_api_error_default(updateSingel.error); reply.status(204).send(); }; var update_single_default = { controller: updateSingleController, zodSchema: controllerSchemas3.updateSingle, swaggerSchema: { description: "Update a single role with the given name and permission groups by ID.", tags: ["roles"], summary: "Update Role", headers: swagger_headers_default({ csrf: true }), body: z12.toJSONSchema(controllerSchemas3.updateSingle.body), params: z12.toJSONSchema(controllerSchemas3.updateSingle.params), response: swagger_response_default({ noProperties: true }) } }; // src/libs/fastify/controllers/roles/index.ts var controllers3 = { createSingle: create_single_default, getSingle: get_single_default, getMultiple: get_multiple_default, deleteSingle: delete_single_default, updateSingle: update_single_default }; var roles_default = controllers3; // src/libs/fastify/routes/v1/api/roles.routes.ts var roleRoutes = async (fastify2) => { route_default(fastify2, { method: "post", url: "", middleware: { authenticate: true, validateCSRF: true }, permissions: ["create_role"], swaggerSchema: roles_default.createSingle.swaggerSchema, zodSchema: roles_default.createSingle.zodSchema, controller: roles_default.createSingle.controller }); route_default(fastify2, { method: "get", url: "/:id", middleware: { authenticate: true }, swaggerSchema: roles_default.getSingle.swaggerSchema, zodSchema: roles_default.getSingle.zodSchema, controller: roles_default.getSingle.controller }); route_default(fastify2, { method: "get", url: "", middleware: { authenticate: true }, swaggerSchema: roles_default.getMultiple.swaggerSchema, zodSchema: roles_default.getMultiple.zodSchema, controller: roles_default.getMultiple.controller }); route_default(fastify2, { method: "delete", url: "/:id", middleware: { authenticate: true, validateCSRF: true }, permissions: ["delete_role"], swaggerSchema: roles_default.deleteSingle.swaggerSchema, zodSchema: roles_default.deleteSingle.zodSchema, controller: roles_default.deleteSingle.controller }); route_default(fastify2, { method: "patch", url: "/:id", permissions: ["update_role"], middleware: { authenticate: true, validateCSRF: true }, swaggerSchema: roles_default.updateSingle.swaggerSchema, zodSchema: roles_default.updateSingle.zodSchema, controller: roles_default.updateSingle.controller }); }; var roles_routes_default = roleRoutes; // src/libs/fastify/controllers/account/update-me.ts import z15 from "zod"; // src/schemas/account.ts import z14 from "zod"; // src/schemas/users.ts import z13 from "zod"; var userResponsePermissionSchema = z13.string().meta({ description: "A permission identifier", example: "create_user" }); var userResponseRoleSchema = z13.object({ id: z13.number().meta({ description: "The role ID", example: 1 }), name: z13.string().meta({ description: "The role name", example: "Admin" }) }); var userResponseSchema = z13.object({ id: z13.number().meta({ description: "The user's ID", example: 1 }), superAdmin: z13.boolean().meta({ description: "Whether the user is a superadmin.", example: true }), email: z13.email().meta({ description: "The user's email address", example: "admin@lucidcms.io" }), username: z13.string().meta({ description: "The user's username", example: "admin" }), firstName: z13.string().nullable().meta({ description: "The user's first name", example: "John" }), lastName: z13.string().nullable().meta({ description: "The user's last name", example: "Smith" }), triggerPasswordReset: z13.boolean().nullable().meta({ description: "Should the UI force a password reset?", example: false }), roles: z13.array(userResponseRoleSchema).meta({ description: "The user's roles" }), permissions: z13.array(userResponsePermissionSchema), createdAt: z13.string().nullable().meta({ description: "The date the user was added", example: "2021-06-10T20:00:00.000Z" }), updatedAt: z13.string().nullable().meta({ description: "The date the user row was last updated", example: "2021-06-10T20:00:00.000Z" }) }); var controllerSchemas4 = { createSingle: { body: z13.object({ email: z13.email().meta({ description: "The user's email address", example: "admin@lucidcms.io" }), username: z13.string().meta({ description: "The user's username", example: "Admin" }), roleIds: z13.array(z13.number()).meta({ description: "A list of role IDs to attach to the user", example: [1, 2] }), firstName: z13.string().meta({ description: "The user's first name", example: "John" }).optional(), lastName: z13.string().meta({ description: "The user's last name", example: "Smith" }).optional(), superAdmin: z13.boolean().meta({ description: "Whether the user is a super admin or not", example: true }).optional() }), query: { string: void 0, formatted: void 0 }, params: void 0, response: userResponseSchema }, updateSingle: { body: z13.object({ roleIds: z13.array(z13.number()).meta({ description: "A list of role IDs to attach to the user", example: [1, 2] }).optional(), superAdmin: z13.boolean().meta({ description: "Whether the user is a super admin or not", example: true }).optional(), triggerPasswordReset: z13.boolean().meta({ description: "Whether the user should be forced to update their password in the UI", example: true }).optional(), isDeleted: z13.literal(false).meta({ description: "Restore a deleted user", example: false }).optional() }), query: { string: void 0, formatted: void 0 }, params: z13.object({ id: z13.string().meta({ description: "The user's ID", example: 1 }) }), response: void 0 }, getSingle: { body: void 0, query: { string: void 0, formatted: void 0 }, params: z13.object({ id: z13.string().meta({ description: "The user's ID", example: 1 }) }), response: userResponseSchema }, getMultiple: { query: { string: z13.object({ "filter[firstName]": queryString.schema.filter(false, "John"), "filter[lastName]": queryString.schema.filter(false, "Smith"), "filter[email]": queryString.schema.filter( false, "admin@lucidcms.io" ), "filter[username]": queryString.schema.filter(false, "admin"), "filter[roleIds]": queryString.schema.filter(true, "1,2,3"), "filter[id]": queryString.schema.filter(true, "1,2"), sort: queryString.schema.sort( "createdAt,updatedAt,firstName,lastName,email,username" ), include: queryString.schema.include("permissions"), page: queryString.schema.page, perPage: queryString.schema.perPage }).meta(queryString.meta), formatted: z13.object({ filter: z13.object({ firstName: queryFormatted.schema.filters.single.optional(), lastName: queryFormatted.schema.filters.single.optional(), email: queryFormatted.schema.filters.single.optional(), username: queryFormatted.schema.filters.single.optional(), roleIds: queryFormatted.schema.filters.union.optional(), id: queryFormatted.schema.filters.union.optional() }).optional(), sort: z13.array( z13.object({ key: z13.enum([ "createdAt", "updatedAt", "firstName", "lastName", "email", "username" ]), value: z13.enum(["asc", "desc"]) }) ).optional(), include: z13.array(z13.enum(["permissions"])).optional(), page: queryFormatted.schema.page, perPage: queryFormatted.schema.perPage }) }, params: void 0, body: void 0, response: z13.array(userResponseSchema) }, deleteSingle: { body: void 0, query: { string: void 0, formatted: void 0 }, params: z13.object({ id: z13.string().meta({ description: "The user's ID", example: 1 }) }), response: void 0 } }; // src/schemas/account.ts var controllerSchemas5 = { getMe: { body: void 0, query: { string: void 0, formatted: void 0 }, params: void 0, response: userResponseSchema }, resetPassword: { body: z14.object({ password: z14.string().min(8).max(128).meta({ description: "Your new password", example: "password123" }), passwordConfirmation: z14.string().min(8).max(128).meta({ description: "A repeat of your new password", example: "password123" }) }).refine((data) => data.password === data.passwordConfirmation, { message: translations_default("please_ensure_passwords_match"), path: ["passwordConfirmation"] }), query: { string: void 0, formatted: void 0 }, params: z14.object({ token: z14.string().meta({ description: "A unique token granted to you when you request a password reset", example: "838ece1033bf7c7468e873e79ba2a3ec" }) }), response: void 0 }, sendResetPassword: { body: z14.object({ email: z14.email().meta({ description: "Your email address", example: "admin@lucidcms.io" }) }), query: { string: void 0, formatted: void 0 }, params: void 0, response: z14.object({ message: z14.string().meta({ description: "A status message", example: translations_default("if_account_exists_with_email_not_found") }) }) }, verifyResetPassword: { body: void 0, query: { string: void 0, formatted: void 0 }, params: z14.object({ token: z14.string().meta({ description: "A unique token granted to you when you request a password reset", example: "838ece1033bf7c7468e873e79ba2a3ec" }) }), response: void 0 }, updateMe: { body: z14.object({ firstName: z14.string().meta({ description: "Your new first name", example: "John" }).optional(), lastName: z14.string().meta({ description: "Your new last name", example: "Smith" }).optional(), username: z14.string().min(3).meta({ description: "Your new username", example: "admin" }).optional(), email: z14.email().meta({ description: "your new email address", example: "admin@lucidcms.io" }).optional(), currentPassword: z14.string().meta({ description: "Your current password", example: "password" }).optional(), newPassword: z14.string().min(8).max(128).meta({ description: "Your new password", example: "password123" }).optional(), passwordConfirmation: z14.string().min(8).max(128).meta({ description: "A repeat of your new password", example: "password123" }).optional() }), query: { string: void 0, formatted: void 0 }, params: void 0, response: void 0 } }; // src/libs/fastify/controllers/account/update-me.ts var updateMeController = async (request, reply) => { const updateMe2 = await service_wrapper_default( request.server.services.account.updateMe, { transaction: true, defaultError: { type: "basic", name: translations_default("route_user_me_update_error_name"), message: translations_default("route_user_me_update_error_message") } } )( { db: request.server.config.db.client, config: request.server.config, services: request.server.services }, { auth: request.auth, firstName: request.body.firstName, lastName: request.body.lastName, username: request.body.username, email: request.body.email, currentPassword: request.body.currentPassword, newPassword: request.body.newPassword, passwordConfirmation: request.body.passwordConfirmation } ); if (updateMe2.error) throw new lucid_api_error_default(updateMe2.error); reply.status(204).send(); }; var update_me_default = { controller: updateMeController, zodSchema: controllerSchemas5.updateMe, swaggerSchema: { description: "Update the authenticated user's information.", tags: ["account"], summary: "Update Authenticated User", headers: swagger_headers_default({ csrf: true }), body: z15.toJSONSchema(controllerSchemas5.updateMe.body), response: swagger_response_default({ noProperties: true }) } }; // src/libs/fastify/controllers/account/get-me.ts import z16 from "zod"; var getMeController = async (request, reply) => { const user = await service_wrapper_default(request.server.services.user.getSingle, { transaction: false, defaultError: { type: "basic", name: translations_default("route_user_fetch_error_name"), message: translations_default("route_user_fetch_error_message") } })( { db: request.server.config.db.client, config: request.server.config, services: request.server.services }, { userId: request.auth.id } ); if (user.error) throw new lucid_api_error_default(user.error); reply.status(200).send( build_response_default(request, { data: user.data }) ); }; var get_me_default = { controller: getMeController, zodSchema: controllerSchemas5.getMe, swaggerSchema: { description: "Returns the authenticated user based on the access token.", tags: ["account"], summary: "Get Authenticated User", response: swagger_response_default({ schema: z16.toJSONSchema(controllerSchemas5.getMe.response) }) } }; // src/libs/fastify/controllers/account/send-reset-password.ts import z17 from "zod"; var sendResetPasswordController = async (request, reply) => { const resetPassword2 = await service_wrapper_default( request.server.services.account.sendResetPassword, { transaction: true, defaultError: { type: "basic", name: translations_default("route_send_password_reset_error_name"), message: translations_default("route_send_password_reset_error_message") } } )( { db: request.server.config.db.client, config: request.server.config, services: request.server.services }, { email: request.body.email } ); if (resetPassword2.error) throw new lucid_api_error_default(resetPassword2.error); reply.status(200).send( build_response_default(request, { data: resetPassword2.data }) ); }; var send_reset_password_default = { controller: sendResetPasswordController, zodSchema: controllerSchemas5.sendResetPassword, swaggerSchema: { description: "Sends an email to the given email address informing them to reset their password.", tags: ["account"], summary: "Send Password Reset", headers: swagger_headers_default({ csrf: true }), body: z17.toJSONSchema(controllerSchemas5.sendResetPassword.body), response: swagger_response_default({ schema: z17.toJSONSchema(controllerSchemas5.sendResetPassword.response) }) } }; // src/libs/fastify/controllers/account/verify-reset-password.ts import z18 from "zod"; var verifyResetPasswordController = async (request, reply) => { const token = await service_wrapper_default( request.server.services.user.token.getSingle, { transaction: false, defaultError: { type: "basic", name: translations_default("route_verify_password_reset_error_name"), message: translations_default("route_verify_password_reset_error_message") } } )( { db: request.server.config.db.client, config: request.server.config, services: request.server.services }, { tokenType: "password_reset", token: request.params.token } ); if (token.error) throw new lucid_api_error_default(token.error); reply.status(204).send(); }; var verify_reset_password_default = { controller: verifyResetPasswordController, zodSchema: controllerSchemas5.verifyResetPassword, swaggerSchema: { description: "Verifies the password reset token is valid.", tags: ["account"], summary: "Verify Reset Token", params: z18.toJSONSchema(controllerSchemas5.verifyResetPassword.params), response: swagger_response_default({ noProperties: true }) } }; // src/libs/fastify/controllers/account/reset-password.ts import z19 from "zod"; var resetPasswordController = async (request, reply) => { const resetPassword2 = await service_wrapper_default( request.server.services.account.resetPassword, { transaction: true, defaultError: { type: "basic", name: translations_default("route_reset_password_error_name"), message: translations_default("route_reset_password_error_message") } } )( { db: reques