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/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import * as
|
|
3
|
-
import * as
|
|
2
|
+
import * as fs3 from 'fs';
|
|
3
|
+
import * as path5 from 'path';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import ora from 'ora';
|
|
6
6
|
|
|
@@ -369,6 +369,26 @@ function mergePermissions(...schemas) {
|
|
|
369
369
|
}
|
|
370
370
|
return merged;
|
|
371
371
|
}
|
|
372
|
+
var ProjectInputSchema = z.object({
|
|
373
|
+
// Required fields
|
|
374
|
+
title: z.string(),
|
|
375
|
+
content: z.string(),
|
|
376
|
+
status: StatusEnum,
|
|
377
|
+
summary: z.string().optional(),
|
|
378
|
+
OwnerUser: relationField({ collection: "Users" }),
|
|
379
|
+
SubscriberUsers: relationsField({ collection: "Users" })
|
|
380
|
+
}).extend(inputImageFileSchema);
|
|
381
|
+
var ProjectSchema = withPermissions(
|
|
382
|
+
ProjectInputSchema.omit(omitImageFilesSchema).extend(baseImageFileSchema),
|
|
383
|
+
{
|
|
384
|
+
template: "owner-only",
|
|
385
|
+
ownerField: "OwnerUser",
|
|
386
|
+
customRules: {
|
|
387
|
+
listRule: '@request.auth.id != ""',
|
|
388
|
+
viewRule: '@request.auth.id != "" && (OwnerUser = @request.auth.id || SubscriberUsers ?= @request.auth.id)'
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
);
|
|
372
392
|
var UserInputSchema = z.object({
|
|
373
393
|
name: z.string().optional(),
|
|
374
394
|
email: z.string().email(),
|
|
@@ -844,10 +864,10 @@ var FileSystemError = class _FileSystemError extends MigrationError {
|
|
|
844
864
|
operation;
|
|
845
865
|
code;
|
|
846
866
|
originalError;
|
|
847
|
-
constructor(message,
|
|
867
|
+
constructor(message, path7, operation, code, originalError) {
|
|
848
868
|
super(message);
|
|
849
869
|
this.name = "FileSystemError";
|
|
850
|
-
this.path =
|
|
870
|
+
this.path = path7;
|
|
851
871
|
this.operation = operation;
|
|
852
872
|
this.code = code;
|
|
853
873
|
this.originalError = originalError;
|
|
@@ -1950,20 +1970,20 @@ function mergeConfig(config) {
|
|
|
1950
1970
|
}
|
|
1951
1971
|
function resolveSchemaDir(config) {
|
|
1952
1972
|
const workspaceRoot = config.workspaceRoot || process.cwd();
|
|
1953
|
-
if (
|
|
1973
|
+
if (path5.isAbsolute(config.schemaDir)) {
|
|
1954
1974
|
return config.schemaDir;
|
|
1955
1975
|
}
|
|
1956
|
-
return
|
|
1976
|
+
return path5.join(workspaceRoot, config.schemaDir);
|
|
1957
1977
|
}
|
|
1958
1978
|
function discoverSchemaFiles(config) {
|
|
1959
1979
|
const normalizedConfig = typeof config === "string" ? { schemaDir: config } : config;
|
|
1960
1980
|
const mergedConfig = mergeConfig(normalizedConfig);
|
|
1961
1981
|
const schemaDir = resolveSchemaDir(normalizedConfig);
|
|
1962
1982
|
try {
|
|
1963
|
-
if (!
|
|
1983
|
+
if (!fs3.existsSync(schemaDir)) {
|
|
1964
1984
|
throw new FileSystemError(`Schema directory not found: ${schemaDir}`, schemaDir, "access", "ENOENT");
|
|
1965
1985
|
}
|
|
1966
|
-
const files =
|
|
1986
|
+
const files = fs3.readdirSync(schemaDir);
|
|
1967
1987
|
const schemaFiles = files.filter((file) => {
|
|
1968
1988
|
const hasValidExtension = mergedConfig.includeExtensions.some((ext) => file.endsWith(ext));
|
|
1969
1989
|
if (!hasValidExtension) return false;
|
|
@@ -1979,7 +1999,7 @@ function discoverSchemaFiles(config) {
|
|
|
1979
1999
|
});
|
|
1980
2000
|
return schemaFiles.map((file) => {
|
|
1981
2001
|
const ext = mergedConfig.includeExtensions.find((ext2) => file.endsWith(ext2)) || ".ts";
|
|
1982
|
-
return
|
|
2002
|
+
return path5.join(schemaDir, file.replace(new RegExp(`\\${ext}$`), ""));
|
|
1983
2003
|
});
|
|
1984
2004
|
} catch (error) {
|
|
1985
2005
|
if (error instanceof FileSystemError) {
|
|
@@ -2013,19 +2033,19 @@ async function importSchemaModule(filePath, config) {
|
|
|
2013
2033
|
let resolvedPath = null;
|
|
2014
2034
|
const jsPath = `${importPath}.js`;
|
|
2015
2035
|
const tsPath = `${importPath}.ts`;
|
|
2016
|
-
if (
|
|
2036
|
+
if (fs3.existsSync(jsPath)) {
|
|
2017
2037
|
resolvedPath = jsPath;
|
|
2018
|
-
} else if (
|
|
2038
|
+
} else if (fs3.existsSync(tsPath)) {
|
|
2019
2039
|
resolvedPath = tsPath;
|
|
2020
2040
|
} else {
|
|
2021
2041
|
resolvedPath = jsPath;
|
|
2022
2042
|
}
|
|
2023
|
-
const fileUrl = new URL(`file://${
|
|
2043
|
+
const fileUrl = new URL(`file://${path5.resolve(resolvedPath)}`);
|
|
2024
2044
|
const module = await import(fileUrl.href);
|
|
2025
2045
|
return module;
|
|
2026
2046
|
} catch (error) {
|
|
2027
2047
|
const tsPath = `${filePath}.ts`;
|
|
2028
|
-
const isTypeScriptFile =
|
|
2048
|
+
const isTypeScriptFile = fs3.existsSync(tsPath);
|
|
2029
2049
|
if (isTypeScriptFile) {
|
|
2030
2050
|
throw new SchemaParsingError(
|
|
2031
2051
|
`Failed to import TypeScript schema file. Node.js cannot import TypeScript files directly.
|
|
@@ -2044,7 +2064,7 @@ Please either:
|
|
|
2044
2064
|
}
|
|
2045
2065
|
}
|
|
2046
2066
|
function getCollectionNameFromFile(filePath) {
|
|
2047
|
-
const filename =
|
|
2067
|
+
const filename = path5.basename(filePath).replace(/\.(ts|js)$/, "");
|
|
2048
2068
|
return toCollectionName(filename);
|
|
2049
2069
|
}
|
|
2050
2070
|
function extractSchemaDefinitions(module, patterns = ["Schema", "InputSchema"]) {
|
|
@@ -2209,7 +2229,7 @@ async function buildSchemaDefinition(config) {
|
|
|
2209
2229
|
importPath = normalizedConfig.pathTransformer(filePath);
|
|
2210
2230
|
} else if (mergedConfig.useCompiledFiles) {
|
|
2211
2231
|
const distPath = filePath.replace(/\/src\//, "/dist/");
|
|
2212
|
-
if (
|
|
2232
|
+
if (fs3.existsSync(`${distPath}.js`) || fs3.existsSync(`${distPath}.mjs`)) {
|
|
2213
2233
|
importPath = distPath;
|
|
2214
2234
|
} else {
|
|
2215
2235
|
importPath = filePath;
|
|
@@ -2265,7 +2285,359 @@ var SchemaAnalyzer = class {
|
|
|
2265
2285
|
return convertZodSchemaToCollectionSchema(name, schema);
|
|
2266
2286
|
}
|
|
2267
2287
|
};
|
|
2288
|
+
|
|
2289
|
+
// src/migration/pocketbase-converter.ts
|
|
2268
2290
|
var SNAPSHOT_VERSION = "1.0.0";
|
|
2291
|
+
function resolveCollectionIdToName(collectionId) {
|
|
2292
|
+
if (collectionId === "_pb_users_auth_") {
|
|
2293
|
+
return "Users";
|
|
2294
|
+
}
|
|
2295
|
+
const nameMatch = collectionId.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
2296
|
+
if (nameMatch) {
|
|
2297
|
+
return nameMatch[1];
|
|
2298
|
+
}
|
|
2299
|
+
return collectionId;
|
|
2300
|
+
}
|
|
2301
|
+
function convertPocketBaseCollection(pbCollection) {
|
|
2302
|
+
const fields = [];
|
|
2303
|
+
const systemFieldNames = ["id", "created", "updated", "collectionId", "collectionName", "expand"];
|
|
2304
|
+
const authSystemFieldNames = ["email", "emailVisibility", "verified", "password", "tokenKey"];
|
|
2305
|
+
if (pbCollection.fields && Array.isArray(pbCollection.fields)) {
|
|
2306
|
+
for (const pbField of pbCollection.fields) {
|
|
2307
|
+
if (pbField.system || systemFieldNames.includes(pbField.name)) {
|
|
2308
|
+
continue;
|
|
2309
|
+
}
|
|
2310
|
+
if (pbCollection.type === "auth" && authSystemFieldNames.includes(pbField.name)) {
|
|
2311
|
+
continue;
|
|
2312
|
+
}
|
|
2313
|
+
const field = {
|
|
2314
|
+
name: pbField.name,
|
|
2315
|
+
type: pbField.type,
|
|
2316
|
+
required: pbField.required || false
|
|
2317
|
+
};
|
|
2318
|
+
field.options = pbField.options ? { ...pbField.options } : {};
|
|
2319
|
+
if (pbField.type === "select") {
|
|
2320
|
+
if (pbField.values && Array.isArray(pbField.values)) {
|
|
2321
|
+
field.options.values = pbField.values;
|
|
2322
|
+
} else if (pbField.options?.values && Array.isArray(pbField.options.values)) {
|
|
2323
|
+
field.options.values = pbField.options.values;
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2326
|
+
if (pbField.type === "relation") {
|
|
2327
|
+
const collectionId = pbField.collectionId || pbField.options?.collectionId || "";
|
|
2328
|
+
const collectionName = resolveCollectionIdToName(collectionId);
|
|
2329
|
+
field.relation = {
|
|
2330
|
+
collection: collectionName,
|
|
2331
|
+
cascadeDelete: pbField.cascadeDelete ?? pbField.options?.cascadeDelete ?? false,
|
|
2332
|
+
maxSelect: pbField.maxSelect ?? pbField.options?.maxSelect,
|
|
2333
|
+
minSelect: pbField.minSelect ?? pbField.options?.minSelect
|
|
2334
|
+
};
|
|
2335
|
+
}
|
|
2336
|
+
const hasOnlyValues = Object.keys(field.options).length === 1 && field.options.values !== void 0;
|
|
2337
|
+
if (Object.keys(field.options).length === 0) {
|
|
2338
|
+
delete field.options;
|
|
2339
|
+
} else if (pbField.type === "select" && hasOnlyValues) ;
|
|
2340
|
+
fields.push(field);
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
const schema = {
|
|
2344
|
+
name: pbCollection.name,
|
|
2345
|
+
type: pbCollection.type || "base",
|
|
2346
|
+
fields
|
|
2347
|
+
};
|
|
2348
|
+
if (pbCollection.indexes && Array.isArray(pbCollection.indexes)) {
|
|
2349
|
+
schema.indexes = pbCollection.indexes;
|
|
2350
|
+
}
|
|
2351
|
+
const rules = {};
|
|
2352
|
+
if (pbCollection.listRule !== void 0) rules.listRule = pbCollection.listRule;
|
|
2353
|
+
if (pbCollection.viewRule !== void 0) rules.viewRule = pbCollection.viewRule;
|
|
2354
|
+
if (pbCollection.createRule !== void 0) rules.createRule = pbCollection.createRule;
|
|
2355
|
+
if (pbCollection.updateRule !== void 0) rules.updateRule = pbCollection.updateRule;
|
|
2356
|
+
if (pbCollection.deleteRule !== void 0) rules.deleteRule = pbCollection.deleteRule;
|
|
2357
|
+
if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
|
|
2358
|
+
if (Object.keys(rules).length > 0) {
|
|
2359
|
+
schema.rules = rules;
|
|
2360
|
+
schema.permissions = { ...rules };
|
|
2361
|
+
}
|
|
2362
|
+
return schema;
|
|
2363
|
+
}
|
|
2364
|
+
function convertPocketBaseMigration(migrationContent) {
|
|
2365
|
+
try {
|
|
2366
|
+
const snapshotMatch = migrationContent.match(/const\s+snapshot\s*=\s*(\[[\s\S]*?\]);/);
|
|
2367
|
+
if (!snapshotMatch) {
|
|
2368
|
+
throw new Error("Could not find snapshot array in migration file");
|
|
2369
|
+
}
|
|
2370
|
+
const snapshotArrayStr = snapshotMatch[1];
|
|
2371
|
+
let snapshotArray;
|
|
2372
|
+
try {
|
|
2373
|
+
snapshotArray = new Function(`return ${snapshotArrayStr}`)();
|
|
2374
|
+
} catch (parseError) {
|
|
2375
|
+
throw new Error(`Failed to parse snapshot array: ${parseError}`);
|
|
2376
|
+
}
|
|
2377
|
+
if (!Array.isArray(snapshotArray)) {
|
|
2378
|
+
throw new Error("Snapshot is not an array");
|
|
2379
|
+
}
|
|
2380
|
+
const collections = /* @__PURE__ */ new Map();
|
|
2381
|
+
for (const pbCollection of snapshotArray) {
|
|
2382
|
+
if (!pbCollection.name) {
|
|
2383
|
+
console.warn("Skipping collection without name");
|
|
2384
|
+
continue;
|
|
2385
|
+
}
|
|
2386
|
+
const schema = convertPocketBaseCollection(pbCollection);
|
|
2387
|
+
collections.set(pbCollection.name, schema);
|
|
2388
|
+
}
|
|
2389
|
+
return {
|
|
2390
|
+
version: SNAPSHOT_VERSION,
|
|
2391
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2392
|
+
collections
|
|
2393
|
+
};
|
|
2394
|
+
} catch (error) {
|
|
2395
|
+
throw new SnapshotError(
|
|
2396
|
+
`Failed to convert PocketBase migration: ${error instanceof Error ? error.message : String(error)}`,
|
|
2397
|
+
void 0,
|
|
2398
|
+
"parse",
|
|
2399
|
+
error instanceof Error ? error : void 0
|
|
2400
|
+
);
|
|
2401
|
+
}
|
|
2402
|
+
}
|
|
2403
|
+
|
|
2404
|
+
// src/migration/migration-parser.ts
|
|
2405
|
+
function extractTimestampFromFilename(filename) {
|
|
2406
|
+
const match = filename.match(/^(\d+)_/);
|
|
2407
|
+
if (match) {
|
|
2408
|
+
return parseInt(match[1], 10);
|
|
2409
|
+
}
|
|
2410
|
+
return null;
|
|
2411
|
+
}
|
|
2412
|
+
function findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp) {
|
|
2413
|
+
try {
|
|
2414
|
+
if (!fs3.existsSync(migrationsPath)) {
|
|
2415
|
+
return [];
|
|
2416
|
+
}
|
|
2417
|
+
const files = fs3.readdirSync(migrationsPath);
|
|
2418
|
+
const migrationFiles = [];
|
|
2419
|
+
for (const file of files) {
|
|
2420
|
+
if (file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")) {
|
|
2421
|
+
continue;
|
|
2422
|
+
}
|
|
2423
|
+
if (!file.endsWith(".js")) {
|
|
2424
|
+
continue;
|
|
2425
|
+
}
|
|
2426
|
+
const timestamp = extractTimestampFromFilename(file);
|
|
2427
|
+
if (timestamp && timestamp > snapshotTimestamp) {
|
|
2428
|
+
migrationFiles.push({
|
|
2429
|
+
path: path5.join(migrationsPath, file),
|
|
2430
|
+
timestamp
|
|
2431
|
+
});
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2434
|
+
migrationFiles.sort((a, b) => a.timestamp - b.timestamp);
|
|
2435
|
+
return migrationFiles.map((f) => f.path);
|
|
2436
|
+
} catch (error) {
|
|
2437
|
+
console.warn(`Error finding migrations after snapshot: ${error}`);
|
|
2438
|
+
return [];
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
function parseMigrationOperationsFromContent(content) {
|
|
2442
|
+
const collectionsToCreate = [];
|
|
2443
|
+
const collectionsToDelete = [];
|
|
2444
|
+
try {
|
|
2445
|
+
let searchIndex = 0;
|
|
2446
|
+
while (true) {
|
|
2447
|
+
const collectionStart = content.indexOf("new Collection(", searchIndex);
|
|
2448
|
+
if (collectionStart === -1) {
|
|
2449
|
+
break;
|
|
2450
|
+
}
|
|
2451
|
+
const openParen = collectionStart + "new Collection(".length;
|
|
2452
|
+
let braceCount = 0;
|
|
2453
|
+
let parenCount = 1;
|
|
2454
|
+
let inString = false;
|
|
2455
|
+
let stringChar = null;
|
|
2456
|
+
let i = openParen;
|
|
2457
|
+
while (i < content.length && /\s/.test(content[i])) {
|
|
2458
|
+
i++;
|
|
2459
|
+
}
|
|
2460
|
+
if (content[i] !== "{") {
|
|
2461
|
+
searchIndex = i + 1;
|
|
2462
|
+
continue;
|
|
2463
|
+
}
|
|
2464
|
+
const objectStart = i;
|
|
2465
|
+
braceCount = 1;
|
|
2466
|
+
i++;
|
|
2467
|
+
while (i < content.length && (braceCount > 0 || parenCount > 0)) {
|
|
2468
|
+
const char = content[i];
|
|
2469
|
+
const prevChar = i > 0 ? content[i - 1] : "";
|
|
2470
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2471
|
+
inString = true;
|
|
2472
|
+
stringChar = char;
|
|
2473
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2474
|
+
inString = false;
|
|
2475
|
+
stringChar = null;
|
|
2476
|
+
}
|
|
2477
|
+
if (!inString) {
|
|
2478
|
+
if (char === "{") braceCount++;
|
|
2479
|
+
if (char === "}") braceCount--;
|
|
2480
|
+
if (char === "(") parenCount++;
|
|
2481
|
+
if (char === ")") parenCount--;
|
|
2482
|
+
}
|
|
2483
|
+
i++;
|
|
2484
|
+
}
|
|
2485
|
+
if (braceCount === 0 && parenCount === 0) {
|
|
2486
|
+
const objectContent = content.substring(objectStart, i - 1);
|
|
2487
|
+
try {
|
|
2488
|
+
const collectionObj = new Function(`return ${objectContent}`)();
|
|
2489
|
+
if (collectionObj && collectionObj.name) {
|
|
2490
|
+
const schema = convertPocketBaseCollection(collectionObj);
|
|
2491
|
+
collectionsToCreate.push(schema);
|
|
2492
|
+
}
|
|
2493
|
+
} catch (error) {
|
|
2494
|
+
console.warn(`Failed to parse collection definition: ${error}`);
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
searchIndex = i;
|
|
2498
|
+
}
|
|
2499
|
+
const deleteMatches = content.matchAll(
|
|
2500
|
+
/app\.delete\s*\(\s*(?:collection_\w+|app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\))\s*\)/g
|
|
2501
|
+
);
|
|
2502
|
+
for (const match of deleteMatches) {
|
|
2503
|
+
if (match[1]) {
|
|
2504
|
+
collectionsToDelete.push(match[1]);
|
|
2505
|
+
} else {
|
|
2506
|
+
const varNameMatch = match[0].match(/collection_(\w+)/);
|
|
2507
|
+
if (varNameMatch) {
|
|
2508
|
+
const varName = `collection_${varNameMatch[1]}`;
|
|
2509
|
+
const deleteIndex = content.indexOf(match[0]);
|
|
2510
|
+
const beforeDelete = content.substring(0, deleteIndex);
|
|
2511
|
+
const varDefMatch = beforeDelete.match(
|
|
2512
|
+
new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`, "g")
|
|
2513
|
+
);
|
|
2514
|
+
if (varDefMatch && varDefMatch.length > 0) {
|
|
2515
|
+
const collectionDefMatch = beforeDelete.match(
|
|
2516
|
+
new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`)
|
|
2517
|
+
);
|
|
2518
|
+
if (collectionDefMatch) {
|
|
2519
|
+
try {
|
|
2520
|
+
const collectionDefStr = collectionDefMatch[1];
|
|
2521
|
+
const collectionObj = new Function(`return ${collectionDefStr}`)();
|
|
2522
|
+
if (collectionObj && collectionObj.name) {
|
|
2523
|
+
collectionsToDelete.push(collectionObj.name);
|
|
2524
|
+
}
|
|
2525
|
+
} catch {
|
|
2526
|
+
}
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
const findAndDeleteMatches = content.matchAll(
|
|
2533
|
+
/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)[\s\S]*?app\.delete/g
|
|
2534
|
+
);
|
|
2535
|
+
for (const match of findAndDeleteMatches) {
|
|
2536
|
+
collectionsToDelete.push(match[1]);
|
|
2537
|
+
}
|
|
2538
|
+
} catch (error) {
|
|
2539
|
+
console.warn(`Failed to parse migration operations from content: ${error}`);
|
|
2540
|
+
}
|
|
2541
|
+
return { collectionsToCreate, collectionsToDelete };
|
|
2542
|
+
}
|
|
2543
|
+
function parseMigrationOperations(migrationContent) {
|
|
2544
|
+
try {
|
|
2545
|
+
const migrateMatch = migrationContent.match(/migrate\s*\(\s*/);
|
|
2546
|
+
if (!migrateMatch) {
|
|
2547
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2548
|
+
}
|
|
2549
|
+
const startIndex = migrateMatch.index + migrateMatch[0].length;
|
|
2550
|
+
let i = startIndex;
|
|
2551
|
+
let parenCount = 0;
|
|
2552
|
+
let foundFirstParen = false;
|
|
2553
|
+
while (i < migrationContent.length) {
|
|
2554
|
+
const char = migrationContent[i];
|
|
2555
|
+
if (char === "(") {
|
|
2556
|
+
parenCount++;
|
|
2557
|
+
foundFirstParen = true;
|
|
2558
|
+
i++;
|
|
2559
|
+
break;
|
|
2560
|
+
}
|
|
2561
|
+
i++;
|
|
2562
|
+
}
|
|
2563
|
+
if (!foundFirstParen) {
|
|
2564
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2565
|
+
}
|
|
2566
|
+
let inString = false;
|
|
2567
|
+
let stringChar = null;
|
|
2568
|
+
let foundBrace = false;
|
|
2569
|
+
let braceStart = -1;
|
|
2570
|
+
while (i < migrationContent.length && !foundBrace) {
|
|
2571
|
+
const char = migrationContent[i];
|
|
2572
|
+
const prevChar = i > 0 ? migrationContent[i - 1] : "";
|
|
2573
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2574
|
+
inString = true;
|
|
2575
|
+
stringChar = char;
|
|
2576
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2577
|
+
inString = false;
|
|
2578
|
+
stringChar = null;
|
|
2579
|
+
}
|
|
2580
|
+
if (!inString) {
|
|
2581
|
+
if (char === "(") parenCount++;
|
|
2582
|
+
if (char === ")") {
|
|
2583
|
+
parenCount--;
|
|
2584
|
+
if (parenCount === 0) {
|
|
2585
|
+
i++;
|
|
2586
|
+
while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
|
|
2587
|
+
i++;
|
|
2588
|
+
}
|
|
2589
|
+
if (i < migrationContent.length - 1 && migrationContent[i] === "=" && migrationContent[i + 1] === ">") {
|
|
2590
|
+
i += 2;
|
|
2591
|
+
while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
|
|
2592
|
+
i++;
|
|
2593
|
+
}
|
|
2594
|
+
if (i < migrationContent.length && migrationContent[i] === "{") {
|
|
2595
|
+
foundBrace = true;
|
|
2596
|
+
braceStart = i + 1;
|
|
2597
|
+
break;
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
i++;
|
|
2604
|
+
}
|
|
2605
|
+
if (!foundBrace || braceStart === -1) {
|
|
2606
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2607
|
+
}
|
|
2608
|
+
let braceCount = 1;
|
|
2609
|
+
i = braceStart;
|
|
2610
|
+
inString = false;
|
|
2611
|
+
stringChar = null;
|
|
2612
|
+
while (i < migrationContent.length && braceCount > 0) {
|
|
2613
|
+
const char = migrationContent[i];
|
|
2614
|
+
const prevChar = i > 0 ? migrationContent[i - 1] : "";
|
|
2615
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2616
|
+
inString = true;
|
|
2617
|
+
stringChar = char;
|
|
2618
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2619
|
+
inString = false;
|
|
2620
|
+
stringChar = null;
|
|
2621
|
+
}
|
|
2622
|
+
if (!inString) {
|
|
2623
|
+
if (char === "{") braceCount++;
|
|
2624
|
+
if (char === "}") braceCount--;
|
|
2625
|
+
}
|
|
2626
|
+
i++;
|
|
2627
|
+
}
|
|
2628
|
+
if (braceCount === 0) {
|
|
2629
|
+
const upMigrationContent = migrationContent.substring(braceStart, i - 1);
|
|
2630
|
+
return parseMigrationOperationsFromContent(upMigrationContent);
|
|
2631
|
+
}
|
|
2632
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2633
|
+
} catch (error) {
|
|
2634
|
+
console.warn(`Failed to parse migration operations: ${error}`);
|
|
2635
|
+
return { collectionsToCreate: [], collectionsToDelete: [] };
|
|
2636
|
+
}
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2639
|
+
// src/migration/snapshot.ts
|
|
2640
|
+
var SNAPSHOT_VERSION2 = "1.0.0";
|
|
2269
2641
|
var DEFAULT_SNAPSHOT_FILENAME = ".migration-snapshot.json";
|
|
2270
2642
|
var SNAPSHOT_MIGRATIONS = [
|
|
2271
2643
|
// Add migrations here as the format evolves
|
|
@@ -2280,7 +2652,7 @@ var DEFAULT_CONFIG2 = {
|
|
|
2280
2652
|
snapshotPath: DEFAULT_SNAPSHOT_FILENAME,
|
|
2281
2653
|
workspaceRoot: process.cwd(),
|
|
2282
2654
|
autoMigrate: true,
|
|
2283
|
-
version:
|
|
2655
|
+
version: SNAPSHOT_VERSION2
|
|
2284
2656
|
};
|
|
2285
2657
|
function mergeConfig2(config = {}) {
|
|
2286
2658
|
return {
|
|
@@ -2292,15 +2664,15 @@ function getSnapshotPath(config = {}) {
|
|
|
2292
2664
|
const mergedConfig = mergeConfig2(config);
|
|
2293
2665
|
const workspaceRoot = mergedConfig.workspaceRoot;
|
|
2294
2666
|
const snapshotFilename = mergedConfig.snapshotPath;
|
|
2295
|
-
if (
|
|
2667
|
+
if (path5.isAbsolute(snapshotFilename)) {
|
|
2296
2668
|
return snapshotFilename;
|
|
2297
2669
|
}
|
|
2298
|
-
return
|
|
2670
|
+
return path5.join(workspaceRoot, snapshotFilename);
|
|
2299
2671
|
}
|
|
2300
2672
|
function snapshotExists(config = {}) {
|
|
2301
2673
|
try {
|
|
2302
2674
|
const snapshotPath = getSnapshotPath(config);
|
|
2303
|
-
return
|
|
2675
|
+
return fs3.existsSync(snapshotPath);
|
|
2304
2676
|
} catch {
|
|
2305
2677
|
return false;
|
|
2306
2678
|
}
|
|
@@ -2359,13 +2731,13 @@ function addSnapshotMetadata(schema, config) {
|
|
|
2359
2731
|
function saveSnapshot(schema, config = {}) {
|
|
2360
2732
|
const snapshotPath = getSnapshotPath(config);
|
|
2361
2733
|
try {
|
|
2362
|
-
const snapshotDir =
|
|
2363
|
-
if (!
|
|
2364
|
-
|
|
2734
|
+
const snapshotDir = path5.dirname(snapshotPath);
|
|
2735
|
+
if (!fs3.existsSync(snapshotDir)) {
|
|
2736
|
+
fs3.mkdirSync(snapshotDir, { recursive: true });
|
|
2365
2737
|
}
|
|
2366
2738
|
const snapshotData = addSnapshotMetadata(schema, config);
|
|
2367
2739
|
const jsonContent = JSON.stringify(snapshotData, null, 2);
|
|
2368
|
-
|
|
2740
|
+
fs3.writeFileSync(snapshotPath, jsonContent, "utf-8");
|
|
2369
2741
|
} catch (error) {
|
|
2370
2742
|
handleFileSystemError(error, "write", snapshotPath);
|
|
2371
2743
|
}
|
|
@@ -2460,7 +2832,7 @@ function deserializeSnapshot(data) {
|
|
|
2460
2832
|
function loadSnapshot(config = {}) {
|
|
2461
2833
|
const snapshotPath = getSnapshotPath(config);
|
|
2462
2834
|
try {
|
|
2463
|
-
const jsonContent =
|
|
2835
|
+
const jsonContent = fs3.readFileSync(snapshotPath, "utf-8");
|
|
2464
2836
|
const data = parseAndValidateSnapshot(jsonContent, snapshotPath);
|
|
2465
2837
|
const migratedData = migrateSnapshotFormat(data, config);
|
|
2466
2838
|
return deserializeSnapshot(migratedData);
|
|
@@ -2495,10 +2867,10 @@ function mergeSnapshots(baseSnapshot, customSnapshot) {
|
|
|
2495
2867
|
}
|
|
2496
2868
|
function findLatestSnapshot(migrationsPath) {
|
|
2497
2869
|
try {
|
|
2498
|
-
if (!
|
|
2870
|
+
if (!fs3.existsSync(migrationsPath)) {
|
|
2499
2871
|
return null;
|
|
2500
2872
|
}
|
|
2501
|
-
const files =
|
|
2873
|
+
const files = fs3.readdirSync(migrationsPath);
|
|
2502
2874
|
const snapshotFiles = files.filter(
|
|
2503
2875
|
(file) => file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")
|
|
2504
2876
|
);
|
|
@@ -2510,20 +2882,74 @@ function findLatestSnapshot(migrationsPath) {
|
|
|
2510
2882
|
if (!latestSnapshot) {
|
|
2511
2883
|
return null;
|
|
2512
2884
|
}
|
|
2513
|
-
return
|
|
2885
|
+
return path5.join(migrationsPath, latestSnapshot);
|
|
2514
2886
|
} catch (error) {
|
|
2515
2887
|
console.warn(`Error finding latest snapshot: ${error}`);
|
|
2516
2888
|
return null;
|
|
2517
2889
|
}
|
|
2518
2890
|
}
|
|
2891
|
+
function applyMigrationOperations(snapshot, operations) {
|
|
2892
|
+
const updatedCollections = new Map(snapshot.collections);
|
|
2893
|
+
for (const collectionName of operations.collectionsToDelete) {
|
|
2894
|
+
updatedCollections.delete(collectionName);
|
|
2895
|
+
}
|
|
2896
|
+
for (const collection of operations.collectionsToCreate) {
|
|
2897
|
+
updatedCollections.set(collection.name, collection);
|
|
2898
|
+
}
|
|
2899
|
+
return {
|
|
2900
|
+
...snapshot,
|
|
2901
|
+
collections: updatedCollections
|
|
2902
|
+
};
|
|
2903
|
+
}
|
|
2904
|
+
function loadSnapshotWithMigrations(config = {}) {
|
|
2905
|
+
const migrationsPath = config.migrationsPath;
|
|
2906
|
+
if (!migrationsPath) {
|
|
2907
|
+
return null;
|
|
2908
|
+
}
|
|
2909
|
+
if (fs3.existsSync(migrationsPath) && fs3.statSync(migrationsPath).isFile()) {
|
|
2910
|
+
try {
|
|
2911
|
+
const migrationContent = fs3.readFileSync(migrationsPath, "utf-8");
|
|
2912
|
+
return convertPocketBaseMigration(migrationContent);
|
|
2913
|
+
} catch (error) {
|
|
2914
|
+
console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
|
|
2915
|
+
return null;
|
|
2916
|
+
}
|
|
2917
|
+
}
|
|
2918
|
+
const latestSnapshotPath = findLatestSnapshot(migrationsPath);
|
|
2919
|
+
if (!latestSnapshotPath) {
|
|
2920
|
+
return null;
|
|
2921
|
+
}
|
|
2922
|
+
try {
|
|
2923
|
+
const migrationContent = fs3.readFileSync(latestSnapshotPath, "utf-8");
|
|
2924
|
+
let snapshot = convertPocketBaseMigration(migrationContent);
|
|
2925
|
+
const snapshotFilename = path5.basename(latestSnapshotPath);
|
|
2926
|
+
const snapshotTimestamp = extractTimestampFromFilename(snapshotFilename);
|
|
2927
|
+
if (snapshotTimestamp) {
|
|
2928
|
+
const migrationFiles = findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp);
|
|
2929
|
+
for (const migrationFile of migrationFiles) {
|
|
2930
|
+
try {
|
|
2931
|
+
const migrationContent2 = fs3.readFileSync(migrationFile, "utf-8");
|
|
2932
|
+
const operations = parseMigrationOperations(migrationContent2);
|
|
2933
|
+
snapshot = applyMigrationOperations(snapshot, operations);
|
|
2934
|
+
} catch (error) {
|
|
2935
|
+
console.warn(`Failed to apply migration ${migrationFile}: ${error}`);
|
|
2936
|
+
}
|
|
2937
|
+
}
|
|
2938
|
+
}
|
|
2939
|
+
return snapshot;
|
|
2940
|
+
} catch (error) {
|
|
2941
|
+
console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
|
|
2942
|
+
return null;
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2519
2945
|
function loadSnapshotIfExists(config = {}) {
|
|
2520
2946
|
const migrationsPath = config.migrationsPath;
|
|
2521
2947
|
if (!migrationsPath) {
|
|
2522
2948
|
return null;
|
|
2523
2949
|
}
|
|
2524
|
-
if (
|
|
2950
|
+
if (fs3.existsSync(migrationsPath) && fs3.statSync(migrationsPath).isFile()) {
|
|
2525
2951
|
try {
|
|
2526
|
-
const migrationContent =
|
|
2952
|
+
const migrationContent = fs3.readFileSync(migrationsPath, "utf-8");
|
|
2527
2953
|
return convertPocketBaseMigration(migrationContent);
|
|
2528
2954
|
} catch (error) {
|
|
2529
2955
|
console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
|
|
@@ -2533,7 +2959,7 @@ function loadSnapshotIfExists(config = {}) {
|
|
|
2533
2959
|
const latestSnapshotPath = findLatestSnapshot(migrationsPath);
|
|
2534
2960
|
if (latestSnapshotPath) {
|
|
2535
2961
|
try {
|
|
2536
|
-
const migrationContent =
|
|
2962
|
+
const migrationContent = fs3.readFileSync(latestSnapshotPath, "utf-8");
|
|
2537
2963
|
return convertPocketBaseMigration(migrationContent);
|
|
2538
2964
|
} catch (error) {
|
|
2539
2965
|
console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
|
|
@@ -2542,100 +2968,9 @@ function loadSnapshotIfExists(config = {}) {
|
|
|
2542
2968
|
}
|
|
2543
2969
|
return null;
|
|
2544
2970
|
}
|
|
2545
|
-
function convertPocketBaseCollection(pbCollection) {
|
|
2546
|
-
const fields = [];
|
|
2547
|
-
const systemFieldNames = ["id", "created", "updated", "collectionId", "collectionName", "expand"];
|
|
2548
|
-
const authSystemFieldNames = ["email", "emailVisibility", "verified", "password", "tokenKey"];
|
|
2549
|
-
if (pbCollection.fields && Array.isArray(pbCollection.fields)) {
|
|
2550
|
-
for (const pbField of pbCollection.fields) {
|
|
2551
|
-
if (pbField.system || systemFieldNames.includes(pbField.name)) {
|
|
2552
|
-
continue;
|
|
2553
|
-
}
|
|
2554
|
-
if (pbCollection.type === "auth" && authSystemFieldNames.includes(pbField.name)) {
|
|
2555
|
-
continue;
|
|
2556
|
-
}
|
|
2557
|
-
const field = {
|
|
2558
|
-
name: pbField.name,
|
|
2559
|
-
type: pbField.type,
|
|
2560
|
-
required: pbField.required || false
|
|
2561
|
-
};
|
|
2562
|
-
if (pbField.options) {
|
|
2563
|
-
field.options = pbField.options;
|
|
2564
|
-
}
|
|
2565
|
-
if (pbField.type === "relation") {
|
|
2566
|
-
field.relation = {
|
|
2567
|
-
collection: pbField.options?.collectionId || "",
|
|
2568
|
-
cascadeDelete: pbField.options?.cascadeDelete || false,
|
|
2569
|
-
maxSelect: pbField.options?.maxSelect,
|
|
2570
|
-
minSelect: pbField.options?.minSelect
|
|
2571
|
-
};
|
|
2572
|
-
}
|
|
2573
|
-
fields.push(field);
|
|
2574
|
-
}
|
|
2575
|
-
}
|
|
2576
|
-
const schema = {
|
|
2577
|
-
name: pbCollection.name,
|
|
2578
|
-
type: pbCollection.type || "base",
|
|
2579
|
-
fields
|
|
2580
|
-
};
|
|
2581
|
-
if (pbCollection.indexes && Array.isArray(pbCollection.indexes)) {
|
|
2582
|
-
schema.indexes = pbCollection.indexes;
|
|
2583
|
-
}
|
|
2584
|
-
const rules = {};
|
|
2585
|
-
if (pbCollection.listRule !== void 0) rules.listRule = pbCollection.listRule;
|
|
2586
|
-
if (pbCollection.viewRule !== void 0) rules.viewRule = pbCollection.viewRule;
|
|
2587
|
-
if (pbCollection.createRule !== void 0) rules.createRule = pbCollection.createRule;
|
|
2588
|
-
if (pbCollection.updateRule !== void 0) rules.updateRule = pbCollection.updateRule;
|
|
2589
|
-
if (pbCollection.deleteRule !== void 0) rules.deleteRule = pbCollection.deleteRule;
|
|
2590
|
-
if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
|
|
2591
|
-
if (Object.keys(rules).length > 0) {
|
|
2592
|
-
schema.rules = rules;
|
|
2593
|
-
schema.permissions = { ...rules };
|
|
2594
|
-
}
|
|
2595
|
-
return schema;
|
|
2596
|
-
}
|
|
2597
|
-
function convertPocketBaseMigration(migrationContent) {
|
|
2598
|
-
try {
|
|
2599
|
-
const snapshotMatch = migrationContent.match(/const\s+snapshot\s*=\s*(\[[\s\S]*?\]);/);
|
|
2600
|
-
if (!snapshotMatch) {
|
|
2601
|
-
throw new Error("Could not find snapshot array in migration file");
|
|
2602
|
-
}
|
|
2603
|
-
const snapshotArrayStr = snapshotMatch[1];
|
|
2604
|
-
let snapshotArray;
|
|
2605
|
-
try {
|
|
2606
|
-
snapshotArray = new Function(`return ${snapshotArrayStr}`)();
|
|
2607
|
-
} catch (parseError) {
|
|
2608
|
-
throw new Error(`Failed to parse snapshot array: ${parseError}`);
|
|
2609
|
-
}
|
|
2610
|
-
if (!Array.isArray(snapshotArray)) {
|
|
2611
|
-
throw new Error("Snapshot is not an array");
|
|
2612
|
-
}
|
|
2613
|
-
const collections = /* @__PURE__ */ new Map();
|
|
2614
|
-
for (const pbCollection of snapshotArray) {
|
|
2615
|
-
if (!pbCollection.name) {
|
|
2616
|
-
console.warn("Skipping collection without name");
|
|
2617
|
-
continue;
|
|
2618
|
-
}
|
|
2619
|
-
const schema = convertPocketBaseCollection(pbCollection);
|
|
2620
|
-
collections.set(pbCollection.name, schema);
|
|
2621
|
-
}
|
|
2622
|
-
return {
|
|
2623
|
-
version: SNAPSHOT_VERSION,
|
|
2624
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2625
|
-
collections
|
|
2626
|
-
};
|
|
2627
|
-
} catch (error) {
|
|
2628
|
-
throw new SnapshotError(
|
|
2629
|
-
`Failed to convert PocketBase migration: ${error instanceof Error ? error.message : String(error)}`,
|
|
2630
|
-
void 0,
|
|
2631
|
-
"parse",
|
|
2632
|
-
error instanceof Error ? error : void 0
|
|
2633
|
-
);
|
|
2634
|
-
}
|
|
2635
|
-
}
|
|
2636
2971
|
function loadBaseMigration(migrationPath) {
|
|
2637
2972
|
try {
|
|
2638
|
-
if (!
|
|
2973
|
+
if (!fs3.existsSync(migrationPath)) {
|
|
2639
2974
|
throw new SnapshotError(
|
|
2640
2975
|
`Base migration file not found: ${migrationPath}
|
|
2641
2976
|
|
|
@@ -2646,7 +2981,7 @@ If the file exists in a different location, update the configuration.`,
|
|
|
2646
2981
|
"read"
|
|
2647
2982
|
);
|
|
2648
2983
|
}
|
|
2649
|
-
const migrationContent =
|
|
2984
|
+
const migrationContent = fs3.readFileSync(migrationPath, "utf-8");
|
|
2650
2985
|
const snapshot = convertPocketBaseMigration(migrationContent);
|
|
2651
2986
|
return snapshot;
|
|
2652
2987
|
} catch (error) {
|
|
@@ -2682,14 +3017,14 @@ Please ensure PocketBase is properly set up by running 'yarn setup'.`,
|
|
|
2682
3017
|
}
|
|
2683
3018
|
}
|
|
2684
3019
|
function getSnapshotVersion() {
|
|
2685
|
-
return
|
|
3020
|
+
return SNAPSHOT_VERSION2;
|
|
2686
3021
|
}
|
|
2687
3022
|
function validateSnapshot(snapshot) {
|
|
2688
3023
|
const issues = [];
|
|
2689
3024
|
if (!snapshot.version) {
|
|
2690
3025
|
issues.push("Missing version field");
|
|
2691
|
-
} else if (compareVersions(snapshot.version,
|
|
2692
|
-
issues.push(`Snapshot version ${snapshot.version} is newer than supported version ${
|
|
3026
|
+
} else if (compareVersions(snapshot.version, SNAPSHOT_VERSION2) > 0) {
|
|
3027
|
+
issues.push(`Snapshot version ${snapshot.version} is newer than supported version ${SNAPSHOT_VERSION2}`);
|
|
2693
3028
|
}
|
|
2694
3029
|
if (!snapshot.timestamp) {
|
|
2695
3030
|
issues.push("Missing timestamp field");
|
|
@@ -2908,6 +3243,9 @@ function compareFieldOptions(currentField, previousField) {
|
|
|
2908
3243
|
for (const key of allKeys) {
|
|
2909
3244
|
const currentValue = currentOptions[key];
|
|
2910
3245
|
const previousValue = previousOptions[key];
|
|
3246
|
+
if (currentValue === void 0 && previousValue === void 0) {
|
|
3247
|
+
continue;
|
|
3248
|
+
}
|
|
2911
3249
|
if (!areValuesEqual(currentValue, previousValue)) {
|
|
2912
3250
|
changes.push({
|
|
2913
3251
|
property: `options.${key}`,
|
|
@@ -2928,11 +3266,26 @@ function compareRelationConfigurations(currentField, previousField) {
|
|
|
2928
3266
|
if (!currentRelation || !previousRelation) {
|
|
2929
3267
|
return changes;
|
|
2930
3268
|
}
|
|
2931
|
-
|
|
3269
|
+
const normalizeCollection = (collection) => {
|
|
3270
|
+
if (!collection) return collection;
|
|
3271
|
+
if (collection === "_pb_users_auth_") {
|
|
3272
|
+
return "Users";
|
|
3273
|
+
}
|
|
3274
|
+
const nameMatch = collection.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
3275
|
+
if (nameMatch) {
|
|
3276
|
+
return nameMatch[1];
|
|
3277
|
+
}
|
|
3278
|
+
return collection;
|
|
3279
|
+
};
|
|
3280
|
+
const normalizedCurrent = normalizeCollection(currentRelation.collection);
|
|
3281
|
+
const normalizedPrevious = normalizeCollection(previousRelation.collection);
|
|
3282
|
+
if (normalizedCurrent !== normalizedPrevious) {
|
|
2932
3283
|
changes.push({
|
|
2933
3284
|
property: "relation.collection",
|
|
2934
|
-
oldValue:
|
|
2935
|
-
|
|
3285
|
+
oldValue: normalizedPrevious,
|
|
3286
|
+
// Use normalized value for clarity
|
|
3287
|
+
newValue: normalizedCurrent
|
|
3288
|
+
// Use normalized value for clarity
|
|
2936
3289
|
});
|
|
2937
3290
|
}
|
|
2938
3291
|
if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {
|
|
@@ -3305,10 +3658,10 @@ function mergeConfig4(config) {
|
|
|
3305
3658
|
}
|
|
3306
3659
|
function resolveMigrationDir(config) {
|
|
3307
3660
|
const workspaceRoot = config.workspaceRoot || process.cwd();
|
|
3308
|
-
if (
|
|
3661
|
+
if (path5.isAbsolute(config.migrationDir)) {
|
|
3309
3662
|
return config.migrationDir;
|
|
3310
3663
|
}
|
|
3311
|
-
return
|
|
3664
|
+
return path5.join(workspaceRoot, config.migrationDir);
|
|
3312
3665
|
}
|
|
3313
3666
|
function generateTimestamp(config) {
|
|
3314
3667
|
if (config?.timestampGenerator) {
|
|
@@ -3366,9 +3719,9 @@ function createMigrationFileStructure(upCode, downCode, config) {
|
|
|
3366
3719
|
}
|
|
3367
3720
|
function writeMigrationFile(migrationDir, filename, content) {
|
|
3368
3721
|
try {
|
|
3369
|
-
if (!
|
|
3722
|
+
if (!fs3.existsSync(migrationDir)) {
|
|
3370
3723
|
try {
|
|
3371
|
-
|
|
3724
|
+
fs3.mkdirSync(migrationDir, { recursive: true });
|
|
3372
3725
|
} catch (error) {
|
|
3373
3726
|
const fsError = error;
|
|
3374
3727
|
if (fsError.code === "EACCES" || fsError.code === "EPERM") {
|
|
@@ -3389,15 +3742,15 @@ function writeMigrationFile(migrationDir, filename, content) {
|
|
|
3389
3742
|
);
|
|
3390
3743
|
}
|
|
3391
3744
|
}
|
|
3392
|
-
const filePath =
|
|
3393
|
-
|
|
3745
|
+
const filePath = path5.join(migrationDir, filename);
|
|
3746
|
+
fs3.writeFileSync(filePath, content, "utf-8");
|
|
3394
3747
|
return filePath;
|
|
3395
3748
|
} catch (error) {
|
|
3396
3749
|
if (error instanceof FileSystemError) {
|
|
3397
3750
|
throw error;
|
|
3398
3751
|
}
|
|
3399
3752
|
const fsError = error;
|
|
3400
|
-
const filePath =
|
|
3753
|
+
const filePath = path5.join(migrationDir, filename);
|
|
3401
3754
|
if (fsError.code === "EACCES" || fsError.code === "EPERM") {
|
|
3402
3755
|
throw new FileSystemError(
|
|
3403
3756
|
`Permission denied writing migration file. Check file and directory permissions.`,
|
|
@@ -4141,8 +4494,8 @@ var DEFAULT_CONFIG5 = {
|
|
|
4141
4494
|
};
|
|
4142
4495
|
function findConfigFile(directory) {
|
|
4143
4496
|
for (const fileName of CONFIG_FILE_NAMES) {
|
|
4144
|
-
const filePath =
|
|
4145
|
-
if (
|
|
4497
|
+
const filePath = path5.join(directory, fileName);
|
|
4498
|
+
if (fs3.existsSync(filePath)) {
|
|
4146
4499
|
return filePath;
|
|
4147
4500
|
}
|
|
4148
4501
|
}
|
|
@@ -4150,7 +4503,7 @@ function findConfigFile(directory) {
|
|
|
4150
4503
|
}
|
|
4151
4504
|
function loadJsonConfig(configPath) {
|
|
4152
4505
|
try {
|
|
4153
|
-
const content =
|
|
4506
|
+
const content = fs3.readFileSync(configPath, "utf-8");
|
|
4154
4507
|
return JSON.parse(content);
|
|
4155
4508
|
} catch (error) {
|
|
4156
4509
|
if (error instanceof SyntaxError) {
|
|
@@ -4179,10 +4532,10 @@ async function loadJsConfig(configPath) {
|
|
|
4179
4532
|
}
|
|
4180
4533
|
}
|
|
4181
4534
|
async function loadConfigFile(configPath) {
|
|
4182
|
-
if (!
|
|
4535
|
+
if (!fs3.existsSync(configPath)) {
|
|
4183
4536
|
return null;
|
|
4184
4537
|
}
|
|
4185
|
-
const ext =
|
|
4538
|
+
const ext = path5.extname(configPath).toLowerCase();
|
|
4186
4539
|
if (ext === ".json") {
|
|
4187
4540
|
return loadJsonConfig(configPath);
|
|
4188
4541
|
} else if (ext === ".js" || ext === ".mjs") {
|
|
@@ -4249,10 +4602,10 @@ function validateConfig(config, configPath) {
|
|
|
4249
4602
|
}
|
|
4250
4603
|
const cwd = process.cwd();
|
|
4251
4604
|
const possiblePaths = [
|
|
4252
|
-
|
|
4253
|
-
|
|
4605
|
+
path5.resolve(cwd, config.schema.directory),
|
|
4606
|
+
path5.resolve(cwd, "shared", config.schema.directory)
|
|
4254
4607
|
];
|
|
4255
|
-
const schemaDir = possiblePaths.find((p) =>
|
|
4608
|
+
const schemaDir = possiblePaths.find((p) => fs3.existsSync(p));
|
|
4256
4609
|
if (!schemaDir) {
|
|
4257
4610
|
throw new ConfigurationError(`Schema directory not found. Tried: ${possiblePaths.join(", ")}`, configPath, [
|
|
4258
4611
|
"schema.directory"
|
|
@@ -4264,15 +4617,15 @@ async function loadConfig(options = {}) {
|
|
|
4264
4617
|
let configFilePath;
|
|
4265
4618
|
const cwd = process.cwd();
|
|
4266
4619
|
if (options.config) {
|
|
4267
|
-
const explicitPath =
|
|
4268
|
-
if (!
|
|
4620
|
+
const explicitPath = path5.resolve(cwd, options.config);
|
|
4621
|
+
if (!fs3.existsSync(explicitPath)) {
|
|
4269
4622
|
throw new ConfigurationError(`Configuration file not found: ${explicitPath}`, explicitPath);
|
|
4270
4623
|
}
|
|
4271
4624
|
configFilePath = explicitPath;
|
|
4272
4625
|
} else {
|
|
4273
|
-
const searchDirs = [cwd,
|
|
4626
|
+
const searchDirs = [cwd, path5.join(cwd, "shared")];
|
|
4274
4627
|
for (const dir of searchDirs) {
|
|
4275
|
-
if (
|
|
4628
|
+
if (fs3.existsSync(dir)) {
|
|
4276
4629
|
const found = findConfigFile(dir);
|
|
4277
4630
|
if (found) {
|
|
4278
4631
|
configFilePath = found;
|
|
@@ -4301,18 +4654,18 @@ async function loadConfig(options = {}) {
|
|
|
4301
4654
|
function getSchemaDirectory(config) {
|
|
4302
4655
|
const cwd = process.cwd();
|
|
4303
4656
|
const possiblePaths = [
|
|
4304
|
-
|
|
4305
|
-
|
|
4657
|
+
path5.resolve(cwd, config.schema.directory),
|
|
4658
|
+
path5.resolve(cwd, "shared", config.schema.directory)
|
|
4306
4659
|
];
|
|
4307
|
-
return possiblePaths.find((p) =>
|
|
4660
|
+
return possiblePaths.find((p) => fs3.existsSync(p)) || possiblePaths[0];
|
|
4308
4661
|
}
|
|
4309
4662
|
function getMigrationsDirectory(config) {
|
|
4310
4663
|
const cwd = process.cwd();
|
|
4311
4664
|
const possiblePaths = [
|
|
4312
|
-
|
|
4313
|
-
|
|
4665
|
+
path5.resolve(cwd, config.migrations.directory),
|
|
4666
|
+
path5.resolve(cwd, "shared", config.migrations.directory)
|
|
4314
4667
|
];
|
|
4315
|
-
return possiblePaths.find((p) =>
|
|
4668
|
+
return possiblePaths.find((p) => fs3.existsSync(p)) || possiblePaths[0];
|
|
4316
4669
|
}
|
|
4317
4670
|
var currentVerbosity = "normal";
|
|
4318
4671
|
function setVerbosity(level) {
|
|
@@ -4529,7 +4882,7 @@ async function executeGenerate(options) {
|
|
|
4529
4882
|
const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
|
|
4530
4883
|
logSuccess(`Found ${currentSchema.collections.size} collection(s)`);
|
|
4531
4884
|
logInfo("Loading previous snapshot...");
|
|
4532
|
-
const previousSnapshot =
|
|
4885
|
+
const previousSnapshot = loadSnapshotWithMigrations({
|
|
4533
4886
|
migrationsPath: migrationsDir,
|
|
4534
4887
|
workspaceRoot: process.cwd()
|
|
4535
4888
|
});
|
|
@@ -4556,7 +4909,7 @@ async function executeGenerate(options) {
|
|
|
4556
4909
|
"Creating migration file...",
|
|
4557
4910
|
() => Promise.resolve(generate(diff, migrationsDir))
|
|
4558
4911
|
);
|
|
4559
|
-
logSuccess(`Migration file created: ${
|
|
4912
|
+
logSuccess(`Migration file created: ${path5.basename(migrationPath)}`);
|
|
4560
4913
|
logSection("\u2705 Next Steps");
|
|
4561
4914
|
console.log();
|
|
4562
4915
|
console.log(" 1. Review the generated migration file:");
|
|
@@ -4722,7 +5075,7 @@ async function executeStatus(options) {
|
|
|
4722
5075
|
const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
|
|
4723
5076
|
logSuccess(`Found ${currentSchema.collections.size} collection(s) in schema`);
|
|
4724
5077
|
logInfo("Loading previous snapshot...");
|
|
4725
|
-
const previousSnapshot =
|
|
5078
|
+
const previousSnapshot = loadSnapshotWithMigrations({
|
|
4726
5079
|
migrationsPath: migrationsDir,
|
|
4727
5080
|
workspaceRoot: process.cwd()
|
|
4728
5081
|
});
|
|
@@ -4823,6 +5176,6 @@ async function executeStatus(options) {
|
|
|
4823
5176
|
}
|
|
4824
5177
|
}
|
|
4825
5178
|
|
|
4826
|
-
export { CLIUsageError, ConfigurationError, DiffEngine, FIELD_TYPE_INFO, FileSystemError, MigrationError, MigrationGenerationError, MigrationGenerator, POCKETBASE_FIELD_TYPES, PermissionTemplates, SchemaAnalyzer, SchemaParsingError, SnapshotError, SnapshotManager, StatusEnum, UserInputSchema, UserMutator, UserSchema, aggregateChanges, baseImageFileSchema, baseSchema, baseSchemaWithTimestamps, boolField, buildFieldDefinition, buildSchemaDefinition, categorizeChangesBySeverity, compare, compareFieldConstraints, compareFieldOptions, compareFieldTypes, comparePermissions, compareRelationConfigurations, convertPocketBaseMigration, convertZodSchemaToCollectionSchema, createMigrationFileStructure, createPermissions, dateField, detectDestructiveChanges, detectFieldChanges, discoverSchemaFiles, editorField, emailField, extractComprehensiveFieldOptions, extractFieldDefinitions, extractFieldOptions, extractIndexes, extractRelationMetadata, extractSchemaDefinitions, fileField, filesField, filterSystemCollections, findLatestSnapshot, findNewCollections, findNewFields, findRemovedCollections, findRemovedFields, formatChangeSummary, generate, generateChangeSummary, generateCollectionCreation, generateCollectionPermissions, generateCollectionRules, generateDownMigration, generateFieldAddition, generateFieldDefinitionObject, generateFieldDeletion, generateFieldModification, generateFieldsArray, generateIndexesArray, executeGenerate as generateMigration, generateMigrationDescription, generateMigrationFilename, generatePermissionUpdate, generateTimestamp, generateUpMigration, geoPointField, getArrayElementType, getCollectionNameFromFile, getDefaultValue, getFieldTypeInfo, getMaxSelect, executeStatus as getMigrationStatus, getMinSelect, getSnapshotPath, getSnapshotVersion, getUsersSystemFields, importSchemaModule, inputImageFileSchema, isArrayType, isAuthCollection, isEditorField, isFieldRequired, isFileFieldByName, isGeoPointType, isMultipleRelationField, isPermissionSchema, isRelationField, isSingleRelationField, isSystemCollection, isTemplateConfig, jsonField, loadBaseMigration, loadConfig, loadSnapshot, loadSnapshotIfExists, logError, logInfo, logSection, logSuccess, logWarning, mapZodArrayType, mapZodBooleanType, mapZodDateType, mapZodEnumType, mapZodNumberType, mapZodRecordType, mapZodStringType, mapZodTypeToPocketBase, matchCollectionsByName, matchFieldsByName, mergePermissions, mergeSnapshots, numberField, omitImageFilesSchema, parseSchemaFiles, pluralize, relationField, relationsField, requiresForceFlag, resolveTargetCollection, resolveTemplate, saveSnapshot, selectField, selectSchemaForCollection, singularize, snapshotExists, textField, toCollectionName, unwrapZodType, urlField, validatePermissionConfig, validateRuleExpression, validateSnapshot, withIndexes, withPermissions, withProgress, writeMigrationFile };
|
|
5179
|
+
export { CLIUsageError, ConfigurationError, DiffEngine, FIELD_TYPE_INFO, FileSystemError, MigrationError, MigrationGenerationError, MigrationGenerator, POCKETBASE_FIELD_TYPES, PermissionTemplates, ProjectInputSchema, ProjectSchema, SchemaAnalyzer, SchemaParsingError, SnapshotError, SnapshotManager, StatusEnum, UserInputSchema, UserMutator, UserSchema, aggregateChanges, baseImageFileSchema, baseSchema, baseSchemaWithTimestamps, boolField, buildFieldDefinition, buildSchemaDefinition, categorizeChangesBySeverity, compare, compareFieldConstraints, compareFieldOptions, compareFieldTypes, comparePermissions, compareRelationConfigurations, convertPocketBaseMigration, convertZodSchemaToCollectionSchema, createMigrationFileStructure, createPermissions, dateField, detectDestructiveChanges, detectFieldChanges, discoverSchemaFiles, editorField, emailField, extractComprehensiveFieldOptions, extractFieldDefinitions, extractFieldOptions, extractIndexes, extractRelationMetadata, extractSchemaDefinitions, fileField, filesField, filterSystemCollections, findLatestSnapshot, findNewCollections, findNewFields, findRemovedCollections, findRemovedFields, formatChangeSummary, generate, generateChangeSummary, generateCollectionCreation, generateCollectionPermissions, generateCollectionRules, generateDownMigration, generateFieldAddition, generateFieldDefinitionObject, generateFieldDeletion, generateFieldModification, generateFieldsArray, generateIndexesArray, executeGenerate as generateMigration, generateMigrationDescription, generateMigrationFilename, generatePermissionUpdate, generateTimestamp, generateUpMigration, geoPointField, getArrayElementType, getCollectionNameFromFile, getDefaultValue, getFieldTypeInfo, getMaxSelect, executeStatus as getMigrationStatus, getMinSelect, getSnapshotPath, getSnapshotVersion, getUsersSystemFields, importSchemaModule, inputImageFileSchema, isArrayType, isAuthCollection, isEditorField, isFieldRequired, isFileFieldByName, isGeoPointType, isMultipleRelationField, isPermissionSchema, isRelationField, isSingleRelationField, isSystemCollection, isTemplateConfig, jsonField, loadBaseMigration, loadConfig, loadSnapshot, loadSnapshotIfExists, loadSnapshotWithMigrations, logError, logInfo, logSection, logSuccess, logWarning, mapZodArrayType, mapZodBooleanType, mapZodDateType, mapZodEnumType, mapZodNumberType, mapZodRecordType, mapZodStringType, mapZodTypeToPocketBase, matchCollectionsByName, matchFieldsByName, mergePermissions, mergeSnapshots, numberField, omitImageFilesSchema, parseSchemaFiles, pluralize, relationField, relationsField, requiresForceFlag, resolveTargetCollection, resolveTemplate, saveSnapshot, selectField, selectSchemaForCollection, singularize, snapshotExists, textField, toCollectionName, unwrapZodType, urlField, validatePermissionConfig, validateRuleExpression, validateSnapshot, withIndexes, withPermissions, withProgress, writeMigrationFile };
|
|
4827
5180
|
//# sourceMappingURL=index.js.map
|
|
4828
5181
|
//# sourceMappingURL=index.js.map
|