pocketbase-zod-schema 0.1.2 → 0.1.3

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 (63) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +329 -99
  3. package/dist/cli/index.cjs +176 -55
  4. package/dist/cli/index.cjs.map +1 -1
  5. package/dist/cli/index.js +176 -55
  6. package/dist/cli/index.js.map +1 -1
  7. package/dist/cli/migrate.cjs +196 -58
  8. package/dist/cli/migrate.cjs.map +1 -1
  9. package/dist/cli/migrate.js +194 -57
  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 +197 -96
  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 +197 -95
  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/generator.cjs +60 -25
  26. package/dist/migration/generator.cjs.map +1 -1
  27. package/dist/migration/generator.d.cts +9 -5
  28. package/dist/migration/generator.d.ts +9 -5
  29. package/dist/migration/generator.js +60 -25
  30. package/dist/migration/generator.js.map +1 -1
  31. package/dist/migration/index.cjs +162 -53
  32. package/dist/migration/index.cjs.map +1 -1
  33. package/dist/migration/index.js +162 -53
  34. package/dist/migration/index.js.map +1 -1
  35. package/dist/migration/snapshot.cjs +1 -0
  36. package/dist/migration/snapshot.cjs.map +1 -1
  37. package/dist/migration/snapshot.js +1 -0
  38. package/dist/migration/snapshot.js.map +1 -1
  39. package/dist/migration/utils/index.cjs +19 -17
  40. package/dist/migration/utils/index.cjs.map +1 -1
  41. package/dist/migration/utils/index.d.cts +3 -1
  42. package/dist/migration/utils/index.d.ts +3 -1
  43. package/dist/migration/utils/index.js +19 -17
  44. package/dist/migration/utils/index.js.map +1 -1
  45. package/dist/mutator.cjs +9 -11
  46. package/dist/mutator.cjs.map +1 -1
  47. package/dist/mutator.d.cts +5 -9
  48. package/dist/mutator.d.ts +5 -9
  49. package/dist/mutator.js +9 -11
  50. package/dist/mutator.js.map +1 -1
  51. package/dist/schema.cjs +50 -53
  52. package/dist/schema.cjs.map +1 -1
  53. package/dist/schema.d.cts +94 -12
  54. package/dist/schema.d.ts +94 -12
  55. package/dist/schema.js +50 -52
  56. package/dist/schema.js.map +1 -1
  57. package/dist/types.d.cts +2 -5
  58. package/dist/types.d.ts +2 -5
  59. package/dist/user-C39DQ40N.d.cts +53 -0
  60. package/dist/user-C39DQ40N.d.ts +53 -0
  61. package/package.json +2 -3
  62. package/dist/user-jS1aYoeD.d.cts +0 -123
  63. package/dist/user-jS1aYoeD.d.ts +0 -123
@@ -1,11 +1,44 @@
1
1
  #!/usr/bin/env node
2
2
  import chalk from 'chalk';
3
3
  import { Command } from 'commander';
4
- import * as path4 from 'path';
5
4
  import * as fs4 from 'fs';
5
+ import { readFileSync } from 'fs';
6
+ import * as path4 from 'path';
7
+ import { dirname, join } from 'path';
8
+ import { fileURLToPath } from 'url';
6
9
  import { z } from 'zod';
7
10
  import ora from 'ora';
8
11
 
12
+ ({
13
+ id: z.string().describe("unique id"),
14
+ collectionId: z.string().describe("collection id"),
15
+ collectionName: z.string().describe("collection name"),
16
+ expand: z.record(z.any()).describe("expandable fields")
17
+ });
18
+ ({
19
+ created: z.string().describe("creation timestamp"),
20
+ updated: z.string().describe("last update timestamp")
21
+ });
22
+ ({
23
+ thumbnailURL: z.string().optional(),
24
+ imageFiles: z.array(z.string())
25
+ });
26
+ ({
27
+ imageFiles: z.array(z.instanceof(File))
28
+ });
29
+ var RELATION_METADATA_KEY = "__pocketbase_relation__";
30
+ function extractRelationMetadata(description) {
31
+ if (!description) return null;
32
+ try {
33
+ const parsed = JSON.parse(description);
34
+ if (parsed[RELATION_METADATA_KEY]) {
35
+ return parsed[RELATION_METADATA_KEY];
36
+ }
37
+ } catch {
38
+ }
39
+ return null;
40
+ }
41
+
9
42
  // src/migration/errors.ts
