pocketbase-zod-schema 0.2.5 → 0.3.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 (66) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/cli/index.cjs +374 -296
  3. package/dist/cli/index.cjs.map +1 -1
  4. package/dist/cli/index.d.cts +2 -2
  5. package/dist/cli/index.d.ts +2 -2
  6. package/dist/cli/index.js +374 -296
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/cli/migrate.cjs +374 -296
  9. package/dist/cli/migrate.cjs.map +1 -1
  10. package/dist/cli/migrate.js +374 -296
  11. package/dist/cli/migrate.js.map +1 -1
  12. package/dist/cli/utils/index.d.cts +2 -2
  13. package/dist/cli/utils/index.d.ts +2 -2
  14. package/dist/{fields-YjcpBXVp.d.cts → fields-UcOPu1OQ.d.cts} +16 -0
  15. package/dist/{fields-YjcpBXVp.d.ts → fields-UcOPu1OQ.d.ts} +16 -0
  16. package/dist/index.cjs +413 -114
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +4 -4
  19. package/dist/index.d.ts +4 -4
  20. package/dist/index.js +414 -103
  21. package/dist/index.js.map +1 -1
  22. package/dist/migration/analyzer.cjs +12 -2
  23. package/dist/migration/analyzer.cjs.map +1 -1
  24. package/dist/migration/analyzer.d.cts +2 -2
  25. package/dist/migration/analyzer.d.ts +2 -2
  26. package/dist/migration/analyzer.js +12 -2
  27. package/dist/migration/analyzer.js.map +1 -1
  28. package/dist/migration/diff.cjs +76 -1
  29. package/dist/migration/diff.cjs.map +1 -1
  30. package/dist/migration/diff.d.cts +2 -2
  31. package/dist/migration/diff.d.ts +2 -2
  32. package/dist/migration/diff.js +76 -1
  33. package/dist/migration/diff.js.map +1 -1
  34. package/dist/migration/generator.cjs +323 -46
  35. package/dist/migration/generator.cjs.map +1 -1
  36. package/dist/migration/generator.d.cts +59 -12
  37. package/dist/migration/generator.d.ts +59 -12
  38. package/dist/migration/generator.js +319 -47
  39. package/dist/migration/generator.js.map +1 -1
  40. package/dist/migration/index.cjs +399 -49
  41. package/dist/migration/index.cjs.map +1 -1
  42. package/dist/migration/index.d.cts +3 -3
  43. package/dist/migration/index.d.ts +3 -3
  44. package/dist/migration/index.js +399 -49
  45. package/dist/migration/index.js.map +1 -1
  46. package/dist/migration/snapshot.cjs.map +1 -1
  47. package/dist/migration/snapshot.d.cts +2 -2
  48. package/dist/migration/snapshot.d.ts +2 -2
  49. package/dist/migration/snapshot.js.map +1 -1
  50. package/dist/migration/utils/index.cjs +64 -0
  51. package/dist/migration/utils/index.cjs.map +1 -1
  52. package/dist/migration/utils/index.d.cts +39 -202
  53. package/dist/migration/utils/index.d.ts +39 -202
  54. package/dist/migration/utils/index.js +63 -1
  55. package/dist/migration/utils/index.js.map +1 -1
  56. package/dist/schema.cjs +0 -61
  57. package/dist/schema.cjs.map +1 -1
  58. package/dist/schema.d.cts +2 -86
  59. package/dist/schema.d.ts +2 -86
  60. package/dist/schema.js +1 -50
  61. package/dist/schema.js.map +1 -1
  62. package/dist/type-mapper-DrQmtznD.d.cts +208 -0
  63. package/dist/type-mapper-n231Fspm.d.ts +208 -0
  64. package/dist/{types-LFBGHl9Y.d.ts → types-Ds3NQvny.d.ts} +33 -2
  65. package/dist/{types-mhQXWNi3.d.cts → types-YoBjsa-A.d.cts} +33 -2
  66. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import * as fs3 from 'fs';
3
3
  import * as path5 from 'path';
4
+ import { randomBytes } from 'crypto';
4
5
  import chalk from 'chalk';
5
6
  import ora from 'ora';
6
7
 
