pocketbase-zod-schema 0.1.2 → 0.1.4

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 (69) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +329 -99
  3. package/dist/cli/index.cjs +577 -152
  4. package/dist/cli/index.cjs.map +1 -1
  5. package/dist/cli/index.js +575 -150
  6. package/dist/cli/index.js.map +1 -1
  7. package/dist/cli/migrate.cjs +595 -153
  8. package/dist/cli/migrate.cjs.map +1 -1
  9. package/dist/cli/migrate.js +592 -151
  10. package/dist/cli/migrate.js.map +1 -1
  11. package/dist/cli/utils/index.cjs +1 -1
  12. package/dist/cli/utils/index.cjs.map +1 -1
  13. package/dist/cli/utils/index.js +1 -1
  14. package/dist/cli/utils/index.js.map +1 -1
  15. package/dist/index.cjs +688 -231
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +3 -3
  18. package/dist/index.d.ts +3 -3
  19. package/dist/index.js +685 -230
  20. package/dist/index.js.map +1 -1
  21. package/dist/migration/analyzer.cjs +101 -28
  22. package/dist/migration/analyzer.cjs.map +1 -1
  23. package/dist/migration/analyzer.js +101 -28
  24. package/dist/migration/analyzer.js.map +1 -1
  25. package/dist/migration/diff.cjs +21 -3
  26. package/dist/migration/diff.cjs.map +1 -1
  27. package/dist/migration/diff.js +21 -3
  28. package/dist/migration/diff.js.map +1 -1
  29. package/dist/migration/generator.cjs +60 -25
  30. package/dist/migration/generator.cjs.map +1 -1
  31. package/dist/migration/generator.d.cts +9 -5
  32. package/dist/migration/generator.d.ts +9 -5
  33. package/dist/migration/generator.js +60 -25
  34. package/dist/migration/generator.js.map +1 -1
  35. package/dist/migration/index.cjs +614 -171
  36. package/dist/migration/index.cjs.map +1 -1
  37. package/dist/migration/index.d.cts +1 -1
  38. package/dist/migration/index.d.ts +1 -1
  39. package/dist/migration/index.js +613 -171
  40. package/dist/migration/index.js.map +1 -1
  41. package/dist/migration/snapshot.cjs +432 -117
  42. package/dist/migration/snapshot.cjs.map +1 -1
  43. package/dist/migration/snapshot.d.cts +34 -12
  44. package/dist/migration/snapshot.d.ts +34 -12
  45. package/dist/migration/snapshot.js +430 -116
  46. package/dist/migration/snapshot.js.map +1 -1
  47. package/dist/migration/utils/index.cjs +19 -17
  48. package/dist/migration/utils/index.cjs.map +1 -1
  49. package/dist/migration/utils/index.d.cts +3 -1
  50. package/dist/migration/utils/index.d.ts +3 -1
  51. package/dist/migration/utils/index.js +19 -17
  52. package/dist/migration/utils/index.js.map +1 -1
  53. package/dist/mutator.cjs +9 -11
  54. package/dist/mutator.cjs.map +1 -1
  55. package/dist/mutator.d.cts +5 -9
  56. package/dist/mutator.d.ts +5 -9
  57. package/dist/mutator.js +9 -11
  58. package/dist/mutator.js.map +1 -1
  59. package/dist/schema.cjs +54 -23
  60. package/dist/schema.cjs.map +1 -1
  61. package/dist/schema.d.cts +94 -12
  62. package/dist/schema.d.ts +94 -12
  63. package/dist/schema.js +54 -24
  64. package/dist/schema.js.map +1 -1
  65. package/dist/types.d.cts +1 -1
  66. package/dist/types.d.ts +1 -1
  67. package/dist/{user-jS1aYoeD.d.cts → user-_AM523hb.d.cts} +6 -6
  68. package/dist/{user-jS1aYoeD.d.ts → user-_AM523hb.d.ts} +6 -6
  69. package/package.json +2 -4
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var path4 = require('path');
4
- var fs4 = require('fs');
3
+ var path5 = require('path');
4
+ var fs5 = require('fs');
5
5
  var zod = require('zod');
6
6
  var chalk = require('chalk');
7
7
  var ora = require('ora');
@@ -26,12 +26,41 @@ function _interopNamespace(e) {
26
26
  return Object.freeze(n);
27
27
  }
28
28
 
29
- var path4__namespace = /*#__PURE__*/_interopNamespace(path4);
30
- var fs4__namespace = /*#__PURE__*/_interopNamespace(fs4);
29
+ var path5__namespace = /*#__PURE__*/_interopNamespace(path5);
30
+ var fs5__namespace = /*#__PURE__*/_interopNamespace(fs5);
31
31
  var chalk__default = /*#__PURE__*/_interopDefault(chalk);
32
32
  var ora__default = /*#__PURE__*/_interopDefault(ora);
33
33
 
34
34
  // src/cli/commands/generate.ts
35
+ ({
36
+ id: zod.z.string().describe("unique id"),
37
+ collectionId: zod.z.string().describe("collection id"),
38
+ collectionName: zod.z.string().describe("collection name"),
39
+ expand: zod.z.record(zod.z.any()).describe("expandable fields")
40
+ });
41
+ ({
42
+ created: zod.z.string().describe("creation timestamp"),
43
+ updated: zod.z.string().describe("last update timestamp")
44
+ });
45
+ ({
46
+ thumbnailURL: zod.z.string().optional(),
47
+ imageFiles: zod.z.array(zod.z.string())
48
+ });
49
+ ({
50
+ imageFiles: zod.z.array(zod.z.instanceof(File))
51
+ });
52
+ var RELATION_METADATA_KEY = "__pocketbase_relation__";
53
+ function extractRelationMetadata(description) {
54
+ if (!description) return null;
55
+ try {
56
+ const parsed = JSON.parse(description);
57
+ if (parsed[RELATION_METADATA_KEY]) {
58
+ return parsed[RELATION_METADATA_KEY];
59
+ }
60
+ } catch {
61
+ }
62
+ return null;
63
+ }
35
64
 
36
65
  // src/migration/errors.ts
