{"version":3,"file":"index.mjs","sources":["../../server/util/enabledContentTypes.ts","../../server/util/pluginId.ts","../../server/hooks/disable.ts","../../server/util/getPluginService.ts","../../server/middlewares/prevent-duplicate-urls.ts","../../server/middlewares/delete-url-alias.ts","../../server/middlewares/generate-url-alias.ts","../../server/register.ts","../../server/bootstrap.ts","../../server/routes/index.ts","../../server/controllers/url-alias.ts","../../server/controllers/url-pattern.ts","../../server/util/getAddons.ts","../../server/controllers/info.ts","../../server/util/sanitizeOutput.ts","../../server/controllers/core.ts","../../server/controllers/search.ts","../../server/controllers/index.ts","../../server/services/url-alias.ts","../../server/util/typeHelpers.ts","../../server/services/url-pattern.ts","../../server/services/bulk-generate.ts","../../server/services/get-main-field.ts","../../server/services/index.ts","../../server/config.ts","../../server/content-types/index.ts","../../server/index.ts"],"sourcesContent":["import get from 'lodash/get';\nimport { Schema } from '@strapi/strapi';\n\n\nexport const isContentTypeEnabled = (contentType: Schema.ContentType) => {\n  const { pluginOptions } = contentType;\n  return get(pluginOptions, ['webtools', 'enabled'], false) as boolean;\n};\n","\n\nimport pluginPkg from '../../package.json';\n\n/**\n * A helper function to obtain the plugin id.\n *\n * @return {string} The plugin id.\n */\nexport const pluginId = pluginPkg.strapi.name;\n","import { Schema } from '@strapi/strapi';\nimport { isContentTypeEnabled } from '../util/enabledContentTypes';\nimport { pluginId } from '../util/pluginId';\n\nexport const disableContentType = async ({ oldContentTypes, contentTypes }: {\n  oldContentTypes?: null | {\n    [uid in keyof Schema.ContentTypes]?: Schema.ContentTypes[uid];\n  } & {\n    [uid: string]: Schema.ContentType;\n  },\n  contentTypes: {\n    [uid in keyof Schema.ContentTypes]: Schema.ContentTypes[uid];\n  } & {\n    [uid: string]: Schema.ContentType;\n  },\n}) => {\n  if (!oldContentTypes) {\n    return;\n  }\n\n  await Promise.all(Object.keys(oldContentTypes).map(async (uid) => {\n    const oldContentType = oldContentTypes[uid];\n    if (!oldContentType) {\n      // This means that the content type must have just been created,\n      // so we should not do anything here\n      return;\n    }\n\n    // This content type could be undefined if the content type was just deleted\n    const contentType = contentTypes[uid];\n\n    const wasEnabled = isContentTypeEnabled(oldContentType);\n    const isEnabled = contentType && isContentTypeEnabled(contentType);\n\n\n    if (!wasEnabled || isEnabled) {\n      return;\n    }\n\n    // remove old paths from the database\n    await strapi.db.query(`plugin::${pluginId}.url-alias`).deleteMany({\n      where: {\n        contenttype: uid,\n      },\n    });\n  }));\n};\n","import { pluginId } from './pluginId';\nimport type config from '..';\n\ntype Config = typeof config;\ntype Services = Config['services'];\n/**\n * A helper function to obtain a plugin service.\n * @param {string} name The name of the service.\n *\n * @return {any} service.\n */\nexport const getPluginService = <ServiceName extends keyof Services>(name: ServiceName) => {\n  const service = strapi.service(`plugin::${pluginId}.${name}`);\n  return service as ReturnType<Services[ServiceName]>;\n};\n","import { Modules } from '@strapi/strapi';\nimport { getPluginService } from '../util/getPluginService';\n\n// eslint-disable-next-line max-len\nconst preventDuplicateUrlsMiddleware: Modules.Documents.Middleware.Middleware = async (context, next) => {\n  const { uid, action } = context;\n\n  // Only run this for the URL alias entities.\n  if (uid !== 'plugin::webtools.url-alias') {\n    return next();\n  }\n\n  // Run this middleware only for the create, update and clone action.\n  if (!['create', 'update'].includes(action)) {\n    return next();\n  }\n\n  const params = context.params as Modules.Documents.ServiceParams<'plugin::webtools.url-alias'>['create' | 'update' | 'clone'] & { documentId: string };\n\n  if (params.data.url_path) {\n    params.data.url_path = await getPluginService('url-alias')\n      .makeUniquePath(params.data.url_path, action !== 'clone' && params.documentId, action !== 'clone' && params.locale);\n  }\n\n  return next();\n};\n\nexport default preventDuplicateUrlsMiddleware;\n","import { Modules } from '@strapi/strapi';\nimport { isContentTypeEnabled } from '../util/enabledContentTypes';\n\nconst deleteUrlAliasMiddleware: Modules.Documents.Middleware.Middleware = async (context, next) => {\n  const {\n    uid, action, params, contentType,\n  } = context;\n  const hasWT = isContentTypeEnabled(contentType);\n\n  // If Webtools isn't enabled, do nothing.\n  if (!hasWT) {\n    return next();\n  }\n\n  // Run this middleware only for the create action.\n  if (action !== 'delete') {\n    return next();\n  }\n\n  const locales = await strapi.documents('plugin::i18n.locale').findMany({ fields: 'code' });\n  let urlAlias: Modules.Documents.Document<'plugin::webtools.url-alias'> | null = null;\n\n  await locales.reduce(async (prevPromise, locale) => {\n    await prevPromise; // Ensure previous iteration is done\n    if (urlAlias) return; // Stop early if we already found one\n\n    const entity = await strapi.documents(uid as 'api::test.test').findOne({\n      documentId: params.documentId,\n      locale: locale.code,\n      populate: {\n        url_alias: {\n          fields: ['id'],\n        },\n      },\n    });\n\n    if (entity?.url_alias[0]) {\n      [urlAlias] = entity.url_alias;\n    }\n  }, Promise.resolve());\n\n  // If a URL alias is present, delete it.\n  if (urlAlias) {\n    await strapi.documents('plugin::webtools.url-alias').delete({\n      locale: params.locale,\n      documentId: urlAlias.documentId,\n    });\n  }\n\n  // Eventually delete the entity.\n  return next();\n};\n\nexport default deleteUrlAliasMiddleware;\n","import { Modules, Data } from '@strapi/strapi';\nimport { isContentTypeEnabled } from '../util/enabledContentTypes';\nimport { getPluginService } from '../util/getPluginService';\n\n// eslint-disable-next-line max-len\nconst generateUrlAliasMiddleware: Modules.Documents.Middleware.Middleware = async (context, next) => {\n  const { uid, action, contentType } = context;\n\n  if (uid === 'plugin::webtools.url-alias' && action === 'update') {\n    const { params } = context;\n    const shouldRegenerate = params.data?.generated === true;\n\n    // @ts-expect-error\n    if (params.skipRegeneration || !shouldRegenerate) {\n      return next();\n    }\n\n    const { entity, contentType: relatedContentType } =\n      await getPluginService('url-alias').findRelatedEntity(\n        params.data?.url_path,\n        {\n          fields: ['documentId', 'locale'],\n        },\n      );\n\n    if (entity && relatedContentType) {\n      let relations: string[] = [];\n\n      const urlPatterns = await getPluginService('url-pattern').findByUid(\n        relatedContentType,\n        entity.locale,\n      );\n\n      urlPatterns.forEach((urlPattern) => {\n        const patternRelations =\n          getPluginService('url-pattern').getRelationsFromPattern(urlPattern);\n        relations = [...relations, ...patternRelations];\n      });\n\n      const fullEntity = await strapi.documents(relatedContentType as 'api::test.test').findOne({\n        documentId: entity.documentId,\n        ...(entity.locale ? { locale: entity.locale } : {}),\n        populate: {\n          ...relations.reduce((obj, key) => ({ ...obj, [key]: {} }), {}),\n        },\n      });\n\n      if (fullEntity) {\n        let generatedPath: string | null = null;\n        urlPatterns.forEach((urlPattern) => {\n          generatedPath = getPluginService('url-pattern').resolvePattern(\n            relatedContentType,\n            fullEntity,\n            urlPattern,\n          );\n        });\n\n        if (generatedPath) {\n          params.data = {\n            ...params.data,\n            generated: true,\n            contenttype: relatedContentType,\n            url_path: generatedPath,\n          };\n        }\n      }\n    }\n\n    return next();\n  }\n\n  const hasWT = isContentTypeEnabled(contentType);\n\n  // If Webtools isn't enabled, do nothing.\n  if (!hasWT) {\n    return next();\n  }\n\n  // Run this middleware only for the create, update and clone action.\n  if (!['clone', 'create', 'update'].includes(action)) {\n    return next();\n  }\n\n  const params = context.params as Modules.Documents.ServiceParams<'api::test.test'>['create' | 'update' | 'clone'];\n\n  // Fetch the URL pattern for this content type.\n  let relations: string[] = [];\n  let urlAliasEntity: Data.ContentType<'plugin::webtools.url-alias'> | undefined;\n\n  let languages: (string | undefined)[] = [undefined];\n  if (params.locale) {\n    const locales = await strapi.entityService.findMany('plugin::i18n.locale', {});\n    languages = locales.map((locale) => locale.code);\n  }\n\n  await Promise.all(languages.map(async (lang) => {\n    const urlPatterns = await getPluginService('url-pattern').findByUid(uid, lang);\n    urlPatterns.forEach((urlPattern) => {\n      const languageRelations = getPluginService('url-pattern').getRelationsFromPattern(urlPattern);\n      relations = [...relations, ...languageRelations];\n    });\n  }));\n\n  // Remove the URL alias if we're cloning the entity.\n  // This way we can generate a new URL alias for the cloned entity.\n  if (action === 'clone') {\n    params.data.url_alias = null;\n  }\n\n  // Fire the action.\n  const entity = await next() as Modules.Documents.AnyDocument;\n\n  // Abort if no entity was created/updated.\n  if (!entity) {\n    return entity;\n  }\n\n  // Fetch the full entity.\n  const fullEntity = await strapi.documents(uid as 'api::test.test').findOne({\n    documentId: entity.documentId,\n    ...(params.locale ? { locale: params.locale } : {}),\n    populate: {\n      ...relations.reduce((obj, key) => ({ ...obj, [key]: {} }), {}),\n      url_alias: {\n        fields: ['id', 'generated'],\n      },\n      localizations: {\n        populate: {\n          url_alias: {\n            fields: ['id'],\n          },\n        },\n      },\n    },\n  });\n\n  // If the document already has a URL alias, fetch it.\n  if (params.data.url_alias?.[0]) {\n    urlAliasEntity = await strapi.documents('plugin::webtools.url-alias').findOne({\n      ...(params.locale ? { locale: params.locale } : {}),\n      documentId: params.data.url_alias[0] as string,\n    });\n  } else if (fullEntity.url_alias[0]) {\n    [urlAliasEntity] = fullEntity.url_alias;\n  }\n\n  // If the URL alias has 'generated' set to false, do nothing.\n  if (urlAliasEntity?.generated === false) {\n    return entity;\n  }\n\n  // Fetch the URL alias localization.\n  const urlAliasLocalization = fullEntity.localizations\n    ?.map((loc) => loc?.url_alias[0]?.documentId)\n    ?.filter((loc) => loc)[0] || null;\n\n  const fullEntityWithoutLocalizations = {\n    ...fullEntity,\n    localizations: undefined,\n  };\n\n  const combinedEntity = { ...fullEntityWithoutLocalizations };\n  const urlPatterns = await getPluginService('url-pattern').findByUid(uid, combinedEntity.locale);\n\n  await Promise.all(urlPatterns.map(async (urlPattern) => {\n    const generatedPath = getPluginService('url-pattern').resolvePattern(uid, combinedEntity, urlPattern);\n\n    // If a URL alias was created and 'generated' is set to true, update the alias.\n    if (urlAliasEntity?.generated === true) {\n      urlAliasEntity = await strapi.documents('plugin::webtools.url-alias').update({\n        documentId: urlAliasEntity.documentId,\n        locale: combinedEntity.locale,\n        data: {\n          url_path: generatedPath,\n          generated: true,\n          contenttype: uid,\n        },\n        skipRegeneration: true,\n      });\n    }\n\n    // If no URL alias was created, create one.\n    if (!urlAliasEntity) {\n      if (urlAliasLocalization) {\n        urlAliasEntity = await strapi.documents('plugin::webtools.url-alias').update({\n          documentId: urlAliasLocalization,\n          locale: combinedEntity.locale,\n          data: {\n            url_path: generatedPath,\n            generated: true,\n            contenttype: uid,\n          },\n          skipRegeneration: true,\n        });\n      } else {\n        urlAliasEntity = await strapi.documents('plugin::webtools.url-alias').create({\n          locale: combinedEntity.locale,\n          data: {\n            url_path: generatedPath,\n            generated: true,\n            contenttype: uid,\n          },\n        });\n      }\n    }\n  }));\n\n  const all = await strapi.db.query(uid as 'api::test.test').findMany({\n    where: {\n      ...(params.locale ? { locale: params.locale } : {}),\n      document_id: entity.documentId,\n    },\n  });\n\n  await Promise.all(all.map(async (doc) => {\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n    await strapi.db.query(uid as 'api::test.test').updateRelations(doc.id as string, {\n      url_alias: [urlAliasEntity?.id],\n    });\n  }));\n\n  const finalEntity = await strapi.documents(uid as 'api::test.test').findOne({\n    documentId: entity.documentId,\n    fields: params.fields,\n    ...(params.locale ? { locale: params.locale } : {}),\n    populate: params.populate,\n  });\n\n  if (action === 'clone') {\n    return {\n      documentId: entity.documentId,\n      entries: [finalEntity],\n    };\n  }\n\n  return finalEntity;\n};\n\nexport default generateUrlAliasMiddleware;\n","/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n\nimport set from 'lodash/set';\nimport { Core, Schema } from '@strapi/strapi';\nimport { isContentTypeEnabled } from './util/enabledContentTypes';\nimport { disableContentType } from './hooks/disable';\nimport preventDuplicateUrlsMiddleware from './middlewares/prevent-duplicate-urls';\nimport deleteUrlAliasMiddleware from './middlewares/delete-url-alias';\nimport generateUrlAliasMiddleware from './middlewares/generate-url-alias';\n\nexport default ({ strapi }: { strapi: Core.Strapi }) => {\n  strapi.hook('strapi::content-types.beforeSync').register(disableContentType);\n\n  strapi.documents.use(preventDuplicateUrlsMiddleware);\n  strapi.documents.use(deleteUrlAliasMiddleware);\n  strapi.documents.use(generateUrlAliasMiddleware);\n\n  // Register the url_alias field.\n  Object.values(strapi.contentTypes).forEach((contentType: Schema.ContentType) => {\n    const { attributes } = contentType;\n\n    // Add a relation field to the url_alias content type, only\n    // when webtools is explicitly enabled using pluginOptions.\n    if (isContentTypeEnabled(contentType)) {\n      set(attributes, 'url_alias', {\n        writable: true,\n        private: false,\n        configurable: false,\n        editable: false,\n        visible: false,\n        default: null,\n        type: 'relation',\n        relation: 'oneToMany',\n        target: 'plugin::webtools.url-alias',\n        unique: true,\n      });\n    }\n  });\n\n  // Register the pattern config type when using the config-sync plugin.\n  if (strapi.plugin('config-sync')) {\n    if (!strapi.plugin('config-sync').pluginTypes) {\n      // eslint-disable-next-line no-param-reassign\n      strapi.plugin('config-sync').pluginTypes = [];\n    }\n\n    strapi.plugin('config-sync').pluginTypes.push({\n      configName: 'url-pattern',\n      queryString: 'plugin::webtools.url-pattern',\n      uid: 'documentId',\n    });\n  }\n};\n","import { Core } from '@strapi/strapi';\n\nexport default ({ strapi }: { strapi: Core.Strapi }) => {\n  try {\n    // Register permission actions.\n    const actions = [\n      {\n        section: 'plugins',\n        displayName: 'Access the overview page',\n        uid: 'settings.overview',\n        pluginName: 'webtools',\n      },\n      {\n        section: 'plugins',\n        displayName: 'Access the URL alias list',\n        uid: 'settings.list',\n        pluginName: 'webtools',\n      },\n      {\n        section: 'plugins',\n        displayName: 'Access the URL alias patterns',\n        uid: 'settings.patterns',\n        pluginName: 'webtools',\n      },\n      {\n        section: 'plugins',\n        displayName: 'Access the URL alias sidebar',\n        uid: 'edit-view.sidebar',\n        pluginName: 'webtools',\n      },\n    ];\n\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n    (strapi.admin.services.permission.actionProvider.registerMany as (a: any) => void)(actions);\n  } catch (error) {\n    strapi.log.error(`Bootstrap failed. ${String(error)}`);\n  }\n};\n","export default {\n  'content-api': {\n    type: 'content-api',\n    routes: [\n      {\n        method: 'GET',\n        path: '/url-alias',\n        handler: 'url-alias.find',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'GET',\n        path: '/url-alias/:id',\n        handler: 'url-alias.findOne',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'DELETE',\n        path: '/url-alias/:id',\n        handler: 'url-alias.delete',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'PUT',\n        path: '/url-alias/:id',\n        handler: 'url-alias.update',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'POST',\n        path: '/url-alias',\n        handler: 'url-alias.create',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'GET',\n        path: '/router',\n        handler: 'core.router',\n        config: {\n          policies: [],\n        },\n      },\n    ],\n  },\n  admin: {\n    type: 'admin',\n    routes: [\n      /**\n       * URL Alias routes\n       */\n      {\n        method: 'GET',\n        path: '/url-alias/findOne/:id',\n        handler: 'url-alias.findOne',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'GET',\n        path: '/url-alias/findMany',\n        handler: 'url-alias.find',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'GET',\n        path: '/url-alias/findFrom',\n        handler: 'url-alias.findFrom',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'POST',\n        path: '/url-alias/delete/:id',\n        handler: 'url-alias.delete',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'PUT',\n        path: '/url-alias/update/:id',\n        handler: 'url-alias.update',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'POST',\n        path: '/url-alias/create',\n        handler: 'url-alias.create',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'GET',\n        path: '/url-alias/editLink',\n        handler: 'url-alias.editLink',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'POST',\n        path: '/url-alias/generate',\n        handler: 'url-alias.generate',\n        config: {\n          policies: [],\n        },\n      },\n\n      /**\n       * Info routes\n       */\n      {\n        method: 'GET',\n        path: '/info/getContentTypes',\n        handler: 'info.getContentTypes',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'GET',\n        path: '/info/getLanguages',\n        handler: 'info.getLanguages',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'GET',\n        path: '/info/addons',\n        handler: 'info.getAddons',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'GET',\n        path: '/info/config',\n        handler: 'info.getConfig',\n        config: {\n          policies: [],\n        },\n      },\n\n      /**\n       * URL Pattern routes\n       */\n      {\n        method: 'GET',\n        path: '/url-pattern/findOne/:id',\n        handler: 'url-pattern.findOne',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'GET',\n        path: '/url-pattern/findMany',\n        handler: 'url-pattern.find',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'GET',\n        path: '/url-pattern/delete/:id',\n        handler: 'url-pattern.delete',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'PUT',\n        path: '/url-pattern/update/:id',\n        handler: 'url-pattern.update',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'POST',\n        path: '/url-pattern/create',\n        handler: 'url-pattern.create',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'GET',\n        path: '/url-pattern/allowed-fields',\n        handler: 'url-pattern.allowedFields',\n        config: {\n          policies: [],\n        },\n      },\n      {\n        method: 'POST',\n        path: '/url-pattern/validate',\n        handler: 'url-pattern.validatePattern',\n        config: {\n          policies: [],\n        },\n      },\n      /**\n       * Search routes\n       */\n      {\n        method: 'GET',\n        path: '/search',\n        handler: 'search.search',\n        config: {\n          policies: [],\n        },\n      },\n      /**\n       * Reverse Search routes for a title or slug\n       */\n      {\n        method: 'GET',\n        path: '/search/reverse/:contentType/:documentId',\n        handler: 'search.reverseSearch',\n        config: {\n          policies: [],\n        },\n      },\n    ],\n  },\n};\n","\nimport { factories, UID } from '@strapi/strapi';\nimport { Context } from 'koa';\nimport { errors } from '@strapi/utils';\n\nimport { getPluginService } from '../util/getPluginService';\nimport { KoaContext } from '../types/koa';\nimport { GenerateParams } from '../services/bulk-generate';\n\n/**\n * URL alias controller\n */\n\nconst contentTypeSlug = 'plugin::webtools.url-alias';\n\nexport default factories.createCoreController(contentTypeSlug, ({ strapi }) => ({\n  editLink: async (ctx: Context) => {\n    const { path } = ctx.query;\n    const { entity, contentType } = await getPluginService('url-alias').findRelatedEntity(path as string, { status: 'draft' });\n\n    if (!entity) {\n      ctx.notFound();\n      return;\n    }\n\n    const contentTypeObj = strapi.contentTypes[contentType];\n    const contentTypeUrlPartial = contentTypeObj.kind === 'singleType' ? 'single-types' : 'collection-types';\n\n    const model = strapi.getModel(contentType);\n    // @ts-expect-error\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n    const isLocalized = model.pluginOptions.i18n?.localized as boolean;\n\n    ctx.body = {\n      link: `/content-manager/${contentTypeUrlPartial}/${contentType}/${contentTypeObj.kind === 'collectionType' ? entity.documentId : ''}${isLocalized ? `?plugins[i18n][locale]=${entity.locale}` : ''}`,\n    };\n  },\n  generate: async (\n    ctx: KoaContext<GenerateParams>,\n  ) => {\n    const { types, generationType } = ctx.request.body;\n\n    // Validation\n    if (!types || !generationType) {\n      const details: { [key in keyof GenerateParams]?: string } = {};\n\n      if (!generationType) details.types = 'required';\n      if (!generationType) details.generationType = 'required';\n\n      throw new errors.ValidationError('Missing required POST parameter(s)', details);\n    }\n\n    const generatedCount = await getPluginService('bulk-generate').generateUrlAliases({ types, generationType });\n\n    // Return the amount of generated URL aliases.\n    ctx.body = {\n      success: true,\n      message: `Successfully generated ${generatedCount} URL alias${generatedCount > 1 ? 'es' : ''}.`,\n    };\n  },\n  findFrom: async (ctx: KoaContext) => {\n    const {\n      model,\n      documentId,\n      locale,\n    } = ctx.query as { model: UID.ContentType, documentId: string, locale?: string };\n\n    const isSingleType = strapi.getModel(model)?.kind === 'singleType';\n\n    const entity = await strapi.documents(model as 'api::test.test').findFirst({\n      ...(!isSingleType ? { filters: { documentId } } : {}),\n      ...(locale ? { locale } : {}),\n      populate: ['url_alias'],\n      fields: [],\n    });\n\n    if (!entity || !entity.url_alias) {\n      ctx.body = [];\n      return;\n    }\n\n    ctx.body = entity.url_alias;\n  },\n}));\n","\n\nimport get from 'lodash/get';\nimport { Context } from 'koa';\nimport { factories, Schema, UID } from '@strapi/strapi';\nimport { KoaContext } from '../types/koa';\nimport { getPluginService } from '../util/getPluginService';\n\n/**\n * URL pattern controller\n */\n\nconst contentTypeSlug = 'plugin::webtools.url-pattern';\n\nexport default factories.createCoreController(contentTypeSlug, ({ strapi }) => ({\n  allowedFields: (ctx: Context) => {\n    const formattedFields = {};\n\n    Object.values(strapi.contentTypes).forEach((contentType: Schema.ContentType) => {\n      const fields = getPluginService('url-pattern').getAllowedFields(\n        contentType,\n        ['pluralName', 'string', 'text', 'uid', 'documentId'],\n      );\n      formattedFields[contentType.uid] = fields;\n    });\n\n    ctx.body = formattedFields;\n  },\n\n  validatePattern: (ctx: KoaContext<{ pattern: string, modelName: UID.ContentType }>) => {\n    const urlPatternService = getPluginService('url-pattern');\n    const { pattern, modelName } = ctx.request.body;\n\n    const contentType = strapi.contentTypes[modelName];\n\n    const fields = urlPatternService.getAllowedFields(contentType, [\n      'pluralName',\n      'string',\n      'text',\n      'uid',\n      'documentId',\n    ]);\n    const validated = urlPatternService.validatePattern(pattern, fields, contentType);\n\n    ctx.body = validated;\n  },\n}));\n","const getAddons = () => {\n  const enabledPlugins = strapi.config.get('enabledPlugins');\n\n  const addons: {\n    [key: string]: unknown\n  } = {};\n\n  Object.keys(enabledPlugins).forEach((plugin) => {\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n    const webtoolsAddon = enabledPlugins[plugin]?.info?.webtoolsAddon as boolean;\n\n    if (webtoolsAddon === true) {\n      addons[plugin] = enabledPlugins[plugin];\n    }\n  });\n\n  return addons;\n};\n\nexport default getAddons;\n","\n\nimport get from 'lodash/get';\nimport { Schema } from '@strapi/strapi';\nimport { Context } from 'koa';\nimport getAddons from '../util/getAddons';\n\n/**\n * Info controller\n */\n\nexport default {\n  getContentTypes: (ctx: Context) => {\n    const contentTypes: {\n      name: string;\n      uid: string;\n      localized: boolean;\n    }[] = [];\n\n    Object.values(strapi.contentTypes).forEach((contentType: Schema.ContentType) => {\n      const { pluginOptions } = contentType;\n\n      // Only return content types which have webtools enabled.\n      const isInContentManager = get(pluginOptions, [\n        'webtools',\n        'enabled',\n      ]) as boolean;\n      const isLocalized = get(pluginOptions, [\n        'i18n',\n        'localized',\n      ]) as boolean;\n      if (isInContentManager === true) {\n        contentTypes.push({\n          name: contentType.info.displayName,\n          uid: contentType.uid,\n          localized: isLocalized || false,\n        });\n      }\n    });\n\n    ctx.body = contentTypes;\n  },\n\n  getLanguages: async (ctx: Context) => {\n    const formattedLocales: {\n      name: string;\n      uid: string;\n    }[] = [];\n    const locales = await strapi.documents('plugin::i18n.locale').findMany();\n    locales.forEach((locale) => {\n      formattedLocales.push({\n        name: locale.name,\n        uid: locale.code,\n      });\n    });\n    ctx.body = formattedLocales;\n  },\n\n  getAddons: (ctx: Context) => {\n    const addons = getAddons();\n    ctx.body = addons;\n  },\n\n  getConfig: (ctx: Context) => {\n    const config = strapi.config.get('plugin::webtools');\n    ctx.body = config;\n  },\n};\n","import { Schema } from '@strapi/strapi';\n\nexport const sanitizeOutput = async (\n  data,\n  contentType: Schema.ContentType,\n  auth: unknown,\n) => strapi.contentAPI.sanitize.output(data, contentType, { auth });\n\nexport default {\n  sanitizeOutput,\n};\n","\nimport { Context } from 'koa';\nimport { Schema } from '@strapi/strapi';\n\nimport { getPluginService } from '../util/getPluginService';\nimport { sanitizeOutput } from '../util/sanitizeOutput';\n\ntype EntityResponse = { data: {}, meta: {} };\n\nconst routerWithControllers = async (ctx: Context) => {\n  const { path, ...searchQuery } = ctx.query;\n\n  // Find related entity by path.\n  const { entity, contentType } = await getPluginService('url-alias').findRelatedEntity(path as string, {\n    ...searchQuery,\n    fields: ['documentId'],\n  });\n\n  if (!entity) {\n    ctx.notFound();\n    return null;\n  }\n\n  const isSingleType = strapi.contentTypes[contentType].kind === 'singleType';\n  let controllerEntity: EntityResponse = null;\n\n  // Query the full entity using the content type controller.\n  if (isSingleType) {\n    controllerEntity = await strapi.controllers[contentType].find(ctx, async () => {}) as\n      EntityResponse;\n  } else {\n    controllerEntity = await strapi.controllers[contentType].findOne({\n      ...ctx,\n      query: {\n        ...ctx.query,\n      },\n      params: {\n        ...ctx.params as {},\n        id: entity.documentId,\n      },\n    }, async () => {}) as EntityResponse;\n  }\n\n  if (!controllerEntity) {\n    ctx.notFound();\n    return null;\n  }\n\n  // Add content type to response.\n  const responseEntity = {\n    data: {\n      ...controllerEntity.data,\n      contentType,\n    },\n    meta: {\n      ...controllerEntity.meta,\n    },\n  };\n\n  return responseEntity;\n};\n\n/**\n * Router controller\n */\n\nexport default {\n  router: async (ctx: Context) => {\n    const { path, ...searchQuery } = ctx.query;\n    const { auth } = ctx.state;\n\n    const routerUseControllers = strapi.config.get('plugin::webtools.router_use_controllers', false);\n\n    if (routerUseControllers) {\n      const entity = await routerWithControllers(ctx);\n\n      if (!entity) {\n        ctx.notFound();\n        return;\n      }\n\n      ctx.body = entity;\n      return;\n    }\n\n    // Find related entity by path.\n    const { entity, contentType } = await getPluginService('url-alias').findRelatedEntity(path as string, searchQuery);\n\n    if (!entity) {\n      ctx.notFound();\n      return;\n    }\n\n    // Check 'find' permissions for the content type we're querying.\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n    await strapi.auth.verify(auth, { scope: [`${contentType}.find`] });\n\n    // Add content type to response.\n    const responseEntity = {\n      ...entity,\n      contentType,\n    };\n\n    const contentTypeObj = strapi.contentTypes[contentType] as Schema.ContentType;\n\n    // Format response.\n    const sanitizedEntity = await sanitizeOutput(responseEntity, contentTypeObj, auth);\n    ctx.body = {\n      data: sanitizedEntity,\n      meta: {},\n    };\n  },\n};\n","import { Context } from 'koa';\nimport { UID, Schema } from '@strapi/strapi';\nimport { errors } from '@strapi/utils';\nimport { isContentTypeEnabled } from '../util/enabledContentTypes';\nimport { getPluginService } from '../util/getPluginService';\n\ninterface DocumentEntry {\n  id: number;\n  documentId: string;\n  [key: string]: unknown; // Dynamic fields like title, etc.\n}\n\ninterface SearchResult extends DocumentEntry {\n  contentType: string;\n}\n\n/**\n * Search controller\n */\nexport default {\n  search: async (ctx: Context & { params: { id: number } }) => {\n    const { q } = ctx.query;\n    const results: SearchResult[] = [];\n\n    const qStr = typeof q === 'string' ? q.trim() : '';\n    if (!qStr) {\n      throw new errors.ValidationError('Missing or invalid query parameter \"?q=\" (must be a non-empty string)');\n    }\n\n    await Promise.all(\n      Object.entries(strapi.contentTypes).map(\n        async ([uid, config]: [UID.ContentType, Schema.ContentType]) => {\n          const hasWT = isContentTypeEnabled(config);\n          if (!hasWT) return;\n\n          const mainField = await getPluginService('get-main-field').getMainField(uid);\n          if (!mainField) return;\n\n          const fieldsArr: string[] = ['documentId', ...(mainField ? [mainField] : [])];\n          const entries = (await strapi.documents(uid).findMany({\n            filters: {\n              [mainField]: { $containsi: qStr },\n            },\n            // @ts-expect-error\n            fields: fieldsArr,\n          }));\n\n          if (!entries || entries.length === 0) return;\n\n          const entriesWithContentType: SearchResult[] = entries.map((entry: DocumentEntry) => ({\n            ...entry,\n            mainField: entry[mainField],\n            contentType: uid,\n          }));\n\n          results.push(...entriesWithContentType);\n        },\n      ),\n    );\n\n    ctx.body = results;\n  },\n  reverseSearch: async (ctx: Context & { params: { contentType: string; documentId: string } }) => {\n    const { contentType, documentId } = ctx.params;\n\n    if (typeof contentType !== 'string' || !(contentType in strapi.contentTypes)) {\n      throw new errors.ValidationError(`Unknown or invalid content type: ${contentType}`);\n    }\n\n    const mainField = await getPluginService('get-main-field').getMainField(\n      contentType as UID.ContentType,\n    );\n    // eslint-disable-next-line max-len\n    const fieldsArr: string[] = ['id', 'documentId', ...(mainField ? [mainField] : [])];\n\n    const entry = (await strapi\n      .documents(contentType as UID.ContentType)\n      .findOne({\n        documentId,\n        // @ts-expect-error\n        fields: fieldsArr,\n      }));\n\n    if (!entry) {\n      throw new errors.NotFoundError('Entry not found');\n    }\n\n    ctx.body = {\n      id: entry.id,\n      documentId: entry.documentId,\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      ...(mainField ? { mainField: entry[mainField] } : {}),\n    };\n  },\n};\n","import urlAliasController from './url-alias';\nimport urlPatternController from './url-pattern';\nimport infoController from './info';\nimport coreController from './core';\nimport searchController from './search';\n\nexport default {\n  'url-alias': urlAliasController,\n  'url-pattern': urlPatternController,\n  info: infoController,\n  core: coreController,\n  search: searchController,\n};\n","import { factories, UID } from '@strapi/strapi';\nimport { Modules } from '@strapi/types';\nimport { getPluginService } from '../util/getPluginService';\n\n/**\n * URL alias service\n */\n\nconst contentTypeSlug = 'plugin::webtools.url-alias';\n\nconst customServices = () => ({\n  findRelatedEntity: async (path: string, query: Modules.Documents.ServiceParams<'api::test.test'>['findFirst'] = {}) => {\n    const urlAliasEntity = await getPluginService('url-alias').findByPath(path);\n    if (!urlAliasEntity) {\n      return {};\n    }\n\n    const contentTypeUid = urlAliasEntity.contenttype as UID.ContentType;\n    const model = strapi.getModel(contentTypeUid);\n    // @ts-expect-error\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n    const isLocalized = model.pluginOptions.i18n?.localized as boolean;\n\n    const entity = await strapi.documents(contentTypeUid as 'api::test.test').findFirst({\n      status: 'published',\n      ...query,\n      ...(isLocalized ? { locale: urlAliasEntity.locale } : {}),\n      filters: {\n        ...query?.filters,\n        url_alias: { documentId: urlAliasEntity.documentId },\n      },\n    });\n\n    if (!entity) {\n      return {};\n    }\n\n    return {\n      entity,\n      contentType: urlAliasEntity.contenttype as UID.ContentType,\n    };\n  },\n\n  /**\n   * findByPath.\n   *\n   * @param path the path.\n   * @param excludeFilters the id to ignore.\n   */\n  findByPath: async (path: string, excludeFilters: { [key: string]: any }[] = [{}]) => {\n    const locales = await strapi.documents('plugin::i18n.locale').findMany({ fields: 'code' });\n\n    let pathEntity: Modules.Documents.Document<'plugin::webtools.url-alias'> | null = null;\n\n    await locales.reduce(async (prevPromise, locale) => {\n      await prevPromise; // Ensure previous iteration is done\n      if (pathEntity) return; // Stop early if we already found one\n\n      pathEntity = await strapi.documents('plugin::webtools.url-alias').findFirst({\n        locale: locale.code,\n        filters: {\n          url_path: path,\n          $not: {\n            $and: excludeFilters,\n          },\n        },\n      });\n    }, Promise.resolve());\n\n    return pathEntity;\n  },\n\n  /**\n   * Finds a path from the original path that is unique\n   *\n   * @param originalPath The path as generated from the pattern and document\n   * @param currentDocumentId If generating for an existing document, its document id\n   * @param currentLocale If generating for an existing i18n document, its locale code\n   */\n  makeUniquePath: async (\n    originalPath: string,\n    currentDocumentId?: string,\n    currentLocale?: string,\n  ): Promise<string> => {\n    const uniquePerLocale = strapi.config.get('plugin::webtools.unique_per_locale', false);\n    let newPath = originalPath;\n\n    // FIXME: limit number of iterations to prevent overloading the server?\n    for (let iteration = -1; ; ++iteration) {\n      if (iteration >= 0) {\n        newPath = `${originalPath}-${iteration}`;\n      }\n\n      const filters: { $and: unknown[] } = {\n        $and: [\n          { url_path: newPath },\n        ],\n      };\n\n      if (currentDocumentId) {\n        const documentFilters: unknown[] = [{\n          documentId: { $eq: currentDocumentId },\n        }];\n\n        if (currentLocale) {\n          documentFilters.push({\n            locale: { $eq: currentLocale },\n          });\n        }\n\n        filters.$and.push({\n          $not: {\n            $and: documentFilters,\n          },\n        });\n      }\n\n      // This loop can't be parallelized as the iteration is increased between each step.\n      // eslint-disable-next-line no-await-in-loop\n      const existingPathEntity = await strapi.documents('plugin::webtools.url-alias').findFirst({\n        locale: uniquePerLocale ? currentLocale : undefined,\n        filters,\n      });\n\n      if (!existingPathEntity) {\n        break;\n      }\n    }\n\n    return newPath;\n  },\n});\n\nexport default factories.createCoreService(contentTypeSlug, customServices);\n","type TupleEntry<T extends readonly unknown[], I extends unknown[] = [], R = never> =\n  T extends readonly [infer Head, ...infer Tail] ?\n    TupleEntry<Tail, [...I, unknown], R | [`${I['length']}`, Head]> :\n    R;\n\n// eslint-disable-next-line @typescript-eslint/ban-types\ntype ObjectEntry<T extends {}> =\n  // eslint-disable-next-line @typescript-eslint/ban-types\n  T extends object ?\n    { [K in keyof T]: [K, Required<T>[K]] }[keyof T] extends infer E ?\n      E extends [infer K, infer V] ?\n        K extends string | number ?\n          [`${K}`, V] :\n          never :\n        never :\n      never :\n    never;\n\n// eslint-disable-next-line @typescript-eslint/ban-types\nexport type Entry<T extends {}> =\n  T extends readonly [unknown, ...unknown[]] ?\n    TupleEntry<T> :\n    T extends ReadonlyArray<infer U> ?\n      [`${number}`, U] :\n      ObjectEntry<T>;\n\n// eslint-disable-next-line @typescript-eslint/ban-types\nexport function typedEntries<T extends {}>(object: T): ReadonlyArray<Entry<T>> {\n  return Object.entries(object) as unknown as ReadonlyArray<Entry<T>>;\n}\n","import { factories, Schema, UID } from '@strapi/strapi';\nimport { getPluginService } from '../util/getPluginService';\nimport { typedEntries } from '../util/typeHelpers';\nimport { Config } from '../config';\n\nconst contentTypeSlug = 'plugin::webtools.url-pattern';\n\nconst customServices = () => ({\n  /**\n   * Find URL patterns by UID and optionally language code.\n   *\n   * @param {string} uid - The UID of the content type.\n   * @param {string} langcode - The optional language code.\n   * @returns {Promise<string[]>} The array of URL patterns.\n   */\n  findByUid: async (uid: string, langcode?: string): Promise<string[]> => {\n    let patterns = await strapi.documents(contentTypeSlug).findMany({\n      filters: {\n        contenttype: uid,\n      },\n    });\n\n    if (langcode) {\n      patterns = patterns.filter((pattern) => (pattern.languages as string).includes(langcode));\n    }\n\n    if (!patterns.length) {\n      return [strapi.config.get('plugin::webtools.default_pattern')];\n    }\n\n    const patternsArray = patterns.map((pattern) => pattern.pattern);\n\n    return patternsArray;\n  },\n\n  /**\n   * Get all field names allowed in the URL of a given content type.\n   *\n   * @param {string} contentType - The content type.\n   * @param {string[]} allowedFields - The allowed fields to include.\n   * @returns {string[]} The list of allowed field names.\n   */\n  getAllowedFields: (contentType: Schema.ContentType, allowedFields: string[] = []) => {\n    const fields: string[] = [];\n    allowedFields.forEach((fieldType) => {\n      typedEntries(contentType.attributes).forEach(([fieldName, field]) => {\n        if ((field.type === fieldType || fieldName === fieldType) && field.type !== 'relation') {\n          fields.push(fieldName);\n        } else if (\n          field.type === 'relation'\n          && fieldName !== 'localizations'\n          && fieldName !== 'createdBy'\n          && fieldName !== 'updatedBy'\n        ) {\n          // @ts-expect-error\n          // field.target is not strongly typed in the Strapi Attribute types.\n          const relation = strapi.contentTypes[field.target as UID.ContentType];\n\n          if (!relation) {\n            return;\n          }\n\n          if (allowedFields.includes('documentId') && !fields.includes(`${fieldName}.documentId`)) {\n            fields.push(`${fieldName}.documentId`);\n          }\n\n          typedEntries(relation.attributes).forEach(([subFieldName, subField]) => {\n            if (subField.type === fieldType || subFieldName === fieldType) {\n              fields.push(`${fieldName}.${subFieldName}`);\n            }\n          });\n        } else if (\n          field.type === 'component'\n          && field.component\n          && field.repeatable !== true // TODO: implement repeatable components.\n        ) {\n          const relation = strapi.components[field.component];\n\n          if (!relation) {\n            return;\n          }\n\n          if (allowedFields.includes('documentId') && !fields.includes(`${fieldName}.documentId`)) {\n            fields.push(`${fieldName}.documentId`);\n          }\n\n          Object.entries(relation.attributes).forEach(([subFieldName, subField]) => {\n            if (subField.type === fieldType || subFieldName === fieldType) {\n              fields.push(`${fieldName}.${subFieldName}`);\n            }\n          });\n        }\n      });\n    });\n\n    // Add documentId field manually because it is not on the attributes object of a content type.\n    if (allowedFields.includes('documentId')) {\n      fields.push('documentId');\n    }\n\n    if (allowedFields.includes('pluralName')) {\n      fields.push('pluralName');\n    }\n\n    return fields;\n  },\n\n  /**\n   * Get all fields from a pattern.\n   *\n   * @param {string} pattern - The patterns to extract fields from.\n   * @returns {string[]} The extracted fields.\n   */\n  getFieldsFromPattern: (pattern: string): string[] => {\n    const fields = pattern.match(/\\[[\\w\\d.\\-[\\]]+\\]/g); // Get all substrings between [] as array.\n\n    if (!fields) {\n      return [];\n    }\n\n    const newFields = fields.map((field) => field.slice(1, -1)); // Strip [] from string.\n\n    return newFields;\n  },\n\n  /**\n   * Get all relations from a pattern.\n   *\n   * @param {string} pattern - The patterns to extract relations from.\n   * @returns {string[]} The extracted relations.\n   */\n  getRelationsFromPattern: (pattern: string): string[] => {\n    // Get fields from the pattern (assuming they are inside square brackets)\n    let fields = getPluginService('url-pattern').getFieldsFromPattern(pattern);\n\n    // Filter out fields that are empty or malformed\n    fields = fields.filter((field) => field);\n\n    // For fields containing dots, extract the first part (relation)\n    const relations = fields\n      .filter((field) => field.includes('.'))\n      .map((field) => field.split('.')[0])\n      .map((relation) => relation.replace(/\\[\\d+\\]/g, '')); // Strip array index\n\n    return relations;\n  },\n\n\n  /**\n   * Resolve a pattern string from pattern to path for a single entity.\n   *\n   * @param {string} uid - The UID of the content type.\n   * @param {object} entity - The entity to resolve the pattern for.\n   * @param {string} [urlPattern] - The URL pattern to resolve.\n   * @returns {string} The resolved path.\n   */\n  resolvePattern: (\n    uid: UID.ContentType,\n    entity: Record<string, unknown>,\n    urlPattern?: string,\n  ): string => {\n    const resolve = (pattern: string) => {\n      let resolvedPattern: string = pattern;\n\n      const fields = getPluginService('url-pattern').getFieldsFromPattern(\n        pattern,\n      );\n\n      fields.forEach((field) => {\n        const relationalField = field.split('.').length > 1 ? field.split('.') : null;\n        const { slugify } = strapi.config.get<Config>('plugin::webtools');\n\n        if (field === 'pluralName') {\n          const fieldValue = strapi.contentTypes[uid].info.pluralName;\n\n          if (!fieldValue) {\n            return;\n          }\n\n          resolvedPattern = resolvedPattern.replace(`[${field}]`, fieldValue || '');\n        } else if (!relationalField) {\n          const fieldValue = slugify(String(entity[field]));\n          resolvedPattern = resolvedPattern.replace(`[${field}]`, fieldValue || '');\n        } else {\n          let relationName = relationalField[0];\n          let relationIndex: number | null = null;\n\n          const arrayMatch = relationName.match(/^([\\w-]+)\\[(\\d+)\\]$/);\n          if (arrayMatch) {\n            const [, name, index] = arrayMatch;\n            relationName = name;\n            relationIndex = parseInt(index, 10);\n          }\n\n          const relationEntity = entity[relationName];\n\n          if (Array.isArray(relationEntity) && relationIndex !== null) {\n            const subEntity = relationEntity[relationIndex] as\n              | Record<string, unknown>\n              | undefined;\n            const value = subEntity?.[relationalField[1]];\n            resolvedPattern = resolvedPattern.replace(\n              `[${field}]`,\n              value ? slugify(String(value)) : '',\n            );\n          } else if (\n            typeof relationEntity === 'object'\n            && relationEntity !== null\n            && !Array.isArray(relationEntity)\n          ) {\n            const value = (relationEntity as Record<string, unknown>)?.[relationalField[1]];\n            resolvedPattern = resolvedPattern.replace(\n              `[${field}]`,\n              value ? slugify(String(value)) : '',\n            );\n          } else {\n            strapi.log.error('Something went wrong whilst resolving the pattern.');\n          }\n        }\n      });\n\n      resolvedPattern = resolvedPattern.replace(/\\/+/g, '/'); // Remove duplicate forward slashes.\n      resolvedPattern = resolvedPattern.startsWith('/') ? resolvedPattern : `/${resolvedPattern}`; // Add a starting slash.\n      return resolvedPattern;\n    };\n\n    if (!urlPattern) {\n      return resolve(strapi.config.get('plugin::webtools.default_pattern'));\n    }\n\n    const path = resolve(urlPattern);\n    return path;\n  },\n\n  /**\n   * Validate if a pattern is correctly structured.\n   *\n   * @param {string} pattern - The pattern to validate.\n   * @param {string[]} allowedFieldNames - The allowed fields.\n   * @param {Schema.ContentType} contentType - The content type.\n   * @returns {object} The validation result.\n   */\n  validatePattern: (\n    pattern: string,\n    allowedFieldNames: string[],\n    contentType?: Schema.ContentType,\n  ): { valid: boolean, message: string } => {\n    if (!pattern) {\n      return {\n        valid: false,\n        message: 'Pattern cannot be empty',\n      };\n    }\n\n    const fields = getPluginService('url-pattern').getFieldsFromPattern(pattern);\n    let valid = true;\n    let message = '';\n\n    fields.forEach((field) => {\n      // Check if the field is allowed.\n      // We strip the array index from the field name to check if it is allowed.\n      // e.g. private_categories[0].slug -> private_categories.slug\n      const fieldName = field.replace(/\\[\\d+\\]/g, '');\n      if (!allowedFieldNames.includes(fieldName)) {\n        valid = false;\n        message = `Pattern contains forbidden fields: ${field}`;\n      }\n\n      // Check if the field is a ToMany relation and has an array index.\n      if (contentType && field.includes('.')) {\n        const [relationName] = field.split('.');\n        // Strip array index to get the attribute name\n        const attributeName = relationName.replace(/\\[\\d+\\]/g, '');\n        const attribute = contentType.attributes[\n          attributeName\n        ] as Schema.Attribute.Relation | undefined;\n\n        if (\n          attribute\n          && attribute.type === 'relation'\n          && typeof attribute.relation === 'string'\n          && !attribute.relation.endsWith('ToOne')\n          && !relationName.includes('[')\n        ) {\n          valid = false;\n          message = `The relation ${attributeName} is a ToMany relation and must include an array index (e.g. ${attributeName}[0]).`;\n        }\n      }\n    });\n\n    return {\n      valid,\n      message,\n    };\n  },\n});\n\nexport default factories.createCoreService(contentTypeSlug, customServices);\n","import { UID, Data } from '@strapi/strapi';\n\nimport { getPluginService } from '../util/getPluginService';\nimport { GenerationType } from '../types';\n\nexport interface GenerateParams {\n  types: UID.ContentType[],\n  generationType: GenerationType,\n}\n\n/**\n * Generate URL aliases based on given parameters.\n *\n * @param {GenerateParams} params - The parameters including types and generation type.\n * @returns {Promise<number>} - The total amount of generated URLs.\n */\nconst generateUrlAliases = async (params: GenerateParams): Promise<number> => {\n  const { types, generationType } = params;\n  let generatedCount = 0;\n\n  // Map over all the types sent in the request.\n  await Promise.all(types.map(async (type) => {\n    await strapi.db.transaction(async () => {\n      if (generationType === 'all') {\n        // Delete all the URL aliases for the given type.\n        await strapi.db.query('plugin::webtools.url-alias').deleteMany({\n          where: { contenttype: type },\n        });\n      }\n\n      if (generationType === 'only_generated') {\n        // Delete all the auto generated URL aliases of the given type.\n        await strapi.db.query('plugin::webtools.url-alias').deleteMany({\n          where: { contenttype: type, generated: true },\n        });\n      }\n\n      let relations: string[] = [];\n\n      // Get all relations for the type from all patterns for all languages.\n      const urlPatterns = await getPluginService('url-pattern').findByUid(type);\n      urlPatterns.forEach((urlPattern) => {\n        const languageRelations = getPluginService('url-pattern').getRelationsFromPattern(urlPattern);\n        relations = [...relations, ...languageRelations];\n      });\n\n      // Query all the entities of the type that do not have a corresponding URL alias.\n      const entities = await strapi.documents(type as 'api::test.test').findMany({\n        filters: { url_alias: null },\n        populate: {\n          ...relations.reduce((obj, key) => ({ ...obj, [key]: {} }), {}),\n          localizations: {\n            populate: {\n              ...relations.reduce((obj, key) => ({ ...obj, [key]: {} }), {}),\n            },\n          },\n        },\n      });\n\n      /**\n       * @todo\n       * We should do a Promise.all(entities.map()) here to speed up the process.\n       * Using that method we can create all the URL aliases in parallel.\n       * Currently this is not possible due to the duplicateCheck function.\n       * Race conditions can occur when two entities have the same URL path.\n       */\n      // eslint-disable-next-line no-restricted-syntax\n      for (const entity of entities) {\n        // FIXME: just filter the `urlPatterns` we already have.\n        // eslint-disable-next-line no-await-in-loop\n        const entityUrlPatterns = await getPluginService('url-pattern').findByUid(type, entity.locale);\n        const resolvedPath = getPluginService('url-pattern').resolvePattern(type, entity, entityUrlPatterns[0]);\n\n        // eslint-disable-next-line no-await-in-loop\n        const newUrlAlias = await strapi.documents('plugin::webtools.url-alias').create({\n          data: {\n            url_path: resolvedPath,\n            generated: true,\n            contenttype: type,\n            locale: entity.locale,\n          },\n        });\n\n        // eslint-disable-next-line no-await-in-loop\n        const allItems = await strapi.db.query(type as 'api::test.test').findMany({\n          where: {\n            ...(entity.locale ? { locale: entity.locale } : {}),\n            document_id: entity.documentId,\n          },\n        }) as Data.ContentType[];\n\n        // eslint-disable-next-line no-restricted-syntax\n        for (const doc of allItems) {\n          // eslint-disable-next-line no-await-in-loop\n          await strapi.db.query(type as 'api::test.test').updateRelations(doc.id, {\n            url_alias: [newUrlAlias.id],\n          });\n        }\n\n        // eslint-disable-next-line no-await-in-loop\n        await Promise.all(entity.localizations.map(async (loc) => {\n          const patterns = await getPluginService('url-pattern').findByUid(type, loc.locale);\n          const path = getPluginService('url-pattern').resolvePattern(type, loc, patterns[0]);\n\n          const alias = await strapi.documents('plugin::webtools.url-alias').update({\n            documentId: newUrlAlias.documentId,\n            locale: loc.locale,\n            data: {\n              url_path: path,\n              generated: true,\n              contenttype: type,\n              locale: entity.locale,\n            },\n            skipRegeneration: true,\n          });\n\n          // eslint-disable-next-line no-await-in-loop\n          const allLocalizations = await strapi.db.query(type as 'api::test.test').findMany({\n            where: {\n              ...(loc.locale ? { locale: loc.locale } : {}),\n              document_id: loc.documentId,\n            },\n          }) as Data.ContentType[];\n\n          // eslint-disable-next-line no-restricted-syntax\n          for (const doc of allLocalizations) {\n            // eslint-disable-next-line no-await-in-loop\n            await strapi.db.query(type as 'api::test.test').updateRelations(doc.id, {\n              url_alias: [alias.id],\n            });\n          }\n        }));\n\n        generatedCount += 1;\n      }\n    });\n  }));\n\n\n  return generatedCount;\n};\n\n\nexport default () => ({\n  generateUrlAliases,\n});\n","import { UID } from '@strapi/strapi';\n\ninterface ContentManagerConfig {\n  settings?: {\n    mainField?: string;\n  };\n}\n\nexport const getMainField = async (uid: UID.ContentType): Promise<string | null> => {\n  const coreStoreSettings = (await strapi\n    // TODO use documents service instead of any\n    .query('strapi::core-store' as UID.Schema)\n    .findMany({\n      where: { key: `plugin_content_manager_configuration_content_types::${uid}` },\n    })) as Array<{ value: string }>;\n\n  if (!coreStoreSettings?.[0]) return null;\n\n  const value = JSON.parse(coreStoreSettings[0].value) as ContentManagerConfig;\n\n  return value?.settings?.mainField ?? null;\n};\n\nexport default () => ({\n  getMainField,\n});\n","import urlAliasService from './url-alias';\nimport urlPatternService from './url-pattern';\nimport bulkGenerateService from './bulk-generate';\nimport getMainFieldService from './get-main-field';\n\nexport default {\n  'url-alias': urlAliasService,\n  'url-pattern': urlPatternService,\n  'bulk-generate': bulkGenerateService,\n  'get-main-field': getMainFieldService,\n};\n","import deburr from 'lodash/deburr';\nimport toLower from 'lodash/toLower';\nimport kebabCase from 'lodash/kebabCase';\n\nexport interface Config {\n  website_url: string;\n  default_pattern: string,\n  unique_per_locale: boolean,\n  router_use_controllers: boolean,\n  slugify: (fieldValue: string) => string,\n}\n\nconst config: {\n  default: Config,\n  validator: () => void\n} = {\n  default: {\n    router_use_controllers: false,\n    website_url: null,\n    default_pattern: '/[pluralName]/[documentId]',\n    slugify: (fieldValue) => kebabCase(deburr(toLower(fieldValue))),\n    unique_per_locale: false,\n  },\n  validator() {},\n};\n\nexport default config;\n","import urlAliasSchema from './url-alias/schema.json';\nimport urlPatternSchema from './url-pattern/schema.json';\n\nexport default {\n  'url-alias': {\n    schema: urlAliasSchema,\n  },\n  'url-pattern': {\n    schema: urlPatternSchema,\n  },\n};\n","\nimport register from './register';\nimport bootstrap from './bootstrap';\nimport routes from './routes';\nimport controllers from './controllers';\nimport services from './services';\nimport config from './config';\nimport contentTypes from './content-types';\n\nexport default {\n  register,\n  bootstrap,\n  config,\n  contentTypes,\n  routes,\n  controllers,\n  services,\n};\n"],"names":["pluginOptions","contentTypes","params","entity","relations","urlPatterns","fullEntity","strapi","attributes","contentTypeSlug","urlPatternService","config","customServices","index"],"mappings":"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"}