@globio/cli 0.1.2 → 0.1.4
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 +617 -195
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/auth/login.ts +158 -51
- package/src/auth/logout.ts +26 -4
- package/src/auth/useProfile.ts +20 -0
- package/src/auth/whoami.ts +28 -6
- package/src/commands/functions.ts +28 -13
- package/src/commands/init.ts +28 -8
- package/src/commands/migrate.ts +9 -2
- package/src/commands/projects.ts +172 -7
- package/src/commands/services.ts +4 -1
- package/src/index.ts +60 -17
- package/src/lib/config.ts +122 -30
- package/src/lib/manage.ts +84 -0
- package/src/lib/sdk.ts +6 -3
- package/src/prompts/init.ts +0 -12
package/jsr.json
CHANGED
package/package.json
CHANGED
package/src/auth/login.ts
CHANGED
|
@@ -1,72 +1,179 @@
|
|
|
1
1
|
import * as p from '@clack/prompts';
|
|
2
|
+
import { exec } from 'child_process';
|
|
2
3
|
import chalk from 'chalk';
|
|
3
4
|
import { config } from '../lib/config.js';
|
|
5
|
+
import { getConsoleCliAuthUrl, manageRequest, type ManageAccount } from '../lib/manage.js';
|
|
4
6
|
import { getCliVersion, muted, orange, printBanner } from '../lib/banner.js';
|
|
5
7
|
|
|
6
|
-
const DEFAULT_BASE_URL = 'https://api.globio.stanlink.online';
|
|
7
8
|
const version = getCliVersion();
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
function openBrowser(url: string) {
|
|
11
|
+
const command = process.platform === 'win32'
|
|
12
|
+
? `start "" "${url}"`
|
|
13
|
+
: process.platform === 'darwin'
|
|
14
|
+
? `open "${url}"`
|
|
15
|
+
: `xdg-open "${url}"`;
|
|
16
|
+
|
|
17
|
+
exec(command);
|
|
18
|
+
}
|
|
11
19
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
function sleep(ms: number) {
|
|
21
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function savePat(token: string) {
|
|
25
|
+
const account = await manageRequest<ManageAccount>('/account', { token });
|
|
26
|
+
return account;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function runTokenLogin(profileName: string) {
|
|
30
|
+
const hadProfiles = config.listProfiles().length > 0;
|
|
31
|
+
const token = await p.text({
|
|
32
|
+
message: 'Paste your personal access token',
|
|
33
|
+
placeholder: 'glo_pat_...',
|
|
34
|
+
validate: (value) => {
|
|
35
|
+
if (!value) return 'Personal access token is required';
|
|
36
|
+
if (!value.startsWith('glo_pat_')) return 'Token must start with glo_pat_';
|
|
37
|
+
return undefined;
|
|
26
38
|
},
|
|
27
|
-
|
|
28
|
-
onCancel: () => {
|
|
29
|
-
p.cancel('Login cancelled.');
|
|
30
|
-
process.exit(0);
|
|
31
|
-
},
|
|
32
|
-
}
|
|
33
|
-
);
|
|
39
|
+
});
|
|
34
40
|
|
|
35
|
-
|
|
36
|
-
|
|
41
|
+
if (p.isCancel(token)) {
|
|
42
|
+
p.cancel('Login cancelled.');
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
37
45
|
|
|
46
|
+
const spinner = p.spinner();
|
|
47
|
+
spinner.start('Validating personal access token...');
|
|
38
48
|
try {
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
49
|
+
const account = await savePat(token);
|
|
50
|
+
config.setProfile(profileName, {
|
|
51
|
+
pat: token,
|
|
52
|
+
account_email: account.email,
|
|
53
|
+
account_name: account.display_name ?? account.email,
|
|
54
|
+
created_at: Date.now(),
|
|
43
55
|
});
|
|
56
|
+
if (profileName === 'default' || !hadProfiles) {
|
|
57
|
+
config.setActiveProfile(profileName);
|
|
58
|
+
}
|
|
59
|
+
spinner.stop('Token validated.');
|
|
60
|
+
p.outro(`Logged in as ${account.email}\nProfile: ${profileName}`);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
spinner.stop('Validation failed.');
|
|
63
|
+
p.outro(chalk.red(error instanceof Error ? error.message : 'Could not validate token'));
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function runBrowserLogin(profileName: string) {
|
|
69
|
+
const state = crypto.randomUUID();
|
|
70
|
+
const spinner = p.spinner();
|
|
71
|
+
const hadProfiles = config.listProfiles().length > 0;
|
|
72
|
+
|
|
73
|
+
await manageRequest('/cli-auth/request', {
|
|
74
|
+
method: 'POST',
|
|
75
|
+
body: { state },
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const url = getConsoleCliAuthUrl(state);
|
|
79
|
+
openBrowser(url);
|
|
80
|
+
console.log(' ' + muted('Browser URL: ') + orange(url));
|
|
81
|
+
console.log('');
|
|
82
|
+
|
|
83
|
+
spinner.start('Waiting for browser approval...');
|
|
84
|
+
const deadline = Date.now() + 5 * 60 * 1000;
|
|
85
|
+
|
|
86
|
+
while (Date.now() < deadline) {
|
|
87
|
+
try {
|
|
88
|
+
const status = await manageRequest<{ status: 'pending' | 'approved' | 'expired'; code?: string }>(
|
|
89
|
+
`/cli-auth/poll?state=${encodeURIComponent(state)}`
|
|
90
|
+
);
|
|
44
91
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
92
|
+
if (status.status === 'expired') {
|
|
93
|
+
spinner.stop('Approval window expired.');
|
|
94
|
+
p.outro(chalk.red('CLI auth request expired. Try again or use globio login --token.'));
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (status.status === 'approved' && status.code) {
|
|
99
|
+
const exchange = await manageRequest<{
|
|
100
|
+
token: string;
|
|
101
|
+
account: { email: string; display_name: string | null };
|
|
102
|
+
}>('/cli-auth/exchange', {
|
|
103
|
+
method: 'POST',
|
|
104
|
+
body: { code: status.code },
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
config.setProfile(profileName, {
|
|
108
|
+
pat: exchange.token,
|
|
109
|
+
account_email: exchange.account.email,
|
|
110
|
+
account_name: exchange.account.display_name ?? exchange.account.email,
|
|
111
|
+
created_at: Date.now(),
|
|
112
|
+
});
|
|
113
|
+
if (profileName === 'default' || !hadProfiles) {
|
|
114
|
+
config.setActiveProfile(profileName);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
spinner.stop('Browser approval received.');
|
|
118
|
+
p.outro(`Logged in as ${exchange.account.email}\nProfile: ${profileName}`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
} catch {
|
|
122
|
+
// Keep polling until timeout.
|
|
49
123
|
}
|
|
50
124
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
125
|
+
await sleep(2000);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
spinner.stop('Approval timed out.');
|
|
129
|
+
p.outro(chalk.red('Timed out waiting for browser approval. Try again or use globio login --token.'));
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export async function login(options: { token?: boolean; profile?: string } = {}) {
|
|
134
|
+
printBanner(version);
|
|
135
|
+
const profileName = options.profile ?? 'default';
|
|
136
|
+
const existing = config.getProfile(profileName);
|
|
137
|
+
|
|
138
|
+
if (existing) {
|
|
139
|
+
const proceed = await p.confirm({
|
|
140
|
+
message: `Already logged in as ${existing.account_email} on profile "${profileName}". Replace?`,
|
|
141
|
+
initialValue: false,
|
|
54
142
|
});
|
|
55
143
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
144
|
+
if (p.isCancel(proceed) || !proceed) {
|
|
145
|
+
p.outro('Login cancelled.');
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (options.token) {
|
|
151
|
+
await runTokenLogin(profileName);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const choice = await p.select({
|
|
156
|
+
message: 'Choose a login method',
|
|
157
|
+
options: [
|
|
158
|
+
{ value: 'browser', label: 'Browser', hint: 'Open console and approve access' },
|
|
159
|
+
{ value: 'token', label: 'Token', hint: 'Paste a personal access token' },
|
|
160
|
+
],
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
if (p.isCancel(choice)) {
|
|
164
|
+
p.cancel('Login cancelled.');
|
|
165
|
+
process.exit(0);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (choice === 'token') {
|
|
169
|
+
await runTokenLogin(profileName);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
await runBrowserLogin(profileName);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
p.outro(chalk.red(error instanceof Error ? error.message : 'Could not connect to Globio.'));
|
|
70
177
|
process.exit(1);
|
|
71
178
|
}
|
|
72
179
|
}
|
package/src/auth/logout.ts
CHANGED
|
@@ -1,8 +1,30 @@
|
|
|
1
|
-
import * as p from '@clack/prompts';
|
|
2
1
|
import chalk from 'chalk';
|
|
3
2
|
import { config } from '../lib/config.js';
|
|
4
3
|
|
|
5
|
-
export async function logout() {
|
|
6
|
-
config.
|
|
7
|
-
|
|
4
|
+
export async function logout(options: { profile?: string } = {}) {
|
|
5
|
+
const activeProfile = config.getActiveProfile();
|
|
6
|
+
const profileName = options.profile ?? activeProfile;
|
|
7
|
+
const profile = profileName ? config.getProfile(profileName) : null;
|
|
8
|
+
|
|
9
|
+
if (!profileName || !profile) {
|
|
10
|
+
console.log(chalk.yellow(`No active session on profile "${profileName || 'default'}".`));
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
config.deleteProfile(profileName);
|
|
15
|
+
|
|
16
|
+
if (profileName === activeProfile) {
|
|
17
|
+
const remaining = config.listProfiles();
|
|
18
|
+
if (remaining.length > 0) {
|
|
19
|
+
config.setActiveProfile(remaining[0]);
|
|
20
|
+
console.log(chalk.green(`Logged out. Switched to profile: ${remaining[0]}`));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
config.setActiveProfile('');
|
|
25
|
+
console.log(chalk.green('Logged out.'));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
console.log(chalk.green(`Logged out profile: ${profileName}`));
|
|
8
30
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { orange } from '../lib/banner.js';
|
|
3
|
+
import { config } from '../lib/config.js';
|
|
4
|
+
|
|
5
|
+
export async function useProfile(profileName: string) {
|
|
6
|
+
const profile = config.getProfile(profileName);
|
|
7
|
+
if (!profile) {
|
|
8
|
+
console.log(
|
|
9
|
+
chalk.red(
|
|
10
|
+
`Profile "${profileName}" not found. Run: globio login --profile ${profileName}`
|
|
11
|
+
)
|
|
12
|
+
);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
config.setActiveProfile(profileName);
|
|
17
|
+
console.log(
|
|
18
|
+
chalk.green('Switched to profile: ') + orange(profileName) + ` (${profile.account_email})`
|
|
19
|
+
);
|
|
20
|
+
}
|
package/src/auth/whoami.ts
CHANGED
|
@@ -1,15 +1,37 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { config } from '../lib/config.js';
|
|
3
|
+
import { muted, orange } from '../lib/banner.js';
|
|
3
4
|
|
|
4
|
-
export async function whoami() {
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
export async function whoami(options: { profile?: string } = {}) {
|
|
6
|
+
const profileName = options.profile ?? config.getActiveProfile() ?? 'default';
|
|
7
|
+
const profile = config.getProfile(profileName);
|
|
8
|
+
|
|
9
|
+
if (!profile) {
|
|
10
|
+
console.log(chalk.red('Not logged in. Run: globio login'));
|
|
8
11
|
return;
|
|
9
12
|
}
|
|
10
13
|
|
|
14
|
+
const allProfiles = config.listProfiles();
|
|
15
|
+
const activeProfile = config.getActiveProfile();
|
|
16
|
+
|
|
11
17
|
console.log('');
|
|
12
|
-
console.log(
|
|
13
|
-
|
|
18
|
+
console.log(
|
|
19
|
+
muted('Profile: ') + orange(profileName) + (profileName === activeProfile ? muted(' (active)') : '')
|
|
20
|
+
);
|
|
21
|
+
console.log(muted('Account: ') + profile.account_email);
|
|
22
|
+
console.log(muted('Name: ') + (profile.account_name || '—'));
|
|
23
|
+
console.log(
|
|
24
|
+
muted('Project: ') +
|
|
25
|
+
(profile.active_project_id
|
|
26
|
+
? orange(profile.active_project_name || 'unnamed') + muted(` (${profile.active_project_id})`)
|
|
27
|
+
: chalk.gray('none — run: globio projects use <id>'))
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
if (allProfiles.length > 1) {
|
|
31
|
+
console.log('');
|
|
32
|
+
console.log(
|
|
33
|
+
muted('Other profiles: ') + allProfiles.filter((name) => name !== profileName).join(', ')
|
|
34
|
+
);
|
|
35
|
+
}
|
|
14
36
|
console.log('');
|
|
15
37
|
}
|
|
@@ -2,11 +2,17 @@ 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 { config } from '../lib/config.js';
|
|
5
6
|
import { gold, muted, orange } from '../lib/banner.js';
|
|
6
7
|
import { getClient } from '../lib/sdk.js';
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
function resolveProfileName(profile?: string) {
|
|
10
|
+
return profile ?? config.getActiveProfile() ?? 'default';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function functionsList(options: { profile?: string } = {}) {
|
|
14
|
+
const profileName = resolveProfileName(options.profile);
|
|
15
|
+
const client = getClient(profileName);
|
|
10
16
|
const spinner = ora('Fetching functions...').start();
|
|
11
17
|
const result = await client.code.listFunctions();
|
|
12
18
|
spinner.stop();
|
|
@@ -29,7 +35,7 @@ export async function functionsList() {
|
|
|
29
35
|
console.log('');
|
|
30
36
|
}
|
|
31
37
|
|
|
32
|
-
export async function functionsCreate(slug: string) {
|
|
38
|
+
export async function functionsCreate(slug: string, _options: { profile?: string } = {}) {
|
|
33
39
|
const filename = `${slug}.js`;
|
|
34
40
|
if (existsSync(filename)) {
|
|
35
41
|
console.log(chalk.yellow(`${filename} already exists.`));
|
|
@@ -60,7 +66,7 @@ async function handler(input, globio) {
|
|
|
60
66
|
|
|
61
67
|
export async function functionsDeploy(
|
|
62
68
|
slug: string,
|
|
63
|
-
options: { file?: string; name?: string }
|
|
69
|
+
options: { file?: string; name?: string; profile?: string }
|
|
64
70
|
) {
|
|
65
71
|
const filename = options.file ?? `${slug}.js`;
|
|
66
72
|
if (!existsSync(filename)) {
|
|
@@ -73,7 +79,8 @@ export async function functionsDeploy(
|
|
|
73
79
|
}
|
|
74
80
|
|
|
75
81
|
const code = readFileSync(filename, 'utf-8');
|
|
76
|
-
const
|
|
82
|
+
const profileName = resolveProfileName(options.profile);
|
|
83
|
+
const client = getClient(profileName);
|
|
77
84
|
const spinner = ora(`Deploying ${slug}...`).start();
|
|
78
85
|
const existing = await client.code.getFunction(slug);
|
|
79
86
|
|
|
@@ -103,7 +110,7 @@ export async function functionsDeploy(
|
|
|
103
110
|
|
|
104
111
|
export async function functionsInvoke(
|
|
105
112
|
slug: string,
|
|
106
|
-
options: { input?: string }
|
|
113
|
+
options: { input?: string; profile?: string }
|
|
107
114
|
) {
|
|
108
115
|
let input: Record<string, unknown> = {};
|
|
109
116
|
if (options.input) {
|
|
@@ -115,7 +122,8 @@ export async function functionsInvoke(
|
|
|
115
122
|
}
|
|
116
123
|
}
|
|
117
124
|
|
|
118
|
-
const
|
|
125
|
+
const profileName = resolveProfileName(options.profile);
|
|
126
|
+
const client = getClient(profileName);
|
|
119
127
|
const spinner = ora(`Invoking ${slug}...`).start();
|
|
120
128
|
const result = await client.code.invoke(slug, input);
|
|
121
129
|
spinner.stop();
|
|
@@ -134,10 +142,11 @@ export async function functionsInvoke(
|
|
|
134
142
|
|
|
135
143
|
export async function functionsLogs(
|
|
136
144
|
slug: string,
|
|
137
|
-
options: { limit?: string }
|
|
145
|
+
options: { limit?: string; profile?: string }
|
|
138
146
|
) {
|
|
139
147
|
const limit = options.limit ? parseInt(options.limit, 10) : 20;
|
|
140
|
-
const
|
|
148
|
+
const profileName = resolveProfileName(options.profile);
|
|
149
|
+
const client = getClient(profileName);
|
|
141
150
|
const spinner = ora('Fetching invocations...').start();
|
|
142
151
|
const result = await client.code.getInvocations(slug, limit);
|
|
143
152
|
spinner.stop();
|
|
@@ -163,8 +172,9 @@ export async function functionsLogs(
|
|
|
163
172
|
console.log('');
|
|
164
173
|
}
|
|
165
174
|
|
|
166
|
-
export async function functionsDelete(slug: string) {
|
|
167
|
-
const
|
|
175
|
+
export async function functionsDelete(slug: string, options: { profile?: string } = {}) {
|
|
176
|
+
const profileName = resolveProfileName(options.profile);
|
|
177
|
+
const client = getClient(profileName);
|
|
168
178
|
const spinner = ora(`Deleting ${slug}...`).start();
|
|
169
179
|
const result = await client.code.deleteFunction(slug);
|
|
170
180
|
if (!result.success) {
|
|
@@ -175,8 +185,13 @@ export async function functionsDelete(slug: string) {
|
|
|
175
185
|
spinner.succeed(`Deleted ${slug}`);
|
|
176
186
|
}
|
|
177
187
|
|
|
178
|
-
export async function functionsToggle(
|
|
179
|
-
|
|
188
|
+
export async function functionsToggle(
|
|
189
|
+
slug: string,
|
|
190
|
+
active: boolean,
|
|
191
|
+
options: { profile?: string } = {}
|
|
192
|
+
) {
|
|
193
|
+
const profileName = resolveProfileName(options.profile);
|
|
194
|
+
const client = getClient(profileName);
|
|
180
195
|
const spinner = ora(
|
|
181
196
|
`${active ? 'Enabling' : 'Disabling'} ${slug}...`
|
|
182
197
|
).start();
|
package/src/commands/init.ts
CHANGED
|
@@ -10,26 +10,43 @@ import {
|
|
|
10
10
|
} from '../lib/banner.js';
|
|
11
11
|
import { promptInit } from '../prompts/init.js';
|
|
12
12
|
import { migrateFirestore, migrateFirebaseStorage } from './migrate.js';
|
|
13
|
+
import { projectsCreate, projectsUse } from './projects.js';
|
|
13
14
|
|
|
14
15
|
const version = getCliVersion();
|
|
15
16
|
|
|
16
|
-
export async function init() {
|
|
17
|
+
export async function init(options: { profile?: string } = {}) {
|
|
17
18
|
printBanner(version);
|
|
18
19
|
p.intro(orange('⇒⇒') + ' Initialize your Globio project');
|
|
19
20
|
|
|
21
|
+
const profileName = options.profile ?? config.getActiveProfile() ?? 'default';
|
|
22
|
+
const profile = config.getProfile(profileName);
|
|
23
|
+
if (!profile) {
|
|
24
|
+
console.log('Run: npx @globio/cli login --profile ' + profileName);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!profile.active_project_id) {
|
|
29
|
+
await projectsCreate({ profile: profileName });
|
|
30
|
+
} else {
|
|
31
|
+
await projectsUse(profile.active_project_id, { profile: profileName });
|
|
32
|
+
}
|
|
33
|
+
|
|
20
34
|
const values = await promptInit();
|
|
35
|
+
const activeProfile = config.getProfile(profileName);
|
|
36
|
+
const activeProjectKey = activeProfile?.project_api_key;
|
|
37
|
+
const { projectId: activeProjectId } = config.requireProject(profileName);
|
|
21
38
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
39
|
+
if (!activeProjectKey) {
|
|
40
|
+
console.log('No project API key cached. Run: npx @globio/cli projects use ' + activeProjectId);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
26
43
|
|
|
27
44
|
if (!existsSync('globio.config.ts')) {
|
|
28
45
|
writeFileSync(
|
|
29
46
|
'globio.config.ts',
|
|
30
|
-
`import {
|
|
47
|
+
`import { Globio } from '@globio/sdk';
|
|
31
48
|
|
|
32
|
-
export const globio = new
|
|
49
|
+
export const globio = new Globio({
|
|
33
50
|
apiKey: process.env.GLOBIO_API_KEY!,
|
|
34
51
|
});
|
|
35
52
|
`
|
|
@@ -38,7 +55,7 @@ export const globio = new GlobioClient({
|
|
|
38
55
|
}
|
|
39
56
|
|
|
40
57
|
if (!existsSync('.env')) {
|
|
41
|
-
writeFileSync('.env', `GLOBIO_API_KEY=${
|
|
58
|
+
writeFileSync('.env', `GLOBIO_API_KEY=${activeProjectKey}\n`);
|
|
42
59
|
printSuccess('Created .env');
|
|
43
60
|
}
|
|
44
61
|
|
|
@@ -49,6 +66,7 @@ export const globio = new GlobioClient({
|
|
|
49
66
|
await migrateFirestore({
|
|
50
67
|
from: values.serviceAccountPath as string,
|
|
51
68
|
all: true,
|
|
69
|
+
profile: profileName,
|
|
52
70
|
});
|
|
53
71
|
|
|
54
72
|
const serviceAccount = JSON.parse(
|
|
@@ -59,6 +77,7 @@ export const globio = new GlobioClient({
|
|
|
59
77
|
from: values.serviceAccountPath as string,
|
|
60
78
|
bucket: `${serviceAccount.project_id}.appspot.com`,
|
|
61
79
|
all: true,
|
|
80
|
+
profile: profileName,
|
|
62
81
|
});
|
|
63
82
|
}
|
|
64
83
|
|
|
@@ -70,6 +89,7 @@ export const globio = new GlobioClient({
|
|
|
70
89
|
muted('Next steps:') +
|
|
71
90
|
'\n\n' +
|
|
72
91
|
' npm install @globio/sdk\n' +
|
|
92
|
+
` # active project: ${activeProjectId}\n` +
|
|
73
93
|
' npx @globio/cli functions create my-first-function'
|
|
74
94
|
);
|
|
75
95
|
}
|
package/src/commands/migrate.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import { initFirebase } from '../lib/firebase.js';
|
|
12
12
|
import { createProgressBar } from '../lib/progress.js';
|
|
13
13
|
import { getClient } from '../lib/sdk.js';
|
|
14
|
+
import { config } from '../lib/config.js';
|
|
14
15
|
|
|
15
16
|
const version = getCliVersion();
|
|
16
17
|
|
|
@@ -18,6 +19,7 @@ interface MigrateFirestoreOptions {
|
|
|
18
19
|
from: string;
|
|
19
20
|
collection?: string;
|
|
20
21
|
all?: boolean;
|
|
22
|
+
profile?: string;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
interface MigrateStorageOptions {
|
|
@@ -25,6 +27,11 @@ interface MigrateStorageOptions {
|
|
|
25
27
|
bucket: string;
|
|
26
28
|
folder?: string;
|
|
27
29
|
all?: boolean;
|
|
30
|
+
profile?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function resolveProfileName(profile?: string) {
|
|
34
|
+
return profile ?? config.getActiveProfile() ?? 'default';
|
|
28
35
|
}
|
|
29
36
|
|
|
30
37
|
export async function migrateFirestore(options: MigrateFirestoreOptions) {
|
|
@@ -32,7 +39,7 @@ export async function migrateFirestore(options: MigrateFirestoreOptions) {
|
|
|
32
39
|
p.intro(gold('⇒⇒') + ' Firebase → Globio Migration');
|
|
33
40
|
|
|
34
41
|
const { firestore } = await initFirebase(options.from);
|
|
35
|
-
const client = getClient();
|
|
42
|
+
const client = getClient(resolveProfileName(options.profile));
|
|
36
43
|
|
|
37
44
|
let collections: string[] = [];
|
|
38
45
|
|
|
@@ -139,7 +146,7 @@ export async function migrateFirebaseStorage(options: MigrateStorageOptions) {
|
|
|
139
146
|
p.intro(gold('⇒⇒') + ' Firebase → Globio Migration');
|
|
140
147
|
|
|
141
148
|
const { storage } = await initFirebase(options.from);
|
|
142
|
-
const client = getClient();
|
|
149
|
+
const client = getClient(resolveProfileName(options.profile));
|
|
143
150
|
|
|
144
151
|
const bucketName = options.bucket.replace(/^gs:\/\//, '');
|
|
145
152
|
const bucket = storage.bucket(bucketName);
|