@tinyweb_dev/oe-meeting-react 0.5.0 → 0.6.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/index.cjs +103 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +44 -5
- package/dist/index.d.ts +44 -5
- package/dist/index.js +101 -27
- package/dist/index.js.map +1 -1
- package/docs/BACKEND-INTEGRATION.md +38 -4
- package/docs/REACT-INTEGRATION.md +40 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -24,6 +24,7 @@ __export(index_exports, {
|
|
|
24
24
|
DEFAULT_IFRAME_ALLOW: () => DEFAULT_IFRAME_ALLOW,
|
|
25
25
|
EMBED_MESSAGE_SOURCE: () => EMBED_MESSAGE_SOURCE,
|
|
26
26
|
EMBED_PROTOCOL_VERSION: () => EMBED_PROTOCOL_VERSION,
|
|
27
|
+
EmbedBackgroundType: () => EmbedBackgroundType,
|
|
27
28
|
EmbedCapability: () => EmbedCapability,
|
|
28
29
|
EmbedCaptureOutcome: () => EmbedCaptureOutcome,
|
|
29
30
|
EmbedCommandAction: () => EmbedCommandAction,
|
|
@@ -32,14 +33,17 @@ __export(index_exports, {
|
|
|
32
33
|
EmbedEventType: () => EmbedEventType,
|
|
33
34
|
EmbedQueryParam: () => EmbedQueryParam,
|
|
34
35
|
EmbedRole: () => EmbedRole,
|
|
36
|
+
MAX_BACKGROUND_URL_LENGTH: () => MAX_BACKGROUND_URL_LENGTH,
|
|
35
37
|
MAX_STAGE_TOOL_ID_LENGTH: () => MAX_STAGE_TOOL_ID_LENGTH,
|
|
36
38
|
MAX_STAGE_URL_LENGTH: () => MAX_STAGE_URL_LENGTH,
|
|
37
39
|
OeMeeting: () => OeMeeting,
|
|
38
40
|
buildEmbedUrl: () => buildEmbedUrl,
|
|
39
41
|
isStageToolId: () => isStageToolId,
|
|
40
42
|
isValidStageUrl: () => isValidStageUrl,
|
|
43
|
+
normalizeEmbedBackground: () => normalizeEmbedBackground,
|
|
41
44
|
normalizeOpenStageInput: () => normalizeOpenStageInput,
|
|
42
45
|
parseEmbedEvent: () => parseEmbedEvent,
|
|
46
|
+
serializeEmbedBackground: () => serializeEmbedBackground,
|
|
43
47
|
useOeMeeting: () => useOeMeeting
|
|
44
48
|
});
|
|
45
49
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -75,6 +79,7 @@ var EmbedCommandAction = /* @__PURE__ */ ((EmbedCommandAction2) => {
|
|
|
75
79
|
EmbedCommandAction2["TOGGLE_CAMERA"] = "toggleCamera";
|
|
76
80
|
EmbedCommandAction2["OPEN_STAGE"] = "openStage";
|
|
77
81
|
EmbedCommandAction2["CLOSE_STAGE"] = "closeStage";
|
|
82
|
+
EmbedCommandAction2["SET_BACKGROUND"] = "setBackground";
|
|
78
83
|
return EmbedCommandAction2;
|
|
79
84
|
})(EmbedCommandAction || {});
|
|
80
85
|
var EmbedErrorCode = /* @__PURE__ */ ((EmbedErrorCode2) => {
|
|
@@ -91,6 +96,16 @@ var EmbedErrorCode = /* @__PURE__ */ ((EmbedErrorCode2) => {
|
|
|
91
96
|
EmbedErrorCode2["UNKNOWN"] = "UNKNOWN";
|
|
92
97
|
return EmbedErrorCode2;
|
|
93
98
|
})(EmbedErrorCode || {});
|
|
99
|
+
var EmbedBackgroundType = /* @__PURE__ */ ((EmbedBackgroundType2) => {
|
|
100
|
+
EmbedBackgroundType2["BLUR"] = "blur";
|
|
101
|
+
EmbedBackgroundType2["IMAGE"] = "image";
|
|
102
|
+
EmbedBackgroundType2["NONE"] = "none";
|
|
103
|
+
return EmbedBackgroundType2;
|
|
104
|
+
})(EmbedBackgroundType || {});
|
|
105
|
+
var MAX_BACKGROUND_URL_LENGTH = 2048;
|
|
106
|
+
var DEFAULT_BACKGROUND_BLUR_RADIUS = 10;
|
|
107
|
+
var MIN_BACKGROUND_BLUR_RADIUS = 1;
|
|
108
|
+
var MAX_BACKGROUND_BLUR_RADIUS = 50;
|
|
94
109
|
var MAX_STAGE_URL_LENGTH = 2048;
|
|
95
110
|
var MAX_STAGE_TOOL_ID_LENGTH = 32;
|
|
96
111
|
var STAGE_TOOL_ID_PATTERN = /^[a-z][a-z0-9._-]{0,31}$/;
|
|
@@ -109,6 +124,7 @@ var EmbedQueryParam = /* @__PURE__ */ ((EmbedQueryParam2) => {
|
|
|
109
124
|
EmbedQueryParam2["AUTO_CAMERA_OFF"] = "autoCameraOff";
|
|
110
125
|
EmbedQueryParam2["AUTO_TRANSCRIBE"] = "autoTranscribe";
|
|
111
126
|
EmbedQueryParam2["AUTO_RECORD"] = "autoRecord";
|
|
127
|
+
EmbedQueryParam2["BACKGROUND"] = "background";
|
|
112
128
|
return EmbedQueryParam2;
|
|
113
129
|
})(EmbedQueryParam || {});
|
|
114
130
|
var EmbedCaptureOutcome = /* @__PURE__ */ ((EmbedCaptureOutcome2) => {
|
|
@@ -128,6 +144,62 @@ var EmbedCapability = /* @__PURE__ */ ((EmbedCapability2) => {
|
|
|
128
144
|
return EmbedCapability2;
|
|
129
145
|
})(EmbedCapability || {});
|
|
130
146
|
|
|
147
|
+
// src/openStage.ts
|
|
148
|
+
function isValidStageUrl(url) {
|
|
149
|
+
if (url.length === 0 || url.length > MAX_STAGE_URL_LENGTH) return false;
|
|
150
|
+
try {
|
|
151
|
+
const parsed = new URL(url);
|
|
152
|
+
if (parsed.protocol === "https:") return true;
|
|
153
|
+
if (parsed.protocol === "http:") {
|
|
154
|
+
return parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1";
|
|
155
|
+
}
|
|
156
|
+
return false;
|
|
157
|
+
} catch {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function normalizeOpenStageInput(input) {
|
|
162
|
+
const url = input.url.trim();
|
|
163
|
+
if (!isValidStageUrl(url)) return null;
|
|
164
|
+
const title = input.title?.trim();
|
|
165
|
+
return {
|
|
166
|
+
url,
|
|
167
|
+
...title ? { title: title.slice(0, 200) } : {},
|
|
168
|
+
...isStageToolId(input.tool) ? { tool: input.tool } : {}
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// src/background.ts
|
|
173
|
+
var isValidBackgroundUrl = (url) => url.length > 0 && url.length <= MAX_BACKGROUND_URL_LENGTH && isValidStageUrl(url);
|
|
174
|
+
var clampBlurRadius = (value) => Number.isFinite(value) ? Math.min(MAX_BACKGROUND_BLUR_RADIUS, Math.max(MIN_BACKGROUND_BLUR_RADIUS, Math.round(value))) : DEFAULT_BACKGROUND_BLUR_RADIUS;
|
|
175
|
+
function normalizeEmbedBackground(input) {
|
|
176
|
+
const locked = input.locked === true ? { locked: true } : {};
|
|
177
|
+
if (input.type === "none" /* NONE */) {
|
|
178
|
+
return { type: "none" /* NONE */, ...locked };
|
|
179
|
+
}
|
|
180
|
+
if (input.type === "blur" /* BLUR */) {
|
|
181
|
+
return {
|
|
182
|
+
type: "blur" /* BLUR */,
|
|
183
|
+
blurRadius: clampBlurRadius(input.blurRadius ?? DEFAULT_BACKGROUND_BLUR_RADIUS),
|
|
184
|
+
...locked
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
if (input.type === "image" /* IMAGE */) {
|
|
188
|
+
const url = input.url?.trim();
|
|
189
|
+
if (!url || !isValidBackgroundUrl(url)) return null;
|
|
190
|
+
return {
|
|
191
|
+
type: "image" /* IMAGE */,
|
|
192
|
+
url,
|
|
193
|
+
...locked
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
function serializeEmbedBackground(input) {
|
|
199
|
+
const normalized = normalizeEmbedBackground(input);
|
|
200
|
+
return normalized ? JSON.stringify(normalized) : void 0;
|
|
201
|
+
}
|
|
202
|
+
|
|
131
203
|
// src/buildEmbedUrl.ts
|
|
132
204
|
var QUERY_FLAG_ENABLED = "1";
|
|
133
205
|
var QUERY_FLAG_DISABLED = "0";
|
|
@@ -149,6 +221,7 @@ function buildEmbedUrl(options) {
|
|
|
149
221
|
}
|
|
150
222
|
const origin = normalizeOrigin(options.origin ?? DEFAULT_EMBED_ORIGIN);
|
|
151
223
|
const url = new URL(`${origin}/embed/${encodeURIComponent(roomSlug)}`);
|
|
224
|
+
const backgroundParam = options.background ? serializeEmbedBackground(options.background) : void 0;
|
|
152
225
|
const entries = [
|
|
153
226
|
["instanceId" /* INSTANCE_ID */, options.instanceId],
|
|
154
227
|
["hostOrigin" /* HOST_ORIGIN */, options.hostOrigin],
|
|
@@ -160,7 +233,8 @@ function buildEmbedUrl(options) {
|
|
|
160
233
|
["hideLeave" /* HIDE_LEAVE */, toFlag(options.hideLeave)],
|
|
161
234
|
["autoCameraOff" /* AUTO_CAMERA_OFF */, toFlag(options.autoCameraOff)],
|
|
162
235
|
["autoTranscribe" /* AUTO_TRANSCRIBE */, toFlag(options.autoTranscribe)],
|
|
163
|
-
["autoRecord" /* AUTO_RECORD */, toFlag(options.autoRecord)]
|
|
236
|
+
["autoRecord" /* AUTO_RECORD */, toFlag(options.autoRecord)],
|
|
237
|
+
["background" /* BACKGROUND */, backgroundParam]
|
|
164
238
|
];
|
|
165
239
|
for (const [key, value] of entries) {
|
|
166
240
|
if (value !== void 0 && value !== "") {
|
|
@@ -173,31 +247,6 @@ function buildEmbedUrl(options) {
|
|
|
173
247
|
// src/useOeMeeting.ts
|
|
174
248
|
var import_react = require("react");
|
|
175
249
|
|
|
176
|
-
// src/openStage.ts
|
|
177
|
-
function isValidStageUrl(url) {
|
|
178
|
-
if (url.length === 0 || url.length > MAX_STAGE_URL_LENGTH) return false;
|
|
179
|
-
try {
|
|
180
|
-
const parsed = new URL(url);
|
|
181
|
-
if (parsed.protocol === "https:") return true;
|
|
182
|
-
if (parsed.protocol === "http:") {
|
|
183
|
-
return parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1";
|
|
184
|
-
}
|
|
185
|
-
return false;
|
|
186
|
-
} catch {
|
|
187
|
-
return false;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
function normalizeOpenStageInput(input) {
|
|
191
|
-
const url = input.url.trim();
|
|
192
|
-
if (!isValidStageUrl(url)) return null;
|
|
193
|
-
const title = input.title?.trim();
|
|
194
|
-
return {
|
|
195
|
-
url,
|
|
196
|
-
...title ? { title: title.slice(0, 200) } : {},
|
|
197
|
-
...isStageToolId(input.tool) ? { tool: input.tool } : {}
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
250
|
// src/parseEmbedEvent.ts
|
|
202
251
|
var EVENT_TYPES = new Set(Object.values(EmbedEventType));
|
|
203
252
|
function isRecord(value) {
|
|
@@ -266,6 +315,7 @@ function postCommand(options) {
|
|
|
266
315
|
function useOeMeeting(options) {
|
|
267
316
|
const iframeRef = (0, import_react.useRef)(null);
|
|
268
317
|
const callbacksRef = (0, import_react.useRef)(options);
|
|
318
|
+
const pendingBackgroundRef = (0, import_react.useRef)(null);
|
|
269
319
|
(0, import_react.useEffect)(() => {
|
|
270
320
|
callbacksRef.current = options;
|
|
271
321
|
}, [options]);
|
|
@@ -282,6 +332,15 @@ function useOeMeeting(options) {
|
|
|
282
332
|
switch (embedEvent.type) {
|
|
283
333
|
case "oemeeting:ready" /* READY */:
|
|
284
334
|
callbacks.onReady?.(embedEvent);
|
|
335
|
+
if (pendingBackgroundRef.current) {
|
|
336
|
+
postCommand({
|
|
337
|
+
iframe: iframeRef.current,
|
|
338
|
+
instanceId: options.instanceId,
|
|
339
|
+
action: "setBackground" /* SET_BACKGROUND */,
|
|
340
|
+
targetOrigin: options.targetOrigin,
|
|
341
|
+
payload: pendingBackgroundRef.current
|
|
342
|
+
});
|
|
343
|
+
}
|
|
285
344
|
break;
|
|
286
345
|
case "oemeeting:joined" /* JOINED */:
|
|
287
346
|
callbacks.onJoined?.(embedEvent);
|
|
@@ -349,6 +408,16 @@ function useOeMeeting(options) {
|
|
|
349
408
|
() => send("closeStage" /* CLOSE_STAGE */),
|
|
350
409
|
[send]
|
|
351
410
|
);
|
|
411
|
+
(0, import_react.useEffect)(() => {
|
|
412
|
+
if (!options.background) {
|
|
413
|
+
pendingBackgroundRef.current = null;
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
const normalized = normalizeEmbedBackground(options.background);
|
|
417
|
+
if (!normalized) return;
|
|
418
|
+
pendingBackgroundRef.current = normalized;
|
|
419
|
+
send("setBackground" /* SET_BACKGROUND */, normalized);
|
|
420
|
+
}, [options.background, send]);
|
|
352
421
|
const getIframe = (0, import_react.useCallback)(() => iframeRef.current, []);
|
|
353
422
|
const handle = (0, import_react.useMemo)(
|
|
354
423
|
() => ({
|
|
@@ -389,6 +458,7 @@ var OeMeeting = (0, import_react2.forwardRef)(
|
|
|
389
458
|
autoCameraOff,
|
|
390
459
|
autoTranscribe,
|
|
391
460
|
autoRecord,
|
|
461
|
+
background,
|
|
392
462
|
title = "OE Meeting room",
|
|
393
463
|
width = "100%",
|
|
394
464
|
height = 640,
|
|
@@ -419,6 +489,7 @@ var OeMeeting = (0, import_react2.forwardRef)(
|
|
|
419
489
|
const embedOrigin = (0, import_react2.useMemo)(() => getOrigin(origin), [origin]);
|
|
420
490
|
const resolvedTargetOrigin = targetOrigin ?? embedOrigin;
|
|
421
491
|
const hostOrigin = typeof window === "undefined" ? void 0 : window.location.origin;
|
|
492
|
+
const initialBackgroundRef = (0, import_react2.useRef)(background);
|
|
422
493
|
const src = (0, import_react2.useMemo)(
|
|
423
494
|
() => buildEmbedUrl({
|
|
424
495
|
roomSlug,
|
|
@@ -432,6 +503,7 @@ var OeMeeting = (0, import_react2.forwardRef)(
|
|
|
432
503
|
autoCameraOff,
|
|
433
504
|
autoTranscribe,
|
|
434
505
|
autoRecord,
|
|
506
|
+
background: initialBackgroundRef.current,
|
|
435
507
|
instanceId,
|
|
436
508
|
hostOrigin
|
|
437
509
|
}),
|
|
@@ -452,6 +524,7 @@ var OeMeeting = (0, import_react2.forwardRef)(
|
|
|
452
524
|
]
|
|
453
525
|
);
|
|
454
526
|
const { iframeRef } = useOeMeeting({
|
|
527
|
+
background,
|
|
455
528
|
instanceId,
|
|
456
529
|
targetOrigin: resolvedTargetOrigin,
|
|
457
530
|
handleRef: ref,
|
|
@@ -510,6 +583,7 @@ OeMeeting.displayName = "OeMeeting";
|
|
|
510
583
|
DEFAULT_IFRAME_ALLOW,
|
|
511
584
|
EMBED_MESSAGE_SOURCE,
|
|
512
585
|
EMBED_PROTOCOL_VERSION,
|
|
586
|
+
EmbedBackgroundType,
|
|
513
587
|
EmbedCapability,
|
|
514
588
|
EmbedCaptureOutcome,
|
|
515
589
|
EmbedCommandAction,
|
|
@@ -518,14 +592,17 @@ OeMeeting.displayName = "OeMeeting";
|
|
|
518
592
|
EmbedEventType,
|
|
519
593
|
EmbedQueryParam,
|
|
520
594
|
EmbedRole,
|
|
595
|
+
MAX_BACKGROUND_URL_LENGTH,
|
|
521
596
|
MAX_STAGE_TOOL_ID_LENGTH,
|
|
522
597
|
MAX_STAGE_URL_LENGTH,
|
|
523
598
|
OeMeeting,
|
|
524
599
|
buildEmbedUrl,
|
|
525
600
|
isStageToolId,
|
|
526
601
|
isValidStageUrl,
|
|
602
|
+
normalizeEmbedBackground,
|
|
527
603
|
normalizeOpenStageInput,
|
|
528
604
|
parseEmbedEvent,
|
|
605
|
+
serializeEmbedBackground,
|
|
529
606
|
useOeMeeting
|
|
530
607
|
});
|
|
531
608
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/OeMeeting.tsx","../src/embed-protocol.ts","../src/buildEmbedUrl.ts","../src/useOeMeeting.ts","../src/openStage.ts","../src/parseEmbedEvent.ts"],"sourcesContent":["export { OeMeeting, DEFAULT_IFRAME_ALLOW } from './OeMeeting';\nexport { useOeMeeting } from './useOeMeeting';\nexport { buildEmbedUrl } from './buildEmbedUrl';\nexport { parseEmbedEvent } from './parseEmbedEvent';\nexport {\n DEFAULT_EMBED_ORIGIN,\n EMBED_MESSAGE_SOURCE,\n EMBED_PROTOCOL_VERSION,\n EmbedCapability,\n EmbedCaptureOutcome,\n EmbedCommandAction,\n EmbedRole,\n EmbedCommandType,\n EmbedErrorCode,\n EmbedEventType,\n EmbedQueryParam,\n isStageToolId,\n MAX_STAGE_TOOL_ID_LENGTH,\n MAX_STAGE_URL_LENGTH,\n} from './embed-protocol';\nexport type { EmbedPermissionMap, StageToolId } from './embed-protocol';\nexport { isValidStageUrl, normalizeOpenStageInput } from './openStage';\nexport type {\n BuildEmbedUrlOptions,\n EmbedCommandMessage,\n EmbedEndedPayload,\n EmbedErrorPayload,\n EmbedEvent,\n EmbedEventOf,\n EmbedEventPayloadMap,\n EmbedJoinedPayload,\n EmbedLeftPayload,\n EmbedMessageBase,\n EmbedParticipantJoinedPayload,\n EmbedParticipantLeftPayload,\n EmbedReadyPayload,\n EmbedRecordingSavedPayload,\n EmbedRecordingStartedPayload,\n EmbedStageChangedPayload,\n EmbedTranscriptStartedPayload,\n OeMeetingHandle,\n OeMeetingProps,\n OpenStageInput,\n} from './types';\n","'use client';\n\nimport {\n forwardRef,\n useId,\n useMemo,\n type CSSProperties,\n} from 'react';\nimport { buildEmbedUrl } from './buildEmbedUrl';\nimport { DEFAULT_EMBED_ORIGIN } from './embed-protocol';\nimport type { OeMeetingHandle, OeMeetingProps } from './types';\nimport { useOeMeeting } from './useOeMeeting';\n\nexport const DEFAULT_IFRAME_ALLOW =\n 'camera; microphone; fullscreen; autoplay; display-capture; clipboard-write; encrypted-media';\n\nfunction toCssSize(value: number | string | undefined): string | undefined {\n if (value === undefined) return undefined;\n return typeof value === 'number' ? `${value}px` : value;\n}\n\nfunction getOrigin(value: string): string {\n return new URL(value).origin;\n}\n\nexport const OeMeeting = forwardRef<OeMeetingHandle, OeMeetingProps>(\n function OeMeeting(props, ref) {\n const {\n roomSlug,\n joinToken,\n userName,\n externalUserId,\n origin = DEFAULT_EMBED_ORIGIN,\n lang,\n autoJoin = true,\n hideLeave,\n autoCameraOff,\n autoTranscribe,\n autoRecord,\n title = 'OE Meeting room',\n width = '100%',\n height = 640,\n className,\n style,\n iframeClassName,\n iframeStyle,\n allow = DEFAULT_IFRAME_ALLOW,\n targetOrigin,\n onReady,\n onJoined,\n onLeft,\n onParticipantJoined,\n onParticipantLeft,\n onEnded,\n onError,\n onStageChanged,\n onTranscriptStarted,\n onRecordingStarted,\n onRecordingSaved,\n onEvent,\n } = props;\n const reactId = useId();\n const instanceId = useMemo(\n () => `oem-${reactId.replace(/:/g, '')}`,\n [reactId],\n );\n const embedOrigin = useMemo(() => getOrigin(origin), [origin]);\n const resolvedTargetOrigin = targetOrigin ?? embedOrigin;\n const hostOrigin =\n typeof window === 'undefined' ? undefined : window.location.origin;\n const src = useMemo(\n () =>\n buildEmbedUrl({\n roomSlug,\n joinToken,\n userName,\n externalUserId,\n origin,\n lang,\n autoJoin,\n hideLeave,\n autoCameraOff,\n autoTranscribe,\n autoRecord,\n instanceId,\n hostOrigin,\n }),\n [\n autoJoin,\n autoRecord,\n autoTranscribe,\n externalUserId,\n hideLeave,\n hostOrigin,\n instanceId,\n joinToken,\n lang,\n origin,\n roomSlug,\n autoCameraOff,\n userName,\n ],\n );\n const { iframeRef } = useOeMeeting({\n instanceId,\n targetOrigin: resolvedTargetOrigin,\n handleRef: ref,\n onReady,\n onJoined,\n onLeft,\n onParticipantJoined,\n onParticipantLeft,\n onEnded,\n onError,\n onStageChanged,\n onTranscriptStarted,\n onRecordingStarted,\n onRecordingSaved,\n onEvent,\n });\n const wrapperStyle: CSSProperties = {\n width: toCssSize(width),\n height: toCssSize(height),\n ...style,\n };\n const frameStyle: CSSProperties = {\n width: '100%',\n height: '100%',\n border: 0,\n display: 'block',\n ...iframeStyle,\n };\n\n return (\n <div\n className={className}\n style={wrapperStyle}\n data-oe-meeting-instance={instanceId}\n >\n <iframe\n ref={iframeRef}\n className={iframeClassName}\n style={frameStyle}\n src={src}\n title={title}\n allow={allow}\n allowFullScreen\n referrerPolicy=\"strict-origin-when-cross-origin\"\n />\n </div>\n );\n },\n);\n\nOeMeeting.displayName = 'OeMeeting';\n","export const EMBED_PROTOCOL_VERSION = 1 as const;\nexport const EMBED_MESSAGE_SOURCE = 'oemeeting' as const;\nexport const DEFAULT_EMBED_ORIGIN = 'https://meet.ocean.edu.vn';\n\nexport enum EmbedEventType {\n READY = 'oemeeting:ready',\n JOINED = 'oemeeting:joined',\n LEFT = 'oemeeting:left',\n PARTICIPANT_JOINED = 'oemeeting:participant-joined',\n PARTICIPANT_LEFT = 'oemeeting:participant-left',\n ENDED = 'oemeeting:ended',\n ERROR = 'oemeeting:error',\n STAGE_CHANGED = 'oemeeting:stage-changed',\n TRANSCRIPT_STARTED = 'oemeeting:transcript-started',\n RECORDING_STARTED = 'oemeeting:recording-started',\n RECORDING_SAVED = 'oemeeting:recording-saved',\n}\n\nexport enum EmbedCommandType {\n COMMAND = 'oemeeting:command',\n}\n\nexport enum EmbedCommandAction {\n LEAVE = 'leave',\n TOGGLE_MIC = 'toggleMic',\n TOGGLE_CAMERA = 'toggleCamera',\n OPEN_STAGE = 'openStage',\n CLOSE_STAGE = 'closeStage',\n}\n\nexport enum EmbedErrorCode {\n TOKEN_INVALID = 'TOKEN_INVALID',\n TOKEN_EXPIRED = 'TOKEN_EXPIRED',\n ROOM_NOT_FOUND = 'ROOM_NOT_FOUND',\n ROOM_ACCESS_DENIED = 'ROOM_ACCESS_DENIED',\n CONNECTION_FAILED = 'CONNECTION_FAILED',\n PROTOCOL_MISMATCH = 'PROTOCOL_MISMATCH',\n STAGE_ORIGIN_DENIED = 'STAGE_ORIGIN_DENIED',\n STAGE_URL_INVALID = 'STAGE_URL_INVALID',\n TRANSCRIPT_START_FAILED = 'TRANSCRIPT_START_FAILED',\n RECORDING_START_FAILED = 'RECORDING_START_FAILED',\n UNKNOWN = 'UNKNOWN',\n}\n\n/** Open host-owned tool id. Meeting does not catalog values. */\nexport type StageToolId = string;\n\nexport const MAX_STAGE_URL_LENGTH = 2048;\nexport const MAX_STAGE_TOOL_ID_LENGTH = 32;\n\nconst STAGE_TOOL_ID_PATTERN = /^[a-z][a-z0-9._-]{0,31}$/;\n\nexport function isStageToolId(value: unknown): value is StageToolId {\n return (\n typeof value === 'string' &&\n value.length > 0 &&\n value.length <= MAX_STAGE_TOOL_ID_LENGTH &&\n STAGE_TOOL_ID_PATTERN.test(value)\n );\n}\n\nexport enum EmbedQueryParam {\n INSTANCE_ID = 'instanceId',\n HOST_ORIGIN = 'hostOrigin',\n JOIN_TOKEN = 'joinToken',\n USER_NAME = 'userName',\n EXTERNAL_USER_ID = 'externalUserId',\n LANG = 'lang',\n AUTO_JOIN = 'autoJoin',\n HIDE_LEAVE = 'hideLeave',\n AUTO_CAMERA_OFF = 'autoCameraOff',\n AUTO_TRANSCRIBE = 'autoTranscribe',\n AUTO_RECORD = 'autoRecord',\n}\n\n/**\n * What happened to the auto-transcribe request the embed made.\n *\n * `ALREADY_RUNNING` is the normal outcome for every participant after the\n * first, because the transcript is a room-level asset rather than a\n * per-participant one. `DISABLED` means the OE Meeting deployment has\n * transcription turned off.\n */\nexport enum EmbedCaptureOutcome {\n STARTED = 'started',\n ALREADY_RUNNING = 'already_running',\n DISABLED = 'disabled',\n FAILED = 'failed',\n}\n\n/**\n * Role the host app assigns when minting a join token.\n * Keep values aligned with `EmbedRole` in the backend embed-permission enum.\n */\nexport enum EmbedRole {\n OWNER = 'owner',\n MEMBER = 'member',\n}\n\n/**\n * Capability the host app may grant per role. Meeting enforces this on the\n * join token, not on a React prop. `screenShare` is the only value today.\n */\nexport enum EmbedCapability {\n SCREEN_SHARE = 'screenShare',\n}\n\nexport interface EmbedPermissionMap {\n owner?: EmbedCapability[];\n member?: EmbedCapability[];\n}\n","import {\n DEFAULT_EMBED_ORIGIN,\n EmbedQueryParam,\n} from './embed-protocol';\nimport type { BuildEmbedUrlOptions } from './types';\n\nconst QUERY_FLAG_ENABLED = '1';\nconst QUERY_FLAG_DISABLED = '0';\n\nfunction toFlag(value: boolean | undefined): string | undefined {\n if (value === undefined) return undefined;\n return value ? QUERY_FLAG_ENABLED : QUERY_FLAG_DISABLED;\n}\n\nfunction normalizeOrigin(origin: string): string {\n return origin.replace(/\\/+$/, '');\n}\n\nexport function buildEmbedUrl(options: BuildEmbedUrlOptions): string {\n const roomSlug = options.roomSlug.trim();\n const joinToken = options.joinToken.trim();\n if (!roomSlug) {\n throw new Error('OE Meeting embed requires a non-empty roomSlug.');\n }\n if (!joinToken) {\n throw new Error('OE Meeting embed requires a non-empty joinToken.');\n }\n\n const origin = normalizeOrigin(options.origin ?? DEFAULT_EMBED_ORIGIN);\n const url = new URL(`${origin}/embed/${encodeURIComponent(roomSlug)}`);\n const entries: Array<[EmbedQueryParam, string | undefined]> = [\n [EmbedQueryParam.INSTANCE_ID, options.instanceId],\n [EmbedQueryParam.HOST_ORIGIN, options.hostOrigin],\n [EmbedQueryParam.JOIN_TOKEN, joinToken],\n [EmbedQueryParam.USER_NAME, options.userName],\n [EmbedQueryParam.EXTERNAL_USER_ID, options.externalUserId],\n [EmbedQueryParam.LANG, options.lang],\n [EmbedQueryParam.AUTO_JOIN, toFlag(options.autoJoin)],\n [EmbedQueryParam.HIDE_LEAVE, toFlag(options.hideLeave)],\n [EmbedQueryParam.AUTO_CAMERA_OFF, toFlag(options.autoCameraOff)],\n [EmbedQueryParam.AUTO_TRANSCRIBE, toFlag(options.autoTranscribe)],\n [EmbedQueryParam.AUTO_RECORD, toFlag(options.autoRecord)],\n ];\n\n for (const [key, value] of entries) {\n if (value !== undefined && value !== '') {\n url.searchParams.set(key, value);\n }\n }\n return url.toString();\n}\n","import {\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n type Ref,\n} from 'react';\nimport {\n EMBED_MESSAGE_SOURCE,\n EMBED_PROTOCOL_VERSION,\n EmbedCommandAction,\n EmbedCommandType,\n EmbedEventType,\n} from './embed-protocol';\nimport { normalizeOpenStageInput } from './openStage';\nimport { parseEmbedEvent } from './parseEmbedEvent';\nimport type {\n EmbedCommandMessage,\n OeMeetingHandle,\n OeMeetingProps,\n OpenStageInput,\n} from './types';\n\ntype UseOeMeetingOptions = Pick<\n OeMeetingProps,\n | 'onReady'\n | 'onJoined'\n | 'onLeft'\n | 'onParticipantJoined'\n | 'onParticipantLeft'\n | 'onEnded'\n | 'onError'\n | 'onStageChanged'\n | 'onTranscriptStarted'\n | 'onRecordingStarted'\n | 'onRecordingSaved'\n | 'onEvent'\n> & {\n instanceId: string;\n targetOrigin: string;\n handleRef?: Ref<OeMeetingHandle>;\n};\n\ninterface PostCommandOptions {\n iframe: HTMLIFrameElement | null;\n instanceId: string;\n action: EmbedCommandAction;\n targetOrigin: string;\n payload?: OpenStageInput;\n}\n\nfunction postCommand(options: PostCommandOptions): void {\n const frameWindow = options.iframe?.contentWindow;\n if (!frameWindow) return;\n const message: EmbedCommandMessage = {\n source: EMBED_MESSAGE_SOURCE,\n version: EMBED_PROTOCOL_VERSION,\n instanceId: options.instanceId,\n type: EmbedCommandType.COMMAND,\n action: options.action,\n ...(options.payload ? { payload: options.payload } : {}),\n };\n frameWindow.postMessage(message, options.targetOrigin);\n}\n\nexport function useOeMeeting(options: UseOeMeetingOptions) {\n const iframeRef = useRef<HTMLIFrameElement | null>(null);\n const callbacksRef = useRef(options);\n\n useEffect(() => {\n callbacksRef.current = options;\n }, [options]);\n\n useEffect(() => {\n const onMessage = (event: MessageEvent<unknown>) => {\n const frameWindow = iframeRef.current?.contentWindow;\n if (\n !frameWindow ||\n event.source !== frameWindow ||\n event.origin !== options.targetOrigin\n ) {\n return;\n }\n const embedEvent = parseEmbedEvent(event.data);\n if (!embedEvent || embedEvent.instanceId !== options.instanceId) return;\n\n const callbacks = callbacksRef.current;\n callbacks.onEvent?.(embedEvent);\n switch (embedEvent.type) {\n case EmbedEventType.READY:\n callbacks.onReady?.(embedEvent);\n break;\n case EmbedEventType.JOINED:\n callbacks.onJoined?.(embedEvent);\n break;\n case EmbedEventType.LEFT:\n callbacks.onLeft?.(embedEvent);\n break;\n case EmbedEventType.PARTICIPANT_JOINED:\n callbacks.onParticipantJoined?.(embedEvent);\n break;\n case EmbedEventType.PARTICIPANT_LEFT:\n callbacks.onParticipantLeft?.(embedEvent);\n break;\n case EmbedEventType.ENDED:\n callbacks.onEnded?.(embedEvent);\n break;\n case EmbedEventType.ERROR:\n callbacks.onError?.(embedEvent);\n break;\n case EmbedEventType.STAGE_CHANGED:\n callbacks.onStageChanged?.(embedEvent);\n break;\n case EmbedEventType.TRANSCRIPT_STARTED:\n callbacks.onTranscriptStarted?.(embedEvent);\n break;\n case EmbedEventType.RECORDING_STARTED:\n callbacks.onRecordingStarted?.(embedEvent);\n break;\n case EmbedEventType.RECORDING_SAVED:\n callbacks.onRecordingSaved?.(embedEvent);\n break;\n }\n };\n\n window.addEventListener('message', onMessage);\n return () => window.removeEventListener('message', onMessage);\n }, [options.instanceId, options.targetOrigin]);\n\n const send = useCallback(\n (action: EmbedCommandAction, payload?: OpenStageInput) =>\n postCommand({\n iframe: iframeRef.current,\n instanceId: options.instanceId,\n action,\n targetOrigin: options.targetOrigin,\n payload,\n }),\n [options.instanceId, options.targetOrigin],\n );\n const leave = useCallback(() => send(EmbedCommandAction.LEAVE), [send]);\n const toggleMic = useCallback(\n () => send(EmbedCommandAction.TOGGLE_MIC),\n [send],\n );\n const toggleCamera = useCallback(\n () => send(EmbedCommandAction.TOGGLE_CAMERA),\n [send],\n );\n const openStage = useCallback(\n (input: OpenStageInput) => {\n const normalized = normalizeOpenStageInput(input);\n if (!normalized) return;\n send(EmbedCommandAction.OPEN_STAGE, normalized);\n },\n [send],\n );\n const closeStage = useCallback(\n () => send(EmbedCommandAction.CLOSE_STAGE),\n [send],\n );\n const getIframe = useCallback(() => iframeRef.current, []);\n const handle = useMemo<OeMeetingHandle>(\n () => ({\n leave,\n toggleMic,\n toggleCamera,\n openStage,\n closeStage,\n getIframe,\n }),\n [closeStage, getIframe, leave, openStage, toggleCamera, toggleMic],\n );\n\n useImperativeHandle(options.handleRef, () => handle, [handle]);\n return { iframeRef, handle };\n}\n","import { isStageToolId, MAX_STAGE_URL_LENGTH } from './embed-protocol';\nimport type { OpenStageInput } from './types';\n\nexport function isValidStageUrl(url: string): boolean {\n if (url.length === 0 || url.length > MAX_STAGE_URL_LENGTH) return false;\n try {\n const parsed = new URL(url);\n if (parsed.protocol === 'https:') return true;\n if (parsed.protocol === 'http:') {\n return (\n parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1'\n );\n }\n return false;\n } catch {\n return false;\n }\n}\n\nexport function normalizeOpenStageInput(\n input: OpenStageInput,\n): OpenStageInput | null {\n const url = input.url.trim();\n if (!isValidStageUrl(url)) return null;\n const title = input.title?.trim();\n return {\n url,\n ...(title ? { title: title.slice(0, 200) } : {}),\n ...(isStageToolId(input.tool) ? { tool: input.tool } : {}),\n };\n}\n","import {\n EMBED_MESSAGE_SOURCE,\n EMBED_PROTOCOL_VERSION,\n EmbedCaptureOutcome,\n EmbedEventType,\n} from './embed-protocol';\nimport type { EmbedEvent } from './types';\n\nconst EVENT_TYPES = new Set<string>(Object.values(EmbedEventType));\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction isOptionalString(value: unknown): boolean {\n return value === undefined || typeof value === 'string';\n}\n\nfunction isNullableString(value: unknown): boolean {\n return value === null || typeof value === 'string';\n}\n\nconst CAPTURE_OUTCOMES = new Set<string>(Object.values(EmbedCaptureOutcome));\n\nfunction isCaptureOutcome(value: unknown): boolean {\n return typeof value === 'string' && CAPTURE_OUTCOMES.has(value);\n}\n\nfunction hasValidPayload(\n type: EmbedEventType,\n payload: Record<string, unknown>,\n): boolean {\n switch (type) {\n case EmbedEventType.READY:\n return typeof payload.roomSlug === 'string';\n case EmbedEventType.JOINED:\n return (\n typeof payload.roomSlug === 'string' &&\n typeof payload.identity === 'string' &&\n isOptionalString(payload.name) &&\n typeof payload.joinedAt === 'string'\n );\n case EmbedEventType.LEFT:\n return (\n typeof payload.roomSlug === 'string' &&\n typeof payload.identity === 'string' &&\n typeof payload.leftAt === 'string' &&\n (payload.durationMs === undefined ||\n typeof payload.durationMs === 'number')\n );\n case EmbedEventType.PARTICIPANT_JOINED:\n return (\n typeof payload.identity === 'string' &&\n isOptionalString(payload.name) &&\n typeof payload.participantCount === 'number'\n );\n case EmbedEventType.PARTICIPANT_LEFT:\n return (\n typeof payload.identity === 'string' &&\n typeof payload.participantCount === 'number'\n );\n case EmbedEventType.ENDED:\n return (\n typeof payload.roomSlug === 'string' &&\n typeof payload.endedAt === 'string'\n );\n case EmbedEventType.ERROR:\n return (\n typeof payload.code === 'string' &&\n typeof payload.message === 'string'\n );\n case EmbedEventType.STAGE_CHANGED:\n return (\n (payload.url === null || typeof payload.url === 'string') &&\n isOptionalString(payload.title) &&\n isOptionalString(payload.tool) &&\n isOptionalString(payload.openedBy)\n );\n case EmbedEventType.TRANSCRIPT_STARTED:\n return (\n typeof payload.roomSlug === 'string' &&\n isCaptureOutcome(payload.outcome) &&\n isNullableString(payload.transcriptId) &&\n isNullableString(payload.status)\n );\n case EmbedEventType.RECORDING_STARTED:\n return (\n typeof payload.roomSlug === 'string' &&\n isCaptureOutcome(payload.outcome) &&\n isNullableString(payload.recordingId) &&\n isNullableString(payload.status)\n );\n case EmbedEventType.RECORDING_SAVED:\n return (\n typeof payload.roomSlug === 'string' &&\n typeof payload.savedAt === 'string'\n );\n }\n}\n\nexport function parseEmbedEvent(data: unknown): EmbedEvent | null {\n if (!isRecord(data)) return null;\n if (\n data.source !== EMBED_MESSAGE_SOURCE ||\n data.version !== EMBED_PROTOCOL_VERSION ||\n typeof data.instanceId !== 'string' ||\n data.instanceId.length === 0 ||\n typeof data.type !== 'string' ||\n !EVENT_TYPES.has(data.type) ||\n !isRecord(data.payload)\n ) {\n return null;\n }\n\n const type = data.type as EmbedEventType;\n if (!hasValidPayload(type, data.payload)) return null;\n return data as unknown as EmbedEvent;\n}\n"],"mappings":"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","names":["import_react","EmbedEventType","EmbedCommandType","EmbedCommandAction","EmbedErrorCode","EmbedQueryParam","EmbedCaptureOutcome","EmbedRole","EmbedCapability","OeMeeting"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/OeMeeting.tsx","../src/embed-protocol.ts","../src/openStage.ts","../src/background.ts","../src/buildEmbedUrl.ts","../src/useOeMeeting.ts","../src/parseEmbedEvent.ts"],"sourcesContent":["export { OeMeeting, DEFAULT_IFRAME_ALLOW } from './OeMeeting';\nexport { useOeMeeting } from './useOeMeeting';\nexport { buildEmbedUrl } from './buildEmbedUrl';\nexport { parseEmbedEvent } from './parseEmbedEvent';\nexport {\n DEFAULT_EMBED_ORIGIN,\n EMBED_MESSAGE_SOURCE,\n EMBED_PROTOCOL_VERSION,\n EmbedCapability,\n EmbedCaptureOutcome,\n EmbedBackgroundType,\n EmbedCommandAction,\n EmbedRole,\n EmbedCommandType,\n EmbedErrorCode,\n EmbedEventType,\n EmbedQueryParam,\n isStageToolId,\n MAX_BACKGROUND_URL_LENGTH,\n MAX_STAGE_TOOL_ID_LENGTH,\n MAX_STAGE_URL_LENGTH,\n} from './embed-protocol';\nexport type { EmbedBackground, EmbedPermissionMap, StageToolId } from './embed-protocol';\nexport { isValidStageUrl, normalizeOpenStageInput } from './openStage';\nexport { normalizeEmbedBackground, serializeEmbedBackground } from './background';\nexport type {\n BuildEmbedUrlOptions,\n EmbedCommandMessage,\n EmbedEndedPayload,\n EmbedErrorPayload,\n EmbedEvent,\n EmbedEventOf,\n EmbedEventPayloadMap,\n EmbedJoinedPayload,\n EmbedLeftPayload,\n EmbedMessageBase,\n EmbedParticipantJoinedPayload,\n EmbedParticipantLeftPayload,\n EmbedReadyPayload,\n EmbedRecordingSavedPayload,\n EmbedRecordingStartedPayload,\n EmbedStageChangedPayload,\n EmbedTranscriptStartedPayload,\n OeMeetingHandle,\n OeMeetingProps,\n OpenStageInput,\n} from './types';\n","'use client';\n\nimport {\n forwardRef,\n useId,\n useMemo,\n useRef,\n type CSSProperties,\n} from 'react';\nimport { buildEmbedUrl } from './buildEmbedUrl';\nimport { DEFAULT_EMBED_ORIGIN } from './embed-protocol';\nimport type { OeMeetingHandle, OeMeetingProps } from './types';\nimport { useOeMeeting } from './useOeMeeting';\n\nexport const DEFAULT_IFRAME_ALLOW =\n 'camera; microphone; fullscreen; autoplay; display-capture; clipboard-write; encrypted-media';\n\nfunction toCssSize(value: number | string | undefined): string | undefined {\n if (value === undefined) return undefined;\n return typeof value === 'number' ? `${value}px` : value;\n}\n\nfunction getOrigin(value: string): string {\n return new URL(value).origin;\n}\n\nexport const OeMeeting = forwardRef<OeMeetingHandle, OeMeetingProps>(\n function OeMeeting(props, ref) {\n const {\n roomSlug,\n joinToken,\n userName,\n externalUserId,\n origin = DEFAULT_EMBED_ORIGIN,\n lang,\n autoJoin = true,\n hideLeave,\n autoCameraOff,\n autoTranscribe,\n autoRecord,\n background,\n title = 'OE Meeting room',\n width = '100%',\n height = 640,\n className,\n style,\n iframeClassName,\n iframeStyle,\n allow = DEFAULT_IFRAME_ALLOW,\n targetOrigin,\n onReady,\n onJoined,\n onLeft,\n onParticipantJoined,\n onParticipantLeft,\n onEnded,\n onError,\n onStageChanged,\n onTranscriptStarted,\n onRecordingStarted,\n onRecordingSaved,\n onEvent,\n } = props;\n const reactId = useId();\n const instanceId = useMemo(\n () => `oem-${reactId.replace(/:/g, '')}`,\n [reactId],\n );\n const embedOrigin = useMemo(() => getOrigin(origin), [origin]);\n const resolvedTargetOrigin = targetOrigin ?? embedOrigin;\n const hostOrigin =\n typeof window === 'undefined' ? undefined : window.location.origin;\n // Only the mount-time background rides the embed URL. Later prop changes\n // travel as `setBackground` commands (useOeMeeting); rebuilding src would\n // reload the whole meeting mid-session.\n const initialBackgroundRef = useRef(background);\n const src = useMemo(\n () =>\n buildEmbedUrl({\n roomSlug,\n joinToken,\n userName,\n externalUserId,\n origin,\n lang,\n autoJoin,\n hideLeave,\n autoCameraOff,\n autoTranscribe,\n autoRecord,\n background: initialBackgroundRef.current,\n instanceId,\n hostOrigin,\n }),\n [\n autoJoin,\n autoRecord,\n autoTranscribe,\n externalUserId,\n hideLeave,\n hostOrigin,\n instanceId,\n joinToken,\n lang,\n origin,\n roomSlug,\n autoCameraOff,\n userName,\n ],\n );\n const { iframeRef } = useOeMeeting({\n background,\n instanceId,\n targetOrigin: resolvedTargetOrigin,\n handleRef: ref,\n onReady,\n onJoined,\n onLeft,\n onParticipantJoined,\n onParticipantLeft,\n onEnded,\n onError,\n onStageChanged,\n onTranscriptStarted,\n onRecordingStarted,\n onRecordingSaved,\n onEvent,\n });\n const wrapperStyle: CSSProperties = {\n width: toCssSize(width),\n height: toCssSize(height),\n ...style,\n };\n const frameStyle: CSSProperties = {\n width: '100%',\n height: '100%',\n border: 0,\n display: 'block',\n ...iframeStyle,\n };\n\n return (\n <div\n className={className}\n style={wrapperStyle}\n data-oe-meeting-instance={instanceId}\n >\n <iframe\n ref={iframeRef}\n className={iframeClassName}\n style={frameStyle}\n src={src}\n title={title}\n allow={allow}\n allowFullScreen\n referrerPolicy=\"strict-origin-when-cross-origin\"\n />\n </div>\n );\n },\n);\n\nOeMeeting.displayName = 'OeMeeting';\n","export const EMBED_PROTOCOL_VERSION = 1 as const;\nexport const EMBED_MESSAGE_SOURCE = 'oemeeting' as const;\nexport const DEFAULT_EMBED_ORIGIN = 'https://meet.ocean.edu.vn';\n\nexport enum EmbedEventType {\n READY = 'oemeeting:ready',\n JOINED = 'oemeeting:joined',\n LEFT = 'oemeeting:left',\n PARTICIPANT_JOINED = 'oemeeting:participant-joined',\n PARTICIPANT_LEFT = 'oemeeting:participant-left',\n ENDED = 'oemeeting:ended',\n ERROR = 'oemeeting:error',\n STAGE_CHANGED = 'oemeeting:stage-changed',\n TRANSCRIPT_STARTED = 'oemeeting:transcript-started',\n RECORDING_STARTED = 'oemeeting:recording-started',\n RECORDING_SAVED = 'oemeeting:recording-saved',\n}\n\nexport enum EmbedCommandType {\n COMMAND = 'oemeeting:command',\n}\n\nexport enum EmbedCommandAction {\n LEAVE = 'leave',\n TOGGLE_MIC = 'toggleMic',\n TOGGLE_CAMERA = 'toggleCamera',\n OPEN_STAGE = 'openStage',\n CLOSE_STAGE = 'closeStage',\n SET_BACKGROUND = 'setBackground',\n}\n\nexport enum EmbedErrorCode {\n TOKEN_INVALID = 'TOKEN_INVALID',\n TOKEN_EXPIRED = 'TOKEN_EXPIRED',\n ROOM_NOT_FOUND = 'ROOM_NOT_FOUND',\n ROOM_ACCESS_DENIED = 'ROOM_ACCESS_DENIED',\n CONNECTION_FAILED = 'CONNECTION_FAILED',\n PROTOCOL_MISMATCH = 'PROTOCOL_MISMATCH',\n STAGE_ORIGIN_DENIED = 'STAGE_ORIGIN_DENIED',\n STAGE_URL_INVALID = 'STAGE_URL_INVALID',\n TRANSCRIPT_START_FAILED = 'TRANSCRIPT_START_FAILED',\n RECORDING_START_FAILED = 'RECORDING_START_FAILED',\n UNKNOWN = 'UNKNOWN',\n}\n\n/**\n * Host-controlled camera background applied to this embed's local user only.\n * `none` clears any active background effect. The host app enforces who may\n * set it; the meeting does not interpret roles for this value.\n */\nexport enum EmbedBackgroundType {\n BLUR = 'blur',\n IMAGE = 'image',\n NONE = 'none',\n}\n\nexport const MAX_BACKGROUND_URL_LENGTH = 2048;\nexport const DEFAULT_BACKGROUND_BLUR_RADIUS = 10;\nexport const MIN_BACKGROUND_BLUR_RADIUS = 1;\nexport const MAX_BACKGROUND_BLUR_RADIUS = 50;\n\nexport interface EmbedBackground {\n type: EmbedBackgroundType;\n /** BLUR only. Defaults to `DEFAULT_BACKGROUND_BLUR_RADIUS`, clamped 1-50. */\n blurRadius?: number;\n /** IMAGE only. http(s) URL, max `MAX_BACKGROUND_URL_LENGTH`. */\n url?: string;\n /** When true the embed user cannot change blur/virtual backgrounds. */\n locked?: boolean;\n}\n\n/** Open host-owned tool id. Meeting does not catalog values. */\nexport type StageToolId = string;\n\nexport const MAX_STAGE_URL_LENGTH = 2048;\nexport const MAX_STAGE_TOOL_ID_LENGTH = 32;\n\nconst STAGE_TOOL_ID_PATTERN = /^[a-z][a-z0-9._-]{0,31}$/;\n\nexport function isStageToolId(value: unknown): value is StageToolId {\n return (\n typeof value === 'string' &&\n value.length > 0 &&\n value.length <= MAX_STAGE_TOOL_ID_LENGTH &&\n STAGE_TOOL_ID_PATTERN.test(value)\n );\n}\n\nexport enum EmbedQueryParam {\n INSTANCE_ID = 'instanceId',\n HOST_ORIGIN = 'hostOrigin',\n JOIN_TOKEN = 'joinToken',\n USER_NAME = 'userName',\n EXTERNAL_USER_ID = 'externalUserId',\n LANG = 'lang',\n AUTO_JOIN = 'autoJoin',\n HIDE_LEAVE = 'hideLeave',\n AUTO_CAMERA_OFF = 'autoCameraOff',\n AUTO_TRANSCRIBE = 'autoTranscribe',\n AUTO_RECORD = 'autoRecord',\n BACKGROUND = 'background',\n}\n\n/**\n * What happened to the auto-transcribe request the embed made.\n *\n * `ALREADY_RUNNING` is the normal outcome for every participant after the\n * first, because the transcript is a room-level asset rather than a\n * per-participant one. `DISABLED` means the OE Meeting deployment has\n * transcription turned off.\n */\nexport enum EmbedCaptureOutcome {\n STARTED = 'started',\n ALREADY_RUNNING = 'already_running',\n DISABLED = 'disabled',\n FAILED = 'failed',\n}\n\n/**\n * Role the host app assigns when minting a join token.\n * Keep values aligned with `EmbedRole` in the backend embed-permission enum.\n */\nexport enum EmbedRole {\n OWNER = 'owner',\n MEMBER = 'member',\n}\n\n/**\n * Capability the host app may grant per role. Meeting enforces this on the\n * join token, not on a React prop. `screenShare` is the only value today.\n */\nexport enum EmbedCapability {\n SCREEN_SHARE = 'screenShare',\n}\n\nexport interface EmbedPermissionMap {\n owner?: EmbedCapability[];\n member?: EmbedCapability[];\n}\n","import { isStageToolId, MAX_STAGE_URL_LENGTH } from './embed-protocol';\nimport type { OpenStageInput } from './types';\n\nexport function isValidStageUrl(url: string): boolean {\n if (url.length === 0 || url.length > MAX_STAGE_URL_LENGTH) return false;\n try {\n const parsed = new URL(url);\n if (parsed.protocol === 'https:') return true;\n if (parsed.protocol === 'http:') {\n return (\n parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1'\n );\n }\n return false;\n } catch {\n return false;\n }\n}\n\nexport function normalizeOpenStageInput(\n input: OpenStageInput,\n): OpenStageInput | null {\n const url = input.url.trim();\n if (!isValidStageUrl(url)) return null;\n const title = input.title?.trim();\n return {\n url,\n ...(title ? { title: title.slice(0, 200) } : {}),\n ...(isStageToolId(input.tool) ? { tool: input.tool } : {}),\n };\n}\n","import { isValidStageUrl } from './openStage';\nimport {\n DEFAULT_BACKGROUND_BLUR_RADIUS,\n EmbedBackgroundType,\n MAX_BACKGROUND_BLUR_RADIUS,\n MAX_BACKGROUND_URL_LENGTH,\n MIN_BACKGROUND_BLUR_RADIUS,\n type EmbedBackground,\n} from './embed-protocol';\n\n/** Same http(s) policy as the stage URL, including the localhost exception. */\nconst isValidBackgroundUrl = (url: string): boolean =>\n url.length > 0 &&\n url.length <= MAX_BACKGROUND_URL_LENGTH &&\n isValidStageUrl(url);\n\nconst clampBlurRadius = (value: number): number =>\n Number.isFinite(value)\n ? Math.min(MAX_BACKGROUND_BLUR_RADIUS, Math.max(MIN_BACKGROUND_BLUR_RADIUS, Math.round(value)))\n : DEFAULT_BACKGROUND_BLUR_RADIUS;\n\n/**\n * Validate and normalize a host-provided background. Returns null for invalid\n * input so callers can silently drop it, mirroring `normalizeOpenStageInput`.\n */\nexport function normalizeEmbedBackground(\n input: EmbedBackground,\n): EmbedBackground | null {\n const locked = input.locked === true ? { locked: true } : {};\n\n if (input.type === EmbedBackgroundType.NONE) {\n return { type: EmbedBackgroundType.NONE, ...locked };\n }\n\n if (input.type === EmbedBackgroundType.BLUR) {\n return {\n type: EmbedBackgroundType.BLUR,\n blurRadius: clampBlurRadius(input.blurRadius ?? DEFAULT_BACKGROUND_BLUR_RADIUS),\n ...locked,\n };\n }\n\n if (input.type === EmbedBackgroundType.IMAGE) {\n const url = input.url?.trim();\n if (!url || !isValidBackgroundUrl(url)) return null;\n return {\n type: EmbedBackgroundType.IMAGE,\n url,\n ...locked,\n };\n }\n\n return null;\n}\n\n/** JSON wire format shared by the `background` query param and the command payload. */\nexport function serializeEmbedBackground(\n input: EmbedBackground,\n): string | undefined {\n const normalized = normalizeEmbedBackground(input);\n return normalized ? JSON.stringify(normalized) : undefined;\n}\n","import {\n DEFAULT_EMBED_ORIGIN,\n EmbedQueryParam,\n} from './embed-protocol';\nimport { serializeEmbedBackground } from './background';\nimport type { BuildEmbedUrlOptions } from './types';\n\nconst QUERY_FLAG_ENABLED = '1';\nconst QUERY_FLAG_DISABLED = '0';\n\nfunction toFlag(value: boolean | undefined): string | undefined {\n if (value === undefined) return undefined;\n return value ? QUERY_FLAG_ENABLED : QUERY_FLAG_DISABLED;\n}\n\nfunction normalizeOrigin(origin: string): string {\n return origin.replace(/\\/+$/, '');\n}\n\nexport function buildEmbedUrl(options: BuildEmbedUrlOptions): string {\n const roomSlug = options.roomSlug.trim();\n const joinToken = options.joinToken.trim();\n if (!roomSlug) {\n throw new Error('OE Meeting embed requires a non-empty roomSlug.');\n }\n if (!joinToken) {\n throw new Error('OE Meeting embed requires a non-empty joinToken.');\n }\n\n const origin = normalizeOrigin(options.origin ?? DEFAULT_EMBED_ORIGIN);\n const url = new URL(`${origin}/embed/${encodeURIComponent(roomSlug)}`);\n const backgroundParam = options.background\n ? serializeEmbedBackground(options.background)\n : undefined;\n\n const entries: Array<[EmbedQueryParam, string | undefined]> = [\n [EmbedQueryParam.INSTANCE_ID, options.instanceId],\n [EmbedQueryParam.HOST_ORIGIN, options.hostOrigin],\n [EmbedQueryParam.JOIN_TOKEN, joinToken],\n [EmbedQueryParam.USER_NAME, options.userName],\n [EmbedQueryParam.EXTERNAL_USER_ID, options.externalUserId],\n [EmbedQueryParam.LANG, options.lang],\n [EmbedQueryParam.AUTO_JOIN, toFlag(options.autoJoin)],\n [EmbedQueryParam.HIDE_LEAVE, toFlag(options.hideLeave)],\n [EmbedQueryParam.AUTO_CAMERA_OFF, toFlag(options.autoCameraOff)],\n [EmbedQueryParam.AUTO_TRANSCRIBE, toFlag(options.autoTranscribe)],\n [EmbedQueryParam.AUTO_RECORD, toFlag(options.autoRecord)],\n [EmbedQueryParam.BACKGROUND, backgroundParam],\n ];\n\n for (const [key, value] of entries) {\n if (value !== undefined && value !== '') {\n url.searchParams.set(key, value);\n }\n }\n return url.toString();\n}\n","import {\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n type Ref,\n} from 'react';\nimport {\n EMBED_MESSAGE_SOURCE,\n EMBED_PROTOCOL_VERSION,\n EmbedCommandAction,\n EmbedCommandType,\n EmbedEventType,\n} from './embed-protocol';\nimport { normalizeEmbedBackground } from './background';\nimport { normalizeOpenStageInput } from './openStage';\nimport { parseEmbedEvent } from './parseEmbedEvent';\nimport type {\n EmbedCommandMessage,\n OeMeetingHandle,\n OeMeetingProps,\n OpenStageInput,\n} from './types';\nimport type { EmbedBackground } from './embed-protocol';\n\ntype UseOeMeetingOptions = Pick<\n OeMeetingProps,\n | 'onReady'\n | 'onJoined'\n | 'onLeft'\n | 'onParticipantJoined'\n | 'onParticipantLeft'\n | 'onEnded'\n | 'onError'\n | 'onStageChanged'\n | 'onTranscriptStarted'\n | 'onRecordingStarted'\n | 'onRecordingSaved'\n | 'onEvent'\n | 'background'\n> & {\n instanceId: string;\n targetOrigin: string;\n handleRef?: Ref<OeMeetingHandle>;\n};\n\ninterface PostCommandOptions {\n iframe: HTMLIFrameElement | null;\n instanceId: string;\n action: EmbedCommandAction;\n targetOrigin: string;\n payload?: OpenStageInput | EmbedBackground;\n}\n\nfunction postCommand(options: PostCommandOptions): void {\n const frameWindow = options.iframe?.contentWindow;\n if (!frameWindow) return;\n const message: EmbedCommandMessage = {\n source: EMBED_MESSAGE_SOURCE,\n version: EMBED_PROTOCOL_VERSION,\n instanceId: options.instanceId,\n type: EmbedCommandType.COMMAND,\n action: options.action,\n ...(options.payload ? { payload: options.payload } : {}),\n };\n frameWindow.postMessage(message, options.targetOrigin);\n}\n\nexport function useOeMeeting(options: UseOeMeetingOptions) {\n const iframeRef = useRef<HTMLIFrameElement | null>(null);\n const callbacksRef = useRef(options);\n // Last background the host set. Resent on READY: commands posted before the\n // iframe bridge mounts are dropped by the browser.\n const pendingBackgroundRef = useRef<EmbedBackground | null>(null);\n\n useEffect(() => {\n callbacksRef.current = options;\n }, [options]);\n\n useEffect(() => {\n const onMessage = (event: MessageEvent<unknown>) => {\n const frameWindow = iframeRef.current?.contentWindow;\n if (\n !frameWindow ||\n event.source !== frameWindow ||\n event.origin !== options.targetOrigin\n ) {\n return;\n }\n const embedEvent = parseEmbedEvent(event.data);\n if (!embedEvent || embedEvent.instanceId !== options.instanceId) return;\n\n const callbacks = callbacksRef.current;\n callbacks.onEvent?.(embedEvent);\n switch (embedEvent.type) {\n case EmbedEventType.READY:\n callbacks.onReady?.(embedEvent);\n if (pendingBackgroundRef.current) {\n postCommand({\n iframe: iframeRef.current,\n instanceId: options.instanceId,\n action: EmbedCommandAction.SET_BACKGROUND,\n targetOrigin: options.targetOrigin,\n payload: pendingBackgroundRef.current,\n });\n }\n break;\n case EmbedEventType.JOINED:\n callbacks.onJoined?.(embedEvent);\n break;\n case EmbedEventType.LEFT:\n callbacks.onLeft?.(embedEvent);\n break;\n case EmbedEventType.PARTICIPANT_JOINED:\n callbacks.onParticipantJoined?.(embedEvent);\n break;\n case EmbedEventType.PARTICIPANT_LEFT:\n callbacks.onParticipantLeft?.(embedEvent);\n break;\n case EmbedEventType.ENDED:\n callbacks.onEnded?.(embedEvent);\n break;\n case EmbedEventType.ERROR:\n callbacks.onError?.(embedEvent);\n break;\n case EmbedEventType.STAGE_CHANGED:\n callbacks.onStageChanged?.(embedEvent);\n break;\n case EmbedEventType.TRANSCRIPT_STARTED:\n callbacks.onTranscriptStarted?.(embedEvent);\n break;\n case EmbedEventType.RECORDING_STARTED:\n callbacks.onRecordingStarted?.(embedEvent);\n break;\n case EmbedEventType.RECORDING_SAVED:\n callbacks.onRecordingSaved?.(embedEvent);\n break;\n }\n };\n\n window.addEventListener('message', onMessage);\n return () => window.removeEventListener('message', onMessage);\n }, [options.instanceId, options.targetOrigin]);\n\n const send = useCallback(\n (\n action: EmbedCommandAction,\n payload?: OpenStageInput | EmbedBackground\n ) =>\n postCommand({\n iframe: iframeRef.current,\n instanceId: options.instanceId,\n action,\n targetOrigin: options.targetOrigin,\n payload,\n }),\n [options.instanceId, options.targetOrigin],\n );\n const leave = useCallback(() => send(EmbedCommandAction.LEAVE), [send]);\n const toggleMic = useCallback(\n () => send(EmbedCommandAction.TOGGLE_MIC),\n [send],\n );\n const toggleCamera = useCallback(\n () => send(EmbedCommandAction.TOGGLE_CAMERA),\n [send],\n );\n const openStage = useCallback(\n (input: OpenStageInput) => {\n const normalized = normalizeOpenStageInput(input);\n if (!normalized) return;\n send(EmbedCommandAction.OPEN_STAGE, normalized);\n },\n [send],\n );\n const closeStage = useCallback(\n () => send(EmbedCommandAction.CLOSE_STAGE),\n [send],\n );\n\n useEffect(() => {\n if (!options.background) {\n pendingBackgroundRef.current = null;\n return;\n }\n const normalized = normalizeEmbedBackground(options.background);\n if (!normalized) return;\n pendingBackgroundRef.current = normalized;\n send(EmbedCommandAction.SET_BACKGROUND, normalized);\n }, [options.background, send]);\n const getIframe = useCallback(() => iframeRef.current, []);\n const handle = useMemo<OeMeetingHandle>(\n () => ({\n leave,\n toggleMic,\n toggleCamera,\n openStage,\n closeStage,\n getIframe,\n }),\n [closeStage, getIframe, leave, openStage, toggleCamera, toggleMic],\n );\n\n useImperativeHandle(options.handleRef, () => handle, [handle]);\n return { iframeRef, handle };\n}\n","import {\n EMBED_MESSAGE_SOURCE,\n EMBED_PROTOCOL_VERSION,\n EmbedCaptureOutcome,\n EmbedEventType,\n} from './embed-protocol';\nimport type { EmbedEvent } from './types';\n\nconst EVENT_TYPES = new Set<string>(Object.values(EmbedEventType));\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction isOptionalString(value: unknown): boolean {\n return value === undefined || typeof value === 'string';\n}\n\nfunction isNullableString(value: unknown): boolean {\n return value === null || typeof value === 'string';\n}\n\nconst CAPTURE_OUTCOMES = new Set<string>(Object.values(EmbedCaptureOutcome));\n\nfunction isCaptureOutcome(value: unknown): boolean {\n return typeof value === 'string' && CAPTURE_OUTCOMES.has(value);\n}\n\nfunction hasValidPayload(\n type: EmbedEventType,\n payload: Record<string, unknown>,\n): boolean {\n switch (type) {\n case EmbedEventType.READY:\n return typeof payload.roomSlug === 'string';\n case EmbedEventType.JOINED:\n return (\n typeof payload.roomSlug === 'string' &&\n typeof payload.identity === 'string' &&\n isOptionalString(payload.name) &&\n typeof payload.joinedAt === 'string'\n );\n case EmbedEventType.LEFT:\n return (\n typeof payload.roomSlug === 'string' &&\n typeof payload.identity === 'string' &&\n typeof payload.leftAt === 'string' &&\n (payload.durationMs === undefined ||\n typeof payload.durationMs === 'number')\n );\n case EmbedEventType.PARTICIPANT_JOINED:\n return (\n typeof payload.identity === 'string' &&\n isOptionalString(payload.name) &&\n typeof payload.participantCount === 'number'\n );\n case EmbedEventType.PARTICIPANT_LEFT:\n return (\n typeof payload.identity === 'string' &&\n typeof payload.participantCount === 'number'\n );\n case EmbedEventType.ENDED:\n return (\n typeof payload.roomSlug === 'string' &&\n typeof payload.endedAt === 'string'\n );\n case EmbedEventType.ERROR:\n return (\n typeof payload.code === 'string' &&\n typeof payload.message === 'string'\n );\n case EmbedEventType.STAGE_CHANGED:\n return (\n (payload.url === null || typeof payload.url === 'string') &&\n isOptionalString(payload.title) &&\n isOptionalString(payload.tool) &&\n isOptionalString(payload.openedBy)\n );\n case EmbedEventType.TRANSCRIPT_STARTED:\n return (\n typeof payload.roomSlug === 'string' &&\n isCaptureOutcome(payload.outcome) &&\n isNullableString(payload.transcriptId) &&\n isNullableString(payload.status)\n );\n case EmbedEventType.RECORDING_STARTED:\n return (\n typeof payload.roomSlug === 'string' &&\n isCaptureOutcome(payload.outcome) &&\n isNullableString(payload.recordingId) &&\n isNullableString(payload.status)\n );\n case EmbedEventType.RECORDING_SAVED:\n return (\n typeof payload.roomSlug === 'string' &&\n typeof payload.savedAt === 'string'\n );\n }\n}\n\nexport function parseEmbedEvent(data: unknown): EmbedEvent | null {\n if (!isRecord(data)) return null;\n if (\n data.source !== EMBED_MESSAGE_SOURCE ||\n data.version !== EMBED_PROTOCOL_VERSION ||\n typeof data.instanceId !== 'string' ||\n data.instanceId.length === 0 ||\n typeof data.type !== 'string' ||\n !EVENT_TYPES.has(data.type) ||\n !isRecord(data.payload)\n ) {\n return null;\n }\n\n const type = data.type as EmbedEventType;\n if (!hasValidPayload(type, data.payload)) return null;\n return data as unknown as EmbedEvent;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,IAAAA,gBAMO;;;ACRA,IAAM,yBAAyB;AAC/B,IAAM,uBAAuB;AAC7B,IAAM,uBAAuB;AAE7B,IAAK,iBAAL,kBAAKC,oBAAL;AACL,EAAAA,gBAAA,WAAQ;AACR,EAAAA,gBAAA,YAAS;AACT,EAAAA,gBAAA,UAAO;AACP,EAAAA,gBAAA,wBAAqB;AACrB,EAAAA,gBAAA,sBAAmB;AACnB,EAAAA,gBAAA,WAAQ;AACR,EAAAA,gBAAA,WAAQ;AACR,EAAAA,gBAAA,mBAAgB;AAChB,EAAAA,gBAAA,wBAAqB;AACrB,EAAAA,gBAAA,uBAAoB;AACpB,EAAAA,gBAAA,qBAAkB;AAXR,SAAAA;AAAA,GAAA;AAcL,IAAK,mBAAL,kBAAKC,sBAAL;AACL,EAAAA,kBAAA,aAAU;AADA,SAAAA;AAAA,GAAA;AAIL,IAAK,qBAAL,kBAAKC,wBAAL;AACL,EAAAA,oBAAA,WAAQ;AACR,EAAAA,oBAAA,gBAAa;AACb,EAAAA,oBAAA,mBAAgB;AAChB,EAAAA,oBAAA,gBAAa;AACb,EAAAA,oBAAA,iBAAc;AACd,EAAAA,oBAAA,oBAAiB;AANP,SAAAA;AAAA,GAAA;AASL,IAAK,iBAAL,kBAAKC,oBAAL;AACL,EAAAA,gBAAA,mBAAgB;AAChB,EAAAA,gBAAA,mBAAgB;AAChB,EAAAA,gBAAA,oBAAiB;AACjB,EAAAA,gBAAA,wBAAqB;AACrB,EAAAA,gBAAA,uBAAoB;AACpB,EAAAA,gBAAA,uBAAoB;AACpB,EAAAA,gBAAA,yBAAsB;AACtB,EAAAA,gBAAA,uBAAoB;AACpB,EAAAA,gBAAA,6BAA0B;AAC1B,EAAAA,gBAAA,4BAAyB;AACzB,EAAAA,gBAAA,aAAU;AAXA,SAAAA;AAAA,GAAA;AAmBL,IAAK,sBAAL,kBAAKC,yBAAL;AACL,EAAAA,qBAAA,UAAO;AACP,EAAAA,qBAAA,WAAQ;AACR,EAAAA,qBAAA,UAAO;AAHG,SAAAA;AAAA,GAAA;AAML,IAAM,4BAA4B;AAClC,IAAM,iCAAiC;AACvC,IAAM,6BAA6B;AACnC,IAAM,6BAA6B;AAenC,IAAM,uBAAuB;AAC7B,IAAM,2BAA2B;AAExC,IAAM,wBAAwB;AAEvB,SAAS,cAAc,OAAsC;AAClE,SACE,OAAO,UAAU,YACjB,MAAM,SAAS,KACf,MAAM,UAAU,4BAChB,sBAAsB,KAAK,KAAK;AAEpC;AAEO,IAAK,kBAAL,kBAAKC,qBAAL;AACL,EAAAA,iBAAA,iBAAc;AACd,EAAAA,iBAAA,iBAAc;AACd,EAAAA,iBAAA,gBAAa;AACb,EAAAA,iBAAA,eAAY;AACZ,EAAAA,iBAAA,sBAAmB;AACnB,EAAAA,iBAAA,UAAO;AACP,EAAAA,iBAAA,eAAY;AACZ,EAAAA,iBAAA,gBAAa;AACb,EAAAA,iBAAA,qBAAkB;AAClB,EAAAA,iBAAA,qBAAkB;AAClB,EAAAA,iBAAA,iBAAc;AACd,EAAAA,iBAAA,gBAAa;AAZH,SAAAA;AAAA,GAAA;AAuBL,IAAK,sBAAL,kBAAKC,yBAAL;AACL,EAAAA,qBAAA,aAAU;AACV,EAAAA,qBAAA,qBAAkB;AAClB,EAAAA,qBAAA,cAAW;AACX,EAAAA,qBAAA,YAAS;AAJC,SAAAA;AAAA,GAAA;AAWL,IAAK,YAAL,kBAAKC,eAAL;AACL,EAAAA,WAAA,WAAQ;AACR,EAAAA,WAAA,YAAS;AAFC,SAAAA;AAAA,GAAA;AASL,IAAK,kBAAL,kBAAKC,qBAAL;AACL,EAAAA,iBAAA,kBAAe;AADL,SAAAA;AAAA,GAAA;;;AChIL,SAAS,gBAAgB,KAAsB;AACpD,MAAI,IAAI,WAAW,KAAK,IAAI,SAAS,qBAAsB,QAAO;AAClE,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,QAAI,OAAO,aAAa,SAAU,QAAO;AACzC,QAAI,OAAO,aAAa,SAAS;AAC/B,aACE,OAAO,aAAa,eAAe,OAAO,aAAa;AAAA,IAE3D;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,wBACd,OACuB;AACvB,QAAM,MAAM,MAAM,IAAI,KAAK;AAC3B,MAAI,CAAC,gBAAgB,GAAG,EAAG,QAAO;AAClC,QAAM,QAAQ,MAAM,OAAO,KAAK;AAChC,SAAO;AAAA,IACL;AAAA,IACA,GAAI,QAAQ,EAAE,OAAO,MAAM,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC;AAAA,IAC9C,GAAI,cAAc,MAAM,IAAI,IAAI,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;AAAA,EAC1D;AACF;;;ACnBA,IAAM,uBAAuB,CAAC,QAC5B,IAAI,SAAS,KACb,IAAI,UAAU,6BACd,gBAAgB,GAAG;AAErB,IAAM,kBAAkB,CAAC,UACvB,OAAO,SAAS,KAAK,IACjB,KAAK,IAAI,4BAA4B,KAAK,IAAI,4BAA4B,KAAK,MAAM,KAAK,CAAC,CAAC,IAC5F;AAMC,SAAS,yBACd,OACwB;AACxB,QAAM,SAAS,MAAM,WAAW,OAAO,EAAE,QAAQ,KAAK,IAAI,CAAC;AAE3D,MAAI,MAAM,4BAAmC;AAC3C,WAAO,EAAE,yBAAgC,GAAG,OAAO;AAAA,EACrD;AAEA,MAAI,MAAM,4BAAmC;AAC3C,WAAO;AAAA,MACL;AAAA,MACA,YAAY,gBAAgB,MAAM,cAAc,8BAA8B;AAAA,MAC9E,GAAG;AAAA,IACL;AAAA,EACF;AAEA,MAAI,MAAM,8BAAoC;AAC5C,UAAM,MAAM,MAAM,KAAK,KAAK;AAC5B,QAAI,CAAC,OAAO,CAAC,qBAAqB,GAAG,EAAG,QAAO;AAC/C,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACL;AAAA,EACF;AAEA,SAAO;AACT;AAGO,SAAS,yBACd,OACoB;AACpB,QAAM,aAAa,yBAAyB,KAAK;AACjD,SAAO,aAAa,KAAK,UAAU,UAAU,IAAI;AACnD;;;ACtDA,IAAM,qBAAqB;AAC3B,IAAM,sBAAsB;AAE5B,SAAS,OAAO,OAAgD;AAC9D,MAAI,UAAU,OAAW,QAAO;AAChC,SAAO,QAAQ,qBAAqB;AACtC;AAEA,SAAS,gBAAgB,QAAwB;AAC/C,SAAO,OAAO,QAAQ,QAAQ,EAAE;AAClC;AAEO,SAAS,cAAc,SAAuC;AACnE,QAAM,WAAW,QAAQ,SAAS,KAAK;AACvC,QAAM,YAAY,QAAQ,UAAU,KAAK;AACzC,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AACA,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AAEA,QAAM,SAAS,gBAAgB,QAAQ,UAAU,oBAAoB;AACrE,QAAM,MAAM,IAAI,IAAI,GAAG,MAAM,UAAU,mBAAmB,QAAQ,CAAC,EAAE;AACrE,QAAM,kBAAkB,QAAQ,aAC5B,yBAAyB,QAAQ,UAAU,IAC3C;AAEJ,QAAM,UAAwD;AAAA,IAC5D,iCAA8B,QAAQ,UAAU;AAAA,IAChD,iCAA8B,QAAQ,UAAU;AAAA,IAChD,+BAA6B,SAAS;AAAA,IACtC,6BAA4B,QAAQ,QAAQ;AAAA,IAC5C,0CAAmC,QAAQ,cAAc;AAAA,IACzD,oBAAuB,QAAQ,IAAI;AAAA,IACnC,6BAA4B,OAAO,QAAQ,QAAQ,CAAC;AAAA,IACpD,+BAA6B,OAAO,QAAQ,SAAS,CAAC;AAAA,IACtD,wCAAkC,OAAO,QAAQ,aAAa,CAAC;AAAA,IAC/D,yCAAkC,OAAO,QAAQ,cAAc,CAAC;AAAA,IAChE,iCAA8B,OAAO,QAAQ,UAAU,CAAC;AAAA,IACxD,gCAA6B,eAAe;AAAA,EAC9C;AAEA,aAAW,CAAC,KAAK,KAAK,KAAK,SAAS;AAClC,QAAI,UAAU,UAAa,UAAU,IAAI;AACvC,UAAI,aAAa,IAAI,KAAK,KAAK;AAAA,IACjC;AAAA,EACF;AACA,SAAO,IAAI,SAAS;AACtB;;;ACxDA,mBAOO;;;ACCP,IAAM,cAAc,IAAI,IAAY,OAAO,OAAO,cAAc,CAAC;AAEjE,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEA,SAAS,iBAAiB,OAAyB;AACjD,SAAO,UAAU,UAAa,OAAO,UAAU;AACjD;AAEA,SAAS,iBAAiB,OAAyB;AACjD,SAAO,UAAU,QAAQ,OAAO,UAAU;AAC5C;AAEA,IAAM,mBAAmB,IAAI,IAAY,OAAO,OAAO,mBAAmB,CAAC;AAE3E,SAAS,iBAAiB,OAAyB;AACjD,SAAO,OAAO,UAAU,YAAY,iBAAiB,IAAI,KAAK;AAChE;AAEA,SAAS,gBACP,MACA,SACS;AACT,UAAQ,MAAM;AAAA,IACZ;AACE,aAAO,OAAO,QAAQ,aAAa;AAAA,IACrC;AACE,aACE,OAAO,QAAQ,aAAa,YAC5B,OAAO,QAAQ,aAAa,YAC5B,iBAAiB,QAAQ,IAAI,KAC7B,OAAO,QAAQ,aAAa;AAAA,IAEhC;AACE,aACE,OAAO,QAAQ,aAAa,YAC5B,OAAO,QAAQ,aAAa,YAC5B,OAAO,QAAQ,WAAW,aACzB,QAAQ,eAAe,UACtB,OAAO,QAAQ,eAAe;AAAA,IAEpC;AACE,aACE,OAAO,QAAQ,aAAa,YAC5B,iBAAiB,QAAQ,IAAI,KAC7B,OAAO,QAAQ,qBAAqB;AAAA,IAExC;AACE,aACE,OAAO,QAAQ,aAAa,YAC5B,OAAO,QAAQ,qBAAqB;AAAA,IAExC;AACE,aACE,OAAO,QAAQ,aAAa,YAC5B,OAAO,QAAQ,YAAY;AAAA,IAE/B;AACE,aACE,OAAO,QAAQ,SAAS,YACxB,OAAO,QAAQ,YAAY;AAAA,IAE/B;AACE,cACG,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,QAAQ,aAChD,iBAAiB,QAAQ,KAAK,KAC9B,iBAAiB,QAAQ,IAAI,KAC7B,iBAAiB,QAAQ,QAAQ;AAAA,IAErC;AACE,aACE,OAAO,QAAQ,aAAa,YAC5B,iBAAiB,QAAQ,OAAO,KAChC,iBAAiB,QAAQ,YAAY,KACrC,iBAAiB,QAAQ,MAAM;AAAA,IAEnC;AACE,aACE,OAAO,QAAQ,aAAa,YAC5B,iBAAiB,QAAQ,OAAO,KAChC,iBAAiB,QAAQ,WAAW,KACpC,iBAAiB,QAAQ,MAAM;AAAA,IAEnC;AACE,aACE,OAAO,QAAQ,aAAa,YAC5B,OAAO,QAAQ,YAAY;AAAA,EAEjC;AACF;AAEO,SAAS,gBAAgB,MAAkC;AAChE,MAAI,CAAC,SAAS,IAAI,EAAG,QAAO;AAC5B,MACE,KAAK,WAAW,wBAChB,KAAK,YAAY,0BACjB,OAAO,KAAK,eAAe,YAC3B,KAAK,WAAW,WAAW,KAC3B,OAAO,KAAK,SAAS,YACrB,CAAC,YAAY,IAAI,KAAK,IAAI,KAC1B,CAAC,SAAS,KAAK,OAAO,GACtB;AACA,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,KAAK;AAClB,MAAI,CAAC,gBAAgB,MAAM,KAAK,OAAO,EAAG,QAAO;AACjD,SAAO;AACT;;;AD9DA,SAAS,YAAY,SAAmC;AACtD,QAAM,cAAc,QAAQ,QAAQ;AACpC,MAAI,CAAC,YAAa;AAClB,QAAM,UAA+B;AAAA,IACnC,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,YAAY,QAAQ;AAAA,IACpB;AAAA,IACA,QAAQ,QAAQ;AAAA,IAChB,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;AAAA,EACxD;AACA,cAAY,YAAY,SAAS,QAAQ,YAAY;AACvD;AAEO,SAAS,aAAa,SAA8B;AACzD,QAAM,gBAAY,qBAAiC,IAAI;AACvD,QAAM,mBAAe,qBAAO,OAAO;AAGnC,QAAM,2BAAuB,qBAA+B,IAAI;AAEhE,8BAAU,MAAM;AACd,iBAAa,UAAU;AAAA,EACzB,GAAG,CAAC,OAAO,CAAC;AAEZ,8BAAU,MAAM;AACd,UAAM,YAAY,CAAC,UAAiC;AAClD,YAAM,cAAc,UAAU,SAAS;AACvC,UACE,CAAC,eACD,MAAM,WAAW,eACjB,MAAM,WAAW,QAAQ,cACzB;AACA;AAAA,MACF;AACA,YAAM,aAAa,gBAAgB,MAAM,IAAI;AAC7C,UAAI,CAAC,cAAc,WAAW,eAAe,QAAQ,WAAY;AAEjE,YAAM,YAAY,aAAa;AAC/B,gBAAU,UAAU,UAAU;AAC9B,cAAQ,WAAW,MAAM;AAAA,QACvB;AACE,oBAAU,UAAU,UAAU;AAC9B,cAAI,qBAAqB,SAAS;AAChC,wBAAY;AAAA,cACV,QAAQ,UAAU;AAAA,cAClB,YAAY,QAAQ;AAAA,cACpB;AAAA,cACA,cAAc,QAAQ;AAAA,cACtB,SAAS,qBAAqB;AAAA,YAChC,CAAC;AAAA,UACH;AACA;AAAA,QACF;AACE,oBAAU,WAAW,UAAU;AAC/B;AAAA,QACF;AACE,oBAAU,SAAS,UAAU;AAC7B;AAAA,QACF;AACE,oBAAU,sBAAsB,UAAU;AAC1C;AAAA,QACF;AACE,oBAAU,oBAAoB,UAAU;AACxC;AAAA,QACF;AACE,oBAAU,UAAU,UAAU;AAC9B;AAAA,QACF;AACE,oBAAU,UAAU,UAAU;AAC9B;AAAA,QACF;AACE,oBAAU,iBAAiB,UAAU;AACrC;AAAA,QACF;AACE,oBAAU,sBAAsB,UAAU;AAC1C;AAAA,QACF;AACE,oBAAU,qBAAqB,UAAU;AACzC;AAAA,QACF;AACE,oBAAU,mBAAmB,UAAU;AACvC;AAAA,MACJ;AAAA,IACF;AAEA,WAAO,iBAAiB,WAAW,SAAS;AAC5C,WAAO,MAAM,OAAO,oBAAoB,WAAW,SAAS;AAAA,EAC9D,GAAG,CAAC,QAAQ,YAAY,QAAQ,YAAY,CAAC;AAE7C,QAAM,WAAO;AAAA,IACX,CACE,QACA,YAEA,YAAY;AAAA,MACV,QAAQ,UAAU;AAAA,MAClB,YAAY,QAAQ;AAAA,MACpB;AAAA,MACA,cAAc,QAAQ;AAAA,MACtB;AAAA,IACF,CAAC;AAAA,IACH,CAAC,QAAQ,YAAY,QAAQ,YAAY;AAAA,EAC3C;AACA,QAAM,YAAQ,0BAAY,MAAM,wBAA6B,GAAG,CAAC,IAAI,CAAC;AACtE,QAAM,gBAAY;AAAA,IAChB,MAAM,iCAAkC;AAAA,IACxC,CAAC,IAAI;AAAA,EACP;AACA,QAAM,mBAAe;AAAA,IACnB,MAAM,uCAAqC;AAAA,IAC3C,CAAC,IAAI;AAAA,EACP;AACA,QAAM,gBAAY;AAAA,IAChB,CAAC,UAA0B;AACzB,YAAM,aAAa,wBAAwB,KAAK;AAChD,UAAI,CAAC,WAAY;AACjB,yCAAoC,UAAU;AAAA,IAChD;AAAA,IACA,CAAC,IAAI;AAAA,EACP;AACA,QAAM,iBAAa;AAAA,IACjB,MAAM,mCAAmC;AAAA,IACzC,CAAC,IAAI;AAAA,EACP;AAEA,8BAAU,MAAM;AACd,QAAI,CAAC,QAAQ,YAAY;AACvB,2BAAqB,UAAU;AAC/B;AAAA,IACF;AACA,UAAM,aAAa,yBAAyB,QAAQ,UAAU;AAC9D,QAAI,CAAC,WAAY;AACjB,yBAAqB,UAAU;AAC/B,+CAAwC,UAAU;AAAA,EACpD,GAAG,CAAC,QAAQ,YAAY,IAAI,CAAC;AAC7B,QAAM,gBAAY,0BAAY,MAAM,UAAU,SAAS,CAAC,CAAC;AACzD,QAAM,aAAS;AAAA,IACb,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,YAAY,WAAW,OAAO,WAAW,cAAc,SAAS;AAAA,EACnE;AAEA,wCAAoB,QAAQ,WAAW,MAAM,QAAQ,CAAC,MAAM,CAAC;AAC7D,SAAO,EAAE,WAAW,OAAO;AAC7B;;;AL3DQ;AArID,IAAM,uBACX;AAEF,SAAS,UAAU,OAAwD;AACzE,MAAI,UAAU,OAAW,QAAO;AAChC,SAAO,OAAO,UAAU,WAAW,GAAG,KAAK,OAAO;AACpD;AAEA,SAAS,UAAU,OAAuB;AACxC,SAAO,IAAI,IAAI,KAAK,EAAE;AACxB;AAEO,IAAM,gBAAY;AAAA,EACvB,SAASC,WAAU,OAAO,KAAK;AAC7B,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,SAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,IAAI;AACJ,UAAM,cAAU,qBAAM;AACtB,UAAM,iBAAa;AAAA,MACjB,MAAM,OAAO,QAAQ,QAAQ,MAAM,EAAE,CAAC;AAAA,MACtC,CAAC,OAAO;AAAA,IACV;AACA,UAAM,kBAAc,uBAAQ,MAAM,UAAU,MAAM,GAAG,CAAC,MAAM,CAAC;AAC7D,UAAM,uBAAuB,gBAAgB;AAC7C,UAAM,aACJ,OAAO,WAAW,cAAc,SAAY,OAAO,SAAS;AAI9D,UAAM,2BAAuB,sBAAO,UAAU;AAC9C,UAAM,UAAM;AAAA,MACV,MACE,cAAc;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY,qBAAqB;AAAA,QACjC;AAAA,QACA;AAAA,MACF,CAAC;AAAA,MACH;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,UAAM,EAAE,UAAU,IAAI,aAAa;AAAA,MACjC;AAAA,MACA;AAAA,MACA,cAAc;AAAA,MACd,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AACD,UAAM,eAA8B;AAAA,MAClC,OAAO,UAAU,KAAK;AAAA,MACtB,QAAQ,UAAU,MAAM;AAAA,MACxB,GAAG;AAAA,IACL;AACA,UAAM,aAA4B;AAAA,MAChC,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,GAAG;AAAA,IACL;AAEA,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,OAAO;AAAA,QACP,4BAA0B;AAAA,QAE1B;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,WAAW;AAAA,YACX,OAAO;AAAA,YACP;AAAA,YACA;AAAA,YACA;AAAA,YACA,iBAAe;AAAA,YACf,gBAAe;AAAA;AAAA,QACjB;AAAA;AAAA,IACF;AAAA,EAEJ;AACF;AAEA,UAAU,cAAc;","names":["import_react","EmbedEventType","EmbedCommandType","EmbedCommandAction","EmbedErrorCode","EmbedBackgroundType","EmbedQueryParam","EmbedCaptureOutcome","EmbedRole","EmbedCapability","OeMeeting"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -25,7 +25,8 @@ declare enum EmbedCommandAction {
|
|
|
25
25
|
TOGGLE_MIC = "toggleMic",
|
|
26
26
|
TOGGLE_CAMERA = "toggleCamera",
|
|
27
27
|
OPEN_STAGE = "openStage",
|
|
28
|
-
CLOSE_STAGE = "closeStage"
|
|
28
|
+
CLOSE_STAGE = "closeStage",
|
|
29
|
+
SET_BACKGROUND = "setBackground"
|
|
29
30
|
}
|
|
30
31
|
declare enum EmbedErrorCode {
|
|
31
32
|
TOKEN_INVALID = "TOKEN_INVALID",
|
|
@@ -40,6 +41,26 @@ declare enum EmbedErrorCode {
|
|
|
40
41
|
RECORDING_START_FAILED = "RECORDING_START_FAILED",
|
|
41
42
|
UNKNOWN = "UNKNOWN"
|
|
42
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Host-controlled camera background applied to this embed's local user only.
|
|
46
|
+
* `none` clears any active background effect. The host app enforces who may
|
|
47
|
+
* set it; the meeting does not interpret roles for this value.
|
|
48
|
+
*/
|
|
49
|
+
declare enum EmbedBackgroundType {
|
|
50
|
+
BLUR = "blur",
|
|
51
|
+
IMAGE = "image",
|
|
52
|
+
NONE = "none"
|
|
53
|
+
}
|
|
54
|
+
declare const MAX_BACKGROUND_URL_LENGTH = 2048;
|
|
55
|
+
interface EmbedBackground {
|
|
56
|
+
type: EmbedBackgroundType;
|
|
57
|
+
/** BLUR only. Defaults to `DEFAULT_BACKGROUND_BLUR_RADIUS`, clamped 1-50. */
|
|
58
|
+
blurRadius?: number;
|
|
59
|
+
/** IMAGE only. http(s) URL, max `MAX_BACKGROUND_URL_LENGTH`. */
|
|
60
|
+
url?: string;
|
|
61
|
+
/** When true the embed user cannot change blur/virtual backgrounds. */
|
|
62
|
+
locked?: boolean;
|
|
63
|
+
}
|
|
43
64
|
/** Open host-owned tool id. Meeting does not catalog values. */
|
|
44
65
|
type StageToolId = string;
|
|
45
66
|
declare const MAX_STAGE_URL_LENGTH = 2048;
|
|
@@ -56,7 +77,8 @@ declare enum EmbedQueryParam {
|
|
|
56
77
|
HIDE_LEAVE = "hideLeave",
|
|
57
78
|
AUTO_CAMERA_OFF = "autoCameraOff",
|
|
58
79
|
AUTO_TRANSCRIBE = "autoTranscribe",
|
|
59
|
-
AUTO_RECORD = "autoRecord"
|
|
80
|
+
AUTO_RECORD = "autoRecord",
|
|
81
|
+
BACKGROUND = "background"
|
|
60
82
|
}
|
|
61
83
|
/**
|
|
62
84
|
* What happened to the auto-transcribe request the embed made.
|
|
@@ -197,7 +219,7 @@ type EmbedEventOf<T extends EmbedEventType> = Extract<EmbedEvent, {
|
|
|
197
219
|
type EmbedCommandMessage = EmbedMessageBase & {
|
|
198
220
|
type: 'oemeeting:command';
|
|
199
221
|
action: EmbedCommandAction;
|
|
200
|
-
payload?: OpenStageInput;
|
|
222
|
+
payload?: OpenStageInput | EmbedBackground;
|
|
201
223
|
};
|
|
202
224
|
interface OeMeetingHandle {
|
|
203
225
|
leave: () => void;
|
|
@@ -231,6 +253,14 @@ interface OeMeetingProps {
|
|
|
231
253
|
autoTranscribe?: boolean;
|
|
232
254
|
/** Start the shared room recording as soon as the embed connects. */
|
|
233
255
|
autoRecord?: boolean;
|
|
256
|
+
/**
|
|
257
|
+
* Apply a camera background to this embed's local user (blur / image /
|
|
258
|
+
* none), optionally locking their own background choices. Pass the same
|
|
259
|
+
* value for every participant to brand an event. The initial value rides
|
|
260
|
+
* the embed URL; later changes are sent as a `setBackground` command once
|
|
261
|
+
* the embed is ready. Invalid input is ignored.
|
|
262
|
+
*/
|
|
263
|
+
background?: EmbedBackground;
|
|
234
264
|
title?: string;
|
|
235
265
|
width?: number | string;
|
|
236
266
|
height?: number | string;
|
|
@@ -270,6 +300,7 @@ interface BuildEmbedUrlOptions {
|
|
|
270
300
|
autoCameraOff?: boolean;
|
|
271
301
|
autoTranscribe?: boolean;
|
|
272
302
|
autoRecord?: boolean;
|
|
303
|
+
background?: EmbedBackground;
|
|
273
304
|
instanceId?: string;
|
|
274
305
|
hostOrigin?: string;
|
|
275
306
|
}
|
|
@@ -277,7 +308,7 @@ interface BuildEmbedUrlOptions {
|
|
|
277
308
|
declare const DEFAULT_IFRAME_ALLOW = "camera; microphone; fullscreen; autoplay; display-capture; clipboard-write; encrypted-media";
|
|
278
309
|
declare const OeMeeting: react.ForwardRefExoticComponent<OeMeetingProps & react.RefAttributes<OeMeetingHandle>>;
|
|
279
310
|
|
|
280
|
-
type UseOeMeetingOptions = Pick<OeMeetingProps, 'onReady' | 'onJoined' | 'onLeft' | 'onParticipantJoined' | 'onParticipantLeft' | 'onEnded' | 'onError' | 'onStageChanged' | 'onTranscriptStarted' | 'onRecordingStarted' | 'onRecordingSaved' | 'onEvent'> & {
|
|
311
|
+
type UseOeMeetingOptions = Pick<OeMeetingProps, 'onReady' | 'onJoined' | 'onLeft' | 'onParticipantJoined' | 'onParticipantLeft' | 'onEnded' | 'onError' | 'onStageChanged' | 'onTranscriptStarted' | 'onRecordingStarted' | 'onRecordingSaved' | 'onEvent' | 'background'> & {
|
|
281
312
|
instanceId: string;
|
|
282
313
|
targetOrigin: string;
|
|
283
314
|
handleRef?: Ref<OeMeetingHandle>;
|
|
@@ -294,4 +325,12 @@ declare function parseEmbedEvent(data: unknown): EmbedEvent | null;
|
|
|
294
325
|
declare function isValidStageUrl(url: string): boolean;
|
|
295
326
|
declare function normalizeOpenStageInput(input: OpenStageInput): OpenStageInput | null;
|
|
296
327
|
|
|
297
|
-
|
|
328
|
+
/**
|
|
329
|
+
* Validate and normalize a host-provided background. Returns null for invalid
|
|
330
|
+
* input so callers can silently drop it, mirroring `normalizeOpenStageInput`.
|
|
331
|
+
*/
|
|
332
|
+
declare function normalizeEmbedBackground(input: EmbedBackground): EmbedBackground | null;
|
|
333
|
+
/** JSON wire format shared by the `background` query param and the command payload. */
|
|
334
|
+
declare function serializeEmbedBackground(input: EmbedBackground): string | undefined;
|
|
335
|
+
|
|
336
|
+
export { type BuildEmbedUrlOptions, DEFAULT_EMBED_ORIGIN, DEFAULT_IFRAME_ALLOW, EMBED_MESSAGE_SOURCE, EMBED_PROTOCOL_VERSION, type EmbedBackground, EmbedBackgroundType, EmbedCapability, EmbedCaptureOutcome, EmbedCommandAction, type EmbedCommandMessage, EmbedCommandType, type EmbedEndedPayload, EmbedErrorCode, type EmbedErrorPayload, type EmbedEvent, type EmbedEventOf, type EmbedEventPayloadMap, EmbedEventType, type EmbedJoinedPayload, type EmbedLeftPayload, type EmbedMessageBase, type EmbedParticipantJoinedPayload, type EmbedParticipantLeftPayload, type EmbedPermissionMap, EmbedQueryParam, type EmbedReadyPayload, type EmbedRecordingSavedPayload, type EmbedRecordingStartedPayload, EmbedRole, type EmbedStageChangedPayload, type EmbedTranscriptStartedPayload, MAX_BACKGROUND_URL_LENGTH, MAX_STAGE_TOOL_ID_LENGTH, MAX_STAGE_URL_LENGTH, OeMeeting, type OeMeetingHandle, type OeMeetingProps, type OpenStageInput, type StageToolId, buildEmbedUrl, isStageToolId, isValidStageUrl, normalizeEmbedBackground, normalizeOpenStageInput, parseEmbedEvent, serializeEmbedBackground, useOeMeeting };
|
package/dist/index.d.ts
CHANGED
|
@@ -25,7 +25,8 @@ declare enum EmbedCommandAction {
|
|
|
25
25
|
TOGGLE_MIC = "toggleMic",
|
|
26
26
|
TOGGLE_CAMERA = "toggleCamera",
|
|
27
27
|
OPEN_STAGE = "openStage",
|
|
28
|
-
CLOSE_STAGE = "closeStage"
|
|
28
|
+
CLOSE_STAGE = "closeStage",
|
|
29
|
+
SET_BACKGROUND = "setBackground"
|
|
29
30
|
}
|
|
30
31
|
declare enum EmbedErrorCode {
|
|
31
32
|
TOKEN_INVALID = "TOKEN_INVALID",
|
|
@@ -40,6 +41,26 @@ declare enum EmbedErrorCode {
|
|
|
40
41
|
RECORDING_START_FAILED = "RECORDING_START_FAILED",
|
|
41
42
|
UNKNOWN = "UNKNOWN"
|
|
42
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Host-controlled camera background applied to this embed's local user only.
|
|
46
|
+
* `none` clears any active background effect. The host app enforces who may
|
|
47
|
+
* set it; the meeting does not interpret roles for this value.
|
|
48
|
+
*/
|
|
49
|
+
declare enum EmbedBackgroundType {
|
|
50
|
+
BLUR = "blur",
|
|
51
|
+
IMAGE = "image",
|
|
52
|
+
NONE = "none"
|
|
53
|
+
}
|
|
54
|
+
declare const MAX_BACKGROUND_URL_LENGTH = 2048;
|
|
55
|
+
interface EmbedBackground {
|
|
56
|
+
type: EmbedBackgroundType;
|
|
57
|
+
/** BLUR only. Defaults to `DEFAULT_BACKGROUND_BLUR_RADIUS`, clamped 1-50. */
|
|
58
|
+
blurRadius?: number;
|
|
59
|
+
/** IMAGE only. http(s) URL, max `MAX_BACKGROUND_URL_LENGTH`. */
|
|
60
|
+
url?: string;
|
|
61
|
+
/** When true the embed user cannot change blur/virtual backgrounds. */
|
|
62
|
+
locked?: boolean;
|
|
63
|
+
}
|
|
43
64
|
/** Open host-owned tool id. Meeting does not catalog values. */
|
|
44
65
|
type StageToolId = string;
|
|
45
66
|
declare const MAX_STAGE_URL_LENGTH = 2048;
|
|
@@ -56,7 +77,8 @@ declare enum EmbedQueryParam {
|
|
|
56
77
|
HIDE_LEAVE = "hideLeave",
|
|
57
78
|
AUTO_CAMERA_OFF = "autoCameraOff",
|
|
58
79
|
AUTO_TRANSCRIBE = "autoTranscribe",
|
|
59
|
-
AUTO_RECORD = "autoRecord"
|
|
80
|
+
AUTO_RECORD = "autoRecord",
|
|
81
|
+
BACKGROUND = "background"
|
|
60
82
|
}
|
|
61
83
|
/**
|
|
62
84
|
* What happened to the auto-transcribe request the embed made.
|
|
@@ -197,7 +219,7 @@ type EmbedEventOf<T extends EmbedEventType> = Extract<EmbedEvent, {
|
|
|
197
219
|
type EmbedCommandMessage = EmbedMessageBase & {
|
|
198
220
|
type: 'oemeeting:command';
|
|
199
221
|
action: EmbedCommandAction;
|
|
200
|
-
payload?: OpenStageInput;
|
|
222
|
+
payload?: OpenStageInput | EmbedBackground;
|
|
201
223
|
};
|
|
202
224
|
interface OeMeetingHandle {
|
|
203
225
|
leave: () => void;
|
|
@@ -231,6 +253,14 @@ interface OeMeetingProps {
|
|
|
231
253
|
autoTranscribe?: boolean;
|
|
232
254
|
/** Start the shared room recording as soon as the embed connects. */
|
|
233
255
|
autoRecord?: boolean;
|
|
256
|
+
/**
|
|
257
|
+
* Apply a camera background to this embed's local user (blur / image /
|
|
258
|
+
* none), optionally locking their own background choices. Pass the same
|
|
259
|
+
* value for every participant to brand an event. The initial value rides
|
|
260
|
+
* the embed URL; later changes are sent as a `setBackground` command once
|
|
261
|
+
* the embed is ready. Invalid input is ignored.
|
|
262
|
+
*/
|
|
263
|
+
background?: EmbedBackground;
|
|
234
264
|
title?: string;
|
|
235
265
|
width?: number | string;
|
|
236
266
|
height?: number | string;
|
|
@@ -270,6 +300,7 @@ interface BuildEmbedUrlOptions {
|
|
|
270
300
|
autoCameraOff?: boolean;
|
|
271
301
|
autoTranscribe?: boolean;
|
|
272
302
|
autoRecord?: boolean;
|
|
303
|
+
background?: EmbedBackground;
|
|
273
304
|
instanceId?: string;
|
|
274
305
|
hostOrigin?: string;
|
|
275
306
|
}
|
|
@@ -277,7 +308,7 @@ interface BuildEmbedUrlOptions {
|
|
|
277
308
|
declare const DEFAULT_IFRAME_ALLOW = "camera; microphone; fullscreen; autoplay; display-capture; clipboard-write; encrypted-media";
|
|
278
309
|
declare const OeMeeting: react.ForwardRefExoticComponent<OeMeetingProps & react.RefAttributes<OeMeetingHandle>>;
|
|
279
310
|
|
|
280
|
-
type UseOeMeetingOptions = Pick<OeMeetingProps, 'onReady' | 'onJoined' | 'onLeft' | 'onParticipantJoined' | 'onParticipantLeft' | 'onEnded' | 'onError' | 'onStageChanged' | 'onTranscriptStarted' | 'onRecordingStarted' | 'onRecordingSaved' | 'onEvent'> & {
|
|
311
|
+
type UseOeMeetingOptions = Pick<OeMeetingProps, 'onReady' | 'onJoined' | 'onLeft' | 'onParticipantJoined' | 'onParticipantLeft' | 'onEnded' | 'onError' | 'onStageChanged' | 'onTranscriptStarted' | 'onRecordingStarted' | 'onRecordingSaved' | 'onEvent' | 'background'> & {
|
|
281
312
|
instanceId: string;
|
|
282
313
|
targetOrigin: string;
|
|
283
314
|
handleRef?: Ref<OeMeetingHandle>;
|
|
@@ -294,4 +325,12 @@ declare function parseEmbedEvent(data: unknown): EmbedEvent | null;
|
|
|
294
325
|
declare function isValidStageUrl(url: string): boolean;
|
|
295
326
|
declare function normalizeOpenStageInput(input: OpenStageInput): OpenStageInput | null;
|
|
296
327
|
|
|
297
|
-
|
|
328
|
+
/**
|
|
329
|
+
* Validate and normalize a host-provided background. Returns null for invalid
|
|
330
|
+
* input so callers can silently drop it, mirroring `normalizeOpenStageInput`.
|
|
331
|
+
*/
|
|
332
|
+
declare function normalizeEmbedBackground(input: EmbedBackground): EmbedBackground | null;
|
|
333
|
+
/** JSON wire format shared by the `background` query param and the command payload. */
|
|
334
|
+
declare function serializeEmbedBackground(input: EmbedBackground): string | undefined;
|
|
335
|
+
|
|
336
|
+
export { type BuildEmbedUrlOptions, DEFAULT_EMBED_ORIGIN, DEFAULT_IFRAME_ALLOW, EMBED_MESSAGE_SOURCE, EMBED_PROTOCOL_VERSION, type EmbedBackground, EmbedBackgroundType, EmbedCapability, EmbedCaptureOutcome, EmbedCommandAction, type EmbedCommandMessage, EmbedCommandType, type EmbedEndedPayload, EmbedErrorCode, type EmbedErrorPayload, type EmbedEvent, type EmbedEventOf, type EmbedEventPayloadMap, EmbedEventType, type EmbedJoinedPayload, type EmbedLeftPayload, type EmbedMessageBase, type EmbedParticipantJoinedPayload, type EmbedParticipantLeftPayload, type EmbedPermissionMap, EmbedQueryParam, type EmbedReadyPayload, type EmbedRecordingSavedPayload, type EmbedRecordingStartedPayload, EmbedRole, type EmbedStageChangedPayload, type EmbedTranscriptStartedPayload, MAX_BACKGROUND_URL_LENGTH, MAX_STAGE_TOOL_ID_LENGTH, MAX_STAGE_URL_LENGTH, OeMeeting, type OeMeetingHandle, type OeMeetingProps, type OpenStageInput, type StageToolId, buildEmbedUrl, isStageToolId, isValidStageUrl, normalizeEmbedBackground, normalizeOpenStageInput, parseEmbedEvent, serializeEmbedBackground, useOeMeeting };
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
import {
|
|
3
3
|
forwardRef,
|
|
4
4
|
useId,
|
|
5
|
-
useMemo as useMemo2
|
|
5
|
+
useMemo as useMemo2,
|
|
6
|
+
useRef as useRef2
|
|
6
7
|
} from "react";
|
|
7
8
|
|
|
8
9
|
// src/embed-protocol.ts
|
|
@@ -33,6 +34,7 @@ var EmbedCommandAction = /* @__PURE__ */ ((EmbedCommandAction2) => {
|
|
|
33
34
|
EmbedCommandAction2["TOGGLE_CAMERA"] = "toggleCamera";
|
|
34
35
|
EmbedCommandAction2["OPEN_STAGE"] = "openStage";
|
|
35
36
|
EmbedCommandAction2["CLOSE_STAGE"] = "closeStage";
|
|
37
|
+
EmbedCommandAction2["SET_BACKGROUND"] = "setBackground";
|
|
36
38
|
return EmbedCommandAction2;
|
|
37
39
|
})(EmbedCommandAction || {});
|
|
38
40
|
var EmbedErrorCode = /* @__PURE__ */ ((EmbedErrorCode2) => {
|
|
@@ -49,6 +51,16 @@ var EmbedErrorCode = /* @__PURE__ */ ((EmbedErrorCode2) => {
|
|
|
49
51
|
EmbedErrorCode2["UNKNOWN"] = "UNKNOWN";
|
|
50
52
|
return EmbedErrorCode2;
|
|
51
53
|
})(EmbedErrorCode || {});
|
|
54
|
+
var EmbedBackgroundType = /* @__PURE__ */ ((EmbedBackgroundType2) => {
|
|
55
|
+
EmbedBackgroundType2["BLUR"] = "blur";
|
|
56
|
+
EmbedBackgroundType2["IMAGE"] = "image";
|
|
57
|
+
EmbedBackgroundType2["NONE"] = "none";
|
|
58
|
+
return EmbedBackgroundType2;
|
|
59
|
+
})(EmbedBackgroundType || {});
|
|
60
|
+
var MAX_BACKGROUND_URL_LENGTH = 2048;
|
|
61
|
+
var DEFAULT_BACKGROUND_BLUR_RADIUS = 10;
|
|
62
|
+
var MIN_BACKGROUND_BLUR_RADIUS = 1;
|
|
63
|
+
var MAX_BACKGROUND_BLUR_RADIUS = 50;
|
|
52
64
|
var MAX_STAGE_URL_LENGTH = 2048;
|
|
53
65
|
var MAX_STAGE_TOOL_ID_LENGTH = 32;
|
|
54
66
|
var STAGE_TOOL_ID_PATTERN = /^[a-z][a-z0-9._-]{0,31}$/;
|
|
@@ -67,6 +79,7 @@ var EmbedQueryParam = /* @__PURE__ */ ((EmbedQueryParam2) => {
|
|
|
67
79
|
EmbedQueryParam2["AUTO_CAMERA_OFF"] = "autoCameraOff";
|
|
68
80
|
EmbedQueryParam2["AUTO_TRANSCRIBE"] = "autoTranscribe";
|
|
69
81
|
EmbedQueryParam2["AUTO_RECORD"] = "autoRecord";
|
|
82
|
+
EmbedQueryParam2["BACKGROUND"] = "background";
|
|
70
83
|
return EmbedQueryParam2;
|
|
71
84
|
})(EmbedQueryParam || {});
|
|
72
85
|
var EmbedCaptureOutcome = /* @__PURE__ */ ((EmbedCaptureOutcome2) => {
|
|
@@ -86,6 +99,62 @@ var EmbedCapability = /* @__PURE__ */ ((EmbedCapability2) => {
|
|
|
86
99
|
return EmbedCapability2;
|
|
87
100
|
})(EmbedCapability || {});
|
|
88
101
|
|
|
102
|
+
// src/openStage.ts
|
|
103
|
+
function isValidStageUrl(url) {
|
|
104
|
+
if (url.length === 0 || url.length > MAX_STAGE_URL_LENGTH) return false;
|
|
105
|
+
try {
|
|
106
|
+
const parsed = new URL(url);
|
|
107
|
+
if (parsed.protocol === "https:") return true;
|
|
108
|
+
if (parsed.protocol === "http:") {
|
|
109
|
+
return parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1";
|
|
110
|
+
}
|
|
111
|
+
return false;
|
|
112
|
+
} catch {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function normalizeOpenStageInput(input) {
|
|
117
|
+
const url = input.url.trim();
|
|
118
|
+
if (!isValidStageUrl(url)) return null;
|
|
119
|
+
const title = input.title?.trim();
|
|
120
|
+
return {
|
|
121
|
+
url,
|
|
122
|
+
...title ? { title: title.slice(0, 200) } : {},
|
|
123
|
+
...isStageToolId(input.tool) ? { tool: input.tool } : {}
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// src/background.ts
|
|
128
|
+
var isValidBackgroundUrl = (url) => url.length > 0 && url.length <= MAX_BACKGROUND_URL_LENGTH && isValidStageUrl(url);
|
|
129
|
+
var clampBlurRadius = (value) => Number.isFinite(value) ? Math.min(MAX_BACKGROUND_BLUR_RADIUS, Math.max(MIN_BACKGROUND_BLUR_RADIUS, Math.round(value))) : DEFAULT_BACKGROUND_BLUR_RADIUS;
|
|
130
|
+
function normalizeEmbedBackground(input) {
|
|
131
|
+
const locked = input.locked === true ? { locked: true } : {};
|
|
132
|
+
if (input.type === "none" /* NONE */) {
|
|
133
|
+
return { type: "none" /* NONE */, ...locked };
|
|
134
|
+
}
|
|
135
|
+
if (input.type === "blur" /* BLUR */) {
|
|
136
|
+
return {
|
|
137
|
+
type: "blur" /* BLUR */,
|
|
138
|
+
blurRadius: clampBlurRadius(input.blurRadius ?? DEFAULT_BACKGROUND_BLUR_RADIUS),
|
|
139
|
+
...locked
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
if (input.type === "image" /* IMAGE */) {
|
|
143
|
+
const url = input.url?.trim();
|
|
144
|
+
if (!url || !isValidBackgroundUrl(url)) return null;
|
|
145
|
+
return {
|
|
146
|
+
type: "image" /* IMAGE */,
|
|
147
|
+
url,
|
|
148
|
+
...locked
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
function serializeEmbedBackground(input) {
|
|
154
|
+
const normalized = normalizeEmbedBackground(input);
|
|
155
|
+
return normalized ? JSON.stringify(normalized) : void 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
89
158
|
// src/buildEmbedUrl.ts
|
|
90
159
|
var QUERY_FLAG_ENABLED = "1";
|
|
91
160
|
var QUERY_FLAG_DISABLED = "0";
|
|
@@ -107,6 +176,7 @@ function buildEmbedUrl(options) {
|
|
|
107
176
|
}
|
|
108
177
|
const origin = normalizeOrigin(options.origin ?? DEFAULT_EMBED_ORIGIN);
|
|
109
178
|
const url = new URL(`${origin}/embed/${encodeURIComponent(roomSlug)}`);
|
|
179
|
+
const backgroundParam = options.background ? serializeEmbedBackground(options.background) : void 0;
|
|
110
180
|
const entries = [
|
|
111
181
|
["instanceId" /* INSTANCE_ID */, options.instanceId],
|
|
112
182
|
["hostOrigin" /* HOST_ORIGIN */, options.hostOrigin],
|
|
@@ -118,7 +188,8 @@ function buildEmbedUrl(options) {
|
|
|
118
188
|
["hideLeave" /* HIDE_LEAVE */, toFlag(options.hideLeave)],
|
|
119
189
|
["autoCameraOff" /* AUTO_CAMERA_OFF */, toFlag(options.autoCameraOff)],
|
|
120
190
|
["autoTranscribe" /* AUTO_TRANSCRIBE */, toFlag(options.autoTranscribe)],
|
|
121
|
-
["autoRecord" /* AUTO_RECORD */, toFlag(options.autoRecord)]
|
|
191
|
+
["autoRecord" /* AUTO_RECORD */, toFlag(options.autoRecord)],
|
|
192
|
+
["background" /* BACKGROUND */, backgroundParam]
|
|
122
193
|
];
|
|
123
194
|
for (const [key, value] of entries) {
|
|
124
195
|
if (value !== void 0 && value !== "") {
|
|
@@ -137,31 +208,6 @@ import {
|
|
|
137
208
|
useRef
|
|
138
209
|
} from "react";
|
|
139
210
|
|
|
140
|
-
// src/openStage.ts
|
|
141
|
-
function isValidStageUrl(url) {
|
|
142
|
-
if (url.length === 0 || url.length > MAX_STAGE_URL_LENGTH) return false;
|
|
143
|
-
try {
|
|
144
|
-
const parsed = new URL(url);
|
|
145
|
-
if (parsed.protocol === "https:") return true;
|
|
146
|
-
if (parsed.protocol === "http:") {
|
|
147
|
-
return parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1";
|
|
148
|
-
}
|
|
149
|
-
return false;
|
|
150
|
-
} catch {
|
|
151
|
-
return false;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
function normalizeOpenStageInput(input) {
|
|
155
|
-
const url = input.url.trim();
|
|
156
|
-
if (!isValidStageUrl(url)) return null;
|
|
157
|
-
const title = input.title?.trim();
|
|
158
|
-
return {
|
|
159
|
-
url,
|
|
160
|
-
...title ? { title: title.slice(0, 200) } : {},
|
|
161
|
-
...isStageToolId(input.tool) ? { tool: input.tool } : {}
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
|
|
165
211
|
// src/parseEmbedEvent.ts
|
|
166
212
|
var EVENT_TYPES = new Set(Object.values(EmbedEventType));
|
|
167
213
|
function isRecord(value) {
|
|
@@ -230,6 +276,7 @@ function postCommand(options) {
|
|
|
230
276
|
function useOeMeeting(options) {
|
|
231
277
|
const iframeRef = useRef(null);
|
|
232
278
|
const callbacksRef = useRef(options);
|
|
279
|
+
const pendingBackgroundRef = useRef(null);
|
|
233
280
|
useEffect(() => {
|
|
234
281
|
callbacksRef.current = options;
|
|
235
282
|
}, [options]);
|
|
@@ -246,6 +293,15 @@ function useOeMeeting(options) {
|
|
|
246
293
|
switch (embedEvent.type) {
|
|
247
294
|
case "oemeeting:ready" /* READY */:
|
|
248
295
|
callbacks.onReady?.(embedEvent);
|
|
296
|
+
if (pendingBackgroundRef.current) {
|
|
297
|
+
postCommand({
|
|
298
|
+
iframe: iframeRef.current,
|
|
299
|
+
instanceId: options.instanceId,
|
|
300
|
+
action: "setBackground" /* SET_BACKGROUND */,
|
|
301
|
+
targetOrigin: options.targetOrigin,
|
|
302
|
+
payload: pendingBackgroundRef.current
|
|
303
|
+
});
|
|
304
|
+
}
|
|
249
305
|
break;
|
|
250
306
|
case "oemeeting:joined" /* JOINED */:
|
|
251
307
|
callbacks.onJoined?.(embedEvent);
|
|
@@ -313,6 +369,16 @@ function useOeMeeting(options) {
|
|
|
313
369
|
() => send("closeStage" /* CLOSE_STAGE */),
|
|
314
370
|
[send]
|
|
315
371
|
);
|
|
372
|
+
useEffect(() => {
|
|
373
|
+
if (!options.background) {
|
|
374
|
+
pendingBackgroundRef.current = null;
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
const normalized = normalizeEmbedBackground(options.background);
|
|
378
|
+
if (!normalized) return;
|
|
379
|
+
pendingBackgroundRef.current = normalized;
|
|
380
|
+
send("setBackground" /* SET_BACKGROUND */, normalized);
|
|
381
|
+
}, [options.background, send]);
|
|
316
382
|
const getIframe = useCallback(() => iframeRef.current, []);
|
|
317
383
|
const handle = useMemo(
|
|
318
384
|
() => ({
|
|
@@ -353,6 +419,7 @@ var OeMeeting = forwardRef(
|
|
|
353
419
|
autoCameraOff,
|
|
354
420
|
autoTranscribe,
|
|
355
421
|
autoRecord,
|
|
422
|
+
background,
|
|
356
423
|
title = "OE Meeting room",
|
|
357
424
|
width = "100%",
|
|
358
425
|
height = 640,
|
|
@@ -383,6 +450,7 @@ var OeMeeting = forwardRef(
|
|
|
383
450
|
const embedOrigin = useMemo2(() => getOrigin(origin), [origin]);
|
|
384
451
|
const resolvedTargetOrigin = targetOrigin ?? embedOrigin;
|
|
385
452
|
const hostOrigin = typeof window === "undefined" ? void 0 : window.location.origin;
|
|
453
|
+
const initialBackgroundRef = useRef2(background);
|
|
386
454
|
const src = useMemo2(
|
|
387
455
|
() => buildEmbedUrl({
|
|
388
456
|
roomSlug,
|
|
@@ -396,6 +464,7 @@ var OeMeeting = forwardRef(
|
|
|
396
464
|
autoCameraOff,
|
|
397
465
|
autoTranscribe,
|
|
398
466
|
autoRecord,
|
|
467
|
+
background: initialBackgroundRef.current,
|
|
399
468
|
instanceId,
|
|
400
469
|
hostOrigin
|
|
401
470
|
}),
|
|
@@ -416,6 +485,7 @@ var OeMeeting = forwardRef(
|
|
|
416
485
|
]
|
|
417
486
|
);
|
|
418
487
|
const { iframeRef } = useOeMeeting({
|
|
488
|
+
background,
|
|
419
489
|
instanceId,
|
|
420
490
|
targetOrigin: resolvedTargetOrigin,
|
|
421
491
|
handleRef: ref,
|
|
@@ -473,6 +543,7 @@ export {
|
|
|
473
543
|
DEFAULT_IFRAME_ALLOW,
|
|
474
544
|
EMBED_MESSAGE_SOURCE,
|
|
475
545
|
EMBED_PROTOCOL_VERSION,
|
|
546
|
+
EmbedBackgroundType,
|
|
476
547
|
EmbedCapability,
|
|
477
548
|
EmbedCaptureOutcome,
|
|
478
549
|
EmbedCommandAction,
|
|
@@ -481,14 +552,17 @@ export {
|
|
|
481
552
|
EmbedEventType,
|
|
482
553
|
EmbedQueryParam,
|
|
483
554
|
EmbedRole,
|
|
555
|
+
MAX_BACKGROUND_URL_LENGTH,
|
|
484
556
|
MAX_STAGE_TOOL_ID_LENGTH,
|
|
485
557
|
MAX_STAGE_URL_LENGTH,
|
|
486
558
|
OeMeeting,
|
|
487
559
|
buildEmbedUrl,
|
|
488
560
|
isStageToolId,
|
|
489
561
|
isValidStageUrl,
|
|
562
|
+
normalizeEmbedBackground,
|
|
490
563
|
normalizeOpenStageInput,
|
|
491
564
|
parseEmbedEvent,
|
|
565
|
+
serializeEmbedBackground,
|
|
492
566
|
useOeMeeting
|
|
493
567
|
};
|
|
494
568
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/OeMeeting.tsx","../src/embed-protocol.ts","../src/buildEmbedUrl.ts","../src/useOeMeeting.ts","../src/openStage.ts","../src/parseEmbedEvent.ts"],"sourcesContent":["'use client';\n\nimport {\n forwardRef,\n useId,\n useMemo,\n type CSSProperties,\n} from 'react';\nimport { buildEmbedUrl } from './buildEmbedUrl';\nimport { DEFAULT_EMBED_ORIGIN } from './embed-protocol';\nimport type { OeMeetingHandle, OeMeetingProps } from './types';\nimport { useOeMeeting } from './useOeMeeting';\n\nexport const DEFAULT_IFRAME_ALLOW =\n 'camera; microphone; fullscreen; autoplay; display-capture; clipboard-write; encrypted-media';\n\nfunction toCssSize(value: number | string | undefined): string | undefined {\n if (value === undefined) return undefined;\n return typeof value === 'number' ? `${value}px` : value;\n}\n\nfunction getOrigin(value: string): string {\n return new URL(value).origin;\n}\n\nexport const OeMeeting = forwardRef<OeMeetingHandle, OeMeetingProps>(\n function OeMeeting(props, ref) {\n const {\n roomSlug,\n joinToken,\n userName,\n externalUserId,\n origin = DEFAULT_EMBED_ORIGIN,\n lang,\n autoJoin = true,\n hideLeave,\n autoCameraOff,\n autoTranscribe,\n autoRecord,\n title = 'OE Meeting room',\n width = '100%',\n height = 640,\n className,\n style,\n iframeClassName,\n iframeStyle,\n allow = DEFAULT_IFRAME_ALLOW,\n targetOrigin,\n onReady,\n onJoined,\n onLeft,\n onParticipantJoined,\n onParticipantLeft,\n onEnded,\n onError,\n onStageChanged,\n onTranscriptStarted,\n onRecordingStarted,\n onRecordingSaved,\n onEvent,\n } = props;\n const reactId = useId();\n const instanceId = useMemo(\n () => `oem-${reactId.replace(/:/g, '')}`,\n [reactId],\n );\n const embedOrigin = useMemo(() => getOrigin(origin), [origin]);\n const resolvedTargetOrigin = targetOrigin ?? embedOrigin;\n const hostOrigin =\n typeof window === 'undefined' ? undefined : window.location.origin;\n const src = useMemo(\n () =>\n buildEmbedUrl({\n roomSlug,\n joinToken,\n userName,\n externalUserId,\n origin,\n lang,\n autoJoin,\n hideLeave,\n autoCameraOff,\n autoTranscribe,\n autoRecord,\n instanceId,\n hostOrigin,\n }),\n [\n autoJoin,\n autoRecord,\n autoTranscribe,\n externalUserId,\n hideLeave,\n hostOrigin,\n instanceId,\n joinToken,\n lang,\n origin,\n roomSlug,\n autoCameraOff,\n userName,\n ],\n );\n const { iframeRef } = useOeMeeting({\n instanceId,\n targetOrigin: resolvedTargetOrigin,\n handleRef: ref,\n onReady,\n onJoined,\n onLeft,\n onParticipantJoined,\n onParticipantLeft,\n onEnded,\n onError,\n onStageChanged,\n onTranscriptStarted,\n onRecordingStarted,\n onRecordingSaved,\n onEvent,\n });\n const wrapperStyle: CSSProperties = {\n width: toCssSize(width),\n height: toCssSize(height),\n ...style,\n };\n const frameStyle: CSSProperties = {\n width: '100%',\n height: '100%',\n border: 0,\n display: 'block',\n ...iframeStyle,\n };\n\n return (\n <div\n className={className}\n style={wrapperStyle}\n data-oe-meeting-instance={instanceId}\n >\n <iframe\n ref={iframeRef}\n className={iframeClassName}\n style={frameStyle}\n src={src}\n title={title}\n allow={allow}\n allowFullScreen\n referrerPolicy=\"strict-origin-when-cross-origin\"\n />\n </div>\n );\n },\n);\n\nOeMeeting.displayName = 'OeMeeting';\n","export const EMBED_PROTOCOL_VERSION = 1 as const;\nexport const EMBED_MESSAGE_SOURCE = 'oemeeting' as const;\nexport const DEFAULT_EMBED_ORIGIN = 'https://meet.ocean.edu.vn';\n\nexport enum EmbedEventType {\n READY = 'oemeeting:ready',\n JOINED = 'oemeeting:joined',\n LEFT = 'oemeeting:left',\n PARTICIPANT_JOINED = 'oemeeting:participant-joined',\n PARTICIPANT_LEFT = 'oemeeting:participant-left',\n ENDED = 'oemeeting:ended',\n ERROR = 'oemeeting:error',\n STAGE_CHANGED = 'oemeeting:stage-changed',\n TRANSCRIPT_STARTED = 'oemeeting:transcript-started',\n RECORDING_STARTED = 'oemeeting:recording-started',\n RECORDING_SAVED = 'oemeeting:recording-saved',\n}\n\nexport enum EmbedCommandType {\n COMMAND = 'oemeeting:command',\n}\n\nexport enum EmbedCommandAction {\n LEAVE = 'leave',\n TOGGLE_MIC = 'toggleMic',\n TOGGLE_CAMERA = 'toggleCamera',\n OPEN_STAGE = 'openStage',\n CLOSE_STAGE = 'closeStage',\n}\n\nexport enum EmbedErrorCode {\n TOKEN_INVALID = 'TOKEN_INVALID',\n TOKEN_EXPIRED = 'TOKEN_EXPIRED',\n ROOM_NOT_FOUND = 'ROOM_NOT_FOUND',\n ROOM_ACCESS_DENIED = 'ROOM_ACCESS_DENIED',\n CONNECTION_FAILED = 'CONNECTION_FAILED',\n PROTOCOL_MISMATCH = 'PROTOCOL_MISMATCH',\n STAGE_ORIGIN_DENIED = 'STAGE_ORIGIN_DENIED',\n STAGE_URL_INVALID = 'STAGE_URL_INVALID',\n TRANSCRIPT_START_FAILED = 'TRANSCRIPT_START_FAILED',\n RECORDING_START_FAILED = 'RECORDING_START_FAILED',\n UNKNOWN = 'UNKNOWN',\n}\n\n/** Open host-owned tool id. Meeting does not catalog values. */\nexport type StageToolId = string;\n\nexport const MAX_STAGE_URL_LENGTH = 2048;\nexport const MAX_STAGE_TOOL_ID_LENGTH = 32;\n\nconst STAGE_TOOL_ID_PATTERN = /^[a-z][a-z0-9._-]{0,31}$/;\n\nexport function isStageToolId(value: unknown): value is StageToolId {\n return (\n typeof value === 'string' &&\n value.length > 0 &&\n value.length <= MAX_STAGE_TOOL_ID_LENGTH &&\n STAGE_TOOL_ID_PATTERN.test(value)\n );\n}\n\nexport enum EmbedQueryParam {\n INSTANCE_ID = 'instanceId',\n HOST_ORIGIN = 'hostOrigin',\n JOIN_TOKEN = 'joinToken',\n USER_NAME = 'userName',\n EXTERNAL_USER_ID = 'externalUserId',\n LANG = 'lang',\n AUTO_JOIN = 'autoJoin',\n HIDE_LEAVE = 'hideLeave',\n AUTO_CAMERA_OFF = 'autoCameraOff',\n AUTO_TRANSCRIBE = 'autoTranscribe',\n AUTO_RECORD = 'autoRecord',\n}\n\n/**\n * What happened to the auto-transcribe request the embed made.\n *\n * `ALREADY_RUNNING` is the normal outcome for every participant after the\n * first, because the transcript is a room-level asset rather than a\n * per-participant one. `DISABLED` means the OE Meeting deployment has\n * transcription turned off.\n */\nexport enum EmbedCaptureOutcome {\n STARTED = 'started',\n ALREADY_RUNNING = 'already_running',\n DISABLED = 'disabled',\n FAILED = 'failed',\n}\n\n/**\n * Role the host app assigns when minting a join token.\n * Keep values aligned with `EmbedRole` in the backend embed-permission enum.\n */\nexport enum EmbedRole {\n OWNER = 'owner',\n MEMBER = 'member',\n}\n\n/**\n * Capability the host app may grant per role. Meeting enforces this on the\n * join token, not on a React prop. `screenShare` is the only value today.\n */\nexport enum EmbedCapability {\n SCREEN_SHARE = 'screenShare',\n}\n\nexport interface EmbedPermissionMap {\n owner?: EmbedCapability[];\n member?: EmbedCapability[];\n}\n","import {\n DEFAULT_EMBED_ORIGIN,\n EmbedQueryParam,\n} from './embed-protocol';\nimport type { BuildEmbedUrlOptions } from './types';\n\nconst QUERY_FLAG_ENABLED = '1';\nconst QUERY_FLAG_DISABLED = '0';\n\nfunction toFlag(value: boolean | undefined): string | undefined {\n if (value === undefined) return undefined;\n return value ? QUERY_FLAG_ENABLED : QUERY_FLAG_DISABLED;\n}\n\nfunction normalizeOrigin(origin: string): string {\n return origin.replace(/\\/+$/, '');\n}\n\nexport function buildEmbedUrl(options: BuildEmbedUrlOptions): string {\n const roomSlug = options.roomSlug.trim();\n const joinToken = options.joinToken.trim();\n if (!roomSlug) {\n throw new Error('OE Meeting embed requires a non-empty roomSlug.');\n }\n if (!joinToken) {\n throw new Error('OE Meeting embed requires a non-empty joinToken.');\n }\n\n const origin = normalizeOrigin(options.origin ?? DEFAULT_EMBED_ORIGIN);\n const url = new URL(`${origin}/embed/${encodeURIComponent(roomSlug)}`);\n const entries: Array<[EmbedQueryParam, string | undefined]> = [\n [EmbedQueryParam.INSTANCE_ID, options.instanceId],\n [EmbedQueryParam.HOST_ORIGIN, options.hostOrigin],\n [EmbedQueryParam.JOIN_TOKEN, joinToken],\n [EmbedQueryParam.USER_NAME, options.userName],\n [EmbedQueryParam.EXTERNAL_USER_ID, options.externalUserId],\n [EmbedQueryParam.LANG, options.lang],\n [EmbedQueryParam.AUTO_JOIN, toFlag(options.autoJoin)],\n [EmbedQueryParam.HIDE_LEAVE, toFlag(options.hideLeave)],\n [EmbedQueryParam.AUTO_CAMERA_OFF, toFlag(options.autoCameraOff)],\n [EmbedQueryParam.AUTO_TRANSCRIBE, toFlag(options.autoTranscribe)],\n [EmbedQueryParam.AUTO_RECORD, toFlag(options.autoRecord)],\n ];\n\n for (const [key, value] of entries) {\n if (value !== undefined && value !== '') {\n url.searchParams.set(key, value);\n }\n }\n return url.toString();\n}\n","import {\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n type Ref,\n} from 'react';\nimport {\n EMBED_MESSAGE_SOURCE,\n EMBED_PROTOCOL_VERSION,\n EmbedCommandAction,\n EmbedCommandType,\n EmbedEventType,\n} from './embed-protocol';\nimport { normalizeOpenStageInput } from './openStage';\nimport { parseEmbedEvent } from './parseEmbedEvent';\nimport type {\n EmbedCommandMessage,\n OeMeetingHandle,\n OeMeetingProps,\n OpenStageInput,\n} from './types';\n\ntype UseOeMeetingOptions = Pick<\n OeMeetingProps,\n | 'onReady'\n | 'onJoined'\n | 'onLeft'\n | 'onParticipantJoined'\n | 'onParticipantLeft'\n | 'onEnded'\n | 'onError'\n | 'onStageChanged'\n | 'onTranscriptStarted'\n | 'onRecordingStarted'\n | 'onRecordingSaved'\n | 'onEvent'\n> & {\n instanceId: string;\n targetOrigin: string;\n handleRef?: Ref<OeMeetingHandle>;\n};\n\ninterface PostCommandOptions {\n iframe: HTMLIFrameElement | null;\n instanceId: string;\n action: EmbedCommandAction;\n targetOrigin: string;\n payload?: OpenStageInput;\n}\n\nfunction postCommand(options: PostCommandOptions): void {\n const frameWindow = options.iframe?.contentWindow;\n if (!frameWindow) return;\n const message: EmbedCommandMessage = {\n source: EMBED_MESSAGE_SOURCE,\n version: EMBED_PROTOCOL_VERSION,\n instanceId: options.instanceId,\n type: EmbedCommandType.COMMAND,\n action: options.action,\n ...(options.payload ? { payload: options.payload } : {}),\n };\n frameWindow.postMessage(message, options.targetOrigin);\n}\n\nexport function useOeMeeting(options: UseOeMeetingOptions) {\n const iframeRef = useRef<HTMLIFrameElement | null>(null);\n const callbacksRef = useRef(options);\n\n useEffect(() => {\n callbacksRef.current = options;\n }, [options]);\n\n useEffect(() => {\n const onMessage = (event: MessageEvent<unknown>) => {\n const frameWindow = iframeRef.current?.contentWindow;\n if (\n !frameWindow ||\n event.source !== frameWindow ||\n event.origin !== options.targetOrigin\n ) {\n return;\n }\n const embedEvent = parseEmbedEvent(event.data);\n if (!embedEvent || embedEvent.instanceId !== options.instanceId) return;\n\n const callbacks = callbacksRef.current;\n callbacks.onEvent?.(embedEvent);\n switch (embedEvent.type) {\n case EmbedEventType.READY:\n callbacks.onReady?.(embedEvent);\n break;\n case EmbedEventType.JOINED:\n callbacks.onJoined?.(embedEvent);\n break;\n case EmbedEventType.LEFT:\n callbacks.onLeft?.(embedEvent);\n break;\n case EmbedEventType.PARTICIPANT_JOINED:\n callbacks.onParticipantJoined?.(embedEvent);\n break;\n case EmbedEventType.PARTICIPANT_LEFT:\n callbacks.onParticipantLeft?.(embedEvent);\n break;\n case EmbedEventType.ENDED:\n callbacks.onEnded?.(embedEvent);\n break;\n case EmbedEventType.ERROR:\n callbacks.onError?.(embedEvent);\n break;\n case EmbedEventType.STAGE_CHANGED:\n callbacks.onStageChanged?.(embedEvent);\n break;\n case EmbedEventType.TRANSCRIPT_STARTED:\n callbacks.onTranscriptStarted?.(embedEvent);\n break;\n case EmbedEventType.RECORDING_STARTED:\n callbacks.onRecordingStarted?.(embedEvent);\n break;\n case EmbedEventType.RECORDING_SAVED:\n callbacks.onRecordingSaved?.(embedEvent);\n break;\n }\n };\n\n window.addEventListener('message', onMessage);\n return () => window.removeEventListener('message', onMessage);\n }, [options.instanceId, options.targetOrigin]);\n\n const send = useCallback(\n (action: EmbedCommandAction, payload?: OpenStageInput) =>\n postCommand({\n iframe: iframeRef.current,\n instanceId: options.instanceId,\n action,\n targetOrigin: options.targetOrigin,\n payload,\n }),\n [options.instanceId, options.targetOrigin],\n );\n const leave = useCallback(() => send(EmbedCommandAction.LEAVE), [send]);\n const toggleMic = useCallback(\n () => send(EmbedCommandAction.TOGGLE_MIC),\n [send],\n );\n const toggleCamera = useCallback(\n () => send(EmbedCommandAction.TOGGLE_CAMERA),\n [send],\n );\n const openStage = useCallback(\n (input: OpenStageInput) => {\n const normalized = normalizeOpenStageInput(input);\n if (!normalized) return;\n send(EmbedCommandAction.OPEN_STAGE, normalized);\n },\n [send],\n );\n const closeStage = useCallback(\n () => send(EmbedCommandAction.CLOSE_STAGE),\n [send],\n );\n const getIframe = useCallback(() => iframeRef.current, []);\n const handle = useMemo<OeMeetingHandle>(\n () => ({\n leave,\n toggleMic,\n toggleCamera,\n openStage,\n closeStage,\n getIframe,\n }),\n [closeStage, getIframe, leave, openStage, toggleCamera, toggleMic],\n );\n\n useImperativeHandle(options.handleRef, () => handle, [handle]);\n return { iframeRef, handle };\n}\n","import { isStageToolId, MAX_STAGE_URL_LENGTH } from './embed-protocol';\nimport type { OpenStageInput } from './types';\n\nexport function isValidStageUrl(url: string): boolean {\n if (url.length === 0 || url.length > MAX_STAGE_URL_LENGTH) return false;\n try {\n const parsed = new URL(url);\n if (parsed.protocol === 'https:') return true;\n if (parsed.protocol === 'http:') {\n return (\n parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1'\n );\n }\n return false;\n } catch {\n return false;\n }\n}\n\nexport function normalizeOpenStageInput(\n input: OpenStageInput,\n): OpenStageInput | null {\n const url = input.url.trim();\n if (!isValidStageUrl(url)) return null;\n const title = input.title?.trim();\n return {\n url,\n ...(title ? { title: title.slice(0, 200) } : {}),\n ...(isStageToolId(input.tool) ? { tool: input.tool } : {}),\n };\n}\n","import {\n EMBED_MESSAGE_SOURCE,\n EMBED_PROTOCOL_VERSION,\n EmbedCaptureOutcome,\n EmbedEventType,\n} from './embed-protocol';\nimport type { EmbedEvent } from './types';\n\nconst EVENT_TYPES = new Set<string>(Object.values(EmbedEventType));\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction isOptionalString(value: unknown): boolean {\n return value === undefined || typeof value === 'string';\n}\n\nfunction isNullableString(value: unknown): boolean {\n return value === null || typeof value === 'string';\n}\n\nconst CAPTURE_OUTCOMES = new Set<string>(Object.values(EmbedCaptureOutcome));\n\nfunction isCaptureOutcome(value: unknown): boolean {\n return typeof value === 'string' && CAPTURE_OUTCOMES.has(value);\n}\n\nfunction hasValidPayload(\n type: EmbedEventType,\n payload: Record<string, unknown>,\n): boolean {\n switch (type) {\n case EmbedEventType.READY:\n return typeof payload.roomSlug === 'string';\n case EmbedEventType.JOINED:\n return (\n typeof payload.roomSlug === 'string' &&\n typeof payload.identity === 'string' &&\n isOptionalString(payload.name) &&\n typeof payload.joinedAt === 'string'\n );\n case EmbedEventType.LEFT:\n return (\n typeof payload.roomSlug === 'string' &&\n typeof payload.identity === 'string' &&\n typeof payload.leftAt === 'string' &&\n (payload.durationMs === undefined ||\n typeof payload.durationMs === 'number')\n );\n case EmbedEventType.PARTICIPANT_JOINED:\n return (\n typeof payload.identity === 'string' &&\n isOptionalString(payload.name) &&\n typeof payload.participantCount === 'number'\n );\n case EmbedEventType.PARTICIPANT_LEFT:\n return (\n typeof payload.identity === 'string' &&\n typeof payload.participantCount === 'number'\n );\n case EmbedEventType.ENDED:\n return (\n typeof payload.roomSlug === 'string' &&\n typeof payload.endedAt === 'string'\n );\n case EmbedEventType.ERROR:\n return (\n typeof payload.code === 'string' &&\n typeof payload.message === 'string'\n );\n case EmbedEventType.STAGE_CHANGED:\n return (\n (payload.url === null || typeof payload.url === 'string') &&\n isOptionalString(payload.title) &&\n isOptionalString(payload.tool) &&\n isOptionalString(payload.openedBy)\n );\n case EmbedEventType.TRANSCRIPT_STARTED:\n return (\n typeof payload.roomSlug === 'string' &&\n isCaptureOutcome(payload.outcome) &&\n isNullableString(payload.transcriptId) &&\n isNullableString(payload.status)\n );\n case EmbedEventType.RECORDING_STARTED:\n return (\n typeof payload.roomSlug === 'string' &&\n isCaptureOutcome(payload.outcome) &&\n isNullableString(payload.recordingId) &&\n isNullableString(payload.status)\n );\n case EmbedEventType.RECORDING_SAVED:\n return (\n typeof payload.roomSlug === 'string' &&\n typeof payload.savedAt === 'string'\n );\n }\n}\n\nexport function parseEmbedEvent(data: unknown): EmbedEvent | null {\n if (!isRecord(data)) return null;\n if (\n data.source !== EMBED_MESSAGE_SOURCE ||\n data.version !== EMBED_PROTOCOL_VERSION ||\n typeof data.instanceId !== 'string' ||\n data.instanceId.length === 0 ||\n typeof data.type !== 'string' ||\n !EVENT_TYPES.has(data.type) ||\n !isRecord(data.payload)\n ) {\n return null;\n }\n\n const type = data.type as EmbedEventType;\n if (!hasValidPayload(type, data.payload)) return null;\n return data as unknown as EmbedEvent;\n}\n"],"mappings":"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","names":["useMemo","EmbedEventType","EmbedCommandType","EmbedCommandAction","EmbedErrorCode","EmbedQueryParam","EmbedCaptureOutcome","EmbedRole","EmbedCapability","OeMeeting","useMemo"]}
|
|
1
|
+
{"version":3,"sources":["../src/OeMeeting.tsx","../src/embed-protocol.ts","../src/openStage.ts","../src/background.ts","../src/buildEmbedUrl.ts","../src/useOeMeeting.ts","../src/parseEmbedEvent.ts"],"sourcesContent":["'use client';\n\nimport {\n forwardRef,\n useId,\n useMemo,\n useRef,\n type CSSProperties,\n} from 'react';\nimport { buildEmbedUrl } from './buildEmbedUrl';\nimport { DEFAULT_EMBED_ORIGIN } from './embed-protocol';\nimport type { OeMeetingHandle, OeMeetingProps } from './types';\nimport { useOeMeeting } from './useOeMeeting';\n\nexport const DEFAULT_IFRAME_ALLOW =\n 'camera; microphone; fullscreen; autoplay; display-capture; clipboard-write; encrypted-media';\n\nfunction toCssSize(value: number | string | undefined): string | undefined {\n if (value === undefined) return undefined;\n return typeof value === 'number' ? `${value}px` : value;\n}\n\nfunction getOrigin(value: string): string {\n return new URL(value).origin;\n}\n\nexport const OeMeeting = forwardRef<OeMeetingHandle, OeMeetingProps>(\n function OeMeeting(props, ref) {\n const {\n roomSlug,\n joinToken,\n userName,\n externalUserId,\n origin = DEFAULT_EMBED_ORIGIN,\n lang,\n autoJoin = true,\n hideLeave,\n autoCameraOff,\n autoTranscribe,\n autoRecord,\n background,\n title = 'OE Meeting room',\n width = '100%',\n height = 640,\n className,\n style,\n iframeClassName,\n iframeStyle,\n allow = DEFAULT_IFRAME_ALLOW,\n targetOrigin,\n onReady,\n onJoined,\n onLeft,\n onParticipantJoined,\n onParticipantLeft,\n onEnded,\n onError,\n onStageChanged,\n onTranscriptStarted,\n onRecordingStarted,\n onRecordingSaved,\n onEvent,\n } = props;\n const reactId = useId();\n const instanceId = useMemo(\n () => `oem-${reactId.replace(/:/g, '')}`,\n [reactId],\n );\n const embedOrigin = useMemo(() => getOrigin(origin), [origin]);\n const resolvedTargetOrigin = targetOrigin ?? embedOrigin;\n const hostOrigin =\n typeof window === 'undefined' ? undefined : window.location.origin;\n // Only the mount-time background rides the embed URL. Later prop changes\n // travel as `setBackground` commands (useOeMeeting); rebuilding src would\n // reload the whole meeting mid-session.\n const initialBackgroundRef = useRef(background);\n const src = useMemo(\n () =>\n buildEmbedUrl({\n roomSlug,\n joinToken,\n userName,\n externalUserId,\n origin,\n lang,\n autoJoin,\n hideLeave,\n autoCameraOff,\n autoTranscribe,\n autoRecord,\n background: initialBackgroundRef.current,\n instanceId,\n hostOrigin,\n }),\n [\n autoJoin,\n autoRecord,\n autoTranscribe,\n externalUserId,\n hideLeave,\n hostOrigin,\n instanceId,\n joinToken,\n lang,\n origin,\n roomSlug,\n autoCameraOff,\n userName,\n ],\n );\n const { iframeRef } = useOeMeeting({\n background,\n instanceId,\n targetOrigin: resolvedTargetOrigin,\n handleRef: ref,\n onReady,\n onJoined,\n onLeft,\n onParticipantJoined,\n onParticipantLeft,\n onEnded,\n onError,\n onStageChanged,\n onTranscriptStarted,\n onRecordingStarted,\n onRecordingSaved,\n onEvent,\n });\n const wrapperStyle: CSSProperties = {\n width: toCssSize(width),\n height: toCssSize(height),\n ...style,\n };\n const frameStyle: CSSProperties = {\n width: '100%',\n height: '100%',\n border: 0,\n display: 'block',\n ...iframeStyle,\n };\n\n return (\n <div\n className={className}\n style={wrapperStyle}\n data-oe-meeting-instance={instanceId}\n >\n <iframe\n ref={iframeRef}\n className={iframeClassName}\n style={frameStyle}\n src={src}\n title={title}\n allow={allow}\n allowFullScreen\n referrerPolicy=\"strict-origin-when-cross-origin\"\n />\n </div>\n );\n },\n);\n\nOeMeeting.displayName = 'OeMeeting';\n","export const EMBED_PROTOCOL_VERSION = 1 as const;\nexport const EMBED_MESSAGE_SOURCE = 'oemeeting' as const;\nexport const DEFAULT_EMBED_ORIGIN = 'https://meet.ocean.edu.vn';\n\nexport enum EmbedEventType {\n READY = 'oemeeting:ready',\n JOINED = 'oemeeting:joined',\n LEFT = 'oemeeting:left',\n PARTICIPANT_JOINED = 'oemeeting:participant-joined',\n PARTICIPANT_LEFT = 'oemeeting:participant-left',\n ENDED = 'oemeeting:ended',\n ERROR = 'oemeeting:error',\n STAGE_CHANGED = 'oemeeting:stage-changed',\n TRANSCRIPT_STARTED = 'oemeeting:transcript-started',\n RECORDING_STARTED = 'oemeeting:recording-started',\n RECORDING_SAVED = 'oemeeting:recording-saved',\n}\n\nexport enum EmbedCommandType {\n COMMAND = 'oemeeting:command',\n}\n\nexport enum EmbedCommandAction {\n LEAVE = 'leave',\n TOGGLE_MIC = 'toggleMic',\n TOGGLE_CAMERA = 'toggleCamera',\n OPEN_STAGE = 'openStage',\n CLOSE_STAGE = 'closeStage',\n SET_BACKGROUND = 'setBackground',\n}\n\nexport enum EmbedErrorCode {\n TOKEN_INVALID = 'TOKEN_INVALID',\n TOKEN_EXPIRED = 'TOKEN_EXPIRED',\n ROOM_NOT_FOUND = 'ROOM_NOT_FOUND',\n ROOM_ACCESS_DENIED = 'ROOM_ACCESS_DENIED',\n CONNECTION_FAILED = 'CONNECTION_FAILED',\n PROTOCOL_MISMATCH = 'PROTOCOL_MISMATCH',\n STAGE_ORIGIN_DENIED = 'STAGE_ORIGIN_DENIED',\n STAGE_URL_INVALID = 'STAGE_URL_INVALID',\n TRANSCRIPT_START_FAILED = 'TRANSCRIPT_START_FAILED',\n RECORDING_START_FAILED = 'RECORDING_START_FAILED',\n UNKNOWN = 'UNKNOWN',\n}\n\n/**\n * Host-controlled camera background applied to this embed's local user only.\n * `none` clears any active background effect. The host app enforces who may\n * set it; the meeting does not interpret roles for this value.\n */\nexport enum EmbedBackgroundType {\n BLUR = 'blur',\n IMAGE = 'image',\n NONE = 'none',\n}\n\nexport const MAX_BACKGROUND_URL_LENGTH = 2048;\nexport const DEFAULT_BACKGROUND_BLUR_RADIUS = 10;\nexport const MIN_BACKGROUND_BLUR_RADIUS = 1;\nexport const MAX_BACKGROUND_BLUR_RADIUS = 50;\n\nexport interface EmbedBackground {\n type: EmbedBackgroundType;\n /** BLUR only. Defaults to `DEFAULT_BACKGROUND_BLUR_RADIUS`, clamped 1-50. */\n blurRadius?: number;\n /** IMAGE only. http(s) URL, max `MAX_BACKGROUND_URL_LENGTH`. */\n url?: string;\n /** When true the embed user cannot change blur/virtual backgrounds. */\n locked?: boolean;\n}\n\n/** Open host-owned tool id. Meeting does not catalog values. */\nexport type StageToolId = string;\n\nexport const MAX_STAGE_URL_LENGTH = 2048;\nexport const MAX_STAGE_TOOL_ID_LENGTH = 32;\n\nconst STAGE_TOOL_ID_PATTERN = /^[a-z][a-z0-9._-]{0,31}$/;\n\nexport function isStageToolId(value: unknown): value is StageToolId {\n return (\n typeof value === 'string' &&\n value.length > 0 &&\n value.length <= MAX_STAGE_TOOL_ID_LENGTH &&\n STAGE_TOOL_ID_PATTERN.test(value)\n );\n}\n\nexport enum EmbedQueryParam {\n INSTANCE_ID = 'instanceId',\n HOST_ORIGIN = 'hostOrigin',\n JOIN_TOKEN = 'joinToken',\n USER_NAME = 'userName',\n EXTERNAL_USER_ID = 'externalUserId',\n LANG = 'lang',\n AUTO_JOIN = 'autoJoin',\n HIDE_LEAVE = 'hideLeave',\n AUTO_CAMERA_OFF = 'autoCameraOff',\n AUTO_TRANSCRIBE = 'autoTranscribe',\n AUTO_RECORD = 'autoRecord',\n BACKGROUND = 'background',\n}\n\n/**\n * What happened to the auto-transcribe request the embed made.\n *\n * `ALREADY_RUNNING` is the normal outcome for every participant after the\n * first, because the transcript is a room-level asset rather than a\n * per-participant one. `DISABLED` means the OE Meeting deployment has\n * transcription turned off.\n */\nexport enum EmbedCaptureOutcome {\n STARTED = 'started',\n ALREADY_RUNNING = 'already_running',\n DISABLED = 'disabled',\n FAILED = 'failed',\n}\n\n/**\n * Role the host app assigns when minting a join token.\n * Keep values aligned with `EmbedRole` in the backend embed-permission enum.\n */\nexport enum EmbedRole {\n OWNER = 'owner',\n MEMBER = 'member',\n}\n\n/**\n * Capability the host app may grant per role. Meeting enforces this on the\n * join token, not on a React prop. `screenShare` is the only value today.\n */\nexport enum EmbedCapability {\n SCREEN_SHARE = 'screenShare',\n}\n\nexport interface EmbedPermissionMap {\n owner?: EmbedCapability[];\n member?: EmbedCapability[];\n}\n","import { isStageToolId, MAX_STAGE_URL_LENGTH } from './embed-protocol';\nimport type { OpenStageInput } from './types';\n\nexport function isValidStageUrl(url: string): boolean {\n if (url.length === 0 || url.length > MAX_STAGE_URL_LENGTH) return false;\n try {\n const parsed = new URL(url);\n if (parsed.protocol === 'https:') return true;\n if (parsed.protocol === 'http:') {\n return (\n parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1'\n );\n }\n return false;\n } catch {\n return false;\n }\n}\n\nexport function normalizeOpenStageInput(\n input: OpenStageInput,\n): OpenStageInput | null {\n const url = input.url.trim();\n if (!isValidStageUrl(url)) return null;\n const title = input.title?.trim();\n return {\n url,\n ...(title ? { title: title.slice(0, 200) } : {}),\n ...(isStageToolId(input.tool) ? { tool: input.tool } : {}),\n };\n}\n","import { isValidStageUrl } from './openStage';\nimport {\n DEFAULT_BACKGROUND_BLUR_RADIUS,\n EmbedBackgroundType,\n MAX_BACKGROUND_BLUR_RADIUS,\n MAX_BACKGROUND_URL_LENGTH,\n MIN_BACKGROUND_BLUR_RADIUS,\n type EmbedBackground,\n} from './embed-protocol';\n\n/** Same http(s) policy as the stage URL, including the localhost exception. */\nconst isValidBackgroundUrl = (url: string): boolean =>\n url.length > 0 &&\n url.length <= MAX_BACKGROUND_URL_LENGTH &&\n isValidStageUrl(url);\n\nconst clampBlurRadius = (value: number): number =>\n Number.isFinite(value)\n ? Math.min(MAX_BACKGROUND_BLUR_RADIUS, Math.max(MIN_BACKGROUND_BLUR_RADIUS, Math.round(value)))\n : DEFAULT_BACKGROUND_BLUR_RADIUS;\n\n/**\n * Validate and normalize a host-provided background. Returns null for invalid\n * input so callers can silently drop it, mirroring `normalizeOpenStageInput`.\n */\nexport function normalizeEmbedBackground(\n input: EmbedBackground,\n): EmbedBackground | null {\n const locked = input.locked === true ? { locked: true } : {};\n\n if (input.type === EmbedBackgroundType.NONE) {\n return { type: EmbedBackgroundType.NONE, ...locked };\n }\n\n if (input.type === EmbedBackgroundType.BLUR) {\n return {\n type: EmbedBackgroundType.BLUR,\n blurRadius: clampBlurRadius(input.blurRadius ?? DEFAULT_BACKGROUND_BLUR_RADIUS),\n ...locked,\n };\n }\n\n if (input.type === EmbedBackgroundType.IMAGE) {\n const url = input.url?.trim();\n if (!url || !isValidBackgroundUrl(url)) return null;\n return {\n type: EmbedBackgroundType.IMAGE,\n url,\n ...locked,\n };\n }\n\n return null;\n}\n\n/** JSON wire format shared by the `background` query param and the command payload. */\nexport function serializeEmbedBackground(\n input: EmbedBackground,\n): string | undefined {\n const normalized = normalizeEmbedBackground(input);\n return normalized ? JSON.stringify(normalized) : undefined;\n}\n","import {\n DEFAULT_EMBED_ORIGIN,\n EmbedQueryParam,\n} from './embed-protocol';\nimport { serializeEmbedBackground } from './background';\nimport type { BuildEmbedUrlOptions } from './types';\n\nconst QUERY_FLAG_ENABLED = '1';\nconst QUERY_FLAG_DISABLED = '0';\n\nfunction toFlag(value: boolean | undefined): string | undefined {\n if (value === undefined) return undefined;\n return value ? QUERY_FLAG_ENABLED : QUERY_FLAG_DISABLED;\n}\n\nfunction normalizeOrigin(origin: string): string {\n return origin.replace(/\\/+$/, '');\n}\n\nexport function buildEmbedUrl(options: BuildEmbedUrlOptions): string {\n const roomSlug = options.roomSlug.trim();\n const joinToken = options.joinToken.trim();\n if (!roomSlug) {\n throw new Error('OE Meeting embed requires a non-empty roomSlug.');\n }\n if (!joinToken) {\n throw new Error('OE Meeting embed requires a non-empty joinToken.');\n }\n\n const origin = normalizeOrigin(options.origin ?? DEFAULT_EMBED_ORIGIN);\n const url = new URL(`${origin}/embed/${encodeURIComponent(roomSlug)}`);\n const backgroundParam = options.background\n ? serializeEmbedBackground(options.background)\n : undefined;\n\n const entries: Array<[EmbedQueryParam, string | undefined]> = [\n [EmbedQueryParam.INSTANCE_ID, options.instanceId],\n [EmbedQueryParam.HOST_ORIGIN, options.hostOrigin],\n [EmbedQueryParam.JOIN_TOKEN, joinToken],\n [EmbedQueryParam.USER_NAME, options.userName],\n [EmbedQueryParam.EXTERNAL_USER_ID, options.externalUserId],\n [EmbedQueryParam.LANG, options.lang],\n [EmbedQueryParam.AUTO_JOIN, toFlag(options.autoJoin)],\n [EmbedQueryParam.HIDE_LEAVE, toFlag(options.hideLeave)],\n [EmbedQueryParam.AUTO_CAMERA_OFF, toFlag(options.autoCameraOff)],\n [EmbedQueryParam.AUTO_TRANSCRIBE, toFlag(options.autoTranscribe)],\n [EmbedQueryParam.AUTO_RECORD, toFlag(options.autoRecord)],\n [EmbedQueryParam.BACKGROUND, backgroundParam],\n ];\n\n for (const [key, value] of entries) {\n if (value !== undefined && value !== '') {\n url.searchParams.set(key, value);\n }\n }\n return url.toString();\n}\n","import {\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n type Ref,\n} from 'react';\nimport {\n EMBED_MESSAGE_SOURCE,\n EMBED_PROTOCOL_VERSION,\n EmbedCommandAction,\n EmbedCommandType,\n EmbedEventType,\n} from './embed-protocol';\nimport { normalizeEmbedBackground } from './background';\nimport { normalizeOpenStageInput } from './openStage';\nimport { parseEmbedEvent } from './parseEmbedEvent';\nimport type {\n EmbedCommandMessage,\n OeMeetingHandle,\n OeMeetingProps,\n OpenStageInput,\n} from './types';\nimport type { EmbedBackground } from './embed-protocol';\n\ntype UseOeMeetingOptions = Pick<\n OeMeetingProps,\n | 'onReady'\n | 'onJoined'\n | 'onLeft'\n | 'onParticipantJoined'\n | 'onParticipantLeft'\n | 'onEnded'\n | 'onError'\n | 'onStageChanged'\n | 'onTranscriptStarted'\n | 'onRecordingStarted'\n | 'onRecordingSaved'\n | 'onEvent'\n | 'background'\n> & {\n instanceId: string;\n targetOrigin: string;\n handleRef?: Ref<OeMeetingHandle>;\n};\n\ninterface PostCommandOptions {\n iframe: HTMLIFrameElement | null;\n instanceId: string;\n action: EmbedCommandAction;\n targetOrigin: string;\n payload?: OpenStageInput | EmbedBackground;\n}\n\nfunction postCommand(options: PostCommandOptions): void {\n const frameWindow = options.iframe?.contentWindow;\n if (!frameWindow) return;\n const message: EmbedCommandMessage = {\n source: EMBED_MESSAGE_SOURCE,\n version: EMBED_PROTOCOL_VERSION,\n instanceId: options.instanceId,\n type: EmbedCommandType.COMMAND,\n action: options.action,\n ...(options.payload ? { payload: options.payload } : {}),\n };\n frameWindow.postMessage(message, options.targetOrigin);\n}\n\nexport function useOeMeeting(options: UseOeMeetingOptions) {\n const iframeRef = useRef<HTMLIFrameElement | null>(null);\n const callbacksRef = useRef(options);\n // Last background the host set. Resent on READY: commands posted before the\n // iframe bridge mounts are dropped by the browser.\n const pendingBackgroundRef = useRef<EmbedBackground | null>(null);\n\n useEffect(() => {\n callbacksRef.current = options;\n }, [options]);\n\n useEffect(() => {\n const onMessage = (event: MessageEvent<unknown>) => {\n const frameWindow = iframeRef.current?.contentWindow;\n if (\n !frameWindow ||\n event.source !== frameWindow ||\n event.origin !== options.targetOrigin\n ) {\n return;\n }\n const embedEvent = parseEmbedEvent(event.data);\n if (!embedEvent || embedEvent.instanceId !== options.instanceId) return;\n\n const callbacks = callbacksRef.current;\n callbacks.onEvent?.(embedEvent);\n switch (embedEvent.type) {\n case EmbedEventType.READY:\n callbacks.onReady?.(embedEvent);\n if (pendingBackgroundRef.current) {\n postCommand({\n iframe: iframeRef.current,\n instanceId: options.instanceId,\n action: EmbedCommandAction.SET_BACKGROUND,\n targetOrigin: options.targetOrigin,\n payload: pendingBackgroundRef.current,\n });\n }\n break;\n case EmbedEventType.JOINED:\n callbacks.onJoined?.(embedEvent);\n break;\n case EmbedEventType.LEFT:\n callbacks.onLeft?.(embedEvent);\n break;\n case EmbedEventType.PARTICIPANT_JOINED:\n callbacks.onParticipantJoined?.(embedEvent);\n break;\n case EmbedEventType.PARTICIPANT_LEFT:\n callbacks.onParticipantLeft?.(embedEvent);\n break;\n case EmbedEventType.ENDED:\n callbacks.onEnded?.(embedEvent);\n break;\n case EmbedEventType.ERROR:\n callbacks.onError?.(embedEvent);\n break;\n case EmbedEventType.STAGE_CHANGED:\n callbacks.onStageChanged?.(embedEvent);\n break;\n case EmbedEventType.TRANSCRIPT_STARTED:\n callbacks.onTranscriptStarted?.(embedEvent);\n break;\n case EmbedEventType.RECORDING_STARTED:\n callbacks.onRecordingStarted?.(embedEvent);\n break;\n case EmbedEventType.RECORDING_SAVED:\n callbacks.onRecordingSaved?.(embedEvent);\n break;\n }\n };\n\n window.addEventListener('message', onMessage);\n return () => window.removeEventListener('message', onMessage);\n }, [options.instanceId, options.targetOrigin]);\n\n const send = useCallback(\n (\n action: EmbedCommandAction,\n payload?: OpenStageInput | EmbedBackground\n ) =>\n postCommand({\n iframe: iframeRef.current,\n instanceId: options.instanceId,\n action,\n targetOrigin: options.targetOrigin,\n payload,\n }),\n [options.instanceId, options.targetOrigin],\n );\n const leave = useCallback(() => send(EmbedCommandAction.LEAVE), [send]);\n const toggleMic = useCallback(\n () => send(EmbedCommandAction.TOGGLE_MIC),\n [send],\n );\n const toggleCamera = useCallback(\n () => send(EmbedCommandAction.TOGGLE_CAMERA),\n [send],\n );\n const openStage = useCallback(\n (input: OpenStageInput) => {\n const normalized = normalizeOpenStageInput(input);\n if (!normalized) return;\n send(EmbedCommandAction.OPEN_STAGE, normalized);\n },\n [send],\n );\n const closeStage = useCallback(\n () => send(EmbedCommandAction.CLOSE_STAGE),\n [send],\n );\n\n useEffect(() => {\n if (!options.background) {\n pendingBackgroundRef.current = null;\n return;\n }\n const normalized = normalizeEmbedBackground(options.background);\n if (!normalized) return;\n pendingBackgroundRef.current = normalized;\n send(EmbedCommandAction.SET_BACKGROUND, normalized);\n }, [options.background, send]);\n const getIframe = useCallback(() => iframeRef.current, []);\n const handle = useMemo<OeMeetingHandle>(\n () => ({\n leave,\n toggleMic,\n toggleCamera,\n openStage,\n closeStage,\n getIframe,\n }),\n [closeStage, getIframe, leave, openStage, toggleCamera, toggleMic],\n );\n\n useImperativeHandle(options.handleRef, () => handle, [handle]);\n return { iframeRef, handle };\n}\n","import {\n EMBED_MESSAGE_SOURCE,\n EMBED_PROTOCOL_VERSION,\n EmbedCaptureOutcome,\n EmbedEventType,\n} from './embed-protocol';\nimport type { EmbedEvent } from './types';\n\nconst EVENT_TYPES = new Set<string>(Object.values(EmbedEventType));\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction isOptionalString(value: unknown): boolean {\n return value === undefined || typeof value === 'string';\n}\n\nfunction isNullableString(value: unknown): boolean {\n return value === null || typeof value === 'string';\n}\n\nconst CAPTURE_OUTCOMES = new Set<string>(Object.values(EmbedCaptureOutcome));\n\nfunction isCaptureOutcome(value: unknown): boolean {\n return typeof value === 'string' && CAPTURE_OUTCOMES.has(value);\n}\n\nfunction hasValidPayload(\n type: EmbedEventType,\n payload: Record<string, unknown>,\n): boolean {\n switch (type) {\n case EmbedEventType.READY:\n return typeof payload.roomSlug === 'string';\n case EmbedEventType.JOINED:\n return (\n typeof payload.roomSlug === 'string' &&\n typeof payload.identity === 'string' &&\n isOptionalString(payload.name) &&\n typeof payload.joinedAt === 'string'\n );\n case EmbedEventType.LEFT:\n return (\n typeof payload.roomSlug === 'string' &&\n typeof payload.identity === 'string' &&\n typeof payload.leftAt === 'string' &&\n (payload.durationMs === undefined ||\n typeof payload.durationMs === 'number')\n );\n case EmbedEventType.PARTICIPANT_JOINED:\n return (\n typeof payload.identity === 'string' &&\n isOptionalString(payload.name) &&\n typeof payload.participantCount === 'number'\n );\n case EmbedEventType.PARTICIPANT_LEFT:\n return (\n typeof payload.identity === 'string' &&\n typeof payload.participantCount === 'number'\n );\n case EmbedEventType.ENDED:\n return (\n typeof payload.roomSlug === 'string' &&\n typeof payload.endedAt === 'string'\n );\n case EmbedEventType.ERROR:\n return (\n typeof payload.code === 'string' &&\n typeof payload.message === 'string'\n );\n case EmbedEventType.STAGE_CHANGED:\n return (\n (payload.url === null || typeof payload.url === 'string') &&\n isOptionalString(payload.title) &&\n isOptionalString(payload.tool) &&\n isOptionalString(payload.openedBy)\n );\n case EmbedEventType.TRANSCRIPT_STARTED:\n return (\n typeof payload.roomSlug === 'string' &&\n isCaptureOutcome(payload.outcome) &&\n isNullableString(payload.transcriptId) &&\n isNullableString(payload.status)\n );\n case EmbedEventType.RECORDING_STARTED:\n return (\n typeof payload.roomSlug === 'string' &&\n isCaptureOutcome(payload.outcome) &&\n isNullableString(payload.recordingId) &&\n isNullableString(payload.status)\n );\n case EmbedEventType.RECORDING_SAVED:\n return (\n typeof payload.roomSlug === 'string' &&\n typeof payload.savedAt === 'string'\n );\n }\n}\n\nexport function parseEmbedEvent(data: unknown): EmbedEvent | null {\n if (!isRecord(data)) return null;\n if (\n data.source !== EMBED_MESSAGE_SOURCE ||\n data.version !== EMBED_PROTOCOL_VERSION ||\n typeof data.instanceId !== 'string' ||\n data.instanceId.length === 0 ||\n typeof data.type !== 'string' ||\n !EVENT_TYPES.has(data.type) ||\n !isRecord(data.payload)\n ) {\n return null;\n }\n\n const type = data.type as EmbedEventType;\n if (!hasValidPayload(type, data.payload)) return null;\n return data as unknown as EmbedEvent;\n}\n"],"mappings":";AAEA;AAAA,EACE;AAAA,EACA;AAAA,EACA,WAAAA;AAAA,EACA,UAAAC;AAAA,OAEK;;;ACRA,IAAM,yBAAyB;AAC/B,IAAM,uBAAuB;AAC7B,IAAM,uBAAuB;AAE7B,IAAK,iBAAL,kBAAKC,oBAAL;AACL,EAAAA,gBAAA,WAAQ;AACR,EAAAA,gBAAA,YAAS;AACT,EAAAA,gBAAA,UAAO;AACP,EAAAA,gBAAA,wBAAqB;AACrB,EAAAA,gBAAA,sBAAmB;AACnB,EAAAA,gBAAA,WAAQ;AACR,EAAAA,gBAAA,WAAQ;AACR,EAAAA,gBAAA,mBAAgB;AAChB,EAAAA,gBAAA,wBAAqB;AACrB,EAAAA,gBAAA,uBAAoB;AACpB,EAAAA,gBAAA,qBAAkB;AAXR,SAAAA;AAAA,GAAA;AAcL,IAAK,mBAAL,kBAAKC,sBAAL;AACL,EAAAA,kBAAA,aAAU;AADA,SAAAA;AAAA,GAAA;AAIL,IAAK,qBAAL,kBAAKC,wBAAL;AACL,EAAAA,oBAAA,WAAQ;AACR,EAAAA,oBAAA,gBAAa;AACb,EAAAA,oBAAA,mBAAgB;AAChB,EAAAA,oBAAA,gBAAa;AACb,EAAAA,oBAAA,iBAAc;AACd,EAAAA,oBAAA,oBAAiB;AANP,SAAAA;AAAA,GAAA;AASL,IAAK,iBAAL,kBAAKC,oBAAL;AACL,EAAAA,gBAAA,mBAAgB;AAChB,EAAAA,gBAAA,mBAAgB;AAChB,EAAAA,gBAAA,oBAAiB;AACjB,EAAAA,gBAAA,wBAAqB;AACrB,EAAAA,gBAAA,uBAAoB;AACpB,EAAAA,gBAAA,uBAAoB;AACpB,EAAAA,gBAAA,yBAAsB;AACtB,EAAAA,gBAAA,uBAAoB;AACpB,EAAAA,gBAAA,6BAA0B;AAC1B,EAAAA,gBAAA,4BAAyB;AACzB,EAAAA,gBAAA,aAAU;AAXA,SAAAA;AAAA,GAAA;AAmBL,IAAK,sBAAL,kBAAKC,yBAAL;AACL,EAAAA,qBAAA,UAAO;AACP,EAAAA,qBAAA,WAAQ;AACR,EAAAA,qBAAA,UAAO;AAHG,SAAAA;AAAA,GAAA;AAML,IAAM,4BAA4B;AAClC,IAAM,iCAAiC;AACvC,IAAM,6BAA6B;AACnC,IAAM,6BAA6B;AAenC,IAAM,uBAAuB;AAC7B,IAAM,2BAA2B;AAExC,IAAM,wBAAwB;AAEvB,SAAS,cAAc,OAAsC;AAClE,SACE,OAAO,UAAU,YACjB,MAAM,SAAS,KACf,MAAM,UAAU,4BAChB,sBAAsB,KAAK,KAAK;AAEpC;AAEO,IAAK,kBAAL,kBAAKC,qBAAL;AACL,EAAAA,iBAAA,iBAAc;AACd,EAAAA,iBAAA,iBAAc;AACd,EAAAA,iBAAA,gBAAa;AACb,EAAAA,iBAAA,eAAY;AACZ,EAAAA,iBAAA,sBAAmB;AACnB,EAAAA,iBAAA,UAAO;AACP,EAAAA,iBAAA,eAAY;AACZ,EAAAA,iBAAA,gBAAa;AACb,EAAAA,iBAAA,qBAAkB;AAClB,EAAAA,iBAAA,qBAAkB;AAClB,EAAAA,iBAAA,iBAAc;AACd,EAAAA,iBAAA,gBAAa;AAZH,SAAAA;AAAA,GAAA;AAuBL,IAAK,sBAAL,kBAAKC,yBAAL;AACL,EAAAA,qBAAA,aAAU;AACV,EAAAA,qBAAA,qBAAkB;AAClB,EAAAA,qBAAA,cAAW;AACX,EAAAA,qBAAA,YAAS;AAJC,SAAAA;AAAA,GAAA;AAWL,IAAK,YAAL,kBAAKC,eAAL;AACL,EAAAA,WAAA,WAAQ;AACR,EAAAA,WAAA,YAAS;AAFC,SAAAA;AAAA,GAAA;AASL,IAAK,kBAAL,kBAAKC,qBAAL;AACL,EAAAA,iBAAA,kBAAe;AADL,SAAAA;AAAA,GAAA;;;AChIL,SAAS,gBAAgB,KAAsB;AACpD,MAAI,IAAI,WAAW,KAAK,IAAI,SAAS,qBAAsB,QAAO;AAClE,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,QAAI,OAAO,aAAa,SAAU,QAAO;AACzC,QAAI,OAAO,aAAa,SAAS;AAC/B,aACE,OAAO,aAAa,eAAe,OAAO,aAAa;AAAA,IAE3D;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,wBACd,OACuB;AACvB,QAAM,MAAM,MAAM,IAAI,KAAK;AAC3B,MAAI,CAAC,gBAAgB,GAAG,EAAG,QAAO;AAClC,QAAM,QAAQ,MAAM,OAAO,KAAK;AAChC,SAAO;AAAA,IACL;AAAA,IACA,GAAI,QAAQ,EAAE,OAAO,MAAM,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC;AAAA,IAC9C,GAAI,cAAc,MAAM,IAAI,IAAI,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;AAAA,EAC1D;AACF;;;ACnBA,IAAM,uBAAuB,CAAC,QAC5B,IAAI,SAAS,KACb,IAAI,UAAU,6BACd,gBAAgB,GAAG;AAErB,IAAM,kBAAkB,CAAC,UACvB,OAAO,SAAS,KAAK,IACjB,KAAK,IAAI,4BAA4B,KAAK,IAAI,4BAA4B,KAAK,MAAM,KAAK,CAAC,CAAC,IAC5F;AAMC,SAAS,yBACd,OACwB;AACxB,QAAM,SAAS,MAAM,WAAW,OAAO,EAAE,QAAQ,KAAK,IAAI,CAAC;AAE3D,MAAI,MAAM,4BAAmC;AAC3C,WAAO,EAAE,yBAAgC,GAAG,OAAO;AAAA,EACrD;AAEA,MAAI,MAAM,4BAAmC;AAC3C,WAAO;AAAA,MACL;AAAA,MACA,YAAY,gBAAgB,MAAM,cAAc,8BAA8B;AAAA,MAC9E,GAAG;AAAA,IACL;AAAA,EACF;AAEA,MAAI,MAAM,8BAAoC;AAC5C,UAAM,MAAM,MAAM,KAAK,KAAK;AAC5B,QAAI,CAAC,OAAO,CAAC,qBAAqB,GAAG,EAAG,QAAO;AAC/C,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACL;AAAA,EACF;AAEA,SAAO;AACT;AAGO,SAAS,yBACd,OACoB;AACpB,QAAM,aAAa,yBAAyB,KAAK;AACjD,SAAO,aAAa,KAAK,UAAU,UAAU,IAAI;AACnD;;;ACtDA,IAAM,qBAAqB;AAC3B,IAAM,sBAAsB;AAE5B,SAAS,OAAO,OAAgD;AAC9D,MAAI,UAAU,OAAW,QAAO;AAChC,SAAO,QAAQ,qBAAqB;AACtC;AAEA,SAAS,gBAAgB,QAAwB;AAC/C,SAAO,OAAO,QAAQ,QAAQ,EAAE;AAClC;AAEO,SAAS,cAAc,SAAuC;AACnE,QAAM,WAAW,QAAQ,SAAS,KAAK;AACvC,QAAM,YAAY,QAAQ,UAAU,KAAK;AACzC,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AACA,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AAEA,QAAM,SAAS,gBAAgB,QAAQ,UAAU,oBAAoB;AACrE,QAAM,MAAM,IAAI,IAAI,GAAG,MAAM,UAAU,mBAAmB,QAAQ,CAAC,EAAE;AACrE,QAAM,kBAAkB,QAAQ,aAC5B,yBAAyB,QAAQ,UAAU,IAC3C;AAEJ,QAAM,UAAwD;AAAA,IAC5D,iCAA8B,QAAQ,UAAU;AAAA,IAChD,iCAA8B,QAAQ,UAAU;AAAA,IAChD,+BAA6B,SAAS;AAAA,IACtC,6BAA4B,QAAQ,QAAQ;AAAA,IAC5C,0CAAmC,QAAQ,cAAc;AAAA,IACzD,oBAAuB,QAAQ,IAAI;AAAA,IACnC,6BAA4B,OAAO,QAAQ,QAAQ,CAAC;AAAA,IACpD,+BAA6B,OAAO,QAAQ,SAAS,CAAC;AAAA,IACtD,wCAAkC,OAAO,QAAQ,aAAa,CAAC;AAAA,IAC/D,yCAAkC,OAAO,QAAQ,cAAc,CAAC;AAAA,IAChE,iCAA8B,OAAO,QAAQ,UAAU,CAAC;AAAA,IACxD,gCAA6B,eAAe;AAAA,EAC9C;AAEA,aAAW,CAAC,KAAK,KAAK,KAAK,SAAS;AAClC,QAAI,UAAU,UAAa,UAAU,IAAI;AACvC,UAAI,aAAa,IAAI,KAAK,KAAK;AAAA,IACjC;AAAA,EACF;AACA,SAAO,IAAI,SAAS;AACtB;;;ACxDA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;;;ACCP,IAAM,cAAc,IAAI,IAAY,OAAO,OAAO,cAAc,CAAC;AAEjE,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEA,SAAS,iBAAiB,OAAyB;AACjD,SAAO,UAAU,UAAa,OAAO,UAAU;AACjD;AAEA,SAAS,iBAAiB,OAAyB;AACjD,SAAO,UAAU,QAAQ,OAAO,UAAU;AAC5C;AAEA,IAAM,mBAAmB,IAAI,IAAY,OAAO,OAAO,mBAAmB,CAAC;AAE3E,SAAS,iBAAiB,OAAyB;AACjD,SAAO,OAAO,UAAU,YAAY,iBAAiB,IAAI,KAAK;AAChE;AAEA,SAAS,gBACP,MACA,SACS;AACT,UAAQ,MAAM;AAAA,IACZ;AACE,aAAO,OAAO,QAAQ,aAAa;AAAA,IACrC;AACE,aACE,OAAO,QAAQ,aAAa,YAC5B,OAAO,QAAQ,aAAa,YAC5B,iBAAiB,QAAQ,IAAI,KAC7B,OAAO,QAAQ,aAAa;AAAA,IAEhC;AACE,aACE,OAAO,QAAQ,aAAa,YAC5B,OAAO,QAAQ,aAAa,YAC5B,OAAO,QAAQ,WAAW,aACzB,QAAQ,eAAe,UACtB,OAAO,QAAQ,eAAe;AAAA,IAEpC;AACE,aACE,OAAO,QAAQ,aAAa,YAC5B,iBAAiB,QAAQ,IAAI,KAC7B,OAAO,QAAQ,qBAAqB;AAAA,IAExC;AACE,aACE,OAAO,QAAQ,aAAa,YAC5B,OAAO,QAAQ,qBAAqB;AAAA,IAExC;AACE,aACE,OAAO,QAAQ,aAAa,YAC5B,OAAO,QAAQ,YAAY;AAAA,IAE/B;AACE,aACE,OAAO,QAAQ,SAAS,YACxB,OAAO,QAAQ,YAAY;AAAA,IAE/B;AACE,cACG,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,QAAQ,aAChD,iBAAiB,QAAQ,KAAK,KAC9B,iBAAiB,QAAQ,IAAI,KAC7B,iBAAiB,QAAQ,QAAQ;AAAA,IAErC;AACE,aACE,OAAO,QAAQ,aAAa,YAC5B,iBAAiB,QAAQ,OAAO,KAChC,iBAAiB,QAAQ,YAAY,KACrC,iBAAiB,QAAQ,MAAM;AAAA,IAEnC;AACE,aACE,OAAO,QAAQ,aAAa,YAC5B,iBAAiB,QAAQ,OAAO,KAChC,iBAAiB,QAAQ,WAAW,KACpC,iBAAiB,QAAQ,MAAM;AAAA,IAEnC;AACE,aACE,OAAO,QAAQ,aAAa,YAC5B,OAAO,QAAQ,YAAY;AAAA,EAEjC;AACF;AAEO,SAAS,gBAAgB,MAAkC;AAChE,MAAI,CAAC,SAAS,IAAI,EAAG,QAAO;AAC5B,MACE,KAAK,WAAW,wBAChB,KAAK,YAAY,0BACjB,OAAO,KAAK,eAAe,YAC3B,KAAK,WAAW,WAAW,KAC3B,OAAO,KAAK,SAAS,YACrB,CAAC,YAAY,IAAI,KAAK,IAAI,KAC1B,CAAC,SAAS,KAAK,OAAO,GACtB;AACA,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,KAAK;AAClB,MAAI,CAAC,gBAAgB,MAAM,KAAK,OAAO,EAAG,QAAO;AACjD,SAAO;AACT;;;AD9DA,SAAS,YAAY,SAAmC;AACtD,QAAM,cAAc,QAAQ,QAAQ;AACpC,MAAI,CAAC,YAAa;AAClB,QAAM,UAA+B;AAAA,IACnC,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,YAAY,QAAQ;AAAA,IACpB;AAAA,IACA,QAAQ,QAAQ;AAAA,IAChB,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;AAAA,EACxD;AACA,cAAY,YAAY,SAAS,QAAQ,YAAY;AACvD;AAEO,SAAS,aAAa,SAA8B;AACzD,QAAM,YAAY,OAAiC,IAAI;AACvD,QAAM,eAAe,OAAO,OAAO;AAGnC,QAAM,uBAAuB,OAA+B,IAAI;AAEhE,YAAU,MAAM;AACd,iBAAa,UAAU;AAAA,EACzB,GAAG,CAAC,OAAO,CAAC;AAEZ,YAAU,MAAM;AACd,UAAM,YAAY,CAAC,UAAiC;AAClD,YAAM,cAAc,UAAU,SAAS;AACvC,UACE,CAAC,eACD,MAAM,WAAW,eACjB,MAAM,WAAW,QAAQ,cACzB;AACA;AAAA,MACF;AACA,YAAM,aAAa,gBAAgB,MAAM,IAAI;AAC7C,UAAI,CAAC,cAAc,WAAW,eAAe,QAAQ,WAAY;AAEjE,YAAM,YAAY,aAAa;AAC/B,gBAAU,UAAU,UAAU;AAC9B,cAAQ,WAAW,MAAM;AAAA,QACvB;AACE,oBAAU,UAAU,UAAU;AAC9B,cAAI,qBAAqB,SAAS;AAChC,wBAAY;AAAA,cACV,QAAQ,UAAU;AAAA,cAClB,YAAY,QAAQ;AAAA,cACpB;AAAA,cACA,cAAc,QAAQ;AAAA,cACtB,SAAS,qBAAqB;AAAA,YAChC,CAAC;AAAA,UACH;AACA;AAAA,QACF;AACE,oBAAU,WAAW,UAAU;AAC/B;AAAA,QACF;AACE,oBAAU,SAAS,UAAU;AAC7B;AAAA,QACF;AACE,oBAAU,sBAAsB,UAAU;AAC1C;AAAA,QACF;AACE,oBAAU,oBAAoB,UAAU;AACxC;AAAA,QACF;AACE,oBAAU,UAAU,UAAU;AAC9B;AAAA,QACF;AACE,oBAAU,UAAU,UAAU;AAC9B;AAAA,QACF;AACE,oBAAU,iBAAiB,UAAU;AACrC;AAAA,QACF;AACE,oBAAU,sBAAsB,UAAU;AAC1C;AAAA,QACF;AACE,oBAAU,qBAAqB,UAAU;AACzC;AAAA,QACF;AACE,oBAAU,mBAAmB,UAAU;AACvC;AAAA,MACJ;AAAA,IACF;AAEA,WAAO,iBAAiB,WAAW,SAAS;AAC5C,WAAO,MAAM,OAAO,oBAAoB,WAAW,SAAS;AAAA,EAC9D,GAAG,CAAC,QAAQ,YAAY,QAAQ,YAAY,CAAC;AAE7C,QAAM,OAAO;AAAA,IACX,CACE,QACA,YAEA,YAAY;AAAA,MACV,QAAQ,UAAU;AAAA,MAClB,YAAY,QAAQ;AAAA,MACpB;AAAA,MACA,cAAc,QAAQ;AAAA,MACtB;AAAA,IACF,CAAC;AAAA,IACH,CAAC,QAAQ,YAAY,QAAQ,YAAY;AAAA,EAC3C;AACA,QAAM,QAAQ,YAAY,MAAM,wBAA6B,GAAG,CAAC,IAAI,CAAC;AACtE,QAAM,YAAY;AAAA,IAChB,MAAM,iCAAkC;AAAA,IACxC,CAAC,IAAI;AAAA,EACP;AACA,QAAM,eAAe;AAAA,IACnB,MAAM,uCAAqC;AAAA,IAC3C,CAAC,IAAI;AAAA,EACP;AACA,QAAM,YAAY;AAAA,IAChB,CAAC,UAA0B;AACzB,YAAM,aAAa,wBAAwB,KAAK;AAChD,UAAI,CAAC,WAAY;AACjB,yCAAoC,UAAU;AAAA,IAChD;AAAA,IACA,CAAC,IAAI;AAAA,EACP;AACA,QAAM,aAAa;AAAA,IACjB,MAAM,mCAAmC;AAAA,IACzC,CAAC,IAAI;AAAA,EACP;AAEA,YAAU,MAAM;AACd,QAAI,CAAC,QAAQ,YAAY;AACvB,2BAAqB,UAAU;AAC/B;AAAA,IACF;AACA,UAAM,aAAa,yBAAyB,QAAQ,UAAU;AAC9D,QAAI,CAAC,WAAY;AACjB,yBAAqB,UAAU;AAC/B,+CAAwC,UAAU;AAAA,EACpD,GAAG,CAAC,QAAQ,YAAY,IAAI,CAAC;AAC7B,QAAM,YAAY,YAAY,MAAM,UAAU,SAAS,CAAC,CAAC;AACzD,QAAM,SAAS;AAAA,IACb,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,YAAY,WAAW,OAAO,WAAW,cAAc,SAAS;AAAA,EACnE;AAEA,sBAAoB,QAAQ,WAAW,MAAM,QAAQ,CAAC,MAAM,CAAC;AAC7D,SAAO,EAAE,WAAW,OAAO;AAC7B;;;AL3DQ;AArID,IAAM,uBACX;AAEF,SAAS,UAAU,OAAwD;AACzE,MAAI,UAAU,OAAW,QAAO;AAChC,SAAO,OAAO,UAAU,WAAW,GAAG,KAAK,OAAO;AACpD;AAEA,SAAS,UAAU,OAAuB;AACxC,SAAO,IAAI,IAAI,KAAK,EAAE;AACxB;AAEO,IAAM,YAAY;AAAA,EACvB,SAASC,WAAU,OAAO,KAAK;AAC7B,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,SAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,IAAI;AACJ,UAAM,UAAU,MAAM;AACtB,UAAM,aAAaC;AAAA,MACjB,MAAM,OAAO,QAAQ,QAAQ,MAAM,EAAE,CAAC;AAAA,MACtC,CAAC,OAAO;AAAA,IACV;AACA,UAAM,cAAcA,SAAQ,MAAM,UAAU,MAAM,GAAG,CAAC,MAAM,CAAC;AAC7D,UAAM,uBAAuB,gBAAgB;AAC7C,UAAM,aACJ,OAAO,WAAW,cAAc,SAAY,OAAO,SAAS;AAI9D,UAAM,uBAAuBC,QAAO,UAAU;AAC9C,UAAM,MAAMD;AAAA,MACV,MACE,cAAc;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY,qBAAqB;AAAA,QACjC;AAAA,QACA;AAAA,MACF,CAAC;AAAA,MACH;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,UAAM,EAAE,UAAU,IAAI,aAAa;AAAA,MACjC;AAAA,MACA;AAAA,MACA,cAAc;AAAA,MACd,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AACD,UAAM,eAA8B;AAAA,MAClC,OAAO,UAAU,KAAK;AAAA,MACtB,QAAQ,UAAU,MAAM;AAAA,MACxB,GAAG;AAAA,IACL;AACA,UAAM,aAA4B;AAAA,MAChC,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,GAAG;AAAA,IACL;AAEA,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,OAAO;AAAA,QACP,4BAA0B;AAAA,QAE1B;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,WAAW;AAAA,YACX,OAAO;AAAA,YACP;AAAA,YACA;AAAA,YACA;AAAA,YACA,iBAAe;AAAA,YACf,gBAAe;AAAA;AAAA,QACjB;AAAA;AAAA,IACF;AAAA,EAEJ;AACF;AAEA,UAAU,cAAc;","names":["useMemo","useRef","EmbedEventType","EmbedCommandType","EmbedCommandAction","EmbedErrorCode","EmbedBackgroundType","EmbedQueryParam","EmbedCaptureOutcome","EmbedRole","EmbedCapability","OeMeeting","useMemo","useRef"]}
|
|
@@ -53,7 +53,9 @@ Request:
|
|
|
53
53
|
"name": "Lesson 98765 - 2026-08-17",
|
|
54
54
|
"slug": "oe-school-lesson-98765",
|
|
55
55
|
"access_level": "restricted",
|
|
56
|
-
"configuration": {
|
|
56
|
+
"configuration": {
|
|
57
|
+
"speakerDiarization": true
|
|
58
|
+
}
|
|
57
59
|
}
|
|
58
60
|
```
|
|
59
61
|
|
|
@@ -62,8 +64,7 @@ Request:
|
|
|
62
64
|
| `name` | Có | Tên hiển thị, tối đa 500 ký tự. |
|
|
63
65
|
| `slug` | Không | Khóa ổn định của phòng, tối đa 100 ký tự. Nếu bỏ trống, server sinh từ `name`. |
|
|
64
66
|
| `access_level` | Không | Nên luôn dùng `restricted`; external API mặc định là `restricted`. |
|
|
65
|
-
| `configuration` | Không | Cấu hình mở rộng
|
|
66
|
-
|
|
67
|
+
| `configuration` | Không | Cấu hình mở rộng. `speakerDiarization: true` bảo agent tách người nói. Mặc định tắt. Gửi trên lần tạo phòng, hoặc lần tạo lại cùng slug. |
|
|
67
68
|
Response mẫu:
|
|
68
69
|
|
|
69
70
|
```json
|
|
@@ -211,7 +212,7 @@ Response mẫu:
|
|
|
211
212
|
| Field | Mô tả |
|
|
212
213
|
|---|---|
|
|
213
214
|
| `status` | `active` khi buổi học đang diễn ra, `paused` khi tạm dừng, `completed` sau khi phòng kết thúc. |
|
|
214
|
-
| `segments` | Các câu nói đã chốt, sắp xếp tăng dần theo `spokenAt`. |
|
|
215
|
+
| `segments` | Các câu nói đã chốt, sắp xếp tăng dần theo `spokenAt`. Client chưa bật `speakerDiarization` nhận đúng shape cũ, không có `speakerId`. |
|
|
215
216
|
| `startedBy` | `null` với phiên do embed tự bật (người tham gia là khách của OE.School, không có tài khoản OE Meeting). |
|
|
216
217
|
|
|
217
218
|
Trả `404` khi phòng chưa từng có transcript nào. Transcript là tài sản cấp
|
|
@@ -219,6 +220,38 @@ phòng: nếu OE.School dùng lại một room cho nhiều buổi, endpoint tr
|
|
|
219
220
|
nhất và các segment của phiên đó. Dùng một room cho mỗi buổi học (theo quy ước
|
|
220
221
|
slug ở 2.1) để tránh nhập nhằng.
|
|
221
222
|
|
|
223
|
+
Với phòng đã tạo với `speakerDiarization: true`, mỗi segment có thêm field
|
|
224
|
+
`speakerId` — nhãn giọng nói Soniox gán trong phạm vi một audio track (mic
|
|
225
|
+
chung, tab share). Hai giọng trên một mic sẽ ra `"1"`, `"2"` xen kẽ:
|
|
226
|
+
|
|
227
|
+
```json
|
|
228
|
+
"segments": [
|
|
229
|
+
{
|
|
230
|
+
"id": "0b0f9d54-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
|
|
231
|
+
"participantIdentity": "oe-school:user:12345",
|
|
232
|
+
"participantName": "Nguyen Van A",
|
|
233
|
+
"speakerId": "1",
|
|
234
|
+
"text": "Chào cả lớp, hôm nay chúng ta học bài 3.",
|
|
235
|
+
"language": "vi",
|
|
236
|
+
"spokenAt": "2026-08-17T02:00:45.000Z"
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
"id": "1c2d3e4f-...",
|
|
240
|
+
"participantIdentity": "oe-school:user:12345",
|
|
241
|
+
"participantName": "Nguyen Van A",
|
|
242
|
+
"speakerId": "2",
|
|
243
|
+
"text": "Khoan, cho em hỏi bài 3 ạ.",
|
|
244
|
+
"language": "vi",
|
|
245
|
+
"spokenAt": "2026-08-17T02:00:52.000Z"
|
|
246
|
+
}
|
|
247
|
+
]
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
`speakerId` là nhãn giọng, không phải tên người: mọi segment vẫn mang
|
|
251
|
+
`participantName` của chủ track. Muốn tên thật cho từng giọng phải tự map
|
|
252
|
+
ngoài hệ thống. Nhãn chỉ phân biệt trong phạm vi một track, không phải toàn
|
|
253
|
+
phòng, và không có trên live caption trong lúc họp.
|
|
254
|
+
|
|
222
255
|
Gọi endpoint này sau event `ENDED` (`onEnded` trên React SDK). Agent transcriber
|
|
223
256
|
chốt phiên (`status: "completed"`) khi phòng LiveKit đóng, nên gọi quá sớm sẽ
|
|
224
257
|
nhận được transcript còn `active` và thiếu các câu cuối. Poll tới khi
|
|
@@ -271,6 +304,7 @@ interface TranscriptSegment {
|
|
|
271
304
|
id: string;
|
|
272
305
|
participantIdentity: string | null;
|
|
273
306
|
participantName: string;
|
|
307
|
+
speakerId?: string;
|
|
274
308
|
text: string;
|
|
275
309
|
language: string | null;
|
|
276
310
|
spokenAt: string;
|
|
@@ -130,6 +130,7 @@ này ở production. Khi chạy local, truyền URL frontend OE Meeting local, v
|
|
|
130
130
|
| `autoCameraOff` | `boolean` | `false` | Vào phòng với camera tắt: màn prejoin khởi tạo camera đang tắt và phòng không phát video lúc kết nối. Người dùng vẫn có thể bật lại thủ công. |
|
|
131
131
|
| `autoTranscribe` | `boolean` | `false` | Tự bật transcript dùng chung khi embed kết nối. |
|
|
132
132
|
| `autoRecord` | `boolean` | `false` | Tự ghi toàn bộ phòng khi embed kết nối. |
|
|
133
|
+
| `background` | `EmbedBackground` | — | Áp background camera (blur / ảnh / none) cho user của iframe này, kèm tuỳ chọn khóa lựa chọn nền của người dùng. Dùng để branding sự kiện: host app truyền cùng một giá trị cho mọi người tham gia. Giá trị ban đầu đi theo embed URL; đổi prop sau mount được gửi vào iframe dưới dạng command `setBackground` (buffer đến khi embed ready). Input không hợp lệ bị bỏ qua. |
|
|
133
134
|
| `userName` | `string` | — | Thông tin tùy chọn truyền vào embed URL. |
|
|
134
135
|
| `externalUserId` | `string` | — | External identity tùy chọn. |
|
|
135
136
|
| `lang` | `string` | — | Ngôn ngữ giao diện. |
|
|
@@ -157,6 +158,45 @@ này ở production. Khi chạy local, truyền URL frontend OE Meeting local, v
|
|
|
157
158
|
Không đặt `targetOrigin="*"`. SDK và iframe đều kiểm tra origin, source và
|
|
158
159
|
`instanceId` trước khi xử lý message.
|
|
159
160
|
|
|
161
|
+
### 3.0.1. Background chung cho sự kiện (`background`)
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
import { EmbedBackgroundType } from '@tinyweb_dev/oe-meeting-react'
|
|
165
|
+
|
|
166
|
+
// Ảnh branding cho mọi người tham gia, người dùng không đổi được
|
|
167
|
+
<OeMeeting
|
|
168
|
+
roomSlug="event-room"
|
|
169
|
+
joinToken={token}
|
|
170
|
+
background={{
|
|
171
|
+
type: EmbedBackgroundType.IMAGE,
|
|
172
|
+
url: 'https://cdn.example.com/event-brand.jpg',
|
|
173
|
+
locked: true,
|
|
174
|
+
}}
|
|
175
|
+
/>
|
|
176
|
+
|
|
177
|
+
// Blur nhẹ, người dùng vẫn tự đổi được
|
|
178
|
+
background={{ type: EmbedBackgroundType.BLUR, blurRadius: 5 }}
|
|
179
|
+
|
|
180
|
+
// Bỏ background đang áp (mở khóa nếu đang khóa)
|
|
181
|
+
background={{ type: EmbedBackgroundType.NONE }}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Quy tắc:
|
|
185
|
+
|
|
186
|
+
- `type: 'blur'` | `'image'` | `'none'`. `blurRadius` mặc định 10, clamp 1–50;
|
|
187
|
+
`url` phải là http(s) (http chỉ cho localhost) và ≤ 2048 ký tự.
|
|
188
|
+
- **Ảnh cross-origin tự đi qua proxy của meeting backend** (`GET /api/v1.0/embed/background-image`): host app truyền URL ảnh công khai bất kỳ, **không cần CORS/ACAO** trên host ảnh. Proxy bảo vệ cho production: join token, DNS pin chặn rebinding, redirect validate lại từng hop (tối đa 3), chặn IP private/loopback/link-local (IPv4+IPv6), chỉ `image/*` ≤ 10MB, rate limit theo identity (mặc định 30/phút), cache 10 phút (budget 32MB). Ops: `EMBED_BACKGROUND_PROXY_ENABLED` (kill switch), `EMBED_BACKGROUND_PROXY_ALLOWED_HOSTS` (allowlist hostname, tùy chọn), `EMBED_BACKGROUND_PROXY_RATE_LIMIT`. URL same-origin với meeting tải trực tiếp. URL không tải được bị bỏ qua an toàn (nền không áp, khóa mở, camera vẫn chạy).
|
|
189
|
+
- `locked: true` vô hiệu hóa chọn blur/nền trong panel Effects của người dùng
|
|
190
|
+
(cả prejoin lẫn trong phòng); `false`/không truyền thì chỉ là mặc định ban đầu.
|
|
191
|
+
- Meeting không kiểm tra role: chỉ tác động lên iframe của chính người đó,
|
|
192
|
+
nên host app tự enforce "ai được set" (vd chỉ dashboard của owner).
|
|
193
|
+
- Đồng bộ tới mọi người tham gia là việc host app: hãy render cùng một giá trị
|
|
194
|
+
`background` trên mọi phiên embed và đẩy update qua kênh realtime của bạn
|
|
195
|
+
khi owner đổi giữa buổi. Người vào phòng trực tiếp (không qua embed) không
|
|
196
|
+
nhận được background này.
|
|
197
|
+
- Command `setBackground` gửi trong lúc prejoin (`autoJoin={false}`, chưa bấm
|
|
198
|
+
Join) bị mất — giá trị ban đầu qua URL vẫn đúng.
|
|
199
|
+
|
|
160
200
|
## 3.1. Phân quyền theo role
|
|
161
201
|
|
|
162
202
|
`<OeMeeting>` không có prop quyền. Quyền nằm trong `joinToken`.
|