@fonoster/common 0.27.0 → 0.30.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.
Files changed (176) hide show
  1. package/dist/assistants/index.d.ts +2 -6
  2. package/dist/assistants/index.js +2 -6
  3. package/dist/assistants/sessionAssistantSchema.d.ts +741 -0
  4. package/dist/assistants/sessionAssistantSchema.js +112 -0
  5. package/dist/assistants/testCasesSchema.d.ts +4 -4
  6. package/dist/{voice/Dial.d.ts → calls/index.d.ts} +16 -13
  7. package/dist/calls/index.js +44 -0
  8. package/dist/cellsecrets/index.d.ts +91 -0
  9. package/dist/cellsecrets/index.js +299 -0
  10. package/dist/config/cli/check.d.ts +6 -0
  11. package/dist/config/cli/check.js +202 -0
  12. package/dist/config/cli/envFile.d.ts +23 -0
  13. package/dist/config/cli/envFile.js +81 -0
  14. package/dist/config/cli/exposure.d.ts +10 -0
  15. package/dist/config/cli/exposure.js +93 -0
  16. package/dist/config/cli/index.d.ts +2 -0
  17. package/dist/{identity/tokenHasAccessKeyId.js → config/cli/index.js} +7 -8
  18. package/dist/config/cli/info.d.ts +6 -0
  19. package/dist/config/cli/info.js +62 -0
  20. package/dist/config/cli/init.d.ts +9 -0
  21. package/dist/config/cli/init.js +152 -0
  22. package/dist/config/cli/main.d.ts +11 -0
  23. package/dist/config/cli/main.js +155 -0
  24. package/dist/config/cli/render.d.ts +44 -0
  25. package/dist/config/cli/render.js +129 -0
  26. package/dist/config/cli/secrets.d.ts +21 -0
  27. package/dist/config/cli/secrets.js +117 -0
  28. package/dist/{utils/findIntegrationsCredentials.d.ts → config/cli/types.d.ts} +6 -5
  29. package/dist/config/cli/types.js +7 -0
  30. package/dist/config/configHints.d.ts +39 -0
  31. package/dist/config/configHints.js +61 -0
  32. package/dist/{voice → config}/index.d.ts +12 -13
  33. package/dist/config/index.js +46 -0
  34. package/dist/config/integrationsSchema.d.ts +32 -0
  35. package/dist/config/integrationsSchema.js +56 -0
  36. package/dist/config/interpolateEnv.d.ts +34 -0
  37. package/dist/config/interpolateEnv.js +70 -0
  38. package/dist/config/loadServiceConfig.d.ts +33 -0
  39. package/dist/config/loadServiceConfig.js +121 -0
  40. package/dist/config/logsSchema.d.ts +76 -0
  41. package/dist/config/logsSchema.js +49 -0
  42. package/dist/config/natsConnection.d.ts +53 -0
  43. package/dist/config/natsConnection.js +58 -0
  44. package/dist/config/parseConfigFile.d.ts +7 -0
  45. package/dist/config/parseConfigFile.js +60 -0
  46. package/dist/config/resolveConfigFile.d.ts +17 -0
  47. package/dist/config/resolveConfigFile.js +54 -0
  48. package/dist/config/resolveSecretRefs.d.ts +35 -0
  49. package/dist/config/resolveSecretRefs.js +129 -0
  50. package/dist/{assistants/audioFiltersSchema.d.ts → config/strictDeep.d.ts} +9 -12
  51. package/dist/config/strictDeep.js +58 -0
  52. package/dist/config/telemetrySchema.d.ts +39 -0
  53. package/dist/config/telemetrySchema.js +44 -0
  54. package/dist/config/toJsonSchema.d.ts +30 -0
  55. package/dist/config/toJsonSchema.js +161 -0
  56. package/dist/constants.d.ts +1 -4
  57. package/dist/constants.js +4 -5
  58. package/dist/envs.d.ts +2 -1
  59. package/dist/envs.js +13 -11
  60. package/dist/identity/createAuthInterceptor.d.ts +9 -2
  61. package/dist/identity/createAuthInterceptor.js +36 -30
  62. package/dist/identity/hasAccess.d.ts +9 -3
  63. package/dist/identity/hasAccess.js +32 -8
  64. package/dist/identity/index.d.ts +1 -0
  65. package/dist/identity/index.js +1 -0
  66. package/dist/identity/isValidToken.d.ts +12 -2
  67. package/dist/identity/isValidToken.js +25 -9
  68. package/dist/identity/roles.js +22 -6
  69. package/dist/identity/types.d.ts +6 -1
  70. package/dist/identity/types.js +1 -0
  71. package/dist/{assistants/LanguageModelProvider.js → identity/verifyAccessToken.d.ts} +10 -11
  72. package/dist/identity/verifyAccessToken.js +44 -0
  73. package/dist/index.d.ts +11 -1
  74. package/dist/index.js +14 -2
  75. package/dist/net/assertPublicDestination.d.ts +52 -0
  76. package/dist/net/assertPublicDestination.js +342 -0
  77. package/dist/{voice/PlayDtmf.d.ts → net/index.d.ts} +1 -5
  78. package/dist/{voice → net}/index.js +1 -13
  79. package/dist/notifications/createSendEmail.js +3 -1
  80. package/dist/protos/applications.proto +124 -3
  81. package/dist/protos/authz.proto +23 -4
  82. package/dist/protos/capabilities.proto +94 -0
  83. package/dist/protos/identity.proto +26 -1
  84. package/dist/protos/providers.proto +135 -0
  85. package/dist/protos/webhooks.proto +140 -0
  86. package/dist/{voice/StopSay.d.ts → regions/hub/index.d.ts} +1 -6
  87. package/dist/regions/hub/index.js +35 -0
  88. package/dist/regions/hub/natsJwt.d.ts +63 -0
  89. package/dist/regions/hub/natsJwt.js +195 -0
  90. package/dist/registry/Registry.d.ts +79 -0
  91. package/dist/registry/Registry.js +418 -0
  92. package/dist/registry/cli.d.ts +20 -0
  93. package/dist/registry/cli.js +424 -0
  94. package/dist/{assistants/audioFiltersSchema.js → registry/features.d.ts} +13 -14
  95. package/dist/registry/features.js +36 -0
  96. package/dist/{assistants/LanguageModelProvider.d.ts → registry/index.d.ts} +6 -8
  97. package/dist/registry/index.js +40 -0
  98. package/dist/registry/prisma.d.ts +67 -0
  99. package/dist/registry/prisma.js +391 -0
  100. package/dist/registry/stores.d.ts +21 -0
  101. package/dist/{assistants/eventsHookSchema.js → registry/stores.js} +55 -18
  102. package/dist/registry/types.d.ts +98 -0
  103. package/dist/{voice/Say.d.ts → registry/types.js} +4 -10
  104. package/dist/registry/workspaceKeys.d.ts +41 -0
  105. package/dist/registry/workspaceKeys.js +64 -0
  106. package/dist/session/index.d.ts +19 -0
  107. package/dist/session/index.js +35 -0
  108. package/dist/session/schema.d.ts +1951 -0
  109. package/dist/session/schema.js +397 -0
  110. package/dist/sessions/index.d.ts +93 -0
  111. package/dist/sessions/index.js +194 -0
  112. package/dist/telemetry.d.ts +76 -0
  113. package/dist/telemetry.js +360 -0
  114. package/dist/types.d.ts +3 -5
  115. package/dist/utils/{findIntegrationsCredentials.js → WriteBehind.d.ts} +13 -10
  116. package/dist/utils/WriteBehind.js +64 -0
  117. package/dist/utils/index.d.ts +1 -1
  118. package/dist/utils/index.js +1 -1
  119. package/dist/{voice/Play.d.ts → utils/logUnhandledRejections.d.ts} +8 -12
  120. package/dist/utils/logUnhandledRejections.js +37 -0
  121. package/dist/validators/calls.d.ts +2 -2
  122. package/dist/validators/calls.js +5 -2
  123. package/dist/validators/identity.d.ts +37 -8
  124. package/dist/validators/identity.js +22 -3
  125. package/dist/validators/index.d.ts +1 -0
  126. package/dist/validators/index.js +1 -0
  127. package/dist/validators/sip.d.ts +40 -0
  128. package/dist/validators/sip.js +99 -0
  129. package/dist/validators/sipnet/credentials.d.ts +2 -2
  130. package/dist/validators/sipnet/domains.js +7 -7
  131. package/dist/validators/sipnet/trunks.d.ts +14 -14
  132. package/dist/validators/sipnet/trunks.js +4 -2
  133. package/dist/webhooks/Dispatcher.d.ts +87 -0
  134. package/dist/webhooks/Dispatcher.js +225 -0
  135. package/dist/webhooks/bus.d.ts +49 -0
  136. package/dist/webhooks/bus.js +170 -0
  137. package/dist/webhooks/events.d.ts +66 -0
  138. package/dist/webhooks/events.js +62 -0
  139. package/dist/webhooks/index.d.ts +23 -0
  140. package/dist/webhooks/index.js +39 -0
  141. package/dist/webhooks/prisma.d.ts +55 -0
  142. package/dist/webhooks/prisma.js +242 -0
  143. package/dist/webhooks/signing.d.ts +8 -0
  144. package/dist/webhooks/signing.js +53 -0
  145. package/package.json +25 -12
  146. package/schema/session.v1.json +791 -0
  147. package/dist/assistants/assistantSchema.d.ts +0 -739
  148. package/dist/assistants/assistantSchema.js +0 -37
  149. package/dist/assistants/conversationSettingsSchema.d.ts +0 -122
  150. package/dist/assistants/conversationSettingsSchema.js +0 -133
  151. package/dist/assistants/eventsHookSchema.d.ts +0 -38
  152. package/dist/assistants/languageModelConfigSchema.d.ts +0 -206
  153. package/dist/assistants/languageModelConfigSchema.js +0 -91
  154. package/dist/identity/tokenHasAccessKeyId.d.ts +0 -2
  155. package/dist/protos/voice.proto +0 -557
  156. package/dist/voice/Dial.js +0 -20
  157. package/dist/voice/Gather.d.ts +0 -37
  158. package/dist/voice/Gather.js +0 -9
  159. package/dist/voice/Mute.d.ts +0 -31
  160. package/dist/voice/Mute.js +0 -9
  161. package/dist/voice/Play.js +0 -2
  162. package/dist/voice/PlayDtmf.js +0 -2
  163. package/dist/voice/PlaybackControl.d.ts +0 -31
  164. package/dist/voice/PlaybackControl.js +0 -11
  165. package/dist/voice/Record.d.ts +0 -36
  166. package/dist/voice/Record.js +0 -7
  167. package/dist/voice/Say.js +0 -2
  168. package/dist/voice/StopSay.js +0 -2
  169. package/dist/voice/Stream.d.ts +0 -53
  170. package/dist/voice/Stream.js +0 -19
  171. package/dist/voice/StreamGather.d.ts +0 -34
  172. package/dist/voice/StreamGather.js +0 -9
  173. package/dist/voice/Verb.d.ts +0 -27
  174. package/dist/voice/Verb.js +0 -2
  175. package/dist/voice/voice.d.ts +0 -171
  176. package/dist/voice/voice.js +0 -65
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
3
+ * http://github.com/fonoster/fonoster
4
+ *
5
+ * This file is part of Fonoster
6
+ *
7
+ * Licensed under the MIT License (the "License");
8
+ * you may not use this file except in compliance with
9
+ * the License. You may obtain a copy of the License at
10
+ *
11
+ * https://opensource.org/licenses/MIT
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ */
19
+ /**
20
+ * OpenTelemetry bootstrap shared by the TypeScript services (add-platform, observability).
21
+ *
22
+ * Driven by the standard OTEL_* variables and a complete no-op when no OTLP endpoint is set:
23
+ * nothing is loaded, nothing is sent, and the service only writes its normal logs. Signals go
24
+ * over OTLP/HTTP with JSON bodies (collector port 4318) using only `@opentelemetry/api`,
25
+ * `sdk-trace-base`, `sdk-trace-node` and `resources`, so no exporter package is needed.
26
+ *
27
+ * Every call-scoped span, log record and metric carries `fonoster.call_ref`.
28
+ */
29
+ export declare const CALL_REF_ATTR = "fonoster.call_ref";
30
+ type Attrs = Record<string, string | number | boolean>;
31
+ export interface CallSpan {
32
+ /** Adds a timeline event to the call's span. */
33
+ event(name: string, attrs?: Attrs): void;
34
+ /** Ends the span; `error` marks it failed. */
35
+ end(attrs?: Attrs, error?: string): void;
36
+ }
37
+ /** A span not tied to a call (a gRPC request, a registry command), optionally continuing a trace. */
38
+ export interface Span extends CallSpan {
39
+ /** The W3C `traceparent` of this span, to send with outgoing messages ("" when disabled). */
40
+ traceparent: string;
41
+ }
42
+ /** NATS/gRPC header carrying the W3C trace context between services. */
43
+ export declare const TRACEPARENT_HEADER = "traceparent";
44
+ export interface Telemetry {
45
+ enabled: boolean;
46
+ /**
47
+ * Starts the span of one call; the returned handle is a no-op when disabled. `parent` (a W3C
48
+ * traceparent from another service, e.g. the media node) makes it a child in that trace.
49
+ */
50
+ startCall(callRef: string, name: string, attrs?: Attrs, parent?: string): CallSpan;
51
+ /**
52
+ * Starts a span; with `parent` (a W3C traceparent received from another service) it joins that
53
+ * trace. A no-op handle when disabled.
54
+ */
55
+ startSpan(name: string, attrs?: Attrs, parent?: string): Span;
56
+ /** The W3C traceparent of a call's span (to propagate over NATS), when one is active. */
57
+ traceparent(callRef: string): string | undefined;
58
+ /** An OTLP log record correlated by call ref (and the active trace, when any). */
59
+ log(level: "debug" | "info" | "warn" | "error", message: string, attrs?: Attrs & {
60
+ callRef?: string;
61
+ }): void;
62
+ /** Adds to a monotonic counter. */
63
+ count(name: string, value?: number, attrs?: Attrs): void;
64
+ /** Reads `fn` at every export and reports it as a gauge. */
65
+ gauge(name: string, fn: () => number, attrs?: Attrs): void;
66
+ /** Flushes and stops the exporters. */
67
+ shutdown(): Promise<void>;
68
+ }
69
+ /** True when any OTLP endpoint is configured and the SDK is not disabled. */
70
+ export declare function telemetryEnabled(env?: NodeJS.ProcessEnv): boolean;
71
+ /**
72
+ * Starts telemetry for one service. Safe to call once at startup; returns a no-op handle when no
73
+ * OTLP endpoint is configured or the OpenTelemetry packages are not installed.
74
+ */
75
+ export declare function initTelemetry(service: string, instanceId?: string, env?: Record<string, string | undefined>): Telemetry;
76
+ export {};
@@ -0,0 +1,360 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
4
+ * http://github.com/fonoster/fonoster
5
+ *
6
+ * This file is part of Fonoster
7
+ *
8
+ * Licensed under the MIT License (the "License");
9
+ * you may not use this file except in compliance with
10
+ * the License. You may obtain a copy of the License at
11
+ *
12
+ * https://opensource.org/licenses/MIT
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ */
20
+ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-require-imports */
21
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
22
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
23
+ return new (P || (P = Promise))(function (resolve, reject) {
24
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
25
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
26
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
27
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
28
+ });
29
+ };
30
+ var __rest = (this && this.__rest) || function (s, e) {
31
+ var t = {};
32
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
33
+ t[p] = s[p];
34
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
35
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
36
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
37
+ t[p[i]] = s[p[i]];
38
+ }
39
+ return t;
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.TRACEPARENT_HEADER = exports.CALL_REF_ATTR = void 0;
43
+ exports.telemetryEnabled = telemetryEnabled;
44
+ exports.initTelemetry = initTelemetry;
45
+ /**
46
+ * OpenTelemetry bootstrap shared by the TypeScript services (add-platform, observability).
47
+ *
48
+ * Driven by the standard OTEL_* variables and a complete no-op when no OTLP endpoint is set:
49
+ * nothing is loaded, nothing is sent, and the service only writes its normal logs. Signals go
50
+ * over OTLP/HTTP with JSON bodies (collector port 4318) using only `@opentelemetry/api`,
51
+ * `sdk-trace-base`, `sdk-trace-node` and `resources`, so no exporter package is needed.
52
+ *
53
+ * Every call-scoped span, log record and metric carries `fonoster.call_ref`.
54
+ */
55
+ exports.CALL_REF_ATTR = "fonoster.call_ref";
56
+ /** NATS/gRPC header carrying the W3C trace context between services. */
57
+ exports.TRACEPARENT_HEADER = "traceparent";
58
+ const NOOP_SPAN = {
59
+ event: () => undefined,
60
+ end: () => undefined,
61
+ traceparent: ""
62
+ };
63
+ const NOOP = {
64
+ enabled: false,
65
+ startCall: () => NOOP_SPAN,
66
+ startSpan: () => NOOP_SPAN,
67
+ traceparent: () => undefined,
68
+ log: () => undefined,
69
+ count: () => undefined,
70
+ gauge: () => undefined,
71
+ shutdown: () => __awaiter(void 0, void 0, void 0, function* () { return undefined; })
72
+ };
73
+ /** True when any OTLP endpoint is configured and the SDK is not disabled. */
74
+ function telemetryEnabled(env = process.env) {
75
+ if (env.OTEL_SDK_DISABLED === "true")
76
+ return false;
77
+ return [
78
+ "OTEL_EXPORTER_OTLP_ENDPOINT",
79
+ "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT",
80
+ "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT",
81
+ "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT"
82
+ ].some((k) => !!env[k]);
83
+ }
84
+ function toValue(v) {
85
+ if (typeof v === "number")
86
+ return Number.isInteger(v) ? { intValue: String(v) } : { doubleValue: v };
87
+ if (typeof v === "boolean")
88
+ return { boolValue: v };
89
+ return { stringValue: String(v) };
90
+ }
91
+ function toAttrs(a = {}) {
92
+ return Object.entries(a)
93
+ .filter(([, v]) => v !== undefined && v !== null)
94
+ .map(([key, value]) => ({ key, value: toValue(value) }));
95
+ }
96
+ const hrToNano = (t) => (BigInt(t[0]) * BigInt(1000000000) + BigInt(t[1])).toString();
97
+ function signalUrl(env, signal) {
98
+ const specific = env[`OTEL_EXPORTER_OTLP_${signal.toUpperCase()}_ENDPOINT`];
99
+ if (specific)
100
+ return specific;
101
+ const base = env.OTEL_EXPORTER_OTLP_ENDPOINT;
102
+ return base ? `${base.replace(/\/$/, "")}/v1/${signal}` : undefined;
103
+ }
104
+ function headers(env) {
105
+ var _a;
106
+ const h = { "content-type": "application/json" };
107
+ for (const pair of ((_a = env.OTEL_EXPORTER_OTLP_HEADERS) !== null && _a !== void 0 ? _a : "")
108
+ .split(",")
109
+ .filter(Boolean)) {
110
+ const i = pair.indexOf("=");
111
+ if (i > 0)
112
+ h[pair.slice(0, i).trim()] = pair.slice(i + 1).trim();
113
+ }
114
+ return h;
115
+ }
116
+ /**
117
+ * Starts telemetry for one service. Safe to call once at startup; returns a no-op handle when no
118
+ * OTLP endpoint is configured or the OpenTelemetry packages are not installed.
119
+ */
120
+ function initTelemetry(service, instanceId, env) {
121
+ var _a, _b, _c;
122
+ if (instanceId === void 0) { instanceId = (_a = process.env.HOSTNAME) !== null && _a !== void 0 ? _a : String(process.pid); }
123
+ if (env === void 0) { env = process.env; }
124
+ if (!telemetryEnabled(env))
125
+ return NOOP;
126
+ let api, base, nodeSdk, resources;
127
+ try {
128
+ api = require("@opentelemetry/api");
129
+ base = require("@opentelemetry/sdk-trace-base");
130
+ nodeSdk = require("@opentelemetry/sdk-trace-node");
131
+ resources = require("@opentelemetry/resources");
132
+ }
133
+ catch (_d) {
134
+ return NOOP;
135
+ }
136
+ const resourceAttrs = {
137
+ "service.name": (_b = env.OTEL_SERVICE_NAME) !== null && _b !== void 0 ? _b : service,
138
+ "service.instance.id": instanceId
139
+ };
140
+ const resource = { attributes: toAttrs(resourceAttrs) };
141
+ const hdrs = headers(env);
142
+ const post = (url, body) => {
143
+ if (!url)
144
+ return Promise.resolve();
145
+ return fetch(url, {
146
+ method: "POST",
147
+ headers: hdrs,
148
+ body: JSON.stringify(body)
149
+ })
150
+ .then(() => undefined)
151
+ .catch(() => undefined);
152
+ };
153
+ // Traces
154
+ const tracesUrl = signalUrl(env, "traces");
155
+ const exporter = {
156
+ export(spans, done) {
157
+ const body = {
158
+ resourceSpans: [
159
+ {
160
+ resource,
161
+ scopeSpans: [
162
+ {
163
+ scope: { name: "fonoster" },
164
+ spans: spans.map((s) => {
165
+ var _a, _b;
166
+ return ({
167
+ traceId: s.spanContext().traceId,
168
+ spanId: s.spanContext().spanId,
169
+ parentSpanId: ((_a = s.parentSpanContext) === null || _a === void 0 ? void 0 : _a.spanId) || undefined,
170
+ name: s.name,
171
+ kind: 1 + ((_b = s.kind) !== null && _b !== void 0 ? _b : 0),
172
+ startTimeUnixNano: hrToNano(s.startTime),
173
+ endTimeUnixNano: hrToNano(s.endTime),
174
+ attributes: toAttrs(s.attributes),
175
+ events: s.events.map((e) => ({
176
+ name: e.name,
177
+ timeUnixNano: hrToNano(e.time),
178
+ attributes: toAttrs(e.attributes)
179
+ })),
180
+ status: s.status.code === 2
181
+ ? { code: 2, message: s.status.message }
182
+ : { code: s.status.code }
183
+ });
184
+ })
185
+ }
186
+ ]
187
+ }
188
+ ]
189
+ };
190
+ void post(tracesUrl, body).then(() => done({ code: 0 }));
191
+ },
192
+ shutdown: () => __awaiter(this, void 0, void 0, function* () { return undefined; })
193
+ };
194
+ const provider = new nodeSdk.NodeTracerProvider({
195
+ resource: resources.resourceFromAttributes(resourceAttrs),
196
+ spanProcessors: [new base.BatchSpanProcessor(exporter)]
197
+ });
198
+ provider.register();
199
+ // The provider's own tracer: the global one stays the first registered (tests init twice).
200
+ const tracer = provider.getTracer("fonoster");
201
+ // Logs
202
+ const logsUrl = signalUrl(env, "logs");
203
+ const logQueue = [];
204
+ const severity = { debug: 5, info: 9, warn: 13, error: 17 };
205
+ const flushLogs = () => {
206
+ if (!logQueue.length)
207
+ return Promise.resolve();
208
+ const records = logQueue.splice(0);
209
+ return post(logsUrl, {
210
+ resourceLogs: [
211
+ {
212
+ resource,
213
+ scopeLogs: [{ scope: { name: "fonoster" }, logRecords: records }]
214
+ }
215
+ ]
216
+ });
217
+ };
218
+ // Metrics
219
+ const metricsUrl = signalUrl(env, "metrics");
220
+ const startNs = (BigInt(Date.now()) * BigInt(1000000)).toString();
221
+ const counters = new Map();
222
+ const gauges = [];
223
+ const flushMetrics = () => {
224
+ const now = (BigInt(Date.now()) * BigInt(1000000)).toString();
225
+ const metrics = [];
226
+ for (const [name, series] of counters) {
227
+ metrics.push({
228
+ name,
229
+ sum: {
230
+ aggregationTemporality: 2,
231
+ isMonotonic: true,
232
+ dataPoints: series.map((s) => ({
233
+ asInt: String(s.value),
234
+ startTimeUnixNano: startNs,
235
+ timeUnixNano: now,
236
+ attributes: toAttrs(s.attrs)
237
+ }))
238
+ }
239
+ });
240
+ }
241
+ for (const g of gauges) {
242
+ let v = 0;
243
+ try {
244
+ v = g.fn();
245
+ }
246
+ catch (_a) {
247
+ continue;
248
+ }
249
+ metrics.push({
250
+ name: g.name,
251
+ gauge: {
252
+ dataPoints: [
253
+ { asDouble: v, timeUnixNano: now, attributes: toAttrs(g.attrs) }
254
+ ]
255
+ }
256
+ });
257
+ }
258
+ if (!metrics.length)
259
+ return Promise.resolve();
260
+ return post(metricsUrl, {
261
+ resourceMetrics: [
262
+ {
263
+ resource,
264
+ scopeMetrics: [{ scope: { name: "fonoster" }, metrics }]
265
+ }
266
+ ]
267
+ });
268
+ };
269
+ const timer = setInterval(() => {
270
+ void flushLogs();
271
+ void flushMetrics();
272
+ }, Number((_c = env.OTEL_METRIC_EXPORT_INTERVAL) !== null && _c !== void 0 ? _c : 15000));
273
+ timer.unref();
274
+ const spanOf = new Map();
275
+ const contextOf = (parent) => parent
276
+ ? api.propagation.extract(api.context.active(), {
277
+ [exports.TRACEPARENT_HEADER]: parent
278
+ })
279
+ : api.context.active();
280
+ const traceparentOf = (span) => {
281
+ var _a;
282
+ const carrier = {};
283
+ api.propagation.inject(api.trace.setSpan(api.context.active(), span), carrier);
284
+ return (_a = carrier[exports.TRACEPARENT_HEADER]) !== null && _a !== void 0 ? _a : "";
285
+ };
286
+ return {
287
+ enabled: true,
288
+ startSpan(name, attrs, parent) {
289
+ const span = tracer.startSpan(name, { attributes: attrs }, contextOf(parent));
290
+ return {
291
+ traceparent: traceparentOf(span),
292
+ event: (n, a) => span.addEvent(n, a),
293
+ end: (a, error) => {
294
+ if (a)
295
+ span.setAttributes(a);
296
+ if (error)
297
+ span.setStatus({ code: 2, message: error });
298
+ span.end();
299
+ }
300
+ };
301
+ },
302
+ traceparent(callRef) {
303
+ const span = spanOf.get(callRef);
304
+ return span ? traceparentOf(span) : undefined;
305
+ },
306
+ startCall(callRef, name, attrs, parent) {
307
+ const span = tracer.startSpan(name, { attributes: Object.assign({ [exports.CALL_REF_ATTR]: callRef }, attrs) }, contextOf(parent));
308
+ spanOf.set(callRef, span);
309
+ return {
310
+ event: (n, a) => span.addEvent(n, Object.assign({ [exports.CALL_REF_ATTR]: callRef }, a)),
311
+ end: (a, error) => {
312
+ if (a)
313
+ span.setAttributes(a);
314
+ if (error)
315
+ span.setStatus({ code: 2, message: error });
316
+ span.end();
317
+ spanOf.delete(callRef);
318
+ }
319
+ };
320
+ },
321
+ log(level, message, attrs = {}) {
322
+ var _a, _b, _c;
323
+ const { callRef } = attrs, rest = __rest(attrs, ["callRef"]);
324
+ const span = callRef ? spanOf.get(callRef) : undefined;
325
+ const ctx = (_b = (_a = span === null || span === void 0 ? void 0 : span.spanContext) === null || _a === void 0 ? void 0 : _a.call(span)) !== null && _b !== void 0 ? _b : (_c = api.trace.getActiveSpan()) === null || _c === void 0 ? void 0 : _c.spanContext();
326
+ logQueue.push({
327
+ timeUnixNano: (BigInt(Date.now()) * BigInt(1000000)).toString(),
328
+ severityNumber: severity[level],
329
+ severityText: level.toUpperCase(),
330
+ body: { stringValue: message },
331
+ attributes: toAttrs(callRef ? Object.assign({ [exports.CALL_REF_ATTR]: callRef }, rest) : rest),
332
+ traceId: ctx === null || ctx === void 0 ? void 0 : ctx.traceId,
333
+ spanId: ctx === null || ctx === void 0 ? void 0 : ctx.spanId
334
+ });
335
+ if (logQueue.length >= 100)
336
+ void flushLogs();
337
+ },
338
+ count(name, value = 1, attrs = {}) {
339
+ var _a;
340
+ const series = (_a = counters.get(name)) !== null && _a !== void 0 ? _a : [];
341
+ const key = JSON.stringify(attrs);
342
+ const hit = series.find((s) => JSON.stringify(s.attrs) === key);
343
+ if (hit)
344
+ hit.value += value;
345
+ else
346
+ series.push({ attrs, value });
347
+ counters.set(name, series);
348
+ },
349
+ gauge(name, fn, attrs) {
350
+ gauges.push({ name, fn, attrs });
351
+ },
352
+ shutdown() {
353
+ return __awaiter(this, void 0, void 0, function* () {
354
+ clearInterval(timer);
355
+ yield provider.shutdown().catch(() => undefined);
356
+ yield Promise.all([flushLogs(), flushMetrics()]);
357
+ });
358
+ }
359
+ };
360
+ }
package/dist/types.d.ts CHANGED
@@ -19,9 +19,7 @@
19
19
  type NumberPreconditionsCheck = (request: {
20
20
  appRef?: string;
21
21
  agentAor?: string;
22
+ /** The caller's workspace: an appRef must belong to it (RV-B4). */
23
+ accessKeyId?: string;
22
24
  }) => Promise<void>;