10
43
  var MigrationError = class _MigrationError extends Error {
11
44
  constructor(message) {
@@ -169,7 +202,7 @@ Cause: ${this.originalError.message}`);
169
202
  }
170
203
  };
171
204
 
172
- // src/schema/permission-templates.ts
205
+ // src/utils/permission-templates.ts
173
206
  var PermissionTemplates = {
174
207
  /**
175
208
  * Public access - anyone can perform all operations
@@ -828,26 +861,28 @@ function getMaxSelect(fieldName, zodType) {
828
861
  return 1;
829
862
  }
830
863
  function getMinSelect(fieldName, zodType) {
831
- if (!isMultipleRelationField(fieldName, zodType)) {
832
- return void 0;
833
- }
834
- let unwrappedType = zodType;
835
- if (zodType instanceof z.ZodOptional) {
836
- unwrappedType = zodType._def.innerType;
837
- }
838
- if (unwrappedType instanceof z.ZodNullable) {
839
- unwrappedType = unwrappedType._def.innerType;
840
- }
841
- if (unwrappedType instanceof z.ZodDefault) {
842
- unwrappedType = unwrappedType._def.innerType;
864
+ if (isSingleRelationField(fieldName, zodType)) {
865
+ return 0;
843
866
  }
844
- if (unwrappedType instanceof z.ZodArray) {
845
- const arrayDef = unwrappedType._def;
846
- if (arrayDef.minLength) {
847
- return arrayDef.minLength.value;
867
+ if (isMultipleRelationField(fieldName, zodType)) {
868
+ let unwrappedType = zodType;
869
+ if (zodType instanceof z.ZodOptional) {
870
+ unwrappedType = zodType._def.innerType;
871
+ }
872
+ if (unwrappedType instanceof z.ZodNullable) {
873
+ unwrappedType = unwrappedType._def.innerType;
874
+ }
875
+ if (unwrappedType instanceof z.ZodDefault) {
876
+ unwrappedType = unwrappedType._def.innerType;
877
+ }
878
+ if (unwrappedType instanceof z.ZodArray) {
879
+ const arrayDef = unwrappedType._def;
880
+ if (arrayDef.minLength) {
881
+ return arrayDef.minLength.value;
882
+ }
848
883
  }
849
884
  }
850
- return void 0;
885
+ return 0;
851
886
  }
852
887
  function mapZodStringType(zodType) {
853
888
  const checks = zodType._def.checks || [];
@@ -1105,13 +1140,32 @@ async function importSchemaModule(filePath, config) {
1105
1140
  if (config?.pathTransformer) {
1106
1141
  importPath = config.pathTransformer(filePath);
1107
1142
  }
1108
- if (!importPath.endsWith(".js")) {
1109
- importPath = `${importPath}.js`;
1143
+ let resolvedPath = null;
1144
+ const jsPath = `${importPath}.js`;
1145
+ const tsPath = `${importPath}.ts`;
1146
+ if (fs4.existsSync(jsPath)) {
1147
+ resolvedPath = jsPath;
1148
+ } else if (fs4.existsSync(tsPath)) {
1149
+ resolvedPath = tsPath;
1150
+ } else {
1151
+ resolvedPath = jsPath;
1110
1152
  }
1111
- const fileUrl = new URL(`file://${path4.resolve(importPath)}`);
1153
+ const fileUrl = new URL(`file://${path4.resolve(resolvedPath)}`);
1112
1154
  const module = await import(fileUrl.href);
1113
1155
  return module;
1114
1156
  } catch (error) {
1157
+ const tsPath = `${filePath}.ts`;
1158
+ const isTypeScriptFile = fs4.existsSync(tsPath);
1159
+ if (isTypeScriptFile) {
1160
+ throw new SchemaParsingError(
1161
+ `Failed to import TypeScript schema file. Node.js cannot import TypeScript files directly.
1162
+ Please either:
1163
+ 1. Compile your schema files to JavaScript first, or
1164
+ 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")`,
1165
+ filePath,
1166
+ error
1167
+ );
1168
+ }
1115
1169
  throw new SchemaParsingError(
1116
1170
  `Failed to import schema module. Make sure the schema files are compiled to JavaScript.`,
1117
1171
  filePath,
@@ -1174,7 +1228,17 @@ function buildFieldDefinition(fieldName, zodType) {
1174
1228
  required,
1175
1229
  options
1176
1230
  };
1177
- if (isRelationField(fieldName, zodType)) {
1231
+ const relationMetadata = extractRelationMetadata(zodType.description);
1232
+ if (relationMetadata) {
1233
+ fieldDef.type = "relation";
1234
+ fieldDef.relation = {
1235
+ collection: relationMetadata.collection,
1236
+ maxSelect: relationMetadata.maxSelect,
1237
+ minSelect: relationMetadata.minSelect,
1238
+ cascadeDelete: relationMetadata.cascadeDelete
1239
+ };
1240
+ fieldDef.options = void 0;
1241
+ } else if (isRelationField(fieldName, zodType)) {
1178
1242
  fieldDef.type = "relation";
1179
1243
  const targetCollection = resolveTargetCollection(fieldName);
1180
1244
  const maxSelect = getMaxSelect(fieldName, zodType);
@@ -1186,6 +1250,13 @@ function buildFieldDefinition(fieldName, zodType) {
1186
1250
  cascadeDelete: false
1187
1251
  // Default to false, can be configured later
1188
1252
  };
1253
+ if (fieldDef.options) {
1254
+ const { min, max, pattern, ...relationSafeOptions } = fieldDef.options;
1255
+ console.log("min", min);
1256
+ console.log("max", max);
1257
+ console.log("pattern", pattern);
1258
+ fieldDef.options = Object.keys(relationSafeOptions).length > 0 ? relationSafeOptions : void 0;
1259
+ }
1189
1260
  }
1190
1261
  return fieldDef;
1191
1262
  }
@@ -1238,11 +1309,12 @@ function convertZodSchemaToCollectionSchema(collectionName, zodSchema) {
1238
1309
  fields,
1239
1310
  indexes,
1240
1311
  rules: {
1241
- listRule: null,
1242
- viewRule: null,
1243
- createRule: null,
1244
- updateRule: null,
1245
- deleteRule: null
1312
+ listRule: permissions?.listRule ?? null,
1313
+ viewRule: permissions?.viewRule ?? null,
1314
+ createRule: permissions?.createRule ?? null,
1315
+ updateRule: permissions?.updateRule ?? null,
1316
+ deleteRule: permissions?.deleteRule ?? null,
1317
+ manageRule: permissions?.manageRule ?? null
1246
1318
  },
1247
1319
  permissions
1248
1320
  };
@@ -1266,7 +1338,12 @@ async function buildSchemaDefinition(config) {
1266
1338
  if (normalizedConfig.pathTransformer) {
1267
1339
  importPath = normalizedConfig.pathTransformer(filePath);
1268
1340
  } else if (mergedConfig.useCompiledFiles) {
1269
- importPath = filePath.replace(/\/src\//, "/dist/");
1341
+ const distPath = filePath.replace(/\/src\//, "/dist/");
1342
+ if (fs4.existsSync(`${distPath}.js`) || fs4.existsSync(`${distPath}.mjs`)) {
1343
+ importPath = distPath;
1344
+ } else {
1345
+ importPath = filePath;
1346
+ }
1270
1347
  }
1271
1348
  const module = await importSchemaModule(importPath, normalizedConfig);
1272
1349
  const schemas = extractSchemaDefinitions(module, mergedConfig.schemaPatterns);
@@ -1664,10 +1741,8 @@ function compare(currentSchema, previousSnapshot, config) {
1664
1741
  var DEFAULT_TEMPLATE = `/// <reference path="{{TYPES_PATH}}" />
1665
1742
  migrate((app) => {
1666
1743
  {{UP_CODE}}
1667
- return true;
1668
1744
  }, (app) => {
1669
1745
  {{DOWN_CODE}}
1670
- return true;
1671
1746
  });
1672
1747
  `;
1673
1748
  var DEFAULT_CONFIG3 = {
@@ -1832,7 +1907,8 @@ function generateFieldDefinitionObject(field) {
1832
1907
  }
1833
1908
  }
1834
1909
  if (field.relation) {
1835
- const collectionIdPlaceholder = field.relation.collection === "Users" ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
1910
+ const isUsersCollection = field.relation.collection.toLowerCase() === "users";
1911
+ const collectionIdPlaceholder = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
1836
1912
  parts.push(` collectionId: ${collectionIdPlaceholder}`);
1837
1913
  if (field.relation.maxSelect !== void 0) {
1838
1914
  parts.push(` maxSelect: ${field.relation.maxSelect}`);
@@ -1916,7 +1992,7 @@ function generateIndexesArray(indexes) {
1916
1992
  ${indexStrings.join(",\n ")},
1917
1993
  ]`;
1918
1994
  }
1919
- function generateCollectionCreation(collection, varName = "collection") {
1995
+ function generateCollectionCreation(collection, varName = "collection", isLast = false) {
1920
1996
  const lines = [];
1921
1997
  lines.push(` const ${varName} = new Collection({`);
1922
1998
  lines.push(` name: "${collection.name}",`);
@@ -1932,7 +2008,7 @@ function generateCollectionCreation(collection, varName = "collection") {
1932
2008
  lines.push(` indexes: ${generateIndexesArray(collection.indexes)},`);
1933
2009
  lines.push(` });`);
1934
2010
  lines.push(``);
1935
- lines.push(` app.save(${varName});`);
2011
+ lines.push(isLast ? ` return app.save(${varName});` : ` app.save(${varName});`);
1936
2012
  return lines.join("\n");
1937
2013
  }
1938
2014
  function getFieldConstructorName(fieldType) {
@@ -1963,7 +2039,8 @@ function generateFieldConstructorOptions(field) {
1963
2039
  }
1964
2040
  }
1965
2041
  if (field.relation && field.type === "relation") {
1966
- const collectionIdPlaceholder = field.relation.collection === "Users" ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
2042
+ const isUsersCollection = field.relation.collection.toLowerCase() === "users";
2043
+ const collectionIdPlaceholder = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
1967
2044
  parts.push(` collectionId: ${collectionIdPlaceholder}`);
1968
2045
  if (field.relation.maxSelect !== void 0) {
1969
2046
  parts.push(` maxSelect: ${field.relation.maxSelect}`);
@@ -1977,7 +2054,7 @@ function generateFieldConstructorOptions(field) {
1977
2054
  }
1978
2055
  return parts.join(",\n");
1979
2056
  }
1980
- function generateFieldAddition(collectionName, field, varName) {
2057
+ function generateFieldAddition(collectionName, field, varName, isLast = false) {
1981
2058
  const lines = [];
1982
2059
  const constructorName = getFieldConstructorName(field.type);
1983
2060
  const collectionVar = varName || `collection_${collectionName}_${field.name}`;
@@ -1987,10 +2064,10 @@ function generateFieldAddition(collectionName, field, varName) {
1987
2064
  lines.push(generateFieldConstructorOptions(field));
1988
2065
  lines.push(` }));`);
1989
2066
  lines.push(``);
1990
- lines.push(` app.save(${collectionVar});`);
2067
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
1991
2068
  return lines.join("\n");
1992
2069
  }
1993
- function generateFieldModification(collectionName, modification, varName) {
2070
+ function generateFieldModification(collectionName, modification, varName, isLast = false) {
1994
2071
  const lines = [];
1995
2072
  const collectionVar = varName || `collection_${collectionName}_${modification.fieldName}`;
1996
2073
  const fieldVar = `${collectionVar}_field`;
@@ -2004,7 +2081,8 @@ function generateFieldModification(collectionName, modification, varName) {
2004
2081
  } else if (change.property.startsWith("relation.")) {
2005
2082
  const relationKey = change.property.replace("relation.", "");
2006
2083
  if (relationKey === "collection") {
2007
- const collectionIdValue = change.newValue === "Users" ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${change.newValue}").id`;
2084
+ const isUsersCollection = String(change.newValue).toLowerCase() === "users";
2085
+ const collectionIdValue = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${change.newValue}").id`;
2008
2086
  lines.push(` ${fieldVar}.collectionId = ${collectionIdValue};`);
2009
2087
  } else {
2010
2088
  lines.push(` ${fieldVar}.${relationKey} = ${formatValue(change.newValue)};`);
@@ -2014,10 +2092,10 @@ function generateFieldModification(collectionName, modification, varName) {
2014
2092
  }
2015
2093
  }
2016
2094
  lines.push(``);
2017
- lines.push(` app.save(${collectionVar});`);
2095
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2018
2096
  return lines.join("\n");
2019
2097
  }
2020
- function generateFieldDeletion(collectionName, fieldName, varName) {
2098
+ function generateFieldDeletion(collectionName, fieldName, varName, isLast = false) {
2021
2099
  const lines = [];
2022
2100
  const collectionVar = varName || `collection_${collectionName}_${fieldName}`;
2023
2101
  const fieldVar = `${collectionVar}_field`;
@@ -2026,18 +2104,18 @@ function generateFieldDeletion(collectionName, fieldName, varName) {
2026
2104
  lines.push(``);
2027
2105
  lines.push(` ${collectionVar}.fields.remove(${fieldVar}.id);`);
2028
2106
  lines.push(``);
2029
- lines.push(` app.save(${collectionVar});`);
2107
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2030
2108
  return lines.join("\n");
2031
2109
  }
2032
- function generateIndexAddition(collectionName, index, varName) {
2110
+ function generateIndexAddition(collectionName, index, varName, isLast = false) {
2033
2111
  const lines = [];
2034
2112
  const collectionVar = varName || `collection_${collectionName}_idx`;
2035
2113
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
2036
2114
  lines.push(` ${collectionVar}.indexes.push("${index}");`);
2037
- lines.push(` app.save(${collectionVar});`);
2115
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2038
2116
  return lines.join("\n");
2039
2117
  }
2040
- function generateIndexRemoval(collectionName, index, varName) {
2118
+ function generateIndexRemoval(collectionName, index, varName, isLast = false) {
2041
2119
  const lines = [];
2042
2120
  const collectionVar = varName || `collection_${collectionName}_idx`;
2043
2121
  const indexVar = `${collectionVar}_indexToRemove`;
@@ -2046,29 +2124,29 @@ function generateIndexRemoval(collectionName, index, varName) {
2046
2124
  lines.push(` if (${indexVar} !== -1) {`);
2047
2125
  lines.push(` ${collectionVar}.indexes.splice(${indexVar}, 1);`);
2048
2126
  lines.push(` }`);
2049
- lines.push(` app.save(${collectionVar});`);
2127
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2050
2128
  return lines.join("\n");
2051
2129
  }
2052
- function generateRuleUpdate(collectionName, ruleType, newValue, varName) {
2130
+ function generateRuleUpdate(collectionName, ruleType, newValue, varName, isLast = false) {
2053
2131
  const lines = [];
2054
2132
  const collectionVar = varName || `collection_${collectionName}_${ruleType}`;
2055
2133
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
2056
2134
  lines.push(` ${collectionVar}.${ruleType} = ${formatValue(newValue)};`);
2057
- lines.push(` app.save(${collectionVar});`);
2135
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2058
2136
  return lines.join("\n");
2059
2137
  }
2060
- function generatePermissionUpdate(collectionName, ruleType, newValue, varName) {
2138
+ function generatePermissionUpdate(collectionName, ruleType, newValue, varName, isLast = false) {
2061
2139
  const lines = [];
2062
2140
  const collectionVar = varName || `collection_${collectionName}_${ruleType}`;
2063
2141
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
2064
2142
  lines.push(` ${collectionVar}.${ruleType} = ${formatValue(newValue)};`);
2065
- lines.push(` app.save(${collectionVar});`);
2143
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2066
2144
  return lines.join("\n");
2067
2145
  }
2068
- function generateCollectionDeletion(collectionName, varName = "collection") {
2146
+ function generateCollectionDeletion(collectionName, varName = "collection", isLast = false) {
2069
2147
  const lines = [];
2070
2148
  lines.push(` const ${varName} = app.findCollectionByNameOrId("${collectionName}");`);
2071
- lines.push(` app.delete(${varName});`);
2149
+ lines.push(isLast ? ` return app.delete(${varName});` : ` app.delete(${varName});`);
2072
2150
  return lines.join("\n");
2073
2151
  }
2074
2152
  function generateUpMigration(diff) {
@@ -2160,7 +2238,24 @@ function generateUpMigration(diff) {
2160
2238
  lines.push(` // No changes detected`);
2161
2239
  lines.push(``);
2162
2240
  }
2163
- return lines.join("\n");
2241
+ let code = lines.join("\n");
2242
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
2243
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
2244
+ const saveMatches = [...code.matchAll(savePattern)];
2245
+ const deleteMatches = [...code.matchAll(deletePattern)];
2246
+ const allMatches = [
2247
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
2248
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
2249
+ ].sort((a, b) => b.index - a.index);
2250
+ if (allMatches.length > 0) {
2251
+ const lastMatch = allMatches[0];
2252
+ if (lastMatch.type === "save") {
2253
+ 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);
2254
+ } else {
2255
+ 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);
2256
+ }
2257
+ }
2258
+ return code;
2164
2259
  }
2165
2260
  function generateDownMigration(diff) {
2166
2261
  const lines = [];
@@ -2262,7 +2357,24 @@ function generateDownMigration(diff) {
2262
2357
  lines.push(` // No changes to revert`);
2263
2358
  lines.push(``);
2264
2359
  }
2265
- return lines.join("\n");
2360
+ let code = lines.join("\n");
2361
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
2362
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
2363
+ const saveMatches = [...code.matchAll(savePattern)];
2364
+ const deleteMatches = [...code.matchAll(deletePattern)];
2365
+ const allMatches = [
2366
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
2367
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
2368
+ ].sort((a, b) => b.index - a.index);
2369
+ if (allMatches.length > 0) {
2370
+ const lastMatch = allMatches[0];
2371
+ if (lastMatch.type === "save") {
2372
+ 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);
2373
+ } else {
2374
+ 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);
2375
+ }
2376
+ }
2377
+ return code;
2266
2378
  }
2267
2379
  function generate(diff, config) {
2268
2380
  const normalizedConfig = typeof config === "string" ? { migrationDir: config } : config;
@@ -2385,6 +2497,7 @@ function convertPocketBaseCollection(pbCollection) {
2385
2497
  if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
2386
2498
  if (Object.keys(rules).length > 0) {
2387
2499
  schema.rules = rules;
2500
+ schema.permissions = { ...rules };
2388
2501
  }
2389
2502
  return schema;
2390
2503
  }
@@ -2975,7 +3088,13 @@ async function executeGenerate(options) {
2975
3088
  const schemaDir = getSchemaDirectory(config);
2976
3089
  const migrationsDir = getMigrationsDirectory(config);
2977
3090
  logSection("\u{1F50D} Analyzing Schema");
2978
- const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(schemaDir));
3091
+ const analyzerConfig = {
3092
+ schemaDir,
3093
+ excludePatterns: config.schema.exclude,
3094
+ useCompiledFiles: false
3095
+ // Use source files since we're in development/testing
3096
+ };
3097
+ const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
2979
3098
  logSuccess(`Found ${currentSchema.collections.size} collection(s)`);
2980
3099
  logInfo("Loading previous snapshot...");
2981
3100
  const previousSnapshot = loadSnapshotIfExists({
@@ -3174,7 +3293,13 @@ async function executeStatus(options) {
3174
3293
  const schemaDir = getSchemaDirectory(config);
3175
3294
  const migrationsDir = getMigrationsDirectory(config);
3176
3295
  logSection("\u{1F50D} Checking Migration Status");
3177
- const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(schemaDir));
3296
+ const analyzerConfig = {
3297
+ schemaDir,
3298
+ excludePatterns: config.schema.exclude,
3299
+ useCompiledFiles: false
3300
+ // Use source files since we're in development/testing
3301
+ };
3302
+ const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
3178
3303
  logSuccess(`Found ${currentSchema.collections.size} collection(s) in schema`);
3179
3304
  logInfo("Loading previous snapshot...");
3180
3305
  const previousSnapshot = loadSnapshotIfExists({
@@ -3290,7 +3415,19 @@ Examples:
3290
3415
  }
3291
3416
 
3292
3417
  // src/cli/migrate.ts
3293
- var VERSION = "0.1.0";
3418
+ function getVersion() {
3419
+ try {
3420
+ const __filename2 = fileURLToPath(import.meta.url);
3421
+ const __dirname2 = dirname(__filename2);
3422
+ const packageJsonPath = join(__dirname2, "../../package.json");
3423
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
3424
+ return packageJson.version || "0.0.0";
3425
+ } catch {
3426
+ console.warn("Warning: Could not read version from package.json");
3427
+ return "0.0.0";
3428
+ }
3429
+ }
3430
+ var VERSION = getVersion();
3294
3431
  function displayBanner() {
3295
3432
  console.log();
3296
3433
  console.log(chalk.cyan.bold(" PocketBase Zod Migration Tool"));