pocketbase-zod-schema 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +233 -98
- package/dist/cli/index.cjs +449 -108
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +447 -106
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/migrate.cjs +452 -111
- package/dist/cli/migrate.cjs.map +1 -1
- package/dist/cli/migrate.js +447 -106
- package/dist/cli/migrate.js.map +1 -1
- package/dist/index.cjs +593 -175
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +583 -172
- package/dist/index.js.map +1 -1
- package/dist/migration/analyzer.cjs +44 -6
- package/dist/migration/analyzer.cjs.map +1 -1
- package/dist/migration/analyzer.d.cts +11 -1
- package/dist/migration/analyzer.d.ts +11 -1
- package/dist/migration/analyzer.js +44 -7
- package/dist/migration/analyzer.js.map +1 -1
- package/dist/migration/diff.cjs +21 -3
- package/dist/migration/diff.cjs.map +1 -1
- package/dist/migration/diff.js +21 -3
- package/dist/migration/diff.js.map +1 -1
- package/dist/migration/index.cjs +500 -129
- package/dist/migration/index.cjs.map +1 -1
- package/dist/migration/index.d.cts +1 -1
- package/dist/migration/index.d.ts +1 -1
- package/dist/migration/index.js +499 -129
- package/dist/migration/index.js.map +1 -1
- package/dist/migration/snapshot.cjs +432 -118
- package/dist/migration/snapshot.cjs.map +1 -1
- package/dist/migration/snapshot.d.cts +34 -12
- package/dist/migration/snapshot.d.ts +34 -12
- package/dist/migration/snapshot.js +430 -117
- package/dist/migration/snapshot.js.map +1 -1
- package/dist/mutator.cjs +20 -21
- package/dist/mutator.cjs.map +1 -1
- package/dist/mutator.d.cts +4 -4
- package/dist/mutator.d.ts +4 -4
- package/dist/mutator.js +20 -21
- package/dist/mutator.js.map +1 -1
- package/dist/schema.cjs +69 -10
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +98 -8
- package/dist/schema.d.ts +98 -8
- package/dist/schema.js +62 -9
- package/dist/schema.js.map +1 -1
- package/dist/types.d.cts +5 -2
- package/dist/types.d.ts +5 -2
- package/dist/user-DTJQIj4K.d.cts +149 -0
- package/dist/user-DTJQIj4K.d.ts +149 -0
- package/package.json +3 -3
- package/dist/user-C39DQ40N.d.cts +0 -53
- package/dist/user-C39DQ40N.d.ts +0 -53
package/dist/migration/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var fs3 = require('fs');
|
|
4
4
|
var path = require('path');
|
|
5
5
|
var zod = require('zod');
|
|
6
6
|
|
|
@@ -22,7 +22,7 @@ function _interopNamespace(e) {
|
|
|
22
22
|
return Object.freeze(n);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
var
|
|
25
|
+
var fs3__namespace = /*#__PURE__*/_interopNamespace(fs3);
|
|
26
26
|
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
27
27
|
|
|
28
28
|
// src/migration/analyzer.ts
|
|
@@ -153,10 +153,10 @@ var FileSystemError = class _FileSystemError extends MigrationError {
|
|
|
153
153
|
operation;
|
|
154
154
|
code;
|
|
155
155
|
originalError;
|
|
156
|
-
constructor(message,
|
|
156
|
+
constructor(message, path5, operation, code, originalError) {
|
|
157
157
|
super(message);
|
|
158
158
|
this.name = "FileSystemError";
|
|
159
|
-
this.path =
|
|
159
|
+
this.path = path5;
|
|
160
160
|
this.operation = operation;
|
|
161
161
|
this.code = code;
|
|
162
162
|
this.originalError = originalError;
|
|
@@ -1342,6 +1342,16 @@ function getFieldTypeInfo(zodType, fieldName) {
|
|
|
1342
1342
|
}
|
|
1343
1343
|
|
|
1344
1344
|
// src/migration/analyzer.ts
|
|
1345
|
+
var tsxLoaderRegistered = false;
|
|
1346
|
+
async function ensureTsxLoader() {
|
|
1347
|
+
if (tsxLoaderRegistered) return;
|
|
1348
|
+
try {
|
|
1349
|
+
await import('tsx/esm');
|
|
1350
|
+
tsxLoaderRegistered = true;
|
|
1351
|
+
} catch {
|
|
1352
|
+
tsxLoaderRegistered = false;
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1345
1355
|
var DEFAULT_CONFIG = {
|
|
1346
1356
|
workspaceRoot: process.cwd(),
|
|
1347
1357
|
excludePatterns: [
|
|
@@ -1379,10 +1389,10 @@ function discoverSchemaFiles(config) {
|
|
|
1379
1389
|
const mergedConfig = mergeConfig(normalizedConfig);
|
|
1380
1390
|
const schemaDir = resolveSchemaDir(normalizedConfig);
|
|
1381
1391
|
try {
|
|
1382
|
-
if (!
|
|
1392
|
+
if (!fs3__namespace.existsSync(schemaDir)) {
|
|
1383
1393
|
throw new FileSystemError(`Schema directory not found: ${schemaDir}`, schemaDir, "access", "ENOENT");
|
|
1384
1394
|
}
|
|
1385
|
-
const files =
|
|
1395
|
+
const files = fs3__namespace.readdirSync(schemaDir);
|
|
1386
1396
|
const schemaFiles = files.filter((file) => {
|
|
1387
1397
|
const hasValidExtension = mergedConfig.includeExtensions.some((ext) => file.endsWith(ext));
|
|
1388
1398
|
if (!hasValidExtension) return false;
|
|
@@ -1432,31 +1442,44 @@ async function importSchemaModule(filePath, config) {
|
|
|
1432
1442
|
let resolvedPath = null;
|
|
1433
1443
|
const jsPath = `${importPath}.js`;
|
|
1434
1444
|
const tsPath = `${importPath}.ts`;
|
|
1435
|
-
if (
|
|
1445
|
+
if (fs3__namespace.existsSync(jsPath)) {
|
|
1436
1446
|
resolvedPath = jsPath;
|
|
1437
|
-
} else if (
|
|
1447
|
+
} else if (fs3__namespace.existsSync(tsPath)) {
|
|
1438
1448
|
resolvedPath = tsPath;
|
|
1439
1449
|
} else {
|
|
1440
1450
|
resolvedPath = jsPath;
|
|
1441
1451
|
}
|
|
1452
|
+
if (resolvedPath.endsWith(".ts")) {
|
|
1453
|
+
await ensureTsxLoader();
|
|
1454
|
+
if (!tsxLoaderRegistered) {
|
|
1455
|
+
throw new SchemaParsingError(
|
|
1456
|
+
`Failed to import TypeScript schema file. The 'tsx' package is required to load TypeScript files.
|
|
1457
|
+
Please install tsx: npm install tsx (or yarn add tsx, or pnpm add tsx)
|
|
1458
|
+
Alternatively, compile your schema files to JavaScript first.`,
|
|
1459
|
+
filePath
|
|
1460
|
+
);
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1442
1463
|
const fileUrl = new URL(`file://${path__namespace.resolve(resolvedPath)}`);
|
|
1443
1464
|
const module = await import(fileUrl.href);
|
|
1444
1465
|
return module;
|
|
1445
1466
|
} catch (error) {
|
|
1446
1467
|
const tsPath = `${filePath}.ts`;
|
|
1447
|
-
const isTypeScriptFile =
|
|
1468
|
+
const isTypeScriptFile = fs3__namespace.existsSync(tsPath);
|
|
1469
|
+
if (isTypeScriptFile && error instanceof SchemaParsingError) {
|
|
1470
|
+
throw error;
|
|
1471
|
+
}
|
|
1448
1472
|
if (isTypeScriptFile) {
|
|
1449
1473
|
throw new SchemaParsingError(
|
|
1450
|
-
`Failed to import TypeScript schema file.
|
|
1451
|
-
Please
|
|
1452
|
-
|
|
1453
|
-
2. Use tsx to run the migration tool (e.g., "npx tsx package/dist/cli/migrate.js status" or "tsx package/dist/cli/migrate.js status")`,
|
|
1474
|
+
`Failed to import TypeScript schema file. The 'tsx' package is required to load TypeScript files.
|
|
1475
|
+
Please install tsx: npm install tsx (or yarn add tsx, or pnpm add tsx)
|
|
1476
|
+
Alternatively, compile your schema files to JavaScript first.`,
|
|
1454
1477
|
filePath,
|
|
1455
1478
|
error
|
|
1456
1479
|
);
|
|
1457
1480
|
}
|
|
1458
1481
|
throw new SchemaParsingError(
|
|
1459
|
-
`Failed to import schema module. Make sure the schema files
|
|
1482
|
+
`Failed to import schema module. Make sure the schema files exist and are valid.`,
|
|
1460
1483
|
filePath,
|
|
1461
1484
|
error
|
|
1462
1485
|
);
|
|
@@ -1466,6 +1489,19 @@ function getCollectionNameFromFile(filePath) {
|
|
|
1466
1489
|
const filename = path__namespace.basename(filePath).replace(/\.(ts|js)$/, "");
|
|
1467
1490
|
return toCollectionName(filename);
|
|
1468
1491
|
}
|
|
1492
|
+
function extractCollectionNameFromSchema(zodSchema) {
|
|
1493
|
+
if (!zodSchema.description) {
|
|
1494
|
+
return null;
|
|
1495
|
+
}
|
|
1496
|
+
try {
|
|
1497
|
+
const metadata = JSON.parse(zodSchema.description);
|
|
1498
|
+
if (metadata.collectionName && typeof metadata.collectionName === "string") {
|
|
1499
|
+
return metadata.collectionName;
|
|
1500
|
+
}
|
|
1501
|
+
} catch {
|
|
1502
|
+
}
|
|
1503
|
+
return null;
|
|
1504
|
+
}
|
|
1469
1505
|
function extractSchemaDefinitions(module, patterns = ["Schema", "InputSchema"]) {
|
|
1470
1506
|
const result = {};
|
|
1471
1507
|
for (const [key, value] of Object.entries(module)) {
|
|
@@ -1628,7 +1664,7 @@ async function buildSchemaDefinition(config) {
|
|
|
1628
1664
|
importPath = normalizedConfig.pathTransformer(filePath);
|
|
1629
1665
|
} else if (mergedConfig.useCompiledFiles) {
|
|
1630
1666
|
const distPath = filePath.replace(/\/src\//, "/dist/");
|
|
1631
|
-
if (
|
|
1667
|
+
if (fs3__namespace.existsSync(`${distPath}.js`) || fs3__namespace.existsSync(`${distPath}.mjs`)) {
|
|
1632
1668
|
importPath = distPath;
|
|
1633
1669
|
} else {
|
|
1634
1670
|
importPath = filePath;
|
|
@@ -1641,7 +1677,8 @@ async function buildSchemaDefinition(config) {
|
|
|
1641
1677
|
console.warn(`No valid schema found in ${filePath}, skipping...`);
|
|
1642
1678
|
continue;
|
|
1643
1679
|
}
|
|
1644
|
-
const
|
|
1680
|
+
const collectionNameFromSchema = extractCollectionNameFromSchema(zodSchema);
|
|
1681
|
+
const collectionName = collectionNameFromSchema ?? getCollectionNameFromFile(filePath);
|
|
1645
1682
|
const collectionSchema = convertZodSchemaToCollectionSchema(collectionName, zodSchema);
|
|
1646
1683
|
collections.set(collectionName, collectionSchema);
|
|
1647
1684
|
} catch (error) {
|
|
@@ -1684,7 +1721,359 @@ var SchemaAnalyzer = class {
|
|
|
1684
1721
|
return convertZodSchemaToCollectionSchema(name, schema);
|
|
1685
1722
|
}
|
|
1686
1723
|
};
|
|
1724
|
+
|
|
1725
|
+
// src/migration/pocketbase-converter.ts
|
|
1687
1726
|
var SNAPSHOT_VERSION = "1.0.0";
|
|
1727
|
+
function resolveCollectionIdToName(collectionId) {
|
|
1728
|
+
if (collectionId === "_pb_users_auth_") {
|
|
1729
|
+
return "Users";
|
|
1730
|
+
}
|
|
1731
|
+
const nameMatch = collectionId.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
1732
|
+
if (nameMatch) {
|
|
1733
|
+
return nameMatch[1];
|
|
1734
|
+
}
|
|
1735
|
+
return collectionId;
|
|
1736
|
+
}
|
|
1737
|
+
function convertPocketBaseCollection(pbCollection) {
|
|
1738
|
+
const fields = [];
|
|
1739
|
+
const systemFieldNames = ["id", "created", "updated", "collectionId", "collectionName", "expand"];
|
|
1740
|
+
const authSystemFieldNames = ["email", "emailVisibility", "verified", "password", "tokenKey"];
|
|
1741
|
+
if (pbCollection.fields && Array.isArray(pbCollection.fields)) {
|
|
1742
|
+
for (const pbField of pbCollection.fields) {
|
|
1743
|
+
if (pbField.system || systemFieldNames.includes(pbField.name)) {
|
|
1744
|
+
continue;
|
|
1745
|
+
}
|
|
1746
|
+
if (pbCollection.type === "auth" && authSystemFieldNames.includes(pbField.name)) {
|
|
1747
|
+
continue;
|
|
1748
|
+
}
|
|
1749
|
+
const field = {
|
|
1750
|
+
name: pbField.name,
|
|
1751
|
+
type: pbField.type,
|
|
1752
|
+
required: pbField.required || false
|
|
1753
|
+
};
|
|
1754
|
+
field.options = pbField.options ? { ...pbField.options } : {};
|
|
1755
|
+
if (pbField.type === "select") {
|
|
1756
|
+
if (pbField.values && Array.isArray(pbField.values)) {
|
|
1757
|
+
field.options.values = pbField.values;
|
|
1758
|
+
} else if (pbField.options?.values && Array.isArray(pbField.options.values)) {
|
|
1759
|
+
field.options.values = pbField.options.values;
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
if (pbField.type === "relation") {
|
|
1763
|
+
const collectionId = pbField.collectionId || pbField.options?.collectionId || "";
|
|
1764
|
+
const collectionName = resolveCollectionIdToName(collectionId);
|
|
1765
|
+
field.relation = {
|
|
1766
|
+
collection: collectionName,
|
|
1767
|
+
cascadeDelete: pbField.cascadeDelete ?? pbField.options?.cascadeDelete ?? false,
|
|
1768
|
+
maxSelect: pbField.maxSelect ?? pbField.options?.maxSelect,
|
|
1769
|
+
minSelect: pbField.minSelect ?? pbField.options?.minSelect
|
|
1770
|
+
};
|
|
1771
|
+
}
|
|
1772
|
+
const hasOnlyValues = Object.keys(field.options).length === 1 && field.options.values !== void 0;
|
|
1773
|
+
if (Object.keys(field.options).length === 0) {
|
|
1774
|
+
delete field.options;
|
|
1775
|
+
} else if (pbField.type === "select" && hasOnlyValues) ;
|
|
1776
|
+
fields.push(field);
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
const schema = {
|
|
1780
|
+
name: pbCollection.name,
|
|
1781
|
+
type: pbCollection.type || "base",
|
|
1782
|
+
fields
|
|
1783
|
+
};
|
|
1784
|
+
if (pbCollection.indexes && Array.isArray(pbCollection.indexes)) {
|
|
1785
|
+
schema.indexes = pbCollection.indexes;
|
|
1786
|
+
}
|
|
1787
|
+
const rules = {};
|
|
1788
|
+
if (pbCollection.listRule !== void 0) rules.listRule = pbCollection.listRule;
|
|
1789
|
+
if (pbCollection.viewRule !== void 0) rules.viewRule = pbCollection.viewRule;
|
|
1790
|
+
if (pbCollection.createRule !== void 0) rules.createRule = pbCollection.createRule;
|
|
1791
|
+
if (pbCollection.updateRule !== void 0) rules.updateRule = pbCollection.updateRule;
|
|
1792
|
+
if (pbCollection.deleteRule !== void 0) rules.deleteRule = pbCollection.deleteRule;
|
|
1793
|
+
if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
|
|
1794
|
+
if (Object.keys(rules).length > 0) {
|
|
1795
|
+
schema.rules = rules;
|
|
1796
|
+
schema.permissions = { ...rules };
|
|
1797
|
+
}
|
|
1798
|
+
return schema;
|
|
1799
|
+
}
|
|
1800
|
+
function convertPocketBaseMigration(migrationContent) {
|
|
1801
|
+
try {
|
|
1802
|
+
const snapshotMatch = migrationContent.match(/const\s+snapshot\s*=\s*(\[[\s\S]*?\]);/);
|
|
1803
|
+
if (!snapshotMatch) {
|
|
1804
|
+
throw new Error("Could not find snapshot array in migration file");
|
|
1805
|
+
}
|
|
1806
|
+
const snapshotArrayStr = snapshotMatch[1];
|
|
1807
|
+
let snapshotArray;
|
|
1808
|
+
try {
|
|
1809
|
+
snapshotArray = new Function(`return ${snapshotArrayStr}`)();
|
|
1810
|
+
} catch (parseError) {
|
|
1811
|
+
throw new Error(`Failed to parse snapshot array: ${parseError}`);
|
|
1812
|
+
}
|
|
1813
|
+
if (!Array.isArray(snapshotArray)) {
|
|
1814
|
+
throw new Error("Snapshot is not an array");
|
|
1815
|
+
}
|
|
1816
|
+
const collections = /* @__PURE__ */ new Map();
|
|
1817
|
+
for (const pbCollection of snapshotArray) {
|
|
1818
|
+
if (!pbCollection.name) {
|
|
1819
|
+
console.warn("Skipping collection without name");
|
|
1820
|
+
continue;
|
|
1821
|
+
}
|
|
1822
|
+
const schema = convertPocketBaseCollection(pbCollection);
|
|
1823
|
+
collections.set(pbCollection.name, schema);
|
|
1824
|
+
}
|
|
1825
|
+
return {
|
|
1826
|
+
version: SNAPSHOT_VERSION,
|
|
1827
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1828
|
+
collections
|
|
1829
|
+
};
|
|
1830
|
+
} catch (error) {
|
|
1831
|
+
throw new SnapshotError(
|
|
1832
|
+
`Failed to convert PocketBase migration: ${error instanceof Error ? error.message : String(error)}`,
|
|
1833
|
+
void 0,
|
|
1834
|
+
"parse",
|
|
1835
|
+
error instanceof Error ? error : void 0
|
|
1836
|
+
);
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
// src/migration/migration-parser.ts
|
|
1841
|
+
function extractTimestampFromFilename(filename) {
|
|
1842
|
+
const match = filename.match(/^(\d+)_/);
|
|
1843
|
+
if (match) {
|
|
1844
|
+
return parseInt(match[1], 10);
|
|
1845
|
+
}
|
|
1846
|
+
return null;
|
|
1847
|
+
}
|
|
1848
|
+
function findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp) {
|
|
1849
|
+
try {
|
|
1850
|
+
if (!fs3__namespace.existsSync(migrationsPath)) {
|
|
1851
|
+
return [];
|
|
1852
|
+
}
|
|
1853
|
+
const files = fs3__namespace.readdirSync(migrationsPath);
|
|
1854
|
+
const migrationFiles = [];
|
|
1855
|
+
for (const file of files) {
|
|
1856
|
+
if (file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")) {
|
|
1857
|
+
continue;
|
|
1858
|
+
}
|
|
1859
|
+
if (!file.endsWith(".js")) {
|
|
1860
|
+
continue;
|
|
1861
|
+
}
|
|
1862
|
+
const timestamp = extractTimestampFromFilename(file);
|
|
1863
|
+
if (timestamp && timestamp > snapshotTimestamp) {
|
|
1864
|
+
migrationFiles.push({
|
|
1865
|
+
path: path__namespace.join(migrationsPath, file),
|
|
1866
|
+
timestamp
|
|
1867
|
+
});
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
migrationFiles.sort((a, b) => a.timestamp - b.timestamp);
|
|
1871
|
+
return migrationFiles.map((f) => f.path);
|
|
1872
|
+
} catch (error) {
|
|
1873
|
+
console.warn(`Error finding migrations after snapshot: ${error}`);
|
|
1874
|
+
return [];
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
function parseMigrationOperationsFromContent(content) {
|
|
1878
|
+
const collectionsToCreate = [];
|
|
1879
|
+
const collectionsToDelete = [];
|
|
1880
|
+
try {
|
|
1881
|
+
let searchIndex = 0;
|
|
1882
|
+
while (true) {
|
|
1883
|
+
const collectionStart = content.indexOf("new Collection(", searchIndex);
|
|
1884
|
+
if (collectionStart === -1) {
|
|
1885
|
+
break;
|
|
1886
|
+
}
|
|
1887
|
+
const openParen = collectionStart + "new Collection(".length;
|
|
1888
|
+
let braceCount = 0;
|
|
1889
|
+
let parenCount = 1;
|
|
1890
|
+
let inString = false;
|
|
1891
|
+
let stringChar = null;
|
|
1892
|
+
let i = openParen;
|
|
1893
|
+
while (i < content.length && /\s/.test(content[i])) {
|
|
1894
|
+
i++;
|
|
1895
|
+
}
|
|
1896
|
+
if (content[i] !== "{") {
|
|
1897
|
+
searchIndex = i + 1;
|
|
1898
|
+
continue;
|
|
1899
|
+
}
|
|
1900
|
+
const objectStart = i;
|
|
1901
|
+
braceCount = 1;
|
|
1902
|
+
i++;
|
|
1903
|
+
while (i < content.length && (braceCount > 0 || parenCount > 0)) {
|
|
1904
|
+
const char = content[i];
|
|
1905
|
+
const prevChar = i > 0 ? content[i - 1] : "";
|
|
1906
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
1907
|
+
inString = true;
|
|
1908
|
+
stringChar = char;
|
|
1909
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
1910
|
+
inString = false;
|
|
1911
|
+
stringChar = null;
|
|
1912
|
+
}
|
|
1913
|
+
if (!inString) {
|
|
1914
|
+
if (char === "{") braceCount++;
|
|
1915
|
+
if (char === "}") braceCount--;
|
|
1916
|
+
if (char === "(") parenCount++;
|
|
1917
|
+
if (char === ")") parenCount--;
|
|
1918
|
+
}
|
|
1919
|
+
i++;
|
|
1920
|
+
}
|
|
1921
|
+
if (braceCount === 0 && parenCount === 0) {
|
|
1922
|
+
const objectContent = content.substring(objectStart, i - 1);
|
|
1923
|
+
try {
|
|
1924
|
+
const collectionObj = new Function(`return ${objectContent}`)();
|
|
1925
|
+
if (collectionObj && collectionObj.name) {
|
|
1926
|
+
const schema = convertPocketBaseCollection(collectionObj);
|
|
1927
|
+
collectionsToCreate.push(schema);
|
|
1928
|
+
}
|
|
1929
|
+
} catch (error) {
|
|
1930
|
+
console.warn(`Failed to parse collection definition: ${error}`);
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
searchIndex = i;
|
|
1934
|
+
}
|
|
1935
|
+
const deleteMatches = content.matchAll(
|
|
1936
|
+
/app\.delete\s*\(\s*(?:collection_\w+|app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\))\s*\)/g
|
|
1937
|
+
);
|
|
1938
|
+
for (const match of deleteMatches) {
|
|
1939
|
+
if (match[1]) {
|
|
1940
|
+
collectionsToDelete.push(match[1]);
|
|
1941
|
+
} else {
|
|
1942
|
+
const varNameMatch = match[0].match(/collection_(\w+)/);
|
|
1943
|
+
if (varNameMatch) {
|
|
1944
|
+
const varName = `collection_${varNameMatch[1]}`;
|
|
1945
|
+
const deleteIndex = content.indexOf(match[0]);
|
|
1946
|
+
const beforeDelete = content.substring(0, deleteIndex);
|
|
1947
|
+
const varDefMatch = beforeDelete.match(
|
|
1948
|
+
new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`, "g")
|
|
1949
|
+
);
|
|
1950
|
+
if (varDefMatch && varDefMatch.length > 0) {
|
|
1951
|
+
const collectionDefMatch = beforeDelete.match(
|
|
1952
|
+
new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`)
|
|
1953
|
+
);
|
|
1954
|
+
if (collectionDefMatch) {
|
|
1955
|
+
try {
|
|
1956
|
+
const collectionDefStr = collectionDefMatch[1];
|
|
1957
|
+
const collectionObj = new Function(`return ${collectionDefStr}`)();
|
|
1958
|
+
if (collectionObj && collectionObj.name) {
|
|
1959
|
+
collectionsToDelete.push(collectionObj.name);
|
|
1960
|
+
}
|
|
1961
|
+
} catch {
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
const findAndDeleteMatches = content.matchAll(
|
|
1969
|
+
/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)[\s\S]*?app\.delete/g
|
|
1970
|
+
);
|
|
1971
|
+
for (const match of findAndDeleteMatches) {
|
|
1972
|
+
collectionsToDelete.push(match[1]);
|
|
1973
|
+
}
|
|
1974
|
+
} catch (error) {
|
|
1975
|
+
console.warn(`Failed to parse migration operations from content: ${error}`);
|
|
1976
|
+
}
|
|
1977
|
+
return { collectionsToCreate, collectionsToDelete };
|
|
1978
|
+
}
|
|
1979
|
+
function parseMigrationOperations(migrationContent) {
|
|
1980
|
+
try {
|
|
1981
|
+
const migrateMatch = migrationContent.match(/migrate\s*\(\s*/);
|
|
1982
|
+
if (!migrateMatch) {
|
|
1983
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
1984
|
+
}
|
|
1985
|
+
const startIndex = migrateMatch.index + migrateMatch[0].length;
|
|
1986
|
+
let i = startIndex;
|
|
1987
|
+
let parenCount = 0;
|
|
1988
|
+
let foundFirstParen = false;
|
|
1989
|
+
while (i < migrationContent.length) {
|
|
1990
|
+
const char = migrationContent[i];
|
|
1991
|
+
if (char === "(") {
|
|
1992
|
+
parenCount++;
|
|
1993
|
+
foundFirstParen = true;
|
|
1994
|
+
i++;
|
|
1995
|
+
break;
|
|
1996
|
+
}
|
|
1997
|
+
i++;
|
|
1998
|
+
}
|
|
1999
|
+
if (!foundFirstParen) {
|
|
2000
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2001
|
+
}
|
|
2002
|
+
let inString = false;
|
|
2003
|
+
let stringChar = null;
|
|
2004
|
+
let foundBrace = false;
|
|
2005
|
+
let braceStart = -1;
|
|
2006
|
+
while (i < migrationContent.length && !foundBrace) {
|
|
2007
|
+
const char = migrationContent[i];
|
|
2008
|
+
const prevChar = i > 0 ? migrationContent[i - 1] : "";
|
|
2009
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2010
|
+
inString = true;
|
|
2011
|
+
stringChar = char;
|
|
2012
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2013
|
+
inString = false;
|
|
2014
|
+
stringChar = null;
|
|
2015
|
+
}
|
|
2016
|
+
if (!inString) {
|
|
2017
|
+
if (char === "(") parenCount++;
|
|
2018
|
+
if (char === ")") {
|
|
2019
|
+
parenCount--;
|
|
2020
|
+
if (parenCount === 0) {
|
|
2021
|
+
i++;
|
|
2022
|
+
while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
|
|
2023
|
+
i++;
|
|
2024
|
+
}
|
|
2025
|
+
if (i < migrationContent.length - 1 && migrationContent[i] === "=" && migrationContent[i + 1] === ">") {
|
|
2026
|
+
i += 2;
|
|
2027
|
+
while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
|
|
2028
|
+
i++;
|
|
2029
|
+
}
|
|
2030
|
+
if (i < migrationContent.length && migrationContent[i] === "{") {
|
|
2031
|
+
foundBrace = true;
|
|
2032
|
+
braceStart = i + 1;
|
|
2033
|
+
break;
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
i++;
|
|
2040
|
+
}
|
|
2041
|
+
if (!foundBrace || braceStart === -1) {
|
|
2042
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2043
|
+
}
|
|
2044
|
+
let braceCount = 1;
|
|
2045
|
+
i = braceStart;
|
|
2046
|
+
inString = false;
|
|
2047
|
+
stringChar = null;
|
|
2048
|
+
while (i < migrationContent.length && braceCount > 0) {
|
|
2049
|
+
const char = migrationContent[i];
|
|
2050
|
+
const prevChar = i > 0 ? migrationContent[i - 1] : "";
|
|
2051
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2052
|
+
inString = true;
|
|
2053
|
+
stringChar = char;
|
|
2054
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2055
|
+
inString = false;
|
|
2056
|
+
stringChar = null;
|
|
2057
|
+
}
|
|
2058
|
+
if (!inString) {
|
|
2059
|
+
if (char === "{") braceCount++;
|
|
2060
|
+
if (char === "}") braceCount--;
|
|
2061
|
+
}
|
|
2062
|
+
i++;
|
|
2063
|
+
}
|
|
2064
|
+
if (braceCount === 0) {
|
|
2065
|
+
const upMigrationContent = migrationContent.substring(braceStart, i - 1);
|
|
2066
|
+
return parseMigrationOperationsFromContent(upMigrationContent);
|
|
2067
|
+
}
|
|
2068
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2069
|
+
} catch (error) {
|
|
2070
|
+
console.warn(`Failed to parse migration operations: ${error}`);
|
|
2071
|
+
return { collectionsToCreate: [], collectionsToDelete: [] };
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
|
|
2075
|
+
// src/migration/snapshot.ts
|
|
2076
|
+
var SNAPSHOT_VERSION2 = "1.0.0";
|
|
1688
2077
|
var DEFAULT_SNAPSHOT_FILENAME = ".migration-snapshot.json";
|
|
1689
2078
|
var SNAPSHOT_MIGRATIONS = [
|
|
1690
2079
|
// Add migrations here as the format evolves
|
|
@@ -1699,7 +2088,7 @@ var DEFAULT_CONFIG2 = {
|
|
|
1699
2088
|
snapshotPath: DEFAULT_SNAPSHOT_FILENAME,
|
|
1700
2089
|
workspaceRoot: process.cwd(),
|
|
1701
2090
|
autoMigrate: true,
|
|
1702
|
-
version:
|
|
2091
|
+
version: SNAPSHOT_VERSION2
|
|
1703
2092
|
};
|
|
1704
2093
|
function mergeConfig2(config = {}) {
|
|
1705
2094
|
return {
|
|
@@ -1719,7 +2108,7 @@ function getSnapshotPath(config = {}) {
|
|
|
1719
2108
|
function snapshotExists(config = {}) {
|
|
1720
2109
|
try {
|
|
1721
2110
|
const snapshotPath = getSnapshotPath(config);
|
|
1722
|
-
return
|
|
2111
|
+
return fs3__namespace.existsSync(snapshotPath);
|
|
1723
2112
|
} catch {
|
|
1724
2113
|
return false;
|
|
1725
2114
|
}
|
|
@@ -1779,12 +2168,12 @@ function saveSnapshot(schema, config = {}) {
|
|
|
1779
2168
|
const snapshotPath = getSnapshotPath(config);
|
|
1780
2169
|
try {
|
|
1781
2170
|
const snapshotDir = path__namespace.dirname(snapshotPath);
|
|
1782
|
-
if (!
|
|
1783
|
-
|
|
2171
|
+
if (!fs3__namespace.existsSync(snapshotDir)) {
|
|
2172
|
+
fs3__namespace.mkdirSync(snapshotDir, { recursive: true });
|
|
1784
2173
|
}
|
|
1785
2174
|
const snapshotData = addSnapshotMetadata(schema, config);
|
|
1786
2175
|
const jsonContent = JSON.stringify(snapshotData, null, 2);
|
|
1787
|
-
|
|
2176
|
+
fs3__namespace.writeFileSync(snapshotPath, jsonContent, "utf-8");
|
|
1788
2177
|
} catch (error) {
|
|
1789
2178
|
handleFileSystemError(error, "write", snapshotPath);
|
|
1790
2179
|
}
|
|
@@ -1879,7 +2268,7 @@ function deserializeSnapshot(data) {
|
|
|
1879
2268
|
function loadSnapshot(config = {}) {
|
|
1880
2269
|
const snapshotPath = getSnapshotPath(config);
|
|
1881
2270
|
try {
|
|
1882
|
-
const jsonContent =
|
|
2271
|
+
const jsonContent = fs3__namespace.readFileSync(snapshotPath, "utf-8");
|
|
1883
2272
|
const data = parseAndValidateSnapshot(jsonContent, snapshotPath);
|
|
1884
2273
|
const migratedData = migrateSnapshotFormat(data, config);
|
|
1885
2274
|
return deserializeSnapshot(migratedData);
|
|
@@ -1914,10 +2303,10 @@ function mergeSnapshots(baseSnapshot, customSnapshot) {
|
|
|
1914
2303
|
}
|
|
1915
2304
|
function findLatestSnapshot(migrationsPath) {
|
|
1916
2305
|
try {
|
|
1917
|
-
if (!
|
|
2306
|
+
if (!fs3__namespace.existsSync(migrationsPath)) {
|
|
1918
2307
|
return null;
|
|
1919
2308
|
}
|
|
1920
|
-
const files =
|
|
2309
|
+
const files = fs3__namespace.readdirSync(migrationsPath);
|
|
1921
2310
|
const snapshotFiles = files.filter(
|
|
1922
2311
|
(file) => file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")
|
|
1923
2312
|
);
|
|
@@ -1935,14 +2324,68 @@ function findLatestSnapshot(migrationsPath) {
|
|
|
1935
2324
|
return null;
|
|
1936
2325
|
}
|
|
1937
2326
|
}
|
|
2327
|
+
function applyMigrationOperations(snapshot, operations) {
|
|
2328
|
+
const updatedCollections = new Map(snapshot.collections);
|
|
2329
|
+
for (const collectionName of operations.collectionsToDelete) {
|
|
2330
|
+
updatedCollections.delete(collectionName);
|
|
2331
|
+
}
|
|
2332
|
+
for (const collection of operations.collectionsToCreate) {
|
|
2333
|
+
updatedCollections.set(collection.name, collection);
|
|
2334
|
+
}
|
|
2335
|
+
return {
|
|
2336
|
+
...snapshot,
|
|
2337
|
+
collections: updatedCollections
|
|
2338
|
+
};
|
|
2339
|
+
}
|
|
2340
|
+
function loadSnapshotWithMigrations(config = {}) {
|
|
2341
|
+
const migrationsPath = config.migrationsPath;
|
|
2342
|
+
if (!migrationsPath) {
|
|
2343
|
+
return null;
|
|
2344
|
+
}
|
|
2345
|
+
if (fs3__namespace.existsSync(migrationsPath) && fs3__namespace.statSync(migrationsPath).isFile()) {
|
|
2346
|
+
try {
|
|
2347
|
+
const migrationContent = fs3__namespace.readFileSync(migrationsPath, "utf-8");
|
|
2348
|
+
return convertPocketBaseMigration(migrationContent);
|
|
2349
|
+
} catch (error) {
|
|
2350
|
+
console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
|
|
2351
|
+
return null;
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
const latestSnapshotPath = findLatestSnapshot(migrationsPath);
|
|
2355
|
+
if (!latestSnapshotPath) {
|
|
2356
|
+
return null;
|
|
2357
|
+
}
|
|
2358
|
+
try {
|
|
2359
|
+
const migrationContent = fs3__namespace.readFileSync(latestSnapshotPath, "utf-8");
|
|
2360
|
+
let snapshot = convertPocketBaseMigration(migrationContent);
|
|
2361
|
+
const snapshotFilename = path__namespace.basename(latestSnapshotPath);
|
|
2362
|
+
const snapshotTimestamp = extractTimestampFromFilename(snapshotFilename);
|
|
2363
|
+
if (snapshotTimestamp) {
|
|
2364
|
+
const migrationFiles = findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp);
|
|
2365
|
+
for (const migrationFile of migrationFiles) {
|
|
2366
|
+
try {
|
|
2367
|
+
const migrationContent2 = fs3__namespace.readFileSync(migrationFile, "utf-8");
|
|
2368
|
+
const operations = parseMigrationOperations(migrationContent2);
|
|
2369
|
+
snapshot = applyMigrationOperations(snapshot, operations);
|
|
2370
|
+
} catch (error) {
|
|
2371
|
+
console.warn(`Failed to apply migration ${migrationFile}: ${error}`);
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
return snapshot;
|
|
2376
|
+
} catch (error) {
|
|
2377
|
+
console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
|
|
2378
|
+
return null;
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
1938
2381
|
function loadSnapshotIfExists(config = {}) {
|
|
1939
2382
|
const migrationsPath = config.migrationsPath;
|
|
1940
2383
|
if (!migrationsPath) {
|
|
1941
2384
|
return null;
|
|
1942
2385
|
}
|
|
1943
|
-
if (
|
|
2386
|
+
if (fs3__namespace.existsSync(migrationsPath) && fs3__namespace.statSync(migrationsPath).isFile()) {
|
|
1944
2387
|
try {
|
|
1945
|
-
const migrationContent =
|
|
2388
|
+
const migrationContent = fs3__namespace.readFileSync(migrationsPath, "utf-8");
|
|
1946
2389
|
return convertPocketBaseMigration(migrationContent);
|
|
1947
2390
|
} catch (error) {
|
|
1948
2391
|
console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
|
|
@@ -1952,7 +2395,7 @@ function loadSnapshotIfExists(config = {}) {
|
|
|
1952
2395
|
const latestSnapshotPath = findLatestSnapshot(migrationsPath);
|
|
1953
2396
|
if (latestSnapshotPath) {
|
|
1954
2397
|
try {
|
|
1955
|
-
const migrationContent =
|
|
2398
|
+
const migrationContent = fs3__namespace.readFileSync(latestSnapshotPath, "utf-8");
|
|
1956
2399
|
return convertPocketBaseMigration(migrationContent);
|
|
1957
2400
|
} catch (error) {
|
|
1958
2401
|
console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
|
|
@@ -1961,100 +2404,9 @@ function loadSnapshotIfExists(config = {}) {
|
|
|
1961
2404
|
}
|
|
1962
2405
|
return null;
|
|
1963
2406
|
}
|
|
1964
|
-
function convertPocketBaseCollection(pbCollection) {
|
|
1965
|
-
const fields = [];
|
|
1966
|
-
const systemFieldNames = ["id", "created", "updated", "collectionId", "collectionName", "expand"];
|
|
1967
|
-
const authSystemFieldNames = ["email", "emailVisibility", "verified", "password", "tokenKey"];
|
|
1968
|
-
if (pbCollection.fields && Array.isArray(pbCollection.fields)) {
|
|
1969
|
-
for (const pbField of pbCollection.fields) {
|
|
1970
|
-
if (pbField.system || systemFieldNames.includes(pbField.name)) {
|
|
1971
|
-
continue;
|
|
1972
|
-
}
|
|
1973
|
-
if (pbCollection.type === "auth" && authSystemFieldNames.includes(pbField.name)) {
|
|
1974
|
-
continue;
|
|
1975
|
-
}
|
|
1976
|
-
const field = {
|
|
1977
|
-
name: pbField.name,
|
|
1978
|
-
type: pbField.type,
|
|
1979
|
-
required: pbField.required || false
|
|
1980
|
-
};
|
|
1981
|
-
if (pbField.options) {
|
|
1982
|
-
field.options = pbField.options;
|
|
1983
|
-
}
|
|
1984
|
-
if (pbField.type === "relation") {
|
|
1985
|
-
field.relation = {
|
|
1986
|
-
collection: pbField.options?.collectionId || "",
|
|
1987
|
-
cascadeDelete: pbField.options?.cascadeDelete || false,
|
|
1988
|
-
maxSelect: pbField.options?.maxSelect,
|
|
1989
|
-
minSelect: pbField.options?.minSelect
|
|
1990
|
-
};
|
|
1991
|
-
}
|
|
1992
|
-
fields.push(field);
|
|
1993
|
-
}
|
|
1994
|
-
}
|
|
1995
|
-
const schema = {
|
|
1996
|
-
name: pbCollection.name,
|
|
1997
|
-
type: pbCollection.type || "base",
|
|
1998
|
-
fields
|
|
1999
|
-
};
|
|
2000
|
-
if (pbCollection.indexes && Array.isArray(pbCollection.indexes)) {
|
|
2001
|
-
schema.indexes = pbCollection.indexes;
|
|
2002
|
-
}
|
|
2003
|
-
const rules = {};
|
|
2004
|
-
if (pbCollection.listRule !== void 0) rules.listRule = pbCollection.listRule;
|
|
2005
|
-
if (pbCollection.viewRule !== void 0) rules.viewRule = pbCollection.viewRule;
|
|
2006
|
-
if (pbCollection.createRule !== void 0) rules.createRule = pbCollection.createRule;
|
|
2007
|
-
if (pbCollection.updateRule !== void 0) rules.updateRule = pbCollection.updateRule;
|
|
2008
|
-
if (pbCollection.deleteRule !== void 0) rules.deleteRule = pbCollection.deleteRule;
|
|
2009
|
-
if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
|
|
2010
|
-
if (Object.keys(rules).length > 0) {
|
|
2011
|
-
schema.rules = rules;
|
|
2012
|
-
schema.permissions = { ...rules };
|
|
2013
|
-
}
|
|
2014
|
-
return schema;
|
|
2015
|
-
}
|
|
2016
|
-
function convertPocketBaseMigration(migrationContent) {
|
|
2017
|
-
try {
|
|
2018
|
-
const snapshotMatch = migrationContent.match(/const\s+snapshot\s*=\s*(\[[\s\S]*?\]);/);
|
|
2019
|
-
if (!snapshotMatch) {
|
|
2020
|
-
throw new Error("Could not find snapshot array in migration file");
|
|
2021
|
-
}
|
|
2022
|
-
const snapshotArrayStr = snapshotMatch[1];
|
|
2023
|
-
let snapshotArray;
|
|
2024
|
-
try {
|
|
2025
|
-
snapshotArray = new Function(`return ${snapshotArrayStr}`)();
|
|
2026
|
-
} catch (parseError) {
|
|
2027
|
-
throw new Error(`Failed to parse snapshot array: ${parseError}`);
|
|
2028
|
-
}
|
|
2029
|
-
if (!Array.isArray(snapshotArray)) {
|
|
2030
|
-
throw new Error("Snapshot is not an array");
|
|
2031
|
-
}
|
|
2032
|
-
const collections = /* @__PURE__ */ new Map();
|
|
2033
|
-
for (const pbCollection of snapshotArray) {
|
|
2034
|
-
if (!pbCollection.name) {
|
|
2035
|
-
console.warn("Skipping collection without name");
|
|
2036
|
-
continue;
|
|
2037
|
-
}
|
|
2038
|
-
const schema = convertPocketBaseCollection(pbCollection);
|
|
2039
|
-
collections.set(pbCollection.name, schema);
|
|
2040
|
-
}
|
|
2041
|
-
return {
|
|
2042
|
-
version: SNAPSHOT_VERSION,
|
|
2043
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2044
|
-
collections
|
|
2045
|
-
};
|
|
2046
|
-
} catch (error) {
|
|
2047
|
-
throw new SnapshotError(
|
|
2048
|
-
`Failed to convert PocketBase migration: ${error instanceof Error ? error.message : String(error)}`,
|
|
2049
|
-
void 0,
|
|
2050
|
-
"parse",
|
|
2051
|
-
error instanceof Error ? error : void 0
|
|
2052
|
-
);
|
|
2053
|
-
}
|
|
2054
|
-
}
|
|
2055
2407
|
function loadBaseMigration(migrationPath) {
|
|
2056
2408
|
try {
|
|
2057
|
-
if (!
|
|
2409
|
+
if (!fs3__namespace.existsSync(migrationPath)) {
|
|
2058
2410
|
throw new SnapshotError(
|
|
2059
2411
|
`Base migration file not found: ${migrationPath}
|
|
2060
2412
|
|
|
@@ -2065,7 +2417,7 @@ If the file exists in a different location, update the configuration.`,
|
|
|
2065
2417
|
"read"
|
|
2066
2418
|
);
|
|
2067
2419
|
}
|
|
2068
|
-
const migrationContent =
|
|
2420
|
+
const migrationContent = fs3__namespace.readFileSync(migrationPath, "utf-8");
|
|
2069
2421
|
const snapshot = convertPocketBaseMigration(migrationContent);
|
|
2070
2422
|
return snapshot;
|
|
2071
2423
|
} catch (error) {
|
|
@@ -2101,14 +2453,14 @@ Please ensure PocketBase is properly set up by running 'yarn setup'.`,
|
|
|
2101
2453
|
}
|
|
2102
2454
|
}
|
|
2103
2455
|
function getSnapshotVersion() {
|
|
2104
|
-
return
|
|
2456
|
+
return SNAPSHOT_VERSION2;
|
|
2105
2457
|
}
|
|
2106
2458
|
function validateSnapshot(snapshot) {
|
|
2107
2459
|
const issues = [];
|
|
2108
2460
|
if (!snapshot.version) {
|
|
2109
2461
|
issues.push("Missing version field");
|
|
2110
|
-
} else if (compareVersions(snapshot.version,
|
|
2111
|
-
issues.push(`Snapshot version ${snapshot.version} is newer than supported version ${
|
|
2462
|
+
} else if (compareVersions(snapshot.version, SNAPSHOT_VERSION2) > 0) {
|
|
2463
|
+
issues.push(`Snapshot version ${snapshot.version} is newer than supported version ${SNAPSHOT_VERSION2}`);
|
|
2112
2464
|
}
|
|
2113
2465
|
if (!snapshot.timestamp) {
|
|
2114
2466
|
issues.push("Missing timestamp field");
|
|
@@ -2327,6 +2679,9 @@ function compareFieldOptions(currentField, previousField) {
|
|
|
2327
2679
|
for (const key of allKeys) {
|
|
2328
2680
|
const currentValue = currentOptions[key];
|
|
2329
2681
|
const previousValue = previousOptions[key];
|
|
2682
|
+
if (currentValue === void 0 && previousValue === void 0) {
|
|
2683
|
+
continue;
|
|
2684
|
+
}
|
|
2330
2685
|
if (!areValuesEqual(currentValue, previousValue)) {
|
|
2331
2686
|
changes.push({
|
|
2332
2687
|
property: `options.${key}`,
|
|
@@ -2347,11 +2702,26 @@ function compareRelationConfigurations(currentField, previousField) {
|
|
|
2347
2702
|
if (!currentRelation || !previousRelation) {
|
|
2348
2703
|
return changes;
|
|
2349
2704
|
}
|
|
2350
|
-
|
|
2705
|
+
const normalizeCollection = (collection) => {
|
|
2706
|
+
if (!collection) return collection;
|
|
2707
|
+
if (collection === "_pb_users_auth_") {
|
|
2708
|
+
return "Users";
|
|
2709
|
+
}
|
|
2710
|
+
const nameMatch = collection.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
2711
|
+
if (nameMatch) {
|
|
2712
|
+
return nameMatch[1];
|
|
2713
|
+
}
|
|
2714
|
+
return collection;
|
|
2715
|
+
};
|
|
2716
|
+
const normalizedCurrent = normalizeCollection(currentRelation.collection);
|
|
2717
|
+
const normalizedPrevious = normalizeCollection(previousRelation.collection);
|
|
2718
|
+
if (normalizedCurrent !== normalizedPrevious) {
|
|
2351
2719
|
changes.push({
|
|
2352
2720
|
property: "relation.collection",
|
|
2353
|
-
oldValue:
|
|
2354
|
-
|
|
2721
|
+
oldValue: normalizedPrevious,
|
|
2722
|
+
// Use normalized value for clarity
|
|
2723
|
+
newValue: normalizedCurrent
|
|
2724
|
+
// Use normalized value for clarity
|
|
2355
2725
|
});
|
|
2356
2726
|
}
|
|
2357
2727
|
if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {
|
|
@@ -2785,9 +3155,9 @@ function createMigrationFileStructure(upCode, downCode, config) {
|
|
|
2785
3155
|
}
|
|
2786
3156
|
function writeMigrationFile(migrationDir, filename, content) {
|
|
2787
3157
|
try {
|
|
2788
|
-
if (!
|
|
3158
|
+
if (!fs3__namespace.existsSync(migrationDir)) {
|
|
2789
3159
|
try {
|
|
2790
|
-
|
|
3160
|
+
fs3__namespace.mkdirSync(migrationDir, { recursive: true });
|
|
2791
3161
|
} catch (error) {
|
|
2792
3162
|
const fsError = error;
|
|
2793
3163
|
if (fsError.code === "EACCES" || fsError.code === "EPERM") {
|
|
@@ -2809,7 +3179,7 @@ function writeMigrationFile(migrationDir, filename, content) {
|
|
|
2809
3179
|
}
|
|
2810
3180
|
}
|
|
2811
3181
|
const filePath = path__namespace.join(migrationDir, filename);
|
|
2812
|
-
|
|
3182
|
+
fs3__namespace.writeFileSync(filePath, content, "utf-8");
|
|
2813
3183
|
return filePath;
|
|
2814
3184
|
} catch (error) {
|
|
2815
3185
|
if (error instanceof FileSystemError) {
|
|
@@ -3472,6 +3842,7 @@ exports.isSystemCollection = isSystemCollection;
|
|
|
3472
3842
|
exports.loadBaseMigration = loadBaseMigration;
|
|
3473
3843
|
exports.loadSnapshot = loadSnapshot;
|
|
3474
3844
|
exports.loadSnapshotIfExists = loadSnapshotIfExists;
|
|
3845
|
+
exports.loadSnapshotWithMigrations = loadSnapshotWithMigrations;
|
|
3475
3846
|
exports.mapZodArrayType = mapZodArrayType;
|
|
3476
3847
|
exports.mapZodBooleanType = mapZodBooleanType;
|
|
3477
3848
|
exports.mapZodDateType = mapZodDateType;
|