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
@@ -32,6 +32,35 @@ var chalk__default = /*#__PURE__*/_interopDefault(chalk);
32
32
  var ora__default = /*#__PURE__*/_interopDefault(ora);
33
33
 
34
34
  // src/cli/commands/generate.ts
35
+ ({
36
+ id: zod.z.string().describe("unique id"),
37
+ collectionId: zod.z.string().describe("collection id"),
38
+ collectionName: zod.z.string().describe("collection name"),
39
+ expand: zod.z.record(zod.z.any()).describe("expandable fields")
40
+ });
41
+ ({
42
+ created: zod.z.string().describe("creation timestamp"),
43
+ updated: zod.z.string().describe("last update timestamp")
44
+ });
45
+ ({
46
+ thumbnailURL: zod.z.string().optional(),
47
+ imageFiles: zod.z.array(zod.z.string())
48
+ });
49
+ ({
50
+ imageFiles: zod.z.array(zod.z.instanceof(File))
51
+ });
52
+ var RELATION_METADATA_KEY = "__pocketbase_relation__";
53
+ function extractRelationMetadata(description) {
54
+ if (!description) return null;
55
+ try {
56
+ const parsed = JSON.parse(description);
57
+ if (parsed[RELATION_METADATA_KEY]) {
58
+ return parsed[RELATION_METADATA_KEY];
59
+ }
60
+ } catch {
61
+ }
62
+ return null;
63
+ }
35
64
 
36
65
  // src/migration/errors.ts
