appwrite-utils-cli 1.6.3 → 1.6.5
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/CONFIG_TODO.md +1189 -0
- package/SERVICE_IMPLEMENTATION_REPORT.md +462 -0
- package/dist/cli/commands/configCommands.js +7 -1
- package/dist/collections/attributes.js +102 -30
- package/dist/collections/indexes.js +6 -1
- package/dist/collections/methods.js +4 -5
- package/dist/config/ConfigManager.d.ts +445 -0
- package/dist/config/ConfigManager.js +625 -0
- package/dist/config/index.d.ts +8 -0
- package/dist/config/index.js +7 -0
- package/dist/config/services/ConfigDiscoveryService.d.ts +126 -0
- package/dist/config/services/ConfigDiscoveryService.js +374 -0
- package/dist/config/services/ConfigLoaderService.d.ts +105 -0
- package/dist/config/services/ConfigLoaderService.js +410 -0
- package/dist/config/services/ConfigMergeService.d.ts +208 -0
- package/dist/config/services/ConfigMergeService.js +307 -0
- package/dist/config/services/ConfigValidationService.d.ts +214 -0
- package/dist/config/services/ConfigValidationService.js +310 -0
- package/dist/config/services/SessionAuthService.d.ts +225 -0
- package/dist/config/services/SessionAuthService.js +456 -0
- package/dist/config/services/__tests__/ConfigMergeService.test.d.ts +1 -0
- package/dist/config/services/__tests__/ConfigMergeService.test.js +271 -0
- package/dist/config/services/index.d.ts +13 -0
- package/dist/config/services/index.js +10 -0
- package/dist/interactiveCLI.js +8 -6
- package/dist/main.js +14 -19
- package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +1 -1
- package/dist/shared/operationQueue.js +1 -1
- package/dist/utils/ClientFactory.d.ts +87 -0
- package/dist/utils/ClientFactory.js +164 -0
- package/dist/utils/getClientFromConfig.js +4 -3
- package/dist/utils/helperFunctions.d.ts +1 -0
- package/dist/utils/helperFunctions.js +21 -5
- package/dist/utils/yamlConverter.d.ts +2 -2
- package/dist/utils/yamlConverter.js +2 -2
- package/dist/utilsController.d.ts +18 -15
- package/dist/utilsController.js +83 -131
- package/package.json +1 -1
- package/src/cli/commands/configCommands.ts +8 -1
- package/src/collections/attributes.ts +118 -31
- package/src/collections/indexes.ts +7 -1
- package/src/collections/methods.ts +4 -6
- package/src/config/ConfigManager.ts +808 -0
- package/src/config/index.ts +10 -0
- package/src/config/services/ConfigDiscoveryService.ts +463 -0
- package/src/config/services/ConfigLoaderService.ts +560 -0
- package/src/config/services/ConfigMergeService.ts +386 -0
- package/src/config/services/ConfigValidationService.ts +394 -0
- package/src/config/services/SessionAuthService.ts +565 -0
- package/src/config/services/__tests__/ConfigMergeService.test.ts +351 -0
- package/src/config/services/index.ts +29 -0
- package/src/interactiveCLI.ts +9 -7
- package/src/main.ts +14 -24
- package/src/shared/operationQueue.ts +1 -1
- package/src/utils/ClientFactory.ts +186 -0
- package/src/utils/getClientFromConfig.ts +4 -3
- package/src/utils/helperFunctions.ts +27 -7
- package/src/utils/yamlConverter.ts +4 -4
- package/src/utilsController.ts +99 -187
@@ -3,6 +3,7 @@ import { Client } from "node-appwrite";
|
|
3
3
|
import { AdapterFactory } from "../adapters/AdapterFactory.js";
|
4
4
|
import { findSessionByEndpointAndProject, hasSessionAuth, isValidSessionCookie } from "./sessionAuth.js";
|
5
5
|
import { MessageFormatter } from "../shared/messageFormatter.js";
|
6
|
+
import { logger } from "../shared/logging.js";
|
6
7
|
/**
|
7
8
|
* Enhanced client creation from config with session authentication support
|
8
9
|
* @deprecated Use getAdapterFromConfig for dual API support with session auth
|
@@ -28,7 +29,7 @@ export const getClientWithAuth = (endpoint, project, key, sessionCookie) => {
|
|
28
29
|
if (sessionCookie) {
|
29
30
|
if (isValidSessionCookie(sessionCookie)) {
|
30
31
|
client.setSession(sessionCookie);
|
31
|
-
|
32
|
+
logger.debug("Using explicit session authentication", { prefix: "Auth", project });
|
32
33
|
return client;
|
33
34
|
}
|
34
35
|
else {
|
@@ -41,7 +42,7 @@ export const getClientWithAuth = (endpoint, project, key, sessionCookie) => {
|
|
41
42
|
if (sessionAuth) {
|
42
43
|
if (isValidSessionCookie(sessionAuth.sessionCookie)) {
|
43
44
|
client.setSession(sessionAuth.sessionCookie);
|
44
|
-
|
45
|
+
logger.debug("Using session authentication", { prefix: "Auth", project, email: sessionAuth.email || 'unknown user' });
|
45
46
|
return client;
|
46
47
|
}
|
47
48
|
else {
|
@@ -56,7 +57,7 @@ export const getClientWithAuth = (endpoint, project, key, sessionCookie) => {
|
|
56
57
|
}
|
57
58
|
else {
|
58
59
|
client.setKey(key);
|
59
|
-
|
60
|
+
logger.debug("Using API key authentication", { prefix: "Auth", project });
|
60
61
|
return client;
|
61
62
|
}
|
62
63
|
}
|
@@ -38,6 +38,7 @@ export declare const finalizeByAttributeMap: (appwriteFolderPath: string, collec
|
|
38
38
|
export declare let numTimesFailedTotal: number;
|
39
39
|
/**
|
40
40
|
* Tries to execute the given createFunction and retries up to 5 times if it fails.
|
41
|
+
* Only retries on transient errors (network failures, 5xx errors). Does NOT retry validation errors (4xx).
|
41
42
|
*
|
42
43
|
* @param {() => Promise<any>} createFunction - The function to be executed.
|
43
44
|
* @param {number} [attemptNum=0] - The number of attempts made so far (default: 0).
|
@@ -83,6 +83,7 @@ export const finalizeByAttributeMap = async (appwriteFolderPath, collection, ite
|
|
83
83
|
export let numTimesFailedTotal = 0;
|
84
84
|
/**
|
85
85
|
* Tries to execute the given createFunction and retries up to 5 times if it fails.
|
86
|
+
* Only retries on transient errors (network failures, 5xx errors). Does NOT retry validation errors (4xx).
|
86
87
|
*
|
87
88
|
* @param {() => Promise<any>} createFunction - The function to be executed.
|
88
89
|
* @param {number} [attemptNum=0] - The number of attempts made so far (default: 0).
|
@@ -93,11 +94,25 @@ export const tryAwaitWithRetry = async (createFunction, attemptNum = 0, throwErr
|
|
93
94
|
return await createFunction();
|
94
95
|
}
|
95
96
|
catch (error) {
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
97
|
+
const errorMessage = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
|
98
|
+
const errorCode = error.code;
|
99
|
+
// Check if this is a validation error that should NOT be retried
|
100
|
+
const isValidationError = errorCode === 400 || errorCode === 409 || errorCode === 422 ||
|
101
|
+
errorMessage.includes("already exists") ||
|
102
|
+
errorMessage.includes("attribute with the same key") ||
|
103
|
+
errorMessage.includes("invalid") && !errorMessage.includes("fetch failed") ||
|
104
|
+
errorMessage.includes("conflict") ||
|
105
|
+
errorMessage.includes("bad request");
|
106
|
+
// Check if this is a transient error that SHOULD be retried
|
107
|
+
const isTransientError = errorCode === 522 || errorCode === "522" || // Cloudflare error
|
108
|
+
errorCode >= 500 && errorCode < 600 || // 5xx server errors
|
109
|
+
errorMessage.includes("fetch failed") || // Network failures
|
110
|
+
errorMessage.includes("timeout") ||
|
111
|
+
errorMessage.includes("econnrefused") ||
|
112
|
+
errorMessage.includes("network error");
|
113
|
+
// Only retry if it's a transient error AND not a validation error
|
114
|
+
if (isTransientError && !isValidationError) {
|
115
|
+
if (errorCode === 522 || errorCode === "522") {
|
101
116
|
console.log("Cloudflare error. Retrying...");
|
102
117
|
}
|
103
118
|
else {
|
@@ -110,6 +125,7 @@ export const tryAwaitWithRetry = async (createFunction, attemptNum = 0, throwErr
|
|
110
125
|
await delay(2500);
|
111
126
|
return tryAwaitWithRetry(createFunction, attemptNum + 1);
|
112
127
|
}
|
128
|
+
// For validation errors or non-transient errors, throw immediately
|
113
129
|
if (throwError) {
|
114
130
|
throw error;
|
115
131
|
}
|
@@ -14,7 +14,7 @@ export interface YamlCollectionData {
|
|
14
14
|
size?: number;
|
15
15
|
required?: boolean;
|
16
16
|
array?: boolean;
|
17
|
-
|
17
|
+
encrypted?: boolean;
|
18
18
|
default?: any;
|
19
19
|
min?: number;
|
20
20
|
max?: number;
|
@@ -32,7 +32,7 @@ export interface YamlCollectionData {
|
|
32
32
|
size?: number;
|
33
33
|
required?: boolean;
|
34
34
|
array?: boolean;
|
35
|
-
|
35
|
+
encrypted?: boolean;
|
36
36
|
default?: any;
|
37
37
|
min?: number;
|
38
38
|
max?: number;
|
@@ -39,9 +39,9 @@ export function collectionToYaml(collection, config = {
|
|
39
39
|
yamlAttr.required = attr.required;
|
40
40
|
if (attr.array !== undefined)
|
41
41
|
yamlAttr.array = attr.array;
|
42
|
-
// Always include
|
42
|
+
// Always include encrypted field for string attributes (default to false)
|
43
43
|
if (attr.type === 'string') {
|
44
|
-
yamlAttr.
|
44
|
+
yamlAttr.encrypted = ('encrypted' in attr && attr.encrypted === true) ? true : false;
|
45
45
|
}
|
46
46
|
if ('xdefault' in attr && attr.xdefault !== undefined)
|
47
47
|
yamlAttr.default = attr.xdefault;
|
@@ -19,8 +19,23 @@ export interface SetupOptions {
|
|
19
19
|
shouldWriteFile?: boolean;
|
20
20
|
}
|
21
21
|
export declare class UtilsController {
|
22
|
+
private static instance;
|
23
|
+
private isInitialized;
|
24
|
+
/**
|
25
|
+
* Get the UtilsController singleton instance
|
26
|
+
*/
|
27
|
+
static getInstance(currentUserDir: string, directConfig?: {
|
28
|
+
appwriteEndpoint?: string;
|
29
|
+
appwriteProject?: string;
|
30
|
+
appwriteKey?: string;
|
31
|
+
}): UtilsController;
|
32
|
+
/**
|
33
|
+
* Clear the singleton instance (useful for testing)
|
34
|
+
*/
|
35
|
+
static clearInstance(): void;
|
22
36
|
private appwriteFolderPath?;
|
23
37
|
private appwriteConfigPath?;
|
38
|
+
private currentUserDir;
|
24
39
|
config?: AppwriteConfig;
|
25
40
|
appwriteServer?: Client;
|
26
41
|
database?: Databases;
|
@@ -29,9 +44,6 @@ export declare class UtilsController {
|
|
29
44
|
converterDefinitions: ConverterFunctions;
|
30
45
|
validityRuleDefinitions: ValidationRules;
|
31
46
|
afterImportActionsDefinitions: AfterImportActions;
|
32
|
-
private sessionCookie?;
|
33
|
-
private authMethod?;
|
34
|
-
private sessionMetadata?;
|
35
47
|
constructor(currentUserDir: string, directConfig?: {
|
36
48
|
appwriteEndpoint?: string;
|
37
49
|
appwriteProject?: string;
|
@@ -75,23 +87,14 @@ export declare class UtilsController {
|
|
75
87
|
* Validates the current configuration for collections/tables conflicts
|
76
88
|
*/
|
77
89
|
validateConfiguration(strictMode?: boolean): Promise<ValidationResult>;
|
78
|
-
/**
|
79
|
-
* Extract session information from the current authenticated client
|
80
|
-
* This preserves session context for use across config reloads and adapter operations
|
81
|
-
*/
|
82
|
-
private extractSessionInfo;
|
83
|
-
/**
|
84
|
-
* Create session preservation options for passing to loadConfig
|
85
|
-
* Returns current session state to maintain authentication across config reloads
|
86
|
-
*/
|
87
|
-
private createSessionPreservationOptions;
|
88
90
|
/**
|
89
91
|
* Get current session information for debugging/logging purposes
|
92
|
+
* Delegates to ConfigManager for session info
|
90
93
|
*/
|
91
|
-
getSessionInfo(): {
|
94
|
+
getSessionInfo(): Promise<{
|
92
95
|
hasSession: boolean;
|
93
96
|
authMethod?: string;
|
94
97
|
email?: string;
|
95
98
|
expiresAt?: string;
|
96
|
-
}
|
99
|
+
}>;
|
97
100
|
}
|
package/dist/utilsController.js
CHANGED
@@ -16,20 +16,45 @@ import { transferDatabaseLocalToLocal, transferDatabaseLocalToRemote, transferSt
|
|
16
16
|
import { getClient, getClientWithAuth } from "./utils/getClientFromConfig.js";
|
17
17
|
import { getAdapterFromConfig } from "./utils/getClientFromConfig.js";
|
18
18
|
import { hasSessionAuth, findSessionByEndpointAndProject, isValidSessionCookie } from "./utils/sessionAuth.js";
|
19
|
-
import { createSessionPreservation } from "./utils/loadConfigs.js";
|
20
19
|
import { fetchAllDatabases } from "./databases/methods.js";
|
21
20
|
import { listFunctions, updateFunctionSpecifications, } from "./functions/methods.js";
|
22
21
|
import chalk from "chalk";
|
23
22
|
import { deployLocalFunction } from "./functions/deployments.js";
|
24
23
|
import fs from "node:fs";
|
25
|
-
import { configureLogging, updateLogger } from "./shared/logging.js";
|
24
|
+
import { configureLogging, updateLogger, logger } from "./shared/logging.js";
|
26
25
|
import { MessageFormatter, Messages } from "./shared/messageFormatter.js";
|
27
26
|
import { SchemaGenerator } from "./shared/schemaGenerator.js";
|
28
27
|
import { findYamlConfig } from "./config/yamlConfig.js";
|
29
28
|
import { validateCollectionsTablesConfig, reportValidationResults, validateWithStrictMode } from "./config/configValidation.js";
|
29
|
+
import { ConfigManager } from "./config/ConfigManager.js";
|
30
|
+
import { ClientFactory } from "./utils/ClientFactory.js";
|
30
31
|
export class UtilsController {
|
32
|
+
// ──────────────────────────────────────────────────
|
33
|
+
// SINGLETON PATTERN
|
34
|
+
// ──────────────────────────────────────────────────
|
35
|
+
static instance = null;
|
36
|
+
isInitialized = false;
|
37
|
+
/**
|
38
|
+
* Get the UtilsController singleton instance
|
39
|
+
*/
|
40
|
+
static getInstance(currentUserDir, directConfig) {
|
41
|
+
if (!UtilsController.instance) {
|
42
|
+
UtilsController.instance = new UtilsController(currentUserDir, directConfig);
|
43
|
+
}
|
44
|
+
return UtilsController.instance;
|
45
|
+
}
|
46
|
+
/**
|
47
|
+
* Clear the singleton instance (useful for testing)
|
48
|
+
*/
|
49
|
+
static clearInstance() {
|
50
|
+
UtilsController.instance = null;
|
51
|
+
}
|
52
|
+
// ──────────────────────────────────────────────────
|
53
|
+
// INSTANCE FIELDS
|
54
|
+
// ──────────────────────────────────────────────────
|
31
55
|
appwriteFolderPath;
|
32
56
|
appwriteConfigPath;
|
57
|
+
currentUserDir;
|
33
58
|
config;
|
34
59
|
appwriteServer;
|
35
60
|
database;
|
@@ -38,11 +63,8 @@ export class UtilsController {
|
|
38
63
|
converterDefinitions = converterFunctions;
|
39
64
|
validityRuleDefinitions = validationRules;
|
40
65
|
afterImportActionsDefinitions = afterImportActions;
|
41
|
-
// Session preservation fields
|
42
|
-
sessionCookie;
|
43
|
-
authMethod;
|
44
|
-
sessionMetadata;
|
45
66
|
constructor(currentUserDir, directConfig) {
|
67
|
+
this.currentUserDir = currentUserDir;
|
46
68
|
const basePath = currentUserDir;
|
47
69
|
if (directConfig) {
|
48
70
|
let hasErrors = false;
|
@@ -107,96 +129,58 @@ export class UtilsController {
|
|
107
129
|
}
|
108
130
|
}
|
109
131
|
async init(options = {}) {
|
110
|
-
const { validate = false, strictMode = false
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
if (validation && validate) {
|
120
|
-
reportValidationResults(validation, { verbose: false });
|
121
|
-
// In strict mode, throw if validation fails
|
122
|
-
if (strictMode && !validation.isValid) {
|
123
|
-
throw new Error(`Configuration validation failed in strict mode. Found ${validation.errors.length} validation errors.`);
|
124
|
-
}
|
125
|
-
}
|
126
|
-
}
|
127
|
-
catch (error) {
|
128
|
-
MessageFormatter.error("Failed to load config from file", error instanceof Error ? error : undefined, { prefix: "Config" });
|
129
|
-
return;
|
130
|
-
}
|
131
|
-
}
|
132
|
-
else {
|
133
|
-
MessageFormatter.error("No configuration available", undefined, { prefix: "Config" });
|
134
|
-
return;
|
135
|
-
}
|
132
|
+
const { validate = false, strictMode = false } = options;
|
133
|
+
const configManager = ConfigManager.getInstance();
|
134
|
+
// Load config if not already loaded
|
135
|
+
if (!configManager.hasConfig()) {
|
136
|
+
await configManager.loadConfig({
|
137
|
+
configDir: this.currentUserDir,
|
138
|
+
validate,
|
139
|
+
strictMode,
|
140
|
+
});
|
136
141
|
}
|
142
|
+
const config = configManager.getConfig();
|
137
143
|
// Configure logging based on config
|
138
|
-
if (
|
139
|
-
configureLogging(
|
144
|
+
if (config.logging) {
|
145
|
+
configureLogging(config.logging);
|
140
146
|
updateLogger();
|
141
147
|
}
|
142
|
-
//
|
143
|
-
|
144
|
-
|
145
|
-
this.
|
148
|
+
// Create client and adapter (session already in config from ConfigManager)
|
149
|
+
const { client, adapter } = await ClientFactory.createFromConfig(config);
|
150
|
+
this.appwriteServer = client;
|
151
|
+
this.adapter = adapter;
|
152
|
+
this.config = config;
|
146
153
|
this.database = new Databases(this.appwriteServer);
|
147
154
|
this.storage = new Storage(this.appwriteServer);
|
148
155
|
this.config.appwriteClient = this.appwriteServer;
|
149
|
-
//
|
150
|
-
|
151
|
-
const
|
152
|
-
|
153
|
-
|
154
|
-
prefix: "Adapter"
|
155
|
-
});
|
156
|
+
// Log only on FIRST initialization to avoid spam
|
157
|
+
if (!this.isInitialized) {
|
158
|
+
const apiMode = adapter.getApiMode();
|
159
|
+
MessageFormatter.info(`Database adapter initialized (apiMode: ${apiMode})`, { prefix: "Adapter" });
|
160
|
+
this.isInitialized = true;
|
156
161
|
}
|
157
|
-
|
158
|
-
|
162
|
+
else {
|
163
|
+
logger.debug("Adapter reused from cache", { prefix: "UtilsController" });
|
159
164
|
}
|
160
|
-
// Extract and store session information after successful authentication
|
161
|
-
this.extractSessionInfo();
|
162
165
|
}
|
163
166
|
async reloadConfig() {
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
}
|
168
|
-
// Preserve session authentication during config reload
|
169
|
-
const preserveAuth = this.createSessionPreservationOptions();
|
170
|
-
this.config = await loadConfig(this.appwriteFolderPath, {
|
171
|
-
preserveAuth
|
172
|
-
});
|
173
|
-
if (!this.config) {
|
174
|
-
MessageFormatter.error("Failed to load config", undefined, { prefix: "Controller" });
|
175
|
-
return;
|
176
|
-
}
|
167
|
+
const configManager = ConfigManager.getInstance();
|
168
|
+
// Session preservation is automatic in ConfigManager
|
169
|
+
const config = await configManager.reloadConfig();
|
177
170
|
// Configure logging based on updated config
|
178
|
-
if (
|
179
|
-
configureLogging(
|
171
|
+
if (config.logging) {
|
172
|
+
configureLogging(config.logging);
|
180
173
|
updateLogger();
|
181
174
|
}
|
182
|
-
//
|
183
|
-
|
175
|
+
// Recreate client and adapter
|
176
|
+
const { client, adapter } = await ClientFactory.createFromConfig(config);
|
177
|
+
this.appwriteServer = client;
|
178
|
+
this.adapter = adapter;
|
179
|
+
this.config = config;
|
184
180
|
this.database = new Databases(this.appwriteServer);
|
185
181
|
this.storage = new Storage(this.appwriteServer);
|
186
182
|
this.config.appwriteClient = this.appwriteServer;
|
187
|
-
|
188
|
-
try {
|
189
|
-
const { adapter, apiMode } = await getAdapterFromConfig(this.config, false, this.sessionCookie);
|
190
|
-
this.adapter = adapter;
|
191
|
-
MessageFormatter.info(`Database adapter re-initialized (apiMode: ${apiMode})`, {
|
192
|
-
prefix: "Adapter"
|
193
|
-
});
|
194
|
-
}
|
195
|
-
catch (error) {
|
196
|
-
MessageFormatter.warning('Database adapter re-initialization failed - some features may not work', { prefix: "Adapter" });
|
197
|
-
}
|
198
|
-
// Re-extract session information after reload
|
199
|
-
this.extractSessionInfo();
|
183
|
+
logger.debug("Config reloaded, adapter refreshed", { prefix: "UtilsController" });
|
200
184
|
}
|
201
185
|
async ensureDatabaseConfigBucketsExist(databases = []) {
|
202
186
|
await this.init();
|
@@ -339,7 +323,8 @@ export class UtilsController {
|
|
339
323
|
if (!this.database || !this.config)
|
340
324
|
throw new Error("Database not initialized");
|
341
325
|
try {
|
342
|
-
|
326
|
+
// Session is already in config from ConfigManager
|
327
|
+
const { adapter, apiMode } = await getAdapterFromConfig(this.config, false);
|
343
328
|
if (apiMode === 'tablesdb') {
|
344
329
|
await wipeAllTables(adapter, database.$id);
|
345
330
|
}
|
@@ -382,7 +367,8 @@ export class UtilsController {
|
|
382
367
|
if (!this.database || !this.config)
|
383
368
|
throw new Error("Database not initialized");
|
384
369
|
try {
|
385
|
-
|
370
|
+
// Session is already in config from ConfigManager
|
371
|
+
const { adapter, apiMode } = await getAdapterFromConfig(this.config, false);
|
386
372
|
if (apiMode === 'tablesdb') {
|
387
373
|
await wipeTableRows(adapter, database.$id, collection.$id);
|
388
374
|
}
|
@@ -618,59 +604,25 @@ export class UtilsController {
|
|
618
604
|
return validation;
|
619
605
|
}
|
620
606
|
/**
|
621
|
-
*
|
622
|
-
*
|
607
|
+
* Get current session information for debugging/logging purposes
|
608
|
+
* Delegates to ConfigManager for session info
|
623
609
|
*/
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
MessageFormatter.debug("Extracted session from config", { prefix: "Session" });
|
634
|
-
return;
|
635
|
-
}
|
636
|
-
// Fall back to finding session from Appwrite CLI preferences
|
637
|
-
const sessionAuth = findSessionByEndpointAndProject(this.config.appwriteEndpoint, this.config.appwriteProject);
|
638
|
-
if (sessionAuth && isValidSessionCookie(sessionAuth.sessionCookie)) {
|
639
|
-
this.sessionCookie = sessionAuth.sessionCookie;
|
640
|
-
this.authMethod = "session";
|
641
|
-
this.sessionMetadata = {
|
642
|
-
email: sessionAuth.email
|
610
|
+
async getSessionInfo() {
|
611
|
+
const configManager = ConfigManager.getInstance();
|
612
|
+
try {
|
613
|
+
const authStatus = await configManager.getAuthStatus();
|
614
|
+
return {
|
615
|
+
hasSession: authStatus.hasValidSession,
|
616
|
+
authMethod: authStatus.authMethod,
|
617
|
+
email: authStatus.sessionInfo?.email,
|
618
|
+
expiresAt: authStatus.sessionInfo?.expiresAt
|
643
619
|
};
|
644
|
-
MessageFormatter.debug(`Extracted session from CLI preferences for ${sessionAuth.email || 'unknown user'}`, { prefix: "Session" });
|
645
|
-
return;
|
646
620
|
}
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
MessageFormatter.debug("Using API key authentication", { prefix: "Session" });
|
653
|
-
}
|
654
|
-
}
|
655
|
-
/**
|
656
|
-
* Create session preservation options for passing to loadConfig
|
657
|
-
* Returns current session state to maintain authentication across config reloads
|
658
|
-
*/
|
659
|
-
createSessionPreservationOptions() {
|
660
|
-
if (!this.sessionCookie || !isValidSessionCookie(this.sessionCookie)) {
|
661
|
-
return undefined;
|
621
|
+
catch (error) {
|
622
|
+
// If config not loaded, return empty status
|
623
|
+
return {
|
624
|
+
hasSession: false
|
625
|
+
};
|
662
626
|
}
|
663
|
-
return createSessionPreservation(this.sessionCookie, this.sessionMetadata?.email, this.sessionMetadata?.expiresAt);
|
664
|
-
}
|
665
|
-
/**
|
666
|
-
* Get current session information for debugging/logging purposes
|
667
|
-
*/
|
668
|
-
getSessionInfo() {
|
669
|
-
return {
|
670
|
-
hasSession: !!this.sessionCookie && isValidSessionCookie(this.sessionCookie),
|
671
|
-
authMethod: this.authMethod,
|
672
|
-
email: this.sessionMetadata?.email,
|
673
|
-
expiresAt: this.sessionMetadata?.expiresAt
|
674
|
-
};
|
675
627
|
}
|
676
628
|
}
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "appwrite-utils-cli",
|
3
3
|
"description": "Appwrite Utility Functions to help with database management, data conversion, data import, migrations, and much more. Meant to be used as a CLI tool, I do not recommend installing this in frontend environments.",
|
4
|
-
"version": "1.6.
|
4
|
+
"version": "1.6.5",
|
5
5
|
"main": "src/main.ts",
|
6
6
|
"type": "module",
|
7
7
|
"repository": {
|
@@ -14,6 +14,8 @@ import {
|
|
14
14
|
import { createEmptyCollection } from "../../utils/setupFiles.js";
|
15
15
|
import chalk from "chalk";
|
16
16
|
import type { InteractiveCLI } from "../../interactiveCLI.js";
|
17
|
+
import { ConfigManager } from "../../config/ConfigManager.js";
|
18
|
+
import { UtilsController } from "../../utilsController.js";
|
17
19
|
|
18
20
|
export const configCommands = {
|
19
21
|
async migrateTypeScriptConfig(cli: InteractiveCLI): Promise<void> {
|
@@ -23,6 +25,10 @@ export const configCommands = {
|
|
23
25
|
// Perform the migration
|
24
26
|
await migrateConfig((cli as any).currentDir);
|
25
27
|
|
28
|
+
// Clear instances after migration to reload new config
|
29
|
+
UtilsController.clearInstance();
|
30
|
+
ConfigManager.resetInstance();
|
31
|
+
|
26
32
|
// Reset the detection flag
|
27
33
|
(cli as any).isUsingTypeScriptConfig = false;
|
28
34
|
|
@@ -173,7 +179,8 @@ export const configCommands = {
|
|
173
179
|
}
|
174
180
|
|
175
181
|
// Reinitialize controller with session preservation
|
176
|
-
|
182
|
+
UtilsController.clearInstance();
|
183
|
+
(cli as any).controller = UtilsController.getInstance((cli as any).currentDir, directConfig);
|
177
184
|
await (cli as any).controller.init();
|
178
185
|
|
179
186
|
MessageFormatter.success("Configuration reloaded with session preserved", { prefix: "Config" });
|