23
- type IntegrationConfig = {
24
- productRef: string;
25
- credentials: Record<string, unknown>;
26
- };
27
- export { NumberPreconditionsCheck, IntegrationConfig };
25
+ export { NumberPreconditionsCheck };
@@ -1,6 +1,3 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.findIntegrationsCredentials = findIntegrationsCredentials;
4
1
  /**
5
2
  * Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
6
3
  * http://github.com/fonoster/fonoster
@@ -19,11 +16,17 @@ exports.findIntegrationsCredentials = findIntegrationsCredentials;
19
16
  * See the License for the specific language governing permissions and
20
17
  * limitations under the License.
21
18
  */
22
- function findIntegrationsCredentials(integrations, engine) {
23
- var _a;
24
- const integration = (_a = integrations.find((i) => i.productRef === engine)) === null || _a === void 0 ? void 0 : _a.credentials;
25
- if (!integration) {
26
- throw new Error(`Integration ${engine} not found`);
27
- }
28
- return integration;
19
+ /**
20
+ * Runs database writes one after another, in the order they were queued, behind a synchronous
21
+ * store interface (the registry and webhook stores are synchronous; see P-B1 in
22
+ * add-provider-registry/build-log.md). `flush()` waits for every queued write and throws the
23
+ * first failure.
24
+ */
25
+ export declare class WriteBehind {
26
+ private readonly onError?;
27
+ private tail;
28
+ private failure?;
29
+ constructor(onError?: (e: unknown) => void);
30
+ push(write: () => Promise<unknown>): void;
31
+ flush(): Promise<void>;
29
32
  }
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
4
+ * http://github.com/fonoster/fonoster
5
+ *
6
+ * This file is part of Fonoster
7
+ *
8
+ * Licensed under the MIT License (the "License");
9
+ * you may not use this file except in compliance with
10
+ * the License. You may obtain a copy of the License at
11
+ *
12
+ * https://opensource.org/licenses/MIT
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ */
20
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
21
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
22
+ return new (P || (P = Promise))(function (resolve, reject) {
23
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
24
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
25
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
26
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
27
+ });
28
+ };
29
+ Object.defineProperty(exports, "__esModule", { value: true });
30
+ exports.WriteBehind = void 0;
31
+ /**
32
+ * Runs database writes one after another, in the order they were queued, behind a synchronous
33
+ * store interface (the registry and webhook stores are synchronous; see P-B1 in
34
+ * add-provider-registry/build-log.md). `flush()` waits for every queued write and throws the
35
+ * first failure.
36
+ */
37
+ class WriteBehind {
38
+ constructor(onError) {
39
+ this.onError = onError;
40
+ this.tail = Promise.resolve();
41
+ }
42
+ push(write) {
43
+ this.tail = this.tail.then(() => __awaiter(this, void 0, void 0, function* () {
44
+ var _a, _b;
45
+ try {
46
+ yield write();
47
+ }
48
+ catch (e) {
49
+ (_a = this.failure) !== null && _a !== void 0 ? _a : (this.failure = e);
50
+ (_b = this.onError) === null || _b === void 0 ? void 0 : _b.call(this, e);
51
+ }
52
+ }));
53
+ }
54
+ flush() {
55
+ return __awaiter(this, void 0, void 0, function* () {
56
+ yield this.tail;
57
+ const failure = this.failure;
58
+ this.failure = undefined;
59
+ if (failure)
60
+ throw failure;
61
+ });
62
+ }
63
+ }
64
+ exports.WriteBehind = WriteBehind;
@@ -29,5 +29,5 @@ export * from "./withErrorHandlingAndValidation";
29
29
  export * from "./withValidation";
