strapi-plugin-magic-mail 2.10.9 → 2.10.11
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/CHANGELOG.md +14 -0
- package/dist/server/index.js +66 -4
- package/dist/server/index.mjs +66 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [2.10.11](https://github.com/Schero94/Magic-Mail/compare/v2.10.10...v2.10.11) (2026-04-21)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **email-designer:** generate duplicate-template refId within int4 range ([d1ecae8](https://github.com/Schero94/Magic-Mail/commit/d1ecae8d657ead41521b08fcad35d9c483f779d9))
|
|
7
|
+
|
|
8
|
+
## [2.10.10](https://github.com/Schero94/Magic-Mail/compare/v2.10.9...v2.10.10) (2026-04-21)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **validation:** auto-strip Strapi system metadata before .strict() check ([039b889](https://github.com/Schero94/Magic-Mail/commit/039b889d96d6a076e199bec7497304c6900b8165))
|
|
14
|
+
|
|
1
15
|
## [2.10.9](https://github.com/Schero94/Magic-Mail/compare/v2.10.8...v2.10.9) (2026-04-21)
|
|
2
16
|
|
|
3
17
|
|
package/dist/server/index.js
CHANGED
|
@@ -1256,12 +1256,44 @@ const schemas = {
|
|
|
1256
1256
|
phoneNumber: z.string().min(5).max(32).regex(/^[\d+\-() ]+$/)
|
|
1257
1257
|
})
|
|
1258
1258
|
};
|
|
1259
|
+
const STRAPI_METADATA_FIELDS = Object.freeze([
|
|
1260
|
+
"id",
|
|
1261
|
+
"documentId",
|
|
1262
|
+
"createdAt",
|
|
1263
|
+
"updatedAt",
|
|
1264
|
+
"publishedAt",
|
|
1265
|
+
"locale",
|
|
1266
|
+
"localizations",
|
|
1267
|
+
"createdBy",
|
|
1268
|
+
"updatedBy",
|
|
1269
|
+
"__component",
|
|
1270
|
+
// Populated relations/components we never want to round-trip as a write:
|
|
1271
|
+
"versions"
|
|
1272
|
+
]);
|
|
1273
|
+
function stripStrapiMetadata(body, schemaName) {
|
|
1274
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) return body;
|
|
1275
|
+
const cleaned = { ...body };
|
|
1276
|
+
const removed = [];
|
|
1277
|
+
for (const key of STRAPI_METADATA_FIELDS) {
|
|
1278
|
+
if (key in cleaned) {
|
|
1279
|
+
delete cleaned[key];
|
|
1280
|
+
removed.push(key);
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
if (removed.length > 0 && typeof strapi !== "undefined" && strapi?.log?.debug) {
|
|
1284
|
+
strapi.log.debug(
|
|
1285
|
+
`[magic-mail] Stripped Strapi metadata from ${schemaName} payload: ${removed.join(", ")}`
|
|
1286
|
+
);
|
|
1287
|
+
}
|
|
1288
|
+
return cleaned;
|
|
1289
|
+
}
|
|
1259
1290
|
function validate$5(schemaName, body) {
|
|
1260
1291
|
const schema = schemas[schemaName];
|
|
1261
1292
|
if (!schema) {
|
|
1262
1293
|
throw new Error(`Unknown validation schema: ${schemaName}`);
|
|
1263
1294
|
}
|
|
1264
|
-
const
|
|
1295
|
+
const sanitized = stripStrapiMetadata(body, schemaName);
|
|
1296
|
+
const result2 = schema.safeParse(sanitized);
|
|
1265
1297
|
if (!result2.success) {
|
|
1266
1298
|
const strapiErrors = require$$1__default.default.errors;
|
|
1267
1299
|
const flattened = result2.error.flatten();
|
|
@@ -15877,7 +15909,7 @@ var oauth$1 = ({ strapi: strapi2 }) => ({
|
|
|
15877
15909
|
return account;
|
|
15878
15910
|
}
|
|
15879
15911
|
});
|
|
15880
|
-
const version = "2.10.
|
|
15912
|
+
const version = "2.10.10";
|
|
15881
15913
|
const require$$2 = {
|
|
15882
15914
|
version
|
|
15883
15915
|
};
|
|
@@ -16526,6 +16558,35 @@ var emailDesigner$1 = ({ strapi: strapi2 }) => ({
|
|
|
16526
16558
|
strapi2.log.info(`[magic-mail] [SUCCESS] Template "${template.name}" and ${allVersions.length} versions deleted`);
|
|
16527
16559
|
return result2;
|
|
16528
16560
|
},
|
|
16561
|
+
/**
|
|
16562
|
+
* Generate a new `templateReferenceId` guaranteed to fit in PostgreSQL's
|
|
16563
|
+
* `integer` column (max 2_147_483_647). We retry a few times to dodge
|
|
16564
|
+
* the astronomically unlikely collision with an already-used reference
|
|
16565
|
+
* id — the schema declares `unique: true`, so picking a duplicate here
|
|
16566
|
+
* would otherwise fail at insert time.
|
|
16567
|
+
*
|
|
16568
|
+
* Previous implementation used `Date.now()` which overflows the int4
|
|
16569
|
+
* range (13 digits vs. 10-digit max), producing a "value is out of range
|
|
16570
|
+
* for type integer" error on every duplicate call.
|
|
16571
|
+
*
|
|
16572
|
+
* @returns {Promise<number>}
|
|
16573
|
+
* @throws {Error} if no unique id can be found after MAX_ATTEMPTS tries
|
|
16574
|
+
*/
|
|
16575
|
+
async _generateUniqueTemplateReferenceId() {
|
|
16576
|
+
const MAX_ATTEMPTS = 5;
|
|
16577
|
+
const UPPER_BOUND = 2e9;
|
|
16578
|
+
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt += 1) {
|
|
16579
|
+
const candidate = Math.floor(Math.random() * UPPER_BOUND) + 1;
|
|
16580
|
+
const existing = await this.findByReferenceId(candidate);
|
|
16581
|
+
if (!existing) return candidate;
|
|
16582
|
+
strapi2.log.warn(
|
|
16583
|
+
`[magic-mail] [DUPLICATE] templateReferenceId collision on ${candidate} (attempt ${attempt + 1}/${MAX_ATTEMPTS}); retrying`
|
|
16584
|
+
);
|
|
16585
|
+
}
|
|
16586
|
+
throw new Error(
|
|
16587
|
+
`Could not generate a unique templateReferenceId after ${MAX_ATTEMPTS} attempts`
|
|
16588
|
+
);
|
|
16589
|
+
},
|
|
16529
16590
|
/**
|
|
16530
16591
|
* Duplicate template
|
|
16531
16592
|
* @param {string|number} idOrDocumentId - Either numeric id or documentId
|
|
@@ -16537,6 +16598,7 @@ var emailDesigner$1 = ({ strapi: strapi2 }) => ({
|
|
|
16537
16598
|
throw new Error("Template not found");
|
|
16538
16599
|
}
|
|
16539
16600
|
strapi2.log.info(`[magic-mail] [PACKAGE] Original template: documentId=${original.documentId}, name="${original.name}"`);
|
|
16601
|
+
const newRefId = await this._generateUniqueTemplateReferenceId();
|
|
16540
16602
|
const duplicateData = {
|
|
16541
16603
|
name: `${original.name} copy`,
|
|
16542
16604
|
subject: original.subject,
|
|
@@ -16546,10 +16608,10 @@ var emailDesigner$1 = ({ strapi: strapi2 }) => ({
|
|
|
16546
16608
|
category: original.category,
|
|
16547
16609
|
tags: original.tags,
|
|
16548
16610
|
isActive: original.isActive,
|
|
16549
|
-
templateReferenceId:
|
|
16611
|
+
templateReferenceId: newRefId
|
|
16550
16612
|
};
|
|
16551
16613
|
const duplicated = await this.create(duplicateData);
|
|
16552
|
-
strapi2.log.info(`[magic-mail] [SUCCESS] Template duplicated: documentId=${duplicated.documentId}`);
|
|
16614
|
+
strapi2.log.info(`[magic-mail] [SUCCESS] Template duplicated: documentId=${duplicated.documentId}, newRefId=${newRefId}`);
|
|
16553
16615
|
return duplicated;
|
|
16554
16616
|
},
|
|
16555
16617
|
// ============================================================
|
package/dist/server/index.mjs
CHANGED
|
@@ -1243,12 +1243,44 @@ const schemas = {
|
|
|
1243
1243
|
phoneNumber: z.string().min(5).max(32).regex(/^[\d+\-() ]+$/)
|
|
1244
1244
|
})
|
|
1245
1245
|
};
|
|
1246
|
+
const STRAPI_METADATA_FIELDS = Object.freeze([
|
|
1247
|
+
"id",
|
|
1248
|
+
"documentId",
|
|
1249
|
+
"createdAt",
|
|
1250
|
+
"updatedAt",
|
|
1251
|
+
"publishedAt",
|
|
1252
|
+
"locale",
|
|
1253
|
+
"localizations",
|
|
1254
|
+
"createdBy",
|
|
1255
|
+
"updatedBy",
|
|
1256
|
+
"__component",
|
|
1257
|
+
// Populated relations/components we never want to round-trip as a write:
|
|
1258
|
+
"versions"
|
|
1259
|
+
]);
|
|
1260
|
+
function stripStrapiMetadata(body, schemaName) {
|
|
1261
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) return body;
|
|
1262
|
+
const cleaned = { ...body };
|
|
1263
|
+
const removed = [];
|
|
1264
|
+
for (const key of STRAPI_METADATA_FIELDS) {
|
|
1265
|
+
if (key in cleaned) {
|
|
1266
|
+
delete cleaned[key];
|
|
1267
|
+
removed.push(key);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
if (removed.length > 0 && typeof strapi !== "undefined" && strapi?.log?.debug) {
|
|
1271
|
+
strapi.log.debug(
|
|
1272
|
+
`[magic-mail] Stripped Strapi metadata from ${schemaName} payload: ${removed.join(", ")}`
|
|
1273
|
+
);
|
|
1274
|
+
}
|
|
1275
|
+
return cleaned;
|
|
1276
|
+
}
|
|
1246
1277
|
function validate$5(schemaName, body) {
|
|
1247
1278
|
const schema = schemas[schemaName];
|
|
1248
1279
|
if (!schema) {
|
|
1249
1280
|
throw new Error(`Unknown validation schema: ${schemaName}`);
|
|
1250
1281
|
}
|
|
1251
|
-
const
|
|
1282
|
+
const sanitized = stripStrapiMetadata(body, schemaName);
|
|
1283
|
+
const result2 = schema.safeParse(sanitized);
|
|
1252
1284
|
if (!result2.success) {
|
|
1253
1285
|
const strapiErrors = require$$1$2.errors;
|
|
1254
1286
|
const flattened = result2.error.flatten();
|
|
@@ -15864,7 +15896,7 @@ var oauth$1 = ({ strapi: strapi2 }) => ({
|
|
|
15864
15896
|
return account;
|
|
15865
15897
|
}
|
|
15866
15898
|
});
|
|
15867
|
-
const version = "2.10.
|
|
15899
|
+
const version = "2.10.10";
|
|
15868
15900
|
const require$$2 = {
|
|
15869
15901
|
version
|
|
15870
15902
|
};
|
|
@@ -16513,6 +16545,35 @@ var emailDesigner$1 = ({ strapi: strapi2 }) => ({
|
|
|
16513
16545
|
strapi2.log.info(`[magic-mail] [SUCCESS] Template "${template.name}" and ${allVersions.length} versions deleted`);
|
|
16514
16546
|
return result2;
|
|
16515
16547
|
},
|
|
16548
|
+
/**
|
|
16549
|
+
* Generate a new `templateReferenceId` guaranteed to fit in PostgreSQL's
|
|
16550
|
+
* `integer` column (max 2_147_483_647). We retry a few times to dodge
|
|
16551
|
+
* the astronomically unlikely collision with an already-used reference
|
|
16552
|
+
* id — the schema declares `unique: true`, so picking a duplicate here
|
|
16553
|
+
* would otherwise fail at insert time.
|
|
16554
|
+
*
|
|
16555
|
+
* Previous implementation used `Date.now()` which overflows the int4
|
|
16556
|
+
* range (13 digits vs. 10-digit max), producing a "value is out of range
|
|
16557
|
+
* for type integer" error on every duplicate call.
|
|
16558
|
+
*
|
|
16559
|
+
* @returns {Promise<number>}
|
|
16560
|
+
* @throws {Error} if no unique id can be found after MAX_ATTEMPTS tries
|
|
16561
|
+
*/
|
|
16562
|
+
async _generateUniqueTemplateReferenceId() {
|
|
16563
|
+
const MAX_ATTEMPTS = 5;
|
|
16564
|
+
const UPPER_BOUND = 2e9;
|
|
16565
|
+
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt += 1) {
|
|
16566
|
+
const candidate = Math.floor(Math.random() * UPPER_BOUND) + 1;
|
|
16567
|
+
const existing = await this.findByReferenceId(candidate);
|
|
16568
|
+
if (!existing) return candidate;
|
|
16569
|
+
strapi2.log.warn(
|
|
16570
|
+
`[magic-mail] [DUPLICATE] templateReferenceId collision on ${candidate} (attempt ${attempt + 1}/${MAX_ATTEMPTS}); retrying`
|
|
16571
|
+
);
|
|
16572
|
+
}
|
|
16573
|
+
throw new Error(
|
|
16574
|
+
`Could not generate a unique templateReferenceId after ${MAX_ATTEMPTS} attempts`
|
|
16575
|
+
);
|
|
16576
|
+
},
|
|
16516
16577
|
/**
|
|
16517
16578
|
* Duplicate template
|
|
16518
16579
|
* @param {string|number} idOrDocumentId - Either numeric id or documentId
|
|
@@ -16524,6 +16585,7 @@ var emailDesigner$1 = ({ strapi: strapi2 }) => ({
|
|
|
16524
16585
|
throw new Error("Template not found");
|
|
16525
16586
|
}
|
|
16526
16587
|
strapi2.log.info(`[magic-mail] [PACKAGE] Original template: documentId=${original.documentId}, name="${original.name}"`);
|
|
16588
|
+
const newRefId = await this._generateUniqueTemplateReferenceId();
|
|
16527
16589
|
const duplicateData = {
|
|
16528
16590
|
name: `${original.name} copy`,
|
|
16529
16591
|
subject: original.subject,
|
|
@@ -16533,10 +16595,10 @@ var emailDesigner$1 = ({ strapi: strapi2 }) => ({
|
|
|
16533
16595
|
category: original.category,
|
|
16534
16596
|
tags: original.tags,
|
|
16535
16597
|
isActive: original.isActive,
|
|
16536
|
-
templateReferenceId:
|
|
16598
|
+
templateReferenceId: newRefId
|
|
16537
16599
|
};
|
|
16538
16600
|
const duplicated = await this.create(duplicateData);
|
|
16539
|
-
strapi2.log.info(`[magic-mail] [SUCCESS] Template duplicated: documentId=${duplicated.documentId}`);
|
|
16601
|
+
strapi2.log.info(`[magic-mail] [SUCCESS] Template duplicated: documentId=${duplicated.documentId}, newRefId=${newRefId}`);
|
|
16540
16602
|
return duplicated;
|
|
16541
16603
|
},
|
|
16542
16604
|
// ============================================================
|
package/package.json
CHANGED