gigadrive 1.1.2 → 2.0.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/dist/index.cjs CHANGED
@@ -26,6 +26,45 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  // src/index.ts
27
27
  var import_commander = require("commander");
28
28
 
29
+ // src/util/log.ts
30
+ var import_consola = require("consola");
31
+ var verbose = false;
32
+ var consola = (0, import_consola.createConsola)({
33
+ level: verbose ? 4 : 3,
34
+ // 4 includes debug messages, 3 is the default (info and above)
35
+ formatOptions: {
36
+ colors: true
37
+ }
38
+ });
39
+ var updateConsola = () => {
40
+ consola.level = verbose ? 4 : 3;
41
+ };
42
+ var setVerbose = (value) => {
43
+ verbose = value;
44
+ updateConsola();
45
+ };
46
+ var log = (message) => {
47
+ consola.info(message);
48
+ };
49
+ var error = (message) => {
50
+ consola.error(message);
51
+ };
52
+ var success = (message) => {
53
+ consola.success(message);
54
+ };
55
+ var warn = (message) => {
56
+ consola.warn(message);
57
+ };
58
+ var debug = (message, ...optionalParams) => {
59
+ if (!verbose) {
60
+ return;
61
+ }
62
+ consola.debug("[DEBUG]", message, ...optionalParams);
63
+ };
64
+ var spinner = (message) => {
65
+ log(message);
66
+ };
67
+
29
68
  // src/commands/build/index.ts
30
69
  var import_build_utils = require("@gigadrive/build-utils");
31
70
  var import_fs2 = __toESM(require("fs"), 1);
