@absolutejs/voice 0.0.22-beta.472 → 0.0.22-beta.473

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -225,4 +225,6 @@ export { buildVoiceProofPackInput, buildVoiceProofPack, buildVoiceProofPackFromO
225
225
  export type { VoiceProofPack, VoiceProofPackBuildContext, VoiceProofPackBuildContextOptions, VoiceProofPackBuildTiming, VoiceProofPackEvidence, VoiceProofPackInput, VoiceProofPackInputBuilderLoaderInput, VoiceProofPackInputBuilderOperationsLoaderInput, VoiceProofPackInputBuilderOptions, VoiceProofPackInputBuilderSupportBundle, VoiceProofPackRefreshState, VoiceProofPackRefreshStatus, VoiceProofPackRoutesOptions, VoiceProofPackSection, VoiceProofPackSourceValue, VoiceProofPackStatus, VoiceProofPackStaleWhileRefreshSource, VoiceProofPackStaleWhileRefreshSourceOptions, VoiceProofPackWriteResult, VoiceProofRefreshSnapshot, VoiceProofRefreshSnapshotOptions, } from "./proofPack";
226
226
  export { buildVoiceMultilingualProofReadinessCheck, renderVoiceMultilingualProofMarkdown, runVoiceMultilingualProof, } from "./multilingualProof";
227
227
  export type { VoiceMultilingualLanguageCode, VoiceMultilingualProofAdapterEntry, VoiceMultilingualProofAdapterReport, VoiceMultilingualProofDefaultThresholds, VoiceMultilingualProofLanguageMetrics, VoiceMultilingualProofLanguageReport, VoiceMultilingualProofLanguageThresholds, VoiceMultilingualProofOptions, VoiceMultilingualProofReadinessCheck, VoiceMultilingualProofReadinessOptions, VoiceMultilingualProofReport, } from "./multilingualProof";
228
+ export { buildVoiceMonitorPlan, createVoiceInMemoryMonitorRegistry, createVoiceLiveMonitorRoutes, createVoiceMonitorSession, } from "./monitor";
229
+ export type { VoiceMonitorAudioEvent, VoiceMonitorAudioSource, VoiceMonitorAuthenticate, VoiceMonitorAuthenticateInput, VoiceMonitorControlAck, VoiceMonitorControlHandler, VoiceMonitorControlHandlerInput, VoiceMonitorControlMessage, VoiceMonitorMutableRegistry, VoiceMonitorPlan, VoiceMonitorPlanInput, VoiceMonitorRegistry, VoiceMonitorRegistryRegisterInput, VoiceLiveMonitorRoutesOptions, VoiceMonitorSessionRecord, } from "./monitor";
228
230
  export * from "./types";
package/dist/index.js CHANGED
@@ -44454,6 +44454,415 @@ var buildVoiceMultilingualProofReadinessCheck = (report, options = {}) => {
44454
44454
  value: failedAdapters.length
44455
44455
  };
44456
44456
  };