37
66
  var MigrationError = class _MigrationError extends Error {
@@ -130,10 +159,10 @@ var FileSystemError = class _FileSystemError extends MigrationError {
130
159
  operation;
131
160
  code;
132
161
  originalError;
133
- constructor(message, path6, operation, code, originalError) {
162
+ constructor(message, path7, operation, code, originalError) {
134
163
  super(message);
135
164
  this.name = "FileSystemError";
136
- this.path = path6;
165
+ this.path = path7;
137
166
  this.operation = operation;
138
167
  this.code = code;
139
168
  this.originalError = originalError;
@@ -196,7 +225,7 @@ Cause: ${this.originalError.message}`);
196
225
  }
197
226
  };
198
227
 
199
- // src/schema/permission-templates.ts
228
+ // src/utils/permission-templates.ts
200
229
  var PermissionTemplates = {
201
230
  /**
202
231
  * Public access - anyone can perform all operations
@@ -855,26 +884,28 @@ function getMaxSelect(fieldName, zodType) {
855
884
  return 1;
856
885
  }
857
886
  function getMinSelect(fieldName, zodType) {
858
- if (!isMultipleRelationField(fieldName, zodType)) {
859
- return void 0;
860
- }
861
- let unwrappedType = zodType;
862
- if (zodType instanceof zod.z.ZodOptional) {
863
- unwrappedType = zodType._def.innerType;
864
- }
865
- if (unwrappedType instanceof zod.z.ZodNullable) {
866
- unwrappedType = unwrappedType._def.innerType;
867
- }
868
- if (unwrappedType instanceof zod.z.ZodDefault) {
869
- unwrappedType = unwrappedType._def.innerType;
887
+ if (isSingleRelationField(fieldName, zodType)) {
888
+ return 0;
870
889
  }
871
- if (unwrappedType instanceof zod.z.ZodArray) {
872
- const arrayDef = unwrappedType._def;
873
- if (arrayDef.minLength) {
874
- return arrayDef.minLength.value;
890
+ if (isMultipleRelationField(fieldName, zodType)) {
891
+ let unwrappedType = zodType;
892
+ if (zodType instanceof zod.z.ZodOptional) {
893
+ unwrappedType = zodType._def.innerType;
894
+ }
895
+ if (unwrappedType instanceof zod.z.ZodNullable) {
896
+ unwrappedType = unwrappedType._def.innerType;
897
+ }
898
+ if (unwrappedType instanceof zod.z.ZodDefault) {
899
+ unwrappedType = unwrappedType._def.innerType;
900
+ }
901
+ if (unwrappedType instanceof zod.z.ZodArray) {
902
+ const arrayDef = unwrappedType._def;
903
+ if (arrayDef.minLength) {
904
+ return arrayDef.minLength.value;
905
+ }
875
906
  }
876
907
  }
877
- return void 0;
908
+ return 0;
878
909
  }
879
910
  function mapZodStringType(zodType) {
880
911
  const checks = zodType._def.checks || [];
@@ -1072,20 +1103,20 @@ function mergeConfig(config) {
1072
1103
  }
1073
1104
  function resolveSchemaDir(config) {
1074
1105
  const workspaceRoot = config.workspaceRoot || process.cwd();
1075
- if (path4__namespace.isAbsolute(config.schemaDir)) {
1106
+ if (path5__namespace.isAbsolute(config.schemaDir)) {
1076
1107
  return config.schemaDir;
1077
1108
  }
1078
- return path4__namespace.join(workspaceRoot, config.schemaDir);
1109
+ return path5__namespace.join(workspaceRoot, config.schemaDir);
1079
1110
  }
1080
1111
  function discoverSchemaFiles(config) {
1081
1112
  const normalizedConfig = typeof config === "string" ? { schemaDir: config } : config;
1082
1113
  const mergedConfig = mergeConfig(normalizedConfig);
1083
1114
  const schemaDir = resolveSchemaDir(normalizedConfig);
1084
1115
  try {
1085
- if (!fs4__namespace.existsSync(schemaDir)) {
1116
+ if (!fs5__namespace.existsSync(schemaDir)) {
1086
1117
  throw new FileSystemError(`Schema directory not found: ${schemaDir}`, schemaDir, "access", "ENOENT");
1087
1118
  }
1088
- const files = fs4__namespace.readdirSync(schemaDir);
1119
+ const files = fs5__namespace.readdirSync(schemaDir);
1089
1120
  const schemaFiles = files.filter((file) => {
1090
1121
  const hasValidExtension = mergedConfig.includeExtensions.some((ext) => file.endsWith(ext));
1091
1122
  if (!hasValidExtension) return false;
@@ -1101,7 +1132,7 @@ function discoverSchemaFiles(config) {
1101
1132
  });
1102
1133
  return schemaFiles.map((file) => {
1103
1134
  const ext = mergedConfig.includeExtensions.find((ext2) => file.endsWith(ext2)) || ".ts";
1104
- return path4__namespace.join(schemaDir, file.replace(new RegExp(`\\${ext}$`), ""));
1135
+ return path5__namespace.join(schemaDir, file.replace(new RegExp(`\\${ext}$`), ""));
1105
1136
  });
1106
1137
  } catch (error) {
1107
1138
  if (error instanceof FileSystemError) {
@@ -1132,13 +1163,32 @@ async function importSchemaModule(filePath, config) {
1132
1163
  if (config?.pathTransformer) {
1133
1164
  importPath = config.pathTransformer(filePath);
1134
1165
  }
1135
- if (!importPath.endsWith(".js")) {
1136
- importPath = `${importPath}.js`;
1166
+ let resolvedPath = null;
1167
+ const jsPath = `${importPath}.js`;
1168
+ const tsPath = `${importPath}.ts`;
1169
+ if (fs5__namespace.existsSync(jsPath)) {
1170
+ resolvedPath = jsPath;
1171
+ } else if (fs5__namespace.existsSync(tsPath)) {
1172
+ resolvedPath = tsPath;
1173
+ } else {
1174
+ resolvedPath = jsPath;
1137
1175
  }
1138
- const fileUrl = new URL(`file://${path4__namespace.resolve(importPath)}`);
1176
+ const fileUrl = new URL(`file://${path5__namespace.resolve(resolvedPath)}`);
1139
1177
  const module = await import(fileUrl.href);
1140
1178
  return module;
1141
1179
  } catch (error) {
1180
+ const tsPath = `${filePath}.ts`;
1181
+ const isTypeScriptFile = fs5__namespace.existsSync(tsPath);
1182
+ if (isTypeScriptFile) {
1183
+ throw new SchemaParsingError(
1184
+ `Failed to import TypeScript schema file. Node.js cannot import TypeScript files directly.
1185
+ Please either:
1186
+ 1. Compile your schema files to JavaScript first, or
1187
+ 2. Use tsx to run the migration tool (e.g., "npx tsx package/dist/cli/migrate.js status" or "tsx package/dist/cli/migrate.js status")`,
1188
+ filePath,
1189
+ error
1190
+ );
1191
+ }
1142
1192
  throw new SchemaParsingError(
1143
1193
  `Failed to import schema module. Make sure the schema files are compiled to JavaScript.`,
1144
1194
  filePath,
@@ -1147,7 +1197,7 @@ async function importSchemaModule(filePath, config) {
1147
1197
  }
1148
1198
  }
1149
1199
  function getCollectionNameFromFile(filePath) {
1150
- const filename = path4__namespace.basename(filePath).replace(/\.(ts|js)$/, "");
1200
+ const filename = path5__namespace.basename(filePath).replace(/\.(ts|js)$/, "");
1151
1201
  return toCollectionName(filename);
1152
1202
  }
1153
1203
  function extractSchemaDefinitions(module, patterns = ["Schema", "InputSchema"]) {
@@ -1201,7 +1251,17 @@ function buildFieldDefinition(fieldName, zodType) {
1201
1251
  required,
1202
1252
  options
1203
1253
  };
1204
- if (isRelationField(fieldName, zodType)) {
1254
+ const relationMetadata = extractRelationMetadata(zodType.description);
1255
+ if (relationMetadata) {
1256
+ fieldDef.type = "relation";
1257
+ fieldDef.relation = {
1258
+ collection: relationMetadata.collection,
1259
+ maxSelect: relationMetadata.maxSelect,
1260
+ minSelect: relationMetadata.minSelect,
1261
+ cascadeDelete: relationMetadata.cascadeDelete
1262
+ };
1263
+ fieldDef.options = void 0;
1264
+ } else if (isRelationField(fieldName, zodType)) {
1205
1265
  fieldDef.type = "relation";
1206
1266
  const targetCollection = resolveTargetCollection(fieldName);
1207
1267
  const maxSelect = getMaxSelect(fieldName, zodType);
@@ -1213,6 +1273,13 @@ function buildFieldDefinition(fieldName, zodType) {
1213
1273
  cascadeDelete: false
1214
1274
  // Default to false, can be configured later
1215
1275
  };
1276
+ if (fieldDef.options) {
1277
+ const { min, max, pattern, ...relationSafeOptions } = fieldDef.options;
1278
+ console.log("min", min);
1279
+ console.log("max", max);
1280
+ console.log("pattern", pattern);
1281
+ fieldDef.options = Object.keys(relationSafeOptions).length > 0 ? relationSafeOptions : void 0;
1282
+ }
1216
1283
  }
1217
1284
  return fieldDef;
1218
1285
  }
@@ -1265,11 +1332,12 @@ function convertZodSchemaToCollectionSchema(collectionName, zodSchema) {
1265
1332
  fields,
1266
1333
  indexes,
1267
1334
  rules: {
1268
- listRule: null,
1269
- viewRule: null,
1270
- createRule: null,
1271
- updateRule: null,
1272
- deleteRule: null
1335
+ listRule: permissions?.listRule ?? null,
1336
+ viewRule: permissions?.viewRule ?? null,
1337
+ createRule: permissions?.createRule ?? null,
1338
+ updateRule: permissions?.updateRule ?? null,
1339
+ deleteRule: permissions?.deleteRule ?? null,
1340
+ manageRule: permissions?.manageRule ?? null
1273
1341
  },
1274
1342
  permissions
1275
1343
  };
@@ -1293,7 +1361,12 @@ async function buildSchemaDefinition(config) {
1293
1361
  if (normalizedConfig.pathTransformer) {
1294
1362
  importPath = normalizedConfig.pathTransformer(filePath);
1295
1363
  } else if (mergedConfig.useCompiledFiles) {
1296
- importPath = filePath.replace(/\/src\//, "/dist/");
1364
+ const distPath = filePath.replace(/\/src\//, "/dist/");
1365
+ if (fs5__namespace.existsSync(`${distPath}.js`) || fs5__namespace.existsSync(`${distPath}.mjs`)) {
1366
+ importPath = distPath;
1367
+ } else {
1368
+ importPath = filePath;
1369
+ }
1297
1370
  }
1298
1371
  const module = await importSchemaModule(importPath, normalizedConfig);
1299
1372
  const schemas = extractSchemaDefinitions(module, mergedConfig.schemaPatterns);
@@ -1466,6 +1539,9 @@ function compareFieldOptions(currentField, previousField) {
1466
1539
  for (const key of allKeys) {
1467
1540
  const currentValue = currentOptions[key];
1468
1541
  const previousValue = previousOptions[key];
1542
+ if (currentValue === void 0 && previousValue === void 0) {
1543
+ continue;
1544
+ }
1469
1545
  if (!areValuesEqual(currentValue, previousValue)) {
1470
1546
  changes.push({
1471
1547
  property: `options.${key}`,
@@ -1486,11 +1562,26 @@ function compareRelationConfigurations(currentField, previousField) {
1486
1562
  if (!currentRelation || !previousRelation) {
1487
1563
  return changes;
1488
1564
  }
1489
- if (currentRelation.collection !== previousRelation.collection) {
1565
+ const normalizeCollection = (collection) => {
1566
+ if (!collection) return collection;
1567
+ if (collection === "_pb_users_auth_") {
1568
+ return "Users";
1569
+ }
1570
+ const nameMatch = collection.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
1571
+ if (nameMatch) {
1572
+ return nameMatch[1];
1573
+ }
1574
+ return collection;
1575
+ };
1576
+ const normalizedCurrent = normalizeCollection(currentRelation.collection);
1577
+ const normalizedPrevious = normalizeCollection(previousRelation.collection);
1578
+ if (normalizedCurrent !== normalizedPrevious) {
1490
1579
  changes.push({
1491
1580
  property: "relation.collection",
1492
- oldValue: previousRelation.collection,
1493
- newValue: currentRelation.collection
1581
+ oldValue: normalizedPrevious,
1582
+ // Use normalized value for clarity
1583
+ newValue: normalizedCurrent
1584
+ // Use normalized value for clarity
1494
1585
  });
1495
1586
  }
1496
1587
  if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {
@@ -1691,10 +1782,8 @@ function compare(currentSchema, previousSnapshot, config) {
1691
1782
  var DEFAULT_TEMPLATE = `/// <reference path="{{TYPES_PATH}}" />
1692
1783
  migrate((app) => {
1693
1784
  {{UP_CODE}}
1694
- return true;
1695
1785
  }, (app) => {
1696
1786
  {{DOWN_CODE}}
1697
- return true;
1698
1787
  });
1699
1788
  `;
1700
1789
  var DEFAULT_CONFIG3 = {
@@ -1712,10 +1801,10 @@ function mergeConfig3(config) {
1712
1801
  }
1713
1802
  function resolveMigrationDir(config) {
1714
1803
  const workspaceRoot = config.workspaceRoot || process.cwd();
1715
- if (path4__namespace.isAbsolute(config.migrationDir)) {
1804
+ if (path5__namespace.isAbsolute(config.migrationDir)) {
1716
1805
  return config.migrationDir;
1717
1806
  }
1718
- return path4__namespace.join(workspaceRoot, config.migrationDir);
1807
+ return path5__namespace.join(workspaceRoot, config.migrationDir);
1719
1808
  }
1720
1809
  function generateTimestamp(config) {
1721
1810
  if (config?.timestampGenerator) {
@@ -1773,9 +1862,9 @@ function createMigrationFileStructure(upCode, downCode, config) {
1773
1862
  }
1774
1863
  function writeMigrationFile(migrationDir, filename, content) {
1775
1864
  try {
1776
- if (!fs4__namespace.existsSync(migrationDir)) {
1865
+ if (!fs5__namespace.existsSync(migrationDir)) {
1777
1866
  try {
1778
- fs4__namespace.mkdirSync(migrationDir, { recursive: true });
1867
+ fs5__namespace.mkdirSync(migrationDir, { recursive: true });
1779
1868
  } catch (error) {
1780
1869
  const fsError = error;
1781
1870
  if (fsError.code === "EACCES" || fsError.code === "EPERM") {
@@ -1796,15 +1885,15 @@ function writeMigrationFile(migrationDir, filename, content) {
1796
1885
  );
1797
1886
  }
1798
1887
  }
1799
- const filePath = path4__namespace.join(migrationDir, filename);
1800
- fs4__namespace.writeFileSync(filePath, content, "utf-8");
1888
+ const filePath = path5__namespace.join(migrationDir, filename);
1889
+ fs5__namespace.writeFileSync(filePath, content, "utf-8");
1801
1890
  return filePath;
1802
1891
  } catch (error) {
1803
1892
  if (error instanceof FileSystemError) {
1804
1893
  throw error;
1805
1894
  }
1806
1895
  const fsError = error;
1807
- const filePath = path4__namespace.join(migrationDir, filename);
1896
+ const filePath = path5__namespace.join(migrationDir, filename);
1808
1897
  if (fsError.code === "EACCES" || fsError.code === "EPERM") {
1809
1898
  throw new FileSystemError(
1810
1899
  `Permission denied writing migration file. Check file and directory permissions.`,
@@ -1859,7 +1948,8 @@ function generateFieldDefinitionObject(field) {
1859
1948
  }
1860
1949
  }
1861
1950
  if (field.relation) {
1862
- const collectionIdPlaceholder = field.relation.collection === "Users" ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
1951
+ const isUsersCollection = field.relation.collection.toLowerCase() === "users";
1952
+ const collectionIdPlaceholder = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
1863
1953
  parts.push(` collectionId: ${collectionIdPlaceholder}`);
1864
1954
  if (field.relation.maxSelect !== void 0) {
1865
1955
  parts.push(` maxSelect: ${field.relation.maxSelect}`);
@@ -1943,7 +2033,7 @@ function generateIndexesArray(indexes) {
1943
2033
  ${indexStrings.join(",\n ")},
1944
2034
  ]`;
1945
2035
  }
1946
- function generateCollectionCreation(collection, varName = "collection") {
2036
+ function generateCollectionCreation(collection, varName = "collection", isLast = false) {
1947
2037
  const lines = [];
1948
2038
  lines.push(` const ${varName} = new Collection({`);
1949
2039
  lines.push(` name: "${collection.name}",`);
@@ -1959,7 +2049,7 @@ function generateCollectionCreation(collection, varName = "collection") {
1959
2049
  lines.push(` indexes: ${generateIndexesArray(collection.indexes)},`);
1960
2050
  lines.push(` });`);
1961
2051
  lines.push(``);
1962
- lines.push(` app.save(${varName});`);
2052
+ lines.push(isLast ? ` return app.save(${varName});` : ` app.save(${varName});`);
1963
2053
  return lines.join("\n");
1964
2054
  }
1965
2055
  function getFieldConstructorName(fieldType) {
@@ -1990,7 +2080,8 @@ function generateFieldConstructorOptions(field) {
1990
2080
  }
1991
2081
  }
1992
2082
  if (field.relation && field.type === "relation") {
1993
- const collectionIdPlaceholder = field.relation.collection === "Users" ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
2083
+ const isUsersCollection = field.relation.collection.toLowerCase() === "users";
2084
+ const collectionIdPlaceholder = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
1994
2085
  parts.push(` collectionId: ${collectionIdPlaceholder}`);
1995
2086
  if (field.relation.maxSelect !== void 0) {
1996
2087
  parts.push(` maxSelect: ${field.relation.maxSelect}`);
@@ -2004,7 +2095,7 @@ function generateFieldConstructorOptions(field) {
2004
2095
  }
2005
2096
  return parts.join(",\n");
2006
2097
  }
2007
- function generateFieldAddition(collectionName, field, varName) {
2098
+ function generateFieldAddition(collectionName, field, varName, isLast = false) {
2008
2099
  const lines = [];
2009
2100
  const constructorName = getFieldConstructorName(field.type);
2010
2101
  const collectionVar = varName || `collection_${collectionName}_${field.name}`;
@@ -2014,10 +2105,10 @@ function generateFieldAddition(collectionName, field, varName) {
2014
2105
  lines.push(generateFieldConstructorOptions(field));
2015
2106
  lines.push(` }));`);
2016
2107
  lines.push(``);
2017
- lines.push(` app.save(${collectionVar});`);
2108
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2018
2109
  return lines.join("\n");
2019
2110
  }
2020
- function generateFieldModification(collectionName, modification, varName) {
2111
+ function generateFieldModification(collectionName, modification, varName, isLast = false) {
2021
2112
  const lines = [];
2022
2113
  const collectionVar = varName || `collection_${collectionName}_${modification.fieldName}`;
2023
2114
  const fieldVar = `${collectionVar}_field`;
@@ -2031,7 +2122,8 @@ function generateFieldModification(collectionName, modification, varName) {
2031
2122
  } else if (change.property.startsWith("relation.")) {
2032
2123
  const relationKey = change.property.replace("relation.", "");
2033
2124
  if (relationKey === "collection") {
2034
- const collectionIdValue = change.newValue === "Users" ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${change.newValue}").id`;
2125
+ const isUsersCollection = String(change.newValue).toLowerCase() === "users";
2126
+ const collectionIdValue = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${change.newValue}").id`;
2035
2127
  lines.push(` ${fieldVar}.collectionId = ${collectionIdValue};`);
2036
2128
  } else {
2037
2129
  lines.push(` ${fieldVar}.${relationKey} = ${formatValue(change.newValue)};`);
@@ -2041,10 +2133,10 @@ function generateFieldModification(collectionName, modification, varName) {
2041
2133
  }
2042
2134
  }
2043
2135
  lines.push(``);
2044
- lines.push(` app.save(${collectionVar});`);
2136
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2045
2137
  return lines.join("\n");
2046
2138
  }
2047
- function generateFieldDeletion(collectionName, fieldName, varName) {
2139
+ function generateFieldDeletion(collectionName, fieldName, varName, isLast = false) {
2048
2140
  const lines = [];
2049
2141
  const collectionVar = varName || `collection_${collectionName}_${fieldName}`;
2050
2142
  const fieldVar = `${collectionVar}_field`;
@@ -2053,18 +2145,18 @@ function generateFieldDeletion(collectionName, fieldName, varName) {
2053
2145
  lines.push(``);
2054
2146
  lines.push(` ${collectionVar}.fields.remove(${fieldVar}.id);`);
2055
2147
  lines.push(``);
2056
- lines.push(` app.save(${collectionVar});`);
2148
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2057
2149
  return lines.join("\n");
2058
2150
  }
2059
- function generateIndexAddition(collectionName, index, varName) {
2151
+ function generateIndexAddition(collectionName, index, varName, isLast = false) {
2060
2152
  const lines = [];
2061
2153
  const collectionVar = varName || `collection_${collectionName}_idx`;
2062
2154
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
2063
2155
  lines.push(` ${collectionVar}.indexes.push("${index}");`);
2064
- lines.push(` app.save(${collectionVar});`);
2156
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2065
2157
  return lines.join("\n");
2066
2158
  }
2067
- function generateIndexRemoval(collectionName, index, varName) {
2159
+ function generateIndexRemoval(collectionName, index, varName, isLast = false) {
2068
2160
  const lines = [];
2069
2161
  const collectionVar = varName || `collection_${collectionName}_idx`;
2070
2162
  const indexVar = `${collectionVar}_indexToRemove`;
@@ -2073,29 +2165,29 @@ function generateIndexRemoval(collectionName, index, varName) {
2073
2165
  lines.push(` if (${indexVar} !== -1) {`);
2074
2166
  lines.push(` ${collectionVar}.indexes.splice(${indexVar}, 1);`);
2075
2167
  lines.push(` }`);
2076
- lines.push(` app.save(${collectionVar});`);
2168
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2077
2169
  return lines.join("\n");
2078
2170
  }
2079
- function generateRuleUpdate(collectionName, ruleType, newValue, varName) {
2171
+ function generateRuleUpdate(collectionName, ruleType, newValue, varName, isLast = false) {
2080
2172
  const lines = [];
2081
2173
  const collectionVar = varName || `collection_${collectionName}_${ruleType}`;
2082
2174
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
2083
2175
  lines.push(` ${collectionVar}.${ruleType} = ${formatValue(newValue)};`);
2084
- lines.push(` app.save(${collectionVar});`);
2176
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2085
2177
  return lines.join("\n");
2086
2178
  }
2087
- function generatePermissionUpdate(collectionName, ruleType, newValue, varName) {
2179
+ function generatePermissionUpdate(collectionName, ruleType, newValue, varName, isLast = false) {
2088
2180
  const lines = [];
2089
2181
  const collectionVar = varName || `collection_${collectionName}_${ruleType}`;
2090
2182
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
2091
2183
  lines.push(` ${collectionVar}.${ruleType} = ${formatValue(newValue)};`);
2092
- lines.push(` app.save(${collectionVar});`);
2184
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2093
2185
  return lines.join("\n");
2094
2186
  }
2095
- function generateCollectionDeletion(collectionName, varName = "collection") {
2187
+ function generateCollectionDeletion(collectionName, varName = "collection", isLast = false) {
2096
2188
  const lines = [];
2097
2189
  lines.push(` const ${varName} = app.findCollectionByNameOrId("${collectionName}");`);
2098
- lines.push(` app.delete(${varName});`);
2190
+ lines.push(isLast ? ` return app.delete(${varName});` : ` app.delete(${varName});`);
2099
2191
  return lines.join("\n");
2100
2192
  }
2101
2193
  function generateUpMigration(diff) {
@@ -2187,7 +2279,24 @@ function generateUpMigration(diff) {
2187
2279
  lines.push(` // No changes detected`);
2188
2280
  lines.push(``);
2189
2281
  }
2190
- return lines.join("\n");
2282
+ let code = lines.join("\n");
2283
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
2284
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
2285
+ const saveMatches = [...code.matchAll(savePattern)];
2286
+ const deleteMatches = [...code.matchAll(deletePattern)];
2287
+ const allMatches = [
2288
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
2289
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
2290
+ ].sort((a, b) => b.index - a.index);
2291
+ if (allMatches.length > 0) {
2292
+ const lastMatch = allMatches[0];
2293
+ if (lastMatch.type === "save") {
2294
+ 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);
2295
+ } else {
2296
+ 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);
2297
+ }
2298
+ }
2299
+ return code;
2191
2300
  }
2192
2301
  function generateDownMigration(diff) {
2193
2302
  const lines = [];
@@ -2289,7 +2398,24 @@ function generateDownMigration(diff) {
2289
2398
  lines.push(` // No changes to revert`);
2290
2399
  lines.push(``);
2291
2400
  }
2292
- return lines.join("\n");
2401
+ let code = lines.join("\n");
2402
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
2403
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
2404
+ const saveMatches = [...code.matchAll(savePattern)];
2405
+ const deleteMatches = [...code.matchAll(deletePattern)];
2406
+ const allMatches = [
2407
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
2408
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
2409
+ ].sort((a, b) => b.index - a.index);
2410
+ if (allMatches.length > 0) {
2411
+ const lastMatch = allMatches[0];
2412
+ if (lastMatch.type === "save") {
2413
+ 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);
2414
+ } else {
2415
+ 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);
2416
+ }
2417
+ }
2418
+ return code;
2293
2419
  }
2294
2420
  function generate(diff, config) {
2295
2421
  const normalizedConfig = typeof config === "string" ? { migrationDir: config } : config;
@@ -2312,57 +2438,18 @@ function generate(diff, config) {
2312
2438
  );
2313
2439
  }
2314
2440
  }
2441
+
2442
+ // src/migration/pocketbase-converter.ts
2315
2443
  var SNAPSHOT_VERSION = "1.0.0";
2316
- ({
2317
- workspaceRoot: process.cwd()});
2318
- function findLatestSnapshot(migrationsPath) {
2319
- try {
2320
- if (!fs4__namespace.existsSync(migrationsPath)) {
2321
- return null;
2322
- }
2323
- const files = fs4__namespace.readdirSync(migrationsPath);
2324
- const snapshotFiles = files.filter(
2325
- (file) => file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")
2326
- );
2327
- if (snapshotFiles.length === 0) {
2328
- return null;
2329
- }
2330
- snapshotFiles.sort().reverse();
2331
- const latestSnapshot = snapshotFiles[0];
2332
- if (!latestSnapshot) {
2333
- return null;
2334
- }
2335
- return path4__namespace.join(migrationsPath, latestSnapshot);
2336
- } catch (error) {
2337
- console.warn(`Error finding latest snapshot: ${error}`);
2338
- return null;
2444
+ function resolveCollectionIdToName(collectionId) {
2445
+ if (collectionId === "_pb_users_auth_") {
2446
+ return "Users";
2339
2447
  }
2340
- }
2341
- function loadSnapshotIfExists(config = {}) {
2342
- const migrationsPath = config.migrationsPath;
2343
- if (!migrationsPath) {
2344
- return null;
2448
+ const nameMatch = collectionId.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
2449
+ if (nameMatch) {
2450
+ return nameMatch[1];
2345
2451
  }
2346
- if (fs4__namespace.existsSync(migrationsPath) && fs4__namespace.statSync(migrationsPath).isFile()) {
2347
- try {
2348
- const migrationContent = fs4__namespace.readFileSync(migrationsPath, "utf-8");
2349
- return convertPocketBaseMigration(migrationContent);
2350
- } catch (error) {
2351
- console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
2352
- return null;
2353
- }
2354
- }
2355
- const latestSnapshotPath = findLatestSnapshot(migrationsPath);
2356
- if (latestSnapshotPath) {
2357
- try {
2358
- const migrationContent = fs4__namespace.readFileSync(latestSnapshotPath, "utf-8");
2359
- return convertPocketBaseMigration(migrationContent);
2360
- } catch (error) {
2361
- console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
2362
- return null;
2363
- }
2364
- }
2365
- return null;
2452
+ return collectionId;
2366
2453
  }
2367
2454
  function convertPocketBaseCollection(pbCollection) {
2368
2455
  const fields = [];
@@ -2381,17 +2468,28 @@ function convertPocketBaseCollection(pbCollection) {
2381
2468
  type: pbField.type,
2382
2469
  required: pbField.required || false
2383
2470
  };
2384
- if (pbField.options) {
2385
- field.options = pbField.options;
2471
+ field.options = pbField.options ? { ...pbField.options } : {};
2472
+ if (pbField.type === "select") {
2473
+ if (pbField.values && Array.isArray(pbField.values)) {
2474
+ field.options.values = pbField.values;
2475
+ } else if (pbField.options?.values && Array.isArray(pbField.options.values)) {
2476
+ field.options.values = pbField.options.values;
2477
+ }
2386
2478
  }
2387
2479
  if (pbField.type === "relation") {
2480
+ const collectionId = pbField.collectionId || pbField.options?.collectionId || "";
2481
+ const collectionName = resolveCollectionIdToName(collectionId);
2388
2482
  field.relation = {
2389
- collection: pbField.options?.collectionId || "",
2390
- cascadeDelete: pbField.options?.cascadeDelete || false,
2391
- maxSelect: pbField.options?.maxSelect,
2392
- minSelect: pbField.options?.minSelect
2483
+ collection: collectionName,
2484
+ cascadeDelete: pbField.cascadeDelete ?? pbField.options?.cascadeDelete ?? false,
2485
+ maxSelect: pbField.maxSelect ?? pbField.options?.maxSelect,
2486
+ minSelect: pbField.minSelect ?? pbField.options?.minSelect
2393
2487
  };
2394
2488
  }
2489
+ const hasOnlyValues = Object.keys(field.options).length === 1 && field.options.values !== void 0;
2490
+ if (Object.keys(field.options).length === 0) {
2491
+ delete field.options;
2492
+ } else if (pbField.type === "select" && hasOnlyValues) ;
2395
2493
  fields.push(field);
2396
2494
  }
2397
2495
  }
@@ -2412,6 +2510,7 @@ function convertPocketBaseCollection(pbCollection) {
2412
2510
  if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
2413
2511
  if (Object.keys(rules).length > 0) {
2414
2512
  schema.rules = rules;
2513
+ schema.permissions = { ...rules };
2415
2514
  }
2416
2515
  return schema;
2417
2516
  }
@@ -2455,6 +2554,320 @@ function convertPocketBaseMigration(migrationContent) {
2455
2554
  }
2456
2555
  }
2457
2556
 
2557
+ // src/migration/migration-parser.ts
2558
+ function extractTimestampFromFilename(filename) {
2559
+ const match = filename.match(/^(\d+)_/);
2560
+ if (match) {
2561
+ return parseInt(match[1], 10);
2562
+ }
2563
+ return null;
2564
+ }
2565
+ function findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp) {
2566
+ try {
2567
+ if (!fs5__namespace.existsSync(migrationsPath)) {
2568
+ return [];
2569
+ }
2570
+ const files = fs5__namespace.readdirSync(migrationsPath);
2571
+ const migrationFiles = [];
2572
+ for (const file of files) {
2573
+ if (file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")) {
2574
+ continue;
2575
+ }
2576
+ if (!file.endsWith(".js")) {
2577
+ continue;
2578
+ }
2579
+ const timestamp = extractTimestampFromFilename(file);
2580
+ if (timestamp && timestamp > snapshotTimestamp) {
2581
+ migrationFiles.push({
2582
+ path: path5__namespace.join(migrationsPath, file),
2583
+ timestamp
2584
+ });
2585
+ }
2586
+ }
2587
+ migrationFiles.sort((a, b) => a.timestamp - b.timestamp);
2588
+ return migrationFiles.map((f) => f.path);
2589
+ } catch (error) {
2590
+ console.warn(`Error finding migrations after snapshot: ${error}`);
2591
+ return [];
2592
+ }
2593
+ }
2594
+ function parseMigrationOperationsFromContent(content) {
2595
+ const collectionsToCreate = [];
2596
+ const collectionsToDelete = [];
2597
+ try {
2598
+ let searchIndex = 0;
2599
+ while (true) {
2600
+ const collectionStart = content.indexOf("new Collection(", searchIndex);
2601
+ if (collectionStart === -1) {
2602
+ break;
2603
+ }
2604
+ const openParen = collectionStart + "new Collection(".length;
2605
+ let braceCount = 0;
2606
+ let parenCount = 1;
2607
+ let inString = false;
2608
+ let stringChar = null;
2609
+ let i = openParen;
2610
+ while (i < content.length && /\s/.test(content[i])) {
2611
+ i++;
2612
+ }
2613
+ if (content[i] !== "{") {
2614
+ searchIndex = i + 1;
2615
+ continue;
2616
+ }
2617
+ const objectStart = i;
2618
+ braceCount = 1;
2619
+ i++;
2620
+ while (i < content.length && (braceCount > 0 || parenCount > 0)) {
2621
+ const char = content[i];
2622
+ const prevChar = i > 0 ? content[i - 1] : "";
2623
+ if (!inString && (char === '"' || char === "'")) {
2624
+ inString = true;
2625
+ stringChar = char;
2626
+ } else if (inString && char === stringChar && prevChar !== "\\") {
2627
+ inString = false;
2628
+ stringChar = null;
2629
+ }
2630
+ if (!inString) {
2631
+ if (char === "{") braceCount++;
2632
+ if (char === "}") braceCount--;
2633
+ if (char === "(") parenCount++;
2634
+ if (char === ")") parenCount--;
2635
+ }
2636
+ i++;
2637
+ }
2638
+ if (braceCount === 0 && parenCount === 0) {
2639
+ const objectContent = content.substring(objectStart, i - 1);
2640
+ try {
2641
+ const collectionObj = new Function(`return ${objectContent}`)();
2642
+ if (collectionObj && collectionObj.name) {
2643
+ const schema = convertPocketBaseCollection(collectionObj);
2644
+ collectionsToCreate.push(schema);
2645
+ }
2646
+ } catch (error) {
2647
+ console.warn(`Failed to parse collection definition: ${error}`);
2648
+ }
2649
+ }
2650
+ searchIndex = i;
2651
+ }
2652
+ const deleteMatches = content.matchAll(
2653
+ /app\.delete\s*\(\s*(?:collection_\w+|app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\))\s*\)/g
2654
+ );
2655
+ for (const match of deleteMatches) {
2656
+ if (match[1]) {
2657
+ collectionsToDelete.push(match[1]);
2658
+ } else {
2659
+ const varNameMatch = match[0].match(/collection_(\w+)/);
2660
+ if (varNameMatch) {
2661
+ const varName = `collection_${varNameMatch[1]}`;
2662
+ const deleteIndex = content.indexOf(match[0]);
2663
+ const beforeDelete = content.substring(0, deleteIndex);
2664
+ const varDefMatch = beforeDelete.match(
2665
+ new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`, "g")
2666
+ );
2667
+ if (varDefMatch && varDefMatch.length > 0) {
2668
+ const collectionDefMatch = beforeDelete.match(
2669
+ new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`)
2670
+ );
2671
+ if (collectionDefMatch) {
2672
+ try {
2673
+ const collectionDefStr = collectionDefMatch[1];
2674
+ const collectionObj = new Function(`return ${collectionDefStr}`)();
2675
+ if (collectionObj && collectionObj.name) {
2676
+ collectionsToDelete.push(collectionObj.name);
2677
+ }
2678
+ } catch {
2679
+ }
2680
+ }
2681
+ }
2682
+ }
2683
+ }
2684
+ }
2685
+ const findAndDeleteMatches = content.matchAll(
2686
+ /app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)[\s\S]*?app\.delete/g
2687
+ );
2688
+ for (const match of findAndDeleteMatches) {
2689
+ collectionsToDelete.push(match[1]);
2690
+ }
2691
+ } catch (error) {
2692
+ console.warn(`Failed to parse migration operations from content: ${error}`);
2693
+ }
2694
+ return { collectionsToCreate, collectionsToDelete };
2695
+ }
2696
+ function parseMigrationOperations(migrationContent) {
2697
+ try {
2698
+ const migrateMatch = migrationContent.match(/migrate\s*\(\s*/);
2699
+ if (!migrateMatch) {
2700
+ return parseMigrationOperationsFromContent(migrationContent);
2701
+ }
2702
+ const startIndex = migrateMatch.index + migrateMatch[0].length;
2703
+ let i = startIndex;
2704
+ let parenCount = 0;
2705
+ let foundFirstParen = false;
2706
+ while (i < migrationContent.length) {
2707
+ const char = migrationContent[i];
2708
+ if (char === "(") {
2709
+ parenCount++;
2710
+ foundFirstParen = true;
2711
+ i++;
2712
+ break;
2713
+ }
2714
+ i++;
2715
+ }
2716
+ if (!foundFirstParen) {
2717
+ return parseMigrationOperationsFromContent(migrationContent);
2718
+ }
2719
+ let inString = false;
2720
+ let stringChar = null;
2721
+ let foundBrace = false;
2722
+ let braceStart = -1;
2723
+ while (i < migrationContent.length && !foundBrace) {
2724
+ const char = migrationContent[i];
2725
+ const prevChar = i > 0 ? migrationContent[i - 1] : "";
2726
+ if (!inString && (char === '"' || char === "'")) {
2727
+ inString = true;
2728
+ stringChar = char;
2729
+ } else if (inString && char === stringChar && prevChar !== "\\") {
2730
+ inString = false;
2731
+ stringChar = null;
2732
+ }
2733
+ if (!inString) {
2734
+ if (char === "(") parenCount++;
2735
+ if (char === ")") {
2736
+ parenCount--;
2737
+ if (parenCount === 0) {
2738
+ i++;
2739
+ while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
2740
+ i++;
2741
+ }
2742
+ if (i < migrationContent.length - 1 && migrationContent[i] === "=" && migrationContent[i + 1] === ">") {
2743
+ i += 2;
2744
+ while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
2745
+ i++;
2746
+ }
2747
+ if (i < migrationContent.length && migrationContent[i] === "{") {
2748
+ foundBrace = true;
2749
+ braceStart = i + 1;
2750
+ break;
2751
+ }
2752
+ }
2753
+ }
2754
+ }
2755
+ }
2756
+ i++;
2757
+ }
2758
+ if (!foundBrace || braceStart === -1) {
2759
+ return parseMigrationOperationsFromContent(migrationContent);
2760
+ }
2761
+ let braceCount = 1;
2762
+ i = braceStart;
2763
+ inString = false;
2764
+ stringChar = null;
2765
+ while (i < migrationContent.length && braceCount > 0) {
2766
+ const char = migrationContent[i];
2767
+ const prevChar = i > 0 ? migrationContent[i - 1] : "";
2768
+ if (!inString && (char === '"' || char === "'")) {
2769
+ inString = true;
2770
+ stringChar = char;
2771
+ } else if (inString && char === stringChar && prevChar !== "\\") {
2772
+ inString = false;
2773
+ stringChar = null;
2774
+ }
2775
+ if (!inString) {
2776
+ if (char === "{") braceCount++;
2777
+ if (char === "}") braceCount--;
2778
+ }
2779
+ i++;
2780
+ }
2781
+ if (braceCount === 0) {
2782
+ const upMigrationContent = migrationContent.substring(braceStart, i - 1);
2783
+ return parseMigrationOperationsFromContent(upMigrationContent);
2784
+ }
2785
+ return parseMigrationOperationsFromContent(migrationContent);
2786
+ } catch (error) {
2787
+ console.warn(`Failed to parse migration operations: ${error}`);
2788
+ return { collectionsToCreate: [], collectionsToDelete: [] };
2789
+ }
2790
+ }
2791
+ ({
2792
+ workspaceRoot: process.cwd()});
2793
+ function findLatestSnapshot(migrationsPath) {
2794
+ try {
2795
+ if (!fs5__namespace.existsSync(migrationsPath)) {
2796
+ return null;
2797
+ }
2798
+ const files = fs5__namespace.readdirSync(migrationsPath);
2799
+ const snapshotFiles = files.filter(
2800
+ (file) => file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")
2801
+ );
2802
+ if (snapshotFiles.length === 0) {
2803
+ return null;
2804
+ }
2805
+ snapshotFiles.sort().reverse();
2806
+ const latestSnapshot = snapshotFiles[0];
2807
+ if (!latestSnapshot) {
2808
+ return null;
2809
+ }
2810
+ return path5__namespace.join(migrationsPath, latestSnapshot);
2811
+ } catch (error) {
2812
+ console.warn(`Error finding latest snapshot: ${error}`);
2813
+ return null;
2814
+ }
2815
+ }
2816
+ function applyMigrationOperations(snapshot, operations) {
2817
+ const updatedCollections = new Map(snapshot.collections);
2818
+ for (const collectionName of operations.collectionsToDelete) {
2819
+ updatedCollections.delete(collectionName);
2820
+ }
2821
+ for (const collection of operations.collectionsToCreate) {
2822
+ updatedCollections.set(collection.name, collection);
2823
+ }
2824
+ return {
2825
+ ...snapshot,
2826
+ collections: updatedCollections
2827
+ };
2828
+ }
2829
+ function loadSnapshotWithMigrations(config = {}) {
2830
+ const migrationsPath = config.migrationsPath;
2831
+ if (!migrationsPath) {
2832
+ return null;
2833
+ }
2834
+ if (fs5__namespace.existsSync(migrationsPath) && fs5__namespace.statSync(migrationsPath).isFile()) {
2835
+ try {
2836
+ const migrationContent = fs5__namespace.readFileSync(migrationsPath, "utf-8");
2837
+ return convertPocketBaseMigration(migrationContent);
2838
+ } catch (error) {
2839
+ console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
2840
+ return null;
2841
+ }
2842
+ }
2843
+ const latestSnapshotPath = findLatestSnapshot(migrationsPath);
2844
+ if (!latestSnapshotPath) {
2845
+ return null;
2846
+ }
2847
+ try {
2848
+ const migrationContent = fs5__namespace.readFileSync(latestSnapshotPath, "utf-8");
2849
+ let snapshot = convertPocketBaseMigration(migrationContent);
2850
+ const snapshotFilename = path5__namespace.basename(latestSnapshotPath);
2851
+ const snapshotTimestamp = extractTimestampFromFilename(snapshotFilename);
2852
+ if (snapshotTimestamp) {
2853
+ const migrationFiles = findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp);
2854
+ for (const migrationFile of migrationFiles) {
2855
+ try {
2856
+ const migrationContent2 = fs5__namespace.readFileSync(migrationFile, "utf-8");
2857
+ const operations = parseMigrationOperations(migrationContent2);
2858
+ snapshot = applyMigrationOperations(snapshot, operations);
2859
+ } catch (error) {
2860
+ console.warn(`Failed to apply migration ${migrationFile}: ${error}`);
2861
+ }
2862
+ }
2863
+ }
2864
+ return snapshot;
2865
+ } catch (error) {
2866
+ console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
2867
+ return null;
2868
+ }
2869
+ }
2870
+
2458
2871
  // src/migration/validation.ts
2459
2872
  function detectCollectionDeletions(diff) {
2460
2873
  const changes = [];
@@ -2623,8 +3036,8 @@ var DEFAULT_CONFIG5 = {
2623
3036
  };
2624
3037
  function findConfigFile(directory) {
2625
3038
  for (const fileName of CONFIG_FILE_NAMES) {
2626
- const filePath = path4__namespace.join(directory, fileName);
2627
- if (fs4__namespace.existsSync(filePath)) {
3039
+ const filePath = path5__namespace.join(directory, fileName);
3040
+ if (fs5__namespace.existsSync(filePath)) {
2628
3041
  return filePath;
2629
3042
  }
2630
3043
  }
@@ -2632,7 +3045,7 @@ function findConfigFile(directory) {
2632
3045
  }
2633
3046
  function loadJsonConfig(configPath) {
2634
3047
  try {
2635
- const content = fs4__namespace.readFileSync(configPath, "utf-8");
3048
+ const content = fs5__namespace.readFileSync(configPath, "utf-8");
2636
3049
  return JSON.parse(content);
2637
3050
  } catch (error) {
2638
3051
  if (error instanceof SyntaxError) {
@@ -2661,10 +3074,10 @@ async function loadJsConfig(configPath) {
2661
3074
  }
2662
3075
  }
2663
3076
  async function loadConfigFile(configPath) {
2664
- if (!fs4__namespace.existsSync(configPath)) {
3077
+ if (!fs5__namespace.existsSync(configPath)) {
2665
3078
  return null;
2666
3079
  }
2667
- const ext = path4__namespace.extname(configPath).toLowerCase();
3080
+ const ext = path5__namespace.extname(configPath).toLowerCase();
2668
3081
  if (ext === ".json") {
2669
3082
  return loadJsonConfig(configPath);
2670
3083
  } else if (ext === ".js" || ext === ".mjs") {
@@ -2731,10 +3144,10 @@ function validateConfig(config, configPath) {
2731
3144
  }
2732
3145
  const cwd = process.cwd();
2733
3146
  const possiblePaths = [
2734
- path4__namespace.resolve(cwd, config.schema.directory),
2735
- path4__namespace.resolve(cwd, "shared", config.schema.directory)
3147
+ path5__namespace.resolve(cwd, config.schema.directory),
3148
+ path5__namespace.resolve(cwd, "shared", config.schema.directory)
2736
3149
  ];
2737
- const schemaDir = possiblePaths.find((p) => fs4__namespace.existsSync(p));
3150
+ const schemaDir = possiblePaths.find((p) => fs5__namespace.existsSync(p));
2738
3151
  if (!schemaDir) {
2739
3152
  throw new ConfigurationError(`Schema directory not found. Tried: ${possiblePaths.join(", ")}`, configPath, [
2740
3153
  "schema.directory"
@@ -2746,15 +3159,15 @@ async function loadConfig(options = {}) {
2746
3159
  let configFilePath;
2747
3160
  const cwd = process.cwd();
2748
3161
  if (options.config) {
2749
- const explicitPath = path4__namespace.resolve(cwd, options.config);
2750
- if (!fs4__namespace.existsSync(explicitPath)) {
3162
+ const explicitPath = path5__namespace.resolve(cwd, options.config);
3163
+ if (!fs5__namespace.existsSync(explicitPath)) {
2751
3164
  throw new ConfigurationError(`Configuration file not found: ${explicitPath}`, explicitPath);
2752
3165
  }
2753
3166
  configFilePath = explicitPath;
2754
3167
  } else {
2755
- const searchDirs = [cwd, path4__namespace.join(cwd, "shared")];
3168
+ const searchDirs = [cwd, path5__namespace.join(cwd, "shared")];
2756
3169
  for (const dir of searchDirs) {
2757
- if (fs4__namespace.existsSync(dir)) {
3170
+ if (fs5__namespace.existsSync(dir)) {
2758
3171
  const found = findConfigFile(dir);
2759
3172
  if (found) {
2760
3173
  configFilePath = found;
@@ -2783,18 +3196,18 @@ async function loadConfig(options = {}) {
2783
3196
  function getSchemaDirectory(config) {
2784
3197
  const cwd = process.cwd();
2785
3198
  const possiblePaths = [
2786
- path4__namespace.resolve(cwd, config.schema.directory),
2787
- path4__namespace.resolve(cwd, "shared", config.schema.directory)
3199
+ path5__namespace.resolve(cwd, config.schema.directory),
3200
+ path5__namespace.resolve(cwd, "shared", config.schema.directory)
2788
3201
  ];
2789
- return possiblePaths.find((p) => fs4__namespace.existsSync(p)) || possiblePaths[0];
3202
+ return possiblePaths.find((p) => fs5__namespace.existsSync(p)) || possiblePaths[0];
2790
3203
  }
2791
3204
  function getMigrationsDirectory(config) {
2792
3205
  const cwd = process.cwd();
2793
3206
  const possiblePaths = [
2794
- path4__namespace.resolve(cwd, config.migrations.directory),
2795
- path4__namespace.resolve(cwd, "shared", config.migrations.directory)
3207
+ path5__namespace.resolve(cwd, config.migrations.directory),
3208
+ path5__namespace.resolve(cwd, "shared", config.migrations.directory)
2796
3209
  ];
2797
- return possiblePaths.find((p) => fs4__namespace.existsSync(p)) || possiblePaths[0];
3210
+ return possiblePaths.find((p) => fs5__namespace.existsSync(p)) || possiblePaths[0];
2798
3211
  }
2799
3212
  var currentVerbosity = "normal";
2800
3213
  function setVerbosity(level) {
@@ -3062,10 +3475,16 @@ async function executeGenerate(options) {
3062
3475
  const schemaDir = getSchemaDirectory(config);
3063
3476
  const migrationsDir = getMigrationsDirectory(config);
3064
3477
  logSection("\u{1F50D} Analyzing Schema");
3065
- const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(schemaDir));
3478
+ const analyzerConfig = {
3479
+ schemaDir,
3480
+ excludePatterns: config.schema.exclude,
3481
+ useCompiledFiles: false
3482
+ // Use source files since we're in development/testing
3483
+ };
3484
+ const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
3066
3485
  logSuccess(`Found ${currentSchema.collections.size} collection(s)`);
3067
3486
  logInfo("Loading previous snapshot...");
3068
- const previousSnapshot = loadSnapshotIfExists({
3487
+ const previousSnapshot = loadSnapshotWithMigrations({
3069
3488
  migrationsPath: migrationsDir,
3070
3489
  workspaceRoot: process.cwd()
3071
3490
  });
@@ -3092,7 +3511,7 @@ async function executeGenerate(options) {
3092
3511
  "Creating migration file...",
3093
3512
  () => Promise.resolve(generate(diff, migrationsDir))
3094
3513
  );
3095
- logSuccess(`Migration file created: ${path4__namespace.basename(migrationPath)}`);
3514
+ logSuccess(`Migration file created: ${path5__namespace.basename(migrationPath)}`);
3096
3515
  logSection("\u2705 Next Steps");
3097
3516
  console.log();
3098
3517
  console.log(" 1. Review the generated migration file:");
@@ -3249,10 +3668,16 @@ async function executeStatus(options) {
3249
3668
  const schemaDir = getSchemaDirectory(config);
3250
3669
  const migrationsDir = getMigrationsDirectory(config);
3251
3670
  logSection("\u{1F50D} Checking Migration Status");
3252
- const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(schemaDir));
3671
+ const analyzerConfig = {
3672
+ schemaDir,
3673
+ excludePatterns: config.schema.exclude,
3674
+ useCompiledFiles: false
3675
+ // Use source files since we're in development/testing
3676
+ };
3677
+ const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
3253
3678
  logSuccess(`Found ${currentSchema.collections.size} collection(s) in schema`);
3254
3679
  logInfo("Loading previous snapshot...");
3255
- const previousSnapshot = loadSnapshotIfExists({
3680
+ const previousSnapshot = loadSnapshotWithMigrations({
3256
3681
  migrationsPath: migrationsDir,
3257
3682
  workspaceRoot: process.cwd()
3258
3683
  });