@playruo/embed 1.2.0 → 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 +500 -28
- package/dist/index.d.cts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +489 -28
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,11 +17,20 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
21
31
|
var index_exports = {};
|
|
22
32
|
__export(index_exports, {
|
|
33
|
+
EmbedTester: () => EmbedTester,
|
|
23
34
|
PlayruoEmbed: () => PlayruoEmbed,
|
|
24
35
|
buildEmbedUrl: () => buildEmbedUrl,
|
|
25
36
|
isPlayruoEmbedCommand: () => isPlayruoEmbedCommand,
|
|
@@ -96,7 +107,7 @@ var PlayruoEmbed = ({
|
|
|
96
107
|
status: "Ready"
|
|
97
108
|
}
|
|
98
109
|
}), [hasPlayedOnce, isCompatible]);
|
|
99
|
-
const checkKeyboardLockPermission = async () => {
|
|
110
|
+
const checkKeyboardLockPermission = (0, import_react.useCallback)(async () => {
|
|
100
111
|
if (!navigator.permissions) {
|
|
101
112
|
console.log("[PlayruoEmbed] Permissions API not supported");
|
|
102
113
|
return false;
|
|
@@ -115,8 +126,8 @@ var PlayruoEmbed = ({
|
|
|
115
126
|
console.warn("[PlayruoEmbed] Error checking keyboard lock permission:", error);
|
|
116
127
|
return false;
|
|
117
128
|
}
|
|
118
|
-
};
|
|
119
|
-
const requestFullscreenWithKeyboardLock = async () => {
|
|
129
|
+
}, []);
|
|
130
|
+
const requestFullscreenWithKeyboardLock = (0, import_react.useCallback)(async () => {
|
|
120
131
|
const iframe = iframeRef.current;
|
|
121
132
|
if (!iframe?.requestFullscreen) {
|
|
122
133
|
console.log("[PlayruoEmbed] Fullscreen not supported on this browser");
|
|
@@ -124,18 +135,30 @@ var PlayruoEmbed = ({
|
|
|
124
135
|
}
|
|
125
136
|
try {
|
|
126
137
|
const fullscreenPromise = iframe.requestFullscreen();
|
|
127
|
-
if (navigator.keyboard) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
138
|
+
if (navigator.keyboard && window.self === window.top) {
|
|
139
|
+
try {
|
|
140
|
+
const permissionPromise = checkKeyboardLockPermission();
|
|
141
|
+
const keyboardLockPromise = navigator.keyboard.lock(["Escape"]);
|
|
142
|
+
void Promise.all([permissionPromise, keyboardLockPromise]).then(([hasPermission]) => {
|
|
143
|
+
if (hasPermission) {
|
|
144
|
+
console.log("[PlayruoEmbed] Keyboard locked successfully");
|
|
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);
|
|
133
156
|
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
});
|
|
137
|
-
} else {
|
|
157
|
+
}
|
|
158
|
+
} else if (!navigator.keyboard) {
|
|
138
159
|
console.log("[PlayruoEmbed] Keyboard API not supported");
|
|
160
|
+
} else {
|
|
161
|
+
console.log("[PlayruoEmbed] Keyboard lock not available (not in top-level context)");
|
|
139
162
|
}
|
|
140
163
|
void fullscreenPromise.then(() => {
|
|
141
164
|
console.log("[PlayruoEmbed] Fullscreen activated successfully");
|
|
@@ -147,7 +170,7 @@ var PlayruoEmbed = ({
|
|
|
147
170
|
console.error("[PlayruoEmbed] Error requesting fullscreen:", error);
|
|
148
171
|
return false;
|
|
149
172
|
}
|
|
150
|
-
};
|
|
173
|
+
}, [iframeRef, checkKeyboardLockPermission]);
|
|
151
174
|
const handleTryNow = (0, import_react.useCallback)(() => {
|
|
152
175
|
if (!isCompatible) {
|
|
153
176
|
console.warn("[PlayruoEmbed] Browser not compatible");
|
|
@@ -160,6 +183,13 @@ var PlayruoEmbed = ({
|
|
|
160
183
|
}
|
|
161
184
|
setShowGameIframe(true);
|
|
162
185
|
try {
|
|
186
|
+
const el = iframeRef.current;
|
|
187
|
+
if (el) {
|
|
188
|
+
try {
|
|
189
|
+
el.focus();
|
|
190
|
+
} catch {
|
|
191
|
+
}
|
|
192
|
+
}
|
|
163
193
|
requestFullscreenWithKeyboardLock();
|
|
164
194
|
iframe.contentWindow?.postMessage({
|
|
165
195
|
type: "playruo",
|
|
@@ -179,7 +209,7 @@ var PlayruoEmbed = ({
|
|
|
179
209
|
setErrorMessage("Failed to start game");
|
|
180
210
|
onError?.("Failed to start game");
|
|
181
211
|
}
|
|
182
|
-
}, [isCompatible, hasPlayedOnce, onError, iframeRef]);
|
|
212
|
+
}, [isCompatible, hasPlayedOnce, onError, iframeRef, requestFullscreenWithKeyboardLock]);
|
|
183
213
|
const handleBuyNow = (0, import_react.useCallback)(() => {
|
|
184
214
|
if (!storeUrl) {
|
|
185
215
|
console.warn("[PlayruoEmbed] No store URL provided");
|
|
@@ -229,6 +259,7 @@ var PlayruoEmbed = ({
|
|
|
229
259
|
clearTimeout(escapeKeyTimer.current);
|
|
230
260
|
escapeKeyTimer.current = null;
|
|
231
261
|
}
|
|
262
|
+
setShowGameIframe(false);
|
|
232
263
|
setHasPlayedOnce(true);
|
|
233
264
|
onDemoCompleted?.({
|
|
234
265
|
reason: "Demo session ended",
|
|
@@ -285,12 +316,96 @@ var PlayruoEmbed = ({
|
|
|
285
316
|
};
|
|
286
317
|
}, []);
|
|
287
318
|
(0, import_react.useEffect)(() => {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
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 {
|
|
292
329
|
}
|
|
293
|
-
}, []);
|
|
330
|
+
}, [showGameIframe, showIframe, isIframeLoaded, iframeRef]);
|
|
331
|
+
(0, import_react.useEffect)(() => {
|
|
332
|
+
const logCrossOriginStatus = () => {
|
|
333
|
+
const isIsolated = self.crossOriginIsolated;
|
|
334
|
+
const hasSharedArrayBuffer = typeof SharedArrayBuffer !== "undefined";
|
|
335
|
+
const hasHighResTime = typeof performance !== "undefined" && typeof performance.now === "function";
|
|
336
|
+
console.group("[PlayruoEmbed] \u{1F512} Cross-Origin Isolation Status");
|
|
337
|
+
if (isIsolated) {
|
|
338
|
+
console.log("\u2705 Cross-origin isolation: ENABLED");
|
|
339
|
+
console.log("\u2705 SharedArrayBuffer support:", hasSharedArrayBuffer ? "Available" : "Not available");
|
|
340
|
+
console.log("\u2705 High-resolution timers:", hasHighResTime ? "Available" : "Not available");
|
|
341
|
+
console.log("\u{1F3AE} Game performance: Optimal");
|
|
342
|
+
} else {
|
|
343
|
+
console.warn("\u26A0\uFE0F Cross-origin isolation: DISABLED");
|
|
344
|
+
console.warn("\u26A0\uFE0F SharedArrayBuffer support:", hasSharedArrayBuffer ? "Available" : "Not available");
|
|
345
|
+
console.warn("\u26A0\uFE0F High-resolution timers:", hasHighResTime ? "Available" : "Not available");
|
|
346
|
+
console.warn("\u{1F3AE} Game performance: May be degraded");
|
|
347
|
+
console.group("\u{1F4CB} Setup Instructions:");
|
|
348
|
+
console.log("Add these headers to your server:");
|
|
349
|
+
console.log(" Cross-Origin-Opener-Policy: same-origin");
|
|
350
|
+
console.log(" Cross-Origin-Embedder-Policy: credentialless");
|
|
351
|
+
console.groupEnd();
|
|
352
|
+
console.group("\u{1F527} Framework-specific setup:");
|
|
353
|
+
console.log("Next.js (next.config.js):");
|
|
354
|
+
console.log(`const nextConfig = {
|
|
355
|
+
async headers() {
|
|
356
|
+
return [
|
|
357
|
+
{
|
|
358
|
+
source: '/:path*',
|
|
359
|
+
headers: [
|
|
360
|
+
{ key: 'Cross-Origin-Opener-Policy', value: 'same-origin' },
|
|
361
|
+
{ key: 'Cross-Origin-Embedder-Policy', value: 'credentialless' }
|
|
362
|
+
]
|
|
363
|
+
}
|
|
364
|
+
];
|
|
365
|
+
}
|
|
366
|
+
};`);
|
|
367
|
+
console.log("Vite (vite.config.ts):");
|
|
368
|
+
console.log(`export default defineConfig({
|
|
369
|
+
server: {
|
|
370
|
+
headers: {
|
|
371
|
+
'Cross-Origin-Opener-Policy': 'same-origin',
|
|
372
|
+
'Cross-Origin-Embedder-Policy': 'credentialless'
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
});`);
|
|
376
|
+
console.log("Express.js:");
|
|
377
|
+
console.log(`app.use((req, res, next) => {
|
|
378
|
+
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
|
|
379
|
+
res.setHeader('Cross-Origin-Embedder-Policy', 'credentialless');
|
|
380
|
+
next();
|
|
381
|
+
});`);
|
|
382
|
+
console.groupEnd();
|
|
383
|
+
console.group("\u{1F50D} Debug Information:");
|
|
384
|
+
console.log("Current origin:", window.location.origin);
|
|
385
|
+
console.log("Protocol:", window.location.protocol);
|
|
386
|
+
console.log("User agent:", navigator.userAgent);
|
|
387
|
+
console.log("Available APIs:", {
|
|
388
|
+
SharedArrayBuffer: hasSharedArrayBuffer,
|
|
389
|
+
Performance: hasHighResTime,
|
|
390
|
+
WebGL: !!document.createElement("canvas").getContext("webgl"),
|
|
391
|
+
WebGL2: !!document.createElement("canvas").getContext("webgl2"),
|
|
392
|
+
WebAssembly: typeof WebAssembly !== "undefined"
|
|
393
|
+
});
|
|
394
|
+
console.groupEnd();
|
|
395
|
+
}
|
|
396
|
+
console.groupEnd();
|
|
397
|
+
if (isIsolated) {
|
|
398
|
+
console.log("[PlayruoEmbed] \u{1F680} All performance features available - optimal gaming experience!");
|
|
399
|
+
} else {
|
|
400
|
+
console.warn("[PlayruoEmbed] \u26A0\uFE0F Some features may not work optimally without cross-origin isolation");
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
logCrossOriginStatus();
|
|
404
|
+
if (isReady) {
|
|
405
|
+
console.log("[PlayruoEmbed] \u{1F4CA} Final status check:");
|
|
406
|
+
logCrossOriginStatus();
|
|
407
|
+
}
|
|
408
|
+
}, [isReady]);
|
|
294
409
|
const isAvailable = Boolean(isReady && isCompatible);
|
|
295
410
|
const renderContent = () => {
|
|
296
411
|
if (!renderState) return null;
|
|
@@ -320,19 +435,20 @@ var PlayruoEmbed = ({
|
|
|
320
435
|
{
|
|
321
436
|
ref: iframeRef,
|
|
322
437
|
src,
|
|
323
|
-
allow: "fullscreen *; autoplay *; gamepad *; clipboard-write *; web-share *; encrypted-media *; accelerometer *; gyroscope *",
|
|
438
|
+
allow: "cross-origin-isolated; fullscreen *; autoplay *; gamepad *; clipboard-write *; web-share *; encrypted-media *; accelerometer *; gyroscope *",
|
|
439
|
+
allowFullScreen: true,
|
|
324
440
|
className: "w-full h-[70vh] rounded-lg border",
|
|
325
441
|
...{ credentialless: "true" },
|
|
326
442
|
sandbox: "allow-same-origin allow-scripts allow-popups allow-forms allow-presentation allow-top-navigation allow-modals allow-pointer-lock",
|
|
327
443
|
title: "Playruo",
|
|
444
|
+
referrerPolicy: "strict-origin-when-cross-origin",
|
|
328
445
|
style: {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
pointerEvents: showIframe ? "auto" : "none"
|
|
446
|
+
// Only mounted when compatible; visible after click (internal) or if parent explicitly asks
|
|
447
|
+
opacity: showGameIframe || showIframe ? 1 : 0,
|
|
448
|
+
pointerEvents: showGameIframe || showIframe ? "auto" : "none",
|
|
449
|
+
width: "100%",
|
|
450
|
+
height: "100%",
|
|
451
|
+
border: 0
|
|
336
452
|
},
|
|
337
453
|
onLoad: () => {
|
|
338
454
|
setIsIframeLoaded(true);
|
|
@@ -353,6 +469,361 @@ var PlayruoEmbed = ({
|
|
|
353
469
|
] });
|
|
354
470
|
};
|
|
355
471
|
|
|
472
|
+
// src/react/embed-tester.tsx
|
|
473
|
+
var import_react2 = __toESM(require("react"), 1);
|
|
474
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
475
|
+
var EmbedTester = (props = {}) => {
|
|
476
|
+
const [operation, setOperation] = (0, import_react2.useState)(props.operation ?? "iframe");
|
|
477
|
+
const [storeUrl, setStoreUrl] = (0, import_react2.useState)(
|
|
478
|
+
props.storeUrl ?? "https://store.steampowered.com/app/123456"
|
|
479
|
+
);
|
|
480
|
+
const [key, setKey] = (0, import_react2.useState)(0);
|
|
481
|
+
const [hasUserClicked, setHasUserClicked] = (0, import_react2.useState)(false);
|
|
482
|
+
const [showIframe, setShowIframe] = (0, import_react2.useState)(false);
|
|
483
|
+
const [embedState, setEmbedState] = (0, import_react2.useState)({
|
|
484
|
+
buyNow: { available: false, status: "Not ready" },
|
|
485
|
+
hasPlayedOnce: false,
|
|
486
|
+
isReady: false,
|
|
487
|
+
tryNow: { available: false, status: "Not ready" }
|
|
488
|
+
});
|
|
489
|
+
const [eventLog, setEventLog] = (0, import_react2.useState)([]);
|
|
490
|
+
const [diagnostics, setDiagnostics] = (0, import_react2.useState)({
|
|
491
|
+
crossOriginIsolation: false,
|
|
492
|
+
gamepadSupported: false,
|
|
493
|
+
fullscreenSupported: false,
|
|
494
|
+
keyboardLockSupported: false
|
|
495
|
+
});
|
|
496
|
+
const baseUrl = props.baseUrl;
|
|
497
|
+
const enableConsoleLog = props.enableConsoleLog ?? false;
|
|
498
|
+
const hasReadyBeenCalled = (0, import_react2.useRef)(false);
|
|
499
|
+
const previousStateRef = (0, import_react2.useRef)("");
|
|
500
|
+
const iframeRef = (0, import_react2.useRef)(null);
|
|
501
|
+
const addEvent = (0, import_react2.useCallback)(
|
|
502
|
+
(message) => {
|
|
503
|
+
const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString();
|
|
504
|
+
setEventLog((prev) => [...prev.slice(-10), { message, timestamp }]);
|
|
505
|
+
if (enableConsoleLog) {
|
|
506
|
+
console.log(`[EmbedTester] ${timestamp}: ${message}`);
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
[enableConsoleLog]
|
|
510
|
+
);
|
|
511
|
+
const runDiagnostics = (0, import_react2.useCallback)(() => {
|
|
512
|
+
const newDiagnostics = {
|
|
513
|
+
crossOriginIsolation: !!(window.crossOriginIsolated || window.crossOriginIsolated),
|
|
514
|
+
gamepadSupported: "getGamepads" in navigator,
|
|
515
|
+
fullscreenSupported: !!(document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled),
|
|
516
|
+
keyboardLockSupported: "keyboard" in navigator && "lock" in navigator.keyboard
|
|
517
|
+
};
|
|
518
|
+
setDiagnostics(newDiagnostics);
|
|
519
|
+
addEvent(`\u{1F50D} Diagnostics updated - COI: ${newDiagnostics.crossOriginIsolation}, Gamepad: ${newDiagnostics.gamepadSupported}`);
|
|
520
|
+
}, [addEvent]);
|
|
521
|
+
import_react2.default.useEffect(() => {
|
|
522
|
+
runDiagnostics();
|
|
523
|
+
}, [runDiagnostics]);
|
|
524
|
+
const handleReady = (0, import_react2.useCallback)(() => {
|
|
525
|
+
if (!hasReadyBeenCalled.current) {
|
|
526
|
+
hasReadyBeenCalled.current = true;
|
|
527
|
+
addEvent("Embed ready");
|
|
528
|
+
setEmbedState((prev) => ({ ...prev, isReady: true }));
|
|
529
|
+
}
|
|
530
|
+
}, [addEvent]);
|
|
531
|
+
const handleStateChange = (0, import_react2.useCallback)((state) => {
|
|
532
|
+
const stateString = JSON.stringify(state);
|
|
533
|
+
if (stateString !== previousStateRef.current) {
|
|
534
|
+
previousStateRef.current = stateString;
|
|
535
|
+
setEmbedState(state);
|
|
536
|
+
addEvent(`State changed: ${stateString}`);
|
|
537
|
+
}
|
|
538
|
+
}, [addEvent]);
|
|
539
|
+
const handleDemoCompleted = (0, import_react2.useCallback)((data) => {
|
|
540
|
+
const payload = data;
|
|
541
|
+
addEvent(`\u{1F3AF} Demo completed! Reason: ${payload.reason}`);
|
|
542
|
+
addEvent(`Store URL available for purchase: ${payload.storeUrl}`);
|
|
543
|
+
setShowIframe(false);
|
|
544
|
+
setHasUserClicked(false);
|
|
545
|
+
}, [addEvent]);
|
|
546
|
+
const handleError = (0, import_react2.useCallback)((error) => {
|
|
547
|
+
addEvent(`Error: ${error}`);
|
|
548
|
+
if (enableConsoleLog) {
|
|
549
|
+
console.error("Embed error:", error);
|
|
550
|
+
}
|
|
551
|
+
}, [addEvent, enableConsoleLog]);
|
|
552
|
+
const handlePurchaseRequest = (0, import_react2.useCallback)((data) => {
|
|
553
|
+
addEvent(`\u{1F4B3} Explicit purchase request from Buy Now button`);
|
|
554
|
+
addEvent(`Opening store: ${data.storeUrl}`);
|
|
555
|
+
window.open(data.storeUrl, "_blank");
|
|
556
|
+
}, [addEvent]);
|
|
557
|
+
const handleRestart = (0, import_react2.useCallback)(() => {
|
|
558
|
+
setKey((prev) => prev + 1);
|
|
559
|
+
setHasUserClicked(false);
|
|
560
|
+
setShowIframe(false);
|
|
561
|
+
hasReadyBeenCalled.current = false;
|
|
562
|
+
previousStateRef.current = "";
|
|
563
|
+
addEvent("Embed restarted");
|
|
564
|
+
}, [addEvent]);
|
|
565
|
+
const buttonStyle = {
|
|
566
|
+
padding: "8px 16px",
|
|
567
|
+
margin: "4px",
|
|
568
|
+
border: "1px solid #404040",
|
|
569
|
+
borderRadius: "4px",
|
|
570
|
+
backgroundColor: "#2a2a2a",
|
|
571
|
+
color: "#e5e5e5",
|
|
572
|
+
cursor: "pointer",
|
|
573
|
+
fontSize: "14px",
|
|
574
|
+
transition: "all 0.2s ease"
|
|
575
|
+
};
|
|
576
|
+
const inputStyle = {
|
|
577
|
+
width: "100%",
|
|
578
|
+
padding: "8px",
|
|
579
|
+
margin: "4px 0",
|
|
580
|
+
border: "1px solid #404040",
|
|
581
|
+
borderRadius: "4px",
|
|
582
|
+
backgroundColor: "#1a1a1a",
|
|
583
|
+
color: "#e5e5e5",
|
|
584
|
+
fontSize: "14px"
|
|
585
|
+
};
|
|
586
|
+
const cardStyle = {
|
|
587
|
+
border: "1px solid #333333",
|
|
588
|
+
borderRadius: "8px",
|
|
589
|
+
padding: "16px",
|
|
590
|
+
margin: "8px 0",
|
|
591
|
+
backgroundColor: "#1a1a1a"
|
|
592
|
+
};
|
|
593
|
+
const statusStyle = {
|
|
594
|
+
display: "inline-block",
|
|
595
|
+
padding: "4px 8px",
|
|
596
|
+
margin: "2px",
|
|
597
|
+
borderRadius: "12px",
|
|
598
|
+
fontSize: "12px",
|
|
599
|
+
fontWeight: "500"
|
|
600
|
+
};
|
|
601
|
+
const successStatus = { ...statusStyle, backgroundColor: "#0d5d1f", color: "#4ade80" };
|
|
602
|
+
const errorStatus = { ...statusStyle, backgroundColor: "#5d1a1a", color: "#f87171" };
|
|
603
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: props.className, style: { minHeight: "100vh", padding: "20px", backgroundColor: "#000000", color: "#e5e5e5" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { maxWidth: "1200px", margin: "0 auto" }, children: [
|
|
604
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h1", { style: { marginBottom: "20px", fontSize: "24px", fontWeight: "bold", color: "#ffffff" }, children: "\u{1F9EA} Playruo Embed Tester" }),
|
|
605
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "20px" }, children: [
|
|
606
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
607
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: cardStyle, children: [
|
|
608
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { style: { margin: "0 0 16px 0", fontSize: "18px", fontWeight: "600", color: "#ffffff" }, children: "Test Controls" }),
|
|
609
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginBottom: "12px" }, children: [
|
|
610
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { htmlFor: "operation", style: { display: "block", marginBottom: "4px", fontWeight: "500", color: "#d4d4d4" }, children: "Operation" }),
|
|
611
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
612
|
+
"input",
|
|
613
|
+
{
|
|
614
|
+
style: inputStyle,
|
|
615
|
+
onChange: (e) => setOperation(e.target.value),
|
|
616
|
+
placeholder: "e.g., iframe",
|
|
617
|
+
value: operation
|
|
618
|
+
}
|
|
619
|
+
)
|
|
620
|
+
] }),
|
|
621
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginBottom: "12px" }, children: [
|
|
622
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { htmlFor: "storeUrl", style: { display: "block", marginBottom: "4px", fontWeight: "500", color: "#d4d4d4" }, children: "Store URL" }),
|
|
623
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
624
|
+
"input",
|
|
625
|
+
{
|
|
626
|
+
style: inputStyle,
|
|
627
|
+
onChange: (e) => setStoreUrl(e.target.value),
|
|
628
|
+
placeholder: "https://store.example.com",
|
|
629
|
+
value: storeUrl
|
|
630
|
+
}
|
|
631
|
+
)
|
|
632
|
+
] }),
|
|
633
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
634
|
+
"button",
|
|
635
|
+
{
|
|
636
|
+
type: "button",
|
|
637
|
+
style: {
|
|
638
|
+
...buttonStyle,
|
|
639
|
+
backgroundColor: "#0066cc",
|
|
640
|
+
color: "#ffffff",
|
|
641
|
+
border: "none",
|
|
642
|
+
fontWeight: "600"
|
|
643
|
+
},
|
|
644
|
+
onClick: handleRestart,
|
|
645
|
+
onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "#0052a3",
|
|
646
|
+
onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "#0066cc",
|
|
647
|
+
children: "\u{1F504} Restart Embed"
|
|
648
|
+
}
|
|
649
|
+
)
|
|
650
|
+
] }),
|
|
651
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: cardStyle, children: [
|
|
652
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { style: { margin: "0 0 16px 0", fontSize: "18px", fontWeight: "600", color: "#ffffff" }, children: "Status" }),
|
|
653
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
654
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: embedState.isReady ? successStatus : errorStatus, children: embedState.isReady ? "\u2705 Ready" : "\u274C Not Ready" }),
|
|
655
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: embedState.hasPlayedOnce ? successStatus : errorStatus, children: embedState.hasPlayedOnce ? "\u2705 Played" : "\u274C Not Played" }),
|
|
656
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: embedState.tryNow?.available ? successStatus : errorStatus, children: embedState.tryNow?.available ? "\u2705 Try Now" : "\u274C Try Now" }),
|
|
657
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: embedState.buyNow?.available ? successStatus : errorStatus, children: embedState.buyNow?.available ? "\u2705 Buy Now" : "\u274C Buy Now" })
|
|
658
|
+
] })
|
|
659
|
+
] }),
|
|
660
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: cardStyle, children: [
|
|
661
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { style: { margin: "0 0 16px 0", fontSize: "18px", fontWeight: "600", color: "#ffffff" }, children: "\u{1F50D} Browser Diagnostics" }),
|
|
662
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
|
|
663
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
664
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: diagnostics.crossOriginIsolation ? successStatus : errorStatus, children: diagnostics.crossOriginIsolation ? "\u2705" : "\u274C" }),
|
|
665
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontSize: "12px", color: "#d4d4d4" }, children: "Cross-Origin Isolation" })
|
|
666
|
+
] }),
|
|
667
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
668
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: diagnostics.gamepadSupported ? successStatus : errorStatus, children: diagnostics.gamepadSupported ? "\u2705" : "\u274C" }),
|
|
669
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontSize: "12px", color: "#d4d4d4" }, children: "Gamepad API" })
|
|
670
|
+
] }),
|
|
671
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
672
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: diagnostics.fullscreenSupported ? successStatus : errorStatus, children: diagnostics.fullscreenSupported ? "\u2705" : "\u274C" }),
|
|
673
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontSize: "12px", color: "#d4d4d4" }, children: "Fullscreen API" })
|
|
674
|
+
] }),
|
|
675
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
676
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: diagnostics.keyboardLockSupported ? successStatus : errorStatus, children: diagnostics.keyboardLockSupported ? "\u2705" : "\u274C" }),
|
|
677
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontSize: "12px", color: "#d4d4d4" }, children: "Keyboard Lock" })
|
|
678
|
+
] })
|
|
679
|
+
] })
|
|
680
|
+
] }),
|
|
681
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: cardStyle, children: [
|
|
682
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { style: { margin: "0 0 16px 0", fontSize: "18px", fontWeight: "600", color: "#ffffff" }, children: "Event Log" }),
|
|
683
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: {
|
|
684
|
+
backgroundColor: "#0a0a0a",
|
|
685
|
+
padding: "12px",
|
|
686
|
+
borderRadius: "4px",
|
|
687
|
+
height: "200px",
|
|
688
|
+
overflowY: "auto",
|
|
689
|
+
fontFamily: "monospace",
|
|
690
|
+
fontSize: "12px",
|
|
691
|
+
border: "1px solid #333333"
|
|
692
|
+
}, children: eventLog.length ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: eventLog.map((event) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginBottom: "4px" }, children: [
|
|
693
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { color: "#737373" }, children: [
|
|
694
|
+
"[",
|
|
695
|
+
event.timestamp,
|
|
696
|
+
"]"
|
|
697
|
+
] }),
|
|
698
|
+
" ",
|
|
699
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#e5e5e5" }, children: event.message })
|
|
700
|
+
] }, event.timestamp)) }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { color: "#737373" }, children: "No events yet..." }) })
|
|
701
|
+
] })
|
|
702
|
+
] }),
|
|
703
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: cardStyle, children: [
|
|
704
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "16px" }, children: [
|
|
705
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { style: { margin: "0", fontSize: "18px", fontWeight: "600", color: "#ffffff" }, children: "Embed Container" }),
|
|
706
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: {
|
|
707
|
+
backgroundColor: "#2a2a2a",
|
|
708
|
+
color: "#e5e5e5",
|
|
709
|
+
padding: "4px 8px",
|
|
710
|
+
borderRadius: "12px",
|
|
711
|
+
fontSize: "12px",
|
|
712
|
+
fontWeight: "500",
|
|
713
|
+
border: "1px solid #404040"
|
|
714
|
+
}, children: [
|
|
715
|
+
"\u{1F9EA} ",
|
|
716
|
+
baseUrl ? new URL(baseUrl).host : "localhost:3000"
|
|
717
|
+
] })
|
|
718
|
+
] }),
|
|
719
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: {
|
|
720
|
+
position: "relative",
|
|
721
|
+
minHeight: "500px",
|
|
722
|
+
overflow: "hidden",
|
|
723
|
+
borderRadius: "8px",
|
|
724
|
+
border: "1px solid #333333",
|
|
725
|
+
backgroundColor: "#0a0a0a"
|
|
726
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
727
|
+
PlayruoEmbed,
|
|
728
|
+
{
|
|
729
|
+
baseUrl: baseUrl || "",
|
|
730
|
+
className: "w-full h-full absolute inset-0",
|
|
731
|
+
iframeRef,
|
|
732
|
+
onDemoCompleted: handleDemoCompleted,
|
|
733
|
+
onError: handleError,
|
|
734
|
+
onPurchaseRequest: handlePurchaseRequest,
|
|
735
|
+
onReady: handleReady,
|
|
736
|
+
onStateChange: handleStateChange,
|
|
737
|
+
operation,
|
|
738
|
+
renderState: ({ actions, message, status }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: !hasUserClicked && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: {
|
|
739
|
+
position: "absolute",
|
|
740
|
+
inset: "0",
|
|
741
|
+
display: "flex",
|
|
742
|
+
flexDirection: "column",
|
|
743
|
+
alignItems: "center",
|
|
744
|
+
justifyContent: "center",
|
|
745
|
+
gap: "16px",
|
|
746
|
+
backgroundColor: "rgba(0, 0, 0, 0.85)",
|
|
747
|
+
backdropFilter: "blur(8px)",
|
|
748
|
+
zIndex: 50,
|
|
749
|
+
padding: "20px"
|
|
750
|
+
}, children: [
|
|
751
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { style: { margin: "0", fontSize: "14px", color: "#d4d4d4" }, children: [
|
|
752
|
+
"Status: ",
|
|
753
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#ffffff", fontWeight: "600" }, children: status })
|
|
754
|
+
] }),
|
|
755
|
+
message && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: { margin: "0", fontSize: "14px", color: "#d4d4d4" }, children: message }),
|
|
756
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
757
|
+
"button",
|
|
758
|
+
{
|
|
759
|
+
type: "button",
|
|
760
|
+
style: {
|
|
761
|
+
...buttonStyle,
|
|
762
|
+
backgroundColor: "#16a34a",
|
|
763
|
+
color: "#ffffff",
|
|
764
|
+
border: "none",
|
|
765
|
+
padding: "12px 24px",
|
|
766
|
+
fontSize: "16px",
|
|
767
|
+
fontWeight: "600",
|
|
768
|
+
cursor: actions.canTryNow ? "pointer" : "not-allowed",
|
|
769
|
+
opacity: actions.canTryNow ? 1 : 0.5
|
|
770
|
+
},
|
|
771
|
+
disabled: !actions.canTryNow,
|
|
772
|
+
onMouseEnter: (e) => {
|
|
773
|
+
if (actions.canTryNow) {
|
|
774
|
+
e.currentTarget.style.backgroundColor = "#15803d";
|
|
775
|
+
}
|
|
776
|
+
},
|
|
777
|
+
onMouseLeave: (e) => {
|
|
778
|
+
if (actions.canTryNow) {
|
|
779
|
+
e.currentTarget.style.backgroundColor = "#16a34a";
|
|
780
|
+
}
|
|
781
|
+
},
|
|
782
|
+
onClick: () => {
|
|
783
|
+
setHasUserClicked(true);
|
|
784
|
+
setShowIframe(true);
|
|
785
|
+
addEvent(embedState.hasPlayedOnce ? "User clicked - Resuming game" : "User clicked - Starting game with tryNow");
|
|
786
|
+
actions.tryNow();
|
|
787
|
+
},
|
|
788
|
+
children: [
|
|
789
|
+
"\u{1F3AE} ",
|
|
790
|
+
embedState.hasPlayedOnce ? "Resume Game" : "Try Demo Now"
|
|
791
|
+
]
|
|
792
|
+
}
|
|
793
|
+
),
|
|
794
|
+
actions.canBuyNow && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
795
|
+
"button",
|
|
796
|
+
{
|
|
797
|
+
type: "button",
|
|
798
|
+
style: {
|
|
799
|
+
...buttonStyle,
|
|
800
|
+
backgroundColor: "#525252",
|
|
801
|
+
color: "#ffffff",
|
|
802
|
+
border: "none",
|
|
803
|
+
padding: "8px 16px",
|
|
804
|
+
fontSize: "14px",
|
|
805
|
+
fontWeight: "500"
|
|
806
|
+
},
|
|
807
|
+
onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "#404040",
|
|
808
|
+
onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "#525252",
|
|
809
|
+
onClick: () => {
|
|
810
|
+
addEvent("Buy Now clicked");
|
|
811
|
+
actions.buyNow();
|
|
812
|
+
},
|
|
813
|
+
children: "Buy Now"
|
|
814
|
+
}
|
|
815
|
+
)
|
|
816
|
+
] }) }),
|
|
817
|
+
showIframe,
|
|
818
|
+
storeUrl
|
|
819
|
+
},
|
|
820
|
+
key
|
|
821
|
+
) })
|
|
822
|
+
] }) })
|
|
823
|
+
] })
|
|
824
|
+
] }) });
|
|
825
|
+
};
|
|
826
|
+
|
|
356
827
|
// src/post-message-types.ts
|
|
357
828
|
var isPlayruoEmbedMessage = (data) => {
|
|
358
829
|
if (!data || typeof data !== "object") return false;
|
|
@@ -368,6 +839,7 @@ var isPlayruoEmbedCommand = (data) => {
|
|
|
368
839
|
};
|
|
369
840
|
// Annotate the CommonJS export names for ESM import in node:
|
|
370
841
|
0 && (module.exports = {
|
|
842
|
+
EmbedTester,
|
|
371
843
|
PlayruoEmbed,
|
|
372
844
|
buildEmbedUrl,
|
|
373
845
|
isPlayruoEmbedCommand,
|
package/dist/index.d.cts
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 };
|