@wowlabtech/mini-app-adapter 0.2.2 → 0.2.3
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 +144 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +144 -35
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -479,7 +479,7 @@ async function startHtml5Qrcode() {
|
|
|
479
479
|
if (typeof document === "undefined") {
|
|
480
480
|
throw new Error("QR scanning requires a browser environment.");
|
|
481
481
|
}
|
|
482
|
-
const [{ Html5Qrcode
|
|
482
|
+
const [{ Html5Qrcode }] = await Promise.all([import("html5-qrcode")]);
|
|
483
483
|
return new Promise((resolve, reject) => {
|
|
484
484
|
const elementId = `native-shell-qr-${Date.now()}`;
|
|
485
485
|
const overlay = document.createElement("div");
|
|
@@ -516,7 +516,7 @@ async function startHtml5Qrcode() {
|
|
|
516
516
|
const previousOverflow = document.body.style.overflow;
|
|
517
517
|
document.body.style.overflow = "hidden";
|
|
518
518
|
let disposed = false;
|
|
519
|
-
const scanner = new
|
|
519
|
+
const scanner = new Html5Qrcode(elementId);
|
|
520
520
|
const cleanup = async (result, error) => {
|
|
521
521
|
if (disposed) {
|
|
522
522
|
return;
|
|
@@ -2401,7 +2401,7 @@ var VKMiniAppAdapter = class extends BaseMiniAppAdapter {
|
|
|
2401
2401
|
};
|
|
2402
2402
|
|
|
2403
2403
|
// src/adapters/webAdapter.ts
|
|
2404
|
-
var
|
|
2404
|
+
var import_jsqr = __toESM(require("jsqr"), 1);
|
|
2405
2405
|
var WebMiniAppAdapter = class extends BaseMiniAppAdapter {
|
|
2406
2406
|
constructor() {
|
|
2407
2407
|
super("web", {
|
|
@@ -2471,14 +2471,31 @@ var WebMiniAppAdapter = class extends BaseMiniAppAdapter {
|
|
|
2471
2471
|
closeBtn.style.cursor = "pointer";
|
|
2472
2472
|
closeBtn.style.zIndex = "9999999999";
|
|
2473
2473
|
overlay.appendChild(closeBtn);
|
|
2474
|
+
const scanSize = Math.min(Math.floor(Math.min(window.innerWidth, window.innerHeight) * 0.72), 320);
|
|
2475
|
+
const scanBox = document.createElement("div");
|
|
2476
|
+
scanBox.style.width = `${scanSize}px`;
|
|
2477
|
+
scanBox.style.height = `${scanSize}px`;
|
|
2478
|
+
scanBox.style.position = "relative";
|
|
2479
|
+
scanBox.style.flex = "0 0 auto";
|
|
2480
|
+
scanBox.style.borderRadius = "18px";
|
|
2481
|
+
scanBox.style.overflow = "hidden";
|
|
2482
|
+
overlay.appendChild(scanBox);
|
|
2474
2483
|
const scanArea = document.createElement("div");
|
|
2475
|
-
scanArea.
|
|
2476
|
-
scanArea.style.
|
|
2477
|
-
scanArea.style.
|
|
2478
|
-
scanArea.style.
|
|
2479
|
-
scanArea
|
|
2480
|
-
|
|
2481
|
-
|
|
2484
|
+
scanArea.style.position = "absolute";
|
|
2485
|
+
scanArea.style.inset = "0";
|
|
2486
|
+
scanArea.style.zIndex = "1";
|
|
2487
|
+
scanArea.style.background = "#000";
|
|
2488
|
+
scanBox.appendChild(scanArea);
|
|
2489
|
+
const video = document.createElement("video");
|
|
2490
|
+
video.setAttribute("playsinline", "true");
|
|
2491
|
+
video.autoplay = true;
|
|
2492
|
+
video.muted = true;
|
|
2493
|
+
video.style.width = "100%";
|
|
2494
|
+
video.style.height = "100%";
|
|
2495
|
+
video.style.objectFit = "cover";
|
|
2496
|
+
video.style.position = "absolute";
|
|
2497
|
+
video.style.inset = "0";
|
|
2498
|
+
scanArea.appendChild(video);
|
|
2482
2499
|
const frame = document.createElement("div");
|
|
2483
2500
|
frame.style.position = "absolute";
|
|
2484
2501
|
frame.style.top = "0";
|
|
@@ -2488,8 +2505,8 @@ var WebMiniAppAdapter = class extends BaseMiniAppAdapter {
|
|
|
2488
2505
|
frame.style.border = "3px solid rgba(255,255,255,0.9)";
|
|
2489
2506
|
frame.style.borderRadius = "18px";
|
|
2490
2507
|
frame.style.pointerEvents = "none";
|
|
2491
|
-
frame.style.zIndex = "
|
|
2492
|
-
|
|
2508
|
+
frame.style.zIndex = "3";
|
|
2509
|
+
scanBox.appendChild(frame);
|
|
2493
2510
|
const line = document.createElement("div");
|
|
2494
2511
|
line.style.position = "absolute";
|
|
2495
2512
|
line.style.left = "0";
|
|
@@ -2498,8 +2515,8 @@ var WebMiniAppAdapter = class extends BaseMiniAppAdapter {
|
|
|
2498
2515
|
line.style.background = "rgba(255,255,255,0.85)";
|
|
2499
2516
|
line.style.borderRadius = "2px";
|
|
2500
2517
|
line.style.animation = "qr-line 2s infinite";
|
|
2501
|
-
line.style.zIndex = "
|
|
2502
|
-
|
|
2518
|
+
line.style.zIndex = "4";
|
|
2519
|
+
scanBox.appendChild(line);
|
|
2503
2520
|
const styleTag = document.createElement("style");
|
|
2504
2521
|
styleTag.innerHTML = `
|
|
2505
2522
|
@keyframes qr-line {
|
|
@@ -2516,17 +2533,26 @@ var WebMiniAppAdapter = class extends BaseMiniAppAdapter {
|
|
|
2516
2533
|
hint.style.fontSize = "17px";
|
|
2517
2534
|
hint.style.opacity = "0.9";
|
|
2518
2535
|
overlay.appendChild(hint);
|
|
2519
|
-
const
|
|
2536
|
+
const canvas = document.createElement("canvas");
|
|
2537
|
+
const context = canvas.getContext("2d", { willReadFrequently: true });
|
|
2538
|
+
let stream = null;
|
|
2539
|
+
let rafId = null;
|
|
2540
|
+
let lastScanAt = 0;
|
|
2520
2541
|
let closed = false;
|
|
2521
2542
|
const finalize = async (result) => {
|
|
2522
2543
|
if (closed) {
|
|
2523
2544
|
return;
|
|
2524
2545
|
}
|
|
2525
2546
|
closed = true;
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2547
|
+
if (rafId !== null) {
|
|
2548
|
+
cancelAnimationFrame(rafId);
|
|
2549
|
+
rafId = null;
|
|
2529
2550
|
}
|
|
2551
|
+
if (stream) {
|
|
2552
|
+
stream.getTracks().forEach((track) => track.stop());
|
|
2553
|
+
stream = null;
|
|
2554
|
+
}
|
|
2555
|
+
video.srcObject = null;
|
|
2530
2556
|
overlay.remove();
|
|
2531
2557
|
styleTag.remove();
|
|
2532
2558
|
document.body.style.overflow = prevOverflow;
|
|
@@ -2545,19 +2571,50 @@ var WebMiniAppAdapter = class extends BaseMiniAppAdapter {
|
|
|
2545
2571
|
};
|
|
2546
2572
|
closeBtn.onclick = () => closeScanner(null);
|
|
2547
2573
|
try {
|
|
2548
|
-
|
|
2549
|
-
{ facingMode: "environment" },
|
|
2550
|
-
{
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
()
|
|
2574
|
+
const constraints = [
|
|
2575
|
+
{ video: { facingMode: { ideal: "environment" } }, audio: false },
|
|
2576
|
+
{ video: { facingMode: "environment" }, audio: false },
|
|
2577
|
+
{ video: true, audio: false }
|
|
2578
|
+
];
|
|
2579
|
+
let lastError = null;
|
|
2580
|
+
for (const constraint of constraints) {
|
|
2581
|
+
try {
|
|
2582
|
+
stream = await navigator.mediaDevices.getUserMedia(constraint);
|
|
2583
|
+
break;
|
|
2584
|
+
} catch (error) {
|
|
2585
|
+
lastError = error;
|
|
2586
|
+
}
|
|
2587
|
+
}
|
|
2588
|
+
if (!stream) {
|
|
2589
|
+
throw lastError instanceof Error ? lastError : new Error("Unable to access camera");
|
|
2590
|
+
}
|
|
2591
|
+
video.srcObject = stream;
|
|
2592
|
+
await video.play();
|
|
2593
|
+
const scanFrame = (now) => {
|
|
2594
|
+
if (closed) {
|
|
2595
|
+
return;
|
|
2559
2596
|
}
|
|
2560
|
-
|
|
2597
|
+
if (now - lastScanAt >= 100 && context && video.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA) {
|
|
2598
|
+
const width = video.videoWidth;
|
|
2599
|
+
const height = video.videoHeight;
|
|
2600
|
+
if (width > 0 && height > 0) {
|
|
2601
|
+
canvas.width = width;
|
|
2602
|
+
canvas.height = height;
|
|
2603
|
+
context.drawImage(video, 0, 0, width, height);
|
|
2604
|
+
const imageData = context.getImageData(0, 0, width, height);
|
|
2605
|
+
const result = (0, import_jsqr.default)(imageData.data, width, height, {
|
|
2606
|
+
inversionAttempts: "attemptBoth"
|
|
2607
|
+
});
|
|
2608
|
+
if (result?.data) {
|
|
2609
|
+
closeScanner(result.data);
|
|
2610
|
+
return;
|
|
2611
|
+
}
|
|
2612
|
+
lastScanAt = now;
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
rafId = requestAnimationFrame(scanFrame);
|
|
2616
|
+
};
|
|
2617
|
+
rafId = requestAnimationFrame(scanFrame);
|
|
2561
2618
|
} catch (error) {
|
|
2562
2619
|
console.error("QR Start error", error);
|
|
2563
2620
|
closeScanner(null);
|
|
@@ -2610,6 +2667,8 @@ ${url}` : url;
|
|
|
2610
2667
|
};
|
|
2611
2668
|
|
|
2612
2669
|
// src/adapters/index.ts
|
|
2670
|
+
var CONFIRMED_PLATFORM_STORAGE_KEY = "mini-app-adapter:confirmed-platform";
|
|
2671
|
+
var CONFIRMED_PLATFORM_TTL_MS = 30 * 60 * 1e3;
|
|
2613
2672
|
function detectPlatform() {
|
|
2614
2673
|
if (typeof window === "undefined") {
|
|
2615
2674
|
return "web";
|
|
@@ -2621,30 +2680,76 @@ function detectPlatform() {
|
|
|
2621
2680
|
})();
|
|
2622
2681
|
const getParam = (name) => searchParams.get(name) ?? hashParams.get(name);
|
|
2623
2682
|
const hasParam = (...names) => names.some((name) => getParam(name));
|
|
2683
|
+
const readConfirmedPlatform = () => {
|
|
2684
|
+
try {
|
|
2685
|
+
const raw = window.sessionStorage.getItem(CONFIRMED_PLATFORM_STORAGE_KEY);
|
|
2686
|
+
if (!raw) {
|
|
2687
|
+
return null;
|
|
2688
|
+
}
|
|
2689
|
+
const parsed = JSON.parse(raw);
|
|
2690
|
+
if (!parsed?.platform || typeof parsed.ts !== "number") {
|
|
2691
|
+
return null;
|
|
2692
|
+
}
|
|
2693
|
+
if (Date.now() - parsed.ts > CONFIRMED_PLATFORM_TTL_MS) {
|
|
2694
|
+
return null;
|
|
2695
|
+
}
|
|
2696
|
+
return parsed.platform;
|
|
2697
|
+
} catch {
|
|
2698
|
+
return null;
|
|
2699
|
+
}
|
|
2700
|
+
};
|
|
2701
|
+
const persistConfirmedPlatform = (platform) => {
|
|
2702
|
+
if (platform === "web") {
|
|
2703
|
+
return;
|
|
2704
|
+
}
|
|
2705
|
+
try {
|
|
2706
|
+
window.sessionStorage.setItem(
|
|
2707
|
+
CONFIRMED_PLATFORM_STORAGE_KEY,
|
|
2708
|
+
JSON.stringify({ platform, ts: Date.now() })
|
|
2709
|
+
);
|
|
2710
|
+
} catch {
|
|
2711
|
+
}
|
|
2712
|
+
};
|
|
2624
2713
|
const shellPlatform = readShellPlatform();
|
|
2625
2714
|
if (shellPlatform) {
|
|
2715
|
+
persistConfirmedPlatform(shellPlatform);
|
|
2626
2716
|
return shellPlatform;
|
|
2627
2717
|
}
|
|
2628
2718
|
const userAgent = navigator.userAgent.toLowerCase();
|
|
2629
2719
|
const hasNativeBridge = typeof window.NativeBridge?.postMessage === "function";
|
|
2630
2720
|
if (hasNativeBridge) {
|
|
2631
2721
|
if (userAgent.includes("android")) {
|
|
2722
|
+
persistConfirmedPlatform("shell_android");
|
|
2632
2723
|
return "shell_android";
|
|
2633
2724
|
}
|
|
2725
|
+
persistConfirmedPlatform("shell_ios");
|
|
2634
2726
|
return "shell_ios";
|
|
2635
2727
|
}
|
|
2636
|
-
|
|
2728
|
+
const telegramGlobals = window;
|
|
2729
|
+
const hasTelegramGlobal = Boolean(window.Telegram?.WebApp) || typeof telegramGlobals.TelegramWebviewProxy !== "undefined" || typeof telegramGlobals.TelegramGameProxy !== "undefined";
|
|
2730
|
+
const hasTelegramParams = hasParam("tgWebAppPlatform", "tgWebAppVersion", "tgWebAppData", "tgWebAppLanguage");
|
|
2731
|
+
if (hasTelegramGlobal || hasTelegramParams || userAgent.includes("telegram")) {
|
|
2732
|
+
persistConfirmedPlatform("telegram");
|
|
2637
2733
|
return "telegram";
|
|
2638
2734
|
}
|
|
2639
2735
|
if (window.WebApp) {
|
|
2736
|
+
persistConfirmedPlatform("max");
|
|
2640
2737
|
return "max";
|
|
2641
2738
|
}
|
|
2642
2739
|
if (window.MaxMiniApp) {
|
|
2740
|
+
persistConfirmedPlatform("max");
|
|
2643
2741
|
return "max";
|
|
2644
2742
|
}
|
|
2645
|
-
|
|
2743
|
+
const hasVkParams = hasParam("vk_app_id", "vk_platform", "vk_user_id", "vk_language", "sign");
|
|
2744
|
+
const hasVkUserAgentSignal = userAgent.includes("vkclient") || userAgent.includes("vk-android") || userAgent.includes("vkontakte");
|
|
2745
|
+
if (hasVkParams || hasVkUserAgentSignal) {
|
|
2746
|
+
persistConfirmedPlatform("vk");
|
|
2646
2747
|
return "vk";
|
|
2647
2748
|
}
|
|
2749
|
+
const confirmedPlatform = readConfirmedPlatform();
|
|
2750
|
+
if (confirmedPlatform && confirmedPlatform !== "web") {
|
|
2751
|
+
return confirmedPlatform;
|
|
2752
|
+
}
|
|
2648
2753
|
return "web";
|
|
2649
2754
|
}
|
|
2650
2755
|
function createAdapter(input) {
|
|
@@ -2845,14 +2950,18 @@ var cachedPlatform = null;
|
|
|
2845
2950
|
function getPlatform() {
|
|
2846
2951
|
const adapter = getActiveAdapter();
|
|
2847
2952
|
if (adapter) {
|
|
2848
|
-
|
|
2953
|
+
if (adapter.platform !== "web") {
|
|
2954
|
+
cachedPlatform = adapter.platform;
|
|
2955
|
+
}
|
|
2849
2956
|
return adapter.platform;
|
|
2850
2957
|
}
|
|
2851
|
-
if (cachedPlatform) {
|
|
2958
|
+
if (cachedPlatform && cachedPlatform !== "web") {
|
|
2852
2959
|
return cachedPlatform;
|
|
2853
2960
|
}
|
|
2854
2961
|
const detectedPlatform = detectPlatform();
|
|
2855
|
-
|
|
2962
|
+
if (detectedPlatform !== "web") {
|
|
2963
|
+
cachedPlatform = detectedPlatform;
|
|
2964
|
+
}
|
|
2856
2965
|
return detectedPlatform;
|
|
2857
2966
|
}
|
|
2858
2967
|
|