pocketbase-zod-schema 0.3.1 → 0.3.3

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 (60) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cli/index.cjs +64 -38
  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 +64 -38
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/cli/migrate.cjs +64 -38
  9. package/dist/cli/migrate.cjs.map +1 -1
  10. package/dist/cli/migrate.js +64 -38
  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-RVj26U-O.d.cts → fields-DBBm06VU.d.cts} +34 -7
  15. package/dist/{fields-RVj26U-O.d.ts → fields-DBBm06VU.d.ts} +34 -7
  16. package/dist/index.cjs +167 -75
  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 -75
  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 +10 -1
  27. package/dist/migration/diff.cjs.map +1 -1
  28. package/dist/migration/diff.d.cts +2 -2
  29. package/dist/migration/diff.d.ts +2 -2
  30. package/dist/migration/diff.js +10 -1
  31. package/dist/migration/diff.js.map +1 -1
  32. package/dist/migration/generator.cjs +102 -68
  33. package/dist/migration/generator.cjs.map +1 -1
  34. package/dist/migration/generator.d.cts +3 -3
  35. package/dist/migration/generator.d.ts +3 -3
  36. package/dist/migration/generator.js +102 -68
  37. package/dist/migration/generator.js.map +1 -1
  38. package/dist/migration/index.cjs +112 -69
  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 +112 -69
  43. package/dist/migration/index.js.map +1 -1
  44. package/dist/migration/snapshot.d.cts +2 -2
  45. package/dist/migration/snapshot.d.ts +2 -2
  46. package/dist/migration/utils/index.cjs.map +1 -1
  47. package/dist/migration/utils/index.d.cts +2 -2
  48. package/dist/migration/utils/index.d.ts +2 -2
  49. package/dist/migration/utils/index.js.map +1 -1
  50. package/dist/schema.cjs +55 -6
  51. package/dist/schema.cjs.map +1 -1
  52. package/dist/schema.d.cts +1 -1
  53. package/dist/schema.d.ts +1 -1
  54. package/dist/schema.js +55 -6
  55. package/dist/schema.js.map +1 -1
  56. package/dist/{type-mapper-DaBe-1ph.d.cts → type-mapper-DsGgZwUo.d.cts} +1 -1
  57. package/dist/{type-mapper-CZzVeDj7.d.ts → type-mapper-Dvh4QTM-.d.ts} +1 -1
  58. package/dist/{types-CUVzgZ9k.d.ts → types-BWhwQxG-.d.ts} +6 -1
  59. package/dist/{types-D-Fsdn_O.d.cts → types-d0yBwHoN.d.cts} +6 -1
  60. package/package.json +1 -1
package/dist/index.d.cts CHANGED
@@ -1,15 +1,15 @@
1
1
  export { StatusEnum, StatusEnumType } from './enums.cjs';
2
2
  export { BaseMutator, MutatorOptions } from './mutator.cjs';
3
3
  export { CollectionConfig, PermissionTemplates, PermissionValidationResult, RelationConfig, RelationField, RelationsConfig, RelationsField, baseImageFileSchema, baseSchema, baseSchemaWithTimestamps, createPermissions, defineCollection, extractRelationMetadata, inputImageFileSchema, isPermissionSchema, isTemplateConfig, mergePermissions, omitImageFilesSchema, resolveTemplate, validatePermissionConfig, validateRuleExpression, withIndexes, withPermissions } from './schema.cjs';
4
- export { i as AutodateField, A as AutodateFieldOptions, B as BoolField, h as DateField, D as DateFieldOptions, g as EditorField, E as EmailField, F as FIELD_METADATA_KEY, a as FieldMetadata, k as FileField, b as FileFieldOptions, l as FilesField, c as FilesFieldOptions, G as GeoPointField, J as JSONField, d as NumberField, N as NumberFieldOptions, P as PocketBaseFieldType, j as SelectField, S as SelectFieldOptions, f as TextField, T as TextFieldOptions, U as URLField, e as extractFieldMetadata } from './fields-RVj26U-O.cjs';
4
+ export { j as AutodateField, A as AutodateFieldOptions, d as BoolField, B as ByteSize, i as DateField, D as DateFieldOptions, h as EditorField, E as EmailField, F as FIELD_METADATA_KEY, a as FieldMetadata, l as FileField, b as FileFieldOptions, m as FilesField, c as FilesFieldOptions, G as GeoPointField, J as JSONField, f as NumberField, N as NumberFieldOptions, P as PocketBaseFieldType, k as SelectField, S as SelectFieldOptions, g as TextField, T as TextFieldOptions, U as URLField, e as extractFieldMetadata } from './fields-DBBm06VU.cjs';
5
5
  export { A as APIRuleType, P as PermissionSchema, a as PermissionTemplate, b as PermissionTemplateConfig, R as RuleExpression } from './permissions-ZHafVSIx.cjs';
