{"version":3,"file":"index.mjs","sources":["../../server/src/constants.ts","../../server/src/utils/getService.ts","../../server/src/utils/isProtectedEntry.ts","../../server/src/bootstrap.ts","../../server/src/register.ts","../../server/src/services/validation.ts","../../server/src/services/index.ts","../../server/src/index.ts"],"sourcesContent":["export const PLUGIN_ID = 'do-not-delete';\n","import { PLUGIN_ID } from '../constants';\nimport { type DoNotDeleteServices } from '../services';\n\nconst getService = <TName extends keyof DoNotDeleteServices>(\n  name: TName\n): DoNotDeleteServices[TName] =>\n  global.strapi.plugin(PLUGIN_ID).service<DoNotDeleteServices[TName]>(name);\n\nexport default getService;\n","import { type DoNotDeleteRule } from '../types';\n\nconst COMPARATOR_ACTIONS = {\n  // Equality.\n  is: (value, attr) => value === attr,\n  isNot: (value, attr) => value !== attr,\n\n  // Contains.\n  has: (value, attr) => attr.includes(value),\n  hasNot: (value, attr) => !attr.includes(value),\n  in: (value, attr) => value.includes(attr),\n  notIn: (value, attr) => !value.includes(attr),\n\n  // Greater than or equal to.\n  between: (value, attr) => attr >= value[0] && attr <= value[1],\n  gt: (value, attr) => attr > value,\n  gte: (value, attr) => attr >= value,\n  lt: (value, attr) => attr < value,\n  lte: (value, attr) => attr <= value,\n\n  // Dates.\n  after: (value, attr) => new Date(attr) > new Date(value),\n  before: (value, attr) => new Date(attr) < new Date(value),\n  day: (value, attr) => {\n    const d1 = new Date(attr);\n    const d2 = new Date(value);\n\n    return (\n      d1.getUTCDate() === d2.getUTCDate() &&\n      d1.getUTCMonth() === d2.getUTCMonth() &&\n      d1.getUTCFullYear() === d2.getUTCFullYear()\n    );\n  },\n  month: (value, attr) => {\n    const d1 = new Date(attr);\n    const d2 = new Date(value);\n\n    return d1.getUTCMonth() === d2.getUTCMonth() && d1.getUTCFullYear() === d2.getUTCFullYear();\n  },\n  year: (value, attr) => new Date(attr).getUTCFullYear() === new Date(value).getUTCFullYear(),\n\n  // Regular expression.\n  matches: (value, attr) => RegExp(value).test(attr),\n};\n\nconst isProtectedEntry = (entity: any, rules: DoNotDeleteRule[]): boolean =>\n  rules.some((rule) => {\n    const [attr, comparator, value] = rule;\n    const entityAttr = entity[attr];\n    const comparatorAction = COMPARATOR_ACTIONS[comparator];\n\n    return !!(comparatorAction && comparatorAction(value, entityAttr));\n  });\n\nexport default isProtectedEntry;\n","import { type Core, type UID } from '@strapi/strapi';\n\nimport { PLUGIN_ID } from './constants';\nimport { type DoNotDeletePluginOptions } from './types';\nimport { getService } from './utils';\n\nconst bootstrap = ({ strapi }: { strapi: Core.Strapi }) => {\n  const validateService = getService('validation');\n\n  // Verify any \"do not delete\" plugin options.\n  Object.keys(strapi.contentTypes).forEach((uid: UID.ContentType) => {\n    const contentType = strapi.contentTypes[uid];\n    const pluginOptions = contentType.pluginOptions\n      ? (contentType.pluginOptions[PLUGIN_ID] as DoNotDeletePluginOptions)\n      : null;\n\n    if (pluginOptions) {\n      validateService.validatePluginOptions(uid, pluginOptions);\n    }\n  });\n};\n\nexport default bootstrap;\n","import { type Core } from '@strapi/strapi';\n\nimport { PLUGIN_ID } from './constants';\nimport { getService } from './utils';\n\nconst register = async ({ strapi }: { strapi: Core.Strapi }) => {\n  const validateService = getService('validation');\n\n  // Middleware for the documents \"delete\" action.\n  strapi.documents.use(async (context: any, next) => {\n    const { action, contentType, params, uid } = context;\n    const { documentId } = params;\n    const pluginOptions = contentType.pluginOptions[PLUGIN_ID];\n\n    // Only run if this is a \"delete\" action and the contentType is configured for this plugin.\n    if (!['delete'].includes(action) || !pluginOptions) {\n      return next();\n    }\n\n    // Ensure the entity exists.\n    const entity = await strapi.documents(uid).findOne({ documentId });\n\n    if (!entity) {\n      return;\n    }\n\n    // Validate the delete action.\n    validateService.validateDeleteAction(entity, pluginOptions.rules);\n\n    return next();\n  });\n};\n\nexport default register;\n","import { type UID } from '@strapi/strapi';\nimport { errors } from '@strapi/utils';\n\nimport { type DoNotDeletePluginOptions, type DoNotDeleteRule } from '../types';\nimport { isProtectedEntry } from '../utils';\n\nexport type ValidationService = ReturnType<typeof validationService>;\n\nconst validationService = () => ({\n  validateDeleteAction(entry: any, rules: DoNotDeleteRule[]): void {\n    if (!rules || !rules.length) {\n      return;\n    }\n\n    // Do not delete if this is a protected entry.\n    if (isProtectedEntry(entry, rules)) {\n      throw new errors.ValidationError('This entry is protected and cannot be deleted.');\n    }\n  },\n\n  validatePluginOptions(uid: UID.ContentType, options: DoNotDeletePluginOptions): void {\n    // Require array for the `rules` prop.\n    if (!Array.isArray(options.rules)) {\n      throw new errors.ValidationError(\n        `Must define delete protection rules as an array for ${uid}.`\n      );\n    }\n\n    options.rules.forEach((rule) => {\n      // Require an array for each rule.\n      if (!Array.isArray(rule)) {\n        throw new errors.ValidationError(\n          `Must define delete protection rules as an array for ${uid}.`\n        );\n      }\n\n      // Require all 3 arguments per rule.\n      if (rule.length !== 3) {\n        throw new errors.ValidationError(\n          `Must define delete protection rules with all arguments for ${uid}.`\n        );\n      }\n\n      const comparator = rule[1];\n      const value = rule[2];\n      const comparators = [\n        'after',\n        'before',\n        'between',\n        'has',\n        'hasNot',\n        'in',\n        'notIn',\n        'is',\n        'isNot',\n        'gt',\n        'gte',\n        'lt',\n        'lte',\n        'day',\n        'month',\n        'year',\n        'matches',\n      ];\n\n      // Validate each `comparator` arg is a valid comparator.\n      if (!comparators.includes(comparator)) {\n        throw new errors.ValidationError(\n          `Unknown comparator ${comparator} used for ${uid} protection rules.`\n        );\n      }\n\n      // Validate `in` and `notIn` comparators are compared against an array `value`.\n      if (['in', 'notIn', 'between'].includes(comparator) && !Array.isArray(value)) {\n        throw new errors.ValidationError(\n          `Invalid ${comparator} value for ${uid} protection rules.`\n        );\n      }\n\n      // Validate `between` comparators are compared against an array of 2 `values`.\n      if (comparator === 'between' && value.length !== 2) {\n        throw new errors.ValidationError(\n          `Invalid number of array values for between comparators for ${uid} protection rules.`\n        );\n      }\n\n      // Validate date comparators are compared against a valid date string.\n      if (['day', 'month', 'year'].includes(comparator)) {\n        throw new errors.ValidationError(\n          `Invalid date string for ${comparator} value for ${uid} protection rules.`\n        );\n      }\n    });\n  },\n});\n\nexport default validationService;\n","import validation, { type ValidationService } from './validation';\n\nexport type DoNotDeleteServices = {\n  validation: ValidationService;\n};\n\nexport default {\n  validation,\n};\n","import bootstrap from './bootstrap';\nimport register from './register';\nimport services from './services';\n\nexport default {\n  bootstrap,\n  register,\n  services,\n};\n"],"names":["validation"],"mappings":"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"}