pocketbase-zod-schema 0.1.3 → 0.2.0

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 (57) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +233 -98
  3. package/dist/cli/index.cjs +449 -108
  4. package/dist/cli/index.cjs.map +1 -1
  5. package/dist/cli/index.js +447 -106
  6. package/dist/cli/index.js.map +1 -1
  7. package/dist/cli/migrate.cjs +452 -111
  8. package/dist/cli/migrate.cjs.map +1 -1
  9. package/dist/cli/migrate.js +447 -106
  10. package/dist/cli/migrate.js.map +1 -1
  11. package/dist/index.cjs +593 -175
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.cts +4 -4
  14. package/dist/index.d.ts +4 -4
  15. package/dist/index.js +583 -172
  16. package/dist/index.js.map +1 -1
  17. package/dist/migration/analyzer.cjs +44 -6
  18. package/dist/migration/analyzer.cjs.map +1 -1
  19. package/dist/migration/analyzer.d.cts +11 -1
  20. package/dist/migration/analyzer.d.ts +11 -1
  21. package/dist/migration/analyzer.js +44 -7
  22. package/dist/migration/analyzer.js.map +1 -1
  23. package/dist/migration/diff.cjs +21 -3
  24. package/dist/migration/diff.cjs.map +1 -1
  25. package/dist/migration/diff.js +21 -3
  26. package/dist/migration/diff.js.map +1 -1
  27. package/dist/migration/index.cjs +500 -129
  28. package/dist/migration/index.cjs.map +1 -1
  29. package/dist/migration/index.d.cts +1 -1
  30. package/dist/migration/index.d.ts +1 -1
  31. package/dist/migration/index.js +499 -129
  32. package/dist/migration/index.js.map +1 -1
  33. package/dist/migration/snapshot.cjs +432 -118
  34. package/dist/migration/snapshot.cjs.map +1 -1
  35. package/dist/migration/snapshot.d.cts +34 -12
  36. package/dist/migration/snapshot.d.ts +34 -12
  37. package/dist/migration/snapshot.js +430 -117
  38. package/dist/migration/snapshot.js.map +1 -1
  39. package/dist/mutator.cjs +20 -21
  40. package/dist/mutator.cjs.map +1 -1
  41. package/dist/mutator.d.cts +4 -4
  42. package/dist/mutator.d.ts +4 -4
  43. package/dist/mutator.js +20 -21
  44. package/dist/mutator.js.map +1 -1
  45. package/dist/schema.cjs +69 -10
  46. package/dist/schema.cjs.map +1 -1
  47. package/dist/schema.d.cts +98 -8
  48. package/dist/schema.d.ts +98 -8
  49. package/dist/schema.js +62 -9
  50. package/dist/schema.js.map +1 -1
  51. package/dist/types.d.cts +5 -2
  52. package/dist/types.d.ts +5 -2
  53. package/dist/user-DTJQIj4K.d.cts +149 -0
  54. package/dist/user-DTJQIj4K.d.ts +149 -0
  55. package/package.json +3 -3
  56. package/dist/user-C39DQ40N.d.cts +0 -53
  57. package/dist/user-C39DQ40N.d.ts +0 -53
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
- import * as fs2 from 'fs';
3
- import * as path4 from 'path';
2
+ import * as fs3 from 'fs';
3
+ import * as path5 from 'path';
4
4
  import chalk from 'chalk';
5
5
  import ora from 'ora';
6
6
 
@@ -78,7 +78,7 @@ function filesField(options) {
78
78
  return schema;
79
79
  }
80
80
  var RELATION_METADATA_KEY = "__pocketbase_relation__";
