pocketbase-zod-schema 0.3.0 → 0.3.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 (64) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/cli/index.cjs +167 -46
  3. package/dist/cli/index.cjs.map +1 -1
  4. package/dist/cli/index.d.cts +2 -2
  5. package/dist/cli/index.d.ts +2 -2
  6. package/dist/cli/index.js +167 -46
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/cli/migrate.cjs +167 -46
  9. package/dist/cli/migrate.cjs.map +1 -1
  10. package/dist/cli/migrate.js +167 -46
  11. package/dist/cli/migrate.js.map +1 -1
  12. package/dist/cli/utils/index.d.cts +2 -2
  13. package/dist/cli/utils/index.d.ts +2 -2
  14. package/dist/{fields-UcOPu1OQ.d.cts → fields-RVj26U-O.d.cts} +1 -0
  15. package/dist/{fields-UcOPu1OQ.d.ts → fields-RVj26U-O.d.ts} +1 -0
  16. package/dist/index.cjs +167 -46
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +3 -3
  19. package/dist/index.d.ts +3 -3
  20. package/dist/index.js +167 -46
  21. package/dist/index.js.map +1 -1
  22. package/dist/migration/analyzer.cjs.map +1 -1
  23. package/dist/migration/analyzer.d.cts +2 -2
  24. package/dist/migration/analyzer.d.ts +2 -2
  25. package/dist/migration/analyzer.js.map +1 -1
  26. package/dist/migration/diff.cjs +77 -26
  27. package/dist/migration/diff.cjs.map +1 -1
  28. package/dist/migration/diff.d.cts +4 -4
  29. package/dist/migration/diff.d.ts +4 -4
  30. package/dist/migration/diff.js +77 -26
  31. package/dist/migration/diff.js.map +1 -1
  32. package/dist/migration/generator.cjs +39 -2
  33. package/dist/migration/generator.cjs.map +1 -1
  34. package/dist/migration/generator.d.cts +2 -2
  35. package/dist/migration/generator.d.ts +2 -2
  36. package/dist/migration/generator.js +39 -2
  37. package/dist/migration/generator.js.map +1 -1
  38. package/dist/migration/index.cjs +167 -46
  39. package/dist/migration/index.cjs.map +1 -1
  40. package/dist/migration/index.d.cts +3 -3
  41. package/dist/migration/index.d.ts +3 -3
  42. package/dist/migration/index.js +167 -46
  43. package/dist/migration/index.js.map +1 -1
  44. package/dist/migration/snapshot.cjs +51 -18
  45. package/dist/migration/snapshot.cjs.map +1 -1
  46. package/dist/migration/snapshot.d.cts +2 -2
  47. package/dist/migration/snapshot.d.ts +2 -2
  48. package/dist/migration/snapshot.js +51 -18
  49. package/dist/migration/snapshot.js.map +1 -1
  50. package/dist/migration/utils/index.cjs +5 -3
  51. package/dist/migration/utils/index.cjs.map +1 -1
  52. package/dist/migration/utils/index.d.cts +4 -4
  53. package/dist/migration/utils/index.d.ts +4 -4
  54. package/dist/migration/utils/index.js +5 -3
  55. package/dist/migration/utils/index.js.map +1 -1
  56. package/dist/schema.cjs.map +1 -1
  57. package/dist/schema.d.cts +1 -1
  58. package/dist/schema.d.ts +1 -1
  59. package/dist/schema.js.map +1 -1
  60. package/dist/{type-mapper-n231Fspm.d.ts → type-mapper-CZzVeDj7.d.ts} +1 -1
  61. package/dist/{type-mapper-DrQmtznD.d.cts → type-mapper-DaBe-1ph.d.cts} +1 -1
  62. package/dist/{types-Ds3NQvny.d.ts → types-CUVzgZ9k.d.ts} +1 -1
  63. package/dist/{types-YoBjsa-A.d.cts → types-D-Fsdn_O.d.cts} +1 -1
  64. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import { Ora } from 'ora';
