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.mjs CHANGED
@@ -3,6 +3,45 @@
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
5
 
6
+ // src/util/log.ts
7
+ import { createConsola } from "consola";
8
+ var verbose = false;
9
+ var consola = createConsola({
10
+ level: verbose ? 4 : 3,
11
+ // 4 includes debug messages, 3 is the default (info and above)
12
+ formatOptions: {
13
+ colors: true
14
+ }
15
+ });
16
+ var updateConsola = () => {
17
+ consola.level = verbose ? 4 : 3;
18
+ };
19
+ var setVerbose = (value) => {
20
+ verbose = value;
21
+ updateConsola();
22
+ };
23
+ var log = (message) => {
24
+ consola.info(message);
25
+ };
26
+ var error = (message) => {
27
+ consola.error(message);
28
+ };
29
+ var success = (message) => {
30
+ consola.success(message);
31
+ };
32
+ var warn = (message) => {
33
+ consola.warn(message);
34
+ };
35
+ var debug = (message, ...optionalParams) => {
36
+ if (!verbose) {
37
+ return;
38
+ }
39
+ consola.debug("[DEBUG]", message, ...optionalParams);
40
+ };
41
+ var spinner = (message) => {
42
+ log(message);
43
+ };
44
+
6
45
  // src/commands/build/index.ts
7
46
  import { exec as exec2 } from "@gigadrive/build-utils";
8
47
  import fs2 from "fs";
