pocketbase-zod-schema 0.1.2 → 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 +15 -0
- package/README.md +329 -99
- package/dist/cli/index.cjs +577 -152
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +575 -150
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/migrate.cjs +595 -153
- package/dist/cli/migrate.cjs.map +1 -1
- package/dist/cli/migrate.js +592 -151
- package/dist/cli/migrate.js.map +1 -1
- package/dist/cli/utils/index.cjs +1 -1
- package/dist/cli/utils/index.cjs.map +1 -1
- package/dist/cli/utils/index.js +1 -1
- package/dist/cli/utils/index.js.map +1 -1
- package/dist/index.cjs +688 -231
- 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 +685 -230
- package/dist/index.js.map +1 -1
- package/dist/migration/analyzer.cjs +101 -28
- package/dist/migration/analyzer.cjs.map +1 -1
- package/dist/migration/analyzer.js +101 -28
- 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/generator.cjs +60 -25
- package/dist/migration/generator.cjs.map +1 -1
- package/dist/migration/generator.d.cts +9 -5
- package/dist/migration/generator.d.ts +9 -5
- package/dist/migration/generator.js +60 -25
- package/dist/migration/generator.js.map +1 -1
- package/dist/migration/index.cjs +614 -171
- 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 +613 -171
- package/dist/migration/index.js.map +1 -1
- package/dist/migration/snapshot.cjs +432 -117
- 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 -116
- package/dist/migration/snapshot.js.map +1 -1
- package/dist/migration/utils/index.cjs +19 -17
- package/dist/migration/utils/index.cjs.map +1 -1
- package/dist/migration/utils/index.d.cts +3 -1
- package/dist/migration/utils/index.d.ts +3 -1
- package/dist/migration/utils/index.js +19 -17
- package/dist/migration/utils/index.js.map +1 -1
- package/dist/mutator.cjs +9 -11
- package/dist/mutator.cjs.map +1 -1
- package/dist/mutator.d.cts +5 -9
- package/dist/mutator.d.ts +5 -9
- package/dist/mutator.js +9 -11
- package/dist/mutator.js.map +1 -1
- package/dist/schema.cjs +54 -23
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +94 -12
- package/dist/schema.d.ts +94 -12
- package/dist/schema.js +54 -24
- package/dist/schema.js.map +1 -1
- package/dist/types.d.cts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/{user-jS1aYoeD.d.cts → user-_AM523hb.d.cts} +6 -6
- package/dist/{user-jS1aYoeD.d.ts → user-_AM523hb.d.ts} +6 -6
- package/package.json +2 -4
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
|
|
|
@@ -77,14 +77,48 @@ function filesField(options) {
|
|
|
77
77
|
if (options?.max !== void 0) schema = schema.max(options.max);
|
|
78
78
|
return schema;
|
|
79
79
|
}
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
var RELATION_METADATA_KEY = "__pocketbase_relation__";
|
|
81
|
+
function relationField(config) {
|
|
82
|
+
const metadata = {
|
|
83
|
+
[RELATION_METADATA_KEY]: {
|
|
84
|
+
type: "single",
|
|
85
|
+
collection: config.collection,
|
|
86
|
+
cascadeDelete: config.cascadeDelete ?? false,
|
|
87
|
+
maxSelect: 1,
|
|
88
|
+
minSelect: 0
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
return z.string().describe(JSON.stringify(metadata));
|
|
82
92
|
}
|
|
83
|
-
function relationsField(
|
|
93
|
+
function relationsField(config) {
|
|
94
|
+
const metadata = {
|
|
95
|
+
[RELATION_METADATA_KEY]: {
|
|
96
|
+
type: "multiple",
|
|
97
|
+
collection: config.collection,
|
|
98
|
+
cascadeDelete: config.cascadeDelete ?? false,
|
|
99
|
+
maxSelect: config.maxSelect ?? 999,
|
|
100
|
+
minSelect: config.minSelect ?? 0
|
|
101
|
+
}
|
|
102
|
+
};
|
|
84
103
|
let schema = z.array(z.string());
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
|
|
104
|
+
if (config.minSelect !== void 0) {
|
|
105
|
+
schema = schema.min(config.minSelect);
|
|
106
|
+
}
|
|
107
|
+
if (config.maxSelect !== void 0) {
|
|
108
|
+
schema = schema.max(config.maxSelect);
|
|
109
|
+
}
|
|
110
|
+
return schema.describe(JSON.stringify(metadata));
|
|
111
|
+
}
|
|
112
|
+
function extractRelationMetadata(description) {
|
|
113
|
+
if (!description) return null;
|
|
114
|
+
try {
|
|
115
|
+
const parsed = JSON.parse(description);
|
|
116
|
+
if (parsed[RELATION_METADATA_KEY]) {
|
|
117
|
+
return parsed[RELATION_METADATA_KEY];
|
|
118
|
+
}
|
|
119
|
+
} catch {
|
|
120
|
+
}
|
|
121
|
+
return null;
|
|
88
122
|
}
|
|
89
123
|
function editorField() {
|
|
90
124
|
return z.string();
|
|
@@ -116,7 +150,7 @@ function withIndexes(schema, indexes) {
|
|
|
116
150
|
return schema.describe(JSON.stringify(metadata));
|
|
117
151
|
}
|
|
118
152
|
|
|
119
|
-
// src/
|
|
153
|
+
// src/utils/permission-templates.ts
|
|
120
154
|
var PermissionTemplates = {
|
|
121
155
|
/**
|
|
122
156
|
* Public access - anyone can perform all operations
|
|
@@ -341,38 +375,36 @@ var ProjectInputSchema = z.object({
|
|
|
341
375
|
content: z.string(),
|
|
342
376
|
status: StatusEnum,
|
|
343
377
|
summary: z.string().optional(),
|
|
344
|
-
|
|
345
|
-
SubscriberUsers:
|
|
378
|
+
OwnerUser: relationField({ collection: "Users" }),
|
|
379
|
+
SubscriberUsers: relationsField({ collection: "Users" })
|
|
346
380
|
}).extend(inputImageFileSchema);
|
|
347
381
|
var ProjectSchema = withPermissions(
|
|
348
382
|
ProjectInputSchema.omit(omitImageFilesSchema).extend(baseImageFileSchema),
|
|
349
383
|
{
|
|
350
384
|
template: "owner-only",
|
|
351
|
-
ownerField: "
|
|
385
|
+
ownerField: "OwnerUser",
|
|
352
386
|
customRules: {
|
|
353
|
-
// Override list rule to allow authenticated users to see all projects
|
|
354
387
|
listRule: '@request.auth.id != ""',
|
|
355
|
-
|
|
356
|
-
viewRule: '@request.auth.id != "" && (User = @request.auth.id || SubscriberUsers ?= @request.auth.id)'
|
|
388
|
+
viewRule: '@request.auth.id != "" && (OwnerUser = @request.auth.id || SubscriberUsers ?= @request.auth.id)'
|
|
357
389
|
}
|
|
358
390
|
}
|
|
359
391
|
);
|
|
360
392
|
var UserInputSchema = z.object({
|
|
361
|
-
name: z.string().
|
|
393
|
+
name: z.string().optional(),
|
|
362
394
|
email: z.string().email(),
|
|
363
395
|
password: z.string().min(8, "Password must be at least 8 characters"),
|
|
364
396
|
passwordConfirm: z.string(),
|
|
365
397
|
avatar: z.instanceof(File).optional()
|
|
366
398
|
});
|
|
367
399
|
var UserDatabaseSchema = z.object({
|
|
368
|
-
name: z.string().
|
|
400
|
+
name: z.string().optional(),
|
|
369
401
|
email: z.string().email(),
|
|
370
402
|
password: z.string().min(8, "Password must be at least 8 characters"),
|
|
371
403
|
avatar: z.instanceof(File).optional()
|
|
372
404
|
});
|
|
373
405
|
var UserSchema = withIndexes(
|
|
374
406
|
withPermissions(UserDatabaseSchema.extend(baseSchema), {
|
|
375
|
-
// Users can list
|
|
407
|
+
// Users can list their own profile
|
|
376
408
|
listRule: "id = @request.auth.id",
|
|
377
409
|
// Users can view their own profile
|
|
378
410
|
viewRule: "id = @request.auth.id",
|
|
@@ -381,15 +413,13 @@ var UserSchema = withIndexes(
|
|
|
381
413
|
// Users can only update their own profile
|
|
382
414
|
updateRule: "id = @request.auth.id",
|
|
383
415
|
// Users can only delete their own account
|
|
384
|
-
deleteRule: "id = @request.auth.id"
|
|
385
|
-
//
|
|
386
|
-
manageRule: "id = @request.auth.id"
|
|
416
|
+
deleteRule: "id = @request.auth.id"
|
|
417
|
+
// manageRule is null in PocketBase default (not set)
|
|
387
418
|
}),
|
|
388
419
|
[
|
|
389
|
-
//
|
|
390
|
-
"CREATE UNIQUE INDEX
|
|
391
|
-
|
|
392
|
-
"CREATE INDEX idx_users_name ON users (name)"
|
|
420
|
+
// PocketBase's default indexes for auth collections
|
|
421
|
+
"CREATE UNIQUE INDEX `idx_tokenKey__pb_users_auth_` ON `users` (`tokenKey`)",
|
|
422
|
+
"CREATE UNIQUE INDEX `idx_email__pb_users_auth_` ON `users` (`email`) WHERE `email` != ''"
|
|
393
423
|
]
|
|
394
424
|
);
|
|
395
425
|
var BaseMutator = class {
|
|
@@ -730,7 +760,7 @@ var UserMutator = class extends BaseMutator {
|
|
|
730
760
|
};
|
|
731
761
|
}
|
|
732
762
|
getCollection() {
|
|
733
|
-
return this.pb.collection("
|
|
763
|
+
return this.pb.collection("Users");
|
|
734
764
|
}
|
|
735
765
|
async validateInput(input) {
|
|
736
766
|
return UserInputSchema.parse(input);
|
|
@@ -834,10 +864,10 @@ var FileSystemError = class _FileSystemError extends MigrationError {
|
|
|
834
864
|
operation;
|
|
835
865
|
code;
|
|
836
866
|
originalError;
|
|
837
|
-
constructor(message,
|
|
867
|
+
constructor(message, path7, operation, code, originalError) {
|
|
838
868
|
super(message);
|
|
839
869
|
this.name = "FileSystemError";
|
|
840
|
-
this.path =
|
|
870
|
+
this.path = path7;
|
|
841
871
|
this.operation = operation;
|
|
842
872
|
this.code = code;
|
|
843
873
|
this.originalError = originalError;
|
|
@@ -1496,26 +1526,28 @@ function getMaxSelect(fieldName, zodType) {
|
|
|
1496
1526
|
return 1;
|
|
1497
1527
|
}
|
|
1498
1528
|
function getMinSelect(fieldName, zodType) {
|
|
1499
|
-
if (
|
|
1500
|
-
return
|
|
1501
|
-
}
|
|
1502
|
-
let unwrappedType = zodType;
|
|
1503
|
-
if (zodType instanceof z.ZodOptional) {
|
|
1504
|
-
unwrappedType = zodType._def.innerType;
|
|
1505
|
-
}
|
|
1506
|
-
if (unwrappedType instanceof z.ZodNullable) {
|
|
1507
|
-
unwrappedType = unwrappedType._def.innerType;
|
|
1508
|
-
}
|
|
1509
|
-
if (unwrappedType instanceof z.ZodDefault) {
|
|
1510
|
-
unwrappedType = unwrappedType._def.innerType;
|
|
1529
|
+
if (isSingleRelationField(fieldName, zodType)) {
|
|
1530
|
+
return 0;
|
|
1511
1531
|
}
|
|
1512
|
-
if (
|
|
1513
|
-
|
|
1514
|
-
if (
|
|
1515
|
-
|
|
1532
|
+
if (isMultipleRelationField(fieldName, zodType)) {
|
|
1533
|
+
let unwrappedType = zodType;
|
|
1534
|
+
if (zodType instanceof z.ZodOptional) {
|
|
1535
|
+
unwrappedType = zodType._def.innerType;
|
|
1536
|
+
}
|
|
1537
|
+
if (unwrappedType instanceof z.ZodNullable) {
|
|
1538
|
+
unwrappedType = unwrappedType._def.innerType;
|
|
1539
|
+
}
|
|
1540
|
+
if (unwrappedType instanceof z.ZodDefault) {
|
|
1541
|
+
unwrappedType = unwrappedType._def.innerType;
|
|
1542
|
+
}
|
|
1543
|
+
if (unwrappedType instanceof z.ZodArray) {
|
|
1544
|
+
const arrayDef = unwrappedType._def;
|
|
1545
|
+
if (arrayDef.minLength) {
|
|
1546
|
+
return arrayDef.minLength.value;
|
|
1547
|
+
}
|
|
1516
1548
|
}
|
|
1517
1549
|
}
|
|
1518
|
-
return
|
|
1550
|
+
return 0;
|
|
1519
1551
|
}
|
|
1520
1552
|
var POCKETBASE_FIELD_TYPES = [
|
|
1521
1553
|
"text",
|
|
@@ -1938,20 +1970,20 @@ function mergeConfig(config) {
|
|
|
1938
1970
|
}
|
|
1939
1971
|
function resolveSchemaDir(config) {
|
|
1940
1972
|
const workspaceRoot = config.workspaceRoot || process.cwd();
|
|
1941
|
-
if (
|
|
1973
|
+
if (path5.isAbsolute(config.schemaDir)) {
|
|
1942
1974
|
return config.schemaDir;
|
|
1943
1975
|
}
|
|
1944
|
-
return
|
|
1976
|
+
return path5.join(workspaceRoot, config.schemaDir);
|
|
1945
1977
|
}
|
|
1946
1978
|
function discoverSchemaFiles(config) {
|
|
1947
1979
|
const normalizedConfig = typeof config === "string" ? { schemaDir: config } : config;
|
|
1948
1980
|
const mergedConfig = mergeConfig(normalizedConfig);
|
|
1949
1981
|
const schemaDir = resolveSchemaDir(normalizedConfig);
|
|
1950
1982
|
try {
|
|
1951
|
-
if (!
|
|
1983
|
+
if (!fs3.existsSync(schemaDir)) {
|
|
1952
1984
|
throw new FileSystemError(`Schema directory not found: ${schemaDir}`, schemaDir, "access", "ENOENT");
|
|
1953
1985
|
}
|
|
1954
|
-
const files =
|
|
1986
|
+
const files = fs3.readdirSync(schemaDir);
|
|
1955
1987
|
const schemaFiles = files.filter((file) => {
|
|
1956
1988
|
const hasValidExtension = mergedConfig.includeExtensions.some((ext) => file.endsWith(ext));
|
|
1957
1989
|
if (!hasValidExtension) return false;
|
|
@@ -1967,7 +1999,7 @@ function discoverSchemaFiles(config) {
|
|
|
1967
1999
|
});
|
|
1968
2000
|
return schemaFiles.map((file) => {
|
|
1969
2001
|
const ext = mergedConfig.includeExtensions.find((ext2) => file.endsWith(ext2)) || ".ts";
|
|
1970
|
-
return
|
|
2002
|
+
return path5.join(schemaDir, file.replace(new RegExp(`\\${ext}$`), ""));
|
|
1971
2003
|
});
|
|
1972
2004
|
} catch (error) {
|
|
1973
2005
|
if (error instanceof FileSystemError) {
|
|
@@ -1998,13 +2030,32 @@ async function importSchemaModule(filePath, config) {
|
|
|
1998
2030
|
if (config?.pathTransformer) {
|
|
1999
2031
|
importPath = config.pathTransformer(filePath);
|
|
2000
2032
|
}
|
|
2001
|
-
|
|
2002
|
-
|
|
2033
|
+
let resolvedPath = null;
|
|
2034
|
+
const jsPath = `${importPath}.js`;
|
|
2035
|
+
const tsPath = `${importPath}.ts`;
|
|
2036
|
+
if (fs3.existsSync(jsPath)) {
|
|
2037
|
+
resolvedPath = jsPath;
|
|
2038
|
+
} else if (fs3.existsSync(tsPath)) {
|
|
2039
|
+
resolvedPath = tsPath;
|
|
2040
|
+
} else {
|
|
2041
|
+
resolvedPath = jsPath;
|
|
2003
2042
|
}
|
|
2004
|
-
const fileUrl = new URL(`file://${
|
|
2043
|
+
const fileUrl = new URL(`file://${path5.resolve(resolvedPath)}`);
|
|
2005
2044
|
const module = await import(fileUrl.href);
|
|
2006
2045
|
return module;
|
|
2007
2046
|
} catch (error) {
|
|
2047
|
+
const tsPath = `${filePath}.ts`;
|
|
2048
|
+
const isTypeScriptFile = fs3.existsSync(tsPath);
|
|
2049
|
+
if (isTypeScriptFile) {
|
|
2050
|
+
throw new SchemaParsingError(
|
|
2051
|
+
`Failed to import TypeScript schema file. Node.js cannot import TypeScript files directly.
|
|
2052
|
+
Please either:
|
|
2053
|
+
1. Compile your schema files to JavaScript first, or
|
|
2054
|
+
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")`,
|
|
2055
|
+
filePath,
|
|
2056
|
+
error
|
|
2057
|
+
);
|
|
2058
|
+
}
|
|
2008
2059
|
throw new SchemaParsingError(
|
|
2009
2060
|
`Failed to import schema module. Make sure the schema files are compiled to JavaScript.`,
|
|
2010
2061
|
filePath,
|
|
@@ -2013,7 +2064,7 @@ async function importSchemaModule(filePath, config) {
|
|
|
2013
2064
|
}
|
|
2014
2065
|
}
|
|
2015
2066
|
function getCollectionNameFromFile(filePath) {
|
|
2016
|
-
const filename =
|
|
2067
|
+
const filename = path5.basename(filePath).replace(/\.(ts|js)$/, "");
|
|
2017
2068
|
return toCollectionName(filename);
|
|
2018
2069
|
}
|
|
2019
2070
|
function extractSchemaDefinitions(module, patterns = ["Schema", "InputSchema"]) {
|
|
@@ -2067,7 +2118,17 @@ function buildFieldDefinition(fieldName, zodType) {
|
|
|
2067
2118
|
required,
|
|
2068
2119
|
options
|
|
2069
2120
|
};
|
|
2070
|
-
|
|
2121
|
+
const relationMetadata = extractRelationMetadata(zodType.description);
|
|
2122
|
+
if (relationMetadata) {
|
|
2123
|
+
fieldDef.type = "relation";
|
|
2124
|
+
fieldDef.relation = {
|
|
2125
|
+
collection: relationMetadata.collection,
|
|
2126
|
+
maxSelect: relationMetadata.maxSelect,
|
|
2127
|
+
minSelect: relationMetadata.minSelect,
|
|
2128
|
+
cascadeDelete: relationMetadata.cascadeDelete
|
|
2129
|
+
};
|
|
2130
|
+
fieldDef.options = void 0;
|
|
2131
|
+
} else if (isRelationField(fieldName, zodType)) {
|
|
2071
2132
|
fieldDef.type = "relation";
|
|
2072
2133
|
const targetCollection = resolveTargetCollection(fieldName);
|
|
2073
2134
|
const maxSelect = getMaxSelect(fieldName, zodType);
|
|
@@ -2079,6 +2140,13 @@ function buildFieldDefinition(fieldName, zodType) {
|
|
|
2079
2140
|
cascadeDelete: false
|
|
2080
2141
|
// Default to false, can be configured later
|
|
2081
2142
|
};
|
|
2143
|
+
if (fieldDef.options) {
|
|
2144
|
+
const { min, max, pattern, ...relationSafeOptions } = fieldDef.options;
|
|
2145
|
+
console.log("min", min);
|
|
2146
|
+
console.log("max", max);
|
|
2147
|
+
console.log("pattern", pattern);
|
|
2148
|
+
fieldDef.options = Object.keys(relationSafeOptions).length > 0 ? relationSafeOptions : void 0;
|
|
2149
|
+
}
|
|
2082
2150
|
}
|
|
2083
2151
|
return fieldDef;
|
|
2084
2152
|
}
|
|
@@ -2131,11 +2199,12 @@ function convertZodSchemaToCollectionSchema(collectionName, zodSchema) {
|
|
|
2131
2199
|
fields,
|
|
2132
2200
|
indexes,
|
|
2133
2201
|
rules: {
|
|
2134
|
-
listRule: null,
|
|
2135
|
-
viewRule: null,
|
|
2136
|
-
createRule: null,
|
|
2137
|
-
updateRule: null,
|
|
2138
|
-
deleteRule: null
|
|
2202
|
+
listRule: permissions?.listRule ?? null,
|
|
2203
|
+
viewRule: permissions?.viewRule ?? null,
|
|
2204
|
+
createRule: permissions?.createRule ?? null,
|
|
2205
|
+
updateRule: permissions?.updateRule ?? null,
|
|
2206
|
+
deleteRule: permissions?.deleteRule ?? null,
|
|
2207
|
+
manageRule: permissions?.manageRule ?? null
|
|
2139
2208
|
},
|
|
2140
2209
|
permissions
|
|
2141
2210
|
};
|
|
@@ -2159,7 +2228,12 @@ async function buildSchemaDefinition(config) {
|
|
|
2159
2228
|
if (normalizedConfig.pathTransformer) {
|
|
2160
2229
|
importPath = normalizedConfig.pathTransformer(filePath);
|
|
2161
2230
|
} else if (mergedConfig.useCompiledFiles) {
|
|
2162
|
-
|
|
2231
|
+
const distPath = filePath.replace(/\/src\//, "/dist/");
|
|
2232
|
+
if (fs3.existsSync(`${distPath}.js`) || fs3.existsSync(`${distPath}.mjs`)) {
|
|
2233
|
+
importPath = distPath;
|
|
2234
|
+
} else {
|
|
2235
|
+
importPath = filePath;
|
|
2236
|
+
}
|
|
2163
2237
|
}
|
|
2164
2238
|
const module = await importSchemaModule(importPath, normalizedConfig);
|
|
2165
2239
|
const schemas = extractSchemaDefinitions(module, mergedConfig.schemaPatterns);
|
|
@@ -2211,7 +2285,359 @@ var SchemaAnalyzer = class {
|
|
|
2211
2285
|
return convertZodSchemaToCollectionSchema(name, schema);
|
|
2212
2286
|
}
|
|
2213
2287
|
};
|
|
2288
|
+
|
|
2289
|
+
// src/migration/pocketbase-converter.ts
|
|
2214
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";
|
|
2215
2641
|
var DEFAULT_SNAPSHOT_FILENAME = ".migration-snapshot.json";
|
|
2216
2642
|
var SNAPSHOT_MIGRATIONS = [
|
|
2217
2643
|
// Add migrations here as the format evolves
|
|
@@ -2226,7 +2652,7 @@ var DEFAULT_CONFIG2 = {
|
|
|
2226
2652
|
snapshotPath: DEFAULT_SNAPSHOT_FILENAME,
|
|
2227
2653
|
workspaceRoot: process.cwd(),
|
|
2228
2654
|
autoMigrate: true,
|
|
2229
|
-
version:
|
|
2655
|
+
version: SNAPSHOT_VERSION2
|
|
2230
2656
|
};
|
|
2231
2657
|
function mergeConfig2(config = {}) {
|
|
2232
2658
|
return {
|
|
@@ -2238,15 +2664,15 @@ function getSnapshotPath(config = {}) {
|
|
|
2238
2664
|
const mergedConfig = mergeConfig2(config);
|
|
2239
2665
|
const workspaceRoot = mergedConfig.workspaceRoot;
|
|
2240
2666
|
const snapshotFilename = mergedConfig.snapshotPath;
|
|
2241
|
-
if (
|
|
2667
|
+
if (path5.isAbsolute(snapshotFilename)) {
|
|
2242
2668
|
return snapshotFilename;
|
|
2243
2669
|
}
|
|
2244
|
-
return
|
|
2670
|
+
return path5.join(workspaceRoot, snapshotFilename);
|
|
2245
2671
|
}
|
|
2246
2672
|
function snapshotExists(config = {}) {
|
|
2247
2673
|
try {
|
|
2248
2674
|
const snapshotPath = getSnapshotPath(config);
|
|
2249
|
-
return
|
|
2675
|
+
return fs3.existsSync(snapshotPath);
|
|
2250
2676
|
} catch {
|
|
2251
2677
|
return false;
|
|
2252
2678
|
}
|
|
@@ -2305,13 +2731,13 @@ function addSnapshotMetadata(schema, config) {
|
|
|
2305
2731
|
function saveSnapshot(schema, config = {}) {
|
|
2306
2732
|
const snapshotPath = getSnapshotPath(config);
|
|
2307
2733
|
try {
|
|
2308
|
-
const snapshotDir =
|
|
2309
|
-
if (!
|
|
2310
|
-
|
|
2734
|
+
const snapshotDir = path5.dirname(snapshotPath);
|
|
2735
|
+
if (!fs3.existsSync(snapshotDir)) {
|
|
2736
|
+
fs3.mkdirSync(snapshotDir, { recursive: true });
|
|
2311
2737
|
}
|
|
2312
2738
|
const snapshotData = addSnapshotMetadata(schema, config);
|
|
2313
2739
|
const jsonContent = JSON.stringify(snapshotData, null, 2);
|
|
2314
|
-
|
|
2740
|
+
fs3.writeFileSync(snapshotPath, jsonContent, "utf-8");
|
|
2315
2741
|
} catch (error) {
|
|
2316
2742
|
handleFileSystemError(error, "write", snapshotPath);
|
|
2317
2743
|
}
|
|
@@ -2406,7 +2832,7 @@ function deserializeSnapshot(data) {
|
|
|
2406
2832
|
function loadSnapshot(config = {}) {
|
|
2407
2833
|
const snapshotPath = getSnapshotPath(config);
|
|
2408
2834
|
try {
|
|
2409
|
-
const jsonContent =
|
|
2835
|
+
const jsonContent = fs3.readFileSync(snapshotPath, "utf-8");
|
|
2410
2836
|
const data = parseAndValidateSnapshot(jsonContent, snapshotPath);
|
|
2411
2837
|
const migratedData = migrateSnapshotFormat(data, config);
|
|
2412
2838
|
return deserializeSnapshot(migratedData);
|
|
@@ -2441,10 +2867,10 @@ function mergeSnapshots(baseSnapshot, customSnapshot) {
|
|
|
2441
2867
|
}
|
|
2442
2868
|
function findLatestSnapshot(migrationsPath) {
|
|
2443
2869
|
try {
|
|
2444
|
-
if (!
|
|
2870
|
+
if (!fs3.existsSync(migrationsPath)) {
|
|
2445
2871
|
return null;
|
|
2446
2872
|
}
|
|
2447
|
-
const files =
|
|
2873
|
+
const files = fs3.readdirSync(migrationsPath);
|
|
2448
2874
|
const snapshotFiles = files.filter(
|
|
2449
2875
|
(file) => file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")
|
|
2450
2876
|
);
|
|
@@ -2456,20 +2882,74 @@ function findLatestSnapshot(migrationsPath) {
|
|
|
2456
2882
|
if (!latestSnapshot) {
|
|
2457
2883
|
return null;
|
|
2458
2884
|
}
|
|
2459
|
-
return
|
|
2885
|
+
return path5.join(migrationsPath, latestSnapshot);
|
|
2460
2886
|
} catch (error) {
|
|
2461
2887
|
console.warn(`Error finding latest snapshot: ${error}`);
|
|
2462
2888
|
return null;
|
|
2463
2889
|
}
|
|
2464
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
|
+
}
|
|
2465
2945
|
function loadSnapshotIfExists(config = {}) {
|
|
2466
2946
|
const migrationsPath = config.migrationsPath;
|
|
2467
2947
|
if (!migrationsPath) {
|
|
2468
2948
|
return null;
|
|
2469
2949
|
}
|
|
2470
|
-
if (
|
|
2950
|
+
if (fs3.existsSync(migrationsPath) && fs3.statSync(migrationsPath).isFile()) {
|
|
2471
2951
|
try {
|
|
2472
|
-
const migrationContent =
|
|
2952
|
+
const migrationContent = fs3.readFileSync(migrationsPath, "utf-8");
|
|
2473
2953
|
return convertPocketBaseMigration(migrationContent);
|
|
2474
2954
|
} catch (error) {
|
|
2475
2955
|
console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
|
|
@@ -2479,7 +2959,7 @@ function loadSnapshotIfExists(config = {}) {
|
|
|
2479
2959
|
const latestSnapshotPath = findLatestSnapshot(migrationsPath);
|
|
2480
2960
|
if (latestSnapshotPath) {
|
|
2481
2961
|
try {
|
|
2482
|
-
const migrationContent =
|
|
2962
|
+
const migrationContent = fs3.readFileSync(latestSnapshotPath, "utf-8");
|
|
2483
2963
|
return convertPocketBaseMigration(migrationContent);
|
|
2484
2964
|
} catch (error) {
|
|
2485
2965
|
console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
|
|
@@ -2488,99 +2968,9 @@ function loadSnapshotIfExists(config = {}) {
|
|
|
2488
2968
|
}
|
|
2489
2969
|
return null;
|
|
2490
2970
|
}
|
|
2491
|
-
function convertPocketBaseCollection(pbCollection) {
|
|
2492
|
-
const fields = [];
|
|
2493
|
-
const systemFieldNames = ["id", "created", "updated", "collectionId", "collectionName", "expand"];
|
|
2494
|
-
const authSystemFieldNames = ["email", "emailVisibility", "verified", "password", "tokenKey"];
|
|
2495
|
-
if (pbCollection.fields && Array.isArray(pbCollection.fields)) {
|
|
2496
|
-
for (const pbField of pbCollection.fields) {
|
|
2497
|
-
if (pbField.system || systemFieldNames.includes(pbField.name)) {
|
|
2498
|
-
continue;
|
|
2499
|
-
}
|
|
2500
|
-
if (pbCollection.type === "auth" && authSystemFieldNames.includes(pbField.name)) {
|
|
2501
|
-
continue;
|
|
2502
|
-
}
|
|
2503
|
-
const field = {
|
|
2504
|
-
name: pbField.name,
|
|
2505
|
-
type: pbField.type,
|
|
2506
|
-
required: pbField.required || false
|
|
2507
|
-
};
|
|
2508
|
-
if (pbField.options) {
|
|
2509
|
-
field.options = pbField.options;
|
|
2510
|
-
}
|
|
2511
|
-
if (pbField.type === "relation") {
|
|
2512
|
-
field.relation = {
|
|
2513
|
-
collection: pbField.options?.collectionId || "",
|
|
2514
|
-
cascadeDelete: pbField.options?.cascadeDelete || false,
|
|
2515
|
-
maxSelect: pbField.options?.maxSelect,
|
|
2516
|
-
minSelect: pbField.options?.minSelect
|
|
2517
|
-
};
|
|
2518
|
-
}
|
|
2519
|
-
fields.push(field);
|
|
2520
|
-
}
|
|
2521
|
-
}
|
|
2522
|
-
const schema = {
|
|
2523
|
-
name: pbCollection.name,
|
|
2524
|
-
type: pbCollection.type || "base",
|
|
2525
|
-
fields
|
|
2526
|
-
};
|
|
2527
|
-
if (pbCollection.indexes && Array.isArray(pbCollection.indexes)) {
|
|
2528
|
-
schema.indexes = pbCollection.indexes;
|
|
2529
|
-
}
|
|
2530
|
-
const rules = {};
|
|
2531
|
-
if (pbCollection.listRule !== void 0) rules.listRule = pbCollection.listRule;
|
|
2532
|
-
if (pbCollection.viewRule !== void 0) rules.viewRule = pbCollection.viewRule;
|
|
2533
|
-
if (pbCollection.createRule !== void 0) rules.createRule = pbCollection.createRule;
|
|
2534
|
-
if (pbCollection.updateRule !== void 0) rules.updateRule = pbCollection.updateRule;
|
|
2535
|
-
if (pbCollection.deleteRule !== void 0) rules.deleteRule = pbCollection.deleteRule;
|
|
2536
|
-
if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
|
|
2537
|
-
if (Object.keys(rules).length > 0) {
|
|
2538
|
-
schema.rules = rules;
|
|
2539
|
-
}
|
|
2540
|
-
return schema;
|
|
2541
|
-
}
|
|
2542
|
-
function convertPocketBaseMigration(migrationContent) {
|
|
2543
|
-
try {
|
|
2544
|
-
const snapshotMatch = migrationContent.match(/const\s+snapshot\s*=\s*(\[[\s\S]*?\]);/);
|
|
2545
|
-
if (!snapshotMatch) {
|
|
2546
|
-
throw new Error("Could not find snapshot array in migration file");
|
|
2547
|
-
}
|
|
2548
|
-
const snapshotArrayStr = snapshotMatch[1];
|
|
2549
|
-
let snapshotArray;
|
|
2550
|
-
try {
|
|
2551
|
-
snapshotArray = new Function(`return ${snapshotArrayStr}`)();
|
|
2552
|
-
} catch (parseError) {
|
|
2553
|
-
throw new Error(`Failed to parse snapshot array: ${parseError}`);
|
|
2554
|
-
}
|
|
2555
|
-
if (!Array.isArray(snapshotArray)) {
|
|
2556
|
-
throw new Error("Snapshot is not an array");
|
|
2557
|
-
}
|
|
2558
|
-
const collections = /* @__PURE__ */ new Map();
|
|
2559
|
-
for (const pbCollection of snapshotArray) {
|
|
2560
|
-
if (!pbCollection.name) {
|
|
2561
|
-
console.warn("Skipping collection without name");
|
|
2562
|
-
continue;
|
|
2563
|
-
}
|
|
2564
|
-
const schema = convertPocketBaseCollection(pbCollection);
|
|
2565
|
-
collections.set(pbCollection.name, schema);
|
|
2566
|
-
}
|
|
2567
|
-
return {
|
|
2568
|
-
version: SNAPSHOT_VERSION,
|
|
2569
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2570
|
-
collections
|
|
2571
|
-
};
|
|
2572
|
-
} catch (error) {
|
|
2573
|
-
throw new SnapshotError(
|
|
2574
|
-
`Failed to convert PocketBase migration: ${error instanceof Error ? error.message : String(error)}`,
|
|
2575
|
-
void 0,
|
|
2576
|
-
"parse",
|
|
2577
|
-
error instanceof Error ? error : void 0
|
|
2578
|
-
);
|
|
2579
|
-
}
|
|
2580
|
-
}
|
|
2581
2971
|
function loadBaseMigration(migrationPath) {
|
|
2582
2972
|
try {
|
|
2583
|
-
if (!
|
|
2973
|
+
if (!fs3.existsSync(migrationPath)) {
|
|
2584
2974
|
throw new SnapshotError(
|
|
2585
2975
|
`Base migration file not found: ${migrationPath}
|
|
2586
2976
|
|
|
@@ -2591,7 +2981,7 @@ If the file exists in a different location, update the configuration.`,
|
|
|
2591
2981
|
"read"
|
|
2592
2982
|
);
|
|
2593
2983
|
}
|
|
2594
|
-
const migrationContent =
|
|
2984
|
+
const migrationContent = fs3.readFileSync(migrationPath, "utf-8");
|
|
2595
2985
|
const snapshot = convertPocketBaseMigration(migrationContent);
|
|
2596
2986
|
return snapshot;
|
|
2597
2987
|
} catch (error) {
|
|
@@ -2627,14 +3017,14 @@ Please ensure PocketBase is properly set up by running 'yarn setup'.`,
|
|
|
2627
3017
|
}
|
|
2628
3018
|
}
|
|
2629
3019
|
function getSnapshotVersion() {
|
|
2630
|
-
return
|
|
3020
|
+
return SNAPSHOT_VERSION2;
|
|
2631
3021
|
}
|
|
2632
3022
|
function validateSnapshot(snapshot) {
|
|
2633
3023
|
const issues = [];
|
|
2634
3024
|
if (!snapshot.version) {
|
|
2635
3025
|
issues.push("Missing version field");
|
|
2636
|
-
} else if (compareVersions(snapshot.version,
|
|
2637
|
-
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}`);
|
|
2638
3028
|
}
|
|
2639
3029
|
if (!snapshot.timestamp) {
|
|
2640
3030
|
issues.push("Missing timestamp field");
|
|
@@ -2853,6 +3243,9 @@ function compareFieldOptions(currentField, previousField) {
|
|
|
2853
3243
|
for (const key of allKeys) {
|
|
2854
3244
|
const currentValue = currentOptions[key];
|
|
2855
3245
|
const previousValue = previousOptions[key];
|
|
3246
|
+
if (currentValue === void 0 && previousValue === void 0) {
|
|
3247
|
+
continue;
|
|
3248
|
+
}
|
|
2856
3249
|
if (!areValuesEqual(currentValue, previousValue)) {
|
|
2857
3250
|
changes.push({
|
|
2858
3251
|
property: `options.${key}`,
|
|
@@ -2873,11 +3266,26 @@ function compareRelationConfigurations(currentField, previousField) {
|
|
|
2873
3266
|
if (!currentRelation || !previousRelation) {
|
|
2874
3267
|
return changes;
|
|
2875
3268
|
}
|
|
2876
|
-
|
|
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) {
|
|
2877
3283
|
changes.push({
|
|
2878
3284
|
property: "relation.collection",
|
|
2879
|
-
oldValue:
|
|
2880
|
-
|
|
3285
|
+
oldValue: normalizedPrevious,
|
|
3286
|
+
// Use normalized value for clarity
|
|
3287
|
+
newValue: normalizedCurrent
|
|
3288
|
+
// Use normalized value for clarity
|
|
2881
3289
|
});
|
|
2882
3290
|
}
|
|
2883
3291
|
if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {
|
|
@@ -3231,10 +3639,8 @@ var DiffEngine = class {
|
|
|
3231
3639
|
var DEFAULT_TEMPLATE = `/// <reference path="{{TYPES_PATH}}" />
|
|
3232
3640
|
migrate((app) => {
|
|
3233
3641
|
{{UP_CODE}}
|
|
3234
|
-
return true;
|
|
3235
3642
|
}, (app) => {
|
|
3236
3643
|
{{DOWN_CODE}}
|
|
3237
|
-
return true;
|
|
3238
3644
|
});
|
|
3239
3645
|
`;
|
|
3240
3646
|
var DEFAULT_CONFIG4 = {
|
|
@@ -3252,10 +3658,10 @@ function mergeConfig4(config) {
|
|
|
3252
3658
|
}
|
|
3253
3659
|
function resolveMigrationDir(config) {
|
|
3254
3660
|
const workspaceRoot = config.workspaceRoot || process.cwd();
|
|
3255
|
-
if (
|
|
3661
|
+
if (path5.isAbsolute(config.migrationDir)) {
|
|
3256
3662
|
return config.migrationDir;
|
|
3257
3663
|
}
|
|
3258
|
-
return
|
|
3664
|
+
return path5.join(workspaceRoot, config.migrationDir);
|
|
3259
3665
|
}
|
|
3260
3666
|
function generateTimestamp(config) {
|
|
3261
3667
|
if (config?.timestampGenerator) {
|
|
@@ -3313,9 +3719,9 @@ function createMigrationFileStructure(upCode, downCode, config) {
|
|
|
3313
3719
|
}
|
|
3314
3720
|
function writeMigrationFile(migrationDir, filename, content) {
|
|
3315
3721
|
try {
|
|
3316
|
-
if (!
|
|
3722
|
+
if (!fs3.existsSync(migrationDir)) {
|
|
3317
3723
|
try {
|
|
3318
|
-
|
|
3724
|
+
fs3.mkdirSync(migrationDir, { recursive: true });
|
|
3319
3725
|
} catch (error) {
|
|
3320
3726
|
const fsError = error;
|
|
3321
3727
|
if (fsError.code === "EACCES" || fsError.code === "EPERM") {
|
|
@@ -3336,15 +3742,15 @@ function writeMigrationFile(migrationDir, filename, content) {
|
|
|
3336
3742
|
);
|
|
3337
3743
|
}
|
|
3338
3744
|
}
|
|
3339
|
-
const filePath =
|
|
3340
|
-
|
|
3745
|
+
const filePath = path5.join(migrationDir, filename);
|
|
3746
|
+
fs3.writeFileSync(filePath, content, "utf-8");
|
|
3341
3747
|
return filePath;
|
|
3342
3748
|
} catch (error) {
|
|
3343
3749
|
if (error instanceof FileSystemError) {
|
|
3344
3750
|
throw error;
|
|
3345
3751
|
}
|
|
3346
3752
|
const fsError = error;
|
|
3347
|
-
const filePath =
|
|
3753
|
+
const filePath = path5.join(migrationDir, filename);
|
|
3348
3754
|
if (fsError.code === "EACCES" || fsError.code === "EPERM") {
|
|
3349
3755
|
throw new FileSystemError(
|
|
3350
3756
|
`Permission denied writing migration file. Check file and directory permissions.`,
|
|
@@ -3399,7 +3805,8 @@ function generateFieldDefinitionObject(field) {
|
|
|
3399
3805
|
}
|
|
3400
3806
|
}
|
|
3401
3807
|
if (field.relation) {
|
|
3402
|
-
const
|
|
3808
|
+
const isUsersCollection = field.relation.collection.toLowerCase() === "users";
|
|
3809
|
+
const collectionIdPlaceholder = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
|
|
3403
3810
|
parts.push(` collectionId: ${collectionIdPlaceholder}`);
|
|
3404
3811
|
if (field.relation.maxSelect !== void 0) {
|
|
3405
3812
|
parts.push(` maxSelect: ${field.relation.maxSelect}`);
|
|
@@ -3483,7 +3890,7 @@ function generateIndexesArray(indexes) {
|
|
|
3483
3890
|
${indexStrings.join(",\n ")},
|
|
3484
3891
|
]`;
|
|
3485
3892
|
}
|
|
3486
|
-
function generateCollectionCreation(collection, varName = "collection") {
|
|
3893
|
+
function generateCollectionCreation(collection, varName = "collection", isLast = false) {
|
|
3487
3894
|
const lines = [];
|
|
3488
3895
|
lines.push(` const ${varName} = new Collection({`);
|
|
3489
3896
|
lines.push(` name: "${collection.name}",`);
|
|
@@ -3499,7 +3906,7 @@ function generateCollectionCreation(collection, varName = "collection") {
|
|
|
3499
3906
|
lines.push(` indexes: ${generateIndexesArray(collection.indexes)},`);
|
|
3500
3907
|
lines.push(` });`);
|
|
3501
3908
|
lines.push(``);
|
|
3502
|
-
lines.push(` app.save(${varName});`);
|
|
3909
|
+
lines.push(isLast ? ` return app.save(${varName});` : ` app.save(${varName});`);
|
|
3503
3910
|
return lines.join("\n");
|
|
3504
3911
|
}
|
|
3505
3912
|
function getFieldConstructorName(fieldType) {
|
|
@@ -3530,7 +3937,8 @@ function generateFieldConstructorOptions(field) {
|
|
|
3530
3937
|
}
|
|
3531
3938
|
}
|
|
3532
3939
|
if (field.relation && field.type === "relation") {
|
|
3533
|
-
const
|
|
3940
|
+
const isUsersCollection = field.relation.collection.toLowerCase() === "users";
|
|
3941
|
+
const collectionIdPlaceholder = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
|
|
3534
3942
|
parts.push(` collectionId: ${collectionIdPlaceholder}`);
|
|
3535
3943
|
if (field.relation.maxSelect !== void 0) {
|
|
3536
3944
|
parts.push(` maxSelect: ${field.relation.maxSelect}`);
|
|
@@ -3544,7 +3952,7 @@ function generateFieldConstructorOptions(field) {
|
|
|
3544
3952
|
}
|
|
3545
3953
|
return parts.join(",\n");
|
|
3546
3954
|
}
|
|
3547
|
-
function generateFieldAddition(collectionName, field, varName) {
|
|
3955
|
+
function generateFieldAddition(collectionName, field, varName, isLast = false) {
|
|
3548
3956
|
const lines = [];
|
|
3549
3957
|
const constructorName = getFieldConstructorName(field.type);
|
|
3550
3958
|
const collectionVar = varName || `collection_${collectionName}_${field.name}`;
|
|
@@ -3554,10 +3962,10 @@ function generateFieldAddition(collectionName, field, varName) {
|
|
|
3554
3962
|
lines.push(generateFieldConstructorOptions(field));
|
|
3555
3963
|
lines.push(` }));`);
|
|
3556
3964
|
lines.push(``);
|
|
3557
|
-
lines.push(` app.save(${collectionVar});`);
|
|
3965
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
3558
3966
|
return lines.join("\n");
|
|
3559
3967
|
}
|
|
3560
|
-
function generateFieldModification(collectionName, modification, varName) {
|
|
3968
|
+
function generateFieldModification(collectionName, modification, varName, isLast = false) {
|
|
3561
3969
|
const lines = [];
|
|
3562
3970
|
const collectionVar = varName || `collection_${collectionName}_${modification.fieldName}`;
|
|
3563
3971
|
const fieldVar = `${collectionVar}_field`;
|
|
@@ -3571,7 +3979,8 @@ function generateFieldModification(collectionName, modification, varName) {
|
|
|
3571
3979
|
} else if (change.property.startsWith("relation.")) {
|
|
3572
3980
|
const relationKey = change.property.replace("relation.", "");
|
|
3573
3981
|
if (relationKey === "collection") {
|
|
3574
|
-
const
|
|
3982
|
+
const isUsersCollection = String(change.newValue).toLowerCase() === "users";
|
|
3983
|
+
const collectionIdValue = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${change.newValue}").id`;
|
|
3575
3984
|
lines.push(` ${fieldVar}.collectionId = ${collectionIdValue};`);
|
|
3576
3985
|
} else {
|
|
3577
3986
|
lines.push(` ${fieldVar}.${relationKey} = ${formatValue(change.newValue)};`);
|
|
@@ -3581,10 +3990,10 @@ function generateFieldModification(collectionName, modification, varName) {
|
|
|
3581
3990
|
}
|
|
3582
3991
|
}
|
|
3583
3992
|
lines.push(``);
|
|
3584
|
-
lines.push(` app.save(${collectionVar});`);
|
|
3993
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
3585
3994
|
return lines.join("\n");
|
|
3586
3995
|
}
|
|
3587
|
-
function generateFieldDeletion(collectionName, fieldName, varName) {
|
|
3996
|
+
function generateFieldDeletion(collectionName, fieldName, varName, isLast = false) {
|
|
3588
3997
|
const lines = [];
|
|
3589
3998
|
const collectionVar = varName || `collection_${collectionName}_${fieldName}`;
|
|
3590
3999
|
const fieldVar = `${collectionVar}_field`;
|
|
@@ -3593,18 +4002,18 @@ function generateFieldDeletion(collectionName, fieldName, varName) {
|
|
|
3593
4002
|
lines.push(``);
|
|
3594
4003
|
lines.push(` ${collectionVar}.fields.remove(${fieldVar}.id);`);
|
|
3595
4004
|
lines.push(``);
|
|
3596
|
-
lines.push(` app.save(${collectionVar});`);
|
|
4005
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
3597
4006
|
return lines.join("\n");
|
|
3598
4007
|
}
|
|
3599
|
-
function generateIndexAddition(collectionName, index, varName) {
|
|
4008
|
+
function generateIndexAddition(collectionName, index, varName, isLast = false) {
|
|
3600
4009
|
const lines = [];
|
|
3601
4010
|
const collectionVar = varName || `collection_${collectionName}_idx`;
|
|
3602
4011
|
lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
|
|
3603
4012
|
lines.push(` ${collectionVar}.indexes.push("${index}");`);
|
|
3604
|
-
lines.push(` app.save(${collectionVar});`);
|
|
4013
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
3605
4014
|
return lines.join("\n");
|
|
3606
4015
|
}
|
|
3607
|
-
function generateIndexRemoval(collectionName, index, varName) {
|
|
4016
|
+
function generateIndexRemoval(collectionName, index, varName, isLast = false) {
|
|
3608
4017
|
const lines = [];
|
|
3609
4018
|
const collectionVar = varName || `collection_${collectionName}_idx`;
|
|
3610
4019
|
const indexVar = `${collectionVar}_indexToRemove`;
|
|
@@ -3613,29 +4022,29 @@ function generateIndexRemoval(collectionName, index, varName) {
|
|
|
3613
4022
|
lines.push(` if (${indexVar} !== -1) {`);
|
|
3614
4023
|
lines.push(` ${collectionVar}.indexes.splice(${indexVar}, 1);`);
|
|
3615
4024
|
lines.push(` }`);
|
|
3616
|
-
lines.push(` app.save(${collectionVar});`);
|
|
4025
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
3617
4026
|
return lines.join("\n");
|
|
3618
4027
|
}
|
|
3619
|
-
function generateRuleUpdate(collectionName, ruleType, newValue, varName) {
|
|
4028
|
+
function generateRuleUpdate(collectionName, ruleType, newValue, varName, isLast = false) {
|
|
3620
4029
|
const lines = [];
|
|
3621
4030
|
const collectionVar = varName || `collection_${collectionName}_${ruleType}`;
|
|
3622
4031
|
lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
|
|
3623
4032
|
lines.push(` ${collectionVar}.${ruleType} = ${formatValue(newValue)};`);
|
|
3624
|
-
lines.push(` app.save(${collectionVar});`);
|
|
4033
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
3625
4034
|
return lines.join("\n");
|
|
3626
4035
|
}
|
|
3627
|
-
function generatePermissionUpdate(collectionName, ruleType, newValue, varName) {
|
|
4036
|
+
function generatePermissionUpdate(collectionName, ruleType, newValue, varName, isLast = false) {
|
|
3628
4037
|
const lines = [];
|
|
3629
4038
|
const collectionVar = varName || `collection_${collectionName}_${ruleType}`;
|
|
3630
4039
|
lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
|
|
3631
4040
|
lines.push(` ${collectionVar}.${ruleType} = ${formatValue(newValue)};`);
|
|
3632
|
-
lines.push(` app.save(${collectionVar});`);
|
|
4041
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
3633
4042
|
return lines.join("\n");
|
|
3634
4043
|
}
|
|
3635
|
-
function generateCollectionDeletion(collectionName, varName = "collection") {
|
|
4044
|
+
function generateCollectionDeletion(collectionName, varName = "collection", isLast = false) {
|
|
3636
4045
|
const lines = [];
|
|
3637
4046
|
lines.push(` const ${varName} = app.findCollectionByNameOrId("${collectionName}");`);
|
|
3638
|
-
lines.push(` app.delete(${varName});`);
|
|
4047
|
+
lines.push(isLast ? ` return app.delete(${varName});` : ` app.delete(${varName});`);
|
|
3639
4048
|
return lines.join("\n");
|
|
3640
4049
|
}
|
|
3641
4050
|
function generateUpMigration(diff) {
|
|
@@ -3727,7 +4136,24 @@ function generateUpMigration(diff) {
|
|
|
3727
4136
|
lines.push(` // No changes detected`);
|
|
3728
4137
|
lines.push(``);
|
|
3729
4138
|
}
|
|
3730
|
-
|
|
4139
|
+
let code = lines.join("\n");
|
|
4140
|
+
const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
|
|
4141
|
+
const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
|
|
4142
|
+
const saveMatches = [...code.matchAll(savePattern)];
|
|
4143
|
+
const deleteMatches = [...code.matchAll(deletePattern)];
|
|
4144
|
+
const allMatches = [
|
|
4145
|
+
...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
|
|
4146
|
+
...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
|
|
4147
|
+
].sort((a, b) => b.index - a.index);
|
|
4148
|
+
if (allMatches.length > 0) {
|
|
4149
|
+
const lastMatch = allMatches[0];
|
|
4150
|
+
if (lastMatch.type === "save") {
|
|
4151
|
+
code = code.substring(0, lastMatch.match.index) + lastMatch.match[1] + "return app.save(" + lastMatch.match[2] + ");" + code.substring(lastMatch.match.index + lastMatch.match[0].length);
|
|
4152
|
+
} else {
|
|
4153
|
+
code = code.substring(0, lastMatch.match.index) + lastMatch.match[1] + "return app.delete(" + lastMatch.match[2] + ");" + code.substring(lastMatch.match.index + lastMatch.match[0].length);
|
|
4154
|
+
}
|
|
4155
|
+
}
|
|
4156
|
+
return code;
|
|
3731
4157
|
}
|
|
3732
4158
|
function generateDownMigration(diff) {
|
|
3733
4159
|
const lines = [];
|
|
@@ -3829,7 +4255,24 @@ function generateDownMigration(diff) {
|
|
|
3829
4255
|
lines.push(` // No changes to revert`);
|
|
3830
4256
|
lines.push(``);
|
|
3831
4257
|
}
|
|
3832
|
-
|
|
4258
|
+
let code = lines.join("\n");
|
|
4259
|
+
const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
|
|
4260
|
+
const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
|
|
4261
|
+
const saveMatches = [...code.matchAll(savePattern)];
|
|
4262
|
+
const deleteMatches = [...code.matchAll(deletePattern)];
|
|
4263
|
+
const allMatches = [
|
|
4264
|
+
...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
|
|
4265
|
+
...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
|
|
4266
|
+
].sort((a, b) => b.index - a.index);
|
|
4267
|
+
if (allMatches.length > 0) {
|
|
4268
|
+
const lastMatch = allMatches[0];
|
|
4269
|
+
if (lastMatch.type === "save") {
|
|
4270
|
+
code = code.substring(0, lastMatch.match.index) + lastMatch.match[1] + "return app.save(" + lastMatch.match[2] + ");" + code.substring(lastMatch.match.index + lastMatch.match[0].length);
|
|
4271
|
+
} else {
|
|
4272
|
+
code = code.substring(0, lastMatch.match.index) + lastMatch.match[1] + "return app.delete(" + lastMatch.match[2] + ");" + code.substring(lastMatch.match.index + lastMatch.match[0].length);
|
|
4273
|
+
}
|
|
4274
|
+
}
|
|
4275
|
+
return code;
|
|
3833
4276
|
}
|
|
3834
4277
|
function generate(diff, config) {
|
|
3835
4278
|
const normalizedConfig = typeof config === "string" ? { migrationDir: config } : config;
|
|
@@ -4051,8 +4494,8 @@ var DEFAULT_CONFIG5 = {
|
|
|
4051
4494
|
};
|
|
4052
4495
|
function findConfigFile(directory) {
|
|
4053
4496
|
for (const fileName of CONFIG_FILE_NAMES) {
|
|
4054
|
-
const filePath =
|
|
4055
|
-
if (
|
|
4497
|
+
const filePath = path5.join(directory, fileName);
|
|
4498
|
+
if (fs3.existsSync(filePath)) {
|
|
4056
4499
|
return filePath;
|
|
4057
4500
|
}
|
|
4058
4501
|
}
|
|
@@ -4060,7 +4503,7 @@ function findConfigFile(directory) {
|
|
|
4060
4503
|
}
|
|
4061
4504
|
function loadJsonConfig(configPath) {
|
|
4062
4505
|
try {
|
|
4063
|
-
const content =
|
|
4506
|
+
const content = fs3.readFileSync(configPath, "utf-8");
|
|
4064
4507
|
return JSON.parse(content);
|
|
4065
4508
|
} catch (error) {
|
|
4066
4509
|
if (error instanceof SyntaxError) {
|
|
@@ -4089,10 +4532,10 @@ async function loadJsConfig(configPath) {
|
|
|
4089
4532
|
}
|
|
4090
4533
|
}
|
|
4091
4534
|
async function loadConfigFile(configPath) {
|
|
4092
|
-
if (!
|
|
4535
|
+
if (!fs3.existsSync(configPath)) {
|
|
4093
4536
|
return null;
|
|
4094
4537
|
}
|
|
4095
|
-
const ext =
|
|
4538
|
+
const ext = path5.extname(configPath).toLowerCase();
|
|
4096
4539
|
if (ext === ".json") {
|
|
4097
4540
|
return loadJsonConfig(configPath);
|
|
4098
4541
|
} else if (ext === ".js" || ext === ".mjs") {
|
|
@@ -4159,10 +4602,10 @@ function validateConfig(config, configPath) {
|
|
|
4159
4602
|
}
|
|
4160
4603
|
const cwd = process.cwd();
|
|
4161
4604
|
const possiblePaths = [
|
|
4162
|
-
|
|
4163
|
-
|
|
4605
|
+
path5.resolve(cwd, config.schema.directory),
|
|
4606
|
+
path5.resolve(cwd, "shared", config.schema.directory)
|
|
4164
4607
|
];
|
|
4165
|
-
const schemaDir = possiblePaths.find((p) =>
|
|
4608
|
+
const schemaDir = possiblePaths.find((p) => fs3.existsSync(p));
|
|
4166
4609
|
if (!schemaDir) {
|
|
4167
4610
|
throw new ConfigurationError(`Schema directory not found. Tried: ${possiblePaths.join(", ")}`, configPath, [
|
|
4168
4611
|
"schema.directory"
|
|
@@ -4174,15 +4617,15 @@ async function loadConfig(options = {}) {
|
|
|
4174
4617
|
let configFilePath;
|
|
4175
4618
|
const cwd = process.cwd();
|
|
4176
4619
|
if (options.config) {
|
|
4177
|
-
const explicitPath =
|
|
4178
|
-
if (!
|
|
4620
|
+
const explicitPath = path5.resolve(cwd, options.config);
|
|
4621
|
+
if (!fs3.existsSync(explicitPath)) {
|
|
4179
4622
|
throw new ConfigurationError(`Configuration file not found: ${explicitPath}`, explicitPath);
|
|
4180
4623
|
}
|
|
4181
4624
|
configFilePath = explicitPath;
|
|
4182
4625
|
} else {
|
|
4183
|
-
const searchDirs = [cwd,
|
|
4626
|
+
const searchDirs = [cwd, path5.join(cwd, "shared")];
|
|
4184
4627
|
for (const dir of searchDirs) {
|
|
4185
|
-
if (
|
|
4628
|
+
if (fs3.existsSync(dir)) {
|
|
4186
4629
|
const found = findConfigFile(dir);
|
|
4187
4630
|
if (found) {
|
|
4188
4631
|
configFilePath = found;
|
|
@@ -4211,18 +4654,18 @@ async function loadConfig(options = {}) {
|
|
|
4211
4654
|
function getSchemaDirectory(config) {
|
|
4212
4655
|
const cwd = process.cwd();
|
|
4213
4656
|
const possiblePaths = [
|
|
4214
|
-
|
|
4215
|
-
|
|
4657
|
+
path5.resolve(cwd, config.schema.directory),
|
|
4658
|
+
path5.resolve(cwd, "shared", config.schema.directory)
|
|
4216
4659
|
];
|
|
4217
|
-
return possiblePaths.find((p) =>
|
|
4660
|
+
return possiblePaths.find((p) => fs3.existsSync(p)) || possiblePaths[0];
|
|
4218
4661
|
}
|
|
4219
4662
|
function getMigrationsDirectory(config) {
|
|
4220
4663
|
const cwd = process.cwd();
|
|
4221
4664
|
const possiblePaths = [
|
|
4222
|
-
|
|
4223
|
-
|
|
4665
|
+
path5.resolve(cwd, config.migrations.directory),
|
|
4666
|
+
path5.resolve(cwd, "shared", config.migrations.directory)
|
|
4224
4667
|
];
|
|
4225
|
-
return possiblePaths.find((p) =>
|
|
4668
|
+
return possiblePaths.find((p) => fs3.existsSync(p)) || possiblePaths[0];
|
|
4226
4669
|
}
|
|
4227
4670
|
var currentVerbosity = "normal";
|
|
4228
4671
|
function setVerbosity(level) {
|
|
@@ -4430,10 +4873,16 @@ async function executeGenerate(options) {
|
|
|
4430
4873
|
const schemaDir = getSchemaDirectory(config);
|
|
4431
4874
|
const migrationsDir = getMigrationsDirectory(config);
|
|
4432
4875
|
logSection("\u{1F50D} Analyzing Schema");
|
|
4433
|
-
const
|
|
4876
|
+
const analyzerConfig = {
|
|
4877
|
+
schemaDir,
|
|
4878
|
+
excludePatterns: config.schema.exclude,
|
|
4879
|
+
useCompiledFiles: false
|
|
4880
|
+
// Use source files since we're in development/testing
|
|
4881
|
+
};
|
|
4882
|
+
const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
|
|
4434
4883
|
logSuccess(`Found ${currentSchema.collections.size} collection(s)`);
|
|
4435
4884
|
logInfo("Loading previous snapshot...");
|
|
4436
|
-
const previousSnapshot =
|
|
4885
|
+
const previousSnapshot = loadSnapshotWithMigrations({
|
|
4437
4886
|
migrationsPath: migrationsDir,
|
|
4438
4887
|
workspaceRoot: process.cwd()
|
|
4439
4888
|
});
|
|
@@ -4460,7 +4909,7 @@ async function executeGenerate(options) {
|
|
|
4460
4909
|
"Creating migration file...",
|
|
4461
4910
|
() => Promise.resolve(generate(diff, migrationsDir))
|
|
4462
4911
|
);
|
|
4463
|
-
logSuccess(`Migration file created: ${
|
|
4912
|
+
logSuccess(`Migration file created: ${path5.basename(migrationPath)}`);
|
|
4464
4913
|
logSection("\u2705 Next Steps");
|
|
4465
4914
|
console.log();
|
|
4466
4915
|
console.log(" 1. Review the generated migration file:");
|
|
@@ -4617,10 +5066,16 @@ async function executeStatus(options) {
|
|
|
4617
5066
|
const schemaDir = getSchemaDirectory(config);
|
|
4618
5067
|
const migrationsDir = getMigrationsDirectory(config);
|
|
4619
5068
|
logSection("\u{1F50D} Checking Migration Status");
|
|
4620
|
-
const
|
|
5069
|
+
const analyzerConfig = {
|
|
5070
|
+
schemaDir,
|
|
5071
|
+
excludePatterns: config.schema.exclude,
|
|
5072
|
+
useCompiledFiles: false
|
|
5073
|
+
// Use source files since we're in development/testing
|
|
5074
|
+
};
|
|
5075
|
+
const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
|
|
4621
5076
|
logSuccess(`Found ${currentSchema.collections.size} collection(s) in schema`);
|
|
4622
5077
|
logInfo("Loading previous snapshot...");
|
|
4623
|
-
const previousSnapshot =
|
|
5078
|
+
const previousSnapshot = loadSnapshotWithMigrations({
|
|
4624
5079
|
migrationsPath: migrationsDir,
|
|
4625
5080
|
workspaceRoot: process.cwd()
|
|
4626
5081
|
});
|
|
@@ -4721,6 +5176,6 @@ async function executeStatus(options) {
|
|
|
4721
5176
|
}
|
|
4722
5177
|
}
|
|
4723
5178
|
|
|
4724
|
-
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, 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 };
|
|
4725
5180
|
//# sourceMappingURL=index.js.map
|
|
4726
5181
|
//# sourceMappingURL=index.js.map
|