@strapi/content-releases 5.37.1 → 5.38.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/dist/admin/assets/purchase-page-illustration-dark.jpg.js.map +1 -1
  2. package/dist/admin/assets/purchase-page-illustration-dark.jpg.mjs.map +1 -1
  3. package/dist/admin/assets/purchase-page-illustration-light.jpg.js.map +1 -1
  4. package/dist/admin/assets/purchase-page-illustration-light.jpg.mjs.map +1 -1
  5. package/dist/admin/components/EntryValidationPopover.js.map +1 -1
  6. package/dist/admin/components/EntryValidationPopover.mjs +1 -1
  7. package/dist/admin/components/EntryValidationPopover.mjs.map +1 -1
  8. package/dist/admin/components/RelativeTime.js.map +1 -1
  9. package/dist/admin/components/RelativeTime.mjs.map +1 -1
  10. package/dist/admin/components/ReleaseAction.js.map +1 -1
  11. package/dist/admin/components/ReleaseAction.mjs +1 -1
  12. package/dist/admin/components/ReleaseAction.mjs.map +1 -1
  13. package/dist/admin/components/ReleaseActionMenu.js.map +1 -1
  14. package/dist/admin/components/ReleaseActionMenu.mjs +3 -3
  15. package/dist/admin/components/ReleaseActionMenu.mjs.map +1 -1
  16. package/dist/admin/components/ReleaseActionModal.js.map +1 -1
  17. package/dist/admin/components/ReleaseActionModal.mjs +2 -2
  18. package/dist/admin/components/ReleaseActionModal.mjs.map +1 -1
  19. package/dist/admin/components/ReleaseActionOptions.js.map +1 -1
  20. package/dist/admin/components/ReleaseActionOptions.mjs.map +1 -1
  21. package/dist/admin/components/ReleaseListCell.js.map +1 -1
  22. package/dist/admin/components/ReleaseListCell.mjs.map +1 -1
  23. package/dist/admin/components/ReleaseModal.js.map +1 -1
  24. package/dist/admin/components/ReleaseModal.mjs.map +1 -1
  25. package/dist/admin/components/ReleasesPanel.js.map +1 -1
  26. package/dist/admin/components/ReleasesPanel.mjs.map +1 -1
  27. package/dist/admin/components/Widgets.js.map +1 -1
  28. package/dist/admin/components/Widgets.mjs +1 -1
  29. package/dist/admin/components/Widgets.mjs.map +1 -1
  30. package/dist/admin/constants.js.map +1 -1
  31. package/dist/admin/constants.mjs.map +1 -1
  32. package/dist/admin/index.js +1 -0
  33. package/dist/admin/index.js.map +1 -1
  34. package/dist/admin/index.mjs +1 -0
  35. package/dist/admin/index.mjs.map +1 -1
  36. package/dist/admin/modules/hooks.js.map +1 -1
  37. package/dist/admin/modules/hooks.mjs.map +1 -1
  38. package/dist/admin/pages/App.js.map +1 -1
  39. package/dist/admin/pages/App.mjs.map +1 -1
  40. package/dist/admin/pages/PurchaseContentReleases.js.map +1 -1
  41. package/dist/admin/pages/PurchaseContentReleases.mjs.map +1 -1
  42. package/dist/admin/pages/ReleaseDetailsPage.js.map +1 -1
  43. package/dist/admin/pages/ReleaseDetailsPage.mjs +2 -2
  44. package/dist/admin/pages/ReleaseDetailsPage.mjs.map +1 -1
  45. package/dist/admin/pages/ReleasesPage.js.map +1 -1
  46. package/dist/admin/pages/ReleasesPage.mjs +1 -1
  47. package/dist/admin/pages/ReleasesPage.mjs.map +1 -1
  48. package/dist/admin/pages/ReleasesSettingsPage.js.map +1 -1
  49. package/dist/admin/pages/ReleasesSettingsPage.mjs +1 -1
  50. package/dist/admin/pages/ReleasesSettingsPage.mjs.map +1 -1
  51. package/dist/admin/services/homepage.js.map +1 -1
  52. package/dist/admin/services/homepage.mjs.map +1 -1
  53. package/dist/admin/services/release.js.map +1 -1
  54. package/dist/admin/services/release.mjs.map +1 -1
  55. package/dist/admin/store/hooks.js.map +1 -1
  56. package/dist/admin/store/hooks.mjs.map +1 -1
  57. package/dist/admin/translations/es.json.js +103 -0
  58. package/dist/admin/translations/es.json.js.map +1 -0
  59. package/dist/admin/translations/es.json.mjs +101 -0
  60. package/dist/admin/translations/es.json.mjs.map +1 -0
  61. package/dist/admin/utils/api.js.map +1 -1
  62. package/dist/admin/utils/api.mjs.map +1 -1
  63. package/dist/admin/utils/prefixPluginTranslations.js.map +1 -1
  64. package/dist/admin/utils/prefixPluginTranslations.mjs.map +1 -1
  65. package/dist/admin/utils/time.js.map +1 -1
  66. package/dist/admin/utils/time.mjs.map +1 -1
  67. package/dist/admin/validation/schemas.js.map +1 -1
  68. package/dist/admin/validation/schemas.mjs.map +1 -1
  69. package/dist/server/bootstrap.js.map +1 -1
  70. package/dist/server/bootstrap.mjs.map +1 -1
  71. package/dist/server/constants.js.map +1 -1
  72. package/dist/server/constants.mjs.map +1 -1
  73. package/dist/server/content-types/index.js +4 -4
  74. package/dist/server/content-types/index.js.map +1 -1
  75. package/dist/server/content-types/index.mjs.map +1 -1
  76. package/dist/server/content-types/release/index.js.map +1 -1
  77. package/dist/server/content-types/release/index.mjs.map +1 -1
  78. package/dist/server/content-types/release/schema.js.map +1 -1
  79. package/dist/server/content-types/release/schema.mjs.map +1 -1
  80. package/dist/server/content-types/release-action/index.js.map +1 -1
  81. package/dist/server/content-types/release-action/index.mjs.map +1 -1
  82. package/dist/server/content-types/release-action/schema.js.map +1 -1
  83. package/dist/server/content-types/release-action/schema.mjs.map +1 -1
  84. package/dist/server/controllers/homepage.js.map +1 -1
  85. package/dist/server/controllers/homepage.mjs.map +1 -1
  86. package/dist/server/controllers/index.js.map +1 -1
  87. package/dist/server/controllers/index.mjs.map +1 -1
  88. package/dist/server/controllers/release-action.js.map +1 -1
  89. package/dist/server/controllers/release-action.mjs +1 -1
  90. package/dist/server/controllers/release-action.mjs.map +1 -1
  91. package/dist/server/controllers/release.js.map +1 -1
  92. package/dist/server/controllers/release.mjs +1 -1
  93. package/dist/server/controllers/release.mjs.map +1 -1
  94. package/dist/server/controllers/settings.js.map +1 -1
  95. package/dist/server/controllers/settings.mjs.map +1 -1
  96. package/dist/server/controllers/validation/release-action.js.map +1 -1
  97. package/dist/server/controllers/validation/release-action.mjs.map +1 -1
  98. package/dist/server/controllers/validation/release.js.map +1 -1
  99. package/dist/server/controllers/validation/release.mjs.map +1 -1
  100. package/dist/server/controllers/validation/settings.js.map +1 -1
  101. package/dist/server/controllers/validation/settings.mjs.map +1 -1
  102. package/dist/server/destroy.js.map +1 -1
  103. package/dist/server/destroy.mjs.map +1 -1
  104. package/dist/server/index.js +9 -9
  105. package/dist/server/index.js.map +1 -1
  106. package/dist/server/index.mjs.map +1 -1
  107. package/dist/server/middlewares/documents.js.map +1 -1
  108. package/dist/server/middlewares/documents.mjs +1 -1
  109. package/dist/server/middlewares/documents.mjs.map +1 -1
  110. package/dist/server/migrations/database/5.0.0-document-id-in-actions.js.map +1 -1
  111. package/dist/server/migrations/database/5.0.0-document-id-in-actions.mjs.map +1 -1
  112. package/dist/server/migrations/index.js.map +1 -1
  113. package/dist/server/migrations/index.mjs.map +1 -1
  114. package/dist/server/register.js.map +1 -1
  115. package/dist/server/register.mjs.map +1 -1
  116. package/dist/server/routes/homepage.js.map +1 -1
  117. package/dist/server/routes/homepage.mjs.map +1 -1
  118. package/dist/server/routes/index.js.map +1 -1
  119. package/dist/server/routes/index.mjs.map +1 -1
  120. package/dist/server/routes/release-action.js.map +1 -1
  121. package/dist/server/routes/release-action.mjs.map +1 -1
  122. package/dist/server/routes/release.js.map +1 -1
  123. package/dist/server/routes/release.mjs.map +1 -1
  124. package/dist/server/routes/settings.js.map +1 -1
  125. package/dist/server/routes/settings.mjs.map +1 -1
  126. package/dist/server/services/homepage.js.map +1 -1
  127. package/dist/server/services/homepage.mjs.map +1 -1
  128. package/dist/server/services/index.js.map +1 -1
  129. package/dist/server/services/index.mjs.map +1 -1
  130. package/dist/server/services/release-action.js.map +1 -1
  131. package/dist/server/services/release-action.mjs +3 -3
  132. package/dist/server/services/release-action.mjs.map +1 -1
  133. package/dist/server/services/release.js +10 -3
  134. package/dist/server/services/release.js.map +1 -1
  135. package/dist/server/services/release.mjs +13 -6
  136. package/dist/server/services/release.mjs.map +1 -1
  137. package/dist/server/services/scheduling.js.map +1 -1
  138. package/dist/server/services/scheduling.mjs.map +1 -1
  139. package/dist/server/services/settings.js.map +1 -1
  140. package/dist/server/services/settings.mjs.map +1 -1
  141. package/dist/server/services/validation.js.map +1 -1
  142. package/dist/server/services/validation.mjs.map +1 -1
  143. package/dist/server/src/services/release.d.ts.map +1 -1
  144. package/dist/server/src/utils/index.d.ts +16 -0
  145. package/dist/server/src/utils/index.d.ts.map +1 -1
  146. package/dist/server/utils/index.js +91 -0
  147. package/dist/server/utils/index.js.map +1 -1
  148. package/dist/server/utils/index.mjs +91 -1
  149. package/dist/server/utils/index.mjs.map +1 -1
  150. package/package.json +17 -12
