appwrite-utils-cli 1.5.1 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +199 -0
- package/README.md +251 -29
- package/dist/adapters/AdapterFactory.d.ts +10 -3
- package/dist/adapters/AdapterFactory.js +213 -17
- package/dist/adapters/TablesDBAdapter.js +60 -17
- package/dist/backups/operations/bucketBackup.d.ts +19 -0
- package/dist/backups/operations/bucketBackup.js +197 -0
- package/dist/backups/operations/collectionBackup.d.ts +30 -0
- package/dist/backups/operations/collectionBackup.js +201 -0
- package/dist/backups/operations/comprehensiveBackup.d.ts +25 -0
- package/dist/backups/operations/comprehensiveBackup.js +238 -0
- package/dist/backups/schemas/bucketManifest.d.ts +93 -0
- package/dist/backups/schemas/bucketManifest.js +33 -0
- package/dist/backups/schemas/comprehensiveManifest.d.ts +108 -0
- package/dist/backups/schemas/comprehensiveManifest.js +32 -0
- package/dist/backups/tracking/centralizedTracking.d.ts +34 -0
- package/dist/backups/tracking/centralizedTracking.js +274 -0
- package/dist/cli/commands/configCommands.d.ts +8 -0
- package/dist/cli/commands/configCommands.js +160 -0
- package/dist/cli/commands/databaseCommands.d.ts +13 -0
- package/dist/cli/commands/databaseCommands.js +478 -0
- package/dist/cli/commands/functionCommands.d.ts +7 -0
- package/dist/cli/commands/functionCommands.js +289 -0
- package/dist/cli/commands/schemaCommands.d.ts +7 -0
- package/dist/cli/commands/schemaCommands.js +134 -0
- package/dist/cli/commands/transferCommands.d.ts +5 -0
- package/dist/cli/commands/transferCommands.js +384 -0
- package/dist/collections/attributes.d.ts +5 -4
- package/dist/collections/attributes.js +539 -246
- package/dist/collections/indexes.js +39 -37
- package/dist/collections/methods.d.ts +2 -16
- package/dist/collections/methods.js +90 -538
- package/dist/collections/transferOperations.d.ts +7 -0
- package/dist/collections/transferOperations.js +331 -0
- package/dist/collections/wipeOperations.d.ts +16 -0
- package/dist/collections/wipeOperations.js +328 -0
- package/dist/config/configMigration.d.ts +87 -0
- package/dist/config/configMigration.js +390 -0
- package/dist/config/configValidation.d.ts +66 -0
- package/dist/config/configValidation.js +358 -0
- package/dist/config/yamlConfig.d.ts +455 -1
- package/dist/config/yamlConfig.js +145 -52
- package/dist/databases/methods.js +3 -2
- package/dist/databases/setup.d.ts +1 -2
- package/dist/databases/setup.js +9 -87
- package/dist/examples/yamlTerminologyExample.d.ts +42 -0
- package/dist/examples/yamlTerminologyExample.js +269 -0
- package/dist/functions/deployments.js +11 -10
- package/dist/functions/methods.d.ts +1 -1
- package/dist/functions/methods.js +5 -4
- package/dist/init.js +9 -9
- package/dist/interactiveCLI.d.ts +8 -17
- package/dist/interactiveCLI.js +186 -1171
- package/dist/main.js +364 -21
- package/dist/migrations/afterImportActions.js +22 -30
- package/dist/migrations/appwriteToX.js +71 -25
- package/dist/migrations/dataLoader.js +35 -26
- package/dist/migrations/importController.js +29 -30
- package/dist/migrations/relationships.js +13 -12
- package/dist/migrations/services/ImportOrchestrator.js +16 -19
- package/dist/migrations/transfer.js +46 -46
- package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +3 -1
- package/dist/migrations/yaml/YamlImportConfigLoader.js +6 -3
- package/dist/migrations/yaml/YamlImportIntegration.d.ts +9 -3
- package/dist/migrations/yaml/YamlImportIntegration.js +22 -11
- package/dist/migrations/yaml/generateImportSchemas.d.ts +14 -1
- package/dist/migrations/yaml/generateImportSchemas.js +736 -7
- package/dist/schemas/authUser.d.ts +1 -1
- package/dist/setupController.js +3 -2
- package/dist/shared/backupMetadataSchema.d.ts +94 -0
- package/dist/shared/backupMetadataSchema.js +38 -0
- package/dist/shared/backupTracking.d.ts +18 -0
- package/dist/shared/backupTracking.js +176 -0
- package/dist/shared/confirmationDialogs.js +15 -15
- package/dist/shared/errorUtils.d.ts +54 -0
- package/dist/shared/errorUtils.js +95 -0
- package/dist/shared/functionManager.js +20 -19
- package/dist/shared/indexManager.js +12 -11
- package/dist/shared/jsonSchemaGenerator.js +10 -26
- package/dist/shared/logging.d.ts +51 -0
- package/dist/shared/logging.js +70 -0
- package/dist/shared/messageFormatter.d.ts +2 -0
- package/dist/shared/messageFormatter.js +10 -0
- package/dist/shared/migrationHelpers.d.ts +6 -16
- package/dist/shared/migrationHelpers.js +24 -21
- package/dist/shared/operationLogger.d.ts +8 -1
- package/dist/shared/operationLogger.js +11 -24
- package/dist/shared/operationQueue.d.ts +28 -1
- package/dist/shared/operationQueue.js +268 -66
- package/dist/shared/operationsTable.d.ts +26 -0
- package/dist/shared/operationsTable.js +286 -0
- package/dist/shared/operationsTableSchema.d.ts +48 -0
- package/dist/shared/operationsTableSchema.js +35 -0
- package/dist/shared/relationshipExtractor.d.ts +56 -0
- package/dist/shared/relationshipExtractor.js +138 -0
- package/dist/shared/schemaGenerator.d.ts +19 -1
- package/dist/shared/schemaGenerator.js +56 -75
- package/dist/storage/backupCompression.d.ts +20 -0
- package/dist/storage/backupCompression.js +67 -0
- package/dist/storage/methods.d.ts +16 -2
- package/dist/storage/methods.js +98 -14
- package/dist/users/methods.js +9 -8
- package/dist/utils/configDiscovery.d.ts +78 -0
- package/dist/utils/configDiscovery.js +430 -0
- package/dist/utils/directoryUtils.d.ts +22 -0
- package/dist/utils/directoryUtils.js +59 -0
- package/dist/utils/getClientFromConfig.d.ts +17 -8
- package/dist/utils/getClientFromConfig.js +162 -17
- package/dist/utils/helperFunctions.d.ts +16 -2
- package/dist/utils/helperFunctions.js +19 -5
- package/dist/utils/loadConfigs.d.ts +34 -9
- package/dist/utils/loadConfigs.js +236 -316
- package/dist/utils/pathResolvers.d.ts +53 -0
- package/dist/utils/pathResolvers.js +72 -0
- package/dist/utils/projectConfig.d.ts +119 -0
- package/dist/utils/projectConfig.js +171 -0
- package/dist/utils/retryFailedPromises.js +4 -2
- package/dist/utils/sessionAuth.d.ts +48 -0
- package/dist/utils/sessionAuth.js +164 -0
- package/dist/utils/sessionPreservationExample.d.ts +1666 -0
- package/dist/utils/sessionPreservationExample.js +101 -0
- package/dist/utils/setupFiles.js +301 -41
- package/dist/utils/typeGuards.d.ts +35 -0
- package/dist/utils/typeGuards.js +57 -0
- package/dist/utils/versionDetection.js +145 -9
- package/dist/utils/yamlConverter.d.ts +53 -3
- package/dist/utils/yamlConverter.js +232 -13
- package/dist/utils/yamlLoader.d.ts +70 -0
- package/dist/utils/yamlLoader.js +263 -0
- package/dist/utilsController.d.ts +36 -3
- package/dist/utilsController.js +186 -56
- package/package.json +12 -2
- package/src/adapters/AdapterFactory.ts +263 -35
- package/src/adapters/TablesDBAdapter.ts +225 -36
- package/src/backups/operations/bucketBackup.ts +277 -0
- package/src/backups/operations/collectionBackup.ts +310 -0
- package/src/backups/operations/comprehensiveBackup.ts +342 -0
- package/src/backups/schemas/bucketManifest.ts +78 -0
- package/src/backups/schemas/comprehensiveManifest.ts +76 -0
- package/src/backups/tracking/centralizedTracking.ts +352 -0
- package/src/cli/commands/configCommands.ts +194 -0
- package/src/cli/commands/databaseCommands.ts +635 -0
- package/src/cli/commands/functionCommands.ts +379 -0
- package/src/cli/commands/schemaCommands.ts +163 -0
- package/src/cli/commands/transferCommands.ts +457 -0
- package/src/collections/attributes.ts +900 -621
- package/src/collections/attributes.ts.backup +1555 -0
- package/src/collections/indexes.ts +116 -114
- package/src/collections/methods.ts +295 -968
- package/src/collections/transferOperations.ts +516 -0
- package/src/collections/wipeOperations.ts +501 -0
- package/src/config/README.md +274 -0
- package/src/config/configMigration.ts +575 -0
- package/src/config/configValidation.ts +445 -0
- package/src/config/yamlConfig.ts +168 -55
- package/src/databases/methods.ts +3 -2
- package/src/databases/setup.ts +11 -138
- package/src/examples/yamlTerminologyExample.ts +341 -0
- package/src/functions/deployments.ts +14 -12
- package/src/functions/methods.ts +11 -11
- package/src/functions/templates/hono-typescript/README.md +286 -0
- package/src/functions/templates/hono-typescript/package.json +26 -0
- package/src/functions/templates/hono-typescript/src/adapters/request.ts +74 -0
- package/src/functions/templates/hono-typescript/src/adapters/response.ts +106 -0
- package/src/functions/templates/hono-typescript/src/app.ts +180 -0
- package/src/functions/templates/hono-typescript/src/context.ts +103 -0
- package/src/functions/templates/hono-typescript/src/index.ts +54 -0
- package/src/functions/templates/hono-typescript/src/middleware/appwrite.ts +119 -0
- package/src/functions/templates/hono-typescript/tsconfig.json +20 -0
- package/src/functions/templates/typescript-node/package.json +2 -1
- package/src/functions/templates/typescript-node/src/context.ts +103 -0
- package/src/functions/templates/typescript-node/src/index.ts +18 -12
- package/src/functions/templates/uv/pyproject.toml +1 -0
- package/src/functions/templates/uv/src/context.py +125 -0
- package/src/functions/templates/uv/src/index.py +35 -5
- package/src/init.ts +9 -11
- package/src/interactiveCLI.ts +276 -1591
- package/src/main.ts +418 -24
- package/src/migrations/afterImportActions.ts +71 -44
- package/src/migrations/appwriteToX.ts +100 -34
- package/src/migrations/dataLoader.ts +48 -34
- package/src/migrations/importController.ts +44 -39
- package/src/migrations/relationships.ts +28 -18
- package/src/migrations/services/ImportOrchestrator.ts +24 -27
- package/src/migrations/transfer.ts +159 -121
- package/src/migrations/yaml/YamlImportConfigLoader.ts +11 -4
- package/src/migrations/yaml/YamlImportIntegration.ts +47 -20
- package/src/migrations/yaml/generateImportSchemas.ts +751 -12
- package/src/setupController.ts +3 -2
- package/src/shared/backupMetadataSchema.ts +93 -0
- package/src/shared/backupTracking.ts +211 -0
- package/src/shared/confirmationDialogs.ts +19 -19
- package/src/shared/errorUtils.ts +110 -0
- package/src/shared/functionManager.ts +21 -20
- package/src/shared/indexManager.ts +12 -11
- package/src/shared/jsonSchemaGenerator.ts +38 -52
- package/src/shared/logging.ts +75 -0
- package/src/shared/messageFormatter.ts +14 -1
- package/src/shared/migrationHelpers.ts +45 -38
- package/src/shared/operationLogger.ts +11 -36
- package/src/shared/operationQueue.ts +322 -93
- package/src/shared/operationsTable.ts +338 -0
- package/src/shared/operationsTableSchema.ts +60 -0
- package/src/shared/relationshipExtractor.ts +214 -0
- package/src/shared/schemaGenerator.ts +179 -219
- package/src/storage/backupCompression.ts +88 -0
- package/src/storage/methods.ts +131 -34
- package/src/users/methods.ts +11 -9
- package/src/utils/configDiscovery.ts +502 -0
- package/src/utils/directoryUtils.ts +61 -0
- package/src/utils/getClientFromConfig.ts +205 -22
- package/src/utils/helperFunctions.ts +23 -5
- package/src/utils/loadConfigs.ts +313 -345
- package/src/utils/pathResolvers.ts +81 -0
- package/src/utils/projectConfig.ts +299 -0
- package/src/utils/retryFailedPromises.ts +4 -2
- package/src/utils/sessionAuth.ts +230 -0
- package/src/utils/setupFiles.ts +322 -54
- package/src/utils/typeGuards.ts +65 -0
- package/src/utils/versionDetection.ts +218 -64
- package/src/utils/yamlConverter.ts +296 -13
- package/src/utils/yamlLoader.ts +364 -0
- package/src/utilsController.ts +314 -110
- package/tests/README.md +497 -0
- package/tests/adapters/AdapterFactory.test.ts +277 -0
- package/tests/integration/syncOperations.test.ts +463 -0
- package/tests/jest.config.js +25 -0
- package/tests/migration/configMigration.test.ts +546 -0
- package/tests/setup.ts +62 -0
- package/tests/testUtils.ts +340 -0
- package/tests/utils/loadConfigs.test.ts +350 -0
- package/tests/validation/configValidation.test.ts +412 -0
- package/src/utils/schemaStrings.ts +0 -517
package/src/config/yamlConfig.ts
CHANGED
@@ -3,12 +3,21 @@ import yaml from "js-yaml";
|
|
3
3
|
import fs from "fs";
|
4
4
|
import path from "path";
|
5
5
|
import { AppwriteConfigSchema, type AppwriteConfig, RuntimeSchema, FunctionScopes, FunctionSpecifications, permissionsSchema, PermissionToAppwritePermission, type AppwriteFunction } from "appwrite-utils";
|
6
|
+
import { shouldIgnoreDirectory } from "../utils/directoryUtils.js";
|
7
|
+
import { MessageFormatter } from "../shared/messageFormatter.js";
|
6
8
|
|
7
9
|
const YamlConfigSchema = z.object({
|
8
10
|
appwrite: z.object({
|
9
11
|
endpoint: z.string().default("https://cloud.appwrite.io/v1"),
|
10
12
|
project: z.string(),
|
11
13
|
key: z.string(),
|
14
|
+
// Session authentication support
|
15
|
+
sessionCookie: z.string().optional(),
|
16
|
+
authMethod: z.enum(["session", "apikey", "auto"]).optional().default("auto"),
|
17
|
+
sessionMetadata: z.object({
|
18
|
+
email: z.string().optional(),
|
19
|
+
expiresAt: z.string().optional(),
|
20
|
+
}).optional(),
|
12
21
|
}),
|
13
22
|
logging: z
|
14
23
|
.object({
|
@@ -47,12 +56,14 @@ const YamlConfigSchema = z.object({
|
|
47
56
|
outputDirectory: z.string().default("schemas"),
|
48
57
|
yamlSchemaDirectory: z.string().default(".yaml_schemas"),
|
49
58
|
collectionsDirectory: z.string().default("collections"),
|
59
|
+
tablesDirectory: z.string().default("tables"),
|
50
60
|
})
|
51
61
|
.optional()
|
52
62
|
.default({
|
53
63
|
outputDirectory: "schemas",
|
54
64
|
yamlSchemaDirectory: ".yaml_schemas",
|
55
65
|
collectionsDirectory: "collections",
|
66
|
+
tablesDirectory: "tables",
|
56
67
|
}),
|
57
68
|
migrations: z
|
58
69
|
.object({
|
@@ -150,6 +161,10 @@ export const convertYamlToAppwriteConfig = (yamlConfig: YamlConfig): AppwriteCon
|
|
150
161
|
appwriteEndpoint: yamlConfig.appwrite.endpoint,
|
151
162
|
appwriteProject: yamlConfig.appwrite.project,
|
152
163
|
appwriteKey: yamlConfig.appwrite.key,
|
164
|
+
// Session authentication support from YAML
|
165
|
+
sessionCookie: yamlConfig.appwrite.sessionCookie,
|
166
|
+
authMethod: yamlConfig.appwrite.authMethod || "auto",
|
167
|
+
sessionMetadata: yamlConfig.appwrite.sessionMetadata,
|
153
168
|
apiMode: "auto", // Default to auto-detect for dual API support
|
154
169
|
appwriteClient: null,
|
155
170
|
logging: {
|
@@ -165,12 +180,12 @@ export const convertYamlToAppwriteConfig = (yamlConfig: YamlConfig): AppwriteCon
|
|
165
180
|
enableMockData: yamlConfig.data.enableMockData,
|
166
181
|
documentBucketId: yamlConfig.data.documentBucketId,
|
167
182
|
usersCollectionName: yamlConfig.data.usersCollectionName,
|
168
|
-
useMigrations: yamlConfig.migrations.enabled,
|
169
183
|
schemaConfig: {
|
170
184
|
outputDirectory: yamlConfig.schemas.outputDirectory,
|
171
185
|
yamlSchemaDirectory: yamlConfig.schemas.yamlSchemaDirectory,
|
172
186
|
importDirectory: yamlConfig.data.importDirectory,
|
173
187
|
collectionsDirectory: yamlConfig.schemas.collectionsDirectory || "collections",
|
188
|
+
tablesDirectory: yamlConfig.schemas.tablesDirectory || "tables",
|
174
189
|
},
|
175
190
|
databases: yamlConfig.databases.map((db) => ({
|
176
191
|
$id: db.id,
|
@@ -238,23 +253,78 @@ export const convertYamlToAppwriteConfig = (yamlConfig: YamlConfig): AppwriteCon
|
|
238
253
|
return appwriteConfig;
|
239
254
|
};
|
240
255
|
|
256
|
+
/**
|
257
|
+
* Enhanced config loading with session authentication support
|
258
|
+
* Supports session override options for preserving session state
|
259
|
+
*/
|
260
|
+
export interface YamlSessionOptions {
|
261
|
+
sessionCookie?: string;
|
262
|
+
authMethod?: "session" | "apikey" | "auto";
|
263
|
+
sessionMetadata?: { email?: string; expiresAt?: string; };
|
264
|
+
}
|
265
|
+
|
266
|
+
/**
|
267
|
+
* Load YAML config with optional session preservation
|
268
|
+
* Maintains authentication priority: explicit session > YAML file > system prefs
|
269
|
+
*/
|
270
|
+
export const loadYamlConfigWithSession = async (
|
271
|
+
configPath: string,
|
272
|
+
sessionOptions?: YamlSessionOptions
|
273
|
+
): Promise<AppwriteConfig | null> => {
|
274
|
+
try {
|
275
|
+
const fileContent = fs.readFileSync(configPath, "utf8");
|
276
|
+
const yamlData = yaml.load(fileContent) as unknown;
|
277
|
+
|
278
|
+
const yamlConfig = YamlConfigSchema.parse(yamlData);
|
279
|
+
const appwriteConfig = convertYamlToAppwriteConfig(yamlConfig);
|
280
|
+
|
281
|
+
// Apply session preservation if provided (explicit overrides take priority)
|
282
|
+
if (sessionOptions) {
|
283
|
+
if (sessionOptions.sessionCookie) {
|
284
|
+
appwriteConfig.sessionCookie = sessionOptions.sessionCookie;
|
285
|
+
}
|
286
|
+
if (sessionOptions.authMethod) {
|
287
|
+
appwriteConfig.authMethod = sessionOptions.authMethod;
|
288
|
+
}
|
289
|
+
if (sessionOptions.sessionMetadata) {
|
290
|
+
appwriteConfig.sessionMetadata = sessionOptions.sessionMetadata;
|
291
|
+
}
|
292
|
+
}
|
293
|
+
|
294
|
+
return appwriteConfig;
|
295
|
+
} catch (error) {
|
296
|
+
if (error instanceof z.ZodError) {
|
297
|
+
MessageFormatter.error("YAML config validation failed", undefined, { prefix: "Config" });
|
298
|
+
error.issues.forEach((err) => {
|
299
|
+
MessageFormatter.error(`${err.path.join('.')} → ${err.message}`, undefined, { prefix: "Config" });
|
300
|
+
});
|
301
|
+
} else {
|
302
|
+
MessageFormatter.error("Error loading YAML config", error instanceof Error ? error : undefined, { prefix: "Config" });
|
303
|
+
if (error instanceof Error && error.stack) {
|
304
|
+
MessageFormatter.debug("Stack trace", error.stack, { prefix: "Config" });
|
305
|
+
}
|
306
|
+
}
|
307
|
+
return null;
|
308
|
+
}
|
309
|
+
};
|
310
|
+
|
241
311
|
export const loadYamlConfig = async (configPath: string): Promise<AppwriteConfig | null> => {
|
242
312
|
try {
|
243
313
|
const fileContent = fs.readFileSync(configPath, "utf8");
|
244
314
|
const yamlData = yaml.load(fileContent) as unknown;
|
245
|
-
|
315
|
+
|
246
316
|
const yamlConfig = YamlConfigSchema.parse(yamlData);
|
247
317
|
return convertYamlToAppwriteConfig(yamlConfig);
|
248
318
|
} catch (error) {
|
249
319
|
if (error instanceof z.ZodError) {
|
250
|
-
|
320
|
+
MessageFormatter.error("YAML config validation failed", undefined, { prefix: "Config" });
|
251
321
|
error.issues.forEach((err) => {
|
252
|
-
|
322
|
+
MessageFormatter.error(`${err.path.join('.')} → ${err.message}`, undefined, { prefix: "Config" });
|
253
323
|
});
|
254
324
|
} else {
|
255
|
-
|
325
|
+
MessageFormatter.error("Error loading YAML config", error instanceof Error ? error : undefined, { prefix: "Config" });
|
256
326
|
if (error instanceof Error && error.stack) {
|
257
|
-
|
327
|
+
MessageFormatter.debug("Stack trace", error.stack, { prefix: "Config" });
|
258
328
|
}
|
259
329
|
}
|
260
330
|
return null;
|
@@ -306,47 +376,6 @@ export const findYamlConfig = (startDir: string): string | null => {
|
|
306
376
|
return null;
|
307
377
|
};
|
308
378
|
|
309
|
-
const shouldIgnoreDirectory = (dirName: string): boolean => {
|
310
|
-
const ignoredDirs = [
|
311
|
-
'node_modules',
|
312
|
-
'dist',
|
313
|
-
'build',
|
314
|
-
'coverage',
|
315
|
-
'.next',
|
316
|
-
'.nuxt',
|
317
|
-
'.cache',
|
318
|
-
'.git',
|
319
|
-
'.svn',
|
320
|
-
'.hg',
|
321
|
-
'__pycache__',
|
322
|
-
'.pytest_cache',
|
323
|
-
'.mypy_cache',
|
324
|
-
'venv',
|
325
|
-
'.venv',
|
326
|
-
'env',
|
327
|
-
'.env',
|
328
|
-
'target',
|
329
|
-
'out',
|
330
|
-
'bin',
|
331
|
-
'obj',
|
332
|
-
'.vs',
|
333
|
-
'.vscode',
|
334
|
-
'.idea',
|
335
|
-
'temp',
|
336
|
-
'tmp',
|
337
|
-
'.tmp',
|
338
|
-
'logs',
|
339
|
-
'log',
|
340
|
-
'.DS_Store',
|
341
|
-
'Thumbs.db'
|
342
|
-
];
|
343
|
-
|
344
|
-
return ignoredDirs.includes(dirName) ||
|
345
|
-
dirName.startsWith('.git') ||
|
346
|
-
dirName.startsWith('node_modules') ||
|
347
|
-
(dirName.startsWith('.') && dirName !== '.appwrite');
|
348
|
-
};
|
349
|
-
|
350
379
|
const findYamlConfigRecursive = (dir: string, depth: number = 0): string | null => {
|
351
380
|
// Limit search depth to prevent infinite recursion
|
352
381
|
if (depth > 5) {
|
@@ -398,6 +427,9 @@ export const generateYamlConfigTemplate = (outputPath: string) => {
|
|
398
427
|
endpoint: "https://cloud.appwrite.io/v1",
|
399
428
|
project: "YOUR_PROJECT_ID",
|
400
429
|
key: "YOUR_API_KEY",
|
430
|
+
authMethod: "auto" as const,
|
431
|
+
// Optional session authentication (leave empty to use API key)
|
432
|
+
// sessionCookie: "session_cookie_from_appwrite_cli",
|
401
433
|
},
|
402
434
|
logging: {
|
403
435
|
enabled: false,
|
@@ -420,6 +452,7 @@ export const generateYamlConfigTemplate = (outputPath: string) => {
|
|
420
452
|
outputDirectory: "schemas",
|
421
453
|
yamlSchemaDirectory: ".yaml_schemas",
|
422
454
|
collectionsDirectory: "collections",
|
455
|
+
tablesDirectory: "tables",
|
423
456
|
},
|
424
457
|
migrations: {
|
425
458
|
enabled: true,
|
@@ -433,15 +466,43 @@ export const generateYamlConfigTemplate = (outputPath: string) => {
|
|
433
466
|
functions: [],
|
434
467
|
};
|
435
468
|
|
436
|
-
|
469
|
+
let yamlContent = yaml.dump(template, {
|
437
470
|
indent: 2,
|
438
471
|
lineWidth: 120,
|
439
472
|
sortKeys: false,
|
440
473
|
});
|
441
474
|
|
442
|
-
// Add
|
475
|
+
// Add inline comments to the schemas section
|
476
|
+
yamlContent = yamlContent.replace(
|
477
|
+
/schemas:\s*\n(\s*)outputDirectory: schemas\n(\s*)yamlSchemaDirectory: \.yaml_schemas\n(\s*)collectionsDirectory: collections\n(\s*)tablesDirectory: tables/,
|
478
|
+
`schemas:
|
479
|
+
$1outputDirectory: schemas
|
480
|
+
$2yamlSchemaDirectory: .yaml_schemas
|
481
|
+
$3# Directory for legacy Databases API collection definitions
|
482
|
+
$3collectionsDirectory: collections
|
483
|
+
$4# Directory for new TablesDB API table definitions
|
484
|
+
$4tablesDirectory: tables`
|
485
|
+
);
|
486
|
+
|
487
|
+
// Add schema reference header and documentation
|
443
488
|
const schemaReference = "# yaml-language-server: $schema=./.yaml_schemas/appwrite-config.schema.json\n";
|
444
|
-
const
|
489
|
+
const documentation = `# Appwrite Project Configuration
|
490
|
+
#
|
491
|
+
# Authentication Configuration:
|
492
|
+
# - key: Standard API key authentication
|
493
|
+
# - sessionCookie: Session cookie from Appwrite CLI authentication
|
494
|
+
# - authMethod: "auto" (detects available method), "session" (prefer session), "apikey" (prefer API key)
|
495
|
+
# - Priority: Explicit CLI args > YAML config > ~/.appwrite/prefs.json > Error
|
496
|
+
#
|
497
|
+
# Directory Configuration:
|
498
|
+
# - collectionsDirectory: Use for legacy Databases API (default: "collections")
|
499
|
+
# - tablesDirectory: Use for new TablesDB API (default: "tables")
|
500
|
+
# - API mode is auto-detected based on server version, or set explicitly via apiMode
|
501
|
+
#
|
502
|
+
# For dual API support, both directories can coexist with different definitions
|
503
|
+
|
504
|
+
`;
|
505
|
+
const finalContent = schemaReference + documentation + yamlContent;
|
445
506
|
|
446
507
|
fs.writeFileSync(outputPath, finalContent, "utf8");
|
447
508
|
};
|
@@ -459,6 +520,10 @@ export const writeYamlConfig = async (configPath: string, config: AppwriteConfig
|
|
459
520
|
endpoint: config.appwriteEndpoint,
|
460
521
|
project: config.appwriteProject,
|
461
522
|
key: config.appwriteKey,
|
523
|
+
// Include session authentication fields
|
524
|
+
sessionCookie: config.sessionCookie,
|
525
|
+
authMethod: config.authMethod || "auto",
|
526
|
+
sessionMetadata: config.sessionMetadata,
|
462
527
|
},
|
463
528
|
logging: {
|
464
529
|
enabled: config.logging?.enabled || false,
|
@@ -482,9 +547,10 @@ export const writeYamlConfig = async (configPath: string, config: AppwriteConfig
|
|
482
547
|
outputDirectory: config.schemaConfig?.outputDirectory || "schemas",
|
483
548
|
yamlSchemaDirectory: config.schemaConfig?.yamlSchemaDirectory || ".yaml_schemas",
|
484
549
|
collectionsDirectory: config.schemaConfig?.collectionsDirectory || "collections",
|
550
|
+
tablesDirectory: config.schemaConfig?.tablesDirectory || "tables",
|
485
551
|
},
|
486
552
|
migrations: {
|
487
|
-
enabled:
|
553
|
+
enabled: true,
|
488
554
|
},
|
489
555
|
databases: config.databases?.map(db => ({
|
490
556
|
id: db.$id,
|
@@ -574,9 +640,9 @@ export const writeYamlConfig = async (configPath: string, config: AppwriteConfig
|
|
574
640
|
}
|
575
641
|
|
576
642
|
fs.writeFileSync(configPath, finalContent, "utf8");
|
577
|
-
|
643
|
+
MessageFormatter.success(`Updated YAML configuration at ${configPath}`, { prefix: "Config" });
|
578
644
|
} catch (error) {
|
579
|
-
|
645
|
+
MessageFormatter.error("Error writing YAML config", error instanceof Error ? error : undefined, { prefix: "Config" });
|
580
646
|
throw error;
|
581
647
|
}
|
582
648
|
};
|
@@ -640,9 +706,56 @@ export const addFunctionToYamlConfig = async (configPath: string, newFunction: A
|
|
640
706
|
}
|
641
707
|
|
642
708
|
fs.writeFileSync(configPath, finalContent, "utf8");
|
643
|
-
|
709
|
+
MessageFormatter.success(`Added function "${newFunction.name}" to YAML config`, { prefix: "Config" });
|
644
710
|
} catch (error) {
|
645
|
-
|
711
|
+
MessageFormatter.error("Error adding function to YAML config", error instanceof Error ? error : undefined, { prefix: "Config" });
|
646
712
|
throw error;
|
647
713
|
}
|
714
|
+
};
|
715
|
+
|
716
|
+
/**
|
717
|
+
* Extract session options from AppwriteConfig for YAML operations
|
718
|
+
* Useful for preserving session state during config reloads
|
719
|
+
*/
|
720
|
+
export const extractSessionOptionsFromConfig = (config: AppwriteConfig): YamlSessionOptions => {
|
721
|
+
return {
|
722
|
+
sessionCookie: config.sessionCookie,
|
723
|
+
authMethod: config.authMethod,
|
724
|
+
sessionMetadata: config.sessionMetadata,
|
725
|
+
};
|
726
|
+
};
|
727
|
+
|
728
|
+
/**
|
729
|
+
* Create session-preserved YAML config operations
|
730
|
+
* Maintains authentication state during config file updates
|
731
|
+
*/
|
732
|
+
export const createSessionPreservingYamlConfig = (configPath: string, sessionOptions: YamlSessionOptions) => {
|
733
|
+
return {
|
734
|
+
load: () => loadYamlConfigWithSession(configPath, sessionOptions),
|
735
|
+
write: (config: AppwriteConfig) => {
|
736
|
+
// Merge session options into config before writing
|
737
|
+
const enhancedConfig = {
|
738
|
+
...config,
|
739
|
+
sessionCookie: sessionOptions.sessionCookie || config.sessionCookie,
|
740
|
+
authMethod: sessionOptions.authMethod || config.authMethod,
|
741
|
+
sessionMetadata: sessionOptions.sessionMetadata || config.sessionMetadata,
|
742
|
+
};
|
743
|
+
return writeYamlConfig(configPath, enhancedConfig);
|
744
|
+
},
|
745
|
+
addFunction: (func: AppwriteFunction) => addFunctionToYamlConfig(configPath, func),
|
746
|
+
};
|
747
|
+
};
|
748
|
+
|
749
|
+
/**
|
750
|
+
* Determine if YAML config has session authentication configured
|
751
|
+
*/
|
752
|
+
export const hasYamlSessionAuth = (configPath: string): boolean => {
|
753
|
+
try {
|
754
|
+
const fileContent = fs.readFileSync(configPath, "utf8");
|
755
|
+
const yamlData = yaml.load(fileContent) as any;
|
756
|
+
|
757
|
+
return !!(yamlData?.appwrite?.sessionCookie && yamlData.appwrite.sessionCookie.trim());
|
758
|
+
} catch (error) {
|
759
|
+
return false;
|
760
|
+
}
|
648
761
|
};
|
package/src/databases/methods.ts
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import { Databases, Query, type Models } from "node-appwrite";
|
2
2
|
import { delay, tryAwaitWithRetry } from "../utils/helperFunctions.js";
|
3
3
|
import { fetchAllCollections } from "../collections/methods.js";
|
4
|
+
import { MessageFormatter } from "../shared/messageFormatter.js";
|
4
5
|
|
5
6
|
export const fetchAllDatabases = async (
|
6
7
|
database: Databases
|
@@ -30,13 +31,13 @@ export const wipeDatabase = async (
|
|
30
31
|
database: Databases,
|
31
32
|
databaseId: string
|
32
33
|
): Promise<{ collectionId: string; collectionName: string }[]> => {
|
33
|
-
|
34
|
+
MessageFormatter.info(`Wiping database: ${databaseId}`, { prefix: "Database" });
|
34
35
|
const existingCollections = await fetchAllCollections(databaseId, database);
|
35
36
|
let collectionsDeleted: { collectionId: string; collectionName: string }[] =
|
36
37
|
[];
|
37
38
|
|
38
39
|
for (const { $id: collectionId, name } of existingCollections) {
|
39
|
-
|
40
|
+
MessageFormatter.info(`Deleting collection: ${collectionId}`, { prefix: "Database" });
|
40
41
|
collectionsDeleted.push({ collectionId, collectionName: name });
|
41
42
|
await tryAwaitWithRetry(
|
42
43
|
async () => await database.deleteCollection(databaseId, collectionId)
|
package/src/databases/setup.ts
CHANGED
@@ -1,126 +1,18 @@
|
|
1
1
|
import { Databases, Query, type Models } from "node-appwrite";
|
2
|
-
import {
|
3
|
-
import { getMigrationCollectionSchemas } from "../storage/schemas.js";
|
4
|
-
import {
|
5
|
-
areCollectionNamesSame,
|
6
|
-
delay,
|
7
|
-
toCamelCase,
|
8
|
-
tryAwaitWithRetry,
|
9
|
-
} from "../utils/index.js";
|
2
|
+
import { tryAwaitWithRetry } from "../utils/index.js";
|
10
3
|
import { type AppwriteConfig } from "appwrite-utils";
|
11
4
|
import { ulid } from "ulidx";
|
5
|
+
import { MessageFormatter } from "../shared/messageFormatter.js";
|
12
6
|
|
13
|
-
export const
|
14
|
-
if (!config.useMigrations) {
|
15
|
-
console.log("Migrations database disabled, skipping setup");
|
16
|
-
return;
|
17
|
-
}
|
18
|
-
|
19
|
-
console.log("---------------------------------");
|
20
|
-
console.log("Starting Migrations Setup");
|
21
|
-
console.log("---------------------------------");
|
22
|
-
const database = new Databases(config.appwriteClient);
|
7
|
+
export const ensureDatabasesExist = async (config: AppwriteConfig, databasesToEnsure?: Models.Database[]) => {
|
23
8
|
if (!config.appwriteClient) {
|
24
9
|
throw new Error("Appwrite client is not initialized in the config");
|
25
10
|
}
|
26
|
-
|
27
|
-
const
|
28
|
-
|
29
|
-
try {
|
30
|
-
db = await tryAwaitWithRetry(
|
31
|
-
async () => await database.get("migrations"),
|
32
|
-
undefined,
|
33
|
-
true
|
34
|
-
);
|
35
|
-
console.log("Migrations database found");
|
36
|
-
} catch (e) {
|
37
|
-
db = await tryAwaitWithRetry(
|
38
|
-
async () => await database.create("migrations", "Migrations", true)
|
39
|
-
);
|
40
|
-
console.log("Migrations database created");
|
41
|
-
}
|
42
|
-
|
43
|
-
if (!db) {
|
44
|
-
console.error("Failed to create or retrieve the migrations database");
|
45
|
-
return;
|
46
|
-
}
|
47
|
-
|
48
|
-
for (const [collectionName, { collection, attributes }] of Object.entries(
|
49
|
-
migrationCollectionsSetup
|
50
|
-
)) {
|
51
|
-
const collectionId = toCamelCase(collectionName);
|
52
|
-
let collectionFound: Models.Collection | undefined;
|
53
|
-
try {
|
54
|
-
collectionFound = await tryAwaitWithRetry(
|
55
|
-
async () => await database.getCollection(db.$id, collectionId),
|
56
|
-
undefined,
|
57
|
-
true
|
58
|
-
);
|
59
|
-
console.log(`Collection found: ${collectionId}`);
|
60
|
-
} catch (e) {
|
61
|
-
console.log(`Collection not found: ${collectionId}`);
|
62
|
-
try {
|
63
|
-
collectionFound = await tryAwaitWithRetry(
|
64
|
-
async () =>
|
65
|
-
await database.createCollection(
|
66
|
-
db.$id,
|
67
|
-
collectionId,
|
68
|
-
collectionName,
|
69
|
-
undefined,
|
70
|
-
collection.documentSecurity,
|
71
|
-
collection.enabled
|
72
|
-
),
|
73
|
-
undefined,
|
74
|
-
true
|
75
|
-
);
|
76
|
-
console.log(`Collection created: ${collectionId}`);
|
77
|
-
} catch (createError) {
|
78
|
-
console.error(
|
79
|
-
`Failed to create collection: ${collectionId}`,
|
80
|
-
createError
|
81
|
-
);
|
82
|
-
continue;
|
83
|
-
}
|
84
|
-
}
|
85
|
-
|
86
|
-
if (!collectionFound) {
|
87
|
-
console.error(`Failed to create or retrieve collection: ${collectionId}`);
|
88
|
-
continue;
|
89
|
-
}
|
90
|
-
|
91
|
-
for (const attribute of attributes) {
|
92
|
-
try {
|
93
|
-
await createOrUpdateAttributeWithStatusCheck(
|
94
|
-
database,
|
95
|
-
db.$id,
|
96
|
-
collectionFound,
|
97
|
-
attribute
|
98
|
-
);
|
99
|
-
await delay(100);
|
100
|
-
console.log(`Attribute created/updated: ${attribute.key}`);
|
101
|
-
} catch (attrError) {
|
102
|
-
console.error(
|
103
|
-
`Failed to create/update attribute: ${attribute.key}`,
|
104
|
-
attrError
|
105
|
-
);
|
106
|
-
}
|
107
|
-
}
|
108
|
-
}
|
109
|
-
console.log("---------------------------------");
|
110
|
-
console.log("Migrations Setup Complete");
|
111
|
-
console.log("---------------------------------");
|
112
|
-
};
|
113
|
-
|
114
|
-
export const ensureDatabasesExist = async (config: AppwriteConfig, databasesToEnsure?: Models.Database[]) => {
|
115
|
-
if (!config.appwriteClient) {
|
116
|
-
throw new Error("Appwrite client is not initialized in the config");
|
117
|
-
}
|
118
|
-
const database = new Databases(config.appwriteClient);
|
119
|
-
// Work on a shallow copy so we don't mutate caller-provided arrays
|
120
|
-
const databasesToCreate = [...(databasesToEnsure || config.databases || [])];
|
11
|
+
const database = new Databases(config.appwriteClient);
|
12
|
+
const databasesToCreate = databasesToEnsure || config.databases || [];
|
121
13
|
|
122
14
|
if (!databasesToCreate.length) {
|
123
|
-
|
15
|
+
MessageFormatter.info("No databases to create");
|
124
16
|
return;
|
125
17
|
}
|
126
18
|
|
@@ -128,47 +20,28 @@ export const ensureDatabasesExist = async (config: AppwriteConfig, databasesToEn
|
|
128
20
|
async () => await database.list([Query.limit(500)])
|
129
21
|
);
|
130
22
|
|
131
|
-
const migrationsDatabase = existingDatabases.databases.find(
|
132
|
-
(d) => d.name.toLowerCase().trim().replace(" ", "") === "migrations"
|
133
|
-
);
|
134
|
-
if (config.useMigrations && existingDatabases.databases.length !== 0 && migrationsDatabase) {
|
135
|
-
console.log("Creating all databases including migrations");
|
136
|
-
// Ensure migrations exists, but do not mutate the caller's array
|
137
|
-
if (!databasesToCreate.some((d) => d.$id === migrationsDatabase.$id)) {
|
138
|
-
databasesToCreate.push(migrationsDatabase);
|
139
|
-
}
|
140
|
-
}
|
141
|
-
|
142
23
|
for (const db of databasesToCreate) {
|
143
24
|
if (!existingDatabases.databases.some((d) => d.name === db.name)) {
|
144
25
|
await tryAwaitWithRetry(
|
145
26
|
async () => await database.create(db.$id || ulid(), db.name, true)
|
146
27
|
);
|
147
|
-
|
28
|
+
MessageFormatter.success(`${db.name} database created`);
|
148
29
|
}
|
149
30
|
}
|
150
31
|
};
|
151
32
|
|
152
33
|
export const wipeOtherDatabases = async (
|
153
34
|
database: Databases,
|
154
|
-
databasesToKeep: Models.Database[]
|
155
|
-
useMigrations: boolean = true
|
35
|
+
databasesToKeep: Models.Database[]
|
156
36
|
) => {
|
157
|
-
|
37
|
+
MessageFormatter.info(`Databases to keep: ${databasesToKeep.map(db => db.name).join(", ")}`);
|
158
38
|
const allDatabases = await tryAwaitWithRetry(
|
159
39
|
async () => await database.list([Query.limit(500)])
|
160
40
|
);
|
161
|
-
const migrationsDatabase = allDatabases.databases.find(
|
162
|
-
(d) => d.name.toLowerCase().trim().replace(" ", "") === "migrations"
|
163
|
-
);
|
164
|
-
if (useMigrations && allDatabases.databases.length !== 0 && migrationsDatabase) {
|
165
|
-
console.log("Wiping all databases except migrations");
|
166
|
-
databasesToKeep.push(migrationsDatabase);
|
167
|
-
}
|
168
41
|
for (const db of allDatabases.databases) {
|
169
42
|
if (!databasesToKeep.some((d) => d.name === db.name)) {
|
170
43
|
await tryAwaitWithRetry(async () => await database.delete(db.$id));
|
171
|
-
|
44
|
+
MessageFormatter.success(`Deleted database: ${db.name}`);
|
172
45
|
}
|
173
46
|
}
|
174
47
|
};
|
@@ -198,7 +71,7 @@ export const ensureCollectionsExist = async (
|
|
198
71
|
true
|
199
72
|
)
|
200
73
|
);
|
201
|
-
|
74
|
+
MessageFormatter.success(`${collection.name} collection created in ${database.name}`);
|
202
75
|
}
|
203
76
|
}
|
204
77
|
};
|