@playruo/embed 1.3.3 → 1.5.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/README.md +92 -0
- package/dist/index.cjs +166 -76
- package/dist/index.d.cts +166 -64
- package/dist/index.d.ts +166 -64
- package/dist/index.js +163 -75
- package/package.json +34 -9
package/dist/index.js
CHANGED
|
@@ -8,27 +8,72 @@ var normalizeOperation = (operation) => {
|
|
|
8
8
|
if (trimmedOperation === "") {
|
|
9
9
|
throw new Error("`operation` is required to build a Playruo embed URL.");
|
|
10
10
|
}
|
|
11
|
+
const operationQuery = trimmedOperation.split("?")[1];
|
|
12
|
+
if (operationQuery != null && new URLSearchParams(operationQuery).has("op")) {
|
|
13
|
+
console.warn(
|
|
14
|
+
"[PlayruoEmbed] `?op=` inside `operation` is deprecated: pass it as the `operationKey` prop."
|
|
15
|
+
);
|
|
16
|
+
}
|
|
11
17
|
return trimmedOperation.startsWith("/") ? trimmedOperation.slice(1) : trimmedOperation;
|
|
12
18
|
};
|
|
13
|
-
var buildEmbedUrl = ({
|
|
14
|
-
|
|
19
|
+
var buildEmbedUrl = ({
|
|
20
|
+
operation,
|
|
21
|
+
operationKey,
|
|
22
|
+
storeUrl
|
|
23
|
+
}) => {
|
|
24
|
+
return buildEmbedUrlWithOrigin(PLAYRUO_ORIGIN, {
|
|
25
|
+
operation,
|
|
26
|
+
operationKey,
|
|
27
|
+
storeUrl
|
|
28
|
+
});
|
|
15
29
|
};
|
|
16
|
-
var buildEmbedUrlWithOrigin = (origin, { operation, storeUrl }) => {
|
|
30
|
+
var buildEmbedUrlWithOrigin = (origin, { operation, operationKey, storeUrl }) => {
|
|
17
31
|
const operationPath = normalizeOperation(operation);
|
|
18
32
|
const url = new URL(`/${operationPath}`, origin);
|
|
19
33
|
url.searchParams.set("iframe", "true");
|
|
34
|
+
const trimmedOperationKey = operationKey?.trim();
|
|
35
|
+
if (trimmedOperationKey) {
|
|
36
|
+
url.searchParams.set("op", trimmedOperationKey);
|
|
37
|
+
}
|
|
20
38
|
if (storeUrl) {
|
|
21
39
|
url.searchParams.set("storeUrl", storeUrl);
|
|
22
40
|
}
|
|
23
41
|
return url.toString();
|
|
24
42
|
};
|
|
25
43
|
|
|
44
|
+
// src/visitor-uuid.ts
|
|
45
|
+
var PLAYRUO_UUID_STORAGE_KEY = "playruo_uuid";
|
|
46
|
+
var generateUUID = () => {
|
|
47
|
+
if (self.crypto.randomUUID) return self.crypto.randomUUID();
|
|
48
|
+
const bytes = new Uint8Array(16);
|
|
49
|
+
self.crypto.getRandomValues(bytes);
|
|
50
|
+
bytes[6] = bytes[6] & 15 | 64;
|
|
51
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
52
|
+
return [...bytes].map(
|
|
53
|
+
(b, i) => ([4, 6, 8, 10].includes(i) ? "-" : "") + b.toString(16).padStart(2, "0")
|
|
54
|
+
).join("");
|
|
55
|
+
};
|
|
56
|
+
var resolveVisitorUuid = (clientFingerprint) => {
|
|
57
|
+
const provided = clientFingerprint?.trim();
|
|
58
|
+
if (provided) {
|
|
59
|
+
return provided;
|
|
60
|
+
}
|
|
61
|
+
let uuid = localStorage.getItem(PLAYRUO_UUID_STORAGE_KEY);
|
|
62
|
+
if (!uuid) {
|
|
63
|
+
uuid = generateUUID();
|
|
64
|
+
localStorage.setItem(PLAYRUO_UUID_STORAGE_KEY, uuid);
|
|
65
|
+
}
|
|
66
|
+
return uuid;
|
|
67
|
+
};
|
|
68
|
+
|
|
26
69
|
// src/react/playruo-embed.tsx
|
|
27
70
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
28
71
|
var PlayruoEmbed = ({
|
|
29
72
|
baseUrl,
|
|
30
73
|
operation,
|
|
74
|
+
operationKey,
|
|
31
75
|
storeUrl,
|
|
76
|
+
clientFingerprint,
|
|
32
77
|
showIframe = false,
|
|
33
78
|
className,
|
|
34
79
|
onReady,
|
|
@@ -37,6 +82,8 @@ var PlayruoEmbed = ({
|
|
|
37
82
|
onEvent,
|
|
38
83
|
onPurchaseRequest,
|
|
39
84
|
onError,
|
|
85
|
+
onPasswordRequired,
|
|
86
|
+
onPasswordResult,
|
|
40
87
|
enableWindowedLaunch = false,
|
|
41
88
|
forwardEventsToParent = true,
|
|
42
89
|
renderState,
|
|
@@ -54,12 +101,24 @@ var PlayruoEmbed = ({
|
|
|
54
101
|
const [isValidChromium, setIsValidChromium] = useState(true);
|
|
55
102
|
const [errorMessage, setErrorMessage] = useState(null);
|
|
56
103
|
const [iframeState, setIframeState] = useState(null);
|
|
104
|
+
const [passwordRequired, setPasswordRequired] = useState(false);
|
|
105
|
+
const [passwordChecked, setPasswordChecked] = useState(false);
|
|
106
|
+
const [passwordUnlocked, setPasswordUnlocked] = useState(false);
|
|
107
|
+
const [passwordError, setPasswordError] = useState(
|
|
108
|
+
void 0
|
|
109
|
+
);
|
|
57
110
|
const src = useMemo(
|
|
58
|
-
() => baseUrl != null && baseUrl !== "" ? buildEmbedUrlWithOrigin(baseUrl, { operation, storeUrl }) : buildEmbedUrl({ operation, storeUrl }),
|
|
59
|
-
[baseUrl, operation, storeUrl]
|
|
111
|
+
() => baseUrl != null && baseUrl !== "" ? buildEmbedUrlWithOrigin(baseUrl, { operation, operationKey, storeUrl }) : buildEmbedUrl({ operation, operationKey, storeUrl }),
|
|
112
|
+
[baseUrl, operation, operationKey, storeUrl]
|
|
60
113
|
);
|
|
114
|
+
const embedOrigin = useMemo(() => new URL(src).origin, [src]);
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
setPasswordRequired(false);
|
|
117
|
+
setPasswordChecked(false);
|
|
118
|
+
setPasswordUnlocked(false);
|
|
119
|
+
setPasswordError(void 0);
|
|
120
|
+
}, [src]);
|
|
61
121
|
useEffect(() => {
|
|
62
|
-
if (typeof window === "undefined") return;
|
|
63
122
|
const detectMobile = () => {
|
|
64
123
|
const userAgent = navigator.userAgent || navigator.vendor || window.opera;
|
|
65
124
|
return /android|iPad|iPhone|iPod/i.test(userAgent);
|
|
@@ -97,15 +156,14 @@ var PlayruoEmbed = ({
|
|
|
97
156
|
tryNow: {
|
|
98
157
|
...currentState.tryNow,
|
|
99
158
|
available: hasIframeConfirmed,
|
|
100
|
-
|
|
159
|
+
// A missing status means the state came from the iframe, which only loads on
|
|
160
|
+
// compatible browsers — the incompatible copy is supplied by currentState.
|
|
161
|
+
status: currentState.tryNow.status ?? (hasIframeConfirmed ? "Ready" : "Checking availability\u2026")
|
|
101
162
|
}
|
|
102
163
|
}),
|
|
103
|
-
[currentState, hasIframeConfirmed
|
|
164
|
+
[currentState, hasIframeConfirmed]
|
|
104
165
|
);
|
|
105
166
|
const getKeyboardApi = useCallback(() => {
|
|
106
|
-
if (typeof navigator === "undefined") {
|
|
107
|
-
return void 0;
|
|
108
|
-
}
|
|
109
167
|
return navigator.keyboard;
|
|
110
168
|
}, []);
|
|
111
169
|
const releaseEscapeKeyLock = useCallback(() => {
|
|
@@ -135,6 +193,23 @@ var PlayruoEmbed = ({
|
|
|
135
193
|
},
|
|
136
194
|
[onDemoCompleted, storeUrl]
|
|
137
195
|
);
|
|
196
|
+
const postPasswordAction = useCallback(
|
|
197
|
+
(message) => {
|
|
198
|
+
const contentWindow = iframeRef.current?.contentWindow;
|
|
199
|
+
if (!contentWindow) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
try {
|
|
203
|
+
contentWindow.postMessage(
|
|
204
|
+
{ type: "playruo", fromEmbed: true, ...message },
|
|
205
|
+
embedOrigin
|
|
206
|
+
);
|
|
207
|
+
} catch {
|
|
208
|
+
console.error("[PlayruoEmbed] Failed to send the password action");
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
[embedOrigin, iframeRef]
|
|
212
|
+
);
|
|
138
213
|
const postExitFullscreenToIframe = useCallback(() => {
|
|
139
214
|
const iframe = iframeRef.current;
|
|
140
215
|
if (!iframe) {
|
|
@@ -147,22 +222,22 @@ var PlayruoEmbed = ({
|
|
|
147
222
|
fromEmbed: true,
|
|
148
223
|
isFullscreen: false,
|
|
149
224
|
parentWillHandleFullscreen: true
|
|
150
|
-
},
|
|
225
|
+
}, embedOrigin);
|
|
151
226
|
} catch {
|
|
152
227
|
console.error("[PlayruoEmbed] Failed to exit fullscreen");
|
|
153
228
|
}
|
|
154
|
-
}, [iframeRef]);
|
|
229
|
+
}, [embedOrigin, iframeRef]);
|
|
155
230
|
const postExitFullscreenAckToIframe = useCallback(() => {
|
|
156
231
|
const iframe = iframeRef.current;
|
|
157
232
|
if (!iframe) {
|
|
158
233
|
return;
|
|
159
234
|
}
|
|
160
235
|
try {
|
|
161
|
-
iframe.contentWindow?.postMessage({ type: "ACK_EXIT_FULLSCREEN" },
|
|
236
|
+
iframe.contentWindow?.postMessage({ type: "ACK_EXIT_FULLSCREEN" }, embedOrigin);
|
|
162
237
|
} catch {
|
|
163
238
|
console.error("[PlayruoEmbed] Failed to acknowledge fullscreen exit");
|
|
164
239
|
}
|
|
165
|
-
}, [iframeRef]);
|
|
240
|
+
}, [embedOrigin, iframeRef]);
|
|
166
241
|
const exitEmbedFullscreen = useCallback(
|
|
167
242
|
async ({
|
|
168
243
|
reason = "cleanup",
|
|
@@ -248,7 +323,7 @@ var PlayruoEmbed = ({
|
|
|
248
323
|
}, []);
|
|
249
324
|
const forwardEventToParent = useCallback(
|
|
250
325
|
(message) => {
|
|
251
|
-
if (!forwardEventsToParent ||
|
|
326
|
+
if (!forwardEventsToParent || window.parent === window) {
|
|
252
327
|
return;
|
|
253
328
|
}
|
|
254
329
|
try {
|
|
@@ -317,7 +392,7 @@ var PlayruoEmbed = ({
|
|
|
317
392
|
isFullscreen: isParentFullscreen,
|
|
318
393
|
parentWillHandleFullscreen: isParentFullscreen,
|
|
319
394
|
isReplay: hasPlayedOnce
|
|
320
|
-
},
|
|
395
|
+
}, embedOrigin);
|
|
321
396
|
console.log("[PlayruoEmbed] Sent tryNowClick to game", hasPlayedOnce ? "(replay)" : "(first time)");
|
|
322
397
|
iframe.focus();
|
|
323
398
|
requestAnimationFrame(() => {
|
|
@@ -364,6 +439,9 @@ var PlayruoEmbed = ({
|
|
|
364
439
|
if (!iframe || event.source !== iframe.contentWindow) {
|
|
365
440
|
return;
|
|
366
441
|
}
|
|
442
|
+
if (event.origin !== embedOrigin) {
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
367
445
|
console.log("\u{1F537} [Embed] Message received from iframe:", { type, data });
|
|
368
446
|
if (type === "playruo_ready") {
|
|
369
447
|
console.log("\u{1F537} [Embed] playruo_ready received");
|
|
@@ -432,6 +510,24 @@ var PlayruoEmbed = ({
|
|
|
432
510
|
const eventPayload = message.payload;
|
|
433
511
|
onEvent?.(eventPayload);
|
|
434
512
|
forwardEventToParent({ type: "playruo_event", data: eventPayload });
|
|
513
|
+
} else if (type === "playruo_password_required") {
|
|
514
|
+
console.log("\u{1F537} [Embed] playruo_password_required received");
|
|
515
|
+
setPasswordRequired(true);
|
|
516
|
+
setPasswordChecked(true);
|
|
517
|
+
setPasswordUnlocked(false);
|
|
518
|
+
setPasswordError(void 0);
|
|
519
|
+
onPasswordRequired?.();
|
|
520
|
+
} else if (type === "playruo_password_not_required") {
|
|
521
|
+
console.log("\u{1F537} [Embed] playruo_password_not_required received");
|
|
522
|
+
setPasswordRequired(false);
|
|
523
|
+
setPasswordChecked(true);
|
|
524
|
+
} else if (type === "playruo_password_result" && data) {
|
|
525
|
+
const result = data;
|
|
526
|
+
const success = result.success === true;
|
|
527
|
+
console.log("\u{1F537} [Embed] playruo_password_result received:", result);
|
|
528
|
+
setPasswordUnlocked(success);
|
|
529
|
+
setPasswordError(success ? void 0 : result.error ?? "unknown");
|
|
530
|
+
onPasswordResult?.({ success, error: result.error });
|
|
435
531
|
}
|
|
436
532
|
if (type === "error" || type === "closeForBuy" || type === "goToStore") {
|
|
437
533
|
console.log("\u{1F537} [Embed] Legacy message received:", type);
|
|
@@ -447,6 +543,7 @@ var PlayruoEmbed = ({
|
|
|
447
543
|
return () => window.removeEventListener("message", handleGameMessage);
|
|
448
544
|
}, [
|
|
449
545
|
cleanupEmbedSession,
|
|
546
|
+
embedOrigin,
|
|
450
547
|
exitEmbedFullscreen,
|
|
451
548
|
forwardEventToParent,
|
|
452
549
|
hasPlayedOnce,
|
|
@@ -454,70 +551,53 @@ var PlayruoEmbed = ({
|
|
|
454
551
|
markStreamActive,
|
|
455
552
|
onEvent,
|
|
456
553
|
onError,
|
|
554
|
+
onPasswordRequired,
|
|
555
|
+
onPasswordResult,
|
|
457
556
|
onPurchaseRequest,
|
|
458
557
|
onReady,
|
|
459
558
|
onStateChange,
|
|
460
559
|
postExitFullscreenAckToIframe,
|
|
461
560
|
storeUrl
|
|
462
561
|
]);
|
|
463
|
-
const generateUUID = () => {
|
|
464
|
-
if (self.crypto.randomUUID) return self.crypto.randomUUID();
|
|
465
|
-
const bytes = new Uint8Array(16);
|
|
466
|
-
self.crypto.getRandomValues(bytes);
|
|
467
|
-
bytes[6] = bytes[6] & 15 | 64;
|
|
468
|
-
bytes[8] = bytes[8] & 63 | 128;
|
|
469
|
-
return [...bytes].map(
|
|
470
|
-
(b, i) => ([4, 6, 8, 10].includes(i) ? "-" : "") + b.toString(16).padStart(2, "0")
|
|
471
|
-
).join("");
|
|
472
|
-
};
|
|
473
562
|
useEffect(() => {
|
|
474
563
|
const handleUUIDMessage = (event) => {
|
|
475
564
|
const iframe = iframeRef.current;
|
|
476
565
|
if (!iframe || event.source !== iframe.contentWindow) {
|
|
477
566
|
return;
|
|
478
567
|
}
|
|
568
|
+
if (event.origin !== embedOrigin) {
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
479
571
|
const { type, requestId } = event.data || {};
|
|
480
572
|
if (type === "playruo_uuid_request") {
|
|
481
573
|
try {
|
|
482
|
-
let storedUUID = localStorage.getItem("playruo_uuid");
|
|
483
|
-
if (!storedUUID) {
|
|
484
|
-
storedUUID = generateUUID();
|
|
485
|
-
localStorage.setItem("playruo_uuid", storedUUID);
|
|
486
|
-
}
|
|
487
574
|
iframe.contentWindow?.postMessage(
|
|
488
575
|
{
|
|
489
576
|
type: "playruo_uuid_response",
|
|
490
577
|
requestId,
|
|
491
|
-
uuid:
|
|
578
|
+
uuid: resolveVisitorUuid(clientFingerprint)
|
|
492
579
|
},
|
|
493
|
-
|
|
580
|
+
embedOrigin
|
|
494
581
|
);
|
|
495
582
|
} catch (e) {
|
|
496
583
|
}
|
|
497
|
-
} else if (type === "playruo_uuid_remove") {
|
|
498
|
-
try {
|
|
499
|
-
localStorage.removeItem("playruo_uuid");
|
|
500
|
-
} catch (e) {
|
|
501
|
-
}
|
|
502
584
|
}
|
|
503
585
|
};
|
|
504
586
|
window.addEventListener("message", handleUUIDMessage);
|
|
505
587
|
return () => window.removeEventListener("message", handleUUIDMessage);
|
|
506
|
-
}, [iframeRef]);
|
|
588
|
+
}, [clientFingerprint, embedOrigin, iframeRef]);
|
|
507
589
|
useEffect(() => {
|
|
508
590
|
const handleFullscreenChange = () => {
|
|
509
591
|
const iframe = iframeRef.current;
|
|
510
592
|
const fullscreenElement = getFullscreenElement();
|
|
511
593
|
const isEmbedFullscreen = Boolean(iframe && fullscreenElement === iframe);
|
|
512
|
-
if (isEmbedFullscreen) {
|
|
594
|
+
if (isEmbedFullscreen && iframe) {
|
|
513
595
|
wasEmbedFullscreenRef.current = true;
|
|
514
596
|
void lockEscapeKey();
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
}, 200);
|
|
520
|
-
}
|
|
597
|
+
setTimeout(() => {
|
|
598
|
+
iframe.focus();
|
|
599
|
+
iframe.contentWindow?.focus();
|
|
600
|
+
}, 200);
|
|
521
601
|
return;
|
|
522
602
|
}
|
|
523
603
|
if (fullscreenElement) {
|
|
@@ -562,17 +642,16 @@ var PlayruoEmbed = ({
|
|
|
562
642
|
const logCrossOriginStatus = () => {
|
|
563
643
|
const isIsolated = self.crossOriginIsolated;
|
|
564
644
|
const hasSharedArrayBuffer = typeof SharedArrayBuffer !== "undefined";
|
|
565
|
-
const hasHighResTime = typeof performance !== "undefined" && typeof performance.now === "function";
|
|
566
645
|
console.group("[PlayruoEmbed] \u{1F512} Cross-Origin Isolation Status");
|
|
567
646
|
if (isIsolated) {
|
|
568
647
|
console.log("\u2705 Cross-origin isolation: ENABLED");
|
|
569
648
|
console.log("\u2705 SharedArrayBuffer support:", hasSharedArrayBuffer ? "Available" : "Not available");
|
|
570
|
-
console.log("\u2705 High-resolution timers:
|
|
649
|
+
console.log("\u2705 High-resolution timers: Full precision");
|
|
571
650
|
console.log("\u{1F3AE} Game performance: Optimal");
|
|
572
651
|
} else {
|
|
573
652
|
console.warn("\u26A0\uFE0F Cross-origin isolation: DISABLED");
|
|
574
653
|
console.warn("\u26A0\uFE0F SharedArrayBuffer support:", hasSharedArrayBuffer ? "Available" : "Not available");
|
|
575
|
-
console.warn("\u26A0\uFE0F High-resolution timers:
|
|
654
|
+
console.warn("\u26A0\uFE0F High-resolution timers: Reduced precision");
|
|
576
655
|
console.warn("\u{1F3AE} Game performance: May be degraded");
|
|
577
656
|
console.group("\u{1F4CB} Setup Instructions:");
|
|
578
657
|
console.log("Add these headers to your server:");
|
|
@@ -616,7 +695,7 @@ var PlayruoEmbed = ({
|
|
|
616
695
|
console.log("User agent:", navigator.userAgent);
|
|
617
696
|
console.log("Available APIs:", {
|
|
618
697
|
SharedArrayBuffer: hasSharedArrayBuffer,
|
|
619
|
-
Performance:
|
|
698
|
+
Performance: true,
|
|
620
699
|
WebGL: !!document.createElement("canvas").getContext("webgl"),
|
|
621
700
|
WebGL2: !!document.createElement("canvas").getContext("webgl2"),
|
|
622
701
|
WebAssembly: typeof WebAssembly !== "undefined"
|
|
@@ -648,22 +727,44 @@ var PlayruoEmbed = ({
|
|
|
648
727
|
tryNow: handleTryNow,
|
|
649
728
|
buyNow: handleBuyNow,
|
|
650
729
|
canTryNow,
|
|
651
|
-
canBuyNow: Boolean(isReady)
|
|
730
|
+
canBuyNow: Boolean(isReady),
|
|
731
|
+
submitPassword: (password2) => {
|
|
732
|
+
if (!password2) {
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
postPasswordAction({ action: "submitPassword", password: password2 });
|
|
736
|
+
},
|
|
737
|
+
requestPassword: () => postPasswordAction({ action: "requestPassword" })
|
|
738
|
+
};
|
|
739
|
+
const password = {
|
|
740
|
+
required: passwordRequired,
|
|
741
|
+
checked: passwordChecked,
|
|
742
|
+
unlocked: passwordUnlocked,
|
|
743
|
+
error: passwordError
|
|
652
744
|
};
|
|
653
745
|
if (errorMessage) {
|
|
654
|
-
return renderState({ status: "error", message: errorMessage, actions });
|
|
746
|
+
return renderState({ status: "error", message: errorMessage, actions, password });
|
|
747
|
+
}
|
|
748
|
+
if (password.required && !password.unlocked) {
|
|
749
|
+
return renderState({
|
|
750
|
+
status: "loading",
|
|
751
|
+
message: "Password required",
|
|
752
|
+
actions,
|
|
753
|
+
password
|
|
754
|
+
});
|
|
655
755
|
}
|
|
656
756
|
if (!isReady) {
|
|
657
|
-
return renderState({ status: "loading", message: "Loading\u2026", actions });
|
|
757
|
+
return renderState({ status: "loading", message: "Loading\u2026", actions, password });
|
|
658
758
|
}
|
|
659
759
|
if (isCompatible && !iframeState) {
|
|
660
|
-
return renderState({ status: "loading", message: "Checking availability\u2026", actions });
|
|
760
|
+
return renderState({ status: "loading", message: "Checking availability\u2026", actions, password });
|
|
661
761
|
}
|
|
662
762
|
const message = !isAvailable ? currentState.tryNow.status ?? exposedState.tryNow.status : void 0;
|
|
663
763
|
return renderState({
|
|
664
764
|
status: isAvailable ? "available" : "unavailable",
|
|
665
765
|
message,
|
|
666
|
-
actions
|
|
766
|
+
actions,
|
|
767
|
+
password
|
|
667
768
|
});
|
|
668
769
|
};
|
|
669
770
|
return /* @__PURE__ */ jsxs("div", { className, children: [
|
|
@@ -709,12 +810,6 @@ var PlayruoEmbed = ({
|
|
|
709
810
|
},
|
|
710
811
|
onLoad: () => {
|
|
711
812
|
setIsIframeLoaded(true);
|
|
712
|
-
setTimeout(() => {
|
|
713
|
-
if (iframeRef.current) {
|
|
714
|
-
iframeRef.current.focus();
|
|
715
|
-
iframeRef.current.contentWindow?.focus();
|
|
716
|
-
}
|
|
717
|
-
}, 500);
|
|
718
813
|
},
|
|
719
814
|
onError: () => {
|
|
720
815
|
console.error("[PlayruoEmbed] Iframe failed to load");
|
|
@@ -890,20 +985,11 @@ var EmbedTester = (props = {}) => {
|
|
|
890
985
|
addEvent(message);
|
|
891
986
|
}, [addEvent]);
|
|
892
987
|
const handleApply = useCallback2(() => {
|
|
893
|
-
if (!hasPendingConfigChanges) {
|
|
894
|
-
return;
|
|
895
|
-
}
|
|
896
988
|
setAppliedOperation(operationDraft);
|
|
897
989
|
setAppliedStoreUrl(storeUrlDraft);
|
|
898
990
|
setAppliedEnableWindowedLaunch(enableWindowedLaunchDraft);
|
|
899
991
|
resetEmbedSession("Applied updated embed settings");
|
|
900
|
-
}, [
|
|
901
|
-
enableWindowedLaunchDraft,
|
|
902
|
-
hasPendingConfigChanges,
|
|
903
|
-
operationDraft,
|
|
904
|
-
resetEmbedSession,
|
|
905
|
-
storeUrlDraft
|
|
906
|
-
]);
|
|
992
|
+
}, [enableWindowedLaunchDraft, operationDraft, resetEmbedSession, storeUrlDraft]);
|
|
907
993
|
const handleRestartSession = useCallback2(() => {
|
|
908
994
|
resetEmbedSession("Embed restarted with applied settings");
|
|
909
995
|
}, [resetEmbedSession]);
|
|
@@ -2007,17 +2093,19 @@ var isPlayruoEmbedMessage = (data) => {
|
|
|
2007
2093
|
if (!data || typeof data !== "object") return false;
|
|
2008
2094
|
const msg = data;
|
|
2009
2095
|
if (typeof msg.type !== "string") return false;
|
|
2010
|
-
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" || msg.type === "REQUEST_EXIT_FULLSCREEN" || msg.type === "playruo_event";
|
|
2096
|
+
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" || msg.type === "REQUEST_EXIT_FULLSCREEN" || msg.type === "playruo_event" || msg.type === "playruo_password_required" || msg.type === "playruo_password_not_required" || msg.type === "playruo_password_result";
|
|
2011
2097
|
};
|
|
2012
2098
|
var isPlayruoInternalMessage = (data) => {
|
|
2013
2099
|
if (!data || typeof data !== "object") return false;
|
|
2014
2100
|
const msg = data;
|
|
2015
|
-
return msg.type === "playruo" && typeof msg.action === "string" && (msg.action === "tryNowClick" || msg.action === "exitFullscreen" || msg.action === "mute" || msg.action === "unmute") && msg.fromEmbed === true;
|
|
2101
|
+
return msg.type === "playruo" && typeof msg.action === "string" && (msg.action === "tryNowClick" || msg.action === "exitFullscreen" || msg.action === "mute" || msg.action === "unmute" || msg.action === "submitPassword" || msg.action === "requestPassword") && msg.fromEmbed === true;
|
|
2016
2102
|
};
|
|
2017
2103
|
export {
|
|
2018
2104
|
EmbedTester,
|
|
2105
|
+
PLAYRUO_UUID_STORAGE_KEY,
|
|
2019
2106
|
PlayruoEmbed,
|
|
2020
2107
|
buildEmbedUrl,
|
|
2021
2108
|
isPlayruoEmbedMessage,
|
|
2022
|
-
isPlayruoInternalMessage
|
|
2109
|
+
isPlayruoInternalMessage,
|
|
2110
|
+
resolveVisitorUuid
|
|
2023
2111
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@playruo/embed",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "React SDK to embed Playruo with postMessage API.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -9,27 +9,52 @@
|
|
|
9
9
|
"types": "dist/index.d.ts",
|
|
10
10
|
"exports": {
|
|
11
11
|
".": {
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
"import": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"require": {
|
|
17
|
+
"types": "./dist/index.d.cts",
|
|
18
|
+
"default": "./dist/index.cjs"
|
|
19
|
+
}
|
|
16
20
|
}
|
|
17
21
|
},
|
|
18
|
-
"files": [
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
19
25
|
"sideEffects": false,
|
|
20
26
|
"peerDependencies": {
|
|
21
27
|
"react": ">=18",
|
|
22
28
|
"react-dom": ">=18"
|
|
23
29
|
},
|
|
24
30
|
"devDependencies": {
|
|
31
|
+
"@arethetypeswrong/cli": "^0.18.5",
|
|
32
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
33
|
+
"@testing-library/react": "^16.3.0",
|
|
34
|
+
"@testing-library/user-event": "^14.6.1",
|
|
35
|
+
"@types/node": "^26.2.0",
|
|
36
|
+
"@types/react": "^19",
|
|
37
|
+
"@types/react-dom": "^19",
|
|
38
|
+
"@vitest/browser": "^3.2.7",
|
|
39
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
40
|
+
"jsdom": "^26.1.0",
|
|
41
|
+
"playwright": "^1.62.1",
|
|
42
|
+
"react": "^19.1.0",
|
|
43
|
+
"react-dom": "^19.1.0",
|
|
25
44
|
"tsup": "^8.0.0",
|
|
26
45
|
"typescript": "^5.4.0",
|
|
27
|
-
"
|
|
28
|
-
"@types/react-dom": "^19"
|
|
46
|
+
"vitest": "^3.2.4"
|
|
29
47
|
},
|
|
30
48
|
"scripts": {
|
|
31
49
|
"build": "tsup src/index.ts --format esm,cjs --dts --clean",
|
|
32
50
|
"dev": "tsup src/index.ts --format esm --dts --watch",
|
|
33
|
-
"prepare": "npm run build"
|
|
51
|
+
"prepare": "npm run build",
|
|
52
|
+
"typecheck": "tsc -p tsconfig.test.json",
|
|
53
|
+
"check:exports": "attw --pack .",
|
|
54
|
+
"test": "npm run build && vitest run --coverage",
|
|
55
|
+
"test:browser": "vitest run --config vitest.browser.config.ts",
|
|
56
|
+
"test:watch": "npm run build && vitest",
|
|
57
|
+
"docs:notion:dry-run": "node scripts/sync-notion-docs.mjs",
|
|
58
|
+
"docs:notion:publish": "node scripts/sync-notion-docs.mjs --publish"
|
|
34
59
|
}
|
|
35
60
|
}
|