@sinch/cli 0.3.3 โ†’ 0.3.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.
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs-extra');
4
+ const path = require('path');
5
+ const os = require('os');
6
+ const { execSync, spawn } = require('child_process');
7
+
8
+ const SINCH_BIN = path.join(os.homedir(), '.sinch', 'bin');
9
+ const BINARY_NAME = process.platform === 'win32' ? 'sinch.exe' : 'sinch';
10
+ const BINARY_SRC = path.join(__dirname, '..', 'dist', 'sinch-bun.exe');
11
+ const BINARY_DEST = path.join(SINCH_BIN, BINARY_NAME);
12
+
13
+ async function setup() {
14
+ console.log('\n๐Ÿ”ง Setting up Sinch CLI development environment\n');
15
+
16
+ // 1. Copy Bun binary to ~/.sinch/bin/
17
+ console.log('๐Ÿ“ฆ Installing Bun binary...');
18
+ await fs.ensureDir(SINCH_BIN);
19
+
20
+ if (await fs.pathExists(BINARY_SRC)) {
21
+ await fs.copy(BINARY_SRC, BINARY_DEST, { overwrite: true });
22
+ if (process.platform !== 'win32') {
23
+ await fs.chmod(BINARY_DEST, 0o755);
24
+ }
25
+ console.log(` โœ… Installed to ${BINARY_DEST}`);
26
+ } else {
27
+ console.log(' โš ๏ธ Bun binary not found โ€” run "npm run build:binary" first');
28
+ console.log(` Expected at: ${BINARY_SRC}`);
29
+ }
30
+
31
+ // 2. Generate PowerShell profile additions
32
+ if (process.platform === 'win32') {
33
+ await setupPowerShell();
34
+ } else {
35
+ await setupShell();
36
+ }
37
+
38
+ // 3. Install shell completions
39
+ console.log('\n๐Ÿ”ง Installing shell completions...');
40
+ try {
41
+ await installCompletions();
42
+ console.log(' โœ… Completions installed');
43
+ } catch (e) {
44
+ console.log(` โš ๏ธ Completion install failed: ${e.message}`);
45
+ }
46
+
47
+ // 4. Smoke test
48
+ console.log('\n๐Ÿงช Smoke test...');
49
+ try {
50
+ const version = execSync(`"${BINARY_DEST}" --version`, { encoding: 'utf8' }).trim();
51
+ console.log(` โœ… sinch binary v${version}`);
52
+ } catch (e) {
53
+ console.log(` โš ๏ธ Binary smoke test failed: ${e.message}`);
54
+ }
55
+
56
+ try {
57
+ const devVersion = execSync('sinch --version', { encoding: 'utf8' }).trim();
58
+ console.log(` โœ… sinch dev (npm link) v${devVersion}`);
59
+ } catch (e) {
60
+ console.log(` โš ๏ธ npm link not set up: ${e.message}`);
61
+ }
62
+
63
+ console.log('\nโœจ Setup complete!\n');
64
+ console.log('Commands:');
65
+ console.log(' s โ†’ Fast Bun binary (for daily use)');
66
+ console.log(' sf <cmd> โ†’ Shortcut for "s functions <cmd>"');
67
+ console.log(' sd <cmd> โ†’ Dev version via npm link (for CLI development)');
68
+ console.log(' sinch <cmd> โ†’ Same as sd (npm-linked)');
69
+ console.log('');
70
+
71
+ if (process.platform === 'win32') {
72
+ console.log('โšก Restart PowerShell or run: . $PROFILE');
73
+ } else {
74
+ console.log('โšก Restart your shell or run: source ~/.bashrc');
75
+ }
76
+ console.log('');
77
+ }
78
+
79
+ async function setupPowerShell() {
80
+ console.log('\n๐Ÿ–ฅ๏ธ Setting up PowerShell aliases...');
81
+
82
+ const profileSnippet = `
83
+ # โ”€โ”€ Sinch CLI aliases (auto-generated by sinch-cli setup) โ”€โ”€
84
+ function s { & "$env:USERPROFILE\\.sinch\\bin\\sinch.exe" @args }
85
+ function sf { & "$env:USERPROFILE\\.sinch\\bin\\sinch.exe" functions @args }
86
+ function sd { & sinch @args }
87
+ # โ”€โ”€ End Sinch CLI aliases โ”€โ”€
88
+ `.trim();
89
+
90
+ // Find PowerShell profile
91
+ const profilePath = await getPowerShellProfilePath();
92
+
93
+ if (!profilePath) {
94
+ console.log(' โš ๏ธ Could not detect PowerShell profile path');
95
+ console.log(' Add these to your PowerShell profile manually:\n');
96
+ console.log(profileSnippet);
97
+ return;
98
+ }
99
+
100
+ // Read existing profile
101
+ let profileContent = '';
102
+ if (await fs.pathExists(profilePath)) {
103
+ profileContent = await fs.readFile(profilePath, 'utf8');
104
+ }
105
+
106
+ // Check if already installed
107
+ if (profileContent.includes('Sinch CLI aliases')) {
108
+ // Replace existing block
109
+ const replaced = profileContent.replace(
110
+ /# โ”€โ”€ Sinch CLI aliases.*?# โ”€โ”€ End Sinch CLI aliases โ”€โ”€/s,
111
+ profileSnippet
112
+ );
113
+ await fs.writeFile(profilePath, replaced);
114
+ console.log(` โœ… Updated aliases in ${profilePath}`);
115
+ } else {
116
+ // Append
117
+ await fs.writeFile(profilePath, profileContent + '\n\n' + profileSnippet + '\n');
118
+ console.log(` โœ… Added aliases to ${profilePath}`);
119
+ }
120
+ }
121
+
122
+ async function setupShell() {
123
+ console.log('\n๐Ÿ–ฅ๏ธ Setting up shell aliases...');
124
+
125
+ const snippet = `
126
+ # โ”€โ”€ Sinch CLI aliases (auto-generated by sinch-cli setup) โ”€โ”€
127
+ alias s='$HOME/.sinch/bin/sinch'
128
+ sf() { $HOME/.sinch/bin/sinch functions "$@"; }
129
+ alias sd='sinch'
130
+ # โ”€โ”€ End Sinch CLI aliases โ”€โ”€
131
+ `.trim();
132
+
133
+ // Try .bashrc, then .zshrc
134
+ const rcFile = (await fs.pathExists(path.join(os.homedir(), '.zshrc')))
135
+ ? path.join(os.homedir(), '.zshrc')
136
+ : path.join(os.homedir(), '.bashrc');
137
+
138
+ let content = '';
139
+ if (await fs.pathExists(rcFile)) {
140
+ content = await fs.readFile(rcFile, 'utf8');
141
+ }
142
+
143
+ if (content.includes('Sinch CLI aliases')) {
144
+ const replaced = content.replace(
145
+ /# โ”€โ”€ Sinch CLI aliases.*?# โ”€โ”€ End Sinch CLI aliases โ”€โ”€/s,
146
+ snippet
147
+ );
148
+ await fs.writeFile(rcFile, replaced);
149
+ console.log(` โœ… Updated aliases in ${rcFile}`);
150
+ } else {
151
+ await fs.writeFile(rcFile, content + '\n\n' + snippet + '\n');
152
+ console.log(` โœ… Added aliases to ${rcFile}`);
153
+ }
154
+ }
155
+
156
+ async function installCompletions() {
157
+ execSync('node scripts/postinstall.js', {
158
+ cwd: path.join(__dirname, '..'),
159
+ env: { ...process.env, SINCH_FORCE_POSTINSTALL: '1' },
160
+ stdio: 'pipe',
161
+ });
162
+ }
163
+
164
+ function getPowerShellProfilePath() {
165
+ return new Promise((resolve) => {
166
+ // Try pwsh first, then powershell
167
+ const tryShell = (cmd) => {
168
+ return new Promise((res) => {
169
+ const ps = spawn(cmd, ['-NoProfile', '-Command', '$PROFILE'], {
170
+ stdio: ['ignore', 'pipe', 'pipe'],
171
+ });
172
+ let out = '';
173
+ ps.stdout.on('data', (d) => (out += d.toString()));
174
+ ps.on('close', (code) => res(code === 0 ? out.trim() : null));
175
+ ps.on('error', () => res(null));
176
+ });
177
+ };
178
+
179
+ tryShell('pwsh').then((p) => {
180
+ if (p) return resolve(p);
181
+ tryShell('powershell').then((p2) => resolve(p2));
182
+ });
183
+ });
184
+ }
185
+
186
+ setup().catch((err) => {
187
+ console.error('Setup failed:', err.message);
188
+ process.exit(1);
189
+ });
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Smoke test for the Bun-compiled binary.
5
+ * Verifies the binary works for key code paths that could differ from Node.js.
6
+ */
7
+
8
+ const { execSync } = require('child_process');
9
+ const path = require('path');
10
+ const os = require('os');
11
+
12
+ const rawBinary =
13
+ process.argv[2] ||
14
+ path.join(os.homedir(), '.sinch', 'bin', process.platform === 'win32' ? 'sinch.exe' : 'sinch');
15
+ const BINARY = path.resolve(rawBinary);
16
+
17
+ let passed = 0;
18
+ let failed = 0;
19
+
20
+ function test(name, fn) {
21
+ try {
22
+ fn();
23
+ console.log(` โœ… ${name}`);
24
+ passed++;
25
+ } catch (e) {
26
+ console.log(` โŒ ${name}: ${e.message}`);
27
+ failed++;
28
+ }
29
+ }
30
+
31
+ function run(args) {
32
+ return execSync(`"${BINARY}" ${args}`, {
33
+ encoding: 'utf8',
34
+ timeout: 10000,
35
+ env: { ...process.env, CI: '1' },
36
+ }).trim();
37
+ }
38
+
39
+ console.log(`\n๐Ÿงช Smoke testing: ${BINARY}\n`);
40
+
41
+ test('--version returns semver', () => {
42
+ const version = run('--version');
43
+ if (!/^\d+\.\d+\.\d+/.test(version)) {
44
+ throw new Error(`Got: ${version}`);
45
+ }
46
+ });
47
+
48
+ test('--help shows all top-level commands', () => {
49
+ const help = run('--help');
50
+ const required = ['functions', 'templates', 'voice', 'auth', 'config', 'fax', 'sip', 'numbers'];
51
+ for (const cmd of required) {
52
+ if (!help.includes(cmd)) {
53
+ throw new Error(`Missing command: ${cmd}`);
54
+ }
55
+ }
56
+ });
57
+
58
+ test('functions --help shows subcommands', () => {
59
+ const help = run('functions --help');
60
+ const required = ['init', 'list', 'deploy', 'dev', 'status', 'logs'];
61
+ for (const cmd of required) {
62
+ if (!help.includes(cmd)) {
63
+ throw new Error(`Missing subcommand: ${cmd}`);
64
+ }
65
+ }
66
+ });
67
+
68
+ test('fax --help shows subcommands', () => {
69
+ const help = run('fax --help');
70
+ if (!help.includes('send') || !help.includes('list')) {
71
+ throw new Error('Missing fax subcommands');
72
+ }
73
+ });
74
+
75
+ test('sip --help shows subcommands', () => {
76
+ const help = run('sip --help');
77
+ if (!help.includes('trunks') || !help.includes('endpoints')) {
78
+ throw new Error('Missing sip subcommands');
79
+ }
80
+ });
81
+
82
+ test('config --help shows subcommands', () => {
83
+ const help = run('config --help');
84
+ if (!help.includes('set') || !help.includes('get') || !help.includes('profile')) {
85
+ throw new Error('Missing config subcommands');
86
+ }
87
+ });
88
+
89
+ console.log(`\n${passed} passed, ${failed} failed\n`);
90
+ process.exit(failed > 0 ? 1 : 0);