appwrite-utils-cli 1.7.2 → 1.7.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.
@@ -178,9 +178,11 @@ export class AdapterFactory {
178
178
  client = new Client()
179
179
  .setEndpoint(config.appwriteEndpoint)
180
180
  .setProject(config.appwriteProject);
181
- // Set authentication method based on priority
181
+ // Set authentication method with mode headers
182
+ // Prefer session with admin mode, fallback to API key with default mode
182
183
  if (config.sessionCookie && isValidSessionCookie(config.sessionCookie)) {
183
184
  client.setSession(config.sessionCookie);
185
+ client.setHeader('X-Appwrite-Mode', 'admin');
184
186
  logger.debug('Using session authentication for TablesDB adapter', {
185
187
  project: config.appwriteProject,
186
188
  operation: 'createTablesDBAdapter'
@@ -188,11 +190,15 @@ export class AdapterFactory {
188
190
  }
189
191
  else if (config.appwriteKey) {
190
192
  client.setKey(config.appwriteKey);
193
+ client.setHeader('X-Appwrite-Mode', 'default');
191
194
  logger.debug('Using API key authentication for TablesDB adapter', {
192
195
  project: config.appwriteProject,
193
196
  operation: 'createTablesDBAdapter'
194
197
  });
195
198
  }
199
+ else {
200
+ throw new Error("No authentication available for adapter");
201
+ }
196
202
  }
197
203
  const tablesDB = new TablesDB(client);
198
204
  const adapter = new TablesDBAdapter(tablesDB);
@@ -246,9 +252,11 @@ export class AdapterFactory {
246
252
  client = new Client()
247
253
  .setEndpoint(config.appwriteEndpoint)
248
254
  .setProject(config.appwriteProject);
249
- // Set authentication method based on priority
255
+ // Set authentication method with mode headers
256
+ // Prefer session with admin mode, fallback to API key with default mode
250
257
  if (config.sessionCookie && isValidSessionCookie(config.sessionCookie)) {
251
258
  client.setSession(config.sessionCookie);
259
+ client.setHeader('X-Appwrite-Mode', 'admin');
252
260
  logger.debug('Using session authentication for Legacy adapter', {
253
261
  project: config.appwriteProject,
254
262
  operation: 'createLegacyAdapter'
@@ -256,11 +264,15 @@ export class AdapterFactory {
256
264
  }
257
265
  else if (config.appwriteKey) {
258
266
  client.setKey(config.appwriteKey);
267
+ client.setHeader('X-Appwrite-Mode', 'default');
259
268
  logger.debug('Using API key authentication for Legacy adapter', {
260
269
  project: config.appwriteProject,
261
270
  operation: 'createLegacyAdapter'
262
271
  });
263
272
  }
273
+ else {
274
+ throw new Error("No authentication available for adapter");
275
+ }
264
276
  }
265
277
  const databases = new Databases(client);
266
278
  const adapter = new LegacyAdapter(databases);
@@ -149,26 +149,9 @@ export class ConfigManager {
149
149
  logger.debug(`Config discovered at: ${configPath}`, { prefix: "ConfigManager" });
150
150
  // 3. Load config from file
151
151
  let config = await this.loaderService.loadFromPath(configPath);
152
- // 4. Load session authentication (only if appropriate based on config)
153
- // Determine if we should load session:
154
- // - Load if authMethod is explicitly "session"
155
- // - Load if authMethod is "auto" or undefined AND no API key exists
156
- // - Skip if authMethod is "apikey" or if API key is present with "auto" mode
157
- const hasApiKey = !!(config.appwriteKey && config.appwriteKey.trim().length > 0);
158
- const authMethod = config.authMethod || "auto";
159
- const shouldLoadSession = options.sessionOverride !== undefined ||
160
- authMethod === "session" ||
161
- (authMethod === "auto" && !hasApiKey);
162
- logger.debug("Session loading decision", {
163
- prefix: "ConfigManager",
164
- hasApiKey,
165
- authMethod,
166
- shouldLoadSession,
167
- });
168
- const session = shouldLoadSession
169
- ? options.sessionOverride ||
170
- (await this.sessionService.findSession(config.appwriteEndpoint, config.appwriteProject))
171
- : null;
152
+ // 4. Load session authentication
153
+ const session = options.sessionOverride ||
154
+ (await this.sessionService.findSession(config.appwriteEndpoint, config.appwriteProject));
172
155
  // 5. Merge session into config
173
156
  if (session) {
174
157
  logger.debug("Merging session authentication into config", { prefix: "ConfigManager" });
@@ -57,11 +57,8 @@ export class ConfigMergeService {
57
57
  const merged = cloneDeep(config);
58
58
  // Add session authentication (map 'cookie' to 'sessionCookie')
59
59
  merged.sessionCookie = session.cookie;
60
- // Only set authMethod to "session" if not explicitly set to "apikey"
61
- // This allows API key authentication to take priority when both are available
62
- if (merged.authMethod !== "apikey") {
63
- merged.authMethod = "session";
64
- }
60
+ // Set authMethod to session (priority handled by ClientFactory)
61
+ merged.authMethod = "session";
65
62
  // Add session metadata if available
66
63
  if (session.email || session.expiresAt) {
67
64
  merged.sessionMetadata = {
@@ -60,32 +60,80 @@ export class ClientFactory {
60
60
  const client = new Client()
61
61
  .setEndpoint(config.appwriteEndpoint)
62
62
  .setProject(config.appwriteProject);
63
- // Apply authentication (priority already resolved by ConfigManager)
64
- if (config.sessionCookie) {
65
- // Session authentication (from ConfigManager's session loading)
63
+ // Apply authentication based on authMethod preference with mode headers
64
+ // Mode headers: "admin" for sessions (elevated permissions), "default" for API keys
65
+ const authMethod = config.authMethod || "auto";
66
+ logger.debug("Applying authentication with mode headers", {
67
+ prefix: "ClientFactory",
68
+ authMethod,
69
+ hasApiKey: !!config.appwriteKey,
70
+ hasSession: !!config.sessionCookie,
71
+ });
72
+ if (authMethod === "session") {
73
+ // Explicit session preference - use only session with admin mode
74
+ if (!config.sessionCookie) {
75
+ const error = new Error("authMethod set to 'session' but no session cookie available.\n\n" +
76
+ "Either:\n" +
77
+ " - Run 'appwrite login' to create a session\n" +
78
+ " - Change authMethod to 'apikey' or 'auto'\n" +
79
+ " - Provide --sessionCookie flag");
80
+ logger.error("Failed to create client - session required", { prefix: "ClientFactory" });
81
+ throw error;
82
+ }
66
83
  client.setSession(config.sessionCookie);
67
- logger.debug("Applied session authentication to client", {
84
+ client.headers['X-Appwrite-Mode'] = 'admin';
85
+ logger.debug("Applied session authentication with admin mode (explicit preference)", {
68
86
  prefix: "ClientFactory",
69
87
  email: config.sessionMetadata?.email,
70
88
  });
71
89
  }
72
- else if (config.appwriteKey) {
73
- // API key authentication (from config file or overrides)
90
+ else if (authMethod === "apikey") {
91
+ // Explicit API key preference - use only API key with default mode
92
+ if (!config.appwriteKey || config.appwriteKey.trim().length === 0) {
93
+ const error = new Error("authMethod set to 'apikey' but no API key provided.\n\n" +
94
+ "Either:\n" +
95
+ " - Set appwriteKey in your config file\n" +
96
+ " - Provide --apiKey flag\n" +
97
+ " - Set APPWRITE_API_KEY environment variable");
98
+ logger.error("Failed to create client - API key required", { prefix: "ClientFactory" });
99
+ throw error;
100
+ }
74
101
  client.setKey(config.appwriteKey);
75
- logger.debug("Applied API key authentication to client", {
102
+ client.headers['X-Appwrite-Mode'] = 'default';
103
+ logger.debug("Applied API key authentication with default mode (explicit preference)", {
76
104
  prefix: "ClientFactory",
77
105
  });
78
106
  }
79
107
  else {
80
- // No authentication available - this should have been caught by ConfigManager
81
- const error = new Error("No authentication method available in configuration.\n\n" +
82
- "This should have been resolved by ConfigManager during config loading.\n" +
83
- "Expected either:\n" +
84
- " - config.sessionCookie (from session authentication)\n" +
85
- " - config.appwriteKey (from config file or CLI overrides)\n\n" +
86
- "Suggestion: Ensure ConfigManager.loadConfig() was called before ClientFactory.createFromConfig().");
87
- logger.error("Failed to create client - no authentication", { prefix: "ClientFactory" });
88
- throw error;
108
+ // Auto mode: Prefer session with admin mode (like official CLI), fallback to API key
109
+ if (config.sessionCookie) {
110
+ client.setSession(config.sessionCookie);
111
+ client.headers['X-Appwrite-Mode'] = 'admin';
112
+ logger.debug("Applied session authentication with admin mode (auto - preferred)", {
113
+ prefix: "ClientFactory",
114
+ email: config.sessionMetadata?.email,
115
+ });
116
+ }
117
+ else if (config.appwriteKey && config.appwriteKey.trim().length > 0) {
118
+ client.setKey(config.appwriteKey);
119
+ client.headers['X-Appwrite-Mode'] = 'default';
120
+ logger.debug("Applied API key authentication with default mode (auto - fallback)", {
121
+ prefix: "ClientFactory",
122
+ });
123
+ }
124
+ else {
125
+ // No authentication available
126
+ const error = new Error("No authentication method available in configuration.\n\n" +
127
+ "Expected either:\n" +
128
+ " - config.sessionCookie (from session authentication via 'appwrite login')\n" +
129
+ " - config.appwriteKey (from config file, CLI flags, or environment)\n\n" +
130
+ "Suggestion:\n" +
131
+ " - Run 'appwrite login' to create a session, OR\n" +
132
+ " - Add appwriteKey to your config file, OR\n" +
133
+ " - Provide --apiKey flag");
134
+ logger.error("Failed to create client - no authentication", { prefix: "ClientFactory" });
135
+ throw error;
136
+ }
89
137
  }
90
138
  // Create adapter with version detection
91
139
  // AdapterFactory uses internal caching, so repeated calls are fast
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.7.2",
4
+ "version": "1.7.4",
5
5
  "main": "src/main.ts",
6
6
  "type": "module",
7
7
  "repository": {
@@ -231,19 +231,24 @@ export class AdapterFactory {
231
231
  .setEndpoint(config.appwriteEndpoint)
232
232
  .setProject(config.appwriteProject);
233
233
 
234
- // Set authentication method based on priority
234
+ // Set authentication method with mode headers
235
+ // Prefer session with admin mode, fallback to API key with default mode
235
236
  if (config.sessionCookie && isValidSessionCookie(config.sessionCookie)) {
236
237
  (client as any).setSession(config.sessionCookie);
238
+ client.setHeader('X-Appwrite-Mode', 'admin');
237
239
  logger.debug('Using session authentication for TablesDB adapter', {
238
240
  project: config.appwriteProject,
239
241
  operation: 'createTablesDBAdapter'
240
242
  });
241
243
  } else if (config.appwriteKey) {
242
244
  client.setKey(config.appwriteKey);
245
+ client.setHeader('X-Appwrite-Mode', 'default');
243
246
  logger.debug('Using API key authentication for TablesDB adapter', {
244
247
  project: config.appwriteProject,
245
248
  operation: 'createTablesDBAdapter'
246
249
  });
250
+ } else {
251
+ throw new Error("No authentication available for adapter");
247
252
  }
248
253
  }
249
254
 
@@ -311,19 +316,24 @@ export class AdapterFactory {
311
316
  .setEndpoint(config.appwriteEndpoint)
312
317
  .setProject(config.appwriteProject);
313
318
 
314
- // Set authentication method based on priority
319
+ // Set authentication method with mode headers
320
+ // Prefer session with admin mode, fallback to API key with default mode
315
321
  if (config.sessionCookie && isValidSessionCookie(config.sessionCookie)) {
316
322
  (client as any).setSession(config.sessionCookie);
323
+ client.setHeader('X-Appwrite-Mode', 'admin');
317
324
  logger.debug('Using session authentication for Legacy adapter', {
318
325
  project: config.appwriteProject,
319
326
  operation: 'createLegacyAdapter'
320
327
  });
321
328
  } else if (config.appwriteKey) {
322
329
  client.setKey(config.appwriteKey);
330
+ client.setHeader('X-Appwrite-Mode', 'default');
323
331
  logger.debug('Using API key authentication for Legacy adapter', {
324
332
  project: config.appwriteProject,
325
333
  operation: 'createLegacyAdapter'
326
334
  });
335
+ } else {
336
+ throw new Error("No authentication available for adapter");
327
337
  }
328
338
  }
329
339
 
@@ -249,30 +249,10 @@ export class ConfigManager {
249
249
  // 3. Load config from file
250
250
  let config = await this.loaderService.loadFromPath(configPath);
251
251
 
252
- // 4. Load session authentication (only if appropriate based on config)
253
- // Determine if we should load session:
254
- // - Load if authMethod is explicitly "session"
255
- // - Load if authMethod is "auto" or undefined AND no API key exists
256
- // - Skip if authMethod is "apikey" or if API key is present with "auto" mode
257
- const hasApiKey = !!(config.appwriteKey && config.appwriteKey.trim().length > 0);
258
- const authMethod = config.authMethod || "auto";
259
-
260
- const shouldLoadSession =
261
- options.sessionOverride !== undefined ||
262
- authMethod === "session" ||
263
- (authMethod === "auto" && !hasApiKey);
264
-
265
- logger.debug("Session loading decision", {
266
- prefix: "ConfigManager",
267
- hasApiKey,
268
- authMethod,
269
- shouldLoadSession,
270
- });
271
-
272
- const session = shouldLoadSession
273
- ? options.sessionOverride ||
274
- (await this.sessionService.findSession(config.appwriteEndpoint, config.appwriteProject))
275
- : null;
252
+ // 4. Load session authentication
253
+ const session =
254
+ options.sessionOverride ||
255
+ (await this.sessionService.findSession(config.appwriteEndpoint, config.appwriteProject));
276
256
 
277
257
  // 5. Merge session into config
278
258
  if (session) {
@@ -81,11 +81,8 @@ export class ConfigMergeService {
81
81
  // Add session authentication (map 'cookie' to 'sessionCookie')
82
82
  merged.sessionCookie = session.cookie;
83
83
 
84
- // Only set authMethod to "session" if not explicitly set to "apikey"
85
- // This allows API key authentication to take priority when both are available
86
- if (merged.authMethod !== "apikey") {
87
- merged.authMethod = "session";
88
- }
84
+ // Set authMethod to session (priority handled by ClientFactory)
85
+ merged.authMethod = "session";
89
86
 
90
87
  // Add session metadata if available
91
88
  if (session.email || session.expiresAt) {
@@ -67,32 +67,86 @@ export class ClientFactory {
67
67
  .setEndpoint(config.appwriteEndpoint)
68
68
  .setProject(config.appwriteProject);
69
69
 
70
- // Apply authentication (priority already resolved by ConfigManager)
71
- if (config.sessionCookie) {
72
- // Session authentication (from ConfigManager's session loading)
70
+ // Apply authentication based on authMethod preference with mode headers
71
+ // Mode headers: "admin" for sessions (elevated permissions), "default" for API keys
72
+ const authMethod = config.authMethod || "auto";
73
+
74
+ logger.debug("Applying authentication with mode headers", {
75
+ prefix: "ClientFactory",
76
+ authMethod,
77
+ hasApiKey: !!config.appwriteKey,
78
+ hasSession: !!config.sessionCookie,
79
+ });
80
+
81
+ if (authMethod === "session") {
82
+ // Explicit session preference - use only session with admin mode
83
+ if (!config.sessionCookie) {
84
+ const error = new Error(
85
+ "authMethod set to 'session' but no session cookie available.\n\n" +
86
+ "Either:\n" +
87
+ " - Run 'appwrite login' to create a session\n" +
88
+ " - Change authMethod to 'apikey' or 'auto'\n" +
89
+ " - Provide --sessionCookie flag"
90
+ );
91
+ logger.error("Failed to create client - session required", { prefix: "ClientFactory" });
92
+ throw error;
93
+ }
73
94
  client.setSession(config.sessionCookie);
74
- logger.debug("Applied session authentication to client", {
95
+ client.headers['X-Appwrite-Mode'] = 'admin';
96
+ logger.debug("Applied session authentication with admin mode (explicit preference)", {
75
97
  prefix: "ClientFactory",
76
98
  email: config.sessionMetadata?.email,
77
99
  });
78
- } else if (config.appwriteKey) {
79
- // API key authentication (from config file or overrides)
100
+
101
+ } else if (authMethod === "apikey") {
102
+ // Explicit API key preference - use only API key with default mode
103
+ if (!config.appwriteKey || config.appwriteKey.trim().length === 0) {
104
+ const error = new Error(
105
+ "authMethod set to 'apikey' but no API key provided.\n\n" +
106
+ "Either:\n" +
107
+ " - Set appwriteKey in your config file\n" +
108
+ " - Provide --apiKey flag\n" +
109
+ " - Set APPWRITE_API_KEY environment variable"
110
+ );
111
+ logger.error("Failed to create client - API key required", { prefix: "ClientFactory" });
112
+ throw error;
113
+ }
80
114
  client.setKey(config.appwriteKey);
81
- logger.debug("Applied API key authentication to client", {
115
+ client.headers['X-Appwrite-Mode'] = 'default';
116
+ logger.debug("Applied API key authentication with default mode (explicit preference)", {
82
117
  prefix: "ClientFactory",
83
118
  });
119
+
84
120
  } else {
85
- // No authentication available - this should have been caught by ConfigManager
86
- const error = new Error(
87
- "No authentication method available in configuration.\n\n" +
88
- "This should have been resolved by ConfigManager during config loading.\n" +
89
- "Expected either:\n" +
90
- " - config.sessionCookie (from session authentication)\n" +
91
- " - config.appwriteKey (from config file or CLI overrides)\n\n" +
92
- "Suggestion: Ensure ConfigManager.loadConfig() was called before ClientFactory.createFromConfig()."
93
- );
94
- logger.error("Failed to create client - no authentication", { prefix: "ClientFactory" });
95
- throw error;
121
+ // Auto mode: Prefer session with admin mode (like official CLI), fallback to API key
122
+ if (config.sessionCookie) {
123
+ client.setSession(config.sessionCookie);
124
+ client.headers['X-Appwrite-Mode'] = 'admin';
125
+ logger.debug("Applied session authentication with admin mode (auto - preferred)", {
126
+ prefix: "ClientFactory",
127
+ email: config.sessionMetadata?.email,
128
+ });
129
+ } else if (config.appwriteKey && config.appwriteKey.trim().length > 0) {
130
+ client.setKey(config.appwriteKey);
131
+ client.headers['X-Appwrite-Mode'] = 'default';
132
+ logger.debug("Applied API key authentication with default mode (auto - fallback)", {
133
+ prefix: "ClientFactory",
134
+ });
135
+ } else {
136
+ // No authentication available
137
+ const error = new Error(
138
+ "No authentication method available in configuration.\n\n" +
139
+ "Expected either:\n" +
140
+ " - config.sessionCookie (from session authentication via 'appwrite login')\n" +
141
+ " - config.appwriteKey (from config file, CLI flags, or environment)\n\n" +
142
+ "Suggestion:\n" +
143
+ " - Run 'appwrite login' to create a session, OR\n" +
144
+ " - Add appwriteKey to your config file, OR\n" +
145
+ " - Provide --apiKey flag"
146
+ );
147
+ logger.error("Failed to create client - no authentication", { prefix: "ClientFactory" });
148
+ throw error;
149
+ }
96
150
  }
97
151
 
98
152
  // Create adapter with version detection