@absolutejs/voice 0.0.22-beta.114 → 0.0.22-beta.116
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/campaignDialers.d.ts +90 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +389 -29
- package/dist/testing/index.js +4 -1
- package/package.json +1 -1
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { applyVoiceCampaignTelephonyOutcome, VoiceCampaignDialer, VoiceCampaignDialerInput, type VoiceCampaignRecord, type VoiceCampaignStore, type VoiceCampaignTickResult } from './campaign';
|
|
2
|
+
type VoiceCampaignDialerFetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
3
|
+
type VoiceCampaignDialerMetadataInput = VoiceCampaignDialerInput & {
|
|
4
|
+
provider: 'plivo' | 'telnyx' | 'twilio';
|
|
5
|
+
};
|
|
6
|
+
type VoiceCampaignDialerMetadata = Record<string, string | number | boolean | undefined> | ((input: VoiceCampaignDialerMetadataInput) => Record<string, string | number | boolean | undefined> | Promise<Record<string, string | number | boolean | undefined>>);
|
|
7
|
+
type VoiceCampaignURLInput = {
|
|
8
|
+
attempt: VoiceCampaignDialerInput['attempt'];
|
|
9
|
+
campaign: VoiceCampaignDialerInput['campaign'];
|
|
10
|
+
recipient: VoiceCampaignDialerInput['recipient'];
|
|
11
|
+
};
|
|
12
|
+
type VoiceCampaignURLResolver = string | ((input: VoiceCampaignURLInput) => string | Promise<string>);
|
|
13
|
+
export type VoiceTwilioCampaignDialerOptions = {
|
|
14
|
+
accountSid: string;
|
|
15
|
+
answerMethod?: 'GET' | 'POST';
|
|
16
|
+
answerUrl: VoiceCampaignURLResolver;
|
|
17
|
+
apiBaseUrl?: string;
|
|
18
|
+
authToken: string;
|
|
19
|
+
fetch?: VoiceCampaignDialerFetch;
|
|
20
|
+
from: string;
|
|
21
|
+
machineDetection?: string;
|
|
22
|
+
metadata?: VoiceCampaignDialerMetadata;
|
|
23
|
+
statusCallbackEvents?: string[];
|
|
24
|
+
statusCallbackMethod?: 'GET' | 'POST';
|
|
25
|
+
statusCallbackUrl?: VoiceCampaignURLResolver;
|
|
26
|
+
};
|
|
27
|
+
export type VoiceTelnyxCampaignDialerOptions = {
|
|
28
|
+
apiBaseUrl?: string;
|
|
29
|
+
apiKey: string;
|
|
30
|
+
clientState?: VoiceCampaignDialerMetadata;
|
|
31
|
+
connectionId: string;
|
|
32
|
+
fetch?: VoiceCampaignDialerFetch;
|
|
33
|
+
from: string;
|
|
34
|
+
webhookUrl?: VoiceCampaignURLResolver;
|
|
35
|
+
webhookUrlMethod?: 'GET' | 'POST';
|
|
36
|
+
};
|
|
37
|
+
export type VoicePlivoCampaignDialerOptions = {
|
|
38
|
+
answerMethod?: 'GET' | 'POST';
|
|
39
|
+
answerUrl: VoiceCampaignURLResolver;
|
|
40
|
+
apiBaseUrl?: string;
|
|
41
|
+
authId: string;
|
|
42
|
+
authToken: string;
|
|
43
|
+
callbackMethod?: 'GET' | 'POST';
|
|
44
|
+
callbackUrl?: VoiceCampaignURLResolver;
|
|
45
|
+
fetch?: VoiceCampaignDialerFetch;
|
|
46
|
+
from: string;
|
|
47
|
+
metadata?: VoiceCampaignDialerMetadata;
|
|
48
|
+
};
|
|
49
|
+
export type VoiceCampaignDialerProofProvider = 'plivo' | 'telnyx' | 'twilio';
|
|
50
|
+
export type VoiceCampaignDialerProofCarrierRequest = {
|
|
51
|
+
body: unknown;
|
|
52
|
+
method: string;
|
|
53
|
+
provider: VoiceCampaignDialerProofProvider;
|
|
54
|
+
url: string;
|
|
55
|
+
};
|
|
56
|
+
export type VoiceCampaignDialerProofProviderResult = {
|
|
57
|
+
campaignId: string;
|
|
58
|
+
carrierRequests: VoiceCampaignDialerProofCarrierRequest[];
|
|
59
|
+
final?: VoiceCampaignRecord;
|
|
60
|
+
outcomes: Awaited<ReturnType<typeof applyVoiceCampaignTelephonyOutcome>>[];
|
|
61
|
+
provider: VoiceCampaignDialerProofProvider;
|
|
62
|
+
tick: VoiceCampaignTickResult;
|
|
63
|
+
};
|
|
64
|
+
export type VoiceCampaignDialerProofReport = {
|
|
65
|
+
generatedAt: number;
|
|
66
|
+
mode: 'dry-run';
|
|
67
|
+
ok: boolean;
|
|
68
|
+
providers: VoiceCampaignDialerProofProviderResult[];
|
|
69
|
+
};
|
|
70
|
+
export type VoiceCampaignDialerProofStatus = {
|
|
71
|
+
generatedAt: number;
|
|
72
|
+
mode: 'dry-run';
|
|
73
|
+
ok: boolean;
|
|
74
|
+
providers: VoiceCampaignDialerProofProvider[];
|
|
75
|
+
runPath?: string;
|
|
76
|
+
safe: true;
|
|
77
|
+
};
|
|
78
|
+
export type VoiceCampaignDialerProofOptions = {
|
|
79
|
+
baseUrl?: string;
|
|
80
|
+
from?: string;
|
|
81
|
+
providers?: VoiceCampaignDialerProofProvider[];
|
|
82
|
+
runPath?: string;
|
|
83
|
+
store?: VoiceCampaignStore;
|
|
84
|
+
};
|
|
85
|
+
export declare const createVoiceTwilioCampaignDialer: (options: VoiceTwilioCampaignDialerOptions) => VoiceCampaignDialer;
|
|
86
|
+
export declare const createVoiceTelnyxCampaignDialer: (options: VoiceTelnyxCampaignDialerOptions) => VoiceCampaignDialer;
|
|
87
|
+
export declare const createVoicePlivoCampaignDialer: (options: VoicePlivoCampaignDialerOptions) => VoiceCampaignDialer;
|
|
88
|
+
export declare const getVoiceCampaignDialerProofStatus: (options?: Pick<VoiceCampaignDialerProofOptions, "providers" | "runPath">) => VoiceCampaignDialerProofStatus;
|
|
89
|
+
export declare const runVoiceCampaignDialerProof: (options?: VoiceCampaignDialerProofOptions) => Promise<VoiceCampaignDialerProofReport>;
|
|
90
|
+
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { voice } from './plugin';
|
|
2
2
|
export { createVoiceAppKit, createVoiceAppKitRoutes, summarizeVoiceAppKitStatus } from './appKit';
|
|
3
3
|
export { applyVoiceCampaignTelephonyOutcome, buildVoiceCampaignObservabilityReport, createVoiceCampaignTelephonyOutcomeHandler, createVoiceCampaign, createVoiceCampaignRoutes, createVoiceCampaignWorker, createVoiceCampaignWorkerLoop, createVoiceMemoryCampaignStore, renderVoiceCampaignObservabilityHTML, renderVoiceCampaignsHTML, runVoiceCampaignProof, summarizeVoiceCampaigns } from './campaign';
|
|
4
|
+
export { createVoicePlivoCampaignDialer, createVoiceTelnyxCampaignDialer, createVoiceTwilioCampaignDialer, getVoiceCampaignDialerProofStatus, runVoiceCampaignDialerProof } from './campaignDialers';
|
|
4
5
|
export { createVoiceAssistant, createVoiceExperiment, summarizeVoiceAssistantRuns } from './assistant';
|
|
5
6
|
export { createVoiceAssistantHealthHTMLHandler, createVoiceAssistantHealthJSONHandler, createVoiceAssistantHealthRoutes, renderVoiceAssistantHealthHTML, summarizeVoiceAssistantHealth } from './assistantHealth';
|
|
6
7
|
export { createVoiceBargeInRoutes, renderVoiceBargeInHTML, summarizeVoiceBargeIn } from './bargeInRoutes';
|
|
@@ -55,6 +56,7 @@ export { resolveTurnDetectionConfig, TURN_PROFILE_DEFAULTS } from './turnProfile
|
|
|
55
56
|
export { createVoiceCallReviewFromLiveTelephonyReport, createVoiceCallReviewRecorder, renderVoiceCallReviewHTML, renderVoiceCallReviewMarkdown } from './testing/review';
|
|
56
57
|
export type { VoiceAppKitLink, VoiceAppKitRoutes, VoiceAppKitRoutesOptions, VoiceAppKitStatus, VoiceAppKitStatusOptions, VoiceAppKitStatusReport, VoiceAppKitSurface } from './appKit';
|
|
57
58
|
export type { VoiceCampaign, VoiceCampaignAttempt, VoiceCampaignAttemptResultInput, VoiceCampaignAttemptStatus, VoiceCampaignCreateInput, VoiceCampaignDialer, VoiceCampaignDialerInput, VoiceCampaignDialerResult, VoiceCampaignProofOptions, VoiceCampaignProofReport, VoiceCampaignRecipient, VoiceCampaignRecipientInput, VoiceCampaignRecipientStatus, VoiceCampaignRecord, VoiceCampaignRoutesOptions, VoiceCampaignRuntime, VoiceCampaignRuntimeOptions, VoiceCampaignStatus, VoiceCampaignStore, VoiceCampaignSummary, VoiceCampaignTickResult } from './campaign';
|
|
59
|
+
export type { VoiceCampaignDialerProofCarrierRequest, VoiceCampaignDialerProofOptions, VoiceCampaignDialerProofProvider, VoiceCampaignDialerProofProviderResult, VoiceCampaignDialerProofReport, VoiceCampaignDialerProofStatus, VoicePlivoCampaignDialerOptions, VoiceTelnyxCampaignDialerOptions, VoiceTwilioCampaignDialerOptions } from './campaignDialers';
|
|
58
60
|
export type { VoiceBargeInReport, VoiceBargeInRoutesOptions } from './bargeInRoutes';
|
|
59
61
|
export type { VoiceAssistant, VoiceAssistantArtifactPlan, VoiceAssistantExperiment, VoiceAssistantExperimentOptions, VoiceAssistantGuardrailInput, VoiceAssistantGuardrails, VoiceAssistantMemoryLifecycle, VoiceAssistantMemoryLifecycleInput, VoiceAssistantOptions, VoiceAssistantOutputGuardrailInput, VoiceAssistantPreset, VoiceAssistantRunsSummary, VoiceAssistantRunSummary, VoiceAssistantVariant } from './assistant';
|
|
60
62
|
export type { VoiceAssistantHealthFailure, VoiceAssistantHealthHTMLHandlerOptions, VoiceAssistantHealthRoutesOptions, VoiceAssistantHealthSummary, VoiceAssistantHealthSummaryOptions } from './assistantHealth';
|
package/dist/index.js
CHANGED
|
@@ -11256,6 +11256,358 @@ var createVoiceCampaignRoutes = (options) => {
|
|
|
11256
11256
|
}
|
|
11257
11257
|
return app;
|
|
11258
11258
|
};
|
|
11259
|
+
// src/campaignDialers.ts
|
|
11260
|
+
import { Buffer as Buffer3 } from "buffer";
|
|
11261
|
+
var resolveFetch = (fetcher) => {
|
|
11262
|
+
const activeFetch = fetcher ?? globalThis.fetch;
|
|
11263
|
+
if (!activeFetch) {
|
|
11264
|
+
throw new Error("Campaign dialer requires fetch or globalThis.fetch.");
|
|
11265
|
+
}
|
|
11266
|
+
return activeFetch;
|
|
11267
|
+
};
|
|
11268
|
+
var resolveURL = async (resolver, input) => {
|
|
11269
|
+
if (!resolver) {
|
|
11270
|
+
return;
|
|
11271
|
+
}
|
|
11272
|
+
return typeof resolver === "function" ? await resolver(input) : resolver;
|
|
11273
|
+
};
|
|
11274
|
+
var baseCampaignMetadata = (input) => ({
|
|
11275
|
+
attemptId: input.attempt.id,
|
|
11276
|
+
campaignId: input.campaign.id,
|
|
11277
|
+
recipientId: input.recipient.id,
|
|
11278
|
+
voiceCampaignAttemptId: input.attempt.id,
|
|
11279
|
+
voiceCampaignId: input.campaign.id,
|
|
11280
|
+
voiceCampaignRecipientId: input.recipient.id
|
|
11281
|
+
});
|
|
11282
|
+
var resolveMetadata = async (metadata, input) => ({
|
|
11283
|
+
...baseCampaignMetadata(input),
|
|
11284
|
+
...typeof metadata === "function" ? await metadata(input) : metadata
|
|
11285
|
+
});
|
|
11286
|
+
var appendQuery = (url, params) => {
|
|
11287
|
+
if (!url) {
|
|
11288
|
+
return;
|
|
11289
|
+
}
|
|
11290
|
+
const parsed = new URL(url);
|
|
11291
|
+
for (const [key, value] of Object.entries(params)) {
|
|
11292
|
+
if (value !== undefined) {
|
|
11293
|
+
parsed.searchParams.set(key, String(value));
|
|
11294
|
+
}
|
|
11295
|
+
}
|
|
11296
|
+
return parsed.toString();
|
|
11297
|
+
};
|
|
11298
|
+
var readJson = async (response) => {
|
|
11299
|
+
const text = await response.text();
|
|
11300
|
+
if (!text.trim()) {
|
|
11301
|
+
return {};
|
|
11302
|
+
}
|
|
11303
|
+
try {
|
|
11304
|
+
return JSON.parse(text);
|
|
11305
|
+
} catch {
|
|
11306
|
+
return {
|
|
11307
|
+
text
|
|
11308
|
+
};
|
|
11309
|
+
}
|
|
11310
|
+
};
|
|
11311
|
+
var assertOk = async (response, provider) => {
|
|
11312
|
+
const body = await readJson(response);
|
|
11313
|
+
if (!response.ok) {
|
|
11314
|
+
throw new Error(`${provider} campaign dialer failed with ${response.status}: ${JSON.stringify(body)}`);
|
|
11315
|
+
}
|
|
11316
|
+
return body;
|
|
11317
|
+
};
|
|
11318
|
+
var firstString2 = (values) => {
|
|
11319
|
+
for (const value of values) {
|
|
11320
|
+
if (typeof value === "string" && value.trim()) {
|
|
11321
|
+
return value.trim();
|
|
11322
|
+
}
|
|
11323
|
+
}
|
|
11324
|
+
};
|
|
11325
|
+
var formBody = (values) => {
|
|
11326
|
+
const body = new URLSearchParams;
|
|
11327
|
+
for (const [key, value] of Object.entries(values)) {
|
|
11328
|
+
if (Array.isArray(value)) {
|
|
11329
|
+
for (const item of value) {
|
|
11330
|
+
if (item !== undefined) {
|
|
11331
|
+
body.append(key, String(item));
|
|
11332
|
+
}
|
|
11333
|
+
}
|
|
11334
|
+
continue;
|
|
11335
|
+
}
|
|
11336
|
+
if (value !== undefined) {
|
|
11337
|
+
body.set(key, String(value));
|
|
11338
|
+
}
|
|
11339
|
+
}
|
|
11340
|
+
return body;
|
|
11341
|
+
};
|
|
11342
|
+
var createVoiceTwilioCampaignDialer = (options) => async (input) => {
|
|
11343
|
+
const fetcher = resolveFetch(options.fetch);
|
|
11344
|
+
const metadata = await resolveMetadata(options.metadata, {
|
|
11345
|
+
...input,
|
|
11346
|
+
provider: "twilio"
|
|
11347
|
+
});
|
|
11348
|
+
const answerUrl = appendQuery(await resolveURL(options.answerUrl, input), metadata);
|
|
11349
|
+
const statusCallbackUrl = appendQuery(await resolveURL(options.statusCallbackUrl, input), metadata);
|
|
11350
|
+
const response = await fetcher(`${options.apiBaseUrl ?? "https://api.twilio.com"}/2010-04-01/Accounts/${encodeURIComponent(options.accountSid)}/Calls.json`, {
|
|
11351
|
+
body: formBody({
|
|
11352
|
+
From: options.from,
|
|
11353
|
+
MachineDetection: options.machineDetection,
|
|
11354
|
+
Method: options.answerMethod,
|
|
11355
|
+
StatusCallback: statusCallbackUrl,
|
|
11356
|
+
StatusCallbackEvent: options.statusCallbackEvents,
|
|
11357
|
+
StatusCallbackMethod: options.statusCallbackMethod,
|
|
11358
|
+
To: input.recipient.phone,
|
|
11359
|
+
Url: answerUrl
|
|
11360
|
+
}),
|
|
11361
|
+
headers: {
|
|
11362
|
+
authorization: `Basic ${Buffer3.from(`${options.accountSid}:${options.authToken}`).toString("base64")}`,
|
|
11363
|
+
"content-type": "application/x-www-form-urlencoded"
|
|
11364
|
+
},
|
|
11365
|
+
method: "POST"
|
|
11366
|
+
});
|
|
11367
|
+
const body = await assertOk(response, "Twilio");
|
|
11368
|
+
return {
|
|
11369
|
+
externalCallId: firstString2([body.sid, body.callSid, body.call_sid]),
|
|
11370
|
+
metadata: {
|
|
11371
|
+
provider: "twilio",
|
|
11372
|
+
response: body
|
|
11373
|
+
},
|
|
11374
|
+
status: "running"
|
|
11375
|
+
};
|
|
11376
|
+
};
|
|
11377
|
+
var createVoiceTelnyxCampaignDialer = (options) => async (input) => {
|
|
11378
|
+
const fetcher = resolveFetch(options.fetch);
|
|
11379
|
+
const metadata = await resolveMetadata(options.clientState, {
|
|
11380
|
+
...input,
|
|
11381
|
+
provider: "telnyx"
|
|
11382
|
+
});
|
|
11383
|
+
const webhookUrl = appendQuery(await resolveURL(options.webhookUrl, input), metadata);
|
|
11384
|
+
const response = await fetcher(`${options.apiBaseUrl ?? "https://api.telnyx.com"}/v2/calls`, {
|
|
11385
|
+
body: JSON.stringify({
|
|
11386
|
+
client_state: Buffer3.from(JSON.stringify(metadata)).toString("base64"),
|
|
11387
|
+
connection_id: options.connectionId,
|
|
11388
|
+
from: options.from,
|
|
11389
|
+
to: input.recipient.phone,
|
|
11390
|
+
webhook_url: webhookUrl,
|
|
11391
|
+
webhook_url_method: options.webhookUrlMethod
|
|
11392
|
+
}),
|
|
11393
|
+
headers: {
|
|
11394
|
+
authorization: `Bearer ${options.apiKey}`,
|
|
11395
|
+
"content-type": "application/json"
|
|
11396
|
+
},
|
|
11397
|
+
method: "POST"
|
|
11398
|
+
});
|
|
11399
|
+
const body = await assertOk(response, "Telnyx");
|
|
11400
|
+
const data = typeof body.data === "object" && body.data !== null ? body.data : body;
|
|
11401
|
+
return {
|
|
11402
|
+
externalCallId: firstString2([
|
|
11403
|
+
data.call_control_id,
|
|
11404
|
+
data.call_session_id,
|
|
11405
|
+
data.call_leg_id,
|
|
11406
|
+
body.call_control_id,
|
|
11407
|
+
body.call_session_id
|
|
11408
|
+
]),
|
|
11409
|
+
metadata: {
|
|
11410
|
+
provider: "telnyx",
|
|
11411
|
+
response: body
|
|
11412
|
+
},
|
|
11413
|
+
status: "running"
|
|
11414
|
+
};
|
|
11415
|
+
};
|
|
11416
|
+
var createVoicePlivoCampaignDialer = (options) => async (input) => {
|
|
11417
|
+
const fetcher = resolveFetch(options.fetch);
|
|
11418
|
+
const metadata = await resolveMetadata(options.metadata, {
|
|
11419
|
+
...input,
|
|
11420
|
+
provider: "plivo"
|
|
11421
|
+
});
|
|
11422
|
+
const answerUrl = appendQuery(await resolveURL(options.answerUrl, input), metadata);
|
|
11423
|
+
const callbackUrl = appendQuery(await resolveURL(options.callbackUrl, input), metadata);
|
|
11424
|
+
const response = await fetcher(`${options.apiBaseUrl ?? "https://api.plivo.com"}/v1/Account/${encodeURIComponent(options.authId)}/Call/`, {
|
|
11425
|
+
body: formBody({
|
|
11426
|
+
answer_method: options.answerMethod,
|
|
11427
|
+
answer_url: answerUrl,
|
|
11428
|
+
callback_method: options.callbackMethod,
|
|
11429
|
+
callback_url: callbackUrl,
|
|
11430
|
+
from: options.from,
|
|
11431
|
+
to: input.recipient.phone
|
|
11432
|
+
}),
|
|
11433
|
+
headers: {
|
|
11434
|
+
authorization: `Basic ${Buffer3.from(`${options.authId}:${options.authToken}`).toString("base64")}`,
|
|
11435
|
+
"content-type": "application/x-www-form-urlencoded"
|
|
11436
|
+
},
|
|
11437
|
+
method: "POST"
|
|
11438
|
+
});
|
|
11439
|
+
const body = await assertOk(response, "Plivo");
|
|
11440
|
+
return {
|
|
11441
|
+
externalCallId: firstString2([
|
|
11442
|
+
body.request_uuid,
|
|
11443
|
+
body.requestUuid,
|
|
11444
|
+
body.call_uuid,
|
|
11445
|
+
body.callUuid
|
|
11446
|
+
]),
|
|
11447
|
+
metadata: {
|
|
11448
|
+
provider: "plivo",
|
|
11449
|
+
response: body
|
|
11450
|
+
},
|
|
11451
|
+
status: "running"
|
|
11452
|
+
};
|
|
11453
|
+
};
|
|
11454
|
+
var campaignDialerProofProviders = [
|
|
11455
|
+
"twilio",
|
|
11456
|
+
"telnyx",
|
|
11457
|
+
"plivo"
|
|
11458
|
+
];
|
|
11459
|
+
var joinUrlPath = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
11460
|
+
var serializeProofRequestBody = (body) => {
|
|
11461
|
+
if (body instanceof URLSearchParams) {
|
|
11462
|
+
return Object.fromEntries(body.entries());
|
|
11463
|
+
}
|
|
11464
|
+
if (typeof body === "string") {
|
|
11465
|
+
try {
|
|
11466
|
+
return JSON.parse(body);
|
|
11467
|
+
} catch {
|
|
11468
|
+
return body;
|
|
11469
|
+
}
|
|
11470
|
+
}
|
|
11471
|
+
return body ? String(body) : undefined;
|
|
11472
|
+
};
|
|
11473
|
+
var createProofFetch = (provider, requests) => {
|
|
11474
|
+
let sequence = 0;
|
|
11475
|
+
return async (url, init) => {
|
|
11476
|
+
sequence += 1;
|
|
11477
|
+
requests.push({
|
|
11478
|
+
body: serializeProofRequestBody(init?.body),
|
|
11479
|
+
method: init?.method ?? "GET",
|
|
11480
|
+
provider,
|
|
11481
|
+
url: String(url)
|
|
11482
|
+
});
|
|
11483
|
+
const externalCallId = `dry-run-${provider}-${sequence}`;
|
|
11484
|
+
const payload = provider === "twilio" ? { sid: externalCallId } : provider === "telnyx" ? { data: { call_control_id: externalCallId } } : { request_uuid: externalCallId };
|
|
11485
|
+
return Response.json(payload);
|
|
11486
|
+
};
|
|
11487
|
+
};
|
|
11488
|
+
var createProofDialer = (input) => {
|
|
11489
|
+
const fetch2 = createProofFetch(input.provider, input.requests);
|
|
11490
|
+
if (input.provider === "twilio") {
|
|
11491
|
+
return createVoiceTwilioCampaignDialer({
|
|
11492
|
+
accountSid: "AC_dry_run",
|
|
11493
|
+
answerUrl: joinUrlPath(input.baseUrl, "/api/twilio/voice"),
|
|
11494
|
+
apiBaseUrl: "https://twilio.dry-run.absolutejs.local",
|
|
11495
|
+
authToken: "dry-run-token",
|
|
11496
|
+
fetch: fetch2,
|
|
11497
|
+
from: input.from,
|
|
11498
|
+
statusCallbackEvents: ["answered", "completed"],
|
|
11499
|
+
statusCallbackUrl: joinUrlPath(input.baseUrl, "/api/telephony-webhook")
|
|
11500
|
+
});
|
|
11501
|
+
}
|
|
11502
|
+
if (input.provider === "telnyx") {
|
|
11503
|
+
return createVoiceTelnyxCampaignDialer({
|
|
11504
|
+
apiBaseUrl: "https://telnyx.dry-run.absolutejs.local",
|
|
11505
|
+
apiKey: "dry-run-token",
|
|
11506
|
+
connectionId: "dry-run-connection",
|
|
11507
|
+
fetch: fetch2,
|
|
11508
|
+
from: input.from,
|
|
11509
|
+
webhookUrl: joinUrlPath(input.baseUrl, "/api/telnyx/webhook")
|
|
11510
|
+
});
|
|
11511
|
+
}
|
|
11512
|
+
return createVoicePlivoCampaignDialer({
|
|
11513
|
+
answerUrl: joinUrlPath(input.baseUrl, "/api/plivo/voice"),
|
|
11514
|
+
apiBaseUrl: "https://plivo.dry-run.absolutejs.local",
|
|
11515
|
+
authId: "dry-run-auth-id",
|
|
11516
|
+
authToken: "dry-run-token",
|
|
11517
|
+
callbackUrl: joinUrlPath(input.baseUrl, "/api/plivo/webhook"),
|
|
11518
|
+
fetch: fetch2,
|
|
11519
|
+
from: input.from
|
|
11520
|
+
});
|
|
11521
|
+
};
|
|
11522
|
+
var runCampaignDialerProofForProvider = async (input) => {
|
|
11523
|
+
const carrierRequests = [];
|
|
11524
|
+
const runtime = createVoiceCampaign({
|
|
11525
|
+
dialer: createProofDialer({
|
|
11526
|
+
baseUrl: input.baseUrl,
|
|
11527
|
+
from: input.from,
|
|
11528
|
+
provider: input.provider,
|
|
11529
|
+
requests: carrierRequests
|
|
11530
|
+
}),
|
|
11531
|
+
store: input.store
|
|
11532
|
+
});
|
|
11533
|
+
const proof = await runVoiceCampaignProof({
|
|
11534
|
+
campaign: {
|
|
11535
|
+
description: "Dry-run carrier dialer proof with campaign metadata and webhook outcome resolution.",
|
|
11536
|
+
id: `campaign-dialer-proof-${input.provider}-${crypto.randomUUID()}`,
|
|
11537
|
+
metadata: {
|
|
11538
|
+
mode: "dry-run",
|
|
11539
|
+
provider: input.provider
|
|
11540
|
+
},
|
|
11541
|
+
name: `AbsoluteJS Voice ${input.provider} Campaign Dialer Proof`
|
|
11542
|
+
},
|
|
11543
|
+
completeAttempts: false,
|
|
11544
|
+
recipients: [
|
|
11545
|
+
{
|
|
11546
|
+
id: `dialer-proof-${input.provider}-recipient`,
|
|
11547
|
+
metadata: {
|
|
11548
|
+
provider: input.provider,
|
|
11549
|
+
source: "campaign-dialer-proof"
|
|
11550
|
+
},
|
|
11551
|
+
name: `${input.provider} dry-run recipient`,
|
|
11552
|
+
phone: "+15550001001"
|
|
11553
|
+
}
|
|
11554
|
+
],
|
|
11555
|
+
runtime
|
|
11556
|
+
});
|
|
11557
|
+
const outcomes = await Promise.all(proof.tick.started.map((attempt) => applyVoiceCampaignTelephonyOutcome({
|
|
11558
|
+
decision: {
|
|
11559
|
+
action: "complete",
|
|
11560
|
+
confidence: "high",
|
|
11561
|
+
disposition: "completed",
|
|
11562
|
+
source: "status"
|
|
11563
|
+
},
|
|
11564
|
+
event: {
|
|
11565
|
+
metadata: {
|
|
11566
|
+
attemptId: attempt.id,
|
|
11567
|
+
campaignId: attempt.campaignId,
|
|
11568
|
+
externalCallId: attempt.externalCallId,
|
|
11569
|
+
voiceCampaignAttemptId: attempt.id,
|
|
11570
|
+
voiceCampaignId: attempt.campaignId
|
|
11571
|
+
},
|
|
11572
|
+
provider: input.provider,
|
|
11573
|
+
status: "completed"
|
|
11574
|
+
}
|
|
11575
|
+
}, {
|
|
11576
|
+
runtime
|
|
11577
|
+
})));
|
|
11578
|
+
return {
|
|
11579
|
+
campaignId: proof.campaign.campaign.id,
|
|
11580
|
+
carrierRequests,
|
|
11581
|
+
final: await runtime.get(proof.campaign.campaign.id),
|
|
11582
|
+
outcomes,
|
|
11583
|
+
provider: input.provider,
|
|
11584
|
+
tick: proof.tick
|
|
11585
|
+
};
|
|
11586
|
+
};
|
|
11587
|
+
var getVoiceCampaignDialerProofStatus = (options = {}) => ({
|
|
11588
|
+
generatedAt: Date.now(),
|
|
11589
|
+
mode: "dry-run",
|
|
11590
|
+
ok: true,
|
|
11591
|
+
providers: options.providers ?? campaignDialerProofProviders,
|
|
11592
|
+
runPath: options.runPath,
|
|
11593
|
+
safe: true
|
|
11594
|
+
});
|
|
11595
|
+
var runVoiceCampaignDialerProof = async (options = {}) => {
|
|
11596
|
+
const providers = options.providers ?? campaignDialerProofProviders;
|
|
11597
|
+
const store = options.store ?? createVoiceMemoryCampaignStore();
|
|
11598
|
+
const results = await Promise.all(providers.map((provider) => runCampaignDialerProofForProvider({
|
|
11599
|
+
baseUrl: options.baseUrl ?? "http://localhost",
|
|
11600
|
+
from: options.from ?? "+15550009999",
|
|
11601
|
+
provider,
|
|
11602
|
+
store
|
|
11603
|
+
})));
|
|
11604
|
+
return {
|
|
11605
|
+
generatedAt: Date.now(),
|
|
11606
|
+
mode: "dry-run",
|
|
11607
|
+
ok: results.every((result) => result.carrierRequests.length > 0 && result.outcomes.every((outcome) => outcome.applied)),
|
|
11608
|
+
providers: results
|
|
11609
|
+
};
|
|
11610
|
+
};
|
|
11259
11611
|
// src/simulationSuite.ts
|
|
11260
11612
|
import { Elysia as Elysia20 } from "elysia";
|
|
11261
11613
|
|
|
@@ -12690,7 +13042,7 @@ var createMemoryVoiceTelephonyWebhookIdempotencyStore = () => {
|
|
|
12690
13042
|
};
|
|
12691
13043
|
};
|
|
12692
13044
|
var normalizeToken = (value) => typeof value === "string" ? value.trim().toLowerCase().replace(/\s+/g, "-").replace(/_+/g, "-") : undefined;
|
|
12693
|
-
var
|
|
13045
|
+
var firstString3 = (source, keys) => {
|
|
12694
13046
|
for (const key of keys) {
|
|
12695
13047
|
const value = source[key];
|
|
12696
13048
|
if (typeof value === "string" && value.trim()) {
|
|
@@ -13062,8 +13414,8 @@ var verifyVoiceTelephonyWebhook = async (input) => {
|
|
|
13062
13414
|
var durationMsFromSeconds = (value) => typeof value === "number" ? value * 1000 : undefined;
|
|
13063
13415
|
var parseVoiceTelephonyWebhookEvent = (input) => {
|
|
13064
13416
|
const payload = flattenPayload(input.body);
|
|
13065
|
-
const provider =
|
|
13066
|
-
const status =
|
|
13417
|
+
const provider = firstString3(payload, ["provider", "Provider"]) ?? input.provider;
|
|
13418
|
+
const status = firstString3(payload, [
|
|
13067
13419
|
"CallStatus",
|
|
13068
13420
|
"call_status",
|
|
13069
13421
|
"callStatus",
|
|
@@ -13088,9 +13440,9 @@ var parseVoiceTelephonyWebhookEvent = (input) => {
|
|
|
13088
13440
|
"sip_code",
|
|
13089
13441
|
"hangupCauseCode"
|
|
13090
13442
|
]);
|
|
13091
|
-
const from =
|
|
13092
|
-
const to =
|
|
13093
|
-
const target =
|
|
13443
|
+
const from = firstString3(payload, ["From", "from", "caller_id", "callerId"]);
|
|
13444
|
+
const to = firstString3(payload, ["To", "to", "called_number", "calledNumber"]);
|
|
13445
|
+
const target = firstString3(payload, [
|
|
13094
13446
|
"transferTarget",
|
|
13095
13447
|
"TransferTarget",
|
|
13096
13448
|
"target",
|
|
@@ -13098,7 +13450,7 @@ var parseVoiceTelephonyWebhookEvent = (input) => {
|
|
|
13098
13450
|
"department"
|
|
13099
13451
|
]);
|
|
13100
13452
|
return {
|
|
13101
|
-
answeredBy:
|
|
13453
|
+
answeredBy: firstString3(payload, [
|
|
13102
13454
|
"AnsweredBy",
|
|
13103
13455
|
"answered_by",
|
|
13104
13456
|
"answeredBy",
|
|
@@ -13107,9 +13459,12 @@ var parseVoiceTelephonyWebhookEvent = (input) => {
|
|
|
13107
13459
|
]),
|
|
13108
13460
|
durationMs,
|
|
13109
13461
|
from,
|
|
13110
|
-
metadata:
|
|
13462
|
+
metadata: {
|
|
13463
|
+
...input.query,
|
|
13464
|
+
...payload
|
|
13465
|
+
},
|
|
13111
13466
|
provider,
|
|
13112
|
-
reason:
|
|
13467
|
+
reason: firstString3(payload, [
|
|
13113
13468
|
"Reason",
|
|
13114
13469
|
"reason",
|
|
13115
13470
|
"HangupCause",
|
|
@@ -13125,7 +13480,7 @@ var parseVoiceTelephonyWebhookEvent = (input) => {
|
|
|
13125
13480
|
var defaultSessionId = (input) => {
|
|
13126
13481
|
const payload = flattenPayload(input.body);
|
|
13127
13482
|
const metadataSessionId = input.event.metadata?.sessionId;
|
|
13128
|
-
return
|
|
13483
|
+
return firstString3(input.query, ["sessionId", "session_id"]) ?? firstString3(payload, [
|
|
13129
13484
|
"sessionId",
|
|
13130
13485
|
"session_id",
|
|
13131
13486
|
"SessionId",
|
|
@@ -13140,7 +13495,7 @@ var defaultSessionId = (input) => {
|
|
|
13140
13495
|
};
|
|
13141
13496
|
var defaultIdempotencyKey = (input) => {
|
|
13142
13497
|
const payload = flattenPayload(input.body);
|
|
13143
|
-
const eventId =
|
|
13498
|
+
const eventId = firstString3(payload, [
|
|
13144
13499
|
"id",
|
|
13145
13500
|
"event_id",
|
|
13146
13501
|
"eventId",
|
|
@@ -13301,11 +13656,11 @@ var createVoiceTelephonyWebhookRoutes = (options = {}) => {
|
|
|
13301
13656
|
import { Elysia as Elysia28 } from "elysia";
|
|
13302
13657
|
|
|
13303
13658
|
// src/telephony/plivo.ts
|
|
13304
|
-
import { Buffer as
|
|
13659
|
+
import { Buffer as Buffer5 } from "buffer";
|
|
13305
13660
|
import { Elysia as Elysia26 } from "elysia";
|
|
13306
13661
|
|
|
13307
13662
|
// src/telephony/twilio.ts
|
|
13308
|
-
import { Buffer as
|
|
13663
|
+
import { Buffer as Buffer4 } from "buffer";
|
|
13309
13664
|
import { Elysia as Elysia25 } from "elysia";
|
|
13310
13665
|
var TWILIO_MULAW_SAMPLE_RATE = 8000;
|
|
13311
13666
|
var VOICE_PCM_SAMPLE_RATE = 16000;
|
|
@@ -13335,7 +13690,7 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
|
|
|
13335
13690
|
}
|
|
13336
13691
|
return parameters;
|
|
13337
13692
|
};
|
|
13338
|
-
var
|
|
13693
|
+
var joinUrlPath2 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
13339
13694
|
var escapeHtml25 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
13340
13695
|
var getWebhookVerificationUrl = (webhook, input) => {
|
|
13341
13696
|
if (!webhook?.verificationUrl) {
|
|
@@ -13349,8 +13704,8 @@ var getWebhookVerificationUrl = (webhook, input) => {
|
|
|
13349
13704
|
var buildTwilioVoiceSetupStatus = async (options, input) => {
|
|
13350
13705
|
const origin = resolveRequestOrigin(input.request);
|
|
13351
13706
|
const stream = await resolveTwilioStreamUrl(options, input);
|
|
13352
|
-
const twiml =
|
|
13353
|
-
const webhook =
|
|
13707
|
+
const twiml = joinUrlPath2(origin, input.twimlPath);
|
|
13708
|
+
const webhook = joinUrlPath2(origin, input.webhookPath);
|
|
13354
13709
|
const verificationUrl = getWebhookVerificationUrl(options.webhook, input);
|
|
13355
13710
|
const missing = Object.entries(options.setup?.requiredEnv ?? {}).filter((entry) => !entry[1]).map(([name]) => name);
|
|
13356
13711
|
const signingConfigured = Boolean(options.webhook?.signingSecret || options.webhook?.verify);
|
|
@@ -13596,7 +13951,7 @@ var bytesToInt16Array = (bytes) => {
|
|
|
13596
13951
|
return output;
|
|
13597
13952
|
};
|
|
13598
13953
|
var decodeTwilioMulawBase64 = (payload) => {
|
|
13599
|
-
const bytes = Uint8Array.from(
|
|
13954
|
+
const bytes = Uint8Array.from(Buffer4.from(payload, "base64"));
|
|
13600
13955
|
const samples = new Int16Array(bytes.length);
|
|
13601
13956
|
for (let index = 0;index < bytes.length; index += 1) {
|
|
13602
13957
|
samples[index] = decodeMulawSample(bytes[index] ?? 0);
|
|
@@ -13608,7 +13963,7 @@ var encodeTwilioMulawBase64 = (samples) => {
|
|
|
13608
13963
|
for (let index = 0;index < samples.length; index += 1) {
|
|
13609
13964
|
bytes[index] = encodeMulawSample(samples[index] ?? 0);
|
|
13610
13965
|
}
|
|
13611
|
-
return
|
|
13966
|
+
return Buffer4.from(bytes).toString("base64");
|
|
13612
13967
|
};
|
|
13613
13968
|
var transcodeTwilioInboundPayloadToPCM16 = (payload) => {
|
|
13614
13969
|
const narrowband = decodeTwilioMulawBase64(payload);
|
|
@@ -13617,7 +13972,7 @@ var transcodeTwilioInboundPayloadToPCM16 = (payload) => {
|
|
|
13617
13972
|
};
|
|
13618
13973
|
var transcodePCMToTwilioOutboundPayload = (chunk, format) => {
|
|
13619
13974
|
if (format.container === "raw" && format.encoding === "mulaw" && format.channels === 1 && format.sampleRateHz === TWILIO_MULAW_SAMPLE_RATE) {
|
|
13620
|
-
return
|
|
13975
|
+
return Buffer4.from(chunk).toString("base64");
|
|
13621
13976
|
}
|
|
13622
13977
|
if (format.encoding !== "pcm_s16le") {
|
|
13623
13978
|
throw new Error(`Unsupported outbound telephony audio format: ${format.container}/${format.encoding}`);
|
|
@@ -13658,7 +14013,7 @@ var createTwilioSocketAdapter = (socket, getState) => ({
|
|
|
13658
14013
|
return;
|
|
13659
14014
|
}
|
|
13660
14015
|
if (message.type === "audio") {
|
|
13661
|
-
const payload = transcodePCMToTwilioOutboundPayload(Uint8Array.from(
|
|
14016
|
+
const payload = transcodePCMToTwilioOutboundPayload(Uint8Array.from(Buffer4.from(message.chunkBase64, "base64")), message.format);
|
|
13662
14017
|
state.hasOutboundAudioSinceLastInbound = true;
|
|
13663
14018
|
state.reviewRecorder?.recordTwilioOutbound({
|
|
13664
14019
|
bytes: payload.length,
|
|
@@ -14017,7 +14372,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
14017
14372
|
// src/telephony/plivo.ts
|
|
14018
14373
|
var escapeXml3 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
14019
14374
|
var escapeHtml26 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
14020
|
-
var
|
|
14375
|
+
var joinUrlPath3 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
14021
14376
|
var resolveRequestOrigin2 = (request) => {
|
|
14022
14377
|
const url = new URL(request.url);
|
|
14023
14378
|
const forwardedHost = request.headers.get("x-forwarded-host");
|
|
@@ -14184,7 +14539,7 @@ var createPlivoMediaStreamBridge = (socket, options) => {
|
|
|
14184
14539
|
}
|
|
14185
14540
|
};
|
|
14186
14541
|
};
|
|
14187
|
-
var toBase642 = (bytes) =>
|
|
14542
|
+
var toBase642 = (bytes) => Buffer5.from(new Uint8Array(bytes)).toString("base64");
|
|
14188
14543
|
var timingSafeEqual2 = (left, right) => {
|
|
14189
14544
|
const encoder = new TextEncoder;
|
|
14190
14545
|
const leftBytes = encoder.encode(left);
|
|
@@ -14238,8 +14593,8 @@ var verifyVoicePlivoWebhookSignature = async (input) => {
|
|
|
14238
14593
|
var buildPlivoVoiceSetupStatus = async (options, input) => {
|
|
14239
14594
|
const origin = resolveRequestOrigin2(input.request);
|
|
14240
14595
|
const stream = await resolvePlivoStreamUrl(options, input);
|
|
14241
|
-
const answer =
|
|
14242
|
-
const webhook =
|
|
14596
|
+
const answer = joinUrlPath3(origin, input.answerPath);
|
|
14597
|
+
const webhook = joinUrlPath3(origin, input.webhookPath);
|
|
14243
14598
|
const missing = Object.entries(options.setup?.requiredEnv ?? {}).filter((entry) => !entry[1]).map(([name]) => name);
|
|
14244
14599
|
const signingConfigured = Boolean(options.webhook?.authToken || options.webhook?.verify);
|
|
14245
14600
|
const warnings = [
|
|
@@ -14486,11 +14841,11 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
14486
14841
|
};
|
|
14487
14842
|
|
|
14488
14843
|
// src/telephony/telnyx.ts
|
|
14489
|
-
import { Buffer as
|
|
14844
|
+
import { Buffer as Buffer6 } from "buffer";
|
|
14490
14845
|
import { Elysia as Elysia27 } from "elysia";
|
|
14491
14846
|
var escapeXml4 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
14492
14847
|
var escapeHtml27 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
14493
|
-
var
|
|
14848
|
+
var joinUrlPath4 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
14494
14849
|
var resolveRequestOrigin3 = (request) => {
|
|
14495
14850
|
const url = new URL(request.url);
|
|
14496
14851
|
const forwardedHost = request.headers.get("x-forwarded-host");
|
|
@@ -14636,7 +14991,7 @@ var createTelnyxMediaStreamBridge = (socket, options) => {
|
|
|
14636
14991
|
}
|
|
14637
14992
|
};
|
|
14638
14993
|
};
|
|
14639
|
-
var decodeBase64 = (value) => Uint8Array.from(
|
|
14994
|
+
var decodeBase64 = (value) => Uint8Array.from(Buffer6.from(value, "base64"));
|
|
14640
14995
|
var verifyVoiceTelnyxWebhookSignature = async (input) => {
|
|
14641
14996
|
if (!input.publicKey) {
|
|
14642
14997
|
return { ok: false, reason: "missing-secret" };
|
|
@@ -14662,8 +15017,8 @@ var verifyVoiceTelnyxWebhookSignature = async (input) => {
|
|
|
14662
15017
|
var buildTelnyxVoiceSetupStatus = async (options, input) => {
|
|
14663
15018
|
const origin = resolveRequestOrigin3(input.request);
|
|
14664
15019
|
const stream = await resolveTelnyxStreamUrl(options, input);
|
|
14665
|
-
const texml =
|
|
14666
|
-
const webhook =
|
|
15020
|
+
const texml = joinUrlPath4(origin, input.texmlPath);
|
|
15021
|
+
const webhook = joinUrlPath4(origin, input.webhookPath);
|
|
14667
15022
|
const missing = Object.entries(options.setup?.requiredEnv ?? {}).filter((entry) => !entry[1]).map(([name]) => name);
|
|
14668
15023
|
const signingConfigured = Boolean(options.webhook?.publicKey || options.webhook?.verify);
|
|
14669
15024
|
const warnings = [
|
|
@@ -19262,6 +19617,7 @@ export {
|
|
|
19262
19617
|
runVoiceScenarioEvals,
|
|
19263
19618
|
runVoiceOutcomeContractSuite,
|
|
19264
19619
|
runVoiceCampaignProof,
|
|
19620
|
+
runVoiceCampaignDialerProof,
|
|
19265
19621
|
resolveVoiceTraceRedactionOptions,
|
|
19266
19622
|
resolveVoiceTelephonyOutcome,
|
|
19267
19623
|
resolveVoiceSTTRoutingStrategy,
|
|
@@ -19321,6 +19677,7 @@ export {
|
|
|
19321
19677
|
isVoiceOpsTaskOverdue,
|
|
19322
19678
|
heartbeatVoiceOpsTask,
|
|
19323
19679
|
hasVoiceOpsTaskSLABreach,
|
|
19680
|
+
getVoiceCampaignDialerProofStatus,
|
|
19324
19681
|
filterVoiceTraceEvents,
|
|
19325
19682
|
failVoiceOpsTask,
|
|
19326
19683
|
exportVoiceTrace,
|
|
@@ -19346,6 +19703,7 @@ export {
|
|
|
19346
19703
|
createVoiceWebhookDeliveryWorkerLoop,
|
|
19347
19704
|
createVoiceWebhookDeliveryWorker,
|
|
19348
19705
|
createVoiceTwilioRedirectHandoffAdapter,
|
|
19706
|
+
createVoiceTwilioCampaignDialer,
|
|
19349
19707
|
createVoiceTurnQualityRoutes,
|
|
19350
19708
|
createVoiceTurnQualityJSONHandler,
|
|
19351
19709
|
createVoiceTurnQualityHTMLHandler,
|
|
@@ -19368,6 +19726,7 @@ export {
|
|
|
19368
19726
|
createVoiceToolContractJSONHandler,
|
|
19369
19727
|
createVoiceToolContractHTMLHandler,
|
|
19370
19728
|
createVoiceToolContract,
|
|
19729
|
+
createVoiceTelnyxCampaignDialer,
|
|
19371
19730
|
createVoiceTelephonyWebhookRoutes,
|
|
19372
19731
|
createVoiceTelephonyWebhookHandler,
|
|
19373
19732
|
createVoiceTelephonyOutcomePolicy,
|
|
@@ -19424,6 +19783,7 @@ export {
|
|
|
19424
19783
|
createVoicePostgresIntegrationEventStore,
|
|
19425
19784
|
createVoicePostgresExternalObjectMapStore,
|
|
19426
19785
|
createVoicePostgresCampaignStore,
|
|
19786
|
+
createVoicePlivoCampaignDialer,
|
|
19427
19787
|
createVoicePhoneAgent,
|
|
19428
19788
|
createVoiceOutcomeContractRoutes,
|
|
19429
19789
|
createVoiceOutcomeContractJSONHandler,
|
package/dist/testing/index.js
CHANGED
|
@@ -8434,7 +8434,10 @@ var parseVoiceTelephonyWebhookEvent = (input) => {
|
|
|
8434
8434
|
]),
|
|
8435
8435
|
durationMs,
|
|
8436
8436
|
from,
|
|
8437
|
-
metadata:
|
|
8437
|
+
metadata: {
|
|
8438
|
+
...input.query,
|
|
8439
|
+
...payload
|
|
8440
|
+
},
|
|
8438
8441
|
provider,
|
|
8439
8442
|
reason: firstString(payload, [
|
|
8440
8443
|
"Reason",
|