37
66
  var MigrationError = class _MigrationError extends Error {
@@ -196,7 +225,7 @@ Cause: ${this.originalError.message}`);
196
225
  }
197
226
  };
198
227
 
199
- // src/schema/permission-templates.ts
228
+ // src/utils/permission-templates.ts
200
229
  var PermissionTemplates = {
201
230
  /**
202
231
  * Public access - anyone can perform all operations
@@ -855,26 +884,28 @@ function getMaxSelect(fieldName, zodType) {
855
884
  return 1;
856
885
  }
857
886
  function getMinSelect(fieldName, zodType) {
858
- if (!isMultipleRelationField(fieldName, zodType)) {
859
- return void 0;
860
- }
861
- let unwrappedType = zodType;
862
- if (zodType instanceof zod.z.ZodOptional) {
863
- unwrappedType = zodType._def.innerType;
864
- }
865
- if (unwrappedType instanceof zod.z.ZodNullable) {
866
- unwrappedType = unwrappedType._def.innerType;
867
- }
868
- if (unwrappedType instanceof zod.z.ZodDefault) {
869
- unwrappedType = unwrappedType._def.innerType;
887
+ if (isSingleRelationField(fieldName, zodType)) {
888
+ return 0;
870
889
  }
871
- if (unwrappedType instanceof zod.z.ZodArray) {
872
- const arrayDef = unwrappedType._def;
873
- if (arrayDef.minLength) {
874
- return arrayDef.minLength.value;
890
+ if (isMultipleRelationField(fieldName, zodType)) {
891
+ let unwrappedType = zodType;
892
+ if (zodType instanceof zod.z.ZodOptional) {
893
+ unwrappedType = zodType._def.innerType;
894
+ }
895
+ if (unwrappedType instanceof zod.z.ZodNullable) {
896
+ unwrappedType = unwrappedType._def.innerType;
897
+ }
898
+ if (unwrappedType instanceof zod.z.ZodDefault) {
899
+ unwrappedType = unwrappedType._def.innerType;
900
+ }
901
+ if (unwrappedType instanceof zod.z.ZodArray) {
902
+ const arrayDef = unwrappedType._def;
903
+ if (arrayDef.minLength) {
904
+ return arrayDef.minLength.value;
905
+ }
875
906
  }
876
907
  }
877
- return void 0;
908
+ return 0;
878
909
  }
879
910
  function mapZodStringType(zodType) {
880
911
  const checks = zodType._def.checks || [];
@@ -1132,13 +1163,32 @@ async function importSchemaModule(filePath, config) {
1132
1163
  if (config?.pathTransformer) {
1133
1164
  importPath = config.pathTransformer(filePath);
1134
1165
  }
1135
- if (!importPath.endsWith(".js")) {
1136
- importPath = `${importPath}.js`;
1166
+ let resolvedPath = null;
1167
+ const jsPath = `${importPath}.js`;
1168
+ const tsPath = `${importPath}.ts`;
1169
+ if (fs4__namespace.existsSync(jsPath)) {
1170
+ resolvedPath = jsPath;
1171
+ } else if (fs4__namespace.existsSync(tsPath)) {
1172
+ resolvedPath = tsPath;
1173
+ } else {
1174
+ resolvedPath = jsPath;
1137
1175
  }
1138
- const fileUrl = new URL(`file://${path4__namespace.resolve(importPath)}`);
1176
+ const fileUrl = new URL(`file://${path4__namespace.resolve(resolvedPath)}`);
1139
1177
  const module = await import(fileUrl.href);
1140
1178
  return module;
1141
1179
  } catch (error) {
1180
+ const tsPath = `${filePath}.ts`;
1181
+ const isTypeScriptFile = fs4__namespace.existsSync(tsPath);
1182
+ if (isTypeScriptFile) {
1183
+ throw new SchemaParsingError(
1184
+ `Failed to import TypeScript schema file. Node.js cannot import TypeScript files directly.
1185
+ Please either:
1186
+ 1. Compile your schema files to JavaScript first, or
1187
+ 2. Use tsx to run the migration tool (e.g., "npx tsx package/dist/cli/migrate.js status" or "tsx package/dist/cli/migrate.js status")`,
1188
+ filePath,
1189
+ error
1190
+ );
1191
+ }
1142
1192
  throw new SchemaParsingError(
1143
1193
  `Failed to import schema module. Make sure the schema files are compiled to JavaScript.`,
1144
1194
  filePath,
@@ -1201,7 +1251,17 @@ function buildFieldDefinition(fieldName, zodType) {
1201
1251
  required,
1202
1252
  options
1203
1253
  };
1204
- if (isRelationField(fieldName, zodType)) {
1254
+ const relationMetadata = extractRelationMetadata(zodType.description);
1255
+ if (relationMetadata) {
1256
+ fieldDef.type = "relation";
1257
+ fieldDef.relation = {
1258
+ collection: relationMetadata.collection,
1259
+ maxSelect: relationMetadata.maxSelect,
1260
+ minSelect: relationMetadata.minSelect,
1261
+ cascadeDelete: relationMetadata.cascadeDelete
1262
+ };
1263
+ fieldDef.options = void 0;
1264
+ } else if (isRelationField(fieldName, zodType)) {
1205
1265
  fieldDef.type = "relation";
1206
1266
  const targetCollection = resolveTargetCollection(fieldName);
1207
1267
  const maxSelect = getMaxSelect(fieldName, zodType);
@@ -1213,6 +1273,13 @@ function buildFieldDefinition(fieldName, zodType) {
1213
1273
  cascadeDelete: false
1214
1274
  // Default to false, can be configured later
1215
1275
  };
1276
+ if (fieldDef.options) {
1277
+ const { min, max, pattern, ...relationSafeOptions } = fieldDef.options;
1278
+ console.log("min", min);
1279
+ console.log("max", max);
1280
+ console.log("pattern", pattern);
1281
+ fieldDef.options = Object.keys(relationSafeOptions).length > 0 ? relationSafeOptions : void 0;
1282
+ }
1216
1283
  }
1217
1284
  return fieldDef;
1218
1285
  }
@@ -1265,11 +1332,12 @@ function convertZodSchemaToCollectionSchema(collectionName, zodSchema) {
1265
1332
  fields,
1266
1333
  indexes,
1267
1334
  rules: {
1268
- listRule: null,
1269
- viewRule: null,
1270
- createRule: null,
1271
- updateRule: null,
1272
- deleteRule: null
1335
+ listRule: permissions?.listRule ?? null,
1336
+ viewRule: permissions?.viewRule ?? null,
1337
+ createRule: permissions?.createRule ?? null,
1338
+ updateRule: permissions?.updateRule ?? null,
1339
+ deleteRule: permissions?.deleteRule ?? null,
1340
+ manageRule: permissions?.manageRule ?? null
1273
1341
  },
1274
1342
  permissions
1275
1343
  };
@@ -1293,7 +1361,12 @@ async function buildSchemaDefinition(config) {
1293
1361
  if (normalizedConfig.pathTransformer) {
1294
1362
  importPath = normalizedConfig.pathTransformer(filePath);
1295
1363
  } else if (mergedConfig.useCompiledFiles) {
1296
- importPath = filePath.replace(/\/src\//, "/dist/");
1364
+ const distPath = filePath.replace(/\/src\//, "/dist/");
1365
+ if (fs4__namespace.existsSync(`${distPath}.js`) || fs4__namespace.existsSync(`${distPath}.mjs`)) {
1366
+ importPath = distPath;
1367
+ } else {
1368
+ importPath = filePath;
1369
+ }
1297
1370
  }
1298
1371
  const module = await importSchemaModule(importPath, normalizedConfig);
1299
1372
  const schemas = extractSchemaDefinitions(module, mergedConfig.schemaPatterns);
@@ -1691,10 +1764,8 @@ function compare(currentSchema, previousSnapshot, config) {
1691
1764
  var DEFAULT_TEMPLATE = `/// <reference path="{{TYPES_PATH}}" />
1692
1765
  migrate((app) => {
1693
1766
  {{UP_CODE}}
1694
- return true;
1695
1767
  }, (app) => {
1696
1768
  {{DOWN_CODE}}
1697
- return true;
1698
1769
  });
1699
1770
  `;
1700
1771
  var DEFAULT_CONFIG3 = {
@@ -1859,7 +1930,8 @@ function generateFieldDefinitionObject(field) {
1859
1930
  }
1860
1931
  }
1861
1932
  if (field.relation) {
1862
- const collectionIdPlaceholder = field.relation.collection === "Users" ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
1933
+ const isUsersCollection = field.relation.collection.toLowerCase() === "users";
1934
+ const collectionIdPlaceholder = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
1863
1935
  parts.push(` collectionId: ${collectionIdPlaceholder}`);
1864
1936
  if (field.relation.maxSelect !== void 0) {
1865
1937
  parts.push(` maxSelect: ${field.relation.maxSelect}`);
@@ -1943,7 +2015,7 @@ function generateIndexesArray(indexes) {
1943
2015
  ${indexStrings.join(",\n ")},
1944
2016
  ]`;
1945
2017
  }
1946
- function generateCollectionCreation(collection, varName = "collection") {
2018
+ function generateCollectionCreation(collection, varName = "collection", isLast = false) {
1947
2019
  const lines = [];
1948
2020
  lines.push(` const ${varName} = new Collection({`);
1949
2021
  lines.push(` name: "${collection.name}",`);
@@ -1959,7 +2031,7 @@ function generateCollectionCreation(collection, varName = "collection") {
1959
2031
  lines.push(` indexes: ${generateIndexesArray(collection.indexes)},`);
1960
2032
  lines.push(` });`);
1961
2033
  lines.push(``);
1962
- lines.push(` app.save(${varName});`);
2034
+ lines.push(isLast ? ` return app.save(${varName});` : ` app.save(${varName});`);
1963
2035
  return lines.join("\n");
1964
2036
  }
1965
2037
  function getFieldConstructorName(fieldType) {
@@ -1990,7 +2062,8 @@ function generateFieldConstructorOptions(field) {
1990
2062
  }
1991
2063
  }
1992
2064
  if (field.relation && field.type === "relation") {
1993
- const collectionIdPlaceholder = field.relation.collection === "Users" ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
2065
+ const isUsersCollection = field.relation.collection.toLowerCase() === "users";
2066
+ const collectionIdPlaceholder = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
1994
2067
  parts.push(` collectionId: ${collectionIdPlaceholder}`);
1995
2068
  if (field.relation.maxSelect !== void 0) {
1996
2069
  parts.push(` maxSelect: ${field.relation.maxSelect}`);
@@ -2004,7 +2077,7 @@ function generateFieldConstructorOptions(field) {
2004
2077
  }
2005
2078
  return parts.join(",\n");
2006
2079
  }
2007
- function generateFieldAddition(collectionName, field, varName) {
2080
+ function generateFieldAddition(collectionName, field, varName, isLast = false) {
2008
2081
  const lines = [];
2009
2082
  const constructorName = getFieldConstructorName(field.type);
2010
2083
  const collectionVar = varName || `collection_${collectionName}_${field.name}`;
@@ -2014,10 +2087,10 @@ function generateFieldAddition(collectionName, field, varName) {
2014
2087
  lines.push(generateFieldConstructorOptions(field));
2015
2088
  lines.push(` }));`);
2016
2089
  lines.push(``);
2017
- lines.push(` app.save(${collectionVar});`);
2090
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2018
2091
  return lines.join("\n");
2019
2092
  }
2020
- function generateFieldModification(collectionName, modification, varName) {
2093
+ function generateFieldModification(collectionName, modification, varName, isLast = false) {
2021
2094
  const lines = [];
2022
2095
  const collectionVar = varName || `collection_${collectionName}_${modification.fieldName}`;
2023
2096
  const fieldVar = `${collectionVar}_field`;
@@ -2031,7 +2104,8 @@ function generateFieldModification(collectionName, modification, varName) {
2031
2104
  } else if (change.property.startsWith("relation.")) {
2032
2105
  const relationKey = change.property.replace("relation.", "");
2033
2106
  if (relationKey === "collection") {
2034
- const collectionIdValue = change.newValue === "Users" ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${change.newValue}").id`;
2107
+ const isUsersCollection = String(change.newValue).toLowerCase() === "users";
2108
+ const collectionIdValue = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${change.newValue}").id`;
2035
2109
  lines.push(` ${fieldVar}.collectionId = ${collectionIdValue};`);
2036
2110
  } else {
2037
2111
  lines.push(` ${fieldVar}.${relationKey} = ${formatValue(change.newValue)};`);
@@ -2041,10 +2115,10 @@ function generateFieldModification(collectionName, modification, varName) {
2041
2115
  }
2042
2116
  }
2043
2117
  lines.push(``);
2044
- lines.push(` app.save(${collectionVar});`);
2118
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2045
2119
  return lines.join("\n");
2046
2120
  }
2047
- function generateFieldDeletion(collectionName, fieldName, varName) {
2121
+ function generateFieldDeletion(collectionName, fieldName, varName, isLast = false) {
2048
2122
  const lines = [];
2049
2123
  const collectionVar = varName || `collection_${collectionName}_${fieldName}`;
2050
2124
  const fieldVar = `${collectionVar}_field`;
@@ -2053,18 +2127,18 @@ function generateFieldDeletion(collectionName, fieldName, varName) {
2053
2127
  lines.push(``);
2054
2128
  lines.push(` ${collectionVar}.fields.remove(${fieldVar}.id);`);
2055
2129
  lines.push(``);
2056
- lines.push(` app.save(${collectionVar});`);
2130
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2057
2131
  return lines.join("\n");
2058
2132
  }
2059
- function generateIndexAddition(collectionName, index, varName) {
2133
+ function generateIndexAddition(collectionName, index, varName, isLast = false) {
2060
2134
  const lines = [];
2061
2135
  const collectionVar = varName || `collection_${collectionName}_idx`;
2062
2136
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
2063
2137
  lines.push(` ${collectionVar}.indexes.push("${index}");`);
2064
- lines.push(` app.save(${collectionVar});`);
2138
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2065
2139
  return lines.join("\n");
2066
2140
  }
2067
- function generateIndexRemoval(collectionName, index, varName) {
2141
+ function generateIndexRemoval(collectionName, index, varName, isLast = false) {
2068
2142
  const lines = [];
2069
2143
  const collectionVar = varName || `collection_${collectionName}_idx`;
2070
2144
  const indexVar = `${collectionVar}_indexToRemove`;
@@ -2073,29 +2147,29 @@ function generateIndexRemoval(collectionName, index, varName) {
2073
2147
  lines.push(` if (${indexVar} !== -1) {`);
2074
2148
  lines.push(` ${collectionVar}.indexes.splice(${indexVar}, 1);`);
2075
2149
  lines.push(` }`);
2076
- lines.push(` app.save(${collectionVar});`);
2150
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2077
2151
  return lines.join("\n");
2078
2152
  }
2079
- function generateRuleUpdate(collectionName, ruleType, newValue, varName) {
2153
+ function generateRuleUpdate(collectionName, ruleType, newValue, varName, isLast = false) {
2080
2154
  const lines = [];
2081
2155
  const collectionVar = varName || `collection_${collectionName}_${ruleType}`;
2082
2156
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
2083
2157
  lines.push(` ${collectionVar}.${ruleType} = ${formatValue(newValue)};`);
2084
- lines.push(` app.save(${collectionVar});`);
2158
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2085
2159
  return lines.join("\n");
2086
2160
  }
2087
- function generatePermissionUpdate(collectionName, ruleType, newValue, varName) {
2161
+ function generatePermissionUpdate(collectionName, ruleType, newValue, varName, isLast = false) {
2088
2162
  const lines = [];
2089
2163
  const collectionVar = varName || `collection_${collectionName}_${ruleType}`;
2090
2164
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
2091
2165
  lines.push(` ${collectionVar}.${ruleType} = ${formatValue(newValue)};`);
2092
- lines.push(` app.save(${collectionVar});`);
2166
+ lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2093
2167
  return lines.join("\n");
2094
2168
  }
2095
- function generateCollectionDeletion(collectionName, varName = "collection") {
2169
+ function generateCollectionDeletion(collectionName, varName = "collection", isLast = false) {
2096
2170
  const lines = [];
2097
2171
  lines.push(` const ${varName} = app.findCollectionByNameOrId("${collectionName}");`);
2098
- lines.push(` app.delete(${varName});`);
2172
+ lines.push(isLast ? ` return app.delete(${varName});` : ` app.delete(${varName});`);
2099
2173
  return lines.join("\n");
2100
2174
  }
2101
2175
  function generateUpMigration(diff) {
@@ -2187,7 +2261,24 @@ function generateUpMigration(diff) {
2187
2261
  lines.push(` // No changes detected`);
2188
2262
  lines.push(``);
2189
2263
  }
2190
- return lines.join("\n");
2264
+ let code = lines.join("\n");
2265
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
2266
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
2267
+ const saveMatches = [...code.matchAll(savePattern)];
2268
+ const deleteMatches = [...code.matchAll(deletePattern)];
2269
+ const allMatches = [
2270
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
2271
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
2272
+ ].sort((a, b) => b.index - a.index);
2273
+ if (allMatches.length > 0) {
2274
+ const lastMatch = allMatches[0];
2275
+ if (lastMatch.type === "save") {
2276
+ 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);
2277
+ } else {
2278
+ 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);
2279
+ }
2280
+ }
2281
+ return code;
2191
2282
  }
2192
2283
  function generateDownMigration(diff) {
2193
2284
  const lines = [];
@@ -2289,7 +2380,24 @@ function generateDownMigration(diff) {
2289
2380
  lines.push(` // No changes to revert`);
2290
2381
  lines.push(``);
2291
2382
  }
2292
- return lines.join("\n");
2383
+ let code = lines.join("\n");
2384
+ const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
2385
+ const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
2386
+ const saveMatches = [...code.matchAll(savePattern)];
2387
+ const deleteMatches = [...code.matchAll(deletePattern)];
2388
+ const allMatches = [
2389
+ ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
2390
+ ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
2391
+ ].sort((a, b) => b.index - a.index);
2392
+ if (allMatches.length > 0) {
2393
+ const lastMatch = allMatches[0];
2394
+ if (lastMatch.type === "save") {
2395
+ 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);
2396
+ } else {
2397
+ 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);
2398
+ }
2399
+ }
2400
+ return code;
2293
2401
  }
2294
2402
  function generate(diff, config) {
2295
2403
  const normalizedConfig = typeof config === "string" ? { migrationDir: config } : config;
@@ -2412,6 +2520,7 @@ function convertPocketBaseCollection(pbCollection) {
2412
2520
  if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
2413
2521
  if (Object.keys(rules).length > 0) {
2414
2522
  schema.rules = rules;
2523
+ schema.permissions = { ...rules };
2415
2524
  }
2416
2525
  return schema;
2417
2526
  }
@@ -3062,7 +3171,13 @@ async function executeGenerate(options) {
3062
3171
  const schemaDir = getSchemaDirectory(config);
3063
3172
  const migrationsDir = getMigrationsDirectory(config);
3064
3173
  logSection("\u{1F50D} Analyzing Schema");
3065
- const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(schemaDir));
3174
+ const analyzerConfig = {
3175
+ schemaDir,
3176
+ excludePatterns: config.schema.exclude,
3177
+ useCompiledFiles: false
3178
+ // Use source files since we're in development/testing
3179
+ };
3180
+ const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
3066
3181
  logSuccess(`Found ${currentSchema.collections.size} collection(s)`);
3067
3182
  logInfo("Loading previous snapshot...");
3068
3183
  const previousSnapshot = loadSnapshotIfExists({
@@ -3249,7 +3364,13 @@ async function executeStatus(options) {
3249
3364
  const schemaDir = getSchemaDirectory(config);
3250
3365
  const migrationsDir = getMigrationsDirectory(config);
3251
3366
  logSection("\u{1F50D} Checking Migration Status");
3252
- const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(schemaDir));
3367
+ const analyzerConfig = {
3368
+ schemaDir,
3369
+ excludePatterns: config.schema.exclude,
3370
+ useCompiledFiles: false
3371
+ // Use source files since we're in development/testing
3372
+ };
3373
+ const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
3253
3374
  logSuccess(`Found ${currentSchema.collections.size} collection(s) in schema`);
3254
3375
  logInfo("Loading previous snapshot...");
3255
3376
  const previousSnapshot = loadSnapshotIfExists({