@openclaw/voice-call 2026.9.7 → 2026.10.1-beta.1

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.
Files changed (41) hide show
  1. package/dist/.setup/{cli-D6uwMXyS.mjs → cli-Cn1leykM.mjs} +57 -37
  2. package/dist/.setup/{config-Ds7xoZbI.mjs → config-CX9J-053.mjs} +18 -119
  3. package/dist/.setup/{guarded-json-api-Bqc6QS8A.mjs → guarded-json-api-x55yqHvW.mjs} +39 -94
  4. package/dist/.setup/{mock-ClWW6Ufu.mjs → mock-eLv_Dc4o.mjs} +3 -6
  5. package/dist/.setup/{plivo-69ObrQPk.mjs → plivo-CpPIENu4.mjs} +48 -101
  6. package/dist/.setup/{realtime-handler-BgDPcPZt.mjs → realtime-handler-Do7Sz7Gh.mjs} +123 -235
  7. package/dist/.setup/{response-generator-BzKrJMEb.mjs → response-generator-DAhbXEta.mjs} +6 -25
  8. package/dist/.setup/{runtime-entry-BNOQRXii.mjs → runtime-entry-CbSKxSKk.mjs} +554 -425
  9. package/dist/.setup/state-retention-api-ONgqE-_V.mjs +201 -0
  10. package/dist/.setup/store-path-Cfwff6j7.mjs +33 -0
  11. package/dist/.setup/{telnyx-DjFGCfy1.mjs → telnyx-DPilutCH.mjs} +10 -29
  12. package/dist/.setup/{twilio-Bp3gfmUB.mjs → twilio-BWFNGyVx.mjs} +78 -201
  13. package/dist/.setup/{twilio-region-4fkgz3UG.mjs → twilio-region-wBOx-8sz.mjs} +1 -4
  14. package/dist/.setup/voice-mapping-B_iAUkER.mjs +31 -0
  15. package/dist/.setup/{webhook-replay-CCQSoBNF.mjs → webhook-replay-B7RJNWNG.mjs} +2 -5
  16. package/dist/doctor-contract-api.js +7 -330
  17. package/dist/index.js +18 -16
  18. package/dist/runtime-entry.js +1 -1
  19. package/dist/state-retention-api.js +2 -0
  20. package/openclaw.plugin.json +1 -1
  21. package/package.json +4 -6
  22. package/dist/.setup/utils-B5pnM_Ij.mjs +0 -437
  23. package/node_modules/ws/LICENSE +0 -20
  24. package/node_modules/ws/README.md +0 -548
  25. package/node_modules/ws/browser.js +0 -8
  26. package/node_modules/ws/index.js +0 -22
  27. package/node_modules/ws/lib/buffer-util.js +0 -131
  28. package/node_modules/ws/lib/constants.js +0 -19
  29. package/node_modules/ws/lib/event-target.js +0 -292
  30. package/node_modules/ws/lib/extension.js +0 -203
  31. package/node_modules/ws/lib/limiter.js +0 -55
  32. package/node_modules/ws/lib/permessage-deflate.js +0 -530
  33. package/node_modules/ws/lib/receiver.js +0 -743
  34. package/node_modules/ws/lib/sender.js +0 -607
  35. package/node_modules/ws/lib/stream.js +0 -161
  36. package/node_modules/ws/lib/subprotocol.js +0 -62
  37. package/node_modules/ws/lib/validation.js +0 -152
  38. package/node_modules/ws/lib/websocket-server.js +0 -562
  39. package/node_modules/ws/lib/websocket.js +0 -1407
  40. package/node_modules/ws/package.json +0 -74
  41. package/node_modules/ws/wrapper.mjs +0 -21
