UNPKG

@lucidcms/core

Version:

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

1,857 lines (1,832 loc) 49.8 kB
import { constants_default, lucid_error_default, translations_default } from "./chunk-ZMWDUGJW.js"; // src/utils/media/create-cdn-url.ts var createCdnUrl = (host, key) => `${host}/cdn/v1/${key}`; var create_cdn_url_default = createCdnUrl; // src/utils/media/choose-accept-header-format.ts var chooseAcceptHeaderFormat = (accept, queryFormat) => { if (queryFormat) return queryFormat; if (accept) { if (accept.includes("image/webp")) return "webp"; if (accept.includes("image/avif")) return "avif"; } return void 0; }; var choose_accept_header_format_default = chooseAcceptHeaderFormat; // src/utils/media/generate-process-key.ts var generateProcessKey = (data) => { const [targetK, ext] = data.key.split("."); let key = `processed/${targetK}`; if (data.options.quality) key = key.concat(`-${data.options.quality}`); if (data.options.width) key = key.concat(`-${data.options.width}`); if (data.options.height) key = key.concat(`-${data.options.height}`); if (data.options.format) key = key.concat(`.${data.options.format}`); else key = key.concat(`.${ext}`); return key; }; var generate_process_key_default = generateProcessKey; // src/libs/formatters/user-permissions.ts var UserPermissionsFormatter = class { formatMultiple = (props) => { if (!props.roles) { return { roles: [], permissions: [] }; } const permissionsSet = /* @__PURE__ */ new Set(); for (const role of props.roles) { if (!role.permissions) continue; for (const permission of role.permissions) { permissionsSet.add(permission.permission); } } return { roles: props.roles.map(({ id, name }) => ({ id, name })), permissions: Array.from(permissionsSet) }; }; static swaggerPermissions = { type: "array", items: { type: "string", example: "create_user" } }; static swaggerRoles = { type: "array", items: { type: "object", properties: { id: { type: "number", example: 1 }, name: { type: "string", example: "Admin" } } } }; }; // src/libs/formatters/users.ts var UsersFormatter = class { formatMultiple = (props) => { return props.users.map( (u) => this.formatSingle({ user: u }) ); }; formatSingle = (props) => { const { roles, permissions } = new UserPermissionsFormatter().formatMultiple({ roles: props.user.roles || [] }); return { id: props.user.id, superAdmin: props.user.super_admin ?? 0, email: props.user.email, username: props.user.username, firstName: props.user.first_name, lastName: props.user.last_name, roles, permissions, triggerPasswordReset: props.user.triggered_password_reset, createdAt: formatters_default.formatDate(props.user.created_at), updatedAt: formatters_default.formatDate(props.user.updated_at) }; }; static swagger = { type: "object", properties: { id: { type: "number", example: 1 }, superAdmin: { type: "number", example: 1 }, email: { type: "string", example: "admin@lucidcms.io" }, username: { type: "string", example: "admin" }, firstName: { type: "string", example: "Admin" }, lastName: { type: "string", example: "User" }, triggerPasswordReset: { type: "number", example: 0 }, roles: UserPermissionsFormatter.swaggerRoles, permissions: UserPermissionsFormatter.swaggerPermissions, createdAt: { type: "string", example: "2021-06-10T20:00:00.000Z" }, updatedAt: { type: "string", example: "2021-06-10T20:00:00.000Z" } } }; }; // src/libs/formatters/roles.ts var RolesFormatter = class { formatMultiple = (props) => { return props.roles.map( (r) => this.formatSingle({ role: r }) ); }; formatSingle = (props) => { return { id: props.role.id, name: props.role.name, description: props.role.description, permissions: props.role.permissions?.map((p) => { return { id: p.id, permission: p.permission }; }), createdAt: formatters_default.formatDate(props.role.created_at), updatedAt: formatters_default.formatDate(props.role.updated_at) }; }; static swagger = { type: "object", properties: { id: { type: "number" }, name: { type: "string", example: "Admin" }, description: { type: "string", example: "Admin role description" }, permissions: { type: "array", example: [ { id: 1, permission: "create_role" }, { id: 2, permission: "update_role" } ], items: { type: "object", properties: { id: { type: "number" }, permission: { type: "string" } } } }, createdAt: { type: "string", example: "2021-06-10T20:00:00.000Z" }, updatedAt: { type: "string", example: "2021-06-10T20:00:00.000Z" } } }; }; // src/libs/formatters/settings.ts var SettingsFormatter = class { formatSingle = (props) => { return { email: { enabled: props.config.email !== void 0, from: props.config.email?.from ?? null }, media: { enabled: props.config.media?.strategy !== void 0, storage: { total: props.config.media.storage, remaining: props.config.media.storage - props.settings.mediaStorageUsed, used: props.settings.mediaStorageUsed, limit: props.config.media.storage }, processed: { stored: props.config.media.processed.store, imageLimit: props.config.media.processed.limit, total: props.settings.processedImageCount } } }; }; static swagger = { type: "object", properties: { email: { type: "object", properties: { enabled: { type: "boolean" }, from: { type: "object", nullable: true, properties: { email: { type: "string" }, name: { type: "string" } } } } }, media: { type: "object", properties: { enabled: { type: "boolean" }, storage: { type: "object", properties: { total: { type: "number" }, remaining: { type: "number", nullable: true }, used: { type: "number", nullable: true }, limit: { type: "number", nullable: true } } }, processed: { type: "object", properties: { stored: { type: "boolean" }, imageLimit: { type: "number" }, total: { type: "number", nullable: true } } } } } } }; }; // src/libs/formatters/permissions.ts var PermissionsFormatter = class { formatMultiple = (props) => { return Object.values(props.permissions); }; static swagger = { type: "object", properties: { key: { type: "string", example: "users_permissions" }, permissions: { type: "array", example: ["create_user", "update_user", "delete_user"] } } }; }; // src/libs/formatters/options.ts var OptionsFormatter = class { formatSingle = (props) => { return { name: props.option.name, valueText: props.option.value_text, valueInt: props.option.value_int, valueBool: props.option.value_bool }; }; }; // src/libs/formatters/media.ts var MediaFormatter = class { formatMultiple = (props) => { return props.media.map( (m) => this.formatSingle({ media: m, host: props.host }) ); }; formatSingle = (props) => { return { id: props.media.id, key: props.media.key, url: create_cdn_url_default(props.host, props.media.key), title: props.media.title_translations?.map((t) => ({ value: t.value, localeCode: t.locale_code })) ?? [], alt: props.media.alt_translations?.map((t) => ({ value: t.value, localeCode: t.locale_code })) ?? [], type: props.media.type, meta: { mimeType: props.media.mime_type, extension: props.media.file_extension, fileSize: props.media.file_size, width: props.media.width, height: props.media.height, blurHash: props.media.blur_hash, averageColour: props.media.average_colour, isDark: props.media.is_dark, isLight: props.media.is_light }, createdAt: formatters_default.formatDate(props.media.created_at), updatedAt: formatters_default.formatDate(props.media.updated_at) }; }; static swagger = { type: "object", properties: { id: { type: "number", example: 1 }, key: { type: "string", example: "placeholder-1708786317482" }, url: { type: "string", example: "https://example.com/cdn/v1/key" }, title: { type: "array", items: { type: "object", properties: { localeCode: { type: "string", example: "en" }, value: { type: "string" } } } }, alt: { type: "array", items: { type: "object", properties: { localeCode: { type: "string", example: "en" }, value: { type: "string" } } } }, type: { type: "string", example: "image" }, meta: { type: "object", properties: { mimeType: { type: "string", example: "image/jpeg" }, extension: { type: "string", example: "jpeg" }, fileSize: { type: "number", example: 100 }, width: { type: "number", example: 100, nullable: true }, height: { type: "number", example: 100, nullable: true }, blurHash: { type: "string", example: "AQABAAAABAAAAgAA...", nullable: true }, averageColour: { type: "string", example: "rgba(255, 255, 255, 1)", nullable: true }, isDark: { type: "number", example: 1, nullable: true }, isLight: { type: "number", example: 1, nullable: true } } }, createdAt: { type: "string", example: "2022-01-01T00:00:00Z" }, updatedAt: { type: "string", example: "2022-01-01T00:00:00Z" } } }; static presignedUrlSwagger = { type: "object", properties: { url: { type: "string", example: "https://example.com/cdn/v1/key" }, key: { type: "string", example: "2024/09/5ttogd-placeholder-image.png" } } }; }; // src/libs/formatters/locales.ts var LocalesFormatter = class { formatMultiple = (props) => { return props.locales.map((l) => { const configLocale = props.localisation.locales.find( (locale) => locale.code === l.code ); if (!configLocale) { return null; } return this.formatSingle({ locale: l, configLocale, defaultLocale: props.localisation.defaultLocale }); }).filter((l) => l !== null); }; formatSingle = (props) => { return { code: props.locale.code, name: props.configLocale.label, isDefault: props.locale.code === props.defaultLocale ? 1 : 0, createdAt: formatters_default.formatDate(props.locale.created_at), updatedAt: formatters_default.formatDate(props.locale.updated_at) }; }; static swagger = { type: "object", properties: { code: { type: "string", example: "en" }, name: { type: "string", example: "English" }, isDefault: { type: "number", example: 1 }, createdAt: { type: "string", example: "2021-10-05T14:48:00.000Z" }, updatedAt: { type: "string", example: "2021-10-05T14:48:00.000Z" } } }; }; // src/libs/formatters/emails.ts var EmailsFormatter = class { formatMultiple = (props) => { return props.emails.map( (e) => this.formatSingle({ email: e }) ); }; formatSingle = (props) => { return { id: props.email.id, emailHash: props.email.email_hash, type: props.email.type, deliveryStatus: props.email.delivery_status, mailDetails: { from: { address: props.email.from_address, name: props.email.from_name }, to: props.email.to_address, subject: props.email.subject, cc: props.email.cc, bcc: props.email.bcc, template: props.email.template }, data: props.email.data ?? null, sentCount: props.email.sent_count || 0, errorCount: props.email.error_count || 0, errorMessage: props.email.last_error_message, html: props.html ?? null, lastSuccessAt: formatters_default.formatDate(props.email.last_success_at), lastAttemptAt: formatters_default.formatDate(props.email.last_attempt_at), createdAt: formatters_default.formatDate(props.email.created_at) }; }; static swagger = { type: "object", properties: { id: { type: "number" }, emailHash: { type: "string" }, type: { type: "string", enum: ["external", "internal"] }, deliveryStatus: { type: "string", enum: ["sent", "failed", "pending"] }, mailDetails: { type: "object", properties: { from: { type: "object", properties: { address: { type: "string" }, name: { type: "string" } } }, to: { type: "string" }, subject: { type: "string" }, cc: { type: "string", nullable: true }, bcc: { type: "string", nullable: true }, template: { type: "string" } } }, data: { type: "object", nullable: true, additionalProperties: true }, sentCount: { type: "number" }, errorCount: { type: "number" }, errorMessage: { type: "string", nullable: true }, html: { type: "string", nullable: true }, lastSuccessAt: { type: "string", nullable: true }, lastAttemptAt: { type: "string", nullable: true }, createdAt: { type: "string", nullable: true } } }; }; // src/libs/formatters/collections.ts import "zod"; var CollectionsFormatter = class { formatMultiple = (props) => { return props.collections.map( (c) => this.formatSingle({ collection: c, include: props.include, documents: props.documents }) ); }; formatSingle = (props) => { const collectionData = props.collection.getData; const key = props.collection.key; return { key, mode: collectionData.mode, documentId: props.include?.document_id ? this.getDocumentId(key, props.documents) : void 0, details: { name: collectionData.details.name, singularName: collectionData.details.singularName, summary: collectionData.details.summary }, config: { useTranslations: collectionData.config.useTranslations, useDrafts: collectionData.config.useDrafts, useRevisions: collectionData.config.useRevisions, isLocked: collectionData.config.isLocked, fieldIncludes: props.collection.includeFieldKeys, fieldFilters: props.collection.filterableFieldKeys.map((f) => f.key) }, fixedBricks: props.include?.bricks ? props.collection.fixedBricks ?? [] : [], builderBricks: props.include?.bricks ? props.collection.builderBricks ?? [] : [], fields: props.include?.fields ? props.collection.fieldTree ?? [] : [] }; }; getDocumentId = (collectionKey, documents) => { const document = documents?.find( (document2) => document2.collection_key === collectionKey ); return document?.id ?? void 0; }; static swaggerFieldsConfig = { type: "object", additionalProperties: true, properties: { type: { type: "string" }, key: { type: "string" }, collection: { type: "string", nullable: true }, details: { type: "object", additionalProperties: true, properties: { label: { type: ["object", "string"], additionalProperties: true }, summary: { type: ["object", "string"], additionalProperties: true }, placeholder: { type: ["object", "string"], additionalProperties: true }, true: { type: ["object", "string"], additionalProperties: true }, false: { type: ["object", "string"], additionalProperties: true } } }, config: { type: "object", additionalProperties: true, properties: { isHidden: { type: "boolean", nullable: true }, isDisabled: { type: "boolean", nullable: true }, useTranslations: { type: "boolean", nullable: true } } }, fields: { type: "array", items: { type: "object", additionalProperties: true } } } }; static swaggerBricksConfig = { type: "object", additionalProperties: true, properties: { key: { type: "string" }, details: { type: "object", properties: { name: { type: ["object", "string"], additionalProperties: true }, summary: { type: ["object", "string"], additionalProperties: true, nullable: true } } }, preview: { type: "object", additionalProperties: true, properties: { image: { type: "string" } } }, fields: { type: "array", items: this.swaggerFieldsConfig } } }; static swagger = { type: "object", properties: { key: { type: "string", example: "pages" }, mode: { type: "string", example: "single" }, documentId: { type: "number", example: 1, nullable: true }, details: { type: "object", properties: { name: { type: ["object", "string"], additionalProperties: true }, singularName: { type: ["object", "string"], additionalProperties: true }, summary: { type: ["object", "string"], additionalProperties: true, nullable: true } } }, config: { type: "object", properties: { useTranslations: { type: "boolean", example: false }, useDrafts: { type: "boolean", nullable: true }, useRevisions: { type: "boolean", nullable: true }, isLocked: { type: "boolean", nullable: true }, fieldIncludes: { type: "array", items: { type: "string" } }, fieldFilters: { type: "array", items: { type: "string" } } } }, fixedBricks: { type: "array", items: this.swaggerBricksConfig }, builderBricks: { type: "array", items: this.swaggerBricksConfig }, fields: { type: "array", items: this.swaggerFieldsConfig } } }; }; // src/libs/formatters/collection-document-fields.ts var CollectionDocumentFieldsFormatter = class { formatMultiple = (data, meta) => { const fieldConfigTree = meta.builder.fieldTreeNoTab; const sortedGroups = data.groups.sort( (a, b) => a.group_order - b.group_order ); return this.buildFieldTree( { fields: data.fields, groups: sortedGroups }, { builder: meta.builder, fieldConfig: fieldConfigTree, host: meta.host, localisation: meta.localisation, collectionTranslations: meta.collectionTranslations, groupId: null, parentGroupId: null, collections: meta.collections } ); }; formatMultipleFlat = (data, meta) => { if (data.fields.length === 0) return []; const fieldsRes = []; const flatFields = meta.builder.flatFields; for (const fieldConfig of flatFields) { const fieldData = data.fields.filter((f) => f.key === fieldConfig.key).filter((f) => { if (f.type === "repeater") return false; if (f.type === "tab") return false; return true; }); if (fieldData.length === 0) continue; const field = this.buildField( { fields: fieldData }, { builder: meta.builder, fieldConfig, host: meta.host, includeGroupId: true, collectionTranslations: meta.collectionTranslations, localisation: meta.localisation, collections: meta.collections } ); if (field) fieldsRes.push(field); } return fieldsRes; }; // Helpers objectifyFields = (fields) => { return fields.reduce( (acc, field) => { if (!field) return acc; acc[field.key] = { ...field, groups: field.groups?.map((g) => { return { ...g, fields: this.objectifyFields(g.fields || []) }; }) }; return acc; }, {} ); }; // Private methods buildFieldTree = (data, meta) => { const fieldsRes = []; for (const config of meta.fieldConfig) { if (config.type === "repeater") { fieldsRes.push({ key: config.key, type: config.type, groups: this.buildGroups( { fields: data.fields, groups: data.groups }, { builder: meta.builder, repeaterConfig: config, host: meta.host, parentGroupId: meta.groupId, localisation: meta.localisation, collectionTranslations: meta.collectionTranslations, collections: meta.collections } ) }); continue; } const fields = data.fields.filter( (f) => f.key === config.key && f.group_id === meta.groupId ); if (!fields) continue; if (fields.length === 0) continue; const field = this.buildField( { fields }, { builder: meta.builder, fieldConfig: config, host: meta.host, includeGroupId: true, localisation: meta.localisation, collectionTranslations: meta.collectionTranslations, collections: meta.collections } ); if (field) fieldsRes.push(field); } return fieldsRes; }; buildField = (data, meta) => { if (meta.fieldConfig.type !== "repeater" && meta.fieldConfig.type !== "tab" && meta.fieldConfig.config.useTranslations === true && meta.collectionTranslations === true) { return this.addEmptyLocales( { field: this.reduceFieldLocales(data, meta) }, { fieldConfig: meta.fieldConfig, host: meta.host, localisation: meta.localisation } ); } const defaultField = data.fields.find( (f) => f.locale_code === meta.localisation.default ); if (!defaultField) return null; const cfInstance = meta.builder.fields.get(meta.fieldConfig.key); if (!cfInstance) return null; return { key: meta.fieldConfig.key, type: meta.fieldConfig.type, groupId: meta.includeGroupId ? defaultField.group_id ?? void 0 : void 0, ...cfInstance.responseValueFormat({ data: defaultField, formatMeta: meta }) }; }; buildGroups = (data, meta) => { const groups = []; const repeaterFields = meta.repeaterConfig.fields; if (!repeaterFields) return groups; const repeaterGroups = data.groups.filter( (g) => g.repeater_key === meta.repeaterConfig.key && g.parent_group_id === meta.parentGroupId ); for (const group of repeaterGroups) { groups.push({ id: group.group_id, order: group.group_order, open: group.group_open, fields: this.buildFieldTree( { fields: data.fields, groups: data.groups }, { builder: meta.builder, fieldConfig: repeaterFields, host: meta.host, groupId: group.group_id, parentGroupId: group.parent_group_id, collectionTranslations: meta.collectionTranslations, localisation: meta.localisation, collections: meta.collections } ) }); } return groups; }; reduceFieldLocales = (data, meta) => { return data.fields.reduce( (acc, field) => { const cfInstance = meta.builder.fields.get(meta.fieldConfig.key); if (!cfInstance) return acc; if (acc.translations === void 0) acc.translations = {}; if (acc.meta === void 0 || acc.meta === null) acc.meta = {}; if (meta.includeGroupId) acc.groupId = field.group_id ?? void 0; const fieldRes = cfInstance.responseValueFormat({ data: field, formatMeta: meta }); acc.translations[field.locale_code] = fieldRes.value; acc.meta[field.locale_code] = fieldRes.meta; return acc; }, { key: meta.fieldConfig.key, type: meta.fieldConfig.type } ); }; addEmptyLocales = (data, meta) => { if (data.field.translations === void 0) data.field.translations = {}; if (data.field.meta === void 0) data.field.meta = {}; const emptyLocales = meta.localisation.locales.filter( (l) => !data.field.translations[l] ); for (const locale of emptyLocales) { data.field.translations[locale] = meta.fieldConfig.config.default ?? null; data.field.meta[locale] = null; } return data.field; }; static swagger = { type: "object", additionalProperties: true, properties: { key: { type: "string" }, type: { type: "string", enum: [ "tab", "text", "wysiwyg", "media", "number", "checkbox", "select", "textarea", "json", "colour", "datetime", "link", "repeater", "user" ] }, groupId: { type: "number", nullable: true }, collectionDocumentId: { type: "number" }, translations: { type: "object", additionalProperties: true }, value: {}, meta: { type: "object", additionalProperties: true, nullable: true, properties: { id: { type: "number", nullable: true }, url: { type: "string", nullable: true }, key: { type: "string", nullable: true }, mimeType: { type: "string", nullable: true }, extension: { type: "string", nullable: true }, fileSize: { type: "number", nullable: true }, width: { type: "number", nullable: true }, height: { type: "number", nullable: true }, blurHash: { type: "string", nullable: true }, averageColour: { type: "string", nullable: true }, isDark: { type: "number", nullable: true }, isLight: { type: "number", nullable: true }, title: { type: "object", additionalProperties: true }, alt: { type: "object", additionalProperties: true }, type: { type: "string", nullable: true, enum: ["image", "video", "audio", "document"] }, email: { type: "string", nullable: true }, username: { type: "string", nullable: true }, firstName: { type: "string", nullable: true }, lastName: { type: "string", nullable: true }, fields: { type: "object", additionalProperties: true, nullable: true } } }, groups: { type: "array", items: { type: "object", additionalProperties: true, properties: { id: { type: "number" }, order: { type: "number" }, open: { type: "number", nullable: true }, fields: { type: "array", items: { type: "object", additionalProperties: true } } } } } } }; }; // src/libs/formatters/collection-document-bricks.ts var CollectionDocumentBricksFormatter = class { formatMultiple = (props) => { const CollectionDocumentFieldsFormatter2 = formatters_default.get( "collection-document-fields" ); return props.bricks.filter((brick) => { if (brick.brick_type === constants_default.brickTypes.collectionFields) return false; const builder = props.collection.brickInstances.find((b) => { return b.key === brick.brick_key; }); if (!builder) return false; return true; }).map((brick) => { const builder = props.collection.brickInstances.find((b) => { return b.key === brick.brick_key; }); return { id: brick.id, key: brick.brick_key, order: brick.brick_order, type: brick.brick_type, open: brick.brick_open, fields: CollectionDocumentFieldsFormatter2.formatMultiple( { fields: brick.fields, groups: brick.groups }, { host: props.config.host, builder, localisation: { locales: props.config.localisation.locales.map((l) => l.code), default: props.config.localisation.defaultLocale }, collectionTranslations: props.collection.getData.config.useTranslations, collections: props.config.collections } ) }; }); }; formatCollectionPseudoBrick = (props) => { const CollectionDocumentFieldsFormatter2 = formatters_default.get( "collection-document-fields" ); return props.bricks.filter((brick) => { if (brick.brick_type !== constants_default.brickTypes.collectionFields) return false; return true; }).flatMap( (brick) => CollectionDocumentFieldsFormatter2.formatMultiple( { fields: brick.fields, groups: brick.groups }, { host: props.config.host, builder: props.collection, collectionTranslations: props.collection.getData.config.useTranslations, localisation: { locales: props.config.localisation.locales.map((l) => l.code), default: props.config.localisation.defaultLocale }, collections: props.config.collections } ) ); }; static swagger = { type: "object", additionalProperties: true, properties: { id: { type: "number" }, key: { type: "string" }, order: { type: "number" }, open: { type: "number", nullable: true }, type: { type: "string", enum: ["builder", "fixed"] }, fields: { type: "array", items: CollectionDocumentFieldsFormatter.swagger } } }; }; // src/libs/formatters/collection-documents.ts var CollectionDocumentsFormatter = class _CollectionDocumentsFormatter { formatMultiple = (props) => { return props.documents.map( (d) => this.formatSingle({ document: d, collection: props.collection, config: props.config }) ); }; formatSingle = (props) => { let fields = props.fields ?? null; const FieldsFormatter = formatters_default.get("collection-document-fields"); if (fields === null && props.document.fields) { if (props.document.groups) { fields = FieldsFormatter.formatMultiple( { fields: props.document.fields, groups: props.document.groups }, { host: props.config.host, builder: props.collection, collectionTranslations: props.collection.getData.config.useTranslations, localisation: { locales: props.config.localisation.locales.map((l) => l.code), default: props.config.localisation.defaultLocale }, collections: props.config.collections } ); } else { fields = FieldsFormatter.formatMultipleFlat( { fields: props.document.fields }, { host: props.config.host, builder: props.collection, collectionTranslations: props.collection.getData.config.useTranslations, localisation: { locales: props.config.localisation.locales.map((l) => l.code), default: props.config.localisation.defaultLocale }, collections: props.config.collections } ); } } return { id: props.document.id, collectionKey: props.document.collection_key, status: props.document.version_type ?? null, versionId: props.document.version_id ?? null, version: this.formatVersion({ document: props.document }), bricks: props.bricks ?? null, fields, createdBy: props.document.cb_user_id ? { id: props.document.cb_user_id, email: props.document.cb_user_email ?? null, firstName: props.document.cb_user_first_name ?? null, lastName: props.document.cb_user_last_name ?? null, username: props.document.cb_user_username ?? null } : null, updatedBy: props.document.ub_user_id ? { id: props.document.ub_user_id, email: props.document.ub_user_email ?? null, firstName: props.document.ub_user_first_name ?? null, lastName: props.document.ub_user_last_name ?? null, username: props.document.ub_user_username ?? null } : null, createdAt: formatters_default.formatDate(props.document.created_at), updatedAt: formatters_default.formatDate(props.document.updated_at) }; }; formatVersion = (props) => { const draftVersion = props.document.versions?.find( (v) => v.version_type === "draft" ); const publishedVersion = props.document.versions?.find( (v) => v.version_type === "published" ); return { draft: draftVersion?.id ? { id: draftVersion.id, promotedFrom: draftVersion.promoted_from, createdAt: formatters_default.formatDate(draftVersion.created_at), createdBy: draftVersion.created_by } : null, published: publishedVersion?.id ? { id: publishedVersion.id, promotedFrom: publishedVersion.promoted_from, createdAt: formatters_default.formatDate(publishedVersion.created_at), createdBy: publishedVersion.created_by } : null }; }; // Client formatClientMultiple = (props) => { return props.documents.map( (d) => this.formatClientSingle({ document: d, collection: props.collection, config: props.config }) ); }; formatClientSingle = (props) => { const FieldsFormatter = formatters_default.get("collection-document-fields"); const res = this.formatSingle({ document: props.document, collection: props.collection, bricks: props.bricks, fields: props.fields, config: props.config }); return { ...res, bricks: res.bricks !== null ? res.bricks.map((b) => { return { ...b, fields: FieldsFormatter.objectifyFields(b.fields) }; }) : null, fields: res.fields !== null ? FieldsFormatter.objectifyFields(res.fields) : null }; }; static swagger = { type: "object", properties: { id: { type: "number" }, versionId: { type: "number", nullable: true }, collectionKey: { type: "string", nullable: true }, status: { type: "string", nullable: true, enum: ["published", "draft", "revision"] }, version: { type: "object", properties: { draft: { type: "object", properties: { id: { type: "number", nullable: true }, promotedFrom: { type: "number", nullable: true }, createdAt: { type: "string", nullable: true }, createdBy: { type: "number", nullable: true } }, nullable: true }, published: { type: "object", properties: { id: { type: "number", nullable: true }, promotedFrom: { type: "number", nullable: true }, createdAt: { type: "string", nullable: true }, createdBy: { type: "number", nullable: true } }, nullable: true } } }, bricks: { type: "array", items: CollectionDocumentBricksFormatter.swagger, nullable: true }, fields: { type: "array", nullable: true, items: CollectionDocumentFieldsFormatter.swagger }, createdBy: { type: "object", nullable: true, properties: { id: { type: "number" }, email: { type: "string", nullable: true }, firstName: { type: "string", nullable: true }, lastName: { type: "string", nullable: true }, username: { type: "string", nullable: true } } }, createdAt: { type: "string", nullable: true }, updatedAt: { type: "string", nullable: true }, updatedBy: { type: "object", nullable: true, properties: { id: { type: "number" }, email: { type: "string", nullable: true }, firstName: { type: "string", nullable: true }, lastName: { type: "string", nullable: true }, username: { type: "string", nullable: true } } } } }; static swaggerClient = { type: "object", properties: { ..._CollectionDocumentsFormatter.swagger.properties, bricks: { type: "array", nullable: true, items: { type: "object", additionalProperties: true, properties: { ...CollectionDocumentBricksFormatter.swagger.properties, fields: { type: "object", additionalProperties: true } } } }, fields: { type: "object", nullable: true, additionalProperties: true } } }; }; // src/libs/formatters/collection-document-versions.ts var CollectionDocumentVersions = class { formatMultiple = (props) => { return props.versions.map( (v) => this.formatSingle({ version: v }) ); }; formatSingle = (props) => { return { id: props.version.id, versionType: props.version.version_type, promotedFrom: props.version.promoted_from ?? null, createdAt: formatters_default.formatDate(props.version.created_at), createdBy: props.version.created_by ?? null, document: { id: props.version.document_id ?? null, collectionKey: props.version.collection_key, createdBy: props.version.document_created_by ?? null, createdAt: formatters_default.formatDate(props.version.document_created_at), updatedAt: formatters_default.formatDate(props.version.document_updated_at), updatedBy: props.version.document_updated_by ?? null }, bricks: props.version.bricks.reduce( (acc, brick) => { if (!acc[brick.brick_type]) { acc[brick.brick_type] = []; } acc[brick.brick_type].push({ id: brick.id, brickKey: brick.brick_key, fields: typeof brick.field_count === "number" ? brick.field_count : 0 }); return acc; }, {} ) }; }; static swagger = { type: "object", properties: { id: { type: "number" }, versionType: { type: "string", nullable: true, enum: ["published", "draft", "revision"] }, promotedFrom: { type: "number", nullable: true }, createdAt: { type: "string", nullable: true }, createdBy: { type: "number", nullable: true }, bricks: { type: "object", nullable: true, additionalProperties: { type: "array", items: { type: "object", properties: { id: { type: "number" }, brickKey: { type: "string", nullable: true }, fields: { type: "number" } } } } }, document: { type: "object", nullable: true, properties: { id: { type: "number" }, collectionKey: { type: "string", nullable: true }, createdBy: { type: "number", nullable: true }, createdAt: { type: "string", nullable: true }, updatedAt: { type: "string", nullable: true }, updatedBy: { type: "number", nullable: true } } } } }; }; // src/libs/formatters/client-integrations.ts var ClientIntegrationsFormatter = class { formatMultiple = (props) => { return props.integrations.map( (i) => this.formatSingle({ integration: i }) ); }; formatSingle = (props) => { return { id: props.integration.id, key: props.integration.key, name: props.integration.name, description: props.integration.description, enabled: props.integration.enabled, createdAt: formatters_default.formatDate(props.integration.created_at), updatedAt: formatters_default.formatDate(props.integration.updated_at) }; }; static swagger = { type: "object", additionalProperties: true, properties: { id: { type: "number" }, key: { type: "string" }, name: { type: "string" }, description: { type: "string" }, enabled: { type: "number" }, createdAt: { type: "string" }, updatedAt: { type: "string" } } }; }; // src/libs/formatters/index.ts var Formatter = class { static get(format) { switch (format) { case "users": return new UsersFormatter(); case "user-permissions": return new UserPermissionsFormatter(); case "settings": return new SettingsFormatter(); case "roles": return new RolesFormatter(); case "permissions": return new PermissionsFormatter(); case "options": return new OptionsFormatter(); case "media": return new MediaFormatter(); case "locales": return new LocalesFormatter(); case "emails": return new EmailsFormatter(); case "collections": return new CollectionsFormatter(); case "collection-documents": return new CollectionDocumentsFormatter(); case "collection-document-bricks": return new CollectionDocumentBricksFormatter(); case "collection-document-fields": return new CollectionDocumentFieldsFormatter(); case "collection-document-versions": return new CollectionDocumentVersions(); case "client-integrations": return new ClientIntegrationsFormatter(); default: throw new lucid_error_default({ message: translations_default("cannot_find_formatter", { name: format }) }); } } // helpers static formatDate = (date) => { if (typeof date === "string") { return date; } return date ? date.toISOString() : null; }; static parseJSON = (json) => { if (typeof json === "object") return json; if (!json) return null; try { return JSON.parse(json); } catch (error) { return null; } }; static stringifyJSON = (json) => { try { if (!json) return null; return JSON.stringify(json); } catch (error) { return null; } }; static parseCount = (count) => { return Number.parseInt(count || "0") || 0; }; }; var formatters_default = Formatter; // src/utils/translations/objectify-translations.ts var objectifyTranslations = (values, locales) => { return locales.reduce((acc, locale) => { const value = values.find((v) => v.locale_code === locale); if (!value) { acc[locale] = ""; } else { acc[locale] = value.value ?? ""; } return acc; }, {}); }; var objectify_translations_default = objectifyTranslations; // src/utils/translations/remove-duplicates.ts var removeDuplicates = (translations) => translations.filter( (translation, index, self) => index === self.findIndex((t) => t.localeCode === translation.localeCode) ); var remove_duplicates_default = removeDuplicates; // src/utils/translations/merge-translation-groups.ts var mergeTranslationGroups = (items) => { const translations = []; for (const item of items) { const itemTranslations = remove_duplicates_default(item.translations); for (const translation of itemTranslations) { translations.push({ ...translation, key: item.key }); } } return translations; }; var merge_translation_groups_default = mergeTranslationGroups; // src/utils/translations/get-unique-locale-codes.ts var getUniqueLocaleCodes = (items) => { const localeCodes = items.flatMap((t) => t.map((t2) => t2.localeCode)); return Array.from(new Set(localeCodes)); }; var get_unique_locale_codes_default = getUniqueLocaleCodes; // src/utils/translations/should-update-translations.ts var shouldUpdateTranslations = (item) => item.some((t) => t !== void 0 && t.length > 0); var should_update_translations_default = shouldUpdateTranslations; export { UsersFormatter, RolesFormatter, SettingsFormatter, PermissionsFormatter, choose_accept_header_format_default, generate_process_key_default, create_cdn_url_default, MediaFormatter, LocalesFormatter, EmailsFormatter, CollectionsFormatter, CollectionDocumentsFormatter, CollectionDocumentVersions, ClientIntegrationsFormatter, formatters_default, merge_translation_groups_default, get_unique_locale_codes_default, should_update_translations_default, objectify_translations_default }; //# sourceMappingURL=chunk-URI3PAN7.js.map