@sendblue/cli 0.2.0 → 0.4.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/commands/add-contact.js +10 -10
- package/dist/commands/login.d.ts +1 -0
- package/dist/commands/login.js +84 -0
- package/dist/commands/send.js +9 -5
- package/dist/commands/setup.d.ts +1 -1
- package/dist/commands/setup.js +41 -32
- package/dist/commands/status.js +5 -2
- package/dist/commands/whoami.js +11 -2
- package/dist/index.js +11 -3
- package/dist/lib/api.d.ts +3 -1
- package/dist/lib/api.js +15 -3
- package/dist/lib/format.d.ts +1 -0
- package/dist/lib/format.js +18 -1
- package/package.json +2 -1
|
@@ -1,29 +1,27 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
2
3
|
import { getCredentials } from '../lib/config.js';
|
|
3
4
|
import { addContact, getSharedContacts } from '../lib/api.js';
|
|
4
|
-
import { formatPhoneNumber,
|
|
5
|
+
import { formatPhoneNumber, normalizeNumber, printError } from '../lib/format.js';
|
|
5
6
|
export async function addContactCommand(number) {
|
|
6
7
|
const creds = getCredentials();
|
|
7
8
|
if (!creds) {
|
|
8
9
|
printError('No credentials found. Run `sendblue login` first.');
|
|
9
10
|
process.exit(1);
|
|
10
11
|
}
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
console.log();
|
|
14
|
-
printInfo(` Adding contact ${formatPhoneNumber(normalized)}...`);
|
|
12
|
+
const normalized = normalizeNumber(number);
|
|
13
|
+
const spinner = ora({ text: `Adding contact ${formatPhoneNumber(normalized)}...`, indent: 2 }).start();
|
|
15
14
|
try {
|
|
16
15
|
const result = await addContact(creds.apiKey, creds.apiSecret, normalized);
|
|
17
16
|
if (result.verified) {
|
|
18
|
-
|
|
17
|
+
spinner.succeed(`Contact ${formatPhoneNumber(normalized)} is already verified!`);
|
|
19
18
|
console.log();
|
|
20
19
|
console.log(chalk.bold(' You can now send messages:'));
|
|
21
20
|
console.log(chalk.cyan(` sendblue send ${normalized} "Hello!"`));
|
|
22
21
|
console.log();
|
|
23
22
|
return;
|
|
24
23
|
}
|
|
25
|
-
|
|
26
|
-
console.log(chalk.green(` Contact added!`));
|
|
24
|
+
spinner.succeed('Contact added!');
|
|
27
25
|
console.log();
|
|
28
26
|
// Get the shared number
|
|
29
27
|
const contacts = await getSharedContacts(creds.apiKey, creds.apiSecret);
|
|
@@ -46,7 +44,7 @@ export async function addContactCommand(number) {
|
|
|
46
44
|
console.log();
|
|
47
45
|
}
|
|
48
46
|
catch (err) {
|
|
49
|
-
|
|
47
|
+
spinner.fail(`Failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
50
48
|
process.exit(1);
|
|
51
49
|
}
|
|
52
50
|
}
|
|
@@ -56,8 +54,10 @@ export async function contactsCommand() {
|
|
|
56
54
|
printError('No credentials found. Run `sendblue login` first.');
|
|
57
55
|
process.exit(1);
|
|
58
56
|
}
|
|
57
|
+
const spinner = ora({ text: 'Fetching contacts...', indent: 2 }).start();
|
|
59
58
|
try {
|
|
60
59
|
const result = await getSharedContacts(creds.apiKey, creds.apiSecret);
|
|
60
|
+
spinner.stop();
|
|
61
61
|
console.log();
|
|
62
62
|
console.log(chalk.bold(' Contacts'));
|
|
63
63
|
if (result.sharedNumber) {
|
|
@@ -84,7 +84,7 @@ export async function contactsCommand() {
|
|
|
84
84
|
console.log();
|
|
85
85
|
}
|
|
86
86
|
catch (err) {
|
|
87
|
-
|
|
87
|
+
spinner.fail(`Failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
88
88
|
process.exit(1);
|
|
89
89
|
}
|
|
90
90
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function loginCommand(): Promise<void>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import prompts from 'prompts';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import { getCredentials, saveCredentials, credentialsPath } from '../lib/config.js';
|
|
5
|
+
import { sendCode, verifyLogin } from '../lib/api.js';
|
|
6
|
+
import { printError, formatPhoneNumber } from '../lib/format.js';
|
|
7
|
+
const onCancel = () => {
|
|
8
|
+
console.log();
|
|
9
|
+
printError('Login cancelled.');
|
|
10
|
+
process.exit(0);
|
|
11
|
+
};
|
|
12
|
+
export async function loginCommand() {
|
|
13
|
+
console.log();
|
|
14
|
+
console.log(chalk.bold(' sendblue login'));
|
|
15
|
+
console.log(chalk.dim(' Log in to an existing Sendblue account'));
|
|
16
|
+
console.log();
|
|
17
|
+
// Check for existing credentials
|
|
18
|
+
const existing = getCredentials();
|
|
19
|
+
if (existing) {
|
|
20
|
+
const { overwrite } = await prompts({
|
|
21
|
+
type: 'confirm',
|
|
22
|
+
name: 'overwrite',
|
|
23
|
+
message: `You already have an account configured (${existing.email}). Overwrite?`,
|
|
24
|
+
initial: false
|
|
25
|
+
}, { onCancel });
|
|
26
|
+
if (!overwrite) {
|
|
27
|
+
console.log(chalk.dim(' Login cancelled.'));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Step 1: Collect email
|
|
32
|
+
const { email } = await prompts({
|
|
33
|
+
type: 'text',
|
|
34
|
+
name: 'email',
|
|
35
|
+
message: 'Email',
|
|
36
|
+
validate: (v) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v) || 'Enter a valid email'
|
|
37
|
+
}, { onCancel });
|
|
38
|
+
// Step 2: Send verification code
|
|
39
|
+
const sendSpinner = ora({ text: 'Sending verification code...', indent: 2 }).start();
|
|
40
|
+
try {
|
|
41
|
+
await sendCode(email);
|
|
42
|
+
sendSpinner.succeed(`Code sent to ${email}`);
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
sendSpinner.fail(`Failed to send code: ${err instanceof Error ? err.message : String(err)}`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
console.log();
|
|
49
|
+
// Step 3: Enter code
|
|
50
|
+
const { code } = await prompts({
|
|
51
|
+
type: 'text',
|
|
52
|
+
name: 'code',
|
|
53
|
+
message: 'Verification code',
|
|
54
|
+
validate: (v) => /^\d{8}$/.test(v) || 'Enter the 8-digit code from your email'
|
|
55
|
+
}, { onCancel });
|
|
56
|
+
// Step 4: Verify code + look up existing account
|
|
57
|
+
const loginSpinner = ora({ text: 'Logging in...', indent: 2 }).start();
|
|
58
|
+
try {
|
|
59
|
+
const result = await verifyLogin(email, code);
|
|
60
|
+
loginSpinner.succeed('Logged in!');
|
|
61
|
+
saveCredentials({
|
|
62
|
+
apiKey: result.apiKey,
|
|
63
|
+
apiSecret: result.apiSecret,
|
|
64
|
+
email: result.email,
|
|
65
|
+
assignedNumber: result.assignedNumber,
|
|
66
|
+
plan: result.plan,
|
|
67
|
+
createdAt: new Date().toISOString()
|
|
68
|
+
});
|
|
69
|
+
console.log();
|
|
70
|
+
console.log(` ${chalk.bold('Email')}: ${result.email}`);
|
|
71
|
+
console.log(` ${chalk.bold('Company')}: ${result.companyName}`);
|
|
72
|
+
if (result.assignedNumber) {
|
|
73
|
+
console.log(` ${chalk.bold('Phone Number')}: ${formatPhoneNumber(result.assignedNumber)}`);
|
|
74
|
+
}
|
|
75
|
+
console.log(` ${chalk.bold('Plan')}: ${result.plan}`);
|
|
76
|
+
console.log();
|
|
77
|
+
console.log(chalk.dim(` Credentials saved to ${credentialsPath()}`));
|
|
78
|
+
console.log();
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
loginSpinner.fail(`Login failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
}
|
package/dist/commands/send.js
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
2
3
|
import { getCredentials } from '../lib/config.js';
|
|
3
4
|
import { sendMessage } from '../lib/api.js';
|
|
4
|
-
import {
|
|
5
|
+
import { normalizeNumber } from '../lib/format.js';
|
|
6
|
+
import { printError } from '../lib/format.js';
|
|
5
7
|
export async function sendCommand(number, message) {
|
|
6
8
|
const creds = getCredentials();
|
|
7
9
|
if (!creds) {
|
|
8
|
-
printError('No credentials found. Run `sendblue
|
|
10
|
+
printError('No credentials found. Run `sendblue login` first.');
|
|
9
11
|
process.exit(1);
|
|
10
12
|
}
|
|
13
|
+
const normalized = normalizeNumber(number);
|
|
14
|
+
const spinner = ora({ text: `Sending to ${normalized}...`, indent: 2 }).start();
|
|
11
15
|
try {
|
|
12
|
-
const result = await sendMessage(creds.apiKey, creds.apiSecret,
|
|
13
|
-
|
|
16
|
+
const result = await sendMessage(creds.apiKey, creds.apiSecret, normalized, message);
|
|
17
|
+
spinner.succeed(`Message sent to ${normalized}`);
|
|
14
18
|
if (result.messageId) {
|
|
15
19
|
console.log(chalk.dim(` Message ID: ${result.messageId}`));
|
|
16
20
|
}
|
|
17
21
|
}
|
|
18
22
|
catch (err) {
|
|
19
|
-
|
|
23
|
+
spinner.fail(`Send failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
20
24
|
process.exit(1);
|
|
21
25
|
}
|
|
22
26
|
}
|
package/dist/commands/setup.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function
|
|
1
|
+
export declare function setupCommand(): Promise<void>;
|
package/dist/commands/setup.js
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import prompts from 'prompts';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
+
import ora from 'ora';
|
|
3
4
|
import { getCredentials, saveCredentials, credentialsPath } from '../lib/config.js';
|
|
4
|
-
import { sendCode,
|
|
5
|
-
import { printCredentials, printError,
|
|
6
|
-
|
|
5
|
+
import { sendCode, verifySetup } from '../lib/api.js';
|
|
6
|
+
import { printCredentials, printError, formatPhoneNumber } from '../lib/format.js';
|
|
7
|
+
const onCancel = () => {
|
|
7
8
|
console.log();
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
printError('Setup cancelled.');
|
|
10
|
+
process.exit(0);
|
|
11
|
+
};
|
|
12
|
+
export async function setupCommand() {
|
|
13
|
+
console.log();
|
|
14
|
+
console.log(chalk.bold(' sendblue setup'));
|
|
15
|
+
console.log(chalk.dim(' Create a new Sendblue account'));
|
|
10
16
|
console.log();
|
|
11
17
|
// Check for existing credentials
|
|
12
18
|
const existing = getCredentials();
|
|
@@ -16,9 +22,9 @@ export async function loginCommand() {
|
|
|
16
22
|
name: 'overwrite',
|
|
17
23
|
message: `You already have an account configured (${existing.email}). Overwrite?`,
|
|
18
24
|
initial: false
|
|
19
|
-
});
|
|
25
|
+
}, { onCancel });
|
|
20
26
|
if (!overwrite) {
|
|
21
|
-
|
|
27
|
+
console.log(chalk.dim(' Setup cancelled.'));
|
|
22
28
|
return;
|
|
23
29
|
}
|
|
24
30
|
}
|
|
@@ -28,46 +34,45 @@ export async function loginCommand() {
|
|
|
28
34
|
name: 'email',
|
|
29
35
|
message: 'Email',
|
|
30
36
|
validate: (v) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v) || 'Enter a valid email'
|
|
31
|
-
});
|
|
32
|
-
if (!email) {
|
|
33
|
-
printError('Login cancelled.');
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
37
|
+
}, { onCancel });
|
|
36
38
|
// Step 2: Send verification code
|
|
37
|
-
|
|
38
|
-
printInfo(' Sending verification code...');
|
|
39
|
+
const sendSpinner = ora({ text: 'Sending verification code...', indent: 2 }).start();
|
|
39
40
|
try {
|
|
40
41
|
await sendCode(email);
|
|
42
|
+
sendSpinner.succeed(`Code sent to ${email}`);
|
|
41
43
|
}
|
|
42
44
|
catch (err) {
|
|
43
|
-
|
|
45
|
+
sendSpinner.fail(`Failed to send code: ${err instanceof Error ? err.message : String(err)}`);
|
|
44
46
|
process.exit(1);
|
|
45
47
|
}
|
|
46
|
-
console.log(chalk.green(` Code sent to ${email}`));
|
|
47
48
|
console.log();
|
|
48
49
|
// Step 3: Enter code
|
|
49
50
|
const { code } = await prompts({
|
|
50
51
|
type: 'text',
|
|
51
52
|
name: 'code',
|
|
52
53
|
message: 'Verification code',
|
|
53
|
-
validate: (v) => /^\d{
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
printError('Login cancelled.');
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
// Step 4: Optional company name
|
|
54
|
+
validate: (v) => /^\d{8}$/.test(v) || 'Enter the 8-digit code from your email'
|
|
55
|
+
}, { onCancel });
|
|
56
|
+
// Step 4: Company name (required for setup)
|
|
60
57
|
const { companyName } = await prompts({
|
|
61
58
|
type: 'text',
|
|
62
59
|
name: 'companyName',
|
|
63
|
-
message: 'Company name (
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
60
|
+
message: 'Company name (lowercase, hyphens/underscores only)',
|
|
61
|
+
validate: (v) => {
|
|
62
|
+
if (!v)
|
|
63
|
+
return 'Company name is required';
|
|
64
|
+
if (!/^[a-z0-9_-]+$/.test(v))
|
|
65
|
+
return 'Only lowercase letters, numbers, hyphens, and underscores';
|
|
66
|
+
if (v.length < 3 || v.length > 64)
|
|
67
|
+
return 'Must be 3-64 characters';
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
}, { onCancel });
|
|
68
71
|
// Step 5: Verify code + create account
|
|
72
|
+
const setupSpinner = ora({ text: 'Setting up your account...', indent: 2 }).start();
|
|
69
73
|
try {
|
|
70
|
-
const result = await
|
|
74
|
+
const result = await verifySetup(email, code, companyName);
|
|
75
|
+
setupSpinner.succeed('Account created!');
|
|
71
76
|
saveCredentials({
|
|
72
77
|
apiKey: result.apiKey,
|
|
73
78
|
apiSecret: result.apiSecret,
|
|
@@ -79,12 +84,16 @@ export async function loginCommand() {
|
|
|
79
84
|
printCredentials(result);
|
|
80
85
|
console.log(chalk.dim(` Credentials saved to ${credentialsPath()}`));
|
|
81
86
|
console.log();
|
|
82
|
-
console.log(chalk.bold('
|
|
83
|
-
console.log(chalk.cyan(` sendblue
|
|
87
|
+
console.log(chalk.bold(' Next step — add a contact:'));
|
|
88
|
+
console.log(chalk.cyan(` sendblue add-contact +15551234567`));
|
|
84
89
|
console.log();
|
|
90
|
+
if (result.assignedNumber) {
|
|
91
|
+
console.log(chalk.dim(` Your contact will need to text ${formatPhoneNumber(result.assignedNumber)} to verify.`));
|
|
92
|
+
console.log();
|
|
93
|
+
}
|
|
85
94
|
}
|
|
86
95
|
catch (err) {
|
|
87
|
-
|
|
96
|
+
setupSpinner.fail(`Setup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
88
97
|
process.exit(1);
|
|
89
98
|
}
|
|
90
99
|
}
|
package/dist/commands/status.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
2
3
|
import { getCredentials } from '../lib/config.js';
|
|
3
4
|
import { getAccount } from '../lib/api.js';
|
|
4
5
|
import { formatPhoneNumber, printError } from '../lib/format.js';
|
|
5
6
|
export async function statusCommand() {
|
|
6
7
|
const creds = getCredentials();
|
|
7
8
|
if (!creds) {
|
|
8
|
-
printError('No credentials found. Run `sendblue
|
|
9
|
+
printError('No credentials found. Run `sendblue login` first.');
|
|
9
10
|
process.exit(1);
|
|
10
11
|
}
|
|
12
|
+
const spinner = ora({ text: 'Fetching account status...', indent: 2 }).start();
|
|
11
13
|
try {
|
|
12
14
|
const account = await getAccount(creds.apiKey, creds.apiSecret);
|
|
15
|
+
spinner.stop();
|
|
13
16
|
console.log();
|
|
14
17
|
console.log(chalk.bold(' Account Status'));
|
|
15
18
|
console.log();
|
|
@@ -19,7 +22,7 @@ export async function statusCommand() {
|
|
|
19
22
|
console.log();
|
|
20
23
|
}
|
|
21
24
|
catch (err) {
|
|
22
|
-
|
|
25
|
+
spinner.fail(`Failed to fetch status: ${err instanceof Error ? err.message : String(err)}`);
|
|
23
26
|
process.exit(1);
|
|
24
27
|
}
|
|
25
28
|
}
|
package/dist/commands/whoami.js
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
2
3
|
import { getCredentials, credentialsPath } from '../lib/config.js';
|
|
3
4
|
import { testKeys } from '../lib/api.js';
|
|
4
5
|
import { formatPhoneNumber, printError } from '../lib/format.js';
|
|
5
6
|
export async function whoamiCommand() {
|
|
6
7
|
const creds = getCredentials();
|
|
7
8
|
if (!creds) {
|
|
8
|
-
printError('No credentials found. Run `sendblue
|
|
9
|
+
printError('No credentials found. Run `sendblue login` first.');
|
|
9
10
|
process.exit(1);
|
|
10
11
|
}
|
|
11
|
-
const
|
|
12
|
+
const spinner = ora({ text: 'Validating keys...', indent: 2 }).start();
|
|
13
|
+
let valid = false;
|
|
14
|
+
try {
|
|
15
|
+
valid = await testKeys(creds.apiKey, creds.apiSecret);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
// Network error — keys may still be valid
|
|
19
|
+
}
|
|
20
|
+
spinner.stop();
|
|
12
21
|
console.log();
|
|
13
22
|
console.log(chalk.bold(' Current Account'));
|
|
14
23
|
console.log();
|
package/dist/index.js
CHANGED
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
2
3
|
import { Command } from 'commander';
|
|
3
|
-
import {
|
|
4
|
+
import { setupCommand } from './commands/setup.js';
|
|
5
|
+
import { loginCommand } from './commands/login.js';
|
|
4
6
|
import { sendCommand } from './commands/send.js';
|
|
5
7
|
import { statusCommand } from './commands/status.js';
|
|
6
8
|
import { whoamiCommand } from './commands/whoami.js';
|
|
7
9
|
import { addContactCommand, contactsCommand } from './commands/add-contact.js';
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
11
|
+
const { version } = require('../package.json');
|
|
8
12
|
const program = new Command();
|
|
9
13
|
program
|
|
10
14
|
.name('sendblue')
|
|
11
15
|
.description('Sendblue CLI — iMessage numbers for agents')
|
|
12
|
-
.version(
|
|
16
|
+
.version(version);
|
|
17
|
+
program
|
|
18
|
+
.command('setup')
|
|
19
|
+
.description('Create a new Sendblue account and get an iMessage number')
|
|
20
|
+
.action(setupCommand);
|
|
13
21
|
program
|
|
14
22
|
.command('login')
|
|
15
|
-
.description('
|
|
23
|
+
.description('Log in to an existing Sendblue account')
|
|
16
24
|
.action(loginCommand);
|
|
17
25
|
program
|
|
18
26
|
.command('add-contact')
|
package/dist/lib/api.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
interface SetupResponse {
|
|
2
2
|
status: string;
|
|
3
3
|
email: string;
|
|
4
|
+
companyName: string;
|
|
4
5
|
apiKey: string;
|
|
5
6
|
apiSecret: string;
|
|
6
7
|
assignedNumber: string;
|
|
@@ -19,7 +20,8 @@ interface AccountResponse {
|
|
|
19
20
|
[key: string]: unknown;
|
|
20
21
|
}
|
|
21
22
|
export declare function sendCode(email: string): Promise<void>;
|
|
22
|
-
export declare function
|
|
23
|
+
export declare function verifySetup(email: string, code: string, companyName: string): Promise<SetupResponse>;
|
|
24
|
+
export declare function verifyLogin(email: string, code: string): Promise<SetupResponse>;
|
|
23
25
|
export declare function sendMessage(apiKey: string, apiSecret: string, number: string, content: string): Promise<SendMessageResponse>;
|
|
24
26
|
export declare function getAccount(apiKey: string, apiSecret: string): Promise<AccountResponse>;
|
|
25
27
|
interface ContactRoute {
|
package/dist/lib/api.js
CHANGED
|
@@ -11,15 +11,27 @@ export async function sendCode(email) {
|
|
|
11
11
|
throw new Error(body.error || body.message || `Failed to send code (${res.status})`);
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
-
export async function
|
|
14
|
+
export async function verifySetup(email, code, companyName) {
|
|
15
15
|
const res = await fetch(`${SETUP_BASE}/api/v3/cli/setup`, {
|
|
16
16
|
method: 'POST',
|
|
17
17
|
headers: { 'Content-Type': 'application/json' },
|
|
18
|
-
body: JSON.stringify({ email, code, companyName, action: 'verify' })
|
|
18
|
+
body: JSON.stringify({ email, code, companyName, action: 'verify-setup' })
|
|
19
19
|
});
|
|
20
20
|
if (!res.ok) {
|
|
21
21
|
const body = await res.json().catch(() => ({}));
|
|
22
|
-
throw new Error(body.error || body.message || `
|
|
22
|
+
throw new Error(body.error || body.message || `Setup failed (${res.status})`);
|
|
23
|
+
}
|
|
24
|
+
return res.json();
|
|
25
|
+
}
|
|
26
|
+
export async function verifyLogin(email, code) {
|
|
27
|
+
const res = await fetch(`${SETUP_BASE}/api/v3/cli/setup`, {
|
|
28
|
+
method: 'POST',
|
|
29
|
+
headers: { 'Content-Type': 'application/json' },
|
|
30
|
+
body: JSON.stringify({ email, code, action: 'verify-login' })
|
|
31
|
+
});
|
|
32
|
+
if (!res.ok) {
|
|
33
|
+
const body = await res.json().catch(() => ({}));
|
|
34
|
+
throw new Error(body.error || body.message || `Login failed (${res.status})`);
|
|
23
35
|
}
|
|
24
36
|
return res.json();
|
|
25
37
|
}
|
package/dist/lib/format.d.ts
CHANGED
package/dist/lib/format.js
CHANGED
|
@@ -1,4 +1,21 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
+
export function normalizeNumber(input) {
|
|
3
|
+
// Strip non-digit chars except leading +
|
|
4
|
+
let num = input.replace(/[^\d+]/g, '');
|
|
5
|
+
// 10-digit US number: prepend +1
|
|
6
|
+
if (/^\d{10}$/.test(num)) {
|
|
7
|
+
num = `+1${num}`;
|
|
8
|
+
}
|
|
9
|
+
// 11-digit starting with 1: prepend +
|
|
10
|
+
else if (/^1\d{10}$/.test(num)) {
|
|
11
|
+
num = `+${num}`;
|
|
12
|
+
}
|
|
13
|
+
// Already has +: keep as-is
|
|
14
|
+
else if (!num.startsWith('+')) {
|
|
15
|
+
num = `+${num}`;
|
|
16
|
+
}
|
|
17
|
+
return num;
|
|
18
|
+
}
|
|
2
19
|
export function formatPhoneNumber(e164) {
|
|
3
20
|
// +15551234567 -> +1 (555) 123-4567
|
|
4
21
|
const match = e164.match(/^\+1(\d{3})(\d{3})(\d{4})$/);
|
|
@@ -22,7 +39,7 @@ export function printCredentials(data) {
|
|
|
22
39
|
console.log();
|
|
23
40
|
console.log(` ${chalk.bold('Phone Number')}: ${formatPhoneNumber(data.assignedNumber)}`);
|
|
24
41
|
console.log(` ${chalk.bold('API Key')}: ${data.apiKey}`);
|
|
25
|
-
console.log(` ${chalk.bold('API Secret')}: ${data.apiSecret}`);
|
|
42
|
+
console.log(` ${chalk.bold('API Secret')}: ${'*'.repeat(data.apiSecret.length - 4)}${data.apiSecret.slice(-4)}`);
|
|
26
43
|
console.log(` ${chalk.bold('Plan')}: ${data.plan}`);
|
|
27
44
|
console.log();
|
|
28
45
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sendblue/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Sendblue CLI — iMessage numbers for agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"chalk": "^5.3.0",
|
|
31
31
|
"commander": "^12.1.0",
|
|
32
|
+
"ora": "^9.3.0",
|
|
32
33
|
"prompts": "^2.4.2"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|