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
@@ -3,8 +3,9 @@
3
3
 
4
4
  var chalk = require('chalk');
5
5
  var commander = require('commander');
6
- var path4 = require('path');
7
- var fs4 = require('fs');
6
+ var fs5 = require('fs');
7
+ var path5 = require('path');
8
+ var url = require('url');
8
9
  var zod = require('zod');
9
10
  var ora = require('ora');
10
11
 
@@ -29,10 +30,43 @@ function _interopNamespace(e) {
29
30
  }
30
31
 
31
32
  var chalk__default = /*#__PURE__*/_interopDefault(chalk);
32
- var path4__namespace = /*#__PURE__*/_interopNamespace(path4);
33
- var fs4__namespace = /*#__PURE__*/_interopNamespace(fs4);
33
+ var fs5__namespace = /*#__PURE__*/_interopNamespace(fs5);
34
+ var path5__namespace = /*#__PURE__*/_interopNamespace(path5);
34
35
  var ora__default = /*#__PURE__*/_interopDefault(ora);
35
36
 
37
+ // ../node_modules/tsup/assets/cjs_shims.js
38
+ var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
39
+ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
40
+ ({
41
+ id: zod.z.string().describe("unique id"),
42
+ collectionId: zod.z.string().describe("collection id"),
43
+ collectionName: zod.z.string().describe("collection name"),
44
+ expand: zod.z.record(zod.z.any()).describe("expandable fields")
45
+ });
46
+ ({
47
+ created: zod.z.string().describe("creation timestamp"),
48
+ updated: zod.z.string().describe("last update timestamp")
49
+ });
50
+ ({
51
+ thumbnailURL: zod.z.string().optional(),
52
+ imageFiles: zod.z.array(zod.z.string())
53
+ });
54
+ ({
55
+ imageFiles: zod.z.array(zod.z.instanceof(File))
56
+ });
57
+ var RELATION_METADATA_KEY = "__pocketbase_relation__";
58
+ function extractRelationMetadata(description) {
59
+ if (!description) return null;
60
+ try {
61
+ const parsed = JSON.parse(description);
62
+ if (parsed[RELATION_METADATA_KEY]) {
63
+ return parsed[RELATION_METADATA_KEY];
64
+ }
65
+ } catch {
66
+ }
67
+ return null;
68
+ }
69
+
36
70
  // src/migration/errors.ts