6
6
  export { SchemaAnalyzer, SchemaAnalyzerConfig, buildFieldDefinition, buildSchemaDefinition, convertZodSchemaToCollectionSchema, discoverSchemaFiles, extractFieldDefinitions, extractIndexes, extractSchemaDefinitions, getCollectionNameFromFile, importSchemaModule, isAuthCollection, parseSchemaFiles, selectSchemaForCollection } from './migration/analyzer.cjs';
7
7
  export { SnapshotConfig, SnapshotManager, convertPocketBaseMigration, findLatestSnapshot, getSnapshotPath, getSnapshotVersion, loadBaseMigration, loadSnapshot, loadSnapshotIfExists, loadSnapshotWithMigrations, mergeSnapshots, saveSnapshot, snapshotExists, validateSnapshot } from './migration/snapshot.cjs';
8
8
  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 './migration/diff.cjs';
9
9
  export { MigrationGenerator, MigrationGeneratorConfig, createMigrationFileStructure, generate, generateCollectionCreation, generateCollectionPermissions, generateCollectionRules, generateDownMigration, generateFieldAddition, generateFieldDefinitionObject, generateFieldDeletion, generateFieldModification, generateFieldsArray, generateIndexesArray, generateMigrationDescription, generateMigrationFilename, generatePermissionUpdate, generateTimestamp, generateUpMigration, writeMigrationFile } from './migration/generator.cjs';
10
- 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-D-Fsdn_O.cjs';
10
+ 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-d0yBwHoN.cjs';
11
11
  export { CLIUsageError, ConfigurationError, FileSystemError, MigrationError, MigrationGenerationError, SchemaParsingError, SnapshotError } from './migration/index.cjs';
12
- 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-DaBe-1ph.cjs';
12
+ 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';
13
13
  export { generateMigration, getMigrationStatus } from './cli/index.cjs';
14
14
  export { formatChangeSummary, loadConfig, logError, logInfo, logSection, logSuccess, logWarning, withProgress } from './cli/utils/index.cjs';
15
15
  import 'zod';
package/dist/index.d.ts CHANGED
@@ -1,15 +1,15 @@
1
1
  export { StatusEnum, StatusEnumType } from './enums.js';
2
2
  export { BaseMutator, MutatorOptions } from './mutator.js';
3
3
  export { CollectionConfig, PermissionTemplates, PermissionValidationResult, RelationConfig, RelationField, RelationsConfig, RelationsField, baseImageFileSchema, baseSchema, baseSchemaWithTimestamps, createPermissions, defineCollection, extractRelationMetadata, inputImageFileSchema, isPermissionSchema, isTemplateConfig, mergePermissions, omitImageFilesSchema, resolveTemplate, validatePermissionConfig, validateRuleExpression, withIndexes, withPermissions } from './schema.js';
4
- export { i as AutodateField, A as AutodateFieldOptions, B as BoolField, h as DateField, D as DateFieldOptions, g as EditorField, E as EmailField, F as FIELD_METADATA_KEY, a as FieldMetadata, k as FileField, b as FileFieldOptions, l as FilesField, c as FilesFieldOptions, G as GeoPointField, J as JSONField, d as NumberField, N as NumberFieldOptions, P as PocketBaseFieldType, j as SelectField, S as SelectFieldOptions, f as TextField, T as TextFieldOptions, U as URLField, e as extractFieldMetadata } from './fields-RVj26U-O.js';
4
+ export { j as AutodateField, A as AutodateFieldOptions, d as BoolField, B as ByteSize, i as DateField, D as DateFieldOptions, h as EditorField, E as EmailField, F as FIELD_METADATA_KEY, a as FieldMetadata, l as FileField, b as FileFieldOptions, m as FilesField, c as FilesFieldOptions, G as GeoPointField, J as JSONField, f as NumberField, N as NumberFieldOptions, P as PocketBaseFieldType, k as SelectField, S as SelectFieldOptions, g as TextField, T as TextFieldOptions, U as URLField, e as extractFieldMetadata } from './fields-DBBm06VU.js';
5
5
  export { A as APIRuleType, P as PermissionSchema, a as PermissionTemplate, b as PermissionTemplateConfig, R as RuleExpression } from './permissions-ZHafVSIx.js';
