@absolutejs/voice 0.0.22-beta.151 → 0.0.22-beta.153
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 +30 -0
- package/dist/angular/index.d.ts +2 -0
- package/dist/angular/index.js +604 -124
- package/dist/angular/voice-delivery-runtime.component.d.ts +17 -0
- package/dist/angular/voice-delivery-runtime.service.d.ts +16 -0
- package/dist/client/deliveryRuntime.d.ts +34 -0
- package/dist/client/deliveryRuntimeWidget.d.ts +37 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.js +371 -100
- package/dist/deliveryRuntime.d.ts +14 -2
- package/dist/index.js +44 -1
- package/dist/react/VoiceDeliveryRuntime.d.ts +7 -0
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.js +632 -256
- package/dist/react/useVoiceDeliveryRuntime.d.ts +13 -0
- package/dist/svelte/createVoiceDeliveryRuntime.d.ts +11 -0
- package/dist/svelte/index.d.ts +1 -0
- package/dist/svelte/index.js +394 -114
- package/dist/vue/VoiceDeliveryRuntime.d.ts +30 -0
- package/dist/vue/index.d.ts +2 -0
- package/dist/vue/index.js +649 -261
- package/dist/vue/useVoiceDeliveryRuntime.d.ts +13 -0
- package/package.json +1 -1
package/dist/svelte/index.js
CHANGED
|
@@ -189,6 +189,285 @@ var createVoiceCampaignDialerProofStore = (path = "/api/voice/campaigns/dialer-p
|
|
|
189
189
|
|
|
190
190
|
// src/svelte/createVoiceCampaignDialerProof.ts
|
|
191
191
|
var createVoiceCampaignDialerProof = (path = "/api/voice/campaigns/dialer-proof", options = {}) => createVoiceCampaignDialerProofStore(path, options);
|
|
192
|
+
// src/client/deliveryRuntime.ts
|
|
193
|
+
var getDefaultActionPath = (path, action, options) => {
|
|
194
|
+
if (action === "tick") {
|
|
195
|
+
return options.tickPath ?? `${path.replace(/\/$/, "")}/tick`;
|
|
196
|
+
}
|
|
197
|
+
return options.requeueDeadLettersPath ?? `${path.replace(/\/$/, "")}/requeue-dead-letters`;
|
|
198
|
+
};
|
|
199
|
+
var fetchVoiceDeliveryRuntime = async (path = "/api/voice-delivery-runtime", options = {}) => {
|
|
200
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
201
|
+
const response = await fetchImpl(path);
|
|
202
|
+
if (!response.ok) {
|
|
203
|
+
throw new Error(`Voice delivery runtime failed: HTTP ${response.status}`);
|
|
204
|
+
}
|
|
205
|
+
return await response.json();
|
|
206
|
+
};
|
|
207
|
+
var runVoiceDeliveryRuntimeAction = async (action, path = "/api/voice-delivery-runtime", options = {}) => {
|
|
208
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
209
|
+
const response = await fetchImpl(getDefaultActionPath(path, action, options), {
|
|
210
|
+
method: "POST"
|
|
211
|
+
});
|
|
212
|
+
if (!response.ok) {
|
|
213
|
+
throw new Error(`Voice delivery runtime ${action} failed: HTTP ${response.status}`);
|
|
214
|
+
}
|
|
215
|
+
const body = await response.json();
|
|
216
|
+
return {
|
|
217
|
+
action,
|
|
218
|
+
result: body.result,
|
|
219
|
+
summary: body.summary,
|
|
220
|
+
updatedAt: Date.now()
|
|
221
|
+
};
|
|
222
|
+
};
|
|
223
|
+
var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", options = {}) => {
|
|
224
|
+
const listeners = new Set;
|
|
225
|
+
let closed = false;
|
|
226
|
+
let timer;
|
|
227
|
+
let snapshot = {
|
|
228
|
+
actionError: null,
|
|
229
|
+
actionStatus: "idle",
|
|
230
|
+
error: null,
|
|
231
|
+
isLoading: false
|
|
232
|
+
};
|
|
233
|
+
const emit = () => {
|
|
234
|
+
for (const listener of listeners) {
|
|
235
|
+
listener();
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
const refresh = async () => {
|
|
239
|
+
if (closed) {
|
|
240
|
+
return snapshot.report;
|
|
241
|
+
}
|
|
242
|
+
snapshot = {
|
|
243
|
+
...snapshot,
|
|
244
|
+
error: null,
|
|
245
|
+
isLoading: true
|
|
246
|
+
};
|
|
247
|
+
emit();
|
|
248
|
+
try {
|
|
249
|
+
const report = await fetchVoiceDeliveryRuntime(path, options);
|
|
250
|
+
snapshot = {
|
|
251
|
+
...snapshot,
|
|
252
|
+
error: null,
|
|
253
|
+
isLoading: false,
|
|
254
|
+
report,
|
|
255
|
+
updatedAt: Date.now()
|
|
256
|
+
};
|
|
257
|
+
emit();
|
|
258
|
+
return report;
|
|
259
|
+
} catch (error) {
|
|
260
|
+
snapshot = {
|
|
261
|
+
...snapshot,
|
|
262
|
+
error: error instanceof Error ? error.message : String(error),
|
|
263
|
+
isLoading: false
|
|
264
|
+
};
|
|
265
|
+
emit();
|
|
266
|
+
throw error;
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
const runAction = async (action) => {
|
|
270
|
+
if (closed) {
|
|
271
|
+
return snapshot.lastAction;
|
|
272
|
+
}
|
|
273
|
+
snapshot = {
|
|
274
|
+
...snapshot,
|
|
275
|
+
actionError: null,
|
|
276
|
+
actionStatus: "running"
|
|
277
|
+
};
|
|
278
|
+
emit();
|
|
279
|
+
try {
|
|
280
|
+
const result = await runVoiceDeliveryRuntimeAction(action, path, options);
|
|
281
|
+
snapshot = {
|
|
282
|
+
...snapshot,
|
|
283
|
+
actionError: null,
|
|
284
|
+
actionStatus: "completed",
|
|
285
|
+
lastAction: result
|
|
286
|
+
};
|
|
287
|
+
emit();
|
|
288
|
+
await refresh();
|
|
289
|
+
return result;
|
|
290
|
+
} catch (error) {
|
|
291
|
+
snapshot = {
|
|
292
|
+
...snapshot,
|
|
293
|
+
actionError: error instanceof Error ? error.message : String(error),
|
|
294
|
+
actionStatus: "failed"
|
|
295
|
+
};
|
|
296
|
+
emit();
|
|
297
|
+
throw error;
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
const close = () => {
|
|
301
|
+
closed = true;
|
|
302
|
+
if (timer) {
|
|
303
|
+
clearInterval(timer);
|
|
304
|
+
timer = undefined;
|
|
305
|
+
}
|
|
306
|
+
listeners.clear();
|
|
307
|
+
};
|
|
308
|
+
if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
|
|
309
|
+
timer = setInterval(() => {
|
|
310
|
+
refresh().catch(() => {});
|
|
311
|
+
}, options.intervalMs);
|
|
312
|
+
}
|
|
313
|
+
return {
|
|
314
|
+
close,
|
|
315
|
+
getServerSnapshot: () => snapshot,
|
|
316
|
+
getSnapshot: () => snapshot,
|
|
317
|
+
requeueDeadLetters: () => runAction("requeue-dead-letters"),
|
|
318
|
+
refresh,
|
|
319
|
+
tick: () => runAction("tick"),
|
|
320
|
+
subscribe: (listener) => {
|
|
321
|
+
listeners.add(listener);
|
|
322
|
+
return () => {
|
|
323
|
+
listeners.delete(listener);
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
// src/client/deliveryRuntimeWidget.ts
|
|
330
|
+
var DEFAULT_TITLE = "Voice Delivery Runtime";
|
|
331
|
+
var DEFAULT_DESCRIPTION = "Audit and trace delivery worker health from your AbsoluteJS voice app.";
|
|
332
|
+
var escapeHtml = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
333
|
+
var createSurface = (id, summary) => {
|
|
334
|
+
if (!summary) {
|
|
335
|
+
return {
|
|
336
|
+
deadLettered: 0,
|
|
337
|
+
detail: "Worker disabled",
|
|
338
|
+
failed: 0,
|
|
339
|
+
id,
|
|
340
|
+
label: id === "audit" ? "Audit delivery" : "Trace delivery",
|
|
341
|
+
pending: 0,
|
|
342
|
+
status: "disabled",
|
|
343
|
+
total: 0
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
const blocked = summary.failed + summary.deadLettered;
|
|
347
|
+
return {
|
|
348
|
+
deadLettered: summary.deadLettered,
|
|
349
|
+
detail: `${summary.delivered}/${summary.total} delivered, ${summary.pending} pending`,
|
|
350
|
+
failed: summary.failed,
|
|
351
|
+
id,
|
|
352
|
+
label: id === "audit" ? "Audit delivery" : "Trace delivery",
|
|
353
|
+
pending: summary.pending,
|
|
354
|
+
status: blocked > 0 ? "warn" : "pass",
|
|
355
|
+
total: summary.total
|
|
356
|
+
};
|
|
357
|
+
};
|
|
358
|
+
var createVoiceDeliveryRuntimeViewModel = (snapshot, options = {}) => {
|
|
359
|
+
const report = snapshot.report;
|
|
360
|
+
const surfaces = [
|
|
361
|
+
createSurface("audit", report?.summary.audit),
|
|
362
|
+
createSurface("trace", report?.summary.trace)
|
|
363
|
+
];
|
|
364
|
+
const hasWarnings = surfaces.some((surface) => surface.status === "warn");
|
|
365
|
+
return {
|
|
366
|
+
description: options.description ?? DEFAULT_DESCRIPTION,
|
|
367
|
+
error: snapshot.error,
|
|
368
|
+
actionError: snapshot.actionError,
|
|
369
|
+
actionStatus: snapshot.actionStatus,
|
|
370
|
+
isLoading: snapshot.isLoading,
|
|
371
|
+
isRunning: Boolean(report?.isRunning),
|
|
372
|
+
label: snapshot.error ? "Unavailable" : report ? report.isRunning ? "Running" : "Stopped" : "Checking",
|
|
373
|
+
status: snapshot.error ? "error" : report ? hasWarnings ? "warn" : "pass" : "loading",
|
|
374
|
+
surfaces,
|
|
375
|
+
title: options.title ?? DEFAULT_TITLE,
|
|
376
|
+
updatedAt: snapshot.updatedAt
|
|
377
|
+
};
|
|
378
|
+
};
|
|
379
|
+
var renderVoiceDeliveryRuntimeHTML = (snapshot, options = {}) => {
|
|
380
|
+
const model = createVoiceDeliveryRuntimeViewModel(snapshot, options);
|
|
381
|
+
const surfaces = model.surfaces.map((surface) => `<li class="absolute-voice-delivery-runtime__surface absolute-voice-delivery-runtime__surface--${escapeHtml(surface.status)}">
|
|
382
|
+
<span>${escapeHtml(surface.label)}</span>
|
|
383
|
+
<strong>${escapeHtml(surface.detail)}</strong>
|
|
384
|
+
<small>${String(surface.failed)} failed · ${String(surface.deadLettered)} dead-lettered</small>
|
|
385
|
+
</li>`).join("");
|
|
386
|
+
const actions = options.includeActions === false ? "" : `<div class="absolute-voice-delivery-runtime__actions">
|
|
387
|
+
<button type="button" data-absolute-voice-delivery-runtime-action="tick">${model.actionStatus === "running" ? "Working..." : "Tick workers"}</button>
|
|
388
|
+
<button type="button" data-absolute-voice-delivery-runtime-action="requeue-dead-letters"${model.surfaces.some((surface) => surface.deadLettered > 0) ? "" : " disabled"}>Requeue dead letters</button>
|
|
389
|
+
</div>`;
|
|
390
|
+
const actionError = model.actionError ? `<p class="absolute-voice-delivery-runtime__error">${escapeHtml(model.actionError)}</p>` : "";
|
|
391
|
+
return `<section class="absolute-voice-delivery-runtime absolute-voice-delivery-runtime--${escapeHtml(model.status)}">
|
|
392
|
+
<header class="absolute-voice-delivery-runtime__header">
|
|
393
|
+
<span class="absolute-voice-delivery-runtime__eyebrow">${escapeHtml(model.title)}</span>
|
|
394
|
+
<strong class="absolute-voice-delivery-runtime__label">${escapeHtml(model.label)}</strong>
|
|
395
|
+
</header>
|
|
396
|
+
<p class="absolute-voice-delivery-runtime__description">${escapeHtml(model.description)}</p>
|
|
397
|
+
<ul class="absolute-voice-delivery-runtime__surfaces">${surfaces}</ul>
|
|
398
|
+
${actions}
|
|
399
|
+
${actionError}
|
|
400
|
+
${model.error ? `<p class="absolute-voice-delivery-runtime__error">${escapeHtml(model.error)}</p>` : ""}
|
|
401
|
+
</section>`;
|
|
402
|
+
};
|
|
403
|
+
var getVoiceDeliveryRuntimeCSS = () => `.absolute-voice-delivery-runtime{border:1px solid #c9d8cf;border-radius:20px;background:#f6fff9;color:#0d1b12;padding:18px;box-shadow:0 18px 40px rgba(19,55,35,.12);font-family:inherit}.absolute-voice-delivery-runtime--warn,.absolute-voice-delivery-runtime--error{border-color:#f2b56b;background:#fff9ed}.absolute-voice-delivery-runtime__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-delivery-runtime__eyebrow{color:#4e6b59;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-delivery-runtime__label{font-size:28px;line-height:1}.absolute-voice-delivery-runtime__description{color:#33483b;margin:12px 0 0}.absolute-voice-delivery-runtime__surfaces{display:grid;gap:8px;list-style:none;margin:16px 0 0;padding:0}.absolute-voice-delivery-runtime__surface{background:#fff;border:1px solid #d9eadf;border-radius:14px;display:grid;gap:4px;padding:10px 12px}.absolute-voice-delivery-runtime__surface--warn{border-color:#f2b56b}.absolute-voice-delivery-runtime__surface--disabled{opacity:.72}.absolute-voice-delivery-runtime__surface span,.absolute-voice-delivery-runtime__surface small{color:#587063}.absolute-voice-delivery-runtime__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px}.absolute-voice-delivery-runtime__actions button{background:#134e2d;border:0;border-radius:999px;color:#f6fff9;cursor:pointer;font:inherit;font-weight:800;padding:8px 12px}.absolute-voice-delivery-runtime__actions button:disabled{cursor:not-allowed;opacity:.48}.absolute-voice-delivery-runtime__error{color:#9f1239;font-weight:700}`;
|
|
404
|
+
var mountVoiceDeliveryRuntime = (element, path = "/api/voice-delivery-runtime", options = {}) => {
|
|
405
|
+
const store = createVoiceDeliveryRuntimeStore(path, options);
|
|
406
|
+
const render = () => {
|
|
407
|
+
element.innerHTML = renderVoiceDeliveryRuntimeHTML(store.getSnapshot(), options);
|
|
408
|
+
};
|
|
409
|
+
const unsubscribe = store.subscribe(render);
|
|
410
|
+
const handleClick = (event) => {
|
|
411
|
+
const target = event.target;
|
|
412
|
+
if (!(target instanceof Element)) {
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
const action = target.closest("[data-absolute-voice-delivery-runtime-action]");
|
|
416
|
+
const actionName = action?.getAttribute("data-absolute-voice-delivery-runtime-action");
|
|
417
|
+
if (actionName === "tick") {
|
|
418
|
+
store.tick().catch(() => {});
|
|
419
|
+
}
|
|
420
|
+
if (actionName === "requeue-dead-letters") {
|
|
421
|
+
store.requeueDeadLetters().catch(() => {});
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
element.addEventListener?.("click", handleClick);
|
|
425
|
+
render();
|
|
426
|
+
store.refresh().catch(() => {});
|
|
427
|
+
return {
|
|
428
|
+
close: () => {
|
|
429
|
+
element.removeEventListener?.("click", handleClick);
|
|
430
|
+
unsubscribe();
|
|
431
|
+
store.close();
|
|
432
|
+
},
|
|
433
|
+
refresh: store.refresh
|
|
434
|
+
};
|
|
435
|
+
};
|
|
436
|
+
var defineVoiceDeliveryRuntimeElement = (tagName = "absolute-voice-delivery-runtime") => {
|
|
437
|
+
if (typeof window === "undefined" || typeof customElements === "undefined" || customElements.get(tagName)) {
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
customElements.define(tagName, class AbsoluteVoiceDeliveryRuntimeElement extends HTMLElement {
|
|
441
|
+
mounted;
|
|
442
|
+
connectedCallback() {
|
|
443
|
+
const intervalMs = Number(this.getAttribute("interval-ms") ?? 5000);
|
|
444
|
+
this.mounted = mountVoiceDeliveryRuntime(this, this.getAttribute("path") ?? "/api/voice-delivery-runtime", {
|
|
445
|
+
description: this.getAttribute("description") ?? undefined,
|
|
446
|
+
intervalMs: Number.isFinite(intervalMs) ? intervalMs : 5000,
|
|
447
|
+
title: this.getAttribute("title") ?? undefined
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
disconnectedCallback() {
|
|
451
|
+
this.mounted?.close();
|
|
452
|
+
this.mounted = undefined;
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
// src/svelte/createVoiceDeliveryRuntime.ts
|
|
458
|
+
var createVoiceDeliveryRuntime = (path = "/api/voice-delivery-runtime", options = {}) => {
|
|
459
|
+
const store = createVoiceDeliveryRuntimeStore(path, options);
|
|
460
|
+
return {
|
|
461
|
+
close: store.close,
|
|
462
|
+
getHTML: () => renderVoiceDeliveryRuntimeHTML(store.getSnapshot(), options),
|
|
463
|
+
getSnapshot: store.getSnapshot,
|
|
464
|
+
getViewModel: () => createVoiceDeliveryRuntimeViewModel(store.getSnapshot(), options),
|
|
465
|
+
requeueDeadLetters: store.requeueDeadLetters,
|
|
466
|
+
refresh: store.refresh,
|
|
467
|
+
subscribe: store.subscribe,
|
|
468
|
+
tick: store.tick
|
|
469
|
+
};
|
|
470
|
+
};
|
|
192
471
|
// src/client/opsStatus.ts
|
|
193
472
|
var fetchVoiceOpsStatus = async (path = "/api/voice/ops-status", options = {}) => {
|
|
194
473
|
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
@@ -269,8 +548,8 @@ var createVoiceOpsStatusStore = (path = "/api/voice/ops-status", options = {}) =
|
|
|
269
548
|
};
|
|
270
549
|
|
|
271
550
|
// src/client/opsStatusWidget.ts
|
|
272
|
-
var
|
|
273
|
-
var
|
|
551
|
+
var DEFAULT_TITLE2 = "Voice Ops Status";
|
|
552
|
+
var DEFAULT_DESCRIPTION2 = "Certified workflow, provider, and handoff readiness from your AbsoluteJS voice app.";
|
|
274
553
|
var SURFACE_LABELS = {
|
|
275
554
|
handoffs: "Handoffs",
|
|
276
555
|
providers: "Providers",
|
|
@@ -278,7 +557,7 @@ var SURFACE_LABELS = {
|
|
|
278
557
|
sessions: "Sessions",
|
|
279
558
|
workflows: "Workflows"
|
|
280
559
|
};
|
|
281
|
-
var
|
|
560
|
+
var escapeHtml2 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
282
561
|
var readNumber = (value, key) => value && typeof value === "object" && (key in value) ? Number(value[key] ?? 0) : 0;
|
|
283
562
|
var surfaceDetail = (surface) => {
|
|
284
563
|
const total = readNumber(surface, "total");
|
|
@@ -318,7 +597,7 @@ var createVoiceOpsStatusViewModel = (snapshot, options = {}) => {
|
|
|
318
597
|
};
|
|
319
598
|
});
|
|
320
599
|
return {
|
|
321
|
-
description: options.description ??
|
|
600
|
+
description: options.description ?? DEFAULT_DESCRIPTION2,
|
|
322
601
|
error: snapshot.error,
|
|
323
602
|
isLoading: snapshot.isLoading,
|
|
324
603
|
label: getVoiceOpsStatusLabel(report, snapshot.error),
|
|
@@ -326,31 +605,31 @@ var createVoiceOpsStatusViewModel = (snapshot, options = {}) => {
|
|
|
326
605
|
passed: report?.passed ?? 0,
|
|
327
606
|
status: snapshot.error ? "error" : report ? report.status : snapshot.isLoading ? "loading" : "loading",
|
|
328
607
|
surfaces,
|
|
329
|
-
title: options.title ??
|
|
608
|
+
title: options.title ?? DEFAULT_TITLE2,
|
|
330
609
|
total: report?.total ?? 0,
|
|
331
610
|
updatedAt: snapshot.updatedAt
|
|
332
611
|
};
|
|
333
612
|
};
|
|
334
613
|
var renderVoiceOpsStatusHTML = (snapshot, options = {}) => {
|
|
335
614
|
const model = createVoiceOpsStatusViewModel(snapshot, options);
|
|
336
|
-
const surfaces = model.surfaces.length ? model.surfaces.map((surface) => `<li class="absolute-voice-ops-status__surface absolute-voice-ops-status__surface--${
|
|
337
|
-
<span>${
|
|
338
|
-
<strong>${
|
|
615
|
+
const surfaces = model.surfaces.length ? model.surfaces.map((surface) => `<li class="absolute-voice-ops-status__surface absolute-voice-ops-status__surface--${escapeHtml2(surface.status)}">
|
|
616
|
+
<span>${escapeHtml2(surface.label)}</span>
|
|
617
|
+
<strong>${escapeHtml2(surface.detail)}</strong>
|
|
339
618
|
</li>`).join("") : '<li class="absolute-voice-ops-status__surface"><span>Status</span><strong>Waiting for first check</strong></li>';
|
|
340
|
-
const links = model.links.length ? `<nav class="absolute-voice-ops-status__links">${model.links.slice(0, 4).map((link) => `<a href="${
|
|
341
|
-
return `<section class="absolute-voice-ops-status absolute-voice-ops-status--${
|
|
619
|
+
const links = model.links.length ? `<nav class="absolute-voice-ops-status__links">${model.links.slice(0, 4).map((link) => `<a href="${escapeHtml2(link.href)}">${escapeHtml2(link.label)}</a>`).join("")}</nav>` : "";
|
|
620
|
+
return `<section class="absolute-voice-ops-status absolute-voice-ops-status--${escapeHtml2(model.status)}">
|
|
342
621
|
<header class="absolute-voice-ops-status__header">
|
|
343
|
-
<span class="absolute-voice-ops-status__eyebrow">${
|
|
344
|
-
<strong class="absolute-voice-ops-status__label">${
|
|
622
|
+
<span class="absolute-voice-ops-status__eyebrow">${escapeHtml2(model.title)}</span>
|
|
623
|
+
<strong class="absolute-voice-ops-status__label">${escapeHtml2(model.label)}</strong>
|
|
345
624
|
</header>
|
|
346
|
-
<p class="absolute-voice-ops-status__description">${
|
|
625
|
+
<p class="absolute-voice-ops-status__description">${escapeHtml2(model.description)}</p>
|
|
347
626
|
<div class="absolute-voice-ops-status__summary">
|
|
348
627
|
<span>${model.passed} passing</span>
|
|
349
628
|
<span>${Math.max(model.total - model.passed, 0)} failing</span>
|
|
350
629
|
<span>${model.total} checks</span>
|
|
351
630
|
</div>
|
|
352
631
|
<ul class="absolute-voice-ops-status__surfaces">${surfaces}</ul>
|
|
353
|
-
${model.error ? `<p class="absolute-voice-ops-status__error">${
|
|
632
|
+
${model.error ? `<p class="absolute-voice-ops-status__error">${escapeHtml2(model.error)}</p>` : ""}
|
|
354
633
|
${links}
|
|
355
634
|
</section>`;
|
|
356
635
|
};
|
|
@@ -485,7 +764,7 @@ var createVoiceProviderSimulationControlsStore = (options) => {
|
|
|
485
764
|
};
|
|
486
765
|
|
|
487
766
|
// src/client/providerSimulationControlsWidget.ts
|
|
488
|
-
var
|
|
767
|
+
var escapeHtml3 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
489
768
|
var formatKind = (kind) => (kind ?? "stt").toUpperCase();
|
|
490
769
|
var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
|
|
491
770
|
const configuredProviders = options.providers.filter((provider) => provider.configured !== false);
|
|
@@ -505,18 +784,18 @@ var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
|
|
|
505
784
|
};
|
|
506
785
|
var renderVoiceProviderSimulationControlsHTML = (snapshot, options) => {
|
|
507
786
|
const model = createVoiceProviderSimulationControlsViewModel(snapshot, options);
|
|
508
|
-
const failureButtons = model.failureProviders.map((provider) => `<button type="button" data-voice-provider-fail="${
|
|
509
|
-
const recoveryButtons = model.providers.map((provider) => `<button type="button" data-voice-provider-recover="${
|
|
787
|
+
const failureButtons = model.failureProviders.map((provider) => `<button type="button" data-voice-provider-fail="${escapeHtml3(provider.provider)}"${!model.canSimulateFailure || snapshot.isRunning ? " disabled" : ""}>Simulate ${escapeHtml3(provider.provider)} ${escapeHtml3(formatKind(options.kind))} failure</button>`).join("");
|
|
788
|
+
const recoveryButtons = model.providers.map((provider) => `<button type="button" data-voice-provider-recover="${escapeHtml3(provider.provider)}"${snapshot.isRunning ? " disabled" : ""}>Mark ${escapeHtml3(provider.provider)} recovered</button>`).join("");
|
|
510
789
|
return `<section class="absolute-voice-provider-simulation absolute-voice-provider-simulation--${snapshot.error ? "error" : snapshot.isRunning ? "running" : "ready"}">
|
|
511
790
|
<header class="absolute-voice-provider-simulation__header">
|
|
512
|
-
<span class="absolute-voice-provider-simulation__eyebrow">${
|
|
513
|
-
<strong class="absolute-voice-provider-simulation__label">${
|
|
791
|
+
<span class="absolute-voice-provider-simulation__eyebrow">${escapeHtml3(model.title)}</span>
|
|
792
|
+
<strong class="absolute-voice-provider-simulation__label">${escapeHtml3(model.label)}</strong>
|
|
514
793
|
</header>
|
|
515
|
-
<p class="absolute-voice-provider-simulation__description">${
|
|
516
|
-
${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${
|
|
794
|
+
<p class="absolute-voice-provider-simulation__description">${escapeHtml3(model.description)}</p>
|
|
795
|
+
${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${escapeHtml3(options.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure.")}</p>`}
|
|
517
796
|
<div class="absolute-voice-provider-simulation__actions">${failureButtons}${recoveryButtons}</div>
|
|
518
|
-
${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${
|
|
519
|
-
${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${
|
|
797
|
+
${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${escapeHtml3(snapshot.error)}</p>` : ""}
|
|
798
|
+
${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${escapeHtml3(model.resultText)}</pre>` : ""}
|
|
520
799
|
</section>`;
|
|
521
800
|
};
|
|
522
801
|
var bindVoiceProviderSimulationControls = (element, store) => {
|
|
@@ -671,9 +950,9 @@ var createVoiceProviderCapabilitiesStore = (path = "/api/provider-capabilities",
|
|
|
671
950
|
};
|
|
672
951
|
|
|
673
952
|
// src/client/providerCapabilitiesWidget.ts
|
|
674
|
-
var
|
|
675
|
-
var
|
|
676
|
-
var
|
|
953
|
+
var DEFAULT_TITLE3 = "Provider Capabilities";
|
|
954
|
+
var DEFAULT_DESCRIPTION3 = "Configured, selected, and healthy voice providers for this deployment.";
|
|
955
|
+
var escapeHtml4 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
677
956
|
var formatProvider = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
|
|
678
957
|
var formatKind2 = (kind) => kind.toUpperCase();
|
|
679
958
|
var formatStatus = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
|
|
@@ -717,36 +996,36 @@ var createVoiceProviderCapabilitiesViewModel = (snapshot, options = {}) => {
|
|
|
717
996
|
const selectedCount = snapshot.report?.selected ?? capabilities.filter((capability) => capability.selected).length;
|
|
718
997
|
return {
|
|
719
998
|
capabilities,
|
|
720
|
-
description: options.description ??
|
|
999
|
+
description: options.description ?? DEFAULT_DESCRIPTION3,
|
|
721
1000
|
error: snapshot.error,
|
|
722
1001
|
isLoading: snapshot.isLoading,
|
|
723
1002
|
label: snapshot.error ? "Unavailable" : capabilities.length ? warningCount > 0 ? `${warningCount} needs attention` : `${selectedCount} selected` : snapshot.isLoading ? "Checking" : "No capabilities",
|
|
724
1003
|
status: snapshot.error ? "error" : capabilities.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
|
|
725
|
-
title: options.title ??
|
|
1004
|
+
title: options.title ?? DEFAULT_TITLE3,
|
|
726
1005
|
updatedAt: snapshot.updatedAt
|
|
727
1006
|
};
|
|
728
1007
|
};
|
|
729
1008
|
var renderVoiceProviderCapabilitiesHTML = (snapshot, options = {}) => {
|
|
730
1009
|
const model = createVoiceProviderCapabilitiesViewModel(snapshot, options);
|
|
731
|
-
const capabilities = model.capabilities.length ? `<div class="absolute-voice-provider-capabilities__providers">${model.capabilities.map((capability) => `<article class="absolute-voice-provider-capabilities__provider absolute-voice-provider-capabilities__provider--${
|
|
1010
|
+
const capabilities = model.capabilities.length ? `<div class="absolute-voice-provider-capabilities__providers">${model.capabilities.map((capability) => `<article class="absolute-voice-provider-capabilities__provider absolute-voice-provider-capabilities__provider--${escapeHtml4(capability.status)}">
|
|
732
1011
|
<header>
|
|
733
|
-
<strong>${
|
|
734
|
-
<span>${
|
|
1012
|
+
<strong>${escapeHtml4(capability.label)}</strong>
|
|
1013
|
+
<span>${escapeHtml4(formatStatus(capability.status))}</span>
|
|
735
1014
|
</header>
|
|
736
|
-
<p>${
|
|
1015
|
+
<p>${escapeHtml4(capability.detail)}</p>
|
|
737
1016
|
<dl>${capability.rows.map((row) => `<div>
|
|
738
|
-
<dt>${
|
|
739
|
-
<dd>${
|
|
1017
|
+
<dt>${escapeHtml4(row.label)}</dt>
|
|
1018
|
+
<dd>${escapeHtml4(row.value)}</dd>
|
|
740
1019
|
</div>`).join("")}</dl>
|
|
741
1020
|
</article>`).join("")}</div>` : '<p class="absolute-voice-provider-capabilities__empty">Configure provider capabilities to see deployment coverage.</p>';
|
|
742
|
-
return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${
|
|
1021
|
+
return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${escapeHtml4(model.status)}">
|
|
743
1022
|
<header class="absolute-voice-provider-capabilities__header">
|
|
744
|
-
<span class="absolute-voice-provider-capabilities__eyebrow">${
|
|
745
|
-
<strong class="absolute-voice-provider-capabilities__label">${
|
|
1023
|
+
<span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml4(model.title)}</span>
|
|
1024
|
+
<strong class="absolute-voice-provider-capabilities__label">${escapeHtml4(model.label)}</strong>
|
|
746
1025
|
</header>
|
|
747
|
-
<p class="absolute-voice-provider-capabilities__description">${
|
|
1026
|
+
<p class="absolute-voice-provider-capabilities__description">${escapeHtml4(model.description)}</p>
|
|
748
1027
|
${capabilities}
|
|
749
|
-
${model.error ? `<p class="absolute-voice-provider-capabilities__error">${
|
|
1028
|
+
${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml4(model.error)}</p>` : ""}
|
|
750
1029
|
</section>`;
|
|
751
1030
|
};
|
|
752
1031
|
var getVoiceProviderCapabilitiesCSS = () => `.absolute-voice-provider-capabilities{border:1px solid #bfd7ea;border-radius:20px;background:#f6fbff;color:#08131f;padding:18px;box-shadow:0 18px 40px rgba(14,51,78,.12);font-family:inherit}.absolute-voice-provider-capabilities--error,.absolute-voice-provider-capabilities--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-provider-capabilities__header,.absolute-voice-provider-capabilities__provider header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-provider-capabilities__eyebrow{color:#255f85;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-provider-capabilities__label{font-size:24px;line-height:1}.absolute-voice-provider-capabilities__description,.absolute-voice-provider-capabilities__provider p,.absolute-voice-provider-capabilities__provider dt,.absolute-voice-provider-capabilities__empty{color:#405467}.absolute-voice-provider-capabilities__providers{display:grid;gap:12px;margin-top:14px}.absolute-voice-provider-capabilities__provider{background:#fff;border:1px solid #d7e7f3;border-radius:16px;padding:14px}.absolute-voice-provider-capabilities__provider--selected,.absolute-voice-provider-capabilities__provider--healthy{border-color:#86efac}.absolute-voice-provider-capabilities__provider--degraded,.absolute-voice-provider-capabilities__provider--rate-limited,.absolute-voice-provider-capabilities__provider--suppressed,.absolute-voice-provider-capabilities__provider--unconfigured{border-color:#f2a7a7}.absolute-voice-provider-capabilities__provider p{margin:10px 0}.absolute-voice-provider-capabilities__provider dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-provider-capabilities__provider div{background:#f6fbff;border:1px solid #d7e7f3;border-radius:12px;padding:8px}.absolute-voice-provider-capabilities__provider dt{font-size:12px}.absolute-voice-provider-capabilities__provider dd{font-weight:800;margin:4px 0 0}.absolute-voice-provider-capabilities__empty{margin:14px 0 0}.absolute-voice-provider-capabilities__error{color:#9f1239;font-weight:700}`;
|
|
@@ -1519,9 +1798,9 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
|
|
|
1519
1798
|
};
|
|
1520
1799
|
|
|
1521
1800
|
// src/client/providerStatusWidget.ts
|
|
1522
|
-
var
|
|
1523
|
-
var
|
|
1524
|
-
var
|
|
1801
|
+
var DEFAULT_TITLE4 = "Voice Providers";
|
|
1802
|
+
var DEFAULT_DESCRIPTION4 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
|
|
1803
|
+
var escapeHtml5 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
1525
1804
|
var formatProvider2 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
|
|
1526
1805
|
var formatStatus2 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
|
|
1527
1806
|
var formatLatency = (value) => typeof value === "number" ? `${value}ms` : "No samples";
|
|
@@ -1565,37 +1844,37 @@ var createVoiceProviderStatusViewModel = (snapshot, options = {}) => {
|
|
|
1565
1844
|
const warningCount = providers.filter((provider) => isWarningStatus2(provider.status)).length;
|
|
1566
1845
|
const healthyCount = providers.filter((provider) => provider.status === "healthy").length;
|
|
1567
1846
|
return {
|
|
1568
|
-
description: options.description ??
|
|
1847
|
+
description: options.description ?? DEFAULT_DESCRIPTION4,
|
|
1569
1848
|
error: snapshot.error,
|
|
1570
1849
|
isLoading: snapshot.isLoading,
|
|
1571
1850
|
label: snapshot.error ? "Unavailable" : providers.length ? warningCount > 0 ? `${warningCount} needs attention` : `${healthyCount} healthy` : snapshot.isLoading ? "Checking" : "No provider traffic",
|
|
1572
1851
|
providers,
|
|
1573
1852
|
status: snapshot.error ? "error" : providers.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
|
|
1574
|
-
title: options.title ??
|
|
1853
|
+
title: options.title ?? DEFAULT_TITLE4,
|
|
1575
1854
|
updatedAt: snapshot.updatedAt
|
|
1576
1855
|
};
|
|
1577
1856
|
};
|
|
1578
1857
|
var renderVoiceProviderStatusHTML = (snapshot, options = {}) => {
|
|
1579
1858
|
const model = createVoiceProviderStatusViewModel(snapshot, options);
|
|
1580
|
-
const providers = model.providers.length ? `<div class="absolute-voice-provider-status__providers">${model.providers.map((provider) => `<article class="absolute-voice-provider-status__provider absolute-voice-provider-status__provider--${
|
|
1859
|
+
const providers = model.providers.length ? `<div class="absolute-voice-provider-status__providers">${model.providers.map((provider) => `<article class="absolute-voice-provider-status__provider absolute-voice-provider-status__provider--${escapeHtml5(provider.status)}">
|
|
1581
1860
|
<header>
|
|
1582
|
-
<strong>${
|
|
1583
|
-
<span>${
|
|
1861
|
+
<strong>${escapeHtml5(provider.label)}</strong>
|
|
1862
|
+
<span>${escapeHtml5(formatStatus2(provider.status))}</span>
|
|
1584
1863
|
</header>
|
|
1585
|
-
<p>${
|
|
1864
|
+
<p>${escapeHtml5(provider.detail)}</p>
|
|
1586
1865
|
<dl>${provider.rows.map((row) => `<div>
|
|
1587
|
-
<dt>${
|
|
1588
|
-
<dd>${
|
|
1866
|
+
<dt>${escapeHtml5(row.label)}</dt>
|
|
1867
|
+
<dd>${escapeHtml5(row.value)}</dd>
|
|
1589
1868
|
</div>`).join("")}</dl>
|
|
1590
1869
|
</article>`).join("")}</div>` : '<p class="absolute-voice-provider-status__empty">Run voice traffic to see provider health.</p>';
|
|
1591
|
-
return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${
|
|
1870
|
+
return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml5(model.status)}">
|
|
1592
1871
|
<header class="absolute-voice-provider-status__header">
|
|
1593
|
-
<span class="absolute-voice-provider-status__eyebrow">${
|
|
1594
|
-
<strong class="absolute-voice-provider-status__label">${
|
|
1872
|
+
<span class="absolute-voice-provider-status__eyebrow">${escapeHtml5(model.title)}</span>
|
|
1873
|
+
<strong class="absolute-voice-provider-status__label">${escapeHtml5(model.label)}</strong>
|
|
1595
1874
|
</header>
|
|
1596
|
-
<p class="absolute-voice-provider-status__description">${
|
|
1875
|
+
<p class="absolute-voice-provider-status__description">${escapeHtml5(model.description)}</p>
|
|
1597
1876
|
${providers}
|
|
1598
|
-
${model.error ? `<p class="absolute-voice-provider-status__error">${
|
|
1877
|
+
${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml5(model.error)}</p>` : ""}
|
|
1599
1878
|
</section>`;
|
|
1600
1879
|
};
|
|
1601
1880
|
var getVoiceProviderStatusCSS = () => `.absolute-voice-provider-status{border:1px solid #d8d2c4;border-radius:20px;background:#fffaf0;color:#16130d;padding:18px;box-shadow:0 18px 40px rgba(47,37,18,.12);font-family:inherit}.absolute-voice-provider-status--error,.absolute-voice-provider-status--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-provider-status__header,.absolute-voice-provider-status__provider header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-provider-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-provider-status__label{font-size:24px;line-height:1}.absolute-voice-provider-status__description,.absolute-voice-provider-status__provider p,.absolute-voice-provider-status__provider dt,.absolute-voice-provider-status__empty{color:#514733}.absolute-voice-provider-status__providers{display:grid;gap:12px;margin-top:14px}.absolute-voice-provider-status__provider{background:#fff;border:1px solid #eee4d2;border-radius:16px;padding:14px}.absolute-voice-provider-status__provider--degraded,.absolute-voice-provider-status__provider--rate-limited,.absolute-voice-provider-status__provider--suppressed{border-color:#f2a7a7}.absolute-voice-provider-status__provider--recoverable{border-color:#fbbf24}.absolute-voice-provider-status__provider p{margin:10px 0}.absolute-voice-provider-status__provider dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-provider-status__provider div{background:#fffaf0;border:1px solid #eee4d2;border-radius:12px;padding:8px}.absolute-voice-provider-status__provider dt{font-size:12px}.absolute-voice-provider-status__provider dd{font-weight:800;margin:4px 0 0}.absolute-voice-provider-status__empty{margin:14px 0 0}.absolute-voice-provider-status__error{color:#9f1239;font-weight:700}`;
|
|
@@ -1726,9 +2005,9 @@ var createVoiceRoutingStatusStore = (path = "/api/routing/latest", options = {})
|
|
|
1726
2005
|
};
|
|
1727
2006
|
|
|
1728
2007
|
// src/client/routingStatusWidget.ts
|
|
1729
|
-
var
|
|
1730
|
-
var
|
|
1731
|
-
var
|
|
2008
|
+
var DEFAULT_TITLE5 = "Voice Routing";
|
|
2009
|
+
var DEFAULT_DESCRIPTION5 = "Latest provider routing decision from the self-hosted trace store.";
|
|
2010
|
+
var escapeHtml6 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
1732
2011
|
var formatValue = (value, fallback = "None") => typeof value === "string" && value.trim() ? value : typeof value === "number" && Number.isFinite(value) ? String(value) : fallback;
|
|
1733
2012
|
var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
|
|
1734
2013
|
const decision = snapshot.decision;
|
|
@@ -1752,30 +2031,30 @@ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
|
|
|
1752
2031
|
] : [];
|
|
1753
2032
|
return {
|
|
1754
2033
|
decision,
|
|
1755
|
-
description: options.description ??
|
|
2034
|
+
description: options.description ?? DEFAULT_DESCRIPTION5,
|
|
1756
2035
|
error: snapshot.error,
|
|
1757
2036
|
isLoading: snapshot.isLoading,
|
|
1758
2037
|
label: snapshot.error ? "Unavailable" : decision ? `${formatValue(decision.kind).toUpperCase()} ${formatValue(decision.status, "unknown")}` : snapshot.isLoading ? "Checking" : "No routing yet",
|
|
1759
2038
|
rows,
|
|
1760
2039
|
status: snapshot.error ? "error" : decision ? "ready" : snapshot.isLoading ? "loading" : "empty",
|
|
1761
|
-
title: options.title ??
|
|
2040
|
+
title: options.title ?? DEFAULT_TITLE5,
|
|
1762
2041
|
updatedAt: snapshot.updatedAt
|
|
1763
2042
|
};
|
|
1764
2043
|
};
|
|
1765
2044
|
var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
|
|
1766
2045
|
const model = createVoiceRoutingStatusViewModel(snapshot, options);
|
|
1767
2046
|
const rows = model.rows.length ? `<div class="absolute-voice-routing-status__grid">${model.rows.map((row) => `<div>
|
|
1768
|
-
<span>${
|
|
1769
|
-
<strong>${
|
|
2047
|
+
<span>${escapeHtml6(row.label)}</span>
|
|
2048
|
+
<strong>${escapeHtml6(row.value)}</strong>
|
|
1770
2049
|
</div>`).join("")}</div>` : '<p class="absolute-voice-routing-status__empty">Start a voice session to see the selected provider.</p>';
|
|
1771
|
-
return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${
|
|
2050
|
+
return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml6(model.status)}">
|
|
1772
2051
|
<header class="absolute-voice-routing-status__header">
|
|
1773
|
-
<span class="absolute-voice-routing-status__eyebrow">${
|
|
1774
|
-
<strong class="absolute-voice-routing-status__label">${
|
|
2052
|
+
<span class="absolute-voice-routing-status__eyebrow">${escapeHtml6(model.title)}</span>
|
|
2053
|
+
<strong class="absolute-voice-routing-status__label">${escapeHtml6(model.label)}</strong>
|
|
1775
2054
|
</header>
|
|
1776
|
-
<p class="absolute-voice-routing-status__description">${
|
|
2055
|
+
<p class="absolute-voice-routing-status__description">${escapeHtml6(model.description)}</p>
|
|
1777
2056
|
${rows}
|
|
1778
|
-
${model.error ? `<p class="absolute-voice-routing-status__error">${
|
|
2057
|
+
${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml6(model.error)}</p>` : ""}
|
|
1779
2058
|
</section>`;
|
|
1780
2059
|
};
|
|
1781
2060
|
var getVoiceRoutingStatusCSS = () => `.absolute-voice-routing-status{border:1px solid #d8d2c4;border-radius:20px;background:#fffaf0;color:#16130d;padding:18px;box-shadow:0 18px 40px rgba(47,37,18,.12);font-family:inherit}.absolute-voice-routing-status--error{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-routing-status__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-routing-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-routing-status__label{font-size:24px;line-height:1}.absolute-voice-routing-status__description{color:#514733;margin:12px 0 0}.absolute-voice-routing-status__grid{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin-top:14px}.absolute-voice-routing-status__grid div{background:#fff;border:1px solid #eee4d2;border-radius:14px;padding:10px 12px}.absolute-voice-routing-status__grid span{color:#655944;display:block;font-size:12px;margin-bottom:4px}.absolute-voice-routing-status__grid strong{overflow-wrap:anywhere}.absolute-voice-routing-status__empty{color:#655944;margin:14px 0 0}.absolute-voice-routing-status__error{color:#9f1239;font-weight:700}`;
|
|
@@ -1906,9 +2185,9 @@ var createVoiceTraceTimelineStore = (path = "/api/voice-traces", options = {}) =
|
|
|
1906
2185
|
};
|
|
1907
2186
|
|
|
1908
2187
|
// src/client/traceTimelineWidget.ts
|
|
1909
|
-
var
|
|
1910
|
-
var
|
|
1911
|
-
var
|
|
2188
|
+
var DEFAULT_TITLE6 = "Voice Traces";
|
|
2189
|
+
var DEFAULT_DESCRIPTION6 = "Latest call timelines with provider latency, fallbacks, handoffs, and errors from your self-hosted trace store.";
|
|
2190
|
+
var escapeHtml7 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
1912
2191
|
var formatMs = (value) => typeof value === "number" ? `${value}ms` : "n/a";
|
|
1913
2192
|
var formatProviders = (session) => session.providers.length ? session.providers.map((provider) => provider.provider).join(", ") : "No providers";
|
|
1914
2193
|
var createVoiceTraceTimelineViewModel = (snapshot, options = {}) => {
|
|
@@ -1922,34 +2201,34 @@ var createVoiceTraceTimelineViewModel = (snapshot, options = {}) => {
|
|
|
1922
2201
|
const failed = sessions.filter((session) => session.status === "failed").length;
|
|
1923
2202
|
const warnings = sessions.filter((session) => session.status === "warning").length;
|
|
1924
2203
|
return {
|
|
1925
|
-
description: options.description ??
|
|
2204
|
+
description: options.description ?? DEFAULT_DESCRIPTION6,
|
|
1926
2205
|
error: snapshot.error,
|
|
1927
2206
|
isLoading: snapshot.isLoading,
|
|
1928
2207
|
label: snapshot.error ? "Unavailable" : failed > 0 ? `${failed} failed` : warnings > 0 ? `${warnings} warning` : sessions.length ? `${sessions.length} recent` : snapshot.isLoading ? "Checking" : "No traces yet",
|
|
1929
2208
|
sessions,
|
|
1930
2209
|
status: snapshot.error ? "error" : failed > 0 ? "failed" : warnings > 0 ? "warning" : sessions.length ? "ready" : snapshot.isLoading ? "loading" : "empty",
|
|
1931
|
-
title: options.title ??
|
|
2210
|
+
title: options.title ?? DEFAULT_TITLE6,
|
|
1932
2211
|
updatedAt: snapshot.updatedAt
|
|
1933
2212
|
};
|
|
1934
2213
|
};
|
|
1935
2214
|
var renderVoiceTraceTimelineWidgetHTML = (snapshot, options = {}) => {
|
|
1936
2215
|
const model = createVoiceTraceTimelineViewModel(snapshot, options);
|
|
1937
|
-
const sessions = model.sessions.length ? `<div class="absolute-voice-trace-timeline__sessions">${model.sessions.map((session) => `<article class="absolute-voice-trace-timeline__session absolute-voice-trace-timeline__session--${
|
|
2216
|
+
const sessions = model.sessions.length ? `<div class="absolute-voice-trace-timeline__sessions">${model.sessions.map((session) => `<article class="absolute-voice-trace-timeline__session absolute-voice-trace-timeline__session--${escapeHtml7(session.status)}">
|
|
1938
2217
|
<header>
|
|
1939
|
-
<strong>${
|
|
1940
|
-
<span>${
|
|
2218
|
+
<strong>${escapeHtml7(session.sessionId)}</strong>
|
|
2219
|
+
<span>${escapeHtml7(session.status)}</span>
|
|
1941
2220
|
</header>
|
|
1942
|
-
<p>${
|
|
1943
|
-
<a href="${
|
|
2221
|
+
<p>${escapeHtml7(session.label)} \xB7 ${escapeHtml7(session.durationLabel)} \xB7 ${escapeHtml7(session.providerLabel)}</p>
|
|
2222
|
+
<a href="${escapeHtml7(session.detailHref)}">Open timeline</a>
|
|
1944
2223
|
</article>`).join("")}</div>` : '<p class="absolute-voice-trace-timeline__empty">Run a voice session to see call timelines.</p>';
|
|
1945
|
-
return `<section class="absolute-voice-trace-timeline absolute-voice-trace-timeline--${
|
|
2224
|
+
return `<section class="absolute-voice-trace-timeline absolute-voice-trace-timeline--${escapeHtml7(model.status)}">
|
|
1946
2225
|
<header class="absolute-voice-trace-timeline__header">
|
|
1947
|
-
<span class="absolute-voice-trace-timeline__eyebrow">${
|
|
1948
|
-
<strong class="absolute-voice-trace-timeline__label">${
|
|
2226
|
+
<span class="absolute-voice-trace-timeline__eyebrow">${escapeHtml7(model.title)}</span>
|
|
2227
|
+
<strong class="absolute-voice-trace-timeline__label">${escapeHtml7(model.label)}</strong>
|
|
1949
2228
|
</header>
|
|
1950
|
-
<p class="absolute-voice-trace-timeline__description">${
|
|
2229
|
+
<p class="absolute-voice-trace-timeline__description">${escapeHtml7(model.description)}</p>
|
|
1951
2230
|
${sessions}
|
|
1952
|
-
${model.error ? `<p class="absolute-voice-trace-timeline__error">${
|
|
2231
|
+
${model.error ? `<p class="absolute-voice-trace-timeline__error">${escapeHtml7(model.error)}</p>` : ""}
|
|
1953
2232
|
</section>`;
|
|
1954
2233
|
};
|
|
1955
2234
|
var getVoiceTraceTimelineCSS = () => `.absolute-voice-trace-timeline{border:1px solid #bad7d3;border-radius:20px;background:#f3fffb;color:#09201c;padding:18px;box-shadow:0 18px 40px rgba(9,32,28,.12);font-family:inherit}.absolute-voice-trace-timeline--error,.absolute-voice-trace-timeline--failed{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-trace-timeline--warning{border-color:#fbbf24;background:#fffaf0}.absolute-voice-trace-timeline__header,.absolute-voice-trace-timeline__session header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-trace-timeline__eyebrow{color:#17665b;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-trace-timeline__label{font-size:24px;line-height:1}.absolute-voice-trace-timeline__description,.absolute-voice-trace-timeline__session p,.absolute-voice-trace-timeline__empty{color:#35544f}.absolute-voice-trace-timeline__sessions{display:grid;gap:12px;margin-top:14px}.absolute-voice-trace-timeline__session{background:#fff;border:1px solid #cfe7e2;border-radius:16px;padding:14px}.absolute-voice-trace-timeline__session--failed{border-color:#f2a7a7}.absolute-voice-trace-timeline__session--warning{border-color:#fbbf24}.absolute-voice-trace-timeline__session p{margin:10px 0}.absolute-voice-trace-timeline__session a{color:#0f766e;font-weight:800}.absolute-voice-trace-timeline__empty{margin:14px 0 0}.absolute-voice-trace-timeline__error{color:#9f1239;font-weight:700}`;
|
|
@@ -2106,10 +2385,10 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
|
|
|
2106
2385
|
};
|
|
2107
2386
|
|
|
2108
2387
|
// src/client/turnLatencyWidget.ts
|
|
2109
|
-
var
|
|
2110
|
-
var
|
|
2388
|
+
var DEFAULT_TITLE7 = "Turn Latency";
|
|
2389
|
+
var DEFAULT_DESCRIPTION7 = "Per-turn timing from first transcript to commit and assistant response start.";
|
|
2111
2390
|
var DEFAULT_PROOF_LABEL = "Run latency proof";
|
|
2112
|
-
var
|
|
2391
|
+
var escapeHtml8 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
2113
2392
|
var formatMs2 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
|
|
2114
2393
|
var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
|
|
2115
2394
|
const turns = (snapshot.report?.turns ?? []).map((turn) => ({
|
|
@@ -2123,39 +2402,39 @@ var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
|
|
|
2123
2402
|
const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
|
|
2124
2403
|
const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
|
|
2125
2404
|
return {
|
|
2126
|
-
description: options.description ??
|
|
2405
|
+
description: options.description ?? DEFAULT_DESCRIPTION7,
|
|
2127
2406
|
error: snapshot.error,
|
|
2128
2407
|
isLoading: snapshot.isLoading,
|
|
2129
2408
|
label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} slow` : warningCount > 0 ? `${warningCount} warnings` : `avg ${formatMs2(snapshot.report?.averageTotalMs)}` : snapshot.isLoading ? "Checking" : "No turns",
|
|
2130
2409
|
proofLabel: options.proofPath ? options.proofLabel ?? DEFAULT_PROOF_LABEL : undefined,
|
|
2131
2410
|
showProofAction: Boolean(options.proofPath),
|
|
2132
2411
|
status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
|
|
2133
|
-
title: options.title ??
|
|
2412
|
+
title: options.title ?? DEFAULT_TITLE7,
|
|
2134
2413
|
turns,
|
|
2135
2414
|
updatedAt: snapshot.updatedAt
|
|
2136
2415
|
};
|
|
2137
2416
|
};
|
|
2138
2417
|
var renderVoiceTurnLatencyHTML = (snapshot, options = {}) => {
|
|
2139
2418
|
const model = createVoiceTurnLatencyViewModel(snapshot, options);
|
|
2140
|
-
const turns = model.turns.length ? `<div class="absolute-voice-turn-latency__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-latency__turn absolute-voice-turn-latency__turn--${
|
|
2419
|
+
const turns = model.turns.length ? `<div class="absolute-voice-turn-latency__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-latency__turn absolute-voice-turn-latency__turn--${escapeHtml8(turn.status)}">
|
|
2141
2420
|
<header>
|
|
2142
|
-
<strong>${
|
|
2143
|
-
<span>${
|
|
2421
|
+
<strong>${escapeHtml8(turn.label)}</strong>
|
|
2422
|
+
<span>${escapeHtml8(turn.status)}</span>
|
|
2144
2423
|
</header>
|
|
2145
2424
|
<dl>${turn.rows.map((row) => `<div>
|
|
2146
|
-
<dt>${
|
|
2147
|
-
<dd>${
|
|
2425
|
+
<dt>${escapeHtml8(row.label)}</dt>
|
|
2426
|
+
<dd>${escapeHtml8(row.value)}</dd>
|
|
2148
2427
|
</div>`).join("")}</dl>
|
|
2149
2428
|
</article>`).join("")}</div>` : '<p class="absolute-voice-turn-latency__empty">Complete a voice turn to see latency diagnostics.</p>';
|
|
2150
|
-
return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${
|
|
2429
|
+
return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml8(model.status)}">
|
|
2151
2430
|
<header class="absolute-voice-turn-latency__header">
|
|
2152
|
-
<span class="absolute-voice-turn-latency__eyebrow">${
|
|
2153
|
-
<strong class="absolute-voice-turn-latency__label">${
|
|
2431
|
+
<span class="absolute-voice-turn-latency__eyebrow">${escapeHtml8(model.title)}</span>
|
|
2432
|
+
<strong class="absolute-voice-turn-latency__label">${escapeHtml8(model.label)}</strong>
|
|
2154
2433
|
</header>
|
|
2155
|
-
<p class="absolute-voice-turn-latency__description">${
|
|
2156
|
-
${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${
|
|
2434
|
+
<p class="absolute-voice-turn-latency__description">${escapeHtml8(model.description)}</p>
|
|
2435
|
+
${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml8(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
|
|
2157
2436
|
${turns}
|
|
2158
|
-
${model.error ? `<p class="absolute-voice-turn-latency__error">${
|
|
2437
|
+
${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml8(model.error)}</p>` : ""}
|
|
2159
2438
|
</section>`;
|
|
2160
2439
|
};
|
|
2161
2440
|
var mountVoiceTurnLatency = (element, path = "/api/turn-latency", options = {}) => {
|
|
@@ -2294,9 +2573,9 @@ var createVoiceTurnQualityStore = (path = "/api/turn-quality", options = {}) =>
|
|
|
2294
2573
|
};
|
|
2295
2574
|
|
|
2296
2575
|
// src/client/turnQualityWidget.ts
|
|
2297
|
-
var
|
|
2298
|
-
var
|
|
2299
|
-
var
|
|
2576
|
+
var DEFAULT_TITLE8 = "Turn Quality";
|
|
2577
|
+
var DEFAULT_DESCRIPTION8 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
|
|
2578
|
+
var escapeHtml9 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
2300
2579
|
var formatConfidence = (value) => typeof value === "number" ? `${Math.round(value * 100)}%` : "n/a";
|
|
2301
2580
|
var formatMaybe = (value) => value === undefined || value === "" ? "n/a" : String(value);
|
|
2302
2581
|
var getTurnDetail = (turn) => {
|
|
@@ -2334,37 +2613,37 @@ var createVoiceTurnQualityViewModel = (snapshot, options = {}) => {
|
|
|
2334
2613
|
const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
|
|
2335
2614
|
const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
|
|
2336
2615
|
return {
|
|
2337
|
-
description: options.description ??
|
|
2616
|
+
description: options.description ?? DEFAULT_DESCRIPTION8,
|
|
2338
2617
|
error: snapshot.error,
|
|
2339
2618
|
isLoading: snapshot.isLoading,
|
|
2340
2619
|
label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} failed` : warningCount > 0 ? `${warningCount} warnings` : `${turns.length} healthy` : snapshot.isLoading ? "Checking" : "No turns",
|
|
2341
2620
|
status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
|
|
2342
|
-
title: options.title ??
|
|
2621
|
+
title: options.title ?? DEFAULT_TITLE8,
|
|
2343
2622
|
turns,
|
|
2344
2623
|
updatedAt: snapshot.updatedAt
|
|
2345
2624
|
};
|
|
2346
2625
|
};
|
|
2347
2626
|
var renderVoiceTurnQualityHTML = (snapshot, options = {}) => {
|
|
2348
2627
|
const model = createVoiceTurnQualityViewModel(snapshot, options);
|
|
2349
|
-
const turns = model.turns.length ? `<div class="absolute-voice-turn-quality__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-quality__turn absolute-voice-turn-quality__turn--${
|
|
2628
|
+
const turns = model.turns.length ? `<div class="absolute-voice-turn-quality__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-quality__turn absolute-voice-turn-quality__turn--${escapeHtml9(turn.status)}">
|
|
2350
2629
|
<header>
|
|
2351
|
-
<strong>${
|
|
2352
|
-
<span>${
|
|
2630
|
+
<strong>${escapeHtml9(turn.label)}</strong>
|
|
2631
|
+
<span>${escapeHtml9(turn.status)}</span>
|
|
2353
2632
|
</header>
|
|
2354
|
-
<p>${
|
|
2633
|
+
<p>${escapeHtml9(turn.detail)}</p>
|
|
2355
2634
|
<dl>${turn.rows.map((row) => `<div>
|
|
2356
|
-
<dt>${
|
|
2357
|
-
<dd>${
|
|
2635
|
+
<dt>${escapeHtml9(row.label)}</dt>
|
|
2636
|
+
<dd>${escapeHtml9(row.value)}</dd>
|
|
2358
2637
|
</div>`).join("")}</dl>
|
|
2359
2638
|
</article>`).join("")}</div>` : '<p class="absolute-voice-turn-quality__empty">Complete a voice turn to see STT quality diagnostics.</p>';
|
|
2360
|
-
return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${
|
|
2639
|
+
return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml9(model.status)}">
|
|
2361
2640
|
<header class="absolute-voice-turn-quality__header">
|
|
2362
|
-
<span class="absolute-voice-turn-quality__eyebrow">${
|
|
2363
|
-
<strong class="absolute-voice-turn-quality__label">${
|
|
2641
|
+
<span class="absolute-voice-turn-quality__eyebrow">${escapeHtml9(model.title)}</span>
|
|
2642
|
+
<strong class="absolute-voice-turn-quality__label">${escapeHtml9(model.label)}</strong>
|
|
2364
2643
|
</header>
|
|
2365
|
-
<p class="absolute-voice-turn-quality__description">${
|
|
2644
|
+
<p class="absolute-voice-turn-quality__description">${escapeHtml9(model.description)}</p>
|
|
2366
2645
|
${turns}
|
|
2367
|
-
${model.error ? `<p class="absolute-voice-turn-quality__error">${
|
|
2646
|
+
${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml9(model.error)}</p>` : ""}
|
|
2368
2647
|
</section>`;
|
|
2369
2648
|
};
|
|
2370
2649
|
var getVoiceTurnQualityCSS = () => `.absolute-voice-turn-quality{border:1px solid #e4d1a3;border-radius:20px;background:#fff9eb;color:#17120a;padding:18px;box-shadow:0 18px 40px rgba(73,48,14,.12);font-family:inherit}.absolute-voice-turn-quality--error,.absolute-voice-turn-quality--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-turn-quality__header,.absolute-voice-turn-quality__turn header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-turn-quality__eyebrow{color:#8a5a0a;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-turn-quality__label{font-size:24px;line-height:1}.absolute-voice-turn-quality__description,.absolute-voice-turn-quality__turn p,.absolute-voice-turn-quality__turn dt,.absolute-voice-turn-quality__empty{color:#5a4930}.absolute-voice-turn-quality__turns{display:grid;gap:12px;margin-top:14px}.absolute-voice-turn-quality__turn{background:#fff;border:1px solid #f0dfba;border-radius:16px;padding:14px}.absolute-voice-turn-quality__turn--pass{border-color:#86efac}.absolute-voice-turn-quality__turn--warn,.absolute-voice-turn-quality__turn--unknown{border-color:#fbbf24}.absolute-voice-turn-quality__turn--fail{border-color:#f2a7a7}.absolute-voice-turn-quality__turn p{margin:10px 0}.absolute-voice-turn-quality__turn dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-turn-quality__turn div{background:#fff9eb;border:1px solid #f0dfba;border-radius:12px;padding:8px}.absolute-voice-turn-quality__turn dt{font-size:12px}.absolute-voice-turn-quality__turn dd{font-weight:800;margin:4px 0 0}.absolute-voice-turn-quality__empty{margin:14px 0 0}.absolute-voice-turn-quality__error{color:#9f1239;font-weight:700}`;
|
|
@@ -3146,6 +3425,7 @@ export {
|
|
|
3146
3425
|
createVoiceProviderSimulationControls,
|
|
3147
3426
|
createVoiceProviderCapabilities,
|
|
3148
3427
|
createVoiceOpsStatus,
|
|
3428
|
+
createVoiceDeliveryRuntime,
|
|
3149
3429
|
createVoiceController,
|
|
3150
3430
|
createVoiceCampaignDialerProof
|
|
3151
3431
|
};
|