pocketbase-zod-schema 1.0.0 → 1.0.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 (101) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +28 -69
  3. package/dist/cli/migrate.cjs +548 -674
  4. package/dist/cli/migrate.cjs.map +1 -1
  5. package/dist/cli/migrate.js +545 -671
  6. package/dist/cli/migrate.js.map +1 -1
  7. package/dist/index.cjs +37 -555
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.cts +903 -6
  10. package/dist/index.d.ts +903 -6
  11. package/dist/index.js +38 -540
  12. package/dist/index.js.map +1 -1
  13. package/dist/server.cjs +674 -2614
  14. package/dist/server.cjs.map +1 -1
  15. package/dist/server.d.cts +1344 -18
  16. package/dist/server.d.ts +1344 -18
  17. package/dist/server.js +673 -2481
  18. package/dist/server.js.map +1 -1
  19. package/package.json +2 -64
  20. package/dist/cli/index.cjs +0 -7873
  21. package/dist/cli/index.cjs.map +0 -1
  22. package/dist/cli/index.d.cts +0 -32
  23. package/dist/cli/index.d.ts +0 -32
  24. package/dist/cli/index.js +0 -7819
  25. package/dist/cli/index.js.map +0 -1
  26. package/dist/cli/utils/index.cjs +0 -596
  27. package/dist/cli/utils/index.cjs.map +0 -1
  28. package/dist/cli/utils/index.d.cts +0 -282
  29. package/dist/cli/utils/index.d.ts +0 -282
  30. package/dist/cli/utils/index.js +0 -542
  31. package/dist/cli/utils/index.js.map +0 -1
  32. package/dist/enums.cjs +0 -19
  33. package/dist/enums.cjs.map +0 -1
  34. package/dist/enums.d.cts +0 -11
  35. package/dist/enums.d.ts +0 -11
  36. package/dist/enums.js +0 -17
  37. package/dist/enums.js.map +0 -1
  38. package/dist/fields-B96iGprI.d.cts +0 -480
  39. package/dist/fields-B96iGprI.d.ts +0 -480
  40. package/dist/migration/analyzer.cjs +0 -1725
  41. package/dist/migration/analyzer.cjs.map +0 -1
  42. package/dist/migration/analyzer.d.cts +0 -245
  43. package/dist/migration/analyzer.d.ts +0 -245
  44. package/dist/migration/analyzer.js +0 -1684
  45. package/dist/migration/analyzer.js.map +0 -1
  46. package/dist/migration/diff.cjs +0 -943
  47. package/dist/migration/diff.cjs.map +0 -1
  48. package/dist/migration/diff.d.cts +0 -370
  49. package/dist/migration/diff.d.ts +0 -370
  50. package/dist/migration/diff.js +0 -911
  51. package/dist/migration/diff.js.map +0 -1
  52. package/dist/migration/engine.cjs +0 -3263
  53. package/dist/migration/engine.cjs.map +0 -1
  54. package/dist/migration/engine.d.cts +0 -105
  55. package/dist/migration/engine.d.ts +0 -105
  56. package/dist/migration/engine.js +0 -3173
  57. package/dist/migration/engine.js.map +0 -1
  58. package/dist/migration/generator.cjs +0 -1596
  59. package/dist/migration/generator.cjs.map +0 -1
  60. package/dist/migration/generator.d.cts +0 -493
  61. package/dist/migration/generator.d.ts +0 -493
  62. package/dist/migration/generator.js +0 -1529
  63. package/dist/migration/generator.js.map +0 -1
  64. package/dist/migration/index.cjs +0 -8190
  65. package/dist/migration/index.cjs.map +0 -1
  66. package/dist/migration/index.d.cts +0 -193
  67. package/dist/migration/index.d.ts +0 -193
  68. package/dist/migration/index.js +0 -8015
  69. package/dist/migration/index.js.map +0 -1
  70. package/dist/migration/snapshot.cjs +0 -2814
  71. package/dist/migration/snapshot.cjs.map +0 -1
  72. package/dist/migration/snapshot.d.cts +0 -186
  73. package/dist/migration/snapshot.d.ts +0 -186
  74. package/dist/migration/snapshot.js +0 -2779
  75. package/dist/migration/snapshot.js.map +0 -1
  76. package/dist/migration/utils/index.cjs +0 -891
  77. package/dist/migration/utils/index.cjs.map +0 -1
  78. package/dist/migration/utils/index.d.cts +0 -66
  79. package/dist/migration/utils/index.d.ts +0 -66
  80. package/dist/migration/utils/index.js +0 -854
  81. package/dist/migration/utils/index.js.map +0 -1
  82. package/dist/mutator.cjs +0 -355
  83. package/dist/mutator.cjs.map +0 -1
  84. package/dist/mutator.d.cts +0 -164
  85. package/dist/mutator.d.ts +0 -164
  86. package/dist/mutator.js +0 -353
  87. package/dist/mutator.js.map +0 -1
  88. package/dist/schema.cjs +0 -715
  89. package/dist/schema.cjs.map +0 -1
  90. package/dist/schema.d.cts +0 -563
  91. package/dist/schema.d.ts +0 -563
  92. package/dist/schema.js +0 -674
  93. package/dist/schema.js.map +0 -1
  94. package/dist/type-mapper-BSPTj8t5.d.cts +0 -216
  95. package/dist/type-mapper-D31WYDee.d.ts +0 -216
  96. package/dist/types-B_MLb1Ob.d.ts +0 -475
  97. package/dist/types-CnzfX6JH.d.cts +0 -148
  98. package/dist/types-Do3jyFBm.d.ts +0 -148
  99. package/dist/types-upZBVMfb.d.cts +0 -475
  100. package/dist/verify-BF72n2df.d.ts +0 -402
  101. package/dist/verify-DTzYpiXX.d.cts +0 -402
@@ -4,7 +4,7 @@
4
4
  var chalk = require('chalk');
5
5
  var commander = require('commander');
6
6
  var fs10 = require('fs');
7
- var path8 = require('path');
7
+ var path7 = require('path');
8
8
  var url = require('url');
9
9
  var zod = require('zod');
10
10
  var crypto = require('crypto');