@@ -0,0 +1,201 @@
1
+ import { n as resolveVoiceCallStorePath } from "./store-path-Cfwff6j7.mjs";
2
+ import path from "node:path";
3
+ //#region \0rolldown/runtime.js
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __exportAll = (all, no_symbols) => {
9
+ let target = {};
10
+ for (var name in all) __defProp(target, name, {
11
+ get: all[name],
12
+ enumerable: true
13
+ });
14
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
15
+ return target;
16
+ };
17
+ var __copyProps = (to, from, except, desc) => {
18
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
19
+ key = keys[i];
20
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
21
+ get: ((k) => from[k]).bind(null, key),
22
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
23
+ });
24
+ }
25
+ return to;
26
+ };
27
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
28
+ //#endregion
29
+ //#region packages/normalization-core/src/record-coerce.ts
30
+ /** Type guard for non-array object records at browser-safe boundaries. */
31
+ function isRecord(value) {
32
+ return value !== null && typeof value === "object" && !Array.isArray(value);
33
+ }
34
+ /** Returns a non-array record or null. */
35
+ function asNullableRecord(value) {
36
+ return isRecord(value) ? value : null;
37
+ }
38
+ //#endregion
39
+ //#region src/config/channel-config-normalization.ts
40
+ /** Applies one channel-specific doctor migration to every object-shaped account. */
41
+ function normalizeChannelAccounts(params) {
42
+ const rawAccounts = asNullableRecord(params.entry.accounts);
43
+ if (!rawAccounts) return {
44
+ entry: params.entry,
45
+ changed: false
46
+ };
47
+ let changed = false;
48
+ const accounts = { ...rawAccounts };
49
+ for (const [accountId, value] of Object.entries(rawAccounts)) {
50
+ const account = asNullableRecord(value);
51
+ if (!account) continue;
52
+ const normalized = params.normalizeAccount({
53
+ account,
54
+ accountId,
55
+ pathPrefix: `${params.pathPrefix}.accounts.${accountId}`,
56
+ changes: params.changes
57
+ });
58
+ if (normalized.changed) {
59
+ accounts[accountId] = normalized.entry;
60
+ changed = true;
61
+ }
62
+ }
63
+ return changed ? {
64
+ entry: {
65
+ ...params.entry,
66
+ accounts
67
+ },
68
+ changed: true
69
+ } : {
70
+ entry: params.entry,
71
+ changed: false
72
+ };
73
+ }
74
+ /** Applies the same channel-specific doctor migration at root and account scope. */
75
+ function normalizeChannelConfigEntries(params) {
76
+ const changes = params.changes ?? [];
77
+ const channels = params.cfg.channels;
78
+ const entry = asNullableRecord(channels?.[params.channelId]);
79
+ if (!entry) return {
80
+ config: params.cfg,
81
+ changes
82
+ };
83
+ const channelPath = `channels.${params.channelId}`;
84
+ const root = params.normalizeEntry({
85
+ entry,
86
+ pathPrefix: channelPath,
87
+ changes
88
+ });
89
+ const accounts = normalizeChannelAccounts({
90
+ entry: root.entry,
91
+ pathPrefix: channelPath,
92
+ changes,
93
+ normalizeAccount: (accountParams) => params.normalizeEntry({
94
+ entry: accountParams.account,
95
+ accountId: accountParams.accountId,
96
+ pathPrefix: accountParams.pathPrefix,
97
+ changes: accountParams.changes
98
+ })
99
+ });
100
+ if (!root.changed && !accounts.changed) return {
101
+ config: params.cfg,
102
+ changes
103
+ };
104
+ return {
105
+ config: {
106
+ ...params.cfg,
107
+ channels: {
108
+ ...channels,
109
+ [params.channelId]: accounts.entry
110
+ }
111
+ },
112
+ changes
113
+ };
114
+ }
115
+ //#endregion
116
+ //#region src/plugin-sdk/legacy-webhook-listener-migration.ts
117
+ /** Preserve explicitly configured webhook listeners while moving ingress onto Gateway routes. */
118
+ function createLegacyWebhookListenerDoctorContract(params) {
119
+ const portKey = params.portKey ?? "webhookPort";
120
+ const hostKey = params.hostKey === void 0 ? "webhookHost" : params.hostKey;
121
+ const source = (entry) => params.webhookKey ? asNullableRecord(entry[params.webhookKey]) : entry;
122
+ const hasLegacy = (value) => {
123
+ const entry = asNullableRecord(value);
124
+ const listener = entry && source(entry);
125
+ return Boolean(listener && (Object.hasOwn(listener, portKey) || hostKey && Object.hasOwn(listener, hostKey)));
126
+ };
127
+ const prefix = `channels.${params.channelKey}`;
128
+ return {
129
+ historicalWebhookListener: {
130
+ channelId: params.channelKey,
131
+ port: params.defaultPort,
132
+ preserveAuthoredActivation: params.preserveAuthoredActivation,
133
+ ...params.defaultHost === void 0 ? {} : { host: params.defaultHost }
134
+ },
135
+ legacyConfigRules: [{
136
+ path: ["channels", params.channelKey],
137
+ message: `${prefix} webhook listeners moved to Gateway routes. Run "openclaw doctor --fix" to preserve explicitly configured listener settings as legacyWebhook.`,
138
+ match: (value) => {
139
+ const accounts = asNullableRecord(asNullableRecord(value)?.accounts);
140
+ return hasLegacy(value) || Object.values(accounts ?? {}).some(hasLegacy);
141
+ }
142
+ }],
143
+ normalizeCompatibilityConfig: ({ cfg }) => {
144
+ const root = asNullableRecord(asNullableRecord(cfg.channels)?.[params.channelKey]);
145
+ const inherited = root && source(root);
146
+ const canonicalRoot = asNullableRecord(root?.legacyWebhook);
147
+ return normalizeChannelConfigEntries({
148
+ cfg,
149
+ channelId: params.channelKey,
150
+ normalizeEntry: ({ entry, accountId, pathPrefix, changes }) => {
151
+ const listener = source(entry);
152
+ if (!listener || !hasLegacy(entry)) return {
153
+ entry,
154
+ changed: false
155
+ };
156
+ const next = { ...entry };
157
+ const port = Object.hasOwn(listener, portKey) ? listener[portKey] : (accountId ? canonicalRoot?.port ?? inherited?.[portKey] : void 0) ?? params.defaultPort;
158
+ const inheritedHost = accountId ? canonicalRoot ? canonicalRoot.host : (hostKey ? inherited?.[hostKey] : void 0) ?? params.defaultHost : params.defaultHost;
159
+ const host = hostKey ? listener[hostKey] ?? inheritedHost : inheritedHost;
160
+ const legacyPath = [pathPrefix, params.webhookKey].filter(Boolean).join(".");
161
+ if (Object.hasOwn(entry, "legacyWebhook")) changes.push(`Removed ${legacyPath} legacy listener keys; ${pathPrefix}.legacyWebhook is already configured.`);
162
+ else if (accountId && root?.legacyWebhook === false) changes.push(`Removed ${legacyPath} legacy listener keys; ${prefix}.legacyWebhook: false keeps this account's inherited listener disabled.`);
163
+ else {
164
+ next.legacyWebhook = {
165
+ port,
166
+ ...host !== void 0 ? { host } : {}
167
+ };
168
+ changes.push(`Moved ${legacyPath} listener settings to ${pathPrefix}.legacyWebhook. Point the external callback or reverse proxy at the Gateway port and webhook path, verify delivery, then set legacyWebhook: false to disable legacy forwarding.`);
169
+ }
170
+ const updated = params.webhookKey ? { ...listener } : next;
171
+ delete updated[portKey];
172
+ if (hostKey) delete updated[hostKey];
173
+ if (params.webhookKey) {
174
+ if (Object.keys(updated).length) next[params.webhookKey] = updated;
175
+ else delete next[params.webhookKey];
176
+ }
177
+ return {
178
+ entry: next,
179
+ changed: true
180
+ };
181
+ }
182
+ });
183
+ }
184
+ };
185
+ }
186
+ //#endregion
187
+ //#region \0openclaw:bundled-sdk:openclaw/plugin-sdk/runtime-doctor-migrations
188
+ var runtime_doctor_migrations_exports = /* @__PURE__ */ __exportAll({ createLegacyWebhookListenerDoctorContract: () => createLegacyWebhookListenerDoctorContract });
189
+ import * as import_openclaw_plugin_sdk_runtime_doctor_migrations from "openclaw/plugin-sdk/runtime-doctor-migrations";
190
+ __reExport(runtime_doctor_migrations_exports, import_openclaw_plugin_sdk_runtime_doctor_migrations);
191
+ //#endregion
192
+ //#region extensions/voice-call/state-retention-api.ts
193
+ const packageName = "@openclaw/voice-call";
194
+ const stateMigrations = [(0, runtime_doctor_migrations_exports.defineRetiredPluginStateMigration)({
195
+ id: "voice-call-calls-jsonl-to-plugin-state",
196
+ label: "Voice Call JSONL call log",
197
+ intermediateVersion: "2026.9.7",
198
+ findSources: (input) => [path.join(resolveVoiceCallStorePath(input), "calls.jsonl")]
199
+ })];
200
+ //#endregion
201
+ export { stateMigrations as n, packageName as t };
@@ -0,0 +1,33 @@
1
+ import { asOptionalRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { resolveStateDir } from "openclaw/plugin-sdk/state-paths";
5
+ //#region extensions/voice-call/src/utils.ts
6
+ /** Runtime uses the OS home; Doctor supplies the home from its migration environment. */
7
+ function resolveUserPath(input, homedir = os.homedir) {
8
+ const trimmed = input.trim();
9
+ if (!trimmed) return trimmed;
10
+ return path.resolve(trimmed.replace(/^~(?=$|[\\/])/, homedir));
11
+ }
12
+ //#endregion
13
+ //#region extensions/voice-call/src/store-path.ts
14
+ /** Resolve the plugin-owned store below OpenClaw's canonical state directory. */
15
+ function resolveDefaultVoiceCallStoreDir(env = process.env) {
16
+ return path.join(resolveStateDir(env), "voice-calls");
17
+ }
18
+ /** Read the configured voice-call store path from either package id. */
19
+ function getVoiceCallConfigStore(config) {
20
+ for (const pluginId of ["voice-call", "@openclaw/voice-call"]) {
21
+ const store = asOptionalRecord(config.plugins?.entries?.[pluginId]?.config)?.store;
22
+ if (typeof store === "string" && store.trim()) return store.trim();
23
+ }
24
+ return "";
25
+ }
26
+ /** Resolve the voice-call store path used by legacy and plugin-state call records. */
27
+ function resolveVoiceCallStorePath(params) {
28
+ const configuredStore = getVoiceCallConfigStore(params.config);
29
+ if (configuredStore) return resolveUserPath(configuredStore, () => params.env.HOME?.trim() || os.homedir());
30
+ return resolveDefaultVoiceCallStoreDir(params.env);
31
+ }
32
+ //#endregion
33
+ export { resolveVoiceCallStorePath as n, resolveUserPath as r, resolveDefaultVoiceCallStoreDir as t };
@@ -1,14 +1,9 @@
1
- import { c as verifyTelnyxWebhook, n as readProviderCallStatus, t as guardedJsonApiRequest } from "./guarded-json-api-Bqc6QS8A.mjs";
1
+ import { a as verifyTelnyxWebhook, n as readProviderCallStatus, t as guardedJsonApiRequest } from "./guarded-json-api-x55yqHvW.mjs";
2
2
  import crypto from "node:crypto";
3
3
  //#region extensions/voice-call/src/providers/telnyx.ts
4
4
  function normalizeTelnyxDirection(direction) {
5
- switch (direction) {
6
- case "incoming":
7
- case "inbound": return "inbound";
8
- case "outgoing":
9
- case "outbound": return "outbound";
10
- default: return;
11
- }
5
+ if (direction === "incoming" || direction === "inbound") return "inbound";
6
+ if (direction === "outgoing" || direction === "outbound") return "outbound";
12
7
  }
13
8
  function normalizeBase64ForCompare(value) {
14
9
  return value.replace(/=+$/u, "").replace(/-/gu, "+").replace(/_/gu, "/");
@@ -46,14 +41,7 @@ var TelnyxProvider = class {
46
41
  });
47
42
  }
