@globio/cli 0.1.0 → 0.1.2

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.
@@ -27,7 +27,20 @@ jobs:
27
27
  - name: Build
28
28
  run: npm run build
29
29
 
30
+ - name: Read package version
31
+ id: package_version
32
+ run: |
33
+ VERSION="$(node -p "JSON.parse(require('fs').readFileSync('package.json','utf8')).version")"
34
+ echo "version=$VERSION" >> "$GITHUB_OUTPUT"
35
+
36
+ - name: Check npm version
37
+ id: npm_version
38
+ run: |
39
+ CURRENT="$(npm view @globio/cli version 2>/dev/null || true)"
40
+ echo "current=$CURRENT" >> "$GITHUB_OUTPUT"
41
+
30
42
  - name: Publish to npm
43
+ if: steps.npm_version.outputs.current != steps.package_version.outputs.version
31
44
  run: npm publish --access public
32
45
  env:
33
46
  NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -35,7 +48,12 @@ jobs:
35
48
  - name: Setup Deno for JSR
36
49
  uses: denoland/setup-deno@v1
37
50
 
51
+ - name: Check JSR version
52
+ id: jsr_version
53
+ run: |
54
+ CURRENT="$(curl -fsS https://jsr.io/api/scopes/globio/packages/cli | node -e "let data=''; process.stdin.on('data', d => data += d); process.stdin.on('end', () => { try { const json = JSON.parse(data); process.stdout.write(json.latestVersion ?? ''); } catch { process.stdout.write(''); } });" || true)"
55
+ echo "current=$CURRENT" >> "$GITHUB_OUTPUT"
56
+
38
57
  - name: Publish to JSR
39
- run: npx jsr publish --allow-dirty
40
- env:
41
- JSR_TOKEN: ${{ secrets.JSR_TOKEN }}
58
+ if: steps.jsr_version.outputs.current != steps.package_version.outputs.version
59
+ run: npx jsr publish --allow-dirty --token "${{ secrets.JSR_TOKEN }}"
package/dist/index.js CHANGED
@@ -45,11 +45,44 @@ var config = {
45
45
  }
46
46
  };
47
47
 
48
+ // src/lib/banner.ts
49
+ import { readFileSync } from "fs";
50
+ import figlet from "figlet";
51
+ import gradientString from "gradient-string";
52
+ var globioGradient = gradientString(
53
+ "#e85d04",
54
+ "#f48c06",
55
+ "#faa307",
56
+ "#ffba08",
57
+ "#ffd000"
58
+ );
59
+ function printBanner(version5) {
60
+ const art = figlet.textSync("Globio", {
61
+ font: "ANSI Shadow",
62
+ horizontalLayout: "default"
63
+ });
64
+ console.log(globioGradient.multiline(art));
65
+ console.log(
66
+ globioGradient(" \u21D2\u21D2") + " Game Backend as a Service \x1B[2mv" + version5 + "\x1B[0m"
67
+ );
68
+ console.log("");
69
+ }
70
+ function printSuccess(message) {
71
+ console.log("\x1B[38;2;250;163;7m\u2713\x1B[0m " + message);
72
+ }
73
+ var orange = (s) => "\x1B[38;2;244;140;6m" + s + "\x1B[0m";
74
+ var gold = (s) => "\x1B[38;2;255;208;0m" + s + "\x1B[0m";
75
+ var muted = (s) => "\x1B[2m" + s + "\x1B[0m";
76
+ function getCliVersion() {
77
+ const file = readFileSync(new URL("../package.json", import.meta.url), "utf8");
78
+ return JSON.parse(file).version;
79
+ }
80
+
48
81
  // src/auth/login.ts
49
82
  var DEFAULT_BASE_URL = "https://api.globio.stanlink.online";
