@tinyweb_dev/oe-meeting-react 0.4.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 +108 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -5
- package/dist/index.d.ts +52 -5
- package/dist/index.js +106 -27
- package/dist/index.js.map +1 -1
- package/docs/BACKEND-INTEGRATION.md +38 -4
- package/docs/REACT-INTEGRATION.md +42 -2
- 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}$/;
|
|
@@ -106,8 +121,10 @@ var EmbedQueryParam = /* @__PURE__ */ ((EmbedQueryParam2) => {
|
|
|
106
121
|
EmbedQueryParam2["LANG"] = "lang";
|
|
107
122
|
EmbedQueryParam2["AUTO_JOIN"] = "autoJoin";
|
|
108
123
|
EmbedQueryParam2["HIDE_LEAVE"] = "hideLeave";
|
|
124
|
+
EmbedQueryParam2["AUTO_CAMERA_OFF"] = "autoCameraOff";
|
|
109
125
|
EmbedQueryParam2["AUTO_TRANSCRIBE"] = "autoTranscribe";
|
|
110
126
|
EmbedQueryParam2["AUTO_RECORD"] = "autoRecord";
|
|
127
|
+
EmbedQueryParam2["BACKGROUND"] = "background";
|
|
111
128
|
return EmbedQueryParam2;
|
|
112
129
|
})(EmbedQueryParam || {});
|
|
113
130
|
var EmbedCaptureOutcome = /* @__PURE__ */ ((EmbedCaptureOutcome2) => {
|
|
@@ -127,6 +144,62 @@ var EmbedCapability = /* @__PURE__ */ ((EmbedCapability2) => {
|
|
|
127
144
|
return EmbedCapability2;
|
|
128
145
|
})(EmbedCapability || {});
|
|
129
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
|
+
|
|
130
203
|
// src/buildEmbedUrl.ts
|
|
131
204
|
var QUERY_FLAG_ENABLED = "1";
|
|
132
205
|
var QUERY_FLAG_DISABLED = "0";
|
|
@@ -148,6 +221,7 @@ function buildEmbedUrl(options) {
|
|
|
148
221
|
}
|
|
149
222
|
const origin = normalizeOrigin(options.origin ?? DEFAULT_EMBED_ORIGIN);
|
|
150
223
|
const url = new URL(`${origin}/embed/${encodeURIComponent(roomSlug)}`);
|
|
224
|
+
const backgroundParam = options.background ? serializeEmbedBackground(options.background) : void 0;
|
|
151
225
|
const entries = [
|
|
152
226
|
["instanceId" /* INSTANCE_ID */, options.instanceId],
|
|
153
227
|
["hostOrigin" /* HOST_ORIGIN */, options.hostOrigin],
|
|
@@ -157,8 +231,10 @@ function buildEmbedUrl(options) {
|
|
|
157
231
|
["lang" /* LANG */, options.lang],
|
|
158
232
|
["autoJoin" /* AUTO_JOIN */, toFlag(options.autoJoin)],
|
|
159
233
|
["hideLeave" /* HIDE_LEAVE */, toFlag(options.hideLeave)],
|
|
234
|
+
["autoCameraOff" /* AUTO_CAMERA_OFF */, toFlag(options.autoCameraOff)],
|
|
160
235
|
["autoTranscribe" /* AUTO_TRANSCRIBE */, toFlag(options.autoTranscribe)],
|
|
161
|
-
["autoRecord" /* AUTO_RECORD */, toFlag(options.autoRecord)]
|
|
236
|
+
["autoRecord" /* AUTO_RECORD */, toFlag(options.autoRecord)],
|
|
237
|
+
["background" /* BACKGROUND */, backgroundParam]
|
|
162
238
|
];
|
|
163
239
|
for (const [key, value] of entries) {
|
|
164
240
|
if (value !== void 0 && value !== "") {
|
|
@@ -171,31 +247,6 @@ function buildEmbedUrl(options) {
|
|
|
171
247
|
// src/useOeMeeting.ts
|
|
172
248
|
var import_react = require("react");
|
|
173
249
|
|
|
174
|
-
// src/openStage.ts
|
|
175
|
-
function isValidStageUrl(url) {
|
|
176
|
-
if (url.length === 0 || url.length > MAX_STAGE_URL_LENGTH) return false;
|
|
177
|
-
try {
|
|
178
|
-
const parsed = new URL(url);
|
|
179
|
-
if (parsed.protocol === "https:") return true;
|
|
180
|
-
if (parsed.protocol === "http:") {
|
|
181
|
-
return parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1";
|
|
182
|
-
}
|
|
183
|
-
return false;
|
|
184
|
-
} catch {
|
|
185
|
-
return false;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
function normalizeOpenStageInput(input) {
|
|
189
|
-
const url = input.url.trim();
|
|
190
|
-
if (!isValidStageUrl(url)) return null;
|
|
191
|
-
const title = input.title?.trim();
|
|
192
|
-
return {
|
|
193
|
-
url,
|
|
194
|
-
...title ? { title: title.slice(0, 200) } : {},
|
|
195
|
-
...isStageToolId(input.tool) ? { tool: input.tool } : {}
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
|
|
199
250
|
// src/parseEmbedEvent.ts
|
|
200
251
|
var EVENT_TYPES = new Set(Object.values(EmbedEventType));
|
|
201
252
|
function isRecord(value) {
|
|
@@ -264,6 +315,7 @@ function postCommand(options) {
|
|
|
264
315
|
function useOeMeeting(options) {
|
|
265
316
|
const iframeRef = (0, import_react.useRef)(null);
|
|
266
317
|
const callbacksRef = (0, import_react.useRef)(options);
|
|
318
|
+
const pendingBackgroundRef = (0, import_react.useRef)(null);
|
|
267
319
|
(0, import_react.useEffect)(() => {
|
|
268
320
|
callbacksRef.current = options;
|
|
269
321
|
}, [options]);
|
|
@@ -280,6 +332,15 @@ function useOeMeeting(options) {
|
|
|
280
332
|
switch (embedEvent.type) {
|
|
281
333
|
case "oemeeting:ready" /* READY */:
|
|
282
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
|
+
}
|
|
283
344
|
break;
|
|
284
345
|
case "oemeeting:joined" /* JOINED */:
|
|
285
346
|
callbacks.onJoined?.(embedEvent);
|
|
@@ -347,6 +408,16 @@ function useOeMeeting(options) {
|
|
|
347
408
|
() => send("closeStage" /* CLOSE_STAGE */),
|
|
348
409
|
[send]
|
|
349
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]);
|
|
350
421
|
const getIframe = (0, import_react.useCallback)(() => iframeRef.current, []);
|
|
351
422
|
const handle = (0, import_react.useMemo)(
|
|
352
423
|
() => ({
|
|
@@ -384,8 +455,10 @@ var OeMeeting = (0, import_react2.forwardRef)(
|
|
|
384
455
|
lang,
|
|
385
456
|
autoJoin = true,
|
|
386
457
|
hideLeave,
|
|
458
|
+
autoCameraOff,
|
|
387
459
|
autoTranscribe,
|
|
388
460
|
autoRecord,
|
|
461
|
+
background,
|
|
389
462
|
title = "OE Meeting room",
|
|
390
463
|
width = "100%",
|
|
391
464
|
height = 640,
|
|
@@ -416,6 +489,7 @@ var OeMeeting = (0, import_react2.forwardRef)(
|
|
|
416
489
|
const embedOrigin = (0, import_react2.useMemo)(() => getOrigin(origin), [origin]);
|
|
417
490
|
const resolvedTargetOrigin = targetOrigin ?? embedOrigin;
|
|
418
491
|
const hostOrigin = typeof window === "undefined" ? void 0 : window.location.origin;
|
|
492
|
+
const initialBackgroundRef = (0, import_react2.useRef)(background);
|
|
419
493
|
const src = (0, import_react2.useMemo)(
|
|
420
494
|
() => buildEmbedUrl({
|
|
421
495
|
roomSlug,
|
|
@@ -426,8 +500,10 @@ var OeMeeting = (0, import_react2.forwardRef)(
|
|
|
426
500
|
lang,
|
|
427
501
|
autoJoin,
|
|
428
502
|
hideLeave,
|
|
503
|
+
autoCameraOff,
|
|
429
504
|
autoTranscribe,
|
|
430
505
|
autoRecord,
|
|
506
|
+
background: initialBackgroundRef.current,
|
|
431
507
|
instanceId,
|
|
432
508
|
hostOrigin
|
|
433
509
|
}),
|
|
@@ -443,10 +519,12 @@ var OeMeeting = (0, import_react2.forwardRef)(
|
|
|
443
519
|
lang,
|
|
444
520
|
origin,
|
|
445
521
|
roomSlug,
|
|
522
|
+
autoCameraOff,
|
|
446
523
|
userName
|
|
447
524
|
]
|
|
448
525
|
);
|
|
449
526
|
const { iframeRef } = useOeMeeting({
|
|
527
|
+
background,
|
|
450
528
|
instanceId,
|
|
451
529
|
targetOrigin: resolvedTargetOrigin,
|
|
452
530
|
handleRef: ref,
|
|
@@ -505,6 +583,7 @@ OeMeeting.displayName = "OeMeeting";
|
|
|
505
583
|
DEFAULT_IFRAME_ALLOW,
|
|
506
584
|
EMBED_MESSAGE_SOURCE,
|
|
507
585
|
EMBED_PROTOCOL_VERSION,
|
|
586
|
+
EmbedBackgroundType,
|
|
508
587
|
EmbedCapability,
|
|
509
588
|
EmbedCaptureOutcome,
|
|
510
589
|
EmbedCommandAction,
|
|
@@ -513,14 +592,17 @@ OeMeeting.displayName = "OeMeeting";
|
|
|
513
592
|
EmbedEventType,
|
|
514
593
|
EmbedQueryParam,
|
|
515
594
|
EmbedRole,
|
|
595
|
+
MAX_BACKGROUND_URL_LENGTH,
|
|
516
596
|
MAX_STAGE_TOOL_ID_LENGTH,
|
|
517
597
|
MAX_STAGE_URL_LENGTH,
|
|
518
598
|
OeMeeting,
|
|
519
599
|
buildEmbedUrl,
|
|
520
600
|
isStageToolId,
|
|
521
601
|
isValidStageUrl,
|
|
602
|
+
normalizeEmbedBackground,
|
|
522
603
|
normalizeOpenStageInput,
|
|
523
604
|
parseEmbedEvent,
|
|
605
|
+
serializeEmbedBackground,
|
|
524
606
|
useOeMeeting
|
|
525
607
|
});
|
|
526
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 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 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 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_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_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;
|
|
@@ -54,8 +75,10 @@ declare enum EmbedQueryParam {
|
|
|
54
75
|
LANG = "lang",
|
|
55
76
|
AUTO_JOIN = "autoJoin",
|
|
56
77
|
HIDE_LEAVE = "hideLeave",
|
|
78
|
+
AUTO_CAMERA_OFF = "autoCameraOff",
|
|
57
79
|
AUTO_TRANSCRIBE = "autoTranscribe",
|
|
58
|
-
AUTO_RECORD = "autoRecord"
|
|
80
|
+
AUTO_RECORD = "autoRecord",
|
|
81
|
+
BACKGROUND = "background"
|
|
59
82
|
}
|
|
60
83
|
/**
|
|
61
84
|
* What happened to the auto-transcribe request the embed made.
|
|
@@ -196,7 +219,7 @@ type EmbedEventOf<T extends EmbedEventType> = Extract<EmbedEvent, {
|
|
|
196
219
|
type EmbedCommandMessage = EmbedMessageBase & {
|
|
197
220
|
type: 'oemeeting:command';
|
|
198
221
|
action: EmbedCommandAction;
|
|
199
|
-
payload?: OpenStageInput;
|
|
222
|
+
payload?: OpenStageInput | EmbedBackground;
|
|
200
223
|
};
|
|
201
224
|
interface OeMeetingHandle {
|
|
202
225
|
leave: () => void;
|
|
@@ -215,6 +238,12 @@ interface OeMeetingProps {
|
|
|
215
238
|
lang?: string;
|
|
216
239
|
autoJoin?: boolean;
|
|
217
240
|
hideLeave?: boolean;
|
|
241
|
+
/**
|
|
242
|
+
* Start with the camera off: the prejoin screen initializes with video
|
|
243
|
+
* disabled and the room does not publish video on connect. The user can
|
|
244
|
+
* still turn the camera on manually.
|
|
245
|
+
*/
|
|
246
|
+
autoCameraOff?: boolean;
|
|
218
247
|
/**
|
|
219
248
|
* Start the shared transcript as soon as the embed connects. The transcript
|
|
220
249
|
* is a room-level asset: the first participant to connect starts it and it
|
|
@@ -224,6 +253,14 @@ interface OeMeetingProps {
|
|
|
224
253
|
autoTranscribe?: boolean;
|
|
225
254
|
/** Start the shared room recording as soon as the embed connects. */
|
|
226
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;
|
|
227
264
|
title?: string;
|
|
228
265
|
width?: number | string;
|
|
229
266
|
height?: number | string;
|
|
@@ -260,8 +297,10 @@ interface BuildEmbedUrlOptions {
|
|
|
260
297
|
lang?: string;
|
|
261
298
|
autoJoin?: boolean;
|
|
262
299
|
hideLeave?: boolean;
|
|
300
|
+
autoCameraOff?: boolean;
|
|
263
301
|
autoTranscribe?: boolean;
|
|
264
302
|
autoRecord?: boolean;
|
|
303
|
+
background?: EmbedBackground;
|
|
265
304
|
instanceId?: string;
|
|
266
305
|
hostOrigin?: string;
|
|
267
306
|
}
|
|
@@ -269,7 +308,7 @@ interface BuildEmbedUrlOptions {
|
|
|
269
308
|
declare const DEFAULT_IFRAME_ALLOW = "camera; microphone; fullscreen; autoplay; display-capture; clipboard-write; encrypted-media";
|
|
270
309
|
declare const OeMeeting: react.ForwardRefExoticComponent<OeMeetingProps & react.RefAttributes<OeMeetingHandle>>;
|
|
271
310
|
|
|
272
|
-
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'> & {
|
|
273
312
|
instanceId: string;
|
|
274
313
|
targetOrigin: string;
|
|
275
314
|
handleRef?: Ref<OeMeetingHandle>;
|
|
@@ -286,4 +325,12 @@ declare function parseEmbedEvent(data: unknown): EmbedEvent | null;
|
|
|
286
325
|
declare function isValidStageUrl(url: string): boolean;
|
|
287
326
|
declare function normalizeOpenStageInput(input: OpenStageInput): OpenStageInput | null;
|
|
288
327
|
|
|
289
|
-
|
|
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;
|
|
@@ -54,8 +75,10 @@ declare enum EmbedQueryParam {
|
|
|
54
75
|
LANG = "lang",
|
|
55
76
|
AUTO_JOIN = "autoJoin",
|
|
56
77
|
HIDE_LEAVE = "hideLeave",
|
|
78
|
+
AUTO_CAMERA_OFF = "autoCameraOff",
|
|
57
79
|
AUTO_TRANSCRIBE = "autoTranscribe",
|
|
58
|
-
AUTO_RECORD = "autoRecord"
|
|
80
|
+
AUTO_RECORD = "autoRecord",
|
|
81
|
+
BACKGROUND = "background"
|
|
59
82
|
}
|
|
60
83
|
/**
|
|
61
84
|
* What happened to the auto-transcribe request the embed made.
|
|
@@ -196,7 +219,7 @@ type EmbedEventOf<T extends EmbedEventType> = Extract<EmbedEvent, {
|
|
|
196
219
|
type EmbedCommandMessage = EmbedMessageBase & {
|
|
197
220
|
type: 'oemeeting:command';
|
|
198
221
|
action: EmbedCommandAction;
|
|
199
|
-
payload?: OpenStageInput;
|
|
222
|
+
payload?: OpenStageInput | EmbedBackground;
|
|
200
223
|
};
|
|
201
224
|
interface OeMeetingHandle {
|
|
202
225
|
leave: () => void;
|
|
@@ -215,6 +238,12 @@ interface OeMeetingProps {
|
|
|
215
238
|
lang?: string;
|
|
216
239
|
autoJoin?: boolean;
|
|
217
240
|
hideLeave?: boolean;
|
|
241
|
+
/**
|
|
242
|
+
* Start with the camera off: the prejoin screen initializes with video
|
|
243
|
+
* disabled and the room does not publish video on connect. The user can
|
|
244
|
+
* still turn the camera on manually.
|
|
245
|
+
*/
|
|
246
|
+
autoCameraOff?: boolean;
|
|
218
247
|
/**
|
|
219
248
|
* Start the shared transcript as soon as the embed connects. The transcript
|
|
220
249
|
* is a room-level asset: the first participant to connect starts it and it
|
|
@@ -224,6 +253,14 @@ interface OeMeetingProps {
|
|
|
224
253
|
autoTranscribe?: boolean;
|
|
225
254
|
/** Start the shared room recording as soon as the embed connects. */
|
|
226
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;
|
|
227
264
|
title?: string;
|
|
228
265
|
width?: number | string;
|
|
229
266
|
height?: number | string;
|
|
@@ -260,8 +297,10 @@ interface BuildEmbedUrlOptions {
|
|
|
260
297
|
lang?: string;
|
|
261
298
|
autoJoin?: boolean;
|
|
262
299
|
hideLeave?: boolean;
|
|
300
|
+
autoCameraOff?: boolean;
|
|
263
301
|
autoTranscribe?: boolean;
|
|
264
302
|
autoRecord?: boolean;
|
|
303
|
+
background?: EmbedBackground;
|
|
265
304
|
instanceId?: string;
|
|
266
305
|
hostOrigin?: string;
|
|
267
306
|
}
|
|
@@ -269,7 +308,7 @@ interface BuildEmbedUrlOptions {
|
|
|
269
308
|
declare const DEFAULT_IFRAME_ALLOW = "camera; microphone; fullscreen; autoplay; display-capture; clipboard-write; encrypted-media";
|
|
270
309
|
declare const OeMeeting: react.ForwardRefExoticComponent<OeMeetingProps & react.RefAttributes<OeMeetingHandle>>;
|
|
271
310
|
|
|
272
|
-
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'> & {
|
|
273
312
|
instanceId: string;
|
|
274
313
|
targetOrigin: string;
|
|
275
314
|
handleRef?: Ref<OeMeetingHandle>;
|
|
@@ -286,4 +325,12 @@ declare function parseEmbedEvent(data: unknown): EmbedEvent | null;
|
|
|
286
325
|
declare function isValidStageUrl(url: string): boolean;
|
|
287
326
|
declare function normalizeOpenStageInput(input: OpenStageInput): OpenStageInput | null;
|
|
288
327
|
|
|
289
|
-
|
|
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}$/;
|
|
@@ -64,8 +76,10 @@ var EmbedQueryParam = /* @__PURE__ */ ((EmbedQueryParam2) => {
|
|
|
64
76
|
EmbedQueryParam2["LANG"] = "lang";
|
|
65
77
|
EmbedQueryParam2["AUTO_JOIN"] = "autoJoin";
|
|
66
78
|
EmbedQueryParam2["HIDE_LEAVE"] = "hideLeave";
|
|
79
|
+
EmbedQueryParam2["AUTO_CAMERA_OFF"] = "autoCameraOff";
|
|
67
80
|
EmbedQueryParam2["AUTO_TRANSCRIBE"] = "autoTranscribe";
|
|
68
81
|
EmbedQueryParam2["AUTO_RECORD"] = "autoRecord";
|
|
82
|
+
EmbedQueryParam2["BACKGROUND"] = "background";
|
|
69
83
|
return EmbedQueryParam2;
|
|
70
84
|
})(EmbedQueryParam || {});
|
|
71
85
|
var EmbedCaptureOutcome = /* @__PURE__ */ ((EmbedCaptureOutcome2) => {
|
|
@@ -85,6 +99,62 @@ var EmbedCapability = /* @__PURE__ */ ((EmbedCapability2) => {
|
|
|
85
99
|
return EmbedCapability2;
|
|
86
100
|
})(EmbedCapability || {});
|
|
87
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
|
+
|
|
88
158
|
// src/buildEmbedUrl.ts
|
|
89
159
|
var QUERY_FLAG_ENABLED = "1";
|
|
90
160
|
var QUERY_FLAG_DISABLED = "0";
|
|
@@ -106,6 +176,7 @@ function buildEmbedUrl(options) {
|
|
|
106
176
|
}
|
|
107
177
|
const origin = normalizeOrigin(options.origin ?? DEFAULT_EMBED_ORIGIN);
|
|
108
178
|
const url = new URL(`${origin}/embed/${encodeURIComponent(roomSlug)}`);
|
|
179
|
+
const backgroundParam = options.background ? serializeEmbedBackground(options.background) : void 0;
|
|
109
180
|
const entries = [
|
|
110
181
|
["instanceId" /* INSTANCE_ID */, options.instanceId],
|
|
111
182
|
["hostOrigin" /* HOST_ORIGIN */, options.hostOrigin],
|
|
@@ -115,8 +186,10 @@ function buildEmbedUrl(options) {
|
|
|
115
186
|
["lang" /* LANG */, options.lang],
|
|
116
187
|
["autoJoin" /* AUTO_JOIN */, toFlag(options.autoJoin)],
|
|
117
188
|
["hideLeave" /* HIDE_LEAVE */, toFlag(options.hideLeave)],
|
|
189
|
+
["autoCameraOff" /* AUTO_CAMERA_OFF */, toFlag(options.autoCameraOff)],
|
|
118
190
|
["autoTranscribe" /* AUTO_TRANSCRIBE */, toFlag(options.autoTranscribe)],
|
|
119
|
-
["autoRecord" /* AUTO_RECORD */, toFlag(options.autoRecord)]
|
|
191
|
+
["autoRecord" /* AUTO_RECORD */, toFlag(options.autoRecord)],
|
|
192
|
+
["background" /* BACKGROUND */, backgroundParam]
|
|
120
193
|
];
|
|
121
194
|
for (const [key, value] of entries) {
|
|
122
195
|
if (value !== void 0 && value !== "") {
|
|
@@ -135,31 +208,6 @@ import {
|
|
|
135
208
|
useRef
|
|
136
209
|
} from "react";
|
|
137
210
|
|
|
138
|
-
// src/openStage.ts
|
|
139
|
-
function isValidStageUrl(url) {
|
|
140
|
-
if (url.length === 0 || url.length > MAX_STAGE_URL_LENGTH) return false;
|
|
141
|
-
try {
|
|
142
|
-
const parsed = new URL(url);
|
|
143
|
-
if (parsed.protocol === "https:") return true;
|
|
144
|
-
if (parsed.protocol === "http:") {
|
|
145
|
-
return parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1";
|
|
146
|
-
}
|
|
147
|
-
return false;
|
|
148
|
-
} catch {
|
|
149
|
-
return false;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
function normalizeOpenStageInput(input) {
|
|
153
|
-
const url = input.url.trim();
|
|
154
|
-
if (!isValidStageUrl(url)) return null;
|
|
155
|
-
const title = input.title?.trim();
|
|
156
|
-
return {
|
|
157
|
-
url,
|
|
158
|
-
...title ? { title: title.slice(0, 200) } : {},
|
|
159
|
-
...isStageToolId(input.tool) ? { tool: input.tool } : {}
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
|
|
163
211
|
// src/parseEmbedEvent.ts
|
|
164
212
|
var EVENT_TYPES = new Set(Object.values(EmbedEventType));
|
|
165
213
|
function isRecord(value) {
|
|
@@ -228,6 +276,7 @@ function postCommand(options) {
|
|
|
228
276
|
function useOeMeeting(options) {
|
|
229
277
|
const iframeRef = useRef(null);
|
|
230
278
|
const callbacksRef = useRef(options);
|
|
279
|
+
const pendingBackgroundRef = useRef(null);
|
|
231
280
|
useEffect(() => {
|
|
232
281
|
callbacksRef.current = options;
|
|
233
282
|
}, [options]);
|
|
@@ -244,6 +293,15 @@ function useOeMeeting(options) {
|
|
|
244
293
|
switch (embedEvent.type) {
|
|
245
294
|
case "oemeeting:ready" /* READY */:
|
|
246
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
|
+
}
|
|
247
305
|
break;
|
|
248
306
|
case "oemeeting:joined" /* JOINED */:
|
|
249
307
|
callbacks.onJoined?.(embedEvent);
|
|
@@ -311,6 +369,16 @@ function useOeMeeting(options) {
|
|
|
311
369
|
() => send("closeStage" /* CLOSE_STAGE */),
|
|
312
370
|
[send]
|
|
313
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]);
|
|
314
382
|
const getIframe = useCallback(() => iframeRef.current, []);
|
|
315
383
|
const handle = useMemo(
|
|
316
384
|
() => ({
|
|
@@ -348,8 +416,10 @@ var OeMeeting = forwardRef(
|
|
|
348
416
|
lang,
|
|
349
417
|
autoJoin = true,
|
|
350
418
|
hideLeave,
|
|
419
|
+
autoCameraOff,
|
|
351
420
|
autoTranscribe,
|
|
352
421
|
autoRecord,
|
|
422
|
+
background,
|
|
353
423
|
title = "OE Meeting room",
|
|
354
424
|
width = "100%",
|
|
355
425
|
height = 640,
|
|
@@ -380,6 +450,7 @@ var OeMeeting = forwardRef(
|
|
|
380
450
|
const embedOrigin = useMemo2(() => getOrigin(origin), [origin]);
|
|
381
451
|
const resolvedTargetOrigin = targetOrigin ?? embedOrigin;
|
|
382
452
|
const hostOrigin = typeof window === "undefined" ? void 0 : window.location.origin;
|
|
453
|
+
const initialBackgroundRef = useRef2(background);
|
|
383
454
|
const src = useMemo2(
|
|
384
455
|
() => buildEmbedUrl({
|
|
385
456
|
roomSlug,
|
|
@@ -390,8 +461,10 @@ var OeMeeting = forwardRef(
|
|
|
390
461
|
lang,
|
|
391
462
|
autoJoin,
|
|
392
463
|
hideLeave,
|
|
464
|
+
autoCameraOff,
|
|
393
465
|
autoTranscribe,
|
|
394
466
|
autoRecord,
|
|
467
|
+
background: initialBackgroundRef.current,
|
|
395
468
|
instanceId,
|
|
396
469
|
hostOrigin
|
|
397
470
|
}),
|
|
@@ -407,10 +480,12 @@ var OeMeeting = forwardRef(
|
|
|
407
480
|
lang,
|
|
408
481
|
origin,
|
|
409
482
|
roomSlug,
|
|
483
|
+
autoCameraOff,
|
|
410
484
|
userName
|
|
411
485
|
]
|
|
412
486
|
);
|
|
413
487
|
const { iframeRef } = useOeMeeting({
|
|
488
|
+
background,
|
|
414
489
|
instanceId,
|
|
415
490
|
targetOrigin: resolvedTargetOrigin,
|
|
416
491
|
handleRef: ref,
|
|
@@ -468,6 +543,7 @@ export {
|
|
|
468
543
|
DEFAULT_IFRAME_ALLOW,
|
|
469
544
|
EMBED_MESSAGE_SOURCE,
|
|
470
545
|
EMBED_PROTOCOL_VERSION,
|
|
546
|
+
EmbedBackgroundType,
|
|
471
547
|
EmbedCapability,
|
|
472
548
|
EmbedCaptureOutcome,
|
|
473
549
|
EmbedCommandAction,
|
|
@@ -476,14 +552,17 @@ export {
|
|
|
476
552
|
EmbedEventType,
|
|
477
553
|
EmbedQueryParam,
|
|
478
554
|
EmbedRole,
|
|
555
|
+
MAX_BACKGROUND_URL_LENGTH,
|
|
479
556
|
MAX_STAGE_TOOL_ID_LENGTH,
|
|
480
557
|
MAX_STAGE_URL_LENGTH,
|
|
481
558
|
OeMeeting,
|
|
482
559
|
buildEmbedUrl,
|
|
483
560
|
isStageToolId,
|
|
484
561
|
isValidStageUrl,
|
|
562
|
+
normalizeEmbedBackground,
|
|
485
563
|
normalizeOpenStageInput,
|
|
486
564
|
parseEmbedEvent,
|
|
565
|
+
serializeEmbedBackground,
|
|
487
566
|
useOeMeeting
|
|
488
567
|
};
|
|
489
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 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 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 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_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_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":"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","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;
|
|
@@ -125,10 +125,12 @@ này ở production. Khi chạy local, truyền URL frontend OE Meeting local, v
|
|
|
125
125
|
| `roomSlug` | `string` | Bắt buộc | Slug phòng do backend trả về. |
|
|
126
126
|
| `joinToken` | `string` | Bắt buộc | Token cấp riêng cho user hiện tại. |
|
|
127
127
|
| `origin` | `string` | `https://meet.ocean.edu.vn` | Origin của OE Meeting. |
|
|
128
|
-
| `autoJoin` | `boolean` | `true` |
|
|
128
|
+
| `autoJoin` | `boolean` | `true` | `false` hiển thị màn preview (prejoin) trong iframe: kiểm tra camera/mic, chọn thiết bị rồi bấm vào mới vào phòng. Khi bật prejoin, `onReady`/`onJoined` chỉ kích hoạt sau khi người dùng vào phòng. |
|
|
129
129
|
| `hideLeave` | `boolean` | `false` | Ẩn nút rời phòng trong iframe. |
|
|
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. |
|
|
130
131
|
| `autoTranscribe` | `boolean` | `false` | Tự bật transcript dùng chung khi embed kết nối. |
|
|
131
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. |
|
|
132
134
|
| `userName` | `string` | — | Thông tin tùy chọn truyền vào embed URL. |
|
|
133
135
|
| `externalUserId` | `string` | — | External identity tùy chọn. |
|
|
134
136
|
| `lang` | `string` | — | Ngôn ngữ giao diện. |
|
|
@@ -156,6 +158,45 @@ này ở production. Khi chạy local, truyền URL frontend OE Meeting local, v
|
|
|
156
158
|
Không đặt `targetOrigin="*"`. SDK và iframe đều kiểm tra origin, source và
|
|
157
159
|
`instanceId` trước khi xử lý message.
|
|
158
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
|
+
|
|
159
200
|
## 3.1. Phân quyền theo role
|
|
160
201
|
|
|
161
202
|
`<OeMeeting>` không có prop quyền. Quyền nằm trong `joinToken`.
|
|
@@ -443,6 +484,5 @@ về đúng origin đó.
|
|
|
443
484
|
quyền trước mỗi lần cấp token.
|
|
444
485
|
- Chưa có API thu hồi token đã cấp hoặc kick participant theo lesson attendance.
|
|
445
486
|
- Protocol v1 chưa có token handshake qua `postMessage`.
|
|
446
|
-
- `autoJoin={false}` chưa có prejoin flow; phiên bản hiện tại yêu cầu auto join.
|
|
447
487
|
- Các lỗi token/access chưa được phân loại riêng; frontend có thể nhận
|
|
448
488
|
`CONNECTION_FAILED` cho các lỗi kết nối liên quan token.
|