pocketbase-zod-schema 0.1.3 → 0.1.4
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 +7 -0
- package/dist/cli/index.cjs +406 -102
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +404 -100
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/migrate.cjs +409 -105
- package/dist/cli/migrate.cjs.map +1 -1
- package/dist/cli/migrate.js +404 -100
- package/dist/cli/migrate.js.map +1 -1
- package/dist/index.cjs +515 -159
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +511 -158
- package/dist/index.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 +457 -123
- 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 +456 -123
- 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.d.cts +3 -3
- package/dist/mutator.d.ts +3 -3
- package/dist/schema.cjs +34 -0
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +33 -1
- package/dist/schema.js.map +1 -1
- package/dist/types.d.cts +5 -2
- package/dist/types.d.ts +5 -2
- package/dist/user-_AM523hb.d.cts +123 -0
- package/dist/user-_AM523hb.d.ts +123 -0
- package/package.json +2 -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;
|
|
@@ -1379,10 +1379,10 @@ function discoverSchemaFiles(config) {
|
|
|
1379
1379
|
const mergedConfig = mergeConfig(normalizedConfig);
|
|
1380
1380
|
const schemaDir = resolveSchemaDir(normalizedConfig);
|
|
1381
1381
|
try {
|
|
1382
|
-
if (!
|
|
1382
|
+
if (!fs3__namespace.existsSync(schemaDir)) {
|
|
1383
1383
|
throw new FileSystemError(`Schema directory not found: ${schemaDir}`, schemaDir, "access", "ENOENT");
|
|
1384
1384
|
}
|
|
1385
|
-
const files =
|
|
1385
|
+
const files = fs3__namespace.readdirSync(schemaDir);
|
|
1386
1386
|
const schemaFiles = files.filter((file) => {
|
|
1387
1387
|
const hasValidExtension = mergedConfig.includeExtensions.some((ext) => file.endsWith(ext));
|
|
1388
1388
|
if (!hasValidExtension) return false;
|
|
@@ -1432,9 +1432,9 @@ async function importSchemaModule(filePath, config) {
|
|
|
1432
1432
|
let resolvedPath = null;
|
|
1433
1433
|
const jsPath = `${importPath}.js`;
|
|
1434
1434
|
const tsPath = `${importPath}.ts`;
|
|
1435
|
-
if (
|
|
1435
|
+
if (fs3__namespace.existsSync(jsPath)) {
|
|
1436
1436
|
resolvedPath = jsPath;
|
|
1437
|
-
} else if (
|
|
1437
|
+
} else if (fs3__namespace.existsSync(tsPath)) {
|
|
1438
1438
|
resolvedPath = tsPath;
|
|
1439
1439
|
} else {
|
|
1440
1440
|
resolvedPath = jsPath;
|
|
@@ -1444,7 +1444,7 @@ async function importSchemaModule(filePath, config) {
|
|
|
1444
1444
|
return module;
|
|
1445
1445
|
} catch (error) {
|
|
1446
1446
|
const tsPath = `${filePath}.ts`;
|
|
1447
|
-
const isTypeScriptFile =
|
|
1447
|
+
const isTypeScriptFile = fs3__namespace.existsSync(tsPath);
|
|
1448
1448
|
if (isTypeScriptFile) {
|
|
1449
1449
|
throw new SchemaParsingError(
|
|
1450
1450
|
`Failed to import TypeScript schema file. Node.js cannot import TypeScript files directly.
|
|
@@ -1628,7 +1628,7 @@ async function buildSchemaDefinition(config) {
|
|
|
1628
1628
|
importPath = normalizedConfig.pathTransformer(filePath);
|
|
1629
1629
|
} else if (mergedConfig.useCompiledFiles) {
|
|
1630
1630
|
const distPath = filePath.replace(/\/src\//, "/dist/");
|
|
1631
|
-
if (
|
|
1631
|
+
if (fs3__namespace.existsSync(`${distPath}.js`) || fs3__namespace.existsSync(`${distPath}.mjs`)) {
|
|
1632
1632
|
importPath = distPath;
|
|
1633
1633
|
} else {
|
|
1634
1634
|
importPath = filePath;
|
|
@@ -1684,7 +1684,359 @@ var SchemaAnalyzer = class {
|
|
|
1684
1684
|
return convertZodSchemaToCollectionSchema(name, schema);
|
|
1685
1685
|
}
|
|
1686
1686
|
};
|
|
1687
|
+
|
|
1688
|
+
// src/migration/pocketbase-converter.ts
|
|
1687
1689
|
var SNAPSHOT_VERSION = "1.0.0";
|
|
1690
|
+
function resolveCollectionIdToName(collectionId) {
|
|
1691
|
+
if (collectionId === "_pb_users_auth_") {
|
|
1692
|
+
return "Users";
|
|
1693
|
+
}
|
|
1694
|
+
const nameMatch = collectionId.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
1695
|
+
if (nameMatch) {
|
|
1696
|
+
return nameMatch[1];
|
|
1697
|
+
}
|
|
1698
|
+
return collectionId;
|
|
1699
|
+
}
|
|
1700
|
+
function convertPocketBaseCollection(pbCollection) {
|
|
1701
|
+
const fields = [];
|
|
1702
|
+
const systemFieldNames = ["id", "created", "updated", "collectionId", "collectionName", "expand"];
|
|
1703
|
+
const authSystemFieldNames = ["email", "emailVisibility", "verified", "password", "tokenKey"];
|
|
1704
|
+
if (pbCollection.fields && Array.isArray(pbCollection.fields)) {
|
|
1705
|
+
for (const pbField of pbCollection.fields) {
|
|
1706
|
+
if (pbField.system || systemFieldNames.includes(pbField.name)) {
|
|
1707
|
+
continue;
|
|
1708
|
+
}
|
|
1709
|
+
if (pbCollection.type === "auth" && authSystemFieldNames.includes(pbField.name)) {
|
|
1710
|
+
continue;
|
|
1711
|
+
}
|
|
1712
|
+
const field = {
|
|
1713
|
+
name: pbField.name,
|
|
1714
|
+
type: pbField.type,
|
|
1715
|
+
required: pbField.required || false
|
|
1716
|
+
};
|
|
1717
|
+
field.options = pbField.options ? { ...pbField.options } : {};
|
|
1718
|
+
if (pbField.type === "select") {
|
|
1719
|
+
if (pbField.values && Array.isArray(pbField.values)) {
|
|
1720
|
+
field.options.values = pbField.values;
|
|
1721
|
+
} else if (pbField.options?.values && Array.isArray(pbField.options.values)) {
|
|
1722
|
+
field.options.values = pbField.options.values;
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
if (pbField.type === "relation") {
|
|
1726
|
+
const collectionId = pbField.collectionId || pbField.options?.collectionId || "";
|
|
1727
|
+
const collectionName = resolveCollectionIdToName(collectionId);
|
|
1728
|
+
field.relation = {
|
|
1729
|
+
collection: collectionName,
|
|
1730
|
+
cascadeDelete: pbField.cascadeDelete ?? pbField.options?.cascadeDelete ?? false,
|
|
1731
|
+
maxSelect: pbField.maxSelect ?? pbField.options?.maxSelect,
|
|
1732
|
+
minSelect: pbField.minSelect ?? pbField.options?.minSelect
|
|
1733
|
+
};
|
|
1734
|
+
}
|
|
1735
|
+
const hasOnlyValues = Object.keys(field.options).length === 1 && field.options.values !== void 0;
|
|
1736
|
+
if (Object.keys(field.options).length === 0) {
|
|
1737
|
+
delete field.options;
|
|
1738
|
+
} else if (pbField.type === "select" && hasOnlyValues) ;
|
|
1739
|
+
fields.push(field);
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
const schema = {
|
|
1743
|
+
name: pbCollection.name,
|
|
1744
|
+
type: pbCollection.type || "base",
|
|
1745
|
+
fields
|
|
1746
|
+
};
|
|
1747
|
+
if (pbCollection.indexes && Array.isArray(pbCollection.indexes)) {
|
|
1748
|
+
schema.indexes = pbCollection.indexes;
|
|
1749
|
+
}
|
|
1750
|
+
const rules = {};
|
|
1751
|
+
if (pbCollection.listRule !== void 0) rules.listRule = pbCollection.listRule;
|
|
1752
|
+
if (pbCollection.viewRule !== void 0) rules.viewRule = pbCollection.viewRule;
|
|
1753
|
+
if (pbCollection.createRule !== void 0) rules.createRule = pbCollection.createRule;
|
|
1754
|
+
if (pbCollection.updateRule !== void 0) rules.updateRule = pbCollection.updateRule;
|
|
1755
|
+
if (pbCollection.deleteRule !== void 0) rules.deleteRule = pbCollection.deleteRule;
|
|
1756
|
+
if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
|
|
1757
|
+
if (Object.keys(rules).length > 0) {
|
|
1758
|
+
schema.rules = rules;
|
|
1759
|
+
schema.permissions = { ...rules };
|
|
1760
|
+
}
|
|
1761
|
+
return schema;
|
|
1762
|
+
}
|
|
1763
|
+
function convertPocketBaseMigration(migrationContent) {
|
|
1764
|
+
try {
|
|
1765
|
+
const snapshotMatch = migrationContent.match(/const\s+snapshot\s*=\s*(\[[\s\S]*?\]);/);
|
|
1766
|
+
if (!snapshotMatch) {
|
|
1767
|
+
throw new Error("Could not find snapshot array in migration file");
|
|
1768
|
+
}
|
|
1769
|
+
const snapshotArrayStr = snapshotMatch[1];
|
|
1770
|
+
let snapshotArray;
|
|
1771
|
+
try {
|
|
1772
|
+
snapshotArray = new Function(`return ${snapshotArrayStr}`)();
|
|
1773
|
+
} catch (parseError) {
|
|
1774
|
+
throw new Error(`Failed to parse snapshot array: ${parseError}`);
|
|
1775
|
+
}
|
|
1776
|
+
if (!Array.isArray(snapshotArray)) {
|
|
1777
|
+
throw new Error("Snapshot is not an array");
|
|
1778
|
+
}
|
|
1779
|
+
const collections = /* @__PURE__ */ new Map();
|
|
1780
|
+
for (const pbCollection of snapshotArray) {
|
|
1781
|
+
if (!pbCollection.name) {
|
|
1782
|
+
console.warn("Skipping collection without name");
|
|
1783
|
+
continue;
|
|
1784
|
+
}
|
|
1785
|
+
const schema = convertPocketBaseCollection(pbCollection);
|
|
1786
|
+
collections.set(pbCollection.name, schema);
|
|
1787
|
+
}
|
|
1788
|
+
return {
|
|
1789
|
+
version: SNAPSHOT_VERSION,
|
|
1790
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1791
|
+
collections
|
|
1792
|
+
};
|
|
1793
|
+
} catch (error) {
|
|
1794
|
+
throw new SnapshotError(
|
|
1795
|
+
`Failed to convert PocketBase migration: ${error instanceof Error ? error.message : String(error)}`,
|
|
1796
|
+
void 0,
|
|
1797
|
+
"parse",
|
|
1798
|
+
error instanceof Error ? error : void 0
|
|
1799
|
+
);
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
// src/migration/migration-parser.ts
|
|
1804
|
+
function extractTimestampFromFilename(filename) {
|
|
1805
|
+
const match = filename.match(/^(\d+)_/);
|
|
1806
|
+
if (match) {
|
|
1807
|
+
return parseInt(match[1], 10);
|
|
1808
|
+
}
|
|
1809
|
+
return null;
|
|
1810
|
+
}
|
|
1811
|
+
function findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp) {
|
|
1812
|
+
try {
|
|
1813
|
+
if (!fs3__namespace.existsSync(migrationsPath)) {
|
|
1814
|
+
return [];
|
|
1815
|
+
}
|
|
1816
|
+
const files = fs3__namespace.readdirSync(migrationsPath);
|
|
1817
|
+
const migrationFiles = [];
|
|
1818
|
+
for (const file of files) {
|
|
1819
|
+
if (file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")) {
|
|
1820
|
+
continue;
|
|
1821
|
+
}
|
|
1822
|
+
if (!file.endsWith(".js")) {
|
|
1823
|
+
continue;
|
|
1824
|
+
}
|
|
1825
|
+
const timestamp = extractTimestampFromFilename(file);
|
|
1826
|
+
if (timestamp && timestamp > snapshotTimestamp) {
|
|
1827
|
+
migrationFiles.push({
|
|
1828
|
+
path: path__namespace.join(migrationsPath, file),
|
|
1829
|
+
timestamp
|
|
1830
|
+
});
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
migrationFiles.sort((a, b) => a.timestamp - b.timestamp);
|
|
1834
|
+
return migrationFiles.map((f) => f.path);
|
|
1835
|
+
} catch (error) {
|
|
1836
|
+
console.warn(`Error finding migrations after snapshot: ${error}`);
|
|
1837
|
+
return [];
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
function parseMigrationOperationsFromContent(content) {
|
|
1841
|
+
const collectionsToCreate = [];
|
|
1842
|
+
const collectionsToDelete = [];
|
|
1843
|
+
try {
|
|
1844
|
+
let searchIndex = 0;
|
|
1845
|
+
while (true) {
|
|
1846
|
+
const collectionStart = content.indexOf("new Collection(", searchIndex);
|
|
1847
|
+
if (collectionStart === -1) {
|
|
1848
|
+
break;
|
|
1849
|
+
}
|
|
1850
|
+
const openParen = collectionStart + "new Collection(".length;
|
|
1851
|
+
let braceCount = 0;
|
|
1852
|
+
let parenCount = 1;
|
|
1853
|
+
let inString = false;
|
|
1854
|
+
let stringChar = null;
|
|
1855
|
+
let i = openParen;
|
|
1856
|
+
while (i < content.length && /\s/.test(content[i])) {
|
|
1857
|
+
i++;
|
|
1858
|
+
}
|
|
1859
|
+
if (content[i] !== "{") {
|
|
1860
|
+
searchIndex = i + 1;
|
|
1861
|
+
continue;
|
|
1862
|
+
}
|
|
1863
|
+
const objectStart = i;
|
|
1864
|
+
braceCount = 1;
|
|
1865
|
+
i++;
|
|
1866
|
+
while (i < content.length && (braceCount > 0 || parenCount > 0)) {
|
|
1867
|
+
const char = content[i];
|
|
1868
|
+
const prevChar = i > 0 ? content[i - 1] : "";
|
|
1869
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
1870
|
+
inString = true;
|
|
1871
|
+
stringChar = char;
|
|
1872
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
1873
|
+
inString = false;
|
|
1874
|
+
stringChar = null;
|
|
1875
|
+
}
|
|
1876
|
+
if (!inString) {
|
|
1877
|
+
if (char === "{") braceCount++;
|
|
1878
|
+
if (char === "}") braceCount--;
|
|
1879
|
+
if (char === "(") parenCount++;
|
|
1880
|
+
if (char === ")") parenCount--;
|
|
1881
|
+
}
|
|
1882
|
+
i++;
|
|
1883
|
+
}
|
|
1884
|
+
if (braceCount === 0 && parenCount === 0) {
|
|
1885
|
+
const objectContent = content.substring(objectStart, i - 1);
|
|
1886
|
+
try {
|
|
1887
|
+
const collectionObj = new Function(`return ${objectContent}`)();
|
|
1888
|
+
if (collectionObj && collectionObj.name) {
|
|
1889
|
+
const schema = convertPocketBaseCollection(collectionObj);
|
|
1890
|
+
collectionsToCreate.push(schema);
|
|
1891
|
+
}
|
|
1892
|
+
} catch (error) {
|
|
1893
|
+
console.warn(`Failed to parse collection definition: ${error}`);
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
searchIndex = i;
|
|
1897
|
+
}
|
|
1898
|
+
const deleteMatches = content.matchAll(
|
|
1899
|
+
/app\.delete\s*\(\s*(?:collection_\w+|app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\))\s*\)/g
|
|
1900
|
+
);
|
|
1901
|
+
for (const match of deleteMatches) {
|
|
1902
|
+
if (match[1]) {
|
|
1903
|
+
collectionsToDelete.push(match[1]);
|
|
1904
|
+
} else {
|
|
1905
|
+
const varNameMatch = match[0].match(/collection_(\w+)/);
|
|
1906
|
+
if (varNameMatch) {
|
|
1907
|
+
const varName = `collection_${varNameMatch[1]}`;
|
|
1908
|
+
const deleteIndex = content.indexOf(match[0]);
|
|
1909
|
+
const beforeDelete = content.substring(0, deleteIndex);
|
|
1910
|
+
const varDefMatch = beforeDelete.match(
|
|
1911
|
+
new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`, "g")
|
|
1912
|
+
);
|
|
1913
|
+
if (varDefMatch && varDefMatch.length > 0) {
|
|
1914
|
+
const collectionDefMatch = beforeDelete.match(
|
|
1915
|
+
new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`)
|
|
1916
|
+
);
|
|
1917
|
+
if (collectionDefMatch) {
|
|
1918
|
+
try {
|
|
1919
|
+
const collectionDefStr = collectionDefMatch[1];
|
|
1920
|
+
const collectionObj = new Function(`return ${collectionDefStr}`)();
|
|
1921
|
+
if (collectionObj && collectionObj.name) {
|
|
1922
|
+
collectionsToDelete.push(collectionObj.name);
|
|
1923
|
+
}
|
|
1924
|
+
} catch {
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
const findAndDeleteMatches = content.matchAll(
|
|
1932
|
+
/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)[\s\S]*?app\.delete/g
|
|
1933
|
+
);
|
|
1934
|
+
for (const match of findAndDeleteMatches) {
|
|
1935
|
+
collectionsToDelete.push(match[1]);
|
|
1936
|
+
}
|
|
1937
|
+
} catch (error) {
|
|
1938
|
+
console.warn(`Failed to parse migration operations from content: ${error}`);
|
|
1939
|
+
}
|
|
1940
|
+
return { collectionsToCreate, collectionsToDelete };
|
|
1941
|
+
}
|
|
1942
|
+
function parseMigrationOperations(migrationContent) {
|
|
1943
|
+
try {
|
|
1944
|
+
const migrateMatch = migrationContent.match(/migrate\s*\(\s*/);
|
|
1945
|
+
if (!migrateMatch) {
|
|
1946
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
1947
|
+
}
|
|
1948
|
+
const startIndex = migrateMatch.index + migrateMatch[0].length;
|
|
1949
|
+
let i = startIndex;
|
|
1950
|
+
let parenCount = 0;
|
|
1951
|
+
let foundFirstParen = false;
|
|
1952
|
+
while (i < migrationContent.length) {
|
|
1953
|
+
const char = migrationContent[i];
|
|
1954
|
+
if (char === "(") {
|
|
1955
|
+
parenCount++;
|
|
1956
|
+
foundFirstParen = true;
|
|
1957
|
+
i++;
|
|
1958
|
+
break;
|
|
1959
|
+
}
|
|
1960
|
+
i++;
|
|
1961
|
+
}
|
|
1962
|
+
if (!foundFirstParen) {
|
|
1963
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
1964
|
+
}
|
|
1965
|
+
let inString = false;
|
|
1966
|
+
let stringChar = null;
|
|
1967
|
+
let foundBrace = false;
|
|
1968
|
+
let braceStart = -1;
|
|
1969
|
+
while (i < migrationContent.length && !foundBrace) {
|
|
1970
|
+
const char = migrationContent[i];
|
|
1971
|
+
const prevChar = i > 0 ? migrationContent[i - 1] : "";
|
|
1972
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
1973
|
+
inString = true;
|
|
1974
|
+
stringChar = char;
|
|
1975
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
1976
|
+
inString = false;
|
|
1977
|
+
stringChar = null;
|
|
1978
|
+
}
|
|
1979
|
+
if (!inString) {
|
|
1980
|
+
if (char === "(") parenCount++;
|
|
1981
|
+
if (char === ")") {
|
|
1982
|
+
parenCount--;
|
|
1983
|
+
if (parenCount === 0) {
|
|
1984
|
+
i++;
|
|
1985
|
+
while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
|
|
1986
|
+
i++;
|
|
1987
|
+
}
|
|
1988
|
+
if (i < migrationContent.length - 1 && migrationContent[i] === "=" && migrationContent[i + 1] === ">") {
|
|
1989
|
+
i += 2;
|
|
1990
|
+
while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
|
|
1991
|
+
i++;
|
|
1992
|
+
}
|
|
1993
|
+
if (i < migrationContent.length && migrationContent[i] === "{") {
|
|
1994
|
+
foundBrace = true;
|
|
1995
|
+
braceStart = i + 1;
|
|
1996
|
+
break;
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
i++;
|
|
2003
|
+
}
|
|
2004
|
+
if (!foundBrace || braceStart === -1) {
|
|
2005
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2006
|
+
}
|
|
2007
|
+
let braceCount = 1;
|
|
2008
|
+
i = braceStart;
|
|
2009
|
+
inString = false;
|
|
2010
|
+
stringChar = null;
|
|
2011
|
+
while (i < migrationContent.length && braceCount > 0) {
|
|
2012
|
+
const char = migrationContent[i];
|
|
2013
|
+
const prevChar = i > 0 ? migrationContent[i - 1] : "";
|
|
2014
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2015
|
+
inString = true;
|
|
2016
|
+
stringChar = char;
|
|
2017
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2018
|
+
inString = false;
|
|
2019
|
+
stringChar = null;
|
|
2020
|
+
}
|
|
2021
|
+
if (!inString) {
|
|
2022
|
+
if (char === "{") braceCount++;
|
|
2023
|
+
if (char === "}") braceCount--;
|
|
2024
|
+
}
|
|
2025
|
+
i++;
|
|
2026
|
+
}
|
|
2027
|
+
if (braceCount === 0) {
|
|
2028
|
+
const upMigrationContent = migrationContent.substring(braceStart, i - 1);
|
|
2029
|
+
return parseMigrationOperationsFromContent(upMigrationContent);
|
|
2030
|
+
}
|
|
2031
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2032
|
+
} catch (error) {
|
|
2033
|
+
console.warn(`Failed to parse migration operations: ${error}`);
|
|
2034
|
+
return { collectionsToCreate: [], collectionsToDelete: [] };
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2038
|
+
// src/migration/snapshot.ts
|
|
2039
|
+
var SNAPSHOT_VERSION2 = "1.0.0";
|
|
1688
2040
|
var DEFAULT_SNAPSHOT_FILENAME = ".migration-snapshot.json";
|
|
1689
2041
|
var SNAPSHOT_MIGRATIONS = [
|
|
1690
2042
|
// Add migrations here as the format evolves
|
|
@@ -1699,7 +2051,7 @@ var DEFAULT_CONFIG2 = {
|
|
|
1699
2051
|
snapshotPath: DEFAULT_SNAPSHOT_FILENAME,
|
|
1700
2052
|
workspaceRoot: process.cwd(),
|
|
1701
2053
|
autoMigrate: true,
|
|
1702
|
-
version:
|
|
2054
|
+
version: SNAPSHOT_VERSION2
|
|
1703
2055
|
};
|
|
1704
2056
|
function mergeConfig2(config = {}) {
|
|
1705
2057
|
return {
|
|
@@ -1719,7 +2071,7 @@ function getSnapshotPath(config = {}) {
|
|
|
1719
2071
|
function snapshotExists(config = {}) {
|
|
1720
2072
|
try {
|
|
1721
2073
|
const snapshotPath = getSnapshotPath(config);
|
|
1722
|
-
return
|
|
2074
|
+
return fs3__namespace.existsSync(snapshotPath);
|
|
1723
2075
|
} catch {
|
|
1724
2076
|
return false;
|
|
1725
2077
|
}
|
|
@@ -1779,12 +2131,12 @@ function saveSnapshot(schema, config = {}) {
|
|
|
1779
2131
|
const snapshotPath = getSnapshotPath(config);
|
|
1780
2132
|
try {
|
|
1781
2133
|
const snapshotDir = path__namespace.dirname(snapshotPath);
|
|
1782
|
-
if (!
|
|
1783
|
-
|
|
2134
|
+
if (!fs3__namespace.existsSync(snapshotDir)) {
|
|
2135
|
+
fs3__namespace.mkdirSync(snapshotDir, { recursive: true });
|
|
1784
2136
|
}
|
|
1785
2137
|
const snapshotData = addSnapshotMetadata(schema, config);
|
|
1786
2138
|
const jsonContent = JSON.stringify(snapshotData, null, 2);
|
|
1787
|
-
|
|
2139
|
+
fs3__namespace.writeFileSync(snapshotPath, jsonContent, "utf-8");
|
|
1788
2140
|
} catch (error) {
|
|
1789
2141
|
handleFileSystemError(error, "write", snapshotPath);
|
|
1790
2142
|
}
|
|
@@ -1879,7 +2231,7 @@ function deserializeSnapshot(data) {
|
|
|
1879
2231
|
function loadSnapshot(config = {}) {
|
|
1880
2232
|
const snapshotPath = getSnapshotPath(config);
|
|
1881
2233
|
try {
|
|
1882
|
-
const jsonContent =
|
|
2234
|
+
const jsonContent = fs3__namespace.readFileSync(snapshotPath, "utf-8");
|
|
1883
2235
|
const data = parseAndValidateSnapshot(jsonContent, snapshotPath);
|
|
1884
2236
|
const migratedData = migrateSnapshotFormat(data, config);
|
|
1885
2237
|
return deserializeSnapshot(migratedData);
|
|
@@ -1914,10 +2266,10 @@ function mergeSnapshots(baseSnapshot, customSnapshot) {
|
|
|
1914
2266
|
}
|
|
1915
2267
|
function findLatestSnapshot(migrationsPath) {
|
|
1916
2268
|
try {
|
|
1917
|
-
if (!
|
|
2269
|
+
if (!fs3__namespace.existsSync(migrationsPath)) {
|
|
1918
2270
|
return null;
|
|
1919
2271
|
}
|
|
1920
|
-
const files =
|
|
2272
|
+
const files = fs3__namespace.readdirSync(migrationsPath);
|
|
1921
2273
|
const snapshotFiles = files.filter(
|
|
1922
2274
|
(file) => file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")
|
|
1923
2275
|
);
|
|
@@ -1935,14 +2287,68 @@ function findLatestSnapshot(migrationsPath) {
|
|
|
1935
2287
|
return null;
|
|
1936
2288
|
}
|
|
1937
2289
|
}
|
|
2290
|
+
function applyMigrationOperations(snapshot, operations) {
|
|
2291
|
+
const updatedCollections = new Map(snapshot.collections);
|
|
2292
|
+
for (const collectionName of operations.collectionsToDelete) {
|
|
2293
|
+
updatedCollections.delete(collectionName);
|
|
2294
|
+
}
|
|
2295
|
+
for (const collection of operations.collectionsToCreate) {
|
|
2296
|
+
updatedCollections.set(collection.name, collection);
|
|
2297
|
+
}
|
|
2298
|
+
return {
|
|
2299
|
+
...snapshot,
|
|
2300
|
+
collections: updatedCollections
|
|
2301
|
+
};
|
|
2302
|
+
}
|
|
2303
|
+
function loadSnapshotWithMigrations(config = {}) {
|
|
2304
|
+
const migrationsPath = config.migrationsPath;
|
|
2305
|
+
if (!migrationsPath) {
|
|
2306
|
+
return null;
|
|
2307
|
+
}
|
|
2308
|
+
if (fs3__namespace.existsSync(migrationsPath) && fs3__namespace.statSync(migrationsPath).isFile()) {
|
|
2309
|
+
try {
|
|
2310
|
+
const migrationContent = fs3__namespace.readFileSync(migrationsPath, "utf-8");
|
|
2311
|
+
return convertPocketBaseMigration(migrationContent);
|
|
2312
|
+
} catch (error) {
|
|
2313
|
+
console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
|
|
2314
|
+
return null;
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
const latestSnapshotPath = findLatestSnapshot(migrationsPath);
|
|
2318
|
+
if (!latestSnapshotPath) {
|
|
2319
|
+
return null;
|
|
2320
|
+
}
|
|
2321
|
+
try {
|
|
2322
|
+
const migrationContent = fs3__namespace.readFileSync(latestSnapshotPath, "utf-8");
|
|
2323
|
+
let snapshot = convertPocketBaseMigration(migrationContent);
|
|
2324
|
+
const snapshotFilename = path__namespace.basename(latestSnapshotPath);
|
|
2325
|
+
const snapshotTimestamp = extractTimestampFromFilename(snapshotFilename);
|
|
2326
|
+
if (snapshotTimestamp) {
|
|
2327
|
+
const migrationFiles = findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp);
|
|
2328
|
+
for (const migrationFile of migrationFiles) {
|
|
2329
|
+
try {
|
|
2330
|
+
const migrationContent2 = fs3__namespace.readFileSync(migrationFile, "utf-8");
|
|
2331
|
+
const operations = parseMigrationOperations(migrationContent2);
|
|
2332
|
+
snapshot = applyMigrationOperations(snapshot, operations);
|
|
2333
|
+
} catch (error) {
|
|
2334
|
+
console.warn(`Failed to apply migration ${migrationFile}: ${error}`);
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
return snapshot;
|
|
2339
|
+
} catch (error) {
|
|
2340
|
+
console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
|
|
2341
|
+
return null;
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
1938
2344
|
function loadSnapshotIfExists(config = {}) {
|
|
1939
2345
|
const migrationsPath = config.migrationsPath;
|
|
1940
2346
|
if (!migrationsPath) {
|
|
1941
2347
|
return null;
|
|
1942
2348
|
}
|
|
1943
|
-
if (
|
|
2349
|
+
if (fs3__namespace.existsSync(migrationsPath) && fs3__namespace.statSync(migrationsPath).isFile()) {
|
|
1944
2350
|
try {
|
|
1945
|
-
const migrationContent =
|
|
2351
|
+
const migrationContent = fs3__namespace.readFileSync(migrationsPath, "utf-8");
|
|
1946
2352
|
return convertPocketBaseMigration(migrationContent);
|
|
1947
2353
|
} catch (error) {
|
|
1948
2354
|
console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
|
|
@@ -1952,7 +2358,7 @@ function loadSnapshotIfExists(config = {}) {
|
|
|
1952
2358
|
const latestSnapshotPath = findLatestSnapshot(migrationsPath);
|
|
1953
2359
|
if (latestSnapshotPath) {
|
|
1954
2360
|
try {
|
|
1955
|
-
const migrationContent =
|
|
2361
|
+
const migrationContent = fs3__namespace.readFileSync(latestSnapshotPath, "utf-8");
|
|
1956
2362
|
return convertPocketBaseMigration(migrationContent);
|
|
1957
2363
|
} catch (error) {
|
|
1958
2364
|
console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
|
|
@@ -1961,100 +2367,9 @@ function loadSnapshotIfExists(config = {}) {
|
|
|
1961
2367
|
}
|
|
1962
2368
|
return null;
|
|
1963
2369
|
}
|
|
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
2370
|
function loadBaseMigration(migrationPath) {
|
|
2056
2371
|
try {
|
|
2057
|
-
if (!
|
|
2372
|
+
if (!fs3__namespace.existsSync(migrationPath)) {
|
|
2058
2373
|
throw new SnapshotError(
|
|
2059
2374
|
`Base migration file not found: ${migrationPath}
|
|
2060
2375
|
|
|
@@ -2065,7 +2380,7 @@ If the file exists in a different location, update the configuration.`,
|
|
|
2065
2380
|
"read"
|
|
2066
2381
|
);
|
|
2067
2382
|
}
|
|
2068
|
-
const migrationContent =
|
|
2383
|
+
const migrationContent = fs3__namespace.readFileSync(migrationPath, "utf-8");
|
|
2069
2384
|
const snapshot = convertPocketBaseMigration(migrationContent);
|
|
2070
2385
|
return snapshot;
|
|
2071
2386
|
} catch (error) {
|
|
@@ -2101,14 +2416,14 @@ Please ensure PocketBase is properly set up by running 'yarn setup'.`,
|
|
|
2101
2416
|
}
|
|
2102
2417
|
}
|
|
2103
2418
|
function getSnapshotVersion() {
|
|
2104
|
-
return
|
|
2419
|
+
return SNAPSHOT_VERSION2;
|
|
2105
2420
|
}
|
|
2106
2421
|
function validateSnapshot(snapshot) {
|
|
2107
2422
|
const issues = [];
|
|
2108
2423
|
if (!snapshot.version) {
|
|
2109
2424
|
issues.push("Missing version field");
|
|
2110
|
-
} else if (compareVersions(snapshot.version,
|
|
2111
|
-
issues.push(`Snapshot version ${snapshot.version} is newer than supported version ${
|
|
2425
|
+
} else if (compareVersions(snapshot.version, SNAPSHOT_VERSION2) > 0) {
|
|
2426
|
+
issues.push(`Snapshot version ${snapshot.version} is newer than supported version ${SNAPSHOT_VERSION2}`);
|
|
2112
2427
|
}
|
|
2113
2428
|
if (!snapshot.timestamp) {
|
|
2114
2429
|
issues.push("Missing timestamp field");
|
|
@@ -2327,6 +2642,9 @@ function compareFieldOptions(currentField, previousField) {
|
|
|
2327
2642
|
for (const key of allKeys) {
|
|
2328
2643
|
const currentValue = currentOptions[key];
|
|
2329
2644
|
const previousValue = previousOptions[key];
|
|
2645
|
+
if (currentValue === void 0 && previousValue === void 0) {
|
|
2646
|
+
continue;
|
|
2647
|
+
}
|
|
2330
2648
|
if (!areValuesEqual(currentValue, previousValue)) {
|
|
2331
2649
|
changes.push({
|
|
2332
2650
|
property: `options.${key}`,
|
|
@@ -2347,11 +2665,26 @@ function compareRelationConfigurations(currentField, previousField) {
|
|
|
2347
2665
|
if (!currentRelation || !previousRelation) {
|
|
2348
2666
|
return changes;
|
|
2349
2667
|
}
|
|
2350
|
-
|
|
2668
|
+
const normalizeCollection = (collection) => {
|
|
2669
|
+
if (!collection) return collection;
|
|
2670
|
+
if (collection === "_pb_users_auth_") {
|
|
2671
|
+
return "Users";
|
|
2672
|
+
}
|
|
2673
|
+
const nameMatch = collection.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
2674
|
+
if (nameMatch) {
|
|
2675
|
+
return nameMatch[1];
|
|
2676
|
+
}
|
|
2677
|
+
return collection;
|
|
2678
|
+
};
|
|
2679
|
+
const normalizedCurrent = normalizeCollection(currentRelation.collection);
|
|
2680
|
+
const normalizedPrevious = normalizeCollection(previousRelation.collection);
|
|
2681
|
+
if (normalizedCurrent !== normalizedPrevious) {
|
|
2351
2682
|
changes.push({
|
|
2352
2683
|
property: "relation.collection",
|
|
2353
|
-
oldValue:
|
|
2354
|
-
|
|
2684
|
+
oldValue: normalizedPrevious,
|
|
2685
|
+
// Use normalized value for clarity
|
|
2686
|
+
newValue: normalizedCurrent
|
|
2687
|
+
// Use normalized value for clarity
|
|
2355
2688
|
});
|
|
2356
2689
|
}
|
|
2357
2690
|
if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {
|
|
@@ -2785,9 +3118,9 @@ function createMigrationFileStructure(upCode, downCode, config) {
|
|
|
2785
3118
|
}
|
|
2786
3119
|
function writeMigrationFile(migrationDir, filename, content) {
|
|
2787
3120
|
try {
|
|
2788
|
-
if (!
|
|
3121
|
+
if (!fs3__namespace.existsSync(migrationDir)) {
|
|
2789
3122
|
try {
|
|
2790
|
-
|
|
3123
|
+
fs3__namespace.mkdirSync(migrationDir, { recursive: true });
|
|
2791
3124
|
} catch (error) {
|
|
2792
3125
|
const fsError = error;
|
|
2793
3126
|
if (fsError.code === "EACCES" || fsError.code === "EPERM") {
|
|
@@ -2809,7 +3142,7 @@ function writeMigrationFile(migrationDir, filename, content) {
|
|
|
2809
3142
|
}
|
|
2810
3143
|
}
|
|
2811
3144
|
const filePath = path__namespace.join(migrationDir, filename);
|
|
2812
|
-
|
|
3145
|
+
fs3__namespace.writeFileSync(filePath, content, "utf-8");
|
|
2813
3146
|
return filePath;
|
|
2814
3147
|
} catch (error) {
|
|
2815
3148
|
if (error instanceof FileSystemError) {
|
|
@@ -3472,6 +3805,7 @@ exports.isSystemCollection = isSystemCollection;
|
|
|
3472
3805
|
exports.loadBaseMigration = loadBaseMigration;
|
|
3473
3806
|
exports.loadSnapshot = loadSnapshot;
|
|
3474
3807
|
exports.loadSnapshotIfExists = loadSnapshotIfExists;
|
|
3808
|
+
exports.loadSnapshotWithMigrations = loadSnapshotWithMigrations;
|
|
3475
3809
|
exports.mapZodArrayType = mapZodArrayType;
|
|
3476
3810
|
exports.mapZodBooleanType = mapZodBooleanType;
|
|
3477
3811
|
exports.mapZodDateType = mapZodDateType;
|