@@ -17,7 +56,7 @@ import { spawn } from "child_process";
17
56
  async function exec({
18
57
  command,
19
58
  cwd = process.cwd(),
20
- env,
59
+ env: env2,
21
60
  onOutput = (data) => console.log(data),
22
61
  onError = (data) => console.error(data)
23
62
  }) {
@@ -35,7 +74,7 @@ async function exec({
35
74
  const childProcess = spawn(spawnCommand, spawnArgs, {
36
75
  cwd,
37
76
  shell: true,
38
- env
77
+ env: env2
39
78
  });
40
79
  childProcess.stdout.on("data", (data) => {
41
80
  onOutput(data.toString().trim());
@@ -101,7 +140,7 @@ var buildCommand = (pm) => {
101
140
  // src/commands/build/index.ts
102
141
  var build = (parent) => {
103
142
  parent.command("build").description("Build the current project").action(async () => {
104
- const env = {
143
+ const env2 = {
105
144
  ...process.env,
106
145
  NODE_ENV: "production",
107
146
  NEBULA: "1",
@@ -112,34 +151,34 @@ var build = (parent) => {
112
151
  const cwd = process.cwd();
113
152
  const packageJsonPath = path2.join(cwd, "package.json");
114
153
  if (!fs2.existsSync(packageJsonPath)) {
115
- console.log("No package.json found");
154
+ error("No package.json found");
116
155
  return;
117
156
  }
118
157
  const packageJson = JSON.parse(fs2.readFileSync(packageJsonPath, "utf-8"));
119
158
  const buildScript = packageJson.scripts?.build;
120
159
  if (!buildScript) {
121
- console.log("No build script found in package.json");
160
+ error("No build script found in package.json");
122
161
  return;
123
162
  }
124
163
  const packageManager = await getPackageManager({ cwd });
125
164
  if (!packageManager) {
126
- console.log("No package manager found");
165
+ error("No package manager found");
127
166
  return;
128
167
  }
129
168
  await exec2({
130
169
  command: installCommand(packageManager),
131
170
  cwd,
132
- env,
171
+ env: env2,
133
172
  onOutput: (chunk) => {
134
- console.log(chunk);
173
+ log(chunk);
135
174
  }
136
175
  });
137
176
  await exec2({
138
177
  command: buildCommand(packageManager),
139
178
  cwd,
140
- env,
179
+ env: env2,
141
180
  onOutput: (chunk) => {
142
- console.log(chunk);
181
+ log(chunk);
143
182
  }
144
183
  });
145
184
  });
@@ -148,47 +187,6 @@ var build = (parent) => {
148
187
  // src/commands/debug/config/index.ts
149
188
  import { findConfig, parseConfig } from "@gigadrive/network-config";
150
189
  import { log as log2 } from "console";
151
-
152
- // src/util/log.ts
153
- import { createConsola } from "consola";
154
- var verbose = false;
155
- var consola = createConsola({
156
- level: verbose ? 4 : 3,
157
- // 4 includes debug messages, 3 is the default (info and above)
158
- formatOptions: {
159
- colors: true
160
- }
161
- });
162
- var updateConsola = () => {
163
- consola.level = verbose ? 4 : 3;
164
- };
165
- var setVerbose = (value) => {
166
- verbose = value;
167
- updateConsola();
168
- };
169
- var log = (message) => {
170
- consola.info(message);
171
- };
172
- var error = (message) => {
173
- consola.error(message);
174
- };
175
- var success = (message) => {
176
- consola.success(message);
177
- };
178
- var warn = (message) => {
179
- consola.warn(message);
180
- };
181
- var debug = (message, ...optionalParams) => {
182
- if (!verbose) {
183
- return;
184
- }
185
- consola.debug("[DEBUG]", message, ...optionalParams);
186
- };
187
- var spinner = (message) => {
188
- log(message);
189
- };
190
-
191
- // src/commands/debug/config/index.ts
192
190
  var config = (parent) => {
193
191
  parent.command("config").description("Provide debug info about the project configuration in the current directory").action(async () => {
194
192
  const configPath = findConfig(process.cwd());
@@ -208,20 +206,441 @@ var debug2 = (program) => {
208
206
  config(debug3);
209
207
  };
210
208
 
209
+ // src/env.ts
210
+ import { createEnv } from "@t3-oss/env-core";
211
+ import { config as loadEnv } from "dotenv";
212
+ import fs3 from "fs";
213
+ import path3 from "path";
214
+ import { z } from "zod";
215
+ (() => {
216
+ const cwd = process.cwd();
217
+ const nodeEnv = process.env.NODE_ENV;
218
+ const candidates = [
219
+ nodeEnv ? `.env.${nodeEnv}.local` : null,
220
+ `.env.local`,
221
+ nodeEnv ? `.env.${nodeEnv}` : null,
222
+ `.env`
223
+ ].filter(Boolean);
224
+ for (const filename of candidates) {
225
+ const fullPath = path3.join(cwd, filename);
226
+ if (fs3.existsSync(fullPath)) {
227
+ console.debug(`Loading environment variables from ${fullPath}`);
228
+ loadEnv({ path: fullPath, override: false });
229
+ }
230
+ }
231
+ })();
232
+ var env = createEnv({
233
+ server: {
234
+ GIGADRIVE_NETWORK_OAUTH_ISSUER_URL: z.url().min(1).default("https://idp.gigadrive.de"),
235
+ GIGADRIVE_NETWORK_OAUTH_CLIENT_ID: z.string().min(1).default("todo_add_client_id")
236
+ },
237
+ runtimeEnv: process.env,
238
+ emptyStringAsUndefined: true
239
+ });
240
+
241
+ // src/config/oauth.ts
242
+ var cachedConfig = null;
243
+ async function getOAuthConfig() {
244
+ if (cachedConfig) return cachedConfig;
245
+ const issuerBase = env.GIGADRIVE_NETWORK_OAUTH_ISSUER_URL.replace(/\/$/, "");
246
+ const controller = new AbortController();
247
+ const timeout = setTimeout(() => controller.abort(), 8e3);
248
+ let discovery = null;
249
+ try {
250
+ const discoveryUrl = `${issuerBase}/.well-known/openid-configuration`;
251
+ const res = await fetch(discoveryUrl, { signal: controller.signal });
252
+ if (res.ok) {
253
+ discovery = await res.json();
254
+ } else {
255
+ discovery = null;
256
+ }
257
+ } catch {
258
+ discovery = null;
259
+ } finally {
260
+ clearTimeout(timeout);
261
+ }
262
+ if (!discovery?.authorization_endpoint || !discovery?.token_endpoint || !discovery?.userinfo_endpoint) {
263
+ throw new Error("OIDC discovery failed or returned incomplete endpoints");
264
+ }
265
+ const DEFAULT_SCOPE = "offline_access openid profile email";
266
+ cachedConfig = {
267
+ clientId: env.GIGADRIVE_NETWORK_OAUTH_CLIENT_ID,
268
+ issuer: discovery.issuer ?? issuerBase,
269
+ authorizeUrl: discovery.authorization_endpoint,
270
+ tokenUrl: discovery.token_endpoint,
271
+ scope: DEFAULT_SCOPE,
272
+ userinfoUrl: discovery.userinfo_endpoint
273
+ };
274
+ return cachedConfig;
275
+ }
276
+
277
+ // src/auth/manager.ts
278
+ import * as crypto from "crypto";
279
+ import * as fs4 from "fs";
280
+ import * as http from "http";
281
+ import * as os from "os";
282
+ import * as path4 from "path";
283
+ import { URL, URLSearchParams } from "url";
284
+ import open from "open";
285
+ function getAuthStoragePaths() {
286
+ const homeDir = os.homedir();
287
+ const authDir = path4.join(homeDir, ".gigadrive");
288
+ const authFile = path4.join(authDir, "auth.json");
289
+ return { directory: authDir, file: authFile };
290
+ }
291
+ async function ensureAuthDirectory() {
292
+ const { directory } = getAuthStoragePaths();
293
+ try {
294
+ await fs4.promises.mkdir(directory, { recursive: true, mode: 448 });
295
+ await fs4.promises.chmod(directory, 448);
296
+ } catch (error2) {
297
+ const errorMessage = error2 instanceof Error ? error2.message : "Unknown error";
298
+ throw new Error(`Failed to create auth directory: ${errorMessage}`);
299
+ }
300
+ }
301
+ function generatePKCE() {
302
+ const codeVerifier = base64URLEncode(crypto.randomBytes(64));
303
+ const challengeBytes = crypto.createHash("sha256").update(codeVerifier, "utf8").digest();
304
+ const codeChallenge = base64URLEncode(challengeBytes);
305
+ return { codeVerifier, codeChallenge };
306
+ }
307
+ function base64URLEncode(buffer) {
308
+ return buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
309
+ }
310
+ var AuthManager = class {
311
+ accessToken = null;
312
+ tokenExpirationTime = 0;
313
+ // Unix timestamp in milliseconds
314
+ codeVerifier = null;
315
+ state = null;
316
+ constructor() {
317
+ }
318
+ /**
319
+ * Retrieves the stored auth data from the local file.
320
+ * @returns {Promise<StoredAuthData | null>} The stored auth data if found, otherwise null.
321
+ * @private
322
+ */
323
+ async _loadStoredAuthData() {
324
+ try {
325
+ const { file } = getAuthStoragePaths();
326
+ const data = await fs4.promises.readFile(file, "utf8");
327
+ const authData = JSON.parse(data);
328
+ if (authData.accessToken && authData.tokenExpirationTime && Date.now() < authData.tokenExpirationTime) {
329
+ this.accessToken = authData.accessToken;
330
+ this.tokenExpirationTime = authData.tokenExpirationTime;
331
+ }
332
+ return authData;
333
+ } catch {
334
+ return null;
335
+ }
336
+ }
337
+ /**
338
+ * Stores the auth data in the local file.
339
+ * @param {StoredAuthData} authData The auth data to store.
340
+ * @private
341
+ */
342
+ async _saveStoredAuthData(authData) {
343
+ try {
344
+ await ensureAuthDirectory();
345
+ const { file } = getAuthStoragePaths();
346
+ await fs4.promises.writeFile(file, JSON.stringify(authData, null, 2), { encoding: "utf8", mode: 384 });
347
+ await fs4.promises.chmod(file, 384);
348
+ console.debug("Auth data saved to local storage.");
349
+ } catch (error2) {
350
+ const errorMessage = error2 instanceof Error ? error2.message : "Unknown error";
351
+ console.error("Error saving auth data to local storage:", errorMessage);
352
+ }
353
+ }
354
+ /**
355
+ * Deletes the stored auth data from the local file.
356
+ */
357
+ async logout() {
358
+ this.accessToken = null;
359
+ this.tokenExpirationTime = 0;
360
+ try {
361
+ const { file } = getAuthStoragePaths();
362
+ await fs4.promises.unlink(file);
363
+ log("Logged out. Auth data removed from local storage.");
364
+ } catch {
365
+ log("Logged out.");
366
+ }
367
+ }
368
+ /**
369
+ * Initiates the OAuth login flow with the IDP via a web portal.
370
+ * Opens a browser for user authentication and listens for the redirect.
371
+ * @returns {Promise<boolean>} True if login was successful, false otherwise.
372
+ */
373
+ async login() {
374
+ await this.logout();
375
+ const { codeVerifier, codeChallenge } = generatePKCE();
376
+ this.codeVerifier = codeVerifier;
377
+ this.state = crypto.randomBytes(16).toString("hex");
378
+ const OAUTH_CONFIG = await getOAuthConfig();
379
+ const loginState = this.state;
380
+ if (!loginState) {
381
+ throw new Error("Internal error: login state not initialized");
382
+ }
383
+ const server = http.createServer();
384
+ let usedRedirectUri = "";
385
+ const serverPromise = new Promise((resolve, reject) => {
386
+ const redirectPath = "/callback";
387
+ server.listen(0, "127.0.0.1", () => {
388
+ const address = server.address();
389
+ if (!address || typeof address !== "object") {
390
+ reject(new Error("Failed to determine callback server address"));
391
+ return;
392
+ }
393
+ const port = address.port;
394
+ usedRedirectUri = `http://127.0.0.1:${port}${redirectPath}`;
395
+ const authUrl = new URL(OAUTH_CONFIG.authorizeUrl);
396
+ authUrl.searchParams.append("client_id", OAUTH_CONFIG.clientId);
397
+ authUrl.searchParams.append("redirect_uri", usedRedirectUri);
398
+ authUrl.searchParams.append("response_type", "code");
399
+ authUrl.searchParams.append("scope", OAUTH_CONFIG.scope);
400
+ authUrl.searchParams.append("code_challenge", codeChallenge);
401
+ authUrl.searchParams.append("code_challenge_method", "S256");
402
+ authUrl.searchParams.append("state", loginState);
403
+ log(`Please open this URL in your browser to log in:
404
+ ${authUrl.toString()}
405
+ `);
406
+ log("Waiting for login callback...");
407
+ void open(authUrl.toString());
408
+ });
409
+ server.on("request", (req, res) => {
410
+ const base = usedRedirectUri || "http://127.0.0.1/callback";
411
+ const reqUrl = new URL(req.url || "", base);
412
+ if (reqUrl.pathname === "/callback") {
413
+ const authCode = reqUrl.searchParams.get("code");
414
+ const receivedState = reqUrl.searchParams.get("state");
415
+ const error2 = reqUrl.searchParams.get("error");
416
+ res.writeHead(200, { "Content-Type": "text/html", Connection: "close" });
417
+ if (error2) {
418
+ res.end("<h1>Login Failed!</h1><p>Error: " + error2 + "</p><p>You can close this tab.</p>");
419
+ reject(new Error(`OAuth error: ${error2}`));
420
+ server.close();
421
+ return;
422
+ }
423
+ if (receivedState !== this.state) {
424
+ res.end("<h1>Login Failed!</h1><p>State mismatch. Possible CSRF attack.</p><p>You can close this tab.</p>");
425
+ reject(new Error("State mismatch"));
426
+ server.close();
427
+ return;
428
+ }
429
+ if (authCode) {
430
+ res.end("<h1>Login Successful!</h1><p>You can close this tab.</p>");
431
+ resolve(authCode);
432
+ server.close();
433
+ } else {
434
+ res.end("<h1>Login Failed!</h1><p>No authorization code received.</p><p>You can close this tab.</p>");
435
+ reject(new Error("No authorization code received"));
436
+ server.close();
437
+ }
438
+ } else {
439
+ res.writeHead(404).end("Not Found");
440
+ }
441
+ });
442
+ server.on("error", (err) => {
443
+ console.error("Local server error:", err);
444
+ reject(err);
445
+ });
446
+ });
447
+ try {
448
+ const authCode = await serverPromise;
449
+ const tokenResponse = await fetch(OAUTH_CONFIG.tokenUrl, {
450
+ method: "POST",
451
+ headers: {
452
+ "Content-Type": "application/x-www-form-urlencoded"
453
+ },
454
+ body: new URLSearchParams({
455
+ grant_type: "authorization_code",
456
+ client_id: OAUTH_CONFIG.clientId,
457
+ code: authCode,
458
+ ...usedRedirectUri ? { redirect_uri: usedRedirectUri } : {},
459
+ code_verifier: this.codeVerifier || ""
460
+ // Use the stored codeVerifier
461
+ }).toString()
462
+ });
463
+ if (!tokenResponse.ok) {
464
+ const errorData = await tokenResponse.json().catch(() => null);
465
+ throw new Error(
466
+ `Token exchange failed: ${tokenResponse.status} ${tokenResponse.statusText} - ${errorData ? JSON.stringify(errorData) : "Unknown error"}`
467
+ );
468
+ }
469
+ const tokens = await tokenResponse.json();
470
+ this.accessToken = tokens.access_token;
471
+ this.tokenExpirationTime = Date.now() + (tokens.expires_in || 3600) * 1e3;
472
+ if (tokens.refresh_token) {
473
+ await this._saveStoredAuthData({
474
+ refreshToken: tokens.refresh_token,
475
+ accessToken: this.accessToken,
476
+ tokenExpirationTime: this.tokenExpirationTime
477
+ });
478
+ success("Login successful!");
479
+ return true;
480
+ } else {
481
+ console.error("Error: No refresh token received from Gigadrive IDP.");
482
+ return false;
483
+ }
484
+ } catch (error2) {
485
+ const errorMessage = error2 instanceof Error ? error2.message : "Unknown error";
486
+ console.error("Login process failed:", errorMessage);
487
+ this.accessToken = null;
488
+ this.tokenExpirationTime = 0;
489
+ return false;
490
+ } finally {
491
+ this.codeVerifier = null;
492
+ this.state = null;
493
+ }
494
+ }
495
+ /**
496
+ * Refreshes the access token using the stored refresh token.
497
+ * This method implicitly loads the refresh token from local storage.
498
+ * @returns {Promise<boolean>} True if refresh was successful, false otherwise.
499
+ */
500
+ async refreshAccessToken() {
501
+ const storedData = await this._loadStoredAuthData();
502
+ const OAUTH_CONFIG = await getOAuthConfig();
503
+ if (!storedData?.refreshToken) {
504
+ error("No refresh token available for refresh. Please log in.");
505
+ return false;
506
+ }
507
+ try {
508
+ const tokenResponse = await fetch(OAUTH_CONFIG.tokenUrl, {
509
+ method: "POST",
510
+ headers: {
511
+ "Content-Type": "application/x-www-form-urlencoded"
512
+ },
513
+ body: new URLSearchParams({
514
+ grant_type: "refresh_token",
515
+ client_id: OAUTH_CONFIG.clientId,
516
+ refresh_token: storedData.refreshToken
517
+ }).toString()
518
+ });
519
+ if (!tokenResponse.ok) {
520
+ const errorData = await tokenResponse.json().catch(() => null);
521
+ 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")) {
522
+ console.error("Refresh token is invalid or expired. Please log in again.");
523
+ await this.logout();
524
+ return false;
525
+ }
526
+ throw new Error(
527
+ `Token refresh failed: ${tokenResponse.status} ${tokenResponse.statusText} - ${errorData ? JSON.stringify(errorData) : "Unknown error"}`
528
+ );
529
+ }
530
+ const tokens = await tokenResponse.json();
531
+ this.accessToken = tokens.access_token;
532
+ this.tokenExpirationTime = Date.now() + (tokens.expires_in || 3600) * 1e3;
533
+ const newRefreshToken = tokens.refresh_token || storedData.refreshToken;
534
+ if (tokens.refresh_token && tokens.refresh_token !== storedData.refreshToken) {
535
+ console.debug("New refresh token received and updated.");
536
+ }
537
+ await this._saveStoredAuthData({
538
+ refreshToken: newRefreshToken,
539
+ accessToken: this.accessToken,
540
+ tokenExpirationTime: this.tokenExpirationTime
541
+ });
542
+ console.debug("Access token refreshed successfully!");
543
+ return true;
544
+ } catch (error2) {
545
+ const errorMessage = error2 instanceof Error ? error2.message : "Unknown error";
546
+ console.error("Error refreshing access token:", errorMessage);
547
+ this.accessToken = null;
548
+ this.tokenExpirationTime = 0;
549
+ return false;
550
+ }
551
+ }
552
+ /**
553
+ * Provides the current valid access token. If the in-memory token is expired,
554
+ * it attempts to refresh it using the stored refresh token.
555
+ * @returns {Promise<string | null>} The valid access token or null if no session.
556
+ */
557
+ async getAccessToken() {
558
+ if (this.accessToken && Date.now() < this.tokenExpirationTime) {
559
+ return this.accessToken;
560
+ }
561
+ console.debug("Access token expired or not available. Attempting to refresh...");
562
+ if (await this.refreshAccessToken()) {
563
+ return this.accessToken;
564
+ }
565
+ error("No valid access token available. Please log in first.");
566
+ return null;
567
+ }
568
+ /**
569
+ * Fetches the current user's information from the configured userinfo endpoint.
570
+ * Attempts a single token refresh and retry on 401/403 responses.
571
+ */
572
+ async getUserInfo() {
573
+ const OAUTH_CONFIG = await getOAuthConfig();
574
+ const currentToken = await this.getAccessToken();
575
+ if (!currentToken) {
576
+ error("Not authenticated. Please log in.");
577
+ return null;
578
+ }
579
+ const fetchUserInfo = async (token) => fetch(OAUTH_CONFIG.userinfoUrl, {
580
+ headers: {
581
+ Authorization: `Bearer ${token}`,
582
+ Accept: "application/json"
583
+ }
584
+ });
585
+ let response = await fetchUserInfo(currentToken);
586
+ if (response.status === 401 || response.status === 403) {
587
+ const refreshed = await this.refreshAccessToken();
588
+ if (!refreshed || !this.accessToken) {
589
+ return null;
590
+ }
591
+ response = await fetchUserInfo(this.accessToken);
592
+ }
593
+ if (!response.ok) {
594
+ const body = await response.text().catch(() => "");
595
+ throw new Error(
596
+ `Failed to fetch user info: ${response.status} ${response.statusText}${body ? ` - ${body}` : ""}`
597
+ );
598
+ }
599
+ const data = await response.json();
600
+ return data;
601
+ }
602
+ };
603
+ var authManager = new AuthManager();
604
+
605
+ // src/commands/login/index.ts
606
+ var login = (program) => {
607
+ program.command("login").description("Login to the platform").action(async () => {
608
+ log("Initiating login...");
609
+ const result = await authManager.login();
610
+ if (result) {
611
+ try {
612
+ const info = await authManager.getUserInfo() ?? {};
613
+ const isNonEmptyString = (value) => typeof value === "string" && value.trim() !== "";
614
+ const nameField = info.name;
615
+ const givenNameField = info.given_name;
616
+ const familyNameField = info.family_name;
617
+ const preferredUsernameField = info.preferred_username;
618
+ const emailField = info.email;
619
+ const inferredName = isNonEmptyString(nameField) && nameField || (isNonEmptyString(givenNameField) && isNonEmptyString(familyNameField) ? `${givenNameField} ${familyNameField}` : void 0) || isNonEmptyString(preferredUsernameField) && preferredUsernameField || isNonEmptyString(emailField) && emailField || "your account";
620
+ success(`You are now logged in as ${inferredName}.`);
621
+ } catch {
622
+ success("You are now logged in.");
623
+ }
624
+ } else {
625
+ error("Login failed. Please try again.");
626
+ }
627
+ });
628
+ };
629
+
211
630
  // src/commands/platform/deploy/index.ts
212
631
  import { formatFileSize, objectToQueryString } from "@gigadrive/commons";
213
632
  import { findConfig as findConfig2, parseConfig as parseConfig2 } from "@gigadrive/network-config";
214
- import fs4 from "fs";
215
- import os from "os";
216
- import path4 from "path";
633
+ import fs6 from "fs";
634
+ import os2 from "os";
635
+ import path6 from "path";
217
636
 
218
637
  // src/util/zip.ts
219
638
  import { getFilesForPattern } from "@gigadrive/build-utils";
220
639
  import archiver from "archiver";
221
- import fs3 from "fs";
640
+ import fs5 from "fs";
222
641
  import fsPromises from "fs/promises";
223
642
  import ignore from "ignore";
224
- import path3 from "path";
643
+ import path5 from "path";
225
644
  var ignoreFileNames = [
226
645
  /*'.gitignore', */
227
646
  ".gigadriveignore",
@@ -241,19 +660,19 @@ async function readIgnoreFile(ignorePath) {
241
660
  async function collectIgnorePatterns(dir, baseDir, ignoreRules) {
242
661
  const items = await fsPromises.readdir(dir);
243
662
  for (const item of items) {
244
- const fullPath = path3.join(dir, item);
245
- const relativePath = path3.relative(baseDir, fullPath);
663
+ const fullPath = path5.join(dir, item);
664
+ const relativePath = path5.relative(baseDir, fullPath);
246
665
  const stat = await fsPromises.lstat(fullPath);
247
666
  if (stat.isDirectory()) {
248
667
  if (ignoreRules.ignores(`${relativePath}/`)) {
249
668
  continue;
250
669
  }
251
670
  for (const ignoreFileName of ignoreFileNames) {
252
- const ignoreFilePath = path3.join(fullPath, ignoreFileName);
671
+ const ignoreFilePath = path5.join(fullPath, ignoreFileName);
253
672
  try {
254
673
  await fsPromises.access(ignoreFilePath);
255
674
  const patterns = (await readIgnoreFile(ignoreFilePath)).map((pattern) => {
256
- return pattern.startsWith("!") ? `!${path3.join(relativePath, pattern.slice(1))}` : path3.join(relativePath, pattern);
675
+ return pattern.startsWith("!") ? `!${path5.join(relativePath, pattern.slice(1))}` : path5.join(relativePath, pattern);
257
676
  });
258
677
  ignoreRules.add(patterns);
259
678
  } catch {
@@ -267,7 +686,7 @@ async function initializeIgnoreRules(baseDir) {
267
686
  const ignoreRules = ignore();
268
687
  ignoreRules.add([".git/", "**/.DS_Store", "**/Thumbs.db"]);
269
688
  for (const ignoreFileName of ignoreFileNames) {
270
- const ignoreFilePath = path3.join(baseDir, ignoreFileName);
689
+ const ignoreFilePath = path5.join(baseDir, ignoreFileName);
271
690
  try {
272
691
  await fsPromises.access(ignoreFilePath);
273
692
  const patterns = (await readIgnoreFile(ignoreFilePath)).map((pattern) => {
@@ -285,8 +704,8 @@ async function getFilesToInclude(dir, ignoreRules, whitelist) {
285
704
  async function walkDir(currentDir) {
286
705
  const items = await fsPromises.readdir(currentDir);
287
706
  for (const item of items) {
288
- const fullPath = path3.join(currentDir, item);
289
- const relativePath = path3.relative(dir, fullPath);
707
+ const fullPath = path5.join(currentDir, item);
708
+ const relativePath = path5.relative(dir, fullPath);
290
709
  const stat = await fsPromises.lstat(fullPath);
291
710
  if (stat.isDirectory()) {
292
711
  if (ignoreRules.ignores(`${relativePath}/`)) {
@@ -308,14 +727,14 @@ async function getFilesToInclude(dir, ignoreRules, whitelist) {
308
727
  async function createZipArchive(inputDir, outputFile, options = {}) {
309
728
  const ignoreRules = options.useIgnoreFiles !== false ? await initializeIgnoreRules(inputDir) : ignore();
310
729
  const filesToInclude = options.whitelist ? await Promise.all(options.whitelist.map((file) => getFilesForPattern(inputDir, file))) : await getFilesToInclude(inputDir, ignoreRules);
311
- const output = fs3.createWriteStream(outputFile);
730
+ const output = fs5.createWriteStream(outputFile);
312
731
  const archive = archiver("zip", { zlib: { level: 9 } });
313
732
  return new Promise((resolve, reject) => {
314
733
  output.on("close", () => resolve());
315
734
  archive.on("error", reject);
316
735
  archive.pipe(output);
317
736
  for (const file of filesToInclude.flat()) {
318
- archive.file(file, { name: path3.relative(inputDir, file) });
737
+ archive.file(file, { name: path5.relative(inputDir, file) });
319
738
  }
320
739
  void archive.finalize();
321
740
  });
@@ -447,11 +866,11 @@ var addLog = (message, type, logs) => {
447
866
  var uploadArchive = async (deploymentId, logs, config2) => {
448
867
  debug("Starting uploadArchive");
449
868
  addLog("Creating archive...", "INFO", logs);
450
- const archivePath = path4.join(process.env.TEMP || os.tmpdir(), `project-${Date.now()}.zip`);
869
+ const archivePath = path6.join(process.env.TEMP || os2.tmpdir(), `project-${Date.now()}.zip`);
451
870
  debug(`Archive path: ${archivePath}`);
452
- if (fs4.existsSync(archivePath)) {
871
+ if (fs6.existsSync(archivePath)) {
453
872
  debug(`Archive already exists, removing: ${archivePath}`);
454
- fs4.unlinkSync(archivePath);
873
+ fs6.unlinkSync(archivePath);
455
874
  }
456
875
  debug("Creating zip archive");
457
876
  await createZipArchive(config2.userArchive?.rootOverwrite || process.cwd(), archivePath, {
@@ -459,7 +878,7 @@ var uploadArchive = async (deploymentId, logs, config2) => {
459
878
  useIgnoreFiles: false,
460
879
  useManagedIgnore: false
461
880
  });
462
- const fileStats = fs4.statSync(archivePath);
881
+ const fileStats = fs6.statSync(archivePath);
463
882
  const fileSize = fileStats.size;
464
883
  debug(`Archive created, size: ${fileSize} bytes (${formatFileSize(fileSize)})`);
465
884
  addLog(`Archive created (${formatFileSize(fileSize)})`, "INFO", logs);
@@ -471,7 +890,7 @@ var uploadArchive = async (deploymentId, logs, config2) => {
471
890
  const fileChunkSize = 10 * 1024 * 1024;
472
891
  const numChunks = Math.ceil(fileSize / fileChunkSize);
473
892
  debug(`File size: ${fileSize}, chunk size: ${fileChunkSize}, number of chunks: ${numChunks}`);
474
- const promises = [];
893
+ const promises2 = [];
475
894
  let start, end;
476
895
  for (let index = 1; index < numChunks + 1; index++) {
477
896
  start = (index - 1) * fileChunkSize;
@@ -483,7 +902,7 @@ var uploadArchive = async (deploymentId, logs, config2) => {
483
902
  void (async () => {
484
903
  try {
485
904
  debug(`Reading chunk ${index} data`);
486
- const readStream = fs4.createReadStream(archivePath, {
905
+ const readStream = fs6.createReadStream(archivePath, {
487
906
  start,
488
907
  end: index < numChunks ? end - 1 : void 0
489
908
  });
@@ -511,12 +930,12 @@ var uploadArchive = async (deploymentId, logs, config2) => {
511
930
  }
512
931
  })();
513
932
  });
514
- promises.push(promise);
933
+ promises2.push(promise);
515
934
  }
516
935
  const finishedParts = [];
517
936
  try {
518
- debug(`Waiting for all ${promises.length} upload promises to complete`);
519
- const responses = await Promise.all(promises);
937
+ debug(`Waiting for all ${promises2.length} upload promises to complete`);
938
+ const responses = await Promise.all(promises2);
520
939
  debug("All upload promises completed");
521
940
  for (let index = 0; index < responses.length; index++) {
522
941
  const res = responses[index];
@@ -663,6 +1082,23 @@ var platform = (program) => {
663
1082
  deploy(platform2);
664
1083
  };
665
1084
 
1085
+ // src/commands/whoami/index.ts
1086
+ var whoami = (program) => {
1087
+ program.command("whoami").description("Show the currently authenticated user information").action(async () => {
1088
+ try {
1089
+ const info = await authManager.getUserInfo();
1090
+ if (!info) {
1091
+ console.log('You are not logged in. Run "gigadrive login" to authenticate.');
1092
+ return;
1093
+ }
1094
+ console.log(JSON.stringify(info, null, 2));
1095
+ } catch (err) {
1096
+ const msg = err instanceof Error ? err.message : String(err);
1097
+ console.error(`Failed to retrieve user info: ${msg}`);
1098
+ }
1099
+ });
1100
+ };
1101
+
666
1102
  // src/index.ts
667
1103
  var { isTTY } = process.stdout;
668
1104
  var main = async () => {
@@ -686,6 +1122,8 @@ var main = async () => {
686
1122
  platform(program);
687
1123
  debug2(program);
688
1124
  build(program);
1125
+ login(program);
1126
+ whoami(program);
689
1127
  try {
690
1128
  await program.parseAsync(process.argv);
691
1129
  } catch (err) {
@@ -720,6 +1158,6 @@ process.on("exit", () => {
720
1158
  terminal?.write("\x1B[?25h");
721
1159
  });
722
1160
  main().then((exitCode) => {
723
- process.exitCode = exitCode;
1161
+ process.exit(exitCode);
724
1162
  }).catch(handleUnexpected);
725
1163
  //# sourceMappingURL=index.mjs.map