pocketbase-zod-schema 0.3.0 → 0.3.2

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 (66) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/cli/index.cjs +175 -50
  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 +175 -50
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/cli/migrate.cjs +175 -50
  9. package/dist/cli/migrate.cjs.map +1 -1
  10. package/dist/cli/migrate.js +175 -50
  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-DBBm06VU.d.cts} +35 -7
  15. package/dist/{fields-UcOPu1OQ.d.ts → fields-DBBm06VU.d.ts} +35 -7
  16. package/dist/index.cjs +264 -84
  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 +264 -84
  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 +81 -34
  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 +81 -34
  37. package/dist/migration/generator.js.map +1 -1
  38. package/dist/migration/index.cjs +209 -78
  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 +209 -78
  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 +55 -6
  57. package/dist/schema.cjs.map +1 -1
  58. package/dist/schema.d.cts +1 -1
  59. package/dist/schema.d.ts +1 -1
  60. package/dist/schema.js +55 -6
  61. package/dist/schema.js.map +1 -1
  62. package/dist/{type-mapper-DrQmtznD.d.cts → type-mapper-DsGgZwUo.d.cts} +1 -1
  63. package/dist/{type-mapper-n231Fspm.d.ts → type-mapper-Dvh4QTM-.d.ts} +1 -1
  64. package/dist/{types-YoBjsa-A.d.cts → types-CVxPCgWX.d.cts} +1 -1
  65. package/dist/{types-Ds3NQvny.d.ts → types-Dfp-NP2D.d.ts} +1 -1
  66. package/package.json +1 -1
