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.cjs CHANGED
@@ -3,6 +3,7 @@
3
3
  var zod = require('zod');
4
4
  var fs3 = require('fs');
5
5
  var path5 = require('path');
6
+ var crypto = require('crypto');
6
7
  var chalk = require('chalk');
7
8
  var ora = require('ora');
8
9
 
@@ -393,46 +394,6 @@ var inputImageFileSchema = {
393
394
  var omitImageFilesSchema = {
394
395
  imageFiles: true
395
396
  };
396
- function textField(options) {
397
- let schema = zod.z.string();
398
- if (options?.min !== void 0) schema = schema.min(options.min);
399
- if (options?.max !== void 0) schema = schema.max(options.max);
400
- if (options?.pattern !== void 0) schema = schema.regex(options.pattern);
401
- return schema;
402
- }
403
- function emailField() {
404
- return zod.z.string().email();
405
- }
406
- function urlField() {
407
- return zod.z.string().url();
408
- }
409
- function numberField(options) {
410
- let schema = zod.z.number();
411
- if (options?.min !== void 0) schema = schema.min(options.min);
412
- if (options?.max !== void 0) schema = schema.max(options.max);
413
- return schema;
414
- }
415
- function boolField() {
416
- return zod.z.boolean();
417
- }
418
- function dateField() {
419
- return zod.z.date();
420
- }
421
- function selectField(values) {
422
- return zod.z.enum(values);
423
- }
424
- function jsonField(schema) {
425
- return schema ?? zod.z.record(zod.z.any());
426
- }
427
- function fileField() {
428
- return zod.z.instanceof(File);
429
- }
430
- function filesField(options) {
431
- let schema = zod.z.array(zod.z.instanceof(File));
432
- if (options?.min !== void 0) schema = schema.min(options.min);
433
- if (options?.max !== void 0) schema = schema.max(options.max);
434
- return schema;
435
- }
436
397
  var RELATION_METADATA_KEY = "__pocketbase_relation__";
437
398
  function RelationField(config) {
438
399
  const metadata = {
@@ -476,15 +437,6 @@ function extractRelationMetadata(description) {
476
437
  }
477
438
  return null;
478
439
  }
479
- function editorField() {
480
- return zod.z.string();
481
- }
482
- function geoPointField() {
483
- return zod.z.object({
484
- lon: zod.z.number(),
485
- lat: zod.z.number()
486
- });
487
- }
488
440
  function withPermissions(schema, config) {
489
441
  const metadata = {
490
442
  permissions: config
@@ -2331,12 +2283,22 @@ function isAuthCollection(fields) {
2331
2283
  function buildFieldDefinition(fieldName, zodType) {
2332
2284
  const fieldMetadata = extractFieldMetadata(zodType.description);
2333
2285
  if (fieldMetadata) {
2334
- const required2 = isFieldRequired(zodType);
2286
+ let required2;
2287
+ if (fieldMetadata.type === "number") {
2288
+ if (fieldMetadata.options?.required !== void 0) {
2289
+ required2 = fieldMetadata.options.required;
2290
+ } else {
2291
+ required2 = false;
2292
+ }
2293
+ } else {
2294
+ required2 = isFieldRequired(zodType);
2295
+ }
2296
+ const { required: _required, ...options2 } = fieldMetadata.options || {};
2335
2297
  const fieldDef2 = {
2336
2298
  name: fieldName,
2337
2299
  type: fieldMetadata.type,
2338
2300
  required: required2,
2339
- options: fieldMetadata.options
2301
+ options: Object.keys(options2).length > 0 ? options2 : void 0
2340
2302
  };
2341
2303
  if (fieldMetadata.type === "relation") {
2342
2304
  const relationMetadata2 = extractRelationMetadata(zodType.description);
@@ -3332,6 +3294,65 @@ var SnapshotManager = class {
3332
3294
  return validateSnapshot(snapshot);
3333
3295
  }
3334
3296
  };
3297
+ function generateCollectionId() {
3298
+ const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
3299
+ const idLength = 15;
3300
+ const bytes = crypto.randomBytes(idLength);
3301
+ let id = "pb_";
3302
+ for (let i = 0; i < idLength; i++) {
3303
+ const index = bytes[i] % chars.length;
3304
+ id += chars[index];
3305
+ }
3306
+ return id;
3307
+ }
3308
+ var CollectionIdRegistry = class {
3309
+ ids;
3310
+ constructor() {
3311
+ this.ids = /* @__PURE__ */ new Set();
3312
+ }
3313
+ /**
3314
+ * Generates a unique collection ID for a given collection name
3315
+ * Special case: Returns constant "_pb_users_auth_" for users collection
3316
+ * Retries up to 10 times if collision occurs (extremely rare)
3317
+ *
3318
+ * @param collectionName - The name of the collection
3319
+ * @returns A unique collection ID
3320
+ * @throws Error if unable to generate unique ID after max attempts
3321
+ */
3322
+ generate(collectionName) {
3323
+ if (collectionName && collectionName.toLowerCase() === "users") {
3324
+ const usersId = "_pb_users_auth_";
3325
+ this.register(usersId);
3326
+ return usersId;
3327
+ }
3328
+ const maxAttempts = 10;
3329
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
3330
+ const id = generateCollectionId();
3331
+ if (!this.has(id)) {
3332
+ this.register(id);
3333
+ return id;
3334
+ }
3335
+ }
3336
+ throw new Error("Failed to generate unique collection ID after maximum attempts");
3337
+ }
3338
+ /**
3339
+ * Checks if an ID has already been registered
3340
+ *
3341
+ * @param id - The collection ID to check
3342
+ * @returns True if the ID exists in the registry
3343
+ */
3344
+ has(id) {
3345
+ return this.ids.has(id);
3346
+ }
3347
+ /**
3348
+ * Registers a collection ID in the registry
3349
+ *
3350
+ * @param id - The collection ID to register
3351
+ */
3352
+ register(id) {
3353
+ this.ids.add(id);
3354
+ }
3355
+ };
3335
3356
 
3336
3357
  // src/migration/diff.ts
3337
3358
  var DEFAULT_CONFIG3 = {
@@ -3674,6 +3695,18 @@ function aggregateChanges(currentSchema, previousSnapshot, config) {
3674
3695
  const filteredCollectionsToDelete = collectionsToDelete.filter(
3675
3696
  (collection) => !isSystemCollection(collection.name, config)
3676
3697
  );
3698
+ const registry = new CollectionIdRegistry();
3699
+ const collectionsWithIds = filteredCollectionsToCreate.map((collection) => {
3700
+ if (collection.id) {
3701
+ registry.register(collection.id);
3702
+ return collection;
3703
+ }
3704
+ const id = registry.generate(collection.name);
3705
+ return {
3706
+ ...collection,
3707
+ id
3708
+ };
3709
+ });
3677
3710
  const collectionsToModify = [];
3678
3711
  const matchedCollections = matchCollectionsByName(currentSchema, previousSnapshot);
3679
3712
  for (const [currentCollection, previousCollection] of matchedCollections) {
@@ -3683,7 +3716,7 @@ function aggregateChanges(currentSchema, previousSnapshot, config) {
3683
3716
  }
3684
3717
  }
3685
3718
  return {
3686
- collectionsToCreate: filteredCollectionsToCreate,
3719
+ collectionsToCreate: collectionsWithIds,
3687
3720
  collectionsToDelete: filteredCollectionsToDelete,
3688
3721
  collectionsToModify
3689
3722
  };
@@ -3919,6 +3952,49 @@ function generateTimestamp(config) {
3919
3952
  }
3920
3953
  return Math.floor(Date.now() / 1e3).toString();
3921
3954
  }
3955
+ function splitDiffByCollection(diff, baseTimestamp) {
3956
+ const operations = [];
3957
+ let currentTimestamp = parseInt(baseTimestamp, 10);
3958
+ for (const collection of diff.collectionsToCreate) {
3959
+ operations.push({
3960
+ type: "create",
3961
+ collection,
3962
+ timestamp: currentTimestamp.toString()
3963
+ });
3964
+ currentTimestamp += 1;
3965
+ }
3966
+ for (const modification of diff.collectionsToModify) {
3967
+ operations.push({
3968
+ type: "modify",
3969
+ collection: modification.collection,
3970
+ modifications: modification,
3971
+ timestamp: currentTimestamp.toString()
3972
+ });
3973
+ currentTimestamp += 1;
3974
+ }
3975
+ for (const collection of diff.collectionsToDelete) {
3976
+ operations.push({
3977
+ type: "delete",
3978
+ collection: collection.name || collection,
3979
+ // Handle both object and string
3980
+ timestamp: currentTimestamp.toString()
3981
+ });
3982
+ currentTimestamp += 1;
3983
+ }
3984
+ return operations;
3985
+ }
3986
+ function generateCollectionMigrationFilename(operation) {
3987
+ const timestamp = operation.timestamp;
3988
+ const operationType = operation.type === "modify" ? "updated" : operation.type === "create" ? "created" : "deleted";
3989
+ let collectionName;
3990
+ if (typeof operation.collection === "string") {
3991
+ collectionName = operation.collection;
3992
+ } else {
3993
+ collectionName = operation.collection.name;
3994
+ }
3995
+ const sanitizedName = collectionName.replace(/[^a-zA-Z0-9_]/g, "_").toLowerCase();
3996
+ return `${timestamp}_${operationType}_${sanitizedName}.js`;
3997
+ }
3922
3998
  function generateMigrationDescription(diff) {
3923
3999
  const parts = [];
3924
4000
  if (diff.collectionsToCreate.length > 0) {
@@ -4026,14 +4102,13 @@ function formatValue(value) {
4026
4102
  return "null";
4027
4103
  }
4028
4104
  if (typeof value === "string") {
4029
- return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n")}"`;
4105
+ return JSON.stringify(value);
4030
4106
  }
4031
4107
  if (typeof value === "number" || typeof value === "boolean") {
4032
4108
  return String(value);
4033
4109
  }
4034
4110
  if (Array.isArray(value)) {
4035
- const items = value.map((v) => formatValue(v)).join(", ");
4036
- return `[${items}]`;
4111
+ return JSON.stringify(value).replace(/","/g, '", "');
4037
4112
  }
4038
4113
  if (typeof value === "object") {
4039
4114
  const entries = Object.entries(value).map(([k, v]) => `${k}: ${formatValue(v)}`).join(", ");
@@ -4041,7 +4116,7 @@ function formatValue(value) {
4041
4116
  }
4042
4117
  return String(value);
4043
4118
  }
4044
- function generateFieldDefinitionObject(field) {
4119
+ function generateFieldDefinitionObject(field, collectionIdMap) {
4045
4120
  const parts = [];
4046
4121
  parts.push(` name: "${field.name}"`);
4047
4122
  parts.push(` type: "${field.type}"`);
@@ -4049,34 +4124,47 @@ function generateFieldDefinitionObject(field) {
4049
4124
  if (field.unique !== void 0) {
4050
4125
  parts.push(` unique: ${field.unique}`);
4051
4126
  }
4127
+ if (field.type === "select") {
4128
+ const maxSelect = field.options?.maxSelect ?? 1;
4129
+ parts.push(` maxSelect: ${maxSelect}`);
4130
+ const values = field.options?.values ?? [];
4131
+ parts.push(` values: ${formatValue(values)}`);
4132
+ }
4052
4133
  if (field.options && Object.keys(field.options).length > 0) {
4053
4134
  for (const [key, value] of Object.entries(field.options)) {
4135
+ if (field.type === "select" && (key === "maxSelect" || key === "values")) {
4136
+ continue;
4137
+ }
4054
4138
  parts.push(` ${key}: ${formatValue(value)}`);
4055
4139
  }
4056
4140
  }
4057
4141
  if (field.relation) {
4058
4142
  const isUsersCollection = field.relation.collection.toLowerCase() === "users";
4059
- const collectionIdPlaceholder = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
4060
- parts.push(` collectionId: ${collectionIdPlaceholder}`);
4061
- if (field.relation.maxSelect !== void 0) {
4062
- parts.push(` maxSelect: ${field.relation.maxSelect}`);
4063
- }
4064
- if (field.relation.minSelect !== void 0) {
4065
- parts.push(` minSelect: ${field.relation.minSelect}`);
4066
- }
4067
- if (field.relation.cascadeDelete !== void 0) {
4068
- parts.push(` cascadeDelete: ${field.relation.cascadeDelete}`);
4143
+ let collectionIdValue;
4144
+ if (isUsersCollection) {
4145
+ collectionIdValue = '"_pb_users_auth_"';
4146
+ } else if (collectionIdMap && collectionIdMap.has(field.relation.collection)) {
4147
+ collectionIdValue = `"${collectionIdMap.get(field.relation.collection)}"`;
4148
+ } else {
4149
+ collectionIdValue = `app.findCollectionByNameOrId("${field.relation.collection}").id`;
4069
4150
  }
4151
+ parts.push(` collectionId: ${collectionIdValue}`);
4152
+ const maxSelect = field.relation.maxSelect ?? 1;
4153
+ parts.push(` maxSelect: ${maxSelect}`);
4154
+ const minSelect = field.relation.minSelect ?? null;
4155
+ parts.push(` minSelect: ${minSelect}`);
4156
+ const cascadeDelete = field.relation.cascadeDelete ?? false;
4157
+ parts.push(` cascadeDelete: ${cascadeDelete}`);
4070
4158
  }
4071
4159
  return ` {
4072
4160
  ${parts.join(",\n")},
4073
4161
  }`;
4074
4162
  }
4075
- function generateFieldsArray(fields) {
4163
+ function generateFieldsArray(fields, collectionIdMap) {
4076
4164
  if (fields.length === 0) {
4077
4165
  return "[]";
4078
4166
  }
4079
- const fieldObjects = fields.map((field) => generateFieldDefinitionObject(field));
4167
+ const fieldObjects = fields.map((field) => generateFieldDefinitionObject(field, collectionIdMap));
4080
4168
  return `[
4081
4169
  ${fieldObjects.join(",\n")},
4082
4170
  ]`;
@@ -4135,7 +4223,7 @@ function generateIndexesArray(indexes) {
4135
4223
  if (!indexes || indexes.length === 0) {
4136
4224
  return "[]";
4137
4225
  }
4138
- const indexStrings = indexes.map((idx) => `"${idx}"`);
4226
+ const indexStrings = indexes.map((idx) => JSON.stringify(idx));
4139
4227
  return `[
4140
4228
  ${indexStrings.join(",\n ")},
4141
4229
  ]`;
@@ -4189,7 +4277,7 @@ function getSystemFields() {
4189
4277
  }
4190
4278
  ];
4191
4279
  }
4192
- function generateCollectionCreation(collection, varName = "collection", isLast = false) {
4280
+ function generateCollectionCreation(collection, varName = "collection", isLast = false, collectionIdMap) {
4193
4281
  const lines = [];
4194
4282
  lines.push(` const ${varName} = new Collection({`);
4195
4283
  lines.push(` name: "${collection.name}",`);
@@ -4203,7 +4291,7 @@ function generateCollectionCreation(collection, varName = "collection", isLast =
4203
4291
  }
4204
4292
  const systemFields = getSystemFields();
4205
4293
  const allFields = [...systemFields, ...collection.fields];
4206
- lines.push(` fields: ${generateFieldsArray(allFields)},`);
4294
+ lines.push(` fields: ${generateFieldsArray(allFields, collectionIdMap)},`);
4207
4295
  lines.push(` indexes: ${generateIndexesArray(collection.indexes)},`);
4208
4296
  lines.push(` });`);
4209
4297
  lines.push(``);
@@ -4225,42 +4313,59 @@ function getFieldConstructorName(fieldType) {
4225
4313
  };
4226
4314
  return constructorMap[fieldType] || "TextField";
4227
4315
  }
4228
- function generateFieldConstructorOptions(field) {
4316
+ function generateFieldConstructorOptions(field, collectionIdMap) {
4229
4317
  const parts = [];
4230
4318
  parts.push(` name: "${field.name}"`);
4231
4319
  parts.push(` required: ${field.required}`);
4232
4320
  if (field.unique !== void 0) {
4233
4321
  parts.push(` unique: ${field.unique}`);
4234
4322
  }
4323
+ if (field.type === "select") {
4324
+ const maxSelect = field.options?.maxSelect ?? 1;
4325
+ parts.push(` maxSelect: ${maxSelect}`);
4326
+ const values = field.options?.values ?? [];
4327
+ parts.push(` values: ${formatValue(values)}`);
4328
+ }
4235
4329
  if (field.options && Object.keys(field.options).length > 0) {
4236
4330
  for (const [key, value] of Object.entries(field.options)) {
4237
- parts.push(` ${key}: ${formatValue(value)}`);
4331
+ if (field.type === "select" && (key === "maxSelect" || key === "values")) {
4332
+ continue;
4333
+ }
4334
+ if (field.type === "number" && key === "noDecimal") {
4335
+ parts.push(` onlyInt: ${formatValue(value)}`);
4336
+ } else {
4337
+ parts.push(` ${key}: ${formatValue(value)}`);
4338
+ }
4238
4339
  }
4239
4340
  }
4240
4341
  if (field.relation && field.type === "relation") {
4241
4342
  const isUsersCollection = field.relation.collection.toLowerCase() === "users";
4242
- const collectionIdPlaceholder = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
4243
- parts.push(` collectionId: ${collectionIdPlaceholder}`);
4244
- if (field.relation.maxSelect !== void 0) {
4245
- parts.push(` maxSelect: ${field.relation.maxSelect}`);
4246
- }
4247
- if (field.relation.minSelect !== void 0) {
4248
- parts.push(` minSelect: ${field.relation.minSelect}`);
4249
- }
4250
- if (field.relation.cascadeDelete !== void 0) {
4251
- parts.push(` cascadeDelete: ${field.relation.cascadeDelete}`);
4343
+ let collectionIdValue;
4344
+ if (isUsersCollection) {
4345
+ collectionIdValue = '"_pb_users_auth_"';
4346
+ } else if (collectionIdMap && collectionIdMap.has(field.relation.collection)) {
4347
+ collectionIdValue = `"${collectionIdMap.get(field.relation.collection)}"`;
4348
+ } else {
4349
+ collectionIdValue = `app.findCollectionByNameOrId("${field.relation.collection}").id`;
4252
4350
  }
4351
+ parts.push(` collectionId: ${collectionIdValue}`);
4352
+ const maxSelect = field.relation.maxSelect ?? 1;
4353
+ parts.push(` maxSelect: ${maxSelect}`);
4354
+ const minSelect = field.relation.minSelect ?? null;
4355
+ parts.push(` minSelect: ${minSelect}`);
4356
+ const cascadeDelete = field.relation.cascadeDelete ?? false;
4357
+ parts.push(` cascadeDelete: ${cascadeDelete}`);
4253
4358
  }
4254
4359
  return parts.join(",\n");
4255
4360
  }
4256
- function generateFieldAddition(collectionName, field, varName, isLast = false) {
4361
+ function generateFieldAddition(collectionName, field, varName, isLast = false, collectionIdMap) {
4257
4362
  const lines = [];
4258
4363
  const constructorName = getFieldConstructorName(field.type);
4259
4364
  const collectionVar = varName || `collection_${collectionName}_${field.name}`;
4260
4365
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
4261
4366
  lines.push(``);
4262
4367
  lines.push(` ${collectionVar}.fields.add(new ${constructorName}({`);
4263
- lines.push(generateFieldConstructorOptions(field));
4368
+ lines.push(generateFieldConstructorOptions(field, collectionIdMap));
4264
4369
  lines.push(` }));`);
4265
4370
  lines.push(``);
4266
4371
  lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
@@ -4310,7 +4415,7 @@ function generateIndexAddition(collectionName, index, varName, isLast = false) {
4310
4415
  const lines = [];
4311
4416
  const collectionVar = varName || `collection_${collectionName}_idx`;
4312
4417
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
4313
- lines.push(` ${collectionVar}.indexes.push("${index}");`);
4418
+ lines.push(` ${collectionVar}.indexes.push(${JSON.stringify(index)});`);
4314
4419
  lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
4315
4420
  return lines.join("\n");
4316
4421
  }
@@ -4319,7 +4424,7 @@ function generateIndexRemoval(collectionName, index, varName, isLast = false) {
4319
4424
  const collectionVar = varName || `collection_${collectionName}_idx`;
4320
4425
  const indexVar = `${collectionVar}_indexToRemove`;
4321
4426
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
4322
- lines.push(` const ${indexVar} = ${collectionVar}.indexes.findIndex(idx => idx === "${index}");`);
4427
+ lines.push(` const ${indexVar} = ${collectionVar}.indexes.findIndex(idx => idx === ${JSON.stringify(index)});`);
4323
4428
  lines.push(` if (${indexVar} !== -1) {`);
4324
4429
  lines.push(` ${collectionVar}.indexes.splice(${indexVar}, 1);`);
4325
4430
  lines.push(` }`);
@@ -4348,16 +4453,179 @@ function generateCollectionDeletion(collectionName, varName = "collection", isLa
4348
4453
  lines.push(isLast ? ` return app.delete(${varName});` : ` app.delete(${varName});`);
4349
4454
  return lines.join("\n");
4350
4455
  }
4456
+ function generateOperationUpMigration(operation, collectionIdMap) {
4457
+ const lines = [];
4458
+ if (operation.type === "create") {
4459
+ const collection = operation.collection;
4460
+ const varName = `collection_${collection.name}`;
4461
+ lines.push(generateCollectionCreation(collection, varName, true, collectionIdMap));
4462
+ } else if (operation.type === "modify") {
4463
+ const modification = operation.modifications;
4464
+ const collectionName = typeof operation.collection === "string" ? operation.collection : operation.collection?.name ?? modification.collection;
4465
+ let operationCount = 0;
4466
+ const totalOperations = modification.fieldsToAdd.length + modification.fieldsToModify.length + modification.fieldsToRemove.length + modification.indexesToAdd.length + modification.indexesToRemove.length + modification.rulesToUpdate.length + modification.permissionsToUpdate.length;
4467
+ for (const field of modification.fieldsToAdd) {
4468
+ operationCount++;
4469
+ const varName = `collection_${collectionName}_add_${field.name}`;
4470
+ const isLast = operationCount === totalOperations;
4471
+ lines.push(generateFieldAddition(collectionName, field, varName, isLast, collectionIdMap));
4472
+ if (!isLast) lines.push("");
4473
+ }
4474
+ for (const fieldMod of modification.fieldsToModify) {
4475
+ operationCount++;
4476
+ const varName = `collection_${collectionName}_modify_${fieldMod.fieldName}`;
4477
+ const isLast = operationCount === totalOperations;
4478
+ lines.push(generateFieldModification(collectionName, fieldMod, varName, isLast));
4479
+ if (!isLast) lines.push("");
4480
+ }
4481
+ for (const field of modification.fieldsToRemove) {
4482
+ operationCount++;
4483
+ const varName = `collection_${collectionName}_remove_${field.name}`;
4484
+ const isLast = operationCount === totalOperations;
4485
+ lines.push(generateFieldDeletion(collectionName, field.name, varName, isLast));
4486
+ if (!isLast) lines.push("");
4487
+ }
4488
+ for (let i = 0; i < modification.indexesToAdd.length; i++) {
4489
+ operationCount++;
4490
+ const index = modification.indexesToAdd[i];
4491
+ const varName = `collection_${collectionName}_addidx_${i}`;
4492
+ const isLast = operationCount === totalOperations;
4493
+ lines.push(generateIndexAddition(collectionName, index, varName, isLast));
4494
+ if (!isLast) lines.push("");
4495
+ }
4496
+ for (let i = 0; i < modification.indexesToRemove.length; i++) {
4497
+ operationCount++;
4498
+ const index = modification.indexesToRemove[i];
4499
+ const varName = `collection_${collectionName}_rmidx_${i}`;
4500
+ const isLast = operationCount === totalOperations;
4501
+ lines.push(generateIndexRemoval(collectionName, index, varName, isLast));
4502
+ if (!isLast) lines.push("");
4503
+ }
4504
+ if (modification.permissionsToUpdate && modification.permissionsToUpdate.length > 0) {
4505
+ for (const permission of modification.permissionsToUpdate) {
4506
+ operationCount++;
4507
+ const varName = `collection_${collectionName}_perm_${permission.ruleType}`;
4508
+ const isLast = operationCount === totalOperations;
4509
+ lines.push(generatePermissionUpdate(collectionName, permission.ruleType, permission.newValue, varName, isLast));
4510
+ if (!isLast) lines.push("");
4511
+ }
4512
+ } else if (modification.rulesToUpdate.length > 0) {
4513
+ for (const rule of modification.rulesToUpdate) {
4514
+ operationCount++;
4515
+ const varName = `collection_${collectionName}_rule_${rule.ruleType}`;
4516
+ const isLast = operationCount === totalOperations;
4517
+ lines.push(generateRuleUpdate(collectionName, rule.ruleType, rule.newValue, varName, isLast));
4518
+ if (!isLast) lines.push("");
4519
+ }
4520
+ }
4521
+ } else if (operation.type === "delete") {
4522
+ const collectionName = typeof operation.collection === "string" ? operation.collection : operation.collection.name;
4523
+ const varName = `collection_${collectionName}`;
4524
+ lines.push(generateCollectionDeletion(collectionName, varName, true));
4525
+ }
4526
+ return lines.join("\n");
4527
+ }
4528
+ function generateOperationDownMigration(operation, collectionIdMap) {
4529
+ const lines = [];
4530
+ if (operation.type === "create") {
4531
+ const collection = operation.collection;
4532
+ const varName = `collection_${collection.name}`;
4533
+ lines.push(generateCollectionDeletion(collection.name, varName, true));
4534
+ } else if (operation.type === "modify") {
4535
+ const modification = operation.modifications;
4536
+ const collectionName = typeof operation.collection === "string" ? operation.collection : operation.collection?.name ?? modification.collection;
4537
+ let operationCount = 0;
4538
+ const totalOperations = modification.fieldsToAdd.length + modification.fieldsToModify.length + modification.fieldsToRemove.length + modification.indexesToAdd.length + modification.indexesToRemove.length + modification.rulesToUpdate.length + modification.permissionsToUpdate.length;
4539
+ if (modification.permissionsToUpdate && modification.permissionsToUpdate.length > 0) {
4540
+ for (const permission of modification.permissionsToUpdate) {
4541
+ operationCount++;
4542
+ const varName = `collection_${collectionName}_revert_perm_${permission.ruleType}`;
4543
+ const isLast = operationCount === totalOperations;
4544
+ lines.push(generatePermissionUpdate(collectionName, permission.ruleType, permission.oldValue, varName, isLast));
4545
+ if (!isLast) lines.push("");
4546
+ }
4547
+ } else if (modification.rulesToUpdate.length > 0) {
4548
+ for (const rule of modification.rulesToUpdate) {
4549
+ operationCount++;
4550
+ const varName = `collection_${collectionName}_revert_rule_${rule.ruleType}`;
4551
+ const isLast = operationCount === totalOperations;
4552
+ lines.push(generateRuleUpdate(collectionName, rule.ruleType, rule.oldValue, varName, isLast));
4553
+ if (!isLast) lines.push("");
4554
+ }
4555
+ }
4556
+ for (let i = 0; i < modification.indexesToRemove.length; i++) {
4557
+ operationCount++;
4558
+ const index = modification.indexesToRemove[i];
4559
+ const varName = `collection_${collectionName}_restore_idx_${i}`;
4560
+ const isLast = operationCount === totalOperations;
4561
+ lines.push(generateIndexAddition(collectionName, index, varName, isLast));
4562
+ if (!isLast) lines.push("");
4563
+ }
4564
+ for (let i = 0; i < modification.indexesToAdd.length; i++) {
4565
+ operationCount++;
4566
+ const index = modification.indexesToAdd[i];
4567
+ const varName = `collection_${collectionName}_revert_idx_${i}`;
4568
+ const isLast = operationCount === totalOperations;
4569
+ lines.push(generateIndexRemoval(collectionName, index, varName, isLast));
4570
+ if (!isLast) lines.push("");
4571
+ }
4572
+ for (const field of modification.fieldsToRemove) {
4573
+ operationCount++;
4574
+ const varName = `collection_${collectionName}_restore_${field.name}`;
4575
+ const isLast = operationCount === totalOperations;
4576
+ lines.push(generateFieldAddition(collectionName, field, varName, isLast, collectionIdMap));
4577
+ if (!isLast) lines.push("");
4578
+ }
4579
+ for (const fieldMod of modification.fieldsToModify) {
4580
+ operationCount++;
4581
+ const reverseChanges = fieldMod.changes.map((change) => ({
4582
+ property: change.property,
4583
+ oldValue: change.newValue,
4584
+ newValue: change.oldValue
4585
+ }));
4586
+ const reverseMod = {
4587
+ fieldName: fieldMod.fieldName,
4588
+ currentDefinition: fieldMod.newDefinition,
4589
+ newDefinition: fieldMod.currentDefinition,
4590
+ changes: reverseChanges
4591
+ };
4592
+ const varName = `collection_${collectionName}_revert_${fieldMod.fieldName}`;
4593
+ const isLast = operationCount === totalOperations;
4594
+ lines.push(generateFieldModification(collectionName, reverseMod, varName, isLast));
4595
+ if (!isLast) lines.push("");
4596
+ }
4597
+ for (const field of modification.fieldsToAdd) {
4598
+ operationCount++;
4599
+ const varName = `collection_${collectionName}_revert_add_${field.name}`;
4600
+ const isLast = operationCount === totalOperations;
4601
+ lines.push(generateFieldDeletion(collectionName, field.name, varName, isLast));
4602
+ if (!isLast) lines.push("");
4603
+ }
4604
+ } else if (operation.type === "delete") {
4605
+ const collection = operation.collection;
4606
+ if (typeof collection !== "string") {
4607
+ const varName = `collection_${collection.name}`;
4608
+ lines.push(generateCollectionCreation(collection, varName, true, collectionIdMap));
4609
+ }
4610
+ }
4611
+ return lines.join("\n");
4612
+ }
4351
4613
  function generateUpMigration(diff) {
4352
4614
  const lines = [];
4353
4615
  lines.push(` // UP MIGRATION`);
4354
4616
  lines.push(``);
4617
+ const collectionIdMap = /* @__PURE__ */ new Map();
4618
+ for (const collection of diff.collectionsToCreate) {
4619
+ if (collection.id) {
4620
+ collectionIdMap.set(collection.name, collection.id);
4621
+ }
4622
+ }
4355
4623
  if (diff.collectionsToCreate.length > 0) {
4356
4624
  lines.push(` // Create new collections`);
4357
4625
  for (let i = 0; i < diff.collectionsToCreate.length; i++) {
4358
4626
  const collection = diff.collectionsToCreate[i];
4359
4627
  const varName = `collection_${collection.name}_create`;
4360
- lines.push(generateCollectionCreation(collection, varName));
4628
+ lines.push(generateCollectionCreation(collection, varName, false, collectionIdMap));
4361
4629
  lines.push(``);
4362
4630
  }
4363
4631
  }
@@ -4369,7 +4637,7 @@ function generateUpMigration(diff) {
4369
4637
  lines.push(` // Add fields to ${collectionName}`);
4370
4638
  for (const field of modification.fieldsToAdd) {
4371
4639
  const varName = `collection_${collectionName}_add_${field.name}`;
4372
- lines.push(generateFieldAddition(collectionName, field, varName));
4640
+ lines.push(generateFieldAddition(collectionName, field, varName, false, collectionIdMap));
4373
4641
  lines.push(``);
4374
4642
  }
4375
4643
  }
@@ -4460,12 +4728,23 @@ function generateDownMigration(diff) {
4460
4728
  const lines = [];
4461
4729
  lines.push(` // DOWN MIGRATION (ROLLBACK)`);
4462
4730
  lines.push(``);
4731
+ const collectionIdMap = /* @__PURE__ */ new Map();
4732
+ for (const collection of diff.collectionsToCreate) {
4733
+ if (collection.id) {
4734
+ collectionIdMap.set(collection.name, collection.id);
4735
+ }
4736
+ }
4737
+ for (const collection of diff.collectionsToDelete) {
4738
+ if (collection.id) {
4739
+ collectionIdMap.set(collection.name, collection.id);
4740
+ }
4741
+ }
4463
4742
  if (diff.collectionsToDelete.length > 0) {
4464
4743
  lines.push(` // Recreate deleted collections`);
4465
4744
  for (let i = 0; i < diff.collectionsToDelete.length; i++) {
4466
4745
  const collection = diff.collectionsToDelete[i];
4467
4746
  const varName = `collection_${collection.name}_recreate`;
4468
- lines.push(generateCollectionCreation(collection, varName));
4747
+ lines.push(generateCollectionCreation(collection, varName, false, collectionIdMap));
4469
4748
  lines.push(``);
4470
4749
  }
4471
4750
  }
@@ -4510,7 +4789,7 @@ function generateDownMigration(diff) {
4510
4789
  lines.push(` // Restore fields to ${collectionName}`);
4511
4790
  for (const field of modification.fieldsToRemove) {
4512
4791
  const varName = `collection_${collectionName}_restore_${field.name}`;
4513
- lines.push(generateFieldAddition(collectionName, field, varName));
4792
+ lines.push(generateFieldAddition(collectionName, field, varName, false, collectionIdMap));
4514
4793
  lines.push(``);
4515
4794
  }
4516
4795
  }
@@ -4579,12 +4858,33 @@ function generate(diff, config) {
4579
4858
  const normalizedConfig = typeof config === "string" ? { migrationDir: config } : config;
4580
4859
  try {
4581
4860
  const migrationDir = resolveMigrationDir(normalizedConfig);
4582
- const upCode = generateUpMigration(diff);
4583
- const downCode = generateDownMigration(diff);
4584
- const content = createMigrationFileStructure(upCode, downCode, normalizedConfig);
4585
- const filename = generateMigrationFilename(diff, normalizedConfig);
4586
- const filePath = writeMigrationFile(migrationDir, filename, content);
4587
- return filePath;
4861
+ const hasChanges4 = diff.collectionsToCreate.length > 0 || diff.collectionsToModify.length > 0 || diff.collectionsToDelete.length > 0;
4862
+ if (!hasChanges4) {
4863
+ return [];
4864
+ }
4865
+ const collectionIdMap = /* @__PURE__ */ new Map();
4866
+ for (const collection of diff.collectionsToCreate) {
4867
+ if (collection.id) {
4868
+ collectionIdMap.set(collection.name, collection.id);
4869
+ }
4870
+ }
4871
+ for (const collection of diff.collectionsToDelete) {
4872
+ if (collection.id) {
4873
+ collectionIdMap.set(collection.name, collection.id);
4874
+ }
4875
+ }
4876
+ const baseTimestamp = generateTimestamp(normalizedConfig);
4877
+ const operations = splitDiffByCollection(diff, baseTimestamp);
4878
+ const filePaths = [];
4879
+ for (const operation of operations) {
4880
+ const upCode = generateOperationUpMigration(operation, collectionIdMap);
4881
+ const downCode = generateOperationDownMigration(operation, collectionIdMap);
4882
+ const content = createMigrationFileStructure(upCode, downCode, normalizedConfig);
4883
+ const filename = generateCollectionMigrationFilename(operation);
4884
+ const filePath = writeMigrationFile(migrationDir, filename, content);
4885
+ filePaths.push(filePath);
4886
+ }
4887
+ return filePaths;
4588
4888
  } catch (error) {
4589
4889
  if (error instanceof MigrationGenerationError || error instanceof FileSystemError) {
4590
4890
  throw error;
@@ -4602,7 +4902,8 @@ var MigrationGenerator = class {
4602
4902
  this.config = mergeConfig4(config);
4603
4903
  }
4604
4904
  /**
4605
- * Generates a migration file from a schema diff
4905
+ * Generates migration files from a schema diff
4906
+ * Returns array of file paths (one per collection operation)
4606
4907
  */
4607
4908
  generate(diff) {
4608
4909
  return generate(diff, this.config);
@@ -5206,15 +5507,25 @@ async function executeGenerate(options) {
5206
5507
  process.exit(1);
5207
5508
  }
5208
5509
  logSection("\u{1F4DD} Generating Migration");
5209
- const migrationPath = await withProgress(
5510
+ const migrationPaths = await withProgress(
5210
5511
  "Creating migration file...",
5211
5512
  () => Promise.resolve(generate(diff, migrationsDir))
5212
5513
  );
5213
- logSuccess(`Migration file created: ${path5__namespace.basename(migrationPath)}`);
5514
+ if (migrationPaths.length === 0) {
5515
+ logWarning("No migration files were generated (no changes detected).");
5516
+ return;
5517
+ }
5518
+ if (migrationPaths.length === 1) {
5519
+ logSuccess(`Migration file created: ${path5__namespace.basename(migrationPaths[0])}`);
5520
+ } else {
5521
+ logSuccess(`Created ${migrationPaths.length} migration files`);
5522
+ }
5214
5523
  logSection("\u2705 Next Steps");
5215
5524
  console.log();
5216
- console.log(" 1. Review the generated migration file:");
5217
- console.log(` ${migrationPath}`);
5525
+ console.log(" 1. Review the generated migration file(s):");
5526
+ migrationPaths.forEach((migrationPath) => {
5527
+ console.log(` ${migrationPath}`);
5528
+ });
5218
5529
  console.log();
5219
5530
  console.log(" 2. Apply the migration by running PocketBase:");
5220
5531
  console.log(" yarn pb");
@@ -5513,7 +5824,6 @@ exports.aggregateChanges = aggregateChanges;
5513
5824
  exports.baseImageFileSchema = baseImageFileSchema;
5514
5825
  exports.baseSchema = baseSchema;
5515
5826
  exports.baseSchemaWithTimestamps = baseSchemaWithTimestamps;
5516
- exports.boolField = boolField;
5517
5827
  exports.buildFieldDefinition = buildFieldDefinition;
5518
5828
  exports.buildSchemaDefinition = buildSchemaDefinition;
5519
5829
  exports.categorizeChangesBySeverity = categorizeChangesBySeverity;
@@ -5527,13 +5837,10 @@ exports.convertPocketBaseMigration = convertPocketBaseMigration;
5527
5837
  exports.convertZodSchemaToCollectionSchema = convertZodSchemaToCollectionSchema;
5528
5838
  exports.createMigrationFileStructure = createMigrationFileStructure;
5529
5839
  exports.createPermissions = createPermissions;
5530
- exports.dateField = dateField;
5531
5840
  exports.defineCollection = defineCollection;
5532
5841
  exports.detectDestructiveChanges = detectDestructiveChanges;
5533
5842
  exports.detectFieldChanges = detectFieldChanges;
5534
5843
  exports.discoverSchemaFiles = discoverSchemaFiles;
5535
- exports.editorField = editorField;
5536
- exports.emailField = emailField;
5537
5844
  exports.extractComprehensiveFieldOptions = extractComprehensiveFieldOptions;
5538
5845
  exports.extractFieldDefinitions = extractFieldDefinitions;
5539
5846
  exports.extractFieldMetadata = extractFieldMetadata;
@@ -5541,8 +5848,6 @@ exports.extractFieldOptions = extractFieldOptions;
5541
5848
  exports.extractIndexes = extractIndexes;
5542
5849
  exports.extractRelationMetadata = extractRelationMetadata;
5543
5850
  exports.extractSchemaDefinitions = extractSchemaDefinitions;
5544
- exports.fileField = fileField;
5545
- exports.filesField = filesField;
5546
5851
  exports.filterSystemCollections = filterSystemCollections;
5547
5852
  exports.findLatestSnapshot = findLatestSnapshot;
5548
5853
  exports.findNewCollections = findNewCollections;
@@ -5568,7 +5873,6 @@ exports.generateMigrationFilename = generateMigrationFilename;
5568
5873
  exports.generatePermissionUpdate = generatePermissionUpdate;
5569
5874
  exports.generateTimestamp = generateTimestamp;
5570
5875
  exports.generateUpMigration = generateUpMigration;
5571
- exports.geoPointField = geoPointField;
5572
5876
  exports.getArrayElementType = getArrayElementType;
5573
5877
  exports.getCollectionNameFromFile = getCollectionNameFromFile;
5574
5878
  exports.getDefaultValue = getDefaultValue;
@@ -5593,7 +5897,6 @@ exports.isRelationField = isRelationField;
5593
5897
  exports.isSingleRelationField = isSingleRelationField;
5594
5898
  exports.isSystemCollection = isSystemCollection;
5595
5899
  exports.isTemplateConfig = isTemplateConfig;
5596
- exports.jsonField = jsonField;
5597
5900
  exports.loadBaseMigration = loadBaseMigration;
5598
5901
  exports.loadConfig = loadConfig;
5599
5902
  exports.loadSnapshot = loadSnapshot;
@@ -5616,7 +5919,6 @@ exports.matchCollectionsByName = matchCollectionsByName;
5616
5919
  exports.matchFieldsByName = matchFieldsByName;
5617
5920
  exports.mergePermissions = mergePermissions;
5618
5921
  exports.mergeSnapshots = mergeSnapshots;
5619
- exports.numberField = numberField;
5620
5922
  exports.omitImageFilesSchema = omitImageFilesSchema;
5621
5923
  exports.parseSchemaFiles = parseSchemaFiles;
5622
5924
  exports.pluralize = pluralize;
@@ -5624,14 +5926,11 @@ exports.requiresForceFlag = requiresForceFlag;
5624
5926
  exports.resolveTargetCollection = resolveTargetCollection;
5625
5927
  exports.resolveTemplate = resolveTemplate;
5626
5928
  exports.saveSnapshot = saveSnapshot;
5627
- exports.selectField = selectField;
5628
5929
  exports.selectSchemaForCollection = selectSchemaForCollection;
5629
5930
  exports.singularize = singularize;
5630
5931
  exports.snapshotExists = snapshotExists;
5631
- exports.textField = textField;
5632
5932
  exports.toCollectionName = toCollectionName;
5633
5933
  exports.unwrapZodType = unwrapZodType;
5634
- exports.urlField = urlField;
5635
5934
  exports.validatePermissionConfig = validatePermissionConfig;
5636
5935
  exports.validateRuleExpression = validateRuleExpression;
5637
5936
  exports.validateSnapshot = validateSnapshot;