48
43
  verifyWebhook(ctx) {
49
- const result = verifyTelnyxWebhook(ctx, this.publicKey, { skipVerification: this.options.skipVerification });
50
- return {
51
- ok: result.ok,
52
- reason: result.reason,
53
- isReplay: result.isReplay,
54
- verifiedRequestKey: result.verifiedRequestKey,
55
- releaseReplay: result.releaseReplay
56
- };
44
+ return verifyTelnyxWebhook(ctx, this.publicKey, { skipVerification: this.options.skipVerification });
57
45
  }
58
46
  parseWebhookEvent(ctx, options) {
59
47
  try {
@@ -89,17 +77,11 @@ var TelnyxProvider = class {
89
77
  to: data.payload?.to
90
78
  };
91
79
  switch (data.event_type) {
92
- case "call.initiated": return {
93
- ...baseEvent,
94
- type: "call.initiated"
95
- };
96
- case "call.ringing": return {
97
- ...baseEvent,
98
- type: "call.ringing"
99
- };
80
+ case "call.initiated":
81
+ case "call.ringing":
100
82
  case "call.answered": return {
101
83
  ...baseEvent,
102
- type: "call.answered"
84
+ type: data.event_type
103
85
  };
104
86
  case "call.bridged": return {
105
87
  ...baseEvent,
@@ -131,8 +113,6 @@ var TelnyxProvider = class {
131
113
  type: "call.dtmf",
132
114
  digits: data.payload?.digit || ""
133
115
  };
134
- case "streaming.started":
135
- case "streaming.stopped": return null;
136
116
  default: return null;
137
117
  }
138
118
  }
@@ -171,7 +151,7 @@ var TelnyxProvider = class {
171
151
  webhook_url_method: "POST",
172
152
  client_state: Buffer.from(input.callId).toString("base64"),
173
153
  timeout_secs: 30,
174
- ...input.streamUrl ? buildTelnyxStreamingFields(input.streamUrl, input.streamAuthToken) : {}
154
+ ...buildTelnyxStreamingFields(input.streamUrl, input.streamAuthToken)
175
155
  };
176
156
  return {
177
157
  providerCallId: (await this.apiRequest("/calls", body)).data.call_control_id,
@@ -184,7 +164,7 @@ var TelnyxProvider = class {
184
164
  async answerCall(input) {
185
165
  const body = {
186
166
  command_id: `openclaw-answer-${input.callId}`,
187
- ...input.streamUrl ? buildTelnyxStreamingFields(input.streamUrl, input.streamAuthToken) : {}
167
+ ...buildTelnyxStreamingFields(input.streamUrl, input.streamAuthToken)
188
168
  };
189
169
  await this.apiRequest(`/calls/${input.providerCallId}/actions/answer`, body);
190
170
  }
@@ -232,6 +212,7 @@ var TelnyxProvider = class {
232
212
  }
233
213
  };
234
214
  function buildTelnyxStreamingFields(streamUrl, streamAuthToken) {
215
+ if (!streamUrl) return {};
235
216
  return {
236
217
  stream_url: streamUrl,
237
218
  stream_track: "inbound_track",