@playruo/embed 1.2.1 → 1.2.2
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 +0 -299
- package/dist/index.cjs +497 -27
- package/dist/index.d.cts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +486 -27
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FC, ReactNode } from 'react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
3
|
|
|
3
4
|
interface PlayruoEmbedState {
|
|
4
5
|
hasPlayedOnce: boolean;
|
|
@@ -65,6 +66,15 @@ interface PlayruoEmbedProps {
|
|
|
65
66
|
}
|
|
66
67
|
declare const PlayruoEmbed: FC<PlayruoEmbedProps>;
|
|
67
68
|
|
|
69
|
+
interface EmbedTesterProps {
|
|
70
|
+
baseUrl?: string;
|
|
71
|
+
enableConsoleLog?: boolean;
|
|
72
|
+
operation?: string;
|
|
73
|
+
storeUrl?: string;
|
|
74
|
+
className?: string;
|
|
75
|
+
}
|
|
76
|
+
declare const EmbedTester: (props?: EmbedTesterProps) => react_jsx_runtime.JSX.Element;
|
|
77
|
+
|
|
68
78
|
interface PlayruoReadyMessage {
|
|
69
79
|
type: "playruo_ready";
|
|
70
80
|
}
|
|
@@ -121,4 +131,4 @@ interface BuildUrlParams {
|
|
|
121
131
|
*/
|
|
122
132
|
declare const buildEmbedUrl: ({ baseUrl, operation, storeUrl }: BuildUrlParams) => string;
|
|
123
133
|
|
|
124
|
-
export { type BuyNowCommand, type DemoCompletedPayload, type GetStateCommand, type PlayruoDemoCompletedMessage, PlayruoEmbed, type PlayruoEmbedActions, type PlayruoEmbedCommand, type PlayruoEmbedMessage, type PlayruoEmbedProps, type PlayruoEmbedRenderState, type PlayruoEmbedState, type PlayruoErrorMessage, type PlayruoPurchaseRequestMessage, type PlayruoReadyMessage, type PlayruoStateUpdateMessage, type TryNowCommand, buildEmbedUrl, isPlayruoEmbedCommand, isPlayruoEmbedMessage };
|
|
134
|
+
export { type BuyNowCommand, type DemoCompletedPayload, EmbedTester, type EmbedTesterProps, type GetStateCommand, type PlayruoDemoCompletedMessage, PlayruoEmbed, type PlayruoEmbedActions, type PlayruoEmbedCommand, type PlayruoEmbedMessage, type PlayruoEmbedProps, type PlayruoEmbedRenderState, type PlayruoEmbedState, type PlayruoErrorMessage, type PlayruoPurchaseRequestMessage, type PlayruoReadyMessage, type PlayruoStateUpdateMessage, type TryNowCommand, buildEmbedUrl, isPlayruoEmbedCommand, isPlayruoEmbedMessage };
|
package/dist/index.js
CHANGED
|
@@ -67,7 +67,7 @@ var PlayruoEmbed = ({
|
|
|
67
67
|
status: "Ready"
|
|
68
68
|
}
|
|
69
69
|
}), [hasPlayedOnce, isCompatible]);
|
|
70
|
-
const checkKeyboardLockPermission = async () => {
|
|
70
|
+
const checkKeyboardLockPermission = useCallback(async () => {
|
|
71
71
|
if (!navigator.permissions) {
|
|
72
72
|
console.log("[PlayruoEmbed] Permissions API not supported");
|
|
73
73
|
return false;
|
|
@@ -86,8 +86,8 @@ var PlayruoEmbed = ({
|
|
|
86
86
|
console.warn("[PlayruoEmbed] Error checking keyboard lock permission:", error);
|
|
87
87
|
return false;
|
|
88
88
|
}
|
|
89
|
-
};
|
|
90
|
-
const requestFullscreenWithKeyboardLock = async () => {
|
|
89
|
+
}, []);
|
|
90
|
+
const requestFullscreenWithKeyboardLock = useCallback(async () => {
|
|
91
91
|
const iframe = iframeRef.current;
|
|
92
92
|
if (!iframe?.requestFullscreen) {
|
|
93
93
|
console.log("[PlayruoEmbed] Fullscreen not supported on this browser");
|
|
@@ -95,18 +95,30 @@ var PlayruoEmbed = ({
|
|
|
95
95
|
}
|
|
96
96
|
try {
|
|
97
97
|
const fullscreenPromise = iframe.requestFullscreen();
|
|
98
|
-
if (navigator.keyboard) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
98
|
+
if (navigator.keyboard && window.self === window.top) {
|
|
99
|
+
try {
|
|
100
|
+
const permissionPromise = checkKeyboardLockPermission();
|
|
101
|
+
const keyboardLockPromise = navigator.keyboard.lock(["Escape"]);
|
|
102
|
+
void Promise.all([permissionPromise, keyboardLockPromise]).then(([hasPermission]) => {
|
|
103
|
+
if (hasPermission) {
|
|
104
|
+
console.log("[PlayruoEmbed] Keyboard locked successfully");
|
|
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);
|
|
104
116
|
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
});
|
|
108
|
-
} else {
|
|
117
|
+
}
|
|
118
|
+
} else if (!navigator.keyboard) {
|
|
109
119
|
console.log("[PlayruoEmbed] Keyboard API not supported");
|
|
120
|
+
} else {
|
|
121
|
+
console.log("[PlayruoEmbed] Keyboard lock not available (not in top-level context)");
|
|
110
122
|
}
|
|
111
123
|
void fullscreenPromise.then(() => {
|
|
112
124
|
console.log("[PlayruoEmbed] Fullscreen activated successfully");
|
|
@@ -118,7 +130,7 @@ var PlayruoEmbed = ({
|
|
|
118
130
|
console.error("[PlayruoEmbed] Error requesting fullscreen:", error);
|
|
119
131
|
return false;
|
|
120
132
|
}
|
|
121
|
-
};
|
|
133
|
+
}, [iframeRef, checkKeyboardLockPermission]);
|
|
122
134
|
const handleTryNow = useCallback(() => {
|
|
123
135
|
if (!isCompatible) {
|
|
124
136
|
console.warn("[PlayruoEmbed] Browser not compatible");
|
|
@@ -131,6 +143,13 @@ var PlayruoEmbed = ({
|
|
|
131
143
|
}
|
|
132
144
|
setShowGameIframe(true);
|
|
133
145
|
try {
|
|
146
|
+
const el = iframeRef.current;
|
|
147
|
+
if (el) {
|
|
148
|
+
try {
|
|
149
|
+
el.focus();
|
|
150
|
+
} catch {
|
|
151
|
+
}
|
|
152
|
+
}
|
|
134
153
|
requestFullscreenWithKeyboardLock();
|
|
135
154
|
iframe.contentWindow?.postMessage({
|
|
136
155
|
type: "playruo",
|
|
@@ -150,7 +169,7 @@ var PlayruoEmbed = ({
|
|
|
150
169
|
setErrorMessage("Failed to start game");
|
|
151
170
|
onError?.("Failed to start game");
|
|
152
171
|
}
|
|
153
|
-
}, [isCompatible, hasPlayedOnce, onError, iframeRef]);
|
|
172
|
+
}, [isCompatible, hasPlayedOnce, onError, iframeRef, requestFullscreenWithKeyboardLock]);
|
|
154
173
|
const handleBuyNow = useCallback(() => {
|
|
155
174
|
if (!storeUrl) {
|
|
156
175
|
console.warn("[PlayruoEmbed] No store URL provided");
|
|
@@ -200,6 +219,7 @@ var PlayruoEmbed = ({
|
|
|
200
219
|
clearTimeout(escapeKeyTimer.current);
|
|
201
220
|
escapeKeyTimer.current = null;
|
|
202
221
|
}
|
|
222
|
+
setShowGameIframe(false);
|
|
203
223
|
setHasPlayedOnce(true);
|
|
204
224
|
onDemoCompleted?.({
|
|
205
225
|
reason: "Demo session ended",
|
|
@@ -256,12 +276,96 @@ var PlayruoEmbed = ({
|
|
|
256
276
|
};
|
|
257
277
|
}, []);
|
|
258
278
|
useEffect(() => {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
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 {
|
|
263
289
|
}
|
|
264
|
-
}, []);
|
|
290
|
+
}, [showGameIframe, showIframe, isIframeLoaded, iframeRef]);
|
|
291
|
+
useEffect(() => {
|
|
292
|
+
const logCrossOriginStatus = () => {
|
|
293
|
+
const isIsolated = self.crossOriginIsolated;
|
|
294
|
+
const hasSharedArrayBuffer = typeof SharedArrayBuffer !== "undefined";
|
|
295
|
+
const hasHighResTime = typeof performance !== "undefined" && typeof performance.now === "function";
|
|
296
|
+
console.group("[PlayruoEmbed] \u{1F512} Cross-Origin Isolation Status");
|
|
297
|
+
if (isIsolated) {
|
|
298
|
+
console.log("\u2705 Cross-origin isolation: ENABLED");
|
|
299
|
+
console.log("\u2705 SharedArrayBuffer support:", hasSharedArrayBuffer ? "Available" : "Not available");
|
|
300
|
+
console.log("\u2705 High-resolution timers:", hasHighResTime ? "Available" : "Not available");
|
|
301
|
+
console.log("\u{1F3AE} Game performance: Optimal");
|
|
302
|
+
} else {
|
|
303
|
+
console.warn("\u26A0\uFE0F Cross-origin isolation: DISABLED");
|
|
304
|
+
console.warn("\u26A0\uFE0F SharedArrayBuffer support:", hasSharedArrayBuffer ? "Available" : "Not available");
|
|
305
|
+
console.warn("\u26A0\uFE0F High-resolution timers:", hasHighResTime ? "Available" : "Not available");
|
|
306
|
+
console.warn("\u{1F3AE} Game performance: May be degraded");
|
|
307
|
+
console.group("\u{1F4CB} Setup Instructions:");
|
|
308
|
+
console.log("Add these headers to your server:");
|
|
309
|
+
console.log(" Cross-Origin-Opener-Policy: same-origin");
|
|
310
|
+
console.log(" Cross-Origin-Embedder-Policy: credentialless");
|
|
311
|
+
console.groupEnd();
|
|
312
|
+
console.group("\u{1F527} Framework-specific setup:");
|
|
313
|
+
console.log("Next.js (next.config.js):");
|
|
314
|
+
console.log(`const nextConfig = {
|
|
315
|
+
async headers() {
|
|
316
|
+
return [
|
|
317
|
+
{
|
|
318
|
+
source: '/:path*',
|
|
319
|
+
headers: [
|
|
320
|
+
{ key: 'Cross-Origin-Opener-Policy', value: 'same-origin' },
|
|
321
|
+
{ key: 'Cross-Origin-Embedder-Policy', value: 'credentialless' }
|
|
322
|
+
]
|
|
323
|
+
}
|
|
324
|
+
];
|
|
325
|
+
}
|
|
326
|
+
};`);
|
|
327
|
+
console.log("Vite (vite.config.ts):");
|
|
328
|
+
console.log(`export default defineConfig({
|
|
329
|
+
server: {
|
|
330
|
+
headers: {
|
|
331
|
+
'Cross-Origin-Opener-Policy': 'same-origin',
|
|
332
|
+
'Cross-Origin-Embedder-Policy': 'credentialless'
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
});`);
|
|
336
|
+
console.log("Express.js:");
|
|
337
|
+
console.log(`app.use((req, res, next) => {
|
|
338
|
+
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
|
|
339
|
+
res.setHeader('Cross-Origin-Embedder-Policy', 'credentialless');
|
|
340
|
+
next();
|
|
341
|
+
});`);
|
|
342
|
+
console.groupEnd();
|
|
343
|
+
console.group("\u{1F50D} Debug Information:");
|
|
344
|
+
console.log("Current origin:", window.location.origin);
|
|
345
|
+
console.log("Protocol:", window.location.protocol);
|
|
346
|
+
console.log("User agent:", navigator.userAgent);
|
|
347
|
+
console.log("Available APIs:", {
|
|
348
|
+
SharedArrayBuffer: hasSharedArrayBuffer,
|
|
349
|
+
Performance: hasHighResTime,
|
|
350
|
+
WebGL: !!document.createElement("canvas").getContext("webgl"),
|
|
351
|
+
WebGL2: !!document.createElement("canvas").getContext("webgl2"),
|
|
352
|
+
WebAssembly: typeof WebAssembly !== "undefined"
|
|
353
|
+
});
|
|
354
|
+
console.groupEnd();
|
|
355
|
+
}
|
|
356
|
+
console.groupEnd();
|
|
357
|
+
if (isIsolated) {
|
|
358
|
+
console.log("[PlayruoEmbed] \u{1F680} All performance features available - optimal gaming experience!");
|
|
359
|
+
} else {
|
|
360
|
+
console.warn("[PlayruoEmbed] \u26A0\uFE0F Some features may not work optimally without cross-origin isolation");
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
logCrossOriginStatus();
|
|
364
|
+
if (isReady) {
|
|
365
|
+
console.log("[PlayruoEmbed] \u{1F4CA} Final status check:");
|
|
366
|
+
logCrossOriginStatus();
|
|
367
|
+
}
|
|
368
|
+
}, [isReady]);
|
|
265
369
|
const isAvailable = Boolean(isReady && isCompatible);
|
|
266
370
|
const renderContent = () => {
|
|
267
371
|
if (!renderState) return null;
|
|
@@ -299,13 +403,12 @@ var PlayruoEmbed = ({
|
|
|
299
403
|
title: "Playruo",
|
|
300
404
|
referrerPolicy: "strict-origin-when-cross-origin",
|
|
301
405
|
style: {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
pointerEvents: showIframe ? "auto" : "none"
|
|
406
|
+
// Only mounted when compatible; visible after click (internal) or if parent explicitly asks
|
|
407
|
+
opacity: showGameIframe || showIframe ? 1 : 0,
|
|
408
|
+
pointerEvents: showGameIframe || showIframe ? "auto" : "none",
|
|
409
|
+
width: "100%",
|
|
410
|
+
height: "100%",
|
|
411
|
+
border: 0
|
|
309
412
|
},
|
|
310
413
|
onLoad: () => {
|
|
311
414
|
setIsIframeLoaded(true);
|
|
@@ -326,6 +429,361 @@ var PlayruoEmbed = ({
|
|
|
326
429
|
] });
|
|
327
430
|
};
|
|
328
431
|
|
|
432
|
+
// src/react/embed-tester.tsx
|
|
433
|
+
import React, { useCallback as useCallback2, useRef as useRef2, useState as useState2 } from "react";
|
|
434
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
435
|
+
var EmbedTester = (props = {}) => {
|
|
436
|
+
const [operation, setOperation] = useState2(props.operation ?? "iframe");
|
|
437
|
+
const [storeUrl, setStoreUrl] = useState2(
|
|
438
|
+
props.storeUrl ?? "https://store.steampowered.com/app/123456"
|
|
439
|
+
);
|
|
440
|
+
const [key, setKey] = useState2(0);
|
|
441
|
+
const [hasUserClicked, setHasUserClicked] = useState2(false);
|
|
442
|
+
const [showIframe, setShowIframe] = useState2(false);
|
|
443
|
+
const [embedState, setEmbedState] = useState2({
|
|
444
|
+
buyNow: { available: false, status: "Not ready" },
|
|
445
|
+
hasPlayedOnce: false,
|
|
446
|
+
isReady: false,
|
|
447
|
+
tryNow: { available: false, status: "Not ready" }
|
|
448
|
+
});
|
|
449
|
+
const [eventLog, setEventLog] = useState2([]);
|
|
450
|
+
const [diagnostics, setDiagnostics] = useState2({
|
|
451
|
+
crossOriginIsolation: false,
|
|
452
|
+
gamepadSupported: false,
|
|
453
|
+
fullscreenSupported: false,
|
|
454
|
+
keyboardLockSupported: false
|
|
455
|
+
});
|
|
456
|
+
const baseUrl = props.baseUrl;
|
|
457
|
+
const enableConsoleLog = props.enableConsoleLog ?? false;
|
|
458
|
+
const hasReadyBeenCalled = useRef2(false);
|
|
459
|
+
const previousStateRef = useRef2("");
|
|
460
|
+
const iframeRef = useRef2(null);
|
|
461
|
+
const addEvent = useCallback2(
|
|
462
|
+
(message) => {
|
|
463
|
+
const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString();
|
|
464
|
+
setEventLog((prev) => [...prev.slice(-10), { message, timestamp }]);
|
|
465
|
+
if (enableConsoleLog) {
|
|
466
|
+
console.log(`[EmbedTester] ${timestamp}: ${message}`);
|
|
467
|
+
}
|
|
468
|
+
},
|
|
469
|
+
[enableConsoleLog]
|
|
470
|
+
);
|
|
471
|
+
const runDiagnostics = useCallback2(() => {
|
|
472
|
+
const newDiagnostics = {
|
|
473
|
+
crossOriginIsolation: !!(window.crossOriginIsolated || window.crossOriginIsolated),
|
|
474
|
+
gamepadSupported: "getGamepads" in navigator,
|
|
475
|
+
fullscreenSupported: !!(document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled),
|
|
476
|
+
keyboardLockSupported: "keyboard" in navigator && "lock" in navigator.keyboard
|
|
477
|
+
};
|
|
478
|
+
setDiagnostics(newDiagnostics);
|
|
479
|
+
addEvent(`\u{1F50D} Diagnostics updated - COI: ${newDiagnostics.crossOriginIsolation}, Gamepad: ${newDiagnostics.gamepadSupported}`);
|
|
480
|
+
}, [addEvent]);
|
|
481
|
+
React.useEffect(() => {
|
|
482
|
+
runDiagnostics();
|
|
483
|
+
}, [runDiagnostics]);
|
|
484
|
+
const handleReady = useCallback2(() => {
|
|
485
|
+
if (!hasReadyBeenCalled.current) {
|
|
486
|
+
hasReadyBeenCalled.current = true;
|
|
487
|
+
addEvent("Embed ready");
|
|
488
|
+
setEmbedState((prev) => ({ ...prev, isReady: true }));
|
|
489
|
+
}
|
|
490
|
+
}, [addEvent]);
|
|
491
|
+
const handleStateChange = useCallback2((state) => {
|
|
492
|
+
const stateString = JSON.stringify(state);
|
|
493
|
+
if (stateString !== previousStateRef.current) {
|
|
494
|
+
previousStateRef.current = stateString;
|
|
495
|
+
setEmbedState(state);
|
|
496
|
+
addEvent(`State changed: ${stateString}`);
|
|
497
|
+
}
|
|
498
|
+
}, [addEvent]);
|
|
499
|
+
const handleDemoCompleted = useCallback2((data) => {
|
|
500
|
+
const payload = data;
|
|
501
|
+
addEvent(`\u{1F3AF} Demo completed! Reason: ${payload.reason}`);
|
|
502
|
+
addEvent(`Store URL available for purchase: ${payload.storeUrl}`);
|
|
503
|
+
setShowIframe(false);
|
|
504
|
+
setHasUserClicked(false);
|
|
505
|
+
}, [addEvent]);
|
|
506
|
+
const handleError = useCallback2((error) => {
|
|
507
|
+
addEvent(`Error: ${error}`);
|
|
508
|
+
if (enableConsoleLog) {
|
|
509
|
+
console.error("Embed error:", error);
|
|
510
|
+
}
|
|
511
|
+
}, [addEvent, enableConsoleLog]);
|
|
512
|
+
const handlePurchaseRequest = useCallback2((data) => {
|
|
513
|
+
addEvent(`\u{1F4B3} Explicit purchase request from Buy Now button`);
|
|
514
|
+
addEvent(`Opening store: ${data.storeUrl}`);
|
|
515
|
+
window.open(data.storeUrl, "_blank");
|
|
516
|
+
}, [addEvent]);
|
|
517
|
+
const handleRestart = useCallback2(() => {
|
|
518
|
+
setKey((prev) => prev + 1);
|
|
519
|
+
setHasUserClicked(false);
|
|
520
|
+
setShowIframe(false);
|
|
521
|
+
hasReadyBeenCalled.current = false;
|
|
522
|
+
previousStateRef.current = "";
|
|
523
|
+
addEvent("Embed restarted");
|
|
524
|
+
}, [addEvent]);
|
|
525
|
+
const buttonStyle = {
|
|
526
|
+
padding: "8px 16px",
|
|
527
|
+
margin: "4px",
|
|
528
|
+
border: "1px solid #404040",
|
|
529
|
+
borderRadius: "4px",
|
|
530
|
+
backgroundColor: "#2a2a2a",
|
|
531
|
+
color: "#e5e5e5",
|
|
532
|
+
cursor: "pointer",
|
|
533
|
+
fontSize: "14px",
|
|
534
|
+
transition: "all 0.2s ease"
|
|
535
|
+
};
|
|
536
|
+
const inputStyle = {
|
|
537
|
+
width: "100%",
|
|
538
|
+
padding: "8px",
|
|
539
|
+
margin: "4px 0",
|
|
540
|
+
border: "1px solid #404040",
|
|
541
|
+
borderRadius: "4px",
|
|
542
|
+
backgroundColor: "#1a1a1a",
|
|
543
|
+
color: "#e5e5e5",
|
|
544
|
+
fontSize: "14px"
|
|
545
|
+
};
|
|
546
|
+
const cardStyle = {
|
|
547
|
+
border: "1px solid #333333",
|
|
548
|
+
borderRadius: "8px",
|
|
549
|
+
padding: "16px",
|
|
550
|
+
margin: "8px 0",
|
|
551
|
+
backgroundColor: "#1a1a1a"
|
|
552
|
+
};
|
|
553
|
+
const statusStyle = {
|
|
554
|
+
display: "inline-block",
|
|
555
|
+
padding: "4px 8px",
|
|
556
|
+
margin: "2px",
|
|
557
|
+
borderRadius: "12px",
|
|
558
|
+
fontSize: "12px",
|
|
559
|
+
fontWeight: "500"
|
|
560
|
+
};
|
|
561
|
+
const successStatus = { ...statusStyle, backgroundColor: "#0d5d1f", color: "#4ade80" };
|
|
562
|
+
const errorStatus = { ...statusStyle, backgroundColor: "#5d1a1a", color: "#f87171" };
|
|
563
|
+
return /* @__PURE__ */ jsx2("div", { className: props.className, style: { minHeight: "100vh", padding: "20px", backgroundColor: "#000000", color: "#e5e5e5" }, children: /* @__PURE__ */ jsxs2("div", { style: { maxWidth: "1200px", margin: "0 auto" }, children: [
|
|
564
|
+
/* @__PURE__ */ jsx2("h1", { style: { marginBottom: "20px", fontSize: "24px", fontWeight: "bold", color: "#ffffff" }, children: "\u{1F9EA} Playruo Embed Tester" }),
|
|
565
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "20px" }, children: [
|
|
566
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
567
|
+
/* @__PURE__ */ jsxs2("div", { style: cardStyle, children: [
|
|
568
|
+
/* @__PURE__ */ jsx2("h3", { style: { margin: "0 0 16px 0", fontSize: "18px", fontWeight: "600", color: "#ffffff" }, children: "Test Controls" }),
|
|
569
|
+
/* @__PURE__ */ jsxs2("div", { style: { marginBottom: "12px" }, children: [
|
|
570
|
+
/* @__PURE__ */ jsx2("label", { htmlFor: "operation", style: { display: "block", marginBottom: "4px", fontWeight: "500", color: "#d4d4d4" }, children: "Operation" }),
|
|
571
|
+
/* @__PURE__ */ jsx2(
|
|
572
|
+
"input",
|
|
573
|
+
{
|
|
574
|
+
style: inputStyle,
|
|
575
|
+
onChange: (e) => setOperation(e.target.value),
|
|
576
|
+
placeholder: "e.g., iframe",
|
|
577
|
+
value: operation
|
|
578
|
+
}
|
|
579
|
+
)
|
|
580
|
+
] }),
|
|
581
|
+
/* @__PURE__ */ jsxs2("div", { style: { marginBottom: "12px" }, children: [
|
|
582
|
+
/* @__PURE__ */ jsx2("label", { htmlFor: "storeUrl", style: { display: "block", marginBottom: "4px", fontWeight: "500", color: "#d4d4d4" }, children: "Store URL" }),
|
|
583
|
+
/* @__PURE__ */ jsx2(
|
|
584
|
+
"input",
|
|
585
|
+
{
|
|
586
|
+
style: inputStyle,
|
|
587
|
+
onChange: (e) => setStoreUrl(e.target.value),
|
|
588
|
+
placeholder: "https://store.example.com",
|
|
589
|
+
value: storeUrl
|
|
590
|
+
}
|
|
591
|
+
)
|
|
592
|
+
] }),
|
|
593
|
+
/* @__PURE__ */ jsx2(
|
|
594
|
+
"button",
|
|
595
|
+
{
|
|
596
|
+
type: "button",
|
|
597
|
+
style: {
|
|
598
|
+
...buttonStyle,
|
|
599
|
+
backgroundColor: "#0066cc",
|
|
600
|
+
color: "#ffffff",
|
|
601
|
+
border: "none",
|
|
602
|
+
fontWeight: "600"
|
|
603
|
+
},
|
|
604
|
+
onClick: handleRestart,
|
|
605
|
+
onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "#0052a3",
|
|
606
|
+
onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "#0066cc",
|
|
607
|
+
children: "\u{1F504} Restart Embed"
|
|
608
|
+
}
|
|
609
|
+
)
|
|
610
|
+
] }),
|
|
611
|
+
/* @__PURE__ */ jsxs2("div", { style: cardStyle, children: [
|
|
612
|
+
/* @__PURE__ */ jsx2("h3", { style: { margin: "0 0 16px 0", fontSize: "18px", fontWeight: "600", color: "#ffffff" }, children: "Status" }),
|
|
613
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
614
|
+
/* @__PURE__ */ jsx2("span", { style: embedState.isReady ? successStatus : errorStatus, children: embedState.isReady ? "\u2705 Ready" : "\u274C Not Ready" }),
|
|
615
|
+
/* @__PURE__ */ jsx2("span", { style: embedState.hasPlayedOnce ? successStatus : errorStatus, children: embedState.hasPlayedOnce ? "\u2705 Played" : "\u274C Not Played" }),
|
|
616
|
+
/* @__PURE__ */ jsx2("span", { style: embedState.tryNow?.available ? successStatus : errorStatus, children: embedState.tryNow?.available ? "\u2705 Try Now" : "\u274C Try Now" }),
|
|
617
|
+
/* @__PURE__ */ jsx2("span", { style: embedState.buyNow?.available ? successStatus : errorStatus, children: embedState.buyNow?.available ? "\u2705 Buy Now" : "\u274C Buy Now" })
|
|
618
|
+
] })
|
|
619
|
+
] }),
|
|
620
|
+
/* @__PURE__ */ jsxs2("div", { style: cardStyle, children: [
|
|
621
|
+
/* @__PURE__ */ jsx2("h3", { style: { margin: "0 0 16px 0", fontSize: "18px", fontWeight: "600", color: "#ffffff" }, children: "\u{1F50D} Browser Diagnostics" }),
|
|
622
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
|
|
623
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
624
|
+
/* @__PURE__ */ jsx2("span", { style: diagnostics.crossOriginIsolation ? successStatus : errorStatus, children: diagnostics.crossOriginIsolation ? "\u2705" : "\u274C" }),
|
|
625
|
+
/* @__PURE__ */ jsx2("span", { style: { fontSize: "12px", color: "#d4d4d4" }, children: "Cross-Origin Isolation" })
|
|
626
|
+
] }),
|
|
627
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
628
|
+
/* @__PURE__ */ jsx2("span", { style: diagnostics.gamepadSupported ? successStatus : errorStatus, children: diagnostics.gamepadSupported ? "\u2705" : "\u274C" }),
|
|
629
|
+
/* @__PURE__ */ jsx2("span", { style: { fontSize: "12px", color: "#d4d4d4" }, children: "Gamepad API" })
|
|
630
|
+
] }),
|
|
631
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
632
|
+
/* @__PURE__ */ jsx2("span", { style: diagnostics.fullscreenSupported ? successStatus : errorStatus, children: diagnostics.fullscreenSupported ? "\u2705" : "\u274C" }),
|
|
633
|
+
/* @__PURE__ */ jsx2("span", { style: { fontSize: "12px", color: "#d4d4d4" }, children: "Fullscreen API" })
|
|
634
|
+
] }),
|
|
635
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
636
|
+
/* @__PURE__ */ jsx2("span", { style: diagnostics.keyboardLockSupported ? successStatus : errorStatus, children: diagnostics.keyboardLockSupported ? "\u2705" : "\u274C" }),
|
|
637
|
+
/* @__PURE__ */ jsx2("span", { style: { fontSize: "12px", color: "#d4d4d4" }, children: "Keyboard Lock" })
|
|
638
|
+
] })
|
|
639
|
+
] })
|
|
640
|
+
] }),
|
|
641
|
+
/* @__PURE__ */ jsxs2("div", { style: cardStyle, children: [
|
|
642
|
+
/* @__PURE__ */ jsx2("h3", { style: { margin: "0 0 16px 0", fontSize: "18px", fontWeight: "600", color: "#ffffff" }, children: "Event Log" }),
|
|
643
|
+
/* @__PURE__ */ jsx2("div", { style: {
|
|
644
|
+
backgroundColor: "#0a0a0a",
|
|
645
|
+
padding: "12px",
|
|
646
|
+
borderRadius: "4px",
|
|
647
|
+
height: "200px",
|
|
648
|
+
overflowY: "auto",
|
|
649
|
+
fontFamily: "monospace",
|
|
650
|
+
fontSize: "12px",
|
|
651
|
+
border: "1px solid #333333"
|
|
652
|
+
}, children: eventLog.length ? /* @__PURE__ */ jsx2("div", { children: eventLog.map((event) => /* @__PURE__ */ jsxs2("div", { style: { marginBottom: "4px" }, children: [
|
|
653
|
+
/* @__PURE__ */ jsxs2("span", { style: { color: "#737373" }, children: [
|
|
654
|
+
"[",
|
|
655
|
+
event.timestamp,
|
|
656
|
+
"]"
|
|
657
|
+
] }),
|
|
658
|
+
" ",
|
|
659
|
+
/* @__PURE__ */ jsx2("span", { style: { color: "#e5e5e5" }, children: event.message })
|
|
660
|
+
] }, event.timestamp)) }) : /* @__PURE__ */ jsx2("div", { style: { color: "#737373" }, children: "No events yet..." }) })
|
|
661
|
+
] })
|
|
662
|
+
] }),
|
|
663
|
+
/* @__PURE__ */ jsx2("div", { children: /* @__PURE__ */ jsxs2("div", { style: cardStyle, children: [
|
|
664
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "16px" }, children: [
|
|
665
|
+
/* @__PURE__ */ jsx2("h3", { style: { margin: "0", fontSize: "18px", fontWeight: "600", color: "#ffffff" }, children: "Embed Container" }),
|
|
666
|
+
/* @__PURE__ */ jsxs2("span", { style: {
|
|
667
|
+
backgroundColor: "#2a2a2a",
|
|
668
|
+
color: "#e5e5e5",
|
|
669
|
+
padding: "4px 8px",
|
|
670
|
+
borderRadius: "12px",
|
|
671
|
+
fontSize: "12px",
|
|
672
|
+
fontWeight: "500",
|
|
673
|
+
border: "1px solid #404040"
|
|
674
|
+
}, children: [
|
|
675
|
+
"\u{1F9EA} ",
|
|
676
|
+
baseUrl ? new URL(baseUrl).host : "localhost:3000"
|
|
677
|
+
] })
|
|
678
|
+
] }),
|
|
679
|
+
/* @__PURE__ */ jsx2("div", { style: {
|
|
680
|
+
position: "relative",
|
|
681
|
+
minHeight: "500px",
|
|
682
|
+
overflow: "hidden",
|
|
683
|
+
borderRadius: "8px",
|
|
684
|
+
border: "1px solid #333333",
|
|
685
|
+
backgroundColor: "#0a0a0a"
|
|
686
|
+
}, children: /* @__PURE__ */ jsx2(
|
|
687
|
+
PlayruoEmbed,
|
|
688
|
+
{
|
|
689
|
+
baseUrl: baseUrl || "",
|
|
690
|
+
className: "w-full h-full absolute inset-0",
|
|
691
|
+
iframeRef,
|
|
692
|
+
onDemoCompleted: handleDemoCompleted,
|
|
693
|
+
onError: handleError,
|
|
694
|
+
onPurchaseRequest: handlePurchaseRequest,
|
|
695
|
+
onReady: handleReady,
|
|
696
|
+
onStateChange: handleStateChange,
|
|
697
|
+
operation,
|
|
698
|
+
renderState: ({ actions, message, status }) => /* @__PURE__ */ jsx2(Fragment, { children: !hasUserClicked && /* @__PURE__ */ jsxs2("div", { style: {
|
|
699
|
+
position: "absolute",
|
|
700
|
+
inset: "0",
|
|
701
|
+
display: "flex",
|
|
702
|
+
flexDirection: "column",
|
|
703
|
+
alignItems: "center",
|
|
704
|
+
justifyContent: "center",
|
|
705
|
+
gap: "16px",
|
|
706
|
+
backgroundColor: "rgba(0, 0, 0, 0.85)",
|
|
707
|
+
backdropFilter: "blur(8px)",
|
|
708
|
+
zIndex: 50,
|
|
709
|
+
padding: "20px"
|
|
710
|
+
}, children: [
|
|
711
|
+
/* @__PURE__ */ jsxs2("p", { style: { margin: "0", fontSize: "14px", color: "#d4d4d4" }, children: [
|
|
712
|
+
"Status: ",
|
|
713
|
+
/* @__PURE__ */ jsx2("span", { style: { color: "#ffffff", fontWeight: "600" }, children: status })
|
|
714
|
+
] }),
|
|
715
|
+
message && /* @__PURE__ */ jsx2("p", { style: { margin: "0", fontSize: "14px", color: "#d4d4d4" }, children: message }),
|
|
716
|
+
/* @__PURE__ */ jsxs2(
|
|
717
|
+
"button",
|
|
718
|
+
{
|
|
719
|
+
type: "button",
|
|
720
|
+
style: {
|
|
721
|
+
...buttonStyle,
|
|
722
|
+
backgroundColor: "#16a34a",
|
|
723
|
+
color: "#ffffff",
|
|
724
|
+
border: "none",
|
|
725
|
+
padding: "12px 24px",
|
|
726
|
+
fontSize: "16px",
|
|
727
|
+
fontWeight: "600",
|
|
728
|
+
cursor: actions.canTryNow ? "pointer" : "not-allowed",
|
|
729
|
+
opacity: actions.canTryNow ? 1 : 0.5
|
|
730
|
+
},
|
|
731
|
+
disabled: !actions.canTryNow,
|
|
732
|
+
onMouseEnter: (e) => {
|
|
733
|
+
if (actions.canTryNow) {
|
|
734
|
+
e.currentTarget.style.backgroundColor = "#15803d";
|
|
735
|
+
}
|
|
736
|
+
},
|
|
737
|
+
onMouseLeave: (e) => {
|
|
738
|
+
if (actions.canTryNow) {
|
|
739
|
+
e.currentTarget.style.backgroundColor = "#16a34a";
|
|
740
|
+
}
|
|
741
|
+
},
|
|
742
|
+
onClick: () => {
|
|
743
|
+
setHasUserClicked(true);
|
|
744
|
+
setShowIframe(true);
|
|
745
|
+
addEvent(embedState.hasPlayedOnce ? "User clicked - Resuming game" : "User clicked - Starting game with tryNow");
|
|
746
|
+
actions.tryNow();
|
|
747
|
+
},
|
|
748
|
+
children: [
|
|
749
|
+
"\u{1F3AE} ",
|
|
750
|
+
embedState.hasPlayedOnce ? "Resume Game" : "Try Demo Now"
|
|
751
|
+
]
|
|
752
|
+
}
|
|
753
|
+
),
|
|
754
|
+
actions.canBuyNow && /* @__PURE__ */ jsx2(
|
|
755
|
+
"button",
|
|
756
|
+
{
|
|
757
|
+
type: "button",
|
|
758
|
+
style: {
|
|
759
|
+
...buttonStyle,
|
|
760
|
+
backgroundColor: "#525252",
|
|
761
|
+
color: "#ffffff",
|
|
762
|
+
border: "none",
|
|
763
|
+
padding: "8px 16px",
|
|
764
|
+
fontSize: "14px",
|
|
765
|
+
fontWeight: "500"
|
|
766
|
+
},
|
|
767
|
+
onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "#404040",
|
|
768
|
+
onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "#525252",
|
|
769
|
+
onClick: () => {
|
|
770
|
+
addEvent("Buy Now clicked");
|
|
771
|
+
actions.buyNow();
|
|
772
|
+
},
|
|
773
|
+
children: "Buy Now"
|
|
774
|
+
}
|
|
775
|
+
)
|
|
776
|
+
] }) }),
|
|
777
|
+
showIframe,
|
|
778
|
+
storeUrl
|
|
779
|
+
},
|
|
780
|
+
key
|
|
781
|
+
) })
|
|
782
|
+
] }) })
|
|
783
|
+
] })
|
|
784
|
+
] }) });
|
|
785
|
+
};
|
|
786
|
+
|
|
329
787
|
// src/post-message-types.ts
|
|
330
788
|
var isPlayruoEmbedMessage = (data) => {
|
|
331
789
|
if (!data || typeof data !== "object") return false;
|
|
@@ -340,6 +798,7 @@ var isPlayruoEmbedCommand = (data) => {
|
|
|
340
798
|
return cmd.type === "try_now" || cmd.type === "buy_now" || cmd.type === "get_state";
|
|
341
799
|
};
|
|
342
800
|
export {
|
|
801
|
+
EmbedTester,
|
|
343
802
|
PlayruoEmbed,
|
|
344
803
|
buildEmbedUrl,
|
|
345
804
|
isPlayruoEmbedCommand,
|