37
71
  var MigrationError = class _MigrationError extends Error {
38
72
  constructor(message) {
@@ -130,10 +164,10 @@ var FileSystemError = class _FileSystemError extends MigrationError {
130
164
  operation;
131
165
  code;
132
166
  originalError;
133
- constructor(message, path6, operation, code, originalError) {
167
+ constructor(message, path7, operation, code, originalError) {
134
168
  super(message);
135
169
  this.name = "FileSystemError";
136
- this.path = path6;
170
+ this.path = path7;
137
171
  this.operation = operation;
138
172
  this.code = code;
139
173
  this.originalError = originalError;
@@ -196,7 +230,7 @@ Cause: ${this.originalError.message}`);
196
230
  }
197
231
  };
198
232
 
199
- // src/schema/permission-templates.ts
233
+ // src/utils/permission-templates.ts
200
234
  var PermissionTemplates = {
201
235
  /**
202
236
  * Public access - anyone can perform all operations
@@ -855,26 +889,28 @@ function getMaxSelect(fieldName, zodType) {
855
889
  return 1;
856
890
  }
857
891
  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;
892
+ if (isSingleRelationField(fieldName, zodType)) {
893
+ return 0;
870
894
  }
871
- if (unwrappedType instanceof zod.z.ZodArray) {
872
- const arrayDef = unwrappedType._def;
873
- if (arrayDef.minLength) {
874
- return arrayDef.minLength.value;
895
+ if (isMultipleRelationField(fieldName, zodType)) {
896
+ let unwrappedType = zodType;
897
+ if (zodType instanceof zod.z.ZodOptional) {
898
+ unwrappedType = zodType._def.innerType;
899
+ }
900
+ if (unwrappedType instanceof zod.z.ZodNullable) {
901
+ unwrappedType = unwrappedType._def.innerType;
902
+ }
903
+ if (unwrappedType instanceof zod.z.ZodDefault) {
904
+ unwrappedType = unwrappedType._def.innerType;
905
+ }
906
+ if (unwrappedType instanceof zod.z.ZodArray) {
907
+ const arrayDef = unwrappedType._def;
908
+ if (arrayDef.minLength) {
909
+ return arrayDef.minLength.value;
910
+ }
875
911
  }
876
912
  }
877
- return void 0;
913
+ return 0;
878
914
  }
879
915
  function mapZodStringType(zodType) {
880
916
  const checks = zodType._def.checks || [];
@@ -1072,20 +1108,20 @@ function mergeConfig(config) {
1072
1108
  }
1073
1109
  function resolveSchemaDir(config) {
1074
1110
  const workspaceRoot = config.workspaceRoot || process.cwd();
1075
- if (path4__namespace.isAbsolute(config.schemaDir)) {
1111
+ if (path5__namespace.isAbsolute(config.schemaDir)) {
1076
1112
  return config.schemaDir;
1077
1113
  }
1078
- return path4__namespace.join(workspaceRoot, config.schemaDir);
1114
+ return path5__namespace.join(workspaceRoot, config.schemaDir);
1079
1115
  }
1080
1116
  function discoverSchemaFiles(config) {
1081
1117
  const normalizedConfig = typeof config === "string" ? { schemaDir: config } : config;
1082
1118
  const mergedConfig = mergeConfig(normalizedConfig);
1083
1119
  const schemaDir = resolveSchemaDir(normalizedConfig);
1084
1120
  try {
1085
- if (!fs4__namespace.existsSync(schemaDir)) {
1121
+ if (!fs5__namespace.existsSync(schemaDir)) {
1086
1122
  throw new FileSystemError(`Schema directory not found: ${schemaDir}`, schemaDir, "access", "ENOENT");
1087
1123
  }
1088
- const files = fs4__namespace.readdirSync(schemaDir);
1124
+ const files = fs5__namespace.readdirSync(schemaDir);
1089
1125
  const schemaFiles = files.filter((file) => {
1090
1126
  const hasValidExtension = mergedConfig.includeExtensions.some((ext) => file.endsWith(ext));
1091
1127
  if (!hasValidExtension) return false;
@@ -1101,7 +1137,7 @@ function discoverSchemaFiles(config) {
1101
1137
  });
1102
1138
  return schemaFiles.map((file) => {
1103
1139
  const ext = mergedConfig.includeExtensions.find((ext2) => file.endsWith(ext2)) || ".ts";
1104
- return path4__namespace.join(schemaDir, file.replace(new RegExp(`\\${ext}$`), ""));
1140
+ return path5__namespace.join(schemaDir, file.replace(new RegExp(`\\${ext}$`), ""));
1105
1141
  });
1106
1142
  } catch (error) {
1107
1143
  if (error instanceof FileSystemError) {
@@ -1132,13 +1168,32 @@ async function importSchemaModule(filePath, config) {
1132
1168
  if (config?.pathTransformer) {
1133
1169
  importPath = config.pathTransformer(filePath);
1134
1170
  }
1135
- if (!importPath.endsWith(".js")) {
1136
- importPath = `${importPath}.js`;
1171
+ let resolvedPath = null;
1172
+ const jsPath = `${importPath}.js`;
1173
+ const tsPath = `${importPath}.ts`;
1174
+ if (fs5__namespace.existsSync(jsPath)) {
1175
+ resolvedPath = jsPath;
1176
+ } else if (fs5__namespace.existsSync(tsPath)) {
1177
+ resolvedPath = tsPath;
1178
+ } else {
1179
+ resolvedPath = jsPath;
1137
1180
  }
1138
- const fileUrl = new URL(`file://${path4__namespace.resolve(importPath)}`);
1181
+ const fileUrl = new URL(`file://${path5__namespace.resolve(resolvedPath)}`);
1139
1182
  const module = await import(fileUrl.href);
1140
1183
  return module;
1141
1184
  } catch (error) {
1185
+ const tsPath = `${filePath}.ts`;
1186
+ const isTypeScriptFile = fs5__namespace.existsSync(tsPath);
1187
+ if (isTypeScriptFile) {
1188
+ throw new SchemaParsingError(
1189
+ `Failed to import TypeScript schema file. Node.js cannot import TypeScript files directly.
1190
+ Please either:
1191
+ 1. Compile your schema files to JavaScript first, or
1192
+ 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")`,
1193
+ filePath,
1194
+ error
1195
+ );
1196
+ }
1142
1197
  throw new SchemaParsingError(
1143
1198
  `Failed to import schema module. Make sure the schema files are compiled to JavaScript.`,
1144
1199
  filePath,
@@ -1147,7 +1202,7 @@ async function importSchemaModule(filePath, config) {
1147
1202
  }
1148
1203
  }
1149
1204
  function getCollectionNameFromFile(filePath) {
1150
- const filename = path4__namespace.basename(filePath).replace(/\.(ts|js)$/, "");
1205
+ const filename = path5__namespace.basename(filePath).replace(/\.(ts|js)$/, "");
1151
1206
  return toCollectionName(filename);
1152
1207
  }
1153
1208
  function extractSchemaDefinitions(module, patterns = ["Schema", "InputSchema"]) {
@@ -1201,7 +1256,17 @@ function buildFieldDefinition(fieldName, zodType) {
1201
1256
  required,
1202
1257
  options
1203
1258
  };
1204
- if (isRelationField(fieldName, zodType)) {
1259
+ const relationMetadata = extractRelationMetadata(zodType.description);
1260
+ if (relationMetadata) {
1261
+ fieldDef.type = "relation";
1262
+ fieldDef.relation = {
1263
+ collection: relationMetadata.collection,
1264
+ maxSelect: relationMetadata.maxSelect,
1265
+ minSelect: relationMetadata.minSelect,
1266
+ cascadeDelete: relationMetadata.cascadeDelete
1267
+ };
1268
+ fieldDef.options = void 0;
1269
+ } else if (isRelationField(fieldName, zodType)) {
1205
1270
  fieldDef.type = "relation";
1206
1271
  const targetCollection = resolveTargetCollection(fieldName);
1207
1272
  const maxSelect = getMaxSelect(fieldName, zodType);
@@ -1213,6 +1278,13 @@ function buildFieldDefinition(fieldName, zodType) {
1213
1278
  cascadeDelete: false
1214
1279
  // Default to false, can be configured later
1215
1280
  };
1281
+ if (fieldDef.options) {
1282
+ const { min, max, pattern, ...relationSafeOptions } = fieldDef.options;
1283
+ console.log("min", min);
1284
+ console.log("max", max);
1285
+ console.log("pattern", pattern);
1286
+ fieldDef.options = Object.keys(relationSafeOptions).length > 0 ? relationSafeOptions : void 0;
1287
+ }
1216
1288
  }
1217
1289
  return fieldDef;
1218
1290
  }
@@ -1265,11 +1337,12 @@ function convertZodSchemaToCollectionSchema(collectionName, zodSchema) {
1265
1337
  fields,
1266
1338
  indexes,
1267
1339
  rules: {
1268
- listRule: null,
1269
- viewRule: null,
1270
- createRule: null,
1271
- updateRule: null,
1272
- deleteRule: null
1340
+ listRule: permissions?.listRule ?? null,
1341
+ viewRule: permissions?.viewRule ?? null,
1342
+ createRule: permissions?.createRule ?? null,
1343
+ updateRule: permissions?.updateRule ?? null,
1344
+ deleteRule: permissions?.deleteRule ?? null,
1345
+ manageRule: permissions?.manageRule ?? null
1273
1346
  },
1274
1347
  permissions
1275
1348
  };
@@ -1293,7 +1366,12 @@ async function buildSchemaDefinition(config) {
1293
1366
  if (normalizedConfig.pathTransformer) {
1294
1367
  importPath = normalizedConfig.pathTransformer(filePath);
1295
1368
  } else if (mergedConfig.useCompiledFiles) {
1296
- importPath = filePath.replace(/\/src\//, "/dist/");
1369
+ const distPath = filePath.replace(/\/src\//, "/dist/");
1370
+ if (fs5__namespace.existsSync(`${distPath}.js`) || fs5__namespace.existsSync(`${distPath}.mjs`)) {
1371
+ importPath = distPath;
1372
+ } else {
1373
+ importPath = filePath;
1374
+ }
1297
1375
  }
1298
1376
  const module = await importSchemaModule(importPath, normalizedConfig);
1299
1377
  const schemas = extractSchemaDefinitions(module, mergedConfig.schemaPatterns);
@@ -1466,6 +1544,9 @@ function compareFieldOptions(currentField, previousField) {
1466
1544
  for (const key of allKeys) {
1467
1545
  const currentValue = currentOptions[key];
1468
1546
  const previousValue = previousOptions[key];
1547
+ if (currentValue === void 0 && previousValue === void 0) {
1548
+ continue;
1549
+ }
1469
1550
  if (!areValuesEqual(currentValue, previousValue)) {
1470
1551
  changes.push({
1471
1552
  property: `options.${key}`,
@@ -1486,11 +1567,26 @@ function compareRelationConfigurations(currentField, previousField) {
1486
1567
  if (!currentRelation || !previousRelation) {
1487
1568
  return changes;
1488
1569
  }
1489
- if (currentRelation.collection !== previousRelation.collection) {
1570
+ const normalizeCollection = (collection) => {
1571
+ if (!collection) return collection;
1572
+ if (collection === "_pb_users_auth_") {
1573
+ return "Users";
1574
+ }
1575
+ const nameMatch = collection.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
1576
+ if (nameMatch) {
1577
+ return nameMatch[1];
1578
+ }
1579
+ return collection;
1580
+ };
1581
+ const normalizedCurrent = normalizeCollection(currentRelation.collection);
1582
+ const normalizedPrevious = normalizeCollection(previousRelation.collection);
1583
+ if (normalizedCurrent !== normalizedPrevious) {
1490
1584
  changes.push({
1491
1585
  property: "relation.collection",
1492
- oldValue: previousRelation.collection,
1493
- newValue: currentRelation.collection
1586
+ oldValue: normalizedPrevious,
1587
+ // Use normalized value for clarity
1588
+ newValue: normalizedCurrent
1589
+ // Use normalized value for clarity
1494
1590
  });
1495
1591
  }
1496
1592
  if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {
@@ -1691,10 +1787,8 @@ function compare(currentSchema, previousSnapshot, config) {
1691
1787
  var DEFAULT_TEMPLATE = `/// <reference path="{{TYPES_PATH}}" />
1692
1788
  migrate((app) => {
1693
1789
  {{UP_CODE}}
1694
- return true;
1695
1790
  }, (app) => {
1696
1791
  {{DOWN_CODE}}
1697
- return true;
1698
1792
  });
1699
1793
  `;
1700
1794
  var DEFAULT_CONFIG3 = {
@@ -1712,10 +1806,10 @@ function mergeConfig3(config) {
1712
1806
  }
1713
1807
  function resolveMigrationDir(config) {
1714
1808
  const workspaceRoot = config.workspaceRoot || process.cwd();
1715
- if (path4__namespace.isAbsolute(config.migrationDir)) {
1809
+ if (path5__namespace.isAbsolute(config.migrationDir)) {
1716
1810
  return config.migrationDir;
1717
1811
  }
1718
- return path4__namespace.join(workspaceRoot, config.migrationDir);
1812
+ return path5__namespace.join(workspaceRoot, config.migrationDir);
1719
1813
  }
1720
1814
  function generateTimestamp(config) {
1721
1815
  if (config?.timestampGenerator) {
@@ -1773,9 +1867,9 @@ function createMigrationFileStructure(upCode, downCode, config) {
1773
1867
  }
1774
1868
  function writeMigrationFile(migrationDir, filename, content) {
1775
1869
  try {
1776
- if (!fs4__namespace.existsSync(migrationDir)) {
1870
+ if (!fs5__namespace.existsSync(migrationDir)) {
1777
1871
  try {
1778
- fs4__namespace.mkdirSync(migrationDir, { recursive: true });
1872
+ fs5__namespace.mkdirSync(migrationDir, { recursive: true });
1779
1873
  } catch (error) {
1780
1874
  const fsError = error;
1781
1875
  if (fsError.code === "EACCES" || fsError.code === "EPERM") {
@@ -1796,15 +1890,15 @@ function writeMigrationFile(migrationDir, filename, content) {
1796
1890
  );
1797
1891
  }
1798
1892
  }
1799
- const filePath = path4__namespace.join(migrationDir, filename);
1800
- fs4__namespace.writeFileSync(filePath, content, "utf-8");
1893
+ const filePath = path5__namespace.join(migrationDir, filename);
1894
+ fs5__namespace.writeFileSync(filePath, content, "utf-8");
1801
1895
  return filePath;
1802
1896
  } catch (error) {
1803
1897
  if (error instanceof FileSystemError) {
1804
1898
  throw error;
1805
1899
  }
1806
1900
  const fsError = error;
1807
- const filePath = path4__namespace.join(migrationDir, filename);
1901
+ const filePath = path5__namespace.join(migrationDir, filename);
1808
1902
  if (fsError.code === "EACCES" || fsError.code === "EPERM") {
1809
1903
  throw new FileSystemError(
1810
1904
  `Permission denied writing migration file. Check file and directory permissions.`,
@@ -1859,7 +1953,8 @@ function generateFieldDefinitionObject(field) {
1859
1953
  }
1860
1954
  }
1861
1955
  if (field.relation) {
1862
- const collectionIdPlaceholder = field.relation.collection === "Users" ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
1956
+ const isUsersCollection = field.relation.collection.toLowerCase() === "users";
1957
+ const collectionIdPlaceholder = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
1863
1958
  parts.push(` collectionId: ${collectionIdPlaceholder}`);
1864
1959
  if (field.relation.maxSelect !== void 0) {
1865
1960
  parts.push(` maxSelect: ${field.relation.maxSelect}`);
@@ -1943,7 +2038,7 @@ function generateIndexesArray(indexes) {
1943
2038
  ${indexStrings.join(",\n ")},
1944
2039
  ]`;
1945
2040
  }
1946
- function generateCollectionCreation(collection, varName = "collection") {
2041
+ function generateCollectionCreation(collection, varName = "collection", isLast = false) {
1947
2042
  const lines = [];
1948
2043
  lines.push(` const ${varName} = new Collection({`);
1949
2044
  lines.push(` name: "${collection.name}",`);
@@ -1959,7 +2054,7 @@ function generateCollectionCreation(collection, varName = "collection") {
1959
2054
  lines.push(` indexes: ${generateIndexesArray(collection.indexes)},`);
1960
2055
  lines.push(` });`);
1961
2056
  lines.push(``);
1962
- lines.push(` app.save(${varName});`);
2057
+ lines.push(isLast ? ` return app.save(${varName});` : ` app.save(${varName});`);
1963
2058
  return lines.join("\n");
1964
2059
  }
1965
2060
  function getFieldConstructorName(fieldType) {
@@ -1990,7 +2085,8 @@ function generateFieldConstructorOptions(field) {
1990
2085
  }
1991
2086
  }
1992
2087
  if (field.relation && field.type === "relation") {
1993
- const collectionIdPlaceholder = field.relation.collection === "Users" ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
2088
+ const isUsersCollection = field.relation.collection.toLowerCase() === "users";
2089
+ const collectionIdPlaceholder = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
1994
2090
  parts.push(` collectionId: ${collectionIdPlaceholder}`);
1995
2091
  if (field.relation.maxSelect !== void 0) {
1996
2092
  parts.push(` maxSelect: ${field.relation.maxSelect}`);
@@ -2004,7 +2100,7 @@ function generateFieldConstructorOptions(field) {
2004
2100
  }
2005
2101
  return parts.join(",\n");
2006
2102
  }
2007
- function generateFieldAddition(collectionName, field, varName) {
2103
+ function generateFieldAddition(collectionName, field, varName, isLast = false) {
2008
2104
  const lines = [];
2009
2105
  const constructorName = getFieldConstructorName(field.type);
2010
2106
  const collectionVar = varName || `collection_${collectionName}_${field.name}`;
@@ -2014,10 +2110,10 @@ function generateFieldAddition(collectionName, field, varName) {
2014
2110
  lines.push(generateFieldConstructorOptions(field));
2015
2111
  lines.push(` }));`);
2016
2112
  lines.push(``);
2017
- lines.push(` app.save(${collectionVar});`);
2113
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2018
2114
  return lines.join("\n");
2019
2115
  }
2020
- function generateFieldModification(collectionName, modification, varName) {
2116
+ function generateFieldModification(collectionName, modification, varName, isLast = false) {
2021
2117
  const lines = [];
2022
2118
  const collectionVar = varName || `collection_${collectionName}_${modification.fieldName}`;
2023
2119
  const fieldVar = `${collectionVar}_field`;
@@ -2031,7 +2127,8 @@ function generateFieldModification(collectionName, modification, varName) {
2031
2127
  } else if (change.property.startsWith("relation.")) {
2032
2128
  const relationKey = change.property.replace("relation.", "");
2033
2129
  if (relationKey === "collection") {
2034
- const collectionIdValue = change.newValue === "Users" ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${change.newValue}").id`;
2130
+ const isUsersCollection = String(change.newValue).toLowerCase() === "users";
2131
+ const collectionIdValue = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${change.newValue}").id`;
2035
2132
  lines.push(` ${fieldVar}.collectionId = ${collectionIdValue};`);
2036
2133
  } else {
2037
2134
  lines.push(` ${fieldVar}.${relationKey} = ${formatValue(change.newValue)};`);
@@ -2041,10 +2138,10 @@ function generateFieldModification(collectionName, modification, varName) {
2041
2138
  }
2042
2139
  }
2043
2140
  lines.push(``);
2044
- lines.push(` app.save(${collectionVar});`);
2141
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2045
2142
  return lines.join("\n");
2046
2143
  }
2047
- function generateFieldDeletion(collectionName, fieldName, varName) {
2144
+ function generateFieldDeletion(collectionName, fieldName, varName, isLast = false) {
2048
2145
  const lines = [];
2049
2146
  const collectionVar = varName || `collection_${collectionName}_${fieldName}`;
2050
2147
  const fieldVar = `${collectionVar}_field`;
@@ -2053,18 +2150,18 @@ function generateFieldDeletion(collectionName, fieldName, varName) {
2053
2150
  lines.push(``);
2054
2151
  lines.push(` ${collectionVar}.fields.remove(${fieldVar}.id);`);
2055
2152
  lines.push(``);
2056
- lines.push(` app.save(${collectionVar});`);
2153
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2057
2154
  return lines.join("\n");
2058
2155
  }
2059
- function generateIndexAddition(collectionName, index, varName) {
2156
+ function generateIndexAddition(collectionName, index, varName, isLast = false) {
2060
2157
  const lines = [];
2061
2158
  const collectionVar = varName || `collection_${collectionName}_idx`;
2062
2159
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
2063
2160
  lines.push(` ${collectionVar}.indexes.push("${index}");`);
2064
- lines.push(` app.save(${collectionVar});`);
2161
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2065
2162
  return lines.join("\n");
2066
2163
  }
2067
- function generateIndexRemoval(collectionName, index, varName) {
2164
+ function generateIndexRemoval(collectionName, index, varName, isLast = false) {
2068
2165
  const lines = [];
2069
2166
  const collectionVar = varName || `collection_${collectionName}_idx`;
2070
2167
  const indexVar = `${collectionVar}_indexToRemove`;
@@ -2073,29 +2170,29 @@ function generateIndexRemoval(collectionName, index, varName) {
2073
2170
  lines.push(` if (${indexVar} !== -1) {`);
2074
2171
  lines.push(` ${collectionVar}.indexes.splice(${indexVar}, 1);`);
2075
2172
  lines.push(` }`);
2076
- lines.push(` app.save(${collectionVar});`);
2173
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2077
2174
  return lines.join("\n");
2078
2175
  }
2079
- function generateRuleUpdate(collectionName, ruleType, newValue, varName) {
2176
+ function generateRuleUpdate(collectionName, ruleType, newValue, varName, isLast = false) {
2080
2177
  const lines = [];
2081
2178
  const collectionVar = varName || `collection_${collectionName}_${ruleType}`;
2082
2179
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
2083
2180
  lines.push(` ${collectionVar}.${ruleType} = ${formatValue(newValue)};`);
2084
- lines.push(` app.save(${collectionVar});`);
2181
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2085
2182
  return lines.join("\n");
2086
2183
  }
2087
- function generatePermissionUpdate(collectionName, ruleType, newValue, varName) {
2184
+ function generatePermissionUpdate(collectionName, ruleType, newValue, varName, isLast = false) {
2088
2185
  const lines = [];
2089
2186
  const collectionVar = varName || `collection_${collectionName}_${ruleType}`;
2090
2187
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
2091
2188
  lines.push(` ${collectionVar}.${ruleType} = ${formatValue(newValue)};`);
2092
- lines.push(` app.save(${collectionVar});`);
2189
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2093
2190
  return lines.join("\n");
2094
2191
  }
2095
- function generateCollectionDeletion(collectionName, varName = "collection") {
2192
+ function generateCollectionDeletion(collectionName, varName = "collection", isLast = false) {
2096
2193
  const lines = [];
2097
2194
  lines.push(` const ${varName} = app.findCollectionByNameOrId("${collectionName}");`);
2098
- lines.push(` app.delete(${varName});`);
2195
+ lines.push(isLast ? ` return app.delete(${varName});` : ` app.delete(${varName});`);
2099
2196
  return lines.join("\n");
2100
2197
  }
2101
2198
  function generateUpMigration(diff) {
@@ -2187,7 +2284,24 @@ function generateUpMigration(diff) {
2187
2284
  lines.push(` // No changes detected`);
2188
2285
  lines.push(``);
2189
2286
  }
2190
- return lines.join("\n");
2287
+ let code = lines.join("\n");
2288
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
2289
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
2290
+ const saveMatches = [...code.matchAll(savePattern)];
2291
+ const deleteMatches = [...code.matchAll(deletePattern)];
2292
+ const allMatches = [
2293
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
2294
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
2295
+ ].sort((a, b) => b.index - a.index);
2296
+ if (allMatches.length > 0) {
2297
+ const lastMatch = allMatches[0];
2298
+ if (lastMatch.type === "save") {
2299
+ 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);
2300
+ } else {
2301
+ 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);
2302
+ }
2303
+ }
2304
+ return code;
2191
2305
  }
2192
2306
  function generateDownMigration(diff) {
2193
2307
  const lines = [];
@@ -2289,7 +2403,24 @@ function generateDownMigration(diff) {
2289
2403
  lines.push(` // No changes to revert`);
2290
2404
  lines.push(``);
2291
2405
  }
2292
- return lines.join("\n");
2406
+ let code = lines.join("\n");
2407
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
2408
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
2409
+ const saveMatches = [...code.matchAll(savePattern)];
2410
+ const deleteMatches = [...code.matchAll(deletePattern)];
2411
+ const allMatches = [
2412
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
2413
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
2414
+ ].sort((a, b) => b.index - a.index);
2415
+ if (allMatches.length > 0) {
2416
+ const lastMatch = allMatches[0];
2417
+ if (lastMatch.type === "save") {
2418
+ 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);
2419
+ } else {
2420
+ 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);
2421
+ }
2422
+ }
2423
+ return code;
2293
2424
  }
2294
2425
  function generate(diff, config) {
2295
2426
  const normalizedConfig = typeof config === "string" ? { migrationDir: config } : config;
@@ -2312,57 +2443,18 @@ function generate(diff, config) {
2312
2443
  );
2313
2444
  }
2314
2445
  }
2446
+
2447
+ // src/migration/pocketbase-converter.ts
2315
2448
  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;
2449
+ function resolveCollectionIdToName(collectionId) {
2450
+ if (collectionId === "_pb_users_auth_") {
2451
+ return "Users";
2339
2452
  }
2340
- }
2341
- function loadSnapshotIfExists(config = {}) {
2342
- const migrationsPath = config.migrationsPath;
2343
- if (!migrationsPath) {
2344
- return null;
2453
+ const nameMatch = collectionId.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
2454
+ if (nameMatch) {
2455
+ return nameMatch[1];
2345
2456
  }
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;
2457
+ return collectionId;
2366
2458
  }
2367
2459
  function convertPocketBaseCollection(pbCollection) {
2368
2460
  const fields = [];
@@ -2381,17 +2473,28 @@ function convertPocketBaseCollection(pbCollection) {
2381
2473
  type: pbField.type,
2382
2474
  required: pbField.required || false
2383
2475
  };
2384
- if (pbField.options) {
2385
- field.options = pbField.options;
2476
+ field.options = pbField.options ? { ...pbField.options } : {};
2477
+ if (pbField.type === "select") {
2478
+ if (pbField.values && Array.isArray(pbField.values)) {
2479
+ field.options.values = pbField.values;
2480
+ } else if (pbField.options?.values && Array.isArray(pbField.options.values)) {
2481
+ field.options.values = pbField.options.values;
2482
+ }
2386
2483
  }
2387
2484
  if (pbField.type === "relation") {
2485
+ const collectionId = pbField.collectionId || pbField.options?.collectionId || "";
2486
+ const collectionName = resolveCollectionIdToName(collectionId);
2388
2487
  field.relation = {
2389
- collection: pbField.options?.collectionId || "",
2390
- cascadeDelete: pbField.options?.cascadeDelete || false,
2391
- maxSelect: pbField.options?.maxSelect,
2392
- minSelect: pbField.options?.minSelect
2488
+ collection: collectionName,
2489
+ cascadeDelete: pbField.cascadeDelete ?? pbField.options?.cascadeDelete ?? false,
2490
+ maxSelect: pbField.maxSelect ?? pbField.options?.maxSelect,
2491
+ minSelect: pbField.minSelect ?? pbField.options?.minSelect
2393
2492
  };
2394
2493
  }
2494
+ const hasOnlyValues = Object.keys(field.options).length === 1 && field.options.values !== void 0;
2495
+ if (Object.keys(field.options).length === 0) {
2496
+ delete field.options;
2497
+ } else if (pbField.type === "select" && hasOnlyValues) ;
2395
2498
  fields.push(field);
2396
2499
  }
2397
2500
  }
@@ -2412,6 +2515,7 @@ function convertPocketBaseCollection(pbCollection) {
2412
2515
  if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
2413
2516
  if (Object.keys(rules).length > 0) {
2414
2517
  schema.rules = rules;
2518
+ schema.permissions = { ...rules };
2415
2519
  }
2416
2520
  return schema;
2417
2521
  }
@@ -2455,6 +2559,320 @@ function convertPocketBaseMigration(migrationContent) {
2455
2559
  }
2456
2560
  }
2457
2561
 
2562
+ // src/migration/migration-parser.ts
2563
+ function extractTimestampFromFilename(filename) {
2564
+ const match = filename.match(/^(\d+)_/);
2565
+ if (match) {
2566
+ return parseInt(match[1], 10);
2567
+ }
2568
+ return null;
2569
+ }
2570
+ function findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp) {
2571
+ try {
2572
+ if (!fs5__namespace.existsSync(migrationsPath)) {
2573
+ return [];
2574
+ }
2575
+ const files = fs5__namespace.readdirSync(migrationsPath);
2576
+ const migrationFiles = [];
2577
+ for (const file of files) {
2578
+ if (file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")) {
2579
+ continue;
2580
+ }
2581
+ if (!file.endsWith(".js")) {
2582
+ continue;
2583
+ }
2584
+ const timestamp = extractTimestampFromFilename(file);
2585
+ if (timestamp && timestamp > snapshotTimestamp) {
2586
+ migrationFiles.push({
2587
+ path: path5__namespace.join(migrationsPath, file),
2588
+ timestamp
2589
+ });
2590
+ }
2591
+ }
2592
+ migrationFiles.sort((a, b) => a.timestamp - b.timestamp);
2593
+ return migrationFiles.map((f) => f.path);
2594
+ } catch (error) {
2595
+ console.warn(`Error finding migrations after snapshot: ${error}`);
2596
+ return [];
2597
+ }
2598
+ }
2599
+ function parseMigrationOperationsFromContent(content) {
2600
+ const collectionsToCreate = [];
2601
+ const collectionsToDelete = [];
2602
+ try {
2603
+ let searchIndex = 0;
2604
+ while (true) {
2605
+ const collectionStart = content.indexOf("new Collection(", searchIndex);
2606
+ if (collectionStart === -1) {
2607
+ break;
2608
+ }
2609
+ const openParen = collectionStart + "new Collection(".length;
2610
+ let braceCount = 0;
2611
+ let parenCount = 1;
2612
+ let inString = false;
2613
+ let stringChar = null;
2614
+ let i = openParen;
2615
+ while (i < content.length && /\s/.test(content[i])) {
2616
+ i++;
2617
+ }
2618
+ if (content[i] !== "{") {
2619
+ searchIndex = i + 1;
2620
+ continue;
2621
+ }
2622
+ const objectStart = i;
2623
+ braceCount = 1;
2624
+ i++;
2625
+ while (i < content.length && (braceCount > 0 || parenCount > 0)) {
2626
+ const char = content[i];
2627
+ const prevChar = i > 0 ? content[i - 1] : "";
2628
+ if (!inString && (char === '"' || char === "'")) {
2629
+ inString = true;
2630
+ stringChar = char;
2631
+ } else if (inString && char === stringChar && prevChar !== "\\") {
2632
+ inString = false;
2633
+ stringChar = null;
2634
+ }
2635
+ if (!inString) {
2636
+ if (char === "{") braceCount++;
2637
+ if (char === "}") braceCount--;
2638
+ if (char === "(") parenCount++;
2639
+ if (char === ")") parenCount--;
2640
+ }
2641
+ i++;
2642
+ }
2643
+ if (braceCount === 0 && parenCount === 0) {
2644
+ const objectContent = content.substring(objectStart, i - 1);
2645
+ try {
2646
+ const collectionObj = new Function(`return ${objectContent}`)();
2647
+ if (collectionObj && collectionObj.name) {
2648
+ const schema = convertPocketBaseCollection(collectionObj);
2649
+ collectionsToCreate.push(schema);
2650
+ }
2651
+ } catch (error) {
2652
+ console.warn(`Failed to parse collection definition: ${error}`);
2653
+ }
2654
+ }
2655
+ searchIndex = i;
2656
+ }
2657
+ const deleteMatches = content.matchAll(
2658
+ /app\.delete\s*\(\s*(?:collection_\w+|app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\))\s*\)/g
2659
+ );
2660
+ for (const match of deleteMatches) {
2661
+ if (match[1]) {
2662
+ collectionsToDelete.push(match[1]);
2663
+ } else {
2664
+ const varNameMatch = match[0].match(/collection_(\w+)/);
2665
+ if (varNameMatch) {
2666
+ const varName = `collection_${varNameMatch[1]}`;
2667
+ const deleteIndex = content.indexOf(match[0]);
2668
+ const beforeDelete = content.substring(0, deleteIndex);
2669
+ const varDefMatch = beforeDelete.match(
2670
+ new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`, "g")
2671
+ );
2672
+ if (varDefMatch && varDefMatch.length > 0) {
2673
+ const collectionDefMatch = beforeDelete.match(
2674
+ new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`)
2675
+ );
2676
+ if (collectionDefMatch) {
2677
+ try {
2678
+ const collectionDefStr = collectionDefMatch[1];
2679
+ const collectionObj = new Function(`return ${collectionDefStr}`)();
2680
+ if (collectionObj && collectionObj.name) {
2681
+ collectionsToDelete.push(collectionObj.name);
2682
+ }
2683
+ } catch {
2684
+ }
2685
+ }
2686
+ }
2687
+ }
2688
+ }
2689
+ }
2690
+ const findAndDeleteMatches = content.matchAll(
2691
+ /app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)[\s\S]*?app\.delete/g
2692
+ );
2693
+ for (const match of findAndDeleteMatches) {
2694
+ collectionsToDelete.push(match[1]);
2695
+ }
2696
+ } catch (error) {
2697
+ console.warn(`Failed to parse migration operations from content: ${error}`);
2698
+ }
2699
+ return { collectionsToCreate, collectionsToDelete };
2700
+ }
2701
+ function parseMigrationOperations(migrationContent) {
2702
+ try {
2703
+ const migrateMatch = migrationContent.match(/migrate\s*\(\s*/);
2704
+ if (!migrateMatch) {
2705
+ return parseMigrationOperationsFromContent(migrationContent);
2706
+ }
2707
+ const startIndex = migrateMatch.index + migrateMatch[0].length;
2708
+ let i = startIndex;
2709
+ let parenCount = 0;
2710
+ let foundFirstParen = false;
2711
+ while (i < migrationContent.length) {
2712
+ const char = migrationContent[i];
2713
+ if (char === "(") {
2714
+ parenCount++;
2715
+ foundFirstParen = true;
2716
+ i++;
2717
+ break;
2718
+ }
2719
+ i++;
2720
+ }
2721
+ if (!foundFirstParen) {
2722
+ return parseMigrationOperationsFromContent(migrationContent);
2723
+ }
2724
+ let inString = false;
2725
+ let stringChar = null;
2726
+ let foundBrace = false;
2727
+ let braceStart = -1;
2728
+ while (i < migrationContent.length && !foundBrace) {
2729
+ const char = migrationContent[i];
2730
+ const prevChar = i > 0 ? migrationContent[i - 1] : "";
2731
+ if (!inString && (char === '"' || char === "'")) {
2732
+ inString = true;
2733
+ stringChar = char;
2734
+ } else if (inString && char === stringChar && prevChar !== "\\") {
2735
+ inString = false;
2736
+ stringChar = null;
2737
+ }
2738
+ if (!inString) {
2739
+ if (char === "(") parenCount++;
2740
+ if (char === ")") {
2741
+ parenCount--;
2742
+ if (parenCount === 0) {
2743
+ i++;
2744
+ while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
2745
+ i++;
2746
+ }
2747
+ if (i < migrationContent.length - 1 && migrationContent[i] === "=" && migrationContent[i + 1] === ">") {
2748
+ i += 2;
2749
+ while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
2750
+ i++;
2751
+ }
2752
+ if (i < migrationContent.length && migrationContent[i] === "{") {
2753
+ foundBrace = true;
2754
+ braceStart = i + 1;
2755
+ break;
2756
+ }
2757
+ }
2758
+ }
2759
+ }
2760
+ }
2761
+ i++;
2762
+ }
2763
+ if (!foundBrace || braceStart === -1) {
2764
+ return parseMigrationOperationsFromContent(migrationContent);
2765
+ }
2766
+ let braceCount = 1;
2767
+ i = braceStart;
2768
+ inString = false;
2769
+ stringChar = null;
2770
+ while (i < migrationContent.length && braceCount > 0) {
2771
+ const char = migrationContent[i];
2772
+ const prevChar = i > 0 ? migrationContent[i - 1] : "";
2773
+ if (!inString && (char === '"' || char === "'")) {
2774
+ inString = true;
2775
+ stringChar = char;
2776
+ } else if (inString && char === stringChar && prevChar !== "\\") {
2777
+ inString = false;
2778
+ stringChar = null;
2779
+ }
2780
+ if (!inString) {
2781
+ if (char === "{") braceCount++;
2782
+ if (char === "}") braceCount--;
2783
+ }
2784
+ i++;
2785
+ }
2786
+ if (braceCount === 0) {
2787
+ const upMigrationContent = migrationContent.substring(braceStart, i - 1);
2788
+ return parseMigrationOperationsFromContent(upMigrationContent);
2789
+ }
2790
+ return parseMigrationOperationsFromContent(migrationContent);
2791
+ } catch (error) {
2792
+ console.warn(`Failed to parse migration operations: ${error}`);
2793
+ return { collectionsToCreate: [], collectionsToDelete: [] };
2794
+ }
2795
+ }
2796
+ ({
2797
+ workspaceRoot: process.cwd()});
2798
+ function findLatestSnapshot(migrationsPath) {
2799
+ try {
2800
+ if (!fs5__namespace.existsSync(migrationsPath)) {
2801
+ return null;
2802
+ }
2803
+ const files = fs5__namespace.readdirSync(migrationsPath);
2804
+ const snapshotFiles = files.filter(
2805
+ (file) => file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")
2806
+ );
2807
+ if (snapshotFiles.length === 0) {
2808
+ return null;
2809
+ }
2810
+ snapshotFiles.sort().reverse();
2811
+ const latestSnapshot = snapshotFiles[0];
2812
+ if (!latestSnapshot) {
2813
+ return null;
2814
+ }
2815
+ return path5__namespace.join(migrationsPath, latestSnapshot);
2816
+ } catch (error) {
2817
+ console.warn(`Error finding latest snapshot: ${error}`);
2818
+ return null;
2819
+ }
2820
+ }
2821
+ function applyMigrationOperations(snapshot, operations) {
2822
+ const updatedCollections = new Map(snapshot.collections);
2823
+ for (const collectionName of operations.collectionsToDelete) {
2824
+ updatedCollections.delete(collectionName);
2825
+ }
2826
+ for (const collection of operations.collectionsToCreate) {
2827
+ updatedCollections.set(collection.name, collection);
2828
+ }
2829
+ return {
2830
+ ...snapshot,
2831
+ collections: updatedCollections
2832
+ };
2833
+ }
2834
+ function loadSnapshotWithMigrations(config = {}) {
2835
+ const migrationsPath = config.migrationsPath;
2836
+ if (!migrationsPath) {
2837
+ return null;
2838
+ }
2839
+ if (fs5__namespace.existsSync(migrationsPath) && fs5__namespace.statSync(migrationsPath).isFile()) {
2840
+ try {
2841
+ const migrationContent = fs5__namespace.readFileSync(migrationsPath, "utf-8");
2842
+ return convertPocketBaseMigration(migrationContent);
2843
+ } catch (error) {
2844
+ console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
2845
+ return null;
2846
+ }
2847
+ }
2848
+ const latestSnapshotPath = findLatestSnapshot(migrationsPath);
2849
+ if (!latestSnapshotPath) {
2850
+ return null;
2851
+ }
2852
+ try {
2853
+ const migrationContent = fs5__namespace.readFileSync(latestSnapshotPath, "utf-8");
2854
+ let snapshot = convertPocketBaseMigration(migrationContent);
2855
+ const snapshotFilename = path5__namespace.basename(latestSnapshotPath);
2856
+ const snapshotTimestamp = extractTimestampFromFilename(snapshotFilename);
2857
+ if (snapshotTimestamp) {
2858
+ const migrationFiles = findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp);
2859
+ for (const migrationFile of migrationFiles) {
2860
+ try {
2861
+ const migrationContent2 = fs5__namespace.readFileSync(migrationFile, "utf-8");
2862
+ const operations = parseMigrationOperations(migrationContent2);
2863
+ snapshot = applyMigrationOperations(snapshot, operations);
2864
+ } catch (error) {
2865
+ console.warn(`Failed to apply migration ${migrationFile}: ${error}`);
2866
+ }
2867
+ }
2868
+ }
2869
+ return snapshot;
2870
+ } catch (error) {
2871
+ console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
2872
+ return null;
2873
+ }
2874
+ }
2875
+
2458
2876
  // src/migration/validation.ts
2459
2877
  function detectCollectionDeletions(diff) {
2460
2878
  const changes = [];
@@ -2623,8 +3041,8 @@ var DEFAULT_CONFIG5 = {
2623
3041
  };
2624
3042
  function findConfigFile(directory) {
2625
3043
  for (const fileName of CONFIG_FILE_NAMES) {
2626
- const filePath = path4__namespace.join(directory, fileName);
2627
- if (fs4__namespace.existsSync(filePath)) {
3044
+ const filePath = path5__namespace.join(directory, fileName);
3045
+ if (fs5__namespace.existsSync(filePath)) {
2628
3046
  return filePath;
2629
3047
  }
2630
3048
  }
@@ -2632,7 +3050,7 @@ function findConfigFile(directory) {
2632
3050
  }
2633
3051
  function loadJsonConfig(configPath) {
2634
3052
  try {
2635
- const content = fs4__namespace.readFileSync(configPath, "utf-8");
3053
+ const content = fs5__namespace.readFileSync(configPath, "utf-8");
2636
3054
  return JSON.parse(content);
2637
3055
  } catch (error) {
2638
3056
  if (error instanceof SyntaxError) {
@@ -2661,10 +3079,10 @@ async function loadJsConfig(configPath) {
2661
3079
  }
2662
3080
  }
2663
3081
  async function loadConfigFile(configPath) {
2664
- if (!fs4__namespace.existsSync(configPath)) {
3082
+ if (!fs5__namespace.existsSync(configPath)) {
2665
3083
  return null;
2666
3084
  }
2667
- const ext = path4__namespace.extname(configPath).toLowerCase();
3085
+ const ext = path5__namespace.extname(configPath).toLowerCase();
2668
3086
  if (ext === ".json") {
2669
3087
  return loadJsonConfig(configPath);
2670
3088
  } else if (ext === ".js" || ext === ".mjs") {
@@ -2731,10 +3149,10 @@ function validateConfig(config, configPath) {
2731
3149
  }
2732
3150
  const cwd = process.cwd();
2733
3151
  const possiblePaths = [
2734
- path4__namespace.resolve(cwd, config.schema.directory),
2735
- path4__namespace.resolve(cwd, "shared", config.schema.directory)
3152
+ path5__namespace.resolve(cwd, config.schema.directory),
3153
+ path5__namespace.resolve(cwd, "shared", config.schema.directory)
2736
3154
  ];
2737
- const schemaDir = possiblePaths.find((p) => fs4__namespace.existsSync(p));
3155
+ const schemaDir = possiblePaths.find((p) => fs5__namespace.existsSync(p));
2738
3156
  if (!schemaDir) {
2739
3157
  throw new ConfigurationError(`Schema directory not found. Tried: ${possiblePaths.join(", ")}`, configPath, [
2740
3158
  "schema.directory"
@@ -2746,15 +3164,15 @@ async function loadConfig(options = {}) {
2746
3164
  let configFilePath;
2747
3165
  const cwd = process.cwd();
2748
3166
  if (options.config) {
2749
- const explicitPath = path4__namespace.resolve(cwd, options.config);
2750
- if (!fs4__namespace.existsSync(explicitPath)) {
3167
+ const explicitPath = path5__namespace.resolve(cwd, options.config);
3168
+ if (!fs5__namespace.existsSync(explicitPath)) {
2751
3169
  throw new ConfigurationError(`Configuration file not found: ${explicitPath}`, explicitPath);
2752
3170
  }
2753
3171
  configFilePath = explicitPath;
2754
3172
  } else {
2755
- const searchDirs = [cwd, path4__namespace.join(cwd, "shared")];
3173
+ const searchDirs = [cwd, path5__namespace.join(cwd, "shared")];
2756
3174
  for (const dir of searchDirs) {
2757
- if (fs4__namespace.existsSync(dir)) {
3175
+ if (fs5__namespace.existsSync(dir)) {
2758
3176
  const found = findConfigFile(dir);
2759
3177
  if (found) {
2760
3178
  configFilePath = found;
@@ -2783,18 +3201,18 @@ async function loadConfig(options = {}) {
2783
3201
  function getSchemaDirectory(config) {
2784
3202
  const cwd = process.cwd();
2785
3203
  const possiblePaths = [
2786
- path4__namespace.resolve(cwd, config.schema.directory),
2787
- path4__namespace.resolve(cwd, "shared", config.schema.directory)
3204
+ path5__namespace.resolve(cwd, config.schema.directory),
3205
+ path5__namespace.resolve(cwd, "shared", config.schema.directory)
2788
3206
  ];
2789
- return possiblePaths.find((p) => fs4__namespace.existsSync(p)) || possiblePaths[0];
3207
+ return possiblePaths.find((p) => fs5__namespace.existsSync(p)) || possiblePaths[0];
2790
3208
  }
2791
3209
  function getMigrationsDirectory(config) {
2792
3210
  const cwd = process.cwd();
2793
3211
  const possiblePaths = [
2794
- path4__namespace.resolve(cwd, config.migrations.directory),
2795
- path4__namespace.resolve(cwd, "shared", config.migrations.directory)
3212
+ path5__namespace.resolve(cwd, config.migrations.directory),
3213
+ path5__namespace.resolve(cwd, "shared", config.migrations.directory)
2796
3214
  ];
2797
- return possiblePaths.find((p) => fs4__namespace.existsSync(p)) || possiblePaths[0];
3215
+ return possiblePaths.find((p) => fs5__namespace.existsSync(p)) || possiblePaths[0];
2798
3216
  }
2799
3217
  var currentVerbosity = "normal";
2800
3218
  function setVerbosity(level) {
@@ -3002,10 +3420,16 @@ async function executeGenerate(options) {
3002
3420
  const schemaDir = getSchemaDirectory(config);
3003
3421
  const migrationsDir = getMigrationsDirectory(config);
3004
3422
  logSection("\u{1F50D} Analyzing Schema");
3005
- const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(schemaDir));
3423
+ const analyzerConfig = {
3424
+ schemaDir,
3425
+ excludePatterns: config.schema.exclude,
3426
+ useCompiledFiles: false
3427
+ // Use source files since we're in development/testing
3428
+ };
3429
+ const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
3006
3430
  logSuccess(`Found ${currentSchema.collections.size} collection(s)`);
3007
3431
  logInfo("Loading previous snapshot...");
3008
- const previousSnapshot = loadSnapshotIfExists({
3432
+ const previousSnapshot = loadSnapshotWithMigrations({
3009
3433
  migrationsPath: migrationsDir,
3010
3434
  workspaceRoot: process.cwd()
3011
3435
  });
@@ -3032,7 +3456,7 @@ async function executeGenerate(options) {
3032
3456
  "Creating migration file...",
3033
3457
  () => Promise.resolve(generate(diff, migrationsDir))
3034
3458
  );
3035
- logSuccess(`Migration file created: ${path4__namespace.basename(migrationPath)}`);
3459
+ logSuccess(`Migration file created: ${path5__namespace.basename(migrationPath)}`);
3036
3460
  logSection("\u2705 Next Steps");
3037
3461
  console.log();
3038
3462
  console.log(" 1. Review the generated migration file:");
@@ -3201,10 +3625,16 @@ async function executeStatus(options) {
3201
3625
  const schemaDir = getSchemaDirectory(config);
3202
3626
  const migrationsDir = getMigrationsDirectory(config);
3203
3627
  logSection("\u{1F50D} Checking Migration Status");
3204
- const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(schemaDir));
3628
+ const analyzerConfig = {
3629
+ schemaDir,
3630
+ excludePatterns: config.schema.exclude,
3631
+ useCompiledFiles: false
3632
+ // Use source files since we're in development/testing
3633
+ };
3634
+ const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
3205
3635
  logSuccess(`Found ${currentSchema.collections.size} collection(s) in schema`);
3206
3636
  logInfo("Loading previous snapshot...");
3207
- const previousSnapshot = loadSnapshotIfExists({
3637
+ const previousSnapshot = loadSnapshotWithMigrations({
3208
3638
  migrationsPath: migrationsDir,
3209
3639
  workspaceRoot: process.cwd()
3210
3640
  });
@@ -3317,7 +3747,19 @@ Examples:
3317
3747
  }
3318
3748
 
3319
3749
  // src/cli/migrate.ts
3320
- var VERSION = "0.1.0";
3750
+ function getVersion() {
3751
+ try {
3752
+ const __filename2 = url.fileURLToPath(importMetaUrl);
3753
+ const __dirname = path5.dirname(__filename2);
3754
+ const packageJsonPath = path5.join(__dirname, "../../package.json");
3755
+ const packageJson = JSON.parse(fs5.readFileSync(packageJsonPath, "utf-8"));
3756
+ return packageJson.version || "0.0.0";
3757
+ } catch {
3758
+ console.warn("Warning: Could not read version from package.json");
3759
+ return "0.0.0";
3760
+ }
3761
+ }
3762
+ var VERSION = getVersion();
3321
3763
  function displayBanner() {
3322
3764
  console.log();
3323
3765
  console.log(chalk__default.default.cyan.bold(" PocketBase Zod Migration Tool"));