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 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
 
@@ -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 result2 = schema.safeParse(body);
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.8";
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: Date.now() + Math.floor(Math.random() * 1e3)
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
  // ============================================================
@@ -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 result2 = schema.safeParse(body);
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.8";
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: Date.now() + Math.floor(Math.random() * 1e3)
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
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.10.9",
2
+ "version": "2.10.11",
3
3
  "keywords": [
4
4
  "strapi",
5
5
  "plugin",