@@ -1 +1 @@
1
- {"version":3,"file":"release.mjs","sources":["../../../server/src/services/release.ts"],"sourcesContent":["import { setCreatorFields, errors } from '@strapi/utils';\n\nimport type { Core, Struct, UID, Data } from '@strapi/types';\n\nimport { ALLOWED_WEBHOOK_EVENTS, RELEASE_ACTION_MODEL_UID, RELEASE_MODEL_UID } from '../constants';\nimport type {\n GetReleases,\n CreateRelease,\n UpdateRelease,\n PublishRelease,\n GetRelease,\n Release,\n DeleteRelease,\n} from '../../../shared/contracts/releases';\nimport type { ReleaseAction } from '../../../shared/contracts/release-actions';\nimport type { UserInfo } from '../../../shared/types';\nimport { getService } from '../utils';\n\nconst createReleaseService = ({ strapi }: { strapi: Core.Strapi }) => {\n const dispatchWebhook = (\n event: string,\n { isPublished, release, error }: { isPublished: boolean; release?: any; error?: unknown }\n ) => {\n strapi.eventHub.emit(event, {\n isPublished,\n error,\n release,\n });\n };\n\n /**\n * Given a release id, it returns the actions formatted ready to be used to publish them.\n * We split them by contentType and type (publish/unpublish) and extract only the documentIds and locales.\n */\n const getFormattedActions = async (releaseId: Release['id']) => {\n const actions = (await strapi.db.query(RELEASE_ACTION_MODEL_UID).findMany({\n where: {\n release: {\n id: releaseId,\n },\n },\n })) as ReleaseAction[];\n\n if (actions.length === 0) {\n throw new errors.ValidationError('No entries to publish');\n }\n\n /**\n * We separate publish and unpublish actions, grouping them by contentType and extracting only their documentIds and locales.\n */\n const formattedActions: {\n [key: UID.ContentType]: {\n publish: { documentId: ReleaseAction['entryDocumentId']; locale?: string }[];\n unpublish: { documentId: ReleaseAction['entryDocumentId']; locale?: string }[];\n };\n } = {};\n\n for (const action of actions) {\n const contentTypeUid: UID.ContentType = action.contentType;\n\n if (!formattedActions[contentTypeUid]) {\n formattedActions[contentTypeUid] = {\n publish: [],\n unpublish: [],\n };\n }\n\n formattedActions[contentTypeUid][action.type].push({\n documentId: action.entryDocumentId,\n locale: action.locale,\n });\n }\n\n return formattedActions;\n };\n\n return {\n async create(releaseData: CreateRelease.Request['body'], { user }: { user: UserInfo }) {\n const releaseWithCreatorFields = await setCreatorFields({ user })(releaseData);\n\n const {\n validatePendingReleasesLimit,\n validateUniqueNameForPendingRelease,\n validateScheduledAtIsLaterThanNow,\n } = getService('release-validation', { strapi });\n\n await Promise.all([\n validatePendingReleasesLimit(),\n validateUniqueNameForPendingRelease(releaseWithCreatorFields.name),\n validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt),\n ]);\n\n const release = await strapi.db.query(RELEASE_MODEL_UID).create({\n data: {\n ...releaseWithCreatorFields,\n status: 'empty',\n },\n });\n\n if (releaseWithCreatorFields.scheduledAt) {\n const schedulingService = getService('scheduling', { strapi });\n\n await schedulingService.set(release.id, release.scheduledAt);\n }\n\n strapi.telemetry.send('didCreateContentRelease');\n\n return release;\n },\n\n async findOne(id: GetRelease.Request['params']['id'], query = {}) {\n const dbQuery = strapi.get('query-params').transform(RELEASE_MODEL_UID, query);\n const release = await strapi.db.query(RELEASE_MODEL_UID).findOne({\n ...dbQuery,\n where: { id },\n });\n\n return release;\n },\n\n findPage(query?: GetReleases.Request['query']) {\n const dbQuery = strapi.get('query-params').transform(RELEASE_MODEL_UID, query ?? {});\n\n return strapi.db.query(RELEASE_MODEL_UID).findPage({\n ...dbQuery,\n populate: {\n actions: {\n count: true,\n },\n },\n });\n },\n\n findMany(query?: any) {\n const dbQuery = strapi.get('query-params').transform(RELEASE_MODEL_UID, query ?? {});\n\n return strapi.db.query(RELEASE_MODEL_UID).findMany({\n ...dbQuery,\n });\n },\n\n async update(\n id: Data.ID,\n releaseData: UpdateRelease.Request['body'],\n { user }: { user: UserInfo }\n ) {\n const releaseWithCreatorFields = await setCreatorFields({ user, isEdition: true })(\n releaseData\n );\n\n const { validateUniqueNameForPendingRelease, validateScheduledAtIsLaterThanNow } = getService(\n 'release-validation',\n { strapi }\n );\n\n await Promise.all([\n validateUniqueNameForPendingRelease(releaseWithCreatorFields.name, id),\n validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt),\n ]);\n\n const release = await strapi.db.query(RELEASE_MODEL_UID).findOne({ where: { id } });\n\n if (!release) {\n throw new errors.NotFoundError(`No release found for id ${id}`);\n }\n\n if (release.releasedAt) {\n throw new errors.ValidationError('Release already published');\n }\n\n const updatedRelease = await strapi.db.query(RELEASE_MODEL_UID).update({\n where: { id },\n data: releaseWithCreatorFields,\n });\n\n const schedulingService = getService('scheduling', { strapi });\n\n if (releaseData.scheduledAt) {\n // set function always cancel the previous job if it exists, so we can call it directly\n await schedulingService.set(id, releaseData.scheduledAt);\n } else if (release.scheduledAt) {\n // When user don't send a scheduledAt and we have one on the release, means that user want to unschedule it\n schedulingService.cancel(id);\n }\n\n this.updateReleaseStatus(id);\n\n strapi.telemetry.send('didUpdateContentRelease');\n\n return updatedRelease;\n },\n\n async getAllComponents() {\n const contentManagerComponentsService = strapi\n .plugin('content-manager')\n .service('components');\n\n const components = await contentManagerComponentsService.findAllComponents();\n\n const componentsMap = components.reduce(\n (\n acc: { [key: Struct.ComponentSchema['uid']]: Struct.ComponentSchema },\n component: Struct.ComponentSchema\n ) => {\n acc[component.uid] = component;\n\n return acc;\n },\n {}\n );\n\n return componentsMap;\n },\n\n async delete(releaseId: DeleteRelease.Request['params']['id']) {\n const release: Release = await strapi.db.query(RELEASE_MODEL_UID).findOne({\n where: { id: releaseId },\n populate: {\n actions: {\n select: ['id'],\n },\n },\n });\n\n if (!release) {\n throw new errors.NotFoundError(`No release found for id ${releaseId}`);\n }\n\n if (release.releasedAt) {\n throw new errors.ValidationError('Release already published');\n }\n\n // Only delete the release and its actions is you in fact can delete all the actions and the release\n // Otherwise, if the transaction fails it throws an error\n await strapi.db.transaction(async () => {\n await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({\n where: {\n id: {\n $in: release.actions.map((action) => action.id),\n },\n },\n });\n\n await strapi.db.query(RELEASE_MODEL_UID).delete({\n where: {\n id: releaseId,\n },\n });\n });\n\n if (release.scheduledAt) {\n const schedulingService = getService('scheduling', { strapi });\n await schedulingService.cancel(release.id);\n }\n\n strapi.telemetry.send('didDeleteContentRelease');\n\n return release;\n },\n\n async publish(releaseId: PublishRelease.Request['params']['id']) {\n const {\n release,\n error,\n }: { release: Pick<Release, 'id' | 'releasedAt' | 'status'> | null; error: unknown | null } =\n await strapi.db.transaction(async ({ trx }) => {\n /**\n * We lock the release in this transaction, so any other process trying to publish it will wait until this transaction is finished\n * In this transaction we don't care about rollback, becasue we want to persist the lock until the end and if it fails we want to change the release status to failed\n */\n const lockedRelease = (await strapi.db\n ?.queryBuilder(RELEASE_MODEL_UID)\n .where({ id: releaseId })\n .select(['id', 'name', 'releasedAt', 'status'])\n .first()\n .transacting(trx)\n .forUpdate()\n .execute()) as Pick<Release, 'id' | 'name' | 'releasedAt' | 'status'> | undefined;\n\n if (!lockedRelease) {\n throw new errors.NotFoundError(`No release found for id ${releaseId}`);\n }\n\n if (lockedRelease.releasedAt) {\n throw new errors.ValidationError('Release already published');\n }\n\n if (lockedRelease.status === 'failed') {\n throw new errors.ValidationError('Release failed to publish');\n }\n\n try {\n strapi.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);\n\n const formattedActions = await getFormattedActions(releaseId);\n\n await strapi.db.transaction(async () =>\n Promise.all(\n Object.keys(formattedActions).map(async (contentTypeUid) => {\n const contentType = contentTypeUid as UID.ContentType;\n const { publish, unpublish } = formattedActions[contentType];\n\n return Promise.all([\n ...publish.map((params) => strapi.documents(contentType).publish(params)),\n ...unpublish.map((params) => strapi.documents(contentType).unpublish(params)),\n ]);\n })\n )\n );\n\n const release = await strapi.db.query(RELEASE_MODEL_UID).update({\n where: {\n id: releaseId,\n },\n data: {\n status: 'done',\n releasedAt: new Date(),\n },\n });\n\n dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {\n isPublished: true,\n release,\n });\n\n strapi.telemetry.send('didPublishContentRelease');\n\n return { release, error: null };\n } catch (error) {\n dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {\n isPublished: false,\n error,\n });\n\n // We need to run the update in the same transaction because the release is locked\n await strapi.db\n ?.queryBuilder(RELEASE_MODEL_UID)\n .where({ id: releaseId })\n .update({\n status: 'failed',\n })\n .transacting(trx)\n .execute();\n\n // At this point, we don't want to throw the error because if that happen we rollback the change in the release status\n // We want to throw the error after the transaction is finished, so we return the error\n return {\n release: null,\n error,\n };\n }\n });\n\n // Now the first transaction is commited, we can safely throw the error if it exists\n if (error instanceof Error) {\n throw error;\n }\n\n return release;\n },\n\n async updateReleaseStatus(releaseId: Release['id']) {\n const releaseActionService = getService('release-action', { strapi });\n\n const [totalActions, invalidActions] = await Promise.all([\n releaseActionService.countActions({\n filters: {\n release: releaseId,\n },\n }),\n releaseActionService.countActions({\n filters: {\n release: releaseId,\n isEntryValid: false,\n },\n }),\n ]);\n\n if (totalActions > 0) {\n if (invalidActions > 0) {\n return strapi.db.query(RELEASE_MODEL_UID).update({\n where: {\n id: releaseId,\n },\n data: {\n status: 'blocked',\n },\n });\n }\n\n return strapi.db.query(RELEASE_MODEL_UID).update({\n where: {\n id: releaseId,\n },\n data: {\n status: 'ready',\n },\n });\n }\n\n return strapi.db.query(RELEASE_MODEL_UID).update({\n where: {\n id: releaseId,\n },\n data: {\n status: 'empty',\n },\n });\n },\n };\n};\n\nexport type ReleaseService = ReturnType<typeof createReleaseService>;\n\nexport default createReleaseService;\n"],"names":["createReleaseService","strapi","dispatchWebhook","event","isPublished","release","error","eventHub","emit","getFormattedActions","releaseId","actions","db","query","RELEASE_ACTION_MODEL_UID","findMany","where","id","length","errors","ValidationError","formattedActions","action","contentTypeUid","contentType","publish","unpublish","type","push","documentId","entryDocumentId","locale","create","releaseData","user","releaseWithCreatorFields","setCreatorFields","validatePendingReleasesLimit","validateUniqueNameForPendingRelease","validateScheduledAtIsLaterThanNow","getService","Promise","all","name","scheduledAt","RELEASE_MODEL_UID","data","status","schedulingService","set","telemetry","send","findOne","dbQuery","get","transform","findPage","populate","count","update","isEdition","NotFoundError","releasedAt","updatedRelease","cancel","updateReleaseStatus","getAllComponents","contentManagerComponentsService","plugin","service","components","findAllComponents","componentsMap","reduce","acc","component","uid","delete","select","transaction","deleteMany","$in","map","trx","lockedRelease","queryBuilder","first","transacting","forUpdate","execute","log","info","Object","keys","params","documents","Date","ALLOWED_WEBHOOK_EVENTS","RELEASES_PUBLISH","Error","releaseActionService","totalActions","invalidActions","countActions","filters","isEntryValid"],"mappings":"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"}
1
+ {"version":3,"file":"release.mjs","sources":["../../../server/src/services/release.ts"],"sourcesContent":["import { setCreatorFields, errors } from '@strapi/utils';\n\nimport type { Core, Struct, UID, Data } from '@strapi/types';\n\nimport { ALLOWED_WEBHOOK_EVENTS, RELEASE_ACTION_MODEL_UID, RELEASE_MODEL_UID } from '../constants';\nimport type {\n GetReleases,\n CreateRelease,\n UpdateRelease,\n PublishRelease,\n GetRelease,\n Release,\n DeleteRelease,\n} from '../../../shared/contracts/releases';\nimport type { ReleaseAction } from '../../../shared/contracts/release-actions';\nimport type { UserInfo } from '../../../shared/types';\nimport { getService, getPublishOrderForContentTypes } from '../utils';\n\nconst createReleaseService = ({ strapi }: { strapi: Core.Strapi }) => {\n const dispatchWebhook = (\n event: string,\n { isPublished, release, error }: { isPublished: boolean; release?: any; error?: unknown }\n ) => {\n strapi.eventHub.emit(event, {\n isPublished,\n error,\n release,\n });\n };\n\n /**\n * Given a release id, it returns the actions formatted ready to be used to publish them.\n * We split them by contentType and type (publish/unpublish) and extract only the documentIds and locales.\n */\n const getFormattedActions = async (releaseId: Release['id']) => {\n const actions = (await strapi.db.query(RELEASE_ACTION_MODEL_UID).findMany({\n where: {\n release: {\n id: releaseId,\n },\n },\n })) as ReleaseAction[];\n\n if (actions.length === 0) {\n throw new errors.ValidationError('No entries to publish');\n }\n\n /**\n * We separate publish and unpublish actions, grouping them by contentType and extracting only their documentIds and locales.\n */\n const formattedActions: {\n [key: UID.ContentType]: {\n publish: { documentId: ReleaseAction['entryDocumentId']; locale?: string }[];\n unpublish: { documentId: ReleaseAction['entryDocumentId']; locale?: string }[];\n };\n } = {};\n\n for (const action of actions) {\n const contentTypeUid: UID.ContentType = action.contentType;\n\n if (!formattedActions[contentTypeUid]) {\n formattedActions[contentTypeUid] = {\n publish: [],\n unpublish: [],\n };\n }\n\n formattedActions[contentTypeUid][action.type].push({\n documentId: action.entryDocumentId,\n locale: action.locale,\n });\n }\n\n return formattedActions;\n };\n\n return {\n async create(releaseData: CreateRelease.Request['body'], { user }: { user: UserInfo }) {\n const releaseWithCreatorFields = await setCreatorFields({ user })(releaseData);\n\n const {\n validatePendingReleasesLimit,\n validateUniqueNameForPendingRelease,\n validateScheduledAtIsLaterThanNow,\n } = getService('release-validation', { strapi });\n\n await Promise.all([\n validatePendingReleasesLimit(),\n validateUniqueNameForPendingRelease(releaseWithCreatorFields.name),\n validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt),\n ]);\n\n const release = await strapi.db.query(RELEASE_MODEL_UID).create({\n data: {\n ...releaseWithCreatorFields,\n status: 'empty',\n },\n });\n\n if (releaseWithCreatorFields.scheduledAt) {\n const schedulingService = getService('scheduling', { strapi });\n\n await schedulingService.set(release.id, release.scheduledAt);\n }\n\n strapi.telemetry.send('didCreateContentRelease');\n\n return release;\n },\n\n async findOne(id: GetRelease.Request['params']['id'], query = {}) {\n const dbQuery = strapi.get('query-params').transform(RELEASE_MODEL_UID, query);\n const release = await strapi.db.query(RELEASE_MODEL_UID).findOne({\n ...dbQuery,\n where: { id },\n });\n\n return release;\n },\n\n findPage(query?: GetReleases.Request['query']) {\n const dbQuery = strapi.get('query-params').transform(RELEASE_MODEL_UID, query ?? {});\n\n return strapi.db.query(RELEASE_MODEL_UID).findPage({\n ...dbQuery,\n populate: {\n actions: {\n count: true,\n },\n },\n });\n },\n\n findMany(query?: any) {\n const dbQuery = strapi.get('query-params').transform(RELEASE_MODEL_UID, query ?? {});\n\n return strapi.db.query(RELEASE_MODEL_UID).findMany({\n ...dbQuery,\n });\n },\n\n async update(\n id: Data.ID,\n releaseData: UpdateRelease.Request['body'],\n { user }: { user: UserInfo }\n ) {\n const releaseWithCreatorFields = await setCreatorFields({ user, isEdition: true })(\n releaseData\n );\n\n const { validateUniqueNameForPendingRelease, validateScheduledAtIsLaterThanNow } = getService(\n 'release-validation',\n { strapi }\n );\n\n await Promise.all([\n validateUniqueNameForPendingRelease(releaseWithCreatorFields.name, id),\n validateScheduledAtIsLaterThanNow(releaseWithCreatorFields.scheduledAt),\n ]);\n\n const release = await strapi.db.query(RELEASE_MODEL_UID).findOne({ where: { id } });\n\n if (!release) {\n throw new errors.NotFoundError(`No release found for id ${id}`);\n }\n\n if (release.releasedAt) {\n throw new errors.ValidationError('Release already published');\n }\n\n const updatedRelease = await strapi.db.query(RELEASE_MODEL_UID).update({\n where: { id },\n data: releaseWithCreatorFields,\n });\n\n const schedulingService = getService('scheduling', { strapi });\n\n if (releaseData.scheduledAt) {\n // set function always cancel the previous job if it exists, so we can call it directly\n await schedulingService.set(id, releaseData.scheduledAt);\n } else if (release.scheduledAt) {\n // When user don't send a scheduledAt and we have one on the release, means that user want to unschedule it\n schedulingService.cancel(id);\n }\n\n this.updateReleaseStatus(id);\n\n strapi.telemetry.send('didUpdateContentRelease');\n\n return updatedRelease;\n },\n\n async getAllComponents() {\n const contentManagerComponentsService = strapi\n .plugin('content-manager')\n .service('components');\n\n const components = await contentManagerComponentsService.findAllComponents();\n\n const componentsMap = components.reduce(\n (\n acc: { [key: Struct.ComponentSchema['uid']]: Struct.ComponentSchema },\n component: Struct.ComponentSchema\n ) => {\n acc[component.uid] = component;\n\n return acc;\n },\n {}\n );\n\n return componentsMap;\n },\n\n async delete(releaseId: DeleteRelease.Request['params']['id']) {\n const release: Release = await strapi.db.query(RELEASE_MODEL_UID).findOne({\n where: { id: releaseId },\n populate: {\n actions: {\n select: ['id'],\n },\n },\n });\n\n if (!release) {\n throw new errors.NotFoundError(`No release found for id ${releaseId}`);\n }\n\n if (release.releasedAt) {\n throw new errors.ValidationError('Release already published');\n }\n\n // Only delete the release and its actions is you in fact can delete all the actions and the release\n // Otherwise, if the transaction fails it throws an error\n await strapi.db.transaction(async () => {\n await strapi.db.query(RELEASE_ACTION_MODEL_UID).deleteMany({\n where: {\n id: {\n $in: release.actions.map((action) => action.id),\n },\n },\n });\n\n await strapi.db.query(RELEASE_MODEL_UID).delete({\n where: {\n id: releaseId,\n },\n });\n });\n\n if (release.scheduledAt) {\n const schedulingService = getService('scheduling', { strapi });\n await schedulingService.cancel(release.id);\n }\n\n strapi.telemetry.send('didDeleteContentRelease');\n\n return release;\n },\n\n async publish(releaseId: PublishRelease.Request['params']['id']) {\n const {\n release,\n error,\n }: { release: Pick<Release, 'id' | 'releasedAt' | 'status'> | null; error: unknown | null } =\n await strapi.db.transaction(async ({ trx }) => {\n /**\n * We lock the release in this transaction, so any other process trying to publish it will wait until this transaction is finished\n * In this transaction we don't care about rollback, becasue we want to persist the lock until the end and if it fails we want to change the release status to failed\n */\n const lockedRelease = (await strapi.db\n ?.queryBuilder(RELEASE_MODEL_UID)\n .where({ id: releaseId })\n .select(['id', 'name', 'releasedAt', 'status'])\n .first()\n .transacting(trx)\n .forUpdate()\n .execute()) as Pick<Release, 'id' | 'name' | 'releasedAt' | 'status'> | undefined;\n\n if (!lockedRelease) {\n throw new errors.NotFoundError(`No release found for id ${releaseId}`);\n }\n\n if (lockedRelease.releasedAt) {\n throw new errors.ValidationError('Release already published');\n }\n\n if (lockedRelease.status === 'failed') {\n throw new errors.ValidationError('Release failed to publish');\n }\n\n try {\n strapi.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);\n\n const formattedActions = await getFormattedActions(releaseId);\n\n // Publish content types in dependency order so that when entity A has a relation\n // to entity B, B is published first to keep this relation.\n const contentTypeUids = getPublishOrderForContentTypes(\n Object.keys(formattedActions) as UID.ContentType[],\n { strapi }\n );\n\n await strapi.db.transaction(async () => {\n for (const contentTypeUid of contentTypeUids) {\n const contentType = contentTypeUid as UID.ContentType;\n const { publish, unpublish } = formattedActions[contentType];\n\n await Promise.all([\n ...publish.map((params) => strapi.documents(contentType).publish(params)),\n ...unpublish.map((params) => strapi.documents(contentType).unpublish(params)),\n ]);\n }\n });\n\n const release = await strapi.db.query(RELEASE_MODEL_UID).update({\n where: {\n id: releaseId,\n },\n data: {\n status: 'done',\n releasedAt: new Date(),\n },\n });\n\n dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {\n isPublished: true,\n release,\n });\n\n strapi.telemetry.send('didPublishContentRelease');\n\n return { release, error: null };\n } catch (error) {\n dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {\n isPublished: false,\n error,\n });\n\n // We need to run the update in the same transaction because the release is locked\n await strapi.db\n ?.queryBuilder(RELEASE_MODEL_UID)\n .where({ id: releaseId })\n .update({\n status: 'failed',\n })\n .transacting(trx)\n .execute();\n\n // At this point, we don't want to throw the error because if that happen we rollback the change in the release status\n // We want to throw the error after the transaction is finished, so we return the error\n return {\n release: null,\n error,\n };\n }\n });\n\n // Now the first transaction is commited, we can safely throw the error if it exists\n if (error instanceof Error) {\n throw error;\n }\n\n return release;\n },\n\n async updateReleaseStatus(releaseId: Release['id']) {\n const releaseActionService = getService('release-action', { strapi });\n\n const [totalActions, invalidActions] = await Promise.all([\n releaseActionService.countActions({\n filters: {\n release: releaseId,\n },\n }),\n releaseActionService.countActions({\n filters: {\n release: releaseId,\n isEntryValid: false,\n },\n }),\n ]);\n\n if (totalActions > 0) {\n if (invalidActions > 0) {\n return strapi.db.query(RELEASE_MODEL_UID).update({\n where: {\n id: releaseId,\n },\n data: {\n status: 'blocked',\n },\n });\n }\n\n return strapi.db.query(RELEASE_MODEL_UID).update({\n where: {\n id: releaseId,\n },\n data: {\n status: 'ready',\n },\n });\n }\n\n return strapi.db.query(RELEASE_MODEL_UID).update({\n where: {\n id: releaseId,\n },\n data: {\n status: 'empty',\n },\n });\n },\n };\n};\n\nexport type ReleaseService = ReturnType<typeof createReleaseService>;\n\nexport default createReleaseService;\n"],"names":["createReleaseService","strapi","dispatchWebhook","event","isPublished","release","error","eventHub","emit","getFormattedActions","releaseId","actions","db","query","RELEASE_ACTION_MODEL_UID","findMany","where","id","length","errors","ValidationError","formattedActions","action","contentTypeUid","contentType","publish","unpublish","type","push","documentId","entryDocumentId","locale","create","releaseData","user","releaseWithCreatorFields","setCreatorFields","validatePendingReleasesLimit","validateUniqueNameForPendingRelease","validateScheduledAtIsLaterThanNow","getService","Promise","all","name","scheduledAt","RELEASE_MODEL_UID","data","status","schedulingService","set","telemetry","send","findOne","dbQuery","get","transform","findPage","populate","count","update","isEdition","NotFoundError","releasedAt","updatedRelease","cancel","updateReleaseStatus","getAllComponents","contentManagerComponentsService","plugin","service","components","findAllComponents","componentsMap","reduce","acc","component","uid","delete","select","transaction","deleteMany","$in","map","trx","lockedRelease","queryBuilder","first","transacting","forUpdate","execute","log","info","contentTypeUids","getPublishOrderForContentTypes","Object","keys","params","documents","Date","ALLOWED_WEBHOOK_EVENTS","RELEASES_PUBLISH","Error","releaseActionService","totalActions","invalidActions","countActions","filters","isEntryValid"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"scheduling.js","sources":["../../../server/src/services/scheduling.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport { errors } from '@strapi/utils';\nimport { Release } from '../../../shared/contracts/releases';\nimport { getService } from '../utils';\nimport { RELEASE_MODEL_UID } from '../constants';\n\nconst createSchedulingService = ({ strapi }: { strapi: Core.Strapi }) => {\n const scheduledJobs = new Map<Release['id'], string>();\n\n return {\n async set(releaseId: Release['id'], scheduleDate: Date) {\n const release = await strapi.db\n .query(RELEASE_MODEL_UID)\n .findOne({ where: { id: releaseId, releasedAt: null } });\n\n if (!release) {\n throw new errors.NotFoundError(`No release found for id ${releaseId}`);\n }\n\n const taskName = `publishRelease_${releaseId}`;\n\n strapi.cron.add({\n [taskName]: {\n async task() {\n try {\n await getService('release', { strapi }).publish(releaseId);\n // @TODO: Trigger webhook with success message\n } catch (error) {\n // @TODO: Trigger webhook with error message\n }\n },\n options: scheduleDate,\n },\n });\n\n if (scheduledJobs.has(releaseId)) {\n this.cancel(releaseId);\n }\n\n scheduledJobs.set(releaseId, taskName);\n\n return scheduledJobs;\n },\n\n cancel(releaseId: Release['id']) {\n if (scheduledJobs.has(releaseId)) {\n strapi.cron.remove(scheduledJobs.get(releaseId)!);\n scheduledJobs.delete(releaseId);\n }\n\n return scheduledJobs;\n },\n\n getAll() {\n return scheduledJobs;\n },\n\n /**\n * On bootstrap, we can use this function to make sure to sync the scheduled jobs from the database that are not yet released\n * This is useful in case the server was restarted and the scheduled jobs were lost\n * This also could be used to sync different Strapi instances in case of a cluster\n */\n async syncFromDatabase() {\n const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({\n where: {\n scheduledAt: {\n $gte: new Date(),\n },\n releasedAt: null,\n },\n });\n\n for (const release of releases) {\n this.set(release.id, release.scheduledAt);\n }\n\n return scheduledJobs;\n },\n };\n};\n\nexport default createSchedulingService;\n"],"names":["createSchedulingService","strapi","scheduledJobs","Map","set","releaseId","scheduleDate","release","db","query","RELEASE_MODEL_UID","findOne","where","id","releasedAt","errors","NotFoundError","taskName","cron","add","task","getService","publish","error","options","has","cancel","remove","get","delete","getAll","syncFromDatabase","releases","findMany","scheduledAt","$gte","Date"],"mappings":";;;;;;AAOA,MAAMA,uBAA0B,GAAA,CAAC,EAAEC,MAAM,EAA2B,GAAA;AAClE,IAAA,MAAMC,gBAAgB,IAAIC,GAAAA,EAAAA;IAE1B,OAAO;QACL,MAAMC,GAAAA,CAAAA,CAAIC,SAAwB,EAAEC,YAAkB,EAAA;YACpD,MAAMC,OAAAA,GAAU,MAAMN,MAAOO,CAAAA,EAAE,CAC5BC,KAAK,CAACC,2BACNC,CAAAA,CAAAA,OAAO,CAAC;gBAAEC,KAAO,EAAA;oBAAEC,EAAIR,EAAAA,SAAAA;oBAAWS,UAAY,EAAA;AAAK;AAAE,aAAA,CAAA;AAExD,YAAA,IAAI,CAACP,OAAS,EAAA;AACZ,gBAAA,MAAM,IAAIQ,YAAOC,CAAAA,aAAa,CAAC,CAAC,wBAAwB,EAAEX,SAAW,CAAA,CAAA,CAAA;AACvE;AAEA,YAAA,MAAMY,QAAW,GAAA,CAAC,eAAe,EAAEZ,SAAW,CAAA,CAAA;YAE9CJ,MAAOiB,CAAAA,IAAI,CAACC,GAAG,CAAC;AACd,gBAAA,CAACF,WAAW;oBACV,MAAMG,IAAAA,CAAAA,GAAAA;wBACJ,IAAI;AACF,4BAAA,MAAMC,iBAAW,SAAW,EAAA;AAAEpB,gCAAAA;AAAO,6BAAA,CAAA,CAAGqB,OAAO,CAACjB,SAAAA,CAAAA;;AAElD,yBAAA,CAAE,OAAOkB,KAAO,EAAA;;AAEhB;AACF,qBAAA;oBACAC,OAASlB,EAAAA;AACX;AACF,aAAA,CAAA;YAEA,IAAIJ,aAAAA,CAAcuB,GAAG,CAACpB,SAAY,CAAA,EAAA;gBAChC,IAAI,CAACqB,MAAM,CAACrB,SAAAA,CAAAA;AACd;YAEAH,aAAcE,CAAAA,GAAG,CAACC,SAAWY,EAAAA,QAAAA,CAAAA;YAE7B,OAAOf,aAAAA;AACT,SAAA;AAEAwB,QAAAA,MAAAA,CAAAA,CAAOrB,SAAwB,EAAA;YAC7B,IAAIH,aAAAA,CAAcuB,GAAG,CAACpB,SAAY,CAAA,EAAA;AAChCJ,gBAAAA,MAAAA,CAAOiB,IAAI,CAACS,MAAM,CAACzB,aAAAA,CAAc0B,GAAG,CAACvB,SAAAA,CAAAA,CAAAA;AACrCH,gBAAAA,aAAAA,CAAc2B,MAAM,CAACxB,SAAAA,CAAAA;AACvB;YAEA,OAAOH,aAAAA;AACT,SAAA;AAEA4B,QAAAA,MAAAA,CAAAA,GAAAA;YACE,OAAO5B,aAAAA;AACT,SAAA;AAEA;;;;AAIC,QACD,MAAM6B,gBAAAA,CAAAA,GAAAA;YACJ,MAAMC,QAAAA,GAAW,MAAM/B,MAAOO,CAAAA,EAAE,CAACC,KAAK,CAACC,2BAAmBuB,CAAAA,CAAAA,QAAQ,CAAC;gBACjErB,KAAO,EAAA;oBACLsB,WAAa,EAAA;AACXC,wBAAAA,IAAAA,EAAM,IAAIC,IAAAA;AACZ,qBAAA;oBACAtB,UAAY,EAAA;AACd;AACF,aAAA,CAAA;YAEA,KAAK,MAAMP,WAAWyB,QAAU,CAAA;AAC9B,gBAAA,IAAI,CAAC5B,GAAG,CAACG,QAAQM,EAAE,EAAEN,QAAQ2B,WAAW,CAAA;AAC1C;YAEA,OAAOhC,aAAAA;AACT;AACF,KAAA;AACF;;;;"}
1
+ {"version":3,"file":"scheduling.js","sources":["../../../server/src/services/scheduling.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport { errors } from '@strapi/utils';\nimport { Release } from '../../../shared/contracts/releases';\nimport { getService } from '../utils';\nimport { RELEASE_MODEL_UID } from '../constants';\n\nconst createSchedulingService = ({ strapi }: { strapi: Core.Strapi }) => {\n const scheduledJobs = new Map<Release['id'], string>();\n\n return {\n async set(releaseId: Release['id'], scheduleDate: Date) {\n const release = await strapi.db\n .query(RELEASE_MODEL_UID)\n .findOne({ where: { id: releaseId, releasedAt: null } });\n\n if (!release) {\n throw new errors.NotFoundError(`No release found for id ${releaseId}`);\n }\n\n const taskName = `publishRelease_${releaseId}`;\n\n strapi.cron.add({\n [taskName]: {\n async task() {\n try {\n await getService('release', { strapi }).publish(releaseId);\n // @TODO: Trigger webhook with success message\n } catch (error) {\n // @TODO: Trigger webhook with error message\n }\n },\n options: scheduleDate,\n },\n });\n\n if (scheduledJobs.has(releaseId)) {\n this.cancel(releaseId);\n }\n\n scheduledJobs.set(releaseId, taskName);\n\n return scheduledJobs;\n },\n\n cancel(releaseId: Release['id']) {\n if (scheduledJobs.has(releaseId)) {\n strapi.cron.remove(scheduledJobs.get(releaseId)!);\n scheduledJobs.delete(releaseId);\n }\n\n return scheduledJobs;\n },\n\n getAll() {\n return scheduledJobs;\n },\n\n /**\n * On bootstrap, we can use this function to make sure to sync the scheduled jobs from the database that are not yet released\n * This is useful in case the server was restarted and the scheduled jobs were lost\n * This also could be used to sync different Strapi instances in case of a cluster\n */\n async syncFromDatabase() {\n const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({\n where: {\n scheduledAt: {\n $gte: new Date(),\n },\n releasedAt: null,\n },\n });\n\n for (const release of releases) {\n this.set(release.id, release.scheduledAt);\n }\n\n return scheduledJobs;\n },\n };\n};\n\nexport default createSchedulingService;\n"],"names":["createSchedulingService","strapi","scheduledJobs","Map","set","releaseId","scheduleDate","release","db","query","RELEASE_MODEL_UID","findOne","where","id","releasedAt","errors","NotFoundError","taskName","cron","add","task","getService","publish","error","options","has","cancel","remove","get","delete","getAll","syncFromDatabase","releases","findMany","scheduledAt","$gte","Date"],"mappings":";;;;;;AAOA,MAAMA,uBAAAA,GAA0B,CAAC,EAAEC,MAAM,EAA2B,GAAA;AAClE,IAAA,MAAMC,gBAAgB,IAAIC,GAAAA,EAAAA;IAE1B,OAAO;QACL,MAAMC,GAAAA,CAAAA,CAAIC,SAAwB,EAAEC,YAAkB,EAAA;YACpD,MAAMC,OAAAA,GAAU,MAAMN,MAAAA,CAAOO,EAAE,CAC5BC,KAAK,CAACC,2BAAAA,CAAAA,CACNC,OAAO,CAAC;gBAAEC,KAAAA,EAAO;oBAAEC,EAAAA,EAAIR,SAAAA;oBAAWS,UAAAA,EAAY;AAAK;AAAE,aAAA,CAAA;AAExD,YAAA,IAAI,CAACP,OAAAA,EAAS;AACZ,gBAAA,MAAM,IAAIQ,YAAAA,CAAOC,aAAa,CAAC,CAAC,wBAAwB,EAAEX,SAAAA,CAAAA,CAAW,CAAA;AACvE,YAAA;AAEA,YAAA,MAAMY,QAAAA,GAAW,CAAC,eAAe,EAAEZ,SAAAA,CAAAA,CAAW;YAE9CJ,MAAAA,CAAOiB,IAAI,CAACC,GAAG,CAAC;AACd,gBAAA,CAACF,WAAW;oBACV,MAAMG,IAAAA,CAAAA,GAAAA;wBACJ,IAAI;AACF,4BAAA,MAAMC,iBAAW,SAAA,EAAW;AAAEpB,gCAAAA;AAAO,6BAAA,CAAA,CAAGqB,OAAO,CAACjB,SAAAA,CAAAA;;AAElD,wBAAA,CAAA,CAAE,OAAOkB,KAAAA,EAAO;;AAEhB,wBAAA;AACF,oBAAA,CAAA;oBACAC,OAAAA,EAASlB;AACX;AACF,aAAA,CAAA;YAEA,IAAIJ,aAAAA,CAAcuB,GAAG,CAACpB,SAAAA,CAAAA,EAAY;gBAChC,IAAI,CAACqB,MAAM,CAACrB,SAAAA,CAAAA;AACd,YAAA;YAEAH,aAAAA,CAAcE,GAAG,CAACC,SAAAA,EAAWY,QAAAA,CAAAA;YAE7B,OAAOf,aAAAA;AACT,QAAA,CAAA;AAEAwB,QAAAA,MAAAA,CAAAA,CAAOrB,SAAwB,EAAA;YAC7B,IAAIH,aAAAA,CAAcuB,GAAG,CAACpB,SAAAA,CAAAA,EAAY;AAChCJ,gBAAAA,MAAAA,CAAOiB,IAAI,CAACS,MAAM,CAACzB,aAAAA,CAAc0B,GAAG,CAACvB,SAAAA,CAAAA,CAAAA;AACrCH,gBAAAA,aAAAA,CAAc2B,MAAM,CAACxB,SAAAA,CAAAA;AACvB,YAAA;YAEA,OAAOH,aAAAA;AACT,QAAA,CAAA;AAEA4B,QAAAA,MAAAA,CAAAA,GAAAA;YACE,OAAO5B,aAAAA;AACT,QAAA,CAAA;AAEA;;;;AAIC,QACD,MAAM6B,gBAAAA,CAAAA,GAAAA;YACJ,MAAMC,QAAAA,GAAW,MAAM/B,MAAAA,CAAOO,EAAE,CAACC,KAAK,CAACC,2BAAAA,CAAAA,CAAmBuB,QAAQ,CAAC;gBACjErB,KAAAA,EAAO;oBACLsB,WAAAA,EAAa;AACXC,wBAAAA,IAAAA,EAAM,IAAIC,IAAAA;AACZ,qBAAA;oBACAtB,UAAAA,EAAY;AACd;AACF,aAAA,CAAA;YAEA,KAAK,MAAMP,WAAWyB,QAAAA,CAAU;AAC9B,gBAAA,IAAI,CAAC5B,GAAG,CAACG,QAAQM,EAAE,EAAEN,QAAQ2B,WAAW,CAAA;AAC1C,YAAA;YAEA,OAAOhC,aAAAA;AACT,QAAA;AACF,KAAA;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"scheduling.mjs","sources":["../../../server/src/services/scheduling.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport { errors } from '@strapi/utils';\nimport { Release } from '../../../shared/contracts/releases';\nimport { getService } from '../utils';\nimport { RELEASE_MODEL_UID } from '../constants';\n\nconst createSchedulingService = ({ strapi }: { strapi: Core.Strapi }) => {\n const scheduledJobs = new Map<Release['id'], string>();\n\n return {\n async set(releaseId: Release['id'], scheduleDate: Date) {\n const release = await strapi.db\n .query(RELEASE_MODEL_UID)\n .findOne({ where: { id: releaseId, releasedAt: null } });\n\n if (!release) {\n throw new errors.NotFoundError(`No release found for id ${releaseId}`);\n }\n\n const taskName = `publishRelease_${releaseId}`;\n\n strapi.cron.add({\n [taskName]: {\n async task() {\n try {\n await getService('release', { strapi }).publish(releaseId);\n // @TODO: Trigger webhook with success message\n } catch (error) {\n // @TODO: Trigger webhook with error message\n }\n },\n options: scheduleDate,\n },\n });\n\n if (scheduledJobs.has(releaseId)) {\n this.cancel(releaseId);\n }\n\n scheduledJobs.set(releaseId, taskName);\n\n return scheduledJobs;\n },\n\n cancel(releaseId: Release['id']) {\n if (scheduledJobs.has(releaseId)) {\n strapi.cron.remove(scheduledJobs.get(releaseId)!);\n scheduledJobs.delete(releaseId);\n }\n\n return scheduledJobs;\n },\n\n getAll() {\n return scheduledJobs;\n },\n\n /**\n * On bootstrap, we can use this function to make sure to sync the scheduled jobs from the database that are not yet released\n * This is useful in case the server was restarted and the scheduled jobs were lost\n * This also could be used to sync different Strapi instances in case of a cluster\n */\n async syncFromDatabase() {\n const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({\n where: {\n scheduledAt: {\n $gte: new Date(),\n },\n releasedAt: null,\n },\n });\n\n for (const release of releases) {\n this.set(release.id, release.scheduledAt);\n }\n\n return scheduledJobs;\n },\n };\n};\n\nexport default createSchedulingService;\n"],"names":["createSchedulingService","strapi","scheduledJobs","Map","set","releaseId","scheduleDate","release","db","query","RELEASE_MODEL_UID","findOne","where","id","releasedAt","errors","NotFoundError","taskName","cron","add","task","getService","publish","error","options","has","cancel","remove","get","delete","getAll","syncFromDatabase","releases","findMany","scheduledAt","$gte","Date"],"mappings":";;;;AAOA,MAAMA,uBAA0B,GAAA,CAAC,EAAEC,MAAM,EAA2B,GAAA;AAClE,IAAA,MAAMC,gBAAgB,IAAIC,GAAAA,EAAAA;IAE1B,OAAO;QACL,MAAMC,GAAAA,CAAAA,CAAIC,SAAwB,EAAEC,YAAkB,EAAA;YACpD,MAAMC,OAAAA,GAAU,MAAMN,MAAOO,CAAAA,EAAE,CAC5BC,KAAK,CAACC,iBACNC,CAAAA,CAAAA,OAAO,CAAC;gBAAEC,KAAO,EAAA;oBAAEC,EAAIR,EAAAA,SAAAA;oBAAWS,UAAY,EAAA;AAAK;AAAE,aAAA,CAAA;AAExD,YAAA,IAAI,CAACP,OAAS,EAAA;AACZ,gBAAA,MAAM,IAAIQ,MAAOC,CAAAA,aAAa,CAAC,CAAC,wBAAwB,EAAEX,SAAW,CAAA,CAAA,CAAA;AACvE;AAEA,YAAA,MAAMY,QAAW,GAAA,CAAC,eAAe,EAAEZ,SAAW,CAAA,CAAA;YAE9CJ,MAAOiB,CAAAA,IAAI,CAACC,GAAG,CAAC;AACd,gBAAA,CAACF,WAAW;oBACV,MAAMG,IAAAA,CAAAA,GAAAA;wBACJ,IAAI;AACF,4BAAA,MAAMC,WAAW,SAAW,EAAA;AAAEpB,gCAAAA;AAAO,6BAAA,CAAA,CAAGqB,OAAO,CAACjB,SAAAA,CAAAA;;AAElD,yBAAA,CAAE,OAAOkB,KAAO,EAAA;;AAEhB;AACF,qBAAA;oBACAC,OAASlB,EAAAA;AACX;AACF,aAAA,CAAA;YAEA,IAAIJ,aAAAA,CAAcuB,GAAG,CAACpB,SAAY,CAAA,EAAA;gBAChC,IAAI,CAACqB,MAAM,CAACrB,SAAAA,CAAAA;AACd;YAEAH,aAAcE,CAAAA,GAAG,CAACC,SAAWY,EAAAA,QAAAA,CAAAA;YAE7B,OAAOf,aAAAA;AACT,SAAA;AAEAwB,QAAAA,MAAAA,CAAAA,CAAOrB,SAAwB,EAAA;YAC7B,IAAIH,aAAAA,CAAcuB,GAAG,CAACpB,SAAY,CAAA,EAAA;AAChCJ,gBAAAA,MAAAA,CAAOiB,IAAI,CAACS,MAAM,CAACzB,aAAAA,CAAc0B,GAAG,CAACvB,SAAAA,CAAAA,CAAAA;AACrCH,gBAAAA,aAAAA,CAAc2B,MAAM,CAACxB,SAAAA,CAAAA;AACvB;YAEA,OAAOH,aAAAA;AACT,SAAA;AAEA4B,QAAAA,MAAAA,CAAAA,GAAAA;YACE,OAAO5B,aAAAA;AACT,SAAA;AAEA;;;;AAIC,QACD,MAAM6B,gBAAAA,CAAAA,GAAAA;YACJ,MAAMC,QAAAA,GAAW,MAAM/B,MAAOO,CAAAA,EAAE,CAACC,KAAK,CAACC,iBAAmBuB,CAAAA,CAAAA,QAAQ,CAAC;gBACjErB,KAAO,EAAA;oBACLsB,WAAa,EAAA;AACXC,wBAAAA,IAAAA,EAAM,IAAIC,IAAAA;AACZ,qBAAA;oBACAtB,UAAY,EAAA;AACd;AACF,aAAA,CAAA;YAEA,KAAK,MAAMP,WAAWyB,QAAU,CAAA;AAC9B,gBAAA,IAAI,CAAC5B,GAAG,CAACG,QAAQM,EAAE,EAAEN,QAAQ2B,WAAW,CAAA;AAC1C;YAEA,OAAOhC,aAAAA;AACT;AACF,KAAA;AACF;;;;"}
1
+ {"version":3,"file":"scheduling.mjs","sources":["../../../server/src/services/scheduling.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport { errors } from '@strapi/utils';\nimport { Release } from '../../../shared/contracts/releases';\nimport { getService } from '../utils';\nimport { RELEASE_MODEL_UID } from '../constants';\n\nconst createSchedulingService = ({ strapi }: { strapi: Core.Strapi }) => {\n const scheduledJobs = new Map<Release['id'], string>();\n\n return {\n async set(releaseId: Release['id'], scheduleDate: Date) {\n const release = await strapi.db\n .query(RELEASE_MODEL_UID)\n .findOne({ where: { id: releaseId, releasedAt: null } });\n\n if (!release) {\n throw new errors.NotFoundError(`No release found for id ${releaseId}`);\n }\n\n const taskName = `publishRelease_${releaseId}`;\n\n strapi.cron.add({\n [taskName]: {\n async task() {\n try {\n await getService('release', { strapi }).publish(releaseId);\n // @TODO: Trigger webhook with success message\n } catch (error) {\n // @TODO: Trigger webhook with error message\n }\n },\n options: scheduleDate,\n },\n });\n\n if (scheduledJobs.has(releaseId)) {\n this.cancel(releaseId);\n }\n\n scheduledJobs.set(releaseId, taskName);\n\n return scheduledJobs;\n },\n\n cancel(releaseId: Release['id']) {\n if (scheduledJobs.has(releaseId)) {\n strapi.cron.remove(scheduledJobs.get(releaseId)!);\n scheduledJobs.delete(releaseId);\n }\n\n return scheduledJobs;\n },\n\n getAll() {\n return scheduledJobs;\n },\n\n /**\n * On bootstrap, we can use this function to make sure to sync the scheduled jobs from the database that are not yet released\n * This is useful in case the server was restarted and the scheduled jobs were lost\n * This also could be used to sync different Strapi instances in case of a cluster\n */\n async syncFromDatabase() {\n const releases = await strapi.db.query(RELEASE_MODEL_UID).findMany({\n where: {\n scheduledAt: {\n $gte: new Date(),\n },\n releasedAt: null,\n },\n });\n\n for (const release of releases) {\n this.set(release.id, release.scheduledAt);\n }\n\n return scheduledJobs;\n },\n };\n};\n\nexport default createSchedulingService;\n"],"names":["createSchedulingService","strapi","scheduledJobs","Map","set","releaseId","scheduleDate","release","db","query","RELEASE_MODEL_UID","findOne","where","id","releasedAt","errors","NotFoundError","taskName","cron","add","task","getService","publish","error","options","has","cancel","remove","get","delete","getAll","syncFromDatabase","releases","findMany","scheduledAt","$gte","Date"],"mappings":";;;;AAOA,MAAMA,uBAAAA,GAA0B,CAAC,EAAEC,MAAM,EAA2B,GAAA;AAClE,IAAA,MAAMC,gBAAgB,IAAIC,GAAAA,EAAAA;IAE1B,OAAO;QACL,MAAMC,GAAAA,CAAAA,CAAIC,SAAwB,EAAEC,YAAkB,EAAA;YACpD,MAAMC,OAAAA,GAAU,MAAMN,MAAAA,CAAOO,EAAE,CAC5BC,KAAK,CAACC,iBAAAA,CAAAA,CACNC,OAAO,CAAC;gBAAEC,KAAAA,EAAO;oBAAEC,EAAAA,EAAIR,SAAAA;oBAAWS,UAAAA,EAAY;AAAK;AAAE,aAAA,CAAA;AAExD,YAAA,IAAI,CAACP,OAAAA,EAAS;AACZ,gBAAA,MAAM,IAAIQ,MAAAA,CAAOC,aAAa,CAAC,CAAC,wBAAwB,EAAEX,SAAAA,CAAAA,CAAW,CAAA;AACvE,YAAA;AAEA,YAAA,MAAMY,QAAAA,GAAW,CAAC,eAAe,EAAEZ,SAAAA,CAAAA,CAAW;YAE9CJ,MAAAA,CAAOiB,IAAI,CAACC,GAAG,CAAC;AACd,gBAAA,CAACF,WAAW;oBACV,MAAMG,IAAAA,CAAAA,GAAAA;wBACJ,IAAI;AACF,4BAAA,MAAMC,WAAW,SAAA,EAAW;AAAEpB,gCAAAA;AAAO,6BAAA,CAAA,CAAGqB,OAAO,CAACjB,SAAAA,CAAAA;;AAElD,wBAAA,CAAA,CAAE,OAAOkB,KAAAA,EAAO;;AAEhB,wBAAA;AACF,oBAAA,CAAA;oBACAC,OAAAA,EAASlB;AACX;AACF,aAAA,CAAA;YAEA,IAAIJ,aAAAA,CAAcuB,GAAG,CAACpB,SAAAA,CAAAA,EAAY;gBAChC,IAAI,CAACqB,MAAM,CAACrB,SAAAA,CAAAA;AACd,YAAA;YAEAH,aAAAA,CAAcE,GAAG,CAACC,SAAAA,EAAWY,QAAAA,CAAAA;YAE7B,OAAOf,aAAAA;AACT,QAAA,CAAA;AAEAwB,QAAAA,MAAAA,CAAAA,CAAOrB,SAAwB,EAAA;YAC7B,IAAIH,aAAAA,CAAcuB,GAAG,CAACpB,SAAAA,CAAAA,EAAY;AAChCJ,gBAAAA,MAAAA,CAAOiB,IAAI,CAACS,MAAM,CAACzB,aAAAA,CAAc0B,GAAG,CAACvB,SAAAA,CAAAA,CAAAA;AACrCH,gBAAAA,aAAAA,CAAc2B,MAAM,CAACxB,SAAAA,CAAAA;AACvB,YAAA;YAEA,OAAOH,aAAAA;AACT,QAAA,CAAA;AAEA4B,QAAAA,MAAAA,CAAAA,GAAAA;YACE,OAAO5B,aAAAA;AACT,QAAA,CAAA;AAEA;;;;AAIC,QACD,MAAM6B,gBAAAA,CAAAA,GAAAA;YACJ,MAAMC,QAAAA,GAAW,MAAM/B,MAAAA,CAAOO,EAAE,CAACC,KAAK,CAACC,iBAAAA,CAAAA,CAAmBuB,QAAQ,CAAC;gBACjErB,KAAAA,EAAO;oBACLsB,WAAAA,EAAa;AACXC,wBAAAA,IAAAA,EAAM,IAAIC,IAAAA;AACZ,qBAAA;oBACAtB,UAAAA,EAAY;AACd;AACF,aAAA,CAAA;YAEA,KAAK,MAAMP,WAAWyB,QAAAA,CAAU;AAC9B,gBAAA,IAAI,CAAC5B,GAAG,CAACG,QAAQM,EAAE,EAAEN,QAAQ2B,WAAW,CAAA;AAC1C,YAAA;YAEA,OAAOhC,aAAAA;AACT,QAAA;AACF,KAAA;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"settings.js","sources":["../../../server/src/services/settings.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport type { Settings } from '../../../shared/contracts/settings';\n\nconst DEFAULT_SETTINGS = {\n defaultTimezone: null,\n} satisfies Settings;\n\nconst createSettingsService = ({ strapi }: { strapi: Core.Strapi }) => {\n const getStore = async () => strapi.store({ type: 'core', name: 'content-releases' });\n\n return {\n async update({ settings }: { settings: Settings }): Promise<Settings> {\n const store = await getStore();\n store.set({ key: 'settings', value: settings });\n return settings;\n },\n async find(): Promise<Settings> {\n const store = await getStore();\n const settings = (await store.get({ key: 'settings' })) as Settings | undefined;\n\n return {\n ...DEFAULT_SETTINGS,\n ...(settings || {}),\n };\n },\n };\n};\n\nexport type SettingsService = ReturnType<typeof createSettingsService>;\n\nexport default createSettingsService;\n"],"names":["DEFAULT_SETTINGS","defaultTimezone","createSettingsService","strapi","getStore","store","type","name","update","settings","set","key","value","find","get"],"mappings":";;AAIA,MAAMA,gBAAmB,GAAA;IACvBC,eAAiB,EAAA;AACnB,CAAA;AAEA,MAAMC,qBAAwB,GAAA,CAAC,EAAEC,MAAM,EAA2B,GAAA;AAChE,IAAA,MAAMC,QAAW,GAAA,UAAYD,MAAOE,CAAAA,KAAK,CAAC;YAAEC,IAAM,EAAA,MAAA;YAAQC,IAAM,EAAA;AAAmB,SAAA,CAAA;IAEnF,OAAO;QACL,MAAMC,MAAAA,CAAAA,CAAO,EAAEC,QAAQ,EAA0B,EAAA;AAC/C,YAAA,MAAMJ,QAAQ,MAAMD,QAAAA,EAAAA;AACpBC,YAAAA,KAAAA,CAAMK,GAAG,CAAC;gBAAEC,GAAK,EAAA,UAAA;gBAAYC,KAAOH,EAAAA;AAAS,aAAA,CAAA;YAC7C,OAAOA,QAAAA;AACT,SAAA;QACA,MAAMI,IAAAA,CAAAA,GAAAA;AACJ,YAAA,MAAMR,QAAQ,MAAMD,QAAAA,EAAAA;AACpB,YAAA,MAAMK,QAAY,GAAA,MAAMJ,KAAMS,CAAAA,GAAG,CAAC;gBAAEH,GAAK,EAAA;AAAW,aAAA,CAAA;YAEpD,OAAO;AACL,gBAAA,GAAGX,gBAAgB;gBACnB,GAAIS,QAAAA,IAAY;AAClB,aAAA;AACF;AACF,KAAA;AACF;;;;"}
1
+ {"version":3,"file":"settings.js","sources":["../../../server/src/services/settings.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport type { Settings } from '../../../shared/contracts/settings';\n\nconst DEFAULT_SETTINGS = {\n defaultTimezone: null,\n} satisfies Settings;\n\nconst createSettingsService = ({ strapi }: { strapi: Core.Strapi }) => {\n const getStore = async () => strapi.store({ type: 'core', name: 'content-releases' });\n\n return {\n async update({ settings }: { settings: Settings }): Promise<Settings> {\n const store = await getStore();\n store.set({ key: 'settings', value: settings });\n return settings;\n },\n async find(): Promise<Settings> {\n const store = await getStore();\n const settings = (await store.get({ key: 'settings' })) as Settings | undefined;\n\n return {\n ...DEFAULT_SETTINGS,\n ...(settings || {}),\n };\n },\n };\n};\n\nexport type SettingsService = ReturnType<typeof createSettingsService>;\n\nexport default createSettingsService;\n"],"names":["DEFAULT_SETTINGS","defaultTimezone","createSettingsService","strapi","getStore","store","type","name","update","settings","set","key","value","find","get"],"mappings":";;AAIA,MAAMA,gBAAAA,GAAmB;IACvBC,eAAAA,EAAiB;AACnB,CAAA;AAEA,MAAMC,qBAAAA,GAAwB,CAAC,EAAEC,MAAM,EAA2B,GAAA;AAChE,IAAA,MAAMC,QAAAA,GAAW,UAAYD,MAAAA,CAAOE,KAAK,CAAC;YAAEC,IAAAA,EAAM,MAAA;YAAQC,IAAAA,EAAM;AAAmB,SAAA,CAAA;IAEnF,OAAO;QACL,MAAMC,MAAAA,CAAAA,CAAO,EAAEC,QAAQ,EAA0B,EAAA;AAC/C,YAAA,MAAMJ,QAAQ,MAAMD,QAAAA,EAAAA;AACpBC,YAAAA,KAAAA,CAAMK,GAAG,CAAC;gBAAEC,GAAAA,EAAK,UAAA;gBAAYC,KAAAA,EAAOH;AAAS,aAAA,CAAA;YAC7C,OAAOA,QAAAA;AACT,QAAA,CAAA;QACA,MAAMI,IAAAA,CAAAA,GAAAA;AACJ,YAAA,MAAMR,QAAQ,MAAMD,QAAAA,EAAAA;AACpB,YAAA,MAAMK,QAAAA,GAAY,MAAMJ,KAAAA,CAAMS,GAAG,CAAC;gBAAEH,GAAAA,EAAK;AAAW,aAAA,CAAA;YAEpD,OAAO;AACL,gBAAA,GAAGX,gBAAgB;gBACnB,GAAIS,QAAAA,IAAY;AAClB,aAAA;AACF,QAAA;AACF,KAAA;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"settings.mjs","sources":["../../../server/src/services/settings.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport type { Settings } from '../../../shared/contracts/settings';\n\nconst DEFAULT_SETTINGS = {\n defaultTimezone: null,\n} satisfies Settings;\n\nconst createSettingsService = ({ strapi }: { strapi: Core.Strapi }) => {\n const getStore = async () => strapi.store({ type: 'core', name: 'content-releases' });\n\n return {\n async update({ settings }: { settings: Settings }): Promise<Settings> {\n const store = await getStore();\n store.set({ key: 'settings', value: settings });\n return settings;\n },\n async find(): Promise<Settings> {\n const store = await getStore();\n const settings = (await store.get({ key: 'settings' })) as Settings | undefined;\n\n return {\n ...DEFAULT_SETTINGS,\n ...(settings || {}),\n };\n },\n };\n};\n\nexport type SettingsService = ReturnType<typeof createSettingsService>;\n\nexport default createSettingsService;\n"],"names":["DEFAULT_SETTINGS","defaultTimezone","createSettingsService","strapi","getStore","store","type","name","update","settings","set","key","value","find","get"],"mappings":"AAIA,MAAMA,gBAAmB,GAAA;IACvBC,eAAiB,EAAA;AACnB,CAAA;AAEA,MAAMC,qBAAwB,GAAA,CAAC,EAAEC,MAAM,EAA2B,GAAA;AAChE,IAAA,MAAMC,QAAW,GAAA,UAAYD,MAAOE,CAAAA,KAAK,CAAC;YAAEC,IAAM,EAAA,MAAA;YAAQC,IAAM,EAAA;AAAmB,SAAA,CAAA;IAEnF,OAAO;QACL,MAAMC,MAAAA,CAAAA,CAAO,EAAEC,QAAQ,EAA0B,EAAA;AAC/C,YAAA,MAAMJ,QAAQ,MAAMD,QAAAA,EAAAA;AACpBC,YAAAA,KAAAA,CAAMK,GAAG,CAAC;gBAAEC,GAAK,EAAA,UAAA;gBAAYC,KAAOH,EAAAA;AAAS,aAAA,CAAA;YAC7C,OAAOA,QAAAA;AACT,SAAA;QACA,MAAMI,IAAAA,CAAAA,GAAAA;AACJ,YAAA,MAAMR,QAAQ,MAAMD,QAAAA,EAAAA;AACpB,YAAA,MAAMK,QAAY,GAAA,MAAMJ,KAAMS,CAAAA,GAAG,CAAC;gBAAEH,GAAK,EAAA;AAAW,aAAA,CAAA;YAEpD,OAAO;AACL,gBAAA,GAAGX,gBAAgB;gBACnB,GAAIS,QAAAA,IAAY;AAClB,aAAA;AACF;AACF,KAAA;AACF;;;;"}
1
+ {"version":3,"file":"settings.mjs","sources":["../../../server/src/services/settings.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport type { Settings } from '../../../shared/contracts/settings';\n\nconst DEFAULT_SETTINGS = {\n defaultTimezone: null,\n} satisfies Settings;\n\nconst createSettingsService = ({ strapi }: { strapi: Core.Strapi }) => {\n const getStore = async () => strapi.store({ type: 'core', name: 'content-releases' });\n\n return {\n async update({ settings }: { settings: Settings }): Promise<Settings> {\n const store = await getStore();\n store.set({ key: 'settings', value: settings });\n return settings;\n },\n async find(): Promise<Settings> {\n const store = await getStore();\n const settings = (await store.get({ key: 'settings' })) as Settings | undefined;\n\n return {\n ...DEFAULT_SETTINGS,\n ...(settings || {}),\n };\n },\n };\n};\n\nexport type SettingsService = ReturnType<typeof createSettingsService>;\n\nexport default createSettingsService;\n"],"names":["DEFAULT_SETTINGS","defaultTimezone","createSettingsService","strapi","getStore","store","type","name","update","settings","set","key","value","find","get"],"mappings":"AAIA,MAAMA,gBAAAA,GAAmB;IACvBC,eAAAA,EAAiB;AACnB,CAAA;AAEA,MAAMC,qBAAAA,GAAwB,CAAC,EAAEC,MAAM,EAA2B,GAAA;AAChE,IAAA,MAAMC,QAAAA,GAAW,UAAYD,MAAAA,CAAOE,KAAK,CAAC;YAAEC,IAAAA,EAAM,MAAA;YAAQC,IAAAA,EAAM;AAAmB,SAAA,CAAA;IAEnF,OAAO;QACL,MAAMC,MAAAA,CAAAA,CAAO,EAAEC,QAAQ,EAA0B,EAAA;AAC/C,YAAA,MAAMJ,QAAQ,MAAMD,QAAAA,EAAAA;AACpBC,YAAAA,KAAAA,CAAMK,GAAG,CAAC;gBAAEC,GAAAA,EAAK,UAAA;gBAAYC,KAAAA,EAAOH;AAAS,aAAA,CAAA;YAC7C,OAAOA,QAAAA;AACT,QAAA,CAAA;QACA,MAAMI,IAAAA,CAAAA,GAAAA;AACJ,YAAA,MAAMR,QAAQ,MAAMD,QAAAA,EAAAA;AACpB,YAAA,MAAMK,QAAAA,GAAY,MAAMJ,KAAAA,CAAMS,GAAG,CAAC;gBAAEH,GAAAA,EAAK;AAAW,aAAA,CAAA;YAEpD,OAAO;AACL,gBAAA,GAAGX,gBAAgB;gBACnB,GAAIS,QAAAA,IAAY;AAClB,aAAA;AACF,QAAA;AACF,KAAA;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"validation.js","sources":["../../../server/src/services/validation.ts"],"sourcesContent":["import { errors, contentTypes } from '@strapi/utils';\nimport type { Core, UID } from '@strapi/types';\nimport type { Release, CreateRelease, UpdateRelease } from '../../../shared/contracts/releases';\nimport type { CreateReleaseAction } from '../../../shared/contracts/release-actions';\nimport { RELEASE_MODEL_UID } from '../constants';\n\nexport class AlreadyOnReleaseError extends errors.ApplicationError<'AlreadyOnReleaseError'> {\n constructor(message: string) {\n super(message);\n this.name = 'AlreadyOnReleaseError';\n }\n}\n\nconst createReleaseValidationService = ({ strapi }: { strapi: Core.Strapi }) => ({\n async validateUniqueEntry(\n releaseId: CreateReleaseAction.Request['params']['releaseId'],\n releaseActionArgs: CreateReleaseAction.Request['body']\n ) {\n /**\n * Asserting the type, otherwise TS complains: 'release.actions' is of type 'unknown', even though the types come through for non-populated fields...\n * Possibly related to the comment on GetValues: https://github.com/strapi/strapi/blob/main/packages/core/types/src/modules/entity-service/result.ts\n */\n const release = (await strapi.db.query(RELEASE_MODEL_UID).findOne({\n where: {\n id: releaseId,\n },\n populate: {\n actions: true,\n },\n })) as Release | null;\n\n if (!release) {\n throw new errors.NotFoundError(`No release found for id ${releaseId}`);\n }\n\n const isEntryInRelease = release.actions.some(\n (action) =>\n action.entryDocumentId === releaseActionArgs.entryDocumentId &&\n action.contentType === releaseActionArgs.contentType &&\n (releaseActionArgs.locale ? action.locale === releaseActionArgs.locale : true)\n );\n\n if (isEntryInRelease) {\n throw new AlreadyOnReleaseError(\n `Entry with documentId ${releaseActionArgs.entryDocumentId}${releaseActionArgs.locale ? `( ${releaseActionArgs.locale})` : ''} and contentType ${releaseActionArgs.contentType} already exists in release with id ${releaseId}`\n );\n }\n },\n validateEntryData(\n contentTypeUid: CreateReleaseAction.Request['body']['contentType'],\n entryDocumentId: CreateReleaseAction.Request['body']['entryDocumentId']\n ) {\n const contentType = strapi.contentType(contentTypeUid as UID.ContentType);\n\n if (!contentType) {\n throw new errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);\n }\n\n if (!contentTypes.hasDraftAndPublish(contentType)) {\n throw new errors.ValidationError(\n `Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`\n );\n }\n\n if (contentType.kind === 'collectionType' && !entryDocumentId) {\n throw new errors.ValidationError('Document id is required for collection type');\n }\n },\n async validatePendingReleasesLimit() {\n // Use the maximum releases option if it exists, otherwise default to 3\n const featureCfg = strapi.ee.features.get('cms-content-releases');\n\n const maximumPendingReleases =\n (typeof featureCfg === 'object' && featureCfg?.options?.maximumReleases) || 3;\n\n const [, pendingReleasesCount] = await strapi.db.query(RELEASE_MODEL_UID).findWithCount({\n filters: {\n releasedAt: {\n $null: true,\n },\n },\n });\n\n // Unlimited is a number that will never be reached like 9999\n if (pendingReleasesCount >= maximumPendingReleases) {\n throw new errors.ValidationError('You have reached the maximum number of pending releases');\n }\n },\n async validateUniqueNameForPendingRelease(\n name: CreateRelease.Request['body']['name'],\n id?: UpdateRelease.Request['params']['id']\n ) {\n const pendingReleases = (await strapi.db.query(RELEASE_MODEL_UID).findMany({\n where: {\n releasedAt: {\n $null: true,\n },\n name,\n ...(id && { id: { $ne: id } }),\n },\n })) as Release[];\n\n const isNameUnique = pendingReleases.length === 0;\n\n if (!isNameUnique) {\n throw new errors.ValidationError(`Release with name ${name} already exists`);\n }\n },\n async validateScheduledAtIsLaterThanNow(\n scheduledAt: CreateRelease.Request['body']['scheduledAt']\n ) {\n if (scheduledAt && new Date(scheduledAt) <= new Date()) {\n throw new errors.ValidationError('Scheduled at must be later than now');\n }\n },\n});\n\nexport default createReleaseValidationService;\n"],"names":["AlreadyOnReleaseError","errors","ApplicationError","message","name","createReleaseValidationService","strapi","validateUniqueEntry","releaseId","releaseActionArgs","release","db","query","RELEASE_MODEL_UID","findOne","where","id","populate","actions","NotFoundError","isEntryInRelease","some","action","entryDocumentId","contentType","locale","validateEntryData","contentTypeUid","contentTypes","hasDraftAndPublish","ValidationError","kind","validatePendingReleasesLimit","featureCfg","ee","features","get","maximumPendingReleases","options","maximumReleases","pendingReleasesCount","findWithCount","filters","releasedAt","$null","validateUniqueNameForPendingRelease","pendingReleases","findMany","$ne","isNameUnique","length","validateScheduledAtIsLaterThanNow","scheduledAt","Date"],"mappings":"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"}
1
+ {"version":3,"file":"validation.js","sources":["../../../server/src/services/validation.ts"],"sourcesContent":["import { errors, contentTypes } from '@strapi/utils';\nimport type { Core, UID } from '@strapi/types';\nimport type { Release, CreateRelease, UpdateRelease } from '../../../shared/contracts/releases';\nimport type { CreateReleaseAction } from '../../../shared/contracts/release-actions';\nimport { RELEASE_MODEL_UID } from '../constants';\n\nexport class AlreadyOnReleaseError extends errors.ApplicationError<'AlreadyOnReleaseError'> {\n constructor(message: string) {\n super(message);\n this.name = 'AlreadyOnReleaseError';\n }\n}\n\nconst createReleaseValidationService = ({ strapi }: { strapi: Core.Strapi }) => ({\n async validateUniqueEntry(\n releaseId: CreateReleaseAction.Request['params']['releaseId'],\n releaseActionArgs: CreateReleaseAction.Request['body']\n ) {\n /**\n * Asserting the type, otherwise TS complains: 'release.actions' is of type 'unknown', even though the types come through for non-populated fields...\n * Possibly related to the comment on GetValues: https://github.com/strapi/strapi/blob/main/packages/core/types/src/modules/entity-service/result.ts\n */\n const release = (await strapi.db.query(RELEASE_MODEL_UID).findOne({\n where: {\n id: releaseId,\n },\n populate: {\n actions: true,\n },\n })) as Release | null;\n\n if (!release) {\n throw new errors.NotFoundError(`No release found for id ${releaseId}`);\n }\n\n const isEntryInRelease = release.actions.some(\n (action) =>\n action.entryDocumentId === releaseActionArgs.entryDocumentId &&\n action.contentType === releaseActionArgs.contentType &&\n (releaseActionArgs.locale ? action.locale === releaseActionArgs.locale : true)\n );\n\n if (isEntryInRelease) {\n throw new AlreadyOnReleaseError(\n `Entry with documentId ${releaseActionArgs.entryDocumentId}${releaseActionArgs.locale ? `( ${releaseActionArgs.locale})` : ''} and contentType ${releaseActionArgs.contentType} already exists in release with id ${releaseId}`\n );\n }\n },\n validateEntryData(\n contentTypeUid: CreateReleaseAction.Request['body']['contentType'],\n entryDocumentId: CreateReleaseAction.Request['body']['entryDocumentId']\n ) {\n const contentType = strapi.contentType(contentTypeUid as UID.ContentType);\n\n if (!contentType) {\n throw new errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);\n }\n\n if (!contentTypes.hasDraftAndPublish(contentType)) {\n throw new errors.ValidationError(\n `Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`\n );\n }\n\n if (contentType.kind === 'collectionType' && !entryDocumentId) {\n throw new errors.ValidationError('Document id is required for collection type');\n }\n },\n async validatePendingReleasesLimit() {\n // Use the maximum releases option if it exists, otherwise default to 3\n const featureCfg = strapi.ee.features.get('cms-content-releases');\n\n const maximumPendingReleases =\n (typeof featureCfg === 'object' && featureCfg?.options?.maximumReleases) || 3;\n\n const [, pendingReleasesCount] = await strapi.db.query(RELEASE_MODEL_UID).findWithCount({\n filters: {\n releasedAt: {\n $null: true,\n },\n },\n });\n\n // Unlimited is a number that will never be reached like 9999\n if (pendingReleasesCount >= maximumPendingReleases) {\n throw new errors.ValidationError('You have reached the maximum number of pending releases');\n }\n },\n async validateUniqueNameForPendingRelease(\n name: CreateRelease.Request['body']['name'],\n id?: UpdateRelease.Request['params']['id']\n ) {\n const pendingReleases = (await strapi.db.query(RELEASE_MODEL_UID).findMany({\n where: {\n releasedAt: {\n $null: true,\n },\n name,\n ...(id && { id: { $ne: id } }),\n },\n })) as Release[];\n\n const isNameUnique = pendingReleases.length === 0;\n\n if (!isNameUnique) {\n throw new errors.ValidationError(`Release with name ${name} already exists`);\n }\n },\n async validateScheduledAtIsLaterThanNow(\n scheduledAt: CreateRelease.Request['body']['scheduledAt']\n ) {\n if (scheduledAt && new Date(scheduledAt) <= new Date()) {\n throw new errors.ValidationError('Scheduled at must be later than now');\n }\n },\n});\n\nexport default createReleaseValidationService;\n"],"names":["AlreadyOnReleaseError","errors","ApplicationError","message","name","createReleaseValidationService","strapi","validateUniqueEntry","releaseId","releaseActionArgs","release","db","query","RELEASE_MODEL_UID","findOne","where","id","populate","actions","NotFoundError","isEntryInRelease","some","action","entryDocumentId","contentType","locale","validateEntryData","contentTypeUid","contentTypes","hasDraftAndPublish","ValidationError","kind","validatePendingReleasesLimit","featureCfg","ee","features","get","maximumPendingReleases","options","maximumReleases","pendingReleasesCount","findWithCount","filters","releasedAt","$null","validateUniqueNameForPendingRelease","pendingReleases","findMany","$ne","isNameUnique","length","validateScheduledAtIsLaterThanNow","scheduledAt","Date"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"validation.mjs","sources":["../../../server/src/services/validation.ts"],"sourcesContent":["import { errors, contentTypes } from '@strapi/utils';\nimport type { Core, UID } from '@strapi/types';\nimport type { Release, CreateRelease, UpdateRelease } from '../../../shared/contracts/releases';\nimport type { CreateReleaseAction } from '../../../shared/contracts/release-actions';\nimport { RELEASE_MODEL_UID } from '../constants';\n\nexport class AlreadyOnReleaseError extends errors.ApplicationError<'AlreadyOnReleaseError'> {\n constructor(message: string) {\n super(message);\n this.name = 'AlreadyOnReleaseError';\n }\n}\n\nconst createReleaseValidationService = ({ strapi }: { strapi: Core.Strapi }) => ({\n async validateUniqueEntry(\n releaseId: CreateReleaseAction.Request['params']['releaseId'],\n releaseActionArgs: CreateReleaseAction.Request['body']\n ) {\n /**\n * Asserting the type, otherwise TS complains: 'release.actions' is of type 'unknown', even though the types come through for non-populated fields...\n * Possibly related to the comment on GetValues: https://github.com/strapi/strapi/blob/main/packages/core/types/src/modules/entity-service/result.ts\n */\n const release = (await strapi.db.query(RELEASE_MODEL_UID).findOne({\n where: {\n id: releaseId,\n },\n populate: {\n actions: true,\n },\n })) as Release | null;\n\n if (!release) {\n throw new errors.NotFoundError(`No release found for id ${releaseId}`);\n }\n\n const isEntryInRelease = release.actions.some(\n (action) =>\n action.entryDocumentId === releaseActionArgs.entryDocumentId &&\n action.contentType === releaseActionArgs.contentType &&\n (releaseActionArgs.locale ? action.locale === releaseActionArgs.locale : true)\n );\n\n if (isEntryInRelease) {\n throw new AlreadyOnReleaseError(\n `Entry with documentId ${releaseActionArgs.entryDocumentId}${releaseActionArgs.locale ? `( ${releaseActionArgs.locale})` : ''} and contentType ${releaseActionArgs.contentType} already exists in release with id ${releaseId}`\n );\n }\n },\n validateEntryData(\n contentTypeUid: CreateReleaseAction.Request['body']['contentType'],\n entryDocumentId: CreateReleaseAction.Request['body']['entryDocumentId']\n ) {\n const contentType = strapi.contentType(contentTypeUid as UID.ContentType);\n\n if (!contentType) {\n throw new errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);\n }\n\n if (!contentTypes.hasDraftAndPublish(contentType)) {\n throw new errors.ValidationError(\n `Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`\n );\n }\n\n if (contentType.kind === 'collectionType' && !entryDocumentId) {\n throw new errors.ValidationError('Document id is required for collection type');\n }\n },\n async validatePendingReleasesLimit() {\n // Use the maximum releases option if it exists, otherwise default to 3\n const featureCfg = strapi.ee.features.get('cms-content-releases');\n\n const maximumPendingReleases =\n (typeof featureCfg === 'object' && featureCfg?.options?.maximumReleases) || 3;\n\n const [, pendingReleasesCount] = await strapi.db.query(RELEASE_MODEL_UID).findWithCount({\n filters: {\n releasedAt: {\n $null: true,\n },\n },\n });\n\n // Unlimited is a number that will never be reached like 9999\n if (pendingReleasesCount >= maximumPendingReleases) {\n throw new errors.ValidationError('You have reached the maximum number of pending releases');\n }\n },\n async validateUniqueNameForPendingRelease(\n name: CreateRelease.Request['body']['name'],\n id?: UpdateRelease.Request['params']['id']\n ) {\n const pendingReleases = (await strapi.db.query(RELEASE_MODEL_UID).findMany({\n where: {\n releasedAt: {\n $null: true,\n },\n name,\n ...(id && { id: { $ne: id } }),\n },\n })) as Release[];\n\n const isNameUnique = pendingReleases.length === 0;\n\n if (!isNameUnique) {\n throw new errors.ValidationError(`Release with name ${name} already exists`);\n }\n },\n async validateScheduledAtIsLaterThanNow(\n scheduledAt: CreateRelease.Request['body']['scheduledAt']\n ) {\n if (scheduledAt && new Date(scheduledAt) <= new Date()) {\n throw new errors.ValidationError('Scheduled at must be later than now');\n }\n },\n});\n\nexport default createReleaseValidationService;\n"],"names":["AlreadyOnReleaseError","errors","ApplicationError","message","name","createReleaseValidationService","strapi","validateUniqueEntry","releaseId","releaseActionArgs","release","db","query","RELEASE_MODEL_UID","findOne","where","id","populate","actions","NotFoundError","isEntryInRelease","some","action","entryDocumentId","contentType","locale","validateEntryData","contentTypeUid","contentTypes","hasDraftAndPublish","ValidationError","kind","validatePendingReleasesLimit","featureCfg","ee","features","get","maximumPendingReleases","options","maximumReleases","pendingReleasesCount","findWithCount","filters","releasedAt","$null","validateUniqueNameForPendingRelease","pendingReleases","findMany","$ne","isNameUnique","length","validateScheduledAtIsLaterThanNow","scheduledAt","Date"],"mappings":"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"}
1
+ {"version":3,"file":"validation.mjs","sources":["../../../server/src/services/validation.ts"],"sourcesContent":["import { errors, contentTypes } from '@strapi/utils';\nimport type { Core, UID } from '@strapi/types';\nimport type { Release, CreateRelease, UpdateRelease } from '../../../shared/contracts/releases';\nimport type { CreateReleaseAction } from '../../../shared/contracts/release-actions';\nimport { RELEASE_MODEL_UID } from '../constants';\n\nexport class AlreadyOnReleaseError extends errors.ApplicationError<'AlreadyOnReleaseError'> {\n constructor(message: string) {\n super(message);\n this.name = 'AlreadyOnReleaseError';\n }\n}\n\nconst createReleaseValidationService = ({ strapi }: { strapi: Core.Strapi }) => ({\n async validateUniqueEntry(\n releaseId: CreateReleaseAction.Request['params']['releaseId'],\n releaseActionArgs: CreateReleaseAction.Request['body']\n ) {\n /**\n * Asserting the type, otherwise TS complains: 'release.actions' is of type 'unknown', even though the types come through for non-populated fields...\n * Possibly related to the comment on GetValues: https://github.com/strapi/strapi/blob/main/packages/core/types/src/modules/entity-service/result.ts\n */\n const release = (await strapi.db.query(RELEASE_MODEL_UID).findOne({\n where: {\n id: releaseId,\n },\n populate: {\n actions: true,\n },\n })) as Release | null;\n\n if (!release) {\n throw new errors.NotFoundError(`No release found for id ${releaseId}`);\n }\n\n const isEntryInRelease = release.actions.some(\n (action) =>\n action.entryDocumentId === releaseActionArgs.entryDocumentId &&\n action.contentType === releaseActionArgs.contentType &&\n (releaseActionArgs.locale ? action.locale === releaseActionArgs.locale : true)\n );\n\n if (isEntryInRelease) {\n throw new AlreadyOnReleaseError(\n `Entry with documentId ${releaseActionArgs.entryDocumentId}${releaseActionArgs.locale ? `( ${releaseActionArgs.locale})` : ''} and contentType ${releaseActionArgs.contentType} already exists in release with id ${releaseId}`\n );\n }\n },\n validateEntryData(\n contentTypeUid: CreateReleaseAction.Request['body']['contentType'],\n entryDocumentId: CreateReleaseAction.Request['body']['entryDocumentId']\n ) {\n const contentType = strapi.contentType(contentTypeUid as UID.ContentType);\n\n if (!contentType) {\n throw new errors.NotFoundError(`No content type found for uid ${contentTypeUid}`);\n }\n\n if (!contentTypes.hasDraftAndPublish(contentType)) {\n throw new errors.ValidationError(\n `Content type with uid ${contentTypeUid} does not have draftAndPublish enabled`\n );\n }\n\n if (contentType.kind === 'collectionType' && !entryDocumentId) {\n throw new errors.ValidationError('Document id is required for collection type');\n }\n },\n async validatePendingReleasesLimit() {\n // Use the maximum releases option if it exists, otherwise default to 3\n const featureCfg = strapi.ee.features.get('cms-content-releases');\n\n const maximumPendingReleases =\n (typeof featureCfg === 'object' && featureCfg?.options?.maximumReleases) || 3;\n\n const [, pendingReleasesCount] = await strapi.db.query(RELEASE_MODEL_UID).findWithCount({\n filters: {\n releasedAt: {\n $null: true,\n },\n },\n });\n\n // Unlimited is a number that will never be reached like 9999\n if (pendingReleasesCount >= maximumPendingReleases) {\n throw new errors.ValidationError('You have reached the maximum number of pending releases');\n }\n },\n async validateUniqueNameForPendingRelease(\n name: CreateRelease.Request['body']['name'],\n id?: UpdateRelease.Request['params']['id']\n ) {\n const pendingReleases = (await strapi.db.query(RELEASE_MODEL_UID).findMany({\n where: {\n releasedAt: {\n $null: true,\n },\n name,\n ...(id && { id: { $ne: id } }),\n },\n })) as Release[];\n\n const isNameUnique = pendingReleases.length === 0;\n\n if (!isNameUnique) {\n throw new errors.ValidationError(`Release with name ${name} already exists`);\n }\n },\n async validateScheduledAtIsLaterThanNow(\n scheduledAt: CreateRelease.Request['body']['scheduledAt']\n ) {\n if (scheduledAt && new Date(scheduledAt) <= new Date()) {\n throw new errors.ValidationError('Scheduled at must be later than now');\n }\n },\n});\n\nexport default createReleaseValidationService;\n"],"names":["AlreadyOnReleaseError","errors","ApplicationError","message","name","createReleaseValidationService","strapi","validateUniqueEntry","releaseId","releaseActionArgs","release","db","query","RELEASE_MODEL_UID","findOne","where","id","populate","actions","NotFoundError","isEntryInRelease","some","action","entryDocumentId","contentType","locale","validateEntryData","contentTypeUid","contentTypes","hasDraftAndPublish","ValidationError","kind","validatePendingReleasesLimit","featureCfg","ee","features","get","maximumPendingReleases","options","maximumReleases","pendingReleasesCount","findWithCount","filters","releasedAt","$null","validateUniqueNameForPendingRelease","pendingReleases","findMany","$ne","isNameUnique","length","validateScheduledAtIsLaterThanNow","scheduledAt","Date"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"release.d.ts","sourceRoot":"","sources":["../../../../server/src/services/release.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAe,IAAI,EAAE,MAAM,eAAe,CAAC;AAG7D,OAAO,KAAK,EACV,WAAW,EACX,aAAa,EACb,aAAa,EACb,cAAc,EACd,UAAU,EACV,OAAO,EACP,aAAa,EACd,MAAM,oCAAoC,CAAC;AAE5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGtD,QAAA,MAAM,oBAAoB,eAAgB;IAAE,MAAM,EAAE,KAAK,MAAM,CAAA;CAAE;wBA2DnC,qBAAqB,CAAC,MAAM,CAAC,YAAY;QAAE,IAAI,EAAE,QAAQ,CAAA;KAAE;gBAiCnE,kBAAkB,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;qBAUnC,mBAAmB,CAAC,OAAO,CAAC;;;;;;;;;qBAa5B,GAAG;eASd,KAAK,EAAE,eACE,qBAAqB,CAAC,MAAM,CAAC,YAChC;QAAE,IAAI,EAAE,QAAQ,CAAA;KAAE;;sBAsEN,qBAAqB,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;uBA8CpC,sBAAsB,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;mCAqG1B,OAAO,CAAC,IAAI,CAAC;CAiDrD,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAErE,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"release.d.ts","sourceRoot":"","sources":["../../../../server/src/services/release.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAe,IAAI,EAAE,MAAM,eAAe,CAAC;AAG7D,OAAO,KAAK,EACV,WAAW,EACX,aAAa,EACb,aAAa,EACb,cAAc,EACd,UAAU,EACV,OAAO,EACP,aAAa,EACd,MAAM,oCAAoC,CAAC;AAE5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGtD,QAAA,MAAM,oBAAoB,eAAgB;IAAE,MAAM,EAAE,KAAK,MAAM,CAAA;CAAE;wBA2DnC,qBAAqB,CAAC,MAAM,CAAC,YAAY;QAAE,IAAI,EAAE,QAAQ,CAAA;KAAE;gBAiCnE,kBAAkB,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;qBAUnC,mBAAmB,CAAC,OAAO,CAAC;;;;;;;;;qBAa5B,GAAG;eASd,KAAK,EAAE,eACE,qBAAqB,CAAC,MAAM,CAAC,YAChC;QAAE,IAAI,EAAE,QAAQ,CAAA;KAAE;;sBAsEN,qBAAqB,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;uBA8CpC,sBAAsB,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;mCA0G1B,OAAO,CAAC,IAAI,CAAC;CAiDrD,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAErE,eAAe,oBAAoB,CAAC"}
@@ -31,5 +31,21 @@ export declare const getEntry: ({ contentType, documentId, locale, populate, sta
31
31
  strapi: Core.Strapi;
32
32
  }) => Promise<import("@strapi/types/dist/modules/documents").AnyDocument | null>;
33
33
  export declare const getEntryStatus: (contentType: UID.ContentType, entry: Data.ContentType) => Promise<"draft" | "published" | "modified">;
34
+ /**
35
+ * Returns content type UIDs sorted by relation dependency order for publishing.
36
+ * When content type A has a relation to content type B (both with draft & publish),
37
+ * B will appear before A in the result. This ensures that when publishing a release,
38
+ * related entities are published first, so that relation IDs can be correctly
39
+ * resolved (published target must exist when publishing source).
40
+ *
41
+ * Relations in components (nested or not) and dynamic zones are also considered.
42
+ *
43
+ * @param contentTypeUids - Content type UIDs that will be published in the release
44
+ * @param strapi - Strapi instance
45
+ * @returns Content type UIDs in publish order (dependencies first)
46
+ */
47
+ export declare const getPublishOrderForContentTypes: (contentTypeUids: UID.ContentType[], { strapi }: {
48
+ strapi: Core.Strapi;
49
+ }) => UID.ContentType[];
34
50
  export {};
35
51
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../server/src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAEvE,KAAK,QAAQ,GAAG;IACd,OAAO,EAAE,cAAc,CAAC;IACxB,oBAAoB,EAAE,GAAG,CAAC;IAC1B,UAAU,EAAE,GAAG,CAAC;IAChB,gBAAgB,EAAE,oBAAoB,CAAC;IACvC,eAAe,EAAE,GAAG,CAAC;IACrB,QAAQ,EAAE,eAAe,CAAC;CAC3B,CAAC;AAEF,UAAU,MAAM;IACd,WAAW,EAAE,GAAG,CAAC,WAAW,CAAC;IAC7B,UAAU,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,UAAU,uCACf,KAAK,cACC;IAAE,MAAM,EAAE,KAAK,MAAM,CAAA;CAAE,KAClC,QAAQ,CAAC,KAAK,CAEhB,CAAC;AAEF,eAAO,MAAM,wBAAwB,wCACE,MAAM,cAC/B;IAAE,MAAM,EAAE,KAAK,MAAM,CAAA;CAAE,qBASpC,CAAC;AAEF,eAAO,MAAM,YAAY,mBACP,MAAM,SACf,GAAG,cACE;IAAE,MAAM,EAAE,KAAK,MAAM,CAAA;CAAE,qBA0BpC,CAAC;AAEF,eAAO,MAAM,QAAQ,2DAOhB,MAAM,GAAG;IAAE,MAAM,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;IAAC,QAAQ,EAAE,GAAG,CAAA;CAAE,cACjD;IAAE,MAAM,EAAE,KAAK,MAAM,CAAA;CAAE,+EAmBpC,CAAC;AAEF,eAAO,MAAM,cAAc,gBAAuB,IAAI,WAAW,SAAS,KAAK,WAAW,gDAwBzF,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../server/src/utils/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAEvE,KAAK,QAAQ,GAAG;IACd,OAAO,EAAE,cAAc,CAAC;IACxB,oBAAoB,EAAE,GAAG,CAAC;IAC1B,UAAU,EAAE,GAAG,CAAC;IAChB,gBAAgB,EAAE,oBAAoB,CAAC;IACvC,eAAe,EAAE,GAAG,CAAC;IACrB,QAAQ,EAAE,eAAe,CAAC;CAC3B,CAAC;AAEF,UAAU,MAAM;IACd,WAAW,EAAE,GAAG,CAAC,WAAW,CAAC;IAC7B,UAAU,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,UAAU,uCACf,KAAK,cACC;IAAE,MAAM,EAAE,KAAK,MAAM,CAAA;CAAE,KAClC,QAAQ,CAAC,KAAK,CAEhB,CAAC;AAEF,eAAO,MAAM,wBAAwB,wCACE,MAAM,cAC/B;IAAE,MAAM,EAAE,KAAK,MAAM,CAAA;CAAE,qBASpC,CAAC;AAEF,eAAO,MAAM,YAAY,mBACP,MAAM,SACf,GAAG,cACE;IAAE,MAAM,EAAE,KAAK,MAAM,CAAA;CAAE,qBA0BpC,CAAC;AAEF,eAAO,MAAM,QAAQ,2DAOhB,MAAM,GAAG;IAAE,MAAM,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;IAAC,QAAQ,EAAE,GAAG,CAAA;CAAE,cACjD;IAAE,MAAM,EAAE,KAAK,MAAM,CAAA;CAAE,+EAmBpC,CAAC;AAEF,eAAO,MAAM,cAAc,gBAAuB,IAAI,WAAW,SAAS,KAAK,WAAW,gDAwBzF,CAAC;AA+CF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,8BAA8B,oBACxB,IAAI,WAAW,EAAE,cACtB;IAAE,MAAM,EAAE,KAAK,MAAM,CAAA;CAAE,KAClC,IAAI,WAAW,EAsDjB,CAAC"}
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ var utils = require('@strapi/utils');
4
+
3
5
  const getService = (name, { strapi: strapi1 })=>{
4
6
  return strapi1.plugin('content-releases').service(name);
5
7
  };
@@ -85,10 +87,99 @@ const getEntryStatus = async (contentType, entry)=>{
85
87
  }
86
88
  return 'published';
87
89
  };
90
+ /**
91
+ * Recursively collects content type UIDs that a model (content type or component) has relations to.
92
+ * Go through component and dynamic zone attributes to find nested relations.
93
+ */ const collectRelationTargets = (modelUid, strapi1, visited = new Set())=>{
94
+ const targets = new Set();
95
+ if (visited.has(modelUid)) {
96
+ return targets;
97
+ }
98
+ visited.add(modelUid);
99
+ const model = strapi1.getModel(modelUid);
100
+ if (!model?.attributes) {
101
+ return targets;
102
+ }
103
+ for (const attribute of Object.values(model.attributes)){
104
+ if (attribute?.type === 'relation' && attribute.target) {
105
+ targets.add(attribute.target);
106
+ }
107
+ if (attribute?.type === 'component' && attribute.component) {
108
+ for (const t of collectRelationTargets(attribute.component, strapi1, visited)){
109
+ targets.add(t);
110
+ }
111
+ }
112
+ if (attribute?.type === 'dynamiczone' && attribute.components) {
113
+ for (const compUid of attribute.components){
114
+ for (const t of collectRelationTargets(compUid, strapi1, visited)){
115
+ targets.add(t);
116
+ }
117
+ }
118
+ }
119
+ }
120
+ return targets;
121
+ };
122
+ /**
123
+ * Returns content type UIDs sorted by relation dependency order for publishing.
124
+ * When content type A has a relation to content type B (both with draft & publish),
125
+ * B will appear before A in the result. This ensures that when publishing a release,
126
+ * related entities are published first, so that relation IDs can be correctly
127
+ * resolved (published target must exist when publishing source).
128
+ *
129
+ * Relations in components (nested or not) and dynamic zones are also considered.
130
+ *
131
+ * @param contentTypeUids - Content type UIDs that will be published in the release
132
+ * @param strapi - Strapi instance
133
+ * @returns Content type UIDs in publish order (dependencies first)
134
+ */ const getPublishOrderForContentTypes = (contentTypeUids, { strapi: strapi1 })=>{
135
+ const uidSet = new Set(contentTypeUids);
136
+ // Build dependency graph: source depends on target (source must be published after target)
137
+ const dependencies = new Map();
138
+ for (const uid of contentTypeUids){
139
+ const model = strapi1.getModel(uid);
140
+ if (model && utils.contentTypes.hasDraftAndPublish(model)) {
141
+ const relationTargets = collectRelationTargets(uid, strapi1);
142
+ for (const targetUid of relationTargets){
143
+ const targetContentTypeUid = targetUid;
144
+ const isTargetInRelease = uidSet.has(targetContentTypeUid) && targetContentTypeUid in strapi1.contentTypes;
145
+ const targetModel = strapi1.getModel(targetContentTypeUid);
146
+ const targetHasDraftAndPublish = targetModel && utils.contentTypes.hasDraftAndPublish(targetModel);
147
+ if (isTargetInRelease && targetHasDraftAndPublish) {
148
+ let dependencySet = dependencies.get(uid);
149
+ if (!dependencySet) {
150
+ dependencySet = new Set();
151
+ dependencies.set(uid, dependencySet);
152
+ }
153
+ dependencySet.add(targetContentTypeUid);
154
+ }
155
+ }
156
+ }
157
+ }
158
+ // Topological sort: dependencies first
159
+ const sorted = [];
160
+ const visited = new Set();
161
+ const visiting = new Set();
162
+ const visit = (uid)=>{
163
+ if (visited.has(uid)) return;
164
+ if (visiting.has(uid)) return; // No cycle in valid schemas
165
+ visiting.add(uid);
166
+ for (const dep of dependencies.get(uid) ?? []){
167
+ visit(dep);
168
+ }
169
+ visiting.delete(uid);
170
+ visited.add(uid);
171
+ sorted.push(uid);
172
+ };
173
+ for (const uid of contentTypeUids){
174
+ visit(uid);
175
+ }
176
+ return sorted;
177
+ };
88
178
 
89
179
  exports.getDraftEntryValidStatus = getDraftEntryValidStatus;
90
180
  exports.getEntry = getEntry;
91
181
  exports.getEntryStatus = getEntryStatus;
182
+ exports.getPublishOrderForContentTypes = getPublishOrderForContentTypes;
92
183
  exports.getService = getService;
93
184
  exports.isEntryValid = isEntryValid;
94
185
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../server/src/utils/index.ts"],"sourcesContent":["import type { UID, Data, Core } from '@strapi/types';\n\nimport type { SettingsService } from '../services/settings';\nimport type { ReleaseService } from '../services/release';\nimport type { ReleaseActionService } from '../services/release-action';\n\ntype Services = {\n release: ReleaseService;\n 'release-validation': any;\n scheduling: any;\n 'release-action': ReleaseActionService;\n 'event-manager': any;\n settings: SettingsService;\n};\n\ninterface Action {\n contentType: UID.ContentType;\n documentId?: Data.DocumentID;\n locale?: string;\n}\n\nexport const getService = <TName extends keyof Services>(\n name: TName,\n { strapi }: { strapi: Core.Strapi }\n): Services[TName] => {\n return strapi.plugin('content-releases').service(name);\n};\n\nexport const getDraftEntryValidStatus = async (\n { contentType, documentId, locale }: Action,\n { strapi }: { strapi: Core.Strapi }\n) => {\n const populateBuilderService = strapi.plugin('content-manager').service('populate-builder');\n // @ts-expect-error - populateBuilderService should be a function but is returning service\n const populate = await populateBuilderService(contentType).populateDeep(Infinity).build();\n\n const entry = await getEntry({ contentType, documentId, locale, populate }, { strapi });\n\n return isEntryValid(contentType, entry, { strapi });\n};\n\nexport const isEntryValid = async (\n contentTypeUid: string,\n entry: any,\n { strapi }: { strapi: Core.Strapi }\n) => {\n try {\n // @TODO: When documents service has validateEntityCreation method, use it instead\n await strapi.entityValidator.validateEntityCreation(\n strapi.getModel(contentTypeUid as UID.ContentType),\n entry,\n undefined,\n // @ts-expect-error - FIXME: entity here is unnecessary\n entry\n );\n\n const workflowsService = strapi.plugin('review-workflows').service('workflows');\n // Workflows service may not be available depending on the license\n const workflow = await workflowsService?.getAssignedWorkflow(contentTypeUid, {\n populate: 'stageRequiredToPublish',\n });\n\n if (workflow?.stageRequiredToPublish) {\n return entry.strapi_stage.id === workflow.stageRequiredToPublish.id;\n }\n\n return true;\n } catch {\n return false;\n }\n};\n\nexport const getEntry = async (\n {\n contentType,\n documentId,\n locale,\n populate,\n status = 'draft',\n }: Action & { status?: 'draft' | 'published'; populate: any },\n { strapi }: { strapi: Core.Strapi }\n) => {\n if (documentId) {\n // Try to get an existing draft or published document\n const entry = await strapi\n .documents(contentType)\n .findOne({ documentId, locale, populate, status });\n\n // The document isn't published yet, but the action is to publish it, fetch the draft\n if (status === 'published' && !entry) {\n return strapi\n .documents(contentType)\n .findOne({ documentId, locale, populate, status: 'draft' });\n }\n\n return entry;\n }\n\n return strapi.documents(contentType).findFirst({ locale, populate, status });\n};\n\nexport const getEntryStatus = async (contentType: UID.ContentType, entry: Data.ContentType) => {\n if (entry.publishedAt) {\n return 'published';\n }\n\n const publishedEntry = await strapi.documents(contentType).findOne({\n documentId: entry.documentId,\n locale: entry.locale,\n status: 'published',\n fields: ['updatedAt'],\n });\n\n if (!publishedEntry) {\n return 'draft';\n }\n\n const entryUpdatedAt = new Date(entry.updatedAt).getTime();\n const publishedEntryUpdatedAt = new Date(publishedEntry.updatedAt).getTime();\n\n if (entryUpdatedAt > publishedEntryUpdatedAt) {\n return 'modified';\n }\n\n return 'published';\n};\n"],"names":["getService","name","strapi","plugin","service","getDraftEntryValidStatus","contentType","documentId","locale","populateBuilderService","populate","populateDeep","Infinity","build","entry","getEntry","isEntryValid","contentTypeUid","entityValidator","validateEntityCreation","getModel","undefined","workflowsService","workflow","getAssignedWorkflow","stageRequiredToPublish","strapi_stage","id","status","documents","findOne","findFirst","getEntryStatus","publishedAt","publishedEntry","fields","entryUpdatedAt","Date","updatedAt","getTime","publishedEntryUpdatedAt"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../server/src/utils/index.ts"],"sourcesContent":["import { contentTypes as contentTypesUtils } from '@strapi/utils';\n\nimport type { UID, Data, Core } from '@strapi/types';\n\nimport type { SettingsService } from '../services/settings';\nimport type { ReleaseService } from '../services/release';\nimport type { ReleaseActionService } from '../services/release-action';\n\ntype Services = {\n release: ReleaseService;\n 'release-validation': any;\n scheduling: any;\n 'release-action': ReleaseActionService;\n 'event-manager': any;\n settings: SettingsService;\n};\n\ninterface Action {\n contentType: UID.ContentType;\n documentId?: Data.DocumentID;\n locale?: string;\n}\n\nexport const getService = <TName extends keyof Services>(\n name: TName,\n { strapi }: { strapi: Core.Strapi }\n): Services[TName] => {\n return strapi.plugin('content-releases').service(name);\n};\n\nexport const getDraftEntryValidStatus = async (\n { contentType, documentId, locale }: Action,\n { strapi }: { strapi: Core.Strapi }\n) => {\n const populateBuilderService = strapi.plugin('content-manager').service('populate-builder');\n // @ts-expect-error - populateBuilderService should be a function but is returning service\n const populate = await populateBuilderService(contentType).populateDeep(Infinity).build();\n\n const entry = await getEntry({ contentType, documentId, locale, populate }, { strapi });\n\n return isEntryValid(contentType, entry, { strapi });\n};\n\nexport const isEntryValid = async (\n contentTypeUid: string,\n entry: any,\n { strapi }: { strapi: Core.Strapi }\n) => {\n try {\n // @TODO: When documents service has validateEntityCreation method, use it instead\n await strapi.entityValidator.validateEntityCreation(\n strapi.getModel(contentTypeUid as UID.ContentType),\n entry,\n undefined,\n // @ts-expect-error - FIXME: entity here is unnecessary\n entry\n );\n\n const workflowsService = strapi.plugin('review-workflows').service('workflows');\n // Workflows service may not be available depending on the license\n const workflow = await workflowsService?.getAssignedWorkflow(contentTypeUid, {\n populate: 'stageRequiredToPublish',\n });\n\n if (workflow?.stageRequiredToPublish) {\n return entry.strapi_stage.id === workflow.stageRequiredToPublish.id;\n }\n\n return true;\n } catch {\n return false;\n }\n};\n\nexport const getEntry = async (\n {\n contentType,\n documentId,\n locale,\n populate,\n status = 'draft',\n }: Action & { status?: 'draft' | 'published'; populate: any },\n { strapi }: { strapi: Core.Strapi }\n) => {\n if (documentId) {\n // Try to get an existing draft or published document\n const entry = await strapi\n .documents(contentType)\n .findOne({ documentId, locale, populate, status });\n\n // The document isn't published yet, but the action is to publish it, fetch the draft\n if (status === 'published' && !entry) {\n return strapi\n .documents(contentType)\n .findOne({ documentId, locale, populate, status: 'draft' });\n }\n\n return entry;\n }\n\n return strapi.documents(contentType).findFirst({ locale, populate, status });\n};\n\nexport const getEntryStatus = async (contentType: UID.ContentType, entry: Data.ContentType) => {\n if (entry.publishedAt) {\n return 'published';\n }\n\n const publishedEntry = await strapi.documents(contentType).findOne({\n documentId: entry.documentId,\n locale: entry.locale,\n status: 'published',\n fields: ['updatedAt'],\n });\n\n if (!publishedEntry) {\n return 'draft';\n }\n\n const entryUpdatedAt = new Date(entry.updatedAt).getTime();\n const publishedEntryUpdatedAt = new Date(publishedEntry.updatedAt).getTime();\n\n if (entryUpdatedAt > publishedEntryUpdatedAt) {\n return 'modified';\n }\n\n return 'published';\n};\n\n/**\n * Recursively collects content type UIDs that a model (content type or component) has relations to.\n * Go through component and dynamic zone attributes to find nested relations.\n */\nconst collectRelationTargets = (\n modelUid: string,\n strapi: Core.Strapi,\n visited = new Set<string>()\n): Set<string> => {\n const targets = new Set<string>();\n if (visited.has(modelUid)) {\n return targets;\n }\n visited.add(modelUid);\n\n const model = strapi.getModel(modelUid as UID.Schema);\n if (!model?.attributes) {\n return targets;\n }\n\n for (const attribute of Object.values(model.attributes) as Array<{\n type?: string;\n target?: string;\n component?: string;\n components?: string[];\n }>) {\n if (attribute?.type === 'relation' && attribute.target) {\n targets.add(attribute.target);\n }\n if (attribute?.type === 'component' && attribute.component) {\n for (const t of collectRelationTargets(attribute.component, strapi, visited)) {\n targets.add(t);\n }\n }\n if (attribute?.type === 'dynamiczone' && attribute.components) {\n for (const compUid of attribute.components) {\n for (const t of collectRelationTargets(compUid, strapi, visited)) {\n targets.add(t);\n }\n }\n }\n }\n return targets;\n};\n\n/**\n * Returns content type UIDs sorted by relation dependency order for publishing.\n * When content type A has a relation to content type B (both with draft & publish),\n * B will appear before A in the result. This ensures that when publishing a release,\n * related entities are published first, so that relation IDs can be correctly\n * resolved (published target must exist when publishing source).\n *\n * Relations in components (nested or not) and dynamic zones are also considered.\n *\n * @param contentTypeUids - Content type UIDs that will be published in the release\n * @param strapi - Strapi instance\n * @returns Content type UIDs in publish order (dependencies first)\n */\nexport const getPublishOrderForContentTypes = (\n contentTypeUids: UID.ContentType[],\n { strapi }: { strapi: Core.Strapi }\n): UID.ContentType[] => {\n const uidSet = new Set(contentTypeUids);\n\n // Build dependency graph: source depends on target (source must be published after target)\n const dependencies = new Map<UID.ContentType, Set<UID.ContentType>>();\n\n for (const uid of contentTypeUids) {\n const model = strapi.getModel(uid);\n if (model && contentTypesUtils.hasDraftAndPublish(model)) {\n const relationTargets = collectRelationTargets(uid, strapi);\n\n for (const targetUid of relationTargets) {\n const targetContentTypeUid = targetUid as UID.ContentType;\n const isTargetInRelease =\n uidSet.has(targetContentTypeUid) && targetContentTypeUid in strapi.contentTypes;\n const targetModel = strapi.getModel(targetContentTypeUid);\n const targetHasDraftAndPublish =\n targetModel && contentTypesUtils.hasDraftAndPublish(targetModel);\n\n if (isTargetInRelease && targetHasDraftAndPublish) {\n let dependencySet = dependencies.get(uid);\n if (!dependencySet) {\n dependencySet = new Set();\n dependencies.set(uid, dependencySet);\n }\n dependencySet.add(targetContentTypeUid);\n }\n }\n }\n }\n\n // Topological sort: dependencies first\n const sorted: UID.ContentType[] = [];\n const visited = new Set<UID.ContentType>();\n const visiting = new Set<UID.ContentType>();\n\n const visit = (uid: UID.ContentType) => {\n if (visited.has(uid)) return;\n if (visiting.has(uid)) return; // No cycle in valid schemas\n\n visiting.add(uid);\n for (const dep of dependencies.get(uid) ?? []) {\n visit(dep);\n }\n visiting.delete(uid);\n visited.add(uid);\n sorted.push(uid);\n };\n\n for (const uid of contentTypeUids) {\n visit(uid);\n }\n\n return sorted;\n};\n"],"names":["getService","name","strapi","plugin","service","getDraftEntryValidStatus","contentType","documentId","locale","populateBuilderService","populate","populateDeep","Infinity","build","entry","getEntry","isEntryValid","contentTypeUid","entityValidator","validateEntityCreation","getModel","undefined","workflowsService","workflow","getAssignedWorkflow","stageRequiredToPublish","strapi_stage","id","status","documents","findOne","findFirst","getEntryStatus","publishedAt","publishedEntry","fields","entryUpdatedAt","Date","updatedAt","getTime","publishedEntryUpdatedAt","collectRelationTargets","modelUid","visited","Set","targets","has","add","model","attributes","attribute","Object","values","type","target","component","t","components","compUid","getPublishOrderForContentTypes","contentTypeUids","uidSet","dependencies","Map","uid","contentTypesUtils","hasDraftAndPublish","relationTargets","targetUid","targetContentTypeUid","isTargetInRelease","contentTypes","targetModel","targetHasDraftAndPublish","dependencySet","get","set","sorted","visiting","visit","dep","delete","push"],"mappings":"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"}