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
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-UcOPu1OQ.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-YoBjsa-A.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-CVxPCgWX.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-DrQmtznD.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-UcOPu1OQ.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-Ds3NQvny.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-Dfp-NP2D.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-n231Fspm.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));
@@ -2470,7 +2519,7 @@ var SchemaAnalyzer = class {
2470
2519
  var SNAPSHOT_VERSION = "1.0.0";
2471
2520
  function resolveCollectionIdToName(collectionId) {
2472
2521
  if (collectionId === "_pb_users_auth_") {
2473
- return "Users";
2522
+ return "users";
2474
2523
  }
2475
2524
  const nameMatch = collectionId.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
2476
2525
  if (nameMatch) {
@@ -2478,6 +2527,39 @@ function resolveCollectionIdToName(collectionId) {
2478
2527
  }
2479
2528
  return collectionId;
2480
2529
  }
2530
+ function extractFieldOptions2(pbField) {
2531
+ const options = {};
2532
+ if (pbField.options && typeof pbField.options === "object") {
2533
+ Object.assign(options, pbField.options);
2534
+ }
2535
+ const directOptionKeys = [
2536
+ "min",
2537
+ "max",
2538
+ "pattern",
2539
+ "noDecimal",
2540
+ // text/number fields
2541
+ "values",
2542
+ "maxSelect",
2543
+ // select fields
2544
+ "mimeTypes",
2545
+ "maxSize",
2546
+ "thumbs",
2547
+ "protected",
2548
+ // file fields
2549
+ "onCreate",
2550
+ "onUpdate",
2551
+ // autodate fields
2552
+ "exceptDomains",
2553
+ "onlyDomains"
2554
+ // email/url fields
2555
+ ];
2556
+ for (const key of directOptionKeys) {
2557
+ if (pbField[key] !== void 0) {
2558
+ options[key] = pbField[key];
2559
+ }
2560
+ }
2561
+ return options;
2562
+ }
2481
2563
  function convertPocketBaseCollection(pbCollection) {
2482
2564
  const fields = [];
2483
2565
  const systemFieldNames = ["id", "created", "updated", "collectionId", "collectionName", "expand"];
@@ -2495,23 +2577,19 @@ function convertPocketBaseCollection(pbCollection) {
2495
2577
  type: pbField.type,
2496
2578
  required: pbField.required || false
2497
2579
  };
2498
- field.options = pbField.options ? { ...pbField.options } : {};
2499
- if (pbField.type === "select") {
2500
- if (pbField.values && Array.isArray(pbField.values)) {
2501
- field.options.values = pbField.values;
2502
- } else if (pbField.options?.values && Array.isArray(pbField.options.values)) {
2503
- field.options.values = pbField.options.values;
2504
- }
2505
- }
2580
+ field.options = extractFieldOptions2(pbField);
2506
2581
  if (pbField.type === "relation") {
2507
2582
  const collectionId = pbField.collectionId || pbField.options?.collectionId || "";
2508
- const collectionName = resolveCollectionIdToName(collectionId);
2583
+ const collectionName = resolveCollectionIdToName(collectionId || "");
2509
2584
  field.relation = {
2510
2585
  collection: collectionName,
2511
2586
  cascadeDelete: pbField.cascadeDelete ?? pbField.options?.cascadeDelete ?? false,
2512
2587
  maxSelect: pbField.maxSelect ?? pbField.options?.maxSelect,
2513
2588
  minSelect: pbField.minSelect ?? pbField.options?.minSelect
2514
2589
  };
2590
+ delete field.options.maxSelect;
2591
+ delete field.options.minSelect;
2592
+ delete field.options.cascadeDelete;
2515
2593
  }
2516
2594
  const hasOnlyValues = Object.keys(field.options).length === 1 && field.options.values !== void 0;
2517
2595
  if (Object.keys(field.options).length === 0) {
@@ -2525,17 +2603,21 @@ function convertPocketBaseCollection(pbCollection) {
2525
2603
  type: pbCollection.type || "base",
2526
2604
  fields
2527
2605
  };
2606
+ if (pbCollection.id) {
2607
+ schema.id = pbCollection.id;
2608
+ }
2528
2609
  if (pbCollection.indexes && Array.isArray(pbCollection.indexes)) {
2529
2610
  schema.indexes = pbCollection.indexes;
2530
2611
  }
2531
- const rules = {};
2532
- if (pbCollection.listRule !== void 0) rules.listRule = pbCollection.listRule;
2533
- if (pbCollection.viewRule !== void 0) rules.viewRule = pbCollection.viewRule;
2534
- if (pbCollection.createRule !== void 0) rules.createRule = pbCollection.createRule;
2535
- if (pbCollection.updateRule !== void 0) rules.updateRule = pbCollection.updateRule;
2536
- if (pbCollection.deleteRule !== void 0) rules.deleteRule = pbCollection.deleteRule;
2537
- if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
2538
- if (Object.keys(rules).length > 0) {
2612
+ 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;
2613
+ if (hasAnyRule) {
2614
+ const rules = {};
2615
+ if (pbCollection.listRule !== void 0) rules.listRule = pbCollection.listRule;
2616
+ if (pbCollection.viewRule !== void 0) rules.viewRule = pbCollection.viewRule;
2617
+ if (pbCollection.createRule !== void 0) rules.createRule = pbCollection.createRule;
2618
+ if (pbCollection.updateRule !== void 0) rules.updateRule = pbCollection.updateRule;
2619
+ if (pbCollection.deleteRule !== void 0) rules.deleteRule = pbCollection.deleteRule;
2620
+ if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
2539
2621
  schema.rules = rules;
2540
2622
  schema.permissions = { ...rules };
2541
2623
  }
@@ -3285,17 +3367,19 @@ var CollectionIdRegistry = class {
3285
3367
  }
3286
3368
  /**
3287
3369
  * Generates a unique collection ID for a given collection name
3288
- * Special case: Returns constant "_pb_users_auth_" for users collection
3289
3370
  * Retries up to 10 times if collision occurs (extremely rare)
3371
+ * Special case: returns "_pb_users_auth_" for users collection
3290
3372
  *
3291
- * @param collectionName - The name of the collection
3373
+ * @param collectionName - The name of the collection (optional)
3292
3374
  * @returns A unique collection ID
3293
3375
  * @throws Error if unable to generate unique ID after max attempts
3294
3376
  */
3295
3377
  generate(collectionName) {
3296
3378
  if (collectionName && collectionName.toLowerCase() === "users") {
3297
3379
  const usersId = "_pb_users_auth_";
3298
- this.register(usersId);
3380
+ if (!this.has(usersId)) {
3381
+ this.register(usersId);
3382
+ }
3299
3383
  return usersId;
3300
3384
  }
3301
3385
  const maxAttempts = 10;
@@ -3479,18 +3563,49 @@ function compareFieldConstraints(currentField, previousField) {
3479
3563
  }
3480
3564
  return changes;
3481
3565
  }
3566
+ function normalizeOptionValue(key, value, fieldType) {
3567
+ if (key === "maxSelect" && value === 1 && (fieldType === "select" || fieldType === "file")) {
3568
+ return void 0;
3569
+ }
3570
+ if (key === "maxSize" && value === 0 && fieldType === "file") {
3571
+ return void 0;
3572
+ }
3573
+ if (fieldType === "file") {
3574
+ if (key === "mimeTypes" && Array.isArray(value) && value.length === 0) {
3575
+ return void 0;
3576
+ }
3577
+ if (key === "thumbs" && Array.isArray(value) && value.length === 0) {
3578
+ return void 0;
3579
+ }
3580
+ if (key === "protected" && value === false) {
3581
+ return void 0;
3582
+ }
3583
+ }
3584
+ if (fieldType === "autodate") {
3585
+ if (key === "onCreate" && value === true) {
3586
+ return void 0;
3587
+ }
3588
+ if (key === "onUpdate" && value === false) {
3589
+ return void 0;
3590
+ }
3591
+ }
3592
+ return value;
3593
+ }
3482
3594
  function compareFieldOptions(currentField, previousField) {
3483
3595
  const changes = [];
3484
3596
  const currentOptions = currentField.options || {};
3485
3597
  const previousOptions = previousField.options || {};
3486
3598
  const allKeys = /* @__PURE__ */ new Set([...Object.keys(currentOptions), ...Object.keys(previousOptions)]);
3599
+ const fieldType = currentField.type;
3487
3600
  for (const key of allKeys) {
3488
3601
  const currentValue = currentOptions[key];
3489
3602
  const previousValue = previousOptions[key];
3490
- if (currentValue === void 0 && previousValue === void 0) {
3603
+ const normalizedCurrent = normalizeOptionValue(key, currentValue, fieldType);
3604
+ const normalizedPrevious = normalizeOptionValue(key, previousValue, fieldType);
3605
+ if (normalizedCurrent === void 0 && normalizedPrevious === void 0) {
3491
3606
  continue;
3492
3607
  }
3493
- if (!areValuesEqual(currentValue, previousValue)) {
3608
+ if (!areValuesEqual(normalizedCurrent, normalizedPrevious)) {
3494
3609
  changes.push({
3495
3610
  property: `options.${key}`,
3496
3611
  oldValue: previousValue,
@@ -3500,7 +3615,7 @@ function compareFieldOptions(currentField, previousField) {
3500
3615
  }
3501
3616
  return changes;
3502
3617
  }
3503
- function compareRelationConfigurations(currentField, previousField) {
3618
+ function compareRelationConfigurations(currentField, previousField, collectionIdToName) {
3504
3619
  const changes = [];
3505
3620
  const currentRelation = currentField.relation;
3506
3621
  const previousRelation = previousField.relation;
@@ -3512,8 +3627,8 @@ function compareRelationConfigurations(currentField, previousField) {
3512
3627
  }
3513
3628
  const normalizeCollection = (collection) => {
3514
3629
  if (!collection) return collection;
3515
- if (collection === "_pb_users_auth_") {
3516
- return "Users";
3630
+ if (collectionIdToName && collectionIdToName.has(collection)) {
3631
+ return collectionIdToName.get(collection);
3517
3632
  }
3518
3633
  const nameMatch = collection.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
3519
3634
  if (nameMatch) {
@@ -3523,13 +3638,11 @@ function compareRelationConfigurations(currentField, previousField) {
3523
3638
  };
3524
3639
  const normalizedCurrent = normalizeCollection(currentRelation.collection);
3525
3640
  const normalizedPrevious = normalizeCollection(previousRelation.collection);
3526
- if (normalizedCurrent !== normalizedPrevious) {
3641
+ if (normalizedCurrent.toLowerCase() !== normalizedPrevious.toLowerCase()) {
3527
3642
  changes.push({
3528
3643
  property: "relation.collection",
3529
- oldValue: normalizedPrevious,
3530
- // Use normalized value for clarity
3531
- newValue: normalizedCurrent
3532
- // Use normalized value for clarity
3644
+ oldValue: previousRelation.collection,
3645
+ newValue: currentRelation.collection
3533
3646
  });
3534
3647
  }
3535
3648
  if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {
@@ -3539,14 +3652,20 @@ function compareRelationConfigurations(currentField, previousField) {
3539
3652
  newValue: currentRelation.cascadeDelete
3540
3653
  });
3541
3654
  }
3542
- if (currentRelation.maxSelect !== previousRelation.maxSelect) {
3655
+ const normalizeMax = (val) => val === 1 ? null : val;
3656
+ const currentMax = normalizeMax(currentRelation.maxSelect);
3657
+ const previousMax = normalizeMax(previousRelation.maxSelect);
3658
+ if (currentMax != previousMax) {
3543
3659
  changes.push({
3544
3660
  property: "relation.maxSelect",
3545
3661
  oldValue: previousRelation.maxSelect,
3546
3662
  newValue: currentRelation.maxSelect
3547
3663
  });
3548
3664
  }
3549
- if (currentRelation.minSelect !== previousRelation.minSelect) {
3665
+ const normalizeMin = (val) => val === 0 ? null : val;
3666
+ const currentMin = normalizeMin(currentRelation.minSelect);
3667
+ const previousMin = normalizeMin(previousRelation.minSelect);
3668
+ if (currentMin != previousMin) {
3550
3669
  changes.push({
3551
3670
  property: "relation.minSelect",
3552
3671
  oldValue: previousRelation.minSelect,
@@ -3555,7 +3674,7 @@ function compareRelationConfigurations(currentField, previousField) {
3555
3674
  }
3556
3675
  return changes;
3557
3676
  }
3558
- function detectFieldChanges(currentField, previousField) {
3677
+ function detectFieldChanges(currentField, previousField, collectionIdToName) {
3559
3678
  const changes = [];
3560
3679
  const typeChange = compareFieldTypes(currentField, previousField);
3561
3680
  if (typeChange) {
@@ -3564,7 +3683,7 @@ function detectFieldChanges(currentField, previousField) {
3564
3683
  changes.push(...compareFieldConstraints(currentField, previousField));
3565
3684
  changes.push(...compareFieldOptions(currentField, previousField));
3566
3685
  if (currentField.type === "relation" && previousField.type === "relation") {
3567
- changes.push(...compareRelationConfigurations(currentField, previousField));
3686
+ changes.push(...compareRelationConfigurations(currentField, previousField, collectionIdToName));
3568
3687
  }
3569
3688
  return changes;
3570
3689
  }
@@ -3575,7 +3694,7 @@ function compareIndexes(currentIndexes = [], previousIndexes = []) {
3575
3694
  const indexesToRemove = previousIndexes.filter((idx) => !currentSet.has(idx));
3576
3695
  return { indexesToAdd, indexesToRemove };
3577
3696
  }
3578
- function compareRules(currentRules, previousRules) {
3697
+ function compareRules(currentRules, previousRules, currentPermissions, previousPermissions) {
3579
3698
  const updates = [];
3580
3699
  const ruleTypes = [
3581
3700
  "listRule",
@@ -3586,8 +3705,8 @@ function compareRules(currentRules, previousRules) {
3586
3705
  "manageRule"
3587
3706
  ];
3588
3707
  for (const ruleType of ruleTypes) {
3589
- const currentValue = currentRules?.[ruleType] ?? null;
3590
- const previousValue = previousRules?.[ruleType] ?? null;
3708
+ const currentValue = currentRules?.[ruleType] ?? currentPermissions?.[ruleType] ?? null;
3709
+ const previousValue = previousRules?.[ruleType] ?? previousPermissions?.[ruleType] ?? null;
3591
3710
  if (currentValue !== previousValue) {
3592
3711
  updates.push({
3593
3712
  ruleType,
@@ -3614,7 +3733,7 @@ function comparePermissions(currentPermissions, previousPermissions) {
3614
3733
  }
3615
3734
  return changes;
3616
3735
  }
3617
- function compareCollectionFields(currentCollection, previousCollection, config) {
3736
+ function compareCollectionFields(currentCollection, previousCollection, config, collectionIdToName) {
3618
3737
  let fieldsToAdd = findNewFields(currentCollection.fields, previousCollection.fields);
3619
3738
  const fieldsToRemove = findRemovedFields(currentCollection.fields, previousCollection.fields);
3620
3739
  const fieldsToModify = [];
@@ -3624,7 +3743,7 @@ function compareCollectionFields(currentCollection, previousCollection, config)
3624
3743
  }
3625
3744
  const matchedFields = matchFieldsByName(currentCollection.fields, previousCollection.fields);
3626
3745
  for (const [currentField, previousField] of matchedFields) {
3627
- const changes = detectFieldChanges(currentField, previousField);
3746
+ const changes = detectFieldChanges(currentField, previousField, collectionIdToName);
3628
3747
  if (changes.length > 0) {
3629
3748
  fieldsToModify.push({
3630
3749
  fieldName: currentField.name,
@@ -3636,14 +3755,20 @@ function compareCollectionFields(currentCollection, previousCollection, config)
3636
3755
  }
3637
3756
  return { fieldsToAdd, fieldsToRemove, fieldsToModify };
3638
3757
  }
3639
- function buildCollectionModification(currentCollection, previousCollection, config) {
3758
+ function buildCollectionModification(currentCollection, previousCollection, config, collectionIdToName) {
3640
3759
  const { fieldsToAdd, fieldsToRemove, fieldsToModify } = compareCollectionFields(
3641
3760
  currentCollection,
3642
3761
  previousCollection,
3643
- config
3762
+ config,
3763
+ collectionIdToName
3644
3764
  );
3645
3765
  const { indexesToAdd, indexesToRemove } = compareIndexes(currentCollection.indexes, previousCollection.indexes);
3646
- const rulesToUpdate = compareRules(currentCollection.rules, previousCollection.rules);
3766
+ const rulesToUpdate = compareRules(
3767
+ currentCollection.rules,
3768
+ previousCollection.rules,
3769
+ currentCollection.permissions,
3770
+ previousCollection.permissions
3771
+ );
3647
3772
  const permissionsToUpdate = comparePermissions(currentCollection.permissions, previousCollection.permissions);
3648
3773
  return {
3649
3774
  collection: currentCollection.name,
@@ -3660,6 +3785,14 @@ function hasChanges(modification) {
3660
3785
  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;
3661
3786
  }
3662
3787
  function aggregateChanges(currentSchema, previousSnapshot, config) {
3788
+ const collectionIdToName = /* @__PURE__ */ new Map();
3789
+ if (previousSnapshot) {
3790
+ for (const [name, collection] of previousSnapshot.collections) {
3791
+ if (collection.id) {
3792
+ collectionIdToName.set(collection.id, name);
3793
+ }
3794
+ }
3795
+ }
3663
3796
  const collectionsToCreate = findNewCollections(currentSchema, previousSnapshot);
3664
3797
  const collectionsToDelete = findRemovedCollections(currentSchema, previousSnapshot);
3665
3798
  const filteredCollectionsToCreate = collectionsToCreate.filter(
@@ -3683,7 +3816,7 @@ function aggregateChanges(currentSchema, previousSnapshot, config) {
3683
3816
  const collectionsToModify = [];
3684
3817
  const matchedCollections = matchCollectionsByName(currentSchema, previousSnapshot);
3685
3818
  for (const [currentCollection, previousCollection] of matchedCollections) {
3686
- const modification = buildCollectionModification(currentCollection, previousCollection, config);
3819
+ const modification = buildCollectionModification(currentCollection, previousCollection, config, collectionIdToName);
3687
3820
  if (hasChanges(modification)) {
3688
3821
  collectionsToModify.push(modification);
3689
3822
  }
@@ -4084,7 +4217,7 @@ function formatValue(value) {
4084
4217
  return JSON.stringify(value).replace(/","/g, '", "');
4085
4218
  }
4086
4219
  if (typeof value === "object") {
4087
- const entries = Object.entries(value).map(([k, v]) => `${k}: ${formatValue(v)}`).join(", ");
4220
+ const entries = Object.entries(value).filter(([_k, v]) => v !== void 0).map(([k, v]) => `${k}: ${formatValue(v)}`).join(", ");
4088
4221
  return `{ ${entries} }`;
4089
4222
  }
4090
4223
  return String(value);
@@ -4253,6 +4386,9 @@ function getSystemFields() {
4253
4386
  function generateCollectionCreation(collection, varName = "collection", isLast = false, collectionIdMap) {
4254
4387
  const lines = [];
4255
4388
  lines.push(` const ${varName} = new Collection({`);
4389
+ if (collection.id) {
4390
+ lines.push(` id: ${formatValue(collection.id)},`);
4391
+ }
4256
4392
  lines.push(` name: "${collection.name}",`);
4257
4393
  lines.push(` type: "${collection.type}",`);
4258
4394
  const permissionsCode = generateCollectionPermissions(collection.permissions);
@@ -4375,11 +4511,9 @@ function generateFieldModification(collectionName, modification, varName, isLast
4375
4511
  function generateFieldDeletion(collectionName, fieldName, varName, isLast = false) {
4376
4512
  const lines = [];
4377
4513
  const collectionVar = varName || `collection_${collectionName}_${fieldName}`;
4378
- const fieldVar = `${collectionVar}_field`;
4379
4514
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
4380
- lines.push(` const ${fieldVar} = ${collectionVar}.fields.getByName("${fieldName}");`);
4381
4515
  lines.push(``);
4382
- lines.push(` ${collectionVar}.fields.remove(${fieldVar}.id);`);
4516
+ lines.push(` ${collectionVar}.fields.removeByName("${fieldName}");`);
4383
4517
  lines.push(``);
4384
4518
  lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
4385
4519
  return lines.join("\n");
@@ -4496,7 +4630,27 @@ function generateOperationUpMigration(operation, collectionIdMap) {
4496
4630
  const varName = `collection_${collectionName}`;
4497
4631
  lines.push(generateCollectionDeletion(collectionName, varName, true));
4498
4632
  }
4499
- return lines.join("\n");
4633
+ let code = lines.join("\n");
4634
+ const hasReturnStatement = /return\s+app\.(save|delete)\(/m.test(code);
4635
+ if (!hasReturnStatement) {
4636
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
4637
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
4638
+ const saveMatches = [...code.matchAll(savePattern)];
4639
+ const deleteMatches = [...code.matchAll(deletePattern)];
4640
+ const allMatches = [
4641
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
4642
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
4643
+ ].sort((a, b) => b.index - a.index);
4644
+ if (allMatches.length > 0) {
4645
+ const lastMatch = allMatches[0];
4646
+ if (lastMatch.type === "save") {
4647
+ 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);
4648
+ } else {
4649
+ 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);
4650
+ }
4651
+ }
4652
+ }
4653
+ return code;
4500
4654
  }
4501
4655
  function generateOperationDownMigration(operation, collectionIdMap) {
4502
4656
  const lines = [];
@@ -4581,7 +4735,27 @@ function generateOperationDownMigration(operation, collectionIdMap) {
4581
4735
  lines.push(generateCollectionCreation(collection, varName, true, collectionIdMap));
4582
4736
  }
4583
4737
  }
4584
- return lines.join("\n");
4738
+ let code = lines.join("\n");
4739
+ const hasReturnStatement = /return\s+app\.(save|delete)\(/m.test(code);
4740
+ if (!hasReturnStatement) {
4741
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
4742
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
4743
+ const saveMatches = [...code.matchAll(savePattern)];
4744
+ const deleteMatches = [...code.matchAll(deletePattern)];
4745
+ const allMatches = [
4746
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
4747
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
4748
+ ].sort((a, b) => b.index - a.index);
4749
+ if (allMatches.length > 0) {
4750
+ const lastMatch = allMatches[0];
4751
+ if (lastMatch.type === "save") {
4752
+ 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);
4753
+ } else {
4754
+ 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);
4755
+ }
4756
+ }
4757
+ }
4758
+ return code;
4585
4759
  }
4586
4760
  function generateUpMigration(diff) {
4587
4761
  const lines = [];
@@ -4679,20 +4853,23 @@ function generateUpMigration(diff) {
4679
4853
  lines.push(``);
4680
4854
  }
4681
4855
  let code = lines.join("\n");
4682
- const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
4683
- const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
4684
- const saveMatches = [...code.matchAll(savePattern)];
4685
- const deleteMatches = [...code.matchAll(deletePattern)];
4686
- const allMatches = [
4687
- ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
4688
- ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
4689
- ].sort((a, b) => b.index - a.index);
4690
- if (allMatches.length > 0) {
4691
- const lastMatch = allMatches[0];
4692
- if (lastMatch.type === "save") {
4693
- 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);
4694
- } else {
4695
- 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);
4856
+ const hasReturnStatement = /return\s+app\.(save|delete)\(/m.test(code);
4857
+ if (!hasReturnStatement) {
4858
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
4859
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
4860
+ const saveMatches = [...code.matchAll(savePattern)];
4861
+ const deleteMatches = [...code.matchAll(deletePattern)];
4862
+ const allMatches = [
4863
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
4864
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
4865
+ ].sort((a, b) => b.index - a.index);
4866
+ if (allMatches.length > 0) {
4867
+ const lastMatch = allMatches[0];
4868
+ if (lastMatch.type === "save") {
4869
+ 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);
4870
+ } else {
4871
+ 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);
4872
+ }
4696
4873
  }
4697
4874
  }
4698
4875
  return code;
@@ -4809,20 +4986,23 @@ function generateDownMigration(diff) {
4809
4986
  lines.push(``);
4810
4987
  }
4811
4988
  let code = lines.join("\n");
4812
- const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
4813
- const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
4814
- const saveMatches = [...code.matchAll(savePattern)];
4815
- const deleteMatches = [...code.matchAll(deletePattern)];
4816
- const allMatches = [
4817
- ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
4818
- ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
4819
- ].sort((a, b) => b.index - a.index);
4820
- if (allMatches.length > 0) {
4821
- const lastMatch = allMatches[0];
4822
- if (lastMatch.type === "save") {
4823
- 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);
4824
- } else {
4825
- 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);
4989
+ const hasReturnStatement = /return\s+app\.(save|delete)\(/m.test(code);
4990
+ if (!hasReturnStatement) {
4991
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
4992
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
4993
+ const saveMatches = [...code.matchAll(savePattern)];
4994
+ const deleteMatches = [...code.matchAll(deletePattern)];
4995
+ const allMatches = [
4996
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
4997
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
4998
+ ].sort((a, b) => b.index - a.index);
4999
+ if (allMatches.length > 0) {
5000
+ const lastMatch = allMatches[0];
5001
+ if (lastMatch.type === "save") {
5002
+ 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);
5003
+ } else {
5004
+ 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);
5005
+ }
4826
5006
  }
4827
5007
  }
4828
5008
  return code;