@sinch/cli 0.4.5 → 0.4.7
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/README.md +1 -1
- package/bin/s +2 -2
- package/bin/sinch +17 -36
- package/bin/sinch.cmd +2 -0
- package/package.json +9 -83
- package/scripts/postinstall.js +143 -1
- package/dist/index.js +0 -722
- package/scripts/README-E2E.md +0 -242
- package/scripts/e2e-test.sh +0 -155
- package/scripts/post-build.js +0 -36
- package/scripts/setup-dev.js +0 -188
- package/scripts/smoke-test.js +0 -90
package/README.md
CHANGED
|
@@ -137,7 +137,7 @@ const stripeKey = process.env.STRIPE_KEY;
|
|
|
137
137
|
|
|
138
138
|
### 🔄 Hot Reload Development
|
|
139
139
|
|
|
140
|
-
Changes to your function are automatically reloaded during `sinch functions dev` via
|
|
140
|
+
Changes to your function are automatically reloaded during `sinch functions dev` via file watching (Node.js) or dotnet watch (C#). No flags needed:
|
|
141
141
|
|
|
142
142
|
```bash
|
|
143
143
|
sinch functions dev
|
package/bin/s
CHANGED
package/bin/sinch
CHANGED
|
@@ -1,36 +1,17 @@
|
|
|
1
|
-
#!/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
process.exit(result.status ?? 1);
|
|
19
|
-
} catch { /* fall through */ }
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Fallback: run source directly via tsx (works with ESM, no CJS issues)
|
|
23
|
-
try {
|
|
24
|
-
const src = path.join(__dirname, '..', 'src', 'index.ts');
|
|
25
|
-
if (fs.existsSync(src)) {
|
|
26
|
-
const result = require('child_process').spawnSync('npx', ['tsx', src, ...process.argv.slice(2)], {
|
|
27
|
-
stdio: 'inherit',
|
|
28
|
-
windowsHide: false,
|
|
29
|
-
shell: true,
|
|
30
|
-
});
|
|
31
|
-
process.exit(result.status ?? 1);
|
|
32
|
-
}
|
|
33
|
-
} catch { /* fall through */ }
|
|
34
|
-
|
|
35
|
-
// Last resort: try requiring dist (works if module format is compatible)
|
|
36
|
-
require('../dist/index.js');
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Native launcher — execs the Bun-compiled binary, no Node.js required.
|
|
3
|
+
# npm registers this via the "bin" field in package.json.
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
5
|
+
ARCH="$(uname -m)"
|
|
6
|
+
case "$ARCH" in
|
|
7
|
+
x86_64|amd64) ARCH="x64" ;;
|
|
8
|
+
aarch64|arm64) ARCH="arm64" ;;
|
|
9
|
+
esac
|
|
10
|
+
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
|
11
|
+
BINARY="$SCRIPT_DIR/../dist/sinch-${OS}-${ARCH}"
|
|
12
|
+
if [ ! -f "$BINARY" ]; then
|
|
13
|
+
echo "Sinch CLI binary not found: $BINARY" >&2
|
|
14
|
+
echo "Reinstall with: npm install -g @sinch/cli" >&2
|
|
15
|
+
exit 1
|
|
16
|
+
fi
|
|
17
|
+
exec "$BINARY" "$@"
|
package/bin/sinch.cmd
ADDED
package/package.json
CHANGED
|
@@ -1,99 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sinch/cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.7",
|
|
4
4
|
"description": "Official Sinch CLI - Manage all Sinch products from your terminal",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
5
|
"bin": {
|
|
7
6
|
"sinch": "bin/sinch",
|
|
8
7
|
"s": "bin/s"
|
|
9
8
|
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"scripts/postinstall.js",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
10
15
|
"scripts": {
|
|
11
|
-
"
|
|
12
|
-
"dev": "tsx watch src/index.ts",
|
|
13
|
-
"build": "tsc && node scripts/post-build.js && npm run build:binary",
|
|
14
|
-
"build:prod": "tsup",
|
|
15
|
-
"typecheck": "tsc --noEmit",
|
|
16
|
-
"test": "jest --config jest.config.js && jest --config tests/e2e/jest.config.js",
|
|
17
|
-
"test:unit": "jest --config jest.config.js",
|
|
18
|
-
"test:e2e": "jest --config tests/e2e/jest.config.js",
|
|
19
|
-
"test:e2e:staging": "jest --config tests/e2e/jest.config.js --env=staging",
|
|
20
|
-
"prepublishOnly": "npm run build:prod",
|
|
21
|
-
"build:binary": "bun build src/index.ts --compile --minify --outfile dist/sinch-bun.exe",
|
|
22
|
-
"test:smoke": "node scripts/smoke-test.js",
|
|
23
|
-
"setup": "npm run build && npm link && npm run build:binary && node scripts/setup-dev.js",
|
|
24
|
-
"format": "prettier --write .",
|
|
25
|
-
"format:check": "prettier --check .",
|
|
26
|
-
"prepare": "husky"
|
|
16
|
+
"postinstall": "node scripts/postinstall.js"
|
|
27
17
|
},
|
|
28
|
-
"keywords": [],
|
|
29
18
|
"author": "Sinch <support@sinch.com> (https://www.sinch.com)",
|
|
30
19
|
"license": "MIT",
|
|
31
|
-
"private": false,
|
|
32
20
|
"publishConfig": {
|
|
33
21
|
"access": "public",
|
|
34
22
|
"registry": "https://registry.npmjs.org/"
|
|
35
23
|
},
|
|
36
|
-
"homepage": "https://www.sinch.com/products/apis/voice/"
|
|
37
|
-
"files": [
|
|
38
|
-
"dist/",
|
|
39
|
-
"bin/",
|
|
40
|
-
"scripts/",
|
|
41
|
-
"README.md",
|
|
42
|
-
"LICENSE"
|
|
43
|
-
],
|
|
44
|
-
"dependencies": {
|
|
45
|
-
"@inquirer/prompts": "^8.2.0",
|
|
46
|
-
"@opentelemetry/api": "^1.9.0",
|
|
47
|
-
"@opentelemetry/exporter-trace-otlp-http": "^0.212.0",
|
|
48
|
-
"@opentelemetry/resources": "^2.5.1",
|
|
49
|
-
"@opentelemetry/sdk-node": "^0.212.0",
|
|
50
|
-
"@opentelemetry/semantic-conventions": "^1.39.0",
|
|
51
|
-
"@opentui/core": "^0.1.87",
|
|
52
|
-
"@sinch/sdk-core": "^1.2.1",
|
|
53
|
-
"adm-zip": "^0.5.10",
|
|
54
|
-
"axios": "1.14.0",
|
|
55
|
-
"axios-retry": "^4.5.0",
|
|
56
|
-
"chalk": "^4.1.2",
|
|
57
|
-
"cli-table3": "^0.6.3",
|
|
58
|
-
"clipboardy": "^5.1.0",
|
|
59
|
-
"commander": "^14.0.0",
|
|
60
|
-
"form-data": "^4.0.0",
|
|
61
|
-
"fs-extra": "^11.3.3",
|
|
62
|
-
"google-libphonenumber": "^3.2.44",
|
|
63
|
-
"stage-js": "^1.0.1"
|
|
64
|
-
},
|
|
65
|
-
"optionalDependencies": {
|
|
66
|
-
"@opentui/core-linux-x64": "^0.1.87",
|
|
67
|
-
"@opentui/core-linux-arm64": "^0.1.87",
|
|
68
|
-
"@opentui/core-darwin-x64": "^0.1.87",
|
|
69
|
-
"@opentui/core-darwin-arm64": "^0.1.87",
|
|
70
|
-
"@opentui/core-win32-x64": "^0.1.87",
|
|
71
|
-
"@opentui/core-win32-arm64": "^0.1.87"
|
|
72
|
-
},
|
|
73
|
-
"devDependencies": {
|
|
74
|
-
"@types/adm-zip": "^0.5.7",
|
|
75
|
-
"@types/fs-extra": "^11.0.4",
|
|
76
|
-
"@types/google-libphonenumber": "^7.4.30",
|
|
77
|
-
"@types/jest": "^30.0.0",
|
|
78
|
-
"@types/node": "24.10.9",
|
|
79
|
-
"execa": "^5.1.1",
|
|
80
|
-
"husky": "^9.1.7",
|
|
81
|
-
"jest": "^30.0.0",
|
|
82
|
-
"lint-staged": "^16.2.7",
|
|
83
|
-
"nodemon": "^3.0.1",
|
|
84
|
-
"prettier": "^3.8.1",
|
|
85
|
-
"ts-jest": "^29.4.6",
|
|
86
|
-
"tsup": "^8.5.0",
|
|
87
|
-
"tsx": "^4.20.4",
|
|
88
|
-
"typescript": "^5.9.2"
|
|
89
|
-
},
|
|
90
|
-
"engines": {
|
|
91
|
-
"node": ">=20.0.0",
|
|
92
|
-
"npm": ">=9.0.0"
|
|
93
|
-
},
|
|
94
|
-
"lint-staged": {
|
|
95
|
-
"*.{js,ts,json,md}": [
|
|
96
|
-
"prettier --write"
|
|
97
|
-
]
|
|
98
|
-
}
|
|
24
|
+
"homepage": "https://www.sinch.com/products/apis/voice/"
|
|
99
25
|
}
|
package/scripts/postinstall.js
CHANGED
|
@@ -14,16 +14,18 @@
|
|
|
14
14
|
const fs = require('fs');
|
|
15
15
|
const path = require('path');
|
|
16
16
|
const os = require('os');
|
|
17
|
+
const https = require('https');
|
|
17
18
|
const { spawn } = require('child_process');
|
|
18
19
|
|
|
19
20
|
const SINCH_DIR = path.join(os.homedir(), '.sinch');
|
|
21
|
+
const PROJECT_ID = '72974711';
|
|
20
22
|
|
|
21
23
|
// Keep in sync with COMPLETION_COMMANDS in src/index.ts.
|
|
22
24
|
// The postAction hook overwrites completions.json on every CLI run, so drift self-heals.
|
|
23
25
|
const COMPLETION_COMMANDS = {
|
|
24
26
|
functions: ['init', 'list', 'deploy', 'download', 'dev', 'status', 'logs', 'delete', 'docs'],
|
|
25
27
|
templates: ['list', 'show', 'node', 'csharp', 'python'],
|
|
26
|
-
voice: ['
|
|
28
|
+
voice: ['applications', 'callouts', 'calls', 'conferences'],
|
|
27
29
|
secrets: ['list', 'add', 'get', 'delete', 'clear'],
|
|
28
30
|
auth: ['login', 'status', 'logout'],
|
|
29
31
|
sip: ['trunks', 'endpoints', 'acls', 'countries', 'credential-lists', 'calls'],
|
|
@@ -31,6 +33,7 @@ const COMPLETION_COMMANDS = {
|
|
|
31
33
|
fax: ['send', 'list', 'get', 'cancel', 'auth-status', 'status'],
|
|
32
34
|
conversation: ['send', 'messages', 'contacts', 'conversations', 'apps', 'webhooks'],
|
|
33
35
|
skills: ['install', 'list', 'uninstall', 'update'],
|
|
36
|
+
porting: ['check', 'config', 'orders', 'documents', 'activation'],
|
|
34
37
|
config: ['--set', '--get', '--list'],
|
|
35
38
|
completion: ['--shell', '--install'],
|
|
36
39
|
};
|
|
@@ -170,6 +173,137 @@ function installBashZshCompletion() {
|
|
|
170
173
|
}
|
|
171
174
|
}
|
|
172
175
|
|
|
176
|
+
// --- Binary download ---
|
|
177
|
+
|
|
178
|
+
const PLATFORM_MAP = {
|
|
179
|
+
'linux-x64': 'sinch-linux-x64',
|
|
180
|
+
'linux-arm64': 'sinch-linux-arm64',
|
|
181
|
+
'darwin-x64': 'sinch-darwin-x64',
|
|
182
|
+
'darwin-arm64': 'sinch-darwin-arm64',
|
|
183
|
+
'win32-x64': 'sinch-windows-x64.exe',
|
|
184
|
+
'win32-arm64': 'sinch-windows-x64.exe',
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
function getTokenFromNpmrc() {
|
|
188
|
+
// Read GitLab token from global .npmrc (same token used for registry auth)
|
|
189
|
+
try {
|
|
190
|
+
const { execSync } = require('child_process');
|
|
191
|
+
const globalConfig = execSync('npm config get globalconfig', { encoding: 'utf8' }).trim();
|
|
192
|
+
const content = fs.readFileSync(globalConfig, 'utf8');
|
|
193
|
+
const match = content.match(
|
|
194
|
+
new RegExp(`//gitlab\\.com/api/v4/projects/${PROJECT_ID}/packages/npm/:_authToken=(.+)`)
|
|
195
|
+
);
|
|
196
|
+
return match ? match[1].trim() : '';
|
|
197
|
+
} catch {
|
|
198
|
+
return '';
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function downloadFile(url, dest, token) {
|
|
203
|
+
return new Promise((resolve, reject) => {
|
|
204
|
+
const headers = {};
|
|
205
|
+
if (token) headers['PRIVATE-TOKEN'] = token;
|
|
206
|
+
|
|
207
|
+
const get = (reqUrl) => {
|
|
208
|
+
https
|
|
209
|
+
.get(reqUrl, { headers }, (res) => {
|
|
210
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
211
|
+
get(res.headers.location); // follow redirect
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (res.statusCode !== 200) {
|
|
215
|
+
reject(new Error(`Download failed: ${res.statusCode} from ${reqUrl}`));
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
const file = fs.createWriteStream(dest);
|
|
219
|
+
res.pipe(file);
|
|
220
|
+
file.on('finish', () => {
|
|
221
|
+
file.close();
|
|
222
|
+
resolve();
|
|
223
|
+
});
|
|
224
|
+
file.on('error', reject);
|
|
225
|
+
})
|
|
226
|
+
.on('error', reject);
|
|
227
|
+
};
|
|
228
|
+
get(url);
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async function downloadBinary(version) {
|
|
233
|
+
const key = `${process.platform}-${process.arch}`;
|
|
234
|
+
const binName = PLATFORM_MAP[key];
|
|
235
|
+
if (!binName) return; // unsupported platform — skip silently
|
|
236
|
+
|
|
237
|
+
const pkgRoot = path.join(__dirname, '..');
|
|
238
|
+
const distDir = path.join(pkgRoot, 'dist');
|
|
239
|
+
const dest = path.join(distDir, binName);
|
|
240
|
+
|
|
241
|
+
// Skip if binary already exists (local dev build)
|
|
242
|
+
if (fs.existsSync(dest)) return;
|
|
243
|
+
|
|
244
|
+
fs.mkdirSync(distDir, { recursive: true });
|
|
245
|
+
|
|
246
|
+
const baseUrl = `https://gitlab.com/api/v4/projects/${PROJECT_ID}/packages/generic/sinch-cli/${version}/${binName}`;
|
|
247
|
+
const token = process.env.SINCH_GITLAB_TOKEN || process.env.GITLAB_TOKEN || getTokenFromNpmrc();
|
|
248
|
+
|
|
249
|
+
try {
|
|
250
|
+
console.log(`Downloading Sinch CLI ${version} for ${key}...`);
|
|
251
|
+
await downloadFile(baseUrl, dest, token);
|
|
252
|
+
|
|
253
|
+
// Make executable on Unix
|
|
254
|
+
if (process.platform !== 'win32') {
|
|
255
|
+
fs.chmodSync(dest, 0o755);
|
|
256
|
+
}
|
|
257
|
+
console.log('Sinch CLI binary downloaded.');
|
|
258
|
+
} catch (err) {
|
|
259
|
+
// Clean up partial download
|
|
260
|
+
try {
|
|
261
|
+
fs.unlinkSync(dest);
|
|
262
|
+
} catch {}
|
|
263
|
+
console.error(`Failed to download Sinch CLI binary: ${err.message}`);
|
|
264
|
+
console.error(
|
|
265
|
+
`You can download manually from: https://gitlab.com/sinch/sinch-projects/voice/functions/sinch-cli/-/releases`
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* On Windows, npm generates .cmd and .ps1 shims that try to run bin/sinch via
|
|
272
|
+
* /bin/sh (broken on Windows). Replace them with our native .cmd launcher that
|
|
273
|
+
* execs the Bun binary directly — zero Node.js overhead.
|
|
274
|
+
*/
|
|
275
|
+
function fixWindowsShims() {
|
|
276
|
+
if (process.platform !== 'win32') return;
|
|
277
|
+
try {
|
|
278
|
+
const prefix = process.env.npm_config_prefix;
|
|
279
|
+
if (!prefix || !path.isAbsolute(prefix)) return;
|
|
280
|
+
|
|
281
|
+
const globalBinDir = prefix;
|
|
282
|
+
const pkgRoot = path.join(__dirname, '..');
|
|
283
|
+
const binaryPath = path.join(pkgRoot, 'dist', 'sinch-windows-x64.exe');
|
|
284
|
+
|
|
285
|
+
// Write a .cmd that uses the absolute path to the binary inside the npm package.
|
|
286
|
+
// Can't copy bin/sinch.cmd because %~dp0 would resolve to the global bin dir,
|
|
287
|
+
// not the package dir where the binary lives.
|
|
288
|
+
fs.writeFileSync(path.join(globalBinDir, 'sinch.cmd'), `@echo off\r\n"${binaryPath}" %*\r\n`);
|
|
289
|
+
|
|
290
|
+
// Remove .ps1 shim (broken — tries /bin/sh) and bash shim (not needed on Windows)
|
|
291
|
+
try {
|
|
292
|
+
fs.unlinkSync(path.join(globalBinDir, 'sinch.ps1'));
|
|
293
|
+
} catch {}
|
|
294
|
+
try {
|
|
295
|
+
fs.unlinkSync(path.join(globalBinDir, 'sinch'));
|
|
296
|
+
} catch {}
|
|
297
|
+
|
|
298
|
+
// Clean up orphaned sinch.exe from previous installToGlobalBin versions
|
|
299
|
+
try {
|
|
300
|
+
fs.unlinkSync(path.join(globalBinDir, 'sinch.exe'));
|
|
301
|
+
} catch {}
|
|
302
|
+
} catch {
|
|
303
|
+
// Non-fatal — npm's .cmd shim may still work for node-based fallback
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
173
307
|
// --- Main ---
|
|
174
308
|
|
|
175
309
|
async function main() {
|
|
@@ -182,6 +316,14 @@ async function main() {
|
|
|
182
316
|
fs.mkdirSync(SINCH_DIR, { recursive: true });
|
|
183
317
|
|
|
184
318
|
const version = getVersion();
|
|
319
|
+
|
|
320
|
+
// Download the platform binary
|
|
321
|
+
await downloadBinary(version);
|
|
322
|
+
|
|
323
|
+
// Replace npm's broken Windows shims with native .cmd launcher
|
|
324
|
+
fixWindowsShims();
|
|
325
|
+
|
|
326
|
+
// Set up shell completions
|
|
185
327
|
writeCompletionsJson(version);
|
|
186
328
|
|
|
187
329
|
if (process.platform === 'win32') {
|