81
- function relationField(config) {
81
+ function RelationField(config) {
82
82
  const metadata = {
83
83
  [RELATION_METADATA_KEY]: {
84
84
  type: "single",
@@ -90,7 +90,7 @@ function relationField(config) {
90
90
  };
91
91
  return z.string().describe(JSON.stringify(metadata));
92
92
  }
93
- function relationsField(config) {
93
+ function RelationsField(config) {
94
94
  const metadata = {
95
95
  [RELATION_METADATA_KEY]: {
96
96
  type: "multiple",
@@ -149,6 +149,22 @@ function withIndexes(schema, indexes) {
149
149
  };
150
150
  return schema.describe(JSON.stringify(metadata));
151
151
  }
152
+ function defineCollection(config) {
153
+ const { collectionName, schema, permissions, indexes, ...futureOptions } = config;
154
+ const metadata = {
155
+ collectionName
156
+ };
157
+ if (permissions) {
158
+ metadata.permissions = permissions;
159
+ }
160
+ if (indexes) {
161
+ metadata.indexes = indexes;
162
+ }
163
+ if (Object.keys(futureOptions).length > 0) {
164
+ Object.assign(metadata, futureOptions);
165
+ }
166
+ return schema.describe(JSON.stringify(metadata));
167
+ }
152
168
 
153
169
  // src/utils/permission-templates.ts
154
170
  var PermissionTemplates = {
@@ -369,6 +385,28 @@ function mergePermissions(...schemas) {
369
385
  }
370
386
  return merged;
371
387
  }
388
+ var ProjectInputSchema = z.object({
389
+ // Required fields
390
+ title: z.string(),
391
+ content: z.string(),
392
+ status: StatusEnum,
393
+ summary: z.string().optional(),
394
+ OwnerUser: RelationField({ collection: "Users" }),
395
+ SubscriberUsers: RelationsField({ collection: "Users" })
396
+ }).extend(inputImageFileSchema);
397
+ var ProjectSchema = ProjectInputSchema.omit(omitImageFilesSchema).extend(baseImageFileSchema);
398
+ var ProjectCollection = defineCollection({
399
+ collectionName: "Projects",
400
+ schema: ProjectSchema,
401
+ permissions: {
402
+ template: "owner-only",
403
+ ownerField: "OwnerUser",
404
+ customRules: {
405
+ listRule: '@request.auth.id != ""',
406
+ viewRule: '@request.auth.id != "" && (OwnerUser = @request.auth.id || SubscriberUsers ?= @request.auth.id)'
407
+ }
408
+ }
409
+ });
372
410
  var UserInputSchema = z.object({
373
411
  name: z.string().optional(),
374
412
  email: z.string().email(),
@@ -376,14 +414,17 @@ var UserInputSchema = z.object({
376
414
  passwordConfirm: z.string(),
377
415
  avatar: z.instanceof(File).optional()
378
416
  });
379
- var UserDatabaseSchema = z.object({
417
+ var UserCollectionSchema = z.object({
380
418
  name: z.string().optional(),
381
419
  email: z.string().email(),
382
420
  password: z.string().min(8, "Password must be at least 8 characters"),
383
421
  avatar: z.instanceof(File).optional()
384
422
  });
385
- var UserSchema = withIndexes(
386
- withPermissions(UserDatabaseSchema.extend(baseSchema), {
423
+ var UserSchema = UserCollectionSchema.extend(baseSchema);
424
+ var UserCollection = defineCollection({
425
+ collectionName: "Users",
426
+ schema: UserSchema,
427
+ permissions: {
387
428
  // Users can list their own profile
388
429
  listRule: "id = @request.auth.id",
389
430
  // Users can view their own profile
@@ -395,13 +436,13 @@ var UserSchema = withIndexes(
395
436
  // Users can only delete their own account
396
437
  deleteRule: "id = @request.auth.id"
397
438
  // manageRule is null in PocketBase default (not set)
398
- }),
399
- [
439
+ },
440
+ indexes: [
400
441
  // PocketBase's default indexes for auth collections
401
442
  "CREATE UNIQUE INDEX `idx_tokenKey__pb_users_auth_` ON `users` (`tokenKey`)",
402
443
  "CREATE UNIQUE INDEX `idx_email__pb_users_auth_` ON `users` (`email`) WHERE `email` != ''"
403
444
  ]
404
- );
445
+ });
405
446
  var BaseMutator = class {
406
447
  pb;
407
448
  // Define a default property that subclasses will override
@@ -844,10 +885,10 @@ var FileSystemError = class _FileSystemError extends MigrationError {
844
885
  operation;
845
886
  code;
846
887
  originalError;
847
- constructor(message, path6, operation, code, originalError) {
888
+ constructor(message, path7, operation, code, originalError) {
848
889
  super(message);
849
890
  this.name = "FileSystemError";
850
- this.path = path6;
891
+ this.path = path7;
851
892
  this.operation = operation;
852
893
  this.code = code;
853
894
  this.originalError = originalError;
@@ -1923,6 +1964,16 @@ function getFieldTypeInfo(zodType, fieldName) {
1923
1964
  }
1924
1965
 
1925
1966
  // src/migration/analyzer.ts
1967
+ var tsxLoaderRegistered = false;
1968
+ async function ensureTsxLoader() {
1969
+ if (tsxLoaderRegistered) return;
1970
+ try {
1971
+ await import('tsx/esm');
1972
+ tsxLoaderRegistered = true;
1973
+ } catch {
1974
+ tsxLoaderRegistered = false;
1975
+ }
1976
+ }
1926
1977
  var DEFAULT_CONFIG = {
1927
1978
  workspaceRoot: process.cwd(),
1928
1979
  excludePatterns: [
@@ -1950,20 +2001,20 @@ function mergeConfig(config) {
1950
2001
  }
1951
2002
  function resolveSchemaDir(config) {
1952
2003
  const workspaceRoot = config.workspaceRoot || process.cwd();
1953
- if (path4.isAbsolute(config.schemaDir)) {
2004
+ if (path5.isAbsolute(config.schemaDir)) {
1954
2005
  return config.schemaDir;
1955
2006
  }
1956
- return path4.join(workspaceRoot, config.schemaDir);
2007
+ return path5.join(workspaceRoot, config.schemaDir);
1957
2008
  }
1958
2009
  function discoverSchemaFiles(config) {
1959
2010
  const normalizedConfig = typeof config === "string" ? { schemaDir: config } : config;
1960
2011
  const mergedConfig = mergeConfig(normalizedConfig);
1961
2012
  const schemaDir = resolveSchemaDir(normalizedConfig);
1962
2013
  try {
1963
- if (!fs2.existsSync(schemaDir)) {
2014
+ if (!fs3.existsSync(schemaDir)) {
1964
2015
  throw new FileSystemError(`Schema directory not found: ${schemaDir}`, schemaDir, "access", "ENOENT");
1965
2016
  }
1966
- const files = fs2.readdirSync(schemaDir);
2017
+ const files = fs3.readdirSync(schemaDir);
1967
2018
  const schemaFiles = files.filter((file) => {
1968
2019
  const hasValidExtension = mergedConfig.includeExtensions.some((ext) => file.endsWith(ext));
1969
2020
  if (!hasValidExtension) return false;
@@ -1979,7 +2030,7 @@ function discoverSchemaFiles(config) {
1979
2030
  });
1980
2031
  return schemaFiles.map((file) => {
1981
2032
  const ext = mergedConfig.includeExtensions.find((ext2) => file.endsWith(ext2)) || ".ts";
1982
- return path4.join(schemaDir, file.replace(new RegExp(`\\${ext}$`), ""));
2033
+ return path5.join(schemaDir, file.replace(new RegExp(`\\${ext}$`), ""));
1983
2034
  });
1984
2035
  } catch (error) {
1985
2036
  if (error instanceof FileSystemError) {
@@ -2013,40 +2064,66 @@ async function importSchemaModule(filePath, config) {
2013
2064
  let resolvedPath = null;
2014
2065
  const jsPath = `${importPath}.js`;
2015
2066
  const tsPath = `${importPath}.ts`;
2016
- if (fs2.existsSync(jsPath)) {
2067
+ if (fs3.existsSync(jsPath)) {
2017
2068
  resolvedPath = jsPath;
2018
- } else if (fs2.existsSync(tsPath)) {
2069
+ } else if (fs3.existsSync(tsPath)) {
2019
2070
  resolvedPath = tsPath;
2020
2071
  } else {
2021
2072
  resolvedPath = jsPath;
2022
2073
  }
2023
- const fileUrl = new URL(`file://${path4.resolve(resolvedPath)}`);
2074
+ if (resolvedPath.endsWith(".ts")) {
2075
+ await ensureTsxLoader();
2076
+ if (!tsxLoaderRegistered) {
2077
+ throw new SchemaParsingError(
2078
+ `Failed to import TypeScript schema file. The 'tsx' package is required to load TypeScript files.
2079
+ Please install tsx: npm install tsx (or yarn add tsx, or pnpm add tsx)
2080
+ Alternatively, compile your schema files to JavaScript first.`,
2081
+ filePath
2082
+ );
2083
+ }
2084
+ }
2085
+ const fileUrl = new URL(`file://${path5.resolve(resolvedPath)}`);
2024
2086
  const module = await import(fileUrl.href);
2025
2087
  return module;
2026
2088
  } catch (error) {
2027
2089
  const tsPath = `${filePath}.ts`;
2028
- const isTypeScriptFile = fs2.existsSync(tsPath);
2090
+ const isTypeScriptFile = fs3.existsSync(tsPath);
2091
+ if (isTypeScriptFile && error instanceof SchemaParsingError) {
2092
+ throw error;
2093
+ }
2029
2094
  if (isTypeScriptFile) {
2030
2095
  throw new SchemaParsingError(
2031
- `Failed to import TypeScript schema file. Node.js cannot import TypeScript files directly.
2032
- Please either:
2033
- 1. Compile your schema files to JavaScript first, or
2034
- 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")`,
2096
+ `Failed to import TypeScript schema file. The 'tsx' package is required to load TypeScript files.
2097
+ Please install tsx: npm install tsx (or yarn add tsx, or pnpm add tsx)
2098
+ Alternatively, compile your schema files to JavaScript first.`,
2035
2099
  filePath,
2036
2100
  error
2037
2101
  );
2038
2102
  }
2039
2103
  throw new SchemaParsingError(
2040
- `Failed to import schema module. Make sure the schema files are compiled to JavaScript.`,
2104
+ `Failed to import schema module. Make sure the schema files exist and are valid.`,
2041
2105
  filePath,
2042
2106
  error
2043
2107
  );
2044
2108
  }
2045
2109
  }
2046
2110
  function getCollectionNameFromFile(filePath) {
2047
- const filename = path4.basename(filePath).replace(/\.(ts|js)$/, "");
2111
+ const filename = path5.basename(filePath).replace(/\.(ts|js)$/, "");
2048
2112
  return toCollectionName(filename);
2049
2113
  }
2114
+ function extractCollectionNameFromSchema(zodSchema) {
2115
+ if (!zodSchema.description) {
2116
+ return null;
2117
+ }
2118
+ try {
2119
+ const metadata = JSON.parse(zodSchema.description);
2120
+ if (metadata.collectionName && typeof metadata.collectionName === "string") {
2121
+ return metadata.collectionName;
2122
+ }
2123
+ } catch {
2124
+ }
2125
+ return null;
2126
+ }
2050
2127
  function extractSchemaDefinitions(module, patterns = ["Schema", "InputSchema"]) {
2051
2128
  const result = {};
2052
2129
  for (const [key, value] of Object.entries(module)) {
@@ -2209,7 +2286,7 @@ async function buildSchemaDefinition(config) {
2209
2286
  importPath = normalizedConfig.pathTransformer(filePath);
2210
2287
  } else if (mergedConfig.useCompiledFiles) {
2211
2288
  const distPath = filePath.replace(/\/src\//, "/dist/");
2212
- if (fs2.existsSync(`${distPath}.js`) || fs2.existsSync(`${distPath}.mjs`)) {
2289
+ if (fs3.existsSync(`${distPath}.js`) || fs3.existsSync(`${distPath}.mjs`)) {
2213
2290
  importPath = distPath;
2214
2291
  } else {
2215
2292
  importPath = filePath;
@@ -2222,7 +2299,8 @@ async function buildSchemaDefinition(config) {
2222
2299
  console.warn(`No valid schema found in ${filePath}, skipping...`);
2223
2300
  continue;
2224
2301
  }
2225
- const collectionName = getCollectionNameFromFile(filePath);
2302
+ const collectionNameFromSchema = extractCollectionNameFromSchema(zodSchema);
2303
+ const collectionName = collectionNameFromSchema ?? getCollectionNameFromFile(filePath);
2226
2304
  const collectionSchema = convertZodSchemaToCollectionSchema(collectionName, zodSchema);
2227
2305
  collections.set(collectionName, collectionSchema);
2228
2306
  } catch (error) {
@@ -2265,7 +2343,359 @@ var SchemaAnalyzer = class {
2265
2343
  return convertZodSchemaToCollectionSchema(name, schema);
2266
2344
  }
2267
2345
  };
2346
+
2347
+ // src/migration/pocketbase-converter.ts
2268
2348
  var SNAPSHOT_VERSION = "1.0.0";
2349
+ function resolveCollectionIdToName(collectionId) {
2350
+ if (collectionId === "_pb_users_auth_") {
2351
+ return "Users";
2352
+ }
2353
+ const nameMatch = collectionId.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
2354
+ if (nameMatch) {
2355
+ return nameMatch[1];
2356
+ }
2357
+ return collectionId;
2358
+ }
2359
+ function convertPocketBaseCollection(pbCollection) {
2360
+ const fields = [];
2361
+ const systemFieldNames = ["id", "created", "updated", "collectionId", "collectionName", "expand"];
2362
+ const authSystemFieldNames = ["email", "emailVisibility", "verified", "password", "tokenKey"];
2363
+ if (pbCollection.fields && Array.isArray(pbCollection.fields)) {
2364
+ for (const pbField of pbCollection.fields) {
2365
+ if (pbField.system || systemFieldNames.includes(pbField.name)) {
2366
+ continue;
2367
+ }
2368
+ if (pbCollection.type === "auth" && authSystemFieldNames.includes(pbField.name)) {
2369
+ continue;
2370
+ }
2371
+ const field = {
2372
+ name: pbField.name,
2373
+ type: pbField.type,
2374
+ required: pbField.required || false
2375
+ };
2376
+ field.options = pbField.options ? { ...pbField.options } : {};
2377
+ if (pbField.type === "select") {
2378
+ if (pbField.values && Array.isArray(pbField.values)) {
2379
+ field.options.values = pbField.values;
2380
+ } else if (pbField.options?.values && Array.isArray(pbField.options.values)) {
2381
+ field.options.values = pbField.options.values;
2382
+ }
2383
+ }
2384
+ if (pbField.type === "relation") {
2385
+ const collectionId = pbField.collectionId || pbField.options?.collectionId || "";
2386
+ const collectionName = resolveCollectionIdToName(collectionId);
2387
+ field.relation = {
2388
+ collection: collectionName,
2389
+ cascadeDelete: pbField.cascadeDelete ?? pbField.options?.cascadeDelete ?? false,
2390
+ maxSelect: pbField.maxSelect ?? pbField.options?.maxSelect,
2391
+ minSelect: pbField.minSelect ?? pbField.options?.minSelect
2392
+ };
2393
+ }
2394
+ const hasOnlyValues = Object.keys(field.options).length === 1 && field.options.values !== void 0;
2395
+ if (Object.keys(field.options).length === 0) {
2396
+ delete field.options;
2397
+ } else if (pbField.type === "select" && hasOnlyValues) ;
2398
+ fields.push(field);
2399
+ }
2400
+ }
2401
+ const schema = {
2402
+ name: pbCollection.name,
2403
+ type: pbCollection.type || "base",
2404
+ fields
2405
+ };
2406
+ if (pbCollection.indexes && Array.isArray(pbCollection.indexes)) {
2407
+ schema.indexes = pbCollection.indexes;
2408
+ }
2409
+ const rules = {};
2410
+ if (pbCollection.listRule !== void 0) rules.listRule = pbCollection.listRule;
2411
+ if (pbCollection.viewRule !== void 0) rules.viewRule = pbCollection.viewRule;
2412
+ if (pbCollection.createRule !== void 0) rules.createRule = pbCollection.createRule;
2413
+ if (pbCollection.updateRule !== void 0) rules.updateRule = pbCollection.updateRule;
2414
+ if (pbCollection.deleteRule !== void 0) rules.deleteRule = pbCollection.deleteRule;
2415
+ if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
2416
+ if (Object.keys(rules).length > 0) {
2417
+ schema.rules = rules;
2418
+ schema.permissions = { ...rules };
2419
+ }
2420
+ return schema;
2421
+ }
2422
+ function convertPocketBaseMigration(migrationContent) {
2423
+ try {
2424
+ const snapshotMatch = migrationContent.match(/const\s+snapshot\s*=\s*(\[[\s\S]*?\]);/);
2425
+ if (!snapshotMatch) {
2426
+ throw new Error("Could not find snapshot array in migration file");
2427
+ }
2428
+ const snapshotArrayStr = snapshotMatch[1];
2429
+ let snapshotArray;
2430
+ try {
2431
+ snapshotArray = new Function(`return ${snapshotArrayStr}`)();
2432
+ } catch (parseError) {
2433
+ throw new Error(`Failed to parse snapshot array: ${parseError}`);
2434
+ }
2435
+ if (!Array.isArray(snapshotArray)) {
2436
+ throw new Error("Snapshot is not an array");
2437
+ }
2438
+ const collections = /* @__PURE__ */ new Map();
2439
+ for (const pbCollection of snapshotArray) {
2440
+ if (!pbCollection.name) {
2441
+ console.warn("Skipping collection without name");
2442
+ continue;
2443
+ }
2444
+ const schema = convertPocketBaseCollection(pbCollection);
2445
+ collections.set(pbCollection.name, schema);
2446
+ }
2447
+ return {
2448
+ version: SNAPSHOT_VERSION,
2449
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2450
+ collections
2451
+ };
2452
+ } catch (error) {
2453
+ throw new SnapshotError(
2454
+ `Failed to convert PocketBase migration: ${error instanceof Error ? error.message : String(error)}`,
2455
+ void 0,
2456
+ "parse",
2457
+ error instanceof Error ? error : void 0
2458
+ );
2459
+ }
2460
+ }
2461
+
2462
+ // src/migration/migration-parser.ts
2463
+ function extractTimestampFromFilename(filename) {
2464
+ const match = filename.match(/^(\d+)_/);
2465
+ if (match) {
2466
+ return parseInt(match[1], 10);
2467
+ }
2468
+ return null;
2469
+ }
2470
+ function findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp) {
2471
+ try {
2472
+ if (!fs3.existsSync(migrationsPath)) {
2473
+ return [];
2474
+ }
2475
+ const files = fs3.readdirSync(migrationsPath);
2476
+ const migrationFiles = [];
2477
+ for (const file of files) {
2478
+ if (file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")) {
2479
+ continue;
2480
+ }
2481
+ if (!file.endsWith(".js")) {
2482
+ continue;
2483
+ }
2484
+ const timestamp = extractTimestampFromFilename(file);
2485
+ if (timestamp && timestamp > snapshotTimestamp) {
2486
+ migrationFiles.push({
2487
+ path: path5.join(migrationsPath, file),
2488
+ timestamp
2489
+ });
2490
+ }
2491
+ }
2492
+ migrationFiles.sort((a, b) => a.timestamp - b.timestamp);
2493
+ return migrationFiles.map((f) => f.path);
2494
+ } catch (error) {
2495
+ console.warn(`Error finding migrations after snapshot: ${error}`);
2496
+ return [];
2497
+ }
2498
+ }
2499
+ function parseMigrationOperationsFromContent(content) {
2500
+ const collectionsToCreate = [];
2501
+ const collectionsToDelete = [];
2502
+ try {
2503
+ let searchIndex = 0;
2504
+ while (true) {
2505
+ const collectionStart = content.indexOf("new Collection(", searchIndex);
2506
+ if (collectionStart === -1) {
2507
+ break;
2508
+ }
2509
+ const openParen = collectionStart + "new Collection(".length;
2510
+ let braceCount = 0;
2511
+ let parenCount = 1;
2512
+ let inString = false;
2513
+ let stringChar = null;
2514
+ let i = openParen;
2515
+ while (i < content.length && /\s/.test(content[i])) {
2516
+ i++;
2517
+ }
2518
+ if (content[i] !== "{") {
2519
+ searchIndex = i + 1;
2520
+ continue;
2521
+ }
2522
+ const objectStart = i;
2523
+ braceCount = 1;
2524
+ i++;
2525
+ while (i < content.length && (braceCount > 0 || parenCount > 0)) {
2526
+ const char = content[i];
2527
+ const prevChar = i > 0 ? content[i - 1] : "";
2528
+ if (!inString && (char === '"' || char === "'")) {
2529
+ inString = true;
2530
+ stringChar = char;
2531
+ } else if (inString && char === stringChar && prevChar !== "\\") {
2532
+ inString = false;
2533
+ stringChar = null;
2534
+ }
2535
+ if (!inString) {
2536
+ if (char === "{") braceCount++;
2537
+ if (char === "}") braceCount--;
2538
+ if (char === "(") parenCount++;
2539
+ if (char === ")") parenCount--;
2540
+ }
2541
+ i++;
2542
+ }
2543
+ if (braceCount === 0 && parenCount === 0) {
2544
+ const objectContent = content.substring(objectStart, i - 1);
2545
+ try {
2546
+ const collectionObj = new Function(`return ${objectContent}`)();
2547
+ if (collectionObj && collectionObj.name) {
2548
+ const schema = convertPocketBaseCollection(collectionObj);
2549
+ collectionsToCreate.push(schema);
2550
+ }
2551
+ } catch (error) {
2552
+ console.warn(`Failed to parse collection definition: ${error}`);
2553
+ }
2554
+ }
2555
+ searchIndex = i;
2556
+ }
2557
+ const deleteMatches = content.matchAll(
2558
+ /app\.delete\s*\(\s*(?:collection_\w+|app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\))\s*\)/g
2559
+ );
2560
+ for (const match of deleteMatches) {
2561
+ if (match[1]) {
2562
+ collectionsToDelete.push(match[1]);
2563
+ } else {
2564
+ const varNameMatch = match[0].match(/collection_(\w+)/);
2565
+ if (varNameMatch) {
2566
+ const varName = `collection_${varNameMatch[1]}`;
2567
+ const deleteIndex = content.indexOf(match[0]);
2568
+ const beforeDelete = content.substring(0, deleteIndex);
2569
+ const varDefMatch = beforeDelete.match(
2570
+ new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`, "g")
2571
+ );
2572
+ if (varDefMatch && varDefMatch.length > 0) {
2573
+ const collectionDefMatch = beforeDelete.match(
2574
+ new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`)
2575
+ );
2576
+ if (collectionDefMatch) {
2577
+ try {
2578
+ const collectionDefStr = collectionDefMatch[1];
2579
+ const collectionObj = new Function(`return ${collectionDefStr}`)();
2580
+ if (collectionObj && collectionObj.name) {
2581
+ collectionsToDelete.push(collectionObj.name);
2582
+ }
2583
+ } catch {
2584
+ }
2585
+ }
2586
+ }
2587
+ }
2588
+ }
2589
+ }
2590
+ const findAndDeleteMatches = content.matchAll(
2591
+ /app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)[\s\S]*?app\.delete/g
2592
+ );
2593
+ for (const match of findAndDeleteMatches) {
2594
+ collectionsToDelete.push(match[1]);
2595
+ }
2596
+ } catch (error) {
2597
+ console.warn(`Failed to parse migration operations from content: ${error}`);
2598
+ }
2599
+ return { collectionsToCreate, collectionsToDelete };
2600
+ }
2601
+ function parseMigrationOperations(migrationContent) {
2602
+ try {
2603
+ const migrateMatch = migrationContent.match(/migrate\s*\(\s*/);
2604
+ if (!migrateMatch) {
2605
+ return parseMigrationOperationsFromContent(migrationContent);
2606
+ }
2607
+ const startIndex = migrateMatch.index + migrateMatch[0].length;
2608
+ let i = startIndex;
2609
+ let parenCount = 0;
2610
+ let foundFirstParen = false;
2611
+ while (i < migrationContent.length) {
2612
+ const char = migrationContent[i];
2613
+ if (char === "(") {
2614
+ parenCount++;
2615
+ foundFirstParen = true;
2616
+ i++;
2617
+ break;
2618
+ }
2619
+ i++;
2620
+ }
2621
+ if (!foundFirstParen) {
2622
+ return parseMigrationOperationsFromContent(migrationContent);
2623
+ }
2624
+ let inString = false;
2625
+ let stringChar = null;
2626
+ let foundBrace = false;
2627
+ let braceStart = -1;
2628
+ while (i < migrationContent.length && !foundBrace) {
2629
+ const char = migrationContent[i];
2630
+ const prevChar = i > 0 ? migrationContent[i - 1] : "";
2631
+ if (!inString && (char === '"' || char === "'")) {
2632
+ inString = true;
2633
+ stringChar = char;
2634
+ } else if (inString && char === stringChar && prevChar !== "\\") {
2635
+ inString = false;
2636
+ stringChar = null;
2637
+ }
2638
+ if (!inString) {
2639
+ if (char === "(") parenCount++;
2640
+ if (char === ")") {
2641
+ parenCount--;
2642
+ if (parenCount === 0) {
2643
+ i++;
2644
+ while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
2645
+ i++;
2646
+ }
2647
+ if (i < migrationContent.length - 1 && migrationContent[i] === "=" && migrationContent[i + 1] === ">") {
2648
+ i += 2;
2649
+ while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
2650
+ i++;
2651
+ }
2652
+ if (i < migrationContent.length && migrationContent[i] === "{") {
2653
+ foundBrace = true;
2654
+ braceStart = i + 1;
2655
+ break;
2656
+ }
2657
+ }
2658
+ }
2659
+ }
2660
+ }
2661
+ i++;
2662
+ }
2663
+ if (!foundBrace || braceStart === -1) {
2664
+ return parseMigrationOperationsFromContent(migrationContent);
2665
+ }
2666
+ let braceCount = 1;
2667
+ i = braceStart;
2668
+ inString = false;
2669
+ stringChar = null;
2670
+ while (i < migrationContent.length && braceCount > 0) {
2671
+ const char = migrationContent[i];
2672
+ const prevChar = i > 0 ? migrationContent[i - 1] : "";
2673
+ if (!inString && (char === '"' || char === "'")) {
2674
+ inString = true;
2675
+ stringChar = char;
2676
+ } else if (inString && char === stringChar && prevChar !== "\\") {
2677
+ inString = false;
2678
+ stringChar = null;
2679
+ }
2680
+ if (!inString) {
2681
+ if (char === "{") braceCount++;
2682
+ if (char === "}") braceCount--;
2683
+ }
2684
+ i++;
2685
+ }
2686
+ if (braceCount === 0) {
2687
+ const upMigrationContent = migrationContent.substring(braceStart, i - 1);
2688
+ return parseMigrationOperationsFromContent(upMigrationContent);
2689
+ }
2690
+ return parseMigrationOperationsFromContent(migrationContent);
2691
+ } catch (error) {
2692
+ console.warn(`Failed to parse migration operations: ${error}`);
2693
+ return { collectionsToCreate: [], collectionsToDelete: [] };
2694
+ }
2695
+ }
2696
+
2697
+ // src/migration/snapshot.ts
2698
+ var SNAPSHOT_VERSION2 = "1.0.0";
2269
2699
  var DEFAULT_SNAPSHOT_FILENAME = ".migration-snapshot.json";
2270
2700
  var SNAPSHOT_MIGRATIONS = [
2271
2701
  // Add migrations here as the format evolves
@@ -2280,7 +2710,7 @@ var DEFAULT_CONFIG2 = {
2280
2710
  snapshotPath: DEFAULT_SNAPSHOT_FILENAME,
2281
2711
  workspaceRoot: process.cwd(),
2282
2712
  autoMigrate: true,
2283
- version: SNAPSHOT_VERSION
2713
+ version: SNAPSHOT_VERSION2
2284
2714
  };
2285
2715
  function mergeConfig2(config = {}) {
2286
2716
  return {
@@ -2292,15 +2722,15 @@ function getSnapshotPath(config = {}) {
2292
2722
  const mergedConfig = mergeConfig2(config);
2293
2723
  const workspaceRoot = mergedConfig.workspaceRoot;
2294
2724
  const snapshotFilename = mergedConfig.snapshotPath;
2295
- if (path4.isAbsolute(snapshotFilename)) {
2725
+ if (path5.isAbsolute(snapshotFilename)) {
2296
2726
  return snapshotFilename;
2297
2727
  }
2298
- return path4.join(workspaceRoot, snapshotFilename);
2728
+ return path5.join(workspaceRoot, snapshotFilename);
2299
2729
  }
2300
2730
  function snapshotExists(config = {}) {
2301
2731
  try {
2302
2732
  const snapshotPath = getSnapshotPath(config);
2303
- return fs2.existsSync(snapshotPath);
2733
+ return fs3.existsSync(snapshotPath);
2304
2734
  } catch {
2305
2735
  return false;
2306
2736
  }
@@ -2359,13 +2789,13 @@ function addSnapshotMetadata(schema, config) {
2359
2789
  function saveSnapshot(schema, config = {}) {
2360
2790
  const snapshotPath = getSnapshotPath(config);
2361
2791
  try {
2362
- const snapshotDir = path4.dirname(snapshotPath);
2363
- if (!fs2.existsSync(snapshotDir)) {
2364
- fs2.mkdirSync(snapshotDir, { recursive: true });
2792
+ const snapshotDir = path5.dirname(snapshotPath);
2793
+ if (!fs3.existsSync(snapshotDir)) {
2794
+ fs3.mkdirSync(snapshotDir, { recursive: true });
2365
2795
  }
2366
2796
  const snapshotData = addSnapshotMetadata(schema, config);
2367
2797
  const jsonContent = JSON.stringify(snapshotData, null, 2);
2368
- fs2.writeFileSync(snapshotPath, jsonContent, "utf-8");
2798
+ fs3.writeFileSync(snapshotPath, jsonContent, "utf-8");
2369
2799
  } catch (error) {
2370
2800
  handleFileSystemError(error, "write", snapshotPath);
2371
2801
  }
@@ -2460,7 +2890,7 @@ function deserializeSnapshot(data) {
2460
2890
  function loadSnapshot(config = {}) {
2461
2891
  const snapshotPath = getSnapshotPath(config);
2462
2892
  try {
2463
- const jsonContent = fs2.readFileSync(snapshotPath, "utf-8");
2893
+ const jsonContent = fs3.readFileSync(snapshotPath, "utf-8");
2464
2894
  const data = parseAndValidateSnapshot(jsonContent, snapshotPath);
2465
2895
  const migratedData = migrateSnapshotFormat(data, config);
2466
2896
  return deserializeSnapshot(migratedData);
@@ -2495,10 +2925,10 @@ function mergeSnapshots(baseSnapshot, customSnapshot) {
2495
2925
  }
2496
2926
  function findLatestSnapshot(migrationsPath) {
2497
2927
  try {
2498
- if (!fs2.existsSync(migrationsPath)) {
2928
+ if (!fs3.existsSync(migrationsPath)) {
2499
2929
  return null;
2500
2930
  }
2501
- const files = fs2.readdirSync(migrationsPath);
2931
+ const files = fs3.readdirSync(migrationsPath);
2502
2932
  const snapshotFiles = files.filter(
2503
2933
  (file) => file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")
2504
2934
  );
@@ -2510,20 +2940,74 @@ function findLatestSnapshot(migrationsPath) {
2510
2940
  if (!latestSnapshot) {
2511
2941
  return null;
2512
2942
  }
2513
- return path4.join(migrationsPath, latestSnapshot);
2943
+ return path5.join(migrationsPath, latestSnapshot);
2514
2944
  } catch (error) {
2515
2945
  console.warn(`Error finding latest snapshot: ${error}`);
2516
2946
  return null;
2517
2947
  }
2518
2948
  }
2949
+ function applyMigrationOperations(snapshot, operations) {
2950
+ const updatedCollections = new Map(snapshot.collections);
2951
+ for (const collectionName of operations.collectionsToDelete) {
2952
+ updatedCollections.delete(collectionName);
2953
+ }
2954
+ for (const collection of operations.collectionsToCreate) {
2955
+ updatedCollections.set(collection.name, collection);
2956
+ }
2957
+ return {
2958
+ ...snapshot,
2959
+ collections: updatedCollections
2960
+ };
2961
+ }
2962
+ function loadSnapshotWithMigrations(config = {}) {
2963
+ const migrationsPath = config.migrationsPath;
2964
+ if (!migrationsPath) {
2965
+ return null;
2966
+ }
2967
+ if (fs3.existsSync(migrationsPath) && fs3.statSync(migrationsPath).isFile()) {
2968
+ try {
2969
+ const migrationContent = fs3.readFileSync(migrationsPath, "utf-8");
2970
+ return convertPocketBaseMigration(migrationContent);
2971
+ } catch (error) {
2972
+ console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
2973
+ return null;
2974
+ }
2975
+ }
2976
+ const latestSnapshotPath = findLatestSnapshot(migrationsPath);
2977
+ if (!latestSnapshotPath) {
2978
+ return null;
2979
+ }
2980
+ try {
2981
+ const migrationContent = fs3.readFileSync(latestSnapshotPath, "utf-8");
2982
+ let snapshot = convertPocketBaseMigration(migrationContent);
2983
+ const snapshotFilename = path5.basename(latestSnapshotPath);
2984
+ const snapshotTimestamp = extractTimestampFromFilename(snapshotFilename);
2985
+ if (snapshotTimestamp) {
2986
+ const migrationFiles = findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp);
2987
+ for (const migrationFile of migrationFiles) {
2988
+ try {
2989
+ const migrationContent2 = fs3.readFileSync(migrationFile, "utf-8");
2990
+ const operations = parseMigrationOperations(migrationContent2);
2991
+ snapshot = applyMigrationOperations(snapshot, operations);
2992
+ } catch (error) {
2993
+ console.warn(`Failed to apply migration ${migrationFile}: ${error}`);
2994
+ }
2995
+ }
2996
+ }
2997
+ return snapshot;
2998
+ } catch (error) {
2999
+ console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
3000
+ return null;
3001
+ }
3002
+ }
2519
3003
  function loadSnapshotIfExists(config = {}) {
2520
3004
  const migrationsPath = config.migrationsPath;
2521
3005
  if (!migrationsPath) {
2522
3006
  return null;
2523
3007
  }
2524
- if (fs2.existsSync(migrationsPath) && fs2.statSync(migrationsPath).isFile()) {
3008
+ if (fs3.existsSync(migrationsPath) && fs3.statSync(migrationsPath).isFile()) {
2525
3009
  try {
2526
- const migrationContent = fs2.readFileSync(migrationsPath, "utf-8");
3010
+ const migrationContent = fs3.readFileSync(migrationsPath, "utf-8");
2527
3011
  return convertPocketBaseMigration(migrationContent);
2528
3012
  } catch (error) {
2529
3013
  console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
@@ -2533,7 +3017,7 @@ function loadSnapshotIfExists(config = {}) {
2533
3017
  const latestSnapshotPath = findLatestSnapshot(migrationsPath);
2534
3018
  if (latestSnapshotPath) {
2535
3019
  try {
2536
- const migrationContent = fs2.readFileSync(latestSnapshotPath, "utf-8");
3020
+ const migrationContent = fs3.readFileSync(latestSnapshotPath, "utf-8");
2537
3021
  return convertPocketBaseMigration(migrationContent);
2538
3022
  } catch (error) {
2539
3023
  console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
@@ -2542,100 +3026,9 @@ function loadSnapshotIfExists(config = {}) {
2542
3026
  }
2543
3027
  return null;
2544
3028
  }
2545
- function convertPocketBaseCollection(pbCollection) {
2546
- const fields = [];
2547
- const systemFieldNames = ["id", "created", "updated", "collectionId", "collectionName", "expand"];
2548
- const authSystemFieldNames = ["email", "emailVisibility", "verified", "password", "tokenKey"];
2549
- if (pbCollection.fields && Array.isArray(pbCollection.fields)) {
2550
- for (const pbField of pbCollection.fields) {
2551
- if (pbField.system || systemFieldNames.includes(pbField.name)) {
2552
- continue;
2553
- }
2554
- if (pbCollection.type === "auth" && authSystemFieldNames.includes(pbField.name)) {
2555
- continue;
2556
- }
2557
- const field = {
2558
- name: pbField.name,
2559
- type: pbField.type,
2560
- required: pbField.required || false
2561
- };
2562
- if (pbField.options) {
2563
- field.options = pbField.options;
2564
- }
2565
- if (pbField.type === "relation") {
2566
- field.relation = {
2567
- collection: pbField.options?.collectionId || "",
2568
- cascadeDelete: pbField.options?.cascadeDelete || false,
2569
- maxSelect: pbField.options?.maxSelect,
2570
- minSelect: pbField.options?.minSelect
2571
- };
2572
- }
2573
- fields.push(field);
2574
- }
2575
- }
2576
- const schema = {
2577
- name: pbCollection.name,
2578
- type: pbCollection.type || "base",
2579
- fields
2580
- };
2581
- if (pbCollection.indexes && Array.isArray(pbCollection.indexes)) {
2582
- schema.indexes = pbCollection.indexes;
2583
- }
2584
- const rules = {};
2585
- if (pbCollection.listRule !== void 0) rules.listRule = pbCollection.listRule;
2586
- if (pbCollection.viewRule !== void 0) rules.viewRule = pbCollection.viewRule;
2587
- if (pbCollection.createRule !== void 0) rules.createRule = pbCollection.createRule;
2588
- if (pbCollection.updateRule !== void 0) rules.updateRule = pbCollection.updateRule;
2589
- if (pbCollection.deleteRule !== void 0) rules.deleteRule = pbCollection.deleteRule;
2590
- if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
2591
- if (Object.keys(rules).length > 0) {
2592
- schema.rules = rules;
2593
- schema.permissions = { ...rules };
2594
- }
2595
- return schema;
2596
- }
2597
- function convertPocketBaseMigration(migrationContent) {
2598
- try {
2599
- const snapshotMatch = migrationContent.match(/const\s+snapshot\s*=\s*(\[[\s\S]*?\]);/);
2600
- if (!snapshotMatch) {
2601
- throw new Error("Could not find snapshot array in migration file");
2602
- }
2603
- const snapshotArrayStr = snapshotMatch[1];
2604
- let snapshotArray;
2605
- try {
2606
- snapshotArray = new Function(`return ${snapshotArrayStr}`)();
2607
- } catch (parseError) {
2608
- throw new Error(`Failed to parse snapshot array: ${parseError}`);
2609
- }
2610
- if (!Array.isArray(snapshotArray)) {
2611
- throw new Error("Snapshot is not an array");
2612
- }
2613
- const collections = /* @__PURE__ */ new Map();
2614
- for (const pbCollection of snapshotArray) {
2615
- if (!pbCollection.name) {
2616
- console.warn("Skipping collection without name");
2617
- continue;
2618
- }
2619
- const schema = convertPocketBaseCollection(pbCollection);
2620
- collections.set(pbCollection.name, schema);
2621
- }
2622
- return {
2623
- version: SNAPSHOT_VERSION,
2624
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2625
- collections
2626
- };
2627
- } catch (error) {
2628
- throw new SnapshotError(
2629
- `Failed to convert PocketBase migration: ${error instanceof Error ? error.message : String(error)}`,
2630
- void 0,
2631
- "parse",
2632
- error instanceof Error ? error : void 0
2633
- );
2634
- }
2635
- }
2636
3029
  function loadBaseMigration(migrationPath) {
2637
3030
  try {
2638
- if (!fs2.existsSync(migrationPath)) {
3031
+ if (!fs3.existsSync(migrationPath)) {
2639
3032
  throw new SnapshotError(
2640
3033
  `Base migration file not found: ${migrationPath}
2641
3034
 
@@ -2646,7 +3039,7 @@ If the file exists in a different location, update the configuration.`,
2646
3039
  "read"
2647
3040
  );
2648
3041
  }
2649
- const migrationContent = fs2.readFileSync(migrationPath, "utf-8");
3042
+ const migrationContent = fs3.readFileSync(migrationPath, "utf-8");
2650
3043
  const snapshot = convertPocketBaseMigration(migrationContent);
2651
3044
  return snapshot;
2652
3045
  } catch (error) {
@@ -2682,14 +3075,14 @@ Please ensure PocketBase is properly set up by running 'yarn setup'.`,
2682
3075
  }
2683
3076
  }
2684
3077
  function getSnapshotVersion() {
2685
- return SNAPSHOT_VERSION;
3078
+ return SNAPSHOT_VERSION2;
2686
3079
  }
2687
3080
  function validateSnapshot(snapshot) {
2688
3081
  const issues = [];
2689
3082
  if (!snapshot.version) {
2690
3083
  issues.push("Missing version field");
2691
- } else if (compareVersions(snapshot.version, SNAPSHOT_VERSION) > 0) {
2692
- issues.push(`Snapshot version ${snapshot.version} is newer than supported version ${SNAPSHOT_VERSION}`);
3084
+ } else if (compareVersions(snapshot.version, SNAPSHOT_VERSION2) > 0) {
3085
+ issues.push(`Snapshot version ${snapshot.version} is newer than supported version ${SNAPSHOT_VERSION2}`);
2693
3086
  }
2694
3087
  if (!snapshot.timestamp) {
2695
3088
  issues.push("Missing timestamp field");
@@ -2908,6 +3301,9 @@ function compareFieldOptions(currentField, previousField) {
2908
3301
  for (const key of allKeys) {
2909
3302
  const currentValue = currentOptions[key];
2910
3303
  const previousValue = previousOptions[key];
3304
+ if (currentValue === void 0 && previousValue === void 0) {
3305
+ continue;
3306
+ }
2911
3307
  if (!areValuesEqual(currentValue, previousValue)) {
2912
3308
  changes.push({
2913
3309
  property: `options.${key}`,
@@ -2928,11 +3324,26 @@ function compareRelationConfigurations(currentField, previousField) {
2928
3324
  if (!currentRelation || !previousRelation) {
2929
3325
  return changes;
2930
3326
  }
2931
- if (currentRelation.collection !== previousRelation.collection) {
3327
+ const normalizeCollection = (collection) => {
3328
+ if (!collection) return collection;
3329
+ if (collection === "_pb_users_auth_") {
3330
+ return "Users";
3331
+ }
3332
+ const nameMatch = collection.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
3333
+ if (nameMatch) {
3334
+ return nameMatch[1];
3335
+ }
3336
+ return collection;
3337
+ };
3338
+ const normalizedCurrent = normalizeCollection(currentRelation.collection);
3339
+ const normalizedPrevious = normalizeCollection(previousRelation.collection);
3340
+ if (normalizedCurrent !== normalizedPrevious) {
2932
3341
  changes.push({
2933
3342
  property: "relation.collection",
2934
- oldValue: previousRelation.collection,
2935
- newValue: currentRelation.collection
3343
+ oldValue: normalizedPrevious,
3344
+ // Use normalized value for clarity
3345
+ newValue: normalizedCurrent
3346
+ // Use normalized value for clarity
2936
3347
  });
2937
3348
  }
2938
3349
  if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {
@@ -3305,10 +3716,10 @@ function mergeConfig4(config) {
3305
3716
  }
3306
3717
  function resolveMigrationDir(config) {
3307
3718
  const workspaceRoot = config.workspaceRoot || process.cwd();
3308
- if (path4.isAbsolute(config.migrationDir)) {
3719
+ if (path5.isAbsolute(config.migrationDir)) {
3309
3720
  return config.migrationDir;
3310
3721
  }
3311
- return path4.join(workspaceRoot, config.migrationDir);
3722
+ return path5.join(workspaceRoot, config.migrationDir);
3312
3723
  }
3313
3724
  function generateTimestamp(config) {
3314
3725
  if (config?.timestampGenerator) {
@@ -3366,9 +3777,9 @@ function createMigrationFileStructure(upCode, downCode, config) {
3366
3777
  }
3367
3778
  function writeMigrationFile(migrationDir, filename, content) {
3368
3779
  try {
3369
- if (!fs2.existsSync(migrationDir)) {
3780
+ if (!fs3.existsSync(migrationDir)) {
3370
3781
  try {
3371
- fs2.mkdirSync(migrationDir, { recursive: true });
3782
+ fs3.mkdirSync(migrationDir, { recursive: true });
3372
3783
  } catch (error) {
3373
3784
  const fsError = error;
3374
3785
  if (fsError.code === "EACCES" || fsError.code === "EPERM") {
@@ -3389,15 +3800,15 @@ function writeMigrationFile(migrationDir, filename, content) {
3389
3800
  );
3390
3801
  }
3391
3802
  }
3392
- const filePath = path4.join(migrationDir, filename);
3393
- fs2.writeFileSync(filePath, content, "utf-8");
3803
+ const filePath = path5.join(migrationDir, filename);
3804
+ fs3.writeFileSync(filePath, content, "utf-8");
3394
3805
  return filePath;
3395
3806
  } catch (error) {
3396
3807
  if (error instanceof FileSystemError) {
3397
3808
  throw error;
3398
3809
  }
3399
3810
  const fsError = error;
3400
- const filePath = path4.join(migrationDir, filename);
3811
+ const filePath = path5.join(migrationDir, filename);
3401
3812
  if (fsError.code === "EACCES" || fsError.code === "EPERM") {
3402
3813
  throw new FileSystemError(
3403
3814
  `Permission denied writing migration file. Check file and directory permissions.`,
@@ -4141,8 +4552,8 @@ var DEFAULT_CONFIG5 = {
4141
4552
  };
4142
4553
  function findConfigFile(directory) {
4143
4554
  for (const fileName of CONFIG_FILE_NAMES) {
4144
- const filePath = path4.join(directory, fileName);
4145
- if (fs2.existsSync(filePath)) {
4555
+ const filePath = path5.join(directory, fileName);
4556
+ if (fs3.existsSync(filePath)) {
4146
4557
  return filePath;
4147
4558
  }
4148
4559
  }
@@ -4150,7 +4561,7 @@ function findConfigFile(directory) {
4150
4561
  }
4151
4562
  function loadJsonConfig(configPath) {
4152
4563
  try {
4153
- const content = fs2.readFileSync(configPath, "utf-8");
4564
+ const content = fs3.readFileSync(configPath, "utf-8");
4154
4565
  return JSON.parse(content);
4155
4566
  } catch (error) {
4156
4567
  if (error instanceof SyntaxError) {
@@ -4179,10 +4590,10 @@ async function loadJsConfig(configPath) {
4179
4590
  }
4180
4591
  }
4181
4592
  async function loadConfigFile(configPath) {
4182
- if (!fs2.existsSync(configPath)) {
4593
+ if (!fs3.existsSync(configPath)) {
4183
4594
  return null;
4184
4595
  }
4185
- const ext = path4.extname(configPath).toLowerCase();
4596
+ const ext = path5.extname(configPath).toLowerCase();
4186
4597
  if (ext === ".json") {
4187
4598
  return loadJsonConfig(configPath);
4188
4599
  } else if (ext === ".js" || ext === ".mjs") {
@@ -4249,10 +4660,10 @@ function validateConfig(config, configPath) {
4249
4660
  }
4250
4661
  const cwd = process.cwd();
4251
4662
  const possiblePaths = [
4252
- path4.resolve(cwd, config.schema.directory),
4253
- path4.resolve(cwd, "shared", config.schema.directory)
4663
+ path5.resolve(cwd, config.schema.directory),
4664
+ path5.resolve(cwd, "shared", config.schema.directory)
4254
4665
  ];
4255
- const schemaDir = possiblePaths.find((p) => fs2.existsSync(p));
4666
+ const schemaDir = possiblePaths.find((p) => fs3.existsSync(p));
4256
4667
  if (!schemaDir) {
4257
4668
  throw new ConfigurationError(`Schema directory not found. Tried: ${possiblePaths.join(", ")}`, configPath, [
4258
4669
  "schema.directory"
@@ -4264,15 +4675,15 @@ async function loadConfig(options = {}) {
4264
4675
  let configFilePath;
4265
4676
  const cwd = process.cwd();
4266
4677
  if (options.config) {
4267
- const explicitPath = path4.resolve(cwd, options.config);
4268
- if (!fs2.existsSync(explicitPath)) {
4678
+ const explicitPath = path5.resolve(cwd, options.config);
4679
+ if (!fs3.existsSync(explicitPath)) {
4269
4680
  throw new ConfigurationError(`Configuration file not found: ${explicitPath}`, explicitPath);
4270
4681
  }
4271
4682
  configFilePath = explicitPath;
4272
4683
  } else {
4273
- const searchDirs = [cwd, path4.join(cwd, "shared")];
4684
+ const searchDirs = [cwd, path5.join(cwd, "shared")];
4274
4685
  for (const dir of searchDirs) {
4275
- if (fs2.existsSync(dir)) {
4686
+ if (fs3.existsSync(dir)) {
4276
4687
  const found = findConfigFile(dir);
4277
4688
  if (found) {
4278
4689
  configFilePath = found;
@@ -4301,18 +4712,18 @@ async function loadConfig(options = {}) {
4301
4712
  function getSchemaDirectory(config) {
4302
4713
  const cwd = process.cwd();
4303
4714
  const possiblePaths = [
4304
- path4.resolve(cwd, config.schema.directory),
4305
- path4.resolve(cwd, "shared", config.schema.directory)
4715
+ path5.resolve(cwd, config.schema.directory),
4716
+ path5.resolve(cwd, "shared", config.schema.directory)
4306
4717
  ];
4307
- return possiblePaths.find((p) => fs2.existsSync(p)) || possiblePaths[0];
4718
+ return possiblePaths.find((p) => fs3.existsSync(p)) || possiblePaths[0];
4308
4719
  }
4309
4720
  function getMigrationsDirectory(config) {
4310
4721
  const cwd = process.cwd();
4311
4722
  const possiblePaths = [
4312
- path4.resolve(cwd, config.migrations.directory),
4313
- path4.resolve(cwd, "shared", config.migrations.directory)
4723
+ path5.resolve(cwd, config.migrations.directory),
4724
+ path5.resolve(cwd, "shared", config.migrations.directory)
4314
4725
  ];
4315
- return possiblePaths.find((p) => fs2.existsSync(p)) || possiblePaths[0];
4726
+ return possiblePaths.find((p) => fs3.existsSync(p)) || possiblePaths[0];
4316
4727
  }
4317
4728
  var currentVerbosity = "normal";
4318
4729
  function setVerbosity(level) {
@@ -4529,7 +4940,7 @@ async function executeGenerate(options) {
4529
4940
  const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
4530
4941
  logSuccess(`Found ${currentSchema.collections.size} collection(s)`);
4531
4942
  logInfo("Loading previous snapshot...");
4532
- const previousSnapshot = loadSnapshotIfExists({
4943
+ const previousSnapshot = loadSnapshotWithMigrations({
4533
4944
  migrationsPath: migrationsDir,
4534
4945
  workspaceRoot: process.cwd()
4535
4946
  });
@@ -4556,7 +4967,7 @@ async function executeGenerate(options) {
4556
4967
  "Creating migration file...",
4557
4968
  () => Promise.resolve(generate(diff, migrationsDir))
4558
4969
  );
4559
- logSuccess(`Migration file created: ${path4.basename(migrationPath)}`);
4970
+ logSuccess(`Migration file created: ${path5.basename(migrationPath)}`);
4560
4971
  logSection("\u2705 Next Steps");
4561
4972
  console.log();
4562
4973
  console.log(" 1. Review the generated migration file:");
@@ -4722,7 +5133,7 @@ async function executeStatus(options) {
4722
5133
  const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
4723
5134
  logSuccess(`Found ${currentSchema.collections.size} collection(s) in schema`);
4724
5135
  logInfo("Loading previous snapshot...");
4725
- const previousSnapshot = loadSnapshotIfExists({
5136
+ const previousSnapshot = loadSnapshotWithMigrations({
4726
5137
  migrationsPath: migrationsDir,
4727
5138
  workspaceRoot: process.cwd()
4728
5139
  });
@@ -4823,6 +5234,6 @@ async function executeStatus(options) {
4823
5234
  }
4824
5235
  }
4825
5236
 
4826
- export { CLIUsageError, ConfigurationError, DiffEngine, FIELD_TYPE_INFO, FileSystemError, MigrationError, MigrationGenerationError, MigrationGenerator, POCKETBASE_FIELD_TYPES, PermissionTemplates, SchemaAnalyzer, SchemaParsingError, SnapshotError, SnapshotManager, StatusEnum, UserInputSchema, UserMutator, UserSchema, aggregateChanges, baseImageFileSchema, baseSchema, baseSchemaWithTimestamps, boolField, buildFieldDefinition, buildSchemaDefinition, categorizeChangesBySeverity, compare, compareFieldConstraints, compareFieldOptions, compareFieldTypes, comparePermissions, compareRelationConfigurations, convertPocketBaseMigration, convertZodSchemaToCollectionSchema, createMigrationFileStructure, createPermissions, dateField, detectDestructiveChanges, detectFieldChanges, discoverSchemaFiles, editorField, emailField, extractComprehensiveFieldOptions, extractFieldDefinitions, extractFieldOptions, extractIndexes, extractRelationMetadata, extractSchemaDefinitions, fileField, filesField, filterSystemCollections, findLatestSnapshot, findNewCollections, findNewFields, findRemovedCollections, findRemovedFields, formatChangeSummary, generate, generateChangeSummary, generateCollectionCreation, generateCollectionPermissions, generateCollectionRules, generateDownMigration, generateFieldAddition, generateFieldDefinitionObject, generateFieldDeletion, generateFieldModification, generateFieldsArray, generateIndexesArray, executeGenerate as generateMigration, generateMigrationDescription, generateMigrationFilename, generatePermissionUpdate, generateTimestamp, generateUpMigration, geoPointField, getArrayElementType, getCollectionNameFromFile, getDefaultValue, getFieldTypeInfo, getMaxSelect, executeStatus as getMigrationStatus, getMinSelect, getSnapshotPath, getSnapshotVersion, getUsersSystemFields, importSchemaModule, inputImageFileSchema, isArrayType, isAuthCollection, isEditorField, isFieldRequired, isFileFieldByName, isGeoPointType, isMultipleRelationField, isPermissionSchema, isRelationField, isSingleRelationField, isSystemCollection, isTemplateConfig, jsonField, loadBaseMigration, loadConfig, loadSnapshot, loadSnapshotIfExists, logError, logInfo, logSection, logSuccess, logWarning, mapZodArrayType, mapZodBooleanType, mapZodDateType, mapZodEnumType, mapZodNumberType, mapZodRecordType, mapZodStringType, mapZodTypeToPocketBase, matchCollectionsByName, matchFieldsByName, mergePermissions, mergeSnapshots, numberField, omitImageFilesSchema, parseSchemaFiles, pluralize, relationField, relationsField, requiresForceFlag, resolveTargetCollection, resolveTemplate, saveSnapshot, selectField, selectSchemaForCollection, singularize, snapshotExists, textField, toCollectionName, unwrapZodType, urlField, validatePermissionConfig, validateRuleExpression, validateSnapshot, withIndexes, withPermissions, withProgress, writeMigrationFile };
5237
+ export { CLIUsageError, ConfigurationError, DiffEngine, FIELD_TYPE_INFO, FileSystemError, MigrationError, MigrationGenerationError, MigrationGenerator, POCKETBASE_FIELD_TYPES, PermissionTemplates, ProjectCollection, ProjectInputSchema, ProjectSchema, RelationField, RelationsField, SchemaAnalyzer, SchemaParsingError, SnapshotError, SnapshotManager, StatusEnum, UserCollection, UserCollectionSchema, UserInputSchema, UserMutator, UserSchema, aggregateChanges, baseImageFileSchema, baseSchema, baseSchemaWithTimestamps, boolField, buildFieldDefinition, buildSchemaDefinition, categorizeChangesBySeverity, compare, compareFieldConstraints, compareFieldOptions, compareFieldTypes, comparePermissions, compareRelationConfigurations, convertPocketBaseMigration, convertZodSchemaToCollectionSchema, createMigrationFileStructure, createPermissions, dateField, defineCollection, detectDestructiveChanges, detectFieldChanges, discoverSchemaFiles, editorField, emailField, extractComprehensiveFieldOptions, extractFieldDefinitions, extractFieldOptions, extractIndexes, extractRelationMetadata, extractSchemaDefinitions, fileField, filesField, filterSystemCollections, findLatestSnapshot, findNewCollections, findNewFields, findRemovedCollections, findRemovedFields, formatChangeSummary, generate, generateChangeSummary, generateCollectionCreation, generateCollectionPermissions, generateCollectionRules, generateDownMigration, generateFieldAddition, generateFieldDefinitionObject, generateFieldDeletion, generateFieldModification, generateFieldsArray, generateIndexesArray, executeGenerate as generateMigration, generateMigrationDescription, generateMigrationFilename, generatePermissionUpdate, generateTimestamp, generateUpMigration, geoPointField, getArrayElementType, getCollectionNameFromFile, getDefaultValue, getFieldTypeInfo, getMaxSelect, executeStatus as getMigrationStatus, getMinSelect, getSnapshotPath, getSnapshotVersion, getUsersSystemFields, importSchemaModule, inputImageFileSchema, isArrayType, isAuthCollection, isEditorField, isFieldRequired, isFileFieldByName, isGeoPointType, isMultipleRelationField, isPermissionSchema, isRelationField, isSingleRelationField, isSystemCollection, isTemplateConfig, jsonField, loadBaseMigration, loadConfig, loadSnapshot, loadSnapshotIfExists, loadSnapshotWithMigrations, logError, logInfo, logSection, logSuccess, logWarning, mapZodArrayType, mapZodBooleanType, mapZodDateType, mapZodEnumType, mapZodNumberType, mapZodRecordType, mapZodStringType, mapZodTypeToPocketBase, matchCollectionsByName, matchFieldsByName, mergePermissions, mergeSnapshots, numberField, omitImageFilesSchema, parseSchemaFiles, pluralize, requiresForceFlag, resolveTargetCollection, resolveTemplate, saveSnapshot, selectField, selectSchemaForCollection, singularize, snapshotExists, textField, toCollectionName, unwrapZodType, urlField, validatePermissionConfig, validateRuleExpression, validateSnapshot, withIndexes, withPermissions, withProgress, writeMigrationFile };
4827
5238
  //# sourceMappingURL=index.js.map
4828
5239
  //# sourceMappingURL=index.js.map