@globio/cli 0.1.8 → 0.1.9

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.js CHANGED
@@ -6,7 +6,6 @@ import { Command } from "commander";
6
6
  // src/auth/login.ts
7
7
  import * as p from "@clack/prompts";
8
8
  import { exec } from "child_process";
9
- import chalk2 from "chalk";
10
9
 
11
10
  // src/lib/config.ts
12
11
  import chalk from "chalk";
@@ -74,6 +73,7 @@ var config = {
74
73
  pat: data.pat ?? existing?.pat ?? "",
75
74
  account_email: data.account_email ?? existing?.account_email ?? "",
76
75
  account_name: data.account_name ?? existing?.account_name ?? "",
76
+ org_name: data.org_name ?? existing?.org_name,
77
77
  active_project_id: data.active_project_id ?? existing?.active_project_id,
78
78
  active_project_name: data.active_project_name ?? existing?.active_project_name,
79
79
  project_api_key: data.project_api_key ?? existing?.project_api_key,
@@ -156,6 +156,73 @@ function getConsoleCliAuthUrl(state) {
156
156
  import { readFileSync as readFileSync2 } from "fs";
157
157
  import figlet from "figlet";
158
158
  import gradientString from "gradient-string";
159
+
160
+ // src/lib/table.ts
161
+ var ANSI_PATTERN = /\x1b\[[0-9;]*m/g;
162
+ var orange = (s) => "\x1B[38;2;244;140;6m" + s;
163
+ var gold = (s) => "\x1B[38;2;255;208;0m" + s;
164
+ var dim = (s) => "\x1B[2m" + s + "\x1B[0m";
165
+ var white = (s) => "\x1B[97m" + s;
166
+ var green = (s) => "\x1B[38;2;34;197;94m" + s;
167
+ var muted = (s) => "\x1B[38;2;85;85;85m" + s;
168
+ var inactive = (s) => "\x1B[38;2;68;68;68m" + s;
169
+ var failure = (s) => "\x1B[38;2;232;93;4m" + s;
170
+ var reset = "\x1B[0m";
171
+ function stripAnsi(value) {
172
+ return value.replace(ANSI_PATTERN, "");
173
+ }
174
+ function fitCell(value, width) {
175
+ const plain = stripAnsi(value);
176
+ if (plain.length <= width) {
177
+ return value + " ".repeat(width - plain.length);
178
+ }
179
+ const truncated = plain.slice(0, width);
180
+ return truncated;
181
+ }
182
+ function renderTable(options) {
183
+ const { columns, rows } = options;
184
+ const lines = [];
185
+ lines.push(
186
+ " \u250C" + columns.map((c) => "\u2500".repeat(c.width + 2)).join("\u252C") + "\u2510"
187
+ );
188
+ lines.push(
189
+ " \u2502" + columns.map((c) => " " + dim(c.header.padEnd(c.width)) + " \u2502").join("")
190
+ );
191
+ lines.push(
192
+ " \u251C" + columns.map((c) => "\u2500".repeat(c.width + 2)).join("\u253C") + "\u2524"
193
+ );
194
+ for (const row of rows) {
195
+ lines.push(
196
+ " \u2502" + columns.map((c, i) => {
197
+ const raw = row[i] ?? "";
198
+ const fitted = fitCell(raw, c.width);
199
+ const colored = c.color ? fitCell(c.color(stripAnsi(raw)), c.width) : fitted;
200
+ return " " + colored + " " + reset + "\u2502";
201
+ }).join("")
202
+ );
203
+ }
204
+ lines.push(
205
+ " \u2514" + columns.map((c) => "\u2500".repeat(c.width + 2)).join("\u2534") + "\u2518"
206
+ );
207
+ return lines.join("\n");
208
+ }
209
+ function header(version10, subtitle) {
210
+ const lines = [
211
+ "",
212
+ orange(" \u21D2\u21D2") + reset + " globio " + dim(version10),
213
+ dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")
214
+ ];
215
+ if (subtitle) {
216
+ lines.push(" " + subtitle);
217
+ }
218
+ lines.push("");
219
+ return lines.join("\n");
220
+ }
221
+ function footer(text4) {
222
+ return "\n" + dim(" " + text4) + "\n";
223
+ }
224
+
225
+ // src/lib/banner.ts
159
226
  var globioGradient = gradientString(
160
227
  "#e85d04",
161
228
  "#f48c06",
@@ -163,23 +230,20 @@ var globioGradient = gradientString(
163
230
  "#ffba08",
164
231
  "#ffd000"
165
232
  );
166
- function printBanner(version5) {
233
+ function printBanner(version10) {
167
234
  const art = figlet.textSync("Globio", {
168
235
  font: "ANSI Shadow",
169
236
  horizontalLayout: "default"
170
237
  });
171
238
  console.log(globioGradient.multiline(art));
172
239
  console.log(
173
- globioGradient(" \u21D2\u21D2") + " Game Backend as a Service \x1B[2mv" + version5 + "\x1B[0m"
240
+ globioGradient(" \u21D2\u21D2") + " Game Backend as a Service \x1B[2mv" + version10 + "\x1B[0m"
174
241
  );
175
242
  console.log("");
176
243
  }
177
244
  function printSuccess(message) {
178
245
  console.log("\x1B[38;2;250;163;7m\u2713\x1B[0m " + message);
179
246
  }
180
- var orange = (s) => "\x1B[38;2;244;140;6m" + s + "\x1B[0m";
181
- var gold = (s) => "\x1B[38;2;255;208;0m" + s + "\x1B[0m";
182
- var muted = (s) => "\x1B[2m" + s + "\x1B[0m";
183
247
  function getCliVersion() {
184
248
  const file = readFileSync2(new URL("../package.json", import.meta.url), "utf8");
185
249
  return JSON.parse(file).version;
@@ -207,7 +271,7 @@ function warnOnDuplicateAccount(accountEmail, targetProfileName) {
207
271
  if (!duplicate) return;
208
272
  console.log("");
209
273
  console.log(
210
- chalk2.yellow(" \u26A0 ") + chalk2.white(accountEmail) + chalk2.gray(" is already logged in under profile ") + orange(`"${duplicate}"`) + chalk2.gray(".")
274
+ failure(" \u26A0 ") + white(accountEmail) + "\x1B[2m is already logged in under profile \x1B[0m" + orange(`"${duplicate}"`) + "\x1B[2m.\x1B[0m"
211
275
  );
212
276
  console.log("");
213
277
  }
@@ -245,7 +309,7 @@ async function runTokenLogin(profileName) {
245
309
  Profile: ${profileName}`);
246
310
  } catch (error) {
247
311
  spinner2.stop("Validation failed.");
248
- p.outro(chalk2.red(error instanceof Error ? error.message : "Could not validate token"));
312
+ p.outro(failure(error instanceof Error ? error.message : "Could not validate token") + "\x1B[0m");
249
313
  process.exit(1);
250
314
  }
251
315
  }
@@ -270,7 +334,7 @@ async function runBrowserLogin(profileName) {
270
334
  );
271
335
  if (status.status === "expired") {
272
336
  spinner2.stop("Approval window expired.");
273
- p.outro(chalk2.red("CLI auth request expired. Try again or use globio login --token."));
337
+ p.outro(failure("CLI auth request expired. Try again or use globio login --token.") + "\x1B[0m");
274
338
  process.exit(1);
275
339
  }
276
340
  if (status.status === "approved" && status.code) {
@@ -298,7 +362,7 @@ Profile: ${profileName}`);
298
362
  await sleep(2e3);
299
363
  }
300
364
  spinner2.stop("Approval timed out.");
301
- p.outro(chalk2.red("Timed out waiting for browser approval. Try again or use globio login --token."));
365
+ p.outro(failure("Timed out waiting for browser approval. Try again or use globio login --token.") + "\x1B[0m");
302
366
  process.exit(1);
303
367
  }
304
368
  async function login(options = {}) {
@@ -337,19 +401,18 @@ async function login(options = {}) {
337
401
  try {
338
402
  await runBrowserLogin(profileName);
339
403
  } catch (error) {
340
- p.outro(chalk2.red(error instanceof Error ? error.message : "Could not connect to Globio."));
404
+ p.outro(failure(error instanceof Error ? error.message : "Could not connect to Globio.") + "\x1B[0m");
341
405
  process.exit(1);
342
406
  }
343
407
  }
344
408
 
345
409
  // src/auth/logout.ts
346
- import chalk3 from "chalk";
347
410
  async function logout(options = {}) {
348
411
  const activeProfile = config.getActiveProfile();
349
412
  const profileName = options.profile ?? activeProfile;
350
413
  const profile = profileName ? config.getProfile(profileName) : null;
351
414
  if (!profileName || !profile) {
352
- console.log(chalk3.yellow(`No active session on profile "${profileName || "default"}".`));
415
+ console.log(inactive(`No active session on profile "${profileName || "default"}".`));
353
416
  return;
354
417
  }
355
418
  config.deleteProfile(profileName);
@@ -357,23 +420,23 @@ async function logout(options = {}) {
357
420
  const remaining = config.listProfiles();
358
421
  if (remaining.length > 0) {
359
422
  config.setActiveProfile(remaining[0]);
360
- console.log(chalk3.green(`Logged out. Switched to profile: ${remaining[0]}`));
423
+ console.log(green(`Logged out. Switched to profile: ${remaining[0]}`));
361
424
  return;
362
425
  }
363
426
  config.setActiveProfile("");
364
- console.log(chalk3.green("Logged out."));
427
+ console.log(green("Logged out."));
365
428
  return;
366
429
  }
367
- console.log(chalk3.green(`Logged out profile: ${profileName}`));
430
+ console.log(green(`Logged out profile: ${profileName}`));
368
431
  }
369
432
 
370
433
  // src/auth/useProfile.ts
371
- import chalk4 from "chalk";
434
+ import chalk2 from "chalk";
372
435
  async function useProfile(profileName) {
373
436
  const profile = config.getProfile(profileName);
374
437
  if (!profile) {
375
438
  console.log(
376
- chalk4.red(
439
+ chalk2.red(
377
440
  `Profile "${profileName}" not found. Run: globio login --profile ${profileName}`
378
441
  )
379
442
  );
@@ -381,36 +444,51 @@ async function useProfile(profileName) {
381
444
  }
382
445
  config.setActiveProfile(profileName);
383
446
  console.log(
384
- chalk4.green("Switched to profile: ") + orange(profileName) + ` (${profile.account_email})`
447
+ chalk2.green("Switched to profile: ") + orange(profileName) + ` (${profile.account_email})`
385
448
  );
386
449
  }
387
450
 
388
451
  // src/auth/whoami.ts
389
- import chalk5 from "chalk";
452
+ var version2 = getCliVersion();
390
453
  async function whoami(options = {}) {
391
454
  const profileName = options.profile ?? config.getActiveProfile() ?? "default";
392
455
  const profile = config.getProfile(profileName);
393
456
  if (!profile) {
394
- console.log(chalk5.red("Not logged in. Run: globio login"));
457
+ console.log(
458
+ header(version2) + " " + failure("Not logged in.") + reset + " Run: globio login\n"
459
+ );
395
460
  return;
396
461
  }
397
462
  const allProfiles = config.listProfiles();
398
- const activeProfile = config.getActiveProfile();
399
- console.log("");
463
+ const active = config.getActiveProfile();
464
+ const otherProfiles = allProfiles.filter((p6) => p6 !== profileName).join(", ") || "\u2014";
400
465
  console.log(
401
- muted("Profile: ") + orange(profileName) + (profileName === activeProfile ? muted(" (active)") : "")
466
+ header(
467
+ version2,
468
+ "Logged in as " + orange(profile.account_name || profile.account_email) + reset + " \xB7 " + muted(profile.account_email)
469
+ )
402
470
  );
403
- console.log(muted("Account: ") + profile.account_email);
404
- console.log(muted("Name: ") + (profile.account_name || "\u2014"));
405
471
  console.log(
406
- muted("Project: ") + (profile.active_project_id ? orange(profile.active_project_name || "unnamed") + muted(` (${profile.active_project_id})`) : chalk5.gray("none \u2014 run: globio projects use <id>"))
472
+ renderTable({
473
+ columns: [
474
+ { header: "Profile", width: 16 },
475
+ { header: "Value", width: 44 }
476
+ ],
477
+ rows: [
478
+ [
479
+ "Profile",
480
+ profileName === active ? orange(profileName) + reset + " " + inactive("(active)") : inactive(profileName)
481
+ ],
482
+ ["Other profiles", inactive(otherProfiles)],
483
+ ["Account", white(profile.account_name || "\u2014")],
484
+ ["Organization", white(profile.org_name || "\u2014")],
485
+ [
486
+ "Active project",
487
+ profile.active_project_id ? gold(profile.active_project_name || "unnamed") + reset + " " + inactive(profile.active_project_id) : inactive("none \u2014 run: globio projects use <id>")
488
+ ]
489
+ ]
490
+ })
407
491
  );
408
- if (allProfiles.length > 1) {
409
- console.log("");
410
- console.log(
411
- muted("Other profiles: ") + allProfiles.filter((name) => name !== profileName).join(", ")
412
- );
413
- }
414
492
  console.log("");
415
493
  }
416
494
 
@@ -443,7 +521,6 @@ async function promptInit() {
443
521
 
444
522
  // src/commands/migrate.ts
445
523
  import * as p3 from "@clack/prompts";
446
- import chalk7 from "chalk";
447
524
  import { basename } from "path";
448
525
 
449
526
  // src/lib/api.ts
@@ -509,12 +586,12 @@ async function initFirebase(serviceAccountPath) {
509
586
  }
510
587
 
511
588
  // src/lib/progress.ts
512
- import chalk6 from "chalk";
589
+ import chalk3 from "chalk";
513
590
  import cliProgress from "cli-progress";
514
591
  function createProgressBar(label) {
515
592
  const bar = new cliProgress.SingleBar(
516
593
  {
517
- format: chalk6.cyan(label) + " [{bar}] {percentage}% | {value}/{total}",
594
+ format: chalk3.cyan(label) + " [{bar}] {percentage}% | {value}/{total}",
518
595
  barCompleteChar: "\u2588",
519
596
  barIncompleteChar: "\u2591",
520
597
  hideCursor: true
@@ -525,12 +602,12 @@ function createProgressBar(label) {
525
602
  }
526
603
 
527
604
  // src/commands/migrate.ts
528
- var version2 = getCliVersion();
605
+ var version3 = getCliVersion();
529
606
  function resolveProfileName(profile) {
530
607
  return profile ?? config.getActiveProfile() ?? "default";
531
608
  }
532
609
  async function migrateFirestore(options) {
533
- printBanner(version2);
610
+ printBanner(version3);
534
611
  p3.intro(gold("\u21D2\u21D2") + " Firebase \u2192 Globio Migration");
535
612
  const { firestore } = await initFirebase(options.from);
536
613
  const profileName = resolveProfileName(options.profile);
@@ -539,14 +616,14 @@ async function migrateFirestore(options) {
539
616
  const snapshot = await firestore.listCollections();
540
617
  collections = snapshot.map((collection) => collection.id);
541
618
  console.log(
542
- chalk7.cyan(
619
+ green(
543
620
  `Found ${collections.length} collections: ${collections.join(", ")}`
544
621
  )
545
622
  );
546
623
  } else if (options.collection) {
547
624
  collections = [options.collection];
548
625
  } else {
549
- console.log(chalk7.red("Specify --collection <name> or --all"));
626
+ console.log(failure("Specify --collection <name> or --all"));
550
627
  process.exit(1);
551
628
  }
552
629
  const results = {};
@@ -598,17 +675,17 @@ async function migrateFirestore(options) {
598
675
  }
599
676
  bar.stop();
600
677
  console.log(
601
- chalk7.green(` \u2713 ${results[collectionId].success} documents migrated`)
678
+ green(` \u2713 ${results[collectionId].success} documents migrated`)
602
679
  );
603
680
  if (indexFieldCount > 0) {
604
681
  console.log(
605
- chalk7.gray(` Indexes created for ${indexFieldCount} fields`)
682
+ muted(` Indexes created for ${indexFieldCount} fields`)
606
683
  );
607
684
  }
608
685
  if (results[collectionId].failed > 0) {
609
- console.log(chalk7.red(` \u2717 ${results[collectionId].failed} failed`));
686
+ console.log(failure(` \u2717 ${results[collectionId].failed} failed`) + "\x1B[0m");
610
687
  console.log(
611
- chalk7.gray(
688
+ muted(
612
689
  " Failed IDs: " + results[collectionId].failedIds.slice(0, 10).join(", ") + (results[collectionId].failedIds.length > 10 ? "..." : "")
613
690
  )
614
691
  );
@@ -620,7 +697,7 @@ async function migrateFirestore(options) {
620
697
  );
621
698
  }
622
699
  async function migrateFirebaseStorage(options) {
623
- printBanner(version2);
700
+ printBanner(version3);
624
701
  p3.intro(gold("\u21D2\u21D2") + " Firebase \u2192 Globio Migration");
625
702
  const { storage } = await initFirebase(options.from);
626
703
  const profileName = resolveProfileName(options.profile);
@@ -632,7 +709,7 @@ async function migrateFirebaseStorage(options) {
632
709
  const bucket = storage.bucket(bucketName);
633
710
  const prefix = options.folder ? options.folder.replace(/^\//, "") : "";
634
711
  const [files] = await bucket.getFiles(prefix ? { prefix } : {});
635
- console.log(chalk7.cyan(`Found ${files.length} files to migrate`));
712
+ console.log(green(`Found ${files.length} files to migrate`));
636
713
  const bar = createProgressBar("Storage");
637
714
  bar.start(files.length, 0);
638
715
  let success = 0;
@@ -669,9 +746,9 @@ async function migrateFirebaseStorage(options) {
669
746
  }
670
747
  bar.stop();
671
748
  console.log("");
672
- console.log(chalk7.green(` \u2713 ${success} files migrated`));
749
+ console.log(green(` \u2713 ${success} files migrated`));
673
750
  if (failed > 0) {
674
- console.log(chalk7.red(` \u2717 ${failed} failed`));
751
+ console.log(failure(` \u2717 ${failed} failed`) + "\x1B[0m");
675
752
  }
676
753
  p3.outro(
677
754
  orange("\u2713") + " Migration complete.\n\n " + muted("Your Firebase data is intact.") + "\n " + muted("Delete it manually when ready.")
@@ -680,7 +757,7 @@ async function migrateFirebaseStorage(options) {
680
757
 
681
758
  // src/commands/projects.ts
682
759
  import * as p4 from "@clack/prompts";
683
- import chalk8 from "chalk";
760
+ var version4 = getCliVersion();
684
761
  function slugify(value) {
685
762
  return value.toLowerCase().trim().replace(/[^a-z0-9\\s-]/g, "").replace(/\\s+/g, "-").replace(/-+/g, "-");
686
763
  }
@@ -706,27 +783,31 @@ async function projectsList(options = {}) {
706
783
  config.requireAuth(profileName);
707
784
  const projects2 = await manageRequest("/projects", { profileName });
708
785
  const activeProjectId = config.getProfile(profileName)?.active_project_id;
709
- const grouped = /* @__PURE__ */ new Map();
710
- for (const project of projects2) {
711
- const list = grouped.get(project.org_name) ?? [];
712
- list.push(project);
713
- grouped.set(project.org_name, list);
714
- }
715
- console.log("");
716
786
  if (!projects2.length) {
717
- console.log(chalk8.gray("No projects found."));
718
- console.log("");
787
+ console.log(header(version4) + " " + muted("No projects found.") + "\n");
719
788
  return;
720
789
  }
721
- for (const [orgName, orgProjects] of grouped.entries()) {
722
- console.log(chalk8.cyan(`org: ${orgName}`));
723
- for (const project of orgProjects) {
724
- const marker = project.id === activeProjectId ? chalk8.green("\u25CF") : chalk8.gray("\u25CB");
725
- const active = project.id === activeProjectId ? chalk8.green(" (active)") : "";
726
- console.log(` ${marker} ${project.slug.padEnd(22)} ${chalk8.gray(project.id)}${active}`);
727
- }
728
- console.log("");
729
- }
790
+ const rows = projects2.map((project) => [
791
+ activeProjectId === project.id ? gold(project.name) + reset + " " + orange("\u25CF") + reset : white(project.name),
792
+ muted(project.id),
793
+ muted(project.org_name || project.org_id),
794
+ inactive(project.environment?.slice(0, 4) ?? "dev")
795
+ ]);
796
+ console.log(header(version4));
797
+ console.log(
798
+ renderTable({
799
+ columns: [
800
+ { header: "Project", width: 24 },
801
+ { header: "ID", width: 26 },
802
+ { header: "Org", width: 16 },
803
+ { header: "Env", width: 6 }
804
+ ],
805
+ rows
806
+ })
807
+ );
808
+ console.log(
809
+ footer("\u25CF active project \xB7 run globio projects use <id> to switch")
810
+ );
730
811
  }
731
812
  async function projectsUse(projectId, options = {}) {
732
813
  const profileName = resolveProfileName2(options.profile);
@@ -734,7 +815,7 @@ async function projectsUse(projectId, options = {}) {
734
815
  const projects2 = await manageRequest("/projects", { profileName });
735
816
  const project = projects2.find((item) => item.id === projectId);
736
817
  if (!project) {
737
- console.log(chalk8.red(`Project not found: ${projectId}`));
818
+ console.log(failure(`Project not found: ${projectId}`));
738
819
  process.exit(1);
739
820
  }
740
821
  await manageRequest(`/projects/${projectId}/keys`, { profileName });
@@ -742,19 +823,18 @@ async function projectsUse(projectId, options = {}) {
742
823
  config.setProfile(profileName, {
743
824
  active_project_id: project.id,
744
825
  active_project_name: project.name,
826
+ org_name: project.org_name,
745
827
  project_api_key: apiKey
746
828
  });
747
829
  config.setActiveProfile(profileName);
748
- console.log(
749
- chalk8.green("Active project set to: ") + chalk8.cyan(`${project.name} (${project.id})`)
750
- );
830
+ console.log(green("Active project: ") + `${project.name} (${project.id})`);
751
831
  }
752
832
  async function projectsCreate(options = {}) {
753
833
  const profileName = resolveProfileName2(options.profile);
754
834
  config.requireAuth(profileName);
755
835
  const orgs = await manageRequest("/orgs", { profileName });
756
836
  if (!orgs.length) {
757
- console.log(chalk8.red("No organizations found. Create one in the console first."));
837
+ console.log(failure("No organizations found. Create one in the console first."));
758
838
  process.exit(1);
759
839
  }
760
840
  const orgId = await p4.select({
@@ -809,26 +889,27 @@ async function projectsCreate(options = {}) {
809
889
  config.setProfile(profileName, {
810
890
  active_project_id: result.project.id,
811
891
  active_project_name: result.project.name,
892
+ org_name: orgs.find((org) => org.id === orgId)?.name,
812
893
  project_api_key: result.keys.server
813
894
  });
814
895
  config.setActiveProfile(profileName);
815
896
  console.log("");
816
- console.log(chalk8.green("Project created successfully."));
817
- console.log(chalk8.cyan("Project: ") + `${result.project.name} (${result.project.id})`);
818
- console.log(chalk8.cyan("Client key: ") + result.keys.client);
819
- console.log(chalk8.cyan("Server key: ") + result.keys.server);
897
+ console.log(green("Project created successfully."));
898
+ console.log(orange("Project: ") + reset + `${result.project.name} (${result.project.id})`);
899
+ console.log(orange("Client key: ") + reset + result.keys.client);
900
+ console.log(orange("Server key: ") + reset + result.keys.server);
820
901
  console.log("");
821
902
  }
822
903
 
823
904
  // src/commands/init.ts
824
- var version3 = getCliVersion();
905
+ var version5 = getCliVersion();
825
906
  async function init(options = {}) {
826
- printBanner(version3);
907
+ printBanner(version5);
827
908
  p5.intro(orange("\u21D2\u21D2") + " Initialize your Globio project");
828
909
  const profileName = options.profile ?? config.getActiveProfile() ?? "default";
829
910
  const profile = config.getProfile(profileName);
830
911
  if (!profile) {
831
- console.log("Run: npx @globio/cli login --profile " + profileName);
912
+ console.log(failure("Run: npx @globio/cli login --profile " + profileName));
832
913
  process.exit(1);
833
914
  }
834
915
  if (!profile.active_project_id) {
@@ -841,7 +922,7 @@ async function init(options = {}) {
841
922
  const activeProjectKey = activeProfile?.project_api_key;
842
923
  const { projectId: activeProjectId } = config.requireProject(profileName);
843
924
  if (!activeProjectKey) {
844
- console.log("No project API key cached. Run: npx @globio/cli projects use " + activeProjectId);
925
+ console.log(failure("No project API key cached. Run: npx @globio/cli projects use " + activeProjectId));
845
926
  process.exit(1);
846
927
  }
847
928
  if (!existsSync2("globio.config.ts")) {
@@ -891,58 +972,90 @@ export const globio = new Globio({
891
972
  }
892
973
 
893
974
  // src/commands/profiles.ts
894
- import chalk9 from "chalk";
975
+ var version6 = getCliVersion();
895
976
  async function profilesList() {
896
977
  const profiles2 = config.listProfiles();
897
978
  const active = config.getActiveProfile();
898
979
  if (!profiles2.length) {
899
- console.log(chalk9.gray("No profiles found. Run: globio login"));
980
+ console.log(
981
+ header(version6) + " " + muted("No profiles. Run: globio login") + "\n"
982
+ );
900
983
  return;
901
984
  }
902
- console.log("");
903
- for (const name of profiles2) {
904
- const data = config.getProfile(name);
985
+ const rows = profiles2.map((name) => {
986
+ const p6 = config.getProfile(name);
905
987
  const isActive = name === active;
906
- const bullet = isActive ? orange("\u25CF") : chalk9.gray("\u25CB");
907
- const label = isActive ? orange(name) : chalk9.white(name);
908
- const email = data?.account_email ? muted(data.account_email) : chalk9.gray("unknown");
909
- const tag = isActive ? muted(" (active)") : "";
910
- console.log(` ${bullet} ${label} ${email}${tag}`);
911
- }
988
+ return [
989
+ isActive ? orange(name) : inactive(name),
990
+ p6?.account_email ? isActive ? white(p6.account_email) : muted(p6.account_email) : inactive("\u2014"),
991
+ isActive ? green("active") : inactive("\u2014")
992
+ ];
993
+ });
994
+ console.log(header(version6));
995
+ console.log(
996
+ renderTable({
997
+ columns: [
998
+ { header: "Profile", width: 16 },
999
+ { header: "Account", width: 36 },
1000
+ { header: "Status", width: 10 }
1001
+ ],
1002
+ rows
1003
+ })
1004
+ );
912
1005
  console.log("");
913
1006
  }
914
1007
 
915
1008
  // src/commands/services.ts
916
- import chalk10 from "chalk";
917
- var ALL_SERVICES = [
918
- "id",
919
- "doc",
920
- "vault",
921
- "pulse",
922
- "scope",
923
- "sync",
924
- "signal",
925
- "mart",
926
- "brain",
927
- "code"
928
- ];
1009
+ var version7 = getCliVersion();
1010
+ var SERVICE_DESCRIPTIONS = {
1011
+ id: "Authentication and user management",
1012
+ doc: "Document database",
1013
+ vault: "File storage",
1014
+ pulse: "Feature flags and remote config",
1015
+ scope: "Analytics and event tracking",
1016
+ sync: "Real-time multiplayer rooms",
1017
+ signal: "Push notifications",
1018
+ mart: "Game economy and payments",
1019
+ brain: "AI agents and LLM routing",
1020
+ code: "Edge functions and GC Hooks"
1021
+ };
929
1022
  async function servicesList(options = {}) {
930
- void options.profile;
931
- void config;
932
- console.log("");
933
- console.log(chalk10.cyan("Available Globio services:"));
934
- ALL_SERVICES.forEach((service) => {
935
- console.log(" " + chalk10.white(service));
1023
+ const profileName = options.profile ?? config.getActiveProfile() ?? "default";
1024
+ const profile = config.getProfile(profileName);
1025
+ let serviceStatuses = {};
1026
+ if (profile?.active_project_id) {
1027
+ try {
1028
+ serviceStatuses = await manageRequest(
1029
+ `/projects/${profile.active_project_id}/services`,
1030
+ { profileName }
1031
+ );
1032
+ } catch {
1033
+ serviceStatuses = {};
1034
+ }
1035
+ }
1036
+ const rows = Object.entries(SERVICE_DESCRIPTIONS).map(([slug, desc]) => {
1037
+ const enabled = serviceStatuses[slug] ?? null;
1038
+ return [
1039
+ orange(slug),
1040
+ muted(desc),
1041
+ enabled === true ? green("enabled") : enabled === false ? inactive("disabled") : inactive("\u2014")
1042
+ ];
936
1043
  });
937
- console.log("");
1044
+ console.log(header(version7));
938
1045
  console.log(
939
- chalk10.gray("Manage service access via console.globio.stanlink.online")
1046
+ renderTable({
1047
+ columns: [
1048
+ { header: "Service", width: 10 },
1049
+ { header: "Description", width: 42 },
1050
+ { header: "Status", width: 10 }
1051
+ ],
1052
+ rows
1053
+ })
940
1054
  );
941
- console.log("");
1055
+ console.log(footer("Manage services at console.globio.stanlink.online"));
942
1056
  }
943
1057
 
944
1058
  // src/commands/functions.ts
945
- import chalk11 from "chalk";
946
1059
  import ora from "ora";
947
1060
  import { existsSync as existsSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
948
1061
 
@@ -958,34 +1071,42 @@ function getClient(profileName) {
958
1071
  }
959
1072
 
960
1073
  // src/commands/functions.ts
1074
+ var version8 = getCliVersion();
961
1075
  function resolveProfileName3(profile) {
962
1076
  return profile ?? config.getActiveProfile() ?? "default";
963
1077
  }
964
1078
  async function functionsList(options = {}) {
965
1079
  const profileName = resolveProfileName3(options.profile);
966
1080
  const client = getClient(profileName);
967
- const spinner2 = ora("Fetching functions...").start();
968
1081
  const result = await client.code.listFunctions();
969
- spinner2.stop();
970
1082
  if (!result.success || !result.data.length) {
971
- console.log(chalk11.gray("No functions found."));
1083
+ console.log(header(version8) + " " + muted("No functions found.") + "\n");
972
1084
  return;
973
1085
  }
974
- console.log("");
975
- result.data.forEach((fn) => {
976
- const status = fn.active ? "\x1B[32m\u25CF\x1B[0m" : "\x1B[2m\u25CB\x1B[0m";
977
- const type = fn.type === "hook" ? gold("[hook]") : orange("[function]");
978
- console.log(" " + status + " " + type + " " + fn.slug);
979
- if (fn.type === "hook" && fn.trigger_event) {
980
- console.log(muted(" trigger: " + fn.trigger_event));
981
- }
982
- });
1086
+ const rows = result.data.map((fn) => [
1087
+ fn.type === "hook" ? gold(fn.slug) : orange(fn.slug),
1088
+ fn.type === "hook" ? gold("hook") : orange("function"),
1089
+ fn.type === "hook" && fn.trigger_event ? gold(fn.trigger_event) : muted("http"),
1090
+ fn.active ? green("active") : inactive("inactive")
1091
+ ]);
1092
+ console.log(header(version8));
1093
+ console.log(
1094
+ renderTable({
1095
+ columns: [
1096
+ { header: "Function", width: 24 },
1097
+ { header: "Type", width: 10 },
1098
+ { header: "Trigger", width: 20 },
1099
+ { header: "Status", width: 10 }
1100
+ ],
1101
+ rows
1102
+ })
1103
+ );
983
1104
  console.log("");
984
1105
  }
985
1106
  async function functionsCreate(slug, _options = {}) {
986
1107
  const filename = `${slug}.js`;
987
1108
  if (existsSync3(filename)) {
988
- console.log(chalk11.yellow(`${filename} already exists.`));
1109
+ console.log(inactive(`${filename} already exists.`));
989
1110
  return;
990
1111
  }
991
1112
  const template = `/**
@@ -1004,16 +1125,14 @@ async function handler(input, globio) {
1004
1125
  }
1005
1126
  `;
1006
1127
  writeFileSync3(filename, template);
1007
- console.log(chalk11.green(`Created ${filename}`));
1008
- console.log(
1009
- chalk11.gray(`Deploy with: npx @globio/cli functions deploy ${slug}`)
1010
- );
1128
+ console.log(green(`Created ${filename}`));
1129
+ console.log(muted(`Deploy with: npx @globio/cli functions deploy ${slug}`));
1011
1130
  }
1012
1131
  async function functionsDeploy(slug, options) {
1013
1132
  const filename = options.file ?? `${slug}.js`;
1014
1133
  if (!existsSync3(filename)) {
1015
1134
  console.log(
1016
- chalk11.red(
1135
+ failure(
1017
1136
  `File not found: ${filename}. Create it with: npx @globio/cli functions create ${slug}`
1018
1137
  )
1019
1138
  );
@@ -1051,7 +1170,7 @@ async function functionsInvoke(slug, options) {
1051
1170
  try {
1052
1171
  input = JSON.parse(options.input);
1053
1172
  } catch {
1054
- console.error(chalk11.red("--input must be valid JSON"));
1173
+ console.error(failure("--input must be valid JSON"));
1055
1174
  process.exit(1);
1056
1175
  }
1057
1176
  }
@@ -1061,7 +1180,7 @@ async function functionsInvoke(slug, options) {
1061
1180
  const result = await client.code.invoke(slug, input);
1062
1181
  spinner2.stop();
1063
1182
  if (!result.success) {
1064
- console.log(chalk11.red("Invocation failed"));
1183
+ console.log(failure("Invocation failed"));
1065
1184
  console.error(result.error.message);
1066
1185
  return;
1067
1186
  }
@@ -1075,21 +1194,32 @@ async function functionsLogs(slug, options) {
1075
1194
  const limit = options.limit ? parseInt(options.limit, 10) : 20;
1076
1195
  const profileName = resolveProfileName3(options.profile);
1077
1196
  const client = getClient(profileName);
1078
- const spinner2 = ora("Fetching invocations...").start();
1079
1197
  const result = await client.code.getInvocations(slug, limit);
1080
- spinner2.stop();
1081
1198
  if (!result.success || !result.data.length) {
1082
- console.log(chalk11.gray("No invocations yet."));
1199
+ console.log(header(version8) + " " + muted("No invocations yet.") + "\n");
1083
1200
  return;
1084
1201
  }
1085
- console.log("");
1086
- result.data.forEach((inv) => {
1087
- const status = inv.success ? "\x1B[38;2;244;140;6m\u2713\x1B[0m" : "\x1B[31m\u2717\x1B[0m";
1202
+ const rows = result.data.map((inv) => {
1088
1203
  const date = new Date(inv.invoked_at * 1e3).toISOString().replace("T", " ").slice(0, 19);
1089
- console.log(
1090
- ` ${status} ${chalk11.gray(date)} ${inv.duration_ms}ms ${chalk11.gray(`[${inv.trigger_type}]`)}`
1091
- );
1204
+ return [
1205
+ muted(date),
1206
+ muted(inv.trigger_type),
1207
+ muted(inv.duration_ms + "ms"),
1208
+ inv.success ? green("success") : failure("failed")
1209
+ ];
1092
1210
  });
1211
+ console.log(header(version8));
1212
+ console.log(
1213
+ renderTable({
1214
+ columns: [
1215
+ { header: "Time", width: 21 },
1216
+ { header: "Trigger", width: 9 },
1217
+ { header: "Duration", width: 10 },
1218
+ { header: "Status", width: 10 }
1219
+ ],
1220
+ rows
1221
+ })
1222
+ );
1093
1223
  console.log("");
1094
1224
  }
1095
1225
  async function functionsDelete(slug, options = {}) {
@@ -1120,10 +1250,10 @@ async function functionsToggle(slug, active, options = {}) {
1120
1250
  }
1121
1251
 
1122
1252
  // src/index.ts
1123
- var version4 = getCliVersion();
1253
+ var version9 = getCliVersion();
1124
1254
  var program = new Command();
1125
- program.name("globio").description("The official Globio CLI").version(version4).addHelpText("beforeAll", () => {
1126
- printBanner(version4);
1255
+ program.name("globio").description("The official Globio CLI").version(version9).addHelpText("beforeAll", () => {
1256
+ printBanner(version9);
1127
1257
  return "";
1128
1258
  }).addHelpText(
1129
1259
  "after",