@playruo/embed 1.2.2 → 1.2.4
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 +133 -147
- package/dist/index.d.cts +22 -20
- package/dist/index.d.ts +22 -20
- package/dist/index.js +131 -145
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -33,8 +33,8 @@ __export(index_exports, {
|
|
|
33
33
|
EmbedTester: () => EmbedTester,
|
|
34
34
|
PlayruoEmbed: () => PlayruoEmbed,
|
|
35
35
|
buildEmbedUrl: () => buildEmbedUrl,
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
isPlayruoEmbedMessage: () => isPlayruoEmbedMessage,
|
|
37
|
+
isPlayruoInternalMessage: () => isPlayruoInternalMessage
|
|
38
38
|
});
|
|
39
39
|
module.exports = __toCommonJS(index_exports);
|
|
40
40
|
|
|
@@ -76,9 +76,7 @@ var PlayruoEmbed = ({
|
|
|
76
76
|
const [isMobile, setIsMobile] = (0, import_react.useState)(false);
|
|
77
77
|
const [isValidChromium, setIsValidChromium] = (0, import_react.useState)(true);
|
|
78
78
|
const [errorMessage, setErrorMessage] = (0, import_react.useState)(null);
|
|
79
|
-
const
|
|
80
|
-
const escapeKeyPressed = (0, import_react.useRef)(false);
|
|
81
|
-
const ESCAPE_HOLD_DURATION = 1500;
|
|
79
|
+
const [iframeState, setIframeState] = (0, import_react.useState)(null);
|
|
82
80
|
const src = (0, import_react.useMemo)(() => buildEmbedUrl({ baseUrl, operation, storeUrl }), [baseUrl, operation, storeUrl]);
|
|
83
81
|
(0, import_react.useEffect)(() => {
|
|
84
82
|
if (typeof window === "undefined") return;
|
|
@@ -96,81 +94,22 @@ var PlayruoEmbed = ({
|
|
|
96
94
|
}, []);
|
|
97
95
|
const isCompatible = !isMobile && isValidChromium;
|
|
98
96
|
const isReady = isCompatible ? isIframeLoaded : true;
|
|
99
|
-
const currentState = (0, import_react.useMemo)(() =>
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
available: isCompatible,
|
|
103
|
-
status: !isCompatible ? "Browser not compatible" : hasPlayedOnce ? "Click to replay" : "Ready"
|
|
104
|
-
},
|
|
105
|
-
buyNow: {
|
|
106
|
-
available: true,
|
|
107
|
-
status: "Ready"
|
|
108
|
-
}
|
|
109
|
-
}), [hasPlayedOnce, isCompatible]);
|
|
110
|
-
const checkKeyboardLockPermission = (0, import_react.useCallback)(async () => {
|
|
111
|
-
if (!navigator.permissions) {
|
|
112
|
-
console.log("[PlayruoEmbed] Permissions API not supported");
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
try {
|
|
116
|
-
const { state } = await navigator.permissions.query({
|
|
117
|
-
name: "keyboard-lock"
|
|
118
|
-
});
|
|
119
|
-
if (state === "granted" || state === "prompt") {
|
|
120
|
-
console.log(`[PlayruoEmbed] Keyboard lock permission: ${state}`);
|
|
121
|
-
return true;
|
|
122
|
-
}
|
|
123
|
-
console.log("[PlayruoEmbed] Keyboard lock permission denied");
|
|
124
|
-
return false;
|
|
125
|
-
} catch (error) {
|
|
126
|
-
console.warn("[PlayruoEmbed] Error checking keyboard lock permission:", error);
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
}, []);
|
|
130
|
-
const requestFullscreenWithKeyboardLock = (0, import_react.useCallback)(async () => {
|
|
131
|
-
const iframe = iframeRef.current;
|
|
132
|
-
if (!iframe?.requestFullscreen) {
|
|
133
|
-
console.log("[PlayruoEmbed] Fullscreen not supported on this browser");
|
|
134
|
-
return false;
|
|
97
|
+
const currentState = (0, import_react.useMemo)(() => {
|
|
98
|
+
if (iframeState) {
|
|
99
|
+
return iframeState;
|
|
135
100
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
}).catch((err) => {
|
|
147
|
-
const isTopLevelContextError = err?.name === "InvalidStateError" && err?.message?.includes("primary top-level browsing context");
|
|
148
|
-
if (!isTopLevelContextError) {
|
|
149
|
-
console.warn("[PlayruoEmbed] Keyboard lock failed:", err);
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
} catch (err) {
|
|
153
|
-
const isTopLevelContextError = err?.name === "InvalidStateError" && err?.message?.includes("primary top-level browsing context");
|
|
154
|
-
if (!isTopLevelContextError) {
|
|
155
|
-
console.warn("[PlayruoEmbed] Keyboard lock error:", err);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
} else if (!navigator.keyboard) {
|
|
159
|
-
console.log("[PlayruoEmbed] Keyboard API not supported");
|
|
160
|
-
} else {
|
|
161
|
-
console.log("[PlayruoEmbed] Keyboard lock not available (not in top-level context)");
|
|
101
|
+
return {
|
|
102
|
+
hasPlayedOnce,
|
|
103
|
+
tryNow: {
|
|
104
|
+
available: isCompatible,
|
|
105
|
+
status: !isCompatible ? "Browser not compatible" : hasPlayedOnce ? "Click to resume" : "Ready"
|
|
106
|
+
},
|
|
107
|
+
buyNow: {
|
|
108
|
+
available: true,
|
|
109
|
+
status: "Ready"
|
|
162
110
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}).catch((err) => {
|
|
166
|
-
console.warn("[PlayruoEmbed] Fullscreen failed:", err);
|
|
167
|
-
});
|
|
168
|
-
return true;
|
|
169
|
-
} catch (error) {
|
|
170
|
-
console.error("[PlayruoEmbed] Error requesting fullscreen:", error);
|
|
171
|
-
return false;
|
|
172
|
-
}
|
|
173
|
-
}, [iframeRef, checkKeyboardLockPermission]);
|
|
111
|
+
};
|
|
112
|
+
}, [hasPlayedOnce, isCompatible, iframeState]);
|
|
174
113
|
const handleTryNow = (0, import_react.useCallback)(() => {
|
|
175
114
|
if (!isCompatible) {
|
|
176
115
|
console.warn("[PlayruoEmbed] Browser not compatible");
|
|
@@ -190,12 +129,10 @@ var PlayruoEmbed = ({
|
|
|
190
129
|
} catch {
|
|
191
130
|
}
|
|
192
131
|
}
|
|
193
|
-
requestFullscreenWithKeyboardLock();
|
|
194
132
|
iframe.contentWindow?.postMessage({
|
|
195
133
|
type: "playruo",
|
|
196
134
|
action: "tryNowClick",
|
|
197
135
|
fromEmbed: true,
|
|
198
|
-
isFullscreen: true,
|
|
199
136
|
isReplay: hasPlayedOnce
|
|
200
137
|
}, "*");
|
|
201
138
|
console.log("[PlayruoEmbed] Sent tryNowClick to game", hasPlayedOnce ? "(replay)" : "(first time)");
|
|
@@ -209,7 +146,7 @@ var PlayruoEmbed = ({
|
|
|
209
146
|
setErrorMessage("Failed to start game");
|
|
210
147
|
onError?.("Failed to start game");
|
|
211
148
|
}
|
|
212
|
-
}, [isCompatible, hasPlayedOnce, onError, iframeRef
|
|
149
|
+
}, [isCompatible, hasPlayedOnce, onError, iframeRef]);
|
|
213
150
|
const handleBuyNow = (0, import_react.useCallback)(() => {
|
|
214
151
|
if (!storeUrl) {
|
|
215
152
|
console.warn("[PlayruoEmbed] No store URL provided");
|
|
@@ -229,18 +166,112 @@ var PlayruoEmbed = ({
|
|
|
229
166
|
}, [isReady, onReady]);
|
|
230
167
|
(0, import_react.useEffect)(() => {
|
|
231
168
|
const handleGameMessage = (event) => {
|
|
232
|
-
const { type } = event.data || {};
|
|
169
|
+
const { type, data } = event.data || {};
|
|
170
|
+
const iframe = iframeRef.current;
|
|
171
|
+
if (!iframe || event.source !== iframe.contentWindow) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
console.log("\u{1F537} [Embed] Message received from iframe:", { type, data });
|
|
175
|
+
if (type === "playruo_ready") {
|
|
176
|
+
console.log("\u{1F537} [Embed] playruo_ready received");
|
|
177
|
+
onReady?.();
|
|
178
|
+
} else if (type === "playruo_state_update" && data) {
|
|
179
|
+
console.log("\u{1F537} [Embed] playruo_state_update received:", data);
|
|
180
|
+
setIframeState(data);
|
|
181
|
+
if (data.hasPlayedOnce !== void 0) {
|
|
182
|
+
setHasPlayedOnce(data.hasPlayedOnce);
|
|
183
|
+
}
|
|
184
|
+
onStateChange?.(data);
|
|
185
|
+
} else if (type === "playruo_purchase_request" && data?.storeUrl) {
|
|
186
|
+
console.log("\u{1F537} [Embed] playruo_purchase_request received:", data);
|
|
187
|
+
onPurchaseRequest?.(data);
|
|
188
|
+
} else if (type === "playruo_demo_completed" && data) {
|
|
189
|
+
console.log("\u{1F537} [Embed] playruo_demo_completed received:", data);
|
|
190
|
+
setHasPlayedOnce(true);
|
|
191
|
+
onDemoCompleted?.(data);
|
|
192
|
+
} else if (type === "playruo_error") {
|
|
193
|
+
const errorMessage2 = typeof data === "string" ? data : data?.message || "Unknown error";
|
|
194
|
+
console.log("\u{1F537} [Embed] playruo_error received:", errorMessage2);
|
|
195
|
+
setErrorMessage(errorMessage2);
|
|
196
|
+
const errorState = {
|
|
197
|
+
hasPlayedOnce,
|
|
198
|
+
tryNow: {
|
|
199
|
+
available: false,
|
|
200
|
+
status: `Error: ${errorMessage2}`
|
|
201
|
+
},
|
|
202
|
+
buyNow: {
|
|
203
|
+
available: true,
|
|
204
|
+
status: "Ready"
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
setIframeState(errorState);
|
|
208
|
+
onStateChange?.(errorState);
|
|
209
|
+
onError?.(errorMessage2);
|
|
210
|
+
} else if (type === "playruo_session_over" && data) {
|
|
211
|
+
console.log("\u{1F537} [Embed] playruo_session_over received:", data);
|
|
212
|
+
setHasPlayedOnce(true);
|
|
213
|
+
setIframeState(data);
|
|
214
|
+
onStateChange?.(data);
|
|
215
|
+
} else if (type === "playruo_stream_start") {
|
|
216
|
+
console.log("\u{1F537} [Embed] playruo_stream_start received");
|
|
217
|
+
}
|
|
233
218
|
if (type === "error" || type === "closeForBuy" || type === "goToStore") {
|
|
219
|
+
console.log("\u{1F537} [Embed] Legacy message received:", type);
|
|
234
220
|
setHasPlayedOnce(true);
|
|
235
|
-
|
|
221
|
+
const payload = {
|
|
236
222
|
reason: "Demo session ended",
|
|
237
223
|
storeUrl
|
|
238
|
-
}
|
|
224
|
+
};
|
|
225
|
+
onDemoCompleted?.(payload);
|
|
239
226
|
}
|
|
240
227
|
};
|
|
241
228
|
window.addEventListener("message", handleGameMessage);
|
|
242
229
|
return () => window.removeEventListener("message", handleGameMessage);
|
|
243
|
-
}, [storeUrl, onDemoCompleted]);
|
|
230
|
+
}, [storeUrl, onDemoCompleted, onReady, onStateChange, onPurchaseRequest, onError, iframeRef]);
|
|
231
|
+
const generateUUID = () => {
|
|
232
|
+
if (self.crypto.randomUUID) return self.crypto.randomUUID();
|
|
233
|
+
const bytes = new Uint8Array(16);
|
|
234
|
+
self.crypto.getRandomValues(bytes);
|
|
235
|
+
bytes[6] = bytes[6] & 15 | 64;
|
|
236
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
237
|
+
return [...bytes].map(
|
|
238
|
+
(b, i) => ([4, 6, 8, 10].includes(i) ? "-" : "") + b.toString(16).padStart(2, "0")
|
|
239
|
+
).join("");
|
|
240
|
+
};
|
|
241
|
+
(0, import_react.useEffect)(() => {
|
|
242
|
+
const handleUUIDMessage = (event) => {
|
|
243
|
+
const iframe = iframeRef.current;
|
|
244
|
+
if (!iframe || event.source !== iframe.contentWindow) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
const { type, requestId } = event.data || {};
|
|
248
|
+
if (type === "playruo_uuid_request") {
|
|
249
|
+
try {
|
|
250
|
+
let storedUUID = localStorage.getItem("playruo_uuid");
|
|
251
|
+
if (!storedUUID) {
|
|
252
|
+
storedUUID = generateUUID();
|
|
253
|
+
localStorage.setItem("playruo_uuid", storedUUID);
|
|
254
|
+
}
|
|
255
|
+
iframe.contentWindow?.postMessage(
|
|
256
|
+
{
|
|
257
|
+
type: "playruo_uuid_response",
|
|
258
|
+
requestId,
|
|
259
|
+
uuid: storedUUID
|
|
260
|
+
},
|
|
261
|
+
"*"
|
|
262
|
+
);
|
|
263
|
+
} catch (e) {
|
|
264
|
+
}
|
|
265
|
+
} else if (type === "playruo_uuid_remove") {
|
|
266
|
+
try {
|
|
267
|
+
localStorage.removeItem("playruo_uuid");
|
|
268
|
+
} catch (e) {
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
window.addEventListener("message", handleUUIDMessage);
|
|
273
|
+
return () => window.removeEventListener("message", handleUUIDMessage);
|
|
274
|
+
}, [iframeRef]);
|
|
244
275
|
(0, import_react.useEffect)(() => {
|
|
245
276
|
const handleFullscreenChange = () => {
|
|
246
277
|
const doc = document;
|
|
@@ -254,10 +285,17 @@ var PlayruoEmbed = ({
|
|
|
254
285
|
}, 200);
|
|
255
286
|
}
|
|
256
287
|
} else {
|
|
257
|
-
|
|
258
|
-
if (
|
|
259
|
-
|
|
260
|
-
|
|
288
|
+
const iframe = iframeRef.current;
|
|
289
|
+
if (iframe) {
|
|
290
|
+
try {
|
|
291
|
+
iframe.contentWindow?.postMessage({
|
|
292
|
+
type: "playruo",
|
|
293
|
+
action: "exitFullscreen",
|
|
294
|
+
fromEmbed: true
|
|
295
|
+
}, "*");
|
|
296
|
+
} catch {
|
|
297
|
+
console.error("[PlayruoEmbed] Failed to exit fullscreen");
|
|
298
|
+
}
|
|
261
299
|
}
|
|
262
300
|
setShowGameIframe(false);
|
|
263
301
|
setHasPlayedOnce(true);
|
|
@@ -278,56 +316,6 @@ var PlayruoEmbed = ({
|
|
|
278
316
|
document.removeEventListener("MSFullscreenChange", handleFullscreenChange);
|
|
279
317
|
};
|
|
280
318
|
}, [storeUrl, onDemoCompleted, iframeRef]);
|
|
281
|
-
(0, import_react.useEffect)(() => {
|
|
282
|
-
const handleKeyDown = (event) => {
|
|
283
|
-
if (event.key === "Escape" && !escapeKeyPressed.current) {
|
|
284
|
-
escapeKeyPressed.current = true;
|
|
285
|
-
event.preventDefault();
|
|
286
|
-
escapeKeyTimer.current = setTimeout(() => {
|
|
287
|
-
if (document.fullscreenElement) {
|
|
288
|
-
document.exitFullscreen();
|
|
289
|
-
}
|
|
290
|
-
}, ESCAPE_HOLD_DURATION);
|
|
291
|
-
}
|
|
292
|
-
if (event.ctrlKey && event.shiftKey && event.key === "R") {
|
|
293
|
-
event.preventDefault();
|
|
294
|
-
if (document.fullscreenElement) {
|
|
295
|
-
document.exitFullscreen().catch(console.warn);
|
|
296
|
-
}
|
|
297
|
-
setTimeout(() => {
|
|
298
|
-
window.location.reload();
|
|
299
|
-
}, 500);
|
|
300
|
-
}
|
|
301
|
-
};
|
|
302
|
-
const handleKeyUp = (event) => {
|
|
303
|
-
if (event.key === "Escape" && escapeKeyPressed.current) {
|
|
304
|
-
escapeKeyPressed.current = false;
|
|
305
|
-
if (escapeKeyTimer.current) {
|
|
306
|
-
clearTimeout(escapeKeyTimer.current);
|
|
307
|
-
escapeKeyTimer.current = null;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
};
|
|
311
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
312
|
-
document.addEventListener("keyup", handleKeyUp);
|
|
313
|
-
return () => {
|
|
314
|
-
document.removeEventListener("keydown", handleKeyDown);
|
|
315
|
-
document.removeEventListener("keyup", handleKeyUp);
|
|
316
|
-
};
|
|
317
|
-
}, []);
|
|
318
|
-
(0, import_react.useEffect)(() => {
|
|
319
|
-
const isVisible = showGameIframe || showIframe;
|
|
320
|
-
const iframe = iframeRef.current;
|
|
321
|
-
if (!iframe || !isIframeLoaded) return;
|
|
322
|
-
try {
|
|
323
|
-
iframe.contentWindow?.postMessage({
|
|
324
|
-
type: "playruo",
|
|
325
|
-
action: isVisible ? "unmute" : "mute",
|
|
326
|
-
fromEmbed: true
|
|
327
|
-
}, "*");
|
|
328
|
-
} catch {
|
|
329
|
-
}
|
|
330
|
-
}, [showGameIframe, showIframe, isIframeLoaded, iframeRef]);
|
|
331
319
|
(0, import_react.useEffect)(() => {
|
|
332
320
|
const logCrossOriginStatus = () => {
|
|
333
321
|
const isIsolated = self.crossOriginIsolated;
|
|
@@ -436,7 +424,6 @@ var PlayruoEmbed = ({
|
|
|
436
424
|
ref: iframeRef,
|
|
437
425
|
src,
|
|
438
426
|
allow: "cross-origin-isolated; fullscreen *; autoplay *; gamepad *; clipboard-write *; web-share *; encrypted-media *; accelerometer *; gyroscope *",
|
|
439
|
-
allowFullScreen: true,
|
|
440
427
|
className: "w-full h-[70vh] rounded-lg border",
|
|
441
428
|
...{ credentialless: "true" },
|
|
442
429
|
sandbox: "allow-same-origin allow-scripts allow-popups allow-forms allow-presentation allow-top-navigation allow-modals allow-pointer-lock",
|
|
@@ -829,19 +816,18 @@ var isPlayruoEmbedMessage = (data) => {
|
|
|
829
816
|
if (!data || typeof data !== "object") return false;
|
|
830
817
|
const msg = data;
|
|
831
818
|
if (typeof msg.type !== "string") return false;
|
|
832
|
-
return msg.type === "playruo_ready" || msg.type === "playruo_state_update" || msg.type === "playruo_purchase_request" || msg.type === "playruo_demo_completed" || msg.type === "playruo_error";
|
|
819
|
+
return msg.type === "playruo_ready" || msg.type === "playruo_state_update" || msg.type === "playruo_purchase_request" || msg.type === "playruo_demo_completed" || msg.type === "playruo_error" || msg.type === "playruo_session_over" || msg.type === "playruo_stream_start" || msg.type === "playruo_stream_stop";
|
|
833
820
|
};
|
|
834
|
-
var
|
|
821
|
+
var isPlayruoInternalMessage = (data) => {
|
|
835
822
|
if (!data || typeof data !== "object") return false;
|
|
836
|
-
const
|
|
837
|
-
|
|
838
|
-
return cmd.type === "try_now" || cmd.type === "buy_now" || cmd.type === "get_state";
|
|
823
|
+
const msg = data;
|
|
824
|
+
return msg.type === "playruo" && typeof msg.action === "string" && (msg.action === "tryNowClick" || msg.action === "exitFullscreen" || msg.action === "mute" || msg.action === "unmute") && msg.fromEmbed === true;
|
|
839
825
|
};
|
|
840
826
|
// Annotate the CommonJS export names for ESM import in node:
|
|
841
827
|
0 && (module.exports = {
|
|
842
828
|
EmbedTester,
|
|
843
829
|
PlayruoEmbed,
|
|
844
830
|
buildEmbedUrl,
|
|
845
|
-
|
|
846
|
-
|
|
831
|
+
isPlayruoEmbedMessage,
|
|
832
|
+
isPlayruoInternalMessage
|
|
847
833
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -10,6 +10,7 @@ interface PlayruoEmbedState {
|
|
|
10
10
|
buyNow: {
|
|
11
11
|
available: boolean;
|
|
12
12
|
status?: string;
|
|
13
|
+
storeUrl?: string;
|
|
13
14
|
};
|
|
14
15
|
}
|
|
15
16
|
interface DemoCompletedPayload {
|
|
@@ -17,15 +18,6 @@ interface DemoCompletedPayload {
|
|
|
17
18
|
storeUrl?: string;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
interface Keyboard {
|
|
21
|
-
lock: (keys: string[]) => Promise<void>;
|
|
22
|
-
unlock: () => void;
|
|
23
|
-
}
|
|
24
|
-
declare global {
|
|
25
|
-
interface Navigator {
|
|
26
|
-
keyboard?: Keyboard;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
21
|
interface PlayruoEmbedActions {
|
|
30
22
|
/** Start the demo session */
|
|
31
23
|
tryNow: () => void;
|
|
@@ -98,25 +90,35 @@ interface PlayruoErrorMessage {
|
|
|
98
90
|
message: string;
|
|
99
91
|
} | string;
|
|
100
92
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
93
|
+
interface PlayruoSessionOverMessage {
|
|
94
|
+
type: "playruo_session_over";
|
|
95
|
+
data: PlayruoEmbedState;
|
|
96
|
+
}
|
|
97
|
+
interface PlayruoStreamStartMessage {
|
|
98
|
+
type: "playruo_stream_start";
|
|
104
99
|
}
|
|
105
|
-
interface
|
|
106
|
-
type: "
|
|
100
|
+
interface PlayruoStreamStopMessage {
|
|
101
|
+
type: "playruo_stream_stop";
|
|
107
102
|
}
|
|
108
|
-
|
|
109
|
-
|
|
103
|
+
type PlayruoEmbedMessage = PlayruoReadyMessage | PlayruoStateUpdateMessage | PlayruoPurchaseRequestMessage | PlayruoDemoCompletedMessage | PlayruoErrorMessage | PlayruoSessionOverMessage | PlayruoStreamStartMessage | PlayruoStreamStopMessage;
|
|
104
|
+
interface PlayruoInternalMessage {
|
|
105
|
+
type: "playruo";
|
|
106
|
+
action: "tryNowClick" | "exitFullscreen" | "mute" | "unmute";
|
|
107
|
+
fromEmbed: true;
|
|
108
|
+
isReplay?: boolean;
|
|
109
|
+
parentWillHandleFullscreen?: boolean;
|
|
110
110
|
}
|
|
111
|
-
type PlayruoEmbedCommand = TryNowCommand | BuyNowCommand | GetStateCommand;
|
|
112
111
|
/**
|
|
113
112
|
* Type guard to check if a message event is a Playruo embed message
|
|
113
|
+
* Messages FROM Embed → Host via postMessage
|
|
114
114
|
*/
|
|
115
115
|
declare const isPlayruoEmbedMessage: (data: unknown) => data is PlayruoEmbedMessage;
|
|
116
116
|
/**
|
|
117
|
-
* Type guard to check if a
|
|
117
|
+
* Type guard to check if a message is a Playruo internal message
|
|
118
|
+
* Format: { type: 'playruo', action: '...', fromEmbed: true }
|
|
119
|
+
* These are messages sent TO the iframe (game), not to the parent
|
|
118
120
|
*/
|
|
119
|
-
declare const
|
|
121
|
+
declare const isPlayruoInternalMessage: (data: unknown) => data is PlayruoInternalMessage;
|
|
120
122
|
|
|
121
123
|
interface BuildUrlParams {
|
|
122
124
|
baseUrl: string;
|
|
@@ -131,4 +133,4 @@ interface BuildUrlParams {
|
|
|
131
133
|
*/
|
|
132
134
|
declare const buildEmbedUrl: ({ baseUrl, operation, storeUrl }: BuildUrlParams) => string;
|
|
133
135
|
|
|
134
|
-
export { type
|
|
136
|
+
export { type DemoCompletedPayload, EmbedTester, type EmbedTesterProps, type PlayruoDemoCompletedMessage, PlayruoEmbed, type PlayruoEmbedActions, type PlayruoEmbedMessage, type PlayruoEmbedProps, type PlayruoEmbedRenderState, type PlayruoEmbedState, type PlayruoErrorMessage, type PlayruoInternalMessage, type PlayruoPurchaseRequestMessage, type PlayruoReadyMessage, type PlayruoSessionOverMessage, type PlayruoStateUpdateMessage, type PlayruoStreamStartMessage, buildEmbedUrl, isPlayruoEmbedMessage, isPlayruoInternalMessage };
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ interface PlayruoEmbedState {
|
|
|
10
10
|
buyNow: {
|
|
11
11
|
available: boolean;
|
|
12
12
|
status?: string;
|
|
13
|
+
storeUrl?: string;
|
|
13
14
|
};
|
|
14
15
|
}
|
|
15
16
|
interface DemoCompletedPayload {
|
|
@@ -17,15 +18,6 @@ interface DemoCompletedPayload {
|
|
|
17
18
|
storeUrl?: string;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
interface Keyboard {
|
|
21
|
-
lock: (keys: string[]) => Promise<void>;
|
|
22
|
-
unlock: () => void;
|
|
23
|
-
}
|
|
24
|
-
declare global {
|
|
25
|
-
interface Navigator {
|
|
26
|
-
keyboard?: Keyboard;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
21
|
interface PlayruoEmbedActions {
|
|
30
22
|
/** Start the demo session */
|
|
31
23
|
tryNow: () => void;
|
|
@@ -98,25 +90,35 @@ interface PlayruoErrorMessage {
|
|
|
98
90
|
message: string;
|
|
99
91
|
} | string;
|
|
100
92
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
93
|
+
interface PlayruoSessionOverMessage {
|
|
94
|
+
type: "playruo_session_over";
|
|
95
|
+
data: PlayruoEmbedState;
|
|
96
|
+
}
|
|
97
|
+
interface PlayruoStreamStartMessage {
|
|
98
|
+
type: "playruo_stream_start";
|
|
104
99
|
}
|
|
105
|
-
interface
|
|
106
|
-
type: "
|
|
100
|
+
interface PlayruoStreamStopMessage {
|
|
101
|
+
type: "playruo_stream_stop";
|
|
107
102
|
}
|
|
108
|
-
|
|
109
|
-
|
|
103
|
+
type PlayruoEmbedMessage = PlayruoReadyMessage | PlayruoStateUpdateMessage | PlayruoPurchaseRequestMessage | PlayruoDemoCompletedMessage | PlayruoErrorMessage | PlayruoSessionOverMessage | PlayruoStreamStartMessage | PlayruoStreamStopMessage;
|
|
104
|
+
interface PlayruoInternalMessage {
|
|
105
|
+
type: "playruo";
|
|
106
|
+
action: "tryNowClick" | "exitFullscreen" | "mute" | "unmute";
|
|
107
|
+
fromEmbed: true;
|
|
108
|
+
isReplay?: boolean;
|
|
109
|
+
parentWillHandleFullscreen?: boolean;
|
|
110
110
|
}
|
|
111
|
-
type PlayruoEmbedCommand = TryNowCommand | BuyNowCommand | GetStateCommand;
|
|
112
111
|
/**
|
|
113
112
|
* Type guard to check if a message event is a Playruo embed message
|
|
113
|
+
* Messages FROM Embed → Host via postMessage
|
|
114
114
|
*/
|
|
115
115
|
declare const isPlayruoEmbedMessage: (data: unknown) => data is PlayruoEmbedMessage;
|
|
116
116
|
/**
|
|
117
|
-
* Type guard to check if a
|
|
117
|
+
* Type guard to check if a message is a Playruo internal message
|
|
118
|
+
* Format: { type: 'playruo', action: '...', fromEmbed: true }
|
|
119
|
+
* These are messages sent TO the iframe (game), not to the parent
|
|
118
120
|
*/
|
|
119
|
-
declare const
|
|
121
|
+
declare const isPlayruoInternalMessage: (data: unknown) => data is PlayruoInternalMessage;
|
|
120
122
|
|
|
121
123
|
interface BuildUrlParams {
|
|
122
124
|
baseUrl: string;
|
|
@@ -131,4 +133,4 @@ interface BuildUrlParams {
|
|
|
131
133
|
*/
|
|
132
134
|
declare const buildEmbedUrl: ({ baseUrl, operation, storeUrl }: BuildUrlParams) => string;
|
|
133
135
|
|
|
134
|
-
export { type
|
|
136
|
+
export { type DemoCompletedPayload, EmbedTester, type EmbedTesterProps, type PlayruoDemoCompletedMessage, PlayruoEmbed, type PlayruoEmbedActions, type PlayruoEmbedMessage, type PlayruoEmbedProps, type PlayruoEmbedRenderState, type PlayruoEmbedState, type PlayruoErrorMessage, type PlayruoInternalMessage, type PlayruoPurchaseRequestMessage, type PlayruoReadyMessage, type PlayruoSessionOverMessage, type PlayruoStateUpdateMessage, type PlayruoStreamStartMessage, buildEmbedUrl, isPlayruoEmbedMessage, isPlayruoInternalMessage };
|
package/dist/index.js
CHANGED
|
@@ -36,9 +36,7 @@ var PlayruoEmbed = ({
|
|
|
36
36
|
const [isMobile, setIsMobile] = useState(false);
|
|
37
37
|
const [isValidChromium, setIsValidChromium] = useState(true);
|
|
38
38
|
const [errorMessage, setErrorMessage] = useState(null);
|
|
39
|
-
const
|
|
40
|
-
const escapeKeyPressed = useRef(false);
|
|
41
|
-
const ESCAPE_HOLD_DURATION = 1500;
|
|
39
|
+
const [iframeState, setIframeState] = useState(null);
|
|
42
40
|
const src = useMemo(() => buildEmbedUrl({ baseUrl, operation, storeUrl }), [baseUrl, operation, storeUrl]);
|
|
43
41
|
useEffect(() => {
|
|
44
42
|
if (typeof window === "undefined") return;
|
|
@@ -56,81 +54,22 @@ var PlayruoEmbed = ({
|
|
|
56
54
|
}, []);
|
|
57
55
|
const isCompatible = !isMobile && isValidChromium;
|
|
58
56
|
const isReady = isCompatible ? isIframeLoaded : true;
|
|
59
|
-
const currentState = useMemo(() =>
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
available: isCompatible,
|
|
63
|
-
status: !isCompatible ? "Browser not compatible" : hasPlayedOnce ? "Click to replay" : "Ready"
|
|
64
|
-
},
|
|
65
|
-
buyNow: {
|
|
66
|
-
available: true,
|
|
67
|
-
status: "Ready"
|
|
68
|
-
}
|
|
69
|
-
}), [hasPlayedOnce, isCompatible]);
|
|
70
|
-
const checkKeyboardLockPermission = useCallback(async () => {
|
|
71
|
-
if (!navigator.permissions) {
|
|
72
|
-
console.log("[PlayruoEmbed] Permissions API not supported");
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
try {
|
|
76
|
-
const { state } = await navigator.permissions.query({
|
|
77
|
-
name: "keyboard-lock"
|
|
78
|
-
});
|
|
79
|
-
if (state === "granted" || state === "prompt") {
|
|
80
|
-
console.log(`[PlayruoEmbed] Keyboard lock permission: ${state}`);
|
|
81
|
-
return true;
|
|
82
|
-
}
|
|
83
|
-
console.log("[PlayruoEmbed] Keyboard lock permission denied");
|
|
84
|
-
return false;
|
|
85
|
-
} catch (error) {
|
|
86
|
-
console.warn("[PlayruoEmbed] Error checking keyboard lock permission:", error);
|
|
87
|
-
return false;
|
|
88
|
-
}
|
|
89
|
-
}, []);
|
|
90
|
-
const requestFullscreenWithKeyboardLock = useCallback(async () => {
|
|
91
|
-
const iframe = iframeRef.current;
|
|
92
|
-
if (!iframe?.requestFullscreen) {
|
|
93
|
-
console.log("[PlayruoEmbed] Fullscreen not supported on this browser");
|
|
94
|
-
return false;
|
|
57
|
+
const currentState = useMemo(() => {
|
|
58
|
+
if (iframeState) {
|
|
59
|
+
return iframeState;
|
|
95
60
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
}).catch((err) => {
|
|
107
|
-
const isTopLevelContextError = err?.name === "InvalidStateError" && err?.message?.includes("primary top-level browsing context");
|
|
108
|
-
if (!isTopLevelContextError) {
|
|
109
|
-
console.warn("[PlayruoEmbed] Keyboard lock failed:", err);
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
} catch (err) {
|
|
113
|
-
const isTopLevelContextError = err?.name === "InvalidStateError" && err?.message?.includes("primary top-level browsing context");
|
|
114
|
-
if (!isTopLevelContextError) {
|
|
115
|
-
console.warn("[PlayruoEmbed] Keyboard lock error:", err);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
} else if (!navigator.keyboard) {
|
|
119
|
-
console.log("[PlayruoEmbed] Keyboard API not supported");
|
|
120
|
-
} else {
|
|
121
|
-
console.log("[PlayruoEmbed] Keyboard lock not available (not in top-level context)");
|
|
61
|
+
return {
|
|
62
|
+
hasPlayedOnce,
|
|
63
|
+
tryNow: {
|
|
64
|
+
available: isCompatible,
|
|
65
|
+
status: !isCompatible ? "Browser not compatible" : hasPlayedOnce ? "Click to resume" : "Ready"
|
|
66
|
+
},
|
|
67
|
+
buyNow: {
|
|
68
|
+
available: true,
|
|
69
|
+
status: "Ready"
|
|
122
70
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}).catch((err) => {
|
|
126
|
-
console.warn("[PlayruoEmbed] Fullscreen failed:", err);
|
|
127
|
-
});
|
|
128
|
-
return true;
|
|
129
|
-
} catch (error) {
|
|
130
|
-
console.error("[PlayruoEmbed] Error requesting fullscreen:", error);
|
|
131
|
-
return false;
|
|
132
|
-
}
|
|
133
|
-
}, [iframeRef, checkKeyboardLockPermission]);
|
|
71
|
+
};
|
|
72
|
+
}, [hasPlayedOnce, isCompatible, iframeState]);
|
|
134
73
|
const handleTryNow = useCallback(() => {
|
|
135
74
|
if (!isCompatible) {
|
|
136
75
|
console.warn("[PlayruoEmbed] Browser not compatible");
|
|
@@ -150,12 +89,10 @@ var PlayruoEmbed = ({
|
|
|
150
89
|
} catch {
|
|
151
90
|
}
|
|
152
91
|
}
|
|
153
|
-
requestFullscreenWithKeyboardLock();
|
|
154
92
|
iframe.contentWindow?.postMessage({
|
|
155
93
|
type: "playruo",
|
|
156
94
|
action: "tryNowClick",
|
|
157
95
|
fromEmbed: true,
|
|
158
|
-
isFullscreen: true,
|
|
159
96
|
isReplay: hasPlayedOnce
|
|
160
97
|
}, "*");
|
|
161
98
|
console.log("[PlayruoEmbed] Sent tryNowClick to game", hasPlayedOnce ? "(replay)" : "(first time)");
|
|
@@ -169,7 +106,7 @@ var PlayruoEmbed = ({
|
|
|
169
106
|
setErrorMessage("Failed to start game");
|
|
170
107
|
onError?.("Failed to start game");
|
|
171
108
|
}
|
|
172
|
-
}, [isCompatible, hasPlayedOnce, onError, iframeRef
|
|
109
|
+
}, [isCompatible, hasPlayedOnce, onError, iframeRef]);
|
|
173
110
|
const handleBuyNow = useCallback(() => {
|
|
174
111
|
if (!storeUrl) {
|
|
175
112
|
console.warn("[PlayruoEmbed] No store URL provided");
|
|
@@ -189,18 +126,112 @@ var PlayruoEmbed = ({
|
|
|
189
126
|
}, [isReady, onReady]);
|
|
190
127
|
useEffect(() => {
|
|
191
128
|
const handleGameMessage = (event) => {
|
|
192
|
-
const { type } = event.data || {};
|
|
129
|
+
const { type, data } = event.data || {};
|
|
130
|
+
const iframe = iframeRef.current;
|
|
131
|
+
if (!iframe || event.source !== iframe.contentWindow) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
console.log("\u{1F537} [Embed] Message received from iframe:", { type, data });
|
|
135
|
+
if (type === "playruo_ready") {
|
|
136
|
+
console.log("\u{1F537} [Embed] playruo_ready received");
|
|
137
|
+
onReady?.();
|
|
138
|
+
} else if (type === "playruo_state_update" && data) {
|
|
139
|
+
console.log("\u{1F537} [Embed] playruo_state_update received:", data);
|
|
140
|
+
setIframeState(data);
|
|
141
|
+
if (data.hasPlayedOnce !== void 0) {
|
|
142
|
+
setHasPlayedOnce(data.hasPlayedOnce);
|
|
143
|
+
}
|
|
144
|
+
onStateChange?.(data);
|
|
145
|
+
} else if (type === "playruo_purchase_request" && data?.storeUrl) {
|
|
146
|
+
console.log("\u{1F537} [Embed] playruo_purchase_request received:", data);
|
|
147
|
+
onPurchaseRequest?.(data);
|
|
148
|
+
} else if (type === "playruo_demo_completed" && data) {
|
|
149
|
+
console.log("\u{1F537} [Embed] playruo_demo_completed received:", data);
|
|
150
|
+
setHasPlayedOnce(true);
|
|
151
|
+
onDemoCompleted?.(data);
|
|
152
|
+
} else if (type === "playruo_error") {
|
|
153
|
+
const errorMessage2 = typeof data === "string" ? data : data?.message || "Unknown error";
|
|
154
|
+
console.log("\u{1F537} [Embed] playruo_error received:", errorMessage2);
|
|
155
|
+
setErrorMessage(errorMessage2);
|
|
156
|
+
const errorState = {
|
|
157
|
+
hasPlayedOnce,
|
|
158
|
+
tryNow: {
|
|
159
|
+
available: false,
|
|
160
|
+
status: `Error: ${errorMessage2}`
|
|
161
|
+
},
|
|
162
|
+
buyNow: {
|
|
163
|
+
available: true,
|
|
164
|
+
status: "Ready"
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
setIframeState(errorState);
|
|
168
|
+
onStateChange?.(errorState);
|
|
169
|
+
onError?.(errorMessage2);
|
|
170
|
+
} else if (type === "playruo_session_over" && data) {
|
|
171
|
+
console.log("\u{1F537} [Embed] playruo_session_over received:", data);
|
|
172
|
+
setHasPlayedOnce(true);
|
|
173
|
+
setIframeState(data);
|
|
174
|
+
onStateChange?.(data);
|
|
175
|
+
} else if (type === "playruo_stream_start") {
|
|
176
|
+
console.log("\u{1F537} [Embed] playruo_stream_start received");
|
|
177
|
+
}
|
|
193
178
|
if (type === "error" || type === "closeForBuy" || type === "goToStore") {
|
|
179
|
+
console.log("\u{1F537} [Embed] Legacy message received:", type);
|
|
194
180
|
setHasPlayedOnce(true);
|
|
195
|
-
|
|
181
|
+
const payload = {
|
|
196
182
|
reason: "Demo session ended",
|
|
197
183
|
storeUrl
|
|
198
|
-
}
|
|
184
|
+
};
|
|
185
|
+
onDemoCompleted?.(payload);
|
|
199
186
|
}
|
|
200
187
|
};
|
|
201
188
|
window.addEventListener("message", handleGameMessage);
|
|
202
189
|
return () => window.removeEventListener("message", handleGameMessage);
|
|
203
|
-
}, [storeUrl, onDemoCompleted]);
|
|
190
|
+
}, [storeUrl, onDemoCompleted, onReady, onStateChange, onPurchaseRequest, onError, iframeRef]);
|
|
191
|
+
const generateUUID = () => {
|
|
192
|
+
if (self.crypto.randomUUID) return self.crypto.randomUUID();
|
|
193
|
+
const bytes = new Uint8Array(16);
|
|
194
|
+
self.crypto.getRandomValues(bytes);
|
|
195
|
+
bytes[6] = bytes[6] & 15 | 64;
|
|
196
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
197
|
+
return [...bytes].map(
|
|
198
|
+
(b, i) => ([4, 6, 8, 10].includes(i) ? "-" : "") + b.toString(16).padStart(2, "0")
|
|
199
|
+
).join("");
|
|
200
|
+
};
|
|
201
|
+
useEffect(() => {
|
|
202
|
+
const handleUUIDMessage = (event) => {
|
|
203
|
+
const iframe = iframeRef.current;
|
|
204
|
+
if (!iframe || event.source !== iframe.contentWindow) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const { type, requestId } = event.data || {};
|
|
208
|
+
if (type === "playruo_uuid_request") {
|
|
209
|
+
try {
|
|
210
|
+
let storedUUID = localStorage.getItem("playruo_uuid");
|
|
211
|
+
if (!storedUUID) {
|
|
212
|
+
storedUUID = generateUUID();
|
|
213
|
+
localStorage.setItem("playruo_uuid", storedUUID);
|
|
214
|
+
}
|
|
215
|
+
iframe.contentWindow?.postMessage(
|
|
216
|
+
{
|
|
217
|
+
type: "playruo_uuid_response",
|
|
218
|
+
requestId,
|
|
219
|
+
uuid: storedUUID
|
|
220
|
+
},
|
|
221
|
+
"*"
|
|
222
|
+
);
|
|
223
|
+
} catch (e) {
|
|
224
|
+
}
|
|
225
|
+
} else if (type === "playruo_uuid_remove") {
|
|
226
|
+
try {
|
|
227
|
+
localStorage.removeItem("playruo_uuid");
|
|
228
|
+
} catch (e) {
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
window.addEventListener("message", handleUUIDMessage);
|
|
233
|
+
return () => window.removeEventListener("message", handleUUIDMessage);
|
|
234
|
+
}, [iframeRef]);
|
|
204
235
|
useEffect(() => {
|
|
205
236
|
const handleFullscreenChange = () => {
|
|
206
237
|
const doc = document;
|
|
@@ -214,10 +245,17 @@ var PlayruoEmbed = ({
|
|
|
214
245
|
}, 200);
|
|
215
246
|
}
|
|
216
247
|
} else {
|
|
217
|
-
|
|
218
|
-
if (
|
|
219
|
-
|
|
220
|
-
|
|
248
|
+
const iframe = iframeRef.current;
|
|
249
|
+
if (iframe) {
|
|
250
|
+
try {
|
|
251
|
+
iframe.contentWindow?.postMessage({
|
|
252
|
+
type: "playruo",
|
|
253
|
+
action: "exitFullscreen",
|
|
254
|
+
fromEmbed: true
|
|
255
|
+
}, "*");
|
|
256
|
+
} catch {
|
|
257
|
+
console.error("[PlayruoEmbed] Failed to exit fullscreen");
|
|
258
|
+
}
|
|
221
259
|
}
|
|
222
260
|
setShowGameIframe(false);
|
|
223
261
|
setHasPlayedOnce(true);
|
|
@@ -238,56 +276,6 @@ var PlayruoEmbed = ({
|
|
|
238
276
|
document.removeEventListener("MSFullscreenChange", handleFullscreenChange);
|
|
239
277
|
};
|
|
240
278
|
}, [storeUrl, onDemoCompleted, iframeRef]);
|
|
241
|
-
useEffect(() => {
|
|
242
|
-
const handleKeyDown = (event) => {
|
|
243
|
-
if (event.key === "Escape" && !escapeKeyPressed.current) {
|
|
244
|
-
escapeKeyPressed.current = true;
|
|
245
|
-
event.preventDefault();
|
|
246
|
-
escapeKeyTimer.current = setTimeout(() => {
|
|
247
|
-
if (document.fullscreenElement) {
|
|
248
|
-
document.exitFullscreen();
|
|
249
|
-
}
|
|
250
|
-
}, ESCAPE_HOLD_DURATION);
|
|
251
|
-
}
|
|
252
|
-
if (event.ctrlKey && event.shiftKey && event.key === "R") {
|
|
253
|
-
event.preventDefault();
|
|
254
|
-
if (document.fullscreenElement) {
|
|
255
|
-
document.exitFullscreen().catch(console.warn);
|
|
256
|
-
}
|
|
257
|
-
setTimeout(() => {
|
|
258
|
-
window.location.reload();
|
|
259
|
-
}, 500);
|
|
260
|
-
}
|
|
261
|
-
};
|
|
262
|
-
const handleKeyUp = (event) => {
|
|
263
|
-
if (event.key === "Escape" && escapeKeyPressed.current) {
|
|
264
|
-
escapeKeyPressed.current = false;
|
|
265
|
-
if (escapeKeyTimer.current) {
|
|
266
|
-
clearTimeout(escapeKeyTimer.current);
|
|
267
|
-
escapeKeyTimer.current = null;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
};
|
|
271
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
272
|
-
document.addEventListener("keyup", handleKeyUp);
|
|
273
|
-
return () => {
|
|
274
|
-
document.removeEventListener("keydown", handleKeyDown);
|
|
275
|
-
document.removeEventListener("keyup", handleKeyUp);
|
|
276
|
-
};
|
|
277
|
-
}, []);
|
|
278
|
-
useEffect(() => {
|
|
279
|
-
const isVisible = showGameIframe || showIframe;
|
|
280
|
-
const iframe = iframeRef.current;
|
|
281
|
-
if (!iframe || !isIframeLoaded) return;
|
|
282
|
-
try {
|
|
283
|
-
iframe.contentWindow?.postMessage({
|
|
284
|
-
type: "playruo",
|
|
285
|
-
action: isVisible ? "unmute" : "mute",
|
|
286
|
-
fromEmbed: true
|
|
287
|
-
}, "*");
|
|
288
|
-
} catch {
|
|
289
|
-
}
|
|
290
|
-
}, [showGameIframe, showIframe, isIframeLoaded, iframeRef]);
|
|
291
279
|
useEffect(() => {
|
|
292
280
|
const logCrossOriginStatus = () => {
|
|
293
281
|
const isIsolated = self.crossOriginIsolated;
|
|
@@ -396,7 +384,6 @@ var PlayruoEmbed = ({
|
|
|
396
384
|
ref: iframeRef,
|
|
397
385
|
src,
|
|
398
386
|
allow: "cross-origin-isolated; fullscreen *; autoplay *; gamepad *; clipboard-write *; web-share *; encrypted-media *; accelerometer *; gyroscope *",
|
|
399
|
-
allowFullScreen: true,
|
|
400
387
|
className: "w-full h-[70vh] rounded-lg border",
|
|
401
388
|
...{ credentialless: "true" },
|
|
402
389
|
sandbox: "allow-same-origin allow-scripts allow-popups allow-forms allow-presentation allow-top-navigation allow-modals allow-pointer-lock",
|
|
@@ -789,18 +776,17 @@ var isPlayruoEmbedMessage = (data) => {
|
|
|
789
776
|
if (!data || typeof data !== "object") return false;
|
|
790
777
|
const msg = data;
|
|
791
778
|
if (typeof msg.type !== "string") return false;
|
|
792
|
-
return msg.type === "playruo_ready" || msg.type === "playruo_state_update" || msg.type === "playruo_purchase_request" || msg.type === "playruo_demo_completed" || msg.type === "playruo_error";
|
|
779
|
+
return msg.type === "playruo_ready" || msg.type === "playruo_state_update" || msg.type === "playruo_purchase_request" || msg.type === "playruo_demo_completed" || msg.type === "playruo_error" || msg.type === "playruo_session_over" || msg.type === "playruo_stream_start" || msg.type === "playruo_stream_stop";
|
|
793
780
|
};
|
|
794
|
-
var
|
|
781
|
+
var isPlayruoInternalMessage = (data) => {
|
|
795
782
|
if (!data || typeof data !== "object") return false;
|
|
796
|
-
const
|
|
797
|
-
|
|
798
|
-
return cmd.type === "try_now" || cmd.type === "buy_now" || cmd.type === "get_state";
|
|
783
|
+
const msg = data;
|
|
784
|
+
return msg.type === "playruo" && typeof msg.action === "string" && (msg.action === "tryNowClick" || msg.action === "exitFullscreen" || msg.action === "mute" || msg.action === "unmute") && msg.fromEmbed === true;
|
|
799
785
|
};
|
|
800
786
|
export {
|
|
801
787
|
EmbedTester,
|
|
802
788
|
PlayruoEmbed,
|
|
803
789
|
buildEmbedUrl,
|
|
804
|
-
|
|
805
|
-
|
|
790
|
+
isPlayruoEmbedMessage,
|
|
791
|
+
isPlayruoInternalMessage
|
|
806
792
|
};
|