payload 3.71.1 → 3.72.0-internal.3e70d4c
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.
- package/dist/collections/config/sanitize.d.ts.map +1 -1
- package/dist/collections/config/sanitize.js +19 -4
- package/dist/collections/config/sanitize.js.map +1 -1
- package/dist/collections/endpoints/create.d.ts.map +1 -1
- package/dist/collections/endpoints/create.js +2 -1
- package/dist/collections/endpoints/create.js.map +1 -1
- package/dist/collections/endpoints/update.d.ts.map +1 -1
- package/dist/collections/endpoints/update.js +3 -1
- package/dist/collections/endpoints/update.js.map +1 -1
- package/dist/collections/endpoints/updateByID.d.ts.map +1 -1
- package/dist/collections/endpoints/updateByID.js +4 -2
- package/dist/collections/endpoints/updateByID.js.map +1 -1
- package/dist/collections/operations/create.d.ts +1 -0
- package/dist/collections/operations/create.d.ts.map +1 -1
- package/dist/collections/operations/create.js +23 -3
- package/dist/collections/operations/create.js.map +1 -1
- package/dist/collections/operations/local/create.d.ts +4 -0
- package/dist/collections/operations/local/create.d.ts.map +1 -1
- package/dist/collections/operations/local/create.js +2 -1
- package/dist/collections/operations/local/create.js.map +1 -1
- package/dist/collections/operations/local/update.d.ts +12 -0
- package/dist/collections/operations/local/update.d.ts.map +1 -1
- package/dist/collections/operations/local/update.js +3 -1
- package/dist/collections/operations/local/update.js.map +1 -1
- package/dist/collections/operations/update.d.ts +2 -0
- package/dist/collections/operations/update.d.ts.map +1 -1
- package/dist/collections/operations/update.js +4 -3
- package/dist/collections/operations/update.js.map +1 -1
- package/dist/collections/operations/updateByID.d.ts +2 -0
- package/dist/collections/operations/updateByID.d.ts.map +1 -1
- package/dist/collections/operations/updateByID.js +4 -3
- package/dist/collections/operations/updateByID.js.map +1 -1
- package/dist/collections/operations/utilities/update.d.ts +4 -3
- package/dist/collections/operations/utilities/update.d.ts.map +1 -1
- package/dist/collections/operations/utilities/update.js +81 -31
- package/dist/collections/operations/utilities/update.js.map +1 -1
- package/dist/config/types.d.ts +16 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js.map +1 -1
- package/dist/database/migrations/templates/localizeStatus.d.ts +10 -0
- package/dist/database/migrations/templates/localizeStatus.d.ts.map +1 -0
- package/dist/database/migrations/templates/localizeStatus.js +54 -0
- package/dist/database/migrations/templates/localizeStatus.js.map +1 -0
- package/dist/exports/migrations.d.ts +19 -0
- package/dist/exports/migrations.d.ts.map +1 -0
- package/dist/exports/migrations.js +19 -0
- package/dist/exports/migrations.js.map +1 -0
- package/dist/exports/shared.d.ts +1 -1
- package/dist/exports/shared.d.ts.map +1 -1
- package/dist/exports/shared.js +1 -1
- package/dist/exports/shared.js.map +1 -1
- package/dist/globals/config/sanitize.d.ts.map +1 -1
- package/dist/globals/config/sanitize.js +11 -1
- package/dist/globals/config/sanitize.js.map +1 -1
- package/dist/globals/endpoints/update.d.ts.map +1 -1
- package/dist/globals/endpoints/update.js +5 -1
- package/dist/globals/endpoints/update.js.map +1 -1
- package/dist/globals/operations/local/update.d.ts +10 -0
- package/dist/globals/operations/local/update.d.ts.map +1 -1
- package/dist/globals/operations/local/update.js +4 -2
- package/dist/globals/operations/local/update.js.map +1 -1
- package/dist/globals/operations/update.d.ts +2 -0
- package/dist/globals/operations/update.d.ts.map +1 -1
- package/dist/globals/operations/update.js +63 -15
- package/dist/globals/operations/update.js.map +1 -1
- package/dist/index.bundled.d.ts +102 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/utilities/getVersionsConfig.d.ts +4 -0
- package/dist/utilities/getVersionsConfig.d.ts.map +1 -1
- package/dist/utilities/getVersionsConfig.js +7 -2
- package/dist/utilities/getVersionsConfig.js.map +1 -1
- package/dist/utilities/mergeLocalizedData.d.ts +20 -0
- package/dist/utilities/mergeLocalizedData.d.ts.map +1 -0
- package/dist/utilities/mergeLocalizedData.js +277 -0
- package/dist/utilities/mergeLocalizedData.js.map +1 -0
- package/dist/utilities/mergeLocalizedData.spec.js +784 -0
- package/dist/utilities/mergeLocalizedData.spec.js.map +1 -0
- package/dist/utilities/miniChalk.d.ts +15 -0
- package/dist/utilities/miniChalk.d.ts.map +1 -0
- package/dist/utilities/miniChalk.js +34 -0
- package/dist/utilities/miniChalk.js.map +1 -0
- package/dist/utilities/parseParams/index.d.ts +24 -20
- package/dist/utilities/parseParams/index.d.ts.map +1 -1
- package/dist/utilities/parseParams/index.js.map +1 -1
- package/dist/utilities/traverseForLocalizedFields.d.ts +3 -0
- package/dist/utilities/traverseForLocalizedFields.d.ts.map +1 -0
- package/dist/utilities/traverseForLocalizedFields.js +41 -0
- package/dist/utilities/traverseForLocalizedFields.js.map +1 -0
- package/dist/versions/baseFields.d.ts +3 -1
- package/dist/versions/baseFields.d.ts.map +1 -1
- package/dist/versions/baseFields.js +16 -15
- package/dist/versions/baseFields.js.map +1 -1
- package/dist/versions/drafts/replaceWithDraftIfAvailable.d.ts.map +1 -1
- package/dist/versions/drafts/replaceWithDraftIfAvailable.js +28 -2
- package/dist/versions/drafts/replaceWithDraftIfAvailable.js.map +1 -1
- package/dist/versions/migrations/localizeStatus/index.d.ts +12 -0
- package/dist/versions/migrations/localizeStatus/index.d.ts.map +1 -0
- package/dist/versions/migrations/localizeStatus/index.js +33 -0
- package/dist/versions/migrations/localizeStatus/index.js.map +1 -0
- package/dist/versions/migrations/localizeStatus/mongo/down.d.ts +9 -0
- package/dist/versions/migrations/localizeStatus/mongo/down.d.ts.map +1 -0
- package/dist/versions/migrations/localizeStatus/mongo/down.js +112 -0
- package/dist/versions/migrations/localizeStatus/mongo/down.js.map +1 -0
- package/dist/versions/migrations/localizeStatus/mongo/index.d.ts +8 -0
- package/dist/versions/migrations/localizeStatus/mongo/index.d.ts.map +1 -0
- package/dist/versions/migrations/localizeStatus/mongo/index.js +8 -0
- package/dist/versions/migrations/localizeStatus/mongo/index.js.map +1 -0
- package/dist/versions/migrations/localizeStatus/mongo/up.d.ts +9 -0
- package/dist/versions/migrations/localizeStatus/mongo/up.d.ts.map +1 -0
- package/dist/versions/migrations/localizeStatus/mongo/up.js +220 -0
- package/dist/versions/migrations/localizeStatus/mongo/up.js.map +1 -0
- package/dist/versions/migrations/localizeStatus/shared.d.ts +59 -0
- package/dist/versions/migrations/localizeStatus/shared.d.ts.map +1 -0
- package/dist/versions/migrations/localizeStatus/shared.js +122 -0
- package/dist/versions/migrations/localizeStatus/shared.js.map +1 -0
- package/dist/versions/migrations/localizeStatus/sql/down.d.ts +11 -0
- package/dist/versions/migrations/localizeStatus/sql/down.d.ts.map +1 -0
- package/dist/versions/migrations/localizeStatus/sql/down.js +213 -0
- package/dist/versions/migrations/localizeStatus/sql/down.js.map +1 -0
- package/dist/versions/migrations/localizeStatus/sql/index.d.ts +8 -0
- package/dist/versions/migrations/localizeStatus/sql/index.d.ts.map +1 -0
- package/dist/versions/migrations/localizeStatus/sql/index.js +8 -0
- package/dist/versions/migrations/localizeStatus/sql/index.js.map +1 -0
- package/dist/versions/migrations/localizeStatus/sql/migrateMainCollection.d.ts +13 -0
- package/dist/versions/migrations/localizeStatus/sql/migrateMainCollection.d.ts.map +1 -0
- package/dist/versions/migrations/localizeStatus/sql/migrateMainCollection.js +51 -0
- package/dist/versions/migrations/localizeStatus/sql/migrateMainCollection.js.map +1 -0
- package/dist/versions/migrations/localizeStatus/sql/migrateMainGlobal.d.ts +13 -0
- package/dist/versions/migrations/localizeStatus/sql/migrateMainGlobal.d.ts.map +1 -0
- package/dist/versions/migrations/localizeStatus/sql/migrateMainGlobal.js +54 -0
- package/dist/versions/migrations/localizeStatus/sql/migrateMainGlobal.js.map +1 -0
- package/dist/versions/migrations/localizeStatus/sql/up.d.ts +11 -0
- package/dist/versions/migrations/localizeStatus/sql/up.d.ts.map +1 -0
- package/dist/versions/migrations/localizeStatus/sql/up.js +277 -0
- package/dist/versions/migrations/localizeStatus/sql/up.js.map +1 -0
- package/dist/versions/saveSnapshot.d.ts.map +1 -1
- package/dist/versions/saveSnapshot.js +0 -1
- package/dist/versions/saveSnapshot.js.map +1 -1
- package/dist/versions/saveVersion.js +0 -3
- package/dist/versions/saveVersion.js.map +1 -1
- package/dist/versions/types.d.ts +18 -0
- package/dist/versions/types.d.ts.map +1 -1
- package/dist/versions/types.js.map +1 -1
- package/package.json +7 -2
- package/dist/uploads/imageResizer.d.ts +0 -40
- package/dist/uploads/imageResizer.d.ts.map +0 -1
- package/dist/uploads/imageResizer.js +0 -356
- package/dist/uploads/imageResizer.js.map +0 -1
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { hasLocalizeStatusEnabled } from '../../../../utilities/getVersionsConfig.js';
|
|
2
|
+
export async function down(args) {
|
|
3
|
+
const { collectionSlug, globalSlug, payload } = args;
|
|
4
|
+
if (!collectionSlug && !globalSlug) {
|
|
5
|
+
throw new Error('Either collectionSlug or globalSlug must be provided');
|
|
6
|
+
}
|
|
7
|
+
if (collectionSlug && globalSlug) {
|
|
8
|
+
throw new Error('Cannot provide both collectionSlug and globalSlug');
|
|
9
|
+
}
|
|
10
|
+
const entitySlug = collectionSlug || globalSlug;
|
|
11
|
+
// MongoDB collection names are case-insensitive and stored as lowercase
|
|
12
|
+
const versionsCollection = `_${entitySlug}_versions`.toLowerCase();
|
|
13
|
+
if (!payload.config.localization) {
|
|
14
|
+
throw new Error('Localization is not enabled in payload config');
|
|
15
|
+
}
|
|
16
|
+
const entityConfig = collectionSlug ? payload.config.collections.find((c)=>c.slug === collectionSlug) : payload.config.globals.find((g)=>g.slug === globalSlug);
|
|
17
|
+
if (!entityConfig) {
|
|
18
|
+
throw new Error(`${collectionSlug ? 'Collection' : 'Global'} not found: ${collectionSlug || globalSlug}`);
|
|
19
|
+
}
|
|
20
|
+
if (hasLocalizeStatusEnabled(entityConfig)) {
|
|
21
|
+
throw new Error(`${entitySlug} has localizeStatus enabled, cannot run down migration. ` + `Please disable localizeStatus in your config before rolling back this migration.`);
|
|
22
|
+
}
|
|
23
|
+
const defaultLocale = payload.config.localization.defaultLocale;
|
|
24
|
+
payload.logger.info({
|
|
25
|
+
msg: `Rolling back _status localization migration for ${collectionSlug ? 'collection' : 'global'}: ${entitySlug}`
|
|
26
|
+
});
|
|
27
|
+
// Get MongoDB connection
|
|
28
|
+
const connection = payload.db.connection;
|
|
29
|
+
payload.logger.info({
|
|
30
|
+
msg: 'Fetching all version documents...'
|
|
31
|
+
});
|
|
32
|
+
// Get all versions
|
|
33
|
+
const allVersions = await connection.collection(versionsCollection).find({}).toArray();
|
|
34
|
+
payload.logger.info({
|
|
35
|
+
msg: `Found ${allVersions.length} version documents`
|
|
36
|
+
});
|
|
37
|
+
// Update each version document: convert version._status from object to string
|
|
38
|
+
let updateCount = 0;
|
|
39
|
+
for (const doc of allVersions){
|
|
40
|
+
const currentStatus = doc.version?._status;
|
|
41
|
+
if (!currentStatus || typeof currentStatus === 'string') {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
// Convert from { en: 'published', es: 'draft' } to 'published' (using default locale)
|
|
45
|
+
const statusValue = typeof currentStatus === 'object' ? currentStatus[defaultLocale] || 'draft' : 'draft';
|
|
46
|
+
await connection.collection(versionsCollection).updateOne({
|
|
47
|
+
_id: doc._id
|
|
48
|
+
}, {
|
|
49
|
+
$set: {
|
|
50
|
+
'version._status': statusValue
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
updateCount++;
|
|
54
|
+
}
|
|
55
|
+
payload.logger.info({
|
|
56
|
+
msg: `Updated ${updateCount} version documents`
|
|
57
|
+
});
|
|
58
|
+
// Rollback main collection/global document status
|
|
59
|
+
if (collectionSlug) {
|
|
60
|
+
const mainCollection = collectionSlug;
|
|
61
|
+
const mainDoc = await connection.collection(mainCollection).findOne({});
|
|
62
|
+
if (mainDoc && '_status' in mainDoc && typeof mainDoc._status === 'object') {
|
|
63
|
+
payload.logger.info({
|
|
64
|
+
msg: `Rolling back main collection documents for: ${mainCollection}`
|
|
65
|
+
});
|
|
66
|
+
const allDocs = await connection.collection(mainCollection).find({}).toArray();
|
|
67
|
+
for (const doc of allDocs){
|
|
68
|
+
if (typeof doc._status === 'object' && !Array.isArray(doc._status)) {
|
|
69
|
+
// Convert from { en: 'published', es: 'draft' } to 'published' (using default locale)
|
|
70
|
+
const statusValue = doc._status[defaultLocale] || 'draft';
|
|
71
|
+
await connection.collection(mainCollection).updateOne({
|
|
72
|
+
_id: doc._id
|
|
73
|
+
}, {
|
|
74
|
+
$set: {
|
|
75
|
+
_status: statusValue
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
payload.logger.info({
|
|
81
|
+
msg: `Rolled back ${allDocs.length} collection documents`
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
} else if (globalSlug) {
|
|
85
|
+
const globalDoc = await connection.collection('globals').findOne({
|
|
86
|
+
globalType: globalSlug
|
|
87
|
+
});
|
|
88
|
+
if (globalDoc && '_status' in globalDoc && typeof globalDoc.status === 'object') {
|
|
89
|
+
payload.logger.info({
|
|
90
|
+
msg: `Rolling back main global document for: ${globalSlug}`
|
|
91
|
+
});
|
|
92
|
+
// Convert from { en: 'published', es: 'draft' } to 'published' (using default locale)
|
|
93
|
+
const statusValue = typeof globalDoc._status === 'object' && !Array.isArray(globalDoc._status) ? globalDoc._status[defaultLocale] || 'draft' : 'draft';
|
|
94
|
+
await connection.collection('globals').updateOne({
|
|
95
|
+
_id: globalDoc._id,
|
|
96
|
+
globalType: globalSlug
|
|
97
|
+
}, {
|
|
98
|
+
$set: {
|
|
99
|
+
_status: statusValue
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
payload.logger.info({
|
|
103
|
+
msg: 'Rolled back global document'
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
payload.logger.info({
|
|
108
|
+
msg: 'Rollback completed successfully'
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
//# sourceMappingURL=down.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../src/versions/migrations/localizeStatus/mongo/down.ts"],"sourcesContent":["import type { Payload } from '../../../../types/index.js'\n\nimport { hasLocalizeStatusEnabled } from '../../../../utilities/getVersionsConfig.js'\n\nexport type LocalizeStatusArgs = {\n collectionSlug?: string\n globalSlug?: string\n payload: Payload\n req?: any\n}\n\nexport async function down(args: LocalizeStatusArgs): Promise<void> {\n const { collectionSlug, globalSlug, payload } = args\n\n if (!collectionSlug && !globalSlug) {\n throw new Error('Either collectionSlug or globalSlug must be provided')\n }\n\n if (collectionSlug && globalSlug) {\n throw new Error('Cannot provide both collectionSlug and globalSlug')\n }\n\n const entitySlug = collectionSlug || globalSlug\n // MongoDB collection names are case-insensitive and stored as lowercase\n const versionsCollection = `_${entitySlug}_versions`.toLowerCase()\n\n if (!payload.config.localization) {\n throw new Error('Localization is not enabled in payload config')\n }\n\n const entityConfig = collectionSlug\n ? payload.config.collections.find((c) => c.slug === collectionSlug)\n : payload.config.globals.find((g) => g.slug === globalSlug!)\n\n if (!entityConfig) {\n throw new Error(\n `${collectionSlug ? 'Collection' : 'Global'} not found: ${collectionSlug || globalSlug}`,\n )\n }\n\n if (hasLocalizeStatusEnabled(entityConfig)) {\n throw new Error(\n `${entitySlug} has localizeStatus enabled, cannot run down migration. ` +\n `Please disable localizeStatus in your config before rolling back this migration.`,\n )\n }\n\n const defaultLocale = payload.config.localization.defaultLocale\n\n payload.logger.info({\n msg: `Rolling back _status localization migration for ${collectionSlug ? 'collection' : 'global'}: ${entitySlug}`,\n })\n\n // Get MongoDB connection\n const connection = (payload.db as any).connection\n\n payload.logger.info({ msg: 'Fetching all version documents...' })\n\n // Get all versions\n const allVersions = await connection.collection(versionsCollection).find({}).toArray()\n\n payload.logger.info({ msg: `Found ${allVersions.length} version documents` })\n\n // Update each version document: convert version._status from object to string\n let updateCount = 0\n for (const doc of allVersions) {\n const currentStatus = doc.version?._status\n\n if (!currentStatus || typeof currentStatus === 'string') {\n // Already rolled back or never migrated\n continue\n }\n\n // Convert from { en: 'published', es: 'draft' } to 'published' (using default locale)\n const statusValue =\n typeof currentStatus === 'object' ? currentStatus[defaultLocale] || 'draft' : 'draft'\n\n await connection.collection(versionsCollection).updateOne(\n { _id: doc._id },\n {\n $set: {\n 'version._status': statusValue,\n },\n },\n )\n\n updateCount++\n }\n\n payload.logger.info({ msg: `Updated ${updateCount} version documents` })\n\n // Rollback main collection/global document status\n if (collectionSlug) {\n const mainCollection = collectionSlug\n const mainDoc = await connection.collection(mainCollection).findOne({})\n\n if (mainDoc && '_status' in mainDoc && typeof mainDoc._status === 'object') {\n payload.logger.info({ msg: `Rolling back main collection documents for: ${mainCollection}` })\n\n const allDocs = await connection.collection(mainCollection).find({}).toArray()\n\n for (const doc of allDocs) {\n if (typeof doc._status === 'object' && !Array.isArray(doc._status)) {\n // Convert from { en: 'published', es: 'draft' } to 'published' (using default locale)\n const statusValue = doc._status[defaultLocale] || 'draft'\n\n await connection.collection(mainCollection).updateOne(\n { _id: doc._id },\n {\n $set: {\n _status: statusValue,\n },\n },\n )\n }\n }\n\n payload.logger.info({ msg: `Rolled back ${allDocs.length} collection documents` })\n }\n } else if (globalSlug) {\n const globalDoc = await connection.collection('globals').findOne({ globalType: globalSlug })\n\n if (globalDoc && '_status' in globalDoc && typeof globalDoc.status === 'object') {\n payload.logger.info({ msg: `Rolling back main global document for: ${globalSlug}` })\n\n // Convert from { en: 'published', es: 'draft' } to 'published' (using default locale)\n const statusValue =\n typeof globalDoc._status === 'object' && !Array.isArray(globalDoc._status)\n ? globalDoc._status[defaultLocale] || 'draft'\n : 'draft'\n\n await connection.collection('globals').updateOne(\n { _id: globalDoc._id, globalType: globalSlug },\n {\n $set: {\n _status: statusValue,\n },\n },\n )\n\n payload.logger.info({ msg: 'Rolled back global document' })\n }\n }\n\n payload.logger.info({ msg: 'Rollback completed successfully' })\n}\n"],"names":["hasLocalizeStatusEnabled","down","args","collectionSlug","globalSlug","payload","Error","entitySlug","versionsCollection","toLowerCase","config","localization","entityConfig","collections","find","c","slug","globals","g","defaultLocale","logger","info","msg","connection","db","allVersions","collection","toArray","length","updateCount","doc","currentStatus","version","_status","statusValue","updateOne","_id","$set","mainCollection","mainDoc","findOne","allDocs","Array","isArray","globalDoc","globalType","status"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/versions/migrations/localizeStatus/mongo/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAA;AAE5B,eAAO,MAAM,cAAc;;;CAG1B,CAAA;AAED,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../src/versions/migrations/localizeStatus/mongo/index.ts"],"sourcesContent":["import { down } from './down.js'\nimport { up } from './up.js'\n\nexport const localizeStatus = {\n down,\n up,\n}\n\nexport type { LocalizeStatusArgs } from './up.js'\n"],"names":["down","up","localizeStatus"],"mappings":"AAAA,SAASA,IAAI,QAAQ,YAAW;AAChC,SAASC,EAAE,QAAQ,UAAS;AAE5B,OAAO,MAAMC,iBAAiB;IAC5BF;IACAC;AACF,EAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Payload } from '../../../../types/index.js';
|
|
2
|
+
export type LocalizeStatusArgs = {
|
|
3
|
+
collectionSlug?: string;
|
|
4
|
+
globalSlug?: string;
|
|
5
|
+
payload: Payload;
|
|
6
|
+
req?: any;
|
|
7
|
+
};
|
|
8
|
+
export declare function up(args: LocalizeStatusArgs): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=up.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"up.d.ts","sourceRoot":"","sources":["../../../../../src/versions/migrations/localizeStatus/mongo/up.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AAIzD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,OAAO,CAAA;IAChB,GAAG,CAAC,EAAE,GAAG,CAAA;CACV,CAAA;AAED,wBAAsB,EAAE,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2PhE"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { calculateVersionLocaleStatuses } from '../shared.js';
|
|
2
|
+
export async function up(args) {
|
|
3
|
+
const { collectionSlug, globalSlug, payload, req } = args;
|
|
4
|
+
if (!collectionSlug && !globalSlug) {
|
|
5
|
+
throw new Error('Either collectionSlug or globalSlug must be provided');
|
|
6
|
+
}
|
|
7
|
+
if (collectionSlug && globalSlug) {
|
|
8
|
+
throw new Error('Cannot provide both collectionSlug and globalSlug');
|
|
9
|
+
}
|
|
10
|
+
const entitySlug = collectionSlug || globalSlug;
|
|
11
|
+
// MongoDB collection names are case-insensitive and stored as lowercase
|
|
12
|
+
const versionsCollection = `_${entitySlug}_versions`.toLowerCase();
|
|
13
|
+
if (!payload.config.localization) {
|
|
14
|
+
throw new Error('Localization is not enabled in payload config');
|
|
15
|
+
}
|
|
16
|
+
// Check if versions are enabled on this collection/global
|
|
17
|
+
let entityConfig;
|
|
18
|
+
if (collectionSlug) {
|
|
19
|
+
const collection = payload.config.collections.find((c)=>c.slug === collectionSlug);
|
|
20
|
+
if (collection) {
|
|
21
|
+
entityConfig = collection;
|
|
22
|
+
}
|
|
23
|
+
} else if (globalSlug) {
|
|
24
|
+
const global = payload.config.globals.find((g)=>g.slug === globalSlug);
|
|
25
|
+
if (global) {
|
|
26
|
+
entityConfig = global;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (!entityConfig) {
|
|
30
|
+
throw new Error(`${collectionSlug ? 'Collection' : 'Global'} not found: ${collectionSlug || globalSlug}`);
|
|
31
|
+
}
|
|
32
|
+
payload.logger.info({
|
|
33
|
+
msg: `Starting _status localization migration for ${collectionSlug ? 'collection' : 'global'}: ${entitySlug}`
|
|
34
|
+
});
|
|
35
|
+
// Check if versions are enabled in config (skip if not)
|
|
36
|
+
if (!entityConfig.versions) {
|
|
37
|
+
payload.logger.info({
|
|
38
|
+
msg: `Skipping migration for ${collectionSlug ? 'collection' : 'global'}: ${entitySlug} - versions not enabled`
|
|
39
|
+
});
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// Get MongoDB connection
|
|
43
|
+
const connection = payload.db.connection;
|
|
44
|
+
// Get filtered locales if filterAvailableLocales is defined
|
|
45
|
+
let locales = payload.config.localization.localeCodes;
|
|
46
|
+
if (typeof payload.config.localization.filterAvailableLocales === 'function') {
|
|
47
|
+
const filteredLocaleObjects = await payload.config.localization.filterAvailableLocales({
|
|
48
|
+
locales: payload.config.localization.locales,
|
|
49
|
+
req
|
|
50
|
+
});
|
|
51
|
+
locales = filteredLocaleObjects.map((locale)=>locale.code);
|
|
52
|
+
}
|
|
53
|
+
payload.logger.info({
|
|
54
|
+
msg: `Locales: ${locales.join(', ')}`
|
|
55
|
+
});
|
|
56
|
+
// Check if version._status exists and is NOT already localized
|
|
57
|
+
const sampleDoc = await connection.collection(versionsCollection).findOne({});
|
|
58
|
+
if (!sampleDoc) {
|
|
59
|
+
payload.logger.info({
|
|
60
|
+
msg: 'No version documents found, nothing to migrate'
|
|
61
|
+
});
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
// Check if _status is already localized
|
|
65
|
+
if (sampleDoc.version?._status && typeof sampleDoc.version._status === 'object' && !Array.isArray(sampleDoc.version._status)) {
|
|
66
|
+
payload.logger.info({
|
|
67
|
+
msg: 'version._status is already localized, migration already completed'
|
|
68
|
+
});
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
// Validate that version._status exists and is a string
|
|
72
|
+
if (!sampleDoc.version || typeof sampleDoc.version._status !== 'string' || Array.isArray(sampleDoc.version._status)) {
|
|
73
|
+
throw new Error(`Migration aborted: version._status field not found or has unexpected format in ${versionsCollection}. ` + `This migration should only run on schemas that have NOT yet been migrated to per-locale status.`);
|
|
74
|
+
}
|
|
75
|
+
payload.logger.info({
|
|
76
|
+
msg: 'Fetching all version documents...'
|
|
77
|
+
});
|
|
78
|
+
// Get all versions, sorted chronologically
|
|
79
|
+
const allVersions = await connection.collection(versionsCollection).find({}).sort({
|
|
80
|
+
createdAt: 1,
|
|
81
|
+
parent: 1
|
|
82
|
+
}).toArray();
|
|
83
|
+
payload.logger.info({
|
|
84
|
+
msg: `Found ${allVersions.length} version documents`
|
|
85
|
+
});
|
|
86
|
+
// Transform MongoDB documents to VersionRecord format
|
|
87
|
+
const versionRecords = allVersions.map((doc)=>({
|
|
88
|
+
id: doc._id.toString(),
|
|
89
|
+
_status: doc.version._status,
|
|
90
|
+
createdAt: doc.createdAt,
|
|
91
|
+
parent: doc.parent?.toString(),
|
|
92
|
+
publishedLocale: doc.publishedLocale,
|
|
93
|
+
snapshot: doc.snapshot || false
|
|
94
|
+
}));
|
|
95
|
+
// Calculate status per locale using shared logic
|
|
96
|
+
const versionLocaleStatus = calculateVersionLocaleStatuses(versionRecords, locales, payload);
|
|
97
|
+
payload.logger.info({
|
|
98
|
+
msg: 'Updating version documents with per-locale status...'
|
|
99
|
+
});
|
|
100
|
+
// Update each version document
|
|
101
|
+
let updateCount = 0;
|
|
102
|
+
for (const doc of allVersions){
|
|
103
|
+
const versionId = doc._id.toString();
|
|
104
|
+
const localeStatusMap = versionLocaleStatus.get(versionId);
|
|
105
|
+
if (!localeStatusMap) {
|
|
106
|
+
payload.logger.warn({
|
|
107
|
+
msg: `No status map found for version ${versionId}, skipping`
|
|
108
|
+
});
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
// Build the new _status object: { en: 'published', es: 'draft', ... }
|
|
112
|
+
const newStatus = {};
|
|
113
|
+
for (const [locale, status] of localeStatusMap.entries()){
|
|
114
|
+
newStatus[locale] = status;
|
|
115
|
+
}
|
|
116
|
+
// Update the document: change version._status from string to object
|
|
117
|
+
await connection.collection(versionsCollection).updateOne({
|
|
118
|
+
_id: doc._id
|
|
119
|
+
}, {
|
|
120
|
+
$set: {
|
|
121
|
+
'version._status': newStatus
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
updateCount++;
|
|
125
|
+
}
|
|
126
|
+
payload.logger.info({
|
|
127
|
+
msg: `Updated ${updateCount} version documents`
|
|
128
|
+
});
|
|
129
|
+
// Migrate main collection/global document _status to per-locale status object
|
|
130
|
+
// Only if it has a status field
|
|
131
|
+
if (collectionSlug) {
|
|
132
|
+
const mainCollection = collectionSlug;
|
|
133
|
+
const mainDoc = await connection.collection(mainCollection).findOne({});
|
|
134
|
+
if (mainDoc && '_status' in mainDoc) {
|
|
135
|
+
payload.logger.info({
|
|
136
|
+
msg: `Migrating main collection documents for: ${mainCollection}`
|
|
137
|
+
});
|
|
138
|
+
const allDocs = await connection.collection(mainCollection).find({}).toArray();
|
|
139
|
+
for (const doc of allDocs){
|
|
140
|
+
if (!doc._id) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
// Get the latest version for this document to determine status per locale
|
|
144
|
+
const latestVersions = await connection.collection(versionsCollection).find({
|
|
145
|
+
parent: doc._id
|
|
146
|
+
}).sort({
|
|
147
|
+
createdAt: -1
|
|
148
|
+
}).limit(1).toArray();
|
|
149
|
+
let statusObj = {};
|
|
150
|
+
if (latestVersions.length > 0 && latestVersions[0]?.version?._status) {
|
|
151
|
+
// Use the status from the latest version
|
|
152
|
+
statusObj = latestVersions[0].version._status;
|
|
153
|
+
} else {
|
|
154
|
+
// Fallback: set all locales to draft
|
|
155
|
+
for (const locale of locales){
|
|
156
|
+
statusObj[locale] = 'draft';
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Update main document
|
|
160
|
+
await connection.collection(mainCollection).updateOne({
|
|
161
|
+
_id: doc._id
|
|
162
|
+
}, {
|
|
163
|
+
$set: {
|
|
164
|
+
_status: statusObj
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
payload.logger.info({
|
|
169
|
+
msg: `Migrated ${allDocs.length} collection documents`
|
|
170
|
+
});
|
|
171
|
+
} else {
|
|
172
|
+
payload.logger.info({
|
|
173
|
+
msg: 'Skipping main document status migration (no status field found)'
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
} else if (globalSlug) {
|
|
177
|
+
// Globals are stored in a single 'globals' collection with globalType discriminator
|
|
178
|
+
const globalDoc = await connection.collection('globals').findOne({
|
|
179
|
+
globalType: globalSlug
|
|
180
|
+
});
|
|
181
|
+
if (globalDoc && '_status' in globalDoc && globalDoc._id) {
|
|
182
|
+
payload.logger.info({
|
|
183
|
+
msg: `Migrating main global document for: ${globalSlug}`
|
|
184
|
+
});
|
|
185
|
+
// Get the latest version for the global
|
|
186
|
+
const latestVersions = await connection.collection(versionsCollection).find({}).sort({
|
|
187
|
+
createdAt: -1
|
|
188
|
+
}).limit(1).toArray();
|
|
189
|
+
let statusObj = {};
|
|
190
|
+
if (latestVersions.length > 0 && latestVersions[0]?.version?._status) {
|
|
191
|
+
statusObj = latestVersions[0].version._status;
|
|
192
|
+
} else {
|
|
193
|
+
for (const locale of locales){
|
|
194
|
+
statusObj[locale] = 'draft';
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// Update global document
|
|
198
|
+
await connection.collection('globals').updateOne({
|
|
199
|
+
_id: globalDoc._id,
|
|
200
|
+
globalType: globalSlug
|
|
201
|
+
}, {
|
|
202
|
+
$set: {
|
|
203
|
+
_status: statusObj
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
payload.logger.info({
|
|
207
|
+
msg: 'Migrated global document'
|
|
208
|
+
});
|
|
209
|
+
} else {
|
|
210
|
+
payload.logger.info({
|
|
211
|
+
msg: 'Skipping main document status migration (no status field found)'
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
payload.logger.info({
|
|
216
|
+
msg: 'Migration completed successfully'
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
//# sourceMappingURL=up.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../src/versions/migrations/localizeStatus/mongo/up.ts"],"sourcesContent":["import type { Payload } from '../../../../types/index.js'\n\nimport { calculateVersionLocaleStatuses, type VersionRecord } from '../shared.js'\n\nexport type LocalizeStatusArgs = {\n collectionSlug?: string\n globalSlug?: string\n payload: Payload\n req?: any\n}\n\nexport async function up(args: LocalizeStatusArgs): Promise<void> {\n const { collectionSlug, globalSlug, payload, req } = args\n\n if (!collectionSlug && !globalSlug) {\n throw new Error('Either collectionSlug or globalSlug must be provided')\n }\n\n if (collectionSlug && globalSlug) {\n throw new Error('Cannot provide both collectionSlug and globalSlug')\n }\n\n const entitySlug = collectionSlug || globalSlug\n // MongoDB collection names are case-insensitive and stored as lowercase\n const versionsCollection = `_${entitySlug}_versions`.toLowerCase()\n\n if (!payload.config.localization) {\n throw new Error('Localization is not enabled in payload config')\n }\n\n // Check if versions are enabled on this collection/global\n let entityConfig\n if (collectionSlug) {\n const collection = payload.config.collections.find((c) => c.slug === collectionSlug)\n if (collection) {\n entityConfig = collection\n }\n } else if (globalSlug) {\n const global = payload.config.globals.find((g) => g.slug === globalSlug)\n if (global) {\n entityConfig = global\n }\n }\n\n if (!entityConfig) {\n throw new Error(\n `${collectionSlug ? 'Collection' : 'Global'} not found: ${collectionSlug || globalSlug}`,\n )\n }\n\n payload.logger.info({\n msg: `Starting _status localization migration for ${collectionSlug ? 'collection' : 'global'}: ${entitySlug}`,\n })\n\n // Check if versions are enabled in config (skip if not)\n if (!entityConfig.versions) {\n payload.logger.info({\n msg: `Skipping migration for ${collectionSlug ? 'collection' : 'global'}: ${entitySlug} - versions not enabled`,\n })\n return\n }\n\n // Get MongoDB connection\n const connection = (payload.db as any).connection\n\n // Get filtered locales if filterAvailableLocales is defined\n let locales = payload.config.localization.localeCodes\n if (typeof payload.config.localization.filterAvailableLocales === 'function') {\n const filteredLocaleObjects = await payload.config.localization.filterAvailableLocales({\n locales: payload.config.localization.locales,\n req,\n })\n locales = filteredLocaleObjects.map((locale) => locale.code)\n }\n payload.logger.info({ msg: `Locales: ${locales.join(', ')}` })\n\n // Check if version._status exists and is NOT already localized\n const sampleDoc = await connection.collection(versionsCollection).findOne({})\n\n if (!sampleDoc) {\n payload.logger.info({ msg: 'No version documents found, nothing to migrate' })\n return\n }\n\n // Check if _status is already localized\n if (\n sampleDoc.version?._status &&\n typeof sampleDoc.version._status === 'object' &&\n !Array.isArray(sampleDoc.version._status)\n ) {\n payload.logger.info({\n msg: 'version._status is already localized, migration already completed',\n })\n return\n }\n\n // Validate that version._status exists and is a string\n if (\n !sampleDoc.version ||\n typeof sampleDoc.version._status !== 'string' ||\n Array.isArray(sampleDoc.version._status)\n ) {\n throw new Error(\n `Migration aborted: version._status field not found or has unexpected format in ${versionsCollection}. ` +\n `This migration should only run on schemas that have NOT yet been migrated to per-locale status.`,\n )\n }\n\n payload.logger.info({ msg: 'Fetching all version documents...' })\n\n // Get all versions, sorted chronologically\n const allVersions = await connection\n .collection(versionsCollection)\n .find({})\n .sort({ createdAt: 1, parent: 1 })\n .toArray()\n\n payload.logger.info({ msg: `Found ${allVersions.length} version documents` })\n\n // Transform MongoDB documents to VersionRecord format\n const versionRecords: VersionRecord[] = allVersions.map((doc: any) => ({\n id: doc._id.toString(),\n _status: doc.version._status as 'draft' | 'published',\n createdAt: doc.createdAt,\n parent: doc.parent?.toString(),\n publishedLocale: doc.publishedLocale,\n snapshot: doc.snapshot || false,\n }))\n\n // Calculate status per locale using shared logic\n const versionLocaleStatus = calculateVersionLocaleStatuses(versionRecords, locales, payload)\n\n payload.logger.info({ msg: 'Updating version documents with per-locale status...' })\n\n // Update each version document\n let updateCount = 0\n for (const doc of allVersions) {\n const versionId = doc._id.toString()\n const localeStatusMap = versionLocaleStatus.get(versionId)\n\n if (!localeStatusMap) {\n payload.logger.warn({ msg: `No status map found for version ${versionId}, skipping` })\n continue\n }\n\n // Build the new _status object: { en: 'published', es: 'draft', ... }\n const newStatus: Record<string, string> = {}\n for (const [locale, status] of localeStatusMap.entries()) {\n newStatus[locale] = status\n }\n\n // Update the document: change version._status from string to object\n await connection.collection(versionsCollection).updateOne(\n { _id: doc._id },\n {\n $set: {\n 'version._status': newStatus,\n },\n },\n )\n\n updateCount++\n }\n\n payload.logger.info({ msg: `Updated ${updateCount} version documents` })\n\n // Migrate main collection/global document _status to per-locale status object\n // Only if it has a status field\n if (collectionSlug) {\n const mainCollection = collectionSlug\n const mainDoc = await connection.collection(mainCollection).findOne({})\n\n if (mainDoc && '_status' in mainDoc) {\n payload.logger.info({ msg: `Migrating main collection documents for: ${mainCollection}` })\n\n const allDocs = await connection.collection(mainCollection).find({}).toArray()\n\n for (const doc of allDocs) {\n if (!doc._id) {\n continue\n }\n\n // Get the latest version for this document to determine status per locale\n const latestVersions = await connection\n .collection(versionsCollection)\n .find({ parent: doc._id })\n .sort({ createdAt: -1 })\n .limit(1)\n .toArray()\n\n let statusObj: Record<string, string> = {}\n\n if (latestVersions.length > 0 && latestVersions[0]?.version?._status) {\n // Use the status from the latest version\n statusObj = latestVersions[0].version._status\n } else {\n // Fallback: set all locales to draft\n for (const locale of locales) {\n statusObj[locale] = 'draft'\n }\n }\n\n // Update main document\n await connection.collection(mainCollection).updateOne(\n { _id: doc._id },\n {\n $set: {\n _status: statusObj,\n },\n },\n )\n }\n\n payload.logger.info({ msg: `Migrated ${allDocs.length} collection documents` })\n } else {\n payload.logger.info({\n msg: 'Skipping main document status migration (no status field found)',\n })\n }\n } else if (globalSlug) {\n // Globals are stored in a single 'globals' collection with globalType discriminator\n const globalDoc = await connection.collection('globals').findOne({ globalType: globalSlug })\n if (globalDoc && '_status' in globalDoc && globalDoc._id) {\n payload.logger.info({ msg: `Migrating main global document for: ${globalSlug}` })\n\n // Get the latest version for the global\n const latestVersions = await connection\n .collection(versionsCollection)\n .find({})\n .sort({ createdAt: -1 })\n .limit(1)\n .toArray()\n\n let statusObj: Record<string, string> = {}\n\n if (latestVersions.length > 0 && latestVersions[0]?.version?._status) {\n statusObj = latestVersions[0].version._status\n } else {\n for (const locale of locales) {\n statusObj[locale] = 'draft'\n }\n }\n\n // Update global document\n await connection.collection('globals').updateOne(\n { _id: globalDoc._id, globalType: globalSlug },\n {\n $set: {\n _status: statusObj,\n },\n },\n )\n\n payload.logger.info({ msg: 'Migrated global document' })\n } else {\n payload.logger.info({\n msg: 'Skipping main document status migration (no status field found)',\n })\n }\n }\n\n payload.logger.info({ msg: 'Migration completed successfully' })\n}\n"],"names":["calculateVersionLocaleStatuses","up","args","collectionSlug","globalSlug","payload","req","Error","entitySlug","versionsCollection","toLowerCase","config","localization","entityConfig","collection","collections","find","c","slug","global","globals","g","logger","info","msg","versions","connection","db","locales","localeCodes","filterAvailableLocales","filteredLocaleObjects","map","locale","code","join","sampleDoc","findOne","version","_status","Array","isArray","allVersions","sort","createdAt","parent","toArray","length","versionRecords","doc","id","_id","toString","publishedLocale","snapshot","versionLocaleStatus","updateCount","versionId","localeStatusMap","get","warn","newStatus","status","entries","updateOne","$set","mainCollection","mainDoc","allDocs","latestVersions","limit","statusObj","globalDoc","globalType"],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Payload } from '../../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Convert to snake_case (matches to-snake-case library behavior)
|
|
4
|
+
* Handles camelCase, PascalCase, and hyphens
|
|
5
|
+
*/
|
|
6
|
+
export declare const toSnakeCase: (str: string) => string;
|
|
7
|
+
export type VersionRecord = {
|
|
8
|
+
_status: 'draft' | 'published';
|
|
9
|
+
created_at?: Date | string;
|
|
10
|
+
createdAt?: Date | string;
|
|
11
|
+
id: number | string;
|
|
12
|
+
parent: number | string;
|
|
13
|
+
published_locale?: string;
|
|
14
|
+
publishedLocale?: string;
|
|
15
|
+
snapshot?: boolean;
|
|
16
|
+
};
|
|
17
|
+
export type VersionLocaleStatusMap = Map<number | string, Map<string, 'draft' | 'published'>>;
|
|
18
|
+
/**
|
|
19
|
+
* Core logic for calculating the status of each locale for each version
|
|
20
|
+
* by processing version history chronologically.
|
|
21
|
+
*
|
|
22
|
+
* This works by:
|
|
23
|
+
* 1. Processing versions in chronological order (oldest first)
|
|
24
|
+
* 2. Tracking the cumulative published state for each document as we process versions
|
|
25
|
+
* 3. For each version, determining what status each locale should have based on:
|
|
26
|
+
* - Publish events with publishedLocale: mark that locale as published, version shows NEW state
|
|
27
|
+
* - Publish events without publishedLocale: mark all locales as published, version shows NEW state
|
|
28
|
+
* - Draft saves (_status='draft'): mark all locales as draft (unpublish everything)
|
|
29
|
+
* - Snapshots: preserve state AFTER publish (snapshots created after publishing specific locale)
|
|
30
|
+
*
|
|
31
|
+
* Snapshot creation flow when publishing one locale:
|
|
32
|
+
* 1. Merge incoming content with last published → update main table
|
|
33
|
+
* 2. Create snapshot object (preserves other locales' draft content + updates published locale)
|
|
34
|
+
* 3. Create publish version (_status='published', publishedLocale set)
|
|
35
|
+
* 4. Create snapshot version (_status='draft', snapshot=true)
|
|
36
|
+
* - Snapshot CONTENT is mixed (draft + published content)
|
|
37
|
+
* - Snapshot STATUS reflects which locales are actually published
|
|
38
|
+
*
|
|
39
|
+
* Example scenario:
|
|
40
|
+
* - V1: publish all locales (no snapshot) → state: {en: published, es: published, de: published}
|
|
41
|
+
* - V2: draft save → state: {en: draft, es: draft, de: draft}
|
|
42
|
+
* - V3: publish en only → state: {en: published, es: draft, de: draft}
|
|
43
|
+
* - V4: snapshot after publishing en → state: {en: published, es: draft, de: draft}
|
|
44
|
+
* - V5: publish all locales (no snapshot) → state: {en: published, es: published, de: published}
|
|
45
|
+
*
|
|
46
|
+
* @param versions - Array of version records (must be sorted by parent, then createdAt ASC)
|
|
47
|
+
* @param locales - Array of locale codes (e.g., ['en', 'es', 'pt'])
|
|
48
|
+
* @param payload - Payload instance for logging
|
|
49
|
+
* @returns Map of versionId -> Map of locale -> status
|
|
50
|
+
*/
|
|
51
|
+
export declare function calculateVersionLocaleStatuses(versions: VersionRecord[], locales: string[], payload: Payload): VersionLocaleStatusMap;
|
|
52
|
+
/**
|
|
53
|
+
* Sorts version records by parent document, then by creation date (oldest first)
|
|
54
|
+
*
|
|
55
|
+
* @param versions - Array of version records
|
|
56
|
+
* @returns Sorted array of version records
|
|
57
|
+
*/
|
|
58
|
+
export declare function sortVersionsChronologically(versions: VersionRecord[]): VersionRecord[];
|
|
59
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../../src/versions/migrations/localizeStatus/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AAEtD;;;GAGG;AACH,eAAO,MAAM,WAAW,QAAS,MAAM,KAAG,MAMzC,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,OAAO,GAAG,WAAW,CAAA;IAC9B,UAAU,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;IAC1B,SAAS,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;IACzB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAA;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,GAAG,WAAW,CAAC,CAAC,CAAA;AAE7F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,aAAa,EAAE,EACzB,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE,OAAO,GACf,sBAAsB,CAoExB;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,aAAa,EAAE,CActF"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert to snake_case (matches to-snake-case library behavior)
|
|
3
|
+
* Handles camelCase, PascalCase, and hyphens
|
|
4
|
+
*/ export const toSnakeCase = (str)=>{
|
|
5
|
+
return str.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '').replace(/-/g, '_') // Convert hyphens to underscores
|
|
6
|
+
;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Core logic for calculating the status of each locale for each version
|
|
10
|
+
* by processing version history chronologically.
|
|
11
|
+
*
|
|
12
|
+
* This works by:
|
|
13
|
+
* 1. Processing versions in chronological order (oldest first)
|
|
14
|
+
* 2. Tracking the cumulative published state for each document as we process versions
|
|
15
|
+
* 3. For each version, determining what status each locale should have based on:
|
|
16
|
+
* - Publish events with publishedLocale: mark that locale as published, version shows NEW state
|
|
17
|
+
* - Publish events without publishedLocale: mark all locales as published, version shows NEW state
|
|
18
|
+
* - Draft saves (_status='draft'): mark all locales as draft (unpublish everything)
|
|
19
|
+
* - Snapshots: preserve state AFTER publish (snapshots created after publishing specific locale)
|
|
20
|
+
*
|
|
21
|
+
* Snapshot creation flow when publishing one locale:
|
|
22
|
+
* 1. Merge incoming content with last published → update main table
|
|
23
|
+
* 2. Create snapshot object (preserves other locales' draft content + updates published locale)
|
|
24
|
+
* 3. Create publish version (_status='published', publishedLocale set)
|
|
25
|
+
* 4. Create snapshot version (_status='draft', snapshot=true)
|
|
26
|
+
* - Snapshot CONTENT is mixed (draft + published content)
|
|
27
|
+
* - Snapshot STATUS reflects which locales are actually published
|
|
28
|
+
*
|
|
29
|
+
* Example scenario:
|
|
30
|
+
* - V1: publish all locales (no snapshot) → state: {en: published, es: published, de: published}
|
|
31
|
+
* - V2: draft save → state: {en: draft, es: draft, de: draft}
|
|
32
|
+
* - V3: publish en only → state: {en: published, es: draft, de: draft}
|
|
33
|
+
* - V4: snapshot after publishing en → state: {en: published, es: draft, de: draft}
|
|
34
|
+
* - V5: publish all locales (no snapshot) → state: {en: published, es: published, de: published}
|
|
35
|
+
*
|
|
36
|
+
* @param versions - Array of version records (must be sorted by parent, then createdAt ASC)
|
|
37
|
+
* @param locales - Array of locale codes (e.g., ['en', 'es', 'pt'])
|
|
38
|
+
* @param payload - Payload instance for logging
|
|
39
|
+
* @returns Map of versionId -> Map of locale -> status
|
|
40
|
+
*/ export function calculateVersionLocaleStatuses(versions, locales, payload) {
|
|
41
|
+
payload.logger.info({
|
|
42
|
+
msg: `Processing ${versions.length} version records`
|
|
43
|
+
});
|
|
44
|
+
// Track the cumulative published state for each document across all locales
|
|
45
|
+
// This represents what IS published at any given point in the version history
|
|
46
|
+
const documentPublishState = new Map();
|
|
47
|
+
// Map to store the final status for each version
|
|
48
|
+
const versionLocaleStatus = new Map();
|
|
49
|
+
// Process versions chronologically to build up status history
|
|
50
|
+
for (const version of versions){
|
|
51
|
+
const versionId = version.id;
|
|
52
|
+
const documentId = version.parent;
|
|
53
|
+
const status = version._status;
|
|
54
|
+
const publishedLocale = version.published_locale || version.publishedLocale;
|
|
55
|
+
const isSnapshot = version.snapshot === true;
|
|
56
|
+
// Initialize document state if first time seeing this document
|
|
57
|
+
if (!documentPublishState.has(documentId)) {
|
|
58
|
+
const localeMap = new Map();
|
|
59
|
+
for (const locale of locales){
|
|
60
|
+
localeMap.set(locale, 'draft');
|
|
61
|
+
}
|
|
62
|
+
documentPublishState.set(documentId, localeMap);
|
|
63
|
+
}
|
|
64
|
+
const currentPublishState = documentPublishState.get(documentId);
|
|
65
|
+
const versionStatusMap = new Map();
|
|
66
|
+
if (isSnapshot) {
|
|
67
|
+
// Snapshots are created AFTER publishing a specific locale
|
|
68
|
+
// Snapshot CONTENT is mixed: preserves other locales' draft content + new published locale content
|
|
69
|
+
// But snapshot STATUS should reflect publish state: which locales are published vs draft
|
|
70
|
+
// We use currentPublishState to track this, which has been updated by the previous publish
|
|
71
|
+
for (const [locale, publishedStatus] of currentPublishState.entries()){
|
|
72
|
+
versionStatusMap.set(locale, publishedStatus);
|
|
73
|
+
}
|
|
74
|
+
} else if (status === 'published') {
|
|
75
|
+
// This is a publish event
|
|
76
|
+
if (publishedLocale) {
|
|
77
|
+
// Publishing ONE locale - update the document's published state for that locale
|
|
78
|
+
currentPublishState.set(publishedLocale, 'published');
|
|
79
|
+
// This version should show the NEW state (after this publish)
|
|
80
|
+
for (const [locale, publishedStatus] of currentPublishState.entries()){
|
|
81
|
+
versionStatusMap.set(locale, publishedStatus);
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
// Publishing ALL locales - update all locales to published
|
|
85
|
+
for (const locale of locales){
|
|
86
|
+
currentPublishState.set(locale, 'published');
|
|
87
|
+
versionStatusMap.set(locale, 'published');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
// This is a draft save - in the OLD system, _status='draft' meant unpublish ALL locales
|
|
92
|
+
for (const locale of locales){
|
|
93
|
+
currentPublishState.set(locale, 'draft');
|
|
94
|
+
versionStatusMap.set(locale, 'draft');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Store the status for this version
|
|
98
|
+
versionLocaleStatus.set(versionId, versionStatusMap);
|
|
99
|
+
}
|
|
100
|
+
return versionLocaleStatus;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Sorts version records by parent document, then by creation date (oldest first)
|
|
104
|
+
*
|
|
105
|
+
* @param versions - Array of version records
|
|
106
|
+
* @returns Sorted array of version records
|
|
107
|
+
*/ export function sortVersionsChronologically(versions) {
|
|
108
|
+
return versions.sort((a, b)=>{
|
|
109
|
+
// First sort by parent
|
|
110
|
+
const parentA = String(a.parent);
|
|
111
|
+
const parentB = String(b.parent);
|
|
112
|
+
if (parentA !== parentB) {
|
|
113
|
+
return parentA.localeCompare(parentB);
|
|
114
|
+
}
|
|
115
|
+
// Then sort by creation date
|
|
116
|
+
const dateA = new Date(a.created_at || a.createdAt || 0);
|
|
117
|
+
const dateB = new Date(b.created_at || b.createdAt || 0);
|
|
118
|
+
return dateA.getTime() - dateB.getTime();
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/versions/migrations/localizeStatus/shared.ts"],"sourcesContent":["import type { Payload } from '../../../types/index.js'\n\n/**\n * Convert to snake_case (matches to-snake-case library behavior)\n * Handles camelCase, PascalCase, and hyphens\n */\nexport const toSnakeCase = (str: string): string => {\n return str\n .replace(/([A-Z])/g, '_$1')\n .toLowerCase()\n .replace(/^_/, '')\n .replace(/-/g, '_') // Convert hyphens to underscores\n}\n\nexport type VersionRecord = {\n _status: 'draft' | 'published'\n created_at?: Date | string\n createdAt?: Date | string\n id: number | string\n parent: number | string\n published_locale?: string\n publishedLocale?: string\n snapshot?: boolean\n}\n\nexport type VersionLocaleStatusMap = Map<number | string, Map<string, 'draft' | 'published'>>\n\n/**\n * Core logic for calculating the status of each locale for each version\n * by processing version history chronologically.\n *\n * This works by:\n * 1. Processing versions in chronological order (oldest first)\n * 2. Tracking the cumulative published state for each document as we process versions\n * 3. For each version, determining what status each locale should have based on:\n * - Publish events with publishedLocale: mark that locale as published, version shows NEW state\n * - Publish events without publishedLocale: mark all locales as published, version shows NEW state\n * - Draft saves (_status='draft'): mark all locales as draft (unpublish everything)\n * - Snapshots: preserve state AFTER publish (snapshots created after publishing specific locale)\n *\n * Snapshot creation flow when publishing one locale:\n * 1. Merge incoming content with last published → update main table\n * 2. Create snapshot object (preserves other locales' draft content + updates published locale)\n * 3. Create publish version (_status='published', publishedLocale set)\n * 4. Create snapshot version (_status='draft', snapshot=true)\n * - Snapshot CONTENT is mixed (draft + published content)\n * - Snapshot STATUS reflects which locales are actually published\n *\n * Example scenario:\n * - V1: publish all locales (no snapshot) → state: {en: published, es: published, de: published}\n * - V2: draft save → state: {en: draft, es: draft, de: draft}\n * - V3: publish en only → state: {en: published, es: draft, de: draft}\n * - V4: snapshot after publishing en → state: {en: published, es: draft, de: draft}\n * - V5: publish all locales (no snapshot) → state: {en: published, es: published, de: published}\n *\n * @param versions - Array of version records (must be sorted by parent, then createdAt ASC)\n * @param locales - Array of locale codes (e.g., ['en', 'es', 'pt'])\n * @param payload - Payload instance for logging\n * @returns Map of versionId -> Map of locale -> status\n */\nexport function calculateVersionLocaleStatuses(\n versions: VersionRecord[],\n locales: string[],\n payload: Payload,\n): VersionLocaleStatusMap {\n payload.logger.info({ msg: `Processing ${versions.length} version records` })\n\n // Track the cumulative published state for each document across all locales\n // This represents what IS published at any given point in the version history\n const documentPublishState = new Map<number | string, Map<string, 'draft' | 'published'>>()\n\n // Map to store the final status for each version\n const versionLocaleStatus: VersionLocaleStatusMap = new Map()\n\n // Process versions chronologically to build up status history\n for (const version of versions) {\n const versionId = version.id\n const documentId = version.parent\n const status = version._status\n const publishedLocale = version.published_locale || version.publishedLocale\n const isSnapshot = version.snapshot === true\n\n // Initialize document state if first time seeing this document\n if (!documentPublishState.has(documentId)) {\n const localeMap = new Map<string, 'draft' | 'published'>()\n for (const locale of locales) {\n localeMap.set(locale, 'draft')\n }\n documentPublishState.set(documentId, localeMap)\n }\n\n const currentPublishState = documentPublishState.get(documentId)!\n const versionStatusMap = new Map<string, 'draft' | 'published'>()\n\n if (isSnapshot) {\n // Snapshots are created AFTER publishing a specific locale\n // Snapshot CONTENT is mixed: preserves other locales' draft content + new published locale content\n // But snapshot STATUS should reflect publish state: which locales are published vs draft\n // We use currentPublishState to track this, which has been updated by the previous publish\n for (const [locale, publishedStatus] of currentPublishState.entries()) {\n versionStatusMap.set(locale, publishedStatus)\n }\n } else if (status === 'published') {\n // This is a publish event\n if (publishedLocale) {\n // Publishing ONE locale - update the document's published state for that locale\n currentPublishState.set(publishedLocale, 'published')\n\n // This version should show the NEW state (after this publish)\n for (const [locale, publishedStatus] of currentPublishState.entries()) {\n versionStatusMap.set(locale, publishedStatus)\n }\n } else {\n // Publishing ALL locales - update all locales to published\n for (const locale of locales) {\n currentPublishState.set(locale, 'published')\n versionStatusMap.set(locale, 'published')\n }\n }\n } else {\n // This is a draft save - in the OLD system, _status='draft' meant unpublish ALL locales\n for (const locale of locales) {\n currentPublishState.set(locale, 'draft')\n versionStatusMap.set(locale, 'draft')\n }\n }\n\n // Store the status for this version\n versionLocaleStatus.set(versionId, versionStatusMap)\n }\n\n return versionLocaleStatus\n}\n\n/**\n * Sorts version records by parent document, then by creation date (oldest first)\n *\n * @param versions - Array of version records\n * @returns Sorted array of version records\n */\nexport function sortVersionsChronologically(versions: VersionRecord[]): VersionRecord[] {\n return versions.sort((a, b) => {\n // First sort by parent\n const parentA = String(a.parent)\n const parentB = String(b.parent)\n if (parentA !== parentB) {\n return parentA.localeCompare(parentB)\n }\n\n // Then sort by creation date\n const dateA = new Date(a.created_at || a.createdAt || 0)\n const dateB = new Date(b.created_at || b.createdAt || 0)\n return dateA.getTime() - dateB.getTime()\n })\n}\n"],"names":["toSnakeCase","str","replace","toLowerCase","calculateVersionLocaleStatuses","versions","locales","payload","logger","info","msg","length","documentPublishState","Map","versionLocaleStatus","version","versionId","id","documentId","parent","status","_status","publishedLocale","published_locale","isSnapshot","snapshot","has","localeMap","locale","set","currentPublishState","get","versionStatusMap","publishedStatus","entries","sortVersionsChronologically","sort","a","b","parentA","String","parentB","localeCompare","dateA","Date","created_at","createdAt","dateB","getTime"],"mappings":"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"}
|