@@ -40,7 +79,7 @@ var import_child_process = require("child_process");
40
79
  async function exec({
41
80
  command,
42
81
  cwd = process.cwd(),
43
- env,
82
+ env: env2,
44
83
  onOutput = (data) => console.log(data),
45
84
  onError = (data) => console.error(data)
46
85
  }) {
@@ -58,7 +97,7 @@ async function exec({
58
97
  const childProcess = (0, import_child_process.spawn)(spawnCommand, spawnArgs, {
59
98
  cwd,
60
99
  shell: true,
61
- env
100
+ env: env2
62
101
  });
63
102
  childProcess.stdout.on("data", (data) => {
64
103
  onOutput(data.toString().trim());
@@ -124,7 +163,7 @@ var buildCommand = (pm) => {
124
163
  // src/commands/build/index.ts
125
164
  var build = (parent) => {
126
165
  parent.command("build").description("Build the current project").action(async () => {
127
- const env = {
166
+ const env2 = {
128
167
  ...process.env,
129
168
  NODE_ENV: "production",
130
169
  NEBULA: "1",
@@ -135,34 +174,34 @@ var build = (parent) => {
135
174
  const cwd = process.cwd();
136
175
  const packageJsonPath = import_path2.default.join(cwd, "package.json");
137
176
  if (!import_fs2.default.existsSync(packageJsonPath)) {
138
- console.log("No package.json found");
177
+ error("No package.json found");
139
178
  return;
140
179
  }
141
180
  const packageJson = JSON.parse(import_fs2.default.readFileSync(packageJsonPath, "utf-8"));
142
181
  const buildScript = packageJson.scripts?.build;
143
182
  if (!buildScript) {
144
- console.log("No build script found in package.json");
183
+ error("No build script found in package.json");
145
184
  return;
146
185
  }
147
186
  const packageManager = await getPackageManager({ cwd });
148
187
  if (!packageManager) {
149
- console.log("No package manager found");
188
+ error("No package manager found");
150
189
  return;
151
190
  }
152
191
  await (0, import_build_utils.exec)({
153
192
  command: installCommand(packageManager),
154
193
  cwd,
155
- env,
194
+ env: env2,
156
195
  onOutput: (chunk) => {
157
- console.log(chunk);
196
+ log(chunk);
158
197
  }
159
198
  });
160
199
  await (0, import_build_utils.exec)({
161
200
  command: buildCommand(packageManager),
162
201
  cwd,
163
- env,
202
+ env: env2,
164
203
  onOutput: (chunk) => {
165
- console.log(chunk);
204
+ log(chunk);
166
205
  }
167
206
  });
168
207
  });
@@ -171,47 +210,6 @@ var build = (parent) => {
171
210
  // src/commands/debug/config/index.ts
172
211
  var import_network_config = require("@gigadrive/network-config");
173
212
  var import_console = require("console");
174
-
175
- // src/util/log.ts
176
- var import_consola = require("consola");
177
- var verbose = false;
178
- var consola = (0, import_consola.createConsola)({
179
- level: verbose ? 4 : 3,
180
- // 4 includes debug messages, 3 is the default (info and above)
181
- formatOptions: {
182
- colors: true
183
- }
184
- });
185
- var updateConsola = () => {
186
- consola.level = verbose ? 4 : 3;
187
- };
188
- var setVerbose = (value) => {
189
- verbose = value;
190
- updateConsola();
191
- };
192
- var log = (message) => {
193
- consola.info(message);
194
- };
195
- var error = (message) => {
196
- consola.error(message);
197
- };
198
- var success = (message) => {
199
- consola.success(message);
200
- };
201
- var warn = (message) => {
202
- consola.warn(message);
203
- };
204
- var debug = (message, ...optionalParams) => {
205
- if (!verbose) {
206
- return;
207
- }
208
- consola.debug("[DEBUG]", message, ...optionalParams);
209
- };
210
- var spinner = (message) => {
211
- log(message);
212
- };
213
-
214
- // src/commands/debug/config/index.ts
215
213
  var config = (parent) => {
216
214
  parent.command("config").description("Provide debug info about the project configuration in the current directory").action(async () => {
217
215
  const configPath = (0, import_network_config.findConfig)(process.cwd());
@@ -231,6 +229,427 @@ var debug2 = (program) => {
231
229
  config(debug3);
232
230
  };
233
231
 
232
+ // src/env.ts
233
+ var import_env_core = require("@t3-oss/env-core");
234
+ var import_dotenv = require("dotenv");
235
+ var import_node_fs = __toESM(require("fs"), 1);
236
+ var import_node_path = __toESM(require("path"), 1);
237
+ var import_zod = require("zod");
238
+ (() => {
239
+ const cwd = process.cwd();
240
+ const nodeEnv = process.env.NODE_ENV;
241
+ const candidates = [
242
+ nodeEnv ? `.env.${nodeEnv}.local` : null,
243
+ `.env.local`,
244
+ nodeEnv ? `.env.${nodeEnv}` : null,
245
+ `.env`
246
+ ].filter(Boolean);
247
+ for (const filename of candidates) {
248
+ const fullPath = import_node_path.default.join(cwd, filename);
249
+ if (import_node_fs.default.existsSync(fullPath)) {
250
+ console.debug(`Loading environment variables from ${fullPath}`);
251
+ (0, import_dotenv.config)({ path: fullPath, override: false });
252
+ }
253
+ }
254
+ })();
255
+ var env = (0, import_env_core.createEnv)({
256
+ server: {
257
+ GIGADRIVE_NETWORK_OAUTH_ISSUER_URL: import_zod.z.url().min(1).default("https://idp.gigadrive.de"),
258
+ GIGADRIVE_NETWORK_OAUTH_CLIENT_ID: import_zod.z.string().min(1).default("todo_add_client_id")
259
+ },
260
+ runtimeEnv: process.env,
261
+ emptyStringAsUndefined: true
262
+ });
263
+
264
+ // src/config/oauth.ts
265
+ var cachedConfig = null;
266
+ async function getOAuthConfig() {
267
+ if (cachedConfig) return cachedConfig;
268
+ const issuerBase = env.GIGADRIVE_NETWORK_OAUTH_ISSUER_URL.replace(/\/$/, "");
269
+ const controller = new AbortController();
270
+ const timeout = setTimeout(() => controller.abort(), 8e3);
271
+ let discovery = null;
272
+ try {
273
+ const discoveryUrl = `${issuerBase}/.well-known/openid-configuration`;
274
+ const res = await fetch(discoveryUrl, { signal: controller.signal });
275
+ if (res.ok) {
276
+ discovery = await res.json();
277
+ } else {
278
+ discovery = null;
279
+ }
280
+ } catch {
281
+ discovery = null;
282
+ } finally {
283
+ clearTimeout(timeout);
284
+ }
285
+ if (!discovery?.authorization_endpoint || !discovery?.token_endpoint || !discovery?.userinfo_endpoint) {
286
+ throw new Error("OIDC discovery failed or returned incomplete endpoints");
287
+ }
288
+ const DEFAULT_SCOPE = "offline_access openid profile email";
289
+ cachedConfig = {
290
+ clientId: env.GIGADRIVE_NETWORK_OAUTH_CLIENT_ID,
291
+ issuer: discovery.issuer ?? issuerBase,
292
+ authorizeUrl: discovery.authorization_endpoint,
293
+ tokenUrl: discovery.token_endpoint,
294
+ scope: DEFAULT_SCOPE,
295
+ userinfoUrl: discovery.userinfo_endpoint
296
+ };
297
+ return cachedConfig;
298
+ }
299
+
300
+ // src/auth/manager.ts
301
+ var crypto = __toESM(require("crypto"), 1);
302
+ var fs4 = __toESM(require("fs"), 1);
303
+ var http = __toESM(require("http"), 1);
304
+ var os = __toESM(require("os"), 1);
305
+ var path4 = __toESM(require("path"), 1);
306
+ var import_node_url = require("url");
307
+ var import_open = __toESM(require("open"), 1);
308
+ function getAuthStoragePaths() {
309
+ const homeDir = os.homedir();
310
+ const authDir = path4.join(homeDir, ".gigadrive");
311
+ const authFile = path4.join(authDir, "auth.json");
312
+ return { directory: authDir, file: authFile };
313
+ }
314
+ async function ensureAuthDirectory() {
315
+ const { directory } = getAuthStoragePaths();
316
+ try {
317
+ await fs4.promises.mkdir(directory, { recursive: true, mode: 448 });
318
+ await fs4.promises.chmod(directory, 448);
319
+ } catch (error2) {
320
+ const errorMessage = error2 instanceof Error ? error2.message : "Unknown error";
321
+ throw new Error(`Failed to create auth directory: ${errorMessage}`);
322
+ }
323
+ }
324
+ function generatePKCE() {
325
+ const codeVerifier = base64URLEncode(crypto.randomBytes(64));
326
+ const challengeBytes = crypto.createHash("sha256").update(codeVerifier, "utf8").digest();
327
+ const codeChallenge = base64URLEncode(challengeBytes);
328
+ return { codeVerifier, codeChallenge };
329
+ }
330
+ function base64URLEncode(buffer) {
331
+ return buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
332
+ }
333
+ var AuthManager = class {
334
+ accessToken = null;
335
+ tokenExpirationTime = 0;
336
+ // Unix timestamp in milliseconds
337
+ codeVerifier = null;
338
+ state = null;
339
+ constructor() {
340
+ }
341
+ /**
342
+ * Retrieves the stored auth data from the local file.
343
+ * @returns {Promise<StoredAuthData | null>} The stored auth data if found, otherwise null.
344
+ * @private
345
+ */
346
+ async _loadStoredAuthData() {
347
+ try {
348
+ const { file } = getAuthStoragePaths();
349
+ const data = await fs4.promises.readFile(file, "utf8");
350
+ const authData = JSON.parse(data);
351
+ if (authData.accessToken && authData.tokenExpirationTime && Date.now() < authData.tokenExpirationTime) {
352
+ this.accessToken = authData.accessToken;
353
+ this.tokenExpirationTime = authData.tokenExpirationTime;
354
+ }
355
+ return authData;
356
+ } catch {
357
+ return null;
358
+ }
359
+ }
360
+ /**
361
+ * Stores the auth data in the local file.
362
+ * @param {StoredAuthData} authData The auth data to store.
363
+ * @private
364
+ */
365
+ async _saveStoredAuthData(authData) {
366
+ try {
367
+ await ensureAuthDirectory();
368
+ const { file } = getAuthStoragePaths();
369
+ await fs4.promises.writeFile(file, JSON.stringify(authData, null, 2), { encoding: "utf8", mode: 384 });
370
+ await fs4.promises.chmod(file, 384);
371
+ console.debug("Auth data saved to local storage.");
372
+ } catch (error2) {
373
+ const errorMessage = error2 instanceof Error ? error2.message : "Unknown error";
374
+ console.error("Error saving auth data to local storage:", errorMessage);
375
+ }
376
+ }
377
+ /**
378
+ * Deletes the stored auth data from the local file.
379
+ */
380
+ async logout() {
381
+ this.accessToken = null;
382
+ this.tokenExpirationTime = 0;
383
+ try {
384
+ const { file } = getAuthStoragePaths();
385
+ await fs4.promises.unlink(file);
386
+ log("Logged out. Auth data removed from local storage.");
387
+ } catch {
388
+ log("Logged out.");
389
+ }
390
+ }
391
+ /**
392
+ * Initiates the OAuth login flow with the IDP via a web portal.
393
+ * Opens a browser for user authentication and listens for the redirect.
394
+ * @returns {Promise<boolean>} True if login was successful, false otherwise.
395
+ */
396
+ async login() {
397
+ await this.logout();
398
+ const { codeVerifier, codeChallenge } = generatePKCE();
399
+ this.codeVerifier = codeVerifier;
400
+ this.state = crypto.randomBytes(16).toString("hex");
401
+ const OAUTH_CONFIG = await getOAuthConfig();
402
+ const loginState = this.state;
403
+ if (!loginState) {
404
+ throw new Error("Internal error: login state not initialized");
405
+ }
406
+ const server = http.createServer();
407
+ let usedRedirectUri = "";
408
+ const serverPromise = new Promise((resolve, reject) => {
409
+ const redirectPath = "/callback";
410
+ server.listen(0, "127.0.0.1", () => {
411
+ const address = server.address();
412
+ if (!address || typeof address !== "object") {
413
+ reject(new Error("Failed to determine callback server address"));
414
+ return;
415
+ }
416
+ const port = address.port;
417
+ usedRedirectUri = `http://127.0.0.1:${port}${redirectPath}`;
418
+ const authUrl = new import_node_url.URL(OAUTH_CONFIG.authorizeUrl);
419
+ authUrl.searchParams.append("client_id", OAUTH_CONFIG.clientId);
420
+ authUrl.searchParams.append("redirect_uri", usedRedirectUri);
421
+ authUrl.searchParams.append("response_type", "code");
422
+ authUrl.searchParams.append("scope", OAUTH_CONFIG.scope);
423
+ authUrl.searchParams.append("code_challenge", codeChallenge);
424
+ authUrl.searchParams.append("code_challenge_method", "S256");
425
+ authUrl.searchParams.append("state", loginState);
426
+ log(`Please open this URL in your browser to log in:
427
+ ${authUrl.toString()}
428
+ `);
429
+ log("Waiting for login callback...");
430
+ void (0, import_open.default)(authUrl.toString());
431
+ });
432
+ server.on("request", (req, res) => {
433
+ const base = usedRedirectUri || "http://127.0.0.1/callback";
434
+ const reqUrl = new import_node_url.URL(req.url || "", base);
435
+ if (reqUrl.pathname === "/callback") {
436
+ const authCode = reqUrl.searchParams.get("code");
437
+ const receivedState = reqUrl.searchParams.get("state");
438
+ const error2 = reqUrl.searchParams.get("error");
439
+ res.writeHead(200, { "Content-Type": "text/html", Connection: "close" });
440
+ if (error2) {
441
+ res.end("<h1>Login Failed!</h1><p>Error: " + error2 + "</p><p>You can close this tab.</p>");
442
+ reject(new Error(`OAuth error: ${error2}`));
443
+ server.close();
444
+ return;
445
+ }
446
+ if (receivedState !== this.state) {
447
+ res.end("<h1>Login Failed!</h1><p>State mismatch. Possible CSRF attack.</p><p>You can close this tab.</p>");
448
+ reject(new Error("State mismatch"));
449
+ server.close();
450
+ return;
451
+ }
452
+ if (authCode) {
453
+ res.end("<h1>Login Successful!</h1><p>You can close this tab.</p>");
454
+ resolve(authCode);
455
+ server.close();
456
+ } else {
457
+ res.end("<h1>Login Failed!</h1><p>No authorization code received.</p><p>You can close this tab.</p>");
458
+ reject(new Error("No authorization code received"));
459
+ server.close();
460
+ }
461
+ } else {
462
+ res.writeHead(404).end("Not Found");
463
+ }
464
+ });
465
+ server.on("error", (err) => {
466
+ console.error("Local server error:", err);
467
+ reject(err);
468
+ });
469
+ });
470
+ try {
471
+ const authCode = await serverPromise;
472
+ const tokenResponse = await fetch(OAUTH_CONFIG.tokenUrl, {
473
+ method: "POST",
474
+ headers: {
475
+ "Content-Type": "application/x-www-form-urlencoded"
476
+ },
477
+ body: new import_node_url.URLSearchParams({
478
+ grant_type: "authorization_code",
479
+ client_id: OAUTH_CONFIG.clientId,
480
+ code: authCode,
481
+ ...usedRedirectUri ? { redirect_uri: usedRedirectUri } : {},
482
+ code_verifier: this.codeVerifier || ""
483
+ // Use the stored codeVerifier
484
+ }).toString()
485
+ });
486
+ if (!tokenResponse.ok) {
487
+ const errorData = await tokenResponse.json().catch(() => null);
488
+ throw new Error(
489
+ `Token exchange failed: ${tokenResponse.status} ${tokenResponse.statusText} - ${errorData ? JSON.stringify(errorData) : "Unknown error"}`
490
+ );
491
+ }
492
+ const tokens = await tokenResponse.json();
493
+ this.accessToken = tokens.access_token;
494
+ this.tokenExpirationTime = Date.now() + (tokens.expires_in || 3600) * 1e3;
495
+ if (tokens.refresh_token) {
496
+ await this._saveStoredAuthData({
497
+ refreshToken: tokens.refresh_token,
498
+ accessToken: this.accessToken,
499
+ tokenExpirationTime: this.tokenExpirationTime
500
+ });
501
+ success("Login successful!");
502
+ return true;
503
+ } else {
504
+ console.error("Error: No refresh token received from Gigadrive IDP.");
505
+ return false;
506
+ }
507
+ } catch (error2) {
508
+ const errorMessage = error2 instanceof Error ? error2.message : "Unknown error";
509
+ console.error("Login process failed:", errorMessage);
510
+ this.accessToken = null;
511
+ this.tokenExpirationTime = 0;
512
+ return false;
513
+ } finally {
514
+ this.codeVerifier = null;
515
+ this.state = null;
516
+ }
517
+ }
518
+ /**
519
+ * Refreshes the access token using the stored refresh token.
520
+ * This method implicitly loads the refresh token from local storage.
521
+ * @returns {Promise<boolean>} True if refresh was successful, false otherwise.
522
+ */
523
+ async refreshAccessToken() {
524
+ const storedData = await this._loadStoredAuthData();
525
+ const OAUTH_CONFIG = await getOAuthConfig();
526
+ if (!storedData?.refreshToken) {
527
+ error("No refresh token available for refresh. Please log in.");
528
+ return false;
529
+ }
530
+ try {
531
+ const tokenResponse = await fetch(OAUTH_CONFIG.tokenUrl, {
532
+ method: "POST",
533
+ headers: {
534
+ "Content-Type": "application/x-www-form-urlencoded"
535
+ },
536
+ body: new import_node_url.URLSearchParams({
537
+ grant_type: "refresh_token",
538
+ client_id: OAUTH_CONFIG.clientId,
539
+ refresh_token: storedData.refreshToken
540
+ }).toString()
541
+ });
542
+ if (!tokenResponse.ok) {
543
+ const errorData = await tokenResponse.json().catch(() => null);
544
+ if (tokenResponse.status === 400 && errorData && (errorData.error === "oauth_token_not_found" || errorData.errors?.[0]?.code === "token_invalid" || errorData.errors?.[0]?.code === "token_expired" || errorData.errors?.[0]?.code === "token_revoked")) {
545
+ console.error("Refresh token is invalid or expired. Please log in again.");
546
+ await this.logout();
547
+ return false;
548
+ }
549
+ throw new Error(
550
+ `Token refresh failed: ${tokenResponse.status} ${tokenResponse.statusText} - ${errorData ? JSON.stringify(errorData) : "Unknown error"}`
551
+ );
552
+ }
553
+ const tokens = await tokenResponse.json();
554
+ this.accessToken = tokens.access_token;
555
+ this.tokenExpirationTime = Date.now() + (tokens.expires_in || 3600) * 1e3;
556
+ const newRefreshToken = tokens.refresh_token || storedData.refreshToken;
557
+ if (tokens.refresh_token && tokens.refresh_token !== storedData.refreshToken) {
558
+ console.debug("New refresh token received and updated.");
559
+ }
560
+ await this._saveStoredAuthData({
561
+ refreshToken: newRefreshToken,
562
+ accessToken: this.accessToken,
563
+ tokenExpirationTime: this.tokenExpirationTime
564
+ });
565
+ console.debug("Access token refreshed successfully!");
566
+ return true;
567
+ } catch (error2) {
568
+ const errorMessage = error2 instanceof Error ? error2.message : "Unknown error";
569
+ console.error("Error refreshing access token:", errorMessage);
570
+ this.accessToken = null;
571
+ this.tokenExpirationTime = 0;
572
+ return false;
573
+ }
574
+ }
575
+ /**
576
+ * Provides the current valid access token. If the in-memory token is expired,
577
+ * it attempts to refresh it using the stored refresh token.
578
+ * @returns {Promise<string | null>} The valid access token or null if no session.
579
+ */
580
+ async getAccessToken() {
581
+ if (this.accessToken && Date.now() < this.tokenExpirationTime) {
582
+ return this.accessToken;
583
+ }
584
+ console.debug("Access token expired or not available. Attempting to refresh...");
585
+ if (await this.refreshAccessToken()) {
586
+ return this.accessToken;
587
+ }
588
+ error("No valid access token available. Please log in first.");
589
+ return null;
590
+ }
591
+ /**
592
+ * Fetches the current user's information from the configured userinfo endpoint.
593
+ * Attempts a single token refresh and retry on 401/403 responses.
594
+ */
595
+ async getUserInfo() {
596
+ const OAUTH_CONFIG = await getOAuthConfig();
597
+ const currentToken = await this.getAccessToken();
598
+ if (!currentToken) {
599
+ error("Not authenticated. Please log in.");
600
+ return null;
601
+ }
602
+ const fetchUserInfo = async (token) => fetch(OAUTH_CONFIG.userinfoUrl, {
603
+ headers: {
604
+ Authorization: `Bearer ${token}`,
605
+ Accept: "application/json"
606
+ }
607
+ });
608
+ let response = await fetchUserInfo(currentToken);
609
+ if (response.status === 401 || response.status === 403) {
610
+ const refreshed = await this.refreshAccessToken();
611
+ if (!refreshed || !this.accessToken) {
612
+ return null;
613
+ }
614
+ response = await fetchUserInfo(this.accessToken);
615
+ }
616
+ if (!response.ok) {
617
+ const body = await response.text().catch(() => "");
618
+ throw new Error(
619
+ `Failed to fetch user info: ${response.status} ${response.statusText}${body ? ` - ${body}` : ""}`
620
+ );
621
+ }
622
+ const data = await response.json();
623
+ return data;
624
+ }
625
+ };
626
+ var authManager = new AuthManager();
627
+
628
+ // src/commands/login/index.ts
629
+ var login = (program) => {
630
+ program.command("login").description("Login to the platform").action(async () => {
631
+ log("Initiating login...");
632
+ const result = await authManager.login();
633
+ if (result) {
634
+ try {
635
+ const info = await authManager.getUserInfo() ?? {};
636
+ const isNonEmptyString = (value) => typeof value === "string" && value.trim() !== "";
637
+ const nameField = info.name;
638
+ const givenNameField = info.given_name;
639
+ const familyNameField = info.family_name;
640
+ const preferredUsernameField = info.preferred_username;
641
+ const emailField = info.email;
642
+ const inferredName = isNonEmptyString(nameField) && nameField || (isNonEmptyString(givenNameField) && isNonEmptyString(familyNameField) ? `${givenNameField} ${familyNameField}` : void 0) || isNonEmptyString(preferredUsernameField) && preferredUsernameField || isNonEmptyString(emailField) && emailField || "your account";
643
+ success(`You are now logged in as ${inferredName}.`);
644
+ } catch {
645
+ success("You are now logged in.");
646
+ }
647
+ } else {
648
+ error("Login failed. Please try again.");
649
+ }
650
+ });
651
+ };
652
+
234
653
  // src/commands/platform/deploy/index.ts
235
654
  var import_commons = require("@gigadrive/commons");
236
655
  var import_network_config2 = require("@gigadrive/network-config");
@@ -494,7 +913,7 @@ var uploadArchive = async (deploymentId, logs, config2) => {
494
913
  const fileChunkSize = 10 * 1024 * 1024;
495
914
  const numChunks = Math.ceil(fileSize / fileChunkSize);
496
915
  debug(`File size: ${fileSize}, chunk size: ${fileChunkSize}, number of chunks: ${numChunks}`);
497
- const promises = [];
916
+ const promises2 = [];
498
917
  let start, end;
499
918
  for (let index = 1; index < numChunks + 1; index++) {
500
919
  start = (index - 1) * fileChunkSize;
@@ -534,12 +953,12 @@ var uploadArchive = async (deploymentId, logs, config2) => {
534
953
  }
535
954
  })();
536
955
  });
537
- promises.push(promise);
956
+ promises2.push(promise);
538
957
  }
539
958
  const finishedParts = [];
540
959
  try {
541
- debug(`Waiting for all ${promises.length} upload promises to complete`);
542
- const responses = await Promise.all(promises);
960
+ debug(`Waiting for all ${promises2.length} upload promises to complete`);
961
+ const responses = await Promise.all(promises2);
543
962
  debug("All upload promises completed");
544
963
  for (let index = 0; index < responses.length; index++) {
545
964
  const res = responses[index];
@@ -686,6 +1105,23 @@ var platform = (program) => {
686
1105
  deploy(platform2);
687
1106
  };
688
1107
 
1108
+ // src/commands/whoami/index.ts
1109
+ var whoami = (program) => {
1110
+ program.command("whoami").description("Show the currently authenticated user information").action(async () => {
1111
+ try {
1112
+ const info = await authManager.getUserInfo();
1113
+ if (!info) {
1114
+ console.log('You are not logged in. Run "gigadrive login" to authenticate.');
1115
+ return;
1116
+ }
1117
+ console.log(JSON.stringify(info, null, 2));
1118
+ } catch (err) {
1119
+ const msg = err instanceof Error ? err.message : String(err);
1120
+ console.error(`Failed to retrieve user info: ${msg}`);
1121
+ }
1122
+ });
1123
+ };
1124
+
689
1125
  // src/index.ts
690
1126
  var { isTTY } = process.stdout;
691
1127
  var main = async () => {
@@ -709,6 +1145,8 @@ var main = async () => {
709
1145
  platform(program);
710
1146
  debug2(program);
711
1147
  build(program);
1148
+ login(program);
1149
+ whoami(program);
712
1150
  try {
713
1151
  await program.parseAsync(process.argv);
714
1152
  } catch (err) {
@@ -743,6 +1181,6 @@ process.on("exit", () => {
743
1181
  terminal?.write("\x1B[?25h");
744
1182
  });
745
1183
  main().then((exitCode) => {
746
- process.exitCode = exitCode;
1184
+ process.exit(exitCode);
747
1185
  }).catch(handleUnexpected);
748
1186
  //# sourceMappingURL=index.cjs.map