@globio/cli 0.1.8 → 0.2.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.js +384 -146
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/auth/login.ts +9 -10
- package/src/auth/logout.ts +5 -5
- package/src/auth/whoami.ts +58 -19
- package/src/commands/functions.ts +60 -34
- package/src/commands/init.ts +3 -2
- package/src/commands/migrate.ts +11 -10
- package/src/commands/profiles.ts +39 -12
- package/src/commands/projects.ts +51 -29
- package/src/commands/services.ts +62 -22
- package/src/commands/watch.ts +173 -0
- package/src/index.ts +6 -0
- package/src/lib/banner.ts +1 -6
- package/src/lib/config.ts +2 -0
- package/src/lib/manage.ts +4 -0
- package/src/lib/table.ts +97 -0
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(version11, subtitle) {
|
|
210
|
+
const lines = [
|
|
211
|
+
"",
|
|
212
|
+
orange(" \u21D2\u21D2") + reset + " globio " + dim(version11),
|
|
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(
|
|
233
|
+
function printBanner(version11) {
|
|
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" +
|
|
240
|
+
globioGradient(" \u21D2\u21D2") + " Game Backend as a Service \x1B[2mv" + version11 + "\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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
423
|
+
console.log(green(`Logged out. Switched to profile: ${remaining[0]}`));
|
|
361
424
|
return;
|
|
362
425
|
}
|
|
363
426
|
config.setActiveProfile("");
|
|
364
|
-
console.log(
|
|
427
|
+
console.log(green("Logged out."));
|
|
365
428
|
return;
|
|
366
429
|
}
|
|
367
|
-
console.log(
|
|
430
|
+
console.log(green(`Logged out profile: ${profileName}`));
|
|
368
431
|
}
|
|
369
432
|
|
|
370
433
|
// src/auth/useProfile.ts
|
|
371
|
-
import
|
|
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
|
-
|
|
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
|
-
|
|
447
|
+
chalk2.green("Switched to profile: ") + orange(profileName) + ` (${profile.account_email})`
|
|
385
448
|
);
|
|
386
449
|
}
|
|
387
450
|
|
|
388
451
|
// src/auth/whoami.ts
|
|
389
|
-
|
|
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(
|
|
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
|
|
399
|
-
|
|
463
|
+
const active = config.getActiveProfile();
|
|
464
|
+
const otherProfiles = allProfiles.filter((p6) => p6 !== profileName).join(", ") || "\u2014";
|
|
400
465
|
console.log(
|
|
401
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
678
|
+
green(` \u2713 ${results[collectionId].success} documents migrated`)
|
|
602
679
|
);
|
|
603
680
|
if (indexFieldCount > 0) {
|
|
604
681
|
console.log(
|
|
605
|
-
|
|
682
|
+
muted(` Indexes created for ${indexFieldCount} fields`)
|
|
606
683
|
);
|
|
607
684
|
}
|
|
608
685
|
if (results[collectionId].failed > 0) {
|
|
609
|
-
console.log(
|
|
686
|
+
console.log(failure(` \u2717 ${results[collectionId].failed} failed`) + "\x1B[0m");
|
|
610
687
|
console.log(
|
|
611
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
749
|
+
console.log(green(` \u2713 ${success} files migrated`));
|
|
673
750
|
if (failed > 0) {
|
|
674
|
-
console.log(
|
|
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
|
-
|
|
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(
|
|
718
|
-
console.log("");
|
|
787
|
+
console.log(header(version4) + " " + muted("No projects found.") + "\n");
|
|
719
788
|
return;
|
|
720
789
|
}
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
817
|
-
console.log(
|
|
818
|
-
console.log(
|
|
819
|
-
console.log(
|
|
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
|
|
905
|
+
var version5 = getCliVersion();
|
|
825
906
|
async function init(options = {}) {
|
|
826
|
-
printBanner(
|
|
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
|
-
|
|
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(
|
|
980
|
+
console.log(
|
|
981
|
+
header(version6) + " " + muted("No profiles. Run: globio login") + "\n"
|
|
982
|
+
);
|
|
900
983
|
return;
|
|
901
984
|
}
|
|
902
|
-
|
|
903
|
-
|
|
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
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
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
|
-
|
|
917
|
-
var
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
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
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
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
|
-
|
|
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(
|
|
1083
|
+
console.log(header(version8) + " " + muted("No functions found.") + "\n");
|
|
972
1084
|
return;
|
|
973
1085
|
}
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
1199
|
+
console.log(header(version8) + " " + muted("No invocations yet.") + "\n");
|
|
1083
1200
|
return;
|
|
1084
1201
|
}
|
|
1085
|
-
|
|
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
|
-
|
|
1090
|
-
|
|
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 = {}) {
|
|
@@ -1119,11 +1249,118 @@ async function functionsToggle(slug, active, options = {}) {
|
|
|
1119
1249
|
spinner2.succeed(`${slug} is now ${active ? "active" : "inactive"}`);
|
|
1120
1250
|
}
|
|
1121
1251
|
|
|
1252
|
+
// src/commands/watch.ts
|
|
1253
|
+
var BASE_URL2 = "https://api.globio.stanlink.online";
|
|
1254
|
+
var version9 = getCliVersion();
|
|
1255
|
+
async function functionsWatch(slug, options = {}) {
|
|
1256
|
+
const profileName = options.profile ?? config.getActiveProfile();
|
|
1257
|
+
const profile = config.getProfile(profileName ?? "default");
|
|
1258
|
+
if (!profile?.project_api_key) {
|
|
1259
|
+
console.log(
|
|
1260
|
+
failure("No active project.") + reset + " Run: globio projects use <id>"
|
|
1261
|
+
);
|
|
1262
|
+
process.exit(1);
|
|
1263
|
+
}
|
|
1264
|
+
console.log(header(version9));
|
|
1265
|
+
console.log(
|
|
1266
|
+
" " + orange("watching") + reset + " " + slug + dim(" \xB7 press Ctrl+C to stop") + "\n"
|
|
1267
|
+
);
|
|
1268
|
+
const res = await fetch(`${BASE_URL2}/code/functions/${slug}/watch`, {
|
|
1269
|
+
headers: {
|
|
1270
|
+
"X-Globio-Key": profile.project_api_key,
|
|
1271
|
+
Accept: "text/event-stream"
|
|
1272
|
+
}
|
|
1273
|
+
});
|
|
1274
|
+
if (!res.ok || !res.body) {
|
|
1275
|
+
console.log(failure("Failed to connect to watch stream.") + reset);
|
|
1276
|
+
process.exit(1);
|
|
1277
|
+
}
|
|
1278
|
+
const reader = res.body.getReader();
|
|
1279
|
+
const decoder = new TextDecoder();
|
|
1280
|
+
let buffer = "";
|
|
1281
|
+
process.on("SIGINT", () => {
|
|
1282
|
+
console.log("\n" + dim(" Stream closed.") + "\n");
|
|
1283
|
+
void reader.cancel();
|
|
1284
|
+
process.exit(0);
|
|
1285
|
+
});
|
|
1286
|
+
while (true) {
|
|
1287
|
+
const { done, value } = await reader.read();
|
|
1288
|
+
if (done) break;
|
|
1289
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1290
|
+
const chunks = buffer.split("\n\n");
|
|
1291
|
+
buffer = chunks.pop() ?? "";
|
|
1292
|
+
for (const chunk of chunks) {
|
|
1293
|
+
const dataLine = chunk.split("\n").find((line) => line.startsWith("data: "));
|
|
1294
|
+
if (!dataLine) continue;
|
|
1295
|
+
try {
|
|
1296
|
+
renderEvent(JSON.parse(dataLine.slice(6)));
|
|
1297
|
+
} catch {
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
function renderEvent(event) {
|
|
1303
|
+
if (event.type === "connected") {
|
|
1304
|
+
console.log(
|
|
1305
|
+
" " + green("\u25CF") + reset + dim(" connected \u2014 waiting for invocations...\n")
|
|
1306
|
+
);
|
|
1307
|
+
return;
|
|
1308
|
+
}
|
|
1309
|
+
if (event.type === "heartbeat") {
|
|
1310
|
+
return;
|
|
1311
|
+
}
|
|
1312
|
+
if (event.type === "timeout") {
|
|
1313
|
+
console.log(
|
|
1314
|
+
"\n" + dim(" Session timed out after 5 minutes.") + " Run again to resume.\n"
|
|
1315
|
+
);
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1318
|
+
if (event.type !== "invocation" || !event.invoked_at) {
|
|
1319
|
+
return;
|
|
1320
|
+
}
|
|
1321
|
+
const time = new Date(event.invoked_at * 1e3).toISOString().replace("T", " ").slice(0, 19);
|
|
1322
|
+
const status = event.success ? green("\u2713") : failure("\u2717");
|
|
1323
|
+
const trigger = dim(`[${event.trigger_type ?? "http"}]`);
|
|
1324
|
+
const duration = dim(`${event.duration_ms ?? 0}ms`);
|
|
1325
|
+
console.log(
|
|
1326
|
+
" " + status + reset + " " + dim(time) + " " + trigger + " " + duration
|
|
1327
|
+
);
|
|
1328
|
+
if (event.input && event.input !== "{}") {
|
|
1329
|
+
try {
|
|
1330
|
+
console.log(
|
|
1331
|
+
" " + dim(" input ") + muted(JSON.stringify(JSON.parse(event.input)))
|
|
1332
|
+
);
|
|
1333
|
+
} catch {
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
if (event.logs) {
|
|
1337
|
+
try {
|
|
1338
|
+
const logs = JSON.parse(event.logs);
|
|
1339
|
+
for (const line of logs) {
|
|
1340
|
+
console.log(" " + dim(" log ") + reset + line);
|
|
1341
|
+
}
|
|
1342
|
+
} catch {
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
if (event.result && event.result !== "null") {
|
|
1346
|
+
try {
|
|
1347
|
+
console.log(
|
|
1348
|
+
" " + dim(" result ") + muted(JSON.stringify(JSON.parse(event.result)))
|
|
1349
|
+
);
|
|
1350
|
+
} catch {
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
if (event.error_message) {
|
|
1354
|
+
console.log(" " + dim(" error ") + failure(event.error_message) + reset);
|
|
1355
|
+
}
|
|
1356
|
+
console.log("");
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1122
1359
|
// src/index.ts
|
|
1123
|
-
var
|
|
1360
|
+
var version10 = getCliVersion();
|
|
1124
1361
|
var program = new Command();
|
|
1125
|
-
program.name("globio").description("The official Globio CLI").version(
|
|
1126
|
-
printBanner(
|
|
1362
|
+
program.name("globio").description("The official Globio CLI").version(version10).addHelpText("beforeAll", () => {
|
|
1363
|
+
printBanner(version10);
|
|
1127
1364
|
return "";
|
|
1128
1365
|
}).addHelpText(
|
|
1129
1366
|
"after",
|
|
@@ -1158,6 +1395,7 @@ functions.command("create <slug>").description("Scaffold a new function file loc
|
|
|
1158
1395
|
functions.command("deploy <slug>").description("Deploy a function to GlobalCode").option("-f, --file <path>", "Path to function file").option("-n, --name <name>", "Display name").option("--profile <name>", "Use a specific profile").action(functionsDeploy);
|
|
1159
1396
|
functions.command("invoke <slug>").description("Invoke a function").option("-i, --input <json>", "JSON input payload").option("--profile <name>", "Use a specific profile").action(functionsInvoke);
|
|
1160
1397
|
functions.command("logs <slug>").description("Show invocation history").option("-l, --limit <n>", "Number of entries", "20").option("--profile <name>", "Use a specific profile").action(functionsLogs);
|
|
1398
|
+
functions.command("watch <slug>").description("Stream live function execution logs").option("--profile <name>", "Use a specific profile").action(functionsWatch);
|
|
1161
1399
|
functions.command("delete <slug>").description("Delete a function").option("--profile <name>", "Use a specific profile").action(functionsDelete);
|
|
1162
1400
|
functions.command("enable <slug>").description("Enable a function").option("--profile <name>", "Use a specific profile").action((slug, options) => functionsToggle(slug, true, options));
|
|
1163
1401
|
functions.command("disable <slug>").description("Disable a function").option("--profile <name>", "Use a specific profile").action((slug, options) => functionsToggle(slug, false, options));
|