@tinyweb_dev/oe-meeting-react 0.1.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/INTEGRATION.md +76 -0
- package/README.md +56 -0
- package/dist/index.cjs +387 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +167 -0
- package/dist/index.d.ts +167 -0
- package/dist/index.js +358 -0
- package/dist/index.js.map +1 -0
- package/docs/BACKEND-INTEGRATION.md +287 -0
- package/docs/REACT-INTEGRATION.md +295 -0
- package/docs/RELEASE.md +116 -0
- package/package.json +66 -0
package/INTEGRATION.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Hướng dẫn tích hợp OE Meeting vào OE.School
|
|
2
|
+
|
|
3
|
+
React SDK cho phép OE.School nhúng toàn bộ phòng học trực tuyến vào trang lesson,
|
|
4
|
+
SSO bằng join token và trao đổi typed events/commands với iframe.
|
|
5
|
+
|
|
6
|
+
## Tài liệu
|
|
7
|
+
|
|
8
|
+
- [Tích hợp backend OE.School](docs/BACKEND-INTEGRATION.md): credentials, external
|
|
9
|
+
API, tạo phòng, cấp token và kiểm tra roster.
|
|
10
|
+
- [Tích hợp React SDK](docs/REACT-INTEGRATION.md): component `OeMeeting`, props,
|
|
11
|
+
events, commands, xử lý lỗi và local development.
|
|
12
|
+
- [README package](README.md): ví dụ sử dụng nhanh và public API.
|
|
13
|
+
- [Release npm](docs/RELEASE.md): cấu hình `NPM_TOKEN`, dry-run và quy trình
|
|
14
|
+
phát hành bằng tag.
|
|
15
|
+
|
|
16
|
+
## Kiến trúc
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
Browser OE.School
|
|
20
|
+
│
|
|
21
|
+
│ GET /api/lessons/:lessonId/meeting-access
|
|
22
|
+
▼
|
|
23
|
+
OE.School backend
|
|
24
|
+
├─ Xác thực session
|
|
25
|
+
├─ Kiểm tra user thuộc roster của lesson
|
|
26
|
+
├─ Loại học sinh nghỉ/không được phép tham gia
|
|
27
|
+
│
|
|
28
|
+
│ Server-to-server: tạo phòng + cấp join token
|
|
29
|
+
▼
|
|
30
|
+
OE Meeting external API
|
|
31
|
+
│
|
|
32
|
+
│ Trả roomSlug + joinToken cho browser
|
|
33
|
+
▼
|
|
34
|
+
<OeMeeting roomSlug={roomSlug} joinToken={joinToken} />
|
|
35
|
+
└─ iframe https://meet.oceanedu.org/embed/:roomSlug
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Access control hai lớp
|
|
39
|
+
|
|
40
|
+
1. **OE.School** là nguồn dữ liệu chính của roster. Backend chỉ cấp token khi
|
|
41
|
+
user được phép tham gia đúng buổi học.
|
|
42
|
+
2. **OE Meeting** tạo phòng với `access_level: "restricted"`, ngăn người dùng
|
|
43
|
+
vào qua link guest. Người dùng phải có join token hợp lệ.
|
|
44
|
+
|
|
45
|
+
Không gọi external API từ browser. `X-Client-Secret` chỉ được lưu tại backend
|
|
46
|
+
OE.School hoặc secret manager.
|
|
47
|
+
|
|
48
|
+
## Luồng tích hợp tối thiểu
|
|
49
|
+
|
|
50
|
+
1. OE Meeting cấp application credentials có scope `rooms:create` và
|
|
51
|
+
`rooms:retrieve` cho backend OE.School.
|
|
52
|
+
2. Giáo viên mở một lesson; backend tạo phòng idempotent theo lesson ID.
|
|
53
|
+
3. User mở trang học; backend xác thực session và kiểm tra roster.
|
|
54
|
+
4. Backend gọi external API để cấp token riêng cho user hiện tại.
|
|
55
|
+
5. Frontend nhận `roomSlug` và `joinToken`, sau đó render `OeMeeting`.
|
|
56
|
+
6. Frontend xử lý events join/leave/error hoặc gửi commands mic/camera/leave.
|
|
57
|
+
|
|
58
|
+
## Production endpoint
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
Meeting origin: https://meet.oceanedu.org
|
|
62
|
+
External API: https://meet.oceanedu.org/external-api/v1.0
|
|
63
|
+
Embed route: https://meet.oceanedu.org/embed/:roomSlug
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Checklist nhanh
|
|
67
|
+
|
|
68
|
+
- [ ] Client secret không xuất hiện trong browser, log hoặc repository.
|
|
69
|
+
- [ ] Phòng lesson dùng access level `restricted`.
|
|
70
|
+
- [ ] Mỗi lần cấp token đều xác thực session và kiểm tra roster.
|
|
71
|
+
- [ ] Học sinh nghỉ/không thuộc lesson nhận HTTP 403 từ OE.School.
|
|
72
|
+
- [ ] API meeting-access dùng `Cache-Control: no-store`.
|
|
73
|
+
- [ ] Frontend có trạng thái loading, forbidden, token expired và connection
|
|
74
|
+
failed.
|
|
75
|
+
- [ ] Không dùng `targetOrigin="*"`.
|
|
76
|
+
- [ ] Không log join token hoặc URL iframe đầy đủ.
|
package/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# `@tinyweb_dev/oe-meeting-react`
|
|
2
|
+
|
|
3
|
+
React SDK để nhúng phòng OE Meeting vào OE.School hoặc hệ thống LMS khác.
|
|
4
|
+
|
|
5
|
+
## Tài liệu tích hợp
|
|
6
|
+
|
|
7
|
+
- [Tổng quan và checklist](INTEGRATION.md)
|
|
8
|
+
- [Backend OE.School: external API, roster và join token](docs/BACKEND-INTEGRATION.md)
|
|
9
|
+
- [Frontend OE.School: React component, events và commands](docs/REACT-INTEGRATION.md)
|
|
10
|
+
- [Quy trình release npm và cấu hình `NPM_TOKEN`](docs/RELEASE.md)
|
|
11
|
+
|
|
12
|
+
## Ví dụ nhanh
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
'use client';
|
|
16
|
+
|
|
17
|
+
import { useRef } from 'react';
|
|
18
|
+
import {
|
|
19
|
+
OeMeeting,
|
|
20
|
+
type OeMeetingHandle,
|
|
21
|
+
} from '@tinyweb_dev/oe-meeting-react';
|
|
22
|
+
|
|
23
|
+
export function OnlineLesson({
|
|
24
|
+
roomSlug,
|
|
25
|
+
joinToken,
|
|
26
|
+
}: {
|
|
27
|
+
roomSlug: string;
|
|
28
|
+
joinToken: string;
|
|
29
|
+
}) {
|
|
30
|
+
const meetingRef = useRef<OeMeetingHandle>(null);
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<OeMeeting
|
|
34
|
+
ref={meetingRef}
|
|
35
|
+
roomSlug={roomSlug}
|
|
36
|
+
joinToken={joinToken}
|
|
37
|
+
height="100vh"
|
|
38
|
+
hideLeave
|
|
39
|
+
onJoined={(event) => console.info('joined', event.payload)}
|
|
40
|
+
onLeft={(event) => console.info('left', event.payload)}
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Bảo mật
|
|
47
|
+
|
|
48
|
+
- `joinToken` phải được backend OE.School lấy server-to-server từ external API.
|
|
49
|
+
- Không đưa `X-Client-Secret` vào browser.
|
|
50
|
+
- Backend OE.School chỉ mint token sau khi kiểm tra user thuộc roster buổi học.
|
|
51
|
+
- Tạo phòng buổi học với access level `restricted`.
|
|
52
|
+
|
|
53
|
+
## Imperative API
|
|
54
|
+
|
|
55
|
+
`OeMeetingHandle` cung cấp `leave()`, `toggleMic()`, `toggleCamera()` và
|
|
56
|
+
`getIframe()`.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
DEFAULT_EMBED_ORIGIN: () => DEFAULT_EMBED_ORIGIN,
|
|
24
|
+
DEFAULT_IFRAME_ALLOW: () => DEFAULT_IFRAME_ALLOW,
|
|
25
|
+
EMBED_MESSAGE_SOURCE: () => EMBED_MESSAGE_SOURCE,
|
|
26
|
+
EMBED_PROTOCOL_VERSION: () => EMBED_PROTOCOL_VERSION,
|
|
27
|
+
EmbedCommandAction: () => EmbedCommandAction,
|
|
28
|
+
EmbedCommandType: () => EmbedCommandType,
|
|
29
|
+
EmbedErrorCode: () => EmbedErrorCode,
|
|
30
|
+
EmbedEventType: () => EmbedEventType,
|
|
31
|
+
EmbedQueryParam: () => EmbedQueryParam,
|
|
32
|
+
OeMeeting: () => OeMeeting,
|
|
33
|
+
buildEmbedUrl: () => buildEmbedUrl,
|
|
34
|
+
parseEmbedEvent: () => parseEmbedEvent,
|
|
35
|
+
useOeMeeting: () => useOeMeeting
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(index_exports);
|
|
38
|
+
|
|
39
|
+
// src/OeMeeting.tsx
|
|
40
|
+
var import_react2 = require("react");
|
|
41
|
+
|
|
42
|
+
// src/embed-protocol.ts
|
|
43
|
+
var EMBED_PROTOCOL_VERSION = 1;
|
|
44
|
+
var EMBED_MESSAGE_SOURCE = "oemeeting";
|
|
45
|
+
var DEFAULT_EMBED_ORIGIN = "https://meet.oceanedu.org";
|
|
46
|
+
var EmbedEventType = /* @__PURE__ */ ((EmbedEventType2) => {
|
|
47
|
+
EmbedEventType2["READY"] = "oemeeting:ready";
|
|
48
|
+
EmbedEventType2["JOINED"] = "oemeeting:joined";
|
|
49
|
+
EmbedEventType2["LEFT"] = "oemeeting:left";
|
|
50
|
+
EmbedEventType2["PARTICIPANT_JOINED"] = "oemeeting:participant-joined";
|
|
51
|
+
EmbedEventType2["PARTICIPANT_LEFT"] = "oemeeting:participant-left";
|
|
52
|
+
EmbedEventType2["ENDED"] = "oemeeting:ended";
|
|
53
|
+
EmbedEventType2["ERROR"] = "oemeeting:error";
|
|
54
|
+
return EmbedEventType2;
|
|
55
|
+
})(EmbedEventType || {});
|
|
56
|
+
var EmbedCommandType = /* @__PURE__ */ ((EmbedCommandType2) => {
|
|
57
|
+
EmbedCommandType2["COMMAND"] = "oemeeting:command";
|
|
58
|
+
return EmbedCommandType2;
|
|
59
|
+
})(EmbedCommandType || {});
|
|
60
|
+
var EmbedCommandAction = /* @__PURE__ */ ((EmbedCommandAction2) => {
|
|
61
|
+
EmbedCommandAction2["LEAVE"] = "leave";
|
|
62
|
+
EmbedCommandAction2["TOGGLE_MIC"] = "toggleMic";
|
|
63
|
+
EmbedCommandAction2["TOGGLE_CAMERA"] = "toggleCamera";
|
|
64
|
+
return EmbedCommandAction2;
|
|
65
|
+
})(EmbedCommandAction || {});
|
|
66
|
+
var EmbedErrorCode = /* @__PURE__ */ ((EmbedErrorCode2) => {
|
|
67
|
+
EmbedErrorCode2["TOKEN_INVALID"] = "TOKEN_INVALID";
|
|
68
|
+
EmbedErrorCode2["TOKEN_EXPIRED"] = "TOKEN_EXPIRED";
|
|
69
|
+
EmbedErrorCode2["ROOM_NOT_FOUND"] = "ROOM_NOT_FOUND";
|
|
70
|
+
EmbedErrorCode2["ROOM_ACCESS_DENIED"] = "ROOM_ACCESS_DENIED";
|
|
71
|
+
EmbedErrorCode2["CONNECTION_FAILED"] = "CONNECTION_FAILED";
|
|
72
|
+
EmbedErrorCode2["PROTOCOL_MISMATCH"] = "PROTOCOL_MISMATCH";
|
|
73
|
+
EmbedErrorCode2["UNKNOWN"] = "UNKNOWN";
|
|
74
|
+
return EmbedErrorCode2;
|
|
75
|
+
})(EmbedErrorCode || {});
|
|
76
|
+
var EmbedQueryParam = /* @__PURE__ */ ((EmbedQueryParam2) => {
|
|
77
|
+
EmbedQueryParam2["INSTANCE_ID"] = "instanceId";
|
|
78
|
+
EmbedQueryParam2["HOST_ORIGIN"] = "hostOrigin";
|
|
79
|
+
EmbedQueryParam2["JOIN_TOKEN"] = "joinToken";
|
|
80
|
+
EmbedQueryParam2["USER_NAME"] = "userName";
|
|
81
|
+
EmbedQueryParam2["EXTERNAL_USER_ID"] = "externalUserId";
|
|
82
|
+
EmbedQueryParam2["LANG"] = "lang";
|
|
83
|
+
EmbedQueryParam2["AUTO_JOIN"] = "autoJoin";
|
|
84
|
+
EmbedQueryParam2["HIDE_LEAVE"] = "hideLeave";
|
|
85
|
+
return EmbedQueryParam2;
|
|
86
|
+
})(EmbedQueryParam || {});
|
|
87
|
+
|
|
88
|
+
// src/buildEmbedUrl.ts
|
|
89
|
+
var QUERY_FLAG_ENABLED = "1";
|
|
90
|
+
var QUERY_FLAG_DISABLED = "0";
|
|
91
|
+
function toFlag(value) {
|
|
92
|
+
if (value === void 0) return void 0;
|
|
93
|
+
return value ? QUERY_FLAG_ENABLED : QUERY_FLAG_DISABLED;
|
|
94
|
+
}
|
|
95
|
+
function normalizeOrigin(origin) {
|
|
96
|
+
return origin.replace(/\/+$/, "");
|
|
97
|
+
}
|
|
98
|
+
function buildEmbedUrl(options) {
|
|
99
|
+
const roomSlug = options.roomSlug.trim();
|
|
100
|
+
const joinToken = options.joinToken.trim();
|
|
101
|
+
if (!roomSlug) {
|
|
102
|
+
throw new Error("OE Meeting embed requires a non-empty roomSlug.");
|
|
103
|
+
}
|
|
104
|
+
if (!joinToken) {
|
|
105
|
+
throw new Error("OE Meeting embed requires a non-empty joinToken.");
|
|
106
|
+
}
|
|
107
|
+
const origin = normalizeOrigin(options.origin ?? DEFAULT_EMBED_ORIGIN);
|
|
108
|
+
const url = new URL(`${origin}/embed/${encodeURIComponent(roomSlug)}`);
|
|
109
|
+
const entries = [
|
|
110
|
+
["instanceId" /* INSTANCE_ID */, options.instanceId],
|
|
111
|
+
["hostOrigin" /* HOST_ORIGIN */, options.hostOrigin],
|
|
112
|
+
["joinToken" /* JOIN_TOKEN */, joinToken],
|
|
113
|
+
["userName" /* USER_NAME */, options.userName],
|
|
114
|
+
["externalUserId" /* EXTERNAL_USER_ID */, options.externalUserId],
|
|
115
|
+
["lang" /* LANG */, options.lang],
|
|
116
|
+
["autoJoin" /* AUTO_JOIN */, toFlag(options.autoJoin)],
|
|
117
|
+
["hideLeave" /* HIDE_LEAVE */, toFlag(options.hideLeave)]
|
|
118
|
+
];
|
|
119
|
+
for (const [key, value] of entries) {
|
|
120
|
+
if (value !== void 0 && value !== "") {
|
|
121
|
+
url.searchParams.set(key, value);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return url.toString();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// src/useOeMeeting.ts
|
|
128
|
+
var import_react = require("react");
|
|
129
|
+
|
|
130
|
+
// src/parseEmbedEvent.ts
|
|
131
|
+
var EVENT_TYPES = new Set(Object.values(EmbedEventType));
|
|
132
|
+
function isRecord(value) {
|
|
133
|
+
return typeof value === "object" && value !== null;
|
|
134
|
+
}
|
|
135
|
+
function isOptionalString(value) {
|
|
136
|
+
return value === void 0 || typeof value === "string";
|
|
137
|
+
}
|
|
138
|
+
function hasValidPayload(type, payload) {
|
|
139
|
+
switch (type) {
|
|
140
|
+
case "oemeeting:ready" /* READY */:
|
|
141
|
+
return typeof payload.roomSlug === "string";
|
|
142
|
+
case "oemeeting:joined" /* JOINED */:
|
|
143
|
+
return typeof payload.roomSlug === "string" && typeof payload.identity === "string" && isOptionalString(payload.name) && typeof payload.joinedAt === "string";
|
|
144
|
+
case "oemeeting:left" /* LEFT */:
|
|
145
|
+
return typeof payload.roomSlug === "string" && typeof payload.identity === "string" && typeof payload.leftAt === "string" && (payload.durationMs === void 0 || typeof payload.durationMs === "number");
|
|
146
|
+
case "oemeeting:participant-joined" /* PARTICIPANT_JOINED */:
|
|
147
|
+
return typeof payload.identity === "string" && isOptionalString(payload.name) && typeof payload.participantCount === "number";
|
|
148
|
+
case "oemeeting:participant-left" /* PARTICIPANT_LEFT */:
|
|
149
|
+
return typeof payload.identity === "string" && typeof payload.participantCount === "number";
|
|
150
|
+
case "oemeeting:ended" /* ENDED */:
|
|
151
|
+
return typeof payload.roomSlug === "string" && typeof payload.endedAt === "string";
|
|
152
|
+
case "oemeeting:error" /* ERROR */:
|
|
153
|
+
return typeof payload.code === "string" && typeof payload.message === "string";
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function parseEmbedEvent(data) {
|
|
157
|
+
if (!isRecord(data)) return null;
|
|
158
|
+
if (data.source !== EMBED_MESSAGE_SOURCE || data.version !== EMBED_PROTOCOL_VERSION || typeof data.instanceId !== "string" || data.instanceId.length === 0 || typeof data.type !== "string" || !EVENT_TYPES.has(data.type) || !isRecord(data.payload)) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
const type = data.type;
|
|
162
|
+
if (!hasValidPayload(type, data.payload)) return null;
|
|
163
|
+
return data;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// src/useOeMeeting.ts
|
|
167
|
+
function postCommand(options) {
|
|
168
|
+
const frameWindow = options.iframe?.contentWindow;
|
|
169
|
+
if (!frameWindow) return;
|
|
170
|
+
const message = {
|
|
171
|
+
source: EMBED_MESSAGE_SOURCE,
|
|
172
|
+
version: EMBED_PROTOCOL_VERSION,
|
|
173
|
+
instanceId: options.instanceId,
|
|
174
|
+
type: "oemeeting:command" /* COMMAND */,
|
|
175
|
+
action: options.action
|
|
176
|
+
};
|
|
177
|
+
frameWindow.postMessage(message, options.targetOrigin);
|
|
178
|
+
}
|
|
179
|
+
function useOeMeeting(options) {
|
|
180
|
+
const iframeRef = (0, import_react.useRef)(null);
|
|
181
|
+
const callbacksRef = (0, import_react.useRef)(options);
|
|
182
|
+
(0, import_react.useEffect)(() => {
|
|
183
|
+
callbacksRef.current = options;
|
|
184
|
+
}, [options]);
|
|
185
|
+
(0, import_react.useEffect)(() => {
|
|
186
|
+
const onMessage = (event) => {
|
|
187
|
+
const frameWindow = iframeRef.current?.contentWindow;
|
|
188
|
+
if (!frameWindow || event.source !== frameWindow || event.origin !== options.targetOrigin) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
const embedEvent = parseEmbedEvent(event.data);
|
|
192
|
+
if (!embedEvent || embedEvent.instanceId !== options.instanceId) return;
|
|
193
|
+
const callbacks = callbacksRef.current;
|
|
194
|
+
callbacks.onEvent?.(embedEvent);
|
|
195
|
+
switch (embedEvent.type) {
|
|
196
|
+
case "oemeeting:ready" /* READY */:
|
|
197
|
+
callbacks.onReady?.(embedEvent);
|
|
198
|
+
break;
|
|
199
|
+
case "oemeeting:joined" /* JOINED */:
|
|
200
|
+
callbacks.onJoined?.(embedEvent);
|
|
201
|
+
break;
|
|
202
|
+
case "oemeeting:left" /* LEFT */:
|
|
203
|
+
callbacks.onLeft?.(embedEvent);
|
|
204
|
+
break;
|
|
205
|
+
case "oemeeting:participant-joined" /* PARTICIPANT_JOINED */:
|
|
206
|
+
callbacks.onParticipantJoined?.(embedEvent);
|
|
207
|
+
break;
|
|
208
|
+
case "oemeeting:participant-left" /* PARTICIPANT_LEFT */:
|
|
209
|
+
callbacks.onParticipantLeft?.(embedEvent);
|
|
210
|
+
break;
|
|
211
|
+
case "oemeeting:ended" /* ENDED */:
|
|
212
|
+
callbacks.onEnded?.(embedEvent);
|
|
213
|
+
break;
|
|
214
|
+
case "oemeeting:error" /* ERROR */:
|
|
215
|
+
callbacks.onError?.(embedEvent);
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
window.addEventListener("message", onMessage);
|
|
220
|
+
return () => window.removeEventListener("message", onMessage);
|
|
221
|
+
}, [options.instanceId, options.targetOrigin]);
|
|
222
|
+
const send = (0, import_react.useCallback)(
|
|
223
|
+
(action) => postCommand({
|
|
224
|
+
iframe: iframeRef.current,
|
|
225
|
+
instanceId: options.instanceId,
|
|
226
|
+
action,
|
|
227
|
+
targetOrigin: options.targetOrigin
|
|
228
|
+
}),
|
|
229
|
+
[options.instanceId, options.targetOrigin]
|
|
230
|
+
);
|
|
231
|
+
const leave = (0, import_react.useCallback)(() => send("leave" /* LEAVE */), [send]);
|
|
232
|
+
const toggleMic = (0, import_react.useCallback)(
|
|
233
|
+
() => send("toggleMic" /* TOGGLE_MIC */),
|
|
234
|
+
[send]
|
|
235
|
+
);
|
|
236
|
+
const toggleCamera = (0, import_react.useCallback)(
|
|
237
|
+
() => send("toggleCamera" /* TOGGLE_CAMERA */),
|
|
238
|
+
[send]
|
|
239
|
+
);
|
|
240
|
+
const getIframe = (0, import_react.useCallback)(() => iframeRef.current, []);
|
|
241
|
+
const handle = (0, import_react.useMemo)(
|
|
242
|
+
() => ({ leave, toggleMic, toggleCamera, getIframe }),
|
|
243
|
+
[getIframe, leave, toggleCamera, toggleMic]
|
|
244
|
+
);
|
|
245
|
+
(0, import_react.useImperativeHandle)(options.handleRef, () => handle, [handle]);
|
|
246
|
+
return { iframeRef, handle };
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// src/OeMeeting.tsx
|
|
250
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
251
|
+
var DEFAULT_IFRAME_ALLOW = "camera; microphone; fullscreen; autoplay; display-capture; clipboard-write; encrypted-media";
|
|
252
|
+
function toCssSize(value) {
|
|
253
|
+
if (value === void 0) return void 0;
|
|
254
|
+
return typeof value === "number" ? `${value}px` : value;
|
|
255
|
+
}
|
|
256
|
+
function getOrigin(value) {
|
|
257
|
+
return new URL(value).origin;
|
|
258
|
+
}
|
|
259
|
+
var OeMeeting = (0, import_react2.forwardRef)(
|
|
260
|
+
function OeMeeting2(props, ref) {
|
|
261
|
+
const {
|
|
262
|
+
roomSlug,
|
|
263
|
+
joinToken,
|
|
264
|
+
userName,
|
|
265
|
+
externalUserId,
|
|
266
|
+
origin = DEFAULT_EMBED_ORIGIN,
|
|
267
|
+
lang,
|
|
268
|
+
autoJoin = true,
|
|
269
|
+
hideLeave,
|
|
270
|
+
title = "OE Meeting room",
|
|
271
|
+
width = "100%",
|
|
272
|
+
height = 640,
|
|
273
|
+
className,
|
|
274
|
+
style,
|
|
275
|
+
iframeClassName,
|
|
276
|
+
iframeStyle,
|
|
277
|
+
allow = DEFAULT_IFRAME_ALLOW,
|
|
278
|
+
targetOrigin,
|
|
279
|
+
onReady,
|
|
280
|
+
onJoined,
|
|
281
|
+
onLeft,
|
|
282
|
+
onParticipantJoined,
|
|
283
|
+
onParticipantLeft,
|
|
284
|
+
onEnded,
|
|
285
|
+
onError,
|
|
286
|
+
onEvent
|
|
287
|
+
} = props;
|
|
288
|
+
const reactId = (0, import_react2.useId)();
|
|
289
|
+
const instanceId = (0, import_react2.useMemo)(
|
|
290
|
+
() => `oem-${reactId.replace(/:/g, "")}`,
|
|
291
|
+
[reactId]
|
|
292
|
+
);
|
|
293
|
+
const embedOrigin = (0, import_react2.useMemo)(() => getOrigin(origin), [origin]);
|
|
294
|
+
const resolvedTargetOrigin = targetOrigin ?? embedOrigin;
|
|
295
|
+
const hostOrigin = typeof window === "undefined" ? void 0 : window.location.origin;
|
|
296
|
+
const src = (0, import_react2.useMemo)(
|
|
297
|
+
() => buildEmbedUrl({
|
|
298
|
+
roomSlug,
|
|
299
|
+
joinToken,
|
|
300
|
+
userName,
|
|
301
|
+
externalUserId,
|
|
302
|
+
origin,
|
|
303
|
+
lang,
|
|
304
|
+
autoJoin,
|
|
305
|
+
hideLeave,
|
|
306
|
+
instanceId,
|
|
307
|
+
hostOrigin
|
|
308
|
+
}),
|
|
309
|
+
[
|
|
310
|
+
autoJoin,
|
|
311
|
+
externalUserId,
|
|
312
|
+
hideLeave,
|
|
313
|
+
hostOrigin,
|
|
314
|
+
instanceId,
|
|
315
|
+
joinToken,
|
|
316
|
+
lang,
|
|
317
|
+
origin,
|
|
318
|
+
roomSlug,
|
|
319
|
+
userName
|
|
320
|
+
]
|
|
321
|
+
);
|
|
322
|
+
const { iframeRef } = useOeMeeting({
|
|
323
|
+
instanceId,
|
|
324
|
+
targetOrigin: resolvedTargetOrigin,
|
|
325
|
+
handleRef: ref,
|
|
326
|
+
onReady,
|
|
327
|
+
onJoined,
|
|
328
|
+
onLeft,
|
|
329
|
+
onParticipantJoined,
|
|
330
|
+
onParticipantLeft,
|
|
331
|
+
onEnded,
|
|
332
|
+
onError,
|
|
333
|
+
onEvent
|
|
334
|
+
});
|
|
335
|
+
const wrapperStyle = {
|
|
336
|
+
width: toCssSize(width),
|
|
337
|
+
height: toCssSize(height),
|
|
338
|
+
...style
|
|
339
|
+
};
|
|
340
|
+
const frameStyle = {
|
|
341
|
+
width: "100%",
|
|
342
|
+
height: "100%",
|
|
343
|
+
border: 0,
|
|
344
|
+
display: "block",
|
|
345
|
+
...iframeStyle
|
|
346
|
+
};
|
|
347
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
348
|
+
"div",
|
|
349
|
+
{
|
|
350
|
+
className,
|
|
351
|
+
style: wrapperStyle,
|
|
352
|
+
"data-oe-meeting-instance": instanceId,
|
|
353
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
354
|
+
"iframe",
|
|
355
|
+
{
|
|
356
|
+
ref: iframeRef,
|
|
357
|
+
className: iframeClassName,
|
|
358
|
+
style: frameStyle,
|
|
359
|
+
src,
|
|
360
|
+
title,
|
|
361
|
+
allow,
|
|
362
|
+
allowFullScreen: true,
|
|
363
|
+
referrerPolicy: "strict-origin-when-cross-origin"
|
|
364
|
+
}
|
|
365
|
+
)
|
|
366
|
+
}
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
);
|
|
370
|
+
OeMeeting.displayName = "OeMeeting";
|
|
371
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
372
|
+
0 && (module.exports = {
|
|
373
|
+
DEFAULT_EMBED_ORIGIN,
|
|
374
|
+
DEFAULT_IFRAME_ALLOW,
|
|
375
|
+
EMBED_MESSAGE_SOURCE,
|
|
376
|
+
EMBED_PROTOCOL_VERSION,
|
|
377
|
+
EmbedCommandAction,
|
|
378
|
+
EmbedCommandType,
|
|
379
|
+
EmbedErrorCode,
|
|
380
|
+
EmbedEventType,
|
|
381
|
+
EmbedQueryParam,
|
|
382
|
+
OeMeeting,
|
|
383
|
+
buildEmbedUrl,
|
|
384
|
+
parseEmbedEvent,
|
|
385
|
+
useOeMeeting
|
|
386
|
+
});
|
|
387
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/OeMeeting.tsx","../src/embed-protocol.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 EmbedCommandAction,\n EmbedCommandType,\n EmbedErrorCode,\n EmbedEventType,\n EmbedQueryParam,\n} from './embed-protocol';\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 OeMeetingHandle,\n OeMeetingProps,\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 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 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 instanceId,\n hostOrigin,\n }),\n [\n autoJoin,\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 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.oceanedu.org';\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}\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}\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 UNKNOWN = 'UNKNOWN',\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}\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 ];\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 { parseEmbedEvent } from './parseEmbedEvent';\nimport type {\n EmbedCommandMessage,\n OeMeetingHandle,\n OeMeetingProps,\n} from './types';\n\ntype UseOeMeetingOptions = Pick<\n OeMeetingProps,\n | 'onReady'\n | 'onJoined'\n | 'onLeft'\n | 'onParticipantJoined'\n | 'onParticipantLeft'\n | 'onEnded'\n | 'onError'\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}\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 };\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 }\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) =>\n postCommand({\n iframe: iframeRef.current,\n instanceId: options.instanceId,\n action,\n targetOrigin: options.targetOrigin,\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 getIframe = useCallback(() => iframeRef.current, []);\n const handle = useMemo<OeMeetingHandle>(\n () => ({ leave, toggleMic, toggleCamera, getIframe }),\n [getIframe, leave, 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 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 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 }\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","OeMeeting"]}
|