@globio/cli 0.0.1 → 0.1.1
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 +59 -0
- package/LICENSE +21 -0
- package/README.md +90 -0
- package/dist/index.js +643 -1
- package/jsr.json +6 -0
- package/package.json +30 -2
- package/src/auth/login.ts +72 -0
- package/src/auth/logout.ts +8 -0
- package/src/auth/whoami.ts +15 -0
- package/src/commands/functions.ts +190 -0
- package/src/commands/init.ts +75 -0
- package/src/commands/migrate.ts +199 -0
- package/src/commands/projects.ts +16 -0
- package/src/commands/services.ts +27 -0
- package/src/index.ts +102 -0
- package/src/lib/banner.ts +51 -0
- package/src/lib/config.ts +47 -0
- package/src/lib/firebase.ts +19 -0
- package/src/lib/progress.ts +17 -0
- package/src/lib/sdk.ts +13 -0
- package/src/prompts/init.ts +38 -0
- package/src/prompts/migrate.ts +8 -0
- package/tsconfig.json +13 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { login } from './auth/login.js';
|
|
4
|
+
import { logout } from './auth/logout.js';
|
|
5
|
+
import { whoami } from './auth/whoami.js';
|
|
6
|
+
import { init } from './commands/init.js';
|
|
7
|
+
import { projectsList, projectsUse } from './commands/projects.js';
|
|
8
|
+
import { servicesList } from './commands/services.js';
|
|
9
|
+
import {
|
|
10
|
+
functionsList,
|
|
11
|
+
functionsCreate,
|
|
12
|
+
functionsDeploy,
|
|
13
|
+
functionsInvoke,
|
|
14
|
+
functionsLogs,
|
|
15
|
+
functionsDelete,
|
|
16
|
+
functionsToggle,
|
|
17
|
+
} from './commands/functions.js';
|
|
18
|
+
import {
|
|
19
|
+
migrateFirestore,
|
|
20
|
+
migrateFirebaseStorage,
|
|
21
|
+
} from './commands/migrate.js';
|
|
22
|
+
import { getCliVersion, printBanner } from './lib/banner.js';
|
|
23
|
+
|
|
24
|
+
const version = getCliVersion();
|
|
25
|
+
|
|
26
|
+
const program = new Command();
|
|
27
|
+
|
|
28
|
+
program
|
|
29
|
+
.name('globio')
|
|
30
|
+
.description('The official Globio CLI')
|
|
31
|
+
.version(version)
|
|
32
|
+
.addHelpText('beforeAll', () => {
|
|
33
|
+
printBanner(version);
|
|
34
|
+
return '';
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
program.command('login').description('Log in to your Globio account').action(login);
|
|
38
|
+
program.command('logout').description('Log out').action(logout);
|
|
39
|
+
program.command('whoami').description('Show current account and project').action(whoami);
|
|
40
|
+
|
|
41
|
+
program.command('init').description('Initialize a Globio project').action(init);
|
|
42
|
+
|
|
43
|
+
const projects = program.command('projects').description('Manage projects');
|
|
44
|
+
projects.command('list').description('List projects').action(projectsList);
|
|
45
|
+
projects.command('use <projectId>').description('Set active project').action(projectsUse);
|
|
46
|
+
|
|
47
|
+
program.command('services').description('List available Globio services').action(servicesList);
|
|
48
|
+
|
|
49
|
+
const functions = program
|
|
50
|
+
.command('functions')
|
|
51
|
+
.alias('fn')
|
|
52
|
+
.description('Manage GlobalCode edge functions');
|
|
53
|
+
|
|
54
|
+
functions.command('list').description('List all functions').action(functionsList);
|
|
55
|
+
functions.command('create <slug>').description('Scaffold a new function file locally').action(functionsCreate);
|
|
56
|
+
functions
|
|
57
|
+
.command('deploy <slug>')
|
|
58
|
+
.description('Deploy a function to GlobalCode')
|
|
59
|
+
.option('-f, --file <path>', 'Path to function file')
|
|
60
|
+
.option('-n, --name <name>', 'Display name')
|
|
61
|
+
.action(functionsDeploy);
|
|
62
|
+
functions
|
|
63
|
+
.command('invoke <slug>')
|
|
64
|
+
.description('Invoke a function')
|
|
65
|
+
.option('-i, --input <json>', 'JSON input payload')
|
|
66
|
+
.action(functionsInvoke);
|
|
67
|
+
functions
|
|
68
|
+
.command('logs <slug>')
|
|
69
|
+
.description('Show invocation history')
|
|
70
|
+
.option('-l, --limit <n>', 'Number of entries', '20')
|
|
71
|
+
.action(functionsLogs);
|
|
72
|
+
functions.command('delete <slug>').description('Delete a function').action(functionsDelete);
|
|
73
|
+
functions.command('enable <slug>').description('Enable a function').action((slug) => functionsToggle(slug, true));
|
|
74
|
+
functions.command('disable <slug>').description('Disable a function').action((slug) => functionsToggle(slug, false));
|
|
75
|
+
|
|
76
|
+
const migrate = program
|
|
77
|
+
.command('migrate')
|
|
78
|
+
.description('Migrate from Firebase to Globio');
|
|
79
|
+
|
|
80
|
+
migrate
|
|
81
|
+
.command('firestore')
|
|
82
|
+
.description('Migrate Firestore collections to GlobalDoc')
|
|
83
|
+
.requiredOption('--from <path>', 'Path to Firebase service account JSON')
|
|
84
|
+
.option('--collection <name>', 'Migrate a specific collection')
|
|
85
|
+
.option('--all', 'Migrate all collections')
|
|
86
|
+
.action(migrateFirestore);
|
|
87
|
+
|
|
88
|
+
migrate
|
|
89
|
+
.command('firebase-storage')
|
|
90
|
+
.description('Migrate Firebase Storage to GlobalVault')
|
|
91
|
+
.requiredOption('--from <path>', 'Path to Firebase service account JSON')
|
|
92
|
+
.requiredOption('--bucket <name>', 'Firebase Storage bucket')
|
|
93
|
+
.option('--folder <path>', 'Migrate a specific folder')
|
|
94
|
+
.option('--all', 'Migrate all files')
|
|
95
|
+
.action(migrateFirebaseStorage);
|
|
96
|
+
|
|
97
|
+
if (process.argv.length <= 2) {
|
|
98
|
+
printBanner(version);
|
|
99
|
+
program.help();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
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
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import Conf from 'conf';
|
|
3
|
+
|
|
4
|
+
interface GlobioConfig {
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
projectId?: string;
|
|
7
|
+
projectName?: string;
|
|
8
|
+
email?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const store = new Conf<GlobioConfig>({
|
|
12
|
+
projectName: 'globio',
|
|
13
|
+
defaults: {},
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export const config = {
|
|
17
|
+
get: (): GlobioConfig => store.store,
|
|
18
|
+
set: (values: Partial<GlobioConfig>) => {
|
|
19
|
+
Object.entries(values).forEach(([key, value]) => {
|
|
20
|
+
if (value !== undefined) {
|
|
21
|
+
store.set(key as keyof GlobioConfig, value);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
clear: () => store.clear(),
|
|
26
|
+
getApiKey: () => store.get('apiKey'),
|
|
27
|
+
requireAuth: () => {
|
|
28
|
+
const key = store.get('apiKey');
|
|
29
|
+
if (!key) {
|
|
30
|
+
console.error(chalk.red('Not logged in. Run: npx @globio/cli login'));
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
return key;
|
|
34
|
+
},
|
|
35
|
+
requireProject: () => {
|
|
36
|
+
const projectId = store.get('projectId');
|
|
37
|
+
if (!projectId) {
|
|
38
|
+
console.error(
|
|
39
|
+
chalk.red('No active project. Run: npx @globio/cli projects use <projectId>')
|
|
40
|
+
);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
return projectId;
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type { GlobioConfig };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export async function initFirebase(serviceAccountPath: string) {
|
|
2
|
+
const admin = await import('firebase-admin');
|
|
3
|
+
const { readFileSync } = await import('fs');
|
|
4
|
+
|
|
5
|
+
const serviceAccount = JSON.parse(readFileSync(serviceAccountPath, 'utf-8'));
|
|
6
|
+
|
|
7
|
+
if (!admin.default.apps.length) {
|
|
8
|
+
admin.default.initializeApp({
|
|
9
|
+
credential: admin.default.credential.cert(serviceAccount),
|
|
10
|
+
storageBucket: serviceAccount.project_id + '.appspot.com',
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
firestore: admin.default.firestore(),
|
|
16
|
+
storage: admin.default.storage(),
|
|
17
|
+
app: admin.default.app(),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import cliProgress from 'cli-progress';
|
|
3
|
+
|
|
4
|
+
export function createProgressBar(label: string) {
|
|
5
|
+
const bar = new cliProgress.SingleBar(
|
|
6
|
+
{
|
|
7
|
+
format:
|
|
8
|
+
chalk.cyan(label) +
|
|
9
|
+
' [{bar}] {percentage}% | {value}/{total}',
|
|
10
|
+
barCompleteChar: '█',
|
|
11
|
+
barIncompleteChar: '░',
|
|
12
|
+
hideCursor: true,
|
|
13
|
+
},
|
|
14
|
+
cliProgress.Presets.shades_classic
|
|
15
|
+
);
|
|
16
|
+
return bar;
|
|
17
|
+
}
|
package/src/lib/sdk.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Globio } from '@globio/sdk';
|
|
2
|
+
import { config } from './config.js';
|
|
3
|
+
|
|
4
|
+
export function getClient(): Globio {
|
|
5
|
+
const apiKey = config.requireAuth();
|
|
6
|
+
config.requireProject();
|
|
7
|
+
return new Globio({ apiKey });
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function getClientWithKey(apiKey: string, projectId: string): Globio {
|
|
11
|
+
void projectId;
|
|
12
|
+
return new Globio({ apiKey });
|
|
13
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as p from '@clack/prompts';
|
|
2
|
+
|
|
3
|
+
export async function promptInit() {
|
|
4
|
+
return p.group(
|
|
5
|
+
{
|
|
6
|
+
apiKey: () =>
|
|
7
|
+
p.text({
|
|
8
|
+
message: 'Globio API key',
|
|
9
|
+
placeholder: 'gk_live_...',
|
|
10
|
+
validate: (value) => (!value ? 'Required' : undefined),
|
|
11
|
+
}),
|
|
12
|
+
projectId: () =>
|
|
13
|
+
p.text({
|
|
14
|
+
message: 'Project ID',
|
|
15
|
+
placeholder: 'proj_...',
|
|
16
|
+
validate: (value) => (!value ? 'Required' : undefined),
|
|
17
|
+
}),
|
|
18
|
+
migrateFromFirebase: () =>
|
|
19
|
+
p.confirm({
|
|
20
|
+
message: 'Migrating from Firebase?',
|
|
21
|
+
initialValue: false,
|
|
22
|
+
}),
|
|
23
|
+
serviceAccountPath: ({ results }) =>
|
|
24
|
+
results.migrateFromFirebase
|
|
25
|
+
? p.text({
|
|
26
|
+
message: 'Path to Firebase service account JSON',
|
|
27
|
+
placeholder: './serviceAccountKey.json',
|
|
28
|
+
})
|
|
29
|
+
: Promise.resolve(undefined),
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
onCancel: () => {
|
|
33
|
+
p.cancel('Cancelled.');
|
|
34
|
+
process.exit(0);
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
}
|
package/tsconfig.json
ADDED