@relaymessenger/sdk 0.3.6-staging.4 → 0.3.6-staging.41
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/README.md +498 -29
- package/dist/a2ui.d.ts +79 -0
- package/dist/a2ui.d.ts.map +1 -0
- package/dist/a2ui.js +99 -0
- package/dist/a2ui.js.map +1 -0
- package/dist/buttons.d.ts +69 -0
- package/dist/buttons.d.ts.map +1 -0
- package/dist/buttons.js +141 -0
- package/dist/buttons.js.map +1 -0
- package/dist/calls/call-room.d.ts +110 -0
- package/dist/calls/call-room.d.ts.map +1 -0
- package/dist/calls/call-room.js +616 -0
- package/dist/calls/call-room.js.map +1 -0
- package/dist/calls/engine-werift-video.d.ts +83 -0
- package/dist/calls/engine-werift-video.d.ts.map +1 -0
- package/dist/calls/engine-werift-video.js +607 -0
- package/dist/calls/engine-werift-video.js.map +1 -0
- package/dist/calls/engine-werift.d.ts +48 -0
- package/dist/calls/engine-werift.d.ts.map +1 -0
- package/dist/calls/engine-werift.js +462 -0
- package/dist/calls/engine-werift.js.map +1 -0
- package/dist/calls/index.d.ts +11 -0
- package/dist/calls/index.d.ts.map +1 -0
- package/dist/calls/index.js +11 -0
- package/dist/calls/index.js.map +1 -0
- package/dist/calls/transport.d.ts +466 -0
- package/dist/calls/transport.d.ts.map +1 -0
- package/dist/calls/transport.js +1409 -0
- package/dist/calls/transport.js.map +1 -0
- package/dist/calls/video-frame.d.ts +56 -0
- package/dist/calls/video-frame.d.ts.map +1 -0
- package/dist/calls/video-frame.js +245 -0
- package/dist/calls/video-frame.js.map +1 -0
- package/dist/calls/video-presets.d.ts +39 -0
- package/dist/calls/video-presets.d.ts.map +1 -0
- package/dist/calls/video-presets.js +40 -0
- package/dist/calls/video-presets.js.map +1 -0
- package/dist/calls/video-rtp.d.ts +51 -0
- package/dist/calls/video-rtp.d.ts.map +1 -0
- package/dist/calls/video-rtp.js +294 -0
- package/dist/calls/video-rtp.js.map +1 -0
- package/dist/calls/video.d.ts +195 -0
- package/dist/calls/video.d.ts.map +1 -0
- package/dist/calls/video.js +228 -0
- package/dist/calls/video.js.map +1 -0
- package/dist/client.d.ts +218 -9
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +497 -17
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts +11 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +16 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +9 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -4
- package/dist/index.js.map +1 -1
- package/dist/links.d.ts +58 -0
- package/dist/links.d.ts.map +1 -0
- package/dist/links.js +127 -0
- package/dist/links.js.map +1 -0
- package/dist/operations.d.ts +117 -9
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +156 -10
- package/dist/operations.js.map +1 -1
- package/dist/pagination.d.ts +5 -0
- package/dist/pagination.d.ts.map +1 -1
- package/dist/pagination.js +10 -0
- package/dist/pagination.js.map +1 -1
- package/dist/payment.d.ts +67 -0
- package/dist/payment.d.ts.map +1 -0
- package/dist/payment.js +147 -0
- package/dist/payment.js.map +1 -0
- package/dist/selection.d.ts +46 -0
- package/dist/selection.d.ts.map +1 -0
- package/dist/selection.js +142 -0
- package/dist/selection.js.map +1 -0
- package/dist/types.d.ts +1102 -88
- package/dist/types.d.ts.map +1 -1
- package/dist/websocket.d.ts +6 -0
- package/dist/websocket.d.ts.map +1 -1
- package/dist/websocket.js +29 -10
- package/dist/websocket.js.map +1 -1
- package/package.json +38 -3
- package/dist/calls-room.d.ts +0 -50
- package/dist/calls-room.d.ts.map +0 -1
- package/dist/calls-room.js +0 -319
- package/dist/calls-room.js.map +0 -1
package/dist/a2ui.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/** The `media_type` of a data part that carries A2UI messages. */
|
|
2
|
+
export const A2UI_MEDIA_TYPE = "application/a2ui+json";
|
|
3
|
+
/** The A2UI version every message these helpers write carries. */
|
|
4
|
+
export const A2UI_VERSION = "v0.9.1";
|
|
5
|
+
/** A2UI v0.9.1's basic catalog, by the `catalogId` its catalog file declares. */
|
|
6
|
+
export const A2UI_BASIC_CATALOG_ID = "https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json";
|
|
7
|
+
/** Relay's catalog: every basic catalog component and function, plus `PaymentRequest`. */
|
|
8
|
+
export const RELAY_A2UI_CATALOG_ID = "https://relayapp.im/a2ui/catalog/v1";
|
|
9
|
+
/** Wraps A2UI messages in the data part Relay carries them in. */
|
|
10
|
+
export const a2uiPart = (messages) => ({
|
|
11
|
+
type: "data",
|
|
12
|
+
media_type: A2UI_MEDIA_TYPE,
|
|
13
|
+
data: messages,
|
|
14
|
+
});
|
|
15
|
+
const send = (client, chatID, messages, { text, ...message } = {}, options) => {
|
|
16
|
+
const parts = text === undefined
|
|
17
|
+
? [a2uiPart(messages)]
|
|
18
|
+
: [{ type: "text", value: text }, a2uiPart(messages)];
|
|
19
|
+
return client.chats.messages.send(chatID, { message: { ...message, parts } }, options);
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Sends a new card into a chat: `createSurface`, `updateComponents` and, when
|
|
23
|
+
* `dataModel` is given, `updateDataModel`, in one data part. Messages Relay
|
|
24
|
+
* could not apply come back in `a2ui_errors` (`A2uiFailure`); a send it could
|
|
25
|
+
* not apply at all throws a `RelayAPIError` whose `body.a2ui_errors` lists each.
|
|
26
|
+
*/
|
|
27
|
+
export const sendA2uiSurface = (client, chatID, surface, message, options) => {
|
|
28
|
+
const { surfaceId, catalogId, components, dataModel, theme, sendDataModel } = surface;
|
|
29
|
+
const messages = [
|
|
30
|
+
{
|
|
31
|
+
version: A2UI_VERSION,
|
|
32
|
+
createSurface: {
|
|
33
|
+
surfaceId,
|
|
34
|
+
catalogId,
|
|
35
|
+
...(theme === undefined ? {} : { theme }),
|
|
36
|
+
...(sendDataModel === undefined ? {} : { sendDataModel }),
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
{ version: A2UI_VERSION, updateComponents: { surfaceId, components } },
|
|
40
|
+
];
|
|
41
|
+
if (dataModel !== undefined) {
|
|
42
|
+
messages.push({ version: A2UI_VERSION, updateDataModel: { surfaceId, value: dataModel } });
|
|
43
|
+
}
|
|
44
|
+
return send(client, chatID, messages, message, options);
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Changes a card already in the chat, in place, for every member. With no
|
|
48
|
+
* `text`, the send adds no Message and returns the card's own Message. Any
|
|
49
|
+
* agent in the chat may update any surface in it.
|
|
50
|
+
*/
|
|
51
|
+
export const updateA2uiSurface = (client, chatID, surfaceId, update, message, options) => {
|
|
52
|
+
const messages = [];
|
|
53
|
+
if (update.components !== undefined) {
|
|
54
|
+
messages.push({ version: A2UI_VERSION, updateComponents: { surfaceId, components: update.components } });
|
|
55
|
+
}
|
|
56
|
+
if (update.dataModel !== undefined) {
|
|
57
|
+
messages.push({ version: A2UI_VERSION, updateDataModel: { surfaceId, ...update.dataModel } });
|
|
58
|
+
}
|
|
59
|
+
if (!messages.length)
|
|
60
|
+
throw new Error("an update needs components or a dataModel");
|
|
61
|
+
return send(client, chatID, messages, message, options);
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Removes a card for everyone. When every surface a Message draws is deleted,
|
|
65
|
+
* the Message reads back with no parts and a non-null `unsent_at`. The
|
|
66
|
+
* `surfaceId` may be created again afterwards.
|
|
67
|
+
*/
|
|
68
|
+
export const deleteA2uiSurface = (client, chatID, surfaceId, message, options) => send(client, chatID, [{ version: A2UI_VERSION, deleteSurface: { surfaceId } }], message, options);
|
|
69
|
+
/**
|
|
70
|
+
* Reads the first A2UI `action` out of a `message.received` event (a signed
|
|
71
|
+
* webhook or a WebSocket event), or out of its `data`. Returns null for any
|
|
72
|
+
* other event and for a Message that carries no tap. When the surface set
|
|
73
|
+
* `sendDataModel`, `dataModel` is that surface's model from
|
|
74
|
+
* `metadata.a2uiClientDataModel`.
|
|
75
|
+
*/
|
|
76
|
+
export const readA2uiAction = (event) => {
|
|
77
|
+
let data;
|
|
78
|
+
if ("event_type" in event) {
|
|
79
|
+
if (event.event_type !== "message.received")
|
|
80
|
+
return null;
|
|
81
|
+
data = event.data;
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
data = event;
|
|
85
|
+
}
|
|
86
|
+
for (const part of data.parts ?? []) {
|
|
87
|
+
if (part.type !== "data" || part.media_type !== A2UI_MEDIA_TYPE)
|
|
88
|
+
continue;
|
|
89
|
+
for (const message of part.data) {
|
|
90
|
+
if (typeof message !== "object" || message === null || !("action" in message))
|
|
91
|
+
continue;
|
|
92
|
+
const { action } = message;
|
|
93
|
+
const dataModel = data.metadata?.a2uiClientDataModel?.surfaces[action.surfaceId];
|
|
94
|
+
return dataModel === undefined ? { action } : { action, dataModel };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
};
|
|
99
|
+
//# sourceMappingURL=a2ui.js.map
|
package/dist/a2ui.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a2ui.js","sourceRoot":"","sources":["../src/a2ui.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { ButtonsPart } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The fence tag a text-only agent uses to put buttons under its answer. The
|
|
4
|
+
* block body is the `items` array of a `buttons` part, exactly as the API
|
|
5
|
+
* takes it, so an agent that has read the contract needs nothing else:
|
|
6
|
+
*
|
|
7
|
+
* ```buttons
|
|
8
|
+
* [{"label": "Approve"}, {"label": "Open report", "url": "https://..."}]
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
export declare const BUTTONS_FENCE = "buttons";
|
|
12
|
+
/**
|
|
13
|
+
* When an agent should send buttons. One text, carried verbatim by every
|
|
14
|
+
* runtime's tool description or prompt, so a person gets buttons under the
|
|
15
|
+
* same conditions whichever agent they talk to. The rules are the ones the
|
|
16
|
+
* messaging platforms give their own business agents: Apple's quick replies
|
|
17
|
+
* ("avoid expecting customers to type responses that could be handled with a
|
|
18
|
+
* tap", 2 to 5 options), Google's RCS suggestions ("design for the most
|
|
19
|
+
* common responses"; never "mimic phone trees"), WhatsApp's reply and
|
|
20
|
+
* call-to-action buttons (distinct options; one call to action). The line
|
|
21
|
+
* between a url button and a link is Messenger's ("use URL buttons for tasks
|
|
22
|
+
* that you want completed on your website (for example, purchases, or
|
|
23
|
+
* account linking)") and Apple's ("all URLs should be sent as Rich Links";
|
|
24
|
+
* product pages, support articles, self-serve resources): a task goes on a
|
|
25
|
+
* button, a thing to look at goes out as a link card.
|
|
26
|
+
*/
|
|
27
|
+
export declare const BUTTONS_GUIDANCE: string;
|
|
28
|
+
/**
|
|
29
|
+
* How a text-only agent puts buttons under its answer: the same words for
|
|
30
|
+
* every bridge that sends the agent's final text for it.
|
|
31
|
+
*/
|
|
32
|
+
export declare const BUTTONS_BLOCK_INSTRUCTION: string;
|
|
33
|
+
/** The server's limits (Discord's button limits): items 1..5, label 1..80, url <= 2048. */
|
|
34
|
+
export declare const BUTTONS_MAX_ITEMS = 5;
|
|
35
|
+
export declare const BUTTON_LABEL_MAX_LENGTH = 80;
|
|
36
|
+
export declare const BUTTON_URL_MAX_LENGTH = 2048;
|
|
37
|
+
export interface SplitButtons {
|
|
38
|
+
/** The answer with the fenced block removed and the edges trimmed. */
|
|
39
|
+
text: string;
|
|
40
|
+
/** The buttons part the block described, when there was a valid one. */
|
|
41
|
+
buttons?: ButtonsPart;
|
|
42
|
+
/** Why a block that was there could not be used. The text then keeps it. */
|
|
43
|
+
error?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Turns a decoded value, an array of items or a whole part, into a `buttons`
|
|
47
|
+
* part, or explains why it cannot. The checks are the server's own, so a bad
|
|
48
|
+
* value fails here with a readable reason instead of a 400 from the API.
|
|
49
|
+
*/
|
|
50
|
+
export declare const buttonsPart: (parsed: unknown) => ButtonsPart | string;
|
|
51
|
+
/** Parses the body of a buttons block, JSON, into a `buttons` part. */
|
|
52
|
+
export declare const parseButtonsBlock: (body: string) => ButtonsPart | string;
|
|
53
|
+
/**
|
|
54
|
+
* Lifts the first ```buttons block out of an agent's answer. The text around
|
|
55
|
+
* it becomes the text part; the block becomes the buttons part. When the
|
|
56
|
+
* block is malformed, the answer is returned untouched with `error` set, so
|
|
57
|
+
* the person still gets the words and the operator sees why.
|
|
58
|
+
*/
|
|
59
|
+
export declare const splitButtons: (answer: string) => SplitButtons;
|
|
60
|
+
/**
|
|
61
|
+
* The parts a text answer with optional buttons becomes: the text first, when
|
|
62
|
+
* there is any, then the buttons. A buttons-only message is one the server
|
|
63
|
+
* accepts, so an answer that is nothing but the block sends just the buttons.
|
|
64
|
+
*/
|
|
65
|
+
export declare const partsWithButtons: (text: string, buttons: ButtonsPart | undefined, limit?: number) => Array<{
|
|
66
|
+
type: "text";
|
|
67
|
+
value: string;
|
|
68
|
+
} | ButtonsPart>;
|
|
69
|
+
//# sourceMappingURL=buttons.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buttons.d.ts","sourceRoot":"","sources":["../src/buttons.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,YAAY,CAAC;AAE1D;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,YAAY,CAAC;AAEvC;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,gBAAgB,QAQlB,CAAC;AAEZ;;;GAGG;AACH,eAAO,MAAM,yBAAyB,QAGwB,CAAC;AAE/D,2FAA2F;AAC3F,eAAO,MAAM,iBAAiB,IAAI,CAAC;AACnC,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAC1C,eAAO,MAAM,qBAAqB,OAAQ,CAAC;AAE3C,MAAM,WAAW,YAAY;IAC3B,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAgCD;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ,OAAO,KAAG,WAAW,GAAG,MAiB3D,CAAC;AAEF,uEAAuE;AACvE,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,KAAG,WAAW,GAAG,MAQ9D,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,KAAG,YAU7C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAM,MAAM,EACZ,SAAS,WAAW,GAAG,SAAS,EAChC,cAAgC,KAC/B,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,WAAW,CAGrD,CAAC"}
|
package/dist/buttons.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fence tag a text-only agent uses to put buttons under its answer. The
|
|
3
|
+
* block body is the `items` array of a `buttons` part, exactly as the API
|
|
4
|
+
* takes it, so an agent that has read the contract needs nothing else:
|
|
5
|
+
*
|
|
6
|
+
* ```buttons
|
|
7
|
+
* [{"label": "Approve"}, {"label": "Open report", "url": "https://..."}]
|
|
8
|
+
* ```
|
|
9
|
+
*/
|
|
10
|
+
export const BUTTONS_FENCE = "buttons";
|
|
11
|
+
/**
|
|
12
|
+
* When an agent should send buttons. One text, carried verbatim by every
|
|
13
|
+
* runtime's tool description or prompt, so a person gets buttons under the
|
|
14
|
+
* same conditions whichever agent they talk to. The rules are the ones the
|
|
15
|
+
* messaging platforms give their own business agents: Apple's quick replies
|
|
16
|
+
* ("avoid expecting customers to type responses that could be handled with a
|
|
17
|
+
* tap", 2 to 5 options), Google's RCS suggestions ("design for the most
|
|
18
|
+
* common responses"; never "mimic phone trees"), WhatsApp's reply and
|
|
19
|
+
* call-to-action buttons (distinct options; one call to action). The line
|
|
20
|
+
* between a url button and a link is Messenger's ("use URL buttons for tasks
|
|
21
|
+
* that you want completed on your website (for example, purchases, or
|
|
22
|
+
* account linking)") and Apple's ("all URLs should be sent as Rich Links";
|
|
23
|
+
* product pages, support articles, self-serve resources): a task goes on a
|
|
24
|
+
* button, a thing to look at goes out as a link card.
|
|
25
|
+
*/
|
|
26
|
+
export const BUTTONS_GUIDANCE = [
|
|
27
|
+
"Send buttons when your message ends with a question the person can answer by picking one of 2 to 5 short options you already know: yes or no, choosing between things you named, picking a next step, or a multiple-choice question in a quiz. Each label is a complete answer, so a tap replaces typing. Put the question in text beside the buttons.",
|
|
28
|
+
"Send one button when there is one thing to do next. A url button is for a task the person completes on a web page: pay, sign in, connect an account, open their booking or order, track a package. Its label names the action, not the site. A plain button confirms one step: Start, Done, Continue. Do not ask \"ready?\" when a single button does the job.",
|
|
29
|
+
"A link is for something the person will look at or read: an article, a listing, a video, a place, a product page, a support article. Send it as a link on its own, so it draws as a card with the page's title and image; never paste a bare URL into your words, and send one link per message. When the page is where the person does something, send a url button; when the page is the thing you are showing them, send a link.",
|
|
30
|
+
"Do not send buttons when the answer is open-ended, when your options are not the full set of likely answers, or when you are not asking anything and there is nothing to do. One question or one action per message; never a menu of things you can do, and never as decoration.",
|
|
31
|
+
"If you would otherwise write \"reply 1, 2 or 3\" or list choices for the person to type, send buttons instead. If the person asks for buttons, send them.",
|
|
32
|
+
"A tap comes back to you as an ordinary message whose text is the label. Labels are at most 80 characters.",
|
|
33
|
+
"Buttons disappear once tapped.",
|
|
34
|
+
].join(" ");
|
|
35
|
+
/**
|
|
36
|
+
* How a text-only agent puts buttons under its answer: the same words for
|
|
37
|
+
* every bridge that sends the agent's final text for it.
|
|
38
|
+
*/
|
|
39
|
+
export const BUTTONS_BLOCK_INSTRUCTION = "To put buttons under your answer, end it with a fenced code block tagged `" + BUTTONS_FENCE + "` "
|
|
40
|
+
+ "holding a JSON array of 1 to 5 items, each {\"label\": \"...\"} or {\"label\": \"...\", \"url\": \"https://...\"}. "
|
|
41
|
+
+ "The block is removed from the text and drawn as buttons.";
|
|
42
|
+
/** The server's limits (Discord's button limits): items 1..5, label 1..80, url <= 2048. */
|
|
43
|
+
export const BUTTONS_MAX_ITEMS = 5;
|
|
44
|
+
export const BUTTON_LABEL_MAX_LENGTH = 80;
|
|
45
|
+
export const BUTTON_URL_MAX_LENGTH = 2_048;
|
|
46
|
+
const FENCE = new RegExp("(^|\\n)[ \\t]*```[ \\t]*" + BUTTONS_FENCE + "[ \\t]*\\r?\\n([\\s\\S]*?)\\r?\\n[ \\t]*```[ \\t]*(?=\\r?\\n|$)", "u");
|
|
47
|
+
const asItem = (value, index) => {
|
|
48
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
49
|
+
return `item ${index + 1} is not an object`;
|
|
50
|
+
}
|
|
51
|
+
const record = value;
|
|
52
|
+
const keys = Object.keys(record).filter((key) => key !== "label" && key !== "url");
|
|
53
|
+
if (keys.length > 0)
|
|
54
|
+
return `item ${index + 1} has unknown field ${keys[0]}`;
|
|
55
|
+
const { label, url } = record;
|
|
56
|
+
if (typeof label !== "string" || label.length === 0)
|
|
57
|
+
return `item ${index + 1} needs a label`;
|
|
58
|
+
if (label.length > BUTTON_LABEL_MAX_LENGTH) {
|
|
59
|
+
return `item ${index + 1} label is over ${BUTTON_LABEL_MAX_LENGTH} characters`;
|
|
60
|
+
}
|
|
61
|
+
if (url === undefined)
|
|
62
|
+
return { label };
|
|
63
|
+
if (typeof url !== "string" || url.length > BUTTON_URL_MAX_LENGTH) {
|
|
64
|
+
return `item ${index + 1} url is not a string of at most ${BUTTON_URL_MAX_LENGTH} characters`;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const parsed = new URL(url);
|
|
68
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:")
|
|
69
|
+
throw new Error();
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return `item ${index + 1} url is not an http(s) URL`;
|
|
73
|
+
}
|
|
74
|
+
return { url, label };
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Turns a decoded value, an array of items or a whole part, into a `buttons`
|
|
78
|
+
* part, or explains why it cannot. The checks are the server's own, so a bad
|
|
79
|
+
* value fails here with a readable reason instead of a 400 from the API.
|
|
80
|
+
*/
|
|
81
|
+
export const buttonsPart = (parsed) => {
|
|
82
|
+
const wrapped = parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)
|
|
83
|
+
? parsed
|
|
84
|
+
: undefined;
|
|
85
|
+
const items = Array.isArray(parsed) ? parsed : Array.isArray(wrapped?.items) ? wrapped.items : undefined;
|
|
86
|
+
if (items === undefined)
|
|
87
|
+
return "the buttons block must be a JSON array of items";
|
|
88
|
+
if (items.length === 0)
|
|
89
|
+
return "the buttons block has no items";
|
|
90
|
+
if (items.length > BUTTONS_MAX_ITEMS) {
|
|
91
|
+
return `the buttons block has ${items.length} items; the most is ${BUTTONS_MAX_ITEMS}`;
|
|
92
|
+
}
|
|
93
|
+
const result = [];
|
|
94
|
+
for (const [index, value] of items.entries()) {
|
|
95
|
+
const item = asItem(value, index);
|
|
96
|
+
if (typeof item === "string")
|
|
97
|
+
return item;
|
|
98
|
+
result.push(item);
|
|
99
|
+
}
|
|
100
|
+
return { type: "buttons", items: result };
|
|
101
|
+
};
|
|
102
|
+
/** Parses the body of a buttons block, JSON, into a `buttons` part. */
|
|
103
|
+
export const parseButtonsBlock = (body) => {
|
|
104
|
+
let parsed;
|
|
105
|
+
try {
|
|
106
|
+
parsed = JSON.parse(body);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return "the buttons block is not valid JSON";
|
|
110
|
+
}
|
|
111
|
+
return buttonsPart(parsed);
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Lifts the first ```buttons block out of an agent's answer. The text around
|
|
115
|
+
* it becomes the text part; the block becomes the buttons part. When the
|
|
116
|
+
* block is malformed, the answer is returned untouched with `error` set, so
|
|
117
|
+
* the person still gets the words and the operator sees why.
|
|
118
|
+
*/
|
|
119
|
+
export const splitButtons = (answer) => {
|
|
120
|
+
const match = FENCE.exec(answer);
|
|
121
|
+
if (!match)
|
|
122
|
+
return { text: answer };
|
|
123
|
+
const parsed = parseButtonsBlock(match[2] ?? "");
|
|
124
|
+
if (typeof parsed === "string")
|
|
125
|
+
return { text: answer, error: parsed };
|
|
126
|
+
const start = match.index + (match[1]?.length ?? 0);
|
|
127
|
+
const before = answer.slice(0, start).replace(/\s+$/u, "");
|
|
128
|
+
const after = answer.slice(match.index + match[0].length).replace(/^\s+/u, "");
|
|
129
|
+
const text = before && after ? `${before}\n\n${after}` : before || after;
|
|
130
|
+
return { text, buttons: parsed };
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* The parts a text answer with optional buttons becomes: the text first, when
|
|
134
|
+
* there is any, then the buttons. A buttons-only message is one the server
|
|
135
|
+
* accepts, so an answer that is nothing but the block sends just the buttons.
|
|
136
|
+
*/
|
|
137
|
+
export const partsWithButtons = (text, buttons, limit = Number.POSITIVE_INFINITY) => [
|
|
138
|
+
...(text.length > 0 ? [{ type: "text", value: text.slice(0, limit) }] : []),
|
|
139
|
+
...(buttons ? [buttons] : []),
|
|
140
|
+
];
|
|
141
|
+
//# sourceMappingURL=buttons.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buttons.js","sourceRoot":"","sources":["../src/buttons.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { CallRoomClientFrame, CallRoomEndedFrame, CallRoomErrorFrame, CallRoomIceServer, CallRoomIceServersFrame, CallRoomServerAnswerFrame, CallRoomServerFrame, CallRoomStateFrame, CallRoomSubscriptionOfferFrame } from "../types.js";
|
|
2
|
+
import type { WebSocketConstructor } from "../websocket.js";
|
|
3
|
+
export interface CallRoomOptions {
|
|
4
|
+
/** Abort closes the signaling socket without ending the Call. */
|
|
5
|
+
signal?: AbortSignal;
|
|
6
|
+
/** Override the Node WebSocket implementation, primarily for tests. */
|
|
7
|
+
WebSocket?: WebSocketConstructor;
|
|
8
|
+
/** Client heartbeat cadence. Relay's room heartbeat frame has no payload. */
|
|
9
|
+
heartbeatIntervalMs?: number;
|
|
10
|
+
/**
|
|
11
|
+
* Called once per unknown server frame type, which the room ignores.
|
|
12
|
+
* Defaults to `console.warn`.
|
|
13
|
+
*/
|
|
14
|
+
onWarning?: (message: string) => void;
|
|
15
|
+
}
|
|
16
|
+
export interface CallRoomCloseEvent {
|
|
17
|
+
code: number;
|
|
18
|
+
reason: string;
|
|
19
|
+
wasClean: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The room socket dropped, or an attempt to open one failed, and the room
|
|
23
|
+
* opens a new one after `delayMs`. Media rides the SFU, not this socket, so the
|
|
24
|
+
* Call and its WebRTC session continue; nothing is re-offered.
|
|
25
|
+
*/
|
|
26
|
+
export interface CallRoomReconnectingEvent {
|
|
27
|
+
/** 1 for the first retry; the count resets once a socket stays open 5 s. */
|
|
28
|
+
attempt: number;
|
|
29
|
+
delayMs: number;
|
|
30
|
+
/** The close that caused the retry; absent when an attempt failed before opening. */
|
|
31
|
+
close?: CallRoomCloseEvent;
|
|
32
|
+
/** Why the failed attempt did not open (connect timeout, handshake error). */
|
|
33
|
+
error?: Error;
|
|
34
|
+
}
|
|
35
|
+
export type CallRoomConnectionState = "idle" | "connecting" | "open" | "reconnecting" | "closed";
|
|
36
|
+
export type CallRoomEventMap = {
|
|
37
|
+
open: [];
|
|
38
|
+
reconnecting: [CallRoomReconnectingEvent];
|
|
39
|
+
/** The room's STUN/TURN servers, sent after every accepted `join`, before its `roomState`. */
|
|
40
|
+
iceServers: [CallRoomIceServersFrame];
|
|
41
|
+
roomState: [CallRoomStateFrame];
|
|
42
|
+
offer: [CallRoomSubscriptionOfferFrame];
|
|
43
|
+
answer: [CallRoomServerAnswerFrame];
|
|
44
|
+
ended: [CallRoomEndedFrame];
|
|
45
|
+
error: [CallRoomErrorFrame | Error];
|
|
46
|
+
/** The room socket closed and the room will not reopen it by itself. */
|
|
47
|
+
close: [CallRoomCloseEvent];
|
|
48
|
+
};
|
|
49
|
+
type CallRoomEvent = keyof CallRoomEventMap;
|
|
50
|
+
type Listener<K extends CallRoomEvent> = (...args: CallRoomEventMap[K]) => void;
|
|
51
|
+
/**
|
|
52
|
+
* Validate one server frame before exposing it to application code. Returns
|
|
53
|
+
* `null` for Relay's echoed heartbeat (not part of the public server-frame
|
|
54
|
+
* union) and for a frame type this client does not know (a newer Relay's
|
|
55
|
+
* frame, ignored). Throws for a known frame type whose shape is invalid.
|
|
56
|
+
*/
|
|
57
|
+
export declare const parseCallRoomServerFrame: (value: unknown) => CallRoomServerFrame | null;
|
|
58
|
+
/**
|
|
59
|
+
* Authenticated JSON signaling socket for one Relay Call participant.
|
|
60
|
+
*
|
|
61
|
+
* The room reopens its socket after any close that neither this client nor the
|
|
62
|
+
* server asked for, with PartySocket's numbers (PROTOCOL.md section 5): first
|
|
63
|
+
* retry after 3000 ms, then x1.3, capped at 10000 ms, a 4000 ms connect
|
|
64
|
+
* timeout, the retry count reset once a socket stays open 5000 ms, and no
|
|
65
|
+
* retry limit. On every open it sends `join`, then `userUpdate` with the last
|
|
66
|
+
* muted/video state, then the frames queued while closed. Media is never
|
|
67
|
+
* re-offered by a socket-only reconnect.
|
|
68
|
+
*/
|
|
69
|
+
export declare class CallRoom {
|
|
70
|
+
#private;
|
|
71
|
+
readonly callID: string;
|
|
72
|
+
readonly url: string;
|
|
73
|
+
state: CallRoomStateFrame | null;
|
|
74
|
+
/**
|
|
75
|
+
* The STUN/TURN servers from the room's latest `iceServers` frame, or `null`
|
|
76
|
+
* before the first one. Relay sends fresh ones on every join, reconnects
|
|
77
|
+
* included, so read this again before building each new peer connection.
|
|
78
|
+
*/
|
|
79
|
+
iceServers: CallRoomIceServer[] | null;
|
|
80
|
+
constructor(callID: string, baseURL: string, apiKey: string, options?: CallRoomOptions);
|
|
81
|
+
/** `reconnecting` while the room waits to reopen a dropped socket. */
|
|
82
|
+
get connectionState(): CallRoomConnectionState;
|
|
83
|
+
on<K extends CallRoomEvent>(event: K, listener: Listener<K>): this;
|
|
84
|
+
off<K extends CallRoomEvent>(event: K, listener: Listener<K>): this;
|
|
85
|
+
/** Resolves on the first open; a failed attempt is retried, not thrown. */
|
|
86
|
+
connect(): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Open a new signaling socket now, keeping application/WebRTC state alive.
|
|
89
|
+
* Relay accepts the new authenticated socket before the previous one closes,
|
|
90
|
+
* so an active Call is not interpreted as having lost its participant. Same
|
|
91
|
+
* path as the automatic reconnect (PartySocket `reconnect()`: retry count
|
|
92
|
+
* reset, no delay); if the new socket fails while the old one is still open,
|
|
93
|
+
* the old one stays and this rejects.
|
|
94
|
+
*/
|
|
95
|
+
reconnect(): Promise<void>;
|
|
96
|
+
/**
|
|
97
|
+
* Send one frame. While the socket is reopening the frame is queued and sent
|
|
98
|
+
* after `join` on the next open (PartySocket's queue); heartbeats are dropped.
|
|
99
|
+
*/
|
|
100
|
+
send(frame: CallRoomClientFrame): void;
|
|
101
|
+
connected(): void;
|
|
102
|
+
userUpdate(update: {
|
|
103
|
+
muted: boolean;
|
|
104
|
+
video?: boolean;
|
|
105
|
+
}): void;
|
|
106
|
+
end(): void;
|
|
107
|
+
close(code?: number, reason?: string): void;
|
|
108
|
+
}
|
|
109
|
+
export {};
|
|
110
|
+
//# sourceMappingURL=call-room.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"call-room.d.ts","sourceRoot":"","sources":["../../src/calls/call-room.ts"],"names":[],"mappings":"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"}
|