83
+ var version = getCliVersion();
50
84
  async function login() {
51
- console.log("");
52
- p.intro(chalk2.bgCyan(chalk2.black(" Globio CLI ")));
85
+ printBanner(version);
53
86
  const values = await p.group(
54
87
  {
55
88
  apiKey: () => p.text({
@@ -89,7 +122,7 @@ async function login() {
89
122
  });
90
123
  spinner2.stop("Credentials validated.");
91
124
  p.outro(
92
- chalk2.green("Logged in. Active project: ") + chalk2.cyan(values.projectId)
125
+ " Logged in.\n\n " + muted("API Key: ") + orange(values.apiKey) + "\n " + muted("Project: ") + orange(values.projectId)
93
126
  );
94
127
  } catch {
95
128
  spinner2.stop("");
@@ -122,8 +155,7 @@ async function whoami() {
122
155
 
123
156
  // src/commands/init.ts
124
157
  import * as p5 from "@clack/prompts";
125
- import chalk7 from "chalk";
126
- import { existsSync, readFileSync, writeFileSync } from "fs";
158
+ import { existsSync, readFileSync as readFileSync2, writeFileSync } from "fs";
127
159
 
128
160
  // src/prompts/init.ts
129
161
  import * as p3 from "@clack/prompts";
@@ -166,8 +198,8 @@ import { basename } from "path";
166
198
  // src/lib/firebase.ts
167
199
  async function initFirebase(serviceAccountPath) {
168
200
  const admin = await import("firebase-admin");
169
- const { readFileSync: readFileSync3 } = await import("fs");
170
- const serviceAccount = JSON.parse(readFileSync3(serviceAccountPath, "utf-8"));
201
+ const { readFileSync: readFileSync4 } = await import("fs");
202
+ const serviceAccount = JSON.parse(readFileSync4(serviceAccountPath, "utf-8"));
171
203
  if (!admin.default.apps.length) {
172
204
  admin.default.initializeApp({
173
205
  credential: admin.default.credential.cert(serviceAccount),
@@ -206,9 +238,10 @@ function getClient() {
206
238
  }
207
239
 
208
240
  // src/commands/migrate.ts
241
+ var version2 = getCliVersion();
209
242
  async function migrateFirestore(options) {
210
- console.log("");
211
- p4.intro(chalk6.bgYellow(chalk6.black(" Globio Migration \u2014 Firestore ")));
243
+ printBanner(version2);
244
+ p4.intro(gold("\u21D2\u21D2") + " Firebase \u2192 Globio Migration");
212
245
  const { firestore } = await initFirebase(options.from);
213
246
  const client = getClient();
214
247
  let collections = [];
@@ -229,7 +262,7 @@ async function migrateFirestore(options) {
229
262
  const results = {};
230
263
  for (const collectionId of collections) {
231
264
  console.log("");
232
- console.log(chalk6.cyan(`Migrating collection: ${collectionId}`));
265
+ console.log(" " + orange(collectionId));
233
266
  const countSnap = await firestore.collection(collectionId).count().get();
234
267
  const total = countSnap.data().count;
235
268
  const bar = createProgressBar(collectionId);
@@ -280,16 +313,13 @@ async function migrateFirestore(options) {
280
313
  }
281
314
  }
282
315
  console.log("");
283
- p4.outro(chalk6.green("Firestore migration complete."));
284
- console.log(
285
- chalk6.gray(
286
- "Your Firebase data is intact. Delete it manually when ready."
287
- )
316
+ p4.outro(
317
+ orange("\u2713") + " Migration complete.\n\n " + muted("Your Firebase data is intact.") + "\n " + muted("Delete it manually when ready.")
288
318
  );
289
319
  }
290
320
  async function migrateFirebaseStorage(options) {
291
- console.log("");
292
- p4.intro(chalk6.bgYellow(chalk6.black(" Globio Migration \u2014 Storage ")));
321
+ printBanner(version2);
322
+ p4.intro(gold("\u21D2\u21D2") + " Firebase \u2192 Globio Migration");
293
323
  const { storage } = await initFirebase(options.from);
294
324
  const client = getClient();
295
325
  const bucketName = options.bucket.replace(/^gs:\/\//, "");
@@ -328,13 +358,16 @@ async function migrateFirebaseStorage(options) {
328
358
  if (failed > 0) {
329
359
  console.log(chalk6.red(` \u2717 ${failed} failed`));
330
360
  }
331
- p4.outro(chalk6.green("Storage migration complete."));
361
+ p4.outro(
362
+ orange("\u2713") + " Migration complete.\n\n " + muted("Your Firebase data is intact.") + "\n " + muted("Delete it manually when ready.")
363
+ );
332
364
  }
333
365
 
334
366
  // src/commands/init.ts
367
+ var version3 = getCliVersion();
335
368
  async function init() {
336
- console.log("");
337
- p5.intro(chalk7.bgCyan(chalk7.black(" Globio \u2014 Game Backend as a Service ")));
369
+ printBanner(version3);
370
+ p5.intro(orange("\u21D2\u21D2") + " Initialize your Globio project");
338
371
  const values = await promptInit();
339
372
  config.set({
340
373
  apiKey: values.apiKey,
@@ -350,22 +383,22 @@ export const globio = new GlobioClient({
350
383
  });
351
384
  `
352
385
  );
353
- console.log(chalk7.green("\u2713 Created globio.config.ts"));
386
+ printSuccess("Created globio.config.ts");
354
387
  }
355
388
  if (!existsSync(".env")) {
356
389
  writeFileSync(".env", `GLOBIO_API_KEY=${values.apiKey}
357
390
  `);
358
- console.log(chalk7.green("\u2713 Created .env"));
391
+ printSuccess("Created .env");
359
392
  }
360
393
  if (values.migrateFromFirebase && values.serviceAccountPath) {
361
394
  console.log("");
362
- console.log(chalk7.cyan("Starting Firebase migration..."));
395
+ printSuccess("Starting Firebase migration...");
363
396
  await migrateFirestore({
364
397
  from: values.serviceAccountPath,
365
398
  all: true
366
399
  });
367
400
  const serviceAccount = JSON.parse(
368
- readFileSync(values.serviceAccountPath, "utf-8")
401
+ readFileSync2(values.serviceAccountPath, "utf-8")
369
402
  );
370
403
  await migrateFirebaseStorage({
371
404
  from: values.serviceAccountPath,
@@ -375,27 +408,27 @@ export const globio = new GlobioClient({
375
408
  }
376
409
  console.log("");
377
410
  p5.outro(
378
- chalk7.green("Your Globio project is ready.") + "\n\n" + chalk7.white(" Next steps:\n") + chalk7.gray(" npm install @globio/sdk\n") + chalk7.gray(" npx @globio/cli functions create my-first-function\n")
411
+ orange("\u21D2\u21D2") + " Your project is ready.\n\n " + muted("Next steps:") + "\n\n npm install @globio/sdk\n npx @globio/cli functions create my-first-function"
379
412
  );
380
413
  }
381
414
 
382
415
  // src/commands/projects.ts
383
- import chalk8 from "chalk";
416
+ import chalk7 from "chalk";
384
417
  async function projectsList() {
385
418
  const cfg = config.get();
386
419
  console.log("");
387
420
  console.log(
388
- chalk8.cyan("Active project: ") + (cfg.projectId ?? chalk8.gray("none"))
421
+ chalk7.cyan("Active project: ") + (cfg.projectId ?? chalk7.gray("none"))
389
422
  );
390
423
  console.log("");
391
424
  }
392
425
  async function projectsUse(projectId) {
393
426
  config.set({ projectId });
394
- console.log(chalk8.green("Active project set to: ") + chalk8.cyan(projectId));
427
+ console.log(chalk7.green("Active project set to: ") + chalk7.cyan(projectId));
395
428
  }
396
429
 
397
430
  // src/commands/services.ts
398
- import chalk9 from "chalk";
431
+ import chalk8 from "chalk";
399
432
  var ALL_SERVICES = [
400
433
  "id",
401
434
  "doc",
@@ -410,37 +443,37 @@ var ALL_SERVICES = [
410
443
  ];
411
444
  async function servicesList() {
412
445
  console.log("");
413
- console.log(chalk9.cyan("Available Globio services:"));
446
+ console.log(chalk8.cyan("Available Globio services:"));
414
447
  ALL_SERVICES.forEach((service) => {
415
- console.log(" " + chalk9.white(service));
448
+ console.log(" " + chalk8.white(service));
416
449
  });
417
450
  console.log("");
418
451
  console.log(
419
- chalk9.gray("Manage service access via console.globio.stanlink.online")
452
+ chalk8.gray("Manage service access via console.globio.stanlink.online")
420
453
  );
421
454
  console.log("");
422
455
  }
423
456
 
424
457
  // src/commands/functions.ts
425
- import chalk10 from "chalk";
458
+ import chalk9 from "chalk";
426
459
  import ora from "ora";
427
- import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
460
+ import { existsSync as existsSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
428
461
  async function functionsList() {
429
462
  const client = getClient();
430
463
  const spinner2 = ora("Fetching functions...").start();
431
464
  const result = await client.code.listFunctions();
432
465
  spinner2.stop();
433
466
  if (!result.success || !result.data.length) {
434
- console.log(chalk10.gray("No functions found."));
467
+ console.log(chalk9.gray("No functions found."));
435
468
  return;
436
469
  }
437
470
  console.log("");
438
471
  result.data.forEach((fn) => {
439
- const status = fn.active ? chalk10.green("\u25CF active") : chalk10.gray("\u25CB inactive");
440
- const type = fn.type === "hook" ? chalk10.yellow("[hook]") : chalk10.cyan("[function]");
441
- console.log(` ${status} ${type} ${chalk10.white(fn.slug)}`);
442
- if (fn.type === "hook") {
443
- console.log(chalk10.gray(` trigger: ${fn.trigger_event}`));
472
+ const status = fn.active ? "\x1B[32m\u25CF\x1B[0m" : "\x1B[2m\u25CB\x1B[0m";
473
+ const type = fn.type === "hook" ? gold("[hook]") : orange("[function]");
474
+ console.log(" " + status + " " + type + " " + fn.slug);
475
+ if (fn.type === "hook" && fn.trigger_event) {
476
+ console.log(muted(" trigger: " + fn.trigger_event));
444
477
  }
445
478
  });
446
479
  console.log("");
@@ -448,7 +481,7 @@ async function functionsList() {
448
481
  async function functionsCreate(slug) {
449
482
  const filename = `${slug}.js`;
450
483
  if (existsSync2(filename)) {
451
- console.log(chalk10.yellow(`${filename} already exists.`));
484
+ console.log(chalk9.yellow(`${filename} already exists.`));
452
485
  return;
453
486
  }
454
487
  const template = `/**
@@ -467,22 +500,22 @@ async function handler(input, globio) {
467
500
  }
468
501
  `;
469
502
  writeFileSync2(filename, template);
470
- console.log(chalk10.green(`Created ${filename}`));
503
+ console.log(chalk9.green(`Created ${filename}`));
471
504
  console.log(
472
- chalk10.gray(`Deploy with: npx @globio/cli functions deploy ${slug}`)
505
+ chalk9.gray(`Deploy with: npx @globio/cli functions deploy ${slug}`)
473
506
  );
474
507
  }
475
508
  async function functionsDeploy(slug, options) {
476
509
  const filename = options.file ?? `${slug}.js`;
477
510
  if (!existsSync2(filename)) {
478
511
  console.log(
479
- chalk10.red(
512
+ chalk9.red(
480
513
  `File not found: ${filename}. Create it with: npx @globio/cli functions create ${slug}`
481
514
  )
482
515
  );
483
516
  process.exit(1);
484
517
  }
485
- const code = readFileSync2(filename, "utf-8");
518
+ const code = readFileSync3(filename, "utf-8");
486
519
  const client = getClient();
487
520
  const spinner2 = ora(`Deploying ${slug}...`).start();
488
521
  const existing = await client.code.getFunction(slug);
@@ -513,7 +546,7 @@ async function functionsInvoke(slug, options) {
513
546
  try {
514
547
  input = JSON.parse(options.input);
515
548
  } catch {
516
- console.error(chalk10.red("--input must be valid JSON"));
549
+ console.error(chalk9.red("--input must be valid JSON"));
517
550
  process.exit(1);
518
551
  }
519
552
  }
@@ -522,14 +555,14 @@ async function functionsInvoke(slug, options) {
522
555
  const result = await client.code.invoke(slug, input);
523
556
  spinner2.stop();
524
557
  if (!result.success) {
525
- console.log(chalk10.red("Invocation failed"));
558
+ console.log(chalk9.red("Invocation failed"));
526
559
  console.error(result.error.message);
527
560
  return;
528
561
  }
529
562
  console.log("");
530
- console.log(chalk10.cyan("Result:"));
563
+ console.log(orange("Result:"));
531
564
  console.log(JSON.stringify(result.data.result, null, 2));
532
- console.log(chalk10.gray(`
565
+ console.log(muted(`
533
566
  Duration: ${result.data.duration_ms}ms`));
534
567
  }
535
568
  async function functionsLogs(slug, options) {
@@ -539,15 +572,15 @@ async function functionsLogs(slug, options) {
539
572
  const result = await client.code.getInvocations(slug, limit);
540
573
  spinner2.stop();
541
574
  if (!result.success || !result.data.length) {
542
- console.log(chalk10.gray("No invocations yet."));
575
+ console.log(chalk9.gray("No invocations yet."));
543
576
  return;
544
577
  }
545
578
  console.log("");
546
579
  result.data.forEach((inv) => {
547
- const status = inv.success ? chalk10.green("\u2713") : chalk10.red("\u2717");
580
+ const status = inv.success ? "\x1B[38;2;244;140;6m\u2713\x1B[0m" : "\x1B[31m\u2717\x1B[0m";
548
581
  const date = new Date(inv.invoked_at * 1e3).toISOString().replace("T", " ").slice(0, 19);
549
582
  console.log(
550
- ` ${status} ${chalk10.gray(date)} ${inv.duration_ms}ms ${chalk10.gray(`[${inv.trigger_type}]`)}`
583
+ ` ${status} ${chalk9.gray(date)} ${inv.duration_ms}ms ${chalk9.gray(`[${inv.trigger_type}]`)}`
551
584
  );
552
585
  });
553
586
  console.log("");
@@ -578,8 +611,12 @@ async function functionsToggle(slug, active) {
578
611
  }
579
612
 
580
613
  // src/index.ts
614
+ var version4 = getCliVersion();
581
615
  var program = new Command();
582
- program.name("globio").description("The official Globio CLI").version("0.1.0");
616
+ program.name("globio").description("The official Globio CLI").version(version4).addHelpText("beforeAll", () => {
617
+ printBanner(version4);
618
+ return "";
619
+ });
583
620
  program.command("login").description("Log in to your Globio account").action(login);
584
621
  program.command("logout").description("Log out").action(logout);
585
622
  program.command("whoami").description("Show current account and project").action(whoami);
@@ -600,4 +637,7 @@ functions.command("disable <slug>").description("Disable a function").action((sl
600
637
  var migrate = program.command("migrate").description("Migrate from Firebase to Globio");
601
638
  migrate.command("firestore").description("Migrate Firestore collections to GlobalDoc").requiredOption("--from <path>", "Path to Firebase service account JSON").option("--collection <name>", "Migrate a specific collection").option("--all", "Migrate all collections").action(migrateFirestore);
602
639
  migrate.command("firebase-storage").description("Migrate Firebase Storage to GlobalVault").requiredOption("--from <path>", "Path to Firebase service account JSON").requiredOption("--bucket <name>", "Firebase Storage bucket").option("--folder <path>", "Migrate a specific folder").option("--all", "Migrate all files").action(migrateFirebaseStorage);
640
+ if (process.argv.length <= 2) {
641
+ program.help();
642
+ }
603
643
  await program.parseAsync();
package/jsr.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@globio/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "license": "MIT",
5
5
  "exports": "./src/index.ts"
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@globio/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "The official CLI for Globio — game backend as a service",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -19,7 +19,9 @@
19
19
  "cli-progress": "^3.12.0",
20
20
  "commander": "^12.0.0",
21
21
  "conf": "^13.0.0",
22
+ "figlet": "^1.11.0",
22
23
  "firebase-admin": "^12.0.0",
24
+ "gradient-string": "^3.0.0",
23
25
  "ora": "^8.0.0"
24
26
  },
25
27
  "devDependencies": {
package/src/auth/login.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  import * as p from '@clack/prompts';
2
2
  import chalk from 'chalk';
3
3
  import { config } from '../lib/config.js';
4
+ import { getCliVersion, muted, orange, printBanner } from '../lib/banner.js';
4
5
 
5
6
  const DEFAULT_BASE_URL = 'https://api.globio.stanlink.online';
7
+ const version = getCliVersion();
6
8
 
7
9
  export async function login() {
8
- console.log('');
9
- p.intro(chalk.bgCyan(chalk.black(' Globio CLI ')));
10
+ printBanner(version);
10
11
 
11
12
  const values = await p.group(
12
13
  {
@@ -54,8 +55,14 @@ export async function login() {
54
55
 
55
56
  spinner.stop('Credentials validated.');
56
57
  p.outro(
57
- chalk.green('Logged in. Active project: ') +
58
- chalk.cyan(values.projectId as string)
58
+ ' Logged in.\n\n' +
59
+ ' ' +
60
+ muted('API Key: ') +
61
+ orange(values.apiKey as string) +
62
+ '\n' +
63
+ ' ' +
64
+ muted('Project: ') +
65
+ orange(values.projectId as string)
59
66
  );
60
67
  } catch {
61
68
  spinner.stop('');
@@ -2,6 +2,7 @@ import chalk from 'chalk';
2
2
  import type { CodeFunction, CodeInvocation } from '@globio/sdk';
3
3
  import ora from 'ora';
4
4
  import { existsSync, readFileSync, writeFileSync } from 'fs';
5
+ import { gold, muted, orange } from '../lib/banner.js';
5
6
  import { getClient } from '../lib/sdk.js';
6
7
 
7
8
  export async function functionsList() {
@@ -17,16 +18,12 @@ export async function functionsList() {
17
18
 
18
19
  console.log('');
19
20
  result.data.forEach((fn: CodeFunction) => {
20
- const status = fn.active
21
- ? chalk.green('● active')
22
- : chalk.gray('○ inactive');
21
+ const status = fn.active ? '\x1b[32m●\x1b[0m' : '\x1b[2m○\x1b[0m';
23
22
  const type =
24
- fn.type === 'hook'
25
- ? chalk.yellow('[hook]')
26
- : chalk.cyan('[function]');
27
- console.log(` ${status} ${type} ${chalk.white(fn.slug)}`);
28
- if (fn.type === 'hook') {
29
- console.log(chalk.gray(` trigger: ${fn.trigger_event}`));
23
+ fn.type === 'hook' ? gold('[hook]') : orange('[function]');
24
+ console.log(' ' + status + ' ' + type + ' ' + fn.slug);
25
+ if (fn.type === 'hook' && fn.trigger_event) {
26
+ console.log(muted(' trigger: ' + fn.trigger_event));
30
27
  }
31
28
  });
32
29
  console.log('');
@@ -130,9 +127,9 @@ export async function functionsInvoke(
130
127
  }
131
128
 
132
129
  console.log('');
133
- console.log(chalk.cyan('Result:'));
130
+ console.log(orange('Result:'));
134
131
  console.log(JSON.stringify(result.data.result, null, 2));
135
- console.log(chalk.gray(`\nDuration: ${result.data.duration_ms}ms`));
132
+ console.log(muted(`\nDuration: ${result.data.duration_ms}ms`));
136
133
  }
137
134
 
138
135
  export async function functionsLogs(
@@ -152,7 +149,9 @@ export async function functionsLogs(
152
149
 
153
150
  console.log('');
154
151
  result.data.forEach((inv: CodeInvocation) => {
155
- const status = inv.success ? chalk.green('✓') : chalk.red('✗');
152
+ const status = inv.success
153
+ ? '\x1b[38;2;244;140;6m✓\x1b[0m'
154
+ : '\x1b[31m✗\x1b[0m';
156
155
  const date = new Date(inv.invoked_at * 1000)
157
156
  .toISOString()
158
157
  .replace('T', ' ')
@@ -1,13 +1,21 @@
1
1
  import * as p from '@clack/prompts';
2
- import chalk from 'chalk';
3
2
  import { existsSync, readFileSync, writeFileSync } from 'fs';
4
3
  import { config } from '../lib/config.js';
4
+ import {
5
+ getCliVersion,
6
+ muted,
7
+ orange,
8
+ printSuccess,
9
+ printBanner,
10
+ } from '../lib/banner.js';
5
11
  import { promptInit } from '../prompts/init.js';
6
12
  import { migrateFirestore, migrateFirebaseStorage } from './migrate.js';
7
13
 
14
+ const version = getCliVersion();
15
+
8
16
  export async function init() {
9
- console.log('');
10
- p.intro(chalk.bgCyan(chalk.black(' Globio Game Backend as a Service ')));
17
+ printBanner(version);
18
+ p.intro(orange('⇒⇒') + ' Initialize your Globio project');
11
19
 
12
20
  const values = await promptInit();
13
21
 
@@ -26,17 +34,17 @@ export const globio = new GlobioClient({
26
34
  });
27
35
  `
28
36
  );
29
- console.log(chalk.green('Created globio.config.ts'));
37
+ printSuccess('Created globio.config.ts');
30
38
  }
31
39
 
32
40
  if (!existsSync('.env')) {
33
41
  writeFileSync('.env', `GLOBIO_API_KEY=${values.apiKey}\n`);
34
- console.log(chalk.green('Created .env'));
42
+ printSuccess('Created .env');
35
43
  }
36
44
 
37
45
  if (values.migrateFromFirebase && values.serviceAccountPath) {
38
46
  console.log('');
39
- console.log(chalk.cyan('Starting Firebase migration...'));
47
+ printSuccess('Starting Firebase migration...');
40
48
 
41
49
  await migrateFirestore({
42
50
  from: values.serviceAccountPath as string,
@@ -56,10 +64,12 @@ export const globio = new GlobioClient({
56
64
 
57
65
  console.log('');
58
66
  p.outro(
59
- chalk.green('Your Globio project is ready.') +
67
+ orange('⇒⇒') +
68
+ ' Your project is ready.\n\n' +
69
+ ' ' +
70
+ muted('Next steps:') +
60
71
  '\n\n' +
61
- chalk.white(' Next steps:\n') +
62
- chalk.gray(' npm install @globio/sdk\n') +
63
- chalk.gray(' npx @globio/cli functions create my-first-function\n')
72
+ ' npm install @globio/sdk\n' +
73
+ ' npx @globio/cli functions create my-first-function'
64
74
  );
65
75
  }
@@ -1,10 +1,19 @@
1
1
  import * as p from '@clack/prompts';
2
2
  import chalk from 'chalk';
3
3
  import { basename } from 'path';
4
+ import {
5
+ getCliVersion,
6
+ gold,
7
+ muted,
8
+ orange,
9
+ printBanner,
10
+ } from '../lib/banner.js';
4
11
  import { initFirebase } from '../lib/firebase.js';
5
12
  import { createProgressBar } from '../lib/progress.js';
6
13
  import { getClient } from '../lib/sdk.js';
7
14
 
15
+ const version = getCliVersion();
16
+
8
17
  interface MigrateFirestoreOptions {
9
18
  from: string;
10
19
  collection?: string;
@@ -19,8 +28,8 @@ interface MigrateStorageOptions {
19
28
  }
20
29
 
21
30
  export async function migrateFirestore(options: MigrateFirestoreOptions) {
22
- console.log('');
23
- p.intro(chalk.bgYellow(chalk.black(' Globio Migration Firestore ')));
31
+ printBanner(version);
32
+ p.intro(gold('⇒⇒') + ' Firebase Globio Migration');
24
33
 
25
34
  const { firestore } = await initFirebase(options.from);
26
35
  const client = getClient();
@@ -49,7 +58,7 @@ export async function migrateFirestore(options: MigrateFirestoreOptions) {
49
58
 
50
59
  for (const collectionId of collections) {
51
60
  console.log('');
52
- console.log(chalk.cyan(`Migrating collection: ${collectionId}`));
61
+ console.log(' ' + orange(collectionId));
53
62
 
54
63
  const countSnap = await firestore.collection(collectionId).count().get();
55
64
  const total = countSnap.data().count;
@@ -114,17 +123,20 @@ export async function migrateFirestore(options: MigrateFirestoreOptions) {
114
123
  }
115
124
 
116
125
  console.log('');
117
- p.outro(chalk.green('Firestore migration complete.'));
118
- console.log(
119
- chalk.gray(
120
- 'Your Firebase data is intact. Delete it manually when ready.'
121
- )
126
+ p.outro(
127
+ orange('✓') +
128
+ ' Migration complete.\n\n' +
129
+ ' ' +
130
+ muted('Your Firebase data is intact.') +
131
+ '\n' +
132
+ ' ' +
133
+ muted('Delete it manually when ready.')
122
134
  );
123
135
  }
124
136
 
125
137
  export async function migrateFirebaseStorage(options: MigrateStorageOptions) {
126
- console.log('');
127
- p.intro(chalk.bgYellow(chalk.black(' Globio Migration Storage ')));
138
+ printBanner(version);
139
+ p.intro(gold('⇒⇒') + ' Firebase Globio Migration');
128
140
 
129
141
  const { storage } = await initFirebase(options.from);
130
142
  const client = getClient();
@@ -175,5 +187,13 @@ export async function migrateFirebaseStorage(options: MigrateStorageOptions) {
175
187
  console.log(chalk.red(` ✗ ${failed} failed`));
176
188
  }
177
189
 
178
- p.outro(chalk.green('Storage migration complete.'));
190
+ p.outro(
191
+ orange('✓') +
192
+ ' Migration complete.\n\n' +
193
+ ' ' +
194
+ muted('Your Firebase data is intact.') +
195
+ '\n' +
196
+ ' ' +
197
+ muted('Delete it manually when ready.')
198
+ );
179
199
  }
package/src/index.ts CHANGED
@@ -19,13 +19,20 @@ import {
19
19
  migrateFirestore,
20
20
  migrateFirebaseStorage,
21
21
  } from './commands/migrate.js';
22
+ import { getCliVersion, printBanner } from './lib/banner.js';
23
+
24
+ const version = getCliVersion();
22
25
 
23
26
  const program = new Command();
24
27
 
25
28
  program
26
29
  .name('globio')
27
30
  .description('The official Globio CLI')
28
- .version('0.1.0');
31
+ .version(version)
32
+ .addHelpText('beforeAll', () => {
33
+ printBanner(version);
34
+ return '';
35
+ });
29
36
 
30
37
  program.command('login').description('Log in to your Globio account').action(login);
31
38
  program.command('logout').description('Log out').action(logout);
@@ -87,4 +94,8 @@ migrate
87
94
  .option('--all', 'Migrate all files')
88
95
  .action(migrateFirebaseStorage);
89
96
 
97
+ if (process.argv.length <= 2) {
98
+ program.help();
99
+ }
100
+
90
101
  await program.parseAsync();
@@ -0,0 +1,51 @@
1
+ import { readFileSync } from 'fs';
2
+ import figlet from 'figlet';
3
+ import gradientString from 'gradient-string';
4
+
5
+ const globioGradient = gradientString(
6
+ '#e85d04',
7
+ '#f48c06',
8
+ '#faa307',
9
+ '#ffba08',
10
+ '#ffd000'
11
+ );
12
+
13
+ export function printBanner(version: string) {
14
+ const art = figlet.textSync('Globio', {
15
+ font: 'ANSI Shadow',
16
+ horizontalLayout: 'default',
17
+ });
18
+
19
+ console.log(globioGradient.multiline(art));
20
+ console.log(
21
+ globioGradient(' ⇒⇒') +
22
+ ' Game Backend as a Service' +
23
+ ' \x1b[2mv' +
24
+ version +
25
+ '\x1b[0m'
26
+ );
27
+ console.log('');
28
+ }
29
+
30
+ export function printSuccess(message: string) {
31
+ console.log('\x1b[38;2;250;163;7m✓\x1b[0m ' + message);
32
+ }
33
+
34
+ export function printError(message: string) {
35
+ console.log('\x1b[31m✗\x1b[0m ' + message);
36
+ }
37
+
38
+ export function printInfo(message: string) {
39
+ console.log('\x1b[2m›\x1b[0m ' + message);
40
+ }
41
+
42
+ export const orange = (s: string) => '\x1b[38;2;244;140;6m' + s + '\x1b[0m';
43
+
44
+ export const gold = (s: string) => '\x1b[38;2;255;208;0m' + s + '\x1b[0m';
45
+
46
+ export const muted = (s: string) => '\x1b[2m' + s + '\x1b[0m';
47
+
48
+ export function getCliVersion() {
49
+ const file = readFileSync(new URL('../package.json', import.meta.url), 'utf8');
50
+ return (JSON.parse(file) as { version: string }).version;
51
+ }