appwrite-utils-cli 1.7.3 → 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,17 @@ export class ClientFactory {
60
60
  const client = new Client()
61
61
  .setEndpoint(config.appwriteEndpoint)
62
62
  .setProject(config.appwriteProject);
63
- // Apply authentication based on authMethod preference
63
+ // Apply authentication based on authMethod preference with mode headers
64
+ // Mode headers: "admin" for sessions (elevated permissions), "default" for API keys
64
65
  const authMethod = config.authMethod || "auto";
65
- logger.debug("Applying authentication", {
66
+ logger.debug("Applying authentication with mode headers", {
66
67
  prefix: "ClientFactory",
67
68
  authMethod,
68
69
  hasApiKey: !!config.appwriteKey,
69
70
  hasSession: !!config.sessionCookie,
70
71
  });
71
- if (authMethod === "apikey") {
72
- // Explicit API key preference - use only API key
73
- if (!config.appwriteKey || config.appwriteKey.trim().length === 0) {
74
- const error = new Error("authMethod set to 'apikey' but no API key provided.\n\n" +
75
- "Either:\n" +
76
- " - Set appwriteKey in your config file\n" +
77
- " - Provide --apiKey flag\n" +
78
- " - Set APPWRITE_API_KEY environment variable");
79
- logger.error("Failed to create client - API key required", { prefix: "ClientFactory" });
80
- throw error;
81
- }
82
- client.setKey(config.appwriteKey);
83
- logger.debug("Applied API key authentication (explicit preference)", {
84
- prefix: "ClientFactory",
85
- });
86
- }
87
- else if (authMethod === "session") {
88
- // Explicit session preference - use only session
72
+ if (authMethod === "session") {
73
+ // Explicit session preference - use only session with admin mode
89
74
  if (!config.sessionCookie) {
90
75
  const error = new Error("authMethod set to 'session' but no session cookie available.\n\n" +
91
76
  "Either:\n" +
@@ -96,35 +81,55 @@ export class ClientFactory {
96
81
  throw error;
97
82
  }
98
83
  client.setSession(config.sessionCookie);
99
- logger.debug("Applied session authentication (explicit preference)", {
84
+ client.headers['X-Appwrite-Mode'] = 'admin';
85
+ logger.debug("Applied session authentication with admin mode (explicit preference)", {
100
86
  prefix: "ClientFactory",
101
87
  email: config.sessionMetadata?.email,
102
88
  });
103
89
  }
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
+ }
101
+ client.setKey(config.appwriteKey);
102
+ client.headers['X-Appwrite-Mode'] = 'default';
103
+ logger.debug("Applied API key authentication with default mode (explicit preference)", {
104
+ prefix: "ClientFactory",
105
+ });
106
+ }
104
107
  else {
105
- // Auto mode: Prefer API key if present, fallback to session
106
- if (config.appwriteKey && config.appwriteKey.trim().length > 0) {
107
- client.setKey(config.appwriteKey);
108
- logger.debug("Applied API key authentication (auto mode - preferred)", {
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)", {
109
113
  prefix: "ClientFactory",
114
+ email: config.sessionMetadata?.email,
110
115
  });
111
116
  }
112
- else if (config.sessionCookie) {
113
- client.setSession(config.sessionCookie);
114
- logger.debug("Applied session authentication (auto mode - fallback)", {
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)", {
115
121
  prefix: "ClientFactory",
116
- email: config.sessionMetadata?.email,
117
122
  });
118
123
  }
119
124
  else {
120
125
  // No authentication available
121
126
  const error = new Error("No authentication method available in configuration.\n\n" +
122
127
  "Expected either:\n" +
123
- " - config.appwriteKey (from config file, CLI flags, or environment)\n" +
124
- " - config.sessionCookie (from session authentication)\n\n" +
128
+ " - config.sessionCookie (from session authentication via 'appwrite login')\n" +
129
+ " - config.appwriteKey (from config file, CLI flags, or environment)\n\n" +
125
130
  "Suggestion:\n" +
126
- " - Add appwriteKey to your config file, OR\n" +
127
131
  " - Run 'appwrite login' to create a session, OR\n" +
132
+ " - Add appwriteKey to your config file, OR\n" +
128
133
  " - Provide --apiKey flag");
129
134
  logger.error("Failed to create client - no authentication", { prefix: "ClientFactory" });
130
135
  throw error;
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.3",
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,36 +67,19 @@ export class ClientFactory {
67
67
  .setEndpoint(config.appwriteEndpoint)
68
68
  .setProject(config.appwriteProject);
69
69
 
70
- // Apply authentication based on authMethod preference
70
+ // Apply authentication based on authMethod preference with mode headers
71
+ // Mode headers: "admin" for sessions (elevated permissions), "default" for API keys
71
72
  const authMethod = config.authMethod || "auto";
72
73
 
73
- logger.debug("Applying authentication", {
74
+ logger.debug("Applying authentication with mode headers", {
74
75
  prefix: "ClientFactory",
75
76
  authMethod,
76
77
  hasApiKey: !!config.appwriteKey,
77
78
  hasSession: !!config.sessionCookie,
78
79
  });
79
80
 
80
- if (authMethod === "apikey") {
81
- // Explicit API key preference - use only API key
82
- if (!config.appwriteKey || config.appwriteKey.trim().length === 0) {
83
- const error = new Error(
84
- "authMethod set to 'apikey' but no API key provided.\n\n" +
85
- "Either:\n" +
86
- " - Set appwriteKey in your config file\n" +
87
- " - Provide --apiKey flag\n" +
88
- " - Set APPWRITE_API_KEY environment variable"
89
- );
90
- logger.error("Failed to create client - API key required", { prefix: "ClientFactory" });
91
- throw error;
92
- }
93
- client.setKey(config.appwriteKey);
94
- logger.debug("Applied API key authentication (explicit preference)", {
95
- prefix: "ClientFactory",
96
- });
97
-
98
- } else if (authMethod === "session") {
99
- // Explicit session preference - use only session
81
+ if (authMethod === "session") {
82
+ // Explicit session preference - use only session with admin mode
100
83
  if (!config.sessionCookie) {
101
84
  const error = new Error(
102
85
  "authMethod set to 'session' but no session cookie available.\n\n" +
@@ -109,34 +92,56 @@ export class ClientFactory {
109
92
  throw error;
110
93
  }
111
94
  client.setSession(config.sessionCookie);
112
- logger.debug("Applied session authentication (explicit preference)", {
95
+ client.headers['X-Appwrite-Mode'] = 'admin';
96
+ logger.debug("Applied session authentication with admin mode (explicit preference)", {
113
97
  prefix: "ClientFactory",
114
98
  email: config.sessionMetadata?.email,
115
99
  });
116
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
+ }
114
+ client.setKey(config.appwriteKey);
115
+ client.headers['X-Appwrite-Mode'] = 'default';
116
+ logger.debug("Applied API key authentication with default mode (explicit preference)", {
117
+ prefix: "ClientFactory",
118
+ });
119
+
117
120
  } else {
118
- // Auto mode: Prefer API key if present, fallback to session
119
- if (config.appwriteKey && config.appwriteKey.trim().length > 0) {
120
- client.setKey(config.appwriteKey);
121
- logger.debug("Applied API key authentication (auto mode - preferred)", {
122
- prefix: "ClientFactory",
123
- });
124
- } else if (config.sessionCookie) {
121
+ // Auto mode: Prefer session with admin mode (like official CLI), fallback to API key
122
+ if (config.sessionCookie) {
125
123
  client.setSession(config.sessionCookie);
126
- logger.debug("Applied session authentication (auto mode - fallback)", {
124
+ client.headers['X-Appwrite-Mode'] = 'admin';
125
+ logger.debug("Applied session authentication with admin mode (auto - preferred)", {
127
126
  prefix: "ClientFactory",
128
127
  email: config.sessionMetadata?.email,
129
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
+ });
130
135
  } else {
131
136
  // No authentication available
132
137
  const error = new Error(
133
138
  "No authentication method available in configuration.\n\n" +
134
139
  "Expected either:\n" +
135
- " - config.appwriteKey (from config file, CLI flags, or environment)\n" +
136
- " - config.sessionCookie (from session authentication)\n\n" +
140
+ " - config.sessionCookie (from session authentication via 'appwrite login')\n" +
141
+ " - config.appwriteKey (from config file, CLI flags, or environment)\n\n" +
137
142
  "Suggestion:\n" +
138
- " - Add appwriteKey to your config file, OR\n" +
139
143
  " - Run 'appwrite login' to create a session, OR\n" +
144
+ " - Add appwriteKey to your config file, OR\n" +
140
145
  " - Provide --apiKey flag"
141
146
  );
142
147
  logger.error("Failed to create client - no authentication", { prefix: "ClientFactory" });