nukebase 2.0.0 → 2.0.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/bin/nukebase.js +12 -3
- package/lib/account-commands.js +43 -0
- package/lib/login.js +7 -1
- package/package.json +1 -1
package/bin/nukebase.js
CHANGED
|
@@ -20,6 +20,9 @@ function usage() {
|
|
|
20
20
|
|
|
21
21
|
Usage: nukebase <command> (or: npx nukebase <command>)
|
|
22
22
|
|
|
23
|
+
New here? Run: npx nukebase start
|
|
24
|
+
signs you in, creates a project and downloads it, ready to build
|
|
25
|
+
|
|
23
26
|
Accounts
|
|
24
27
|
login sign in by approving in your browser
|
|
25
28
|
login --email you@x.com sign in as a specific account (adds it; others stay)
|
|
@@ -33,6 +36,8 @@ Accounts
|
|
|
33
36
|
whoami who owns this project, and are you signed in
|
|
34
37
|
|
|
35
38
|
New projects
|
|
39
|
+
start [name] [size] outside a project: sign in if needed, then create
|
|
40
|
+
(inside a project, start = restart)
|
|
36
41
|
create <name> [size] [email]
|
|
37
42
|
make a project and download it, e.g.
|
|
38
43
|
nukebase create demoapp123 256mb you@example.com
|
|
@@ -79,15 +84,19 @@ dashboard under Signed-in devices).
|
|
|
79
84
|
Sign-ins are kept in ~/.nukebase/credentials.json, never in a project.`);
|
|
80
85
|
}
|
|
81
86
|
|
|
82
|
-
|
|
87
|
+
let command = args.command;
|
|
88
|
+
|
|
89
|
+
// `start` means two things: inside a project it restarts the app (as it always
|
|
90
|
+
// has); anywhere else it is the new-user setup (sign in, create, download).
|
|
91
|
+
if (command === 'start' && !require('../lib/project').findProject(process.cwd())) command = 'setup';
|
|
83
92
|
|
|
84
93
|
if (args.has('version') && !command) {
|
|
85
94
|
console.log(version);
|
|
86
95
|
} else if (!command || command === 'help' || (args.has('help') && !command)) {
|
|
87
96
|
usage();
|
|
88
|
-
} else if (ACCOUNT_COMMANDS.includes(command)) {
|
|
97
|
+
} else if (ACCOUNT_COMMANDS.includes(command) || command === 'setup') {
|
|
89
98
|
Promise.resolve()
|
|
90
|
-
.then(() => require('../lib/account-commands')[command](args))
|
|
99
|
+
.then(() => require('../lib/account-commands')[command === 'setup' ? 'start' : command](args))
|
|
91
100
|
.then(() => process.exit(0), err => { console.error('❌', err.message); process.exit(1); });
|
|
92
101
|
} else if (PROJECT_COMMANDS.includes(command)) {
|
|
93
102
|
require('../lib/project-commands');
|
package/lib/account-commands.js
CHANGED
|
@@ -295,6 +295,10 @@ async function createCommand(args) {
|
|
|
295
295
|
let msg = '';
|
|
296
296
|
try { msg = (await res.json()).error; } catch {}
|
|
297
297
|
if (res.status === 401) fail(`The sign-in for ${acct.label} is no longer valid. Run: nukebase login --email ${acct.label}`);
|
|
298
|
+
// No plan, or no credit: both are fixed on the dashboard.
|
|
299
|
+
if (res.status === 403 && /plan|funds|credit|wallet|balance/i.test(msg)) {
|
|
300
|
+
fail(`${msg}\n Choose a plan or add credit at ${api}/`);
|
|
301
|
+
}
|
|
298
302
|
fail(`Create failed (${res.status}): ${msg || res.statusText}`);
|
|
299
303
|
}
|
|
300
304
|
|
|
@@ -319,6 +323,44 @@ async function createCommand(args) {
|
|
|
319
323
|
console.log(' nukebase push deploy your changes');
|
|
320
324
|
}
|
|
321
325
|
|
|
326
|
+
// ---- start ----------------------------------------------------------------
|
|
327
|
+
// The one command a new user runs after signing up: sign in if needed, then
|
|
328
|
+
// create a project and download it. `nukebase start [name] [size] [email]`.
|
|
329
|
+
// (Inside a project folder `start` means restart; bin/nukebase.js routes it.)
|
|
330
|
+
|
|
331
|
+
async function startCommand(args) {
|
|
332
|
+
const autoYes = args.has('yes');
|
|
333
|
+
const { parse } = require('./args');
|
|
334
|
+
const passFlags = [];
|
|
335
|
+
for (const f of ['api', 'region']) if (args.get(f)) passFlags.push(`--${f}`, args.get(f));
|
|
336
|
+
if (autoYes) passFlags.push('--yes');
|
|
337
|
+
if (args.has('no-install')) passFlags.push('--no-install');
|
|
338
|
+
|
|
339
|
+
console.log('\n Welcome to NukeBase.');
|
|
340
|
+
const emailArg = args.positional.find(a => a.includes('@'));
|
|
341
|
+
if (!creds.list().length || (emailArg && !creds.find(emailArg))) {
|
|
342
|
+
console.log('\n Step 1 of 2: sign in. Click Allow in the browser window that opens.');
|
|
343
|
+
await loginCommand(parse(['login', ...(emailArg ? ['--email', emailArg] : []), ...passFlags]));
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
console.log(`\n ${creds.list().length ? 'Step 2 of 2: ' : ''}create your project`);
|
|
347
|
+
let name = args.positional.find(a => !a.includes('@') && PROJECT_NAME_RE.test(a));
|
|
348
|
+
if (!name) {
|
|
349
|
+
if (autoYes || !process.stdin.isTTY) fail('Give the project a name, e.g.: nukebase start myapp');
|
|
350
|
+
for (;;) {
|
|
351
|
+
name = (await makeAskLine(false)('\n Project name (lowercase, e.g. myapp): ')).trim().toLowerCase();
|
|
352
|
+
if (!name) fail('No name given.');
|
|
353
|
+
if (PROJECT_NAME_RE.test(name)) break;
|
|
354
|
+
console.log(' 3-31 characters: lowercase letters, numbers, - and _, starting with a letter.');
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
const rest = args.positional.filter(a => a !== name);
|
|
358
|
+
await createCommand(parse(['create', name, ...rest, ...passFlags]));
|
|
359
|
+
|
|
360
|
+
console.log('\n Building with Claude Code? Open the folder and describe your app.');
|
|
361
|
+
console.log(' Its CLAUDE.md explains NukeBase, and Claude can deploy with: npx nukebase push --yes');
|
|
362
|
+
}
|
|
363
|
+
|
|
322
364
|
// ---- link -----------------------------------------------------------------
|
|
323
365
|
|
|
324
366
|
async function linkCommand(args) {
|
|
@@ -364,6 +406,7 @@ module.exports = {
|
|
|
364
406
|
use: useCommand,
|
|
365
407
|
whoami: whoamiCommand,
|
|
366
408
|
create: createCommand,
|
|
409
|
+
start: startCommand,
|
|
367
410
|
link: linkCommand,
|
|
368
411
|
resolveTier, sizeToMb
|
|
369
412
|
};
|
package/lib/login.js
CHANGED
|
@@ -98,7 +98,13 @@ async function browser(api, { email } = {}) {
|
|
|
98
98
|
console.log(' Waiting for approval… (Ctrl+C to cancel)');
|
|
99
99
|
openBrowser(url.toString());
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
// The usual reason for a long wait: no account yet, so no sign-in email
|
|
102
|
+
// ever arrives (the server doesn't say which addresses have accounts).
|
|
103
|
+
const hint = setTimeout(() => {
|
|
104
|
+
console.log(`\n Still waiting. No account yet? Sign up at ${api}/start.html first, then run this again.`);
|
|
105
|
+
}, 90 * 1000);
|
|
106
|
+
hint.unref();
|
|
107
|
+
const q = await result.finally(() => clearTimeout(hint));
|
|
102
108
|
if (q.error) throw new Error('Sign-in was cancelled in the browser.');
|
|
103
109
|
if (!q.code) throw new Error('The browser did not return a sign-in code.');
|
|
104
110
|
const r = await postJson(`${api}/cli/token`, { code: q.code, verifier });
|