30
30
  export * from "./types";
31
31
  export * from "./createFetchSingleCallByCallId";
32
- export * from "./findIntegrationsCredentials";
33
32
  export * from "./sendHttpRequest";
33
+ export * from "./logUnhandledRejections";
@@ -45,5 +45,5 @@ __exportStar(require("./withErrorHandlingAndValidation"), exports);
45
45
  __exportStar(require("./withValidation"), exports);
46
46
  __exportStar(require("./types"), exports);
47
47
  __exportStar(require("./createFetchSingleCallByCallId"), exports);
48
- __exportStar(require("./findIntegrationsCredentials"), exports);
49
48
  __exportStar(require("./sendHttpRequest"), exports);
49
+ __exportStar(require("./logUnhandledRejections"), exports);
@@ -16,15 +16,11 @@
16
16
  * See the License for the specific language governing permissions and
17
17
  * limitations under the License.
18
18
  */
19
- import { VerbRequest } from "./Verb";
20
- type PlayOptions = {
21
- playbackRef?: string;
22
- };
23
- type PlayRequest = VerbRequest & {
24
- url: string;
25
- } & PlayOptions;
26
- type PlayResponse = {
27
- mediaSessionRef: string;
28
- playbackRef: string;
29
- };
30
- export { PlayOptions, PlayRequest, PlayResponse };
19
+ /**
20
+ * Keeps a service up when a promise somewhere rejects without a handler (RV-B5): the reason is
21
+ * logged and the process keeps serving, instead of Node's default of exiting. Install once in a
22
+ * service's main.
23
+ */
24
+ export declare function logUnhandledRejections(logger: {
25
+ error: (message: string, meta?: Record<string, unknown>) => unknown;
26
+ }): () => NodeJS.Process;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.logUnhandledRejections = logUnhandledRejections;
4
+ /**
5
+ * Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
6
+ * http://github.com/fonoster/fonoster
7
+ *
8
+ * This file is part of Fonoster
9
+ *
10
+ * Licensed under the MIT License (the "License");
11
+ * you may not use this file except in compliance with
12
+ * the License. You may obtain a copy of the License at
13
+ *
14
+ * https://opensource.org/licenses/MIT
15
+ *
16
+ * Unless required by applicable law or agreed to in writing, software
17
+ * distributed under the License is distributed on an "AS IS" BASIS,
18
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ * See the License for the specific language governing permissions and
20
+ * limitations under the License.
21
+ */
22
+ /**
23
+ * Keeps a service up when a promise somewhere rejects without a handler (RV-B5): the reason is
24
+ * logged and the process keeps serving, instead of Node's default of exiting. Install once in a
25
+ * service's main.
26
+ */
27
+ function logUnhandledRejections(logger) {
28
+ const handler = (reason) => {
29
+ var _a;
30
+ const e = reason;
31
+ logger.error(`unhandled rejection: ${(_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : String(reason)}`, {
32
+ stack: e === null || e === void 0 ? void 0 : e.stack
33
+ });
34
+ };
35
+ process.on("unhandledRejection", handler);
36
+ return () => process.off("unhandledRejection", handler);
37
+ }
@@ -27,14 +27,14 @@ declare const createCallRequestSchema: z.ZodObject<{
27
27
  }, "strip", z.ZodTypeAny, {
28
28
  timeout?: number;
29
29
  metadata?: Record<string, any>;
30
- to?: string;
31
30
  from?: string;
31
+ to?: string;
32
32
  appRef?: string;
33
33
  }, {
34
34
  timeout?: number;
35
35
  metadata?: Record<string, any>;
36
- to?: string;
37
36
  from?: string;
37
+ to?: string;
38
38
  appRef?: string;
39
39
  }>;
40
40
  declare const getCallRequestSchema: z.ZodObject<{
@@ -22,9 +22,12 @@ exports.listCallsRequestSchema = exports.getCallRequestSchema = exports.createCa
22
22
  const types_1 = require("@fonoster/types");
23
23
  const zod_1 = require("zod");
24
24
  const messages_1 = require("../messages");
25
+ const sip_1 = require("./sip");
26
+ // `from` is one of the workspace's Numbers (the Calls service checks ownership); it travels as
27
+ // X-Dod-Number and picks the trunk, so it is an E.164 number. `to` is what the media node dials.
25
28
  const createCallRequestSchema = zod_1.z.object({
26
- from: zod_1.z.string(),
27
- to: zod_1.z.string(),
29
+ from: sip_1.e164Schema,
30
+ to: sip_1.sipTargetSchema,
28
31
  appRef: zod_1.z.string().uuid({ message: "Invalid call reference" }),
29
32
  timeout: zod_1.z
30
33
  .number()