@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.
- package/.github/workflows/publish.yml +21 -3
- package/dist/index.js +93 -53
- package/jsr.json +1 -1
- package/package.json +3 -1
- package/src/auth/login.ts +11 -4
- package/src/commands/functions.ts +11 -12
- package/src/commands/init.ts +20 -10
- package/src/commands/migrate.ts +31 -11
- package/src/index.ts +12 -1
- package/src/lib/banner.ts +51 -0
|
@@ -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
|
-
|
|
40
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
170
|
-
const serviceAccount = JSON.parse(
|
|
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
|
-
|
|
211
|
-
p4.intro(
|
|
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(
|
|
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(
|
|
284
|
-
|
|
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
|
-
|
|
292
|
-
p4.intro(
|
|
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(
|
|
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
|
-
|
|
337
|
-
p5.intro(
|
|
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
|
-
|
|
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
|
-
|
|
391
|
+
printSuccess("Created .env");
|
|
359
392
|
}
|
|
360
393
|
if (values.migrateFromFirebase && values.serviceAccountPath) {
|
|
361
394
|
console.log("");
|
|
362
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
427
|
+
console.log(chalk7.green("Active project set to: ") + chalk7.cyan(projectId));
|
|
395
428
|
}
|
|
396
429
|
|
|
397
430
|
// src/commands/services.ts
|
|
398
|
-
import
|
|
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(
|
|
446
|
+
console.log(chalk8.cyan("Available Globio services:"));
|
|
414
447
|
ALL_SERVICES.forEach((service) => {
|
|
415
|
-
console.log(" " +
|
|
448
|
+
console.log(" " + chalk8.white(service));
|
|
416
449
|
});
|
|
417
450
|
console.log("");
|
|
418
451
|
console.log(
|
|
419
|
-
|
|
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
|
|
458
|
+
import chalk9 from "chalk";
|
|
426
459
|
import ora from "ora";
|
|
427
|
-
import { existsSync as existsSync2, readFileSync as
|
|
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(
|
|
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 ?
|
|
440
|
-
const type = fn.type === "hook" ?
|
|
441
|
-
console.log(
|
|
442
|
-
if (fn.type === "hook") {
|
|
443
|
-
console.log(
|
|
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(
|
|
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(
|
|
503
|
+
console.log(chalk9.green(`Created ${filename}`));
|
|
471
504
|
console.log(
|
|
472
|
-
|
|
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
|
-
|
|
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 =
|
|
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(
|
|
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(
|
|
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(
|
|
563
|
+
console.log(orange("Result:"));
|
|
531
564
|
console.log(JSON.stringify(result.data.result, null, 2));
|
|
532
|
-
console.log(
|
|
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(
|
|
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 ?
|
|
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} ${
|
|
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(
|
|
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@globio/cli",
|
|
3
|
-
"version": "0.1.
|
|
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
|
-
|
|
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
|
-
|
|
58
|
-
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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(
|
|
130
|
+
console.log(orange('Result:'));
|
|
134
131
|
console.log(JSON.stringify(result.data.result, null, 2));
|
|
135
|
-
console.log(
|
|
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
|
|
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', ' ')
|
package/src/commands/init.ts
CHANGED
|
@@ -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
|
-
|
|
10
|
-
p.intro(
|
|
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
|
-
|
|
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
|
-
|
|
42
|
+
printSuccess('Created .env');
|
|
35
43
|
}
|
|
36
44
|
|
|
37
45
|
if (values.migrateFromFirebase && values.serviceAccountPath) {
|
|
38
46
|
console.log('');
|
|
39
|
-
|
|
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
|
-
|
|
67
|
+
orange('⇒⇒') +
|
|
68
|
+
' Your project is ready.\n\n' +
|
|
69
|
+
' ' +
|
|
70
|
+
muted('Next steps:') +
|
|
60
71
|
'\n\n' +
|
|
61
|
-
|
|
62
|
-
|
|
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
|
}
|
package/src/commands/migrate.ts
CHANGED
|
@@ -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
|
-
|
|
23
|
-
p.intro(
|
|
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(
|
|
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(
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
'
|
|
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
|
-
|
|
127
|
-
p.intro(
|
|
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(
|
|
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
|
-
|
|
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
|
+
}
|