2
- import { e as SchemaDiff } from '../../types-YoBjsa-A.cjs';
3
- import '../../fields-UcOPu1OQ.cjs';
2
+ import { e as SchemaDiff } from '../../types-D-Fsdn_O.cjs';
3
+ import '../../fields-RVj26U-O.cjs';
4
4
  import 'zod';
5
5
  import '../../permissions-ZHafVSIx.cjs';
6
6
 
@@ -1,6 +1,6 @@
1
1
  import { Ora } from 'ora';
2
- import { e as SchemaDiff } from '../../types-Ds3NQvny.js';
3
- import '../../fields-UcOPu1OQ.js';
2
+ import { e as SchemaDiff } from '../../types-CUVzgZ9k.js';
3
+ import '../../fields-RVj26U-O.js';
4
4
  import 'zod';
5
5
  import '../../permissions-ZHafVSIx.js';
6
6
 
@@ -132,6 +132,7 @@ interface FileFieldOptions {
132
132
  /**
133
133
  * Thumbnail sizes to generate
134
134
  * Example: ["100x100", "200x200"]
135
+ * Set to null to explicitly disable thumbnails
135
136
  */
136
137
  thumbs?: string[];
137
138
  /**
@@ -132,6 +132,7 @@ interface FileFieldOptions {
132
132
  /**
133
133
  * Thumbnail sizes to generate
134
134
  * Example: ["100x100", "200x200"]
135
+ * Set to null to explicitly disable thumbnails
135
136
  */
136
137
  thumbs?: string[];
137
138
  /**
package/dist/index.cjs CHANGED
@@ -2497,7 +2497,7 @@ var SchemaAnalyzer = class {
2497
2497
  var SNAPSHOT_VERSION = "1.0.0";
2498
2498
  function resolveCollectionIdToName(collectionId) {
2499
2499
  if (collectionId === "_pb_users_auth_") {
2500
- return "Users";
2500
+ return "users";
2501
2501
  }
2502
2502
  const nameMatch = collectionId.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
2503
2503
  if (nameMatch) {
@@ -2505,6 +2505,39 @@ function resolveCollectionIdToName(collectionId) {
2505
2505
  }
2506
2506
  return collectionId;
2507
2507
  }
2508
+ function extractFieldOptions2(pbField) {
2509
+ const options = {};
2510
+ if (pbField.options && typeof pbField.options === "object") {
2511
+ Object.assign(options, pbField.options);
2512
+ }
2513
+ const directOptionKeys = [
2514
+ "min",
2515
+ "max",
2516
+ "pattern",
2517
+ "noDecimal",
2518
+ // text/number fields
2519
+ "values",
2520
+ "maxSelect",
2521
+ // select fields
2522
+ "mimeTypes",
2523
+ "maxSize",
2524
+ "thumbs",
2525
+ "protected",
2526
+ // file fields
2527
+ "onCreate",
2528
+ "onUpdate",
2529
+ // autodate fields
2530
+ "exceptDomains",
2531
+ "onlyDomains"
2532
+ // email/url fields
2533
+ ];
2534
+ for (const key of directOptionKeys) {
2535
+ if (pbField[key] !== void 0) {
2536
+ options[key] = pbField[key];
2537
+ }
2538
+ }
2539
+ return options;
2540
+ }
2508
2541
  function convertPocketBaseCollection(pbCollection) {
2509
2542
  const fields = [];
2510
2543
  const systemFieldNames = ["id", "created", "updated", "collectionId", "collectionName", "expand"];
@@ -2522,23 +2555,19 @@ function convertPocketBaseCollection(pbCollection) {
2522
2555
  type: pbField.type,
2523
2556
  required: pbField.required || false
2524
2557
  };
2525
- field.options = pbField.options ? { ...pbField.options } : {};
2526
- if (pbField.type === "select") {
2527
- if (pbField.values && Array.isArray(pbField.values)) {
2528
- field.options.values = pbField.values;
2529
- } else if (pbField.options?.values && Array.isArray(pbField.options.values)) {
2530
- field.options.values = pbField.options.values;
2531
- }
2532
- }
2558
+ field.options = extractFieldOptions2(pbField);
2533
2559
  if (pbField.type === "relation") {
2534
2560
  const collectionId = pbField.collectionId || pbField.options?.collectionId || "";
2535
- const collectionName = resolveCollectionIdToName(collectionId);
2561
+ const collectionName = resolveCollectionIdToName(collectionId || "");
2536
2562
  field.relation = {
2537
2563
  collection: collectionName,
2538
2564
  cascadeDelete: pbField.cascadeDelete ?? pbField.options?.cascadeDelete ?? false,
2539
2565
  maxSelect: pbField.maxSelect ?? pbField.options?.maxSelect,
2540
2566
  minSelect: pbField.minSelect ?? pbField.options?.minSelect
2541
2567
  };
2568
+ delete field.options.maxSelect;
2569
+ delete field.options.minSelect;
2570
+ delete field.options.cascadeDelete;
2542
2571
  }
2543
2572
  const hasOnlyValues = Object.keys(field.options).length === 1 && field.options.values !== void 0;
2544
2573
  if (Object.keys(field.options).length === 0) {
@@ -2552,17 +2581,21 @@ function convertPocketBaseCollection(pbCollection) {
2552
2581
  type: pbCollection.type || "base",
2553
2582
  fields
2554
2583
  };
2584
+ if (pbCollection.id) {
2585
+ schema.id = pbCollection.id;
2586
+ }
2555
2587
  if (pbCollection.indexes && Array.isArray(pbCollection.indexes)) {
2556
2588
  schema.indexes = pbCollection.indexes;
2557
2589
  }
2558
- const rules = {};
2559
- if (pbCollection.listRule !== void 0) rules.listRule = pbCollection.listRule;
2560
- if (pbCollection.viewRule !== void 0) rules.viewRule = pbCollection.viewRule;
2561
- if (pbCollection.createRule !== void 0) rules.createRule = pbCollection.createRule;
2562
- if (pbCollection.updateRule !== void 0) rules.updateRule = pbCollection.updateRule;
2563
- if (pbCollection.deleteRule !== void 0) rules.deleteRule = pbCollection.deleteRule;
2564
- if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
2565
- if (Object.keys(rules).length > 0) {
2590
+ const hasAnyRule = pbCollection.listRule !== void 0 || pbCollection.viewRule !== void 0 || pbCollection.createRule !== void 0 || pbCollection.updateRule !== void 0 || pbCollection.deleteRule !== void 0 || pbCollection.manageRule !== void 0;
2591
+ if (hasAnyRule) {
2592
+ const rules = {};
2593
+ if (pbCollection.listRule !== void 0) rules.listRule = pbCollection.listRule;
2594
+ if (pbCollection.viewRule !== void 0) rules.viewRule = pbCollection.viewRule;
2595
+ if (pbCollection.createRule !== void 0) rules.createRule = pbCollection.createRule;
2596
+ if (pbCollection.updateRule !== void 0) rules.updateRule = pbCollection.updateRule;
2597
+ if (pbCollection.deleteRule !== void 0) rules.deleteRule = pbCollection.deleteRule;
2598
+ if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
2566
2599
  schema.rules = rules;
2567
2600
  schema.permissions = { ...rules };
2568
2601
  }
@@ -3312,17 +3345,19 @@ var CollectionIdRegistry = class {
3312
3345
  }
3313
3346
  /**
3314
3347
  * Generates a unique collection ID for a given collection name
3315
- * Special case: Returns constant "_pb_users_auth_" for users collection
3316
3348
  * Retries up to 10 times if collision occurs (extremely rare)
3349
+ * Special case: returns "_pb_users_auth_" for users collection
3317
3350
  *
3318
- * @param collectionName - The name of the collection
3351
+ * @param collectionName - The name of the collection (optional)
3319
3352
  * @returns A unique collection ID
3320
3353
  * @throws Error if unable to generate unique ID after max attempts
3321
3354
  */
3322
3355
  generate(collectionName) {
3323
3356
  if (collectionName && collectionName.toLowerCase() === "users") {
3324
3357
  const usersId = "_pb_users_auth_";
3325
- this.register(usersId);
3358
+ if (!this.has(usersId)) {
3359
+ this.register(usersId);
3360
+ }
3326
3361
  return usersId;
3327
3362
  }
3328
3363
  const maxAttempts = 10;
@@ -3506,18 +3541,49 @@ function compareFieldConstraints(currentField, previousField) {
3506
3541
  }
3507
3542
  return changes;
3508
3543
  }
3544
+ function normalizeOptionValue(key, value, fieldType) {
3545
+ if (key === "maxSelect" && value === 1 && (fieldType === "select" || fieldType === "file")) {
3546
+ return void 0;
3547
+ }
3548
+ if (key === "maxSize" && value === 0 && fieldType === "file") {
3549
+ return void 0;
3550
+ }
3551
+ if (fieldType === "file") {
3552
+ if (key === "mimeTypes" && Array.isArray(value) && value.length === 0) {
3553
+ return void 0;
3554
+ }
3555
+ if (key === "thumbs" && Array.isArray(value) && value.length === 0) {
3556
+ return void 0;
3557
+ }
3558
+ if (key === "protected" && value === false) {
3559
+ return void 0;
3560
+ }
3561
+ }
3562
+ if (fieldType === "autodate") {
3563
+ if (key === "onCreate" && value === true) {
3564
+ return void 0;
3565
+ }
3566
+ if (key === "onUpdate" && value === false) {
3567
+ return void 0;
3568
+ }
3569
+ }
3570
+ return value;
3571
+ }
3509
3572
  function compareFieldOptions(currentField, previousField) {
3510
3573
  const changes = [];
3511
3574
  const currentOptions = currentField.options || {};
3512
3575
  const previousOptions = previousField.options || {};
3513
3576
  const allKeys = /* @__PURE__ */ new Set([...Object.keys(currentOptions), ...Object.keys(previousOptions)]);
3577
+ const fieldType = currentField.type;
3514
3578
  for (const key of allKeys) {
3515
3579
  const currentValue = currentOptions[key];
3516
3580
  const previousValue = previousOptions[key];
3517
- if (currentValue === void 0 && previousValue === void 0) {
3581
+ const normalizedCurrent = normalizeOptionValue(key, currentValue, fieldType);
3582
+ const normalizedPrevious = normalizeOptionValue(key, previousValue, fieldType);
3583
+ if (normalizedCurrent === void 0 && normalizedPrevious === void 0) {
3518
3584
  continue;
3519
3585
  }
3520
- if (!areValuesEqual(currentValue, previousValue)) {
3586
+ if (!areValuesEqual(normalizedCurrent, normalizedPrevious)) {
3521
3587
  changes.push({
3522
3588
  property: `options.${key}`,
3523
3589
  oldValue: previousValue,
@@ -3527,7 +3593,7 @@ function compareFieldOptions(currentField, previousField) {
3527
3593
  }
3528
3594
  return changes;
3529
3595
  }
3530
- function compareRelationConfigurations(currentField, previousField) {
3596
+ function compareRelationConfigurations(currentField, previousField, collectionIdToName) {
3531
3597
  const changes = [];
3532
3598
  const currentRelation = currentField.relation;
3533
3599
  const previousRelation = previousField.relation;
@@ -3539,8 +3605,8 @@ function compareRelationConfigurations(currentField, previousField) {
3539
3605
  }
3540
3606
  const normalizeCollection = (collection) => {
3541
3607
  if (!collection) return collection;
3542
- if (collection === "_pb_users_auth_") {
3543
- return "Users";
3608
+ if (collectionIdToName && collectionIdToName.has(collection)) {
3609
+ return collectionIdToName.get(collection);
3544
3610
  }
3545
3611
  const nameMatch = collection.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
3546
3612
  if (nameMatch) {
@@ -3550,13 +3616,11 @@ function compareRelationConfigurations(currentField, previousField) {
3550
3616
  };
3551
3617
  const normalizedCurrent = normalizeCollection(currentRelation.collection);
3552
3618
  const normalizedPrevious = normalizeCollection(previousRelation.collection);
3553
- if (normalizedCurrent !== normalizedPrevious) {
3619
+ if (normalizedCurrent.toLowerCase() !== normalizedPrevious.toLowerCase()) {
3554
3620
  changes.push({
3555
3621
  property: "relation.collection",
3556
- oldValue: normalizedPrevious,
3557
- // Use normalized value for clarity
3558
- newValue: normalizedCurrent
3559
- // Use normalized value for clarity
3622
+ oldValue: previousRelation.collection,
3623
+ newValue: currentRelation.collection
3560
3624
  });
3561
3625
  }
3562
3626
  if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {
@@ -3566,14 +3630,20 @@ function compareRelationConfigurations(currentField, previousField) {
3566
3630
  newValue: currentRelation.cascadeDelete
3567
3631
  });
3568
3632
  }
3569
- if (currentRelation.maxSelect !== previousRelation.maxSelect) {
3633
+ const normalizeMax = (val) => val === 1 ? null : val;
3634
+ const currentMax = normalizeMax(currentRelation.maxSelect);
3635
+ const previousMax = normalizeMax(previousRelation.maxSelect);
3636
+ if (currentMax != previousMax) {
3570
3637
  changes.push({
3571
3638
  property: "relation.maxSelect",
3572
3639
  oldValue: previousRelation.maxSelect,
3573
3640
  newValue: currentRelation.maxSelect
3574
3641
  });
3575
3642
  }
3576
- if (currentRelation.minSelect !== previousRelation.minSelect) {
3643
+ const normalizeMin = (val) => val === 0 ? null : val;
3644
+ const currentMin = normalizeMin(currentRelation.minSelect);
3645
+ const previousMin = normalizeMin(previousRelation.minSelect);
3646
+ if (currentMin != previousMin) {
3577
3647
  changes.push({
3578
3648
  property: "relation.minSelect",
3579
3649
  oldValue: previousRelation.minSelect,
@@ -3582,7 +3652,7 @@ function compareRelationConfigurations(currentField, previousField) {
3582
3652
  }
3583
3653
  return changes;
3584
3654
  }
3585
- function detectFieldChanges(currentField, previousField) {
3655
+ function detectFieldChanges(currentField, previousField, collectionIdToName) {
3586
3656
  const changes = [];
3587
3657
  const typeChange = compareFieldTypes(currentField, previousField);
3588
3658
  if (typeChange) {
@@ -3591,7 +3661,7 @@ function detectFieldChanges(currentField, previousField) {
3591
3661
  changes.push(...compareFieldConstraints(currentField, previousField));
3592
3662
  changes.push(...compareFieldOptions(currentField, previousField));
3593
3663
  if (currentField.type === "relation" && previousField.type === "relation") {
3594
- changes.push(...compareRelationConfigurations(currentField, previousField));
3664
+ changes.push(...compareRelationConfigurations(currentField, previousField, collectionIdToName));
3595
3665
  }
3596
3666
  return changes;
3597
3667
  }
@@ -3602,7 +3672,7 @@ function compareIndexes(currentIndexes = [], previousIndexes = []) {
3602
3672
  const indexesToRemove = previousIndexes.filter((idx) => !currentSet.has(idx));
3603
3673
  return { indexesToAdd, indexesToRemove };
3604
3674
  }
3605
- function compareRules(currentRules, previousRules) {
3675
+ function compareRules(currentRules, previousRules, currentPermissions, previousPermissions) {
3606
3676
  const updates = [];
3607
3677
  const ruleTypes = [
3608
3678
  "listRule",
@@ -3613,8 +3683,8 @@ function compareRules(currentRules, previousRules) {
3613
3683
  "manageRule"
3614
3684
  ];
3615
3685
  for (const ruleType of ruleTypes) {
3616
- const currentValue = currentRules?.[ruleType] ?? null;
3617
- const previousValue = previousRules?.[ruleType] ?? null;
3686
+ const currentValue = currentRules?.[ruleType] ?? currentPermissions?.[ruleType] ?? null;
3687
+ const previousValue = previousRules?.[ruleType] ?? previousPermissions?.[ruleType] ?? null;
3618
3688
  if (currentValue !== previousValue) {
3619
3689
  updates.push({
3620
3690
  ruleType,
@@ -3641,7 +3711,7 @@ function comparePermissions(currentPermissions, previousPermissions) {
3641
3711
  }
3642
3712
  return changes;
3643
3713
  }
3644
- function compareCollectionFields(currentCollection, previousCollection, config) {
3714
+ function compareCollectionFields(currentCollection, previousCollection, config, collectionIdToName) {
3645
3715
  let fieldsToAdd = findNewFields(currentCollection.fields, previousCollection.fields);
3646
3716
  const fieldsToRemove = findRemovedFields(currentCollection.fields, previousCollection.fields);
3647
3717
  const fieldsToModify = [];
@@ -3651,7 +3721,7 @@ function compareCollectionFields(currentCollection, previousCollection, config)
3651
3721
  }
3652
3722
  const matchedFields = matchFieldsByName(currentCollection.fields, previousCollection.fields);
3653
3723
  for (const [currentField, previousField] of matchedFields) {
3654
- const changes = detectFieldChanges(currentField, previousField);
3724
+ const changes = detectFieldChanges(currentField, previousField, collectionIdToName);
3655
3725
  if (changes.length > 0) {
3656
3726
  fieldsToModify.push({
3657
3727
  fieldName: currentField.name,
@@ -3663,14 +3733,20 @@ function compareCollectionFields(currentCollection, previousCollection, config)
3663
3733
  }
3664
3734
  return { fieldsToAdd, fieldsToRemove, fieldsToModify };
3665
3735
  }
3666
- function buildCollectionModification(currentCollection, previousCollection, config) {
3736
+ function buildCollectionModification(currentCollection, previousCollection, config, collectionIdToName) {
3667
3737
  const { fieldsToAdd, fieldsToRemove, fieldsToModify } = compareCollectionFields(
3668
3738
  currentCollection,
3669
3739
  previousCollection,
3670
- config
3740
+ config,
3741
+ collectionIdToName
3671
3742
  );
3672
3743
  const { indexesToAdd, indexesToRemove } = compareIndexes(currentCollection.indexes, previousCollection.indexes);
3673
- const rulesToUpdate = compareRules(currentCollection.rules, previousCollection.rules);
3744
+ const rulesToUpdate = compareRules(
3745
+ currentCollection.rules,
3746
+ previousCollection.rules,
3747
+ currentCollection.permissions,
3748
+ previousCollection.permissions
3749
+ );
3674
3750
  const permissionsToUpdate = comparePermissions(currentCollection.permissions, previousCollection.permissions);
3675
3751
  return {
3676
3752
  collection: currentCollection.name,
@@ -3687,6 +3763,14 @@ function hasChanges(modification) {
3687
3763
  return modification.fieldsToAdd.length > 0 || modification.fieldsToRemove.length > 0 || modification.fieldsToModify.length > 0 || modification.indexesToAdd.length > 0 || modification.indexesToRemove.length > 0 || modification.rulesToUpdate.length > 0 || modification.permissionsToUpdate.length > 0;
3688
3764
  }
3689
3765
  function aggregateChanges(currentSchema, previousSnapshot, config) {
3766
+ const collectionIdToName = /* @__PURE__ */ new Map();
3767
+ if (previousSnapshot) {
3768
+ for (const [name, collection] of previousSnapshot.collections) {
3769
+ if (collection.id) {
3770
+ collectionIdToName.set(collection.id, name);
3771
+ }
3772
+ }
3773
+ }
3690
3774
  const collectionsToCreate = findNewCollections(currentSchema, previousSnapshot);
3691
3775
  const collectionsToDelete = findRemovedCollections(currentSchema, previousSnapshot);
3692
3776
  const filteredCollectionsToCreate = collectionsToCreate.filter(
@@ -3710,7 +3794,7 @@ function aggregateChanges(currentSchema, previousSnapshot, config) {
3710
3794
  const collectionsToModify = [];
3711
3795
  const matchedCollections = matchCollectionsByName(currentSchema, previousSnapshot);
3712
3796
  for (const [currentCollection, previousCollection] of matchedCollections) {
3713
- const modification = buildCollectionModification(currentCollection, previousCollection, config);
3797
+ const modification = buildCollectionModification(currentCollection, previousCollection, config, collectionIdToName);
3714
3798
  if (hasChanges(modification)) {
3715
3799
  collectionsToModify.push(modification);
3716
3800
  }
@@ -4280,6 +4364,9 @@ function getSystemFields() {
4280
4364
  function generateCollectionCreation(collection, varName = "collection", isLast = false, collectionIdMap) {
4281
4365
  const lines = [];
4282
4366
  lines.push(` const ${varName} = new Collection({`);
4367
+ if (collection.id) {
4368
+ lines.push(` id: ${formatValue(collection.id)},`);
4369
+ }
4283
4370
  lines.push(` name: "${collection.name}",`);
4284
4371
  lines.push(` type: "${collection.type}",`);
4285
4372
  const permissionsCode = generateCollectionPermissions(collection.permissions);
@@ -4523,7 +4610,24 @@ function generateOperationUpMigration(operation, collectionIdMap) {
4523
4610
  const varName = `collection_${collectionName}`;
4524
4611
  lines.push(generateCollectionDeletion(collectionName, varName, true));
4525
4612
  }
4526
- return lines.join("\n");
4613
+ let code = lines.join("\n");
4614
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
4615
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
4616
+ const saveMatches = [...code.matchAll(savePattern)];
4617
+ const deleteMatches = [...code.matchAll(deletePattern)];
4618
+ const allMatches = [
4619
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
4620
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
4621
+ ].sort((a, b) => b.index - a.index);
4622
+ if (allMatches.length > 0) {
4623
+ const lastMatch = allMatches[0];
4624
+ if (lastMatch.type === "save") {
4625
+ code = code.substring(0, lastMatch.match.index) + lastMatch.match[1] + "return app.save(" + lastMatch.match[2] + ");" + code.substring(lastMatch.match.index + lastMatch.match[0].length);
4626
+ } else {
4627
+ code = code.substring(0, lastMatch.match.index) + lastMatch.match[1] + "return app.delete(" + lastMatch.match[2] + ");" + code.substring(lastMatch.match.index + lastMatch.match[0].length);
4628
+ }
4629
+ }
4630
+ return code;
4527
4631
  }
4528
4632
  function generateOperationDownMigration(operation, collectionIdMap) {
4529
4633
  const lines = [];
@@ -4608,7 +4712,24 @@ function generateOperationDownMigration(operation, collectionIdMap) {
4608
4712
  lines.push(generateCollectionCreation(collection, varName, true, collectionIdMap));
4609
4713
  }
4610
4714
  }
4611
- return lines.join("\n");
4715
+ let code = lines.join("\n");
4716
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
4717
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
4718
+ const saveMatches = [...code.matchAll(savePattern)];
4719
+ const deleteMatches = [...code.matchAll(deletePattern)];
4720
+ const allMatches = [
4721
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
4722
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
4723
+ ].sort((a, b) => b.index - a.index);
4724
+ if (allMatches.length > 0) {
4725
+ const lastMatch = allMatches[0];
4726
+ if (lastMatch.type === "save") {
4727
+ code = code.substring(0, lastMatch.match.index) + lastMatch.match[1] + "return app.save(" + lastMatch.match[2] + ");" + code.substring(lastMatch.match.index + lastMatch.match[0].length);
4728
+ } else {
4729
+ code = code.substring(0, lastMatch.match.index) + lastMatch.match[1] + "return app.delete(" + lastMatch.match[2] + ");" + code.substring(lastMatch.match.index + lastMatch.match[0].length);
4730
+ }
4731
+ }
4732
+ return code;
4612
4733
  }
4613
4734
  function generateUpMigration(diff) {
4614
4735
  const lines = [];