6
6
  export { SchemaAnalyzer, SchemaAnalyzerConfig, buildFieldDefinition, buildSchemaDefinition, convertZodSchemaToCollectionSchema, discoverSchemaFiles, extractFieldDefinitions, extractIndexes, extractSchemaDefinitions, getCollectionNameFromFile, importSchemaModule, isAuthCollection, parseSchemaFiles, selectSchemaForCollection } from './migration/analyzer.js';
7
7
  export { SnapshotConfig, SnapshotManager, convertPocketBaseMigration, findLatestSnapshot, getSnapshotPath, getSnapshotVersion, loadBaseMigration, loadSnapshot, loadSnapshotIfExists, loadSnapshotWithMigrations, mergeSnapshots, saveSnapshot, snapshotExists, validateSnapshot } from './migration/snapshot.js';
8
8
  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 './migration/diff.js';
9
9
  export { MigrationGenerator, MigrationGeneratorConfig, createMigrationFileStructure, generate, generateCollectionCreation, generateCollectionPermissions, generateCollectionRules, generateDownMigration, generateFieldAddition, generateFieldDefinitionObject, generateFieldDeletion, generateFieldModification, generateFieldsArray, generateIndexesArray, generateMigrationDescription, generateMigrationFilename, generatePermissionUpdate, generateTimestamp, generateUpMigration, writeMigrationFile } from './migration/generator.js';
10
- 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-CUVzgZ9k.js';
10
+ 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-BWhwQxG-.js';
11
11
  export { CLIUsageError, ConfigurationError, FileSystemError, MigrationError, MigrationGenerationError, SchemaParsingError, SnapshotError } from './migration/index.js';
12
- 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-CZzVeDj7.js';
12
+ 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';
13
13
  export { generateMigration, getMigrationStatus } from './cli/index.js';
14
14
  export { formatChangeSummary, loadConfig, logError, logInfo, logSection, logSuccess, logWarning, withProgress } from './cli/utils/index.js';
15
15
  import 'zod';
package/dist/index.js CHANGED
@@ -461,6 +461,45 @@ function extractFieldMetadata(description) {
461
461
  }
462
462
  return null;
463
463
  }
