pocketbase-zod-schema 0.7.0 → 0.7.2
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.
- package/CHANGELOG.md +14 -0
- package/dist/cli/index.cjs +449 -50
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +449 -50
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/migrate.cjs +455 -53
- package/dist/cli/migrate.cjs.map +1 -1
- package/dist/cli/migrate.js +455 -53
- package/dist/cli/migrate.js.map +1 -1
- package/dist/cli/utils/index.cjs +8 -1
- package/dist/cli/utils/index.cjs.map +1 -1
- package/dist/cli/utils/index.d.cts +1 -1
- package/dist/cli/utils/index.d.ts +1 -1
- package/dist/cli/utils/index.js +8 -1
- package/dist/cli/utils/index.js.map +1 -1
- package/dist/index.cjs +90 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +87 -2
- package/dist/index.js.map +1 -1
- package/dist/migration/analyzer.cjs +87 -14
- package/dist/migration/analyzer.cjs.map +1 -1
- package/dist/migration/analyzer.d.cts +12 -4
- package/dist/migration/analyzer.d.ts +12 -4
- package/dist/migration/analyzer.js +87 -15
- package/dist/migration/analyzer.js.map +1 -1
- package/dist/migration/diff.cjs +64 -9
- package/dist/migration/diff.cjs.map +1 -1
- package/dist/migration/diff.d.cts +12 -2
- package/dist/migration/diff.d.ts +12 -2
- package/dist/migration/diff.js +64 -10
- package/dist/migration/diff.js.map +1 -1
- package/dist/migration/generator.cjs +206 -39
- package/dist/migration/generator.cjs.map +1 -1
- package/dist/migration/generator.d.cts +54 -2
- package/dist/migration/generator.d.ts +54 -2
- package/dist/migration/generator.js +203 -40
- package/dist/migration/generator.js.map +1 -1
- package/dist/migration/index.cjs +501 -63
- package/dist/migration/index.cjs.map +1 -1
- package/dist/migration/index.d.cts +2 -2
- package/dist/migration/index.d.ts +2 -2
- package/dist/migration/index.js +501 -63
- package/dist/migration/index.js.map +1 -1
- package/dist/migration/snapshot.cjs +147 -1
- package/dist/migration/snapshot.cjs.map +1 -1
- package/dist/migration/snapshot.d.cts +3 -1
- package/dist/migration/snapshot.d.ts +3 -1
- package/dist/migration/snapshot.js +147 -1
- package/dist/migration/snapshot.js.map +1 -1
- package/dist/migration/utils/index.d.cts +1 -1
- package/dist/migration/utils/index.d.ts +1 -1
- package/dist/schema.cjs +90 -1
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +128 -2
- package/dist/schema.d.ts +128 -2
- package/dist/schema.js +87 -2
- package/dist/schema.js.map +1 -1
- package/dist/server.cjs +545 -65
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +542 -66
- package/dist/server.js.map +1 -1
- package/dist/{types-CWHV6ATd.d.cts → types-CnzfX6JH.d.cts} +20 -2
- package/dist/{types-C2nGWHLV.d.ts → types-Do3jyFBm.d.ts} +20 -2
- package/package.json +1 -1
package/dist/migration/diff.cjs
CHANGED
|
@@ -480,7 +480,45 @@ function compareCollectionFields(currentCollection, previousCollection, config,
|
|
|
480
480
|
fieldsToRemove = fieldsToRemove.filter((_, index) => !processedRemoveIndices.has(index));
|
|
481
481
|
return { fieldsToAdd, fieldsToRemove, fieldsToModify };
|
|
482
482
|
}
|
|
483
|
+
function normalizeSql(query) {
|
|
484
|
+
if (!query) {
|
|
485
|
+
return "";
|
|
486
|
+
}
|
|
487
|
+
return query.split("\n").map((line) => line.trim()).join(" ").replace(/\s+/g, " ").trim();
|
|
488
|
+
}
|
|
489
|
+
function compareViewQuery(currentCollection, previousCollection) {
|
|
490
|
+
const newValue = currentCollection.viewQuery;
|
|
491
|
+
if (typeof newValue !== "string") {
|
|
492
|
+
return void 0;
|
|
493
|
+
}
|
|
494
|
+
if (normalizeSql(newValue) === normalizeSql(previousCollection.viewQuery)) {
|
|
495
|
+
return void 0;
|
|
496
|
+
}
|
|
497
|
+
return {
|
|
498
|
+
oldValue: previousCollection.viewQuery ?? null,
|
|
499
|
+
newValue
|
|
500
|
+
};
|
|
501
|
+
}
|
|
483
502
|
function buildCollectionModification(currentCollection, previousCollection, config, collectionIdToName) {
|
|
503
|
+
const isView = currentCollection.type === "view" || previousCollection.type === "view";
|
|
504
|
+
if (isView) {
|
|
505
|
+
return {
|
|
506
|
+
collection: currentCollection.name,
|
|
507
|
+
fieldsToAdd: [],
|
|
508
|
+
fieldsToRemove: [],
|
|
509
|
+
fieldsToModify: [],
|
|
510
|
+
indexesToAdd: [],
|
|
511
|
+
indexesToRemove: [],
|
|
512
|
+
rulesToUpdate: compareRules(
|
|
513
|
+
currentCollection.rules,
|
|
514
|
+
previousCollection.rules,
|
|
515
|
+
currentCollection.permissions,
|
|
516
|
+
previousCollection.permissions
|
|
517
|
+
),
|
|
518
|
+
permissionsToUpdate: comparePermissions(currentCollection.permissions, previousCollection.permissions),
|
|
519
|
+
viewQueryUpdate: compareViewQuery(currentCollection, previousCollection)
|
|
520
|
+
};
|
|
521
|
+
}
|
|
484
522
|
const { fieldsToAdd, fieldsToRemove, fieldsToModify } = compareCollectionFields(
|
|
485
523
|
currentCollection,
|
|
486
524
|
previousCollection,
|
|
@@ -512,6 +550,9 @@ function detectDestructiveChanges(diff, config) {
|
|
|
512
550
|
const destructiveChanges = [];
|
|
513
551
|
const mergedConfig = mergeConfig(config);
|
|
514
552
|
for (const collection of diff.collectionsToDelete) {
|
|
553
|
+
if (collection.type === "view") {
|
|
554
|
+
continue;
|
|
555
|
+
}
|
|
515
556
|
destructiveChanges.push({
|
|
516
557
|
type: "collection_delete",
|
|
517
558
|
severity: "high",
|
|
@@ -599,7 +640,11 @@ function categorizeChangesBySeverity(diff, _config) {
|
|
|
599
640
|
const destructive = [];
|
|
600
641
|
const nonDestructive = [];
|
|
601
642
|
for (const collection of diff.collectionsToDelete) {
|
|
602
|
-
|
|
643
|
+
if (collection.type === "view") {
|
|
644
|
+
nonDestructive.push(`Delete view collection: ${collection.name}`);
|
|
645
|
+
} else {
|
|
646
|
+
destructive.push(`Delete collection: ${collection.name}`);
|
|
647
|
+
}
|
|
603
648
|
}
|
|
604
649
|
for (const collection of diff.collectionsToCreate) {
|
|
605
650
|
nonDestructive.push(`Create collection: ${collection.name}`);
|
|
@@ -634,6 +679,9 @@ function categorizeChangesBySeverity(diff, _config) {
|
|
|
634
679
|
for (const rule of modification.rulesToUpdate) {
|
|
635
680
|
nonDestructive.push(`Update rule: ${collectionName}.${rule.ruleType}`);
|
|
636
681
|
}
|
|
682
|
+
if (modification.viewQueryUpdate) {
|
|
683
|
+
nonDestructive.push(`Update view query: ${collectionName}`);
|
|
684
|
+
}
|
|
637
685
|
}
|
|
638
686
|
return { destructive, nonDestructive };
|
|
639
687
|
}
|
|
@@ -646,6 +694,7 @@ function generateChangeSummary(diff, config) {
|
|
|
646
694
|
let indexChanges = 0;
|
|
647
695
|
let ruleChanges = 0;
|
|
648
696
|
let permissionChanges = 0;
|
|
697
|
+
let viewQueryChanges = 0;
|
|
649
698
|
for (const modification of diff.collectionsToModify) {
|
|
650
699
|
fieldsToAdd += modification.fieldsToAdd.length;
|
|
651
700
|
fieldsToRemove += modification.fieldsToRemove.length;
|
|
@@ -653,6 +702,9 @@ function generateChangeSummary(diff, config) {
|
|
|
653
702
|
indexChanges += modification.indexesToAdd.length + modification.indexesToRemove.length;
|
|
654
703
|
ruleChanges += modification.rulesToUpdate.length;
|
|
655
704
|
permissionChanges += modification.permissionsToUpdate.length;
|
|
705
|
+
if (modification.viewQueryUpdate) {
|
|
706
|
+
viewQueryChanges += 1;
|
|
707
|
+
}
|
|
656
708
|
}
|
|
657
709
|
return {
|
|
658
710
|
totalChanges: diff.collectionsToCreate.length + diff.collectionsToDelete.length + diff.collectionsToModify.length,
|
|
@@ -665,6 +717,7 @@ function generateChangeSummary(diff, config) {
|
|
|
665
717
|
indexChanges,
|
|
666
718
|
ruleChanges,
|
|
667
719
|
permissionChanges,
|
|
720
|
+
viewQueryChanges,
|
|
668
721
|
destructiveChanges,
|
|
669
722
|
nonDestructiveChanges: nonDestructive
|
|
670
723
|
};
|
|
@@ -694,12 +747,11 @@ function filterDiff(diff, options) {
|
|
|
694
747
|
});
|
|
695
748
|
let collectionsToDelete = diff.collectionsToDelete;
|
|
696
749
|
if (skipDestructive) {
|
|
697
|
-
collectionsToDelete =
|
|
698
|
-
} else {
|
|
699
|
-
collectionsToDelete = collectionsToDelete.filter((col) => {
|
|
700
|
-
return matchesPattern(col.name, patterns);
|
|
701
|
-
});
|
|
750
|
+
collectionsToDelete = collectionsToDelete.filter((col) => col.type === "view");
|
|
702
751
|
}
|
|
752
|
+
collectionsToDelete = collectionsToDelete.filter((col) => {
|
|
753
|
+
return matchesPattern(col.name, patterns);
|
|
754
|
+
});
|
|
703
755
|
const collectionsToModify = diff.collectionsToModify.map((mod) => {
|
|
704
756
|
const collectionMatches = matchesPattern(mod.collection, patterns);
|
|
705
757
|
const fieldsToAdd = mod.fieldsToAdd.filter((field) => {
|
|
@@ -724,6 +776,7 @@ function filterDiff(diff, options) {
|
|
|
724
776
|
const indexesToRemove = collectionMatches ? mod.indexesToRemove : [];
|
|
725
777
|
const rulesToUpdate = collectionMatches ? mod.rulesToUpdate : [];
|
|
726
778
|
const permissionsToUpdate = collectionMatches ? mod.permissionsToUpdate : [];
|
|
779
|
+
const viewQueryUpdate = collectionMatches ? mod.viewQueryUpdate : void 0;
|
|
727
780
|
return {
|
|
728
781
|
...mod,
|
|
729
782
|
fieldsToAdd,
|
|
@@ -732,10 +785,11 @@ function filterDiff(diff, options) {
|
|
|
732
785
|
indexesToAdd,
|
|
733
786
|
indexesToRemove,
|
|
734
787
|
rulesToUpdate,
|
|
735
|
-
permissionsToUpdate
|
|
788
|
+
permissionsToUpdate,
|
|
789
|
+
viewQueryUpdate
|
|
736
790
|
};
|
|
737
791
|
}).filter((mod) => {
|
|
738
|
-
return mod.fieldsToAdd.length > 0 || mod.fieldsToRemove.length > 0 || mod.fieldsToModify.length > 0 || mod.indexesToAdd.length > 0 || mod.indexesToRemove.length > 0 || mod.rulesToUpdate.length > 0 || mod.permissionsToUpdate.length > 0;
|
|
792
|
+
return mod.fieldsToAdd.length > 0 || mod.fieldsToRemove.length > 0 || mod.fieldsToModify.length > 0 || mod.indexesToAdd.length > 0 || mod.indexesToRemove.length > 0 || mod.rulesToUpdate.length > 0 || mod.permissionsToUpdate.length > 0 || mod.viewQueryUpdate !== void 0;
|
|
739
793
|
});
|
|
740
794
|
return {
|
|
741
795
|
...diff,
|
|
@@ -747,7 +801,7 @@ function filterDiff(diff, options) {
|
|
|
747
801
|
|
|
748
802
|
// src/migration/diff/index.ts
|
|
749
803
|
function hasChanges(modification) {
|
|
750
|
-
return modification.fieldsToAdd.length > 0 || modification.fieldsToRemove.length > 0 || modification.fieldsToModify.length > 0 || modification.indexesToAdd.length > 0 || modification.indexesToRemove.length > 0 || modification.rulesToUpdate.length > 0 || modification.permissionsToUpdate.length > 0;
|
|
804
|
+
return modification.fieldsToAdd.length > 0 || modification.fieldsToRemove.length > 0 || modification.fieldsToModify.length > 0 || modification.indexesToAdd.length > 0 || modification.indexesToRemove.length > 0 || modification.rulesToUpdate.length > 0 || modification.permissionsToUpdate.length > 0 || modification.viewQueryUpdate !== void 0;
|
|
751
805
|
}
|
|
752
806
|
function aggregateChanges(currentSchema, previousSnapshot, config) {
|
|
753
807
|
const collectionIdToName = /* @__PURE__ */ new Map();
|
|
@@ -870,6 +924,7 @@ exports.matchCollectionsByName = matchCollectionsByName;
|
|
|
870
924
|
exports.matchFieldsByName = matchFieldsByName;
|
|
871
925
|
exports.mergeConfig = mergeConfig;
|
|
872
926
|
exports.normalizeOptionValue = normalizeOptionValue;
|
|
927
|
+
exports.normalizeSql = normalizeSql;
|
|
873
928
|
exports.requiresForceFlag = requiresForceFlag;
|
|
874
929
|
//# sourceMappingURL=diff.cjs.map
|
|
875
930
|
//# sourceMappingURL=diff.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/migration/utils/collection-id-generator.ts","../../src/migration/diff/config.ts","../../src/migration/diff/utils.ts","../../src/migration/diff/fields.ts","../../src/migration/diff/indexes.ts","../../src/migration/diff/rules.ts","../../src/migration/diff/collections.ts","../../src/migration/diff/destructiveness.ts","../../src/migration/diff/summary.ts","../../src/migration/diff/filter.ts","../../src/migration/diff/index.ts"],"names":["randomBytes"],"mappings":";;;;;AAYO,SAAS,oBAAA,GAA+B;AAC7C,EAAA,MAAM,KAAA,GAAQ,sCAAA;AACd,EAAA,MAAM,QAAA,GAAW,EAAA;AAGjB,EAAA,MAAM,KAAA,GAAQA,mBAAY,QAAQ,CAAA;AAGlC,EAAA,IAAI,EAAA,GAAK,KAAA;AACT,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,QAAA,EAAU,CAAA,EAAA,EAAK;AACjC,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,CAAC,CAAA,GAAI,KAAA,CAAM,MAAA;AAC/B,IAAA,EAAA,IAAM,MAAM,KAAK,CAAA;AAAA,EACnB;AAEA,EAAA,OAAO,EAAA;AACT;AAqCO,IAAM,uBAAN,MAA2B;AAAA,EACxB,GAAA;AAAA,EAER,WAAA,GAAc;AACZ,IAAA,IAAA,CAAK,GAAA,uBAAU,GAAA,EAAY;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,SAAS,cAAA,EAAiC;AAExC,IAAA,IAAI,cAAA,IAAkB,cAAA,CAAe,WAAA,EAAY,KAAM,OAAA,EAAS;AAC9D,MAAA,MAAM,OAAA,GAAU,iBAAA;AAChB,MAAA,IAAI,CAAC,IAAA,CAAK,GAAA,CAAI,OAAO,CAAA,EAAG;AACtB,QAAA,IAAA,CAAK,SAAS,OAAO,CAAA;AAAA,MACvB;AACA,MAAA,OAAO,OAAA;AAAA,IACT;AAEA,IAAA,MAAM,WAAA,GAAc,EAAA;AAEpB,IAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,GAAU,WAAA,EAAa,OAAA,EAAA,EAAW;AACtD,MAAA,MAAM,KAAK,oBAAA,EAAqB;AAEhC,MAAA,IAAI,CAAC,IAAA,CAAK,GAAA,CAAI,EAAE,CAAA,EAAG;AACjB,QAAA,IAAA,CAAK,SAAS,EAAE,CAAA;AAChB,QAAA,OAAO,EAAA;AAAA,MACT;AAAA,IACF;AAEA,IAAA,MAAM,IAAI,MAAM,gEAAgE,CAAA;AAAA,EAClF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,EAAA,EAAqB;AACvB,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,GAAA,CAAI,EAAE,CAAA;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,SAAS,EAAA,EAAkB;AACzB,IAAA,IAAA,CAAK,GAAA,CAAI,IAAI,EAAE,CAAA;AAAA,EACjB;AACF,CAAA;;;ACjFO,IAAM,cAAA,GAA6C;AAAA,EACxD,YAAA,EAAc,IAAA;AAAA,EACd,0BAAA,EAA4B,IAAA;AAAA,EAC5B,iBAAA,EAAmB,MAAA;AAAA,EACnB,mBAAmB,CAAC,OAAA,EAAS,OAAA,EAAS,gBAAA,EAAkB,gBAAgB,aAAa,CAAA;AAAA,EACrF,iBAAA,EAAmB,CAAC,IAAA,EAAM,UAAA,EAAY,YAAY,OAAA,EAAS,iBAAA,EAAmB,UAAA,EAAY,SAAA,EAAW,SAAS;AAChH;AAKO,SAAS,YAAY,MAAA,EAAuD;AACjF,EAAA,OAAO;AAAA,IACL,GAAG,cAAA;AAAA,IACH,GAAG;AAAA,GACL;AACF;;;AC/CO,SAAS,kBAAA,CAAmB,gBAAwB,MAAA,EAAoC;AAC7F,EAAA,MAAM,YAAA,GAAe,YAAY,MAAM,CAAA;AACvC,EAAA,OAAO,YAAA,CAAa,iBAAA,CAAkB,QAAA,CAAS,cAAc,CAAA;AAC/D;AAUO,SAAS,qBAAqB,MAAA,EAAwC;AAC3E,EAAA,MAAM,YAAA,GAAe,YAAY,MAAM,CAAA;AACvC,EAAA,OAAO,IAAI,GAAA,CAAI,YAAA,CAAa,iBAAiB,CAAA;AAC/C;AASO,SAAS,cAAA,CAAe,GAAQ,CAAA,EAAiB;AAEtD,EAAA,IAAI,CAAA,KAAM,GAAG,OAAO,IAAA;AACpB,EAAA,IAAI,CAAA,IAAK,IAAA,IAAQ,CAAA,IAAK,IAAA,EAAM,OAAO,KAAA;AAGnC,EAAA,IAAI,MAAM,OAAA,CAAQ,CAAC,KAAK,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,EAAG;AACxC,IAAA,IAAI,CAAA,CAAE,MAAA,KAAW,CAAA,CAAE,MAAA,EAAQ,OAAO,KAAA;AAClC,IAAA,OAAO,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,EAAK,GAAA,KAAQ,eAAe,GAAA,EAAK,CAAA,CAAE,GAAG,CAAC,CAAC,CAAA;AAAA,EAC1D;AAGA,EAAA,IAAI,OAAO,CAAA,KAAM,QAAA,IAAY,OAAO,MAAM,QAAA,EAAU;AAClD,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA;AAC3B,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA;AAE3B,IAAA,IAAI,KAAA,CAAM,MAAA,KAAW,KAAA,CAAM,MAAA,EAAQ,OAAO,KAAA;AAE1C,IAAA,OAAO,KAAA,CAAM,KAAA,CAAM,CAAC,GAAA,KAAQ,cAAA,CAAe,CAAA,CAAE,GAAG,CAAA,EAAG,CAAA,CAAE,GAAG,CAAC,CAAC,CAAA;AAAA,EAC5D;AAGA,EAAA,OAAO,CAAA,KAAM,CAAA;AACf;AAWO,SAAS,oBAAA,CAAqB,GAAA,EAAa,KAAA,EAAY,SAAA,EAAwB;AAEpF,EAAA,IAAI,QAAQ,WAAA,IAAe,KAAA,KAAU,MAAM,SAAA,KAAc,QAAA,IAAY,cAAc,MAAA,CAAA,EAAS;AAC1F,IAAA,OAAO,MAAA;AAAA,EACT;AAGA,EAAA,IAAI,GAAA,KAAQ,SAAA,IAAa,KAAA,KAAU,CAAA,IAAK,cAAc,MAAA,EAAQ;AAC5D,IAAA,OAAO,MAAA;AAAA,EACT;AAGA,EAAA,IAAI,GAAA,KAAQ,KAAA,IAAS,KAAA,KAAU,CAAA,IAAK,cAAc,QAAA,EAAU;AAC1D,IAAA,OAAO,MAAA;AAAA,EACT;AAGA,EAAA,IAAI,cAAc,MAAA,EAAQ;AACxB,IAAA,IAAI,GAAA,KAAQ,eAAe,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,IAAK,KAAA,CAAM,WAAW,CAAA,EAAG;AACrE,MAAA,OAAO,MAAA;AAAA,IACT;AACA,IAAA,IAAI,GAAA,KAAQ,YAAY,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,IAAK,KAAA,CAAM,WAAW,CAAA,EAAG;AAClE,MAAA,OAAO,MAAA;AAAA,IACT;AACA,IAAA,IAAI,GAAA,KAAQ,WAAA,IAAe,KAAA,KAAU,KAAA,EAAO;AAC1C,MAAA,OAAO,MAAA;AAAA,IACT;AAAA,EACF;AAGA,EAAA,IAAI,cAAc,UAAA,EAAY;AAC5B,IAAA,IAAI,GAAA,KAAQ,UAAA,IAAc,KAAA,KAAU,IAAA,EAAM;AACxC,MAAA,OAAO,MAAA;AAAA,IACT;AACA,IAAA,IAAI,GAAA,KAAQ,UAAA,IAAc,KAAA,KAAU,KAAA,EAAO;AACzC,MAAA,OAAO,MAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;;;ACnGO,SAAS,aAAA,CAAc,eAAkC,cAAA,EAAsD;AACpH,EAAA,MAAM,YAA+B,EAAC;AACtC,EAAA,MAAM,kBAAA,GAAqB,IAAI,GAAA,CAAI,cAAA,CAAe,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAI,CAAC,CAAA;AAEpE,EAAA,KAAA,MAAW,gBAAgB,aAAA,EAAe;AACxC,IAAA,IAAI,CAAC,kBAAA,CAAmB,GAAA,CAAI,YAAA,CAAa,IAAI,CAAA,EAAG;AAC9C,MAAA,SAAA,CAAU,KAAK,YAAY,CAAA;AAAA,IAC7B;AAAA,EACF;AAEA,EAAA,OAAO,SAAA;AACT;AASO,SAAS,iBAAA,CACd,eACA,cAAA,EACmB;AACnB,EAAA,MAAM,gBAAmC,EAAC;AAC1C,EAAA,MAAM,iBAAA,GAAoB,IAAI,GAAA,CAAI,aAAA,CAAc,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAI,CAAC,CAAA;AAElE,EAAA,KAAA,MAAW,iBAAiB,cAAA,EAAgB;AAC1C,IAAA,IAAI,CAAC,iBAAA,CAAkB,GAAA,CAAI,aAAA,CAAc,IAAI,CAAA,EAAG;AAC9C,MAAA,aAAA,CAAc,KAAK,aAAa,CAAA;AAAA,IAClC;AAAA,EACF;AAEA,EAAA,OAAO,aAAA;AACT;AAUO,SAAS,iBAAA,CACd,eACA,cAAA,EAC2C;AAC3C,EAAA,MAAM,UAAqD,EAAC;AAG5D,EAAA,MAAM,gBAAA,uBAAuB,GAAA,EAA6B;AAC1D,EAAA,KAAA,MAAW,iBAAiB,cAAA,EAAgB;AAC1C,IAAA,gBAAA,CAAiB,GAAA,CAAI,aAAA,CAAc,IAAA,EAAM,aAAa,CAAA;AAAA,EACxD;AAGA,EAAA,KAAA,MAAW,gBAAgB,aAAA,EAAe;AACxC,IAAA,MAAM,aAAA,GAAgB,gBAAA,CAAiB,GAAA,CAAI,YAAA,CAAa,IAAI,CAAA;AAE5D,IAAA,IAAI,aAAA,EAAe;AACjB,MAAA,OAAA,CAAQ,IAAA,CAAK,CAAC,YAAA,EAAc,aAAa,CAAC,CAAA;AAAA,IAC5C;AAAA,EACF;AAEA,EAAA,OAAO,OAAA;AACT;AASO,SAAS,iBAAA,CAAkB,cAA+B,aAAA,EAAoD;AACnH,EAAA,IAAI,YAAA,CAAa,IAAA,KAAS,aAAA,CAAc,IAAA,EAAM;AAC5C,IAAA,OAAO;AAAA,MACL,QAAA,EAAU,MAAA;AAAA,MACV,UAAU,aAAA,CAAc,IAAA;AAAA,MACxB,UAAU,YAAA,CAAa;AAAA,KACzB;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT;AASO,SAAS,uBAAA,CAAwB,cAA+B,aAAA,EAA+C;AACpH,EAAA,MAAM,UAAyB,EAAC;AAGhC,EAAA,IAAI,YAAA,CAAa,QAAA,KAAa,aAAA,CAAc,QAAA,EAAU;AACpD,IAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,MACX,QAAA,EAAU,UAAA;AAAA,MACV,UAAU,aAAA,CAAc,QAAA;AAAA,MACxB,UAAU,YAAA,CAAa;AAAA,KACxB,CAAA;AAAA,EACH;AAGA,EAAA,IAAI,YAAA,CAAa,MAAA,KAAW,aAAA,CAAc,MAAA,EAAQ;AAChD,IAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,MACX,QAAA,EAAU,QAAA;AAAA,MACV,UAAU,aAAA,CAAc,MAAA;AAAA,MACxB,UAAU,YAAA,CAAa;AAAA,KACxB,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,OAAA;AACT;AASO,SAAS,mBAAA,CAAoB,cAA+B,aAAA,EAA+C;AAChH,EAAA,MAAM,UAAyB,EAAC;AAEhC,EAAA,MAAM,cAAA,GAAiB,YAAA,CAAa,OAAA,IAAW,EAAC;AAChD,EAAA,MAAM,eAAA,GAAkB,aAAA,CAAc,OAAA,IAAW,EAAC;AAGlD,EAAA,MAAM,OAAA,mBAAU,IAAI,GAAA,CAAI,CAAC,GAAG,MAAA,CAAO,IAAA,CAAK,cAAc,CAAA,EAAG,GAAG,MAAA,CAAO,IAAA,CAAK,eAAe,CAAC,CAAC,CAAA;AAKzF,EAAA,MAAM,YAAY,YAAA,CAAa,IAAA;AAE/B,EAAA,KAAA,MAAW,OAAO,OAAA,EAAS;AACzB,IAAA,MAAM,YAAA,GAAe,eAAe,GAAG,CAAA;AACvC,IAAA,MAAM,aAAA,GAAgB,gBAAgB,GAAG,CAAA;AAIzC,IAAA,MAAM,iBAAA,GAAoB,oBAAA,CAAqB,GAAA,EAAK,YAAA,EAAc,SAAS,CAAA;AAC3E,IAAA,MAAM,kBAAA,GAAqB,oBAAA,CAAqB,GAAA,EAAK,aAAA,EAAe,SAAS,CAAA;AAG7E,IAAA,IAAI,iBAAA,KAAsB,MAAA,IAAa,kBAAA,KAAuB,MAAA,EAAW;AACvE,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,CAAC,cAAA,CAAe,iBAAA,EAAmB,kBAAkB,CAAA,EAAG;AAC1D,MAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,QACX,QAAA,EAAU,WAAW,GAAG,CAAA,CAAA;AAAA,QACxB,QAAA,EAAU,aAAA;AAAA,QACV,QAAA,EAAU;AAAA,OACX,CAAA;AAAA,IACH;AAAA,EACF;AAEA,EAAA,OAAO,OAAA;AACT;AASO,SAAS,6BAAA,CACd,YAAA,EACA,aAAA,EACA,kBAAA,EACe;AACf,EAAA,MAAM,UAAyB,EAAC;AAEhC,EAAA,MAAM,kBAAkB,YAAA,CAAa,QAAA;AACrC,EAAA,MAAM,mBAAmB,aAAA,CAAc,QAAA;AAIvC,EAAA,IAAI,CAAC,eAAA,IAAmB,CAAC,gBAAA,EAAkB;AACzC,IAAA,OAAO,OAAA;AAAA,EACT;AAEA,EAAA,IAAI,CAAC,eAAA,IAAmB,CAAC,gBAAA,EAAkB;AAEzC,IAAA,OAAO,OAAA;AAAA,EACT;AAKA,EAAA,MAAM,mBAAA,GAAsB,CAAC,UAAA,KAA+B;AAC1D,IAAA,IAAI,CAAC,YAAY,OAAO,UAAA;AAGxB,IAAA,IAAI,kBAAA,IAAsB,kBAAA,CAAmB,GAAA,CAAI,UAAU,CAAA,EAAG;AAC5D,MAAA,OAAO,kBAAA,CAAmB,IAAI,UAAU,CAAA;AAAA,IAC1C;AAGA,IAAA,MAAM,SAAA,GAAY,UAAA,CAAW,KAAA,CAAM,4DAA4D,CAAA;AAC/F,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,OAAO,UAAU,CAAC,CAAA;AAAA,IACpB;AACA,IAAA,OAAO,UAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,iBAAA,GAAoB,mBAAA,CAAoB,eAAA,CAAgB,UAAU,CAAA;AAExE,EAAA,MAAM,kBAAA,GAAqB,mBAAA,CAAoB,gBAAA,CAAiB,UAAU,CAAA;AAI1E,EAAA,IAAI,iBAAA,CAAkB,WAAA,EAAY,KAAM,kBAAA,CAAmB,aAAY,EAAG;AACxE,IAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,MACX,QAAA,EAAU,qBAAA;AAAA,MACV,UAAU,gBAAA,CAAiB,UAAA;AAAA,MAC3B,UAAU,eAAA,CAAgB;AAAA,KAC3B,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,eAAA,CAAgB,aAAA,KAAkB,gBAAA,CAAiB,aAAA,EAAe;AACpE,IAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,MACX,QAAA,EAAU,wBAAA;AAAA,MACV,UAAU,gBAAA,CAAiB,aAAA;AAAA,MAC3B,UAAU,eAAA,CAAgB;AAAA,KAC3B,CAAA;AAAA,EACH;AAGA,EAAA,MAAM,YAAA,GAAe,CAAC,GAAA,KAAoC,GAAA,KAAQ,IAAI,IAAA,GAAO,GAAA;AAC7E,EAAA,MAAM,UAAA,GAAa,YAAA,CAAa,eAAA,CAAgB,SAAS,CAAA;AACzD,EAAA,MAAM,WAAA,GAAc,YAAA,CAAa,gBAAA,CAAiB,SAAS,CAAA;AAG3D,EAAA,IAAI,cAAc,WAAA,EAAa;AAC7B,IAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,MACX,QAAA,EAAU,oBAAA;AAAA,MACV,UAAU,gBAAA,CAAiB,SAAA;AAAA,MAC3B,UAAU,eAAA,CAAgB;AAAA,KAC3B,CAAA;AAAA,EACH;AAGA,EAAA,MAAM,YAAA,GAAe,CAAC,GAAA,KAAoC,GAAA,KAAQ,IAAI,IAAA,GAAO,GAAA;AAC7E,EAAA,MAAM,UAAA,GAAa,YAAA,CAAa,eAAA,CAAgB,SAAS,CAAA;AACzD,EAAA,MAAM,WAAA,GAAc,YAAA,CAAa,gBAAA,CAAiB,SAAS,CAAA;AAE3D,EAAA,IAAI,cAAc,WAAA,EAAa;AAC7B,IAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,MACX,QAAA,EAAU,oBAAA;AAAA,MACV,UAAU,gBAAA,CAAiB,SAAA;AAAA,MAC3B,UAAU,eAAA,CAAgB;AAAA,KAC3B,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,OAAA;AACT;AAUO,SAAS,kBAAA,CACd,YAAA,EACA,aAAA,EACA,kBAAA,EACe;AACf,EAAA,MAAM,UAAyB,EAAC;AAGhC,EAAA,MAAM,UAAA,GAAa,iBAAA,CAAkB,YAAA,EAAc,aAAa,CAAA;AAChE,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,OAAA,CAAQ,KAAK,UAAU,CAAA;AAAA,EACzB;AAGA,EAAA,OAAA,CAAQ,IAAA,CAAK,GAAG,uBAAA,CAAwB,YAAA,EAAc,aAAa,CAAC,CAAA;AAGpE,EAAA,OAAA,CAAQ,IAAA,CAAK,GAAG,mBAAA,CAAoB,YAAA,EAAc,aAAa,CAAC,CAAA;AAGhE,EAAA,IAAI,YAAA,CAAa,IAAA,KAAS,UAAA,IAAc,aAAA,CAAc,SAAS,UAAA,EAAY;AACzE,IAAA,OAAA,CAAQ,KAAK,GAAG,6BAAA,CAA8B,YAAA,EAAc,aAAA,EAAe,kBAAkB,CAAC,CAAA;AAAA,EAChG;AAEA,EAAA,OAAO,OAAA;AACT;;;AC5SO,SAAS,eACd,cAAA,GAA2B,EAAC,EAC5B,eAAA,GAA4B,EAAC,EAC0B;AACvD,EAAA,MAAM,UAAA,GAAa,IAAI,GAAA,CAAI,cAAc,CAAA;AACzC,EAAA,MAAM,WAAA,GAAc,IAAI,GAAA,CAAI,eAAe,CAAA;AAE3C,EAAA,MAAM,YAAA,GAAe,eAAe,MAAA,CAAO,CAAC,QAAQ,CAAC,WAAA,CAAY,GAAA,CAAI,GAAG,CAAC,CAAA;AACzE,EAAA,MAAM,eAAA,GAAkB,gBAAgB,MAAA,CAAO,CAAC,QAAQ,CAAC,UAAA,CAAW,GAAA,CAAI,GAAG,CAAC,CAAA;AAE5E,EAAA,OAAO,EAAE,cAAc,eAAA,EAAgB;AACzC;;;ACTO,SAAS,YAAA,CACd,YAAA,EACA,aAAA,EACA,kBAAA,EACA,mBAAA,EACc;AACd,EAAA,MAAM,UAAwB,EAAC;AAE/B,EAAA,MAAM,SAAA,GAAiE;AAAA,IACrE,UAAA;AAAA,IACA,UAAA;AAAA,IACA,YAAA;AAAA,IACA,YAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,KAAA,MAAW,YAAY,SAAA,EAAW;AAEhC,IAAA,MAAM,eAAe,YAAA,GAAe,QAAQ,CAAA,IAAK,kBAAA,GAAqB,QAAQ,CAAA,IAAK,IAAA;AACnF,IAAA,MAAM,gBAAgB,aAAA,GAAgB,QAAQ,CAAA,IAAK,mBAAA,GAAsB,QAAQ,CAAA,IAAK,IAAA;AAEtF,IAAA,IAAI,iBAAiB,aAAA,EAAe;AAClC,MAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,QACX,QAAA;AAAA,QACA,QAAA,EAAU,aAAA;AAAA,QACV,QAAA,EAAU;AAAA,OACX,CAAA;AAAA,IACH;AAAA,EACF;AAEA,EAAA,OAAO,OAAA;AACT;AAUO,SAAS,kBAAA,CACd,oBACA,mBAAA,EACoB;AACpB,EAAA,MAAM,UAA8B,EAAC;AAErC,EAAA,MAAM,YAA2B,CAAC,UAAA,EAAY,YAAY,YAAA,EAAc,YAAA,EAAc,cAAc,YAAY,CAAA;AAEhH,EAAA,KAAA,MAAW,YAAY,SAAA,EAAW;AAChC,IAAA,MAAM,YAAA,GAAe,kBAAA,GAAqB,QAAQ,CAAA,IAAK,IAAA;AACvD,IAAA,MAAM,aAAA,GAAgB,mBAAA,GAAsB,QAAQ,CAAA,IAAK,IAAA;AAGzD,IAAA,IAAI,iBAAiB,aAAA,EAAe;AAClC,MAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,QACX,QAAA;AAAA,QACA,QAAA,EAAU,aAAA;AAAA,QACV,QAAA,EAAU;AAAA,OACX,CAAA;AAAA,IACH;AAAA,EACF;AAEA,EAAA,OAAO,OAAA;AACT;;;ACpDO,SAAS,uBAAA,CAAwB,QAA0B,MAAA,EAA6C;AAC7G,EAAA,MAAM,mBAAA,uBAA0B,GAAA,EAA8B;AAE9D,EAAA,KAAA,MAAW,CAAC,cAAA,EAAgB,gBAAgB,CAAA,IAAK,OAAO,WAAA,EAAa;AACnE,IAAA,IAAI,CAAC,kBAAA,CAAmB,cAAA,EAAgB,MAAM,CAAA,EAAG;AAC/C,MAAA,mBAAA,CAAoB,GAAA,CAAI,gBAAgB,gBAAgB,CAAA;AAAA,IAC1D;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,WAAA,EAAa;AAAA,GACf;AACF;AASO,SAAS,kBAAA,CACd,eACA,gBAAA,EACoB;AACpB,EAAA,MAAM,iBAAqC,EAAC;AAG5C,EAAA,IAAI,CAAC,gBAAA,EAAkB;AACrB,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,aAAA,CAAc,WAAA,CAAY,QAAQ,CAAA;AAAA,EACtD;AAGA,EAAA,KAAA,MAAW,CAAC,cAAA,EAAgB,gBAAgB,CAAA,IAAK,cAAc,WAAA,EAAa;AAC1E,IAAA,IAAI,CAAC,gBAAA,CAAiB,WAAA,CAAY,GAAA,CAAI,cAAc,CAAA,EAAG;AACrD,MAAA,cAAA,CAAe,KAAK,gBAAgB,CAAA;AAAA,IACtC;AAAA,EACF;AAEA,EAAA,OAAO,cAAA;AACT;AASO,SAAS,sBAAA,CACd,eACA,gBAAA,EACoB;AACpB,EAAA,MAAM,qBAAyC,EAAC;AAGhD,EAAA,IAAI,CAAC,gBAAA,EAAkB;AACrB,IAAA,OAAO,kBAAA;AAAA,EACT;AAGA,EAAA,KAAA,MAAW,CAAC,cAAA,EAAgB,gBAAgB,CAAA,IAAK,iBAAiB,WAAA,EAAa;AAC7E,IAAA,IAAI,CAAC,aAAA,CAAc,WAAA,CAAY,GAAA,CAAI,cAAc,CAAA,EAAG;AAClD,MAAA,kBAAA,CAAmB,KAAK,gBAAgB,CAAA;AAAA,IAC1C;AAAA,EACF;AAEA,EAAA,OAAO,kBAAA;AACT;AAUO,SAAS,sBAAA,CACd,eACA,gBAAA,EAC6C;AAC7C,EAAA,MAAM,UAAuD,EAAC;AAG9D,EAAA,IAAI,CAAC,gBAAA,EAAkB;AACrB,IAAA,OAAO,OAAA;AAAA,EACT;AAGA,EAAA,MAAM,wBAAA,uBAA+B,GAAA,EAAwC;AAC7E,EAAA,KAAA,MAAW,CAAC,IAAA,EAAM,UAAU,CAAA,IAAK,iBAAiB,WAAA,EAAa;AAC7D,IAAA,wBAAA,CAAyB,IAAI,IAAA,CAAK,WAAA,IAAe,CAAC,IAAA,EAAM,UAAU,CAAC,CAAA;AAAA,EACrE;AAGA,EAAA,KAAA,MAAW,CAAC,cAAA,EAAgB,iBAAiB,CAAA,IAAK,cAAc,WAAA,EAAa;AAC3E,IAAA,MAAM,aAAA,GAAgB,wBAAA,CAAyB,GAAA,CAAI,cAAA,CAAe,aAAa,CAAA;AAE/E,IAAA,IAAI,aAAA,EAAe;AACjB,MAAA,MAAM,GAAG,kBAAkB,CAAA,GAAI,aAAA;AAC/B,MAAA,OAAA,CAAQ,IAAA,CAAK,CAAC,iBAAA,EAAmB,kBAAkB,CAAC,CAAA;AAAA,IACtD;AAAA,EACF;AAEA,EAAA,OAAO,OAAA;AACT;AAYA,SAAS,uBAAA,CACP,iBAAA,EACA,kBAAA,EACA,MAAA,EACA,kBAAA,EAKA;AACA,EAAA,IAAI,WAAA,GAAc,aAAA,CAAc,iBAAA,CAAkB,MAAA,EAAQ,mBAAmB,MAAM,CAAA;AACnF,EAAA,IAAI,cAAA,GAAiB,iBAAA,CAAkB,iBAAA,CAAkB,MAAA,EAAQ,mBAAmB,MAAM,CAAA;AAC1F,EAAA,MAAM,iBAAsC,EAAC;AAI7C,EAAA,IAAI,iBAAA,CAAkB,SAAS,OAAA,EAAS;AACtC,IAAA,MAAM,YAAA,GAAe,qBAAqB,MAAM,CAAA;AAChD,IAAA,WAAA,GAAc,WAAA,CAAY,OAAO,CAAC,KAAA,KAAU,CAAC,YAAA,CAAa,GAAA,CAAI,KAAA,CAAM,IAAI,CAAC,CAAA;AAAA,EAC3E;AAGA,EAAA,MAAM,aAAA,GAAgB,iBAAA,CAAkB,iBAAA,CAAkB,MAAA,EAAQ,mBAAmB,MAAM,CAAA;AAE3F,EAAA,KAAA,MAAW,CAAC,YAAA,EAAc,aAAa,CAAA,IAAK,aAAA,EAAe;AACzD,IAAA,MAAM,OAAA,GAAU,kBAAA,CAAmB,YAAA,EAAc,aAAA,EAAe,kBAAkB,CAAA;AAElF,IAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACtB,MAAA,cAAA,CAAe,IAAA,CAAK;AAAA,QAClB,WAAW,YAAA,CAAa,IAAA;AAAA,QACxB,iBAAA,EAAmB,aAAA;AAAA,QACnB,aAAA,EAAe,YAAA;AAAA,QACf;AAAA,OACD,CAAA;AAAA,IACH;AAAA,EACF;AAIA,EAAA,MAAM,mBAAA,uBAA0B,GAAA,EAAY;AAC5C,EAAA,MAAM,sBAAA,uBAA6B,GAAA,EAAY;AAG/C,EAAA,MAAM,qBAAA,GAAwB,CAAC,GAAA,KAAwB;AACrD,IAAA,IAAI,CAAC,KAAK,OAAO,GAAA;AACjB,IAAA,IAAI,kBAAA,IAAsB,mBAAmB,GAAA,CAAI,GAAG,GAAG,OAAO,kBAAA,CAAmB,IAAI,GAAG,CAAA;AACxF,IAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,KAAA,CAAM,4DAA4D,CAAA;AACpF,IAAA,OAAO,KAAA,GAAQ,KAAA,CAAM,CAAC,CAAA,GAAI,GAAA;AAAA,EAC5B,CAAA;AAGA,EAAA,MAAM,WAAA,uBAAkB,GAAA,EAAsB;AAC9C,EAAA,WAAA,CAAY,OAAA,CAAQ,CAAC,KAAA,EAAO,KAAA,KAAU;AACpC,IAAA,MAAM,OAAO,KAAA,CAAM,IAAA;AACnB,IAAA,IAAI,CAAC,YAAY,GAAA,CAAI,IAAI,GAAG,WAAA,CAAY,GAAA,CAAI,IAAA,EAAM,EAAE,CAAA;AACpD,IAAA,WAAA,CAAY,GAAA,CAAI,IAAI,CAAA,CAAG,IAAA,CAAK,KAAK,CAAA;AAAA,EACnC,CAAC,CAAA;AAED,EAAA,MAAM,aAAA,uBAAoB,GAAA,EAAsB;AAChD,EAAA,cAAA,CAAe,OAAA,CAAQ,CAAC,KAAA,EAAO,KAAA,KAAU;AACvC,IAAA,MAAM,OAAO,KAAA,CAAM,IAAA;AACnB,IAAA,IAAI,CAAC,cAAc,GAAA,CAAI,IAAI,GAAG,aAAA,CAAc,GAAA,CAAI,IAAA,EAAM,EAAE,CAAA;AACxD,IAAA,aAAA,CAAc,GAAA,CAAI,IAAI,CAAA,CAAG,IAAA,CAAK,KAAK,CAAA;AAAA,EACrC,CAAC,CAAA;AAGD,EAAA,KAAA,MAAW,CAAC,IAAA,EAAM,cAAc,CAAA,IAAK,aAAA,EAAe;AAClD,IAAA,MAAM,YAAA,GAAe,WAAA,CAAY,GAAA,CAAI,IAAI,CAAA;AAGzC,IAAA,IAAI,gBAAgB,YAAA,CAAa,MAAA,KAAW,CAAA,IAAK,cAAA,CAAe,WAAW,CAAA,EAAG;AAC5E,MAAA,MAAM,UAAA,GAAa,aAAa,CAAC,CAAA;AACjC,MAAA,MAAM,YAAA,GAAe,eAAe,CAAC,CAAA;AACrC,MAAA,MAAM,UAAA,GAAa,YAAY,UAAU,CAAA;AACzC,MAAA,MAAM,YAAA,GAAe,eAAe,YAAY,CAAA;AAGhD,MAAA,IAAI,OAAA,GAAU,IAAA;AACd,MAAA,IAAI,SAAS,UAAA,EAAY;AACvB,QAAA,MAAM,WAAA,GAAc,qBAAA,CAAsB,UAAA,CAAW,QAAA,EAAU,cAAc,EAAE,CAAA;AAC/E,QAAA,MAAM,aAAA,GAAgB,qBAAA,CAAsB,YAAA,CAAa,QAAA,EAAU,cAAc,EAAE,CAAA;AACnF,QAAA,IAAI,WAAA,CAAY,WAAA,EAAY,KAAM,aAAA,CAAc,aAAY,EAAG;AAC7D,UAAA,OAAA,GAAU,KAAA;AAAA,QACZ;AAAA,MACF;AAEA,MAAA,IAAI,OAAA,EAAS;AAEX,QAAA,mBAAA,CAAoB,IAAI,UAAU,CAAA;AAClC,QAAA,sBAAA,CAAuB,IAAI,YAAY,CAAA;AAGvC,QAAA,MAAM,OAAA,GAAU,kBAAA,CAAmB,UAAA,EAAY,YAAA,EAAc,kBAAkB,CAAA;AAC/E,QAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,UACX,QAAA,EAAU,MAAA;AAAA,UACV,UAAU,YAAA,CAAa,IAAA;AAAA,UACvB,UAAU,UAAA,CAAW;AAAA,SACtB,CAAA;AAED,QAAA,cAAA,CAAe,IAAA,CAAK;AAAA,UAClB,WAAW,YAAA,CAAa,IAAA;AAAA;AAAA,UACxB,iBAAA,EAAmB,YAAA;AAAA;AAAA,UACnB,aAAA,EAAe,UAAA;AAAA;AAAA,UACf;AAAA,SACD,CAAA;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAGA,EAAA,WAAA,GAAc,WAAA,CAAY,OAAO,CAAC,CAAA,EAAG,UAAU,CAAC,mBAAA,CAAoB,GAAA,CAAI,KAAK,CAAC,CAAA;AAC9E,EAAA,cAAA,GAAiB,cAAA,CAAe,OAAO,CAAC,CAAA,EAAG,UAAU,CAAC,sBAAA,CAAuB,GAAA,CAAI,KAAK,CAAC,CAAA;AAEvF,EAAA,OAAO,EAAE,WAAA,EAAa,cAAA,EAAgB,cAAA,EAAe;AACvD;AAUO,SAAS,2BAAA,CACd,iBAAA,EACA,kBAAA,EACA,MAAA,EACA,kBAAA,EACwB;AAExB,EAAA,MAAM,EAAE,WAAA,EAAa,cAAA,EAAgB,cAAA,EAAe,GAAI,uBAAA;AAAA,IACtD,iBAAA;AAAA,IACA,kBAAA;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACF;AAGA,EAAA,MAAM,EAAE,cAAc,eAAA,EAAgB,GAAI,eAAe,iBAAA,CAAkB,OAAA,EAAS,mBAAmB,OAAO,CAAA;AAG9G,EAAA,MAAM,aAAA,GAAgB,YAAA;AAAA,IACpB,iBAAA,CAAkB,KAAA;AAAA,IAClB,kBAAA,CAAmB,KAAA;AAAA,IACnB,iBAAA,CAAkB,WAAA;AAAA,IAClB,kBAAA,CAAmB;AAAA,GACrB;AAGA,EAAA,MAAM,mBAAA,GAAsB,kBAAA,CAAmB,iBAAA,CAAkB,WAAA,EAAa,mBAAmB,WAAW,CAAA;AAE5G,EAAA,OAAO;AAAA,IACL,YAAY,iBAAA,CAAkB,IAAA;AAAA,IAC9B,WAAA;AAAA,IACA,cAAA;AAAA,IACA,cAAA;AAAA,IACA,YAAA;AAAA,IACA,eAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACF;AACF;;;ACtRO,SAAS,wBAAA,CAAyB,MAAkB,MAAA,EAAgD;AACzG,EAAA,MAAM,qBAA0C,EAAC;AACjD,EAAA,MAAM,YAAA,GAAe,YAAY,MAAM,CAAA;AAGvC,EAAA,KAAA,MAAW,UAAA,IAAc,KAAK,mBAAA,EAAqB;AACjD,IAAA,kBAAA,CAAmB,IAAA,CAAK;AAAA,MACtB,IAAA,EAAM,mBAAA;AAAA,MACN,QAAA,EAAU,MAAA;AAAA,MACV,YAAY,UAAA,CAAW,IAAA;AAAA,MACvB,WAAA,EAAa,CAAA,mBAAA,EAAsB,UAAA,CAAW,IAAI,CAAA;AAAA,KACnD,CAAA;AAAA,EACH;AAGA,EAAA,KAAA,MAAW,YAAA,IAAgB,KAAK,mBAAA,EAAqB;AACnD,IAAA,MAAM,iBAAiB,YAAA,CAAa,UAAA;AAGpC,IAAA,KAAA,MAAW,KAAA,IAAS,aAAa,cAAA,EAAgB;AAC/C,MAAA,kBAAA,CAAmB,IAAA,CAAK;AAAA,QACtB,IAAA,EAAM,cAAA;AAAA,QACN,QAAA,EAAU,MAAA;AAAA,QACV,UAAA,EAAY,cAAA;AAAA,QACZ,OAAO,KAAA,CAAM,IAAA;AAAA,QACb,WAAA,EAAa,CAAA,cAAA,EAAiB,cAAc,CAAA,CAAA,EAAI,MAAM,IAAI,CAAA;AAAA,OAC3D,CAAA;AAAA,IACH;AAGA,IAAA,KAAA,MAAW,QAAA,IAAY,aAAa,cAAA,EAAgB;AAClD,MAAA,MAAM,UAAA,GAAa,SAAS,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,aAAa,MAAM,CAAA;AACrE,MAAA,MAAM,cAAA,GAAiB,QAAA,CAAS,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,QAAA,KAAa,UAAA,IAAc,CAAA,CAAE,QAAA,KAAa,IAAI,CAAA;AAEpG,MAAA,IAAI,UAAA,EAAY;AACd,QAAA,kBAAA,CAAmB,IAAA,CAAK;AAAA,UACtB,IAAA,EAAM,aAAA;AAAA,UACN,QAAA,EAAU,MAAA;AAAA,UACV,UAAA,EAAY,cAAA;AAAA,UACZ,OAAO,QAAA,CAAS,SAAA;AAAA,UAChB,WAAA,EAAa,CAAA,mBAAA,EAAsB,cAAc,CAAA,CAAA,EAAI,QAAA,CAAS,SAAS,CAAA,EAAA,EAAK,UAAA,CAAW,QAAQ,CAAA,QAAA,EAAM,UAAA,CAAW,QAAQ,CAAA,CAAA,CAAA;AAAA,UACxH,UAAU,UAAA,CAAW,QAAA;AAAA,UACrB,UAAU,UAAA,CAAW;AAAA,SACtB,CAAA;AAAA,MACH;AAEA,MAAA,IAAI,cAAA,IAAkB,YAAA,CAAa,iBAAA,KAAsB,MAAA,EAAQ;AAC/D,QAAA,kBAAA,CAAmB,IAAA,CAAK;AAAA,UACtB,IAAA,EAAM,iBAAA;AAAA,UACN,QAAA,EAAU,QAAA;AAAA,UACV,UAAA,EAAY,cAAA;AAAA,UACZ,OAAO,QAAA,CAAS,SAAA;AAAA,UAChB,WAAA,EAAa,CAAA,qBAAA,EAAwB,cAAc,CAAA,CAAA,EAAI,SAAS,SAAS,CAAA,CAAA;AAAA,UACzE,QAAA,EAAU,KAAA;AAAA,UACV,QAAA,EAAU;AAAA,SACX,CAAA;AAAA,MACH;AAGA,MAAA,IAAI,YAAA,CAAa,sBAAsB,KAAA,EAAO;AAC5C,QAAA,MAAM,YAAA,GAAe,QAAA,CAAS,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,QAAA,KAAa,MAAA,IAAU,CAAA,CAAE,QAAA,KAAa,UAAU,CAAA;AACtG,QAAA,KAAA,MAAW,UAAU,YAAA,EAAc;AACjC,UAAA,kBAAA,CAAmB,IAAA,CAAK;AAAA,YACtB,IAAA,EAAM,mBAAA;AAAA,YACN,QAAA,EAAU,KAAA;AAAA,YACV,UAAA,EAAY,cAAA;AAAA,YACZ,OAAO,QAAA,CAAS,SAAA;AAAA,YAChB,WAAA,EAAa,sBAAsB,cAAc,CAAA,CAAA,EAAI,SAAS,SAAS,CAAA,CAAA,EAAI,OAAO,QAAQ,CAAA,CAAA;AAAA,YAC1F,UAAU,MAAA,CAAO,QAAA;AAAA,YACjB,UAAU,MAAA,CAAO;AAAA,WAClB,CAAA;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,kBAAA;AACT;AASO,SAAS,iBAAA,CAAkB,MAAkB,MAAA,EAAoC;AACtF,EAAA,MAAM,YAAA,GAAe,YAAY,MAAM,CAAA;AAEvC,EAAA,IAAI,CAAC,aAAa,0BAAA,EAA4B;AAC5C,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,kBAAA,GAAqB,wBAAA,CAAyB,IAAA,EAAM,MAAM,CAAA;AAGhE,EAAA,MAAM,eAAA,GAAkB,kBAAA,CAAmB,MAAA,CAAO,CAAC,MAAA,KAAW;AAC5D,IAAA,QAAQ,aAAa,iBAAA;AAAmB,MACtC,KAAK,MAAA;AACH,QAAA,OAAO,OAAO,QAAA,KAAa,MAAA;AAAA,MAC7B,KAAK,QAAA;AACH,QAAA,OAAO,MAAA,CAAO,QAAA,KAAa,MAAA,IAAU,MAAA,CAAO,QAAA,KAAa,QAAA;AAAA,MAC3D,KAAK,KAAA;AACH,QAAA,OAAO,IAAA;AAAA,MACT;AACE,QAAA,OAAO,OAAO,QAAA,KAAa,MAAA;AAAA;AAC/B,EACF,CAAC,CAAA;AAED,EAAA,OAAO,gBAAgB,MAAA,GAAS,CAAA;AAClC;;;ACxGO,SAAS,2BAAA,CACd,MACA,OAAA,EAIA;AACA,EAAA,MAAM,cAAwB,EAAC;AAC/B,EAAA,MAAM,iBAA2B,EAAC;AAGlC,EAAA,KAAA,MAAW,UAAA,IAAc,KAAK,mBAAA,EAAqB;AACjD,IAAA,WAAA,CAAY,IAAA,CAAK,CAAA,mBAAA,EAAsB,UAAA,CAAW,IAAI,CAAA,CAAE,CAAA;AAAA,EAC1D;AAGA,EAAA,KAAA,MAAW,UAAA,IAAc,KAAK,mBAAA,EAAqB;AACjD,IAAA,cAAA,CAAe,IAAA,CAAK,CAAA,mBAAA,EAAsB,UAAA,CAAW,IAAI,CAAA,CAAE,CAAA;AAAA,EAC7D;AAGA,EAAA,KAAA,MAAW,YAAA,IAAgB,KAAK,mBAAA,EAAqB;AACnD,IAAA,MAAM,iBAAiB,YAAA,CAAa,UAAA;AAGpC,IAAA,KAAA,MAAW,KAAA,IAAS,aAAa,cAAA,EAAgB;AAC/C,MAAA,WAAA,CAAY,KAAK,CAAA,cAAA,EAAiB,cAAc,CAAA,CAAA,EAAI,KAAA,CAAM,IAAI,CAAA,CAAE,CAAA;AAAA,IAClE;AAGA,IAAA,KAAA,MAAW,KAAA,IAAS,aAAa,WAAA,EAAa;AAC5C,MAAA,cAAA,CAAe,KAAK,CAAA,WAAA,EAAc,cAAc,CAAA,CAAA,EAAI,KAAA,CAAM,IAAI,CAAA,CAAE,CAAA;AAAA,IAClE;AAGA,IAAA,KAAA,MAAW,QAAA,IAAY,aAAa,cAAA,EAAgB;AAClD,MAAA,MAAM,aAAA,GAAgB,SAAS,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,aAAa,MAAM,CAAA;AACxE,MAAA,MAAM,iBAAA,GAAoB,QAAA,CAAS,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,QAAA,KAAa,UAAA,IAAc,CAAA,CAAE,QAAA,KAAa,IAAI,CAAA;AAEvG,MAAA,IAAI,aAAA,EAAe;AACjB,QAAA,WAAA,CAAY,IAAA;AAAA,UACV,CAAA,mBAAA,EAAsB,cAAc,CAAA,CAAA,EAAI,QAAA,CAAS,SAAS,CAAA,EAAA,EAAK,QAAA,CAAS,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,QAAA,KAAa,MAAM,CAAA,EAAG,QAAQ,CAAA,QAAA,EAAM,QAAA,CAAS,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,QAAA,KAAa,MAAM,CAAA,EAAG,QAAQ,CAAA,CAAA;AAAA,SACjM;AAAA,MACF,WAAW,iBAAA,EAAmB;AAC5B,QAAA,WAAA,CAAY,KAAK,CAAA,qBAAA,EAAwB,cAAc,CAAA,CAAA,EAAI,QAAA,CAAS,SAAS,CAAA,CAAE,CAAA;AAAA,MACjF,CAAA,MAAO;AACL,QAAA,cAAA,CAAe,KAAK,CAAA,cAAA,EAAiB,cAAc,CAAA,CAAA,EAAI,QAAA,CAAS,SAAS,CAAA,CAAE,CAAA;AAAA,MAC7E;AAAA,IACF;AAGA,IAAA,KAAA,MAAW,MAAA,IAAU,aAAa,YAAA,EAAc;AAC9C,MAAA,cAAA,CAAe,IAAA,CAAK,CAAA,WAAA,EAAc,cAAc,CAAA,CAAE,CAAA;AAAA,IACpD;AAEA,IAAA,KAAA,MAAW,MAAA,IAAU,aAAa,eAAA,EAAiB;AACjD,MAAA,cAAA,CAAe,IAAA,CAAK,CAAA,cAAA,EAAiB,cAAc,CAAA,CAAE,CAAA;AAAA,IACvD;AAGA,IAAA,KAAA,MAAW,IAAA,IAAQ,aAAa,aAAA,EAAe;AAC7C,MAAA,cAAA,CAAe,KAAK,CAAA,aAAA,EAAgB,cAAc,CAAA,CAAA,EAAI,IAAA,CAAK,QAAQ,CAAA,CAAE,CAAA;AAAA,IACvE;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,aAAa,cAAA,EAAe;AACvC;AAUO,SAAS,qBAAA,CAAsB,MAAkB,MAAA,EAA0C;AAChG,EAAA,MAAM,kBAAA,GAAqB,wBAAA,CAAyB,IAAA,EAAM,MAAM,CAAA;AAChE,EAAA,MAAM,EAAE,cAAA,EAAe,GAAI,2BAAA,CAA4B,IAAY,CAAA;AAEnE,EAAA,IAAI,WAAA,GAAc,CAAA;AAClB,EAAA,IAAI,cAAA,GAAiB,CAAA;AACrB,EAAA,IAAI,cAAA,GAAiB,CAAA;AACrB,EAAA,IAAI,YAAA,GAAe,CAAA;AACnB,EAAA,IAAI,WAAA,GAAc,CAAA;AAClB,EAAA,IAAI,iBAAA,GAAoB,CAAA;AAExB,EAAA,KAAA,MAAW,YAAA,IAAgB,KAAK,mBAAA,EAAqB;AACnD,IAAA,WAAA,IAAe,aAAa,WAAA,CAAY,MAAA;AACxC,IAAA,cAAA,IAAkB,aAAa,cAAA,CAAe,MAAA;AAC9C,IAAA,cAAA,IAAkB,aAAa,cAAA,CAAe,MAAA;AAC9C,IAAA,YAAA,IAAgB,YAAA,CAAa,YAAA,CAAa,MAAA,GAAS,YAAA,CAAa,eAAA,CAAgB,MAAA;AAChF,IAAA,WAAA,IAAe,aAAa,aAAA,CAAc,MAAA;AAC1C,IAAA,iBAAA,IAAqB,aAAa,mBAAA,CAAoB,MAAA;AAAA,EACxD;AAEA,EAAA,OAAO;AAAA,IACL,YAAA,EAAc,KAAK,mBAAA,CAAoB,MAAA,GAAS,KAAK,mBAAA,CAAoB,MAAA,GAAS,KAAK,mBAAA,CAAoB,MAAA;AAAA,IAC3G,mBAAA,EAAqB,KAAK,mBAAA,CAAoB,MAAA;AAAA,IAC9C,mBAAA,EAAqB,KAAK,mBAAA,CAAoB,MAAA;AAAA,IAC9C,mBAAA,EAAqB,KAAK,mBAAA,CAAoB,MAAA;AAAA,IAC9C,WAAA;AAAA,IACA,cAAA;AAAA,IACA,cAAA;AAAA,IACA,YAAA;AAAA,IACA,WAAA;AAAA,IACA,iBAAA;AAAA,IACA,kBAAA;AAAA,IACA,qBAAA,EAAuB;AAAA,GACzB;AACF;;;ACrIA,SAAS,cAAA,CAAe,MAAc,QAAA,EAA6B;AACjE,EAAA,IAAI,CAAC,QAAA,IAAY,QAAA,CAAS,MAAA,KAAW,GAAG,OAAO,IAAA;AAC/C,EAAA,OAAO,QAAA,CAAS,KAAK,CAAA,OAAA,KAAW;AAC9B,IAAA,IAAI;AACA,MAAA,MAAM,KAAA,GAAQ,IAAI,MAAA,CAAO,OAAO,CAAA;AAChC,MAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AAAA,IAC1B,CAAA,CAAA,MAAQ;AACJ,MAAA,OAAO,IAAA,CAAK,SAAS,OAAO,CAAA;AAAA,IAChC;AAAA,EACF,CAAC,CAAA;AACH;AAEA,SAAS,+BAA+B,GAAA,EAAiC;AACrE,EAAA,MAAM,aAAa,GAAA,CAAI,OAAA,CAAQ,KAAK,CAAA,CAAA,KAAK,CAAA,CAAE,aAAa,MAAM,CAAA;AAC9D,EAAA,MAAM,cAAA,GAAiB,GAAA,CAAI,OAAA,CAAQ,IAAA,CAAK,CAAA,CAAA,KAAK,EAAE,QAAA,KAAa,UAAA,IAAc,CAAA,CAAE,QAAA,KAAa,IAAI,CAAA;AAC7F,EAAA,OAAO,CAAC,EAAE,UAAA,IAAc,cAAA,CAAA;AAC5B;AAEO,SAAS,UAAA,CAAW,MAAkB,OAAA,EAAoC;AAC/E,EAAA,MAAM,EAAE,QAAA,GAAW,EAAC,EAAG,eAAA,GAAkB,OAAM,GAAI,OAAA;AAGnD,EAAA,MAAM,mBAAA,GAAsB,IAAA,CAAK,mBAAA,CAAoB,MAAA,CAAO,CAAA,GAAA,KAAO;AACjE,IAAA,OAAO,cAAA,CAAe,GAAA,CAAI,IAAA,EAAM,QAAQ,CAAA;AAAA,EAC1C,CAAC,CAAA;AAGD,EAAA,IAAI,sBAAsB,IAAA,CAAK,mBAAA;AAC/B,EAAA,IAAI,eAAA,EAAiB;AACnB,IAAA,mBAAA,GAAsB,EAAC;AAAA,EACzB,CAAA,MAAO;AACL,IAAA,mBAAA,GAAsB,mBAAA,CAAoB,OAAO,CAAA,GAAA,KAAO;AACtD,MAAA,OAAO,cAAA,CAAe,GAAA,CAAI,IAAA,EAAM,QAAQ,CAAA;AAAA,IAC1C,CAAC,CAAA;AAAA,EACH;AAGA,EAAA,MAAM,mBAAA,GAAsB,IAAA,CAAK,mBAAA,CAAoB,GAAA,CAAI,CAAA,GAAA,KAAO;AAE9D,IAAA,MAAM,iBAAA,GAAoB,cAAA,CAAe,GAAA,CAAI,UAAA,EAAY,QAAQ,CAAA;AAGjE,IAAA,MAAM,WAAA,GAAc,GAAA,CAAI,WAAA,CAAY,MAAA,CAAO,CAAA,KAAA,KAAS;AAClD,MAAA,OAAO,iBAAA,IAAqB,eAAe,CAAA,EAAG,GAAA,CAAI,UAAU,CAAA,CAAA,EAAI,KAAA,CAAM,IAAI,CAAA,CAAA,EAAI,QAAQ,CAAA;AAAA,IACxF,CAAC,CAAA;AAGD,IAAA,IAAI,iBAAiB,GAAA,CAAI,cAAA;AACzB,IAAA,IAAI,eAAA,EAAiB;AACnB,MAAA,cAAA,GAAiB,EAAC;AAAA,IACpB,CAAA,MAAO;AACL,MAAA,cAAA,GAAiB,cAAA,CAAe,OAAO,CAAA,KAAA,KAAS;AAC7C,QAAA,OAAO,iBAAA,IAAqB,eAAe,CAAA,EAAG,GAAA,CAAI,UAAU,CAAA,CAAA,EAAI,KAAA,CAAM,IAAI,CAAA,CAAA,EAAI,QAAQ,CAAA;AAAA,MACzF,CAAC,CAAA;AAAA,IACH;AAGA,IAAA,IAAI,iBAAiB,GAAA,CAAI,cAAA;AACzB,IAAA,IAAI,eAAA,EAAiB;AACjB,MAAA,cAAA,GAAiB,eAAe,MAAA,CAAO,CAAA,CAAA,KAAK,CAAC,8BAAA,CAA+B,CAAC,CAAC,CAAA;AAAA,IAClF;AACA,IAAA,cAAA,GAAiB,cAAA,CAAe,OAAO,CAAA,CAAA,KAAK;AACxC,MAAA,OAAO,iBAAA,IAAqB,eAAe,CAAA,EAAG,GAAA,CAAI,UAAU,CAAA,CAAA,EAAI,CAAA,CAAE,SAAS,CAAA,CAAA,EAAI,QAAQ,CAAA;AAAA,IAC3F,CAAC,CAAA;AAKD,IAAA,MAAM,YAAA,GAAe,iBAAA,GAAoB,GAAA,CAAI,YAAA,GAAe,EAAC;AAC7D,IAAA,MAAM,eAAA,GAAkB,iBAAA,GAAoB,GAAA,CAAI,eAAA,GAAkB,EAAC;AACnE,IAAA,MAAM,aAAA,GAAgB,iBAAA,GAAoB,GAAA,CAAI,aAAA,GAAgB,EAAC;AAC/D,IAAA,MAAM,mBAAA,GAAsB,iBAAA,GAAoB,GAAA,CAAI,mBAAA,GAAsB,EAAC;AAE3E,IAAA,OAAO;AAAA,MACL,GAAG,GAAA;AAAA,MACH,WAAA;AAAA,MACA,cAAA;AAAA,MACA,cAAA;AAAA,MACA,YAAA;AAAA,MACA,eAAA;AAAA,MACA,aAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF,CAAC,CAAA,CAAE,MAAA,CAAO,CAAA,GAAA,KAAO;AAEd,IAAA,OAAO,GAAA,CAAI,WAAA,CAAY,MAAA,GAAS,CAAA,IACzB,GAAA,CAAI,cAAA,CAAe,MAAA,GAAS,CAAA,IAC5B,GAAA,CAAI,cAAA,CAAe,MAAA,GAAS,CAAA,IAC5B,GAAA,CAAI,aAAa,MAAA,GAAS,CAAA,IAC1B,GAAA,CAAI,eAAA,CAAgB,MAAA,GAAS,CAAA,IAC7B,GAAA,CAAI,aAAA,CAAc,MAAA,GAAS,CAAA,IAC3B,GAAA,CAAI,mBAAA,CAAoB,MAAA,GAAS,CAAA;AAAA,EAC3C,CAAC,CAAA;AAED,EAAA,OAAO;AAAA,IACL,GAAG,IAAA;AAAA,IACH,mBAAA;AAAA,IACA,mBAAA;AAAA,IACA;AAAA,GACF;AACF;;;AClEA,SAAS,WAAW,YAAA,EAA+C;AACjE,EAAA,OACE,YAAA,CAAa,WAAA,CAAY,MAAA,GAAS,CAAA,IAClC,YAAA,CAAa,cAAA,CAAe,MAAA,GAAS,CAAA,IACrC,YAAA,CAAa,cAAA,CAAe,MAAA,GAAS,CAAA,IACrC,YAAA,CAAa,aAAa,MAAA,GAAS,CAAA,IACnC,YAAA,CAAa,eAAA,CAAgB,MAAA,GAAS,CAAA,IACtC,YAAA,CAAa,aAAA,CAAc,MAAA,GAAS,CAAA,IACpC,YAAA,CAAa,mBAAA,CAAoB,MAAA,GAAS,CAAA;AAE9C;AAWO,SAAS,gBAAA,CACd,aAAA,EACA,gBAAA,EACA,MAAA,EACY;AAGZ,EAAA,MAAM,kBAAA,uBAAyB,GAAA,EAAoB;AACnD,EAAA,IAAI,gBAAA,EAAkB;AACpB,IAAA,KAAA,MAAW,CAAC,IAAA,EAAM,UAAU,CAAA,IAAK,iBAAiB,WAAA,EAAa;AAC7D,MAAA,IAAI,WAAW,EAAA,EAAI;AACjB,QAAA,kBAAA,CAAmB,GAAA,CAAI,UAAA,CAAW,EAAA,EAAI,IAAI,CAAA;AAAA,MAC5C;AAAA,IACF;AAAA,EACF;AAGA,EAAA,MAAM,mBAAA,GAAsB,kBAAA,CAAmB,aAAA,EAAe,gBAAgB,CAAA;AAC9E,EAAA,MAAM,mBAAA,GAAsB,sBAAA,CAAuB,aAAA,EAAe,gBAAgB,CAAA;AAGlF,EAAA,MAAM,8BAA8B,mBAAA,CAAoB,MAAA;AAAA,IACtD,CAAC,UAAA,KAAe,CAAC,kBAAA,CAAmB,UAAA,CAAW,MAAM,MAAM;AAAA,GAC7D;AACA,EAAA,MAAM,8BAA8B,mBAAA,CAAoB,MAAA;AAAA,IACtD,CAAC,UAAA,KAAe,CAAC,kBAAA,CAAmB,UAAA,CAAW,MAAM,MAAM;AAAA,GAC7D;AAGA,EAAA,MAAM,QAAA,GAAW,IAAI,oBAAA,EAAqB;AAC1C,EAAA,MAAM,kBAAA,GAAqB,2BAAA,CAA4B,GAAA,CAAI,CAAC,UAAA,KAAe;AAEzE,IAAA,IAAI,WAAW,EAAA,EAAI;AACjB,MAAA,QAAA,CAAS,QAAA,CAAS,WAAW,EAAE,CAAA;AAC/B,MAAA,OAAO,UAAA;AAAA,IACT;AAGA,IAAA,MAAM,EAAA,GAAK,QAAA,CAAS,QAAA,CAAS,UAAA,CAAW,IAAI,CAAA;AAC5C,IAAA,OAAO;AAAA,MACL,GAAG,UAAA;AAAA,MACH;AAAA,KACF;AAAA,EACF,CAAC,CAAA;AAGD,EAAA,MAAM,sBAAgD,EAAC;AACvD,EAAA,MAAM,kBAAA,GAAqB,sBAAA,CAAuB,aAAA,EAAe,gBAAgB,CAAA;AAEjF,EAAA,KAAA,MAAW,CAAC,iBAAA,EAAmB,kBAAkB,CAAA,IAAK,kBAAA,EAAoB;AACxE,IAAA,MAAM,YAAA,GAAe,2BAAA,CAA4B,iBAAA,EAAmB,kBAAA,EAAoB,QAAQ,kBAAkB,CAAA;AAIlH,IAAA,IAAI,UAAA,CAAW,YAAY,CAAA,EAAG;AAC5B,MAAA,mBAAA,CAAoB,KAAK,YAAY,CAAA;AAAA,IACvC;AAAA,EACF;AAIA,EAAA,MAAM,qBAAA,uBAA4B,GAAA,EAAoB;AACtD,EAAA,IAAI,gBAAA,EAAkB;AACpB,IAAA,KAAA,MAAW,CAAC,IAAA,EAAM,UAAU,CAAA,IAAK,iBAAiB,WAAA,EAAa;AAC7D,MAAA,IAAI,WAAW,EAAA,EAAI;AACjB,QAAA,qBAAA,CAAsB,GAAA,CAAI,IAAA,EAAM,UAAA,CAAW,EAAE,CAAA;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,mBAAA,EAAqB,kBAAA;AAAA,IACrB,mBAAA,EAAqB,2BAAA;AAAA,IACrB,mBAAA;AAAA,IACA;AAAA,GACF;AACF;AAWO,SAAS,OAAA,CACd,aAAA,EACA,gBAAA,EACA,MAAA,EACY;AACZ,EAAA,OAAO,gBAAA,CAAiB,aAAA,EAAe,gBAAA,EAAkB,MAAM,CAAA;AACjE;AAMO,IAAM,aAAN,MAAiB;AAAA,EACd,MAAA;AAAA,EAER,YAAY,MAAA,EAA2B;AACrC,IAAA,IAAA,CAAK,MAAA,GAAS,YAAY,MAAM,CAAA;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,OAAA,CAAQ,eAAiC,gBAAA,EAAqD;AAC5F,IAAA,OAAO,OAAA,CAAQ,aAAA,EAAe,gBAAA,EAAkB,IAAA,CAAK,MAAM,CAAA;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA,EAKA,yBAAyB,IAAA,EAAuC;AAC9D,IAAA,OAAO,wBAAA,CAAyB,IAAA,EAAM,IAAA,CAAK,MAAM,CAAA;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAKA,4BAA4B,IAAA,EAAuE;AACjG,IAAA,OAAO,2BAAA,CAA4B,IAAA,EAAM,IAAA,CAAK,MAAM,CAAA;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,IAAA,EAAiC;AACrD,IAAA,OAAO,qBAAA,CAAsB,IAAA,EAAM,IAAA,CAAK,MAAM,CAAA;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAkB,IAAA,EAA2B;AAC3C,IAAA,OAAO,iBAAA,CAAkB,IAAA,EAAM,IAAA,CAAK,MAAM,CAAA;AAAA,EAC5C;AACF","file":"diff.cjs","sourcesContent":["/**\n * Collection ID generation utilities for PocketBase migrations\n */\n\nimport { createHash, randomBytes } from \"crypto\";\n\n/**\n * Generates a unique collection ID in PocketBase format\n * Format: pb_ followed by 15 alphanumeric lowercase characters\n *\n * @returns A unique collection ID string (e.g., \"pb_a1b2c3d4e5f6g7h\")\n */\nexport function generateCollectionId(): string {\n const chars = \"abcdefghijklmnopqrstuvwxyz0123456789\";\n const idLength = 15;\n\n // Generate cryptographically secure random bytes\n const bytes = randomBytes(idLength);\n\n // Convert bytes to alphanumeric characters\n let id = \"pb_\";\n for (let i = 0; i < idLength; i++) {\n const index = bytes[i] % chars.length;\n id += chars[index];\n }\n\n return id;\n}\n\n/**\n * Generates a unique field ID based on type and name\n * Format: type followed by 10 alphanumeric lowercase characters\n * If name is provided, the ID is deterministic\n *\n * @param type - PocketBase field type\n * @param name - Optional field name for deterministic ID\n * @returns A unique field ID string\n */\nexport function generateFieldId(type: string, name?: string): string {\n const chars = \"abcdefghijklmnopqrstuvwxyz0123456789\";\n const idLength = 10;\n\n let bytes: Buffer | Uint8Array;\n if (name) {\n // Deterministic based on name to ensure stability across runs\n bytes = createHash(\"sha256\").update(name).digest();\n } else {\n // Random\n bytes = randomBytes(idLength);\n }\n\n // Convert bytes to alphanumeric characters\n let suffix = \"\";\n for (let i = 0; i < idLength; i++) {\n const index = bytes[i] % chars.length;\n suffix += chars[index];\n }\n\n return `${type}${suffix}`;\n}\n\n/**\n * Registry to track generated collection IDs and ensure uniqueness within a migration batch\n */\nexport class CollectionIdRegistry {\n private ids: Set<string>;\n\n constructor() {\n this.ids = new Set<string>();\n }\n\n /**\n * Generates a unique collection ID for a given collection name\n * Retries up to 10 times if collision occurs (extremely rare)\n * Special case: returns \"_pb_users_auth_\" for users collection\n *\n * @param collectionName - The name of the collection (optional)\n * @returns A unique collection ID\n * @throws Error if unable to generate unique ID after max attempts\n */\n generate(collectionName?: string): string {\n // Special case: users collection always uses the constant\n if (collectionName && collectionName.toLowerCase() === \"users\") {\n const usersId = \"_pb_users_auth_\";\n if (!this.has(usersId)) {\n this.register(usersId);\n }\n return usersId;\n }\n\n const maxAttempts = 10;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n const id = generateCollectionId();\n\n if (!this.has(id)) {\n this.register(id);\n return id;\n }\n }\n\n throw new Error(\"Failed to generate unique collection ID after maximum attempts\");\n }\n\n /**\n * Checks if an ID has already been registered\n *\n * @param id - The collection ID to check\n * @returns True if the ID exists in the registry\n */\n has(id: string): boolean {\n return this.ids.has(id);\n }\n\n /**\n * Registers a collection ID in the registry\n *\n * @param id - The collection ID to register\n */\n register(id: string): void {\n this.ids.add(id);\n }\n}\n","/**\n * Configuration options for the diff engine\n */\nexport interface DiffEngineConfig {\n /**\n * Whether to warn on collection deletions\n * Defaults to true\n */\n warnOnDelete?: boolean;\n\n /**\n * Whether to require --force flag for destructive changes\n * Defaults to true\n */\n requireForceForDestructive?: boolean;\n\n /**\n * Severity threshold for requiring force flag\n * 'high' = only collection/field deletions and type changes\n * 'medium' = includes making fields required\n * 'low' = includes any constraint changes\n * Defaults to 'high'\n */\n severityThreshold?: \"high\" | \"medium\" | \"low\";\n\n /**\n * Custom system collections to exclude from diff\n * These collections will not be created or deleted\n */\n systemCollections?: string[];\n\n /**\n * Custom system fields to exclude from user collection diffs\n * These fields will not be included in fieldsToAdd for the users collection\n */\n usersSystemFields?: string[];\n}\n\n/**\n * Default configuration values\n */\nexport const DEFAULT_CONFIG: Required<DiffEngineConfig> = {\n warnOnDelete: true,\n requireForceForDestructive: true,\n severityThreshold: \"high\",\n systemCollections: [\"_mfas\", \"_otps\", \"_externalAuths\", \"_authOrigins\", \"_superusers\"],\n usersSystemFields: [\"id\", \"password\", \"tokenKey\", \"email\", \"emailVisibility\", \"verified\", \"created\", \"updated\"],\n};\n\n/**\n * Merges user config with defaults\n */\nexport function mergeConfig(config?: DiffEngineConfig): Required<DiffEngineConfig> {\n return {\n ...DEFAULT_CONFIG,\n ...config,\n };\n}\n","import { mergeConfig, type DiffEngineConfig } from \"./config\";\n\n/**\n * Checks if a collection is a PocketBase system collection\n * System collections are internal to PocketBase and should not be created or deleted\n *\n * @param collectionName - Name of the collection to check\n * @param config - Optional configuration with custom system collections\n * @returns True if the collection is a system collection\n */\nexport function isSystemCollection(collectionName: string, config?: DiffEngineConfig): boolean {\n const mergedConfig = mergeConfig(config);\n return mergedConfig.systemCollections.includes(collectionName);\n}\n\n/**\n * Returns the list of system field names for the users collection\n * These fields are automatically provided by PocketBase for auth collections\n * and should not be included when generating migrations for users collection extensions\n *\n * @param config - Optional configuration with custom system fields\n * @returns Set of system field names\n */\nexport function getUsersSystemFields(config?: DiffEngineConfig): Set<string> {\n const mergedConfig = mergeConfig(config);\n return new Set(mergedConfig.usersSystemFields);\n}\n\n/**\n * Compares two values for equality, handling deep object comparison\n *\n * @param a - First value\n * @param b - Second value\n * @returns True if values are equal\n */\nexport function areValuesEqual(a: any, b: any): boolean {\n // Handle null/undefined\n if (a === b) return true;\n if (a == null || b == null) return false;\n\n // Handle arrays\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n return a.every((val, idx) => areValuesEqual(val, b[idx]));\n }\n\n // Handle objects\n if (typeof a === \"object\" && typeof b === \"object\") {\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n\n if (keysA.length !== keysB.length) return false;\n\n return keysA.every((key) => areValuesEqual(a[key], b[key]));\n }\n\n // Primitive comparison\n return a === b;\n}\n\n/**\n * Normalizes a field option value to account for PocketBase defaults\n * Returns the normalized value, treating default values as equivalent to undefined\n *\n * @param key - Option key name\n * @param value - Option value\n * @param fieldType - Field type\n * @returns Normalized value (undefined if it's a default value)\n */\nexport function normalizeOptionValue(key: string, value: any, fieldType: string): any {\n // maxSelect: 1 is the default for select and file fields\n if (key === \"maxSelect\" && value === 1 && (fieldType === \"select\" || fieldType === \"file\")) {\n return undefined; // Treat as undefined to match missing default\n }\n\n // maxSize: 0 is default for file fields\n if (key === \"maxSize\" && value === 0 && fieldType === \"file\") {\n return undefined;\n }\n\n // min: 1 can be a default for some PocketBase versions/number fields\n if (key === \"min\" && value === 1 && fieldType === \"number\") {\n return undefined;\n }\n\n // Empty arrays are defaults for file fields\n if (fieldType === \"file\") {\n if (key === \"mimeTypes\" && Array.isArray(value) && value.length === 0) {\n return undefined;\n }\n if (key === \"thumbs\" && Array.isArray(value) && value.length === 0) {\n return undefined;\n }\n if (key === \"protected\" && value === false) {\n return undefined;\n }\n }\n\n // Autodate defaults\n if (fieldType === \"autodate\") {\n if (key === \"onCreate\" && value === true) {\n return undefined;\n }\n if (key === \"onUpdate\" && value === false) {\n return undefined;\n }\n }\n\n return value;\n}\n","import type { FieldChange, FieldDefinition } from \"../types\";\nimport { areValuesEqual, normalizeOptionValue } from \"./utils\";\n\n/**\n * Identifies new fields in current collection that don't exist in previous\n *\n * @param currentFields - Current collection fields\n * @param previousFields - Previous collection fields\n * @returns Array of new fields\n */\nexport function findNewFields(currentFields: FieldDefinition[], previousFields: FieldDefinition[]): FieldDefinition[] {\n const newFields: FieldDefinition[] = [];\n const previousFieldNames = new Set(previousFields.map((f) => f.name));\n\n for (const currentField of currentFields) {\n if (!previousFieldNames.has(currentField.name)) {\n newFields.push(currentField);\n }\n }\n\n return newFields;\n}\n\n/**\n * Identifies fields removed from current collection (exist in previous but not in current)\n *\n * @param currentFields - Current collection fields\n * @param previousFields - Previous collection fields\n * @returns Array of removed fields\n */\nexport function findRemovedFields(\n currentFields: FieldDefinition[],\n previousFields: FieldDefinition[]\n): FieldDefinition[] {\n const removedFields: FieldDefinition[] = [];\n const currentFieldNames = new Set(currentFields.map((f) => f.name));\n\n for (const previousField of previousFields) {\n if (!currentFieldNames.has(previousField.name)) {\n removedFields.push(previousField);\n }\n }\n\n return removedFields;\n}\n\n/**\n * Matches fields by name between current and previous collections\n * Returns pairs of [current, previous] for fields that exist in both\n *\n * @param currentFields - Current collection fields\n * @param previousFields - Previous collection fields\n * @returns Array of matched field pairs\n */\nexport function matchFieldsByName(\n currentFields: FieldDefinition[],\n previousFields: FieldDefinition[]\n): Array<[FieldDefinition, FieldDefinition]> {\n const matches: Array<[FieldDefinition, FieldDefinition]> = [];\n\n // Create a map of previous fields by name for efficient lookup\n const previousFieldMap = new Map<string, FieldDefinition>();\n for (const previousField of previousFields) {\n previousFieldMap.set(previousField.name, previousField);\n }\n\n // Find matching fields\n for (const currentField of currentFields) {\n const previousField = previousFieldMap.get(currentField.name);\n\n if (previousField) {\n matches.push([currentField, previousField]);\n }\n }\n\n return matches;\n}\n\n/**\n * Compares field types between current and previous\n *\n * @param currentField - Current field definition\n * @param previousField - Previous field definition\n * @returns FieldChange if types differ, null otherwise\n */\nexport function compareFieldTypes(currentField: FieldDefinition, previousField: FieldDefinition): FieldChange | null {\n if (currentField.type !== previousField.type) {\n return {\n property: \"type\",\n oldValue: previousField.type,\n newValue: currentField.type,\n };\n }\n\n return null;\n}\n\n/**\n * Compares field constraints (required, unique) between current and previous\n *\n * @param currentField - Current field definition\n * @param previousField - Previous field definition\n * @returns Array of FieldChange for constraint differences\n */\nexport function compareFieldConstraints(currentField: FieldDefinition, previousField: FieldDefinition): FieldChange[] {\n const changes: FieldChange[] = [];\n\n // Compare required constraint\n if (currentField.required !== previousField.required) {\n changes.push({\n property: \"required\",\n oldValue: previousField.required,\n newValue: currentField.required,\n });\n }\n\n // Compare unique constraint\n if (currentField.unique !== previousField.unique) {\n changes.push({\n property: \"unique\",\n oldValue: previousField.unique,\n newValue: currentField.unique,\n });\n }\n\n return changes;\n}\n\n/**\n * Compares field options (min, max, pattern, etc.) between current and previous\n *\n * @param currentField - Current field definition\n * @param previousField - Previous field definition\n * @returns Array of FieldChange for option differences\n */\nexport function compareFieldOptions(currentField: FieldDefinition, previousField: FieldDefinition): FieldChange[] {\n const changes: FieldChange[] = [];\n\n const currentOptions = currentField.options || {};\n const previousOptions = previousField.options || {};\n\n // Get all unique option keys\n const allKeys = new Set([...Object.keys(currentOptions), ...Object.keys(previousOptions)]);\n\n // Compare each option\n // Use currentField.type for normalization since types should match at this point\n // (type changes are handled separately in compareFieldTypes)\n const fieldType = currentField.type;\n\n for (const key of allKeys) {\n const currentValue = currentOptions[key];\n const previousValue = previousOptions[key];\n\n // Normalize values to account for default values\n // This ensures that maxSelect: 1 (default) is treated the same as undefined (missing default)\n const normalizedCurrent = normalizeOptionValue(key, currentValue, fieldType);\n const normalizedPrevious = normalizeOptionValue(key, previousValue, fieldType);\n\n // Handle undefined values - if both are undefined (or normalized to undefined), that's not a change\n if (normalizedCurrent === undefined && normalizedPrevious === undefined) {\n continue;\n }\n\n if (!areValuesEqual(normalizedCurrent, normalizedPrevious)) {\n changes.push({\n property: `options.${key}`,\n oldValue: previousValue,\n newValue: currentValue,\n });\n }\n }\n\n return changes;\n}\n\n/**\n * Compares relation configurations between current and previous\n *\n * @param currentField - Current field definition\n * @param previousField - Previous field definition\n * @returns Array of FieldChange for relation differences\n */\nexport function compareRelationConfigurations(\n currentField: FieldDefinition,\n previousField: FieldDefinition,\n collectionIdToName?: Map<string, string>\n): FieldChange[] {\n const changes: FieldChange[] = [];\n\n const currentRelation = currentField.relation;\n const previousRelation = previousField.relation;\n\n // If one has relation and other doesn't, that's not a config change (handled elsewhere, likely type or structure)\n // But here we assume types match (both relation) or structure implies relation\n if (!currentRelation && !previousRelation) {\n return changes;\n }\n\n if (!currentRelation || !previousRelation) {\n // This shouldn't happen if types match and both are 'relation', but handle gracefully\n return changes;\n }\n\n // Compare relation properties\n // Note: collectionId should already be resolved to collection name during parsing\n // This normalization is just a safety net for edge cases\n const normalizeCollection = (collection: string): string => {\n if (!collection) return collection;\n\n // Resolve ID to name if possible\n if (collectionIdToName && collectionIdToName.has(collection)) {\n return collectionIdToName.get(collection)!;\n }\n\n // Handle expressions that might not have been parsed correctly\n const nameMatch = collection.match(/app\\.findCollectionByNameOrId\\s*\\(\\s*[\"']([^\"']+)[\"']\\s*\\)/);\n if (nameMatch) {\n return nameMatch[1];\n }\n return collection;\n };\n\n const normalizedCurrent = normalizeCollection(currentRelation.collection);\n // We resolve the ID from the previous relation (snapshot) to its name if available\n const normalizedPrevious = normalizeCollection(previousRelation.collection);\n\n // Only report a change if the normalized values differ\n // Use case-insensitive comparison for collection names\n if (normalizedCurrent.toLowerCase() !== normalizedPrevious.toLowerCase()) {\n changes.push({\n property: \"relation.collection\",\n oldValue: previousRelation.collection,\n newValue: currentRelation.collection,\n });\n }\n\n if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {\n changes.push({\n property: \"relation.cascadeDelete\",\n oldValue: previousRelation.cascadeDelete,\n newValue: currentRelation.cascadeDelete,\n });\n }\n\n // Normalize maxSelect: 1 to undefined/null as it's often the default or treated as such\n const normalizeMax = (val: number | null | undefined) => (val === 1 ? null : val);\n const currentMax = normalizeMax(currentRelation.maxSelect);\n const previousMax = normalizeMax(previousRelation.maxSelect);\n\n // Use loose equality to handle null vs undefined\n if (currentMax != previousMax) {\n changes.push({\n property: \"relation.maxSelect\",\n oldValue: previousRelation.maxSelect,\n newValue: currentRelation.maxSelect,\n });\n }\n\n // Normalize minSelect: 0 to undefined/null\n const normalizeMin = (val: number | null | undefined) => (val === 0 ? null : val);\n const currentMin = normalizeMin(currentRelation.minSelect);\n const previousMin = normalizeMin(previousRelation.minSelect);\n\n if (currentMin != previousMin) {\n changes.push({\n property: \"relation.minSelect\",\n oldValue: previousRelation.minSelect,\n newValue: currentRelation.minSelect,\n });\n }\n\n return changes;\n}\n\n/**\n * Detects all changes between two field definitions\n * Combines type, constraint, option, and relation changes\n *\n * @param currentField - Current field definition\n * @param previousField - Previous field definition\n * @returns Array of all detected changes\n */\nexport function detectFieldChanges(\n currentField: FieldDefinition,\n previousField: FieldDefinition,\n collectionIdToName?: Map<string, string>\n): FieldChange[] {\n const changes: FieldChange[] = [];\n\n // Compare types\n const typeChange = compareFieldTypes(currentField, previousField);\n if (typeChange) {\n changes.push(typeChange);\n }\n\n // Compare constraints\n changes.push(...compareFieldConstraints(currentField, previousField));\n\n // Compare options\n changes.push(...compareFieldOptions(currentField, previousField));\n\n // Compare relation configurations (if applicable)\n if (currentField.type === \"relation\" && previousField.type === \"relation\") {\n changes.push(...compareRelationConfigurations(currentField, previousField, collectionIdToName));\n }\n\n return changes;\n}\n","/**\n * Compares indexes between current and previous collections\n *\n * @param currentIndexes - Current collection indexes\n * @param previousIndexes - Previous collection indexes\n * @returns Object with indexes to add and remove\n */\nexport function compareIndexes(\n currentIndexes: string[] = [],\n previousIndexes: string[] = []\n): { indexesToAdd: string[]; indexesToRemove: string[] } {\n const currentSet = new Set(currentIndexes);\n const previousSet = new Set(previousIndexes);\n\n const indexesToAdd = currentIndexes.filter((idx) => !previousSet.has(idx));\n const indexesToRemove = previousIndexes.filter((idx) => !currentSet.has(idx));\n\n return { indexesToAdd, indexesToRemove };\n}\n","import type { APIRuleType, CollectionSchema, PermissionChange, RuleUpdate } from \"../types\";\n\n/**\n * Compares API rules between current and previous collections\n *\n * @param currentRules - Current collection rules\n * @param previousRules - Previous collection rules\n * @returns Array of rule updates\n */\nexport function compareRules(\n currentRules: CollectionSchema[\"rules\"],\n previousRules: CollectionSchema[\"rules\"],\n currentPermissions?: CollectionSchema[\"permissions\"],\n previousPermissions?: CollectionSchema[\"permissions\"]\n): RuleUpdate[] {\n const updates: RuleUpdate[] = [];\n\n const ruleTypes: Array<keyof NonNullable<CollectionSchema[\"rules\"]>> = [\n \"listRule\",\n \"viewRule\",\n \"createRule\",\n \"updateRule\",\n \"deleteRule\",\n \"manageRule\",\n ];\n\n for (const ruleType of ruleTypes) {\n // Use rules if available, otherwise fall back to permissions (they're the same thing)\n const currentValue = currentRules?.[ruleType] ?? currentPermissions?.[ruleType] ?? null;\n const previousValue = previousRules?.[ruleType] ?? previousPermissions?.[ruleType] ?? null;\n\n if (currentValue !== previousValue) {\n updates.push({\n ruleType: ruleType as RuleUpdate[\"ruleType\"],\n oldValue: previousValue,\n newValue: currentValue,\n });\n }\n }\n\n return updates;\n}\n\n/**\n * Compares permissions between current and previous collections\n * Detects changes in permission rules defined in schema\n *\n * @param currentPermissions - Current collection permissions\n * @param previousPermissions - Previous collection permissions\n * @returns Array of permission changes\n */\nexport function comparePermissions(\n currentPermissions: CollectionSchema[\"permissions\"],\n previousPermissions: CollectionSchema[\"permissions\"]\n): PermissionChange[] {\n const changes: PermissionChange[] = [];\n\n const ruleTypes: APIRuleType[] = [\"listRule\", \"viewRule\", \"createRule\", \"updateRule\", \"deleteRule\", \"manageRule\"];\n\n for (const ruleType of ruleTypes) {\n const currentValue = currentPermissions?.[ruleType] ?? null;\n const previousValue = previousPermissions?.[ruleType] ?? null;\n\n // Compare permission values\n if (currentValue !== previousValue) {\n changes.push({\n ruleType,\n oldValue: previousValue,\n newValue: currentValue,\n });\n }\n }\n\n return changes;\n}\n","import type {\n CollectionModification,\n CollectionSchema,\n FieldDefinition,\n FieldModification,\n SchemaDefinition,\n SchemaSnapshot,\n} from \"../types\";\nimport { type DiffEngineConfig } from \"./config\";\nimport { detectFieldChanges, findNewFields, findRemovedFields, matchFieldsByName } from \"./fields\";\nimport { compareIndexes } from \"./indexes\";\nimport { comparePermissions, compareRules } from \"./rules\";\nimport { getUsersSystemFields, isSystemCollection } from \"./utils\";\n\n/**\n * Filters system collections from a schema definition\n * Returns a new SchemaDefinition with only custom (non-system) collections\n *\n * @param schema - Schema definition to filter\n * @param config - Optional configuration\n * @returns Filtered SchemaDefinition without system collections\n */\nexport function filterSystemCollections(schema: SchemaDefinition, config?: DiffEngineConfig): SchemaDefinition {\n const filteredCollections = new Map<string, CollectionSchema>();\n\n for (const [collectionName, collectionSchema] of schema.collections) {\n if (!isSystemCollection(collectionName, config)) {\n filteredCollections.set(collectionName, collectionSchema);\n }\n }\n\n return {\n collections: filteredCollections,\n };\n}\n\n/**\n * Identifies new collections in schema that don't exist in snapshot\n *\n * @param currentSchema - Current schema definition\n * @param previousSnapshot - Previous schema snapshot\n * @returns Array of new collections\n */\nexport function findNewCollections(\n currentSchema: SchemaDefinition,\n previousSnapshot: SchemaSnapshot | null\n): CollectionSchema[] {\n const newCollections: CollectionSchema[] = [];\n\n // If no previous snapshot, all collections are new\n if (!previousSnapshot) {\n return Array.from(currentSchema.collections.values());\n }\n\n // Find collections in current schema that don't exist in snapshot\n for (const [collectionName, collectionSchema] of currentSchema.collections) {\n if (!previousSnapshot.collections.has(collectionName)) {\n newCollections.push(collectionSchema);\n }\n }\n\n return newCollections;\n}\n\n/**\n * Identifies collections removed from schema (exist in snapshot but not in current schema)\n *\n * @param currentSchema - Current schema definition\n * @param previousSnapshot - Previous schema snapshot\n * @returns Array of removed collections\n */\nexport function findRemovedCollections(\n currentSchema: SchemaDefinition,\n previousSnapshot: SchemaSnapshot | null\n): CollectionSchema[] {\n const removedCollections: CollectionSchema[] = [];\n\n // If no previous snapshot, nothing can be removed\n if (!previousSnapshot) {\n return removedCollections;\n }\n\n // Find collections in snapshot that don't exist in current schema\n for (const [collectionName, collectionSchema] of previousSnapshot.collections) {\n if (!currentSchema.collections.has(collectionName)) {\n removedCollections.push(collectionSchema);\n }\n }\n\n return removedCollections;\n}\n\n/**\n * Matches collections by name between current schema and snapshot\n * Returns pairs of [current, previous] for collections that exist in both\n *\n * @param currentSchema - Current schema definition\n * @param previousSnapshot - Previous schema snapshot\n * @returns Array of matched collection pairs\n */\nexport function matchCollectionsByName(\n currentSchema: SchemaDefinition,\n previousSnapshot: SchemaSnapshot | null\n): Array<[CollectionSchema, CollectionSchema]> {\n const matches: Array<[CollectionSchema, CollectionSchema]> = [];\n\n // If no previous snapshot, no matches possible\n if (!previousSnapshot) {\n return matches;\n }\n\n // Create a case-insensitive lookup map for previous collections\n const previousCollectionsLower = new Map<string, [string, CollectionSchema]>();\n for (const [name, collection] of previousSnapshot.collections) {\n previousCollectionsLower.set(name.toLowerCase(), [name, collection]);\n }\n\n // Find collections that exist in both current and previous (case-insensitive)\n for (const [collectionName, currentCollection] of currentSchema.collections) {\n const previousEntry = previousCollectionsLower.get(collectionName.toLowerCase());\n\n if (previousEntry) {\n const [, previousCollection] = previousEntry;\n matches.push([currentCollection, previousCollection]);\n }\n }\n\n return matches;\n}\n\n/**\n * Compares fields between current and previous collections\n * Identifies new, removed, and modified fields\n * For the users collection, filters out system fields from fieldsToAdd\n *\n * @param currentCollection - Current collection schema\n * @param previousCollection - Previous collection schema\n * @param config - Optional configuration\n * @returns Object with field changes\n */\nfunction compareCollectionFields(\n currentCollection: CollectionSchema,\n previousCollection: CollectionSchema,\n config?: DiffEngineConfig,\n collectionIdToName?: Map<string, string>\n): {\n fieldsToAdd: FieldDefinition[];\n fieldsToRemove: FieldDefinition[];\n fieldsToModify: FieldModification[];\n} {\n let fieldsToAdd = findNewFields(currentCollection.fields, previousCollection.fields);\n let fieldsToRemove = findRemovedFields(currentCollection.fields, previousCollection.fields);\n const fieldsToModify: FieldModification[] = [];\n\n // For users collection, filter out system fields from fieldsToAdd\n // System fields are automatically provided by PocketBase and should not be in migrations\n if (currentCollection.name === \"users\") {\n const systemFields = getUsersSystemFields(config);\n fieldsToAdd = fieldsToAdd.filter((field) => !systemFields.has(field.name));\n }\n\n // Check for modified fields\n const matchedFields = matchFieldsByName(currentCollection.fields, previousCollection.fields);\n\n for (const [currentField, previousField] of matchedFields) {\n const changes = detectFieldChanges(currentField, previousField, collectionIdToName);\n\n if (changes.length > 0) {\n fieldsToModify.push({\n fieldName: currentField.name,\n currentDefinition: previousField,\n newDefinition: currentField,\n changes,\n });\n }\n }\n\n // Detect Renames (Heuristic)\n // If we have single removed and added fields of the same type, consider it a rename\n const processedAddIndices = new Set<number>();\n const processedRemoveIndices = new Set<number>();\n\n // Helper to resolve collection name from ID/expression\n const resolveCollectionName = (val: string): string => {\n if (!val) return val;\n if (collectionIdToName && collectionIdToName.has(val)) return collectionIdToName.get(val)!;\n const match = val.match(/app\\.findCollectionByNameOrId\\s*\\(\\s*[\"']([^\"']+)[\"']\\s*\\)/);\n return match ? match[1] : val;\n };\n\n // Group fields by type\n const addedByType = new Map<string, number[]>();\n fieldsToAdd.forEach((field, index) => {\n const type = field.type;\n if (!addedByType.has(type)) addedByType.set(type, []);\n addedByType.get(type)!.push(index);\n });\n\n const removedByType = new Map<string, number[]>();\n fieldsToRemove.forEach((field, index) => {\n const type = field.type;\n if (!removedByType.has(type)) removedByType.set(type, []);\n removedByType.get(type)!.push(index);\n });\n\n // Check each type for potential renames\n for (const [type, removedIndices] of removedByType) {\n const addedIndices = addedByType.get(type);\n\n // Heuristic: Only rename if exactly one field of this type was removed and one added\n if (addedIndices && addedIndices.length === 1 && removedIndices.length === 1) {\n const addedIndex = addedIndices[0];\n const removedIndex = removedIndices[0];\n const addedField = fieldsToAdd[addedIndex];\n const removedField = fieldsToRemove[removedIndex];\n\n // For relations, ensure target collection matches\n let isMatch = true;\n if (type === \"relation\") {\n const addedTarget = resolveCollectionName(addedField.relation?.collection || \"\");\n const removedTarget = resolveCollectionName(removedField.relation?.collection || \"\");\n if (addedTarget.toLowerCase() !== removedTarget.toLowerCase()) {\n isMatch = false;\n }\n }\n\n if (isMatch) {\n // It's a rename!\n processedAddIndices.add(addedIndex);\n processedRemoveIndices.add(removedIndex);\n\n // Calculate changes (including name change)\n const changes = detectFieldChanges(addedField, removedField, collectionIdToName);\n changes.push({\n property: \"name\",\n oldValue: removedField.name,\n newValue: addedField.name,\n });\n\n fieldsToModify.push({\n fieldName: removedField.name, // Use OLD name so generator can find it\n currentDefinition: removedField, // OLD definition\n newDefinition: addedField, // NEW definition\n changes,\n });\n }\n }\n }\n\n // Filter out processed fields\n fieldsToAdd = fieldsToAdd.filter((_, index) => !processedAddIndices.has(index));\n fieldsToRemove = fieldsToRemove.filter((_, index) => !processedRemoveIndices.has(index));\n\n return { fieldsToAdd, fieldsToRemove, fieldsToModify };\n}\n\n/**\n * Builds a CollectionModification for a matched collection pair\n *\n * @param currentCollection - Current collection schema\n * @param previousCollection - Previous collection schema\n * @param config - Optional configuration\n * @returns CollectionModification object\n */\nexport function buildCollectionModification(\n currentCollection: CollectionSchema,\n previousCollection: CollectionSchema,\n config?: DiffEngineConfig,\n collectionIdToName?: Map<string, string>\n): CollectionModification {\n // Compare fields\n const { fieldsToAdd, fieldsToRemove, fieldsToModify } = compareCollectionFields(\n currentCollection,\n previousCollection,\n config,\n collectionIdToName\n );\n\n // Compare indexes\n const { indexesToAdd, indexesToRemove } = compareIndexes(currentCollection.indexes, previousCollection.indexes);\n\n // Compare rules (also check permissions as fallback since they're the same thing)\n const rulesToUpdate = compareRules(\n currentCollection.rules,\n previousCollection.rules,\n currentCollection.permissions,\n previousCollection.permissions\n );\n\n // Compare permissions\n const permissionsToUpdate = comparePermissions(currentCollection.permissions, previousCollection.permissions);\n\n return {\n collection: currentCollection.name,\n fieldsToAdd,\n fieldsToRemove,\n fieldsToModify,\n indexesToAdd,\n indexesToRemove,\n rulesToUpdate,\n permissionsToUpdate,\n };\n}\n","import type { SchemaDiff } from \"../types\";\nimport { mergeConfig, type DiffEngineConfig } from \"./config\";\n\n/**\n * Destructive change information\n */\nexport interface DestructiveChange {\n type: \"collection_delete\" | \"field_delete\" | \"type_change\" | \"required_change\" | \"constraint_change\";\n severity: \"high\" | \"medium\" | \"low\";\n collection: string;\n field?: string;\n description: string;\n oldValue?: any;\n newValue?: any;\n}\n\n/**\n * Detects destructive changes in a schema diff\n * Returns detailed information about each destructive change\n *\n * @param diff - Schema diff to analyze\n * @param config - Optional configuration for severity thresholds\n * @returns Array of destructive changes with severity information\n */\nexport function detectDestructiveChanges(diff: SchemaDiff, config?: DiffEngineConfig): DestructiveChange[] {\n const destructiveChanges: DestructiveChange[] = [];\n const mergedConfig = mergeConfig(config);\n\n // Collection deletions are always high severity\n for (const collection of diff.collectionsToDelete) {\n destructiveChanges.push({\n type: \"collection_delete\",\n severity: \"high\",\n collection: collection.name,\n description: `Delete collection: ${collection.name}`,\n });\n }\n\n // Analyze modifications\n for (const modification of diff.collectionsToModify) {\n const collectionName = modification.collection;\n\n // Field deletions are high severity\n for (const field of modification.fieldsToRemove) {\n destructiveChanges.push({\n type: \"field_delete\",\n severity: \"high\",\n collection: collectionName,\n field: field.name,\n description: `Delete field: ${collectionName}.${field.name}`,\n });\n }\n\n // Field modifications can be various severities\n for (const fieldMod of modification.fieldsToModify) {\n const typeChange = fieldMod.changes.find((c) => c.property === \"type\");\n const requiredChange = fieldMod.changes.find((c) => c.property === \"required\" && c.newValue === true);\n\n if (typeChange) {\n destructiveChanges.push({\n type: \"type_change\",\n severity: \"high\",\n collection: collectionName,\n field: fieldMod.fieldName,\n description: `Change field type: ${collectionName}.${fieldMod.fieldName} (${typeChange.oldValue} → ${typeChange.newValue})`,\n oldValue: typeChange.oldValue,\n newValue: typeChange.newValue,\n });\n }\n\n if (requiredChange && mergedConfig.severityThreshold !== \"high\") {\n destructiveChanges.push({\n type: \"required_change\",\n severity: \"medium\",\n collection: collectionName,\n field: fieldMod.fieldName,\n description: `Make field required: ${collectionName}.${fieldMod.fieldName}`,\n oldValue: false,\n newValue: true,\n });\n }\n\n // Other constraint changes at low severity\n if (mergedConfig.severityThreshold === \"low\") {\n const otherChanges = fieldMod.changes.filter((c) => c.property !== \"type\" && c.property !== \"required\");\n for (const change of otherChanges) {\n destructiveChanges.push({\n type: \"constraint_change\",\n severity: \"low\",\n collection: collectionName,\n field: fieldMod.fieldName,\n description: `Change constraint: ${collectionName}.${fieldMod.fieldName}.${change.property}`,\n oldValue: change.oldValue,\n newValue: change.newValue,\n });\n }\n }\n }\n }\n\n return destructiveChanges;\n}\n\n/**\n * Checks if a diff requires the --force flag based on configuration\n *\n * @param diff - Schema diff to check\n * @param config - Configuration with severity threshold\n * @returns True if force flag is required\n */\nexport function requiresForceFlag(diff: SchemaDiff, config?: DiffEngineConfig): boolean {\n const mergedConfig = mergeConfig(config);\n\n if (!mergedConfig.requireForceForDestructive) {\n return false;\n }\n\n const destructiveChanges = detectDestructiveChanges(diff, config);\n\n // Filter by severity threshold\n const relevantChanges = destructiveChanges.filter((change) => {\n switch (mergedConfig.severityThreshold) {\n case \"high\":\n return change.severity === \"high\";\n case \"medium\":\n return change.severity === \"high\" || change.severity === \"medium\";\n case \"low\":\n return true;\n default:\n return change.severity === \"high\";\n }\n });\n\n return relevantChanges.length > 0;\n}\n","import type { SchemaDiff } from \"../types\";\nimport { type DiffEngineConfig } from \"./config\";\nimport { detectDestructiveChanges, type DestructiveChange } from \"./destructiveness\";\n\n/**\n * Change summary for status reporting\n */\nexport interface ChangeSummary {\n totalChanges: number;\n collectionsToCreate: number;\n collectionsToDelete: number;\n collectionsToModify: number;\n fieldsToAdd: number;\n fieldsToRemove: number;\n fieldsToModify: number;\n indexChanges: number;\n ruleChanges: number;\n permissionChanges: number;\n destructiveChanges: DestructiveChange[];\n nonDestructiveChanges: string[];\n}\n\n/**\n * Categorizes changes by severity\n * Returns object with destructive and non-destructive changes\n *\n * @param diff - Schema diff to categorize\n * @param config - Optional configuration\n * @returns Object with categorized changes\n */\nexport function categorizeChangesBySeverity(\n diff: SchemaDiff,\n _config?: DiffEngineConfig\n): {\n destructive: string[];\n nonDestructive: string[];\n} {\n const destructive: string[] = [];\n const nonDestructive: string[] = [];\n\n // Collection deletions are destructive\n for (const collection of diff.collectionsToDelete) {\n destructive.push(`Delete collection: ${collection.name}`);\n }\n\n // Collection creations are non-destructive\n for (const collection of diff.collectionsToCreate) {\n nonDestructive.push(`Create collection: ${collection.name}`);\n }\n\n // Analyze modifications\n for (const modification of diff.collectionsToModify) {\n const collectionName = modification.collection;\n\n // Field deletions are destructive\n for (const field of modification.fieldsToRemove) {\n destructive.push(`Delete field: ${collectionName}.${field.name}`);\n }\n\n // Field additions are non-destructive\n for (const field of modification.fieldsToAdd) {\n nonDestructive.push(`Add field: ${collectionName}.${field.name}`);\n }\n\n // Field modifications can be destructive or non-destructive\n for (const fieldMod of modification.fieldsToModify) {\n const hasTypeChange = fieldMod.changes.some((c) => c.property === \"type\");\n const hasRequiredChange = fieldMod.changes.some((c) => c.property === \"required\" && c.newValue === true);\n\n if (hasTypeChange) {\n destructive.push(\n `Change field type: ${collectionName}.${fieldMod.fieldName} (${fieldMod.changes.find((c) => c.property === \"type\")?.oldValue} → ${fieldMod.changes.find((c) => c.property === \"type\")?.newValue})`\n );\n } else if (hasRequiredChange) {\n destructive.push(`Make field required: ${collectionName}.${fieldMod.fieldName}`);\n } else {\n nonDestructive.push(`Modify field: ${collectionName}.${fieldMod.fieldName}`);\n }\n }\n\n // Index changes are generally non-destructive\n for (const _index of modification.indexesToAdd) {\n nonDestructive.push(`Add index: ${collectionName}`);\n }\n\n for (const _index of modification.indexesToRemove) {\n nonDestructive.push(`Remove index: ${collectionName}`);\n }\n\n // Rule changes are non-destructive\n for (const rule of modification.rulesToUpdate) {\n nonDestructive.push(`Update rule: ${collectionName}.${rule.ruleType}`);\n }\n }\n\n return { destructive, nonDestructive };\n}\n\n/**\n * Generates a summary of all changes in a diff\n * Useful for status reporting and user feedback\n *\n * @param diff - Schema diff to summarize\n * @param config - Optional configuration\n * @returns Change summary with counts and details\n */\nexport function generateChangeSummary(diff: SchemaDiff, config?: DiffEngineConfig): ChangeSummary {\n const destructiveChanges = detectDestructiveChanges(diff, config);\n const { nonDestructive } = categorizeChangesBySeverity(diff, config);\n\n let fieldsToAdd = 0;\n let fieldsToRemove = 0;\n let fieldsToModify = 0;\n let indexChanges = 0;\n let ruleChanges = 0;\n let permissionChanges = 0;\n\n for (const modification of diff.collectionsToModify) {\n fieldsToAdd += modification.fieldsToAdd.length;\n fieldsToRemove += modification.fieldsToRemove.length;\n fieldsToModify += modification.fieldsToModify.length;\n indexChanges += modification.indexesToAdd.length + modification.indexesToRemove.length;\n ruleChanges += modification.rulesToUpdate.length;\n permissionChanges += modification.permissionsToUpdate.length;\n }\n\n return {\n totalChanges: diff.collectionsToCreate.length + diff.collectionsToDelete.length + diff.collectionsToModify.length,\n collectionsToCreate: diff.collectionsToCreate.length,\n collectionsToDelete: diff.collectionsToDelete.length,\n collectionsToModify: diff.collectionsToModify.length,\n fieldsToAdd,\n fieldsToRemove,\n fieldsToModify,\n indexChanges,\n ruleChanges,\n permissionChanges,\n destructiveChanges,\n nonDestructiveChanges: nonDestructive,\n };\n}\n","import type { SchemaDiff, FieldModification } from \"../types\";\n\nexport interface FilterOptions {\n patterns?: string[];\n skipDestructive?: boolean;\n}\n\nfunction matchesPattern(text: string, patterns: string[]): boolean {\n if (!patterns || patterns.length === 0) return true;\n return patterns.some(pattern => {\n try {\n const regex = new RegExp(pattern);\n return regex.test(text);\n } catch {\n return text.includes(pattern);\n }\n });\n}\n\nfunction isDestructiveFieldModification(mod: FieldModification): boolean {\n const typeChange = mod.changes.find(c => c.property === \"type\");\n const requiredChange = mod.changes.find(c => c.property === \"required\" && c.newValue === true);\n return !!(typeChange || requiredChange);\n}\n\nexport function filterDiff(diff: SchemaDiff, options: FilterOptions): SchemaDiff {\n const { patterns = [], skipDestructive = false } = options;\n\n // 1. Filter Collections to Create\n const collectionsToCreate = diff.collectionsToCreate.filter(col => {\n return matchesPattern(col.name, patterns);\n });\n\n // 2. Filter Collections to Delete\n let collectionsToDelete = diff.collectionsToDelete;\n if (skipDestructive) {\n collectionsToDelete = [];\n } else {\n collectionsToDelete = collectionsToDelete.filter(col => {\n return matchesPattern(col.name, patterns);\n });\n }\n\n // 3. Filter Collections to Modify\n const collectionsToModify = diff.collectionsToModify.map(mod => {\n // Check if collection name itself matches\n const collectionMatches = matchesPattern(mod.collection, patterns);\n\n // Filter fields to add\n const fieldsToAdd = mod.fieldsToAdd.filter(field => {\n return collectionMatches || matchesPattern(`${mod.collection}.${field.name}`, patterns);\n });\n\n // Filter fields to remove\n let fieldsToRemove = mod.fieldsToRemove;\n if (skipDestructive) {\n fieldsToRemove = [];\n } else {\n fieldsToRemove = fieldsToRemove.filter(field => {\n return collectionMatches || matchesPattern(`${mod.collection}.${field.name}`, patterns);\n });\n }\n\n // Filter fields to modify\n let fieldsToModify = mod.fieldsToModify;\n if (skipDestructive) {\n fieldsToModify = fieldsToModify.filter(f => !isDestructiveFieldModification(f));\n }\n fieldsToModify = fieldsToModify.filter(f => {\n return collectionMatches || matchesPattern(`${mod.collection}.${f.fieldName}`, patterns);\n });\n\n // Filter collection-level changes (indexes, rules, permissions)\n // Only include them if the collection name itself matches the pattern.\n // If user targets specific fields (e.g. \"User.name\"), collectionMatches is false, so these are skipped.\n const indexesToAdd = collectionMatches ? mod.indexesToAdd : [];\n const indexesToRemove = collectionMatches ? mod.indexesToRemove : [];\n const rulesToUpdate = collectionMatches ? mod.rulesToUpdate : [];\n const permissionsToUpdate = collectionMatches ? mod.permissionsToUpdate : [];\n\n return {\n ...mod,\n fieldsToAdd,\n fieldsToRemove,\n fieldsToModify,\n indexesToAdd,\n indexesToRemove,\n rulesToUpdate,\n permissionsToUpdate\n };\n }).filter(mod => {\n // Keep modification object only if there is something left to modify\n return mod.fieldsToAdd.length > 0 ||\n mod.fieldsToRemove.length > 0 ||\n mod.fieldsToModify.length > 0 ||\n mod.indexesToAdd.length > 0 ||\n mod.indexesToRemove.length > 0 ||\n mod.rulesToUpdate.length > 0 ||\n mod.permissionsToUpdate.length > 0;\n });\n\n return {\n ...diff,\n collectionsToCreate,\n collectionsToDelete,\n collectionsToModify\n };\n}\n","/**\n * Diff Engine component\n * Compares current schema with previous snapshot and identifies changes\n *\n * This module provides a standalone, configurable diff engine that can be used\n * by consumer projects to compare schema definitions and detect changes.\n */\n\nimport type { CollectionModification, SchemaDefinition, SchemaDiff, SchemaSnapshot } from \"../types\";\nimport { CollectionIdRegistry } from \"../utils/collection-id-generator\";\nimport {\n buildCollectionModification,\n findNewCollections,\n findRemovedCollections,\n matchCollectionsByName,\n} from \"./collections\";\nimport { mergeConfig, type DiffEngineConfig } from \"./config\";\nimport {\n categorizeChangesBySeverity,\n generateChangeSummary,\n type ChangeSummary,\n} from \"./summary\";\nimport { isSystemCollection } from \"./utils\";\nimport { detectDestructiveChanges, type DestructiveChange, requiresForceFlag } from \"./destructiveness\";\n\n// Export everything from submodules\nexport * from \"./collections\";\nexport * from \"./config\";\nexport * from \"./destructiveness\";\nexport * from \"./fields\";\nexport * from \"./indexes\";\nexport * from \"./rules\";\nexport * from \"./summary\";\nexport * from \"./utils\";\n\n/**\n * Checks if a collection modification has any actual changes\n *\n * @param modification - Collection modification to check\n * @returns True if there are any changes\n */\nfunction hasChanges(modification: CollectionModification): boolean {\n return (\n modification.fieldsToAdd.length > 0 ||\n modification.fieldsToRemove.length > 0 ||\n modification.fieldsToModify.length > 0 ||\n modification.indexesToAdd.length > 0 ||\n modification.indexesToRemove.length > 0 ||\n modification.rulesToUpdate.length > 0 ||\n modification.permissionsToUpdate.length > 0\n );\n}\n\n/**\n * Aggregates all detected changes into a SchemaDiff\n * Main entry point for diff comparison\n *\n * @param currentSchema - Current schema definition\n * @param previousSnapshot - Previous schema snapshot\n * @param config - Optional configuration\n * @returns Complete SchemaDiff with all changes\n */\nexport function aggregateChanges(\n currentSchema: SchemaDefinition,\n previousSnapshot: SchemaSnapshot | null,\n config?: DiffEngineConfig\n): SchemaDiff {\n // Build lookup map for ID -> Name from previous snapshot\n // This helps resolve relations where snapshot uses ID but schema uses Name\n const collectionIdToName = new Map<string, string>();\n if (previousSnapshot) {\n for (const [name, collection] of previousSnapshot.collections) {\n if (collection.id) {\n collectionIdToName.set(collection.id, name);\n }\n }\n }\n\n // Find new and removed collections\n const collectionsToCreate = findNewCollections(currentSchema, previousSnapshot);\n const collectionsToDelete = findRemovedCollections(currentSchema, previousSnapshot);\n\n // Filter out system collections from create and delete operations\n const filteredCollectionsToCreate = collectionsToCreate.filter(\n (collection) => !isSystemCollection(collection.name, config)\n );\n const filteredCollectionsToDelete = collectionsToDelete.filter(\n (collection) => !isSystemCollection(collection.name, config)\n );\n\n // Generate and assign collection IDs for new collections\n const registry = new CollectionIdRegistry();\n const collectionsWithIds = filteredCollectionsToCreate.map((collection) => {\n // If the collection already has an ID, register it and use it\n if (collection.id) {\n registry.register(collection.id);\n return collection;\n }\n\n // Generate a new ID for the collection (pass name for special handling)\n const id = registry.generate(collection.name);\n return {\n ...collection,\n id,\n };\n });\n\n // Find modified collections\n const collectionsToModify: CollectionModification[] = [];\n const matchedCollections = matchCollectionsByName(currentSchema, previousSnapshot);\n\n for (const [currentCollection, previousCollection] of matchedCollections) {\n const modification = buildCollectionModification(currentCollection, previousCollection, config, collectionIdToName);\n\n // Only include if there are actual changes\n // Note: We allow modifications to the users collection (non-system)\n if (hasChanges(modification)) {\n collectionsToModify.push(modification);\n }\n }\n\n // Build map of existing collection names to their IDs from the snapshot\n // This is used by the generator to resolve relation field references\n const existingCollectionIds = new Map<string, string>();\n if (previousSnapshot) {\n for (const [name, collection] of previousSnapshot.collections) {\n if (collection.id) {\n existingCollectionIds.set(name, collection.id);\n }\n }\n }\n\n return {\n collectionsToCreate: collectionsWithIds,\n collectionsToDelete: filteredCollectionsToDelete,\n collectionsToModify,\n existingCollectionIds,\n };\n}\n\n/**\n * Main comparison function\n * Compares current schema with previous snapshot and returns complete diff\n *\n * @param currentSchema - Current schema definition\n * @param previousSnapshot - Previous schema snapshot (null for first run)\n * @param config - Optional configuration\n * @returns Complete SchemaDiff with all detected changes\n */\nexport function compare(\n currentSchema: SchemaDefinition,\n previousSnapshot: SchemaSnapshot | null,\n config?: DiffEngineConfig\n): SchemaDiff {\n return aggregateChanges(currentSchema, previousSnapshot, config);\n}\n\n/**\n * DiffEngine class for object-oriented usage\n * Provides a stateful interface for schema comparison\n */\nexport class DiffEngine {\n private config: Required<DiffEngineConfig>;\n\n constructor(config?: DiffEngineConfig) {\n this.config = mergeConfig(config);\n }\n\n /**\n * Compares current schema with previous snapshot\n */\n compare(currentSchema: SchemaDefinition, previousSnapshot: SchemaSnapshot | null): SchemaDiff {\n return compare(currentSchema, previousSnapshot, this.config);\n }\n\n /**\n * Detects destructive changes in a diff\n */\n detectDestructiveChanges(diff: SchemaDiff): DestructiveChange[] {\n return detectDestructiveChanges(diff, this.config);\n }\n\n /**\n * Categorizes changes by severity\n */\n categorizeChangesBySeverity(diff: SchemaDiff): { destructive: string[]; nonDestructive: string[] } {\n return categorizeChangesBySeverity(diff, this.config);\n }\n\n /**\n * Generates a summary of changes\n */\n generateChangeSummary(diff: SchemaDiff): ChangeSummary {\n return generateChangeSummary(diff, this.config);\n }\n\n /**\n * Checks if force flag is required\n */\n requiresForceFlag(diff: SchemaDiff): boolean {\n return requiresForceFlag(diff, this.config);\n }\n}\nexport * from \"./filter.js\";\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/migration/utils/collection-id-generator.ts","../../src/migration/diff/config.ts","../../src/migration/diff/utils.ts","../../src/migration/diff/fields.ts","../../src/migration/diff/indexes.ts","../../src/migration/diff/rules.ts","../../src/migration/diff/collections.ts","../../src/migration/diff/destructiveness.ts","../../src/migration/diff/summary.ts","../../src/migration/diff/filter.ts","../../src/migration/diff/index.ts"],"names":["randomBytes"],"mappings":"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","file":"diff.cjs","sourcesContent":["/**\n * Collection ID generation utilities for PocketBase migrations\n */\n\nimport { createHash, randomBytes } from \"crypto\";\n\n/**\n * Generates a unique collection ID in PocketBase format\n * Format: pb_ followed by 15 alphanumeric lowercase characters\n *\n * @returns A unique collection ID string (e.g., \"pb_a1b2c3d4e5f6g7h\")\n */\nexport function generateCollectionId(): string {\n const chars = \"abcdefghijklmnopqrstuvwxyz0123456789\";\n const idLength = 15;\n\n // Generate cryptographically secure random bytes\n const bytes = randomBytes(idLength);\n\n // Convert bytes to alphanumeric characters\n let id = \"pb_\";\n for (let i = 0; i < idLength; i++) {\n const index = bytes[i] % chars.length;\n id += chars[index];\n }\n\n return id;\n}\n\n/**\n * Generates a unique field ID based on type and name\n * Format: type followed by 10 alphanumeric lowercase characters\n * If name is provided, the ID is deterministic\n *\n * @param type - PocketBase field type\n * @param name - Optional field name for deterministic ID\n * @returns A unique field ID string\n */\nexport function generateFieldId(type: string, name?: string): string {\n const chars = \"abcdefghijklmnopqrstuvwxyz0123456789\";\n const idLength = 10;\n\n let bytes: Buffer | Uint8Array;\n if (name) {\n // Deterministic based on name to ensure stability across runs\n bytes = createHash(\"sha256\").update(name).digest();\n } else {\n // Random\n bytes = randomBytes(idLength);\n }\n\n // Convert bytes to alphanumeric characters\n let suffix = \"\";\n for (let i = 0; i < idLength; i++) {\n const index = bytes[i] % chars.length;\n suffix += chars[index];\n }\n\n return `${type}${suffix}`;\n}\n\n/**\n * Registry to track generated collection IDs and ensure uniqueness within a migration batch\n */\nexport class CollectionIdRegistry {\n private ids: Set<string>;\n\n constructor() {\n this.ids = new Set<string>();\n }\n\n /**\n * Generates a unique collection ID for a given collection name\n * Retries up to 10 times if collision occurs (extremely rare)\n * Special case: returns \"_pb_users_auth_\" for users collection\n *\n * @param collectionName - The name of the collection (optional)\n * @returns A unique collection ID\n * @throws Error if unable to generate unique ID after max attempts\n */\n generate(collectionName?: string): string {\n // Special case: users collection always uses the constant\n if (collectionName && collectionName.toLowerCase() === \"users\") {\n const usersId = \"_pb_users_auth_\";\n if (!this.has(usersId)) {\n this.register(usersId);\n }\n return usersId;\n }\n\n const maxAttempts = 10;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n const id = generateCollectionId();\n\n if (!this.has(id)) {\n this.register(id);\n return id;\n }\n }\n\n throw new Error(\"Failed to generate unique collection ID after maximum attempts\");\n }\n\n /**\n * Checks if an ID has already been registered\n *\n * @param id - The collection ID to check\n * @returns True if the ID exists in the registry\n */\n has(id: string): boolean {\n return this.ids.has(id);\n }\n\n /**\n * Registers a collection ID in the registry\n *\n * @param id - The collection ID to register\n */\n register(id: string): void {\n this.ids.add(id);\n }\n}\n","/**\n * Configuration options for the diff engine\n */\nexport interface DiffEngineConfig {\n /**\n * Whether to warn on collection deletions\n * Defaults to true\n */\n warnOnDelete?: boolean;\n\n /**\n * Whether to require --force flag for destructive changes\n * Defaults to true\n */\n requireForceForDestructive?: boolean;\n\n /**\n * Severity threshold for requiring force flag\n * 'high' = only collection/field deletions and type changes\n * 'medium' = includes making fields required\n * 'low' = includes any constraint changes\n * Defaults to 'high'\n */\n severityThreshold?: \"high\" | \"medium\" | \"low\";\n\n /**\n * Custom system collections to exclude from diff\n * These collections will not be created or deleted\n */\n systemCollections?: string[];\n\n /**\n * Custom system fields to exclude from user collection diffs\n * These fields will not be included in fieldsToAdd for the users collection\n */\n usersSystemFields?: string[];\n}\n\n/**\n * Default configuration values\n */\nexport const DEFAULT_CONFIG: Required<DiffEngineConfig> = {\n warnOnDelete: true,\n requireForceForDestructive: true,\n severityThreshold: \"high\",\n systemCollections: [\"_mfas\", \"_otps\", \"_externalAuths\", \"_authOrigins\", \"_superusers\"],\n usersSystemFields: [\"id\", \"password\", \"tokenKey\", \"email\", \"emailVisibility\", \"verified\", \"created\", \"updated\"],\n};\n\n/**\n * Merges user config with defaults\n */\nexport function mergeConfig(config?: DiffEngineConfig): Required<DiffEngineConfig> {\n return {\n ...DEFAULT_CONFIG,\n ...config,\n };\n}\n","import { mergeConfig, type DiffEngineConfig } from \"./config\";\n\n/**\n * Checks if a collection is a PocketBase system collection\n * System collections are internal to PocketBase and should not be created or deleted\n *\n * @param collectionName - Name of the collection to check\n * @param config - Optional configuration with custom system collections\n * @returns True if the collection is a system collection\n */\nexport function isSystemCollection(collectionName: string, config?: DiffEngineConfig): boolean {\n const mergedConfig = mergeConfig(config);\n return mergedConfig.systemCollections.includes(collectionName);\n}\n\n/**\n * Returns the list of system field names for the users collection\n * These fields are automatically provided by PocketBase for auth collections\n * and should not be included when generating migrations for users collection extensions\n *\n * @param config - Optional configuration with custom system fields\n * @returns Set of system field names\n */\nexport function getUsersSystemFields(config?: DiffEngineConfig): Set<string> {\n const mergedConfig = mergeConfig(config);\n return new Set(mergedConfig.usersSystemFields);\n}\n\n/**\n * Compares two values for equality, handling deep object comparison\n *\n * @param a - First value\n * @param b - Second value\n * @returns True if values are equal\n */\nexport function areValuesEqual(a: any, b: any): boolean {\n // Handle null/undefined\n if (a === b) return true;\n if (a == null || b == null) return false;\n\n // Handle arrays\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n return a.every((val, idx) => areValuesEqual(val, b[idx]));\n }\n\n // Handle objects\n if (typeof a === \"object\" && typeof b === \"object\") {\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n\n if (keysA.length !== keysB.length) return false;\n\n return keysA.every((key) => areValuesEqual(a[key], b[key]));\n }\n\n // Primitive comparison\n return a === b;\n}\n\n/**\n * Normalizes a field option value to account for PocketBase defaults\n * Returns the normalized value, treating default values as equivalent to undefined\n *\n * @param key - Option key name\n * @param value - Option value\n * @param fieldType - Field type\n * @returns Normalized value (undefined if it's a default value)\n */\nexport function normalizeOptionValue(key: string, value: any, fieldType: string): any {\n // maxSelect: 1 is the default for select and file fields\n if (key === \"maxSelect\" && value === 1 && (fieldType === \"select\" || fieldType === \"file\")) {\n return undefined; // Treat as undefined to match missing default\n }\n\n // maxSize: 0 is default for file fields\n if (key === \"maxSize\" && value === 0 && fieldType === \"file\") {\n return undefined;\n }\n\n // min: 1 can be a default for some PocketBase versions/number fields\n if (key === \"min\" && value === 1 && fieldType === \"number\") {\n return undefined;\n }\n\n // Empty arrays are defaults for file fields\n if (fieldType === \"file\") {\n if (key === \"mimeTypes\" && Array.isArray(value) && value.length === 0) {\n return undefined;\n }\n if (key === \"thumbs\" && Array.isArray(value) && value.length === 0) {\n return undefined;\n }\n if (key === \"protected\" && value === false) {\n return undefined;\n }\n }\n\n // Autodate defaults\n if (fieldType === \"autodate\") {\n if (key === \"onCreate\" && value === true) {\n return undefined;\n }\n if (key === \"onUpdate\" && value === false) {\n return undefined;\n }\n }\n\n return value;\n}\n","import type { FieldChange, FieldDefinition } from \"../types\";\nimport { areValuesEqual, normalizeOptionValue } from \"./utils\";\n\n/**\n * Identifies new fields in current collection that don't exist in previous\n *\n * @param currentFields - Current collection fields\n * @param previousFields - Previous collection fields\n * @returns Array of new fields\n */\nexport function findNewFields(currentFields: FieldDefinition[], previousFields: FieldDefinition[]): FieldDefinition[] {\n const newFields: FieldDefinition[] = [];\n const previousFieldNames = new Set(previousFields.map((f) => f.name));\n\n for (const currentField of currentFields) {\n if (!previousFieldNames.has(currentField.name)) {\n newFields.push(currentField);\n }\n }\n\n return newFields;\n}\n\n/**\n * Identifies fields removed from current collection (exist in previous but not in current)\n *\n * @param currentFields - Current collection fields\n * @param previousFields - Previous collection fields\n * @returns Array of removed fields\n */\nexport function findRemovedFields(\n currentFields: FieldDefinition[],\n previousFields: FieldDefinition[]\n): FieldDefinition[] {\n const removedFields: FieldDefinition[] = [];\n const currentFieldNames = new Set(currentFields.map((f) => f.name));\n\n for (const previousField of previousFields) {\n if (!currentFieldNames.has(previousField.name)) {\n removedFields.push(previousField);\n }\n }\n\n return removedFields;\n}\n\n/**\n * Matches fields by name between current and previous collections\n * Returns pairs of [current, previous] for fields that exist in both\n *\n * @param currentFields - Current collection fields\n * @param previousFields - Previous collection fields\n * @returns Array of matched field pairs\n */\nexport function matchFieldsByName(\n currentFields: FieldDefinition[],\n previousFields: FieldDefinition[]\n): Array<[FieldDefinition, FieldDefinition]> {\n const matches: Array<[FieldDefinition, FieldDefinition]> = [];\n\n // Create a map of previous fields by name for efficient lookup\n const previousFieldMap = new Map<string, FieldDefinition>();\n for (const previousField of previousFields) {\n previousFieldMap.set(previousField.name, previousField);\n }\n\n // Find matching fields\n for (const currentField of currentFields) {\n const previousField = previousFieldMap.get(currentField.name);\n\n if (previousField) {\n matches.push([currentField, previousField]);\n }\n }\n\n return matches;\n}\n\n/**\n * Compares field types between current and previous\n *\n * @param currentField - Current field definition\n * @param previousField - Previous field definition\n * @returns FieldChange if types differ, null otherwise\n */\nexport function compareFieldTypes(currentField: FieldDefinition, previousField: FieldDefinition): FieldChange | null {\n if (currentField.type !== previousField.type) {\n return {\n property: \"type\",\n oldValue: previousField.type,\n newValue: currentField.type,\n };\n }\n\n return null;\n}\n\n/**\n * Compares field constraints (required, unique) between current and previous\n *\n * @param currentField - Current field definition\n * @param previousField - Previous field definition\n * @returns Array of FieldChange for constraint differences\n */\nexport function compareFieldConstraints(currentField: FieldDefinition, previousField: FieldDefinition): FieldChange[] {\n const changes: FieldChange[] = [];\n\n // Compare required constraint\n if (currentField.required !== previousField.required) {\n changes.push({\n property: \"required\",\n oldValue: previousField.required,\n newValue: currentField.required,\n });\n }\n\n // Compare unique constraint\n if (currentField.unique !== previousField.unique) {\n changes.push({\n property: \"unique\",\n oldValue: previousField.unique,\n newValue: currentField.unique,\n });\n }\n\n return changes;\n}\n\n/**\n * Compares field options (min, max, pattern, etc.) between current and previous\n *\n * @param currentField - Current field definition\n * @param previousField - Previous field definition\n * @returns Array of FieldChange for option differences\n */\nexport function compareFieldOptions(currentField: FieldDefinition, previousField: FieldDefinition): FieldChange[] {\n const changes: FieldChange[] = [];\n\n const currentOptions = currentField.options || {};\n const previousOptions = previousField.options || {};\n\n // Get all unique option keys\n const allKeys = new Set([...Object.keys(currentOptions), ...Object.keys(previousOptions)]);\n\n // Compare each option\n // Use currentField.type for normalization since types should match at this point\n // (type changes are handled separately in compareFieldTypes)\n const fieldType = currentField.type;\n\n for (const key of allKeys) {\n const currentValue = currentOptions[key];\n const previousValue = previousOptions[key];\n\n // Normalize values to account for default values\n // This ensures that maxSelect: 1 (default) is treated the same as undefined (missing default)\n const normalizedCurrent = normalizeOptionValue(key, currentValue, fieldType);\n const normalizedPrevious = normalizeOptionValue(key, previousValue, fieldType);\n\n // Handle undefined values - if both are undefined (or normalized to undefined), that's not a change\n if (normalizedCurrent === undefined && normalizedPrevious === undefined) {\n continue;\n }\n\n if (!areValuesEqual(normalizedCurrent, normalizedPrevious)) {\n changes.push({\n property: `options.${key}`,\n oldValue: previousValue,\n newValue: currentValue,\n });\n }\n }\n\n return changes;\n}\n\n/**\n * Compares relation configurations between current and previous\n *\n * @param currentField - Current field definition\n * @param previousField - Previous field definition\n * @returns Array of FieldChange for relation differences\n */\nexport function compareRelationConfigurations(\n currentField: FieldDefinition,\n previousField: FieldDefinition,\n collectionIdToName?: Map<string, string>\n): FieldChange[] {\n const changes: FieldChange[] = [];\n\n const currentRelation = currentField.relation;\n const previousRelation = previousField.relation;\n\n // If one has relation and other doesn't, that's not a config change (handled elsewhere, likely type or structure)\n // But here we assume types match (both relation) or structure implies relation\n if (!currentRelation && !previousRelation) {\n return changes;\n }\n\n if (!currentRelation || !previousRelation) {\n // This shouldn't happen if types match and both are 'relation', but handle gracefully\n return changes;\n }\n\n // Compare relation properties\n // Note: collectionId should already be resolved to collection name during parsing\n // This normalization is just a safety net for edge cases\n const normalizeCollection = (collection: string): string => {\n if (!collection) return collection;\n\n // Resolve ID to name if possible\n if (collectionIdToName && collectionIdToName.has(collection)) {\n return collectionIdToName.get(collection)!;\n }\n\n // Handle expressions that might not have been parsed correctly\n const nameMatch = collection.match(/app\\.findCollectionByNameOrId\\s*\\(\\s*[\"']([^\"']+)[\"']\\s*\\)/);\n if (nameMatch) {\n return nameMatch[1];\n }\n return collection;\n };\n\n const normalizedCurrent = normalizeCollection(currentRelation.collection);\n // We resolve the ID from the previous relation (snapshot) to its name if available\n const normalizedPrevious = normalizeCollection(previousRelation.collection);\n\n // Only report a change if the normalized values differ\n // Use case-insensitive comparison for collection names\n if (normalizedCurrent.toLowerCase() !== normalizedPrevious.toLowerCase()) {\n changes.push({\n property: \"relation.collection\",\n oldValue: previousRelation.collection,\n newValue: currentRelation.collection,\n });\n }\n\n if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {\n changes.push({\n property: \"relation.cascadeDelete\",\n oldValue: previousRelation.cascadeDelete,\n newValue: currentRelation.cascadeDelete,\n });\n }\n\n // Normalize maxSelect: 1 to undefined/null as it's often the default or treated as such\n const normalizeMax = (val: number | null | undefined) => (val === 1 ? null : val);\n const currentMax = normalizeMax(currentRelation.maxSelect);\n const previousMax = normalizeMax(previousRelation.maxSelect);\n\n // Use loose equality to handle null vs undefined\n if (currentMax != previousMax) {\n changes.push({\n property: \"relation.maxSelect\",\n oldValue: previousRelation.maxSelect,\n newValue: currentRelation.maxSelect,\n });\n }\n\n // Normalize minSelect: 0 to undefined/null\n const normalizeMin = (val: number | null | undefined) => (val === 0 ? null : val);\n const currentMin = normalizeMin(currentRelation.minSelect);\n const previousMin = normalizeMin(previousRelation.minSelect);\n\n if (currentMin != previousMin) {\n changes.push({\n property: \"relation.minSelect\",\n oldValue: previousRelation.minSelect,\n newValue: currentRelation.minSelect,\n });\n }\n\n return changes;\n}\n\n/**\n * Detects all changes between two field definitions\n * Combines type, constraint, option, and relation changes\n *\n * @param currentField - Current field definition\n * @param previousField - Previous field definition\n * @returns Array of all detected changes\n */\nexport function detectFieldChanges(\n currentField: FieldDefinition,\n previousField: FieldDefinition,\n collectionIdToName?: Map<string, string>\n): FieldChange[] {\n const changes: FieldChange[] = [];\n\n // Compare types\n const typeChange = compareFieldTypes(currentField, previousField);\n if (typeChange) {\n changes.push(typeChange);\n }\n\n // Compare constraints\n changes.push(...compareFieldConstraints(currentField, previousField));\n\n // Compare options\n changes.push(...compareFieldOptions(currentField, previousField));\n\n // Compare relation configurations (if applicable)\n if (currentField.type === \"relation\" && previousField.type === \"relation\") {\n changes.push(...compareRelationConfigurations(currentField, previousField, collectionIdToName));\n }\n\n return changes;\n}\n","/**\n * Compares indexes between current and previous collections\n *\n * @param currentIndexes - Current collection indexes\n * @param previousIndexes - Previous collection indexes\n * @returns Object with indexes to add and remove\n */\nexport function compareIndexes(\n currentIndexes: string[] = [],\n previousIndexes: string[] = []\n): { indexesToAdd: string[]; indexesToRemove: string[] } {\n const currentSet = new Set(currentIndexes);\n const previousSet = new Set(previousIndexes);\n\n const indexesToAdd = currentIndexes.filter((idx) => !previousSet.has(idx));\n const indexesToRemove = previousIndexes.filter((idx) => !currentSet.has(idx));\n\n return { indexesToAdd, indexesToRemove };\n}\n","import type { APIRuleType, CollectionSchema, PermissionChange, RuleUpdate } from \"../types\";\n\n/**\n * Compares API rules between current and previous collections\n *\n * @param currentRules - Current collection rules\n * @param previousRules - Previous collection rules\n * @returns Array of rule updates\n */\nexport function compareRules(\n currentRules: CollectionSchema[\"rules\"],\n previousRules: CollectionSchema[\"rules\"],\n currentPermissions?: CollectionSchema[\"permissions\"],\n previousPermissions?: CollectionSchema[\"permissions\"]\n): RuleUpdate[] {\n const updates: RuleUpdate[] = [];\n\n const ruleTypes: Array<keyof NonNullable<CollectionSchema[\"rules\"]>> = [\n \"listRule\",\n \"viewRule\",\n \"createRule\",\n \"updateRule\",\n \"deleteRule\",\n \"manageRule\",\n ];\n\n for (const ruleType of ruleTypes) {\n // Use rules if available, otherwise fall back to permissions (they're the same thing)\n const currentValue = currentRules?.[ruleType] ?? currentPermissions?.[ruleType] ?? null;\n const previousValue = previousRules?.[ruleType] ?? previousPermissions?.[ruleType] ?? null;\n\n if (currentValue !== previousValue) {\n updates.push({\n ruleType: ruleType as RuleUpdate[\"ruleType\"],\n oldValue: previousValue,\n newValue: currentValue,\n });\n }\n }\n\n return updates;\n}\n\n/**\n * Compares permissions between current and previous collections\n * Detects changes in permission rules defined in schema\n *\n * @param currentPermissions - Current collection permissions\n * @param previousPermissions - Previous collection permissions\n * @returns Array of permission changes\n */\nexport function comparePermissions(\n currentPermissions: CollectionSchema[\"permissions\"],\n previousPermissions: CollectionSchema[\"permissions\"]\n): PermissionChange[] {\n const changes: PermissionChange[] = [];\n\n const ruleTypes: APIRuleType[] = [\"listRule\", \"viewRule\", \"createRule\", \"updateRule\", \"deleteRule\", \"manageRule\"];\n\n for (const ruleType of ruleTypes) {\n const currentValue = currentPermissions?.[ruleType] ?? null;\n const previousValue = previousPermissions?.[ruleType] ?? null;\n\n // Compare permission values\n if (currentValue !== previousValue) {\n changes.push({\n ruleType,\n oldValue: previousValue,\n newValue: currentValue,\n });\n }\n }\n\n return changes;\n}\n","import type {\n CollectionModification,\n CollectionSchema,\n FieldDefinition,\n FieldModification,\n SchemaDefinition,\n SchemaSnapshot,\n ViewQueryUpdate,\n} from \"../types\";\nimport { type DiffEngineConfig } from \"./config\";\nimport { detectFieldChanges, findNewFields, findRemovedFields, matchFieldsByName } from \"./fields\";\nimport { compareIndexes } from \"./indexes\";\nimport { comparePermissions, compareRules } from \"./rules\";\nimport { getUsersSystemFields, isSystemCollection } from \"./utils\";\n\n/**\n * Filters system collections from a schema definition\n * Returns a new SchemaDefinition with only custom (non-system) collections\n *\n * @param schema - Schema definition to filter\n * @param config - Optional configuration\n * @returns Filtered SchemaDefinition without system collections\n */\nexport function filterSystemCollections(schema: SchemaDefinition, config?: DiffEngineConfig): SchemaDefinition {\n const filteredCollections = new Map<string, CollectionSchema>();\n\n for (const [collectionName, collectionSchema] of schema.collections) {\n if (!isSystemCollection(collectionName, config)) {\n filteredCollections.set(collectionName, collectionSchema);\n }\n }\n\n return {\n collections: filteredCollections,\n };\n}\n\n/**\n * Identifies new collections in schema that don't exist in snapshot\n *\n * @param currentSchema - Current schema definition\n * @param previousSnapshot - Previous schema snapshot\n * @returns Array of new collections\n */\nexport function findNewCollections(\n currentSchema: SchemaDefinition,\n previousSnapshot: SchemaSnapshot | null\n): CollectionSchema[] {\n const newCollections: CollectionSchema[] = [];\n\n // If no previous snapshot, all collections are new\n if (!previousSnapshot) {\n return Array.from(currentSchema.collections.values());\n }\n\n // Find collections in current schema that don't exist in snapshot\n for (const [collectionName, collectionSchema] of currentSchema.collections) {\n if (!previousSnapshot.collections.has(collectionName)) {\n newCollections.push(collectionSchema);\n }\n }\n\n return newCollections;\n}\n\n/**\n * Identifies collections removed from schema (exist in snapshot but not in current schema)\n *\n * @param currentSchema - Current schema definition\n * @param previousSnapshot - Previous schema snapshot\n * @returns Array of removed collections\n */\nexport function findRemovedCollections(\n currentSchema: SchemaDefinition,\n previousSnapshot: SchemaSnapshot | null\n): CollectionSchema[] {\n const removedCollections: CollectionSchema[] = [];\n\n // If no previous snapshot, nothing can be removed\n if (!previousSnapshot) {\n return removedCollections;\n }\n\n // Find collections in snapshot that don't exist in current schema\n for (const [collectionName, collectionSchema] of previousSnapshot.collections) {\n if (!currentSchema.collections.has(collectionName)) {\n removedCollections.push(collectionSchema);\n }\n }\n\n return removedCollections;\n}\n\n/**\n * Matches collections by name between current schema and snapshot\n * Returns pairs of [current, previous] for collections that exist in both\n *\n * @param currentSchema - Current schema definition\n * @param previousSnapshot - Previous schema snapshot\n * @returns Array of matched collection pairs\n */\nexport function matchCollectionsByName(\n currentSchema: SchemaDefinition,\n previousSnapshot: SchemaSnapshot | null\n): Array<[CollectionSchema, CollectionSchema]> {\n const matches: Array<[CollectionSchema, CollectionSchema]> = [];\n\n // If no previous snapshot, no matches possible\n if (!previousSnapshot) {\n return matches;\n }\n\n // Create a case-insensitive lookup map for previous collections\n const previousCollectionsLower = new Map<string, [string, CollectionSchema]>();\n for (const [name, collection] of previousSnapshot.collections) {\n previousCollectionsLower.set(name.toLowerCase(), [name, collection]);\n }\n\n // Find collections that exist in both current and previous (case-insensitive)\n for (const [collectionName, currentCollection] of currentSchema.collections) {\n const previousEntry = previousCollectionsLower.get(collectionName.toLowerCase());\n\n if (previousEntry) {\n const [, previousCollection] = previousEntry;\n matches.push([currentCollection, previousCollection]);\n }\n }\n\n return matches;\n}\n\n/**\n * Compares fields between current and previous collections\n * Identifies new, removed, and modified fields\n * For the users collection, filters out system fields from fieldsToAdd\n *\n * @param currentCollection - Current collection schema\n * @param previousCollection - Previous collection schema\n * @param config - Optional configuration\n * @returns Object with field changes\n */\nfunction compareCollectionFields(\n currentCollection: CollectionSchema,\n previousCollection: CollectionSchema,\n config?: DiffEngineConfig,\n collectionIdToName?: Map<string, string>\n): {\n fieldsToAdd: FieldDefinition[];\n fieldsToRemove: FieldDefinition[];\n fieldsToModify: FieldModification[];\n} {\n let fieldsToAdd = findNewFields(currentCollection.fields, previousCollection.fields);\n let fieldsToRemove = findRemovedFields(currentCollection.fields, previousCollection.fields);\n const fieldsToModify: FieldModification[] = [];\n\n // For users collection, filter out system fields from fieldsToAdd\n // System fields are automatically provided by PocketBase and should not be in migrations\n if (currentCollection.name === \"users\") {\n const systemFields = getUsersSystemFields(config);\n fieldsToAdd = fieldsToAdd.filter((field) => !systemFields.has(field.name));\n }\n\n // Check for modified fields\n const matchedFields = matchFieldsByName(currentCollection.fields, previousCollection.fields);\n\n for (const [currentField, previousField] of matchedFields) {\n const changes = detectFieldChanges(currentField, previousField, collectionIdToName);\n\n if (changes.length > 0) {\n fieldsToModify.push({\n fieldName: currentField.name,\n currentDefinition: previousField,\n newDefinition: currentField,\n changes,\n });\n }\n }\n\n // Detect Renames (Heuristic)\n // If we have single removed and added fields of the same type, consider it a rename\n const processedAddIndices = new Set<number>();\n const processedRemoveIndices = new Set<number>();\n\n // Helper to resolve collection name from ID/expression\n const resolveCollectionName = (val: string): string => {\n if (!val) return val;\n if (collectionIdToName && collectionIdToName.has(val)) return collectionIdToName.get(val)!;\n const match = val.match(/app\\.findCollectionByNameOrId\\s*\\(\\s*[\"']([^\"']+)[\"']\\s*\\)/);\n return match ? match[1] : val;\n };\n\n // Group fields by type\n const addedByType = new Map<string, number[]>();\n fieldsToAdd.forEach((field, index) => {\n const type = field.type;\n if (!addedByType.has(type)) addedByType.set(type, []);\n addedByType.get(type)!.push(index);\n });\n\n const removedByType = new Map<string, number[]>();\n fieldsToRemove.forEach((field, index) => {\n const type = field.type;\n if (!removedByType.has(type)) removedByType.set(type, []);\n removedByType.get(type)!.push(index);\n });\n\n // Check each type for potential renames\n for (const [type, removedIndices] of removedByType) {\n const addedIndices = addedByType.get(type);\n\n // Heuristic: Only rename if exactly one field of this type was removed and one added\n if (addedIndices && addedIndices.length === 1 && removedIndices.length === 1) {\n const addedIndex = addedIndices[0];\n const removedIndex = removedIndices[0];\n const addedField = fieldsToAdd[addedIndex];\n const removedField = fieldsToRemove[removedIndex];\n\n // For relations, ensure target collection matches\n let isMatch = true;\n if (type === \"relation\") {\n const addedTarget = resolveCollectionName(addedField.relation?.collection || \"\");\n const removedTarget = resolveCollectionName(removedField.relation?.collection || \"\");\n if (addedTarget.toLowerCase() !== removedTarget.toLowerCase()) {\n isMatch = false;\n }\n }\n\n if (isMatch) {\n // It's a rename!\n processedAddIndices.add(addedIndex);\n processedRemoveIndices.add(removedIndex);\n\n // Calculate changes (including name change)\n const changes = detectFieldChanges(addedField, removedField, collectionIdToName);\n changes.push({\n property: \"name\",\n oldValue: removedField.name,\n newValue: addedField.name,\n });\n\n fieldsToModify.push({\n fieldName: removedField.name, // Use OLD name so generator can find it\n currentDefinition: removedField, // OLD definition\n newDefinition: addedField, // NEW definition\n changes,\n });\n }\n }\n }\n\n // Filter out processed fields\n fieldsToAdd = fieldsToAdd.filter((_, index) => !processedAddIndices.has(index));\n fieldsToRemove = fieldsToRemove.filter((_, index) => !processedRemoveIndices.has(index));\n\n return { fieldsToAdd, fieldsToRemove, fieldsToModify };\n}\n\n/**\n * Normalizes a SQL view query for comparison\n * Collapses whitespace so re-indenting or re-wrapping a query does not produce\n * a migration\n *\n * @param query - The SQL query\n * @returns Normalized query text\n */\nexport function normalizeSql(query: string | null | undefined): string {\n if (!query) {\n return \"\";\n }\n\n return query\n .split(\"\\n\")\n .map((line) => line.trim())\n .join(\" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/**\n * Compares the SQL query of two view collections\n *\n * @param currentCollection - Current collection schema\n * @param previousCollection - Previous collection schema\n * @returns A ViewQueryUpdate when the query changed, undefined otherwise\n */\nfunction compareViewQuery(\n currentCollection: CollectionSchema,\n previousCollection: CollectionSchema\n): ViewQueryUpdate | undefined {\n const newValue = currentCollection.viewQuery;\n\n if (typeof newValue !== \"string\") {\n return undefined;\n }\n\n if (normalizeSql(newValue) === normalizeSql(previousCollection.viewQuery)) {\n return undefined;\n }\n\n return {\n oldValue: previousCollection.viewQuery ?? null,\n newValue,\n };\n}\n\n/**\n * Builds a CollectionModification for a matched collection pair\n *\n * @param currentCollection - Current collection schema\n * @param previousCollection - Previous collection schema\n * @param config - Optional configuration\n * @returns CollectionModification object\n */\nexport function buildCollectionModification(\n currentCollection: CollectionSchema,\n previousCollection: CollectionSchema,\n config?: DiffEngineConfig,\n collectionIdToName?: Map<string, string>\n): CollectionModification {\n // View collections are defined entirely by their SQL query: PocketBase\n // derives the fields from it and views cannot have indexes, so only the\n // query and the read rules are diffed\n const isView = currentCollection.type === \"view\" || previousCollection.type === \"view\";\n\n if (isView) {\n return {\n collection: currentCollection.name,\n fieldsToAdd: [],\n fieldsToRemove: [],\n fieldsToModify: [],\n indexesToAdd: [],\n indexesToRemove: [],\n rulesToUpdate: compareRules(\n currentCollection.rules,\n previousCollection.rules,\n currentCollection.permissions,\n previousCollection.permissions\n ),\n permissionsToUpdate: comparePermissions(currentCollection.permissions, previousCollection.permissions),\n viewQueryUpdate: compareViewQuery(currentCollection, previousCollection),\n };\n }\n\n // Compare fields\n const { fieldsToAdd, fieldsToRemove, fieldsToModify } = compareCollectionFields(\n currentCollection,\n previousCollection,\n config,\n collectionIdToName\n );\n\n // Compare indexes\n const { indexesToAdd, indexesToRemove } = compareIndexes(currentCollection.indexes, previousCollection.indexes);\n\n // Compare rules (also check permissions as fallback since they're the same thing)\n const rulesToUpdate = compareRules(\n currentCollection.rules,\n previousCollection.rules,\n currentCollection.permissions,\n previousCollection.permissions\n );\n\n // Compare permissions\n const permissionsToUpdate = comparePermissions(currentCollection.permissions, previousCollection.permissions);\n\n return {\n collection: currentCollection.name,\n fieldsToAdd,\n fieldsToRemove,\n fieldsToModify,\n indexesToAdd,\n indexesToRemove,\n rulesToUpdate,\n permissionsToUpdate,\n };\n}\n","import type { SchemaDiff } from \"../types\";\nimport { mergeConfig, type DiffEngineConfig } from \"./config\";\n\n/**\n * Destructive change information\n */\nexport interface DestructiveChange {\n type: \"collection_delete\" | \"field_delete\" | \"type_change\" | \"required_change\" | \"constraint_change\";\n severity: \"high\" | \"medium\" | \"low\";\n collection: string;\n field?: string;\n description: string;\n oldValue?: any;\n newValue?: any;\n}\n\n/**\n * Detects destructive changes in a schema diff\n * Returns detailed information about each destructive change\n *\n * @param diff - Schema diff to analyze\n * @param config - Optional configuration for severity thresholds\n * @returns Array of destructive changes with severity information\n */\nexport function detectDestructiveChanges(diff: SchemaDiff, config?: DiffEngineConfig): DestructiveChange[] {\n const destructiveChanges: DestructiveChange[] = [];\n const mergedConfig = mergeConfig(config);\n\n // Collection deletions are always high severity\n // Views are exempt: they store no data, so dropping one loses nothing\n for (const collection of diff.collectionsToDelete) {\n if (collection.type === \"view\") {\n continue;\n }\n\n destructiveChanges.push({\n type: \"collection_delete\",\n severity: \"high\",\n collection: collection.name,\n description: `Delete collection: ${collection.name}`,\n });\n }\n\n // Analyze modifications\n for (const modification of diff.collectionsToModify) {\n const collectionName = modification.collection;\n\n // Field deletions are high severity\n for (const field of modification.fieldsToRemove) {\n destructiveChanges.push({\n type: \"field_delete\",\n severity: \"high\",\n collection: collectionName,\n field: field.name,\n description: `Delete field: ${collectionName}.${field.name}`,\n });\n }\n\n // Field modifications can be various severities\n for (const fieldMod of modification.fieldsToModify) {\n const typeChange = fieldMod.changes.find((c) => c.property === \"type\");\n const requiredChange = fieldMod.changes.find((c) => c.property === \"required\" && c.newValue === true);\n\n if (typeChange) {\n destructiveChanges.push({\n type: \"type_change\",\n severity: \"high\",\n collection: collectionName,\n field: fieldMod.fieldName,\n description: `Change field type: ${collectionName}.${fieldMod.fieldName} (${typeChange.oldValue} → ${typeChange.newValue})`,\n oldValue: typeChange.oldValue,\n newValue: typeChange.newValue,\n });\n }\n\n if (requiredChange && mergedConfig.severityThreshold !== \"high\") {\n destructiveChanges.push({\n type: \"required_change\",\n severity: \"medium\",\n collection: collectionName,\n field: fieldMod.fieldName,\n description: `Make field required: ${collectionName}.${fieldMod.fieldName}`,\n oldValue: false,\n newValue: true,\n });\n }\n\n // Other constraint changes at low severity\n if (mergedConfig.severityThreshold === \"low\") {\n const otherChanges = fieldMod.changes.filter((c) => c.property !== \"type\" && c.property !== \"required\");\n for (const change of otherChanges) {\n destructiveChanges.push({\n type: \"constraint_change\",\n severity: \"low\",\n collection: collectionName,\n field: fieldMod.fieldName,\n description: `Change constraint: ${collectionName}.${fieldMod.fieldName}.${change.property}`,\n oldValue: change.oldValue,\n newValue: change.newValue,\n });\n }\n }\n }\n }\n\n return destructiveChanges;\n}\n\n/**\n * Checks if a diff requires the --force flag based on configuration\n *\n * @param diff - Schema diff to check\n * @param config - Configuration with severity threshold\n * @returns True if force flag is required\n */\nexport function requiresForceFlag(diff: SchemaDiff, config?: DiffEngineConfig): boolean {\n const mergedConfig = mergeConfig(config);\n\n if (!mergedConfig.requireForceForDestructive) {\n return false;\n }\n\n const destructiveChanges = detectDestructiveChanges(diff, config);\n\n // Filter by severity threshold\n const relevantChanges = destructiveChanges.filter((change) => {\n switch (mergedConfig.severityThreshold) {\n case \"high\":\n return change.severity === \"high\";\n case \"medium\":\n return change.severity === \"high\" || change.severity === \"medium\";\n case \"low\":\n return true;\n default:\n return change.severity === \"high\";\n }\n });\n\n return relevantChanges.length > 0;\n}\n","import type { SchemaDiff } from \"../types\";\nimport { type DiffEngineConfig } from \"./config\";\nimport { detectDestructiveChanges, type DestructiveChange } from \"./destructiveness\";\n\n/**\n * Change summary for status reporting\n */\nexport interface ChangeSummary {\n totalChanges: number;\n collectionsToCreate: number;\n collectionsToDelete: number;\n collectionsToModify: number;\n fieldsToAdd: number;\n fieldsToRemove: number;\n fieldsToModify: number;\n indexChanges: number;\n ruleChanges: number;\n permissionChanges: number;\n viewQueryChanges: number;\n destructiveChanges: DestructiveChange[];\n nonDestructiveChanges: string[];\n}\n\n/**\n * Categorizes changes by severity\n * Returns object with destructive and non-destructive changes\n *\n * @param diff - Schema diff to categorize\n * @param config - Optional configuration\n * @returns Object with categorized changes\n */\nexport function categorizeChangesBySeverity(\n diff: SchemaDiff,\n _config?: DiffEngineConfig\n): {\n destructive: string[];\n nonDestructive: string[];\n} {\n const destructive: string[] = [];\n const nonDestructive: string[] = [];\n\n // Collection deletions are destructive, except for views which hold no data\n for (const collection of diff.collectionsToDelete) {\n if (collection.type === \"view\") {\n nonDestructive.push(`Delete view collection: ${collection.name}`);\n } else {\n destructive.push(`Delete collection: ${collection.name}`);\n }\n }\n\n // Collection creations are non-destructive\n for (const collection of diff.collectionsToCreate) {\n nonDestructive.push(`Create collection: ${collection.name}`);\n }\n\n // Analyze modifications\n for (const modification of diff.collectionsToModify) {\n const collectionName = modification.collection;\n\n // Field deletions are destructive\n for (const field of modification.fieldsToRemove) {\n destructive.push(`Delete field: ${collectionName}.${field.name}`);\n }\n\n // Field additions are non-destructive\n for (const field of modification.fieldsToAdd) {\n nonDestructive.push(`Add field: ${collectionName}.${field.name}`);\n }\n\n // Field modifications can be destructive or non-destructive\n for (const fieldMod of modification.fieldsToModify) {\n const hasTypeChange = fieldMod.changes.some((c) => c.property === \"type\");\n const hasRequiredChange = fieldMod.changes.some((c) => c.property === \"required\" && c.newValue === true);\n\n if (hasTypeChange) {\n destructive.push(\n `Change field type: ${collectionName}.${fieldMod.fieldName} (${fieldMod.changes.find((c) => c.property === \"type\")?.oldValue} → ${fieldMod.changes.find((c) => c.property === \"type\")?.newValue})`\n );\n } else if (hasRequiredChange) {\n destructive.push(`Make field required: ${collectionName}.${fieldMod.fieldName}`);\n } else {\n nonDestructive.push(`Modify field: ${collectionName}.${fieldMod.fieldName}`);\n }\n }\n\n // Index changes are generally non-destructive\n for (const _index of modification.indexesToAdd) {\n nonDestructive.push(`Add index: ${collectionName}`);\n }\n\n for (const _index of modification.indexesToRemove) {\n nonDestructive.push(`Remove index: ${collectionName}`);\n }\n\n // Rule changes are non-destructive\n for (const rule of modification.rulesToUpdate) {\n nonDestructive.push(`Update rule: ${collectionName}.${rule.ruleType}`);\n }\n\n // View query changes are non-destructive - a view stores no data\n if (modification.viewQueryUpdate) {\n nonDestructive.push(`Update view query: ${collectionName}`);\n }\n }\n\n return { destructive, nonDestructive };\n}\n\n/**\n * Generates a summary of all changes in a diff\n * Useful for status reporting and user feedback\n *\n * @param diff - Schema diff to summarize\n * @param config - Optional configuration\n * @returns Change summary with counts and details\n */\nexport function generateChangeSummary(diff: SchemaDiff, config?: DiffEngineConfig): ChangeSummary {\n const destructiveChanges = detectDestructiveChanges(diff, config);\n const { nonDestructive } = categorizeChangesBySeverity(diff, config);\n\n let fieldsToAdd = 0;\n let fieldsToRemove = 0;\n let fieldsToModify = 0;\n let indexChanges = 0;\n let ruleChanges = 0;\n let permissionChanges = 0;\n let viewQueryChanges = 0;\n\n for (const modification of diff.collectionsToModify) {\n fieldsToAdd += modification.fieldsToAdd.length;\n fieldsToRemove += modification.fieldsToRemove.length;\n fieldsToModify += modification.fieldsToModify.length;\n indexChanges += modification.indexesToAdd.length + modification.indexesToRemove.length;\n ruleChanges += modification.rulesToUpdate.length;\n permissionChanges += modification.permissionsToUpdate.length;\n if (modification.viewQueryUpdate) {\n viewQueryChanges += 1;\n }\n }\n\n return {\n totalChanges: diff.collectionsToCreate.length + diff.collectionsToDelete.length + diff.collectionsToModify.length,\n collectionsToCreate: diff.collectionsToCreate.length,\n collectionsToDelete: diff.collectionsToDelete.length,\n collectionsToModify: diff.collectionsToModify.length,\n fieldsToAdd,\n fieldsToRemove,\n fieldsToModify,\n indexChanges,\n ruleChanges,\n permissionChanges,\n viewQueryChanges,\n destructiveChanges,\n nonDestructiveChanges: nonDestructive,\n };\n}\n","import type { SchemaDiff, FieldModification } from \"../types\";\n\nexport interface FilterOptions {\n patterns?: string[];\n skipDestructive?: boolean;\n}\n\nfunction matchesPattern(text: string, patterns: string[]): boolean {\n if (!patterns || patterns.length === 0) return true;\n return patterns.some(pattern => {\n try {\n const regex = new RegExp(pattern);\n return regex.test(text);\n } catch {\n return text.includes(pattern);\n }\n });\n}\n\nfunction isDestructiveFieldModification(mod: FieldModification): boolean {\n const typeChange = mod.changes.find(c => c.property === \"type\");\n const requiredChange = mod.changes.find(c => c.property === \"required\" && c.newValue === true);\n return !!(typeChange || requiredChange);\n}\n\nexport function filterDiff(diff: SchemaDiff, options: FilterOptions): SchemaDiff {\n const { patterns = [], skipDestructive = false } = options;\n\n // 1. Filter Collections to Create\n const collectionsToCreate = diff.collectionsToCreate.filter(col => {\n return matchesPattern(col.name, patterns);\n });\n\n // 2. Filter Collections to Delete\n // View collections are kept even when skipping destructive changes: they\n // store no data, so dropping one loses nothing\n let collectionsToDelete = diff.collectionsToDelete;\n if (skipDestructive) {\n collectionsToDelete = collectionsToDelete.filter(col => col.type === \"view\");\n }\n collectionsToDelete = collectionsToDelete.filter(col => {\n return matchesPattern(col.name, patterns);\n });\n\n // 3. Filter Collections to Modify\n const collectionsToModify = diff.collectionsToModify.map(mod => {\n // Check if collection name itself matches\n const collectionMatches = matchesPattern(mod.collection, patterns);\n\n // Filter fields to add\n const fieldsToAdd = mod.fieldsToAdd.filter(field => {\n return collectionMatches || matchesPattern(`${mod.collection}.${field.name}`, patterns);\n });\n\n // Filter fields to remove\n let fieldsToRemove = mod.fieldsToRemove;\n if (skipDestructive) {\n fieldsToRemove = [];\n } else {\n fieldsToRemove = fieldsToRemove.filter(field => {\n return collectionMatches || matchesPattern(`${mod.collection}.${field.name}`, patterns);\n });\n }\n\n // Filter fields to modify\n let fieldsToModify = mod.fieldsToModify;\n if (skipDestructive) {\n fieldsToModify = fieldsToModify.filter(f => !isDestructiveFieldModification(f));\n }\n fieldsToModify = fieldsToModify.filter(f => {\n return collectionMatches || matchesPattern(`${mod.collection}.${f.fieldName}`, patterns);\n });\n\n // Filter collection-level changes (indexes, rules, permissions)\n // Only include them if the collection name itself matches the pattern.\n // If user targets specific fields (e.g. \"User.name\"), collectionMatches is false, so these are skipped.\n const indexesToAdd = collectionMatches ? mod.indexesToAdd : [];\n const indexesToRemove = collectionMatches ? mod.indexesToRemove : [];\n const rulesToUpdate = collectionMatches ? mod.rulesToUpdate : [];\n const permissionsToUpdate = collectionMatches ? mod.permissionsToUpdate : [];\n const viewQueryUpdate = collectionMatches ? mod.viewQueryUpdate : undefined;\n\n return {\n ...mod,\n fieldsToAdd,\n fieldsToRemove,\n fieldsToModify,\n indexesToAdd,\n indexesToRemove,\n rulesToUpdate,\n permissionsToUpdate,\n viewQueryUpdate\n };\n }).filter(mod => {\n // Keep modification object only if there is something left to modify\n return mod.fieldsToAdd.length > 0 ||\n mod.fieldsToRemove.length > 0 ||\n mod.fieldsToModify.length > 0 ||\n mod.indexesToAdd.length > 0 ||\n mod.indexesToRemove.length > 0 ||\n mod.rulesToUpdate.length > 0 ||\n mod.permissionsToUpdate.length > 0 ||\n mod.viewQueryUpdate !== undefined;\n });\n\n return {\n ...diff,\n collectionsToCreate,\n collectionsToDelete,\n collectionsToModify\n };\n}\n","/**\n * Diff Engine component\n * Compares current schema with previous snapshot and identifies changes\n *\n * This module provides a standalone, configurable diff engine that can be used\n * by consumer projects to compare schema definitions and detect changes.\n */\n\nimport type { CollectionModification, SchemaDefinition, SchemaDiff, SchemaSnapshot } from \"../types\";\nimport { CollectionIdRegistry } from \"../utils/collection-id-generator\";\nimport {\n buildCollectionModification,\n findNewCollections,\n findRemovedCollections,\n matchCollectionsByName,\n} from \"./collections\";\nimport { mergeConfig, type DiffEngineConfig } from \"./config\";\nimport {\n categorizeChangesBySeverity,\n generateChangeSummary,\n type ChangeSummary,\n} from \"./summary\";\nimport { isSystemCollection } from \"./utils\";\nimport { detectDestructiveChanges, type DestructiveChange, requiresForceFlag } from \"./destructiveness\";\n\n// Export everything from submodules\nexport * from \"./collections\";\nexport * from \"./config\";\nexport * from \"./destructiveness\";\nexport * from \"./fields\";\nexport * from \"./indexes\";\nexport * from \"./rules\";\nexport * from \"./summary\";\nexport * from \"./utils\";\n\n/**\n * Checks if a collection modification has any actual changes\n *\n * @param modification - Collection modification to check\n * @returns True if there are any changes\n */\nfunction hasChanges(modification: CollectionModification): boolean {\n return (\n modification.fieldsToAdd.length > 0 ||\n modification.fieldsToRemove.length > 0 ||\n modification.fieldsToModify.length > 0 ||\n modification.indexesToAdd.length > 0 ||\n modification.indexesToRemove.length > 0 ||\n modification.rulesToUpdate.length > 0 ||\n modification.permissionsToUpdate.length > 0 ||\n modification.viewQueryUpdate !== undefined\n );\n}\n\n/**\n * Aggregates all detected changes into a SchemaDiff\n * Main entry point for diff comparison\n *\n * @param currentSchema - Current schema definition\n * @param previousSnapshot - Previous schema snapshot\n * @param config - Optional configuration\n * @returns Complete SchemaDiff with all changes\n */\nexport function aggregateChanges(\n currentSchema: SchemaDefinition,\n previousSnapshot: SchemaSnapshot | null,\n config?: DiffEngineConfig\n): SchemaDiff {\n // Build lookup map for ID -> Name from previous snapshot\n // This helps resolve relations where snapshot uses ID but schema uses Name\n const collectionIdToName = new Map<string, string>();\n if (previousSnapshot) {\n for (const [name, collection] of previousSnapshot.collections) {\n if (collection.id) {\n collectionIdToName.set(collection.id, name);\n }\n }\n }\n\n // Find new and removed collections\n const collectionsToCreate = findNewCollections(currentSchema, previousSnapshot);\n const collectionsToDelete = findRemovedCollections(currentSchema, previousSnapshot);\n\n // Filter out system collections from create and delete operations\n const filteredCollectionsToCreate = collectionsToCreate.filter(\n (collection) => !isSystemCollection(collection.name, config)\n );\n const filteredCollectionsToDelete = collectionsToDelete.filter(\n (collection) => !isSystemCollection(collection.name, config)\n );\n\n // Generate and assign collection IDs for new collections\n const registry = new CollectionIdRegistry();\n const collectionsWithIds = filteredCollectionsToCreate.map((collection) => {\n // If the collection already has an ID, register it and use it\n if (collection.id) {\n registry.register(collection.id);\n return collection;\n }\n\n // Generate a new ID for the collection (pass name for special handling)\n const id = registry.generate(collection.name);\n return {\n ...collection,\n id,\n };\n });\n\n // Find modified collections\n const collectionsToModify: CollectionModification[] = [];\n const matchedCollections = matchCollectionsByName(currentSchema, previousSnapshot);\n\n for (const [currentCollection, previousCollection] of matchedCollections) {\n const modification = buildCollectionModification(currentCollection, previousCollection, config, collectionIdToName);\n\n // Only include if there are actual changes\n // Note: We allow modifications to the users collection (non-system)\n if (hasChanges(modification)) {\n collectionsToModify.push(modification);\n }\n }\n\n // Build map of existing collection names to their IDs from the snapshot\n // This is used by the generator to resolve relation field references\n const existingCollectionIds = new Map<string, string>();\n if (previousSnapshot) {\n for (const [name, collection] of previousSnapshot.collections) {\n if (collection.id) {\n existingCollectionIds.set(name, collection.id);\n }\n }\n }\n\n return {\n collectionsToCreate: collectionsWithIds,\n collectionsToDelete: filteredCollectionsToDelete,\n collectionsToModify,\n existingCollectionIds,\n };\n}\n\n/**\n * Main comparison function\n * Compares current schema with previous snapshot and returns complete diff\n *\n * @param currentSchema - Current schema definition\n * @param previousSnapshot - Previous schema snapshot (null for first run)\n * @param config - Optional configuration\n * @returns Complete SchemaDiff with all detected changes\n */\nexport function compare(\n currentSchema: SchemaDefinition,\n previousSnapshot: SchemaSnapshot | null,\n config?: DiffEngineConfig\n): SchemaDiff {\n return aggregateChanges(currentSchema, previousSnapshot, config);\n}\n\n/**\n * DiffEngine class for object-oriented usage\n * Provides a stateful interface for schema comparison\n */\nexport class DiffEngine {\n private config: Required<DiffEngineConfig>;\n\n constructor(config?: DiffEngineConfig) {\n this.config = mergeConfig(config);\n }\n\n /**\n * Compares current schema with previous snapshot\n */\n compare(currentSchema: SchemaDefinition, previousSnapshot: SchemaSnapshot | null): SchemaDiff {\n return compare(currentSchema, previousSnapshot, this.config);\n }\n\n /**\n * Detects destructive changes in a diff\n */\n detectDestructiveChanges(diff: SchemaDiff): DestructiveChange[] {\n return detectDestructiveChanges(diff, this.config);\n }\n\n /**\n * Categorizes changes by severity\n */\n categorizeChangesBySeverity(diff: SchemaDiff): { destructive: string[]; nonDestructive: string[] } {\n return categorizeChangesBySeverity(diff, this.config);\n }\n\n /**\n * Generates a summary of changes\n */\n generateChangeSummary(diff: SchemaDiff): ChangeSummary {\n return generateChangeSummary(diff, this.config);\n }\n\n /**\n * Checks if force flag is required\n */\n requiresForceFlag(diff: SchemaDiff): boolean {\n return requiresForceFlag(diff, this.config);\n }\n}\nexport * from \"./filter.js\";\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { e as SchemaDiff, S as SchemaDefinition, a as SchemaSnapshot, C as CollectionSchema, d as CollectionModification, F as FieldDefinition, b as FieldChange, P as PermissionChange, R as RuleUpdate } from '../types-
|
|
1
|
+
import { e as SchemaDiff, S as SchemaDefinition, a as SchemaSnapshot, C as CollectionSchema, d as CollectionModification, F as FieldDefinition, b as FieldChange, P as PermissionChange, R as RuleUpdate } from '../types-CnzfX6JH.cjs';
|
|
2
2
|
import '../fields-B96iGprI.cjs';
|
|
3
3
|
import 'zod';
|
|
4
4
|
|
|
@@ -88,6 +88,7 @@ interface ChangeSummary {
|
|
|
88
88
|
indexChanges: number;
|
|
89
89
|
ruleChanges: number;
|
|
90
90
|
permissionChanges: number;
|
|
91
|
+
viewQueryChanges: number;
|
|
91
92
|
destructiveChanges: DestructiveChange[];
|
|
92
93
|
nonDestructiveChanges: string[];
|
|
93
94
|
}
|
|
@@ -147,6 +148,15 @@ declare function findRemovedCollections(currentSchema: SchemaDefinition, previou
|
|
|
147
148
|
* @returns Array of matched collection pairs
|
|
148
149
|
*/
|
|
149
150
|
declare function matchCollectionsByName(currentSchema: SchemaDefinition, previousSnapshot: SchemaSnapshot | null): Array<[CollectionSchema, CollectionSchema]>;
|
|
151
|
+
/**
|
|
152
|
+
* Normalizes a SQL view query for comparison
|
|
153
|
+
* Collapses whitespace so re-indenting or re-wrapping a query does not produce
|
|
154
|
+
* a migration
|
|
155
|
+
*
|
|
156
|
+
* @param query - The SQL query
|
|
157
|
+
* @returns Normalized query text
|
|
158
|
+
*/
|
|
159
|
+
declare function normalizeSql(query: string | null | undefined): string;
|
|
150
160
|
/**
|
|
151
161
|
* Builds a CollectionModification for a matched collection pair
|
|
152
162
|
*
|
|
@@ -357,4 +367,4 @@ declare class DiffEngine {
|
|
|
357
367
|
requiresForceFlag(diff: SchemaDiff): boolean;
|
|
358
368
|
}
|
|
359
369
|
|
|
360
|
-
export { type ChangeSummary, DEFAULT_CONFIG, type DestructiveChange, DiffEngine, type DiffEngineConfig, type FilterOptions, aggregateChanges, areValuesEqual, buildCollectionModification, categorizeChangesBySeverity, compare, compareFieldConstraints, compareFieldOptions, compareFieldTypes, compareIndexes, comparePermissions, compareRelationConfigurations, compareRules, detectDestructiveChanges, detectFieldChanges, filterDiff, filterSystemCollections, findNewCollections, findNewFields, findRemovedCollections, findRemovedFields, generateChangeSummary, getUsersSystemFields, isSystemCollection, matchCollectionsByName, matchFieldsByName, mergeConfig, normalizeOptionValue, requiresForceFlag };
|
|
370
|
+
export { type ChangeSummary, DEFAULT_CONFIG, type DestructiveChange, DiffEngine, type DiffEngineConfig, type FilterOptions, aggregateChanges, areValuesEqual, buildCollectionModification, categorizeChangesBySeverity, compare, compareFieldConstraints, compareFieldOptions, compareFieldTypes, compareIndexes, comparePermissions, compareRelationConfigurations, compareRules, detectDestructiveChanges, detectFieldChanges, filterDiff, filterSystemCollections, findNewCollections, findNewFields, findRemovedCollections, findRemovedFields, generateChangeSummary, getUsersSystemFields, isSystemCollection, matchCollectionsByName, matchFieldsByName, mergeConfig, normalizeOptionValue, normalizeSql, requiresForceFlag };
|