44457
+ // src/monitor.ts
44458
+ import { Elysia as Elysia70 } from "elysia";
44459
+ var buildAudioFanout = () => {
44460
+ const handlers = new Set;
44461
+ return {
44462
+ emit: (event) => {
44463
+ for (const handler of handlers)
44464
+ handler(event);
44465
+ },
44466
+ onAudio: (handler) => {
44467
+ handlers.add(handler);
44468
+ return () => {
44469
+ handlers.delete(handler);
44470
+ };
44471
+ }
44472
+ };
44473
+ };
44474
+ var buildCloseFanout = () => {
44475
+ const handlers = new Set;
44476
+ return {
44477
+ emitClose: (reason) => {
44478
+ for (const handler of handlers)
44479
+ handler(reason);
44480
+ },
44481
+ onClose: (handler) => {
44482
+ handlers.add(handler);
44483
+ return () => {
44484
+ handlers.delete(handler);
44485
+ };
44486
+ }
44487
+ };
44488
+ };
44489
+ var createVoiceMonitorSession = (input) => {
44490
+ const audio = buildAudioFanout();
44491
+ const close = buildCloseFanout();
44492
+ return {
44493
+ emit: audio.emit,
44494
+ emitClose: close.emitClose,
44495
+ handle: input.handle,
44496
+ metadata: input.metadata,
44497
+ onAudio: audio.onAudio,
44498
+ onClose: close.onClose,
44499
+ sessionId: input.sessionId
44500
+ };
44501
+ };
44502
+ var createVoiceInMemoryMonitorRegistry = () => {
44503
+ const records = new Map;
44504
+ return {
44505
+ emit: (sessionId, event) => {
44506
+ records.get(sessionId)?.emit(event);
44507
+ },
44508
+ emitClose: (sessionId, reason) => {
44509
+ records.get(sessionId)?.emitClose(reason);
44510
+ },
44511
+ get: (sessionId) => records.get(sessionId),
44512
+ list: () => Array.from(records.keys()).map((sessionId) => ({ sessionId })),
44513
+ register: (record) => {
44514
+ const existing = records.get(record.sessionId);
44515
+ if (existing) {
44516
+ throw new Error(`VoiceMonitorRegistry already has a session "${record.sessionId}"; deregister it before re-registering.`);
44517
+ }
44518
+ const wrapped = "emit" in record && typeof record.emit === "function" ? record : createVoiceMonitorSession({
44519
+ handle: record.handle,
44520
+ metadata: record.metadata,
44521
+ sessionId: record.sessionId
44522
+ });
44523
+ if (wrapped !== record) {
44524
+ record.onAudio((event) => wrapped.emit(event));
44525
+ record.onClose((reason) => wrapped.emitClose(reason));
44526
+ }
44527
+ records.set(record.sessionId, wrapped);
44528
+ return () => {
44529
+ records.delete(record.sessionId);
44530
+ wrapped.emitClose("deregistered");
44531
+ };
44532
+ }
44533
+ };
44534
+ };
44535
+ var buildDefaultControlHandler = (type) => {
44536
+ if (type === "transfer") {
44537
+ return async ({ message, session }) => {
44538
+ if (message.type !== "transfer") {
44539
+ return { error: "internal: type mismatch", ok: false, type };
44540
+ }
44541
+ await session.handle.transfer({
44542
+ metadata: message.metadata,
44543
+ reason: message.reason,
44544
+ target: message.target
44545
+ });
44546
+ return { detail: `Transferred to ${message.target}.`, ok: true, type };
44547
+ };
44548
+ }
44549
+ if (type === "hangup") {
44550
+ return async ({ message, session }) => {
44551
+ if (message.type !== "hangup") {
44552
+ return { error: "internal: type mismatch", ok: false, type };
44553
+ }
44554
+ await session.handle.complete();
44555
+ return {
44556
+ detail: message.reason ? `Hangup: ${message.reason}` : "Hangup.",
44557
+ ok: true,
44558
+ type
44559
+ };
44560
+ };
44561
+ }
44562
+ if (type === "escalate") {
44563
+ return async ({ message, session }) => {
44564
+ if (message.type !== "escalate") {
44565
+ return { error: "internal: type mismatch", ok: false, type };
44566
+ }
44567
+ await session.handle.escalate({
44568
+ metadata: message.metadata,
44569
+ reason: message.reason ?? "monitor-requested-escalation"
44570
+ });
44571
+ return { detail: "Escalated.", ok: true, type };
44572
+ };
44573
+ }
44574
+ if (type === "voicemail") {
44575
+ return async ({ message, session }) => {
44576
+ if (message.type !== "voicemail") {
44577
+ return { error: "internal: type mismatch", ok: false, type };
44578
+ }
44579
+ await session.handle.markVoicemail({ metadata: message.metadata });
44580
+ return { detail: "Voicemail marked.", ok: true, type };
44581
+ };
44582
+ }
44583
+ if (type === "no-answer") {
44584
+ return async ({ message, session }) => {
44585
+ if (message.type !== "no-answer") {
44586
+ return { error: "internal: type mismatch", ok: false, type };
44587
+ }
44588
+ await session.handle.markNoAnswer({ metadata: message.metadata });
44589
+ return { detail: "Marked no-answer.", ok: true, type };
44590
+ };
44591
+ }
44592
+ return;
44593
+ };
44594
+ var parseControlMessage = (raw) => {
44595
+ if (!raw || typeof raw !== "object")
44596
+ return;
44597
+ const record = raw;
44598
+ const type = record.type;
44599
+ if (typeof type !== "string")
44600
+ return;
44601
+ if (type === "transfer") {
44602
+ if (typeof record.target !== "string")
44603
+ return;
44604
+ return {
44605
+ metadata: record.metadata,
44606
+ reason: typeof record.reason === "string" ? record.reason : undefined,
44607
+ target: record.target,
44608
+ type
44609
+ };
44610
+ }
44611
+ if (type === "hangup") {
44612
+ return {
44613
+ reason: typeof record.reason === "string" ? record.reason : undefined,
44614
+ type
44615
+ };
44616
+ }
44617
+ if (type === "escalate") {
44618
+ return {
44619
+ metadata: record.metadata,
44620
+ reason: typeof record.reason === "string" ? record.reason : undefined,
44621
+ type
44622
+ };
44623
+ }
44624
+ if (type === "voicemail" || type === "no-answer") {
44625
+ return {
44626
+ metadata: record.metadata,
44627
+ type
44628
+ };
44629
+ }
44630
+ if (type === "mute") {
44631
+ if (typeof record.muted !== "boolean" || record.target !== "assistant" && record.target !== "caller") {
44632
+ return;
44633
+ }
44634
+ return { muted: record.muted, target: record.target, type };
44635
+ }
44636
+ if (type === "say") {
44637
+ if (typeof record.text !== "string")
44638
+ return;
44639
+ return {
44640
+ interrupt: typeof record.interrupt === "boolean" ? record.interrupt : undefined,
44641
+ text: record.text,
44642
+ type
44643
+ };
44644
+ }
44645
+ if (type === "inject") {
44646
+ if (typeof record.text !== "string" || record.role !== "assistant" && record.role !== "system" && record.role !== "user") {
44647
+ return;
44648
+ }
44649
+ return { role: record.role, text: record.text, type };
44650
+ }
44651
+ return;
44652
+ };
44653
+ var DEFAULT_BASE_PATH = "/api/voice/monitor";
44654
+ var DEFAULT_LISTEN_PATH = ":sessionId/listen";
44655
+ var DEFAULT_CONTROL_PATH = ":sessionId/control";
44656
+ var joinPath = (...parts) => parts.filter((part) => part.length > 0).map((part) => part.replace(/^\/+|\/+$/g, "")).filter((part) => part.length > 0).reduce((path, part) => `${path}/${part}`, "");
44657
+ var substituteSessionId = (template, sessionId) => template.replace(":sessionId", encodeURIComponent(sessionId));
44658
+ var buildVoiceMonitorPlan = (input) => {
44659
+ const basePath = input.basePath ?? DEFAULT_BASE_PATH;
44660
+ const listenTemplate = input.listenPath ?? joinPath(basePath, DEFAULT_LISTEN_PATH);
44661
+ const controlTemplate = input.controlPath ?? joinPath(basePath, DEFAULT_CONTROL_PATH);
44662
+ const baseUrl = input.baseUrl.replace(/\/+$/, "");
44663
+ return {
44664
+ controlUrl: `${baseUrl}${substituteSessionId(controlTemplate, input.sessionId)}`,
44665
+ listenUrl: `${baseUrl}${substituteSessionId(listenTemplate, input.sessionId)}`
44666
+ };
44667
+ };
44668
+ var resolveSessionId3 = (ws) => {
44669
+ const params = ws.data?.params;
44670
+ if (!params)
44671
+ return;
44672
+ const value = params.sessionId;
44673
+ if (typeof value !== "string" || value.length === 0)
44674
+ return;
44675
+ return value;
44676
+ };
44677
+ var resolveAuthenticate = async (authenticate, input) => {
44678
+ if (!authenticate)
44679
+ return true;
44680
+ return await authenticate(input);
44681
+ };
44682
+ var createVoiceLiveMonitorRoutes = (options) => {
44683
+ const basePath = options.basePath ?? DEFAULT_BASE_PATH;
44684
+ const listenPath = options.listenPath === undefined ? joinPath(basePath, DEFAULT_LISTEN_PATH) : options.listenPath;
44685
+ const controlPath = options.controlPath === undefined ? joinPath(basePath, DEFAULT_CONTROL_PATH) : options.controlPath;
44686
+ const handlers = {
44687
+ escalate: options.controlHandlers?.escalate ?? buildDefaultControlHandler("escalate"),
44688
+ hangup: options.controlHandlers?.hangup ?? buildDefaultControlHandler("hangup"),
44689
+ inject: options.controlHandlers?.inject,
44690
+ mute: options.controlHandlers?.mute,
44691
+ "no-answer": options.controlHandlers?.["no-answer"] ?? buildDefaultControlHandler("no-answer"),
44692
+ say: options.controlHandlers?.say,
44693
+ transfer: options.controlHandlers?.transfer ?? buildDefaultControlHandler("transfer"),
44694
+ voicemail: options.controlHandlers?.voicemail ?? buildDefaultControlHandler("voicemail")
44695
+ };
44696
+ const app = new Elysia70({ name: "absolutejs-voice-monitor" });
44697
+ const unsubscribers = new WeakMap;
44698
+ if (listenPath !== false && listenPath.length > 0) {
44699
+ app.ws(`/${listenPath.replace(/^\/+/, "")}`, {
44700
+ close: (ws) => {
44701
+ const subs = unsubscribers.get(ws);
44702
+ if (subs) {
44703
+ for (const unsub of subs)
44704
+ unsub();
44705
+ unsubscribers.delete(ws);
44706
+ }
44707
+ },
44708
+ open: async (ws) => {
44709
+ const webSocket = ws;
44710
+ const sessionId = resolveSessionId3(webSocket);
44711
+ if (!sessionId) {
44712
+ webSocket.send(JSON.stringify({
44713
+ error: "missing sessionId in path params",
44714
+ type: "error"
44715
+ }));
44716
+ webSocket.close(4400, "missing sessionId");
44717
+ return;
44718
+ }
44719
+ const authed = await resolveAuthenticate(options.authenticate, {
44720
+ request: webSocket.raw?.request,
44721
+ route: "listen",
44722
+ sessionId
44723
+ });
44724
+ if (!authed) {
44725
+ webSocket.send(JSON.stringify({ error: "unauthorized", type: "error" }));
44726
+ webSocket.close(4401, "unauthorized");
44727
+ return;
44728
+ }
44729
+ const record = options.registry.get(sessionId);
44730
+ if (!record) {
44731
+ webSocket.send(JSON.stringify({
44732
+ error: `session "${sessionId}" not found`,
44733
+ type: "error"
44734
+ }));
44735
+ webSocket.close(4404, "session not found");
44736
+ return;
44737
+ }
44738
+ const subs = [];
44739
+ webSocket.send(JSON.stringify({
44740
+ sessionId,
44741
+ type: "subscribed"
44742
+ }));
44743
+ subs.push(record.onAudio((event) => {
44744
+ webSocket.send(event.chunk);
44745
+ }));
44746
+ subs.push(record.onClose((reason) => {
44747
+ webSocket.send(JSON.stringify({
44748
+ reason,
44749
+ sessionId,
44750
+ type: "session-closed"
44751
+ }));
44752
+ webSocket.close(1000, reason ?? "session-closed");
44753
+ }));
44754
+ unsubscribers.set(ws, subs);
44755
+ }
44756
+ });
44757
+ }
44758
+ if (controlPath !== false && controlPath.length > 0) {
44759
+ app.ws(`/${controlPath.replace(/^\/+/, "")}`, {
44760
+ close: (ws) => {
44761
+ unsubscribers.delete(ws);
44762
+ },
44763
+ message: async (ws, raw) => {
44764
+ const webSocket = ws;
44765
+ const sessionId = resolveSessionId3(webSocket);
44766
+ if (!sessionId) {
44767
+ webSocket.send(JSON.stringify({
44768
+ error: "missing sessionId in path params",
44769
+ ok: false,
44770
+ type: "error"
44771
+ }));
44772
+ return;
44773
+ }
44774
+ const message = parseControlMessage(raw);
44775
+ if (!message) {
44776
+ webSocket.send(JSON.stringify({
44777
+ error: "invalid control message",
44778
+ ok: false,
44779
+ type: "error"
44780
+ }));
44781
+ return;
44782
+ }
44783
+ const record = options.registry.get(sessionId);
44784
+ if (!record) {
44785
+ webSocket.send(JSON.stringify({
44786
+ error: `session "${sessionId}" not found`,
44787
+ ok: false,
44788
+ type: message.type
44789
+ }));
44790
+ return;
44791
+ }
44792
+ const handler = handlers[message.type];
44793
+ if (!handler) {
44794
+ webSocket.send(JSON.stringify({
44795
+ error: `no handler registered for control type "${message.type}"`,
44796
+ ok: false,
44797
+ type: message.type
44798
+ }));
44799
+ return;
44800
+ }
44801
+ try {
44802
+ const ack = await handler({
44803
+ message,
44804
+ raw,
44805
+ session: record
44806
+ });
44807
+ webSocket.send(JSON.stringify(ack));
44808
+ } catch (error) {
44809
+ webSocket.send(JSON.stringify({
44810
+ error: error instanceof Error ? error.message : String(error),
44811
+ ok: false,
44812
+ type: message.type
44813
+ }));
44814
+ }
44815
+ },
44816
+ open: async (ws) => {
44817
+ const webSocket = ws;
44818
+ const sessionId = resolveSessionId3(webSocket);
44819
+ if (!sessionId) {
44820
+ webSocket.send(JSON.stringify({
44821
+ error: "missing sessionId in path params",
44822
+ type: "error"
44823
+ }));
44824
+ webSocket.close(4400, "missing sessionId");
44825
+ return;
44826
+ }
44827
+ const authed = await resolveAuthenticate(options.authenticate, {
44828
+ request: webSocket.raw?.request,
44829
+ route: "control",
44830
+ sessionId
44831
+ });
44832
+ if (!authed) {
44833
+ webSocket.send(JSON.stringify({ error: "unauthorized", type: "error" }));
44834
+ webSocket.close(4401, "unauthorized");
44835
+ return;
44836
+ }
44837
+ const record = options.registry.get(sessionId);
44838
+ if (!record) {
44839
+ webSocket.send(JSON.stringify({
44840
+ error: `session "${sessionId}" not found`,
44841
+ type: "error"
44842
+ }));
44843
+ webSocket.close(4404, "session not found");
44844
+ return;
44845
+ }
44846
+ webSocket.send(JSON.stringify({
44847
+ sessionId,
44848
+ supports: Object.entries(handlers).filter(([, value]) => value !== undefined).map(([key]) => key),
44849
+ type: "ready"
44850
+ }));
44851
+ }
44852
+ });
44853
+ }
44854
+ if (options.htmlPath !== undefined && options.htmlPath !== false) {
44855
+ const path = options.htmlPath;
44856
+ app.get(path, () => {
44857
+ const sessions = options.registry.list().map((entry) => `<li><code>${entry.sessionId}</code></li>`).join("");
44858
+ const body = `<!doctype html><html lang="en"><head><meta charset="utf-8" /><title>Voice Monitor</title><style>body{background:#0b1216;color:#f6f1e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0;padding:32px}main{margin:auto;max-width:960px}h1{font-size:clamp(2rem,5vw,3.2rem);letter-spacing:-.04em;margin:.2rem 0 1rem}code{background:#171f25;border:1px solid #2c3a44;border-radius:8px;padding:2px 6px}ul{margin:8px 0;padding-left:18px}p.muted{color:#9aa8b2}</style></head><body><main><h1>Voice Monitor</h1><p class="muted">Active sessions registered with this monitor registry.</p><ul>${sessions || "<li><em>None.</em></li>"}</ul><p class="muted">Open <code>${listenPath}</code> and <code>${controlPath}</code> via WebSocket per session for live listen + control.</p></main></body></html>`;
44859
+ return new Response(body, {
44860
+ headers: { "content-type": "text/html; charset=utf-8" }
44861
+ });
44862
+ });
44863
+ }
44864
+ return app;
44865
+ };
44457
44866
  export {
44458
44867
  writeVoiceProofPack,
44459
44868
  writeVoiceMediaPipelineArtifacts,
@@ -44948,6 +45357,7 @@ export {
44948
45357
  createVoiceObservabilityExportRoutes,
44949
45358
  createVoiceObservabilityExportReplayRoutes,
44950
45359
  createVoiceMonitorWebhookNotifier,
45360
+ createVoiceMonitorSession,
44951
45361
  createVoiceMonitorRunnerRoutes,
44952
45362
  createVoiceMonitorRunner,
44953
45363
  createVoiceMonitorRoutes,
@@ -44967,6 +45377,7 @@ export {
44967
45377
  createVoiceMediaPipelineRoutes,
44968
45378
  createVoiceLiveOpsRoutes,
44969
45379
  createVoiceLiveOpsController,
45380
+ createVoiceLiveMonitorRoutes,
44970
45381
  createVoiceLiveLatencyRoutes,
44971
45382
  createVoiceLinearIssueUpdateSink,
44972
45383
  createVoiceLinearIssueSyncSinks,
@@ -44978,6 +45389,7 @@ export {
44978
45389
  createVoiceIncidentTimelineRoutes,
44979
45390
  createVoiceIncidentBundleRoutes,
44980
45391
  createVoiceInMemoryRealCallProfileRecoveryJobStore,
45392
+ createVoiceInMemoryMonitorRegistry,
44981
45393
  createVoiceHubSpotTaskUpdateSink,
44982
45394
  createVoiceHubSpotTaskSyncSinks,
44983
45395
  createVoiceHubSpotTaskSink,
@@ -45153,6 +45565,7 @@ export {
45153
45565
  buildVoiceObservabilityArtifactIndex,
45154
45566
  buildVoiceMultilingualProofReadinessCheck,
45155
45567
  buildVoiceMonitorRunReport,
45568
+ buildVoiceMonitorPlan,
45156
45569
  buildVoiceMediaPipelineReport,
45157
45570
  buildVoiceMediaPipelineReadinessChecks,
45158
45571
  buildVoiceMediaPipelineIncidentEvents,
@@ -0,0 +1,138 @@
1
+ import { Elysia } from "elysia";
2
+ import type { AudioFormat, VoiceSessionHandle, VoiceSessionRecord } from "./types";
3
+ export type VoiceMonitorAudioSource = "assistant" | "caller" | (string & {});
4
+ export type VoiceMonitorAudioEvent = {
5
+ at: number;
6
+ chunk: Uint8Array;
7
+ format: AudioFormat;
8
+ source: VoiceMonitorAudioSource;
9
+ };
10
+ export type VoiceMonitorSessionRecord = {
11
+ handle: VoiceSessionHandle<unknown, VoiceSessionRecord, unknown>;
12
+ metadata?: Record<string, unknown>;
13
+ onAudio: (handler: (event: VoiceMonitorAudioEvent) => void) => () => void;
14
+ onClose: (handler: (reason?: string) => void) => () => void;
15
+ sessionId: string;
16
+ };
17
+ export type VoiceMonitorRegistry = {
18
+ get: (sessionId: string) => VoiceMonitorSessionRecord | undefined;
19
+ list: () => readonly {
20
+ sessionId: string;
21
+ }[];
22
+ };
23
+ export type VoiceMonitorMutableRegistry = VoiceMonitorRegistry & {
24
+ emit: (sessionId: string, event: VoiceMonitorAudioEvent) => void;
25
+ emitClose: (sessionId: string, reason?: string) => void;
26
+ register: (record: VoiceMonitorSessionRecord) => () => void;
27
+ };
28
+ export type VoiceMonitorRegistryRegisterInput = {
29
+ handle: VoiceSessionHandle<unknown, VoiceSessionRecord, unknown>;
30
+ metadata?: Record<string, unknown>;
31
+ sessionId: string;
32
+ };
33
+ export declare const createVoiceMonitorSession: (input: VoiceMonitorRegistryRegisterInput) => VoiceMonitorSessionRecord & {
34
+ emit: (event: VoiceMonitorAudioEvent) => void;
35
+ emitClose: (reason?: string) => void;
36
+ };
37
+ export declare const createVoiceInMemoryMonitorRegistry: () => VoiceMonitorMutableRegistry;
38
+ export type VoiceMonitorControlMessage = {
39
+ metadata?: Record<string, unknown>;
40
+ reason?: string;
41
+ target: string;
42
+ type: "transfer";
43
+ } | {
44
+ reason?: string;
45
+ type: "hangup";
46
+ } | {
47
+ metadata?: Record<string, unknown>;
48
+ reason?: string;
49
+ type: "escalate";
50
+ } | {
51
+ metadata?: Record<string, unknown>;
52
+ type: "voicemail";
53
+ } | {
54
+ metadata?: Record<string, unknown>;
55
+ type: "no-answer";
56
+ } | {
57
+ muted: boolean;
58
+ target: "assistant" | "caller";
59
+ type: "mute";
60
+ } | {
61
+ interrupt?: boolean;
62
+ text: string;
63
+ type: "say";
64
+ } | {
65
+ role: "assistant" | "system" | "user";
66
+ text: string;
67
+ type: "inject";
68
+ };
69
+ export type VoiceMonitorControlAck = {
70
+ detail?: string;
71
+ ok: true;
72
+ type: VoiceMonitorControlMessage["type"];
73
+ } | {
74
+ error: string;
75
+ ok: false;
76
+ type: VoiceMonitorControlMessage["type"];
77
+ };
78
+ export type VoiceMonitorControlHandlerInput = {
79
+ message: VoiceMonitorControlMessage;
80
+ raw: unknown;
81
+ session: VoiceMonitorSessionRecord;
82
+ };
83
+ export type VoiceMonitorControlHandler = (input: VoiceMonitorControlHandlerInput) => Promise<VoiceMonitorControlAck> | VoiceMonitorControlAck;
84
+ export type VoiceMonitorAuthenticateInput = {
85
+ request: unknown;
86
+ route: "control" | "listen";
87
+ sessionId: string;
88
+ };
89
+ export type VoiceMonitorAuthenticate = (input: VoiceMonitorAuthenticateInput) => boolean | Promise<boolean>;
90
+ export type VoiceLiveMonitorRoutesOptions = {
91
+ authenticate?: VoiceMonitorAuthenticate;
92
+ basePath?: string;
93
+ controlHandlers?: Partial<Record<VoiceMonitorControlMessage["type"], VoiceMonitorControlHandler>>;
94
+ controlPath?: false | string;
95
+ htmlPath?: false | string;
96
+ listenPath?: false | string;
97
+ registry: VoiceMonitorRegistry;
98
+ };
99
+ export type VoiceMonitorPlanInput = {
100
+ basePath?: string;
101
+ baseUrl: string;
102
+ controlPath?: string;
103
+ listenPath?: string;
104
+ sessionId: string;
105
+ };
106
+ export type VoiceMonitorPlan = {
107
+ controlUrl: string;
108
+ listenUrl: string;
109
+ };
110
+ export declare const buildVoiceMonitorPlan: (input: VoiceMonitorPlanInput) => VoiceMonitorPlan;
111
+ export declare const createVoiceLiveMonitorRoutes: (options: VoiceLiveMonitorRoutesOptions) => Elysia<"", {
112
+ decorator: {};
113
+ store: {};
114
+ derive: {};
115
+ resolve: {};
116
+ }, {
117
+ typebox: {};
118
+ error: {};
119
+ }, {
120
+ schema: {};
121
+ standaloneSchema: {};
122
+ macro: {};
123
+ macroFn: {};
124
+ parser: {};
125
+ response: {};
126
+ }, {}, {
127
+ derive: {};
128
+ resolve: {};
129
+ schema: {};
130
+ standaloneSchema: {};
131
+ response: {};
132
+ }, {
133
+ derive: {};
134
+ resolve: {};
135
+ schema: {};
136
+ standaloneSchema: {};
137
+ response: {};
138
+ }>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.472",
3
+ "version": "0.0.22-beta.473",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",