@zyratalk1/zyra-twilio-wrapper 1.2.9 → 1.3.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/index.d.mts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +143 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +143 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/types/interface.ts +25 -0
package/dist/index.d.mts
CHANGED
|
@@ -79,6 +79,11 @@ interface WelcomeConfigResult {
|
|
|
79
79
|
welcomeType: WelcomeType;
|
|
80
80
|
routingConfigId: number;
|
|
81
81
|
}
|
|
82
|
+
interface HoldMusicUrlConfigResult {
|
|
83
|
+
success: boolean;
|
|
84
|
+
message: string;
|
|
85
|
+
routingConfigId: number;
|
|
86
|
+
}
|
|
82
87
|
/**
|
|
83
88
|
* Routing Config
|
|
84
89
|
*/
|
|
@@ -366,6 +371,10 @@ declare class ReactNativeVoipSdk {
|
|
|
366
371
|
deregisterWebhook(): Promise<CallResponse<null>>;
|
|
367
372
|
isWebhookConfigured(): Promise<CallResponse<WebhookConfigResult>>;
|
|
368
373
|
welcomeMessageConfig(welcomeType: "audio" | "tts", welcomeMessage: string): Promise<CallResponse<WelcomeConfigResult>>;
|
|
374
|
+
/**
|
|
375
|
+
* Set hold music audio URL (MP3 or WAV HTTPS URL, e.g. from upload-audio).
|
|
376
|
+
*/
|
|
377
|
+
holdMusicUrlConfig(audioUrl: string): Promise<CallResponse<HoldMusicUrlConfigResult>>;
|
|
369
378
|
destroy(): void;
|
|
370
379
|
private ensureAuthenticated;
|
|
371
380
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -79,6 +79,11 @@ interface WelcomeConfigResult {
|
|
|
79
79
|
welcomeType: WelcomeType;
|
|
80
80
|
routingConfigId: number;
|
|
81
81
|
}
|
|
82
|
+
interface HoldMusicUrlConfigResult {
|
|
83
|
+
success: boolean;
|
|
84
|
+
message: string;
|
|
85
|
+
routingConfigId: number;
|
|
86
|
+
}
|
|
82
87
|
/**
|
|
83
88
|
* Routing Config
|
|
84
89
|
*/
|
|
@@ -366,6 +371,10 @@ declare class ReactNativeVoipSdk {
|
|
|
366
371
|
deregisterWebhook(): Promise<CallResponse<null>>;
|
|
367
372
|
isWebhookConfigured(): Promise<CallResponse<WebhookConfigResult>>;
|
|
368
373
|
welcomeMessageConfig(welcomeType: "audio" | "tts", welcomeMessage: string): Promise<CallResponse<WelcomeConfigResult>>;
|
|
374
|
+
/**
|
|
375
|
+
* Set hold music audio URL (MP3 or WAV HTTPS URL, e.g. from upload-audio).
|
|
376
|
+
*/
|
|
377
|
+
holdMusicUrlConfig(audioUrl: string): Promise<CallResponse<HoldMusicUrlConfigResult>>;
|
|
369
378
|
destroy(): void;
|
|
370
379
|
private ensureAuthenticated;
|
|
371
380
|
}
|
package/dist/index.js
CHANGED
|
@@ -1383,7 +1383,77 @@ async function isWebhookConfigured(deps) {
|
|
|
1383
1383
|
}
|
|
1384
1384
|
}
|
|
1385
1385
|
|
|
1386
|
+
// src/holdMusicUrlConfig.ts
|
|
1387
|
+
function isHttpUrl(value) {
|
|
1388
|
+
try {
|
|
1389
|
+
const url = new URL(value);
|
|
1390
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
|
1391
|
+
} catch {
|
|
1392
|
+
return false;
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
function validateHoldMusicUrlConfigInput(input) {
|
|
1396
|
+
const audioUrl = input.audioUrl?.trim() ?? "";
|
|
1397
|
+
if (!audioUrl) {
|
|
1398
|
+
throw new Error("audioUrl is required.");
|
|
1399
|
+
}
|
|
1400
|
+
if (!isHttpUrl(audioUrl)) {
|
|
1401
|
+
throw new Error(
|
|
1402
|
+
"audioUrl must be a valid URL (e.g. S3 URL from upload-audio with purpose hold)."
|
|
1403
|
+
);
|
|
1404
|
+
}
|
|
1405
|
+
try {
|
|
1406
|
+
const pathname = new URL(audioUrl).pathname;
|
|
1407
|
+
const ext = pathname.replace(/^.*\./, "").toLowerCase();
|
|
1408
|
+
if (ext !== "mp3" && ext !== "wav") {
|
|
1409
|
+
throw new Error(
|
|
1410
|
+
"Audio URL must point to an .mp3 or .wav file. Only MP3 and WAV formats are accepted."
|
|
1411
|
+
);
|
|
1412
|
+
}
|
|
1413
|
+
} catch (err) {
|
|
1414
|
+
if (err instanceof Error && err.message.startsWith("Audio URL")) throw err;
|
|
1415
|
+
throw new Error("audioUrl must be a valid URL with .mp3 or .wav file.");
|
|
1416
|
+
}
|
|
1417
|
+
return { audioUrl };
|
|
1418
|
+
}
|
|
1419
|
+
async function holdMusicUrlConfig(deps, input) {
|
|
1420
|
+
deps.ensureAuthenticated();
|
|
1421
|
+
try {
|
|
1422
|
+
const payload = validateHoldMusicUrlConfigInput(input);
|
|
1423
|
+
const res = await deps.axiosInstance.post(
|
|
1424
|
+
`${deps.serverUrl}/voipSdk.holdMusicUrlConfig`,
|
|
1425
|
+
payload,
|
|
1426
|
+
{
|
|
1427
|
+
headers: {
|
|
1428
|
+
Authorization: `Bearer ${deps.sdkToken}`
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
);
|
|
1432
|
+
const data = res?.data?.result ?? res?.data ?? null;
|
|
1433
|
+
if (!data) {
|
|
1434
|
+
throw new Error("Invalid response from server");
|
|
1435
|
+
}
|
|
1436
|
+
return createSuccessResult(data.message || "Hold music URL updated successfully", {
|
|
1437
|
+
success: data.success,
|
|
1438
|
+
message: data.message,
|
|
1439
|
+
routingConfigId: data.routingConfigId
|
|
1440
|
+
});
|
|
1441
|
+
} catch (error) {
|
|
1442
|
+
return createErrorResult(
|
|
1443
|
+
error instanceof Error ? error : "Failed to upsert hold music configuration"
|
|
1444
|
+
);
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1386
1448
|
// src/welcomeMessageConfig.ts
|
|
1449
|
+
var MAX_AUDIO_SIZE_BYTES = 2 * 1024 * 1024;
|
|
1450
|
+
var ALLOWED_AUDIO_EXTENSIONS = ["mp3", "wav"];
|
|
1451
|
+
var ALLOWED_AUDIO_MIME_TYPES = [
|
|
1452
|
+
"audio/mpeg",
|
|
1453
|
+
"audio/mp3",
|
|
1454
|
+
"audio/wav",
|
|
1455
|
+
"audio/x-wav"
|
|
1456
|
+
];
|
|
1387
1457
|
function isUrl(value) {
|
|
1388
1458
|
try {
|
|
1389
1459
|
const url = new URL(value);
|
|
@@ -1395,7 +1465,28 @@ function isUrl(value) {
|
|
|
1395
1465
|
function isAudioLikeInput(value) {
|
|
1396
1466
|
return value.startsWith("http://") || value.startsWith("https://") || value.startsWith("data:audio/");
|
|
1397
1467
|
}
|
|
1468
|
+
function validateAudioFile(file) {
|
|
1469
|
+
const ext = file.name.split(".").pop()?.toLowerCase() ?? "";
|
|
1470
|
+
const mime = (file.type ?? "").toLowerCase();
|
|
1471
|
+
const extOk = ALLOWED_AUDIO_EXTENSIONS.includes(ext);
|
|
1472
|
+
const mimeOk = ALLOWED_AUDIO_MIME_TYPES.includes(mime) || extOk;
|
|
1473
|
+
if (!mimeOk) {
|
|
1474
|
+
return "Only .mp3 and .wav audio files are accepted.";
|
|
1475
|
+
}
|
|
1476
|
+
if (file.size !== void 0 && file.size > MAX_AUDIO_SIZE_BYTES) {
|
|
1477
|
+
const mb = (file.size / (1024 * 1024)).toFixed(1);
|
|
1478
|
+
return `File size is ${mb} MB \u2014 maximum allowed is 2 MB.`;
|
|
1479
|
+
}
|
|
1480
|
+
return null;
|
|
1481
|
+
}
|
|
1398
1482
|
function validateWelcomeConfigInput(input) {
|
|
1483
|
+
if (input.audioFile) {
|
|
1484
|
+
const audioError = validateAudioFile(input.audioFile);
|
|
1485
|
+
if (audioError) {
|
|
1486
|
+
throw new Error(audioError);
|
|
1487
|
+
}
|
|
1488
|
+
return input;
|
|
1489
|
+
}
|
|
1399
1490
|
const welcomeMessage = input.welcomeMessage?.trim();
|
|
1400
1491
|
if (!welcomeMessage) {
|
|
1401
1492
|
throw new Error("Payload is missing or empty. welcomeMessage is required.");
|
|
@@ -1419,10 +1510,50 @@ function validateWelcomeConfigInput(input) {
|
|
|
1419
1510
|
welcomeMessage
|
|
1420
1511
|
};
|
|
1421
1512
|
}
|
|
1513
|
+
async function uploadAudioFile(deps, file, currentAudioUrl) {
|
|
1514
|
+
let uploadBase;
|
|
1515
|
+
try {
|
|
1516
|
+
uploadBase = new URL(deps.serverUrl).origin;
|
|
1517
|
+
} catch {
|
|
1518
|
+
uploadBase = deps.serverUrl.replace(/\/voipSdk.*$/, "").replace(/\/$/, "");
|
|
1519
|
+
}
|
|
1520
|
+
const uploadUrl = `${uploadBase}/api/voip/upload-audio`;
|
|
1521
|
+
const formData = new FormData();
|
|
1522
|
+
formData.append("file", {
|
|
1523
|
+
uri: file.uri,
|
|
1524
|
+
name: file.name,
|
|
1525
|
+
type: file.type || "audio/mpeg"
|
|
1526
|
+
});
|
|
1527
|
+
if (currentAudioUrl) {
|
|
1528
|
+
formData.append("currentUrl", currentAudioUrl);
|
|
1529
|
+
}
|
|
1530
|
+
const response = await fetch(uploadUrl, {
|
|
1531
|
+
method: "POST",
|
|
1532
|
+
headers: {
|
|
1533
|
+
Authorization: `Bearer ${deps.sdkToken}`
|
|
1534
|
+
},
|
|
1535
|
+
body: formData
|
|
1536
|
+
});
|
|
1537
|
+
const json = await response.json();
|
|
1538
|
+
if (!response.ok || !json.success) {
|
|
1539
|
+
throw new Error(json.message ?? `Audio upload failed with status ${response.status}`);
|
|
1540
|
+
}
|
|
1541
|
+
if (!json.url) {
|
|
1542
|
+
throw new Error("Server did not return an audio URL after upload.");
|
|
1543
|
+
}
|
|
1544
|
+
return json.url;
|
|
1545
|
+
}
|
|
1422
1546
|
async function welcomeMessageConfig(deps, input) {
|
|
1423
1547
|
deps.ensureAuthenticated();
|
|
1424
1548
|
try {
|
|
1425
|
-
|
|
1549
|
+
validateWelcomeConfigInput(input);
|
|
1550
|
+
let welcomeType = input.welcomeType;
|
|
1551
|
+
let welcomeMessage = input.welcomeMessage?.trim() ?? "";
|
|
1552
|
+
if (input.audioFile) {
|
|
1553
|
+
welcomeMessage = await uploadAudioFile(deps, input.audioFile);
|
|
1554
|
+
welcomeType = "audio";
|
|
1555
|
+
}
|
|
1556
|
+
const payload = { welcomeType, welcomeMessage };
|
|
1426
1557
|
const res = await deps.axiosInstance.post(
|
|
1427
1558
|
`${deps.serverUrl}/voipSdk.welcomeMessageConfig`,
|
|
1428
1559
|
payload,
|
|
@@ -1483,8 +1614,11 @@ var ConfigService = class {
|
|
|
1483
1614
|
async isWebhookConfigured() {
|
|
1484
1615
|
return isWebhookConfigured(this.withDeps());
|
|
1485
1616
|
}
|
|
1486
|
-
async welcomeMessageConfig(welcomeType, welcomeMessage) {
|
|
1487
|
-
return welcomeMessageConfig(this.withDeps(), { welcomeType, welcomeMessage });
|
|
1617
|
+
async welcomeMessageConfig(welcomeType, welcomeMessage, audioFile) {
|
|
1618
|
+
return welcomeMessageConfig(this.withDeps(), { welcomeType, welcomeMessage, audioFile });
|
|
1619
|
+
}
|
|
1620
|
+
async holdMusicUrlConfig(audioUrl) {
|
|
1621
|
+
return holdMusicUrlConfig(this.withDeps(), { audioUrl });
|
|
1488
1622
|
}
|
|
1489
1623
|
async getVoipProviderConfigStatus() {
|
|
1490
1624
|
return getVoipProviderConfigStatus(this.withDeps());
|
|
@@ -2124,6 +2258,12 @@ var ReactNativeVoipSdk = class {
|
|
|
2124
2258
|
async welcomeMessageConfig(welcomeType, welcomeMessage) {
|
|
2125
2259
|
return this.configService.welcomeMessageConfig(welcomeType, welcomeMessage);
|
|
2126
2260
|
}
|
|
2261
|
+
/**
|
|
2262
|
+
* Set hold music audio URL (MP3 or WAV HTTPS URL, e.g. from upload-audio).
|
|
2263
|
+
*/
|
|
2264
|
+
async holdMusicUrlConfig(audioUrl) {
|
|
2265
|
+
return this.configService.holdMusicUrlConfig(audioUrl);
|
|
2266
|
+
}
|
|
2127
2267
|
destroy() {
|
|
2128
2268
|
logVoipDebug("destroy() invoked");
|
|
2129
2269
|
this.authManager.destroy();
|