464
+ var MAX_FILE_SIZE_BYTES = 8 * 1024 * 1024 * 1024;
465
+ function parseByteSizeToBytes(value, context) {
466
+ let bytes;
467
+ if (typeof value === "number") {
468
+ if (!Number.isFinite(value)) {
469
+ throw new Error(`${context}: maxSize must be a finite number of bytes`);
470
+ }
471
+ bytes = Math.round(value);
472
+ } else {
473
+ const trimmed = value.trim();
474
+ const match = /^(\d+(?:\.\d+)?)\s*([KMG])$/i.exec(trimmed);
475
+ if (!match) {
476
+ throw new Error(`${context}: maxSize string must be like "10K", "5M", or "1G" (case-insensitive)`);
477
+ }
478
+ const amount = Number(match[1]);
479
+ const unit = match[2].toUpperCase();
480
+ if (!Number.isFinite(amount)) {
481
+ throw new Error(`${context}: maxSize must be a valid number`);
482
+ }
483
+ const multiplier = unit === "K" ? 1024 : unit === "M" ? 1024 * 1024 : 1024 * 1024 * 1024;
484
+ bytes = Math.round(amount * multiplier);
485
+ }
486
+ if (bytes < 0) {
487
+ throw new Error(`${context}: maxSize must be >= 0`);
488
+ }
489
+ if (bytes > MAX_FILE_SIZE_BYTES) {
490
+ throw new Error(`${context}: maxSize cannot exceed 8G (${MAX_FILE_SIZE_BYTES} bytes)`);
491
+ }
492
+ return bytes;
493
+ }
494
+ function normalizeFileFieldOptions(options, context) {
495
+ if (!options) return options;
496
+ if (options.maxSize === void 0) return options;
497
+ return {
498
+ ...options,
499
+ // PocketBase expects bytes; normalize any human-friendly inputs to bytes here.
500
+ maxSize: parseByteSizeToBytes(options.maxSize, context)
501
+ };
502
+ }
464
503
  function BoolField() {
465
504
  const metadata = {
466
505
  [FIELD_METADATA_KEY]: {
@@ -583,11 +622,14 @@ function SelectField(values, options) {
583
622
  return enumSchema.describe(JSON.stringify(metadata));
584
623
  }
585
624
  function FileField(options) {
586
- const schema = z.instanceof(File);
625
+ const schema = z.preprocess((val) => {
626
+ return val instanceof File ? val.name || "" : val;
627
+ }, z.string());
628
+ const normalizedOptions = normalizeFileFieldOptions(options, "FileField");
587
629
  const metadata = {
588
630
  [FIELD_METADATA_KEY]: {
589
631
  type: "file",
590
- options: options || {}
632
+ options: normalizedOptions || {}
591
633
  }
592
634
  };
593
635
  return schema.describe(JSON.stringify(metadata));
@@ -598,17 +640,24 @@ function FilesField(options) {
598
640
  throw new Error("FilesField: minSelect cannot be greater than maxSelect");
599
641
  }
600
642
  }
601
- let schema = z.array(z.instanceof(File));
643
+ let baseArraySchema = z.array(z.string());
602
644
  if (options?.minSelect !== void 0) {
603
- schema = schema.min(options.minSelect);
645
+ baseArraySchema = baseArraySchema.min(options.minSelect);
604
646
  }
605
647
  if (options?.maxSelect !== void 0) {
606
- schema = schema.max(options.maxSelect);
648
+ baseArraySchema = baseArraySchema.max(options.maxSelect);
607
649
  }
650
+ const schema = z.preprocess((val) => {
651
+ if (Array.isArray(val)) {
652
+ return val.map((item) => item instanceof File ? item.name || "" : item);
653
+ }
654
+ return val;
655
+ }, baseArraySchema);
656
+ const normalizedOptions = normalizeFileFieldOptions(options, "FilesField");
608
657
  const metadata = {
609
658
  [FIELD_METADATA_KEY]: {
610
659
  type: "file",
611
- options: options || {}
660
+ options: normalizedOptions || {}
612
661
  }
613
662
  };
614
663
  return schema.describe(JSON.stringify(metadata));
@@ -3772,10 +3821,19 @@ function aggregateChanges(currentSchema, previousSnapshot, config) {
3772
3821
  collectionsToModify.push(modification);
3773
3822
  }
3774
3823
  }
3824
+ const existingCollectionIds = /* @__PURE__ */ new Map();
3825
+ if (previousSnapshot) {
3826
+ for (const [name, collection] of previousSnapshot.collections) {
3827
+ if (collection.id) {
3828
+ existingCollectionIds.set(name, collection.id);
3829
+ }
3830
+ }
3831
+ }
3775
3832
  return {
3776
3833
  collectionsToCreate: collectionsWithIds,
3777
3834
  collectionsToDelete: filteredCollectionsToDelete,
3778
- collectionsToModify
3835
+ collectionsToModify,
3836
+ existingCollectionIds
3779
3837
  };
3780
3838
  }
3781
3839
  function detectDestructiveChanges(diff, config) {
@@ -4168,7 +4226,7 @@ function formatValue(value) {
4168
4226
  return JSON.stringify(value).replace(/","/g, '", "');
4169
4227
  }
4170
4228
  if (typeof value === "object") {
4171
- const entries = Object.entries(value).map(([k, v]) => `${k}: ${formatValue(v)}`).join(", ");
4229
+ const entries = Object.entries(value).filter(([_k, v]) => v !== void 0).map(([k, v]) => `${k}: ${formatValue(v)}`).join(", ");
4172
4230
  return `{ ${entries} }`;
4173
4231
  }
4174
4232
  return String(value);
@@ -4431,7 +4489,7 @@ function generateFieldAddition(collectionName, field, varName, isLast = false, c
4431
4489
  lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
4432
4490
  return lines.join("\n");
4433
4491
  }
4434
- function generateFieldModification(collectionName, modification, varName, isLast = false) {
4492
+ function generateFieldModification(collectionName, modification, varName, isLast = false, collectionIdMap) {
4435
4493
  const lines = [];
4436
4494
  const collectionVar = varName || `collection_${collectionName}_${modification.fieldName}`;
4437
4495
  const fieldVar = `${collectionVar}_field`;
@@ -4446,7 +4504,14 @@ function generateFieldModification(collectionName, modification, varName, isLast
4446
4504
  const relationKey = change.property.replace("relation.", "");
4447
4505
  if (relationKey === "collection") {
4448
4506
  const isUsersCollection = String(change.newValue).toLowerCase() === "users";
4449
- const collectionIdValue = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${change.newValue}").id`;
4507
+ let collectionIdValue;
4508
+ if (isUsersCollection) {
4509
+ collectionIdValue = '"_pb_users_auth_"';
4510
+ } else if (collectionIdMap && collectionIdMap.has(String(change.newValue))) {
4511
+ collectionIdValue = `"${collectionIdMap.get(String(change.newValue))}"`;
4512
+ } else {
4513
+ collectionIdValue = `app.findCollectionByNameOrId("${change.newValue}").id`;
4514
+ }
4450
4515
  lines.push(` ${fieldVar}.collectionId = ${collectionIdValue};`);
4451
4516
  } else {
4452
4517
  lines.push(` ${fieldVar}.${relationKey} = ${formatValue(change.newValue)};`);
@@ -4462,11 +4527,9 @@ function generateFieldModification(collectionName, modification, varName, isLast
4462
4527
  function generateFieldDeletion(collectionName, fieldName, varName, isLast = false) {
4463
4528
  const lines = [];
4464
4529
  const collectionVar = varName || `collection_${collectionName}_${fieldName}`;
4465
- const fieldVar = `${collectionVar}_field`;
4466
4530
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
4467
- lines.push(` const ${fieldVar} = ${collectionVar}.fields.getByName("${fieldName}");`);
4468
4531
  lines.push(``);
4469
- lines.push(` ${collectionVar}.fields.remove(${fieldVar}.id);`);
4532
+ lines.push(` ${collectionVar}.fields.removeByName("${fieldName}");`);
4470
4533
  lines.push(``);
4471
4534
  lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
4472
4535
  return lines.join("\n");
@@ -4524,9 +4587,10 @@ function generateOperationUpMigration(operation, collectionIdMap) {
4524
4587
  const collectionName = typeof operation.collection === "string" ? operation.collection : operation.collection?.name ?? modification.collection;
4525
4588
  let operationCount = 0;
4526
4589
  const totalOperations = modification.fieldsToAdd.length + modification.fieldsToModify.length + modification.fieldsToRemove.length + modification.indexesToAdd.length + modification.indexesToRemove.length + modification.rulesToUpdate.length + modification.permissionsToUpdate.length;
4527
- for (const field of modification.fieldsToAdd) {
4590
+ for (let i = 0; i < modification.fieldsToAdd.length; i++) {
4591
+ const field = modification.fieldsToAdd[i];
4528
4592
  operationCount++;
4529
- const varName = `collection_${collectionName}_add_${field.name}`;
4593
+ const varName = `collection_${collectionName}_add_${field.name}_${i}`;
4530
4594
  const isLast = operationCount === totalOperations;
4531
4595
  lines.push(generateFieldAddition(collectionName, field, varName, isLast, collectionIdMap));
4532
4596
  if (!isLast) lines.push("");
@@ -4535,7 +4599,7 @@ function generateOperationUpMigration(operation, collectionIdMap) {
4535
4599
  operationCount++;
4536
4600
  const varName = `collection_${collectionName}_modify_${fieldMod.fieldName}`;
4537
4601
  const isLast = operationCount === totalOperations;
4538
- lines.push(generateFieldModification(collectionName, fieldMod, varName, isLast));
4602
+ lines.push(generateFieldModification(collectionName, fieldMod, varName, isLast, collectionIdMap));
4539
4603
  if (!isLast) lines.push("");
4540
4604
  }
4541
4605
  for (const field of modification.fieldsToRemove) {
@@ -4584,20 +4648,23 @@ function generateOperationUpMigration(operation, collectionIdMap) {
4584
4648
  lines.push(generateCollectionDeletion(collectionName, varName, true));
4585
4649
  }
4586
4650
  let code = lines.join("\n");
4587
- const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
4588
- const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
4589
- const saveMatches = [...code.matchAll(savePattern)];
4590
- const deleteMatches = [...code.matchAll(deletePattern)];
4591
- const allMatches = [
4592
- ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
4593
- ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
4594
- ].sort((a, b) => b.index - a.index);
4595
- if (allMatches.length > 0) {
4596
- const lastMatch = allMatches[0];
4597
- if (lastMatch.type === "save") {
4598
- 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);
4599
- } else {
4600
- 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);
4651
+ const hasReturnStatement = /return\s+app\.(save|delete)\(/m.test(code);
4652
+ if (!hasReturnStatement) {
4653
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
4654
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
4655
+ const saveMatches = [...code.matchAll(savePattern)];
4656
+ const deleteMatches = [...code.matchAll(deletePattern)];
4657
+ const allMatches = [
4658
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
4659
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
4660
+ ].sort((a, b) => b.index - a.index);
4661
+ if (allMatches.length > 0) {
4662
+ const lastMatch = allMatches[0];
4663
+ if (lastMatch.type === "save") {
4664
+ 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);
4665
+ } else {
4666
+ 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);
4667
+ }
4601
4668
  }
4602
4669
  }
4603
4670
  return code;
@@ -4686,20 +4753,23 @@ function generateOperationDownMigration(operation, collectionIdMap) {
4686
4753
  }
4687
4754
  }
4688
4755
  let code = lines.join("\n");
4689
- const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
4690
- const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
4691
- const saveMatches = [...code.matchAll(savePattern)];
4692
- const deleteMatches = [...code.matchAll(deletePattern)];
4693
- const allMatches = [
4694
- ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
4695
- ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
4696
- ].sort((a, b) => b.index - a.index);
4697
- if (allMatches.length > 0) {
4698
- const lastMatch = allMatches[0];
4699
- if (lastMatch.type === "save") {
4700
- 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);
4701
- } else {
4702
- 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);
4756
+ const hasReturnStatement = /return\s+app\.(save|delete)\(/m.test(code);
4757
+ if (!hasReturnStatement) {
4758
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
4759
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
4760
+ const saveMatches = [...code.matchAll(savePattern)];
4761
+ const deleteMatches = [...code.matchAll(deletePattern)];
4762
+ const allMatches = [
4763
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
4764
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
4765
+ ].sort((a, b) => b.index - a.index);
4766
+ if (allMatches.length > 0) {
4767
+ const lastMatch = allMatches[0];
4768
+ if (lastMatch.type === "save") {
4769
+ 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);
4770
+ } else {
4771
+ 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);
4772
+ }
4703
4773
  }
4704
4774
  }
4705
4775
  return code;
@@ -4714,6 +4784,11 @@ function generateUpMigration(diff) {
4714
4784
  collectionIdMap.set(collection.name, collection.id);
4715
4785
  }
4716
4786
  }
4787
+ if (diff.existingCollectionIds) {
4788
+ for (const [name, id] of diff.existingCollectionIds) {
4789
+ collectionIdMap.set(name, id);
4790
+ }
4791
+ }
4717
4792
  if (diff.collectionsToCreate.length > 0) {
4718
4793
  lines.push(` // Create new collections`);
4719
4794
  for (let i = 0; i < diff.collectionsToCreate.length; i++) {
@@ -4729,8 +4804,9 @@ function generateUpMigration(diff) {
4729
4804
  const collectionName = modification.collection;
4730
4805
  if (modification.fieldsToAdd.length > 0) {
4731
4806
  lines.push(` // Add fields to ${collectionName}`);
4732
- for (const field of modification.fieldsToAdd) {
4733
- const varName = `collection_${collectionName}_add_${field.name}`;
4807
+ for (let i = 0; i < modification.fieldsToAdd.length; i++) {
4808
+ const field = modification.fieldsToAdd[i];
4809
+ const varName = `collection_${collectionName}_add_${field.name}_${i}`;
4734
4810
  lines.push(generateFieldAddition(collectionName, field, varName, false, collectionIdMap));
4735
4811
  lines.push(``);
4736
4812
  }
@@ -4739,7 +4815,7 @@ function generateUpMigration(diff) {
4739
4815
  lines.push(` // Modify fields in ${collectionName}`);
4740
4816
  for (const fieldMod of modification.fieldsToModify) {
4741
4817
  const varName = `collection_${collectionName}_modify_${fieldMod.fieldName}`;
4742
- lines.push(generateFieldModification(collectionName, fieldMod, varName));
4818
+ lines.push(generateFieldModification(collectionName, fieldMod, varName, false, collectionIdMap));
4743
4819
  lines.push(``);
4744
4820
  }
4745
4821
  }
@@ -4800,20 +4876,23 @@ function generateUpMigration(diff) {
4800
4876
  lines.push(``);
4801
4877
  }
4802
4878
  let code = lines.join("\n");
4803
- const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
4804
- const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
4805
- const saveMatches = [...code.matchAll(savePattern)];
4806
- const deleteMatches = [...code.matchAll(deletePattern)];
4807
- const allMatches = [
4808
- ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
4809
- ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
4810
- ].sort((a, b) => b.index - a.index);
4811
- if (allMatches.length > 0) {
4812
- const lastMatch = allMatches[0];
4813
- if (lastMatch.type === "save") {
4814
- 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);
4815
- } else {
4816
- 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);
4879
+ const hasReturnStatement = /return\s+app\.(save|delete)\(/m.test(code);
4880
+ if (!hasReturnStatement) {
4881
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
4882
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
4883
+ const saveMatches = [...code.matchAll(savePattern)];
4884
+ const deleteMatches = [...code.matchAll(deletePattern)];
4885
+ const allMatches = [
4886
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
4887
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
4888
+ ].sort((a, b) => b.index - a.index);
4889
+ if (allMatches.length > 0) {
4890
+ const lastMatch = allMatches[0];
4891
+ if (lastMatch.type === "save") {
4892
+ 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);
4893
+ } else {
4894
+ 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);
4895
+ }
4817
4896
  }
4818
4897
  }
4819
4898
  return code;
@@ -4833,6 +4912,11 @@ function generateDownMigration(diff) {
4833
4912
  collectionIdMap.set(collection.name, collection.id);
4834
4913
  }
4835
4914
  }
4915
+ if (diff.existingCollectionIds) {
4916
+ for (const [name, id] of diff.existingCollectionIds) {
4917
+ collectionIdMap.set(name, id);
4918
+ }
4919
+ }
4836
4920
  if (diff.collectionsToDelete.length > 0) {
4837
4921
  lines.push(` // Recreate deleted collections`);
4838
4922
  for (let i = 0; i < diff.collectionsToDelete.length; i++) {
@@ -4930,20 +5014,23 @@ function generateDownMigration(diff) {
4930
5014
  lines.push(``);
4931
5015
  }
4932
5016
  let code = lines.join("\n");
4933
- const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
4934
- const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
4935
- const saveMatches = [...code.matchAll(savePattern)];
4936
- const deleteMatches = [...code.matchAll(deletePattern)];
4937
- const allMatches = [
4938
- ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
4939
- ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
4940
- ].sort((a, b) => b.index - a.index);
4941
- if (allMatches.length > 0) {
4942
- const lastMatch = allMatches[0];
4943
- if (lastMatch.type === "save") {
4944
- 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);
4945
- } else {
4946
- 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);
5017
+ const hasReturnStatement = /return\s+app\.(save|delete)\(/m.test(code);
5018
+ if (!hasReturnStatement) {
5019
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
5020
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
5021
+ const saveMatches = [...code.matchAll(savePattern)];
5022
+ const deleteMatches = [...code.matchAll(deletePattern)];
5023
+ const allMatches = [
5024
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
5025
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
5026
+ ].sort((a, b) => b.index - a.index);
5027
+ if (allMatches.length > 0) {
5028
+ const lastMatch = allMatches[0];
5029
+ if (lastMatch.type === "save") {
5030
+ 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);
5031
+ } else {
5032
+ 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);
5033
+ }
4947
5034
  }
4948
5035
  }
4949
5036
  return code;
@@ -4967,6 +5054,11 @@ function generate(diff, config) {
4967
5054
  collectionIdMap.set(collection.name, collection.id);
4968
5055
  }
4969
5056
  }
5057
+ if (diff.existingCollectionIds) {
5058
+ for (const [name, id] of diff.existingCollectionIds) {
5059
+ collectionIdMap.set(name, id);
5060
+ }
5061
+ }
4970
5062
  const baseTimestamp = generateTimestamp(normalizedConfig);
4971
5063
  const operations = splitDiffByCollection(diff, baseTimestamp);
4972
5064
  const filePaths = [];