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.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var zod = require('zod');
|
|
4
|
-
var
|
|
5
|
-
var
|
|
4
|
+
var fs3 = require('fs');
|
|
5
|
+
var path5 = require('path');
|
|
6
6
|
var chalk = require('chalk');
|
|
7
7
|
var ora = require('ora');
|
|
8
8
|
|
|
@@ -26,8 +26,8 @@ function _interopNamespace(e) {
|
|
|
26
26
|
return Object.freeze(n);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
var
|
|
30
|
-
var
|
|
29
|
+
var fs3__namespace = /*#__PURE__*/_interopNamespace(fs3);
|
|
30
|
+
var path5__namespace = /*#__PURE__*/_interopNamespace(path5);
|
|
31
31
|
var chalk__default = /*#__PURE__*/_interopDefault(chalk);
|
|
32
32
|
var ora__default = /*#__PURE__*/_interopDefault(ora);
|
|
33
33
|
|
|
@@ -104,14 +104,48 @@ function filesField(options) {
|
|
|
104
104
|
if (options?.max !== void 0) schema = schema.max(options.max);
|
|
105
105
|
return schema;
|
|
106
106
|
}
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
var RELATION_METADATA_KEY = "__pocketbase_relation__";
|
|
108
|
+
function relationField(config) {
|
|
109
|
+
const metadata = {
|
|
110
|
+
[RELATION_METADATA_KEY]: {
|
|
111
|
+
type: "single",
|
|
112
|
+
collection: config.collection,
|
|
113
|
+
cascadeDelete: config.cascadeDelete ?? false,
|
|
114
|
+
maxSelect: 1,
|
|
115
|
+
minSelect: 0
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
return zod.z.string().describe(JSON.stringify(metadata));
|
|
109
119
|
}
|
|
110
|
-
function relationsField(
|
|
120
|
+
function relationsField(config) {
|
|
121
|
+
const metadata = {
|
|
122
|
+
[RELATION_METADATA_KEY]: {
|
|
123
|
+
type: "multiple",
|
|
124
|
+
collection: config.collection,
|
|
125
|
+
cascadeDelete: config.cascadeDelete ?? false,
|
|
126
|
+
maxSelect: config.maxSelect ?? 999,
|
|
127
|
+
minSelect: config.minSelect ?? 0
|
|
128
|
+
}
|
|
129
|
+
};
|
|
111
130
|
let schema = zod.z.array(zod.z.string());
|
|
112
|
-
if (
|
|
113
|
-
|
|
114
|
-
|
|
131
|
+
if (config.minSelect !== void 0) {
|
|
132
|
+
schema = schema.min(config.minSelect);
|
|
133
|
+
}
|
|
134
|
+
if (config.maxSelect !== void 0) {
|
|
135
|
+
schema = schema.max(config.maxSelect);
|
|
136
|
+
}
|
|
137
|
+
return schema.describe(JSON.stringify(metadata));
|
|
138
|
+
}
|
|
139
|
+
function extractRelationMetadata(description) {
|
|
140
|
+
if (!description) return null;
|
|
141
|
+
try {
|
|
142
|
+
const parsed = JSON.parse(description);
|
|
143
|
+
if (parsed[RELATION_METADATA_KEY]) {
|
|
144
|
+
return parsed[RELATION_METADATA_KEY];
|
|
145
|
+
}
|
|
146
|
+
} catch {
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
115
149
|
}
|
|
116
150
|
function editorField() {
|
|
117
151
|
return zod.z.string();
|
|
@@ -143,7 +177,7 @@ function withIndexes(schema, indexes) {
|
|
|
143
177
|
return schema.describe(JSON.stringify(metadata));
|
|
144
178
|
}
|
|
145
179
|
|
|
146
|
-
// src/
|
|
180
|
+
// src/utils/permission-templates.ts
|
|
147
181
|
var PermissionTemplates = {
|
|
148
182
|
/**
|
|
149
183
|
* Public access - anyone can perform all operations
|
|
@@ -368,38 +402,36 @@ var ProjectInputSchema = zod.z.object({
|
|
|
368
402
|
content: zod.z.string(),
|
|
369
403
|
status: StatusEnum,
|
|
370
404
|
summary: zod.z.string().optional(),
|
|
371
|
-
|
|
372
|
-
SubscriberUsers:
|
|
405
|
+
OwnerUser: relationField({ collection: "Users" }),
|
|
406
|
+
SubscriberUsers: relationsField({ collection: "Users" })
|
|
373
407
|
}).extend(inputImageFileSchema);
|
|
374
408
|
var ProjectSchema = withPermissions(
|
|
375
409
|
ProjectInputSchema.omit(omitImageFilesSchema).extend(baseImageFileSchema),
|
|
376
410
|
{
|
|
377
411
|
template: "owner-only",
|
|
378
|
-
ownerField: "
|
|
412
|
+
ownerField: "OwnerUser",
|
|
379
413
|
customRules: {
|
|
380
|
-
// Override list rule to allow authenticated users to see all projects
|
|
381
414
|
listRule: '@request.auth.id != ""',
|
|
382
|
-
|
|
383
|
-
viewRule: '@request.auth.id != "" && (User = @request.auth.id || SubscriberUsers ?= @request.auth.id)'
|
|
415
|
+
viewRule: '@request.auth.id != "" && (OwnerUser = @request.auth.id || SubscriberUsers ?= @request.auth.id)'
|
|
384
416
|
}
|
|
385
417
|
}
|
|
386
418
|
);
|
|
387
419
|
var UserInputSchema = zod.z.object({
|
|
388
|
-
name: zod.z.string().
|
|
420
|
+
name: zod.z.string().optional(),
|
|
389
421
|
email: zod.z.string().email(),
|
|
390
422
|
password: zod.z.string().min(8, "Password must be at least 8 characters"),
|
|
391
423
|
passwordConfirm: zod.z.string(),
|
|
392
424
|
avatar: zod.z.instanceof(File).optional()
|
|
393
425
|
});
|
|
394
426
|
var UserDatabaseSchema = zod.z.object({
|
|
395
|
-
name: zod.z.string().
|
|
427
|
+
name: zod.z.string().optional(),
|
|
396
428
|
email: zod.z.string().email(),
|
|
397
429
|
password: zod.z.string().min(8, "Password must be at least 8 characters"),
|
|
398
430
|
avatar: zod.z.instanceof(File).optional()
|
|
399
431
|
});
|
|
400
432
|
var UserSchema = withIndexes(
|
|
401
433
|
withPermissions(UserDatabaseSchema.extend(baseSchema), {
|
|
402
|
-
// Users can list
|
|
434
|
+
// Users can list their own profile
|
|
403
435
|
listRule: "id = @request.auth.id",
|
|
404
436
|
// Users can view their own profile
|
|
405
437
|
viewRule: "id = @request.auth.id",
|
|
@@ -408,15 +440,13 @@ var UserSchema = withIndexes(
|
|
|
408
440
|
// Users can only update their own profile
|
|
409
441
|
updateRule: "id = @request.auth.id",
|
|
410
442
|
// Users can only delete their own account
|
|
411
|
-
deleteRule: "id = @request.auth.id"
|
|
412
|
-
//
|
|
413
|
-
manageRule: "id = @request.auth.id"
|
|
443
|
+
deleteRule: "id = @request.auth.id"
|
|
444
|
+
// manageRule is null in PocketBase default (not set)
|
|
414
445
|
}),
|
|
415
446
|
[
|
|
416
|
-
//
|
|
417
|
-
"CREATE UNIQUE INDEX
|
|
418
|
-
|
|
419
|
-
"CREATE INDEX idx_users_name ON users (name)"
|
|
447
|
+
// PocketBase's default indexes for auth collections
|
|
448
|
+
"CREATE UNIQUE INDEX `idx_tokenKey__pb_users_auth_` ON `users` (`tokenKey`)",
|
|
449
|
+
"CREATE UNIQUE INDEX `idx_email__pb_users_auth_` ON `users` (`email`) WHERE `email` != ''"
|
|
420
450
|
]
|
|
421
451
|
);
|
|
422
452
|
var BaseMutator = class {
|
|
@@ -757,7 +787,7 @@ var UserMutator = class extends BaseMutator {
|
|
|
757
787
|
};
|
|
758
788
|
}
|
|
759
789
|
getCollection() {
|
|
760
|
-
return this.pb.collection("
|
|
790
|
+
return this.pb.collection("Users");
|
|
761
791
|
}
|
|
762
792
|
async validateInput(input) {
|
|
763
793
|
return UserInputSchema.parse(input);
|
|
@@ -861,10 +891,10 @@ var FileSystemError = class _FileSystemError extends MigrationError {
|
|
|
861
891
|
operation;
|
|
862
892
|
code;
|
|
863
893
|
originalError;
|
|
864
|
-
constructor(message,
|
|
894
|
+
constructor(message, path7, operation, code, originalError) {
|
|
865
895
|
super(message);
|
|
866
896
|
this.name = "FileSystemError";
|
|
867
|
-
this.path =
|
|
897
|
+
this.path = path7;
|
|
868
898
|
this.operation = operation;
|
|
869
899
|
this.code = code;
|
|
870
900
|
this.originalError = originalError;
|
|
@@ -1523,26 +1553,28 @@ function getMaxSelect(fieldName, zodType) {
|
|
|
1523
1553
|
return 1;
|
|
1524
1554
|
}
|
|
1525
1555
|
function getMinSelect(fieldName, zodType) {
|
|
1526
|
-
if (
|
|
1527
|
-
return
|
|
1528
|
-
}
|
|
1529
|
-
let unwrappedType = zodType;
|
|
1530
|
-
if (zodType instanceof zod.z.ZodOptional) {
|
|
1531
|
-
unwrappedType = zodType._def.innerType;
|
|
1532
|
-
}
|
|
1533
|
-
if (unwrappedType instanceof zod.z.ZodNullable) {
|
|
1534
|
-
unwrappedType = unwrappedType._def.innerType;
|
|
1535
|
-
}
|
|
1536
|
-
if (unwrappedType instanceof zod.z.ZodDefault) {
|
|
1537
|
-
unwrappedType = unwrappedType._def.innerType;
|
|
1556
|
+
if (isSingleRelationField(fieldName, zodType)) {
|
|
1557
|
+
return 0;
|
|
1538
1558
|
}
|
|
1539
|
-
if (
|
|
1540
|
-
|
|
1541
|
-
if (
|
|
1542
|
-
|
|
1559
|
+
if (isMultipleRelationField(fieldName, zodType)) {
|
|
1560
|
+
let unwrappedType = zodType;
|
|
1561
|
+
if (zodType instanceof zod.z.ZodOptional) {
|
|
1562
|
+
unwrappedType = zodType._def.innerType;
|
|
1563
|
+
}
|
|
1564
|
+
if (unwrappedType instanceof zod.z.ZodNullable) {
|
|
1565
|
+
unwrappedType = unwrappedType._def.innerType;
|
|
1566
|
+
}
|
|
1567
|
+
if (unwrappedType instanceof zod.z.ZodDefault) {
|
|
1568
|
+
unwrappedType = unwrappedType._def.innerType;
|
|
1569
|
+
}
|
|
1570
|
+
if (unwrappedType instanceof zod.z.ZodArray) {
|
|
1571
|
+
const arrayDef = unwrappedType._def;
|
|
1572
|
+
if (arrayDef.minLength) {
|
|
1573
|
+
return arrayDef.minLength.value;
|
|
1574
|
+
}
|
|
1543
1575
|
}
|
|
1544
1576
|
}
|
|
1545
|
-
return
|
|
1577
|
+
return 0;
|
|
1546
1578
|
}
|
|
1547
1579
|
var POCKETBASE_FIELD_TYPES = [
|
|
1548
1580
|
"text",
|
|
@@ -1965,20 +1997,20 @@ function mergeConfig(config) {
|
|
|
1965
1997
|
}
|
|
1966
1998
|
function resolveSchemaDir(config) {
|
|
1967
1999
|
const workspaceRoot = config.workspaceRoot || process.cwd();
|
|
1968
|
-
if (
|
|
2000
|
+
if (path5__namespace.isAbsolute(config.schemaDir)) {
|
|
1969
2001
|
return config.schemaDir;
|
|
1970
2002
|
}
|
|
1971
|
-
return
|
|
2003
|
+
return path5__namespace.join(workspaceRoot, config.schemaDir);
|
|
1972
2004
|
}
|
|
1973
2005
|
function discoverSchemaFiles(config) {
|
|
1974
2006
|
const normalizedConfig = typeof config === "string" ? { schemaDir: config } : config;
|
|
1975
2007
|
const mergedConfig = mergeConfig(normalizedConfig);
|
|
1976
2008
|
const schemaDir = resolveSchemaDir(normalizedConfig);
|
|
1977
2009
|
try {
|
|
1978
|
-
if (!
|
|
2010
|
+
if (!fs3__namespace.existsSync(schemaDir)) {
|
|
1979
2011
|
throw new FileSystemError(`Schema directory not found: ${schemaDir}`, schemaDir, "access", "ENOENT");
|
|
1980
2012
|
}
|
|
1981
|
-
const files =
|
|
2013
|
+
const files = fs3__namespace.readdirSync(schemaDir);
|
|
1982
2014
|
const schemaFiles = files.filter((file) => {
|
|
1983
2015
|
const hasValidExtension = mergedConfig.includeExtensions.some((ext) => file.endsWith(ext));
|
|
1984
2016
|
if (!hasValidExtension) return false;
|
|
@@ -1994,7 +2026,7 @@ function discoverSchemaFiles(config) {
|
|
|
1994
2026
|
});
|
|
1995
2027
|
return schemaFiles.map((file) => {
|
|
1996
2028
|
const ext = mergedConfig.includeExtensions.find((ext2) => file.endsWith(ext2)) || ".ts";
|
|
1997
|
-
return
|
|
2029
|
+
return path5__namespace.join(schemaDir, file.replace(new RegExp(`\\${ext}$`), ""));
|
|
1998
2030
|
});
|
|
1999
2031
|
} catch (error) {
|
|
2000
2032
|
if (error instanceof FileSystemError) {
|
|
@@ -2025,13 +2057,32 @@ async function importSchemaModule(filePath, config) {
|
|
|
2025
2057
|
if (config?.pathTransformer) {
|
|
2026
2058
|
importPath = config.pathTransformer(filePath);
|
|
2027
2059
|
}
|
|
2028
|
-
|
|
2029
|
-
|
|
2060
|
+
let resolvedPath = null;
|
|
2061
|
+
const jsPath = `${importPath}.js`;
|
|
2062
|
+
const tsPath = `${importPath}.ts`;
|
|
2063
|
+
if (fs3__namespace.existsSync(jsPath)) {
|
|
2064
|
+
resolvedPath = jsPath;
|
|
2065
|
+
} else if (fs3__namespace.existsSync(tsPath)) {
|
|
2066
|
+
resolvedPath = tsPath;
|
|
2067
|
+
} else {
|
|
2068
|
+
resolvedPath = jsPath;
|
|
2030
2069
|
}
|
|
2031
|
-
const fileUrl = new URL(`file://${
|
|
2070
|
+
const fileUrl = new URL(`file://${path5__namespace.resolve(resolvedPath)}`);
|
|
2032
2071
|
const module = await import(fileUrl.href);
|
|
2033
2072
|
return module;
|
|
2034
2073
|
} catch (error) {
|
|
2074
|
+
const tsPath = `${filePath}.ts`;
|
|
2075
|
+
const isTypeScriptFile = fs3__namespace.existsSync(tsPath);
|
|
2076
|
+
if (isTypeScriptFile) {
|
|
2077
|
+
throw new SchemaParsingError(
|
|
2078
|
+
`Failed to import TypeScript schema file. Node.js cannot import TypeScript files directly.
|
|
2079
|
+
Please either:
|
|
2080
|
+
1. Compile your schema files to JavaScript first, or
|
|
2081
|
+
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")`,
|
|
2082
|
+
filePath,
|
|
2083
|
+
error
|
|
2084
|
+
);
|
|
2085
|
+
}
|
|
2035
2086
|
throw new SchemaParsingError(
|
|
2036
2087
|
`Failed to import schema module. Make sure the schema files are compiled to JavaScript.`,
|
|
2037
2088
|
filePath,
|
|
@@ -2040,7 +2091,7 @@ async function importSchemaModule(filePath, config) {
|
|
|
2040
2091
|
}
|
|
2041
2092
|
}
|
|
2042
2093
|
function getCollectionNameFromFile(filePath) {
|
|
2043
|
-
const filename =
|
|
2094
|
+
const filename = path5__namespace.basename(filePath).replace(/\.(ts|js)$/, "");
|
|
2044
2095
|
return toCollectionName(filename);
|
|
2045
2096
|
}
|
|
2046
2097
|
function extractSchemaDefinitions(module, patterns = ["Schema", "InputSchema"]) {
|
|
@@ -2094,7 +2145,17 @@ function buildFieldDefinition(fieldName, zodType) {
|
|
|
2094
2145
|
required,
|
|
2095
2146
|
options
|
|
2096
2147
|
};
|
|
2097
|
-
|
|
2148
|
+
const relationMetadata = extractRelationMetadata(zodType.description);
|
|
2149
|
+
if (relationMetadata) {
|
|
2150
|
+
fieldDef.type = "relation";
|
|
2151
|
+
fieldDef.relation = {
|
|
2152
|
+
collection: relationMetadata.collection,
|
|
2153
|
+
maxSelect: relationMetadata.maxSelect,
|
|
2154
|
+
minSelect: relationMetadata.minSelect,
|
|
2155
|
+
cascadeDelete: relationMetadata.cascadeDelete
|
|
2156
|
+
};
|
|
2157
|
+
fieldDef.options = void 0;
|
|
2158
|
+
} else if (isRelationField(fieldName, zodType)) {
|
|
2098
2159
|
fieldDef.type = "relation";
|
|
2099
2160
|
const targetCollection = resolveTargetCollection(fieldName);
|
|
2100
2161
|
const maxSelect = getMaxSelect(fieldName, zodType);
|
|
@@ -2106,6 +2167,13 @@ function buildFieldDefinition(fieldName, zodType) {
|
|
|
2106
2167
|
cascadeDelete: false
|
|
2107
2168
|
// Default to false, can be configured later
|
|
2108
2169
|
};
|
|
2170
|
+
if (fieldDef.options) {
|
|
2171
|
+
const { min, max, pattern, ...relationSafeOptions } = fieldDef.options;
|
|
2172
|
+
console.log("min", min);
|
|
2173
|
+
console.log("max", max);
|
|
2174
|
+
console.log("pattern", pattern);
|
|
2175
|
+
fieldDef.options = Object.keys(relationSafeOptions).length > 0 ? relationSafeOptions : void 0;
|
|
2176
|
+
}
|
|
2109
2177
|
}
|
|
2110
2178
|
return fieldDef;
|
|
2111
2179
|
}
|
|
@@ -2158,11 +2226,12 @@ function convertZodSchemaToCollectionSchema(collectionName, zodSchema) {
|
|
|
2158
2226
|
fields,
|
|
2159
2227
|
indexes,
|
|
2160
2228
|
rules: {
|
|
2161
|
-
listRule: null,
|
|
2162
|
-
viewRule: null,
|
|
2163
|
-
createRule: null,
|
|
2164
|
-
updateRule: null,
|
|
2165
|
-
deleteRule: null
|
|
2229
|
+
listRule: permissions?.listRule ?? null,
|
|
2230
|
+
viewRule: permissions?.viewRule ?? null,
|
|
2231
|
+
createRule: permissions?.createRule ?? null,
|
|
2232
|
+
updateRule: permissions?.updateRule ?? null,
|
|
2233
|
+
deleteRule: permissions?.deleteRule ?? null,
|
|
2234
|
+
manageRule: permissions?.manageRule ?? null
|
|
2166
2235
|
},
|
|
2167
2236
|
permissions
|
|
2168
2237
|
};
|
|
@@ -2186,7 +2255,12 @@ async function buildSchemaDefinition(config) {
|
|
|
2186
2255
|
if (normalizedConfig.pathTransformer) {
|
|
2187
2256
|
importPath = normalizedConfig.pathTransformer(filePath);
|
|
2188
2257
|
} else if (mergedConfig.useCompiledFiles) {
|
|
2189
|
-
|
|
2258
|
+
const distPath = filePath.replace(/\/src\//, "/dist/");
|
|
2259
|
+
if (fs3__namespace.existsSync(`${distPath}.js`) || fs3__namespace.existsSync(`${distPath}.mjs`)) {
|
|
2260
|
+
importPath = distPath;
|
|
2261
|
+
} else {
|
|
2262
|
+
importPath = filePath;
|
|
2263
|
+
}
|
|
2190
2264
|
}
|
|
2191
2265
|
const module = await importSchemaModule(importPath, normalizedConfig);
|
|
2192
2266
|
const schemas = extractSchemaDefinitions(module, mergedConfig.schemaPatterns);
|
|
@@ -2238,7 +2312,359 @@ var SchemaAnalyzer = class {
|
|
|
2238
2312
|
return convertZodSchemaToCollectionSchema(name, schema);
|
|
2239
2313
|
}
|
|
2240
2314
|
};
|
|
2315
|
+
|
|
2316
|
+
// src/migration/pocketbase-converter.ts
|
|
2241
2317
|
var SNAPSHOT_VERSION = "1.0.0";
|
|
2318
|
+
function resolveCollectionIdToName(collectionId) {
|
|
2319
|
+
if (collectionId === "_pb_users_auth_") {
|
|
2320
|
+
return "Users";
|
|
2321
|
+
}
|
|
2322
|
+
const nameMatch = collectionId.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
2323
|
+
if (nameMatch) {
|
|
2324
|
+
return nameMatch[1];
|
|
2325
|
+
}
|
|
2326
|
+
return collectionId;
|
|
2327
|
+
}
|
|
2328
|
+
function convertPocketBaseCollection(pbCollection) {
|
|
2329
|
+
const fields = [];
|
|
2330
|
+
const systemFieldNames = ["id", "created", "updated", "collectionId", "collectionName", "expand"];
|
|
2331
|
+
const authSystemFieldNames = ["email", "emailVisibility", "verified", "password", "tokenKey"];
|
|
2332
|
+
if (pbCollection.fields && Array.isArray(pbCollection.fields)) {
|
|
2333
|
+
for (const pbField of pbCollection.fields) {
|
|
2334
|
+
if (pbField.system || systemFieldNames.includes(pbField.name)) {
|
|
2335
|
+
continue;
|
|
2336
|
+
}
|
|
2337
|
+
if (pbCollection.type === "auth" && authSystemFieldNames.includes(pbField.name)) {
|
|
2338
|
+
continue;
|
|
2339
|
+
}
|
|
2340
|
+
const field = {
|
|
2341
|
+
name: pbField.name,
|
|
2342
|
+
type: pbField.type,
|
|
2343
|
+
required: pbField.required || false
|
|
2344
|
+
};
|
|
2345
|
+
field.options = pbField.options ? { ...pbField.options } : {};
|
|
2346
|
+
if (pbField.type === "select") {
|
|
2347
|
+
if (pbField.values && Array.isArray(pbField.values)) {
|
|
2348
|
+
field.options.values = pbField.values;
|
|
2349
|
+
} else if (pbField.options?.values && Array.isArray(pbField.options.values)) {
|
|
2350
|
+
field.options.values = pbField.options.values;
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
if (pbField.type === "relation") {
|
|
2354
|
+
const collectionId = pbField.collectionId || pbField.options?.collectionId || "";
|
|
2355
|
+
const collectionName = resolveCollectionIdToName(collectionId);
|
|
2356
|
+
field.relation = {
|
|
2357
|
+
collection: collectionName,
|
|
2358
|
+
cascadeDelete: pbField.cascadeDelete ?? pbField.options?.cascadeDelete ?? false,
|
|
2359
|
+
maxSelect: pbField.maxSelect ?? pbField.options?.maxSelect,
|
|
2360
|
+
minSelect: pbField.minSelect ?? pbField.options?.minSelect
|
|
2361
|
+
};
|
|
2362
|
+
}
|
|
2363
|
+
const hasOnlyValues = Object.keys(field.options).length === 1 && field.options.values !== void 0;
|
|
2364
|
+
if (Object.keys(field.options).length === 0) {
|
|
2365
|
+
delete field.options;
|
|
2366
|
+
} else if (pbField.type === "select" && hasOnlyValues) ;
|
|
2367
|
+
fields.push(field);
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
const schema = {
|
|
2371
|
+
name: pbCollection.name,
|
|
2372
|
+
type: pbCollection.type || "base",
|
|
2373
|
+
fields
|
|
2374
|
+
};
|
|
2375
|
+
if (pbCollection.indexes && Array.isArray(pbCollection.indexes)) {
|
|
2376
|
+
schema.indexes = pbCollection.indexes;
|
|
2377
|
+
}
|
|
2378
|
+
const rules = {};
|
|
2379
|
+
if (pbCollection.listRule !== void 0) rules.listRule = pbCollection.listRule;
|
|
2380
|
+
if (pbCollection.viewRule !== void 0) rules.viewRule = pbCollection.viewRule;
|
|
2381
|
+
if (pbCollection.createRule !== void 0) rules.createRule = pbCollection.createRule;
|
|
2382
|
+
if (pbCollection.updateRule !== void 0) rules.updateRule = pbCollection.updateRule;
|
|
2383
|
+
if (pbCollection.deleteRule !== void 0) rules.deleteRule = pbCollection.deleteRule;
|
|
2384
|
+
if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
|
|
2385
|
+
if (Object.keys(rules).length > 0) {
|
|
2386
|
+
schema.rules = rules;
|
|
2387
|
+
schema.permissions = { ...rules };
|
|
2388
|
+
}
|
|
2389
|
+
return schema;
|
|
2390
|
+
}
|
|
2391
|
+
function convertPocketBaseMigration(migrationContent) {
|
|
2392
|
+
try {
|
|
2393
|
+
const snapshotMatch = migrationContent.match(/const\s+snapshot\s*=\s*(\[[\s\S]*?\]);/);
|
|
2394
|
+
if (!snapshotMatch) {
|
|
2395
|
+
throw new Error("Could not find snapshot array in migration file");
|
|
2396
|
+
}
|
|
2397
|
+
const snapshotArrayStr = snapshotMatch[1];
|
|
2398
|
+
let snapshotArray;
|
|
2399
|
+
try {
|
|
2400
|
+
snapshotArray = new Function(`return ${snapshotArrayStr}`)();
|
|
2401
|
+
} catch (parseError) {
|
|
2402
|
+
throw new Error(`Failed to parse snapshot array: ${parseError}`);
|
|
2403
|
+
}
|
|
2404
|
+
if (!Array.isArray(snapshotArray)) {
|
|
2405
|
+
throw new Error("Snapshot is not an array");
|
|
2406
|
+
}
|
|
2407
|
+
const collections = /* @__PURE__ */ new Map();
|
|
2408
|
+
for (const pbCollection of snapshotArray) {
|
|
2409
|
+
if (!pbCollection.name) {
|
|
2410
|
+
console.warn("Skipping collection without name");
|
|
2411
|
+
continue;
|
|
2412
|
+
}
|
|
2413
|
+
const schema = convertPocketBaseCollection(pbCollection);
|
|
2414
|
+
collections.set(pbCollection.name, schema);
|
|
2415
|
+
}
|
|
2416
|
+
return {
|
|
2417
|
+
version: SNAPSHOT_VERSION,
|
|
2418
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2419
|
+
collections
|
|
2420
|
+
};
|
|
2421
|
+
} catch (error) {
|
|
2422
|
+
throw new SnapshotError(
|
|
2423
|
+
`Failed to convert PocketBase migration: ${error instanceof Error ? error.message : String(error)}`,
|
|
2424
|
+
void 0,
|
|
2425
|
+
"parse",
|
|
2426
|
+
error instanceof Error ? error : void 0
|
|
2427
|
+
);
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
// src/migration/migration-parser.ts
|
|
2432
|
+
function extractTimestampFromFilename(filename) {
|
|
2433
|
+
const match = filename.match(/^(\d+)_/);
|
|
2434
|
+
if (match) {
|
|
2435
|
+
return parseInt(match[1], 10);
|
|
2436
|
+
}
|
|
2437
|
+
return null;
|
|
2438
|
+
}
|
|
2439
|
+
function findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp) {
|
|
2440
|
+
try {
|
|
2441
|
+
if (!fs3__namespace.existsSync(migrationsPath)) {
|
|
2442
|
+
return [];
|
|
2443
|
+
}
|
|
2444
|
+
const files = fs3__namespace.readdirSync(migrationsPath);
|
|
2445
|
+
const migrationFiles = [];
|
|
2446
|
+
for (const file of files) {
|
|
2447
|
+
if (file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")) {
|
|
2448
|
+
continue;
|
|
2449
|
+
}
|
|
2450
|
+
if (!file.endsWith(".js")) {
|
|
2451
|
+
continue;
|
|
2452
|
+
}
|
|
2453
|
+
const timestamp = extractTimestampFromFilename(file);
|
|
2454
|
+
if (timestamp && timestamp > snapshotTimestamp) {
|
|
2455
|
+
migrationFiles.push({
|
|
2456
|
+
path: path5__namespace.join(migrationsPath, file),
|
|
2457
|
+
timestamp
|
|
2458
|
+
});
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
migrationFiles.sort((a, b) => a.timestamp - b.timestamp);
|
|
2462
|
+
return migrationFiles.map((f) => f.path);
|
|
2463
|
+
} catch (error) {
|
|
2464
|
+
console.warn(`Error finding migrations after snapshot: ${error}`);
|
|
2465
|
+
return [];
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
function parseMigrationOperationsFromContent(content) {
|
|
2469
|
+
const collectionsToCreate = [];
|
|
2470
|
+
const collectionsToDelete = [];
|
|
2471
|
+
try {
|
|
2472
|
+
let searchIndex = 0;
|
|
2473
|
+
while (true) {
|
|
2474
|
+
const collectionStart = content.indexOf("new Collection(", searchIndex);
|
|
2475
|
+
if (collectionStart === -1) {
|
|
2476
|
+
break;
|
|
2477
|
+
}
|
|
2478
|
+
const openParen = collectionStart + "new Collection(".length;
|
|
2479
|
+
let braceCount = 0;
|
|
2480
|
+
let parenCount = 1;
|
|
2481
|
+
let inString = false;
|
|
2482
|
+
let stringChar = null;
|
|
2483
|
+
let i = openParen;
|
|
2484
|
+
while (i < content.length && /\s/.test(content[i])) {
|
|
2485
|
+
i++;
|
|
2486
|
+
}
|
|
2487
|
+
if (content[i] !== "{") {
|
|
2488
|
+
searchIndex = i + 1;
|
|
2489
|
+
continue;
|
|
2490
|
+
}
|
|
2491
|
+
const objectStart = i;
|
|
2492
|
+
braceCount = 1;
|
|
2493
|
+
i++;
|
|
2494
|
+
while (i < content.length && (braceCount > 0 || parenCount > 0)) {
|
|
2495
|
+
const char = content[i];
|
|
2496
|
+
const prevChar = i > 0 ? content[i - 1] : "";
|
|
2497
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2498
|
+
inString = true;
|
|
2499
|
+
stringChar = char;
|
|
2500
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2501
|
+
inString = false;
|
|
2502
|
+
stringChar = null;
|
|
2503
|
+
}
|
|
2504
|
+
if (!inString) {
|
|
2505
|
+
if (char === "{") braceCount++;
|
|
2506
|
+
if (char === "}") braceCount--;
|
|
2507
|
+
if (char === "(") parenCount++;
|
|
2508
|
+
if (char === ")") parenCount--;
|
|
2509
|
+
}
|
|
2510
|
+
i++;
|
|
2511
|
+
}
|
|
2512
|
+
if (braceCount === 0 && parenCount === 0) {
|
|
2513
|
+
const objectContent = content.substring(objectStart, i - 1);
|
|
2514
|
+
try {
|
|
2515
|
+
const collectionObj = new Function(`return ${objectContent}`)();
|
|
2516
|
+
if (collectionObj && collectionObj.name) {
|
|
2517
|
+
const schema = convertPocketBaseCollection(collectionObj);
|
|
2518
|
+
collectionsToCreate.push(schema);
|
|
2519
|
+
}
|
|
2520
|
+
} catch (error) {
|
|
2521
|
+
console.warn(`Failed to parse collection definition: ${error}`);
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
searchIndex = i;
|
|
2525
|
+
}
|
|
2526
|
+
const deleteMatches = content.matchAll(
|
|
2527
|
+
/app\.delete\s*\(\s*(?:collection_\w+|app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\))\s*\)/g
|
|
2528
|
+
);
|
|
2529
|
+
for (const match of deleteMatches) {
|
|
2530
|
+
if (match[1]) {
|
|
2531
|
+
collectionsToDelete.push(match[1]);
|
|
2532
|
+
} else {
|
|
2533
|
+
const varNameMatch = match[0].match(/collection_(\w+)/);
|
|
2534
|
+
if (varNameMatch) {
|
|
2535
|
+
const varName = `collection_${varNameMatch[1]}`;
|
|
2536
|
+
const deleteIndex = content.indexOf(match[0]);
|
|
2537
|
+
const beforeDelete = content.substring(0, deleteIndex);
|
|
2538
|
+
const varDefMatch = beforeDelete.match(
|
|
2539
|
+
new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`, "g")
|
|
2540
|
+
);
|
|
2541
|
+
if (varDefMatch && varDefMatch.length > 0) {
|
|
2542
|
+
const collectionDefMatch = beforeDelete.match(
|
|
2543
|
+
new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`)
|
|
2544
|
+
);
|
|
2545
|
+
if (collectionDefMatch) {
|
|
2546
|
+
try {
|
|
2547
|
+
const collectionDefStr = collectionDefMatch[1];
|
|
2548
|
+
const collectionObj = new Function(`return ${collectionDefStr}`)();
|
|
2549
|
+
if (collectionObj && collectionObj.name) {
|
|
2550
|
+
collectionsToDelete.push(collectionObj.name);
|
|
2551
|
+
}
|
|
2552
|
+
} catch {
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
const findAndDeleteMatches = content.matchAll(
|
|
2560
|
+
/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)[\s\S]*?app\.delete/g
|
|
2561
|
+
);
|
|
2562
|
+
for (const match of findAndDeleteMatches) {
|
|
2563
|
+
collectionsToDelete.push(match[1]);
|
|
2564
|
+
}
|
|
2565
|
+
} catch (error) {
|
|
2566
|
+
console.warn(`Failed to parse migration operations from content: ${error}`);
|
|
2567
|
+
}
|
|
2568
|
+
return { collectionsToCreate, collectionsToDelete };
|
|
2569
|
+
}
|
|
2570
|
+
function parseMigrationOperations(migrationContent) {
|
|
2571
|
+
try {
|
|
2572
|
+
const migrateMatch = migrationContent.match(/migrate\s*\(\s*/);
|
|
2573
|
+
if (!migrateMatch) {
|
|
2574
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2575
|
+
}
|
|
2576
|
+
const startIndex = migrateMatch.index + migrateMatch[0].length;
|
|
2577
|
+
let i = startIndex;
|
|
2578
|
+
let parenCount = 0;
|
|
2579
|
+
let foundFirstParen = false;
|
|
2580
|
+
while (i < migrationContent.length) {
|
|
2581
|
+
const char = migrationContent[i];
|
|
2582
|
+
if (char === "(") {
|
|
2583
|
+
parenCount++;
|
|
2584
|
+
foundFirstParen = true;
|
|
2585
|
+
i++;
|
|
2586
|
+
break;
|
|
2587
|
+
}
|
|
2588
|
+
i++;
|
|
2589
|
+
}
|
|
2590
|
+
if (!foundFirstParen) {
|
|
2591
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2592
|
+
}
|
|
2593
|
+
let inString = false;
|
|
2594
|
+
let stringChar = null;
|
|
2595
|
+
let foundBrace = false;
|
|
2596
|
+
let braceStart = -1;
|
|
2597
|
+
while (i < migrationContent.length && !foundBrace) {
|
|
2598
|
+
const char = migrationContent[i];
|
|
2599
|
+
const prevChar = i > 0 ? migrationContent[i - 1] : "";
|
|
2600
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2601
|
+
inString = true;
|
|
2602
|
+
stringChar = char;
|
|
2603
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2604
|
+
inString = false;
|
|
2605
|
+
stringChar = null;
|
|
2606
|
+
}
|
|
2607
|
+
if (!inString) {
|
|
2608
|
+
if (char === "(") parenCount++;
|
|
2609
|
+
if (char === ")") {
|
|
2610
|
+
parenCount--;
|
|
2611
|
+
if (parenCount === 0) {
|
|
2612
|
+
i++;
|
|
2613
|
+
while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
|
|
2614
|
+
i++;
|
|
2615
|
+
}
|
|
2616
|
+
if (i < migrationContent.length - 1 && migrationContent[i] === "=" && migrationContent[i + 1] === ">") {
|
|
2617
|
+
i += 2;
|
|
2618
|
+
while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
|
|
2619
|
+
i++;
|
|
2620
|
+
}
|
|
2621
|
+
if (i < migrationContent.length && migrationContent[i] === "{") {
|
|
2622
|
+
foundBrace = true;
|
|
2623
|
+
braceStart = i + 1;
|
|
2624
|
+
break;
|
|
2625
|
+
}
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2630
|
+
i++;
|
|
2631
|
+
}
|
|
2632
|
+
if (!foundBrace || braceStart === -1) {
|
|
2633
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2634
|
+
}
|
|
2635
|
+
let braceCount = 1;
|
|
2636
|
+
i = braceStart;
|
|
2637
|
+
inString = false;
|
|
2638
|
+
stringChar = null;
|
|
2639
|
+
while (i < migrationContent.length && braceCount > 0) {
|
|
2640
|
+
const char = migrationContent[i];
|
|
2641
|
+
const prevChar = i > 0 ? migrationContent[i - 1] : "";
|
|
2642
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2643
|
+
inString = true;
|
|
2644
|
+
stringChar = char;
|
|
2645
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2646
|
+
inString = false;
|
|
2647
|
+
stringChar = null;
|
|
2648
|
+
}
|
|
2649
|
+
if (!inString) {
|
|
2650
|
+
if (char === "{") braceCount++;
|
|
2651
|
+
if (char === "}") braceCount--;
|
|
2652
|
+
}
|
|
2653
|
+
i++;
|
|
2654
|
+
}
|
|
2655
|
+
if (braceCount === 0) {
|
|
2656
|
+
const upMigrationContent = migrationContent.substring(braceStart, i - 1);
|
|
2657
|
+
return parseMigrationOperationsFromContent(upMigrationContent);
|
|
2658
|
+
}
|
|
2659
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2660
|
+
} catch (error) {
|
|
2661
|
+
console.warn(`Failed to parse migration operations: ${error}`);
|
|
2662
|
+
return { collectionsToCreate: [], collectionsToDelete: [] };
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
|
|
2666
|
+
// src/migration/snapshot.ts
|
|
2667
|
+
var SNAPSHOT_VERSION2 = "1.0.0";
|
|
2242
2668
|
var DEFAULT_SNAPSHOT_FILENAME = ".migration-snapshot.json";
|
|
2243
2669
|
var SNAPSHOT_MIGRATIONS = [
|
|
2244
2670
|
// Add migrations here as the format evolves
|
|
@@ -2253,7 +2679,7 @@ var DEFAULT_CONFIG2 = {
|
|
|
2253
2679
|
snapshotPath: DEFAULT_SNAPSHOT_FILENAME,
|
|
2254
2680
|
workspaceRoot: process.cwd(),
|
|
2255
2681
|
autoMigrate: true,
|
|
2256
|
-
version:
|
|
2682
|
+
version: SNAPSHOT_VERSION2
|
|
2257
2683
|
};
|
|
2258
2684
|
function mergeConfig2(config = {}) {
|
|
2259
2685
|
return {
|
|
@@ -2265,15 +2691,15 @@ function getSnapshotPath(config = {}) {
|
|
|
2265
2691
|
const mergedConfig = mergeConfig2(config);
|
|
2266
2692
|
const workspaceRoot = mergedConfig.workspaceRoot;
|
|
2267
2693
|
const snapshotFilename = mergedConfig.snapshotPath;
|
|
2268
|
-
if (
|
|
2694
|
+
if (path5__namespace.isAbsolute(snapshotFilename)) {
|
|
2269
2695
|
return snapshotFilename;
|
|
2270
2696
|
}
|
|
2271
|
-
return
|
|
2697
|
+
return path5__namespace.join(workspaceRoot, snapshotFilename);
|
|
2272
2698
|
}
|
|
2273
2699
|
function snapshotExists(config = {}) {
|
|
2274
2700
|
try {
|
|
2275
2701
|
const snapshotPath = getSnapshotPath(config);
|
|
2276
|
-
return
|
|
2702
|
+
return fs3__namespace.existsSync(snapshotPath);
|
|
2277
2703
|
} catch {
|
|
2278
2704
|
return false;
|
|
2279
2705
|
}
|
|
@@ -2332,13 +2758,13 @@ function addSnapshotMetadata(schema, config) {
|
|
|
2332
2758
|
function saveSnapshot(schema, config = {}) {
|
|
2333
2759
|
const snapshotPath = getSnapshotPath(config);
|
|
2334
2760
|
try {
|
|
2335
|
-
const snapshotDir =
|
|
2336
|
-
if (!
|
|
2337
|
-
|
|
2761
|
+
const snapshotDir = path5__namespace.dirname(snapshotPath);
|
|
2762
|
+
if (!fs3__namespace.existsSync(snapshotDir)) {
|
|
2763
|
+
fs3__namespace.mkdirSync(snapshotDir, { recursive: true });
|
|
2338
2764
|
}
|
|
2339
2765
|
const snapshotData = addSnapshotMetadata(schema, config);
|
|
2340
2766
|
const jsonContent = JSON.stringify(snapshotData, null, 2);
|
|
2341
|
-
|
|
2767
|
+
fs3__namespace.writeFileSync(snapshotPath, jsonContent, "utf-8");
|
|
2342
2768
|
} catch (error) {
|
|
2343
2769
|
handleFileSystemError(error, "write", snapshotPath);
|
|
2344
2770
|
}
|
|
@@ -2433,7 +2859,7 @@ function deserializeSnapshot(data) {
|
|
|
2433
2859
|
function loadSnapshot(config = {}) {
|
|
2434
2860
|
const snapshotPath = getSnapshotPath(config);
|
|
2435
2861
|
try {
|
|
2436
|
-
const jsonContent =
|
|
2862
|
+
const jsonContent = fs3__namespace.readFileSync(snapshotPath, "utf-8");
|
|
2437
2863
|
const data = parseAndValidateSnapshot(jsonContent, snapshotPath);
|
|
2438
2864
|
const migratedData = migrateSnapshotFormat(data, config);
|
|
2439
2865
|
return deserializeSnapshot(migratedData);
|
|
@@ -2468,10 +2894,10 @@ function mergeSnapshots(baseSnapshot, customSnapshot) {
|
|
|
2468
2894
|
}
|
|
2469
2895
|
function findLatestSnapshot(migrationsPath) {
|
|
2470
2896
|
try {
|
|
2471
|
-
if (!
|
|
2897
|
+
if (!fs3__namespace.existsSync(migrationsPath)) {
|
|
2472
2898
|
return null;
|
|
2473
2899
|
}
|
|
2474
|
-
const files =
|
|
2900
|
+
const files = fs3__namespace.readdirSync(migrationsPath);
|
|
2475
2901
|
const snapshotFiles = files.filter(
|
|
2476
2902
|
(file) => file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")
|
|
2477
2903
|
);
|
|
@@ -2483,20 +2909,74 @@ function findLatestSnapshot(migrationsPath) {
|
|
|
2483
2909
|
if (!latestSnapshot) {
|
|
2484
2910
|
return null;
|
|
2485
2911
|
}
|
|
2486
|
-
return
|
|
2912
|
+
return path5__namespace.join(migrationsPath, latestSnapshot);
|
|
2487
2913
|
} catch (error) {
|
|
2488
2914
|
console.warn(`Error finding latest snapshot: ${error}`);
|
|
2489
2915
|
return null;
|
|
2490
2916
|
}
|
|
2491
2917
|
}
|
|
2918
|
+
function applyMigrationOperations(snapshot, operations) {
|
|
2919
|
+
const updatedCollections = new Map(snapshot.collections);
|
|
2920
|
+
for (const collectionName of operations.collectionsToDelete) {
|
|
2921
|
+
updatedCollections.delete(collectionName);
|
|
2922
|
+
}
|
|
2923
|
+
for (const collection of operations.collectionsToCreate) {
|
|
2924
|
+
updatedCollections.set(collection.name, collection);
|
|
2925
|
+
}
|
|
2926
|
+
return {
|
|
2927
|
+
...snapshot,
|
|
2928
|
+
collections: updatedCollections
|
|
2929
|
+
};
|
|
2930
|
+
}
|
|
2931
|
+
function loadSnapshotWithMigrations(config = {}) {
|
|
2932
|
+
const migrationsPath = config.migrationsPath;
|
|
2933
|
+
if (!migrationsPath) {
|
|
2934
|
+
return null;
|
|
2935
|
+
}
|
|
2936
|
+
if (fs3__namespace.existsSync(migrationsPath) && fs3__namespace.statSync(migrationsPath).isFile()) {
|
|
2937
|
+
try {
|
|
2938
|
+
const migrationContent = fs3__namespace.readFileSync(migrationsPath, "utf-8");
|
|
2939
|
+
return convertPocketBaseMigration(migrationContent);
|
|
2940
|
+
} catch (error) {
|
|
2941
|
+
console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
|
|
2942
|
+
return null;
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2945
|
+
const latestSnapshotPath = findLatestSnapshot(migrationsPath);
|
|
2946
|
+
if (!latestSnapshotPath) {
|
|
2947
|
+
return null;
|
|
2948
|
+
}
|
|
2949
|
+
try {
|
|
2950
|
+
const migrationContent = fs3__namespace.readFileSync(latestSnapshotPath, "utf-8");
|
|
2951
|
+
let snapshot = convertPocketBaseMigration(migrationContent);
|
|
2952
|
+
const snapshotFilename = path5__namespace.basename(latestSnapshotPath);
|
|
2953
|
+
const snapshotTimestamp = extractTimestampFromFilename(snapshotFilename);
|
|
2954
|
+
if (snapshotTimestamp) {
|
|
2955
|
+
const migrationFiles = findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp);
|
|
2956
|
+
for (const migrationFile of migrationFiles) {
|
|
2957
|
+
try {
|
|
2958
|
+
const migrationContent2 = fs3__namespace.readFileSync(migrationFile, "utf-8");
|
|
2959
|
+
const operations = parseMigrationOperations(migrationContent2);
|
|
2960
|
+
snapshot = applyMigrationOperations(snapshot, operations);
|
|
2961
|
+
} catch (error) {
|
|
2962
|
+
console.warn(`Failed to apply migration ${migrationFile}: ${error}`);
|
|
2963
|
+
}
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2966
|
+
return snapshot;
|
|
2967
|
+
} catch (error) {
|
|
2968
|
+
console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
|
|
2969
|
+
return null;
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2492
2972
|
function loadSnapshotIfExists(config = {}) {
|
|
2493
2973
|
const migrationsPath = config.migrationsPath;
|
|
2494
2974
|
if (!migrationsPath) {
|
|
2495
2975
|
return null;
|
|
2496
2976
|
}
|
|
2497
|
-
if (
|
|
2977
|
+
if (fs3__namespace.existsSync(migrationsPath) && fs3__namespace.statSync(migrationsPath).isFile()) {
|
|
2498
2978
|
try {
|
|
2499
|
-
const migrationContent =
|
|
2979
|
+
const migrationContent = fs3__namespace.readFileSync(migrationsPath, "utf-8");
|
|
2500
2980
|
return convertPocketBaseMigration(migrationContent);
|
|
2501
2981
|
} catch (error) {
|
|
2502
2982
|
console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
|
|
@@ -2506,7 +2986,7 @@ function loadSnapshotIfExists(config = {}) {
|
|
|
2506
2986
|
const latestSnapshotPath = findLatestSnapshot(migrationsPath);
|
|
2507
2987
|
if (latestSnapshotPath) {
|
|
2508
2988
|
try {
|
|
2509
|
-
const migrationContent =
|
|
2989
|
+
const migrationContent = fs3__namespace.readFileSync(latestSnapshotPath, "utf-8");
|
|
2510
2990
|
return convertPocketBaseMigration(migrationContent);
|
|
2511
2991
|
} catch (error) {
|
|
2512
2992
|
console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
|
|
@@ -2515,99 +2995,9 @@ function loadSnapshotIfExists(config = {}) {
|
|
|
2515
2995
|
}
|
|
2516
2996
|
return null;
|
|
2517
2997
|
}
|
|
2518
|
-
function convertPocketBaseCollection(pbCollection) {
|
|
2519
|
-
const fields = [];
|
|
2520
|
-
const systemFieldNames = ["id", "created", "updated", "collectionId", "collectionName", "expand"];
|
|
2521
|
-
const authSystemFieldNames = ["email", "emailVisibility", "verified", "password", "tokenKey"];
|
|
2522
|
-
if (pbCollection.fields && Array.isArray(pbCollection.fields)) {
|
|
2523
|
-
for (const pbField of pbCollection.fields) {
|
|
2524
|
-
if (pbField.system || systemFieldNames.includes(pbField.name)) {
|
|
2525
|
-
continue;
|
|
2526
|
-
}
|
|
2527
|
-
if (pbCollection.type === "auth" && authSystemFieldNames.includes(pbField.name)) {
|
|
2528
|
-
continue;
|
|
2529
|
-
}
|
|
2530
|
-
const field = {
|
|
2531
|
-
name: pbField.name,
|
|
2532
|
-
type: pbField.type,
|
|
2533
|
-
required: pbField.required || false
|
|
2534
|
-
};
|
|
2535
|
-
if (pbField.options) {
|
|
2536
|
-
field.options = pbField.options;
|
|
2537
|
-
}
|
|
2538
|
-
if (pbField.type === "relation") {
|
|
2539
|
-
field.relation = {
|
|
2540
|
-
collection: pbField.options?.collectionId || "",
|
|
2541
|
-
cascadeDelete: pbField.options?.cascadeDelete || false,
|
|
2542
|
-
maxSelect: pbField.options?.maxSelect,
|
|
2543
|
-
minSelect: pbField.options?.minSelect
|
|
2544
|
-
};
|
|
2545
|
-
}
|
|
2546
|
-
fields.push(field);
|
|
2547
|
-
}
|
|
2548
|
-
}
|
|
2549
|
-
const schema = {
|
|
2550
|
-
name: pbCollection.name,
|
|
2551
|
-
type: pbCollection.type || "base",
|
|
2552
|
-
fields
|
|
2553
|
-
};
|
|
2554
|
-
if (pbCollection.indexes && Array.isArray(pbCollection.indexes)) {
|
|
2555
|
-
schema.indexes = pbCollection.indexes;
|
|
2556
|
-
}
|
|
2557
|
-
const rules = {};
|
|
2558
|
-
if (pbCollection.listRule !== void 0) rules.listRule = pbCollection.listRule;
|
|
2559
|
-
if (pbCollection.viewRule !== void 0) rules.viewRule = pbCollection.viewRule;
|
|
2560
|
-
if (pbCollection.createRule !== void 0) rules.createRule = pbCollection.createRule;
|
|
2561
|
-
if (pbCollection.updateRule !== void 0) rules.updateRule = pbCollection.updateRule;
|
|
2562
|
-
if (pbCollection.deleteRule !== void 0) rules.deleteRule = pbCollection.deleteRule;
|
|
2563
|
-
if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
|
|
2564
|
-
if (Object.keys(rules).length > 0) {
|
|
2565
|
-
schema.rules = rules;
|
|
2566
|
-
}
|
|
2567
|
-
return schema;
|
|
2568
|
-
}
|
|
2569
|
-
function convertPocketBaseMigration(migrationContent) {
|
|
2570
|
-
try {
|
|
2571
|
-
const snapshotMatch = migrationContent.match(/const\s+snapshot\s*=\s*(\[[\s\S]*?\]);/);
|
|
2572
|
-
if (!snapshotMatch) {
|
|
2573
|
-
throw new Error("Could not find snapshot array in migration file");
|
|
2574
|
-
}
|
|
2575
|
-
const snapshotArrayStr = snapshotMatch[1];
|
|
2576
|
-
let snapshotArray;
|
|
2577
|
-
try {
|
|
2578
|
-
snapshotArray = new Function(`return ${snapshotArrayStr}`)();
|
|
2579
|
-
} catch (parseError) {
|
|
2580
|
-
throw new Error(`Failed to parse snapshot array: ${parseError}`);
|
|
2581
|
-
}
|
|
2582
|
-
if (!Array.isArray(snapshotArray)) {
|
|
2583
|
-
throw new Error("Snapshot is not an array");
|
|
2584
|
-
}
|
|
2585
|
-
const collections = /* @__PURE__ */ new Map();
|
|
2586
|
-
for (const pbCollection of snapshotArray) {
|
|
2587
|
-
if (!pbCollection.name) {
|
|
2588
|
-
console.warn("Skipping collection without name");
|
|
2589
|
-
continue;
|
|
2590
|
-
}
|
|
2591
|
-
const schema = convertPocketBaseCollection(pbCollection);
|
|
2592
|
-
collections.set(pbCollection.name, schema);
|
|
2593
|
-
}
|
|
2594
|
-
return {
|
|
2595
|
-
version: SNAPSHOT_VERSION,
|
|
2596
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2597
|
-
collections
|
|
2598
|
-
};
|
|
2599
|
-
} catch (error) {
|
|
2600
|
-
throw new SnapshotError(
|
|
2601
|
-
`Failed to convert PocketBase migration: ${error instanceof Error ? error.message : String(error)}`,
|
|
2602
|
-
void 0,
|
|
2603
|
-
"parse",
|
|
2604
|
-
error instanceof Error ? error : void 0
|
|
2605
|
-
);
|
|
2606
|
-
}
|
|
2607
|
-
}
|
|
2608
2998
|
function loadBaseMigration(migrationPath) {
|
|
2609
2999
|
try {
|
|
2610
|
-
if (!
|
|
3000
|
+
if (!fs3__namespace.existsSync(migrationPath)) {
|
|
2611
3001
|
throw new SnapshotError(
|
|
2612
3002
|
`Base migration file not found: ${migrationPath}
|
|
2613
3003
|
|
|
@@ -2618,7 +3008,7 @@ If the file exists in a different location, update the configuration.`,
|
|
|
2618
3008
|
"read"
|
|
2619
3009
|
);
|
|
2620
3010
|
}
|
|
2621
|
-
const migrationContent =
|
|
3011
|
+
const migrationContent = fs3__namespace.readFileSync(migrationPath, "utf-8");
|
|
2622
3012
|
const snapshot = convertPocketBaseMigration(migrationContent);
|
|
2623
3013
|
return snapshot;
|
|
2624
3014
|
} catch (error) {
|
|
@@ -2654,14 +3044,14 @@ Please ensure PocketBase is properly set up by running 'yarn setup'.`,
|
|
|
2654
3044
|
}
|
|
2655
3045
|
}
|
|
2656
3046
|
function getSnapshotVersion() {
|
|
2657
|
-
return
|
|
3047
|
+
return SNAPSHOT_VERSION2;
|
|
2658
3048
|
}
|
|
2659
3049
|
function validateSnapshot(snapshot) {
|
|
2660
3050
|
const issues = [];
|
|
2661
3051
|
if (!snapshot.version) {
|
|
2662
3052
|
issues.push("Missing version field");
|
|
2663
|
-
} else if (compareVersions(snapshot.version,
|
|
2664
|
-
issues.push(`Snapshot version ${snapshot.version} is newer than supported version ${
|
|
3053
|
+
} else if (compareVersions(snapshot.version, SNAPSHOT_VERSION2) > 0) {
|
|
3054
|
+
issues.push(`Snapshot version ${snapshot.version} is newer than supported version ${SNAPSHOT_VERSION2}`);
|
|
2665
3055
|
}
|
|
2666
3056
|
if (!snapshot.timestamp) {
|
|
2667
3057
|
issues.push("Missing timestamp field");
|
|
@@ -2880,6 +3270,9 @@ function compareFieldOptions(currentField, previousField) {
|
|
|
2880
3270
|
for (const key of allKeys) {
|
|
2881
3271
|
const currentValue = currentOptions[key];
|
|
2882
3272
|
const previousValue = previousOptions[key];
|
|
3273
|
+
if (currentValue === void 0 && previousValue === void 0) {
|
|
3274
|
+
continue;
|
|
3275
|
+
}
|
|
2883
3276
|
if (!areValuesEqual(currentValue, previousValue)) {
|
|
2884
3277
|
changes.push({
|
|
2885
3278
|
property: `options.${key}`,
|
|
@@ -2900,11 +3293,26 @@ function compareRelationConfigurations(currentField, previousField) {
|
|
|
2900
3293
|
if (!currentRelation || !previousRelation) {
|
|
2901
3294
|
return changes;
|
|
2902
3295
|
}
|
|
2903
|
-
|
|
3296
|
+
const normalizeCollection = (collection) => {
|
|
3297
|
+
if (!collection) return collection;
|
|
3298
|
+
if (collection === "_pb_users_auth_") {
|
|
3299
|
+
return "Users";
|
|
3300
|
+
}
|
|
3301
|
+
const nameMatch = collection.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
3302
|
+
if (nameMatch) {
|
|
3303
|
+
return nameMatch[1];
|
|
3304
|
+
}
|
|
3305
|
+
return collection;
|
|
3306
|
+
};
|
|
3307
|
+
const normalizedCurrent = normalizeCollection(currentRelation.collection);
|
|
3308
|
+
const normalizedPrevious = normalizeCollection(previousRelation.collection);
|
|
3309
|
+
if (normalizedCurrent !== normalizedPrevious) {
|
|
2904
3310
|
changes.push({
|
|
2905
3311
|
property: "relation.collection",
|
|
2906
|
-
oldValue:
|
|
2907
|
-
|
|
3312
|
+
oldValue: normalizedPrevious,
|
|
3313
|
+
// Use normalized value for clarity
|
|
3314
|
+
newValue: normalizedCurrent
|
|
3315
|
+
// Use normalized value for clarity
|
|
2908
3316
|
});
|
|
2909
3317
|
}
|
|
2910
3318
|
if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {
|
|
@@ -3258,10 +3666,8 @@ var DiffEngine = class {
|
|
|
3258
3666
|
var DEFAULT_TEMPLATE = `/// <reference path="{{TYPES_PATH}}" />
|
|
3259
3667
|
migrate((app) => {
|
|
3260
3668
|
{{UP_CODE}}
|
|
3261
|
-
return true;
|
|
3262
3669
|
}, (app) => {
|
|
3263
3670
|
{{DOWN_CODE}}
|
|
3264
|
-
return true;
|
|
3265
3671
|
});
|
|
3266
3672
|
`;
|
|
3267
3673
|
var DEFAULT_CONFIG4 = {
|
|
@@ -3279,10 +3685,10 @@ function mergeConfig4(config) {
|
|
|
3279
3685
|
}
|
|
3280
3686
|
function resolveMigrationDir(config) {
|
|
3281
3687
|
const workspaceRoot = config.workspaceRoot || process.cwd();
|
|
3282
|
-
if (
|
|
3688
|
+
if (path5__namespace.isAbsolute(config.migrationDir)) {
|
|
3283
3689
|
return config.migrationDir;
|
|
3284
3690
|
}
|
|
3285
|
-
return
|
|
3691
|
+
return path5__namespace.join(workspaceRoot, config.migrationDir);
|
|
3286
3692
|
}
|
|
3287
3693
|
function generateTimestamp(config) {
|
|
3288
3694
|
if (config?.timestampGenerator) {
|
|
@@ -3340,9 +3746,9 @@ function createMigrationFileStructure(upCode, downCode, config) {
|
|
|
3340
3746
|
}
|
|
3341
3747
|
function writeMigrationFile(migrationDir, filename, content) {
|
|
3342
3748
|
try {
|
|
3343
|
-
if (!
|
|
3749
|
+
if (!fs3__namespace.existsSync(migrationDir)) {
|
|
3344
3750
|
try {
|
|
3345
|
-
|
|
3751
|
+
fs3__namespace.mkdirSync(migrationDir, { recursive: true });
|
|
3346
3752
|
} catch (error) {
|
|
3347
3753
|
const fsError = error;
|
|
3348
3754
|
if (fsError.code === "EACCES" || fsError.code === "EPERM") {
|
|
@@ -3363,15 +3769,15 @@ function writeMigrationFile(migrationDir, filename, content) {
|
|
|
3363
3769
|
);
|
|
3364
3770
|
}
|
|
3365
3771
|
}
|
|
3366
|
-
const filePath =
|
|
3367
|
-
|
|
3772
|
+
const filePath = path5__namespace.join(migrationDir, filename);
|
|
3773
|
+
fs3__namespace.writeFileSync(filePath, content, "utf-8");
|
|
3368
3774
|
return filePath;
|
|
3369
3775
|
} catch (error) {
|
|
3370
3776
|
if (error instanceof FileSystemError) {
|
|
3371
3777
|
throw error;
|
|
3372
3778
|
}
|
|
3373
3779
|
const fsError = error;
|
|
3374
|
-
const filePath =
|
|
3780
|
+
const filePath = path5__namespace.join(migrationDir, filename);
|
|
3375
3781
|
if (fsError.code === "EACCES" || fsError.code === "EPERM") {
|
|
3376
3782
|
throw new FileSystemError(
|
|
3377
3783
|
`Permission denied writing migration file. Check file and directory permissions.`,
|
|
@@ -3426,7 +3832,8 @@ function generateFieldDefinitionObject(field) {
|
|
|
3426
3832
|
}
|
|
3427
3833
|
}
|
|
3428
3834
|
if (field.relation) {
|
|
3429
|
-
const
|
|
3835
|
+
const isUsersCollection = field.relation.collection.toLowerCase() === "users";
|
|
3836
|
+
const collectionIdPlaceholder = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
|
|
3430
3837
|
parts.push(` collectionId: ${collectionIdPlaceholder}`);
|
|
3431
3838
|
if (field.relation.maxSelect !== void 0) {
|
|
3432
3839
|
parts.push(` maxSelect: ${field.relation.maxSelect}`);
|
|
@@ -3510,7 +3917,7 @@ function generateIndexesArray(indexes) {
|
|
|
3510
3917
|
${indexStrings.join(",\n ")},
|
|
3511
3918
|
]`;
|
|
3512
3919
|
}
|
|
3513
|
-
function generateCollectionCreation(collection, varName = "collection") {
|
|
3920
|
+
function generateCollectionCreation(collection, varName = "collection", isLast = false) {
|
|
3514
3921
|
const lines = [];
|
|
3515
3922
|
lines.push(` const ${varName} = new Collection({`);
|
|
3516
3923
|
lines.push(` name: "${collection.name}",`);
|
|
@@ -3526,7 +3933,7 @@ function generateCollectionCreation(collection, varName = "collection") {
|
|
|
3526
3933
|
lines.push(` indexes: ${generateIndexesArray(collection.indexes)},`);
|
|
3527
3934
|
lines.push(` });`);
|
|
3528
3935
|
lines.push(``);
|
|
3529
|
-
lines.push(` app.save(${varName});`);
|
|
3936
|
+
lines.push(isLast ? ` return app.save(${varName});` : ` app.save(${varName});`);
|
|
3530
3937
|
return lines.join("\n");
|
|
3531
3938
|
}
|
|
3532
3939
|
function getFieldConstructorName(fieldType) {
|
|
@@ -3557,7 +3964,8 @@ function generateFieldConstructorOptions(field) {
|
|
|
3557
3964
|
}
|
|
3558
3965
|
}
|
|
3559
3966
|
if (field.relation && field.type === "relation") {
|
|
3560
|
-
const
|
|
3967
|
+
const isUsersCollection = field.relation.collection.toLowerCase() === "users";
|
|
3968
|
+
const collectionIdPlaceholder = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
|
|
3561
3969
|
parts.push(` collectionId: ${collectionIdPlaceholder}`);
|
|
3562
3970
|
if (field.relation.maxSelect !== void 0) {
|
|
3563
3971
|
parts.push(` maxSelect: ${field.relation.maxSelect}`);
|
|
@@ -3571,7 +3979,7 @@ function generateFieldConstructorOptions(field) {
|
|
|
3571
3979
|
}
|
|
3572
3980
|
return parts.join(",\n");
|
|
3573
3981
|
}
|
|
3574
|
-
function generateFieldAddition(collectionName, field, varName) {
|
|
3982
|
+
function generateFieldAddition(collectionName, field, varName, isLast = false) {
|
|
3575
3983
|
const lines = [];
|
|
3576
3984
|
const constructorName = getFieldConstructorName(field.type);
|
|
3577
3985
|
const collectionVar = varName || `collection_${collectionName}_${field.name}`;
|
|
@@ -3581,10 +3989,10 @@ function generateFieldAddition(collectionName, field, varName) {
|
|
|
3581
3989
|
lines.push(generateFieldConstructorOptions(field));
|
|
3582
3990
|
lines.push(` }));`);
|
|
3583
3991
|
lines.push(``);
|
|
3584
|
-
lines.push(` app.save(${collectionVar});`);
|
|
3992
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
3585
3993
|
return lines.join("\n");
|
|
3586
3994
|
}
|
|
3587
|
-
function generateFieldModification(collectionName, modification, varName) {
|
|
3995
|
+
function generateFieldModification(collectionName, modification, varName, isLast = false) {
|
|
3588
3996
|
const lines = [];
|
|
3589
3997
|
const collectionVar = varName || `collection_${collectionName}_${modification.fieldName}`;
|
|
3590
3998
|
const fieldVar = `${collectionVar}_field`;
|
|
@@ -3598,7 +4006,8 @@ function generateFieldModification(collectionName, modification, varName) {
|
|
|
3598
4006
|
} else if (change.property.startsWith("relation.")) {
|
|
3599
4007
|
const relationKey = change.property.replace("relation.", "");
|
|
3600
4008
|
if (relationKey === "collection") {
|
|
3601
|
-
const
|
|
4009
|
+
const isUsersCollection = String(change.newValue).toLowerCase() === "users";
|
|
4010
|
+
const collectionIdValue = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${change.newValue}").id`;
|
|
3602
4011
|
lines.push(` ${fieldVar}.collectionId = ${collectionIdValue};`);
|
|
3603
4012
|
} else {
|
|
3604
4013
|
lines.push(` ${fieldVar}.${relationKey} = ${formatValue(change.newValue)};`);
|
|
@@ -3608,10 +4017,10 @@ function generateFieldModification(collectionName, modification, varName) {
|
|
|
3608
4017
|
}
|
|
3609
4018
|
}
|
|
3610
4019
|
lines.push(``);
|
|
3611
|
-
lines.push(` app.save(${collectionVar});`);
|
|
4020
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
3612
4021
|
return lines.join("\n");
|
|
3613
4022
|
}
|
|
3614
|
-
function generateFieldDeletion(collectionName, fieldName, varName) {
|
|
4023
|
+
function generateFieldDeletion(collectionName, fieldName, varName, isLast = false) {
|
|
3615
4024
|
const lines = [];
|
|
3616
4025
|
const collectionVar = varName || `collection_${collectionName}_${fieldName}`;
|
|
3617
4026
|
const fieldVar = `${collectionVar}_field`;
|
|
@@ -3620,18 +4029,18 @@ function generateFieldDeletion(collectionName, fieldName, varName) {
|
|
|
3620
4029
|
lines.push(``);
|
|
3621
4030
|
lines.push(` ${collectionVar}.fields.remove(${fieldVar}.id);`);
|
|
3622
4031
|
lines.push(``);
|
|
3623
|
-
lines.push(` app.save(${collectionVar});`);
|
|
4032
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
3624
4033
|
return lines.join("\n");
|
|
3625
4034
|
}
|
|
3626
|
-
function generateIndexAddition(collectionName, index, varName) {
|
|
4035
|
+
function generateIndexAddition(collectionName, index, varName, isLast = false) {
|
|
3627
4036
|
const lines = [];
|
|
3628
4037
|
const collectionVar = varName || `collection_${collectionName}_idx`;
|
|
3629
4038
|
lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
|
|
3630
4039
|
lines.push(` ${collectionVar}.indexes.push("${index}");`);
|
|
3631
|
-
lines.push(` app.save(${collectionVar});`);
|
|
4040
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
3632
4041
|
return lines.join("\n");
|
|
3633
4042
|
}
|
|
3634
|
-
function generateIndexRemoval(collectionName, index, varName) {
|
|
4043
|
+
function generateIndexRemoval(collectionName, index, varName, isLast = false) {
|
|
3635
4044
|
const lines = [];
|
|
3636
4045
|
const collectionVar = varName || `collection_${collectionName}_idx`;
|
|
3637
4046
|
const indexVar = `${collectionVar}_indexToRemove`;
|
|
@@ -3640,29 +4049,29 @@ function generateIndexRemoval(collectionName, index, varName) {
|
|
|
3640
4049
|
lines.push(` if (${indexVar} !== -1) {`);
|
|
3641
4050
|
lines.push(` ${collectionVar}.indexes.splice(${indexVar}, 1);`);
|
|
3642
4051
|
lines.push(` }`);
|
|
3643
|
-
lines.push(` app.save(${collectionVar});`);
|
|
4052
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
3644
4053
|
return lines.join("\n");
|
|
3645
4054
|
}
|
|
3646
|
-
function generateRuleUpdate(collectionName, ruleType, newValue, varName) {
|
|
4055
|
+
function generateRuleUpdate(collectionName, ruleType, newValue, varName, isLast = false) {
|
|
3647
4056
|
const lines = [];
|
|
3648
4057
|
const collectionVar = varName || `collection_${collectionName}_${ruleType}`;
|
|
3649
4058
|
lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
|
|
3650
4059
|
lines.push(` ${collectionVar}.${ruleType} = ${formatValue(newValue)};`);
|
|
3651
|
-
lines.push(` app.save(${collectionVar});`);
|
|
4060
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
3652
4061
|
return lines.join("\n");
|
|
3653
4062
|
}
|
|
3654
|
-
function generatePermissionUpdate(collectionName, ruleType, newValue, varName) {
|
|
4063
|
+
function generatePermissionUpdate(collectionName, ruleType, newValue, varName, isLast = false) {
|
|
3655
4064
|
const lines = [];
|
|
3656
4065
|
const collectionVar = varName || `collection_${collectionName}_${ruleType}`;
|
|
3657
4066
|
lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
|
|
3658
4067
|
lines.push(` ${collectionVar}.${ruleType} = ${formatValue(newValue)};`);
|
|
3659
|
-
lines.push(` app.save(${collectionVar});`);
|
|
4068
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
3660
4069
|
return lines.join("\n");
|
|
3661
4070
|
}
|
|
3662
|
-
function generateCollectionDeletion(collectionName, varName = "collection") {
|
|
4071
|
+
function generateCollectionDeletion(collectionName, varName = "collection", isLast = false) {
|
|
3663
4072
|
const lines = [];
|
|
3664
4073
|
lines.push(` const ${varName} = app.findCollectionByNameOrId("${collectionName}");`);
|
|
3665
|
-
lines.push(` app.delete(${varName});`);
|
|
4074
|
+
lines.push(isLast ? ` return app.delete(${varName});` : ` app.delete(${varName});`);
|
|
3666
4075
|
return lines.join("\n");
|
|
3667
4076
|
}
|
|
3668
4077
|
function generateUpMigration(diff) {
|
|
@@ -3754,7 +4163,24 @@ function generateUpMigration(diff) {
|
|
|
3754
4163
|
lines.push(` // No changes detected`);
|
|
3755
4164
|
lines.push(``);
|
|
3756
4165
|
}
|
|
3757
|
-
|
|
4166
|
+
let code = lines.join("\n");
|
|
4167
|
+
const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
|
|
4168
|
+
const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
|
|
4169
|
+
const saveMatches = [...code.matchAll(savePattern)];
|
|
4170
|
+
const deleteMatches = [...code.matchAll(deletePattern)];
|
|
4171
|
+
const allMatches = [
|
|
4172
|
+
...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
|
|
4173
|
+
...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
|
|
4174
|
+
].sort((a, b) => b.index - a.index);
|
|
4175
|
+
if (allMatches.length > 0) {
|
|
4176
|
+
const lastMatch = allMatches[0];
|
|
4177
|
+
if (lastMatch.type === "save") {
|
|
4178
|
+
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);
|
|
4179
|
+
} else {
|
|
4180
|
+
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);
|
|
4181
|
+
}
|
|
4182
|
+
}
|
|
4183
|
+
return code;
|
|
3758
4184
|
}
|
|
3759
4185
|
function generateDownMigration(diff) {
|
|
3760
4186
|
const lines = [];
|
|
@@ -3856,7 +4282,24 @@ function generateDownMigration(diff) {
|
|
|
3856
4282
|
lines.push(` // No changes to revert`);
|
|
3857
4283
|
lines.push(``);
|
|
3858
4284
|
}
|
|
3859
|
-
|
|
4285
|
+
let code = lines.join("\n");
|
|
4286
|
+
const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
|
|
4287
|
+
const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
|
|
4288
|
+
const saveMatches = [...code.matchAll(savePattern)];
|
|
4289
|
+
const deleteMatches = [...code.matchAll(deletePattern)];
|
|
4290
|
+
const allMatches = [
|
|
4291
|
+
...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
|
|
4292
|
+
...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
|
|
4293
|
+
].sort((a, b) => b.index - a.index);
|
|
4294
|
+
if (allMatches.length > 0) {
|
|
4295
|
+
const lastMatch = allMatches[0];
|
|
4296
|
+
if (lastMatch.type === "save") {
|
|
4297
|
+
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);
|
|
4298
|
+
} else {
|
|
4299
|
+
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);
|
|
4300
|
+
}
|
|
4301
|
+
}
|
|
4302
|
+
return code;
|
|
3860
4303
|
}
|
|
3861
4304
|
function generate(diff, config) {
|
|
3862
4305
|
const normalizedConfig = typeof config === "string" ? { migrationDir: config } : config;
|
|
@@ -4078,8 +4521,8 @@ var DEFAULT_CONFIG5 = {
|
|
|
4078
4521
|
};
|
|
4079
4522
|
function findConfigFile(directory) {
|
|
4080
4523
|
for (const fileName of CONFIG_FILE_NAMES) {
|
|
4081
|
-
const filePath =
|
|
4082
|
-
if (
|
|
4524
|
+
const filePath = path5__namespace.join(directory, fileName);
|
|
4525
|
+
if (fs3__namespace.existsSync(filePath)) {
|
|
4083
4526
|
return filePath;
|
|
4084
4527
|
}
|
|
4085
4528
|
}
|
|
@@ -4087,7 +4530,7 @@ function findConfigFile(directory) {
|
|
|
4087
4530
|
}
|
|
4088
4531
|
function loadJsonConfig(configPath) {
|
|
4089
4532
|
try {
|
|
4090
|
-
const content =
|
|
4533
|
+
const content = fs3__namespace.readFileSync(configPath, "utf-8");
|
|
4091
4534
|
return JSON.parse(content);
|
|
4092
4535
|
} catch (error) {
|
|
4093
4536
|
if (error instanceof SyntaxError) {
|
|
@@ -4116,10 +4559,10 @@ async function loadJsConfig(configPath) {
|
|
|
4116
4559
|
}
|
|
4117
4560
|
}
|
|
4118
4561
|
async function loadConfigFile(configPath) {
|
|
4119
|
-
if (!
|
|
4562
|
+
if (!fs3__namespace.existsSync(configPath)) {
|
|
4120
4563
|
return null;
|
|
4121
4564
|
}
|
|
4122
|
-
const ext =
|
|
4565
|
+
const ext = path5__namespace.extname(configPath).toLowerCase();
|
|
4123
4566
|
if (ext === ".json") {
|
|
4124
4567
|
return loadJsonConfig(configPath);
|
|
4125
4568
|
} else if (ext === ".js" || ext === ".mjs") {
|
|
@@ -4186,10 +4629,10 @@ function validateConfig(config, configPath) {
|
|
|
4186
4629
|
}
|
|
4187
4630
|
const cwd = process.cwd();
|
|
4188
4631
|
const possiblePaths = [
|
|
4189
|
-
|
|
4190
|
-
|
|
4632
|
+
path5__namespace.resolve(cwd, config.schema.directory),
|
|
4633
|
+
path5__namespace.resolve(cwd, "shared", config.schema.directory)
|
|
4191
4634
|
];
|
|
4192
|
-
const schemaDir = possiblePaths.find((p) =>
|
|
4635
|
+
const schemaDir = possiblePaths.find((p) => fs3__namespace.existsSync(p));
|
|
4193
4636
|
if (!schemaDir) {
|
|
4194
4637
|
throw new ConfigurationError(`Schema directory not found. Tried: ${possiblePaths.join(", ")}`, configPath, [
|
|
4195
4638
|
"schema.directory"
|
|
@@ -4201,15 +4644,15 @@ async function loadConfig(options = {}) {
|
|
|
4201
4644
|
let configFilePath;
|
|
4202
4645
|
const cwd = process.cwd();
|
|
4203
4646
|
if (options.config) {
|
|
4204
|
-
const explicitPath =
|
|
4205
|
-
if (!
|
|
4647
|
+
const explicitPath = path5__namespace.resolve(cwd, options.config);
|
|
4648
|
+
if (!fs3__namespace.existsSync(explicitPath)) {
|
|
4206
4649
|
throw new ConfigurationError(`Configuration file not found: ${explicitPath}`, explicitPath);
|
|
4207
4650
|
}
|
|
4208
4651
|
configFilePath = explicitPath;
|
|
4209
4652
|
} else {
|
|
4210
|
-
const searchDirs = [cwd,
|
|
4653
|
+
const searchDirs = [cwd, path5__namespace.join(cwd, "shared")];
|
|
4211
4654
|
for (const dir of searchDirs) {
|
|
4212
|
-
if (
|
|
4655
|
+
if (fs3__namespace.existsSync(dir)) {
|
|
4213
4656
|
const found = findConfigFile(dir);
|
|
4214
4657
|
if (found) {
|
|
4215
4658
|
configFilePath = found;
|
|
@@ -4238,18 +4681,18 @@ async function loadConfig(options = {}) {
|
|
|
4238
4681
|
function getSchemaDirectory(config) {
|
|
4239
4682
|
const cwd = process.cwd();
|
|
4240
4683
|
const possiblePaths = [
|
|
4241
|
-
|
|
4242
|
-
|
|
4684
|
+
path5__namespace.resolve(cwd, config.schema.directory),
|
|
4685
|
+
path5__namespace.resolve(cwd, "shared", config.schema.directory)
|
|
4243
4686
|
];
|
|
4244
|
-
return possiblePaths.find((p) =>
|
|
4687
|
+
return possiblePaths.find((p) => fs3__namespace.existsSync(p)) || possiblePaths[0];
|
|
4245
4688
|
}
|
|
4246
4689
|
function getMigrationsDirectory(config) {
|
|
4247
4690
|
const cwd = process.cwd();
|
|
4248
4691
|
const possiblePaths = [
|
|
4249
|
-
|
|
4250
|
-
|
|
4692
|
+
path5__namespace.resolve(cwd, config.migrations.directory),
|
|
4693
|
+
path5__namespace.resolve(cwd, "shared", config.migrations.directory)
|
|
4251
4694
|
];
|
|
4252
|
-
return possiblePaths.find((p) =>
|
|
4695
|
+
return possiblePaths.find((p) => fs3__namespace.existsSync(p)) || possiblePaths[0];
|
|
4253
4696
|
}
|
|
4254
4697
|
var currentVerbosity = "normal";
|
|
4255
4698
|
function setVerbosity(level) {
|
|
@@ -4457,10 +4900,16 @@ async function executeGenerate(options) {
|
|
|
4457
4900
|
const schemaDir = getSchemaDirectory(config);
|
|
4458
4901
|
const migrationsDir = getMigrationsDirectory(config);
|
|
4459
4902
|
logSection("\u{1F50D} Analyzing Schema");
|
|
4460
|
-
const
|
|
4903
|
+
const analyzerConfig = {
|
|
4904
|
+
schemaDir,
|
|
4905
|
+
excludePatterns: config.schema.exclude,
|
|
4906
|
+
useCompiledFiles: false
|
|
4907
|
+
// Use source files since we're in development/testing
|
|
4908
|
+
};
|
|
4909
|
+
const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
|
|
4461
4910
|
logSuccess(`Found ${currentSchema.collections.size} collection(s)`);
|
|
4462
4911
|
logInfo("Loading previous snapshot...");
|
|
4463
|
-
const previousSnapshot =
|
|
4912
|
+
const previousSnapshot = loadSnapshotWithMigrations({
|
|
4464
4913
|
migrationsPath: migrationsDir,
|
|
4465
4914
|
workspaceRoot: process.cwd()
|
|
4466
4915
|
});
|
|
@@ -4487,7 +4936,7 @@ async function executeGenerate(options) {
|
|
|
4487
4936
|
"Creating migration file...",
|
|
4488
4937
|
() => Promise.resolve(generate(diff, migrationsDir))
|
|
4489
4938
|
);
|
|
4490
|
-
logSuccess(`Migration file created: ${
|
|
4939
|
+
logSuccess(`Migration file created: ${path5__namespace.basename(migrationPath)}`);
|
|
4491
4940
|
logSection("\u2705 Next Steps");
|
|
4492
4941
|
console.log();
|
|
4493
4942
|
console.log(" 1. Review the generated migration file:");
|
|
@@ -4644,10 +5093,16 @@ async function executeStatus(options) {
|
|
|
4644
5093
|
const schemaDir = getSchemaDirectory(config);
|
|
4645
5094
|
const migrationsDir = getMigrationsDirectory(config);
|
|
4646
5095
|
logSection("\u{1F50D} Checking Migration Status");
|
|
4647
|
-
const
|
|
5096
|
+
const analyzerConfig = {
|
|
5097
|
+
schemaDir,
|
|
5098
|
+
excludePatterns: config.schema.exclude,
|
|
5099
|
+
useCompiledFiles: false
|
|
5100
|
+
// Use source files since we're in development/testing
|
|
5101
|
+
};
|
|
5102
|
+
const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
|
|
4648
5103
|
logSuccess(`Found ${currentSchema.collections.size} collection(s) in schema`);
|
|
4649
5104
|
logInfo("Loading previous snapshot...");
|
|
4650
|
-
const previousSnapshot =
|
|
5105
|
+
const previousSnapshot = loadSnapshotWithMigrations({
|
|
4651
5106
|
migrationsPath: migrationsDir,
|
|
4652
5107
|
workspaceRoot: process.cwd()
|
|
4653
5108
|
});
|
|
@@ -4796,6 +5251,7 @@ exports.extractComprehensiveFieldOptions = extractComprehensiveFieldOptions;
|
|
|
4796
5251
|
exports.extractFieldDefinitions = extractFieldDefinitions;
|
|
4797
5252
|
exports.extractFieldOptions = extractFieldOptions;
|
|
4798
5253
|
exports.extractIndexes = extractIndexes;
|
|
5254
|
+
exports.extractRelationMetadata = extractRelationMetadata;
|
|
4799
5255
|
exports.extractSchemaDefinitions = extractSchemaDefinitions;
|
|
4800
5256
|
exports.fileField = fileField;
|
|
4801
5257
|
exports.filesField = filesField;
|
|
@@ -4854,6 +5310,7 @@ exports.loadBaseMigration = loadBaseMigration;
|
|
|
4854
5310
|
exports.loadConfig = loadConfig;
|
|
4855
5311
|
exports.loadSnapshot = loadSnapshot;
|
|
4856
5312
|
exports.loadSnapshotIfExists = loadSnapshotIfExists;
|
|
5313
|
+
exports.loadSnapshotWithMigrations = loadSnapshotWithMigrations;
|
|
4857
5314
|
exports.logError = logError;
|
|
4858
5315
|
exports.logInfo = logInfo;
|
|
4859
5316
|
exports.logSection = logSection;
|