UNPKG

@lucidcms/plugin-pages

Version:

The official Pages plugin for Lucid

1,300 lines (1,273 loc) 41.4 kB
// src/translations/en-gb.json var en_gb_default = { cannot_find_collection: "Cannot find the collection of {{collection}}.", cannot_find_required_field_message: "Cannot find required fields for the pages plugin.", cannot_have_self_as_parent_page_message: "A page cannot be its own parent, please select a different parent page.", slug_cannot_be_slash_and_parent_page_set_message: "The slug cannot be / when a parent page is set.", duplicate_slug_field_found_message: "Please ensure the slug field is unique within the collection.", duplicate_slug_and_parent_page_field_found_message: "Another document in this collection has the same slug and parent page selected. Please ensure the slug field is unique within the collection.", an_unknown_error_occurred_checking_for_duplicate_slugs: "An error occurred while checking for duplicate slugs.", an_unknown_error_occurred_checking_for_circular_parents: "An error occurred while checking for circular parents.", circular_parents_error_message: "The selected page is either a child/grandchild of this one. Please select a different parent page.", parent_page_not_found_or_doesnt_have_a_published_version: "The parent page document of the same version (draft/published) was not found, or doesnt have a slug.", an_unknown_error_occurred_getting_parent_fields: "An error occurred while getting the parent page fields.", an_unknown_error_occurred_getting_descendant_fields: "An error occurred while getting the descendant page fields.", an_unknown_error_occurred_updating_fullslug_fields: "An error occurred while updating the fullSlug children fields.", slug_field_validation_error_message: "The slug field may only contain letters, numbers, underscores, and hyphens.", an_unknown_error_occurred_getting_document_version_fields: "An error occurred while getting the document version fields.", full_slug: "Full Slug", slug: "Slug", parent_page: "Parent Page", field_required: "This field is required." }; // src/translations/index.ts var selectedLang = en_gb_default; var T = (key, data) => { const translation = selectedLang[key]; if (!translation) { return key; } if (!data) { return translation; } return translation.replace( /\{\{(\w+)\}\}/g, (_, p1) => data[p1] ); }; var translations_default = T; // src/constants.ts var PLUGIN_KEY = "plugin-pages"; var LUCID_VERSION = "0.x.x"; var constants_default = { collectionFieldBrickId: "collection-pseudo-brick", fields: { parentPage: { key: "parentPage" }, slug: { key: "slug" }, fullSlug: { key: "fullSlug" } } }; // src/plugin.ts import { logger } from "@lucidcms/core"; // src/services/register-fields.ts import { z } from "@lucidcms/core"; var registerFields = (collection, config) => { collection.addText(constants_default.fields.fullSlug.key, { details: { label: translations_default("full_slug") }, config: { useTranslations: config.useTranslations, isHidden: !config.displayFullSlug, isDisabled: true }, displayInListing: config.displayFullSlug }).addText(constants_default.fields.slug.key, { details: { label: translations_default("slug") }, config: { useTranslations: config.useTranslations, isHidden: false, isDisabled: false }, validation: { required: true, zod: z.union([ z.literal("/"), z.string().regex( /^[a-zA-Z0-9_-]+$/, translations_default("slug_field_validation_error_message") ) ]) }, displayInListing: true }).addDocument(constants_default.fields.parentPage.key, { collection: collection.key, details: { label: translations_default("parent_page") }, config: { isHidden: false, isDisabled: false } }); }; var register_fields_default = registerFields; // src/services/plugin-options.ts var pluginOptions = (given) => { return { collections: given.collections.map((c) => ({ collectionKey: c.collectionKey, useTranslations: c?.useTranslations ?? false, displayFullSlug: c?.displayFullSlug ?? false // fallbackSlugSource: c?.fallbackSlugSource ?? undefined, })) }; }; var plugin_options_default = pluginOptions; // src/services/get-target-collection.ts var getTargetCollection = (data) => { const targetCollection = data.options.collections.find( (c) => c.collectionKey === data.collectionKey ); if (!targetCollection) { return { error: { type: "basic", status: 500, message: translations_default("cannot_find_collection", { collection: data.collectionKey }) }, data: void 0 }; } return { error: void 0, data: targetCollection }; }; var get_target_collection_default = getTargetCollection; // src/services/get-parent-fields.ts import { prefixGeneratedColName } from "@lucidcms/core/helpers"; var getParentFields = async (context, data) => { try { const { version: versionTable, documentFields: fieldsTable } = data.tables; const slugColumn = prefixGeneratedColName(constants_default.fields.slug.key); const parentPageColumn = prefixGeneratedColName( constants_default.fields.parentPage.key ); const fullSlugColumn = prefixGeneratedColName( constants_default.fields.fullSlug.key ); const parentFields = await context.db.selectFrom(fieldsTable).innerJoin( versionTable, `${versionTable}.id`, `${fieldsTable}.document_version_id` ).select([ `${fieldsTable}.${slugColumn}`, `${fieldsTable}.${fullSlugColumn}`, `${fieldsTable}.${parentPageColumn}`, `${versionTable}.document_id`, `${fieldsTable}.locale` ]).where(`${versionTable}.document_id`, "=", data.fields.parentPage.value).where(`${versionTable}.type`, "=", data.versionType).execute(); if (!parentFields || parentFields.length === 0) { return { error: { type: "basic", status: 404, message: translations_default( "parent_page_not_found_or_doesnt_have_a_published_version" ), errorResponse: { body: { fields: [ { key: constants_default.fields.parentPage.key, localeCode: data.defaultLocale, message: translations_default( "parent_page_not_found_or_doesnt_have_a_published_version" ) } ] } } }, data: void 0 }; } return { error: void 0, data: parentFields }; } catch (error) { return { error: { type: "basic", status: 500, message: translations_default("an_unknown_error_occurred_getting_parent_fields") }, data: void 0 }; } }; var get_parent_fields_default = getParentFields; // src/utils/build-fullslug-from-fullslug.ts var buildFullSlug = (data) => { if (data.slug === null || data.slug === void 0) return null; let result = data.slug; const targetParentFullSlugField = data.parentFields.find((field) => { return field.locale === data.targetLocale; }); if (targetParentFullSlugField?._fullSlug) { result = `${targetParentFullSlugField._fullSlug}/${data.slug}`; } if (!result.startsWith("/")) { result = `/${result}`; } result = result.replace(/\/\//g, "/"); return result; }; var build_fullslug_from_fullslug_default = buildFullSlug; // src/services/construct-parent-fullslug.ts var constructParentFullSlug = (data) => { const fullSlug = data.localisation.locales.reduce( (acc, locale) => { acc[locale.code] = null; return acc; }, {} ); if (data.collection.useTranslations && data.fields.slug.translations) { for (let i = 0; i < data.localisation.locales.length; i++) { const locale = data.localisation.locales[i]; if (!locale) continue; fullSlug[locale.code] = build_fullslug_from_fullslug_default({ parentFields: data.parentFields || [], targetLocale: locale.code, slug: data.fields.slug.translations[locale.code] }); } } else { fullSlug[data.localisation.defaultLocale] = build_fullslug_from_fullslug_default({ parentFields: data.parentFields || [], targetLocale: data.localisation.defaultLocale, slug: data.fields.slug.value }); } return { error: void 0, data: fullSlug }; }; var construct_parent_fullslug_default = constructParentFullSlug; // src/services/set-full-slug.ts var setFullSlug = (data) => { if (data.collection.useTranslations) { data.fields.fullSlug.translations = data.fullSlug; } else { data.fields.fullSlug.value = data.fullSlug[data.defaultLocale]; } return { error: void 0, data: void 0 }; }; var set_full_slug_default = setFullSlug; // src/services/get-descendant-fields.ts import { prefixGeneratedColName as prefixGeneratedColName2 } from "@lucidcms/core/helpers"; import { inspect } from "node:util"; var getDescendantFields = async (context, data) => { try { const { documentFields: fieldsTable, version: versionTable } = data.tables; const slugColumn = prefixGeneratedColName2(constants_default.fields.slug.key); const fullSlugColumn = prefixGeneratedColName2( constants_default.fields.fullSlug.key ); const parentPageColumn = prefixGeneratedColName2( constants_default.fields.parentPage.key ); const descendants = await context.db.with( "recursive_cte", (db) => db.selectFrom(fieldsTable).innerJoin( versionTable, `${versionTable}.id`, `${fieldsTable}.document_version_id` ).select([ `${versionTable}.document_id as document_id`, `${fieldsTable}.${parentPageColumn} as parent_id`, `${fieldsTable}.document_version_id` ]).where( ({ eb }) => ( // @ts-expect-error eb(`${fieldsTable}.${parentPageColumn}`, "in", data.ids) ) ).where(`${versionTable}.type`, "=", data.versionType).unionAll( db.selectFrom(fieldsTable).innerJoin( versionTable, `${versionTable}.id`, `${fieldsTable}.document_version_id` ).innerJoin( // @ts-expect-error "recursive_cte as rc", "rc.document_id", `${fieldsTable}.${parentPageColumn}` ).select([ `${versionTable}.document_id as document_id`, `${fieldsTable}.${parentPageColumn} as parent_id`, `${fieldsTable}.document_version_id` ]).where(`${versionTable}.type`, "=", data.versionType) ) ).selectFrom("recursive_cte").select((eb) => [ "document_id", "document_version_id", context.config.db.jsonArrayFrom( eb.selectFrom(fieldsTable).innerJoin( versionTable, `${versionTable}.id`, `${fieldsTable}.document_version_id` ).select([ `${fieldsTable}.locale`, `${fieldsTable}.${slugColumn} as _slug`, `${fieldsTable}.${fullSlugColumn} as _fullSlug`, `${fieldsTable}.${parentPageColumn} as _parentPage` ]).whereRef( `${versionTable}.document_id`, "=", "recursive_cte.document_id" ).where(`${versionTable}.type`, "=", data.versionType) ).as("rows") ]).where(({ eb }) => eb("document_id", "not in", data.ids)).execute(); return { error: void 0, data: descendants.filter((d, i, self) => { return self.findIndex( (e) => e.document_id === d.document_id && e.document_version_id === d.document_version_id ) === i; }) }; } catch (error) { console.log( inspect(error, { depth: Number.POSITIVE_INFINITY, colors: true }) ); return { error: { type: "basic", status: 500, message: translations_default("an_unknown_error_occurred_getting_descendant_fields") }, data: void 0 }; } }; var get_descendant_fields_default = getDescendantFields; // src/utils/build-fullslug-from-slugs.ts var buildFullSlugFromSlugs = (data) => { const rowForLocale = data.currentDescendant.rows.find( (row) => row.locale === data.targetLocale ); if (!rowForLocale || !rowForLocale._slug) return null; const slugFieldValue = rowForLocale._slug; const parentPageValue = rowForLocale._parentPage; if (!parentPageValue) { return postSlugFormat( joinSlugs(data.topLevelFullSlug || "", slugFieldValue) ); } const parentDescendant = data.descendants.find( (descendant) => descendant.document_id === parentPageValue ); if (!parentDescendant) { return postSlugFormat( joinSlugs(data.topLevelFullSlug || "", slugFieldValue) ); } const parentFullSlug = buildFullSlugFromSlugs({ targetLocale: data.targetLocale, currentDescendant: parentDescendant, descendants: data.descendants, topLevelFullSlug: data.topLevelFullSlug }); return postSlugFormat( joinSlugs(parentFullSlug || data.topLevelFullSlug || "", slugFieldValue) ); }; var joinSlugs = (...parts) => { return parts.filter(Boolean).join("/").replace(/\/+/g, "/"); }; var postSlugFormat = (slug) => { if (!slug) return null; let res = slug; if (!res.startsWith("/")) { res = `/${res}`; } return res.replace(/\/\//g, "/"); }; var build_fullslug_from_slugs_default = buildFullSlugFromSlugs; // src/services/construct-child-fullslugs.ts var constructChildFullSlug = (data) => { const documentFullSlugs = []; for (const descendant of data.descendants) { const fullSlug = {}; if (data.collection.useTranslations) { if (data.parentFullSlugField !== void 0 && !data.parentFullSlugField.translations) break; for (const locale of data.localisation.locales) { const currentFullSlugValue = data.parentFullSlugField?.translations?.[locale.code]; if (data.parentFullSlugField !== void 0 && !currentFullSlugValue) { continue; } fullSlug[locale.code] = build_fullslug_from_slugs_default({ targetLocale: locale.code, currentDescendant: descendant, descendants: data.descendants, topLevelFullSlug: currentFullSlugValue }); } } else { if (data.parentFullSlugField !== void 0 && !data.parentFullSlugField.value) break; fullSlug[data.localisation.defaultLocale] = build_fullslug_from_slugs_default({ targetLocale: data.localisation.defaultLocale, currentDescendant: descendant, descendants: data.descendants, topLevelFullSlug: data.parentFullSlugField?.value }); } documentFullSlugs.push({ documentId: descendant.document_id, versionId: descendant.document_version_id, fullSlugs: fullSlug }); } return { error: void 0, data: documentFullSlugs }; }; var construct_child_fullslugs_default = constructChildFullSlug; // src/services/update-fullslug-fields.ts import { prefixGeneratedColName as prefixGeneratedColName3 } from "@lucidcms/core/helpers"; var updateFullSlugFields = async (context, data) => { try { const { documentFields: fieldsTable, version: versionTable } = data.tables; const fullSlugColumn = prefixGeneratedColName3( constants_default.fields.fullSlug.key ); const updateFullSlugsPromises = []; for (const doc of data.docFullSlugs) { for (const [locale, fullSlug] of Object.entries(doc.fullSlugs)) { updateFullSlugsPromises.push( context.db.updateTable(fieldsTable).set({ [fullSlugColumn]: fullSlug }).where( (eb) => eb.exists( eb.selectFrom(versionTable).selectAll().where(`${versionTable}.id`, "=", doc.versionId).where(`${versionTable}.document_id`, "=", doc.documentId).where(`${versionTable}.type`, "=", data.versionType) ) ).where("document_version_id", "=", doc.versionId).where("locale", "=", locale).execute() ); } } await Promise.all(updateFullSlugsPromises); return { error: void 0, data: void 0 }; } catch (error) { return { error: { type: "basic", status: 500, message: translations_default("an_unknown_error_occurred_updating_fullslug_fields") }, data: void 0 }; } }; var update_fullslug_fields_default = updateFullSlugFields; // src/services/get-document-version-fields.ts import { prefixGeneratedColName as prefixGeneratedColName4 } from "@lucidcms/core/helpers"; var getDocumentVersionFields = async (context, data) => { try { const { version: versionTable, documentFields: fieldsTable } = data.tables; const slugColumn = prefixGeneratedColName4(constants_default.fields.slug.key); const fullSlugColumn = prefixGeneratedColName4( constants_default.fields.fullSlug.key ); const parentPageColumn = prefixGeneratedColName4( constants_default.fields.parentPage.key ); const fields = await context.db.selectFrom(fieldsTable).innerJoin( versionTable, `${versionTable}.id`, `${fieldsTable}.document_version_id` ).select([ `${fieldsTable}.locale`, `${versionTable}.document_id`, `${fieldsTable}.${slugColumn}`, `${fieldsTable}.${fullSlugColumn}`, `${fieldsTable}.${parentPageColumn}` ]).where(`${versionTable}.document_id`, "=", data.documentId).where(`${versionTable}.id`, "=", data.versionId).where(`${versionTable}.type`, "=", data.versionType).execute(); if (!fields || fields.length === 0) { return { error: void 0, data: null }; } return { error: void 0, data: fields }; } catch (error) { return { error: { type: "basic", status: 500, message: translations_default("an_unknown_error_occurred_getting_document_version_fields") }, data: void 0 }; } }; var get_document_version_fields_default = getDocumentVersionFields; // src/services/checks/duplicate-slug-parents.ts import { prefixGeneratedColName as prefixGeneratedColName5 } from "@lucidcms/core/helpers"; var checkDuplicateSlugParents = async (context, data) => { try { const { document: documentTable, version: versionTable, documentFields: fieldsTable } = data.tables; const slugConditions = Object.entries( data.fields.slug.translations || {} ).map(([localeCode, slug]) => ({ localeCode, slug })); if (data.fields.slug.value) { slugConditions.push({ localeCode: context.config.localisation.defaultLocale, slug: data.fields.slug.value }); } const slugColumn = prefixGeneratedColName5(constants_default.fields.slug.key); const parentPageColumn = prefixGeneratedColName5( constants_default.fields.parentPage.key ); const duplicates = await context.db.selectFrom(documentTable).leftJoin( versionTable, // @ts-expect-error `${versionTable}.document_id`, `${documentTable}.id` ).leftJoin( fieldsTable, // @ts-expect-error `${fieldsTable}.document_version_id`, `${versionTable}.id` ).select([ `${documentTable}.id`, `${documentTable}.collection_key`, `${fieldsTable}.${slugColumn}`, `${fieldsTable}.locale`, `${fieldsTable}.${parentPageColumn}` ]).where( ({ eb, and, or }) => and([ or( slugConditions.map( ({ localeCode, slug }) => and([ eb(`${fieldsTable}.${slugColumn}`, "=", slug), localeCode ? eb(`${fieldsTable}.locale`, "=", localeCode) : eb(`${fieldsTable}.locale`, "is", null) ]) ) ), data.fields.parentPage.value ? eb( `${fieldsTable}.${parentPageColumn}`, "=", data.fields.parentPage.value ) : eb(`${fieldsTable}.${parentPageColumn}`, "is", null), eb(`${versionTable}.type`, "=", data.versionType) ]) ).where(`${documentTable}.id`, "!=", data.documentId || null).where(`${documentTable}.collection_key`, "=", data.collectionKey).where( `${documentTable}.is_deleted`, "=", context.config.db.getDefault("boolean", "false") ).execute(); if (duplicates.length > 0) { const fieldErrors = []; for (const duplicate of duplicates) { fieldErrors.push({ key: constants_default.fields.slug.key, localeCode: duplicate.locale || void 0, message: duplicate[parentPageColumn] === null ? translations_default("duplicate_slug_field_found_message") : translations_default("duplicate_slug_and_parent_page_field_found_message") }); } return { error: { type: "basic", status: 400, message: translations_default("duplicate_slug_field_found_message"), errorResponse: { body: { fields: fieldErrors } } }, data: void 0 }; } return { error: void 0, data: void 0 }; } catch (error) { return { error: { type: "basic", status: 500, message: translations_default("an_unknown_error_occurred_checking_for_duplicate_slugs") }, data: void 0 }; } }; var duplicate_slug_parents_default = checkDuplicateSlugParents; // src/services/checks/root-slug-withparent.ts var checkRootSlugWithParent = (data) => { if (data.collection.useTranslations && data.fields.slug.translations) { const fieldErrors = []; for (const [key, value] of Object.entries(data.fields.slug.translations)) { if (value === "/" && data.fields.parentPage.value) { fieldErrors.push({ key: constants_default.fields.slug.key, localeCode: key, message: translations_default("slug_cannot_be_slash_and_parent_page_set_message") }); } } if (fieldErrors.length > 0) { return { error: { type: "basic", status: 400, message: translations_default("slug_cannot_be_slash_and_parent_page_set_message"), errorResponse: { body: { fields: fieldErrors } } }, data: void 0 }; } } else if (data.fields.slug.value === "/" && data.fields.parentPage.value) { return { error: { type: "basic", status: 400, message: translations_default("slug_cannot_be_slash_and_parent_page_set_message"), errorResponse: { body: { fields: [ { key: constants_default.fields.parentPage.key, message: translations_default("slug_cannot_be_slash_and_parent_page_set_message") } ] } } }, data: void 0 }; } return { error: void 0, data: void 0 }; }; var root_slug_withparent_default = checkRootSlugWithParent; // src/services/checks/page-is-parent-of-self.ts var checkParentIsPageOfSelf = (data) => { if (data.fields.parentPage.value && data.fields.parentPage.value === data.documentId) { return { error: { type: "basic", status: 400, message: translations_default("cannot_have_self_as_parent_page_message"), errorResponse: { body: { fields: [ { key: constants_default.fields.parentPage.key, localeCode: data.defaultLocale, //* parentPage doesnt use translations so always use default locale message: translations_default("cannot_have_self_as_parent_page_message") } ] } } }, data: void 0 }; } return { error: void 0, data: void 0 }; }; var page_is_parent_of_self_default = checkParentIsPageOfSelf; // src/services/checks/check-fields-exist.ts var checkFieldsExist = (data) => { const fieldErrors = []; if (data.fields.slug === void 0) { fieldErrors.push({ key: "slug", localeCode: null, message: translations_default("field_required") }); } if (data.fields.parentPage === void 0) { fieldErrors.push({ key: "parentPage", localeCode: null, message: translations_default("field_required") }); } if (data.fields.fullSlug === void 0) { fieldErrors.push({ key: "fullSlug", localeCode: null, message: translations_default("field_required") }); } if (fieldErrors.length) { return { error: { type: "basic", message: translations_default("cannot_find_required_field_message"), status: 400, errorResponse: { body: { fields: fieldErrors } } }, data: void 0 }; } return { error: void 0, data: { slug: data.fields.slug, parentPage: data.fields.parentPage, fullSlug: data.fields.fullSlug } }; }; var check_fields_exist_default = checkFieldsExist; // src/services/checks/circular-parents.ts import { prefixGeneratedColName as prefixGeneratedColName6 } from "@lucidcms/core/helpers"; var checkCircularParents = async (context, data) => { try { if (!data.documentId || !data.fields.parentPage.value) { return { error: void 0, data: void 0 }; } const { version: versionTable, documentFields: fieldsTable } = data.tables; const parentPageField = prefixGeneratedColName6( constants_default.fields.parentPage.key ); const result = await context.db.with( "ancestors", (db) => db.selectFrom(fieldsTable).innerJoin( versionTable, `${versionTable}.id`, `${fieldsTable}.document_version_id` ).select([ `${versionTable}.document_id as current_id`, `${fieldsTable}.${parentPageField} as parent_id` ]).where(`${fieldsTable}.locale`, "=", data.defaultLocale).where(`${versionTable}.type`, "=", data.versionType).where( `${versionTable}.document_id`, "=", data.fields.parentPage.value ).unionAll( db.selectFrom(fieldsTable).innerJoin( versionTable, `${versionTable}.id`, `${fieldsTable}.document_version_id` ).innerJoin( // @ts-expect-error "ancestors", "ancestors.parent_id", `${versionTable}.document_id` ).select([ `${versionTable}.document_id as current_id`, `${fieldsTable}.${parentPageField} as parent_id` ]).where(`${fieldsTable}.locale`, "=", data.defaultLocale).where(`${versionTable}.type`, "=", data.versionType) ) ).selectFrom("ancestors").select("parent_id").where("parent_id", "=", data.documentId).executeTakeFirst(); if (result) { return { error: { type: "basic", status: 400, message: translations_default("circular_parents_error_message"), errorResponse: { body: { fields: [ { key: constants_default.fields.parentPage.key, localeCode: data.defaultLocale, //* parentPage doesnt use translations so always use default locale message: translations_default("circular_parents_error_message") } ] } } }, data: void 0 }; } return { error: void 0, data: void 0 }; } catch (error) { return { error: { type: "basic", status: 500, message: translations_default("an_unknown_error_occurred_checking_for_circular_parents") }, data: void 0 }; } }; var circular_parents_default = checkCircularParents; // src/services/hooks/before-upsert-handler.ts var beforeUpsertHandler = (options) => async (context, data) => { const targetCollectionRes = get_target_collection_default({ options, collectionKey: data.meta.collectionKey }); if (targetCollectionRes.error) { return { error: void 0, data: data.data }; } const tablesRes = data.meta.collection.tableNames; if (tablesRes.error) return tablesRes; const checkFieldsExistRes = check_fields_exist_default({ fields: { slug: data.data.fields?.find( (f) => f.key === constants_default.fields.slug.key && f.type === "text" ), parentPage: data.data.fields?.find( (f) => f.key === constants_default.fields.parentPage.key && f.type === "document" ), //* dont care what this value is - only needed to update translations/value fullSlug: data.data.fields?.find( (f) => f.key === constants_default.fields.fullSlug.key && f.type === "text" ) } }); if (checkFieldsExistRes.error) return checkFieldsExistRes; const { slug, parentPage, fullSlug } = checkFieldsExistRes.data; const checkParentIsPageOfSelfRes = page_is_parent_of_self_default({ defaultLocale: context.config.localisation.defaultLocale, documentId: data.data.documentId, fields: { parentPage } }); if (checkParentIsPageOfSelfRes.error) return checkParentIsPageOfSelfRes; const checkRootSlugWithParentRes = root_slug_withparent_default({ collection: targetCollectionRes.data, defaultLocale: context.config.localisation.defaultLocale, fields: { slug, parentPage } }); if (checkRootSlugWithParentRes.error) return checkRootSlugWithParentRes; const checkDuplicateSlugParentsRes = await duplicate_slug_parents_default( context, { documentId: data.data.documentId, versionId: data.data.versionId, versionType: data.data.versionType, collectionKey: targetCollectionRes.data.collectionKey, fields: { slug, parentPage }, tables: tablesRes.data } ); if (checkDuplicateSlugParentsRes.error) return checkDuplicateSlugParentsRes; let parentFieldsData = []; if (parentPage.value) { const circularParentsRes = await circular_parents_default(context, { documentId: data.data.documentId, versionType: data.data.versionType, defaultLocale: context.config.localisation.defaultLocale, fields: { parentPage }, tables: tablesRes.data }); if (circularParentsRes.error) return circularParentsRes; const parentFieldsRes = await get_parent_fields_default(context, { defaultLocale: context.config.localisation.defaultLocale, versionType: data.data.versionType, fields: { parentPage }, tables: tablesRes.data }); if (parentFieldsRes.error) return parentFieldsRes; parentFieldsData = parentFieldsRes.data; } const fullSlugRes = construct_parent_fullslug_default({ parentFields: parentFieldsData, localisation: context.config.localisation, collection: targetCollectionRes.data, fields: { slug } }); if (fullSlugRes.error) return fullSlugRes; set_full_slug_default({ fullSlug: fullSlugRes.data, defaultLocale: context.config.localisation.defaultLocale, collection: targetCollectionRes.data, fields: { fullSlug } }); return { error: void 0, data: data.data }; }; var before_upsert_handler_default = beforeUpsertHandler; // src/services/hooks/after-upsert-handler.ts var afterUpsertHandler = (options) => async (context, data) => { const targetCollectionRes = get_target_collection_default({ options, collectionKey: data.meta.collectionKey }); if (targetCollectionRes.error) { return { error: void 0, data: void 0 }; } const tablesRes = data.meta.collection.tableNames; if (tablesRes.error) return tablesRes; const descendantsRes = await get_descendant_fields_default(context, { ids: [data.data.documentId], versionType: data.data.versionType, tables: tablesRes.data }); if (descendantsRes.error) return descendantsRes; if (descendantsRes.data.length === 0) { return { error: void 0, data: void 0 }; } const currentFullSlugField = data.data.fields.find((field) => { return field.key === constants_default.fields.fullSlug.key; }); if (!currentFullSlugField) { return { error: void 0, data: void 0 }; } const docFullSlugsRes = construct_child_fullslugs_default({ descendants: descendantsRes.data, localisation: context.config.localisation, parentFullSlugField: currentFullSlugField, collection: targetCollectionRes.data }); if (docFullSlugsRes.error) return docFullSlugsRes; await update_fullslug_fields_default(context, { docFullSlugs: docFullSlugsRes.data, versionType: data.data.versionType, tables: tablesRes.data }); return { error: void 0, data: void 0 }; }; var after_upsert_handler_default = afterUpsertHandler; // src/services/hooks/before-delete-handler.ts var beforeDeleteHandler = (options) => async (context, data) => { const targetCollectionRes = get_target_collection_default({ options, collectionKey: data.meta.collectionKey }); if (targetCollectionRes.error) { return { error: void 0, data: void 0 }; } const tablesRes = data.meta.collection.tableNames; if (tablesRes.error) return tablesRes; const versionTypes = ["draft", "published"]; for (const versionType of versionTypes) { const descendantsRes = await get_descendant_fields_default(context, { ids: data.data.ids, versionType, tables: tablesRes.data }); if (descendantsRes.error) return descendantsRes; if (descendantsRes.data.length === 0) { continue; } const docFullSlugsRes = construct_child_fullslugs_default({ descendants: descendantsRes.data, localisation: context.config.localisation, collection: targetCollectionRes.data }); if (docFullSlugsRes.error) return docFullSlugsRes; await update_fullslug_fields_default(context, { docFullSlugs: docFullSlugsRes.data, versionType, tables: tablesRes.data }); } return { error: void 0, data: void 0 }; }; var before_delete_handler_default = beforeDeleteHandler; // src/utils/field-res-to-schema.ts var fieldResToSchema = (key, useTranslations, defaultLocale, items) => { const fieldType = getFieldTypeFromKey(key); if (!fieldType) { throw new Error(`Unable to determine field type for key: ${key}`); } const result = { key, type: fieldType }; if (useTranslations) { result.translations = {}; for (const item of items) { if (fieldType === "text") { result.translations[item.locale] = item[`_${key}`]; } else if (fieldType === "document") { result.translations[item.locale] = item[`_${key}`]; } } } else { const defaultItem = items.find((item) => item.locale === defaultLocale) || items[0]; if (fieldType === "text") { result.value = defaultItem[`_${key}`]; } else if (fieldType === "document") { result.value = defaultItem[`_${key}`]; } } return result; }; function getFieldTypeFromKey(key) { switch (key) { case "slug": case "fullSlug": return "text"; case "parentPage": return "document"; default: return void 0; } } var field_res_to_schema_default = fieldResToSchema; // src/services/hooks/version-promote.ts var versionPromoteHandler = (options) => async (context, data) => { const targetCollectionRes = get_target_collection_default({ options, collectionKey: data.meta.collectionKey }); if (targetCollectionRes.error) { return { error: void 0, data: void 0 }; } const tablesRes = data.meta.collection.tableNames; if (tablesRes.error) return tablesRes; let createFullSlug = true; const docVersionFieldRes = await get_document_version_fields_default(context, { documentId: data.data.documentId, versionId: data.data.versionId, versionType: data.data.versionType, tables: tablesRes.data }); if (docVersionFieldRes.error) return docVersionFieldRes; if (docVersionFieldRes.data === null) createFullSlug = false; const checkFieldsExistRes = check_fields_exist_default({ fields: { slug: field_res_to_schema_default( constants_default.fields.slug.key, targetCollectionRes.data.useTranslations, context.config.localisation.defaultLocale, docVersionFieldRes.data || [] ), parentPage: field_res_to_schema_default( constants_default.fields.parentPage.key, false, context.config.localisation.defaultLocale, docVersionFieldRes.data || [] ), fullSlug: field_res_to_schema_default( constants_default.fields.fullSlug.key, targetCollectionRes.data.useTranslations, context.config.localisation.defaultLocale, docVersionFieldRes.data || [] ) } }); if (checkFieldsExistRes.error) return checkFieldsExistRes; const { slug, parentPage, fullSlug } = checkFieldsExistRes.data; if (createFullSlug) { const checkDuplicateSlugParentsRes = await duplicate_slug_parents_default( context, { documentId: data.data.documentId, versionId: data.data.versionId, versionType: data.data.versionType, collectionKey: targetCollectionRes.data.collectionKey, fields: { slug, parentPage }, tables: tablesRes.data } ); if (checkDuplicateSlugParentsRes.error) return checkDuplicateSlugParentsRes; let parentFieldsData = []; if (parentPage.value) { const circularParentsRes = await circular_parents_default(context, { documentId: data.data.documentId, versionType: data.data.versionType, defaultLocale: context.config.localisation.defaultLocale, fields: { parentPage }, tables: tablesRes.data }); if (circularParentsRes.error) return circularParentsRes; const parentFieldsRes = await get_parent_fields_default(context, { defaultLocale: context.config.localisation.defaultLocale, versionType: data.data.versionType, fields: { parentPage }, tables: tablesRes.data }); if (parentFieldsRes.error) return parentFieldsRes; parentFieldsData = parentFieldsRes.data; } const fullSlugRes = construct_parent_fullslug_default({ parentFields: parentFieldsData, localisation: context.config.localisation, collection: targetCollectionRes.data, fields: { slug } }); if (fullSlugRes.error) return fullSlugRes; set_full_slug_default({ fullSlug: fullSlugRes.data, defaultLocale: context.config.localisation.defaultLocale, collection: targetCollectionRes.data, fields: { fullSlug } }); const updateFullSlugRes = await update_fullslug_fields_default(context, { docFullSlugs: [ { documentId: data.data.documentId, versionId: data.data.versionId, fullSlugs: fullSlugRes.data } ], versionType: data.data.versionType, tables: tablesRes.data }); if (updateFullSlugRes.error) return updateFullSlugRes; } await after_upsert_handler_default(options)(context, { meta: { collection: data.meta.collection, collectionKey: data.meta.collectionKey, userId: data.meta.userId }, data: { documentId: data.data.documentId, versionId: data.data.versionId, versionType: data.data.versionType, bricks: [], fields: [slug, parentPage, fullSlug] } }); return { error: void 0, data: void 0 }; }; var version_promote_default = versionPromoteHandler; // src/plugin.ts var plugin = async (config, plugin2) => { const options = plugin_options_default(plugin2); for (const collectionConfig of options.collections) { const collectionInstance = config.collections.find( (c) => c.key === collectionConfig.collectionKey ); if (!collectionInstance) { logger("warn", { message: translations_default("cannot_find_collection", { collection: collectionConfig.collectionKey }), scope: PLUGIN_KEY }); continue; } register_fields_default(collectionInstance, collectionConfig); if (!collectionInstance.config.hooks) { collectionInstance.config.hooks = []; } } config.hooks.push({ service: "documents", event: "beforeUpsert", handler: before_upsert_handler_default(options) }); config.hooks.push({ service: "documents", event: "afterUpsert", handler: after_upsert_handler_default(options) }); config.hooks.push({ service: "documents", event: "beforeDelete", handler: before_delete_handler_default(options) }); config.hooks.push({ service: "documents", event: "versionPromote", handler: version_promote_default(options) }); return { key: PLUGIN_KEY, lucid: LUCID_VERSION, config }; }; var plugin_default = plugin; // src/index.ts var lucidPagesPlugin = (pluginOptions2) => (config) => plugin_default(config, pluginOptions2); var index_default = lucidPagesPlugin; export { index_default as default }; //# sourceMappingURL=index.js.map