@@ -366,46 +367,6 @@ var inputImageFileSchema = {
366
367
  var omitImageFilesSchema = {
367
368
  imageFiles: true
368
369
  };
369
- function textField(options) {
370
- let schema = z.string();
371
- if (options?.min !== void 0) schema = schema.min(options.min);
372
- if (options?.max !== void 0) schema = schema.max(options.max);
373
- if (options?.pattern !== void 0) schema = schema.regex(options.pattern);
374
- return schema;
375
- }
376
- function emailField() {
377
- return z.string().email();
378
- }
379
- function urlField() {
380
- return z.string().url();
381
- }
382
- function numberField(options) {
383
- let schema = z.number();
384
- if (options?.min !== void 0) schema = schema.min(options.min);
385
- if (options?.max !== void 0) schema = schema.max(options.max);
386
- return schema;
387
- }
388
- function boolField() {
389
- return z.boolean();
390
- }
391
- function dateField() {
392
- return z.date();
393
- }
394
- function selectField(values) {
395
- return z.enum(values);
396
- }
397
- function jsonField(schema) {
398
- return schema ?? z.record(z.any());
399
- }
400
- function fileField() {
401
- return z.instanceof(File);
402
- }
403
- function filesField(options) {
404
- let schema = z.array(z.instanceof(File));
405
- if (options?.min !== void 0) schema = schema.min(options.min);
406
- if (options?.max !== void 0) schema = schema.max(options.max);
407
- return schema;
408
- }
409
370
  var RELATION_METADATA_KEY = "__pocketbase_relation__";
410
371
  function RelationField(config) {
411
372
  const metadata = {
@@ -449,15 +410,6 @@ function extractRelationMetadata(description) {
449
410
  }
450
411
  return null;
451
412
  }
452
- function editorField() {
453
- return z.string();
454
- }
455
- function geoPointField() {
456
- return z.object({
457
- lon: z.number(),
458
- lat: z.number()
459
- });
460
- }
461
413
  function withPermissions(schema, config) {
462
414
  const metadata = {
463
415
  permissions: config
@@ -2304,12 +2256,22 @@ function isAuthCollection(fields) {
2304
2256
  function buildFieldDefinition(fieldName, zodType) {
2305
2257
  const fieldMetadata = extractFieldMetadata(zodType.description);
2306
2258
  if (fieldMetadata) {
2307
- const required2 = isFieldRequired(zodType);
2259
+ let required2;
2260
+ if (fieldMetadata.type === "number") {
2261
+ if (fieldMetadata.options?.required !== void 0) {
2262
+ required2 = fieldMetadata.options.required;
2263
+ } else {
2264
+ required2 = false;
2265
+ }
2266
+ } else {
2267
+ required2 = isFieldRequired(zodType);
2268
+ }
2269
+ const { required: _required, ...options2 } = fieldMetadata.options || {};
2308
2270
  const fieldDef2 = {
2309
2271
  name: fieldName,
2310
2272
  type: fieldMetadata.type,
2311
2273
  required: required2,
2312
- options: fieldMetadata.options
2274
+ options: Object.keys(options2).length > 0 ? options2 : void 0
2313
2275
  };
2314
2276
  if (fieldMetadata.type === "relation") {
2315
2277
  const relationMetadata2 = extractRelationMetadata(zodType.description);
@@ -3305,6 +3267,65 @@ var SnapshotManager = class {
3305
3267
  return validateSnapshot(snapshot);
3306
3268
  }
3307
3269
  };
3270
+ function generateCollectionId() {
3271
+ const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
3272
+ const idLength = 15;
3273
+ const bytes = randomBytes(idLength);
3274
+ let id = "pb_";
3275
+ for (let i = 0; i < idLength; i++) {
3276
+ const index = bytes[i] % chars.length;
3277
+ id += chars[index];
3278
+ }
3279
+ return id;
3280
+ }
3281
+ var CollectionIdRegistry = class {
3282
+ ids;
3283
+ constructor() {
3284
+ this.ids = /* @__PURE__ */ new Set();
3285
+ }
3286
+ /**
3287
+ * Generates a unique collection ID for a given collection name
3288
+ * Special case: Returns constant "_pb_users_auth_" for users collection
3289
+ * Retries up to 10 times if collision occurs (extremely rare)
3290
+ *
3291
+ * @param collectionName - The name of the collection
3292
+ * @returns A unique collection ID
3293
+ * @throws Error if unable to generate unique ID after max attempts
3294
+ */
3295
+ generate(collectionName) {
3296
+ if (collectionName && collectionName.toLowerCase() === "users") {
3297
+ const usersId = "_pb_users_auth_";
3298
+ this.register(usersId);
3299
+ return usersId;
3300
+ }
3301
+ const maxAttempts = 10;
3302
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
3303
+ const id = generateCollectionId();
3304
+ if (!this.has(id)) {
3305
+ this.register(id);
3306
+ return id;
3307
+ }
3308
+ }
3309
+ throw new Error("Failed to generate unique collection ID after maximum attempts");
3310
+ }
3311
+ /**
3312
+ * Checks if an ID has already been registered
3313
+ *
3314
+ * @param id - The collection ID to check
3315
+ * @returns True if the ID exists in the registry
3316
+ */
3317
+ has(id) {
3318
+ return this.ids.has(id);
3319
+ }
3320
+ /**
3321
+ * Registers a collection ID in the registry
3322
+ *
3323
+ * @param id - The collection ID to register
3324
+ */
3325
+ register(id) {
3326
+ this.ids.add(id);
3327
+ }
3328
+ };
3308
3329
 
3309
3330
  // src/migration/diff.ts
3310
3331
  var DEFAULT_CONFIG3 = {
@@ -3647,6 +3668,18 @@ function aggregateChanges(currentSchema, previousSnapshot, config) {
3647
3668
  const filteredCollectionsToDelete = collectionsToDelete.filter(
3648
3669
  (collection) => !isSystemCollection(collection.name, config)
3649
3670
  );
3671
+ const registry = new CollectionIdRegistry();
3672
+ const collectionsWithIds = filteredCollectionsToCreate.map((collection) => {
3673
+ if (collection.id) {
3674
+ registry.register(collection.id);
3675
+ return collection;
3676
+ }
3677
+ const id = registry.generate(collection.name);
3678
+ return {
3679
+ ...collection,
3680
+ id
3681
+ };
3682
+ });
3650
3683
  const collectionsToModify = [];
3651
3684
  const matchedCollections = matchCollectionsByName(currentSchema, previousSnapshot);
3652
3685
  for (const [currentCollection, previousCollection] of matchedCollections) {
@@ -3656,7 +3689,7 @@ function aggregateChanges(currentSchema, previousSnapshot, config) {
3656
3689
  }
3657
3690
  }
3658
3691
  return {
3659
- collectionsToCreate: filteredCollectionsToCreate,
3692
+ collectionsToCreate: collectionsWithIds,
3660
3693
  collectionsToDelete: filteredCollectionsToDelete,
3661
3694
  collectionsToModify
3662
3695
  };
@@ -3892,6 +3925,49 @@ function generateTimestamp(config) {
3892
3925
  }
3893
3926
  return Math.floor(Date.now() / 1e3).toString();
3894
3927
  }
3928
+ function splitDiffByCollection(diff, baseTimestamp) {
3929
+ const operations = [];
3930
+ let currentTimestamp = parseInt(baseTimestamp, 10);
3931
+ for (const collection of diff.collectionsToCreate) {
3932
+ operations.push({
3933
+ type: "create",
3934
+ collection,
3935
+ timestamp: currentTimestamp.toString()
3936
+ });
3937
+ currentTimestamp += 1;
3938
+ }
3939
+ for (const modification of diff.collectionsToModify) {
3940
+ operations.push({
3941
+ type: "modify",
3942
+ collection: modification.collection,
3943
+ modifications: modification,
3944
+ timestamp: currentTimestamp.toString()
3945
+ });
3946
+ currentTimestamp += 1;
3947
+ }
3948
+ for (const collection of diff.collectionsToDelete) {
3949
+ operations.push({
3950
+ type: "delete",
3951
+ collection: collection.name || collection,
3952
+ // Handle both object and string
3953
+ timestamp: currentTimestamp.toString()
3954
+ });
3955
+ currentTimestamp += 1;
3956
+ }
3957
+ return operations;
3958
+ }
3959
+ function generateCollectionMigrationFilename(operation) {
3960
+ const timestamp = operation.timestamp;
3961
+ const operationType = operation.type === "modify" ? "updated" : operation.type === "create" ? "created" : "deleted";
3962
+ let collectionName;
3963
+ if (typeof operation.collection === "string") {
3964
+ collectionName = operation.collection;
3965
+ } else {
3966
+ collectionName = operation.collection.name;
3967
+ }
3968
+ const sanitizedName = collectionName.replace(/[^a-zA-Z0-9_]/g, "_").toLowerCase();
3969
+ return `${timestamp}_${operationType}_${sanitizedName}.js`;
3970
+ }
3895
3971
  function generateMigrationDescription(diff) {
3896
3972
  const parts = [];
3897
3973
  if (diff.collectionsToCreate.length > 0) {
@@ -3999,14 +4075,13 @@ function formatValue(value) {
3999
4075
  return "null";
4000
4076
  }
4001
4077
  if (typeof value === "string") {
4002
- return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n")}"`;
4078
+ return JSON.stringify(value);
4003
4079
  }
4004
4080
  if (typeof value === "number" || typeof value === "boolean") {
4005
4081
  return String(value);
4006
4082
  }
4007
4083
  if (Array.isArray(value)) {
4008
- const items = value.map((v) => formatValue(v)).join(", ");
4009
- return `[${items}]`;
4084
+ return JSON.stringify(value).replace(/","/g, '", "');
4010
4085
  }
4011
4086
  if (typeof value === "object") {
4012
4087
  const entries = Object.entries(value).map(([k, v]) => `${k}: ${formatValue(v)}`).join(", ");
@@ -4014,7 +4089,7 @@ function formatValue(value) {
4014
4089
  }
4015
4090
  return String(value);
4016
4091
  }
4017
- function generateFieldDefinitionObject(field) {
4092
+ function generateFieldDefinitionObject(field, collectionIdMap) {
4018
4093
  const parts = [];
4019
4094
  parts.push(` name: "${field.name}"`);
4020
4095
  parts.push(` type: "${field.type}"`);
@@ -4022,34 +4097,47 @@ function generateFieldDefinitionObject(field) {
4022
4097
  if (field.unique !== void 0) {
4023
4098
  parts.push(` unique: ${field.unique}`);
4024
4099
  }
4100
+ if (field.type === "select") {
4101
+ const maxSelect = field.options?.maxSelect ?? 1;
4102
+ parts.push(` maxSelect: ${maxSelect}`);
4103
+ const values = field.options?.values ?? [];
4104
+ parts.push(` values: ${formatValue(values)}`);
4105
+ }
4025
4106
  if (field.options && Object.keys(field.options).length > 0) {
4026
4107
  for (const [key, value] of Object.entries(field.options)) {
4108
+ if (field.type === "select" && (key === "maxSelect" || key === "values")) {
4109
+ continue;
4110
+ }
4027
4111
  parts.push(` ${key}: ${formatValue(value)}`);
4028
4112
  }
4029
4113
  }
4030
4114
  if (field.relation) {
4031
4115
  const isUsersCollection = field.relation.collection.toLowerCase() === "users";
4032
- const collectionIdPlaceholder = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
4033
- parts.push(` collectionId: ${collectionIdPlaceholder}`);
4034
- if (field.relation.maxSelect !== void 0) {
4035
- parts.push(` maxSelect: ${field.relation.maxSelect}`);
4036
- }
4037
- if (field.relation.minSelect !== void 0) {
4038
- parts.push(` minSelect: ${field.relation.minSelect}`);
4039
- }
4040
- if (field.relation.cascadeDelete !== void 0) {
4041
- parts.push(` cascadeDelete: ${field.relation.cascadeDelete}`);
4116
+ let collectionIdValue;
4117
+ if (isUsersCollection) {
4118
+ collectionIdValue = '"_pb_users_auth_"';
4119
+ } else if (collectionIdMap && collectionIdMap.has(field.relation.collection)) {
4120
+ collectionIdValue = `"${collectionIdMap.get(field.relation.collection)}"`;
4121
+ } else {
4122
+ collectionIdValue = `app.findCollectionByNameOrId("${field.relation.collection}").id`;
4042
4123
  }
4124
+ parts.push(` collectionId: ${collectionIdValue}`);
4125
+ const maxSelect = field.relation.maxSelect ?? 1;
4126
+ parts.push(` maxSelect: ${maxSelect}`);
4127
+ const minSelect = field.relation.minSelect ?? null;
4128
+ parts.push(` minSelect: ${minSelect}`);
4129
+ const cascadeDelete = field.relation.cascadeDelete ?? false;
4130
+ parts.push(` cascadeDelete: ${cascadeDelete}`);
4043
4131
  }
4044
4132
  return ` {
4045
4133
  ${parts.join(",\n")},
4046
4134
  }`;
4047
4135
  }
4048
- function generateFieldsArray(fields) {
4136
+ function generateFieldsArray(fields, collectionIdMap) {
4049
4137
  if (fields.length === 0) {
4050
4138
  return "[]";
4051
4139
  }
4052
- const fieldObjects = fields.map((field) => generateFieldDefinitionObject(field));
4140
+ const fieldObjects = fields.map((field) => generateFieldDefinitionObject(field, collectionIdMap));
4053
4141
  return `[
4054
4142
  ${fieldObjects.join(",\n")},
4055
4143
  ]`;
@@ -4108,7 +4196,7 @@ function generateIndexesArray(indexes) {
4108
4196
  if (!indexes || indexes.length === 0) {
4109
4197
  return "[]";
4110
4198
  }
4111
- const indexStrings = indexes.map((idx) => `"${idx}"`);
4199
+ const indexStrings = indexes.map((idx) => JSON.stringify(idx));
4112
4200
  return `[
4113
4201
  ${indexStrings.join(",\n ")},
4114
4202
  ]`;
@@ -4162,7 +4250,7 @@ function getSystemFields() {
4162
4250
  }
4163
4251
  ];
4164
4252
  }
4165
- function generateCollectionCreation(collection, varName = "collection", isLast = false) {
4253
+ function generateCollectionCreation(collection, varName = "collection", isLast = false, collectionIdMap) {
4166
4254
  const lines = [];
4167
4255
  lines.push(` const ${varName} = new Collection({`);
4168
4256
  lines.push(` name: "${collection.name}",`);
@@ -4176,7 +4264,7 @@ function generateCollectionCreation(collection, varName = "collection", isLast =
4176
4264
  }
4177
4265
  const systemFields = getSystemFields();
4178
4266
  const allFields = [...systemFields, ...collection.fields];
4179
- lines.push(` fields: ${generateFieldsArray(allFields)},`);
4267
+ lines.push(` fields: ${generateFieldsArray(allFields, collectionIdMap)},`);
4180
4268
  lines.push(` indexes: ${generateIndexesArray(collection.indexes)},`);
4181
4269
  lines.push(` });`);
4182
4270
  lines.push(``);
@@ -4198,42 +4286,59 @@ function getFieldConstructorName(fieldType) {
4198
4286
  };
4199
4287
  return constructorMap[fieldType] || "TextField";
4200
4288
  }
4201
- function generateFieldConstructorOptions(field) {
4289
+ function generateFieldConstructorOptions(field, collectionIdMap) {
4202
4290
  const parts = [];
4203
4291
  parts.push(` name: "${field.name}"`);
4204
4292
  parts.push(` required: ${field.required}`);
4205
4293
  if (field.unique !== void 0) {
4206
4294
  parts.push(` unique: ${field.unique}`);
4207
4295
  }
4296
+ if (field.type === "select") {
4297
+ const maxSelect = field.options?.maxSelect ?? 1;
4298
+ parts.push(` maxSelect: ${maxSelect}`);
4299
+ const values = field.options?.values ?? [];
4300
+ parts.push(` values: ${formatValue(values)}`);
4301
+ }
4208
4302
  if (field.options && Object.keys(field.options).length > 0) {
4209
4303
  for (const [key, value] of Object.entries(field.options)) {
4210
- parts.push(` ${key}: ${formatValue(value)}`);
4304
+ if (field.type === "select" && (key === "maxSelect" || key === "values")) {
4305
+ continue;
4306
+ }
4307
+ if (field.type === "number" && key === "noDecimal") {
4308
+ parts.push(` onlyInt: ${formatValue(value)}`);
4309
+ } else {
4310
+ parts.push(` ${key}: ${formatValue(value)}`);
4311
+ }
4211
4312
  }
4212
4313
  }
4213
4314
  if (field.relation && field.type === "relation") {
4214
4315
  const isUsersCollection = field.relation.collection.toLowerCase() === "users";
4215
- const collectionIdPlaceholder = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
4216
- parts.push(` collectionId: ${collectionIdPlaceholder}`);
4217
- if (field.relation.maxSelect !== void 0) {
4218
- parts.push(` maxSelect: ${field.relation.maxSelect}`);
4219
- }
4220
- if (field.relation.minSelect !== void 0) {
4221
- parts.push(` minSelect: ${field.relation.minSelect}`);
4222
- }
4223
- if (field.relation.cascadeDelete !== void 0) {
4224
- parts.push(` cascadeDelete: ${field.relation.cascadeDelete}`);
4316
+ let collectionIdValue;
4317
+ if (isUsersCollection) {
4318
+ collectionIdValue = '"_pb_users_auth_"';
4319
+ } else if (collectionIdMap && collectionIdMap.has(field.relation.collection)) {
4320
+ collectionIdValue = `"${collectionIdMap.get(field.relation.collection)}"`;
4321
+ } else {
4322
+ collectionIdValue = `app.findCollectionByNameOrId("${field.relation.collection}").id`;
4225
4323
  }
4324
+ parts.push(` collectionId: ${collectionIdValue}`);
4325
+ const maxSelect = field.relation.maxSelect ?? 1;
4326
+ parts.push(` maxSelect: ${maxSelect}`);
4327
+ const minSelect = field.relation.minSelect ?? null;
4328
+ parts.push(` minSelect: ${minSelect}`);
4329
+ const cascadeDelete = field.relation.cascadeDelete ?? false;
4330
+ parts.push(` cascadeDelete: ${cascadeDelete}`);
4226
4331
  }
4227
4332
  return parts.join(",\n");
4228
4333
  }
4229
- function generateFieldAddition(collectionName, field, varName, isLast = false) {
4334
+ function generateFieldAddition(collectionName, field, varName, isLast = false, collectionIdMap) {
4230
4335
  const lines = [];
4231
4336
  const constructorName = getFieldConstructorName(field.type);
4232
4337
  const collectionVar = varName || `collection_${collectionName}_${field.name}`;
4233
4338
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
4234
4339
  lines.push(``);
4235
4340
  lines.push(` ${collectionVar}.fields.add(new ${constructorName}({`);
4236
- lines.push(generateFieldConstructorOptions(field));
4341
+ lines.push(generateFieldConstructorOptions(field, collectionIdMap));
4237
4342
  lines.push(` }));`);
4238
4343
  lines.push(``);
4239
4344
  lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
@@ -4283,7 +4388,7 @@ function generateIndexAddition(collectionName, index, varName, isLast = false) {
4283
4388
  const lines = [];
4284
4389
  const collectionVar = varName || `collection_${collectionName}_idx`;
4285
4390
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
4286
- lines.push(` ${collectionVar}.indexes.push("${index}");`);
4391
+ lines.push(` ${collectionVar}.indexes.push(${JSON.stringify(index)});`);
4287
4392
  lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
4288
4393
  return lines.join("\n");
4289
4394
  }
@@ -4292,7 +4397,7 @@ function generateIndexRemoval(collectionName, index, varName, isLast = false) {
4292
4397
  const collectionVar = varName || `collection_${collectionName}_idx`;
4293
4398
  const indexVar = `${collectionVar}_indexToRemove`;
4294
4399
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
4295
- lines.push(` const ${indexVar} = ${collectionVar}.indexes.findIndex(idx => idx === "${index}");`);
4400
+ lines.push(` const ${indexVar} = ${collectionVar}.indexes.findIndex(idx => idx === ${JSON.stringify(index)});`);
4296
4401
  lines.push(` if (${indexVar} !== -1) {`);
4297
4402
  lines.push(` ${collectionVar}.indexes.splice(${indexVar}, 1);`);
4298
4403
  lines.push(` }`);
@@ -4321,16 +4426,179 @@ function generateCollectionDeletion(collectionName, varName = "collection", isLa
4321
4426
  lines.push(isLast ? ` return app.delete(${varName});` : ` app.delete(${varName});`);
4322
4427
  return lines.join("\n");
4323
4428
  }
4429
+ function generateOperationUpMigration(operation, collectionIdMap) {
4430
+ const lines = [];
4431
+ if (operation.type === "create") {
4432
+ const collection = operation.collection;
4433
+ const varName = `collection_${collection.name}`;
4434
+ lines.push(generateCollectionCreation(collection, varName, true, collectionIdMap));
4435
+ } else if (operation.type === "modify") {
4436
+ const modification = operation.modifications;
4437
+ const collectionName = typeof operation.collection === "string" ? operation.collection : operation.collection?.name ?? modification.collection;
4438
+ let operationCount = 0;
4439
+ const totalOperations = modification.fieldsToAdd.length + modification.fieldsToModify.length + modification.fieldsToRemove.length + modification.indexesToAdd.length + modification.indexesToRemove.length + modification.rulesToUpdate.length + modification.permissionsToUpdate.length;
4440
+ for (const field of modification.fieldsToAdd) {
4441
+ operationCount++;
4442
+ const varName = `collection_${collectionName}_add_${field.name}`;
4443
+ const isLast = operationCount === totalOperations;
4444
+ lines.push(generateFieldAddition(collectionName, field, varName, isLast, collectionIdMap));
4445
+ if (!isLast) lines.push("");
4446
+ }
4447
+ for (const fieldMod of modification.fieldsToModify) {
4448
+ operationCount++;
4449
+ const varName = `collection_${collectionName}_modify_${fieldMod.fieldName}`;
4450
+ const isLast = operationCount === totalOperations;
4451
+ lines.push(generateFieldModification(collectionName, fieldMod, varName, isLast));
4452
+ if (!isLast) lines.push("");
4453
+ }
4454
+ for (const field of modification.fieldsToRemove) {
4455
+ operationCount++;
4456
+ const varName = `collection_${collectionName}_remove_${field.name}`;
4457
+ const isLast = operationCount === totalOperations;
4458
+ lines.push(generateFieldDeletion(collectionName, field.name, varName, isLast));
4459
+ if (!isLast) lines.push("");
4460
+ }
4461
+ for (let i = 0; i < modification.indexesToAdd.length; i++) {
4462
+ operationCount++;
4463
+ const index = modification.indexesToAdd[i];
4464
+ const varName = `collection_${collectionName}_addidx_${i}`;
4465
+ const isLast = operationCount === totalOperations;
4466
+ lines.push(generateIndexAddition(collectionName, index, varName, isLast));
4467
+ if (!isLast) lines.push("");
4468
+ }
4469
+ for (let i = 0; i < modification.indexesToRemove.length; i++) {
4470
+ operationCount++;
4471
+ const index = modification.indexesToRemove[i];
4472
+ const varName = `collection_${collectionName}_rmidx_${i}`;
4473
+ const isLast = operationCount === totalOperations;
4474
+ lines.push(generateIndexRemoval(collectionName, index, varName, isLast));
4475
+ if (!isLast) lines.push("");
4476
+ }
4477
+ if (modification.permissionsToUpdate && modification.permissionsToUpdate.length > 0) {
4478
+ for (const permission of modification.permissionsToUpdate) {
4479
+ operationCount++;
4480
+ const varName = `collection_${collectionName}_perm_${permission.ruleType}`;
4481
+ const isLast = operationCount === totalOperations;
4482
+ lines.push(generatePermissionUpdate(collectionName, permission.ruleType, permission.newValue, varName, isLast));
4483
+ if (!isLast) lines.push("");
4484
+ }
4485
+ } else if (modification.rulesToUpdate.length > 0) {
4486
+ for (const rule of modification.rulesToUpdate) {
4487
+ operationCount++;
4488
+ const varName = `collection_${collectionName}_rule_${rule.ruleType}`;
4489
+ const isLast = operationCount === totalOperations;
4490
+ lines.push(generateRuleUpdate(collectionName, rule.ruleType, rule.newValue, varName, isLast));
4491
+ if (!isLast) lines.push("");
4492
+ }
4493
+ }
4494
+ } else if (operation.type === "delete") {
4495
+ const collectionName = typeof operation.collection === "string" ? operation.collection : operation.collection.name;
4496
+ const varName = `collection_${collectionName}`;
4497
+ lines.push(generateCollectionDeletion(collectionName, varName, true));
4498
+ }
4499
+ return lines.join("\n");
4500
+ }
4501
+ function generateOperationDownMigration(operation, collectionIdMap) {
4502
+ const lines = [];
4503
+ if (operation.type === "create") {
4504
+ const collection = operation.collection;
4505
+ const varName = `collection_${collection.name}`;
4506
+ lines.push(generateCollectionDeletion(collection.name, varName, true));
4507
+ } else if (operation.type === "modify") {
4508
+ const modification = operation.modifications;
4509
+ const collectionName = typeof operation.collection === "string" ? operation.collection : operation.collection?.name ?? modification.collection;
4510
+ let operationCount = 0;
4511
+ const totalOperations = modification.fieldsToAdd.length + modification.fieldsToModify.length + modification.fieldsToRemove.length + modification.indexesToAdd.length + modification.indexesToRemove.length + modification.rulesToUpdate.length + modification.permissionsToUpdate.length;
4512
+ if (modification.permissionsToUpdate && modification.permissionsToUpdate.length > 0) {
4513
+ for (const permission of modification.permissionsToUpdate) {
4514
+ operationCount++;
4515
+ const varName = `collection_${collectionName}_revert_perm_${permission.ruleType}`;
4516
+ const isLast = operationCount === totalOperations;
4517
+ lines.push(generatePermissionUpdate(collectionName, permission.ruleType, permission.oldValue, varName, isLast));
4518
+ if (!isLast) lines.push("");
4519
+ }
4520
+ } else if (modification.rulesToUpdate.length > 0) {
4521
+ for (const rule of modification.rulesToUpdate) {
4522
+ operationCount++;
4523
+ const varName = `collection_${collectionName}_revert_rule_${rule.ruleType}`;
4524
+ const isLast = operationCount === totalOperations;
4525
+ lines.push(generateRuleUpdate(collectionName, rule.ruleType, rule.oldValue, varName, isLast));
4526
+ if (!isLast) lines.push("");
4527
+ }
4528
+ }
4529
+ for (let i = 0; i < modification.indexesToRemove.length; i++) {
4530
+ operationCount++;
4531
+ const index = modification.indexesToRemove[i];
4532
+ const varName = `collection_${collectionName}_restore_idx_${i}`;
4533
+ const isLast = operationCount === totalOperations;
4534
+ lines.push(generateIndexAddition(collectionName, index, varName, isLast));
4535
+ if (!isLast) lines.push("");
4536
+ }
4537
+ for (let i = 0; i < modification.indexesToAdd.length; i++) {
4538
+ operationCount++;
4539
+ const index = modification.indexesToAdd[i];
4540
+ const varName = `collection_${collectionName}_revert_idx_${i}`;
4541
+ const isLast = operationCount === totalOperations;
4542
+ lines.push(generateIndexRemoval(collectionName, index, varName, isLast));
4543
+ if (!isLast) lines.push("");
4544
+ }
4545
+ for (const field of modification.fieldsToRemove) {
4546
+ operationCount++;
4547
+ const varName = `collection_${collectionName}_restore_${field.name}`;
4548
+ const isLast = operationCount === totalOperations;
4549
+ lines.push(generateFieldAddition(collectionName, field, varName, isLast, collectionIdMap));
4550
+ if (!isLast) lines.push("");
4551
+ }
4552
+ for (const fieldMod of modification.fieldsToModify) {
4553
+ operationCount++;
4554
+ const reverseChanges = fieldMod.changes.map((change) => ({
4555
+ property: change.property,
4556
+ oldValue: change.newValue,
4557
+ newValue: change.oldValue
4558
+ }));
4559
+ const reverseMod = {
4560
+ fieldName: fieldMod.fieldName,
4561
+ currentDefinition: fieldMod.newDefinition,
4562
+ newDefinition: fieldMod.currentDefinition,
4563
+ changes: reverseChanges
4564
+ };
4565
+ const varName = `collection_${collectionName}_revert_${fieldMod.fieldName}`;
4566
+ const isLast = operationCount === totalOperations;
4567
+ lines.push(generateFieldModification(collectionName, reverseMod, varName, isLast));
4568
+ if (!isLast) lines.push("");
4569
+ }
4570
+ for (const field of modification.fieldsToAdd) {
4571
+ operationCount++;
4572
+ const varName = `collection_${collectionName}_revert_add_${field.name}`;
4573
+ const isLast = operationCount === totalOperations;
4574
+ lines.push(generateFieldDeletion(collectionName, field.name, varName, isLast));
4575
+ if (!isLast) lines.push("");
4576
+ }
4577
+ } else if (operation.type === "delete") {
4578
+ const collection = operation.collection;
4579
+ if (typeof collection !== "string") {
4580
+ const varName = `collection_${collection.name}`;
4581
+ lines.push(generateCollectionCreation(collection, varName, true, collectionIdMap));
4582
+ }
4583
+ }
4584
+ return lines.join("\n");
4585
+ }
4324
4586
  function generateUpMigration(diff) {
4325
4587
  const lines = [];
4326
4588
  lines.push(` // UP MIGRATION`);
4327
4589
  lines.push(``);
4590
+ const collectionIdMap = /* @__PURE__ */ new Map();
4591
+ for (const collection of diff.collectionsToCreate) {
4592
+ if (collection.id) {
4593
+ collectionIdMap.set(collection.name, collection.id);
4594
+ }
4595
+ }
4328
4596
  if (diff.collectionsToCreate.length > 0) {
4329
4597
  lines.push(` // Create new collections`);
4330
4598
  for (let i = 0; i < diff.collectionsToCreate.length; i++) {
4331
4599
  const collection = diff.collectionsToCreate[i];
4332
4600
  const varName = `collection_${collection.name}_create`;
4333
- lines.push(generateCollectionCreation(collection, varName));
4601
+ lines.push(generateCollectionCreation(collection, varName, false, collectionIdMap));
4334
4602
  lines.push(``);
4335
4603
  }
4336
4604
  }
@@ -4342,7 +4610,7 @@ function generateUpMigration(diff) {
4342
4610
  lines.push(` // Add fields to ${collectionName}`);
4343
4611
  for (const field of modification.fieldsToAdd) {
4344
4612
  const varName = `collection_${collectionName}_add_${field.name}`;
4345
- lines.push(generateFieldAddition(collectionName, field, varName));
4613
+ lines.push(generateFieldAddition(collectionName, field, varName, false, collectionIdMap));
4346
4614
  lines.push(``);
4347
4615
  }
4348
4616
  }
@@ -4433,12 +4701,23 @@ function generateDownMigration(diff) {
4433
4701
  const lines = [];
4434
4702
  lines.push(` // DOWN MIGRATION (ROLLBACK)`);
4435
4703
  lines.push(``);
4704
+ const collectionIdMap = /* @__PURE__ */ new Map();
4705
+ for (const collection of diff.collectionsToCreate) {
4706
+ if (collection.id) {
4707
+ collectionIdMap.set(collection.name, collection.id);
4708
+ }
4709
+ }
4710
+ for (const collection of diff.collectionsToDelete) {
4711
+ if (collection.id) {
4712
+ collectionIdMap.set(collection.name, collection.id);
4713
+ }
4714
+ }
4436
4715
  if (diff.collectionsToDelete.length > 0) {
4437
4716
  lines.push(` // Recreate deleted collections`);
4438
4717
  for (let i = 0; i < diff.collectionsToDelete.length; i++) {
4439
4718
  const collection = diff.collectionsToDelete[i];
4440
4719
  const varName = `collection_${collection.name}_recreate`;
4441
- lines.push(generateCollectionCreation(collection, varName));
4720
+ lines.push(generateCollectionCreation(collection, varName, false, collectionIdMap));
4442
4721
  lines.push(``);
4443
4722
  }
4444
4723
  }
@@ -4483,7 +4762,7 @@ function generateDownMigration(diff) {
4483
4762
  lines.push(` // Restore fields to ${collectionName}`);
4484
4763
  for (const field of modification.fieldsToRemove) {
4485
4764
  const varName = `collection_${collectionName}_restore_${field.name}`;
4486
- lines.push(generateFieldAddition(collectionName, field, varName));
4765
+ lines.push(generateFieldAddition(collectionName, field, varName, false, collectionIdMap));
4487
4766
  lines.push(``);
4488
4767
  }
4489
4768
  }
@@ -4552,12 +4831,33 @@ function generate(diff, config) {
4552
4831
  const normalizedConfig = typeof config === "string" ? { migrationDir: config } : config;
4553
4832
  try {
4554
4833
  const migrationDir = resolveMigrationDir(normalizedConfig);
4555
- const upCode = generateUpMigration(diff);
4556
- const downCode = generateDownMigration(diff);
4557
- const content = createMigrationFileStructure(upCode, downCode, normalizedConfig);
4558
- const filename = generateMigrationFilename(diff, normalizedConfig);
4559
- const filePath = writeMigrationFile(migrationDir, filename, content);
4560
- return filePath;
4834
+ const hasChanges4 = diff.collectionsToCreate.length > 0 || diff.collectionsToModify.length > 0 || diff.collectionsToDelete.length > 0;
4835
+ if (!hasChanges4) {
4836
+ return [];
4837
+ }
4838
+ const collectionIdMap = /* @__PURE__ */ new Map();
4839
+ for (const collection of diff.collectionsToCreate) {
4840
+ if (collection.id) {
4841
+ collectionIdMap.set(collection.name, collection.id);
4842
+ }
4843
+ }
4844
+ for (const collection of diff.collectionsToDelete) {
4845
+ if (collection.id) {
4846
+ collectionIdMap.set(collection.name, collection.id);
4847
+ }
4848
+ }
4849
+ const baseTimestamp = generateTimestamp(normalizedConfig);
4850
+ const operations = splitDiffByCollection(diff, baseTimestamp);
4851
+ const filePaths = [];
4852
+ for (const operation of operations) {
4853
+ const upCode = generateOperationUpMigration(operation, collectionIdMap);
4854
+ const downCode = generateOperationDownMigration(operation, collectionIdMap);
4855
+ const content = createMigrationFileStructure(upCode, downCode, normalizedConfig);
4856
+ const filename = generateCollectionMigrationFilename(operation);
4857
+ const filePath = writeMigrationFile(migrationDir, filename, content);
4858
+ filePaths.push(filePath);
4859
+ }
4860
+ return filePaths;
4561
4861
  } catch (error) {
4562
4862
  if (error instanceof MigrationGenerationError || error instanceof FileSystemError) {
4563
4863
  throw error;
@@ -4575,7 +4875,8 @@ var MigrationGenerator = class {
4575
4875
  this.config = mergeConfig4(config);
4576
4876
  }
4577
4877
  /**
4578
- * Generates a migration file from a schema diff
4878
+ * Generates migration files from a schema diff
4879
+ * Returns array of file paths (one per collection operation)
4579
4880
  */
4580
4881
  generate(diff) {
4581
4882
  return generate(diff, this.config);
@@ -5179,15 +5480,25 @@ async function executeGenerate(options) {
5179
5480
  process.exit(1);
5180
5481
  }
5181
5482
  logSection("\u{1F4DD} Generating Migration");
5182
- const migrationPath = await withProgress(
5483
+ const migrationPaths = await withProgress(
5183
5484
  "Creating migration file...",
5184
5485
  () => Promise.resolve(generate(diff, migrationsDir))
5185
5486
  );
5186
- logSuccess(`Migration file created: ${path5.basename(migrationPath)}`);
5487
+ if (migrationPaths.length === 0) {
5488
+ logWarning("No migration files were generated (no changes detected).");
5489
+ return;
5490
+ }
5491
+ if (migrationPaths.length === 1) {
5492
+ logSuccess(`Migration file created: ${path5.basename(migrationPaths[0])}`);
5493
+ } else {
5494
+ logSuccess(`Created ${migrationPaths.length} migration files`);
5495
+ }
5187
5496
  logSection("\u2705 Next Steps");
5188
5497
  console.log();
5189
- console.log(" 1. Review the generated migration file:");
5190
- console.log(` ${migrationPath}`);
5498
+ console.log(" 1. Review the generated migration file(s):");
5499
+ migrationPaths.forEach((migrationPath) => {
5500
+ console.log(` ${migrationPath}`);
5501
+ });
5191
5502
  console.log();
5192
5503
  console.log(" 2. Apply the migration by running PocketBase:");
5193
5504
  console.log(" yarn pb");
@@ -5450,6 +5761,6 @@ async function executeStatus(options) {
5450
5761
  }
5451
5762
  }
5452
5763
 
5453
- export { AutodateField, BaseMutator, BoolField, CLIUsageError, ConfigurationError, DateField, DiffEngine, EditorField, EmailField, FIELD_METADATA_KEY, FIELD_TYPE_INFO, FileField, FileSystemError, FilesField, GeoPointField, JSONField, MigrationError, MigrationGenerationError, MigrationGenerator, NumberField, POCKETBASE_FIELD_TYPES, PermissionTemplates, RelationField, RelationsField, SchemaAnalyzer, SchemaParsingError, SelectField, SnapshotError, SnapshotManager, StatusEnum, TextField, URLField, 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, extractFieldMetadata, 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 };
5764
+ export { AutodateField, BaseMutator, BoolField, CLIUsageError, ConfigurationError, DateField, DiffEngine, EditorField, EmailField, FIELD_METADATA_KEY, FIELD_TYPE_INFO, FileField, FileSystemError, FilesField, GeoPointField, JSONField, MigrationError, MigrationGenerationError, MigrationGenerator, NumberField, POCKETBASE_FIELD_TYPES, PermissionTemplates, RelationField, RelationsField, SchemaAnalyzer, SchemaParsingError, SelectField, SnapshotError, SnapshotManager, StatusEnum, TextField, URLField, aggregateChanges, baseImageFileSchema, baseSchema, baseSchemaWithTimestamps, buildFieldDefinition, buildSchemaDefinition, categorizeChangesBySeverity, compare, compareFieldConstraints, compareFieldOptions, compareFieldTypes, comparePermissions, compareRelationConfigurations, convertPocketBaseMigration, convertZodSchemaToCollectionSchema, createMigrationFileStructure, createPermissions, defineCollection, detectDestructiveChanges, detectFieldChanges, discoverSchemaFiles, extractComprehensiveFieldOptions, extractFieldDefinitions, extractFieldMetadata, extractFieldOptions, extractIndexes, extractRelationMetadata, extractSchemaDefinitions, 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, 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, loadBaseMigration, loadConfig, loadSnapshot, loadSnapshotIfExists, loadSnapshotWithMigrations, logError, logInfo, logSection, logSuccess, logWarning, mapZodArrayType, mapZodBooleanType, mapZodDateType, mapZodEnumType, mapZodNumberType, mapZodRecordType, mapZodStringType, mapZodTypeToPocketBase, matchCollectionsByName, matchFieldsByName, mergePermissions, mergeSnapshots, omitImageFilesSchema, parseSchemaFiles, pluralize, requiresForceFlag, resolveTargetCollection, resolveTemplate, saveSnapshot, selectSchemaForCollection, singularize, snapshotExists, toCollectionName, unwrapZodType, validatePermissionConfig, validateRuleExpression, validateSnapshot, withIndexes, withPermissions, withProgress, writeMigrationFile };
5454
5765
  //# sourceMappingURL=index.js.map
5455
5766
  //# sourceMappingURL=index.js.map