@fonoster/common 0.30.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/{assistants → agents}/index.d.ts +1 -1
- package/dist/{assistants → agents}/index.js +1 -1
- package/dist/{assistants/sessionAssistantSchema.d.ts → agents/sessionAgentSchema.d.ts} +20 -6
- package/dist/{assistants/sessionAssistantSchema.js → agents/sessionAgentSchema.js} +16 -11
- package/dist/cellsecrets/index.d.ts +2 -2
- package/dist/cellsecrets/index.js +3 -3
- package/dist/config/cli/render.d.ts +1 -1
- package/dist/config/cli/render.js +3 -3
- package/dist/config/configHints.d.ts +1 -14
- package/dist/config/configHints.js +16 -30
- package/dist/config/index.d.ts +0 -1
- package/dist/config/index.js +0 -1
- package/dist/config/interpolateEnv.d.ts +1 -1
- package/dist/config/loadServiceConfig.d.ts +0 -5
- package/dist/config/loadServiceConfig.js +3 -12
- package/dist/constants.d.ts +1 -3
- package/dist/constants.js +3 -5
- 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/roles.js +11 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +5 -2
- package/dist/protos/applications.proto +16 -2
- package/dist/protos/authz.proto +3 -0
- package/dist/protos/billing.proto +92 -0
- package/dist/protos/calls.proto +4 -0
- package/dist/protos/capabilities.proto +8 -0
- package/dist/protos/providers.proto +6 -2
- package/dist/protos/roomr.proto +146 -0
- package/dist/protos/session.proto +194 -0
- package/dist/protos/usage.proto +59 -0
- package/dist/registry/Registry.d.ts +13 -5
- package/dist/registry/Registry.js +49 -35
- package/dist/registry/cli.js +19 -7
- package/dist/registry/features.d.ts +2 -2
- package/dist/registry/features.js +7 -5
- package/dist/registry/prisma.d.ts +2 -2
- package/dist/registry/prisma.js +26 -18
- package/dist/registry/types.d.ts +17 -5
- package/dist/registry/types.js +2 -0
- package/dist/roomr/health.d.ts +9 -0
- package/dist/roomr/health.js +75 -0
- 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/schema.d.ts +196 -7
- package/dist/session/schema.js +59 -8
- package/dist/sessions/index.d.ts +15 -12
- package/dist/sessions/index.js +15 -12
- package/dist/telemetry.d.ts +1 -1
- package/dist/usage/CallUsage.d.ts +38 -0
- package/dist/usage/CallUsage.js +76 -0
- package/dist/{utils/types.d.ts → usage/index.d.ts} +4 -5
- 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/index.d.ts +0 -2
- package/dist/utils/index.js +0 -2
- package/dist/utils/withErrorHandling.js +1 -1
- package/dist/validators/calls.d.ts +5 -2
- package/dist/validators/calls.js +8 -1
- package/dist/validators/sip.d.ts +2 -2
- package/dist/validators/sip.js +3 -3
- package/dist/webhooks/bus.d.ts +29 -10
- package/dist/webhooks/bus.js +58 -50
- package/dist/webhooks/events.d.ts +1 -1
- package/dist/webhooks/events.js +1 -1
- package/package.json +9 -8
- package/schema/session.v1.json +82 -2
- package/dist/config/integrationsSchema.d.ts +0 -32
- package/dist/config/integrationsSchema.js +0 -56
- package/dist/utils/createFetchSingleCallByCallId.d.ts +0 -22
- package/dist/utils/createFetchSingleCallByCallId.js +0 -33
- package/dist/utils/types.js +0 -2
- /package/dist/{assistants → agents}/testCasesSchema.d.ts +0 -0
- /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,6 @@
|
|
|
1
|
+
import { UsageLine } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* The id of a usage line (design D7): derived from what it measures, so reporting the same usage
|
|
4
|
+
* twice yields the same id. `scope` is the callRef, the eval step key, or workspaceRef + day.
|
|
5
|
+
*/
|
|
6
|
+
export declare function usageId(scope: string, line: Pick<UsageLine, "meter" | "provider" | "model" | "keySource">): string;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.usageId = usageId;
|
|
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
|
+
const node_crypto_1 = require("node:crypto");
|
|
23
|
+
const ALPHABET = "abcdefghijklmnopqrstuvwxyz234567";
|
|
24
|
+
function base32(bytes) {
|
|
25
|
+
var _a;
|
|
26
|
+
const bits = Array.from(bytes, (b) => b.toString(2).padStart(8, "0")).join("");
|
|
27
|
+
return ((_a = bits.match(/.{1,5}/g)) !== null && _a !== void 0 ? _a : [])
|
|
28
|
+
.map((chunk) => ALPHABET[parseInt(chunk.padEnd(5, "0"), 2)])
|
|
29
|
+
.join("");
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The id of a usage line (design D7): derived from what it measures, so reporting the same usage
|
|
33
|
+
* twice yields the same id. `scope` is the callRef, the eval step key, or workspaceRef + day.
|
|
34
|
+
*/
|
|
35
|
+
function usageId(scope, line) {
|
|
36
|
+
var _a, _b, _c;
|
|
37
|
+
const key = [
|
|
38
|
+
scope,
|
|
39
|
+
line.meter,
|
|
40
|
+
(_a = line.provider) !== null && _a !== void 0 ? _a : "",
|
|
41
|
+
(_b = line.model) !== null && _b !== void 0 ? _b : "",
|
|
42
|
+
(_c = line.keySource) !== null && _c !== void 0 ? _c : ""
|
|
43
|
+
].join("|");
|
|
44
|
+
return ("usg_" + base32((0, node_crypto_1.createHash)("sha256").update(key).digest()).slice(0, 26));
|
|
45
|
+
}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -27,7 +27,5 @@ export * from "./toPascalCase";
|
|
|
27
27
|
export * from "./withErrorHandling";
|
|
28
28
|
export * from "./withErrorHandlingAndValidation";
|
|
29
29
|
export * from "./withValidation";
|
|
30
|
-
export * from "./types";
|
|
31
|
-
export * from "./createFetchSingleCallByCallId";
|
|
32
30
|
export * from "./sendHttpRequest";
|
|
33
31
|
export * from "./logUnhandledRejections";
|
package/dist/utils/index.js
CHANGED
|
@@ -43,7 +43,5 @@ __exportStar(require("./toPascalCase"), exports);
|
|
|
43
43
|
__exportStar(require("./withErrorHandling"), exports);
|
|
44
44
|
__exportStar(require("./withErrorHandlingAndValidation"), exports);
|
|
45
45
|
__exportStar(require("./withValidation"), exports);
|
|
46
|
-
__exportStar(require("./types"), exports);
|
|
47
|
-
__exportStar(require("./createFetchSingleCallByCallId"), exports);
|
|
48
46
|
__exportStar(require("./sendHttpRequest"), exports);
|
|
49
47
|
__exportStar(require("./logUnhandledRejections"), exports);
|
|
@@ -28,7 +28,7 @@ exports.withErrorHandling = withErrorHandling;
|
|
|
28
28
|
* See the License for the specific language governing permissions and
|
|
29
29
|
* limitations under the License.
|
|
30
30
|
*/
|
|
31
|
-
/* eslint-disable @typescript-eslint/
|
|
31
|
+
/* eslint-disable @typescript-eslint/no-unsafe-function-type */
|
|
32
32
|
const errors_1 = require("../errors");
|
|
33
33
|
function withErrorHandling(fn) {
|
|
34
34
|
return (call, callback) => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -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
|
-
from?: string;
|
|
31
30
|
to?: string;
|
|
31
|
+
from?: string;
|
|
32
32
|
appRef?: string;
|
|
33
33
|
}, {
|
|
34
34
|
timeout?: number;
|
|
35
35
|
metadata?: Record<string, any>;
|
|
36
|
-
from?: string;
|
|
37
36
|
to?: string;
|
|
37
|
+
from?: string;
|
|
38
38
|
appRef?: string;
|
|
39
39
|
}>;
|
|
40
40
|
declare const getCallRequestSchema: z.ZodObject<{
|
|
@@ -50,10 +50,12 @@ declare const listCallsRequestSchema: z.ZodObject<{
|
|
|
50
50
|
pageSize: z.ZodOptional<z.ZodNumber>;
|
|
51
51
|
type: z.ZodOptional<z.ZodNativeEnum<typeof CallType>>;
|
|
52
52
|
status: z.ZodOptional<z.ZodNativeEnum<typeof CallStatus>>;
|
|
53
|
+
appRef: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
53
54
|
pageToken: z.ZodOptional<z.ZodString>;
|
|
54
55
|
}, "strip", z.ZodTypeAny, {
|
|
55
56
|
type?: CallType;
|
|
56
57
|
status?: CallStatus;
|
|
58
|
+
appRef?: string;
|
|
57
59
|
after?: string;
|
|
58
60
|
before?: string;
|
|
59
61
|
pageSize?: number;
|
|
@@ -61,6 +63,7 @@ declare const listCallsRequestSchema: z.ZodObject<{
|
|
|
61
63
|
}, {
|
|
62
64
|
type?: CallType;
|
|
63
65
|
status?: CallStatus;
|
|
66
|
+
appRef?: string;
|
|
64
67
|
after?: string;
|
|
65
68
|
before?: string;
|
|
66
69
|
pageSize?: number;
|
package/dist/validators/calls.js
CHANGED
|
@@ -24,7 +24,7 @@ const zod_1 = require("zod");
|
|
|
24
24
|
const messages_1 = require("../messages");
|
|
25
25
|
const sip_1 = require("./sip");
|
|
26
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
|
|
27
|
+
// X-Dod-Number and picks the trunk, so it is an E.164 number. `to` is what the Roomr node dials.
|
|
28
28
|
const createCallRequestSchema = zod_1.z.object({
|
|
29
29
|
from: sip_1.e164Schema,
|
|
30
30
|
to: sip_1.sipTargetSchema,
|
|
@@ -60,6 +60,13 @@ const listCallsRequestSchema = zod_1.z.object({
|
|
|
60
60
|
status: zod_1.z
|
|
61
61
|
.nativeEnum(types_1.CallStatus, { message: "Invalid call status" })
|
|
62
62
|
.optional(),
|
|
63
|
+
// Empty or unset means no filter (proto3 sends ""); anything else must be an app ref.
|
|
64
|
+
appRef: zod_1.z
|
|
65
|
+
.string()
|
|
66
|
+
.refine((v) => v === "" || zod_1.z.string().uuid().safeParse(v).success, {
|
|
67
|
+
message: "Invalid application reference"
|
|
68
|
+
})
|
|
69
|
+
.optional(),
|
|
63
70
|
pageToken: zod_1.z.string().optional()
|
|
64
71
|
});
|
|
65
72
|
exports.listCallsRequestSchema = listCallsRequestSchema;
|
package/dist/validators/sip.d.ts
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import { z } from "zod";
|
|
20
20
|
/**
|
|
21
|
-
* Headers the platform (Routr, the
|
|
21
|
+
* Headers the platform (Routr, the Roomr node, AppBridge, the apiserver) sets and trusts: they
|
|
22
22
|
* pick the app, the call, the workspace and the trunk. Callers and apps may never set them.
|
|
23
23
|
*/
|
|
24
24
|
export declare const RESERVED_SIP_HEADERS: ReadonlySet<string>;
|
|
@@ -34,7 +34,7 @@ export declare const SIP_TARGET: RegExp;
|
|
|
34
34
|
export declare function sipHeaderProblem(name: string, value: unknown): string | undefined;
|
|
35
35
|
/** Why a set of custom SIP headers may not be sent (undefined: they may). */
|
|
36
36
|
export declare function sipHeadersProblem(headers: unknown): string | undefined;
|
|
37
|
-
/** Whether `to` is a target the
|
|
37
|
+
/** Whether `to` is a target the Roomr node may dial or refer to. */
|
|
38
38
|
export declare function isSipTarget(to: unknown): to is string;
|
|
39
39
|
export declare const e164Schema: z.ZodString;
|
|
40
40
|
export declare const sipTargetSchema: z.ZodString;
|
package/dist/validators/sip.js
CHANGED
|
@@ -27,7 +27,7 @@ const zod_1 = require("zod");
|
|
|
27
27
|
// from/to, the `transfer` command's target and headers). sipgo does not escape header values or
|
|
28
28
|
// URI users, so anything that reaches an INVITE or REFER must be safe as-is.
|
|
29
29
|
/**
|
|
30
|
-
* Headers the platform (Routr, the
|
|
30
|
+
* Headers the platform (Routr, the Roomr node, AppBridge, the apiserver) sets and trusts: they
|
|
31
31
|
* pick the app, the call, the workspace and the trunk. Callers and apps may never set them.
|
|
32
32
|
*/
|
|
33
33
|
exports.RESERVED_SIP_HEADERS = new Set([
|
|
@@ -40,7 +40,7 @@ exports.RESERVED_SIP_HEADERS = new Set([
|
|
|
40
40
|
"X-Is-Api-Originated-Type",
|
|
41
41
|
"X-Connect-Token",
|
|
42
42
|
"X-Edgeport-Ref",
|
|
43
|
-
"X-
|
|
43
|
+
"X-AppBridge-Auth",
|
|
44
44
|
"X-Request-Uri",
|
|
45
45
|
"X-Session-Count"
|
|
46
46
|
].map((h) => h.toLowerCase()));
|
|
@@ -87,7 +87,7 @@ function sipHeadersProblem(headers) {
|
|
|
87
87
|
}
|
|
88
88
|
return undefined;
|
|
89
89
|
}
|
|
90
|
-
/** Whether `to` is a target the
|
|
90
|
+
/** Whether `to` is a target the Roomr node may dial or refer to. */
|
|
91
91
|
function isSipTarget(to) {
|
|
92
92
|
return typeof to === "string" && exports.SIP_TARGET.test(to);
|
|
93
93
|
}
|
package/dist/webhooks/bus.d.ts
CHANGED
|
@@ -17,18 +17,37 @@ export type BusConnection = {
|
|
|
17
17
|
export declare function busWebhookPublisher(nc: Pick<BusConnection, "publish">): (event: WebhookEvent) => void;
|
|
18
18
|
/** Parses a bus message; undefined for anything that is not a v1 webhook event. */
|
|
19
19
|
export declare function parseBusEvent(data: Uint8Array): WebhookEvent | undefined;
|
|
20
|
-
/** Where
|
|
21
|
-
export declare const
|
|
22
|
-
/** The reasons a node may give: it only ever fails a call nobody claimed. */
|
|
23
|
-
export declare const NODE_CALL_FAILED_REASONS: readonly ["node_error"];
|
|
20
|
+
/** Where Roomr nodes publish a call's events (`roomr.events.<call_ref>`; room events have one more token). */
|
|
21
|
+
export declare const ROOMR_CALL_EVENTS_SUBJECT = "roomr.events.*";
|
|
24
22
|
/**
|
|
25
|
-
* The call.failed
|
|
26
|
-
*
|
|
27
|
-
* node reason is accepted, the report must name the node of its subject, and the workspace is left
|
|
28
|
-
* empty for the fan-out to resolve from the app: a node never chooses the workspace, the event type
|
|
29
|
-
* or extra data. The id depends on the node and the call, so a repeated report is delivered once.
|
|
23
|
+
* The `call.failed` reasons an unanswered outbound call can end with (the node's `cause`); any
|
|
24
|
+
* other cause is reported as `node_error`.
|
|
30
25
|
*/
|
|
31
|
-
export declare
|
|
26
|
+
export declare const UNANSWERED_CALL_REASONS: readonly ["busy", "no_answer", "rejected", "removed", "node_error"];
|
|
27
|
+
/** An outbound call the callee never answered, as its node's `call.ended` tells it. */
|
|
28
|
+
export type UnansweredCall = {
|
|
29
|
+
callRef: string;
|
|
30
|
+
appRef: string;
|
|
31
|
+
from: string;
|
|
32
|
+
to: string;
|
|
33
|
+
reason: (typeof UNANSWERED_CALL_REASONS)[number];
|
|
34
|
+
sipStatus?: number;
|
|
35
|
+
nodeRef: string;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* The unanswered outbound call a Roomr node's event on `subject` (`roomr.events.<call_ref>`)
|
|
39
|
+
* reports, or undefined: only a `call.ended` with `answered: false` of a call the control plane
|
|
40
|
+
* placed (its `metadata.app_ref`, passed through by the node) for the subject's own call. The
|
|
41
|
+
* parties come from the metadata the control plane set; the node never chooses the workspace
|
|
42
|
+
* (left for the fan-out to resolve from the app), the event type or extra data (M6).
|
|
43
|
+
*/
|
|
44
|
+
export declare function unansweredOutboundCall(subject: string, event: Record<string, unknown> | undefined): UnansweredCall | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* The `call.failed` event for an unanswered outbound call. Its id depends on the call only, so
|
|
47
|
+
* every replica that sees the node's `call.ended` builds the same event and each endpoint gets one
|
|
48
|
+
* delivery.
|
|
49
|
+
*/
|
|
50
|
+
export declare function unansweredCallFailed(call: UnansweredCall, now?: Date): WebhookEvent;
|
|
32
51
|
export type FanoutOptions = {
|
|
33
52
|
/** Usually `WebhookDispatcher.publish`: stores one pending delivery per subscribed endpoint. */
|
|
34
53
|
publish(event: WebhookEvent): Delivery[];
|
package/dist/webhooks/bus.js
CHANGED
|
@@ -9,10 +9,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.
|
|
12
|
+
exports.UNANSWERED_CALL_REASONS = exports.ROOMR_CALL_EVENTS_SUBJECT = exports.WEBHOOK_EVENTS_SUBJECT = void 0;
|
|
13
13
|
exports.busWebhookPublisher = busWebhookPublisher;
|
|
14
14
|
exports.parseBusEvent = parseBusEvent;
|
|
15
|
-
exports.
|
|
15
|
+
exports.unansweredOutboundCall = unansweredOutboundCall;
|
|
16
|
+
exports.unansweredCallFailed = unansweredCallFailed;
|
|
16
17
|
exports.resolveWorkspace = resolveWorkspace;
|
|
17
18
|
exports.subscribeWebhookFanout = subscribeWebhookFanout;
|
|
18
19
|
/**
|
|
@@ -37,15 +38,15 @@ const crypto_1 = require("crypto");
|
|
|
37
38
|
const util_1 = require("util");
|
|
38
39
|
const events_1 = require("./events");
|
|
39
40
|
// Event fan-out from the event bus (add-workspace-webhooks task 2.2, build log LO-B1). Producers
|
|
40
|
-
// that have no database (
|
|
41
|
+
// that have no database (Roomr nodes, appbridges in bus mode, other regions) publish events on
|
|
41
42
|
// `webhooks.events`; one control-plane replica per event (queue group) fans each event out to the
|
|
42
43
|
// workspace's subscribed endpoints. A producer that does not know the workspace leaves
|
|
43
44
|
// `workspaceRef` empty and the fan-out resolves it from `data.appRef`.
|
|
44
45
|
//
|
|
45
|
-
//
|
|
46
|
-
// any workspace).
|
|
47
|
-
//
|
|
48
|
-
// (
|
|
46
|
+
// Roomr nodes may not publish `webhooks.events` (M6: a node could otherwise forge any event for
|
|
47
|
+
// any workspace). An outbound call that is never answered reaches no AppBridge; the control plane
|
|
48
|
+
// builds its call.failed from the node's own `call.ended` on `roomr.events.<call_ref>`
|
|
49
|
+
// (unansweredOutboundCall), with the workspace taken from the app and nothing else trusted.
|
|
49
50
|
exports.WEBHOOK_EVENTS_SUBJECT = "webhooks.events";
|
|
50
51
|
const encoder = new util_1.TextEncoder();
|
|
51
52
|
const decoder = new util_1.TextDecoder();
|
|
@@ -71,63 +72,70 @@ function parseBusEvent(data) {
|
|
|
71
72
|
return undefined;
|
|
72
73
|
return e;
|
|
73
74
|
}
|
|
74
|
-
/** Where
|
|
75
|
-
exports.
|
|
76
|
-
/**
|
|
77
|
-
|
|
75
|
+
/** Where Roomr nodes publish a call's events (`roomr.events.<call_ref>`; room events have one more token). */
|
|
76
|
+
exports.ROOMR_CALL_EVENTS_SUBJECT = "roomr.events.*";
|
|
77
|
+
/**
|
|
78
|
+
* The `call.failed` reasons an unanswered outbound call can end with (the node's `cause`); any
|
|
79
|
+
* other cause is reported as `node_error`.
|
|
80
|
+
*/
|
|
81
|
+
exports.UNANSWERED_CALL_REASONS = [
|
|
82
|
+
"busy",
|
|
83
|
+
"no_answer",
|
|
84
|
+
"rejected",
|
|
85
|
+
"removed",
|
|
86
|
+
"node_error"
|
|
87
|
+
];
|
|
78
88
|
const MAX_FIELD = 256;
|
|
79
89
|
const field = (v, required = false) => typeof v === "string" && v.length <= MAX_FIELD && (!required || v.length > 0)
|
|
80
90
|
? v
|
|
81
91
|
: undefined;
|
|
82
92
|
/**
|
|
83
|
-
* The
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
93
|
+
* The unanswered outbound call a Roomr node's event on `subject` (`roomr.events.<call_ref>`)
|
|
94
|
+
* reports, or undefined: only a `call.ended` with `answered: false` of a call the control plane
|
|
95
|
+
* placed (its `metadata.app_ref`, passed through by the node) for the subject's own call. The
|
|
96
|
+
* parties come from the metadata the control plane set; the node never chooses the workspace
|
|
97
|
+
* (left for the fan-out to resolve from the app), the event type or extra data (M6).
|
|
88
98
|
*/
|
|
89
|
-
function
|
|
90
|
-
var _a;
|
|
99
|
+
function unansweredOutboundCall(subject, event) {
|
|
100
|
+
var _a, _b, _c, _d;
|
|
91
101
|
const tokens = subject.split(".");
|
|
92
|
-
if (tokens.length !==
|
|
93
|
-
tokens[0] !== "media" ||
|
|
94
|
-
tokens[2] !== "events" ||
|
|
95
|
-
tokens[3] !== "call-failed")
|
|
102
|
+
if (tokens.length !== 3 || tokens[0] !== "roomr" || tokens[1] !== "events")
|
|
96
103
|
return undefined;
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
r = JSON.parse(decoder.decode(data));
|
|
100
|
-
}
|
|
101
|
-
catch (_b) {
|
|
104
|
+
if (!event || typeof event !== "object" || event.type !== "call.ended")
|
|
102
105
|
return undefined;
|
|
103
|
-
|
|
104
|
-
|
|
106
|
+
if (event.answered !== false)
|
|
107
|
+
return undefined;
|
|
108
|
+
const callRef = field(event.call_ref, true);
|
|
109
|
+
if (!callRef || callRef !== tokens[2])
|
|
105
110
|
return undefined;
|
|
106
|
-
const
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
const from = field(r.from);
|
|
110
|
-
const to = field(r.to);
|
|
111
|
-
const reason = field(r.reason);
|
|
112
|
-
const direction = (_a = r.direction) !== null && _a !== void 0 ? _a : "inbound";
|
|
113
|
-
if (r.nodeId !== nodeId ||
|
|
114
|
-
!callRef ||
|
|
115
|
-
!appRef ||
|
|
116
|
-
from === undefined ||
|
|
117
|
-
to === undefined ||
|
|
118
|
-
!exports.NODE_CALL_FAILED_REASONS.includes(reason !== null && reason !== void 0 ? reason : "") ||
|
|
119
|
-
(direction !== "inbound" && direction !== "outbound"))
|
|
111
|
+
const metadata = (event.metadata && typeof event.metadata === "object" ? event.metadata : {});
|
|
112
|
+
const appRef = field(metadata.app_ref, true);
|
|
113
|
+
if (!appRef)
|
|
120
114
|
return undefined;
|
|
115
|
+
const cause = String((_a = event.cause) !== null && _a !== void 0 ? _a : "");
|
|
116
|
+
const reason = exports.UNANSWERED_CALL_REASONS.includes(cause)
|
|
117
|
+
? cause
|
|
118
|
+
: "node_error";
|
|
119
|
+
const sipStatus = Number(event.sip_status);
|
|
120
|
+
return Object.assign(Object.assign({ callRef,
|
|
121
|
+
appRef, from: (_b = field(metadata.from)) !== null && _b !== void 0 ? _b : "", to: (_c = field(metadata.to)) !== null && _c !== void 0 ? _c : "", reason }, (Number.isInteger(sipStatus) && sipStatus > 0 ? { sipStatus } : {})), { nodeRef: (_d = field(event.node_ref)) !== null && _d !== void 0 ? _d : "" });
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* The `call.failed` event for an unanswered outbound call. Its id depends on the call only, so
|
|
125
|
+
* every replica that sees the node's `call.ended` builds the same event and each endpoint gets one
|
|
126
|
+
* delivery.
|
|
127
|
+
*/
|
|
128
|
+
function unansweredCallFailed(call, now = new Date()) {
|
|
121
129
|
const event = (0, events_1.callFailed)("", {
|
|
122
|
-
callRef,
|
|
123
|
-
appRef,
|
|
124
|
-
from,
|
|
125
|
-
to,
|
|
126
|
-
direction,
|
|
127
|
-
reason: reason
|
|
130
|
+
callRef: call.callRef,
|
|
131
|
+
appRef: call.appRef,
|
|
132
|
+
from: call.from,
|
|
133
|
+
to: call.to,
|
|
134
|
+
direction: "outbound",
|
|
135
|
+
reason: call.reason
|
|
128
136
|
});
|
|
129
137
|
const digest = (0, crypto_1.createHash)("sha256")
|
|
130
|
-
.update(
|
|
138
|
+
.update(`call.failed\n${call.callRef}`)
|
|
131
139
|
.digest("hex")
|
|
132
140
|
.slice(0, 32);
|
|
133
141
|
return Object.assign(Object.assign({}, event), { id: `evt_node_${digest}`, createdAt: now.toISOString() });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const WEBHOOK_EVENT_TYPES: readonly ["call.started", "call.ended", "call.failed", "call_record.sealed", "provider.deprecated"];
|
|
2
2
|
export type WebhookEventType = (typeof WEBHOOK_EVENT_TYPES)[number];
|
|
3
3
|
/**
|
|
4
|
-
* Event names of the retired Autopilot
|
|
4
|
+
* Event names of the retired Autopilot agent webhook (`eventsHook`) and what replaces them
|
|
5
5
|
* (add-call-record 7.3). The record of a conversation (transcript, turns, recording) is in the call
|
|
6
6
|
* record that `call_record.sealed` links to.
|
|
7
7
|
*/
|
package/dist/webhooks/events.js
CHANGED
|
@@ -30,7 +30,7 @@ exports.WEBHOOK_EVENT_TYPES = [
|
|
|
30
30
|
"provider.deprecated"
|
|
31
31
|
];
|
|
32
32
|
/**
|
|
33
|
-
* Event names of the retired Autopilot
|
|
33
|
+
* Event names of the retired Autopilot agent webhook (`eventsHook`) and what replaces them
|
|
34
34
|
* (add-call-record 7.3). The record of a conversation (transcript, turns, recording) is in the call
|
|
35
35
|
* record that `call_record.sealed` links to.
|
|
36
36
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fonoster/common",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.31.0",
|
|
4
4
|
"description": "Common library for Fonoster projects",
|
|
5
5
|
"author": "Pedro Sanders <psanders@fonoster.com>",
|
|
6
6
|
"homepage": "https://github.com/fonoster/fonoster#readme",
|
|
@@ -15,15 +15,14 @@
|
|
|
15
15
|
"prebuild": "rimraf ./dist tsconfig.tsbuildinfo",
|
|
16
16
|
"build": "tsc -b tsconfig.json",
|
|
17
17
|
"postbuild": "cp -a src/protos dist",
|
|
18
|
-
"
|
|
19
|
-
"generate:
|
|
18
|
+
"generate:session-schema": "tsx scripts/export-session-schema.ts",
|
|
19
|
+
"generate:config-schemas": "tsx scripts/export-config-schemas.ts"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@fonoster/logger": "^0.
|
|
23
|
-
"@fonoster/types": "^0.
|
|
22
|
+
"@fonoster/logger": "^0.31.0",
|
|
23
|
+
"@fonoster/types": "^0.31.0",
|
|
24
24
|
"@grpc/grpc-js": "~1.14.6",
|
|
25
25
|
"@grpc/proto-loader": "^0.7.15",
|
|
26
|
-
"@influxdata/influxdb-client": "^1.35.0",
|
|
27
26
|
"@opentelemetry/api": "^1.9.0",
|
|
28
27
|
"@opentelemetry/resources": "^2.12.0",
|
|
29
28
|
"@opentelemetry/sdk-trace-base": "^2.12.0",
|
|
@@ -58,8 +57,10 @@
|
|
|
58
57
|
"bugs": {
|
|
59
58
|
"url": "https://github.com/fonoster/fonoster/issues"
|
|
60
59
|
},
|
|
61
|
-
"devDependencies": {
|
|
62
|
-
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@fonoster/roomr": "0.2.5"
|
|
62
|
+
},
|
|
63
|
+
"gitHead": "f0a5102dddeea0f70f659234108805bc10690f2e",
|
|
63
64
|
"bin": {
|
|
64
65
|
"fonoster-registry": "dist/registry/cli.js",
|
|
65
66
|
"fonoster-config": "dist/config/cli/index.js"
|
package/schema/session.v1.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"title": "fonoster.session.v1",
|
|
5
5
|
"description": "Messages of the Fonoster session protocol (a stream with protocol fonoster). Unknown types and fields must be ignored.",
|
|
6
6
|
"protocol": "fonoster.session.v1",
|
|
7
|
-
"
|
|
7
|
+
"appBridgeToApp": {
|
|
8
8
|
"session.start": {
|
|
9
9
|
"type": "object",
|
|
10
10
|
"required": [
|
|
@@ -63,6 +63,9 @@
|
|
|
63
63
|
}
|
|
64
64
|
]
|
|
65
65
|
},
|
|
66
|
+
"traceparent": {
|
|
67
|
+
"type": "string"
|
|
68
|
+
},
|
|
66
69
|
"audio": {
|
|
67
70
|
"type": "object",
|
|
68
71
|
"required": [
|
|
@@ -417,6 +420,23 @@
|
|
|
417
420
|
}
|
|
418
421
|
}
|
|
419
422
|
},
|
|
423
|
+
"transfer.answered": {
|
|
424
|
+
"type": "object",
|
|
425
|
+
"required": [
|
|
426
|
+
"type",
|
|
427
|
+
"relatesTo"
|
|
428
|
+
],
|
|
429
|
+
"properties": {
|
|
430
|
+
"type": {
|
|
431
|
+
"const": "transfer.answered"
|
|
432
|
+
},
|
|
433
|
+
"relatesTo": {
|
|
434
|
+
"type": "string",
|
|
435
|
+
"minLength": 1,
|
|
436
|
+
"maxLength": 128
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
},
|
|
420
440
|
"amd.result": {
|
|
421
441
|
"type": "object",
|
|
422
442
|
"required": [
|
|
@@ -461,7 +481,7 @@
|
|
|
461
481
|
}
|
|
462
482
|
}
|
|
463
483
|
},
|
|
464
|
-
"
|
|
484
|
+
"appToAppBridge": {
|
|
465
485
|
"speak": {
|
|
466
486
|
"type": "object",
|
|
467
487
|
"required": [
|
|
@@ -786,6 +806,66 @@
|
|
|
786
806
|
"type": "object"
|
|
787
807
|
}
|
|
788
808
|
}
|
|
809
|
+
},
|
|
810
|
+
"usage.report": {
|
|
811
|
+
"type": "object",
|
|
812
|
+
"required": [
|
|
813
|
+
"type",
|
|
814
|
+
"lines"
|
|
815
|
+
],
|
|
816
|
+
"properties": {
|
|
817
|
+
"type": {
|
|
818
|
+
"const": "usage.report"
|
|
819
|
+
},
|
|
820
|
+
"id": {
|
|
821
|
+
"type": "string",
|
|
822
|
+
"minLength": 1,
|
|
823
|
+
"maxLength": 128
|
|
824
|
+
},
|
|
825
|
+
"lines": {
|
|
826
|
+
"type": "array",
|
|
827
|
+
"minItems": 1,
|
|
828
|
+
"maxItems": 64,
|
|
829
|
+
"items": {
|
|
830
|
+
"type": "object",
|
|
831
|
+
"required": [
|
|
832
|
+
"meter",
|
|
833
|
+
"quantity",
|
|
834
|
+
"provider",
|
|
835
|
+
"keySource"
|
|
836
|
+
],
|
|
837
|
+
"additionalProperties": false,
|
|
838
|
+
"properties": {
|
|
839
|
+
"meter": {
|
|
840
|
+
"enum": [
|
|
841
|
+
"llm.tokens.in",
|
|
842
|
+
"llm.tokens.out",
|
|
843
|
+
"llm.tokens.cached",
|
|
844
|
+
"embedding.tokens"
|
|
845
|
+
]
|
|
846
|
+
},
|
|
847
|
+
"quantity": {
|
|
848
|
+
"type": "integer",
|
|
849
|
+
"minimum": 0
|
|
850
|
+
},
|
|
851
|
+
"provider": {
|
|
852
|
+
"type": "string",
|
|
853
|
+
"minLength": 1
|
|
854
|
+
},
|
|
855
|
+
"model": {
|
|
856
|
+
"type": "string",
|
|
857
|
+
"minLength": 1
|
|
858
|
+
},
|
|
859
|
+
"keySource": {
|
|
860
|
+
"enum": [
|
|
861
|
+
"platform",
|
|
862
|
+
"workspace"
|
|
863
|
+
]
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
}
|
|
789
869
|
}
|
|
790
870
|
}
|
|
791
871
|
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
declare const integrationsConfigSchema: z.ZodArray<z.ZodObject<{
|
|
3
|
-
name: z.ZodString;
|
|
4
|
-
productRef: z.ZodString;
|
|
5
|
-
type: z.ZodEnum<["tts", "stt", "llm"]>;
|
|
6
|
-
credentials: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
7
|
-
}, "strip", z.ZodTypeAny, {
|
|
8
|
-
type?: "tts" | "stt" | "llm";
|
|
9
|
-
name?: string;
|
|
10
|
-
productRef?: string;
|
|
11
|
-
credentials?: Record<string, unknown>;
|
|
12
|
-
}, {
|
|
13
|
-
type?: "tts" | "stt" | "llm";
|
|
14
|
-
name?: string;
|
|
15
|
-
productRef?: string;
|
|
16
|
-
credentials?: Record<string, unknown>;
|
|
17
|
-
}>, "many">;
|
|
18
|
-
/** Spelled out so callers get required fields regardless of tsconfig strictness. */
|
|
19
|
-
type IntegrationsConfig = Array<{
|
|
20
|
-
name: string;
|
|
21
|
-
productRef: string;
|
|
22
|
-
type: "tts" | "stt" | "llm";
|
|
23
|
-
credentials: Record<string, unknown>;
|
|
24
|
-
}>;
|
|
25
|
-
/**
|
|
26
|
-
* Reads and validates the retired integrations file. Only `fonoster-migrate-legacy --integrations`
|
|
27
|
-
* reads it now, to move its keys into operator config by credentialRef (add-provider-registry 5.3).
|
|
28
|
-
* YAML (`.yaml`/`.yml`) or JSON with comments (`.json`/`.jsonc`). Throws with the
|
|
29
|
-
* file path when the file can't be read or doesn't validate.
|
|
30
|
-
*/
|
|
31
|
-
declare function getIntegrationsFromFile(pathToIntegrations: string): IntegrationsConfig;
|
|
32
|
-
export { integrationsConfigSchema, IntegrationsConfig, getIntegrationsFromFile };
|