@fonoster/common 0.27.0 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{voice/PlayDtmf.d.ts → agents/index.d.ts} +3 -5
- package/dist/{assistants → agents}/index.js +2 -6
- package/dist/agents/sessionAgentSchema.d.ts +755 -0
- package/dist/agents/sessionAgentSchema.js +117 -0
- package/dist/{voice/Dial.d.ts → calls/index.d.ts} +16 -13
- package/dist/calls/index.js +44 -0
- package/dist/cellsecrets/index.d.ts +91 -0
- package/dist/cellsecrets/index.js +299 -0
- package/dist/config/cli/check.d.ts +6 -0
- package/dist/config/cli/check.js +202 -0
- package/dist/config/cli/envFile.d.ts +23 -0
- package/dist/config/cli/envFile.js +81 -0
- package/dist/config/cli/exposure.d.ts +10 -0
- package/dist/config/cli/exposure.js +93 -0
- package/dist/config/cli/index.d.ts +2 -0
- package/dist/{identity/tokenHasAccessKeyId.js → config/cli/index.js} +7 -8
- package/dist/config/cli/info.d.ts +6 -0
- package/dist/config/cli/info.js +62 -0
- package/dist/config/cli/init.d.ts +9 -0
- package/dist/config/cli/init.js +152 -0
- package/dist/config/cli/main.d.ts +11 -0
- package/dist/config/cli/main.js +155 -0
- package/dist/config/cli/render.d.ts +44 -0
- package/dist/config/cli/render.js +129 -0
- package/dist/config/cli/secrets.d.ts +21 -0
- package/dist/config/cli/secrets.js +117 -0
- package/dist/config/cli/types.d.ts +24 -0
- package/dist/config/cli/types.js +7 -0
- package/dist/{assistants/index.d.ts → config/configHints.d.ts} +8 -7
- package/dist/config/configHints.js +47 -0
- package/dist/{voice → config}/index.d.ts +11 -13
- package/dist/{voice → config}/index.js +11 -13
- package/dist/config/interpolateEnv.d.ts +34 -0
- package/dist/config/interpolateEnv.js +70 -0
- package/dist/config/loadServiceConfig.d.ts +28 -0
- package/dist/config/loadServiceConfig.js +112 -0
- package/dist/config/logsSchema.d.ts +76 -0
- package/dist/config/logsSchema.js +49 -0
- package/dist/config/natsConnection.d.ts +53 -0
- package/dist/config/natsConnection.js +58 -0
- package/dist/config/parseConfigFile.d.ts +7 -0
- package/dist/config/parseConfigFile.js +60 -0
- package/dist/config/resolveConfigFile.d.ts +17 -0
- package/dist/config/resolveConfigFile.js +54 -0
- package/dist/config/resolveSecretRefs.d.ts +35 -0
- package/dist/config/resolveSecretRefs.js +129 -0
- package/dist/{assistants/audioFiltersSchema.d.ts → config/strictDeep.d.ts} +9 -12
- package/dist/config/strictDeep.js +58 -0
- package/dist/config/telemetrySchema.d.ts +39 -0
- package/dist/config/telemetrySchema.js +44 -0
- package/dist/config/toJsonSchema.d.ts +30 -0
- package/dist/config/toJsonSchema.js +161 -0
- package/dist/constants.d.ts +1 -6
- package/dist/constants.js +4 -7
- package/dist/envs.d.ts +2 -1
- package/dist/envs.js +13 -11
- package/dist/errors/handleZodError.js +3 -1
- package/dist/filters/index.d.ts +70 -0
- package/dist/filters/index.js +101 -0
- package/dist/identity/createAuthInterceptor.d.ts +9 -2
- package/dist/identity/createAuthInterceptor.js +36 -30
- package/dist/identity/hasAccess.d.ts +9 -3
- package/dist/identity/hasAccess.js +32 -8
- package/dist/identity/index.d.ts +1 -0
- package/dist/identity/index.js +1 -0
- package/dist/identity/isValidToken.d.ts +12 -2
- package/dist/identity/isValidToken.js +25 -9
- package/dist/identity/roles.js +33 -7
- package/dist/identity/types.d.ts +6 -1
- package/dist/identity/types.js +1 -0
- package/dist/{assistants/LanguageModelProvider.js → identity/verifyAccessToken.d.ts} +10 -11
- package/dist/identity/verifyAccessToken.js +44 -0
- package/dist/index.d.ts +15 -2
- package/dist/index.js +18 -3
- package/dist/net/assertPublicDestination.d.ts +52 -0
- package/dist/net/assertPublicDestination.js +342 -0
- package/dist/{voice/StopSay.d.ts → net/index.d.ts} +1 -6
- package/dist/net/index.js +35 -0
- package/dist/notifications/createSendEmail.js +3 -1
- package/dist/protos/applications.proto +138 -3
- package/dist/protos/authz.proto +26 -4
- package/dist/protos/billing.proto +92 -0
- package/dist/protos/calls.proto +4 -0
- package/dist/protos/capabilities.proto +102 -0
- package/dist/protos/identity.proto +26 -1
- package/dist/protos/providers.proto +139 -0
- package/dist/protos/roomr.proto +146 -0
- package/dist/protos/session.proto +194 -0
- package/dist/protos/usage.proto +59 -0
- package/dist/protos/webhooks.proto +140 -0
- package/dist/{utils/types.d.ts → regions/hub/index.d.ts} +1 -5
- package/dist/regions/hub/index.js +35 -0
- package/dist/regions/hub/natsJwt.d.ts +63 -0
- package/dist/regions/hub/natsJwt.js +195 -0
- package/dist/registry/Registry.d.ts +87 -0
- package/dist/registry/Registry.js +432 -0
- package/dist/registry/cli.d.ts +20 -0
- package/dist/registry/cli.js +436 -0
- package/dist/registry/features.d.ts +31 -0
- package/dist/registry/features.js +38 -0
- package/dist/registry/index.d.ts +24 -0
- package/dist/registry/index.js +40 -0
- package/dist/registry/prisma.d.ts +67 -0
- package/dist/registry/prisma.js +399 -0
- package/dist/registry/stores.d.ts +21 -0
- package/dist/{assistants/languageModelConfigSchema.js → registry/stores.js} +55 -38
- package/dist/registry/types.d.ts +110 -0
- package/dist/{assistants/LanguageModelProvider.d.ts → registry/types.js} +6 -8
- package/dist/registry/workspaceKeys.d.ts +41 -0
- package/dist/registry/workspaceKeys.js +64 -0
- package/dist/roomr/health.d.ts +9 -0
- package/dist/{assistants/eventsHookSchema.js → roomr/health.js} +22 -18
- package/dist/roomr/index.d.ts +75 -0
- package/dist/roomr/index.js +146 -0
- package/dist/roomr/session.d.ts +133 -0
- package/dist/roomr/session.js +132 -0
- package/dist/session/index.d.ts +19 -0
- package/dist/session/index.js +35 -0
- package/dist/session/schema.d.ts +2140 -0
- package/dist/session/schema.js +448 -0
- package/dist/sessions/index.d.ts +96 -0
- package/dist/sessions/index.js +197 -0
- package/dist/telemetry.d.ts +76 -0
- package/dist/telemetry.js +360 -0
- package/dist/types.d.ts +3 -5
- package/dist/{voice/Gather.d.ts → usage/CallUsage.d.ts} +19 -18
- package/dist/usage/CallUsage.js +76 -0
- package/dist/usage/index.d.ts +22 -0
- package/dist/usage/index.js +38 -0
- package/dist/usage/meters.d.ts +113 -0
- package/dist/usage/meters.js +90 -0
- package/dist/usage/types.d.ts +159 -0
- package/dist/usage/types.js +84 -0
- package/dist/usage/usageId.d.ts +6 -0
- package/dist/usage/usageId.js +45 -0
- package/dist/utils/{findIntegrationsCredentials.js → WriteBehind.d.ts} +13 -10
- package/dist/utils/WriteBehind.js +64 -0
- package/dist/utils/index.d.ts +1 -3
- package/dist/utils/index.js +1 -3
- package/dist/utils/{createFetchSingleCallByCallId.d.ts → logUnhandledRejections.d.ts} +8 -4
- package/dist/{assistants/audioFiltersSchema.js → utils/logUnhandledRejections.js} +17 -12
- package/dist/utils/withErrorHandling.js +1 -1
- package/dist/validators/calls.d.ts +3 -0
- package/dist/validators/calls.js +12 -2
- package/dist/validators/identity.d.ts +37 -8
- package/dist/validators/identity.js +22 -3
- package/dist/validators/index.d.ts +1 -0
- package/dist/validators/index.js +1 -0
- package/dist/validators/sip.d.ts +40 -0
- package/dist/validators/sip.js +99 -0
- package/dist/validators/sipnet/credentials.d.ts +2 -2
- package/dist/validators/sipnet/domains.js +7 -7
- package/dist/validators/sipnet/trunks.d.ts +14 -14
- package/dist/validators/sipnet/trunks.js +4 -2
- package/dist/webhooks/Dispatcher.d.ts +87 -0
- package/dist/webhooks/Dispatcher.js +225 -0
- package/dist/webhooks/bus.d.ts +68 -0
- package/dist/webhooks/bus.js +178 -0
- package/dist/webhooks/events.d.ts +66 -0
- package/dist/webhooks/events.js +62 -0
- package/dist/webhooks/index.d.ts +23 -0
- package/dist/webhooks/index.js +39 -0
- package/dist/webhooks/prisma.d.ts +55 -0
- package/dist/webhooks/prisma.js +242 -0
- package/dist/webhooks/signing.d.ts +8 -0
- package/dist/webhooks/signing.js +53 -0
- package/package.json +25 -11
- package/schema/session.v1.json +871 -0
- package/dist/assistants/assistantSchema.d.ts +0 -739
- package/dist/assistants/assistantSchema.js +0 -37
- package/dist/assistants/conversationSettingsSchema.d.ts +0 -122
- package/dist/assistants/conversationSettingsSchema.js +0 -133
- package/dist/assistants/eventsHookSchema.d.ts +0 -38
- package/dist/assistants/languageModelConfigSchema.d.ts +0 -206
- package/dist/identity/tokenHasAccessKeyId.d.ts +0 -2
- package/dist/protos/voice.proto +0 -557
- package/dist/utils/createFetchSingleCallByCallId.js +0 -33
- package/dist/utils/findIntegrationsCredentials.d.ts +0 -23
- package/dist/utils/types.js +0 -2
- package/dist/voice/Dial.js +0 -20
- package/dist/voice/Gather.js +0 -9
- package/dist/voice/Mute.d.ts +0 -31
- package/dist/voice/Mute.js +0 -9
- package/dist/voice/Play.d.ts +0 -30
- package/dist/voice/Play.js +0 -2
- package/dist/voice/PlayDtmf.js +0 -2
- package/dist/voice/PlaybackControl.d.ts +0 -31
- package/dist/voice/PlaybackControl.js +0 -11
- package/dist/voice/Record.d.ts +0 -36
- package/dist/voice/Record.js +0 -7
- package/dist/voice/Say.d.ts +0 -28
- package/dist/voice/Say.js +0 -2
- package/dist/voice/StopSay.js +0 -2
- package/dist/voice/Stream.d.ts +0 -53
- package/dist/voice/Stream.js +0 -19
- package/dist/voice/StreamGather.d.ts +0 -34
- package/dist/voice/StreamGather.js +0 -9
- package/dist/voice/Verb.d.ts +0 -27
- package/dist/voice/Verb.js +0 -2
- package/dist/voice/voice.d.ts +0 -171
- package/dist/voice/voice.js +0 -65
- package/dist/{assistants → agents}/testCasesSchema.d.ts +4 -4
- /package/dist/{assistants → agents}/testCasesSchema.js +0 -0
- /package/dist/{assistants → agents}/tools/index.d.ts +0 -0
- /package/dist/{assistants → agents}/tools/index.js +0 -0
- /package/dist/{assistants → agents}/tools/propertySchema.d.ts +0 -0
- /package/dist/{assistants → agents}/tools/propertySchema.js +0 -0
- /package/dist/{assistants → agents}/tools/toolSchema.d.ts +0 -0
- /package/dist/{assistants → agents}/tools/toolSchema.js +0 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import net from "node:net";
|
|
2
|
+
import { URL } from "node:url";
|
|
3
|
+
/**
|
|
4
|
+
* Outbound requests to tenant-chosen URLs (Autopilot HTTP tools, webhooks) must not reach the
|
|
5
|
+
* platform's own network (SSRF, RV-B2): http/https only, and every address the host resolves to
|
|
6
|
+
* must be public. Operators who self-host can allow internal destinations with
|
|
7
|
+
* `FONOSTER_ALLOWED_DESTINATIONS` (comma-separated host names, IPs or CIDRs; default empty).
|
|
8
|
+
*/
|
|
9
|
+
export declare class UnsafeDestinationError extends Error {
|
|
10
|
+
constructor(message: string);
|
|
11
|
+
}
|
|
12
|
+
export type DestinationPolicy = {
|
|
13
|
+
/** Host names, IPs or CIDRs allowed although private; defaults to FONOSTER_ALLOWED_DESTINATIONS. */
|
|
14
|
+
allow?: string[];
|
|
15
|
+
};
|
|
16
|
+
/** True when the address is loopback, private, link-local, ULA, CGNAT, multicast or reserved. */
|
|
17
|
+
export declare function isPrivateAddress(ip: string): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Checks a tenant-chosen URL: http/https, not an internal name, and every resolved address
|
|
20
|
+
* public (or allowed by the operator). Returns the parsed URL.
|
|
21
|
+
*/
|
|
22
|
+
export declare function assertPublicDestination(input: string | URL, policy?: DestinationPolicy): Promise<URL>;
|
|
23
|
+
/** Synchronous shape check (scheme, literal IPs, internal names) for request validation. */
|
|
24
|
+
export declare function assertPublicUrlShape(input: string | URL, policy?: DestinationPolicy): URL;
|
|
25
|
+
/**
|
|
26
|
+
* For WebSocket connections to tenant-chosen URLs (session apps, listeners): checks the URL's
|
|
27
|
+
* shape (ws/wss, no internal names or private literal IPs) and returns a socket `lookup` that
|
|
28
|
+
* refuses private addresses when the name resolves. Pass it as the `lookup` option of `ws`.
|
|
29
|
+
*/
|
|
30
|
+
export declare function publicWebSocketGuard(input: string | URL, policy?: DestinationPolicy): {
|
|
31
|
+
lookup: net.LookupFunction;
|
|
32
|
+
};
|
|
33
|
+
/** Synchronous shape check of a ws:// or wss:// URL (see assertPublicUrlShape). */
|
|
34
|
+
export declare function assertPublicWebSocketUrlShape(input: string | URL, policy?: DestinationPolicy): URL;
|
|
35
|
+
export type SafeFetchInit = {
|
|
36
|
+
method?: string;
|
|
37
|
+
headers?: Record<string, string>;
|
|
38
|
+
body?: string;
|
|
39
|
+
signal?: AbortSignal;
|
|
40
|
+
/** Whole-request timeout (default 10 s). */
|
|
41
|
+
timeoutMs?: number;
|
|
42
|
+
/** Redirects followed, each re-checked (default 3). */
|
|
43
|
+
maxRedirects?: number;
|
|
44
|
+
/** Largest response body read (default 5 MiB). */
|
|
45
|
+
maxBytes?: number;
|
|
46
|
+
policy?: DestinationPolicy;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* fetch for tenant-chosen URLs: checks the destination (and each redirect) with
|
|
50
|
+
* assertPublicDestination, re-checks the addresses the socket connects to, and times out.
|
|
51
|
+
*/
|
|
52
|
+
export declare function safeFetch(input: string | URL, init?: SafeFetchInit): Promise<Response>;
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.UnsafeDestinationError = void 0;
|
|
16
|
+
exports.isPrivateAddress = isPrivateAddress;
|
|
17
|
+
exports.assertPublicDestination = assertPublicDestination;
|
|
18
|
+
exports.assertPublicUrlShape = assertPublicUrlShape;
|
|
19
|
+
exports.publicWebSocketGuard = publicWebSocketGuard;
|
|
20
|
+
exports.assertPublicWebSocketUrlShape = assertPublicWebSocketUrlShape;
|
|
21
|
+
exports.safeFetch = safeFetch;
|
|
22
|
+
/**
|
|
23
|
+
* Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
|
|
24
|
+
* http://github.com/fonoster/fonoster
|
|
25
|
+
*
|
|
26
|
+
* This file is part of Fonoster
|
|
27
|
+
*
|
|
28
|
+
* Licensed under the MIT License (the "License");
|
|
29
|
+
* you may not use this file except in compliance with
|
|
30
|
+
* the License. You may obtain a copy of the License at
|
|
31
|
+
*
|
|
32
|
+
* https://opensource.org/licenses/MIT
|
|
33
|
+
*
|
|
34
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
35
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
36
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
37
|
+
* See the License for the specific language governing permissions and
|
|
38
|
+
* limitations under the License.
|
|
39
|
+
*/
|
|
40
|
+
const node_dns_1 = __importDefault(require("node:dns"));
|
|
41
|
+
const node_http_1 = __importDefault(require("node:http"));
|
|
42
|
+
const node_https_1 = __importDefault(require("node:https"));
|
|
43
|
+
const node_net_1 = __importDefault(require("node:net"));
|
|
44
|
+
const node_url_1 = require("node:url");
|
|
45
|
+
/* global Response, Headers */
|
|
46
|
+
/**
|
|
47
|
+
* Outbound requests to tenant-chosen URLs (Autopilot HTTP tools, webhooks) must not reach the
|
|
48
|
+
* platform's own network (SSRF, RV-B2): http/https only, and every address the host resolves to
|
|
49
|
+
* must be public. Operators who self-host can allow internal destinations with
|
|
50
|
+
* `FONOSTER_ALLOWED_DESTINATIONS` (comma-separated host names, IPs or CIDRs; default empty).
|
|
51
|
+
*/
|
|
52
|
+
class UnsafeDestinationError extends Error {
|
|
53
|
+
constructor(message) {
|
|
54
|
+
super(message);
|
|
55
|
+
this.name = "UnsafeDestinationError";
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.UnsafeDestinationError = UnsafeDestinationError;
|
|
59
|
+
const blocked = new node_net_1.default.BlockList();
|
|
60
|
+
for (const [net4, prefix] of [
|
|
61
|
+
["0.0.0.0", 8], // "this network", 0.0.0.0
|
|
62
|
+
["10.0.0.0", 8],
|
|
63
|
+
["100.64.0.0", 10], // CGNAT
|
|
64
|
+
["127.0.0.0", 8],
|
|
65
|
+
["169.254.0.0", 16], // link-local, cloud metadata
|
|
66
|
+
["172.16.0.0", 12],
|
|
67
|
+
["192.0.0.0", 24],
|
|
68
|
+
["192.0.2.0", 24],
|
|
69
|
+
["192.168.0.0", 16],
|
|
70
|
+
["198.18.0.0", 15],
|
|
71
|
+
["198.51.100.0", 24],
|
|
72
|
+
["203.0.113.0", 24],
|
|
73
|
+
["224.0.0.0", 4], // multicast
|
|
74
|
+
["240.0.0.0", 4] // reserved, broadcast
|
|
75
|
+
])
|
|
76
|
+
blocked.addSubnet(net4, prefix, "ipv4");
|
|
77
|
+
for (const [net6, prefix] of [
|
|
78
|
+
["::", 128],
|
|
79
|
+
["::1", 128],
|
|
80
|
+
["64:ff9b::", 96], // NAT64 can reach IPv4 private ranges
|
|
81
|
+
["100::", 64],
|
|
82
|
+
["2001:db8::", 32],
|
|
83
|
+
["fc00::", 7], // ULA
|
|
84
|
+
["fe80::", 10], // link-local
|
|
85
|
+
["ff00::", 8] // multicast
|
|
86
|
+
])
|
|
87
|
+
blocked.addSubnet(net6, prefix, "ipv6");
|
|
88
|
+
const INTERNAL_SUFFIXES = [
|
|
89
|
+
".localhost",
|
|
90
|
+
".local",
|
|
91
|
+
".internal",
|
|
92
|
+
".intranet",
|
|
93
|
+
".lan",
|
|
94
|
+
".home.arpa",
|
|
95
|
+
".cluster.local",
|
|
96
|
+
".svc"
|
|
97
|
+
];
|
|
98
|
+
/** The IPv4 address inside an IPv4-mapped IPv6 address (::ffff:a.b.c.d or ::ffff:hhhh:hhhh). */
|
|
99
|
+
function mappedV4(ip) {
|
|
100
|
+
const m = /^::ffff:(.+)$/i.exec(ip);
|
|
101
|
+
if (!m)
|
|
102
|
+
return undefined;
|
|
103
|
+
if (node_net_1.default.isIPv4(m[1]))
|
|
104
|
+
return m[1];
|
|
105
|
+
const hex = /^([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i.exec(m[1]);
|
|
106
|
+
if (!hex)
|
|
107
|
+
return undefined;
|
|
108
|
+
const hi = parseInt(hex[1], 16);
|
|
109
|
+
const lo = parseInt(hex[2], 16);
|
|
110
|
+
return [hi >> 8, hi & 255, lo >> 8, lo & 255].join(".");
|
|
111
|
+
}
|
|
112
|
+
/** True when the address is loopback, private, link-local, ULA, CGNAT, multicast or reserved. */
|
|
113
|
+
function isPrivateAddress(ip) {
|
|
114
|
+
const bare = ip.replace(/^\[|\]$/g, "").split("%")[0];
|
|
115
|
+
const v4 = mappedV4(bare);
|
|
116
|
+
if (v4)
|
|
117
|
+
return blocked.check(v4, "ipv4");
|
|
118
|
+
if (node_net_1.default.isIPv4(bare))
|
|
119
|
+
return blocked.check(bare, "ipv4");
|
|
120
|
+
if (node_net_1.default.isIPv6(bare))
|
|
121
|
+
return blocked.check(bare, "ipv6");
|
|
122
|
+
return true; // not an address: refuse
|
|
123
|
+
}
|
|
124
|
+
function allowList(policy) {
|
|
125
|
+
var _a, _b;
|
|
126
|
+
return ((_a = policy === null || policy === void 0 ? void 0 : policy.allow) !== null && _a !== void 0 ? _a : ((_b = process.env.FONOSTER_ALLOWED_DESTINATIONS) !== null && _b !== void 0 ? _b : "").split(","))
|
|
127
|
+
.map((s) => s.trim().toLowerCase())
|
|
128
|
+
.filter(Boolean);
|
|
129
|
+
}
|
|
130
|
+
function allowedByOperator(host, ip, allow) {
|
|
131
|
+
var _a;
|
|
132
|
+
for (const entry of allow) {
|
|
133
|
+
if (entry === host)
|
|
134
|
+
return true;
|
|
135
|
+
if (!ip)
|
|
136
|
+
continue;
|
|
137
|
+
const [base, bits] = entry.split("/");
|
|
138
|
+
if (!node_net_1.default.isIP(base))
|
|
139
|
+
continue;
|
|
140
|
+
const family = node_net_1.default.isIPv4(base) ? "ipv4" : "ipv6";
|
|
141
|
+
const list = new node_net_1.default.BlockList();
|
|
142
|
+
const prefix = bits ? Number(bits) : family === "ipv4" ? 32 : 128;
|
|
143
|
+
list.addSubnet(base, prefix, family);
|
|
144
|
+
const target = (_a = mappedV4(ip)) !== null && _a !== void 0 ? _a : ip;
|
|
145
|
+
const targetFamily = node_net_1.default.isIPv4(target) ? "ipv4" : "ipv6";
|
|
146
|
+
if (targetFamily === family && list.check(target, family))
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
function checkAddress(host, ip, allow) {
|
|
152
|
+
if (isPrivateAddress(ip) && !allowedByOperator(host, ip, allow))
|
|
153
|
+
throw new UnsafeDestinationError(`destination ${host} resolves to a non-public address`);
|
|
154
|
+
}
|
|
155
|
+
function hostOf(url) {
|
|
156
|
+
return url.hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
157
|
+
}
|
|
158
|
+
/** Throws unless the URL is http(s) and its host is public, before any DNS lookup. */
|
|
159
|
+
function checkUrlShape(url, allow) {
|
|
160
|
+
if (url.protocol !== "http:" && url.protocol !== "https:")
|
|
161
|
+
throw new UnsafeDestinationError(`unsupported scheme ${url.protocol}`);
|
|
162
|
+
const host = hostOf(url);
|
|
163
|
+
if (!host)
|
|
164
|
+
throw new UnsafeDestinationError("missing host");
|
|
165
|
+
if (node_net_1.default.isIP(host)) {
|
|
166
|
+
checkAddress(host, host, allow);
|
|
167
|
+
return host;
|
|
168
|
+
}
|
|
169
|
+
if (allow.includes(host))
|
|
170
|
+
return host;
|
|
171
|
+
const name = host.replace(/\.$/, "");
|
|
172
|
+
if (!name.includes(".") ||
|
|
173
|
+
name === "localhost" ||
|
|
174
|
+
INTERNAL_SUFFIXES.some((s) => name.endsWith(s)))
|
|
175
|
+
throw new UnsafeDestinationError(`destination ${host} is an internal name`);
|
|
176
|
+
return host;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Checks a tenant-chosen URL: http/https, not an internal name, and every resolved address
|
|
180
|
+
* public (or allowed by the operator). Returns the parsed URL.
|
|
181
|
+
*/
|
|
182
|
+
function assertPublicDestination(input, policy) {
|
|
183
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
184
|
+
let url;
|
|
185
|
+
try {
|
|
186
|
+
url = new node_url_1.URL(String(input));
|
|
187
|
+
}
|
|
188
|
+
catch (_a) {
|
|
189
|
+
throw new UnsafeDestinationError("invalid URL");
|
|
190
|
+
}
|
|
191
|
+
const allow = allowList(policy);
|
|
192
|
+
const host = checkUrlShape(url, allow);
|
|
193
|
+
if (node_net_1.default.isIP(host) || allow.includes(host))
|
|
194
|
+
return url;
|
|
195
|
+
let addresses;
|
|
196
|
+
try {
|
|
197
|
+
addresses = yield node_dns_1.default.promises.lookup(host, { all: true });
|
|
198
|
+
}
|
|
199
|
+
catch (_b) {
|
|
200
|
+
throw new UnsafeDestinationError(`cannot resolve ${host}`);
|
|
201
|
+
}
|
|
202
|
+
for (const a of addresses)
|
|
203
|
+
checkAddress(host, a.address, allow);
|
|
204
|
+
return url;
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
/** Synchronous shape check (scheme, literal IPs, internal names) for request validation. */
|
|
208
|
+
function assertPublicUrlShape(input, policy) {
|
|
209
|
+
let url;
|
|
210
|
+
try {
|
|
211
|
+
url = new node_url_1.URL(String(input));
|
|
212
|
+
}
|
|
213
|
+
catch (_a) {
|
|
214
|
+
throw new UnsafeDestinationError("invalid URL");
|
|
215
|
+
}
|
|
216
|
+
checkUrlShape(url, allowList(policy));
|
|
217
|
+
return url;
|
|
218
|
+
}
|
|
219
|
+
// The connection is checked when the socket resolves the name, so a DNS answer that changes
|
|
220
|
+
// between the check and the request (rebinding) cannot reach a private address.
|
|
221
|
+
function guardedLookup(host, allow) {
|
|
222
|
+
return (hostname, options, callback) => {
|
|
223
|
+
node_dns_1.default.lookup(hostname, Object.assign(Object.assign({}, options), { all: true }), (err, addrs) => {
|
|
224
|
+
if (err)
|
|
225
|
+
return callback(err, "", 4);
|
|
226
|
+
const list = addrs;
|
|
227
|
+
try {
|
|
228
|
+
for (const a of list)
|
|
229
|
+
checkAddress(host, a.address, allow);
|
|
230
|
+
}
|
|
231
|
+
catch (e) {
|
|
232
|
+
return callback(e, "", 4);
|
|
233
|
+
}
|
|
234
|
+
if (options.all)
|
|
235
|
+
return callback(null, list);
|
|
236
|
+
callback(null, list[0].address, list[0].family);
|
|
237
|
+
});
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
/** A ws:// or wss:// URL as the http(s) URL its handshake uses. */
|
|
241
|
+
function asHttpUrl(input) {
|
|
242
|
+
return String(input).replace(/^ws(s?):/i, "http$1:");
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* For WebSocket connections to tenant-chosen URLs (session apps, listeners): checks the URL's
|
|
246
|
+
* shape (ws/wss, no internal names or private literal IPs) and returns a socket `lookup` that
|
|
247
|
+
* refuses private addresses when the name resolves. Pass it as the `lookup` option of `ws`.
|
|
248
|
+
*/
|
|
249
|
+
function publicWebSocketGuard(input, policy) {
|
|
250
|
+
if (!/^wss?:\/\//i.test(String(input)))
|
|
251
|
+
throw new UnsafeDestinationError("unsupported scheme");
|
|
252
|
+
const allow = allowList(policy);
|
|
253
|
+
const url = assertPublicUrlShape(asHttpUrl(input), { allow });
|
|
254
|
+
return { lookup: guardedLookup(hostOf(url), allow) };
|
|
255
|
+
}
|
|
256
|
+
/** Synchronous shape check of a ws:// or wss:// URL (see assertPublicUrlShape). */
|
|
257
|
+
function assertPublicWebSocketUrlShape(input, policy) {
|
|
258
|
+
if (!/^wss?:\/\//i.test(String(input)))
|
|
259
|
+
throw new UnsafeDestinationError("unsupported scheme");
|
|
260
|
+
return assertPublicUrlShape(asHttpUrl(input), policy);
|
|
261
|
+
}
|
|
262
|
+
const NO_BODY = new Set([101, 204, 205, 304]);
|
|
263
|
+
function requestOnce(url, init, method, body, signal, allow) {
|
|
264
|
+
const lookup = guardedLookup(hostOf(url), allow);
|
|
265
|
+
const lib = url.protocol === "https:" ? node_https_1.default : node_http_1.default;
|
|
266
|
+
return new Promise((resolve, reject) => {
|
|
267
|
+
var _a;
|
|
268
|
+
const req = lib.request(url, {
|
|
269
|
+
method,
|
|
270
|
+
headers: Object.assign(Object.assign({}, ((_a = init.headers) !== null && _a !== void 0 ? _a : {})), (body !== undefined
|
|
271
|
+
? { "content-length": String(Buffer.byteLength(body)) }
|
|
272
|
+
: {})),
|
|
273
|
+
lookup,
|
|
274
|
+
signal
|
|
275
|
+
}, (res) => {
|
|
276
|
+
var _a;
|
|
277
|
+
const chunks = [];
|
|
278
|
+
let size = 0;
|
|
279
|
+
const max = (_a = init.maxBytes) !== null && _a !== void 0 ? _a : 5 * 1024 * 1024;
|
|
280
|
+
res.on("data", (c) => {
|
|
281
|
+
size += c.length;
|
|
282
|
+
if (size > max) {
|
|
283
|
+
res.destroy(new UnsafeDestinationError("response too large"));
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
chunks.push(c);
|
|
287
|
+
});
|
|
288
|
+
res.on("error", reject);
|
|
289
|
+
res.on("end", () => {
|
|
290
|
+
var _a;
|
|
291
|
+
const headers = new Headers();
|
|
292
|
+
for (const [k, v] of Object.entries(res.headers)) {
|
|
293
|
+
if (v === undefined)
|
|
294
|
+
continue;
|
|
295
|
+
for (const item of Array.isArray(v) ? v : [v])
|
|
296
|
+
headers.append(k, item);
|
|
297
|
+
}
|
|
298
|
+
const status = (_a = res.statusCode) !== null && _a !== void 0 ? _a : 0;
|
|
299
|
+
resolve(new Response(NO_BODY.has(status) ? null : Buffer.concat(chunks), {
|
|
300
|
+
status: status < 200 || status > 599 ? 502 : status,
|
|
301
|
+
statusText: res.statusMessage,
|
|
302
|
+
headers
|
|
303
|
+
}));
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
req.on("error", reject);
|
|
307
|
+
if (body !== undefined)
|
|
308
|
+
req.write(body);
|
|
309
|
+
req.end();
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* fetch for tenant-chosen URLs: checks the destination (and each redirect) with
|
|
314
|
+
* assertPublicDestination, re-checks the addresses the socket connects to, and times out.
|
|
315
|
+
*/
|
|
316
|
+
function safeFetch(input_1) {
|
|
317
|
+
return __awaiter(this, arguments, void 0, function* (input, init = {}) {
|
|
318
|
+
var _a, _b, _c;
|
|
319
|
+
const allow = allowList(init.policy);
|
|
320
|
+
const timeout = AbortSignal.timeout((_a = init.timeoutMs) !== null && _a !== void 0 ? _a : 10000);
|
|
321
|
+
const signal = init.signal
|
|
322
|
+
? AbortSignal.any([init.signal, timeout])
|
|
323
|
+
: timeout;
|
|
324
|
+
let url = yield assertPublicDestination(input, { allow });
|
|
325
|
+
let method = ((_b = init.method) !== null && _b !== void 0 ? _b : "GET").toUpperCase();
|
|
326
|
+
let body = init.body;
|
|
327
|
+
const maxRedirects = (_c = init.maxRedirects) !== null && _c !== void 0 ? _c : 3;
|
|
328
|
+
for (let hop = 0;; hop++) {
|
|
329
|
+
const res = yield requestOnce(url, init, method, body, signal, allow);
|
|
330
|
+
const location = res.headers.get("location");
|
|
331
|
+
if (![301, 302, 303, 307, 308].includes(res.status) || !location)
|
|
332
|
+
return res;
|
|
333
|
+
if (hop >= maxRedirects)
|
|
334
|
+
throw new UnsafeDestinationError("too many redirects");
|
|
335
|
+
url = yield assertPublicDestination(new node_url_1.URL(location, url), { allow });
|
|
336
|
+
if (res.status === 303 || (res.status <= 302 && method === "POST")) {
|
|
337
|
+
method = "GET";
|
|
338
|
+
body = undefined;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
}
|
|
@@ -16,9 +16,4 @@
|
|
|
16
16
|
* See the License for the specific language governing permissions and
|
|
17
17
|
* limitations under the License.
|
|
18
18
|
*/
|
|
19
|
-
|
|
20
|
-
type StopSayRequest = VerbRequest;
|
|
21
|
-
type StopSayResponse = {
|
|
22
|
-
mediaSessionRef: string;
|
|
23
|
-
};
|
|
24
|
-
export { StopSayRequest, StopSayResponse };
|
|
19
|
+
export * from "./assertPublicDestination";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
/**
|
|
18
|
+
* Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
|
|
19
|
+
* http://github.com/fonoster/fonoster
|
|
20
|
+
*
|
|
21
|
+
* This file is part of Fonoster
|
|
22
|
+
*
|
|
23
|
+
* Licensed under the MIT License (the "License");
|
|
24
|
+
* you may not use this file except in compliance with
|
|
25
|
+
* the License. You may obtain a copy of the License at
|
|
26
|
+
*
|
|
27
|
+
* https://opensource.org/licenses/MIT
|
|
28
|
+
*
|
|
29
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
30
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
31
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
32
|
+
* See the License for the specific language governing permissions and
|
|
33
|
+
* limitations under the License.
|
|
34
|
+
*/
|
|
35
|
+
__exportStar(require("./assertPublicDestination"), exports);
|
|
@@ -37,7 +37,9 @@ function createSendEmail(config) {
|
|
|
37
37
|
host,
|
|
38
38
|
port,
|
|
39
39
|
secure,
|
|
40
|
-
auth
|
|
40
|
+
// Relays without authentication (e.g. a local MailHog) get no auth block;
|
|
41
|
+
// an empty one makes nodemailer fail with "Missing credentials".
|
|
42
|
+
auth: (auth === null || auth === void 0 ? void 0 : auth.user) ? auth : undefined
|
|
41
43
|
});
|
|
42
44
|
return function sendEmail(params) {
|
|
43
45
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -39,13 +39,69 @@ service Applications {
|
|
|
39
39
|
rpc EvaluateIntelligence(EvaluateIntelligenceRequest) returns (stream EvaluateIntelligenceEvent);
|
|
40
40
|
// Create an Ephemeral Agent to perform test calls to an application
|
|
41
41
|
rpc CreateTestToken(google.protobuf.Empty) returns (TestTokenResponse) {}
|
|
42
|
+
// Replace an application's signing secret; the old one stops working at once (no overlap)
|
|
43
|
+
rpc RotateSigningSecret(RotateSigningSecretRequest) returns (RotateSigningSecretResponse) {}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Speech defaults of an application; voices and models are catalog ids (provider/model-or-voice)
|
|
47
|
+
message SpeechDefaults {
|
|
48
|
+
// Default voice, e.g. elevenlabs/rachel
|
|
49
|
+
string voice = 1;
|
|
50
|
+
// Default language (BCP 47), e.g. en-US
|
|
51
|
+
string language = 2;
|
|
52
|
+
// Speech-to-text model, e.g. deepgram/nova-3 (empty: the platform default)
|
|
53
|
+
string stt_model = 3;
|
|
54
|
+
// Text-to-speech model (empty: the voice's default)
|
|
55
|
+
string tts_model = 4;
|
|
56
|
+
// Silence timeout in milliseconds (0: AppBridge default)
|
|
57
|
+
int32 silence_timeout_ms = 5;
|
|
58
|
+
// The Pacing policy's patience: low, normal or high (empty: normal)
|
|
59
|
+
string patience = 6;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Caller and agent audio format for the fonoster protocol
|
|
63
|
+
message AudioFormat {
|
|
64
|
+
// pcm16 or pcmu
|
|
65
|
+
string codec = 1;
|
|
66
|
+
// Sample rate in Hz: 8000, 16000 or 24000 (pcmu is 8000 only)
|
|
67
|
+
int32 rate = 2;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Answering-machine detection: one amd.result event per call
|
|
71
|
+
message AmdSettings {
|
|
72
|
+
// Classify the caller's first seconds of speech
|
|
73
|
+
bool enabled = 1;
|
|
74
|
+
// How much caller speech to classify, in milliseconds (0: 4000; 500 to 15000)
|
|
75
|
+
int32 window_ms = 2;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// A listen-only socket dialed for every session of the app
|
|
79
|
+
message Listener {
|
|
80
|
+
// ws:// or wss:// address
|
|
81
|
+
string url = 1;
|
|
82
|
+
// inbound, outbound or both
|
|
83
|
+
string tracks = 2;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
message RotateSigningSecretRequest {
|
|
87
|
+
// The reference to the application
|
|
88
|
+
string ref = 1;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
message RotateSigningSecretResponse {
|
|
92
|
+
// The reference to the application
|
|
93
|
+
string ref = 1;
|
|
94
|
+
// The new secret; shown only in this response
|
|
95
|
+
string signing_secret = 2;
|
|
96
|
+
// The last characters of the secret
|
|
97
|
+
string signing_secret_hint = 3;
|
|
42
98
|
}
|
|
43
99
|
|
|
44
100
|
// The type of application
|
|
45
101
|
enum ApplicationType {
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
//
|
|
102
|
+
// A stream: your own WebSocket server
|
|
103
|
+
STREAM = 0;
|
|
104
|
+
// An Autopilot agent (hosted by Fonoster)
|
|
49
105
|
AUTOPILOT = 1;
|
|
50
106
|
}
|
|
51
107
|
|
|
@@ -58,6 +114,14 @@ message ProductContainer {
|
|
|
58
114
|
google.protobuf.Struct credentials = 3;
|
|
59
115
|
}
|
|
60
116
|
|
|
117
|
+
// An audio filter run on the caller's audio before speech recognition
|
|
118
|
+
message AudioFilter {
|
|
119
|
+
// Filter name (aiCoustics)
|
|
120
|
+
string name = 1;
|
|
121
|
+
// The filter's public options (model, enhancement_level, bypass)
|
|
122
|
+
google.protobuf.Struct options = 2;
|
|
123
|
+
}
|
|
124
|
+
|
|
61
125
|
// Application definition
|
|
62
126
|
message Application {
|
|
63
127
|
// Reference to the application
|
|
@@ -78,6 +142,28 @@ message Application {
|
|
|
78
142
|
int32 created_at = 8;
|
|
79
143
|
// Update time
|
|
80
144
|
int32 updated_at = 9;
|
|
145
|
+
// The WebSocket URL AppBridge dials
|
|
146
|
+
string url = 10;
|
|
147
|
+
// Stream protocol: fonoster or twilio
|
|
148
|
+
string protocol = 11;
|
|
149
|
+
// The last characters of the signing secret (the secret is never returned on reads)
|
|
150
|
+
string signing_secret_hint = 12;
|
|
151
|
+
// Speech defaults
|
|
152
|
+
SpeechDefaults speech = 13;
|
|
153
|
+
// Audio format (fonoster protocol)
|
|
154
|
+
AudioFormat audio = 14;
|
|
155
|
+
// App used when this one cannot be reached
|
|
156
|
+
string fallback_app_ref = 15;
|
|
157
|
+
// Message spoken when neither the app nor its fallback can be reached
|
|
158
|
+
string fallback_message = 16;
|
|
159
|
+
// Listen-only sockets
|
|
160
|
+
repeated Listener listeners = 17;
|
|
161
|
+
// Recording policy: off, on or consent (empty: the workspace's)
|
|
162
|
+
string recording = 18;
|
|
163
|
+
// Answering-machine detection (off when unset)
|
|
164
|
+
AmdSettings amd = 19;
|
|
165
|
+
// Audio filters in order (empty: none)
|
|
166
|
+
repeated AudioFilter filters = 20;
|
|
81
167
|
}
|
|
82
168
|
|
|
83
169
|
// Request to create a new application
|
|
@@ -94,12 +180,36 @@ message CreateApplicationRequest {
|
|
|
94
180
|
ProductContainer speech_to_text = 5;
|
|
95
181
|
// Inference engine
|
|
96
182
|
ProductContainer intelligence = 6;
|
|
183
|
+
// The WebSocket URL (Autopilot agents default to the hosted Autopilot)
|
|
184
|
+
string url = 7;
|
|
185
|
+
// fonoster or twilio (default fonoster)
|
|
186
|
+
string protocol = 8;
|
|
187
|
+
// Speech defaults
|
|
188
|
+
SpeechDefaults speech = 9;
|
|
189
|
+
// Audio format (fonoster protocol)
|
|
190
|
+
AudioFormat audio = 10;
|
|
191
|
+
// App used when this one cannot be reached
|
|
192
|
+
string fallback_app_ref = 11;
|
|
193
|
+
// Message spoken when neither the app nor its fallback can be reached
|
|
194
|
+
string fallback_message = 12;
|
|
195
|
+
// Listen-only sockets
|
|
196
|
+
repeated Listener listeners = 13;
|
|
197
|
+
// Recording policy: off, on or consent (empty: the workspace's)
|
|
198
|
+
string recording = 14;
|
|
199
|
+
// Answering-machine detection (off when unset)
|
|
200
|
+
AmdSettings amd = 15;
|
|
201
|
+
// Audio filters in order (empty: none)
|
|
202
|
+
repeated AudioFilter filters = 20;
|
|
97
203
|
}
|
|
98
204
|
|
|
99
205
|
// Response for create application
|
|
100
206
|
message CreateApplicationResponse {
|
|
101
207
|
// Echo the reference of the application
|
|
102
208
|
string ref = 1;
|
|
209
|
+
// The app's signing secret; shown only in this response
|
|
210
|
+
string signing_secret = 2;
|
|
211
|
+
// The last characters of the secret
|
|
212
|
+
string signing_secret_hint = 3;
|
|
103
213
|
}
|
|
104
214
|
|
|
105
215
|
// Request to get an application
|
|
@@ -140,12 +250,37 @@ message UpdateApplicationRequest {
|
|
|
140
250
|
ProductContainer speech_to_text = 6;
|
|
141
251
|
// Intelligence product
|
|
142
252
|
ProductContainer intelligence = 7;
|
|
253
|
+
// The WebSocket URL (Autopilot agents default to the hosted Autopilot)
|
|
254
|
+
string url = 8;
|
|
255
|
+
// fonoster or twilio (default fonoster)
|
|
256
|
+
string protocol = 9;
|
|
257
|
+
// Speech defaults
|
|
258
|
+
SpeechDefaults speech = 10;
|
|
259
|
+
// Audio format (fonoster protocol)
|
|
260
|
+
AudioFormat audio = 11;
|
|
261
|
+
// App used when this one cannot be reached
|
|
262
|
+
string fallback_app_ref = 12;
|
|
263
|
+
// Message spoken when neither the app nor its fallback can be reached
|
|
264
|
+
string fallback_message = 13;
|
|
265
|
+
// Listen-only sockets
|
|
266
|
+
repeated Listener listeners = 14;
|
|
267
|
+
// Recording policy: off, on or consent (empty: the workspace's)
|
|
268
|
+
string recording = 15;
|
|
269
|
+
// Answering-machine detection (off when unset)
|
|
270
|
+
AmdSettings amd = 16;
|
|
271
|
+
// Audio filters in order (the update replaces the app: left out clears them)
|
|
272
|
+
repeated AudioFilter filters = 20;
|
|
143
273
|
}
|
|
144
274
|
|
|
145
275
|
// Response for update application
|
|
146
276
|
message UpdateApplicationResponse {
|
|
147
277
|
// Echo the reference of the application
|
|
148
278
|
string ref = 1;
|
|
279
|
+
// A new signing secret when the update generated one (the app stopped being an Autopilot
|
|
280
|
+
// app); shown only in this response. Empty otherwise.
|
|
281
|
+
string signing_secret = 2;
|
|
282
|
+
// The last characters of the new secret (empty when there is none)
|
|
283
|
+
string signing_secret_hint = 3;
|
|
149
284
|
}
|
|
150
285
|
|
|
151
286
|
// Request to delete an application
|