@callembed/sdk 0.1.0 → 0.1.2
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 +14 -0
- package/dist/callembed.iife.js +7 -7
- package/dist/core/api.js +15 -15
- package/dist/core/client.js +17 -0
- package/dist/core/errors.d.ts +1 -1
- package/dist/core/hosted-embed.d.ts +14 -0
- package/dist/core/hosted-embed.js +14 -0
- package/dist/core/types.d.ts +9 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +9 -1
package/dist/core/api.js
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { CallEmbedError } from "./errors.js";
|
|
2
2
|
import { assertValidMetadata } from "./metadata.js";
|
|
3
|
+
/** Publishable request headers; includes parent origin for hosted iframe (B109). */
|
|
4
|
+
function publishableHeaders(cfg, extra) {
|
|
5
|
+
const headers = {
|
|
6
|
+
"X-Publishable-Key": cfg.publishableKey,
|
|
7
|
+
...extra,
|
|
8
|
+
};
|
|
9
|
+
if (cfg.parentOrigin) {
|
|
10
|
+
headers["X-CallEmbed-Parent-Origin"] = cfg.parentOrigin;
|
|
11
|
+
}
|
|
12
|
+
return headers;
|
|
13
|
+
}
|
|
3
14
|
/**
|
|
4
15
|
* Create a call via `POST /v1/calls` using the publishable key only.
|
|
5
16
|
* Response includes `endToken` (memory-only — never persist or log).
|
|
@@ -9,10 +20,7 @@ export async function apiCreateCall(cfg, opts) {
|
|
|
9
20
|
const base = cfg.apiBaseUrl.replace(/\/$/, "");
|
|
10
21
|
const res = await fetch(`${base}/v1/calls`, {
|
|
11
22
|
method: "POST",
|
|
12
|
-
headers: {
|
|
13
|
-
"Content-Type": "application/json",
|
|
14
|
-
"X-Publishable-Key": cfg.publishableKey,
|
|
15
|
-
},
|
|
23
|
+
headers: publishableHeaders(cfg, { "Content-Type": "application/json" }),
|
|
16
24
|
body: JSON.stringify({
|
|
17
25
|
queue: opts.queue,
|
|
18
26
|
...(opts.metadata !== undefined ? { metadata: opts.metadata } : {}),
|
|
@@ -92,10 +100,7 @@ const STATUS_MAX_ATTEMPTS = 3;
|
|
|
92
100
|
export async function apiEndCall(cfg, callId, endToken) {
|
|
93
101
|
const url = endCallUrl(cfg, callId);
|
|
94
102
|
const body = endBody(endToken);
|
|
95
|
-
const headers = {
|
|
96
|
-
"Content-Type": "application/json",
|
|
97
|
-
"X-Publishable-Key": cfg.publishableKey,
|
|
98
|
-
};
|
|
103
|
+
const headers = publishableHeaders(cfg, { "Content-Type": "application/json" });
|
|
99
104
|
for (let attempt = 0; attempt < END_MAX_ATTEMPTS; attempt++) {
|
|
100
105
|
try {
|
|
101
106
|
const res = await fetch(url, { method: "POST", headers, body });
|
|
@@ -123,10 +128,7 @@ export function apiEndCallKeepalive(cfg, callId, endToken) {
|
|
|
123
128
|
try {
|
|
124
129
|
void fetch(endCallUrl(cfg, callId), {
|
|
125
130
|
method: "POST",
|
|
126
|
-
headers: {
|
|
127
|
-
"Content-Type": "application/json",
|
|
128
|
-
"X-Publishable-Key": cfg.publishableKey,
|
|
129
|
-
},
|
|
131
|
+
headers: publishableHeaders(cfg, { "Content-Type": "application/json" }),
|
|
130
132
|
body: endBody(endToken),
|
|
131
133
|
keepalive: true,
|
|
132
134
|
});
|
|
@@ -141,9 +143,7 @@ export function apiEndCallKeepalive(cfg, callId, endToken) {
|
|
|
141
143
|
* Retries briefly on 429 (Retry-After + jitter) so ring polls survive key/IP spikes.
|
|
142
144
|
*/
|
|
143
145
|
export async function apiGetCallStatus(cfg, callId, endToken) {
|
|
144
|
-
const headers =
|
|
145
|
-
"X-Publishable-Key": cfg.publishableKey,
|
|
146
|
-
};
|
|
146
|
+
const headers = publishableHeaders(cfg);
|
|
147
147
|
if (endToken)
|
|
148
148
|
headers["X-Call-End-Token"] = endToken;
|
|
149
149
|
const url = callStatusUrl(cfg, callId);
|
package/dist/core/client.js
CHANGED
|
@@ -86,6 +86,22 @@ export const CallEmbed = {
|
|
|
86
86
|
if (options.apiBaseUrl === undefined || options.apiBaseUrl === null) {
|
|
87
87
|
throw new CallEmbedError("invalid_config", 'apiBaseUrl is required (use "" for same-origin).');
|
|
88
88
|
}
|
|
89
|
+
const parentRaw = typeof options.parentOrigin === "string" ? options.parentOrigin.trim() : "";
|
|
90
|
+
let parentOrigin;
|
|
91
|
+
if (parentRaw) {
|
|
92
|
+
try {
|
|
93
|
+
const u = new URL(parentRaw);
|
|
94
|
+
if (u.protocol !== "http:" && u.protocol !== "https:") {
|
|
95
|
+
throw new CallEmbedError("invalid_config", "parentOrigin must be a valid http(s) origin.");
|
|
96
|
+
}
|
|
97
|
+
parentOrigin = u.origin;
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
if (err instanceof CallEmbedError)
|
|
101
|
+
throw err;
|
|
102
|
+
throw new CallEmbedError("invalid_config", "parentOrigin must be a valid http(s) origin.");
|
|
103
|
+
}
|
|
104
|
+
}
|
|
89
105
|
runtime = {
|
|
90
106
|
publishableKey: options.publishableKey.trim(),
|
|
91
107
|
apiBaseUrl: String(options.apiBaseUrl).trim().replace(/\/$/, ""),
|
|
@@ -94,6 +110,7 @@ export const CallEmbed = {
|
|
|
94
110
|
copyOverrides: options.copy ?? {},
|
|
95
111
|
branding: options.branding !== false,
|
|
96
112
|
debug: options.debug === true,
|
|
113
|
+
...(parentOrigin ? { parentOrigin } : {}),
|
|
97
114
|
};
|
|
98
115
|
},
|
|
99
116
|
/**
|
package/dist/core/errors.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Error codes and {@link CallEmbedError} for the public SDK surface.
|
|
3
3
|
*/
|
|
4
4
|
/** Well-known SDK / API error codes (English, machine-readable). */
|
|
5
|
-
export type ErrorCode = "not_initialized" | "invalid_config" | "invalid_queue" | "invalid_metadata" | "invalid_display_name" | "invalid_container" | "invalid_selector" | "call_in_progress" | "mic_permission_denied" | "no_microphone" | "connection_failed" | "call_failed" | "no_agent_online" | "no_answer" | "agent_busy" | "call_already_answered" | "invalid_end_token" | "quota_exceeded" | "origin_not_allowed" | "invalid_publishable_key" | "rate_limited" | "livekit_not_configured" | "unknown_queue";
|
|
5
|
+
export type ErrorCode = "not_initialized" | "invalid_config" | "invalid_queue" | "invalid_metadata" | "invalid_display_name" | "invalid_container" | "invalid_selector" | "call_in_progress" | "mic_permission_denied" | "no_microphone" | "connection_failed" | "call_failed" | "no_agent_online" | "no_answer" | "agent_busy" | "call_already_answered" | "invalid_end_token" | "quota_exceeded" | "origin_not_allowed" | "parent_origin_required" | "parent_origin_not_allowed" | "invalid_publishable_key" | "rate_limited" | "livekit_not_configured" | "unknown_queue";
|
|
6
6
|
/**
|
|
7
7
|
* Thrown by CallEmbed SDK methods and surfaced via the `error` event.
|
|
8
8
|
*/
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hosted iframe embed defaults (B135).
|
|
3
|
+
*
|
|
4
|
+
* Production iframe lives on its own origin so callembed-web can keep a global
|
|
5
|
+
* `X-Frame-Options: DENY`. Override the URL when self-hosting the embed page.
|
|
6
|
+
*
|
|
7
|
+
* Legacy `https://app.callembed.sealby.me/embed.html` (and the Render
|
|
8
|
+
* `callembed-web` hostname) remain parseable as iframe `src` values but are
|
|
9
|
+
* blocked by the app site's permanent DENY — prefer the URL below.
|
|
10
|
+
*/
|
|
11
|
+
/** Origin that serves the hosted `/embed.html` page. */
|
|
12
|
+
export declare const DEFAULT_HOSTED_EMBED_ORIGIN = "https://callembed-embed.onrender.com";
|
|
13
|
+
/** Default hosted iframe document URL (configurable by overriding iframe `src`). */
|
|
14
|
+
export declare const DEFAULT_HOSTED_EMBED_URL = "https://callembed-embed.onrender.com/embed.html";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hosted iframe embed defaults (B135).
|
|
3
|
+
*
|
|
4
|
+
* Production iframe lives on its own origin so callembed-web can keep a global
|
|
5
|
+
* `X-Frame-Options: DENY`. Override the URL when self-hosting the embed page.
|
|
6
|
+
*
|
|
7
|
+
* Legacy `https://app.callembed.sealby.me/embed.html` (and the Render
|
|
8
|
+
* `callembed-web` hostname) remain parseable as iframe `src` values but are
|
|
9
|
+
* blocked by the app site's permanent DENY — prefer the URL below.
|
|
10
|
+
*/
|
|
11
|
+
/** Origin that serves the hosted `/embed.html` page. */
|
|
12
|
+
export const DEFAULT_HOSTED_EMBED_ORIGIN = "https://callembed-embed.onrender.com";
|
|
13
|
+
/** Default hosted iframe document URL (configurable by overriding iframe `src`). */
|
|
14
|
+
export const DEFAULT_HOSTED_EMBED_URL = `${DEFAULT_HOSTED_EMBED_ORIGIN}/embed.html`;
|
package/dist/core/types.d.ts
CHANGED
|
@@ -43,6 +43,13 @@ export interface InitOptions {
|
|
|
43
43
|
* Default: `false`.
|
|
44
44
|
*/
|
|
45
45
|
debug?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Embedding parent page origin for the hosted iframe (`embed.html`).
|
|
48
|
+
* Sent as `X-CallEmbed-Parent-Origin` on publishable API calls. Required by
|
|
49
|
+
* the API when the browser `Origin` is the hosted embed host (B109).
|
|
50
|
+
* Ordinary first-party SDK usage should omit this.
|
|
51
|
+
*/
|
|
52
|
+
parentOrigin?: string;
|
|
46
53
|
}
|
|
47
54
|
/**
|
|
48
55
|
* Options for {@link CallEmbed.startCall}.
|
|
@@ -172,4 +179,6 @@ export interface RuntimeConfig {
|
|
|
172
179
|
copyOverrides: Partial<Record<string, string>>;
|
|
173
180
|
branding: boolean;
|
|
174
181
|
debug: boolean;
|
|
182
|
+
/** See {@link InitOptions.parentOrigin}. */
|
|
183
|
+
parentOrigin?: string;
|
|
175
184
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,5 +7,6 @@
|
|
|
7
7
|
export { CallEmbed } from "./core/client.js";
|
|
8
8
|
export { CallEmbedError, type ErrorCode } from "./core/errors.js";
|
|
9
9
|
export { METADATA_MAX_BYTES, assertValidMetadata } from "./core/metadata.js";
|
|
10
|
+
export { DEFAULT_HOSTED_EMBED_ORIGIN, DEFAULT_HOSTED_EMBED_URL, } from "./core/hosted-embed.js";
|
|
10
11
|
export type { ActiveCall, ApiErrorBody, CallEventHandler, CallEventMap, CallEventName, CallSession, CallStatus, InitOptions, Locale, RuntimeConfig, StartCallEventHandlers, StartCallOptions, } from "./core/types.js";
|
|
11
12
|
export { CallEmbed as default } from "./core/client.js";
|
package/dist/index.js
CHANGED
|
@@ -7,4 +7,5 @@
|
|
|
7
7
|
export { CallEmbed } from "./core/client.js";
|
|
8
8
|
export { CallEmbedError } from "./core/errors.js";
|
|
9
9
|
export { METADATA_MAX_BYTES, assertValidMetadata } from "./core/metadata.js";
|
|
10
|
+
export { DEFAULT_HOSTED_EMBED_ORIGIN, DEFAULT_HOSTED_EMBED_URL, } from "./core/hosted-embed.js";
|
|
10
11
|
export { CallEmbed as default } from "./core/client.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@callembed/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "CallEmbed embeddable web SDK — headless core + optional UI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Sealby",
|
|
@@ -42,6 +42,14 @@
|
|
|
42
42
|
"pack:verify:workflow": "node ./scripts/pack-verify-workflow-smoke.mjs"
|
|
43
43
|
},
|
|
44
44
|
"homepage": "https://callembed.sealby.me",
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "git+https://github.com/TonyFeng1203/CallEmbed.git",
|
|
48
|
+
"directory": "packages/sdk"
|
|
49
|
+
},
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/TonyFeng1203/CallEmbed/issues"
|
|
52
|
+
},
|
|
45
53
|
"keywords": [
|
|
46
54
|
"callembed",
|
|
47
55
|
"voice",
|