@@ -2,9 +2,9 @@ export { SchemaAnalyzer, SchemaAnalyzerConfig, buildFieldDefinition, buildSchema
2
2
  export { SnapshotConfig, SnapshotManager, convertPocketBaseMigration, findLatestSnapshot, getSnapshotPath, getSnapshotVersion, loadBaseMigration, loadSnapshot, loadSnapshotIfExists, loadSnapshotWithMigrations, mergeSnapshots, saveSnapshot, snapshotExists, validateSnapshot } from './snapshot.cjs';
3
3
  export { ChangeSummary, DestructiveChange, DiffEngine, DiffEngineConfig, aggregateChanges, categorizeChangesBySeverity, compare, compareFieldConstraints, compareFieldOptions, compareFieldTypes, comparePermissions, compareRelationConfigurations, detectDestructiveChanges, detectFieldChanges, filterSystemCollections, findNewCollections, findNewFields, findRemovedCollections, findRemovedFields, generateChangeSummary, getUsersSystemFields, isSystemCollection, matchCollectionsByName, matchFieldsByName, requiresForceFlag } from './diff.cjs';
4
4
  export { MigrationGenerator, MigrationGeneratorConfig, createMigrationFileStructure, generate, generateCollectionCreation, generateCollectionPermissions, generateCollectionRules, generateDownMigration, generateFieldAddition, generateFieldDefinitionObject, generateFieldDeletion, generateFieldModification, generateFieldsArray, generateIndexesArray, generateMigrationDescription, generateMigrationFilename, generatePermissionUpdate, generateTimestamp, generateUpMigration, writeMigrationFile } from './generator.cjs';
5
- export { d as CollectionModification, f as CollectionOperation, C as CollectionSchema, b as FieldChange, F as FieldDefinition, c as FieldModification, P as PermissionChange, R as RuleUpdate, S as SchemaDefinition, e as SchemaDiff, a as SchemaSnapshot } from '../types-YoBjsa-A.cjs';
6
- export { E as ExtractedFieldOptions, d as FIELD_TYPE_INFO, F as FieldTypeInfo, C as FieldTypeResult, P as POCKETBASE_FIELD_TYPES, z as extractComprehensiveFieldOptions, o as extractFieldOptions, x as getArrayElementType, v as getDefaultValue, D as getFieldTypeInfo, g as getMaxSelect, c as getMinSelect, w as isArrayType, A as isEditorField, q as isFieldRequired, B as isFileFieldByName, y as isGeoPointType, a as isMultipleRelationField, b as isRelationField, i as isSingleRelationField, j as mapZodArrayType, f as mapZodBooleanType, k as mapZodDateType, h as mapZodEnumType, e as mapZodNumberType, l as mapZodRecordType, m as mapZodStringType, n as mapZodTypeToPocketBase, p as pluralize, r as resolveTargetCollection, s as singularize, t as toCollectionName, u as unwrapZodType } from '../type-mapper-DrQmtznD.cjs';
7
- export { F as FIELD_METADATA_KEY, a as FieldMetadata, P as PocketBaseFieldType, e as extractFieldMetadata } from '../fields-UcOPu1OQ.cjs';
5
+ export { d as CollectionModification, f as CollectionOperation, C as CollectionSchema, b as FieldChange, F as FieldDefinition, c as FieldModification, P as PermissionChange, R as RuleUpdate, S as SchemaDefinition, e as SchemaDiff, a as SchemaSnapshot } from '../types-CVxPCgWX.cjs';
6
+ export { E as ExtractedFieldOptions, d as FIELD_TYPE_INFO, F as FieldTypeInfo, C as FieldTypeResult, P as POCKETBASE_FIELD_TYPES, z as extractComprehensiveFieldOptions, o as extractFieldOptions, x as getArrayElementType, v as getDefaultValue, D as getFieldTypeInfo, g as getMaxSelect, c as getMinSelect, w as isArrayType, A as isEditorField, q as isFieldRequired, B as isFileFieldByName, y as isGeoPointType, a as isMultipleRelationField, b as isRelationField, i as isSingleRelationField, j as mapZodArrayType, f as mapZodBooleanType, k as mapZodDateType, h as mapZodEnumType, e as mapZodNumberType, l as mapZodRecordType, m as mapZodStringType, n as mapZodTypeToPocketBase, p as pluralize, r as resolveTargetCollection, s as singularize, t as toCollectionName, u as unwrapZodType } from '../type-mapper-DsGgZwUo.cjs';
7
+ export { F as FIELD_METADATA_KEY, a as FieldMetadata, P as PocketBaseFieldType, e as extractFieldMetadata } from '../fields-DBBm06VU.cjs';
8
8
  export { A as APIRuleType } from '../permissions-ZHafVSIx.cjs';
9
9
  import 'zod';
10
10
 
@@ -2,9 +2,9 @@ export { SchemaAnalyzer, SchemaAnalyzerConfig, buildFieldDefinition, buildSchema
2
2
  export { SnapshotConfig, SnapshotManager, convertPocketBaseMigration, findLatestSnapshot, getSnapshotPath, getSnapshotVersion, loadBaseMigration, loadSnapshot, loadSnapshotIfExists, loadSnapshotWithMigrations, mergeSnapshots, saveSnapshot, snapshotExists, validateSnapshot } from './snapshot.js';
3
3
  export { ChangeSummary, DestructiveChange, DiffEngine, DiffEngineConfig, aggregateChanges, categorizeChangesBySeverity, compare, compareFieldConstraints, compareFieldOptions, compareFieldTypes, comparePermissions, compareRelationConfigurations, detectDestructiveChanges, detectFieldChanges, filterSystemCollections, findNewCollections, findNewFields, findRemovedCollections, findRemovedFields, generateChangeSummary, getUsersSystemFields, isSystemCollection, matchCollectionsByName, matchFieldsByName, requiresForceFlag } from './diff.js';
4
4
  export { MigrationGenerator, MigrationGeneratorConfig, createMigrationFileStructure, generate, generateCollectionCreation, generateCollectionPermissions, generateCollectionRules, generateDownMigration, generateFieldAddition, generateFieldDefinitionObject, generateFieldDeletion, generateFieldModification, generateFieldsArray, generateIndexesArray, generateMigrationDescription, generateMigrationFilename, generatePermissionUpdate, generateTimestamp, generateUpMigration, writeMigrationFile } from './generator.js';
5
- export { d as CollectionModification, f as CollectionOperation, C as CollectionSchema, b as FieldChange, F as FieldDefinition, c as FieldModification, P as PermissionChange, R as RuleUpdate, S as SchemaDefinition, e as SchemaDiff, a as SchemaSnapshot } from '../types-Ds3NQvny.js';
6
- export { E as ExtractedFieldOptions, d as FIELD_TYPE_INFO, F as FieldTypeInfo, C as FieldTypeResult, P as POCKETBASE_FIELD_TYPES, z as extractComprehensiveFieldOptions, o as extractFieldOptions, x as getArrayElementType, v as getDefaultValue, D as getFieldTypeInfo, g as getMaxSelect, c as getMinSelect, w as isArrayType, A as isEditorField, q as isFieldRequired, B as isFileFieldByName, y as isGeoPointType, a as isMultipleRelationField, b as isRelationField, i as isSingleRelationField, j as mapZodArrayType, f as mapZodBooleanType, k as mapZodDateType, h as mapZodEnumType, e as mapZodNumberType, l as mapZodRecordType, m as mapZodStringType, n as mapZodTypeToPocketBase, p as pluralize, r as resolveTargetCollection, s as singularize, t as toCollectionName, u as unwrapZodType } from '../type-mapper-n231Fspm.js';
7
- export { F as FIELD_METADATA_KEY, a as FieldMetadata, P as PocketBaseFieldType, e as extractFieldMetadata } from '../fields-UcOPu1OQ.js';
5
+ export { d as CollectionModification, f as CollectionOperation, C as CollectionSchema, b as FieldChange, F as FieldDefinition, c as FieldModification, P as PermissionChange, R as RuleUpdate, S as SchemaDefinition, e as SchemaDiff, a as SchemaSnapshot } from '../types-Dfp-NP2D.js';
6
+ export { E as ExtractedFieldOptions, d as FIELD_TYPE_INFO, F as FieldTypeInfo, C as FieldTypeResult, P as POCKETBASE_FIELD_TYPES, z as extractComprehensiveFieldOptions, o as extractFieldOptions, x as getArrayElementType, v as getDefaultValue, D as getFieldTypeInfo, g as getMaxSelect, c as getMinSelect, w as isArrayType, A as isEditorField, q as isFieldRequired, B as isFileFieldByName, y as isGeoPointType, a as isMultipleRelationField, b as isRelationField, i as isSingleRelationField, j as mapZodArrayType, f as mapZodBooleanType, k as mapZodDateType, h as mapZodEnumType, e as mapZodNumberType, l as mapZodRecordType, m as mapZodStringType, n as mapZodTypeToPocketBase, p as pluralize, r as resolveTargetCollection, s as singularize, t as toCollectionName, u as unwrapZodType } from '../type-mapper-Dvh4QTM-.js';
7
+ export { F as FIELD_METADATA_KEY, a as FieldMetadata, P as PocketBaseFieldType, e as extractFieldMetadata } from '../fields-DBBm06VU.js';
8
8
  export { A as APIRuleType } from '../permissions-ZHafVSIx.js';
9
9
  import 'zod';
10
10
 
@@ -1773,7 +1773,7 @@ var SchemaAnalyzer = class {
1773
1773
  var SNAPSHOT_VERSION = "1.0.0";
1774
1774
  function resolveCollectionIdToName(collectionId) {
1775
1775
  if (collectionId === "_pb_users_auth_") {
1776
- return "Users";
1776
+ return "users";
1777
1777
  }
1778
1778
  const nameMatch = collectionId.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
1779
1779
  if (nameMatch) {
@@ -1781,6 +1781,39 @@ function resolveCollectionIdToName(collectionId) {
1781
1781
  }
1782
1782
  return collectionId;
1783
1783
  }
1784
+ function extractFieldOptions2(pbField) {
1785
+ const options = {};
1786
+ if (pbField.options && typeof pbField.options === "object") {
1787
+ Object.assign(options, pbField.options);
1788
+ }
1789
+ const directOptionKeys = [
1790
+ "min",
1791
+ "max",
1792
+ "pattern",
1793
+ "noDecimal",
1794
+ // text/number fields
1795
+ "values",
1796
+ "maxSelect",
1797
+ // select fields
1798
+ "mimeTypes",
1799
+ "maxSize",
1800
+ "thumbs",
1801
+ "protected",
1802
+ // file fields
1803
+ "onCreate",
1804
+ "onUpdate",
1805
+ // autodate fields
1806
+ "exceptDomains",
1807
+ "onlyDomains"
1808
+ // email/url fields
1809
+ ];
1810
+ for (const key of directOptionKeys) {
1811
+ if (pbField[key] !== void 0) {
1812
+ options[key] = pbField[key];
1813
+ }
1814
+ }
1815
+ return options;
1816
+ }
1784
1817
  function convertPocketBaseCollection(pbCollection) {
1785
1818
  const fields = [];
1786
1819
  const systemFieldNames = ["id", "created", "updated", "collectionId", "collectionName", "expand"];
@@ -1798,23 +1831,19 @@ function convertPocketBaseCollection(pbCollection) {
1798
1831
  type: pbField.type,
1799
1832
  required: pbField.required || false
1800
1833
  };
1801
- field.options = pbField.options ? { ...pbField.options } : {};
1802
- if (pbField.type === "select") {
1803
- if (pbField.values && Array.isArray(pbField.values)) {
1804
- field.options.values = pbField.values;
1805
- } else if (pbField.options?.values && Array.isArray(pbField.options.values)) {
1806
- field.options.values = pbField.options.values;
1807
- }
1808
- }
1834
+ field.options = extractFieldOptions2(pbField);
1809
1835
  if (pbField.type === "relation") {
1810
1836
  const collectionId = pbField.collectionId || pbField.options?.collectionId || "";
1811
- const collectionName = resolveCollectionIdToName(collectionId);
1837
+ const collectionName = resolveCollectionIdToName(collectionId || "");
1812
1838
  field.relation = {
1813
1839
  collection: collectionName,
1814
1840
  cascadeDelete: pbField.cascadeDelete ?? pbField.options?.cascadeDelete ?? false,
1815
1841
  maxSelect: pbField.maxSelect ?? pbField.options?.maxSelect,
1816
1842
  minSelect: pbField.minSelect ?? pbField.options?.minSelect
1817
1843
  };
1844
+ delete field.options.maxSelect;
1845
+ delete field.options.minSelect;
1846
+ delete field.options.cascadeDelete;
1818
1847
  }
1819
1848
  const hasOnlyValues = Object.keys(field.options).length === 1 && field.options.values !== void 0;
1820
1849
  if (Object.keys(field.options).length === 0) {
@@ -1828,17 +1857,21 @@ function convertPocketBaseCollection(pbCollection) {
1828
1857
  type: pbCollection.type || "base",
1829
1858
  fields
1830
1859
  };
1860
+ if (pbCollection.id) {
1861
+ schema.id = pbCollection.id;
1862
+ }
1831
1863
  if (pbCollection.indexes && Array.isArray(pbCollection.indexes)) {
1832
1864
  schema.indexes = pbCollection.indexes;
1833
1865
  }
1834
- const rules = {};
1835
- if (pbCollection.listRule !== void 0) rules.listRule = pbCollection.listRule;
1836
- if (pbCollection.viewRule !== void 0) rules.viewRule = pbCollection.viewRule;
1837
- if (pbCollection.createRule !== void 0) rules.createRule = pbCollection.createRule;
1838
- if (pbCollection.updateRule !== void 0) rules.updateRule = pbCollection.updateRule;
1839
- if (pbCollection.deleteRule !== void 0) rules.deleteRule = pbCollection.deleteRule;
1840
- if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
1841
- if (Object.keys(rules).length > 0) {
1866
+ 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;
1867
+ if (hasAnyRule) {
1868
+ const rules = {};
1869
+ if (pbCollection.listRule !== void 0) rules.listRule = pbCollection.listRule;
1870
+ if (pbCollection.viewRule !== void 0) rules.viewRule = pbCollection.viewRule;
1871
+ if (pbCollection.createRule !== void 0) rules.createRule = pbCollection.createRule;
1872
+ if (pbCollection.updateRule !== void 0) rules.updateRule = pbCollection.updateRule;
1873
+ if (pbCollection.deleteRule !== void 0) rules.deleteRule = pbCollection.deleteRule;
1874
+ if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
1842
1875
  schema.rules = rules;
1843
1876
  schema.permissions = { ...rules };
1844
1877
  }
@@ -2588,17 +2621,19 @@ var CollectionIdRegistry = class {
2588
2621
  }
2589
2622
  /**
2590
2623
  * Generates a unique collection ID for a given collection name
2591
- * Special case: Returns constant "_pb_users_auth_" for users collection
2592
2624
  * Retries up to 10 times if collision occurs (extremely rare)
2625
+ * Special case: returns "_pb_users_auth_" for users collection
2593
2626
  *
2594
- * @param collectionName - The name of the collection
2627
+ * @param collectionName - The name of the collection (optional)
2595
2628
  * @returns A unique collection ID
2596
2629
  * @throws Error if unable to generate unique ID after max attempts
2597
2630
  */
2598
2631
  generate(collectionName) {
2599
2632
  if (collectionName && collectionName.toLowerCase() === "users") {
2600
2633
  const usersId = "_pb_users_auth_";
2601
- this.register(usersId);
2634
+ if (!this.has(usersId)) {
2635
+ this.register(usersId);
2636
+ }
2602
2637
  return usersId;
2603
2638
  }
2604
2639
  const maxAttempts = 10;
@@ -2782,18 +2817,49 @@ function compareFieldConstraints(currentField, previousField) {
2782
2817
  }
2783
2818
  return changes;
2784
2819
  }
2820
+ function normalizeOptionValue(key, value, fieldType) {
2821
+ if (key === "maxSelect" && value === 1 && (fieldType === "select" || fieldType === "file")) {
2822
+ return void 0;
2823
+ }
2824
+ if (key === "maxSize" && value === 0 && fieldType === "file") {
2825
+ return void 0;
2826
+ }
2827
+ if (fieldType === "file") {
2828
+ if (key === "mimeTypes" && Array.isArray(value) && value.length === 0) {
2829
+ return void 0;
2830
+ }
2831
+ if (key === "thumbs" && Array.isArray(value) && value.length === 0) {
2832
+ return void 0;
2833
+ }
2834
+ if (key === "protected" && value === false) {
2835
+ return void 0;
2836
+ }
2837
+ }
2838
+ if (fieldType === "autodate") {
2839
+ if (key === "onCreate" && value === true) {
2840
+ return void 0;
2841
+ }
2842
+ if (key === "onUpdate" && value === false) {
2843
+ return void 0;
2844
+ }
2845
+ }
2846
+ return value;
2847
+ }
2785
2848
  function compareFieldOptions(currentField, previousField) {
2786
2849
  const changes = [];
2787
2850
  const currentOptions = currentField.options || {};
2788
2851
  const previousOptions = previousField.options || {};
2789
2852
  const allKeys = /* @__PURE__ */ new Set([...Object.keys(currentOptions), ...Object.keys(previousOptions)]);
2853
+ const fieldType = currentField.type;
2790
2854
  for (const key of allKeys) {
2791
2855
  const currentValue = currentOptions[key];
2792
2856
  const previousValue = previousOptions[key];
2793
- if (currentValue === void 0 && previousValue === void 0) {
2857
+ const normalizedCurrent = normalizeOptionValue(key, currentValue, fieldType);
2858
+ const normalizedPrevious = normalizeOptionValue(key, previousValue, fieldType);
2859
+ if (normalizedCurrent === void 0 && normalizedPrevious === void 0) {
2794
2860
  continue;
2795
2861
  }
2796
- if (!areValuesEqual(currentValue, previousValue)) {
2862
+ if (!areValuesEqual(normalizedCurrent, normalizedPrevious)) {
2797
2863
  changes.push({
2798
2864
  property: `options.${key}`,
2799
2865
  oldValue: previousValue,
@@ -2803,7 +2869,7 @@ function compareFieldOptions(currentField, previousField) {
2803
2869
  }
2804
2870
  return changes;
2805
2871
  }
2806
- function compareRelationConfigurations(currentField, previousField) {
2872
+ function compareRelationConfigurations(currentField, previousField, collectionIdToName) {
2807
2873
  const changes = [];
2808
2874
  const currentRelation = currentField.relation;
2809
2875
  const previousRelation = previousField.relation;
@@ -2815,8 +2881,8 @@ function compareRelationConfigurations(currentField, previousField) {
2815
2881
  }
2816
2882
  const normalizeCollection = (collection) => {
2817
2883
  if (!collection) return collection;
2818
- if (collection === "_pb_users_auth_") {
2819
- return "Users";
2884
+ if (collectionIdToName && collectionIdToName.has(collection)) {
2885
+ return collectionIdToName.get(collection);
2820
2886
  }
2821
2887
  const nameMatch = collection.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
2822
2888
  if (nameMatch) {
@@ -2826,13 +2892,11 @@ function compareRelationConfigurations(currentField, previousField) {
2826
2892
  };
2827
2893
  const normalizedCurrent = normalizeCollection(currentRelation.collection);
2828
2894
  const normalizedPrevious = normalizeCollection(previousRelation.collection);
2829
- if (normalizedCurrent !== normalizedPrevious) {
2895
+ if (normalizedCurrent.toLowerCase() !== normalizedPrevious.toLowerCase()) {
2830
2896
  changes.push({
2831
2897
  property: "relation.collection",
2832
- oldValue: normalizedPrevious,
2833
- // Use normalized value for clarity
2834
- newValue: normalizedCurrent
2835
- // Use normalized value for clarity
2898
+ oldValue: previousRelation.collection,
2899
+ newValue: currentRelation.collection
2836
2900
  });
2837
2901
  }
2838
2902
  if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {
@@ -2842,14 +2906,20 @@ function compareRelationConfigurations(currentField, previousField) {
2842
2906
  newValue: currentRelation.cascadeDelete
2843
2907
  });
2844
2908
  }
2845
- if (currentRelation.maxSelect !== previousRelation.maxSelect) {
2909
+ const normalizeMax = (val) => val === 1 ? null : val;
2910
+ const currentMax = normalizeMax(currentRelation.maxSelect);
2911
+ const previousMax = normalizeMax(previousRelation.maxSelect);
2912
+ if (currentMax != previousMax) {
2846
2913
  changes.push({
2847
2914
  property: "relation.maxSelect",
2848
2915
  oldValue: previousRelation.maxSelect,
2849
2916
  newValue: currentRelation.maxSelect
2850
2917
  });
2851
2918
  }
2852
- if (currentRelation.minSelect !== previousRelation.minSelect) {
2919
+ const normalizeMin = (val) => val === 0 ? null : val;
2920
+ const currentMin = normalizeMin(currentRelation.minSelect);
2921
+ const previousMin = normalizeMin(previousRelation.minSelect);
2922
+ if (currentMin != previousMin) {
2853
2923
  changes.push({
2854
2924
  property: "relation.minSelect",
2855
2925
  oldValue: previousRelation.minSelect,
@@ -2858,7 +2928,7 @@ function compareRelationConfigurations(currentField, previousField) {
2858
2928
  }
2859
2929
  return changes;
2860
2930
  }
2861
- function detectFieldChanges(currentField, previousField) {
2931
+ function detectFieldChanges(currentField, previousField, collectionIdToName) {
2862
2932
  const changes = [];
2863
2933
  const typeChange = compareFieldTypes(currentField, previousField);
2864
2934
  if (typeChange) {
@@ -2867,7 +2937,7 @@ function detectFieldChanges(currentField, previousField) {
2867
2937
  changes.push(...compareFieldConstraints(currentField, previousField));
2868
2938
  changes.push(...compareFieldOptions(currentField, previousField));
2869
2939
  if (currentField.type === "relation" && previousField.type === "relation") {
2870
- changes.push(...compareRelationConfigurations(currentField, previousField));
2940
+ changes.push(...compareRelationConfigurations(currentField, previousField, collectionIdToName));
2871
2941
  }
2872
2942
  return changes;
2873
2943
  }
@@ -2878,7 +2948,7 @@ function compareIndexes(currentIndexes = [], previousIndexes = []) {
2878
2948
  const indexesToRemove = previousIndexes.filter((idx) => !currentSet.has(idx));
2879
2949
  return { indexesToAdd, indexesToRemove };
2880
2950
  }
2881
- function compareRules(currentRules, previousRules) {
2951
+ function compareRules(currentRules, previousRules, currentPermissions, previousPermissions) {
2882
2952
  const updates = [];
2883
2953
  const ruleTypes = [
2884
2954
  "listRule",
@@ -2889,8 +2959,8 @@ function compareRules(currentRules, previousRules) {
2889
2959
  "manageRule"
2890
2960
  ];
2891
2961
  for (const ruleType of ruleTypes) {
2892
- const currentValue = currentRules?.[ruleType] ?? null;
2893
- const previousValue = previousRules?.[ruleType] ?? null;
2962
+ const currentValue = currentRules?.[ruleType] ?? currentPermissions?.[ruleType] ?? null;
2963
+ const previousValue = previousRules?.[ruleType] ?? previousPermissions?.[ruleType] ?? null;
2894
2964
  if (currentValue !== previousValue) {
2895
2965
  updates.push({
2896
2966
  ruleType,
@@ -2917,7 +2987,7 @@ function comparePermissions(currentPermissions, previousPermissions) {
2917
2987
  }
2918
2988
  return changes;
2919
2989
  }
2920
- function compareCollectionFields(currentCollection, previousCollection, config) {
2990
+ function compareCollectionFields(currentCollection, previousCollection, config, collectionIdToName) {
2921
2991
  let fieldsToAdd = findNewFields(currentCollection.fields, previousCollection.fields);
2922
2992
  const fieldsToRemove = findRemovedFields(currentCollection.fields, previousCollection.fields);
2923
2993
  const fieldsToModify = [];
@@ -2927,7 +2997,7 @@ function compareCollectionFields(currentCollection, previousCollection, config)
2927
2997
  }
2928
2998
  const matchedFields = matchFieldsByName(currentCollection.fields, previousCollection.fields);
2929
2999
  for (const [currentField, previousField] of matchedFields) {
2930
- const changes = detectFieldChanges(currentField, previousField);
3000
+ const changes = detectFieldChanges(currentField, previousField, collectionIdToName);
2931
3001
  if (changes.length > 0) {
2932
3002
  fieldsToModify.push({
2933
3003
  fieldName: currentField.name,
@@ -2939,14 +3009,20 @@ function compareCollectionFields(currentCollection, previousCollection, config)
2939
3009
  }
2940
3010
  return { fieldsToAdd, fieldsToRemove, fieldsToModify };
2941
3011
  }
2942
- function buildCollectionModification(currentCollection, previousCollection, config) {
3012
+ function buildCollectionModification(currentCollection, previousCollection, config, collectionIdToName) {
2943
3013
  const { fieldsToAdd, fieldsToRemove, fieldsToModify } = compareCollectionFields(
2944
3014
  currentCollection,
2945
3015
  previousCollection,
2946
- config
3016
+ config,
3017
+ collectionIdToName
2947
3018
  );
2948
3019
  const { indexesToAdd, indexesToRemove } = compareIndexes(currentCollection.indexes, previousCollection.indexes);
2949
- const rulesToUpdate = compareRules(currentCollection.rules, previousCollection.rules);
3020
+ const rulesToUpdate = compareRules(
3021
+ currentCollection.rules,
3022
+ previousCollection.rules,
3023
+ currentCollection.permissions,
3024
+ previousCollection.permissions
3025
+ );
2950
3026
  const permissionsToUpdate = comparePermissions(currentCollection.permissions, previousCollection.permissions);
2951
3027
  return {
2952
3028
  collection: currentCollection.name,
@@ -2963,6 +3039,14 @@ function hasChanges(modification) {
2963
3039
  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;
2964
3040
  }
2965
3041
  function aggregateChanges(currentSchema, previousSnapshot, config) {
3042
+ const collectionIdToName = /* @__PURE__ */ new Map();
3043
+ if (previousSnapshot) {
3044
+ for (const [name, collection] of previousSnapshot.collections) {
3045
+ if (collection.id) {
3046
+ collectionIdToName.set(collection.id, name);
3047
+ }
3048
+ }
3049
+ }
2966
3050
  const collectionsToCreate = findNewCollections(currentSchema, previousSnapshot);
2967
3051
  const collectionsToDelete = findRemovedCollections(currentSchema, previousSnapshot);
2968
3052
  const filteredCollectionsToCreate = collectionsToCreate.filter(
@@ -2986,7 +3070,7 @@ function aggregateChanges(currentSchema, previousSnapshot, config) {
2986
3070
  const collectionsToModify = [];
2987
3071
  const matchedCollections = matchCollectionsByName(currentSchema, previousSnapshot);
2988
3072
  for (const [currentCollection, previousCollection] of matchedCollections) {
2989
- const modification = buildCollectionModification(currentCollection, previousCollection, config);
3073
+ const modification = buildCollectionModification(currentCollection, previousCollection, config, collectionIdToName);
2990
3074
  if (hasChanges(modification)) {
2991
3075
  collectionsToModify.push(modification);
2992
3076
  }
@@ -3387,7 +3471,7 @@ function formatValue(value) {
3387
3471
  return JSON.stringify(value).replace(/","/g, '", "');
3388
3472
  }
3389
3473
  if (typeof value === "object") {
3390
- const entries = Object.entries(value).map(([k, v]) => `${k}: ${formatValue(v)}`).join(", ");
3474
+ const entries = Object.entries(value).filter(([_k, v]) => v !== void 0).map(([k, v]) => `${k}: ${formatValue(v)}`).join(", ");
3391
3475
  return `{ ${entries} }`;
3392
3476
  }
3393
3477
  return String(value);
@@ -3556,6 +3640,9 @@ function getSystemFields() {
3556
3640
  function generateCollectionCreation(collection, varName = "collection", isLast = false, collectionIdMap) {
3557
3641
  const lines = [];
3558
3642
  lines.push(` const ${varName} = new Collection({`);
3643
+ if (collection.id) {
3644
+ lines.push(` id: ${formatValue(collection.id)},`);
3645
+ }
3559
3646
  lines.push(` name: "${collection.name}",`);
3560
3647
  lines.push(` type: "${collection.type}",`);
3561
3648
  const permissionsCode = generateCollectionPermissions(collection.permissions);
@@ -3678,11 +3765,9 @@ function generateFieldModification(collectionName, modification, varName, isLast
3678
3765
  function generateFieldDeletion(collectionName, fieldName, varName, isLast = false) {
3679
3766
  const lines = [];
3680
3767
  const collectionVar = varName || `collection_${collectionName}_${fieldName}`;
3681
- const fieldVar = `${collectionVar}_field`;
3682
3768
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
3683
- lines.push(` const ${fieldVar} = ${collectionVar}.fields.getByName("${fieldName}");`);
3684
3769
  lines.push(``);
3685
- lines.push(` ${collectionVar}.fields.remove(${fieldVar}.id);`);
3770
+ lines.push(` ${collectionVar}.fields.removeByName("${fieldName}");`);
3686
3771
  lines.push(``);
3687
3772
  lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
3688
3773
  return lines.join("\n");
@@ -3799,7 +3884,27 @@ function generateOperationUpMigration(operation, collectionIdMap) {
3799
3884
  const varName = `collection_${collectionName}`;
3800
3885
  lines.push(generateCollectionDeletion(collectionName, varName, true));
3801
3886
  }
3802
- return lines.join("\n");
3887
+ let code = lines.join("\n");
3888
+ const hasReturnStatement = /return\s+app\.(save|delete)\(/m.test(code);
3889
+ if (!hasReturnStatement) {
3890
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
3891
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
3892
+ const saveMatches = [...code.matchAll(savePattern)];
3893
+ const deleteMatches = [...code.matchAll(deletePattern)];
3894
+ const allMatches = [
3895
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
3896
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
3897
+ ].sort((a, b) => b.index - a.index);
3898
+ if (allMatches.length > 0) {
3899
+ const lastMatch = allMatches[0];
3900
+ if (lastMatch.type === "save") {
3901
+ 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);
3902
+ } else {
3903
+ 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);
3904
+ }
3905
+ }
3906
+ }
3907
+ return code;
3803
3908
  }
3804
3909
  function generateOperationDownMigration(operation, collectionIdMap) {
3805
3910
  const lines = [];
@@ -3884,7 +3989,27 @@ function generateOperationDownMigration(operation, collectionIdMap) {
3884
3989
  lines.push(generateCollectionCreation(collection, varName, true, collectionIdMap));
3885
3990
  }
3886
3991
  }
3887
- return lines.join("\n");
3992
+ let code = lines.join("\n");
3993
+ const hasReturnStatement = /return\s+app\.(save|delete)\(/m.test(code);
3994
+ if (!hasReturnStatement) {
3995
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
3996
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
3997
+ const saveMatches = [...code.matchAll(savePattern)];
3998
+ const deleteMatches = [...code.matchAll(deletePattern)];
3999
+ const allMatches = [
4000
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
4001
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
4002
+ ].sort((a, b) => b.index - a.index);
4003
+ if (allMatches.length > 0) {
4004
+ const lastMatch = allMatches[0];
4005
+ if (lastMatch.type === "save") {
4006
+ 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);
4007
+ } else {
4008
+ 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);
4009
+ }
4010
+ }
4011
+ }
4012
+ return code;
3888
4013
  }
3889
4014
  function generateUpMigration(diff) {
3890
4015
  const lines = [];
@@ -3982,20 +4107,23 @@ function generateUpMigration(diff) {
3982
4107
  lines.push(``);
3983
4108
  }
3984
4109
  let code = lines.join("\n");
3985
- const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
3986
- const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
3987
- const saveMatches = [...code.matchAll(savePattern)];
3988
- const deleteMatches = [...code.matchAll(deletePattern)];
3989
- const allMatches = [
3990
- ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
3991
- ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
3992
- ].sort((a, b) => b.index - a.index);
3993
- if (allMatches.length > 0) {
3994
- const lastMatch = allMatches[0];
3995
- if (lastMatch.type === "save") {
3996
- 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);
3997
- } else {
3998
- 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);
4110
+ const hasReturnStatement = /return\s+app\.(save|delete)\(/m.test(code);
4111
+ if (!hasReturnStatement) {
4112
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
4113
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
4114
+ const saveMatches = [...code.matchAll(savePattern)];
4115
+ const deleteMatches = [...code.matchAll(deletePattern)];
4116
+ const allMatches = [
4117
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
4118
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
4119
+ ].sort((a, b) => b.index - a.index);
4120
+ if (allMatches.length > 0) {
4121
+ const lastMatch = allMatches[0];
4122
+ if (lastMatch.type === "save") {
4123
+ 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);
4124
+ } else {
4125
+ 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);
4126
+ }
3999
4127
  }
4000
4128
  }
4001
4129
  return code;
@@ -4112,20 +4240,23 @@ function generateDownMigration(diff) {
4112
4240
  lines.push(``);
4113
4241
  }
4114
4242
  let code = lines.join("\n");
4115
- const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
4116
- const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
4117
- const saveMatches = [...code.matchAll(savePattern)];
4118
- const deleteMatches = [...code.matchAll(deletePattern)];
4119
- const allMatches = [
4120
- ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
4121
- ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
4122
- ].sort((a, b) => b.index - a.index);
4123
- if (allMatches.length > 0) {
4124
- const lastMatch = allMatches[0];
4125
- if (lastMatch.type === "save") {
4126
- 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);
4127
- } else {
4128
- 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);
4243
+ const hasReturnStatement = /return\s+app\.(save|delete)\(/m.test(code);
4244
+ if (!hasReturnStatement) {
4245
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
4246
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
4247
+ const saveMatches = [...code.matchAll(savePattern)];
4248
+ const deleteMatches = [...code.matchAll(deletePattern)];
4249
+ const allMatches = [
4250
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
4251
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
4252
+ ].sort((a, b) => b.index - a.index);
4253
+ if (allMatches.length > 0) {
4254
+ const lastMatch = allMatches[0];
4255
+ if (lastMatch.type === "save") {
4256
+ 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);
4257
+ } else {
4258
+ 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);
4259
+ }
4129
4260
  }
4130
4261
  }
4131
4262
  return code;