@@ -34,7 +34,7 @@ function _interopNamespace(e) {
34
34
 
35
35
  var chalk__default = /*#__PURE__*/_interopDefault(chalk);
36
36
  var fs10__namespace = /*#__PURE__*/_interopNamespace(fs10);
37
- var path8__namespace = /*#__PURE__*/_interopNamespace(path8);
37
+ var path7__namespace = /*#__PURE__*/_interopNamespace(path7);
38
38
  var vm__namespace = /*#__PURE__*/_interopNamespace(vm);
39
39
  var acorn__namespace = /*#__PURE__*/_interopNamespace(acorn);
40
40
  var ora__default = /*#__PURE__*/_interopDefault(ora);
@@ -172,10 +172,10 @@ var FileSystemError = class _FileSystemError extends MigrationError {
172
172
  operation;
173
173
  code;
174
174
  originalError;
175
- constructor(message, path12, operation, code, originalError) {
175
+ constructor(message, path11, operation, code, originalError) {
176
176
  super(message);
177
177
  this.name = "FileSystemError";
178
- this.path = path12;
178
+ this.path = path11;
179
179
  this.operation = operation;
180
180
  this.code = code;
181
181
  this.originalError = originalError;
@@ -250,7 +250,6 @@ var DEFAULT_CONFIG = {
250
250
  "permission-templates.js"
251
251
  ],
252
252
  includeExtensions: [".ts", ".js"],
253
- schemaPatterns: ["Schema", "InputSchema", "Collection"],
254
253
  useCompiledFiles: true
255
254
  };
256
255
  function mergeConfig(config) {
@@ -258,16 +257,15 @@ function mergeConfig(config) {
258
257
  ...DEFAULT_CONFIG,
259
258
  ...config,
260
259
  excludePatterns: config.excludePatterns || DEFAULT_CONFIG.excludePatterns,
261
- includeExtensions: config.includeExtensions || DEFAULT_CONFIG.includeExtensions,
262
- schemaPatterns: config.schemaPatterns || DEFAULT_CONFIG.schemaPatterns
260
+ includeExtensions: config.includeExtensions || DEFAULT_CONFIG.includeExtensions
263
261
  };
264
262
  }
265
263
  function resolveSchemaDir(config) {
266
264
  const workspaceRoot = config.workspaceRoot || process.cwd();
267
- if (path8__namespace.isAbsolute(config.schemaDir)) {
265
+ if (path7__namespace.isAbsolute(config.schemaDir)) {
268
266
  return config.schemaDir;
269
267
  }
270
- return path8__namespace.join(workspaceRoot, config.schemaDir);
268
+ return path7__namespace.join(workspaceRoot, config.schemaDir);
271
269
  }
272
270
  ({
273
271
  id: zod.z.string().describe("unique id"),
@@ -277,17 +275,6 @@ function resolveSchemaDir(config) {
277
275
  created: zod.z.string().describe("creation timestamp"),
278
276
  updated: zod.z.string().describe("last update timestamp")
279
277
  });
280
- ({
281
- created: zod.z.string().describe("creation timestamp"),
282
- updated: zod.z.string().describe("last update timestamp")
283
- });
284
- ({
285
- thumbnailURL: zod.z.string().optional(),
286
- imageFiles: zod.z.array(zod.z.string())
287
- });
288
- ({
289
- imageFiles: zod.z.array(zod.z.instanceof(File))
290
- });
291
278
  var RELATION_METADATA_KEY = "__pocketbase_relation__";
292
279
  function extractRelationMetadata(description) {
293
280
  if (!description) return null;
@@ -501,14 +488,15 @@ var CollectionIdRegistry = class {
501
488
  };
502
489
 
503
490
  // src/migration/rule-validator.ts
491
+ var BACK_RELATION_SEGMENT = /^[a-zA-Z_][a-zA-Z0-9_]*_via_[a-zA-Z_][a-zA-Z0-9_]*$/;
504
492
  var RuleValidator = class {
505
493
  fields;
506
494
  collectionName;
507
495
  isAuthCollection;
508
- constructor(collectionName, fields, isAuthCollection2 = false) {
496
+ constructor(collectionName, fields, isAuthCollection = false) {
509
497
  this.collectionName = collectionName;
510
498
  this.fields = new Map(fields.map((f) => [f.name, f]));
511
- this.isAuthCollection = isAuthCollection2;
499
+ this.isAuthCollection = isAuthCollection;
512
500
  this.addSystemFields();
513
501
  }
514
502
  /**
@@ -576,7 +564,7 @@ var RuleValidator = class {
576
564
  /**
577
565
  * Extract field references from expression
578
566
  *
579
- * Matches field names that are not @request references.
567
+ * Matches field names that are not @request or @collection references.
580
568
  * Handles dot notation for relations: user.email, post.author.name
581
569
  *
582
570
  * @param expression - The rule expression
@@ -586,6 +574,7 @@ var RuleValidator = class {
586
574
  const refs = [];
587
575
  let cleaned = expression2.replace(/"[^"]*"/g, '""').replace(/'[^']*'/g, "''");
588
576
  cleaned = cleaned.replace(/@request\.[a-zA-Z_][a-zA-Z0-9_.]*/g, "");
577
+ cleaned = cleaned.replace(/@collection\.[a-zA-Z_][a-zA-Z0-9_.]*/g, "");
589
578
  const fieldPattern = /(?:^|[^@\w])([a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*)(?=[^a-zA-Z0-9_.]|$)/g;
590
579
  let match;
591
580
  while ((match = fieldPattern.exec(cleaned)) !== null) {
@@ -606,12 +595,26 @@ var RuleValidator = class {
606
595
  const keywords = ["true", "false", "null", "AND", "OR", "NOT", "LIKE", "IN"];
607
596
  return keywords.includes(word.toUpperCase());
608
597
  }
598
+ /**
599
+ * Check whether a path segment is a back-relation rather than a field
600
+ *
601
+ * A declared field wins: a collection may legitimately contain a field
602
+ * literally named `foo_via_bar`, and it should be validated as one.
603
+ *
604
+ * @param segment - A single dot-separated path segment
605
+ * @returns True if the segment should be treated as a back-relation
606
+ */
607
+ isBackRelationSegment(segment) {
608
+ return !this.fields.has(segment) && BACK_RELATION_SEGMENT.test(segment);
609
+ }
609
610
  /**
610
611
  * Validate a field reference exists in schema
611
612
  *
612
- * Checks if the root field exists and validates relation chains.
613
- * For nested references, warns about potential issues since we can't
614
- * validate across collections without loading related schemas.
613
+ * Only the root of the path is checked — the validator holds a single
614
+ * collection's fields, so anything past the first hop belongs to another
615
+ * collection and is accepted as-is. A root back-relation
616
+ * (`Members_via_WorkspaceRef.UserRef`) has no local field to check against
617
+ * either, so it is accepted too; PocketBase resolves it at runtime.
615
618
  *
616
619
  * @param fieldRef - The field reference to validate (e.g., "user" or "user.email")
617
620
  * @param result - The validation result to update
@@ -619,6 +622,9 @@ var RuleValidator = class {
619
622
  validateFieldReference(fieldRef, result) {
620
623
  const parts = fieldRef.split(".");
621
624
  const rootField = parts[0];
625
+ if (this.isBackRelationSegment(rootField)) {
626
+ return;
627
+ }
622
628
  if (!this.fields.has(rootField)) {
623
629
  result.errors.push(`Field '${rootField}' does not exist in collection '${this.collectionName}'`);
624
630
  result.valid = false;
@@ -629,10 +635,6 @@ var RuleValidator = class {
629
635
  if (field.type !== "relation") {
630
636
  result.errors.push(`Field '${rootField}' is not a relation field, cannot access nested property '${parts[1]}'`);
631
637
  result.valid = false;
632
- } else {
633
- result.warnings.push(
634
- `Nested field reference '${fieldRef}' - ensure target collection has field '${parts.slice(1).join(".")}'`
635
- );
636
638
  }
637
639
  }
638
640
  }
@@ -790,11 +792,11 @@ var PermissionAnalyzer = class {
790
792
  * }
791
793
  * ```
792
794
  */
793
- validatePermissions(collectionName, permissions, fields, isAuthCollection2 = false) {
794
- const validator = new RuleValidator(collectionName, fields, isAuthCollection2);
795
+ validatePermissions(collectionName, permissions, fields, isAuthCollection = false) {
796
+ const validator = new RuleValidator(collectionName, fields, isAuthCollection);
795
797
  const results = /* @__PURE__ */ new Map();
796
798
  const ruleTypes = ["listRule", "viewRule", "createRule", "updateRule", "deleteRule"];
797
- if (isAuthCollection2) {
799
+ if (isAuthCollection) {
798
800
  ruleTypes.push("manageRule");
799
801
  }
800
802
  for (const ruleType of ruleTypes) {
@@ -847,146 +849,22 @@ var PermissionAnalyzer = class {
847
849
  };
848
850
  }
849
851
  };
850
-
851
- // src/migration/utils/pluralize.ts
852
- var SPECIAL_CASES = {
853
- // Common irregular plurals
854
- person: "people",
855
- Person: "People",
856
- child: "children",
857
- Child: "Children",
858
- man: "men",
859
- Man: "Men",
860
- woman: "women",
861
- Woman: "Women",
862
- tooth: "teeth",
863
- Tooth: "Teeth",
864
- foot: "feet",
865
- Foot: "Feet",
866
- mouse: "mice",
867
- Mouse: "Mice",
868
- goose: "geese",
869
- Goose: "Geese",
870
- // Words ending in -y
871
- category: "categories",
872
- Category: "Categories",
873
- company: "companies",
874
- Company: "Companies",
875
- city: "cities",
876
- City: "Cities",
877
- country: "countries",
878
- Country: "Countries",
879
- story: "stories",
880
- Story: "Stories",
881
- party: "parties",
882
- Party: "Parties",
883
- family: "families",
884
- Family: "Families",
885
- activity: "activities",
886
- Activity: "Activities",
887
- priority: "priorities",
888
- Priority: "Priorities",
889
- // Words ending in -f or -fe
890
- life: "lives",
891
- Life: "Lives",
892
- wife: "wives",
893
- Wife: "Wives",
894
- knife: "knives",
895
- Knife: "Knives",
896
- leaf: "leaves",
897
- Leaf: "Leaves",
898
- shelf: "shelves",
899
- Shelf: "Shelves",
900
- half: "halves",
901
- Half: "Halves",
902
- // Words ending in -is
903
- analysis: "analyses",
904
- Analysis: "Analyses",
905
- basis: "bases",
906
- Basis: "Bases",
907
- crisis: "crises",
908
- Crisis: "Crises",
909
- thesis: "theses",
910
- Thesis: "Theses",
911
- // Words ending in -us
912
- cactus: "cacti",
913
- Cactus: "Cacti",
914
- focus: "foci",
915
- Focus: "Foci",
916
- fungus: "fungi",
917
- Fungus: "Fungi",
918
- nucleus: "nuclei",
919
- Nucleus: "Nuclei",
920
- radius: "radii",
921
- Radius: "Radii",
922
- // Words ending in -on
923
- phenomenon: "phenomena",
924
- Phenomenon: "Phenomena",
925
- criterion: "criteria",
926
- Criterion: "Criteria",
927
- // Words ending in -um
928
- datum: "data",
929
- Datum: "Data",
930
- medium: "media",
931
- Medium: "Media",
932
- curriculum: "curricula",
933
- Curriculum: "Curricula",
934
- // Unchanged plurals
935
- sheep: "sheep",
936
- Sheep: "Sheep",
937
- deer: "deer",
938
- Deer: "Deer",
939
- fish: "fish",
940
- Fish: "Fish",
941
- species: "species",
942
- Species: "Species",
943
- series: "series",
944
- Series: "Series"
945
- };
946
- function pluralize(singular) {
947
- if (SPECIAL_CASES[singular]) {
948
- return SPECIAL_CASES[singular];
949
- }
950
- if (singular.length > 3 && singular.endsWith("s") && !singular.endsWith("ss")) {
951
- return singular;
952
- }
953
- const lowerSingular = singular.toLowerCase();
954
- let plural;
955
- if (/(?:s|ss|sh|ch|x|z)$/.test(lowerSingular)) {
956
- plural = singular + "es";
957
- } else if (/[^aeiou]y$/.test(lowerSingular)) {
958
- plural = singular.slice(0, -1) + "ies";
959
- } else if (/[^aeiou]o$/.test(lowerSingular)) {
960
- plural = singular + "es";
961
- } else if (/fe?$/.test(lowerSingular)) {
962
- if (lowerSingular.endsWith("fe")) {
963
- plural = singular.slice(0, -2) + "ves";
964
- } else {
965
- plural = singular.slice(0, -1) + "ves";
966
- }
967
- } else {
968
- plural = singular + "s";
969
- }
970
- return plural;
971
- }
972
- function toCollectionName(entityName) {
973
- return pluralize(entityName);
974
- }
975
-
976
- // src/migration/utils/relation-detector.ts
977
- function unwrapType(zodType) {
978
- let unwrappedType = zodType;
979
- if (unwrappedType instanceof zod.z.ZodOptional) {
980
- unwrappedType = unwrappedType.unwrap();
981
- }
982
- if (unwrappedType instanceof zod.z.ZodNullable) {
983
- unwrappedType = unwrappedType.unwrap();
984
- }
985
- if (unwrappedType instanceof zod.z.ZodDefault) {
986
- unwrappedType = unwrappedType.unwrap();
987
- }
988
- return unwrappedType;
989
- }
852
+ var POCKETBASE_FIELD_TYPES = [
853
+ "text",
854
+ "email",
855
+ "url",
856
+ "number",
857
+ "bool",
858
+ "date",
859
+ "select",
860
+ "relation",
861
+ "file",
862
+ "json",
863
+ "editor",
864
+ "geoPoint",
865
+ "autodate",
866
+ "password"
867
+ ];
990
868
  function getChecks(zodType) {
991
869
  const def = zodType.def ?? zodType._def;
992
870
  return def?.checks ?? [];
@@ -999,94 +877,8 @@ function getJsonSchema(zodType) {
999
877
  return null;
1000
878
  }
1001
879
  }
1002
- function isSingleRelationField(fieldName, zodType) {
1003
- const unwrappedType = unwrapType(zodType);
1004
- if (!(unwrappedType instanceof zod.z.ZodString)) {
1005
- return false;
1006
- }
1007
- const startsWithUppercase = /^[A-Z]/.test(fieldName);
1008
- const commonStringFields = ["Title", "Name", "Description", "Content", "Summary", "Status", "Type"];
1009
- const isCommonField = commonStringFields.includes(fieldName);
1010
- return startsWithUppercase && !isCommonField;
1011
- }
1012
- function isMultipleRelationField(fieldName, zodType) {
1013
- const unwrappedType = unwrapType(zodType);
1014
- if (!(unwrappedType instanceof zod.z.ZodArray)) {
1015
- return false;
1016
- }
1017
- const elementType = unwrappedType.element;
1018
- if (!(elementType instanceof zod.z.ZodString)) {
1019
- return false;
1020
- }
1021
- const hasUppercase = /[A-Z]/.test(fieldName);
1022
- return hasUppercase;
1023
- }
1024
- function resolveTargetCollection(fieldName) {
1025
- const matches = fieldName.match(/[A-Z][a-z]+/g);
1026
- if (!matches || matches.length === 0) {
1027
- return pluralize(fieldName);
1028
- }
1029
- const entityName = matches[matches.length - 1];
1030
- return pluralize(entityName);
1031
- }
1032
- function isRelationField(fieldName, zodType) {
1033
- return isSingleRelationField(fieldName, zodType) || isMultipleRelationField(fieldName, zodType);
1034
- }
1035
- function getMaxSelect(fieldName, zodType) {
1036
- if (isSingleRelationField(fieldName, zodType)) {
1037
- return 1;
1038
- }
1039
- if (isMultipleRelationField(fieldName, zodType)) {
1040
- const unwrappedType = unwrapType(zodType);
1041
- if (unwrappedType instanceof zod.z.ZodArray) {
1042
- const checks = getChecks(unwrappedType);
1043
- const maxCheck = checks.find((check) => check.kind === "max");
1044
- if (maxCheck) {
1045
- return maxCheck.value;
1046
- }
1047
- const schema = getJsonSchema(unwrappedType);
1048
- if (schema && typeof schema.maxItems === "number") {
1049
- return schema.maxItems;
1050
- }
1051
- return 999;
1052
- }
1053
- }
1054
- return 1;
1055
- }
1056
- function getMinSelect(fieldName, zodType) {
1057
- if (isSingleRelationField(fieldName, zodType)) {
1058
- return 0;
1059
- }
1060
- if (isMultipleRelationField(fieldName, zodType)) {
1061
- const unwrappedType = unwrapType(zodType);
1062
- if (unwrappedType instanceof zod.z.ZodArray) {
1063
- const checks = getChecks(unwrappedType);
1064
- const minCheck = checks.find((check) => check.kind === "min");
1065
- if (minCheck) {
1066
- return minCheck.value;
1067
- }
1068
- const schema = getJsonSchema(unwrappedType);
1069
- if (schema && typeof schema.minItems === "number") {
1070
- return schema.minItems;
1071
- }
1072
- }
1073
- }
1074
- return 0;
1075
- }
1076
- function getChecks2(zodType) {
1077
- const def = zodType.def ?? zodType._def;
1078
- return def?.checks ?? [];
1079
- }
1080
- function getJsonSchema2(zodType) {
1081
- try {
1082
- const toJSONSchema = zodType.toJSONSchema;
1083
- return typeof toJSONSchema === "function" ? toJSONSchema.call(zodType) : null;
1084
- } catch {
1085
- return null;
1086
- }
1087
- }
1088
880
  function mapZodStringType(zodType) {
1089
- const checks = getChecks2(zodType);
881
+ const checks = getChecks(zodType);
1090
882
  const hasEmail = checks.some((check) => check.kind === "email" || check.def?.format === "email");
1091
883
  if (hasEmail) {
1092
884
  return "email";
@@ -1112,14 +904,11 @@ function mapZodBooleanType(_zodType) {
1112
904
  function mapZodEnumType(_zodType) {
1113
905
  return "select";
1114
906
  }
1115
- function mapZodArrayType(zodType, _fieldName) {
907
+ function mapZodArrayType(zodType) {
1116
908
  const elementType = zodType.element;
1117
909
  if (elementType instanceof zod.z.ZodFile) {
1118
910
  return "file";
1119
911
  }
1120
- if (elementType instanceof zod.z.ZodString) {
1121
- return "relation";
1122
- }
1123
912
  return "json";
1124
913
  }
1125
914
  function mapZodDateType(_zodType) {
@@ -1128,7 +917,7 @@ function mapZodDateType(_zodType) {
1128
917
  function mapZodRecordType(_zodType) {
1129
918
  return "json";
1130
919
  }
1131
- function mapZodTypeToPocketBase(zodType, fieldName) {
920
+ function mapZodTypeToPocketBase(zodType) {
1132
921
  const unwrappedType = unwrapZodType(zodType);
1133
922
  const metadata = extractFieldMetadata(unwrappedType.description);
1134
923
  if (metadata && metadata.type) {
@@ -1158,7 +947,7 @@ function mapZodTypeToPocketBase(zodType, fieldName) {
1158
947
  function extractFieldOptions(zodType) {
1159
948
  const options = {};
1160
949
  const unwrappedType = unwrapZodType(zodType);
1161
- const checks = getChecks2(unwrappedType);
950
+ const checks = getChecks(unwrappedType);
1162
951
  if (unwrappedType instanceof zod.z.ZodString) {
1163
952
  for (const check of checks) {
1164
953
  if (check.kind === "min") {
@@ -1172,7 +961,7 @@ function extractFieldOptions(zodType) {
1172
961
  }
1173
962
  }
1174
963
  if (options.min === void 0 || options.max === void 0 || options.pattern === void 0) {
1175
- const schema = getJsonSchema2(unwrappedType);
964
+ const schema = getJsonSchema(unwrappedType);
1176
965
  if (schema) {
1177
966
  if (options.min === void 0 && typeof schema.minLength === "number") {
1178
967
  options.min = schema.minLength;
@@ -1195,7 +984,7 @@ function extractFieldOptions(zodType) {
1195
984
  options.max = check.value;
1196
985
  }
1197
986
  }
1198
- const schema = getJsonSchema2(unwrappedType);
987
+ const schema = getJsonSchema(unwrappedType);
1199
988
  if (schema) {
1200
989
  if (options.min === void 0 && typeof schema.minimum === "number") {
1201
990
  options.min = schema.minimum;
@@ -1213,7 +1002,7 @@ function extractFieldOptions(zodType) {
1213
1002
  options.values = unwrappedType.options.map(String);
1214
1003
  }
1215
1004
  if (unwrappedType instanceof zod.z.ZodArray) {
1216
- const arrayChecks = getChecks2(unwrappedType);
1005
+ const arrayChecks = getChecks(unwrappedType);
1217
1006
  for (const check of arrayChecks) {
1218
1007
  if (check.kind === "min") {
1219
1008
  options.minSelect = check.value;
@@ -1223,7 +1012,7 @@ function extractFieldOptions(zodType) {
1223
1012
  }
1224
1013
  }
1225
1014
  if (options.minSelect === void 0 || options.maxSelect === void 0) {
1226
- const schema = getJsonSchema2(unwrappedType);
1015
+ const schema = getJsonSchema(unwrappedType);
1227
1016
  if (schema) {
1228
1017
  if (options.minSelect === void 0 && typeof schema.minItems === "number") {
1229
1018
  options.minSelect = schema.minItems;
@@ -1301,6 +1090,39 @@ function filterSupportedFieldOptions(fieldType, options) {
1301
1090
  }
1302
1091
  return Object.keys(filtered).length > 0 ? filtered : void 0;
1303
1092
  }
1093
+ var OPTION_UNSET_VALUES = {
1094
+ pattern: "",
1095
+ autogeneratePattern: "",
1096
+ cost: 0,
1097
+ maxSize: 0,
1098
+ maxSelect: 0,
1099
+ minSelect: 0,
1100
+ primaryKey: false,
1101
+ onlyInt: false,
1102
+ noDecimal: false,
1103
+ convertURLs: false,
1104
+ protected: false,
1105
+ hidden: false,
1106
+ presentable: false,
1107
+ system: false,
1108
+ values: [],
1109
+ mimeTypes: [],
1110
+ thumbs: [],
1111
+ exceptDomains: [],
1112
+ onlyDomains: []
1113
+ };
1114
+ function getFieldOptionUnsetValue(fieldType, key) {
1115
+ if (key === "min" || key === "max") {
1116
+ if (fieldType === "number") {
1117
+ return null;
1118
+ }
1119
+ if (fieldType === "date") {
1120
+ return "";
1121
+ }
1122
+ return 0;
1123
+ }
1124
+ return OPTION_UNSET_VALUES[key];
1125
+ }
1304
1126
  function dedentSql(value) {
1305
1127
  const lines = value.replace(/\r\n/g, "\n").split("\n");
1306
1128
  while (lines.length > 0 && lines[0].trim() === "") {
@@ -1355,10 +1177,6 @@ function validateViewQuery(collectionName, viewQuery) {
1355
1177
  );
1356
1178
  }
1357
1179
  }
1358
- function getCollectionNameFromFile(filePath) {
1359
- const filename = path8__namespace.basename(filePath).replace(/\.(ts|js)$/, "");
1360
- return toCollectionName(filename);
1361
- }
1362
1180
  function extractCollectionNameFromSchema(zodSchema) {
1363
1181
  if (!zodSchema.description) {
1364
1182
  return null;
@@ -1398,42 +1216,42 @@ function extractViewQueryFromSchema(zodSchema) {
1398
1216
  }
1399
1217
  return null;
1400
1218
  }
1401
- function extractSchemaDefinitions(module, patterns = ["Schema", "InputSchema", "Collection"]) {
1402
- const result = {};
1403
- if (module.default instanceof zod.z.ZodObject) {
1404
- result.schema = module.default;
1405
- }
1219
+ function selectCollectionSchema(module) {
1220
+ const seen = /* @__PURE__ */ new Set();
1221
+ const candidates = [];
1222
+ const consider = (exportName, value) => {
1223
+ if (!(value instanceof zod.z.ZodObject) || seen.has(value)) {
1224
+ return;
1225
+ }
1226
+ const collectionName = extractCollectionNameFromSchema(value);
1227
+ if (!collectionName) {
1228
+ return;
1229
+ }
1230
+ seen.add(value);
1231
+ candidates.push({ schema: value, exportName, collectionName });
1232
+ };
1233
+ consider("default", module.default);
1406
1234
  for (const [key, value] of Object.entries(module)) {
1407
- if (key === "default") continue;
1408
- if (value instanceof zod.z.ZodObject) {
1409
- if (patterns.includes("InputSchema") && key.endsWith("InputSchema")) {
1410
- result.inputSchema = value;
1411
- } else if (!result.schema) {
1412
- if (patterns.includes("Collection") && key.endsWith("Collection")) {
1413
- result.schema = value;
1414
- } else if (patterns.includes("Schema") && key.endsWith("Schema") && !key.endsWith("InputSchema")) {
1415
- result.schema = value;
1416
- }
1417
- }
1235
+ if (key !== "default") {
1236
+ consider(key, value);
1418
1237
  }
1419
1238
  }
1420
- return result;
1421
- }
1422
- function selectSchemaForCollection(schemas) {
1423
- if (schemas.schema) {
1424
- return schemas.schema;
1239
+ if (candidates.length === 0) {
1240
+ return null;
1425
1241
  }
1426
- if (schemas.inputSchema) {
1427
- return schemas.inputSchema;
1242
+ if (candidates.length > 1) {
1243
+ const names = candidates.map((c) => `${c.exportName} (${c.collectionName})`).join(", ");
1244
+ throw new Error(
1245
+ `Multiple collection schemas exported from one file: ${names}. Define one collection per file.`
1246
+ );
1428
1247
  }
1429
- return null;
1248
+ return candidates[0];
1430
1249
  }
1431
1250
  function extractFieldDefinitions(zodSchema, excludeFields) {
1432
1251
  const shape = zodSchema.shape;
1433
1252
  const fields = [];
1434
1253
  const baseFields = ["id", "collectionId", "collectionName", "created", "updated", "expand"];
1435
- const defaultExcludeFields = ["thumbnailURL", "imageFiles"];
1436
- const allExclusions = /* @__PURE__ */ new Set([...baseFields, ...defaultExcludeFields, ...[]]);
1254
+ const allExclusions = /* @__PURE__ */ new Set([...baseFields, ...[]]);
1437
1255
  for (const [fieldName, zodType] of Object.entries(shape)) {
1438
1256
  if (!allExclusions.has(fieldName)) {
1439
1257
  fields.push({ name: fieldName, zodType });
@@ -1646,16 +1464,15 @@ function generateFindCollectionCode(name, collectionIdMap) {
1646
1464
  }
1647
1465
 
1648
1466
  // src/migration/analyzer/converter.ts
1649
- function isAuthCollection(fields) {
1650
- const fieldNames = fields.map((f) => f.name.toLowerCase());
1651
- const hasEmail = fieldNames.includes("email");
1652
- const hasPassword = fieldNames.includes("password");
1653
- return hasEmail && hasPassword;
1654
- }
1655
1467
  function buildFieldDefinition(fieldName, zodType) {
1656
1468
  const unwrappedType = unwrapZodType(zodType);
1657
1469
  const fieldMetadata = extractFieldMetadata(unwrappedType.description ?? zodType.description);
1658
1470
  if (fieldMetadata) {
1471
+ if (!fieldMetadata.type || !POCKETBASE_FIELD_TYPES.includes(fieldMetadata.type)) {
1472
+ throw new Error(
1473
+ `Field "${fieldName}" carries __pocketbase_field__ metadata with unknown type "${fieldMetadata.type}". Use one of: ${POCKETBASE_FIELD_TYPES.join(", ")}.`
1474
+ );
1475
+ }
1659
1476
  let required2;
1660
1477
  if (fieldMetadata.type === "number") {
1661
1478
  if (fieldMetadata.options?.required !== void 0) {
@@ -1666,7 +1483,8 @@ function buildFieldDefinition(fieldName, zodType) {
1666
1483
  } else {
1667
1484
  required2 = isFieldRequired(zodType);
1668
1485
  }
1669
- const { required: _required, ...options2 } = fieldMetadata.options || {};
1486
+ const { required: _required, ...metadataOptions } = fieldMetadata.options || {};
1487
+ const options2 = { ...extractChainedFieldOptions(fieldMetadata.type, unwrappedType), ...metadataOptions };
1670
1488
  const fieldDef2 = {
1671
1489
  name: fieldName,
1672
1490
  id: generateFieldId(fieldMetadata.type, fieldName),
@@ -1689,6 +1507,26 @@ function buildFieldDefinition(fieldName, zodType) {
1689
1507
  }
1690
1508
  return fieldDef2;
1691
1509
  }
1510
+ const relationMetadata = extractRelationMetadata(unwrappedType.description ?? zodType.description);
1511
+ if (relationMetadata) {
1512
+ return {
1513
+ name: fieldName,
1514
+ id: generateFieldId("relation", fieldName),
1515
+ type: "relation",
1516
+ required: isFieldRequired(zodType),
1517
+ // Zod validators on the field (array min/max etc.) are already captured
1518
+ // in the relation metadata; the field itself carries no options
1519
+ options: void 0,
1520
+ zodType,
1521
+ relation: {
1522
+ collection: relationMetadata.collection,
1523
+ maxSelect: relationMetadata.maxSelect,
1524
+ minSelect: relationMetadata.minSelect,
1525
+ cascadeDelete: relationMetadata.cascadeDelete,
1526
+ displayFields: relationMetadata.displayFields
1527
+ }
1528
+ };
1529
+ }
1692
1530
  const fieldType = mapZodTypeToPocketBase(zodType);
1693
1531
  const required = isFieldRequired(zodType);
1694
1532
  const options = extractFieldOptions(zodType);
@@ -1700,35 +1538,6 @@ function buildFieldDefinition(fieldName, zodType) {
1700
1538
  options,
1701
1539
  zodType
1702
1540
  };
1703
- const relationMetadata = extractRelationMetadata(unwrappedType.description ?? zodType.description);
1704
- if (relationMetadata) {
1705
- fieldDef.type = "relation";
1706
- fieldDef.relation = {
1707
- collection: relationMetadata.collection,
1708
- maxSelect: relationMetadata.maxSelect,
1709
- minSelect: relationMetadata.minSelect,
1710
- cascadeDelete: relationMetadata.cascadeDelete,
1711
- displayFields: relationMetadata.displayFields
1712
- };
1713
- fieldDef.options = void 0;
1714
- } else if (isRelationField(fieldName, zodType)) {
1715
- fieldDef.type = "relation";
1716
- const targetCollection = resolveTargetCollection(fieldName);
1717
- const maxSelect = getMaxSelect(fieldName, zodType);
1718
- const minSelect = getMinSelect(fieldName, zodType);
1719
- fieldDef.relation = {
1720
- collection: targetCollection,
1721
- maxSelect,
1722
- minSelect,
1723
- cascadeDelete: false,
1724
- // Default to false, can be configured later
1725
- displayFields: null
1726
- };
1727
- if (fieldDef.options) {
1728
- const { min: _min, max: _max, pattern: _pattern, ...relationSafeOptions } = fieldDef.options;
1729
- fieldDef.options = Object.keys(relationSafeOptions).length ? relationSafeOptions : void 0;
1730
- }
1731
- }
1732
1541
  if (fieldDef.type === "autodate") {
1733
1542
  fieldDef.options = {
1734
1543
  onCreate: true,
@@ -1742,10 +1551,17 @@ function buildFieldDefinition(fieldName, zodType) {
1742
1551
  fieldDef.options = filterSupportedFieldOptions(fieldDef.type, fieldDef.options);
1743
1552
  return fieldDef;
1744
1553
  }
1554
+ var TYPES_READING_CHAINED_VALIDATORS = /* @__PURE__ */ new Set(["text", "password", "number", "select", "file"]);
1555
+ function extractChainedFieldOptions(fieldType, unwrappedType) {
1556
+ if (!TYPES_READING_CHAINED_VALIDATORS.has(fieldType)) {
1557
+ return {};
1558
+ }
1559
+ return extractFieldOptions(unwrappedType);
1560
+ }
1745
1561
  function convertZodSchemaToCollectionSchema(collectionName, zodSchema) {
1746
1562
  const rawFields = extractFieldDefinitions(zodSchema);
1747
1563
  const explicitType = extractCollectionTypeFromSchema(zodSchema);
1748
- const collectionType = explicitType ?? (isAuthCollection(rawFields) ? "auth" : "base");
1564
+ const collectionType = explicitType ?? "base";
1749
1565
  const isView = collectionType === "view";
1750
1566
  const viewQuery = extractViewQueryFromSchema(zodSchema);
1751
1567
  if (isView) {
@@ -1856,9 +1672,8 @@ async function ensureTsxLoader() {
1856
1672
  }
1857
1673
  }
1858
1674
  function discoverSchemaFiles(config) {
1859
- const normalizedConfig = typeof config === "string" ? { schemaDir: config } : config;
1860
- const mergedConfig = mergeConfig(normalizedConfig);
1861
- const schemaDir = resolveSchemaDir(normalizedConfig);
1675
+ const mergedConfig = mergeConfig(config);
1676
+ const schemaDir = resolveSchemaDir(config);
1862
1677
  try {
1863
1678
  if (!fs10__namespace.existsSync(schemaDir)) {
1864
1679
  throw new FileSystemError(`Schema directory not found: ${schemaDir}`, schemaDir, "access", "ENOENT");
@@ -1886,7 +1701,7 @@ function discoverSchemaFiles(config) {
1886
1701
  `(${mergedConfig.includeExtensions.map((ext) => ext.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})$`
1887
1702
  );
1888
1703
  return schemaFiles.map((file) => {
1889
- return path8__namespace.join(schemaDir, file.replace(extensionRemovalRegex, ""));
1704
+ return path7__namespace.join(schemaDir, file.replace(extensionRemovalRegex, ""));
1890
1705
  });
1891
1706
  } catch (error) {
1892
1707
  if (error instanceof FileSystemError) {
@@ -1938,7 +1753,7 @@ Alternatively, compile your schema files to JavaScript first.`,
1938
1753
  );
1939
1754
  }
1940
1755
  }
1941
- const fileUrl = new URL(`file://${path8__namespace.resolve(resolvedPath)}`);
1756
+ const fileUrl = new URL(`file://${path7__namespace.resolve(resolvedPath)}`);
1942
1757
  const module = await import(fileUrl.href);
1943
1758
  return module;
1944
1759
  } catch (error) {
@@ -1965,13 +1780,13 @@ Alternatively, compile your schema files to JavaScript first.`,
1965
1780
  }
1966
1781
 
1967
1782
  // src/migration/analyzer/index.ts
1968
- async function buildSchemaDefinition(config) {
1969
- const normalizedConfig = typeof config === "string" ? { schemaDir: config } : config;
1970
- const mergedConfig = mergeConfig(normalizedConfig);
1783
+ async function parseSchemaFiles(config) {
1784
+ const mergedConfig = mergeConfig(config);
1971
1785
  const collections = /* @__PURE__ */ new Map();
1972
- const schemaFiles = discoverSchemaFiles(normalizedConfig);
1786
+ const collectionSources = /* @__PURE__ */ new Map();
1787
+ const schemaFiles = discoverSchemaFiles(config);
1973
1788
  if (schemaFiles.length === 0) {
1974
- const schemaDir = resolveSchemaDir(normalizedConfig);
1789
+ const schemaDir = resolveSchemaDir(config);
1975
1790
  throw new SchemaParsingError(
1976
1791
  `No schema files found in ${schemaDir}. Make sure you have schema files in the directory.`,
1977
1792
  schemaDir
@@ -1980,8 +1795,8 @@ async function buildSchemaDefinition(config) {
1980
1795
  for (const filePath of schemaFiles) {
1981
1796
  try {
1982
1797
  let importPath = filePath;
1983
- if (normalizedConfig.pathTransformer) {
1984
- importPath = normalizedConfig.pathTransformer(filePath);
1798
+ if (config.pathTransformer) {
1799
+ importPath = config.pathTransformer(filePath);
1985
1800
  } else if (mergedConfig.useCompiledFiles) {
1986
1801
  const distPath = filePath.replace(/\/src\//, "/dist/");
1987
1802
  if (fs10__namespace.existsSync(`${distPath}.js`) || fs10__namespace.existsSync(`${distPath}.mjs`)) {
@@ -1990,17 +1805,25 @@ async function buildSchemaDefinition(config) {
1990
1805
  importPath = filePath;
1991
1806
  }
1992
1807
  }
1993
- const module = await importSchemaModule(importPath, normalizedConfig);
1994
- const schemas = extractSchemaDefinitions(module, mergedConfig.schemaPatterns);
1995
- const zodSchema = selectSchemaForCollection(schemas);
1996
- if (!zodSchema) {
1997
- console.warn(`No valid schema found in ${filePath}, skipping...`);
1808
+ const module = await importSchemaModule(importPath, config);
1809
+ const collectionExport = selectCollectionSchema(module);
1810
+ if (!collectionExport) {
1811
+ console.warn(
1812
+ `${filePath}: no export carries collection metadata (use defineCollection()/defineView()); skipping. If this file previously produced a collection, the diff may now propose deleting it.`
1813
+ );
1998
1814
  continue;
1999
1815
  }
2000
- const collectionNameFromSchema = extractCollectionNameFromSchema(zodSchema);
2001
- const collectionName = collectionNameFromSchema ?? getCollectionNameFromFile(filePath);
2002
- const collectionSchema = convertZodSchemaToCollectionSchema(collectionName, zodSchema);
1816
+ const { collectionName, schema } = collectionExport;
1817
+ const existingSource = collectionSources.get(collectionName);
1818
+ if (existingSource) {
1819
+ throw new SchemaParsingError(
1820
+ `Collection "${collectionName}" is declared in both ${existingSource} and ${filePath}. Collection names must be unique across schema files.`,
1821
+ filePath
1822
+ );
1823
+ }
1824
+ const collectionSchema = convertZodSchemaToCollectionSchema(collectionName, schema);
2003
1825
  collections.set(collectionName, collectionSchema);
1826
+ collectionSources.set(collectionName, filePath);
2004
1827
  } catch (error) {
2005
1828
  if (error instanceof SchemaParsingError) {
2006
1829
  throw error;
@@ -2014,9 +1837,6 @@ async function buildSchemaDefinition(config) {
2014
1837
  }
2015
1838
  return { collections };
2016
1839
  }
2017
- async function parseSchemaFiles(config) {
2018
- return buildSchemaDefinition(config);
2019
- }
2020
1840
 
2021
1841
  // src/migration/engine/fields.ts
2022
1842
  var Field = class {
@@ -2062,12 +1882,26 @@ var FIELD_CONSTRUCTORS = {
2062
1882
  AutodateField,
2063
1883
  PasswordField
2064
1884
  };
2065
- function generateRuntimeFieldId(type) {
2066
- let digits = "";
2067
- for (let i = 0; i < 10; i++) {
2068
- digits += Math.floor(Math.random() * 10).toString();
1885
+ var crcTable = null;
1886
+ function crc32(input) {
1887
+ if (!crcTable) {
1888
+ crcTable = new Uint32Array(256);
1889
+ for (let i = 0; i < 256; i++) {
1890
+ let c = i;
1891
+ for (let bit = 0; bit < 8; bit++) {
1892
+ c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
1893
+ }
1894
+ crcTable[i] = c >>> 0;
1895
+ }
1896
+ }
1897
+ let crc = 4294967295;
1898
+ for (const byte of new TextEncoder().encode(input)) {
1899
+ crc = crcTable[(crc ^ byte) & 255] ^ crc >>> 8;
2069
1900
  }
2070
- return `${type || "field"}${digits}`;
1901
+ return (crc ^ 4294967295) >>> 0;
1902
+ }
1903
+ function generateRuntimeFieldId(type, name) {
1904
+ return `${type || "field"}${crc32(name)}`;
2071
1905
  }
2072
1906
 
2073
1907
  // src/migration/engine/fields-list.ts
@@ -2075,22 +1909,19 @@ var FieldsList = class {
2075
1909
  items = [];
2076
1910
  constructor(fields) {
2077
1911
  if (Array.isArray(fields)) {
2078
- for (const field of fields) {
2079
- this.items.push(field instanceof Field ? field : new Field(field));
2080
- }
1912
+ this.add(...fields);
2081
1913
  }
2082
1914
  }
2083
1915
  get length() {
2084
1916
  return this.items.length;
2085
1917
  }
2086
1918
  /**
2087
- * Appends fields; a field whose id matches an existing entry replaces it
2088
- * in place (position preserved), matching PocketBase upsert semantics.
1919
+ * Appends fields; a field that matches an existing entry replaces it in
1920
+ * place (position preserved), matching PocketBase upsert semantics.
2089
1921
  */
2090
1922
  add(...fields) {
2091
1923
  for (const raw of fields) {
2092
- const field = raw instanceof Field ? raw : new Field(raw);
2093
- const existing = this.indexOfId(field.id);
1924
+ const { field, existing } = this.resolveIncoming(raw);
2094
1925
  if (existing >= 0) {
2095
1926
  this.items[existing] = field;
2096
1927
  } else {
@@ -2099,15 +1930,14 @@ var FieldsList = class {
2099
1930
  }
2100
1931
  }
2101
1932
  /**
2102
- * Inserts fields at a position. A field with an already-present id is
1933
+ * Inserts fields at a position. A field matching an already-present entry is
2103
1934
  * moved: the old entry is removed first, then the field is inserted at
2104
1935
  * the requested position.
2105
1936
  */
2106
1937
  addAt(position, ...fields) {
2107
1938
  let insertAt = Math.max(0, Math.min(position, this.items.length));
2108
1939
  for (const raw of fields) {
2109
- const field = raw instanceof Field ? raw : new Field(raw);
2110
- const existing = this.indexOfId(field.id);
1940
+ const { field, existing } = this.resolveIncoming(raw);
2111
1941
  if (existing >= 0) {
2112
1942
  this.items.splice(existing, 1);
2113
1943
  if (existing < insertAt) {
@@ -2119,6 +1949,36 @@ var FieldsList = class {
2119
1949
  insertAt++;
2120
1950
  }
2121
1951
  }
1952
+ /**
1953
+ * Materializes an incoming field and locates the entry it replaces.
1954
+ *
1955
+ * PocketBase's rule (documented on `FieldsList.Add` in types.d.ts): match by
1956
+ * id, "or by their name if the new field doesn't have an explicit id", and
1957
+ * autogenerate a missing id from the name. Matching by id alone turns the
1958
+ * idiomatic `fields.add(new TextField({name: "title", max: 500}))` — no id,
1959
+ * meant to rewrite `title` — into a second field also called `title`, which
1960
+ * PocketBase would reject on save but the engine used to accept, corrupting
1961
+ * the reconstructed state.
1962
+ *
1963
+ * On a name match the *existing* id is kept rather than replaced with the
1964
+ * derived one. For a collection PocketBase authored the two are identical
1965
+ * (its auto-ids already are `<type><crc32(name)>`); they diverge only when
1966
+ * the stored field carries a hand-assigned id, and there preserving it keeps
1967
+ * a later `removeById`/`getById` in the same migration working.
1968
+ */
1969
+ resolveIncoming(raw) {
1970
+ const field = raw instanceof Field ? raw : new Field(raw);
1971
+ const hasExplicitId = typeof field.id === "string" && field.id !== "";
1972
+ if (hasExplicitId) {
1973
+ return { field, existing: this.indexOfId(field.id) };
1974
+ }
1975
+ const existing = this.items.findIndex((f) => f.name === field.name);
1976
+ field.id = existing >= 0 ? this.items[existing].id : generateRuntimeFieldId(
1977
+ typeof field.type === "string" ? field.type : "",
1978
+ typeof field.name === "string" ? field.name : ""
1979
+ );
1980
+ return { field, existing };
1981
+ }
2122
1982
  removeById(id) {
2123
1983
  const index = this.indexOfId(id);
2124
1984
  if (index >= 0) {
@@ -2131,12 +1991,18 @@ var FieldsList = class {
2131
1991
  this.items.splice(index, 1);
2132
1992
  }
2133
1993
  }
1994
+ /**
1995
+ * Null rather than undefined for a miss: these two return a Go `Field`
1996
+ * interface, and goja surfaces a nil interface to JavaScript as `null`. A
1997
+ * migration written as `if (collection.fields.getByName("x") === null)` has
1998
+ * to take the same branch here as it does in production.
1999
+ */
2134
2000
  getById(id) {
2135
2001
  const index = this.indexOfId(id);
2136
- return index >= 0 ? this.items[index] : void 0;
2002
+ return index >= 0 ? this.items[index] : null;
2137
2003
  }
2138
2004
  getByName(name) {
2139
- return this.items.find((f) => f.name === name);
2005
+ return this.items.find((f) => f.name === name) ?? null;
2140
2006
  }
2141
2007
  at(index) {
2142
2008
  return this.items.at(index);
@@ -2161,9 +2027,14 @@ var FieldsList = class {
2161
2027
  this.items = [];
2162
2028
  this.add(...fields);
2163
2029
  }
2164
- /** Plain objects, in order */
2030
+ /**
2031
+ * Plain objects, in order — copied deeply, so option arrays like a select
2032
+ * field's `values` are not shared with the live list. A shallow spread let a
2033
+ * snapshot handed to the diff engine alias engine state, where an in-place
2034
+ * sort or push downstream would silently rewrite the collection it came from.
2035
+ */
2165
2036
  serialize() {
2166
- return this.items.map((field) => ({ ...field }));
2037
+ return this.items.map((field) => copyPlainData({ ...field }));
2167
2038
  }
2168
2039
  indexOfId(id) {
2169
2040
  if (typeof id !== "string" || id === "") {
@@ -2172,6 +2043,22 @@ var FieldsList = class {
2172
2043
  return this.items.findIndex((f) => f.id === id);
2173
2044
  }
2174
2045
  };
2046
+ function copyPlainData(value) {
2047
+ if (Array.isArray(value)) {
2048
+ return value.map(copyPlainData);
2049
+ }
2050
+ if (value !== null && typeof value === "object" && !(value instanceof Date)) {
2051
+ const prototype = Object.getPrototypeOf(value);
2052
+ if (prototype === Object.prototype || prototype === null) {
2053
+ const copy = {};
2054
+ for (const [key, entry] of Object.entries(value)) {
2055
+ copy[key] = copyPlainData(entry);
2056
+ }
2057
+ return copy;
2058
+ }
2059
+ }
2060
+ return value;
2061
+ }
2175
2062
 
2176
2063
  // src/migration/engine/collection.ts
2177
2064
  var AUTH_SYSTEM_FIELDS = [
@@ -3590,6 +3477,13 @@ function createInertStub(name, options, warn) {
3590
3477
  if (prop === "then") {
3591
3478
  return void 0;
3592
3479
  }
3480
+ if (prop === "length") {
3481
+ return 0;
3482
+ }
3483
+ if (prop === Symbol.iterator) {
3484
+ return function* emptyIterator() {
3485
+ };
3486
+ }
3593
3487
  if (typeof prop === "symbol") {
3594
3488
  return void 0;
3595
3489
  }
@@ -3648,7 +3542,10 @@ var SimulatedAppImpl = class {
3648
3542
  ensureAuthSystemFields(collection);
3649
3543
  for (const field of collection.fields) {
3650
3544
  if (typeof field.id !== "string" || field.id === "") {
3651
- field.id = generateRuntimeFieldId(typeof field.type === "string" ? field.type : "");
3545
+ field.id = generateRuntimeFieldId(
3546
+ typeof field.type === "string" ? field.type : "",
3547
+ typeof field.name === "string" ? field.name : ""
3548
+ );
3652
3549
  }
3653
3550
  }
3654
3551
  this.store.upsert(collection);
@@ -3934,21 +3831,21 @@ function appliedMigrationsFromList(files, origin = "<list>") {
3934
3831
  const entries = [];
3935
3832
  const coreEntries = [];
3936
3833
  for (const file of files) {
3937
- const entry = { file: path8__namespace.basename(file) };
3834
+ const entry = { file: path7__namespace.basename(file) };
3938
3835
  (isCoreMigration(entry.file) ? coreEntries : entries).push(entry);
3939
3836
  }
3940
3837
  return { origin, entries, coreEntries };
3941
3838
  }
3942
3839
  function defaultDataDirectory(migrationsPath) {
3943
- return path8__namespace.resolve(path8__namespace.dirname(path8__namespace.resolve(migrationsPath)), "pb_data");
3840
+ return path7__namespace.resolve(path7__namespace.dirname(path7__namespace.resolve(migrationsPath)), "pb_data");
3944
3841
  }
3945
3842
  function resolveDatabasePath(dataPathOrFile) {
3946
- const resolved = path8__namespace.resolve(dataPathOrFile);
3843
+ const resolved = path7__namespace.resolve(dataPathOrFile);
3947
3844
  if (!fs10__namespace.existsSync(resolved)) {
3948
3845
  return null;
3949
3846
  }
3950
3847
  if (fs10__namespace.statSync(resolved).isDirectory()) {
3951
- const candidate = path8__namespace.join(resolved, POCKETBASE_DATABASE_FILENAME);
3848
+ const candidate = path7__namespace.join(resolved, POCKETBASE_DATABASE_FILENAME);
3952
3849
  return fs10__namespace.existsSync(candidate) ? candidate : null;
3953
3850
  }
3954
3851
  return resolved;
@@ -3957,7 +3854,7 @@ function readAppliedMigrations(dataPathOrFile) {
3957
3854
  const databasePath = resolveDatabasePath(dataPathOrFile);
3958
3855
  if (!databasePath) {
3959
3856
  throw new AppliedMigrationsError(
3960
- `No PocketBase database found at ${path8__namespace.resolve(dataPathOrFile)}. Expected a data.db file, or a pb_data directory containing one.`,
3857
+ `No PocketBase database found at ${path7__namespace.resolve(dataPathOrFile)}. Expected a data.db file, or a pb_data directory containing one.`,
3961
3858
  dataPathOrFile
3962
3859
  );
3963
3860
  }
@@ -4073,7 +3970,7 @@ function discoverMigrations(migrationsPath) {
4073
3970
  continue;
4074
3971
  }
4075
3972
  discovered.push({
4076
- path: path8__namespace.join(migrationsPath, name),
3973
+ path: path7__namespace.join(migrationsPath, name),
4077
3974
  name,
4078
3975
  timestamp,
4079
3976
  isSnapshot: name.endsWith("_collections_snapshot.js") || name.endsWith("_snapshot.js")
@@ -4352,8 +4249,8 @@ function replayMigrationsDirectory(migrationsPath, options = {}) {
4352
4249
  }
4353
4250
  return replayMigrations(plan.filesToReplay, { ...engineOptions, plan });
4354
4251
  }
4355
- ({
4356
- workspaceRoot: process.cwd()});
4252
+
4253
+ // src/migration/snapshot.ts
4357
4254
  function loadSnapshotWithMigrations(config = {}) {
4358
4255
  const migrationsPath = config.migrationsPath;
4359
4256
  if (!migrationsPath) {
@@ -4382,16 +4279,13 @@ function loadSnapshotWithMigrations(config = {}) {
4382
4279
  }
4383
4280
 
4384
4281
  // src/migration/diff/config.ts
4385
- var DEFAULT_CONFIG3 = {
4386
- warnOnDelete: true,
4387
- requireForceForDestructive: true,
4388
- severityThreshold: "high",
4282
+ var DEFAULT_CONFIG2 = {
4389
4283
  systemCollections: ["_mfas", "_otps", "_externalAuths", "_authOrigins", "_superusers"],
4390
4284
  usersSystemFields: ["id", "password", "tokenKey", "email", "emailVisibility", "verified", "created", "updated"]
4391
4285
  };
4392
4286
  function mergeConfig2(config) {
4393
4287
  return {
4394
- ...DEFAULT_CONFIG3,
4288
+ ...DEFAULT_CONFIG2,
4395
4289
  ...config
4396
4290
  };
4397
4291
  }
@@ -4420,40 +4314,23 @@ function areValuesEqual(a, b) {
4420
4314
  }
4421
4315
  return a === b;
4422
4316
  }
4423
- var OPTION_ZERO_VALUES = {
4424
- autogeneratePattern: "",
4425
- pattern: "",
4426
- primaryKey: false,
4427
- convertURLs: false,
4428
- cost: 0,
4429
- hidden: false,
4430
- presentable: false,
4431
- system: false
4432
- };
4433
4317
  function normalizeOptionValue(key, value, fieldType) {
4434
- if (OPTION_ZERO_VALUES[key] !== void 0 && value === OPTION_ZERO_VALUES[key]) {
4318
+ if (value === null || value === void 0) {
4435
4319
  return void 0;
4436
4320
  }
4437
- if (key === "maxSelect" && value === 1 && (fieldType === "select" || fieldType === "file")) {
4321
+ const unsetValue = getFieldOptionUnsetValue(fieldType, key);
4322
+ if (unsetValue !== void 0 && areValuesEqual(value, unsetValue)) {
4438
4323
  return void 0;
4439
4324
  }
4440
- if (key === "maxSize" && value === 0 && fieldType === "file") {
4325
+ if (key === "values" && fieldType === "select" && Array.isArray(value)) {
4326
+ return [...value].sort();
4327
+ }
4328
+ if (key === "maxSelect" && value === 1 && (fieldType === "select" || fieldType === "file")) {
4441
4329
  return void 0;
4442
4330
  }
4443
4331
  if (key === "min" && value === 1 && fieldType === "number") {
4444
4332
  return void 0;
4445
4333
  }
4446
- if (fieldType === "file") {
4447
- if (key === "mimeTypes" && Array.isArray(value) && value.length === 0) {
4448
- return void 0;
4449
- }
4450
- if (key === "thumbs" && Array.isArray(value) && value.length === 0) {
4451
- return void 0;
4452
- }
4453
- if (key === "protected" && value === false) {
4454
- return void 0;
4455
- }
4456
- }
4457
4334
  if (fieldType === "autodate") {
4458
4335
  if (key === "onCreate" && value === true) {
4459
4336
  return void 0;
@@ -4863,57 +4740,6 @@ function buildCollectionModification(currentCollection, previousCollection, conf
4863
4740
  };
4864
4741
  }
4865
4742
 
4866
- // src/migration/diff/summary.ts
4867
- function categorizeChangesBySeverity(diff, _config) {
4868
- const destructive = [];
4869
- const nonDestructive = [];
4870
- for (const collection of diff.collectionsToDelete) {
4871
- if (collection.type === "view") {
4872
- nonDestructive.push(`Delete view collection: ${collection.name}`);
4873
- } else {
4874
- destructive.push(`Delete collection: ${collection.name}`);
4875
- }
4876
- }
4877
- for (const collection of diff.collectionsToCreate) {
4878
- nonDestructive.push(`Create collection: ${collection.name}`);
4879
- }
4880
- for (const modification of diff.collectionsToModify) {
4881
- const collectionName = modification.collection;
4882
- for (const field of modification.fieldsToRemove) {
4883
- destructive.push(`Delete field: ${collectionName}.${field.name}`);
4884
- }
4885
- for (const field of modification.fieldsToAdd) {
4886
- nonDestructive.push(`Add field: ${collectionName}.${field.name}`);
4887
- }
4888
- for (const fieldMod of modification.fieldsToModify) {
4889
- const hasTypeChange = fieldMod.changes.some((c) => c.property === "type");
4890
- const hasRequiredChange = fieldMod.changes.some((c) => c.property === "required" && c.newValue === true);
4891
- if (hasTypeChange) {
4892
- destructive.push(
4893
- `Change field type: ${collectionName}.${fieldMod.fieldName} (${fieldMod.changes.find((c) => c.property === "type")?.oldValue} \u2192 ${fieldMod.changes.find((c) => c.property === "type")?.newValue})`
4894
- );
4895
- } else if (hasRequiredChange) {
4896
- destructive.push(`Make field required: ${collectionName}.${fieldMod.fieldName}`);
4897
- } else {
4898
- nonDestructive.push(`Modify field: ${collectionName}.${fieldMod.fieldName}`);
4899
- }
4900
- }
4901
- for (const _index of modification.indexesToAdd) {
4902
- nonDestructive.push(`Add index: ${collectionName}`);
4903
- }
4904
- for (const _index of modification.indexesToRemove) {
4905
- nonDestructive.push(`Remove index: ${collectionName}`);
4906
- }
4907
- for (const rule of modification.rulesToUpdate) {
4908
- nonDestructive.push(`Update rule: ${collectionName}.${rule.ruleType}`);
4909
- }
4910
- if (modification.viewQueryUpdate) {
4911
- nonDestructive.push(`Update view query: ${collectionName}`);
4912
- }
4913
- }
4914
- return { destructive, nonDestructive };
4915
- }
4916
-
4917
4743
  // src/migration/diff/filter.ts
4918
4744
  function matchesPattern(text, patterns) {
4919
4745
  if (!patterns || patterns.length === 0) return true;
@@ -4990,25 +4816,76 @@ function filterDiff(diff, options) {
4990
4816
  };
4991
4817
  }
4992
4818
 
4993
- // src/migration/diff/index.ts
4994
- function hasChanges(modification) {
4995
- 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 || modification.viewQueryUpdate !== void 0;
4996
- }
4997
- function aggregateChanges(currentSchema, previousSnapshot, config) {
4998
- const collectionIdToName = /* @__PURE__ */ new Map();
4999
- if (previousSnapshot) {
5000
- for (const [name, collection] of previousSnapshot.collections) {
5001
- if (collection.id) {
5002
- collectionIdToName.set(collection.id, name);
5003
- }
4819
+ // src/migration/diff/summary.ts
4820
+ function categorizeChangesBySeverity(diff, _config) {
4821
+ const destructive = [];
4822
+ const nonDestructive = [];
4823
+ for (const collection of diff.collectionsToDelete) {
4824
+ if (collection.type === "view") {
4825
+ nonDestructive.push(`Delete view collection: ${collection.name}`);
4826
+ } else {
4827
+ destructive.push(`Delete collection: ${collection.name}`);
5004
4828
  }
5005
4829
  }
5006
- const collectionsToCreate = findNewCollections(currentSchema, previousSnapshot);
5007
- const collectionsToDelete = findRemovedCollections(currentSchema, previousSnapshot);
5008
- const filteredCollectionsToCreate = collectionsToCreate.filter(
5009
- (collection) => !isSystemCollection(collection.name, config)
5010
- );
5011
- const filteredCollectionsToDelete = collectionsToDelete.filter(
4830
+ for (const collection of diff.collectionsToCreate) {
4831
+ nonDestructive.push(`Create collection: ${collection.name}`);
4832
+ }
4833
+ for (const modification of diff.collectionsToModify) {
4834
+ const collectionName = modification.collection;
4835
+ for (const field of modification.fieldsToRemove) {
4836
+ destructive.push(`Delete field: ${collectionName}.${field.name}`);
4837
+ }
4838
+ for (const field of modification.fieldsToAdd) {
4839
+ nonDestructive.push(`Add field: ${collectionName}.${field.name}`);
4840
+ }
4841
+ for (const fieldMod of modification.fieldsToModify) {
4842
+ const hasTypeChange = fieldMod.changes.some((c) => c.property === "type");
4843
+ const hasRequiredChange = fieldMod.changes.some((c) => c.property === "required" && c.newValue === true);
4844
+ if (hasTypeChange) {
4845
+ destructive.push(
4846
+ `Change field type: ${collectionName}.${fieldMod.fieldName} (${fieldMod.changes.find((c) => c.property === "type")?.oldValue} \u2192 ${fieldMod.changes.find((c) => c.property === "type")?.newValue})`
4847
+ );
4848
+ } else if (hasRequiredChange) {
4849
+ destructive.push(`Make field required: ${collectionName}.${fieldMod.fieldName}`);
4850
+ } else {
4851
+ nonDestructive.push(`Modify field: ${collectionName}.${fieldMod.fieldName}`);
4852
+ }
4853
+ }
4854
+ for (const _index of modification.indexesToAdd) {
4855
+ nonDestructive.push(`Add index: ${collectionName}`);
4856
+ }
4857
+ for (const _index of modification.indexesToRemove) {
4858
+ nonDestructive.push(`Remove index: ${collectionName}`);
4859
+ }
4860
+ for (const rule of modification.rulesToUpdate) {
4861
+ nonDestructive.push(`Update rule: ${collectionName}.${rule.ruleType}`);
4862
+ }
4863
+ if (modification.viewQueryUpdate) {
4864
+ nonDestructive.push(`Update view query: ${collectionName}`);
4865
+ }
4866
+ }
4867
+ return { destructive, nonDestructive };
4868
+ }
4869
+
4870
+ // src/migration/diff/index.ts
4871
+ function hasChanges(modification) {
4872
+ 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 || modification.viewQueryUpdate !== void 0;
4873
+ }
4874
+ function compare2(currentSchema, previousSnapshot, config) {
4875
+ const collectionIdToName = /* @__PURE__ */ new Map();
4876
+ if (previousSnapshot) {
4877
+ for (const [name, collection] of previousSnapshot.collections) {
4878
+ if (collection.id) {
4879
+ collectionIdToName.set(collection.id, name);
4880
+ }
4881
+ }
4882
+ }
4883
+ const collectionsToCreate = findNewCollections(currentSchema, previousSnapshot);
4884
+ const collectionsToDelete = findRemovedCollections(currentSchema, previousSnapshot);
4885
+ const filteredCollectionsToCreate = collectionsToCreate.filter(
4886
+ (collection) => !isSystemCollection(collection.name, config)
4887
+ );
4888
+ const filteredCollectionsToDelete = collectionsToDelete.filter(
5012
4889
  (collection) => !isSystemCollection(collection.name, config)
5013
4890
  );
5014
4891
  const registry = new CollectionIdRegistry();
@@ -5046,8 +4923,153 @@ function aggregateChanges(currentSchema, previousSnapshot, config) {
5046
4923
  existingCollectionIds
5047
4924
  };
5048
4925
  }
5049
- function compare2(currentSchema, previousSnapshot, config) {
5050
- return aggregateChanges(currentSchema, previousSnapshot, config);
4926
+
4927
+ // src/migration/validation.ts
4928
+ function detectCollectionDeletions(diff) {
4929
+ const changes = [];
4930
+ for (const collection of diff.collectionsToDelete) {
4931
+ if (collection.type === "view") {
4932
+ continue;
4933
+ }
4934
+ changes.push({
4935
+ type: "collection_deletion" /* COLLECTION_DELETION */,
4936
+ description: `Delete collection: ${collection.name}`,
4937
+ collection: collection.name,
4938
+ severity: "high",
4939
+ warning: `All data in the "${collection.name}" collection will be permanently deleted.`
4940
+ });
4941
+ }
4942
+ return changes;
4943
+ }
4944
+ function detectFieldDeletions(diff) {
4945
+ const changes = [];
4946
+ for (const modification of diff.collectionsToModify) {
4947
+ for (const field of modification.fieldsToRemove) {
4948
+ changes.push({
4949
+ type: "field_deletion" /* FIELD_DELETION */,
4950
+ description: `Delete field: ${modification.collection}.${field.name}`,
4951
+ collection: modification.collection,
4952
+ field: field.name,
4953
+ severity: "high",
4954
+ warning: `All data in the "${field.name}" field of "${modification.collection}" will be permanently deleted.`
4955
+ });
4956
+ }
4957
+ }
4958
+ return changes;
4959
+ }
4960
+ function detectFieldTypeChanges(diff) {
4961
+ const changes = [];
4962
+ for (const modification of diff.collectionsToModify) {
4963
+ for (const fieldMod of modification.fieldsToModify) {
4964
+ const typeChange = fieldMod.changes.find((c) => c.property === "type");
4965
+ if (typeChange) {
4966
+ changes.push({
4967
+ type: "field_type_change" /* FIELD_TYPE_CHANGE */,
4968
+ description: `Change field type: ${modification.collection}.${fieldMod.fieldName}`,
4969
+ collection: modification.collection,
4970
+ field: fieldMod.fieldName,
4971
+ details: {
4972
+ oldValue: typeChange.oldValue,
4973
+ newValue: typeChange.newValue
4974
+ },
4975
+ severity: "high",
4976
+ warning: `Changing field type from "${typeChange.oldValue}" to "${typeChange.newValue}" may cause data loss or conversion errors.`
4977
+ });
4978
+ }
4979
+ }
4980
+ }
4981
+ return changes;
4982
+ }
4983
+ function detectFieldRequiredChanges(diff) {
4984
+ const changes = [];
4985
+ for (const modification of diff.collectionsToModify) {
4986
+ for (const fieldMod of modification.fieldsToModify) {
4987
+ const requiredChange = fieldMod.changes.find(
4988
+ (c) => c.property === "required" && c.newValue === true && c.oldValue === false
4989
+ );
4990
+ if (requiredChange) {
4991
+ changes.push({
4992
+ type: "field_required_change" /* FIELD_REQUIRED_CHANGE */,
4993
+ description: `Make field required: ${modification.collection}.${fieldMod.fieldName}`,
4994
+ collection: modification.collection,
4995
+ field: fieldMod.fieldName,
4996
+ details: {
4997
+ oldValue: false,
4998
+ newValue: true
4999
+ },
5000
+ severity: "medium",
5001
+ warning: `Making "${fieldMod.fieldName}" required may cause issues with existing records that have null/empty values.`
5002
+ });
5003
+ }
5004
+ }
5005
+ }
5006
+ return changes;
5007
+ }
5008
+ function detectDestructiveChanges(diff) {
5009
+ const changes = [];
5010
+ changes.push(...detectCollectionDeletions(diff));
5011
+ changes.push(...detectFieldDeletions(diff));
5012
+ changes.push(...detectFieldTypeChanges(diff));
5013
+ changes.push(...detectFieldRequiredChanges(diff));
5014
+ return changes;
5015
+ }
5016
+ function formatDestructiveChanges(changes) {
5017
+ if (changes.length === 0) {
5018
+ return "No destructive changes detected.";
5019
+ }
5020
+ const lines = [];
5021
+ const highSeverity = changes.filter((c) => c.severity === "high");
5022
+ const mediumSeverity = changes.filter((c) => c.severity === "medium");
5023
+ const lowSeverity = changes.filter((c) => c.severity === "low");
5024
+ if (highSeverity.length > 0) {
5025
+ lines.push("\u{1F534} HIGH SEVERITY CHANGES (Data Loss Risk):");
5026
+ lines.push("");
5027
+ for (const change of highSeverity) {
5028
+ lines.push(` \u2022 ${change.description}`);
5029
+ lines.push(` \u26A0\uFE0F ${change.warning}`);
5030
+ if (change.details) {
5031
+ if (change.details.oldValue !== void 0 && change.details.newValue !== void 0) {
5032
+ lines.push(` Old: ${change.details.oldValue} \u2192 New: ${change.details.newValue}`);
5033
+ }
5034
+ }
5035
+ lines.push("");
5036
+ }
5037
+ }
5038
+ if (mediumSeverity.length > 0) {
5039
+ lines.push("\u{1F7E1} MEDIUM SEVERITY CHANGES (Potential Issues):");
5040
+ lines.push("");
5041
+ for (const change of mediumSeverity) {
5042
+ lines.push(` \u2022 ${change.description}`);
5043
+ lines.push(` \u26A0\uFE0F ${change.warning}`);
5044
+ if (change.details) {
5045
+ if (change.details.oldValue !== void 0 && change.details.newValue !== void 0) {
5046
+ lines.push(` Old: ${change.details.oldValue} \u2192 New: ${change.details.newValue}`);
5047
+ }
5048
+ }
5049
+ lines.push("");
5050
+ }
5051
+ }
5052
+ if (lowSeverity.length > 0) {
5053
+ lines.push("\u{1F7E2} LOW SEVERITY CHANGES:");
5054
+ lines.push("");
5055
+ for (const change of lowSeverity) {
5056
+ lines.push(` \u2022 ${change.description}`);
5057
+ lines.push(` \u2139\uFE0F ${change.warning}`);
5058
+ lines.push("");
5059
+ }
5060
+ }
5061
+ return lines.join("\n");
5062
+ }
5063
+ function summarizeDestructiveChanges(changes) {
5064
+ return {
5065
+ total: changes.length,
5066
+ high: changes.filter((c) => c.severity === "high").length,
5067
+ medium: changes.filter((c) => c.severity === "medium").length,
5068
+ low: changes.filter((c) => c.severity === "low").length
5069
+ };
5070
+ }
5071
+ function requiresForceFlag(changes) {
5072
+ return changes.some((c) => c.severity === "high" || c.severity === "medium");
5051
5073
  }
5052
5074
 
5053
5075
  // src/migration/generator/config.ts
@@ -5058,7 +5080,7 @@ migrate((app) => {
5058
5080
  {{DOWN_CODE}}
5059
5081
  });
5060
5082
  `;
5061
- var DEFAULT_CONFIG4 = {
5083
+ var DEFAULT_CONFIG3 = {
5062
5084
  workspaceRoot: process.cwd(),
5063
5085
  timestampGenerator: () => Math.floor(Date.now() / 1e3).toString(),
5064
5086
  template: DEFAULT_TEMPLATE,
@@ -5067,20 +5089,20 @@ var DEFAULT_CONFIG4 = {
5067
5089
  };
5068
5090
  function mergeConfig3(config) {
5069
5091
  return {
5070
- ...DEFAULT_CONFIG4,
5092
+ ...DEFAULT_CONFIG3,
5071
5093
  force: false,
5072
5094
  ...config
5073
5095
  };
5074
5096
  }
5075
5097
  function resolveMigrationDir(config) {
5076
5098
  const workspaceRoot = config.workspaceRoot || process.cwd();
5077
- if (path8__namespace.isAbsolute(config.migrationDir)) {
5099
+ if (path7__namespace.isAbsolute(config.migrationDir)) {
5078
5100
  return config.migrationDir;
5079
5101
  }
5080
- return path8__namespace.join(workspaceRoot, config.migrationDir);
5102
+ return path7__namespace.join(workspaceRoot, config.migrationDir);
5081
5103
  }
5082
5104
  function createMigrationFileStructure(upCode, downCode, config) {
5083
- const mergedConfig = config ? mergeConfig3(config) : DEFAULT_CONFIG4;
5105
+ const mergedConfig = config ? mergeConfig3(config) : DEFAULT_CONFIG3;
5084
5106
  let template = mergedConfig.template;
5085
5107
  template = template.replace("{{TYPES_PATH}}", () => mergedConfig.typesPath);
5086
5108
  template = template.replace("{{UP_CODE}}", () => upCode);
@@ -5115,7 +5137,7 @@ function writeMigrationFile(migrationDir, filename, content) {
5115
5137
  );
5116
5138
  }
5117
5139
  }
5118
- const filePath = path8__namespace.join(migrationDir, filename);
5140
+ const filePath = path7__namespace.join(migrationDir, filename);
5119
5141
  fs10__namespace.writeFileSync(filePath, content, "utf-8");
5120
5142
  return filePath;
5121
5143
  } catch (error) {
@@ -5123,7 +5145,7 @@ function writeMigrationFile(migrationDir, filename, content) {
5123
5145
  throw error;
5124
5146
  }
5125
5147
  const fsError = error;
5126
- const filePath = path8__namespace.join(migrationDir, filename);
5148
+ const filePath = path7__namespace.join(migrationDir, filename);
5127
5149
  if (fsError.code === "EACCES" || fsError.code === "EPERM") {
5128
5150
  throw new FileSystemError(
5129
5151
  `Permission denied writing migration file. Check file and directory permissions.`,
@@ -5273,13 +5295,16 @@ function generateFieldModification(collectionName, modification, varName, isLast
5273
5295
  const lines = [];
5274
5296
  const collectionVar = varName || `collection_${collectionName}_${modification.fieldName}`;
5275
5297
  const fieldVar = `${collectionVar}_field`;
5298
+ const fieldType = modification.newDefinition?.type ?? modification.currentDefinition?.type;
5276
5299
  lines.push(` const ${collectionVar} = ${generateFindCollectionCode(collectionName, collectionIdMap)};`);
5277
5300
  lines.push(` const ${fieldVar} = ${collectionVar}.fields.getByName("${modification.fieldName}");`);
5278
5301
  lines.push(``);
5279
5302
  for (const change of modification.changes) {
5280
5303
  if (change.property.startsWith("options.")) {
5281
5304
  const optionKey = change.property.replace("options.", "");
5282
- lines.push(` ${fieldVar}.${optionKey} = ${formatValue(change.newValue)};`);
5305
+ const newValue = change.newValue === void 0 ? getFieldOptionUnsetValue(fieldType, optionKey) : change.newValue;
5306
+ const pbKey = fieldType === "number" && optionKey === "noDecimal" ? "onlyInt" : optionKey;
5307
+ lines.push(` ${fieldVar}.${pbKey} = ${formatValue(newValue)};`);
5283
5308
  } else if (change.property.startsWith("relation.")) {
5284
5309
  const relationKey = change.property.replace("relation.", "");
5285
5310
  if (relationKey === "collection") {
@@ -5887,7 +5912,7 @@ function planMigrations(diff, config) {
5887
5912
  const planned = [];
5888
5913
  let existingFiles = [];
5889
5914
  if (!normalizedConfig.force && fs10__namespace.existsSync(migrationDir)) {
5890
- existingFiles = fs10__namespace.readdirSync(migrationDir).filter((f) => f.endsWith(".js") || f.endsWith(".ts")).map((f) => fs10__namespace.readFileSync(path8__namespace.join(migrationDir, f), "utf-8"));
5915
+ existingFiles = fs10__namespace.readdirSync(migrationDir).filter((f) => f.endsWith(".js") || f.endsWith(".ts")).map((f) => fs10__namespace.readFileSync(path7__namespace.join(migrationDir, f), "utf-8"));
5891
5916
  }
5892
5917
  for (const operation of operations) {
5893
5918
  const upCode = generateOperationUpMigration(operation, collectionIdMap);
@@ -6644,154 +6669,6 @@ function toPhaseError(error, fallbackPhase) {
6644
6669
  }
6645
6670
  return { phase: fallbackPhase, message: error instanceof Error ? error.message : String(error) };
6646
6671
  }
6647
-
6648
- // src/migration/validation.ts
6649
- function detectCollectionDeletions(diff) {
6650
- const changes = [];
6651
- for (const collection of diff.collectionsToDelete) {
6652
- if (collection.type === "view") {
6653
- continue;
6654
- }
6655
- changes.push({
6656
- type: "collection_deletion" /* COLLECTION_DELETION */,
6657
- description: `Delete collection: ${collection.name}`,
6658
- collection: collection.name,
6659
- severity: "high",
6660
- warning: `All data in the "${collection.name}" collection will be permanently deleted.`
6661
- });
6662
- }
6663
- return changes;
6664
- }
6665
- function detectFieldDeletions(diff) {
6666
- const changes = [];
6667
- for (const modification of diff.collectionsToModify) {
6668
- for (const field of modification.fieldsToRemove) {
6669
- changes.push({
6670
- type: "field_deletion" /* FIELD_DELETION */,
6671
- description: `Delete field: ${modification.collection}.${field.name}`,
6672
- collection: modification.collection,
6673
- field: field.name,
6674
- severity: "high",
6675
- warning: `All data in the "${field.name}" field of "${modification.collection}" will be permanently deleted.`
6676
- });
6677
- }
6678
- }
6679
- return changes;
6680
- }
6681
- function detectFieldTypeChanges(diff) {
6682
- const changes = [];
6683
- for (const modification of diff.collectionsToModify) {
6684
- for (const fieldMod of modification.fieldsToModify) {
6685
- const typeChange = fieldMod.changes.find((c) => c.property === "type");
6686
- if (typeChange) {
6687
- changes.push({
6688
- type: "field_type_change" /* FIELD_TYPE_CHANGE */,
6689
- description: `Change field type: ${modification.collection}.${fieldMod.fieldName}`,
6690
- collection: modification.collection,
6691
- field: fieldMod.fieldName,
6692
- details: {
6693
- oldValue: typeChange.oldValue,
6694
- newValue: typeChange.newValue
6695
- },
6696
- severity: "high",
6697
- warning: `Changing field type from "${typeChange.oldValue}" to "${typeChange.newValue}" may cause data loss or conversion errors.`
6698
- });
6699
- }
6700
- }
6701
- }
6702
- return changes;
6703
- }
6704
- function detectFieldRequiredChanges(diff) {
6705
- const changes = [];
6706
- for (const modification of diff.collectionsToModify) {
6707
- for (const fieldMod of modification.fieldsToModify) {
6708
- const requiredChange = fieldMod.changes.find(
6709
- (c) => c.property === "required" && c.newValue === true && c.oldValue === false
6710
- );
6711
- if (requiredChange) {
6712
- changes.push({
6713
- type: "field_required_change" /* FIELD_REQUIRED_CHANGE */,
6714
- description: `Make field required: ${modification.collection}.${fieldMod.fieldName}`,
6715
- collection: modification.collection,
6716
- field: fieldMod.fieldName,
6717
- details: {
6718
- oldValue: false,
6719
- newValue: true
6720
- },
6721
- severity: "medium",
6722
- warning: `Making "${fieldMod.fieldName}" required may cause issues with existing records that have null/empty values.`
6723
- });
6724
- }
6725
- }
6726
- }
6727
- return changes;
6728
- }
6729
- function detectDestructiveChanges(diff) {
6730
- const changes = [];
6731
- changes.push(...detectCollectionDeletions(diff));
6732
- changes.push(...detectFieldDeletions(diff));
6733
- changes.push(...detectFieldTypeChanges(diff));
6734
- changes.push(...detectFieldRequiredChanges(diff));
6735
- return changes;
6736
- }
6737
- function formatDestructiveChanges(changes) {
6738
- if (changes.length === 0) {
6739
- return "No destructive changes detected.";
6740
- }
6741
- const lines = [];
6742
- const highSeverity = changes.filter((c) => c.severity === "high");
6743
- const mediumSeverity = changes.filter((c) => c.severity === "medium");
6744
- const lowSeverity = changes.filter((c) => c.severity === "low");
6745
- if (highSeverity.length > 0) {
6746
- lines.push("\u{1F534} HIGH SEVERITY CHANGES (Data Loss Risk):");
6747
- lines.push("");
6748
- for (const change of highSeverity) {
6749
- lines.push(` \u2022 ${change.description}`);
6750
- lines.push(` \u26A0\uFE0F ${change.warning}`);
6751
- if (change.details) {
6752
- if (change.details.oldValue !== void 0 && change.details.newValue !== void 0) {
6753
- lines.push(` Old: ${change.details.oldValue} \u2192 New: ${change.details.newValue}`);
6754
- }
6755
- }
6756
- lines.push("");
6757
- }
6758
- }
6759
- if (mediumSeverity.length > 0) {
6760
- lines.push("\u{1F7E1} MEDIUM SEVERITY CHANGES (Potential Issues):");
6761
- lines.push("");
6762
- for (const change of mediumSeverity) {
6763
- lines.push(` \u2022 ${change.description}`);
6764
- lines.push(` \u26A0\uFE0F ${change.warning}`);
6765
- if (change.details) {
6766
- if (change.details.oldValue !== void 0 && change.details.newValue !== void 0) {
6767
- lines.push(` Old: ${change.details.oldValue} \u2192 New: ${change.details.newValue}`);
6768
- }
6769
- }
6770
- lines.push("");
6771
- }
6772
- }
6773
- if (lowSeverity.length > 0) {
6774
- lines.push("\u{1F7E2} LOW SEVERITY CHANGES:");
6775
- lines.push("");
6776
- for (const change of lowSeverity) {
6777
- lines.push(` \u2022 ${change.description}`);
6778
- lines.push(` \u2139\uFE0F ${change.warning}`);
6779
- lines.push("");
6780
- }
6781
- }
6782
- return lines.join("\n");
6783
- }
6784
- function summarizeDestructiveChanges(changes) {
6785
- return {
6786
- total: changes.length,
6787
- high: changes.filter((c) => c.severity === "high").length,
6788
- medium: changes.filter((c) => c.severity === "medium").length,
6789
- low: changes.filter((c) => c.severity === "low").length
6790
- };
6791
- }
6792
- function requiresForceFlag(changes) {
6793
- return changes.some((c) => c.severity === "high" || c.severity === "medium");
6794
- }
6795
6672
  var CONFIG_FILE_NAMES = [
6796
6673
  "pocketbase-migrate.config.js",
6797
6674
  "pocketbase-migrate.config.mjs",
@@ -6800,7 +6677,7 @@ var CONFIG_FILE_NAMES = [
6800
6677
  "migrate.config.mjs",
6801
6678
  "migrate.config.json"
6802
6679
  ];
6803
- var DEFAULT_CONFIG5 = {
6680
+ var DEFAULT_CONFIG4 = {
6804
6681
  schema: {
6805
6682
  directory: "src/schema",
6806
6683
  exclude: ["base.ts", "index.ts", "permissions.ts", "permission-templates.ts"]
@@ -6821,7 +6698,7 @@ var DEFAULT_CONFIG5 = {
6821
6698
  };
6822
6699
  function findConfigFile(directory) {
6823
6700
  for (const fileName of CONFIG_FILE_NAMES) {
6824
- const filePath = path8__namespace.join(directory, fileName);
6701
+ const filePath = path7__namespace.join(directory, fileName);
6825
6702
  if (fs10__namespace.existsSync(filePath)) {
6826
6703
  return filePath;
6827
6704
  }
@@ -6862,7 +6739,7 @@ async function loadConfigFile(configPath) {
6862
6739
  if (!fs10__namespace.existsSync(configPath)) {
6863
6740
  return null;
6864
6741
  }
6865
- const ext = path8__namespace.extname(configPath).toLowerCase();
6742
+ const ext = path7__namespace.extname(configPath).toLowerCase();
6866
6743
  if (ext === ".json") {
6867
6744
  return loadJsonConfig(configPath);
6868
6745
  } else if (ext === ".js" || ext === ".mjs") {
@@ -6957,8 +6834,8 @@ function validateConfig(config, configPath) {
6957
6834
  }
6958
6835
  const cwd = process.cwd();
6959
6836
  const possiblePaths = [
6960
- path8__namespace.resolve(cwd, config.schema.directory),
6961
- path8__namespace.resolve(cwd, "shared", config.schema.directory)
6837
+ path7__namespace.resolve(cwd, config.schema.directory),
6838
+ path7__namespace.resolve(cwd, "shared", config.schema.directory)
6962
6839
  ];
6963
6840
  const schemaDir = possiblePaths.find((p) => fs10__namespace.existsSync(p));
6964
6841
  if (!schemaDir) {
@@ -6968,17 +6845,17 @@ function validateConfig(config, configPath) {
6968
6845
  }
6969
6846
  }
6970
6847
  async function loadConfig(options = {}) {
6971
- let config = { ...DEFAULT_CONFIG5 };
6848
+ let config = { ...DEFAULT_CONFIG4 };
6972
6849
  let configFilePath;
6973
6850
  const cwd = process.cwd();
6974
6851
  if (options.config) {
6975
- const explicitPath = path8__namespace.resolve(cwd, options.config);
6852
+ const explicitPath = path7__namespace.resolve(cwd, options.config);
6976
6853
  if (!fs10__namespace.existsSync(explicitPath)) {
6977
6854
  throw new ConfigurationError(`Configuration file not found: ${explicitPath}`, explicitPath);
6978
6855
  }
6979
6856
  configFilePath = explicitPath;
6980
6857
  } else {
6981
- const searchDirs = [cwd, path8__namespace.join(cwd, "shared")];
6858
+ const searchDirs = [cwd, path7__namespace.join(cwd, "shared")];
6982
6859
  for (const dir of searchDirs) {
6983
6860
  if (fs10__namespace.existsSync(dir)) {
6984
6861
  const found = findConfigFile(dir);
@@ -7009,23 +6886,23 @@ async function loadConfig(options = {}) {
7009
6886
  function getSchemaDirectory(config) {
7010
6887
  const cwd = process.cwd();
7011
6888
  const possiblePaths = [
7012
- path8__namespace.resolve(cwd, config.schema.directory),
7013
- path8__namespace.resolve(cwd, "shared", config.schema.directory)
6889
+ path7__namespace.resolve(cwd, config.schema.directory),
6890
+ path7__namespace.resolve(cwd, "shared", config.schema.directory)
7014
6891
  ];
7015
6892
  return possiblePaths.find((p) => fs10__namespace.existsSync(p)) || possiblePaths[0];
7016
6893
  }
7017
6894
  function getMigrationsDirectory(config) {
7018
6895
  const cwd = process.cwd();
7019
6896
  const possiblePaths = [
7020
- path8__namespace.resolve(cwd, config.migrations.directory),
7021
- path8__namespace.resolve(cwd, "shared", config.migrations.directory)
6897
+ path7__namespace.resolve(cwd, config.migrations.directory),
6898
+ path7__namespace.resolve(cwd, "shared", config.migrations.directory)
7022
6899
  ];
7023
6900
  return possiblePaths.find((p) => fs10__namespace.existsSync(p)) || possiblePaths[0];
7024
6901
  }
7025
6902
  function getDataDirectory(config) {
7026
6903
  const configured = config.migrations.dataDirectory.trim();
7027
6904
  if (configured !== "") {
7028
- return path8__namespace.resolve(process.cwd(), configured);
6905
+ return path7__namespace.resolve(process.cwd(), configured);
7029
6906
  }
7030
6907
  return defaultDataDirectory(getMigrationsDirectory(config));
7031
6908
  }
@@ -7324,8 +7201,7 @@ async function executeGenerate(filters, options) {
7324
7201
  logSuccess(`Found ${currentSchema.collections.size} collection(s)`);
7325
7202
  logInfo("Loading previous snapshot...");
7326
7203
  const previousSnapshot = loadSnapshotWithMigrations({
7327
- migrationsPath: migrationsDir,
7328
- workspaceRoot: process.cwd()
7204
+ migrationsPath: migrationsDir
7329
7205
  });
7330
7206
  if (!previousSnapshot) {
7331
7207
  logInfo("No previous snapshot found - treating as empty database (first-time generation)");
@@ -7378,7 +7254,7 @@ async function executeGenerate(filters, options) {
7378
7254
  }
7379
7255
  const migrationPaths = writePlannedMigrations(planned, migrationsDir);
7380
7256
  if (migrationPaths.length === 1) {
7381
- logSuccess(`Migration file created: ${path8__namespace.basename(migrationPaths[0])}`);
7257
+ logSuccess(`Migration file created: ${path7__namespace.basename(migrationPaths[0])}`);
7382
7258
  } else {
7383
7259
  logSuccess(`Created ${migrationPaths.length} migration files`);
7384
7260
  }
@@ -7404,7 +7280,7 @@ async function executeGenerate(filters, options) {
7404
7280
  logInfo("Suggestions:");
7405
7281
  console.log(" \u2022 Make sure your schema files are valid Zod schemas");
7406
7282
  console.log(' \u2022 Run "yarn build" in the shared workspace to compile TypeScript files');
7407
- console.log(' \u2022 Check that schema files export schemas ending with "Schema" or "InputSchema"');
7283
+ console.log(" \u2022 Check that each schema file exports a defineCollection()/defineView() result (default export preferred)");
7408
7284
  } else if (error instanceof SnapshotError) {
7409
7285
  logError("Snapshot Error");
7410
7286
  console.error();
@@ -7754,13 +7630,13 @@ async function executeGenerateTypes(options) {
7754
7630
  const generator = new TypeGenerator(currentSchema);
7755
7631
  const output = await withProgress("Generating TypeScript definitions...", () => Promise.resolve(generator.generate()));
7756
7632
  const outputPath = options.output || config.typeGen.outPath;
7757
- const resolvedPath = path8__namespace.resolve(process.cwd(), outputPath);
7633
+ const resolvedPath = path7__namespace.resolve(process.cwd(), outputPath);
7758
7634
  fs10__namespace.writeFileSync(resolvedPath, output);
7759
7635
  logSuccess(`Types generated successfully at: ${outputPath}`);
7760
7636
  logSection("\u2705 Next Steps");
7761
7637
  console.log();
7762
7638
  console.log(" 1. Import types in your application:");
7763
- console.log(` import { TypedPocketBase } from "./${path8__namespace.basename(outputPath).replace(/\.ts$/, "")}";`);
7639
+ console.log(` import { TypedPocketBase } from "./${path7__namespace.basename(outputPath).replace(/\.ts$/, "")}";`);
7764
7640
  console.log();
7765
7641
  } catch (error) {
7766
7642
  logError(`Failed to generate types: ${error}`);
@@ -7782,14 +7658,14 @@ function collectExecutionWarnings(files) {
7782
7658
  const result = executeMigrationFile(file, store);
7783
7659
  byFile.set(file, result.warnings);
7784
7660
  } catch (error) {
7785
- logDebug(`Skipping execution of ${path8__namespace.basename(file)}: ${error}`);
7661
+ logDebug(`Skipping execution of ${path7__namespace.basename(file)}: ${error}`);
7786
7662
  byFile.set(file, []);
7787
7663
  }
7788
7664
  }
7789
7665
  return byFile;
7790
7666
  }
7791
7667
  function reportResult(result) {
7792
- const name = path8__namespace.basename(result.file);
7668
+ const name = path7__namespace.basename(result.file);
7793
7669
  if (result.findings.length === 0) {
7794
7670
  logDebug(`\u2713 ${name}`);
7795
7671
  return true;
@@ -7815,7 +7691,7 @@ async function executeLint(files, options) {
7815
7691
  }
7816
7692
  const config = await loadConfig(options);
7817
7693
  const migrationsDir = getMigrationsDirectory(config);
7818
- const targets = files.length > 0 ? files.map((file) => path8__namespace.resolve(process.cwd(), file)) : discoverMigrations(migrationsDir).map((migration) => migration.path);
7694
+ const targets = files.length > 0 ? files.map((file) => path7__namespace.resolve(process.cwd(), file)) : discoverMigrations(migrationsDir).map((migration) => migration.path);
7819
7695
  logSection("\u{1F50E} Checking goja Compatibility");
7820
7696
  console.log();
7821
7697
  if (targets.length === 0) {
@@ -7924,17 +7800,15 @@ function lookupAppliedMigrations(migrationsDir, dataPath) {
7924
7800
  throw error;
7925
7801
  }
7926
7802
  }
7927
- function loadStatusBaselines(currentSchema, migrationsDir, workspaceRoot, applied) {
7803
+ function loadStatusBaselines(currentSchema, migrationsDir, applied) {
7928
7804
  const previousSnapshot = loadSnapshotWithMigrations({
7929
- migrationsPath: migrationsDir,
7930
- workspaceRoot
7805
+ migrationsPath: migrationsDir
7931
7806
  });
7932
7807
  if (applied?.status !== "found" || applied.plan.inSync) {
7933
7808
  return { previousSnapshot, appliedDiff: null };
7934
7809
  }
7935
7810
  const appliedSnapshot = loadSnapshotWithMigrations({
7936
7811
  migrationsPath: migrationsDir,
7937
- workspaceRoot,
7938
7812
  appliedMigrations: applied.applied
7939
7813
  });
7940
7814
  return { previousSnapshot, appliedDiff: compare2(currentSchema, appliedSnapshot) };
@@ -8081,7 +7955,7 @@ async function executeStatus(options) {
8081
7955
  process.exit(1);
8082
7956
  }
8083
7957
  logInfo("Loading previous snapshot...");
8084
- const { previousSnapshot, appliedDiff } = loadStatusBaselines(currentSchema, migrationsDir, process.cwd(), applied);
7958
+ const { previousSnapshot, appliedDiff } = loadStatusBaselines(currentSchema, migrationsDir, applied);
8085
7959
  if (applied?.status === "found" && !isJsonMode) {
8086
7960
  const inSync = reportAppliedMigrations(applied.plan);
8087
7961
  if (!inSync) {
@@ -8183,7 +8057,7 @@ async function executeStatus(options) {
8183
8057
  console.error();
8184
8058
  logInfo("Suggestions:");
8185
8059
  console.log(" \u2022 Make sure your schema files are valid Zod schemas");
8186
- console.log(' \u2022 Check that schema files export schemas ending with "Schema" or "InputSchema"');
8060
+ console.log(" \u2022 Check that each schema file exports a defineCollection()/defineView() result (default export preferred)");
8187
8061
  } else if (error instanceof SnapshotError) {
8188
8062
  logError("Snapshot Error");
8189
8063
  console.error();
@@ -8229,8 +8103,8 @@ Examples:
8229
8103
  function getVersion() {
8230
8104
  try {
8231
8105
  const __filename2 = url.fileURLToPath(importMetaUrl);
8232
- const __dirname = path8.dirname(__filename2);
8233
- const packageJsonPath = path8.join(__dirname, "../../package.json");
8106
+ const __dirname = path7.dirname(__filename2);
8107
+ const packageJsonPath = path7.join(__dirname, "../../package.json");
8234
8108
  const packageJson = JSON.parse(fs10.readFileSync(packageJsonPath, "utf-8"));
8235
8109
  return packageJson.version || "0.0.0";
8236
8110
  } catch {