@bountyboard/arcade-sdk 1.0.0 → 1.0.1

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/protocol.ts","../src/core.ts","../src/inert.ts"],"sourcesContent":["/**\n * @bountyboard/arcade-sdk — module entry.\n *\n * import { BBArcade } from '@bountyboard/arcade-sdk';\n *\n * Importing attaches the SDK's postMessage listeners immediately (the Bounty\n * Board host pushes its config at load time, so listener timing matters) but\n * does NOT install a window.BBArcade global — that's the script-tag build\n * (https://www.bountyboard.gg/arcade-sdk/v1.js, or the './global' subpath).\n * Evaluated without a window (SSR/prerender) it exports an inert instance with\n * standalone semantics, so importing is always safe.\n */\nimport { createBBArcade } from './core';\nimport { createInertBBArcade } from './inert';\nimport type { BBArcadeSDK } from './types';\n\nexport const BBArcade: BBArcadeSDK =\n typeof window === 'undefined' ? createInertBBArcade() : createBBArcade();\n\nexport default BBArcade;\n\nexport { VERSION as PROTOCOL_VERSION } from './protocol';\nexport type {\n BBArcadeConfig,\n BBArcadeError,\n BBArcadeErrorCode,\n BBArcadeLockToHostOptions,\n BBArcadePlayer,\n BBArcadeRewardedAdOptions,\n BBArcadeRewardedAdResult,\n BBArcadeRewardedAdStatus,\n BBArcadeRewardedAdsConfig,\n BBArcadeRewardedBreakOptions,\n BBArcadeSDK,\n} from './types';\n","/**\n * Wire-protocol constants for the bb-arcade postMessage protocol. The protocol\n * version is deliberately decoupled from the npm package's semver: every\n * message carries `v: VERSION`, and the host accepts all messages of the same\n * major protocol. Bump VERSION only for a breaking wire change (which also\n * means a new /arcade-sdk/v2.js URL).\n */\nexport const VERSION = 1;\n\n/** `source` field on every message the game/SDK posts to the embedding page. */\nexport const SDK_MESSAGE_SOURCE = 'bb-arcade';\n\n/** `source` field on every message the Bounty Board host posts to the game. */\nexport const HOST_MESSAGE_SOURCE = 'bb-arcade-host';\n","/**\n * Bounty Board Arcade SDK core — a faithful, typed port of the original\n * public/arcade-sdk.js IIFE. The whole SDK is one factory so every piece of\n * state (blocked flag, pending requests, ad config, host config) lives in one\n * closure per instance, exactly like the original script. Behavior parity with\n * the shipped v1 script is the hard requirement here; the v1 behavior test\n * suite (src/__tests__/arcade-sdk.test.ts at the repo root) runs against the\n * generated artifact and must pass unchanged.\n */\nimport { HOST_MESSAGE_SOURCE, SDK_MESSAGE_SOURCE, VERSION } from './protocol';\nimport type {\n BBArcadeConfig,\n BBArcadeError,\n BBArcadeErrorCode,\n BBArcadeLockToHostOptions,\n BBArcadePlayer,\n BBArcadeRewardedAdOptions,\n BBArcadeRewardedAdResult,\n BBArcadeRewardedBreakOptions,\n BBArcadeSDK,\n} from './types';\n\n// Canonical production home, used for the site-lock \"play the original\" link.\nconst BOUNTY_BOARD_URL = 'https://www.bountyboard.gg/arcade';\nconst ADSENSE_CLIENT_ID = 'ca-pub-7727110228190547';\nconst AD_PLACEMENT_SRC =\n 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=' + ADSENSE_CLIENT_ID;\nconst AD_PLACEMENT_SCRIPT_ID = 'bb-arcade-h5-ads';\nconst DEFAULT_AD_LOAD_TIMEOUT_MS = 6000;\nconst SAVE_TIMEOUT_MS = 15000;\n// How long init() waits for the host's config reply before resolving anyway.\n// Standalone play resolves immediately (there is no host to answer), so this\n// grace only delays games embedded somewhere that isn't a Bounty Board host.\nconst INIT_CONFIG_GRACE_MS = 1500;\n\n// Allowed by default: bountyboard.gg (and any *.bountyboard.gg subdomain),\n// Bounty Board's fixed staging alias, and localhost/127.0.0.1 for local\n// development — i.e. every environment Bounty Board itself serves the game\n// from. The staging alias is a single PINNED Bounty Board deployment, so\n// hardcoding that one host is safe; we still deliberately DON'T trust shared\n// or dynamic preview domains broadly (e.g. *.vercel.app) — a per-deploy\n// preview host or your own site must be added via the `allow` option.\n// This list gates BOTH the sitelock AND which parent origin may send the host\n// config (player identity / rewarded-ads), so a missing environment here\n// silently breaks the whole SDK handshake there, not just the sitelock.\nconst DEFAULT_ALLOW = [\n 'bountyboard.gg',\n 'bountyboard-staging.vercel.app',\n 'localhost',\n '127.0.0.1',\n];\n\n// Public half of the sitelock attestation keypair (ECDSA P-256, SPKI). The\n// matching private key lives ONLY in Bounty Board server env\n// (ARCADE_SITELOCK_PRIVATE_KEY); a re-hosting site can neither sign a fresh\n// attestation nor replay a captured one (the sender-origin check below).\nconst SITELOCK_PUBLIC_KEY_B64 =\n 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE6WC8fJweDpfKRcZW9Q9eOLxPXmFCO8R8lY1kfZbuAQt65E0CTu2rM80XfW3nYrSAqO+Eev8gxrGS0bAnNaMDGg==';\n/** Attestations older/newer than this are stale (replay window). */\nconst SITELOCK_MAX_SKEW_MS = 5 * 60 * 1000;\n\n/**\n * Google H5 ads globals the SDK shims/loads on demand. A standalone shape\n * (not `extends Window`) so host apps that augment Window themselves (e.g.\n * test files declaring `adBreak?: jest.Mock`) can't create a conflicting\n * interface under a shared tsconfig.\n */\ntype AdsWindow = {\n adsbygoogle?: unknown[];\n adBreak?: (placement: Record<string, unknown>) => void;\n adConfig?: (settings: Record<string, unknown>) => void;\n};\n\ninterface HostAttestation {\n origin: string;\n ts: number;\n sig: string;\n}\n\n/** The identifying fields every rewarded-ad result/lifecycle event carries. */\ninterface AdResultBase {\n placement: string;\n reward: string;\n adBreakId: string;\n size?: 'small' | 'medium' | 'large';\n}\n\ninterface PendingEntry {\n resolve: (value: unknown) => void;\n reject: (err: BBArcadeError) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\ninterface NormalizedRewardedOptions {\n placement: string;\n reward: string;\n adBreakId: string;\n size: '' | 'small' | 'medium' | 'large';\n adChannel: string;\n testMode: boolean;\n loadTimeoutMs: number;\n beforeReward?: (showAd: () => void) => void;\n adViewed?: (result: BBArcadeRewardedAdResult) => void;\n adDismissed?: (result: BBArcadeRewardedAdResult) => void;\n adBreakDone?: (placementInfo: unknown) => void;\n onReward?: (result: BBArcadeRewardedAdResult) => void;\n onDismissed?: (result: BBArcadeRewardedAdResult) => void;\n onDone?: (result: BBArcadeRewardedAdResult) => void;\n onError?: (result: BBArcadeRewardedAdResult) => void;\n onUnavailable?: (result: BBArcadeRewardedAdResult) => void;\n}\n\nfunction sdkError(code: BBArcadeErrorCode): BBArcadeError {\n const err = new Error(code) as BBArcadeError;\n err.code = code;\n return err;\n}\n\nfunction b64ToBytes(b64: string): Uint8Array {\n const bin = atob(b64);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\n return bytes;\n}\n\nfunction cleanText(value: unknown, fallback?: string, max?: number): string {\n if (typeof value !== 'string') return fallback || '';\n return value.replace(/[^\\w:.-]+/g, '_').slice(0, max || 80) || fallback || '';\n}\n\nfunction toBoolean(value: unknown): boolean {\n return value === true || value === 'true' || value === '1';\n}\n\nfunction cleanRewardedSize(value: unknown): '' | 'small' | 'medium' | 'large' {\n return value === 'small' || value === 'medium' || value === 'large' ? value : '';\n}\n\nfunction safeCall<T>(fn: ((arg: T) => void) | undefined, arg?: T): void {\n if (typeof fn !== 'function') return;\n try {\n fn(arg as T);\n } catch (err) {\n setTimeout(function () {\n throw err;\n }, 0);\n }\n}\n\n// Normalize an allow-list entry to a bare hostname, so a game author can pass a\n// plain host (\"mygame.com\"), a full URL (\"https://mygame.com/play\"), or a\n// host:port and still match against the embedder's hostname.\nfunction toAllowedHost(value: unknown): string {\n const raw = String(value).toLowerCase().trim();\n if (!raw) return '';\n try {\n return new URL(raw.indexOf('//') === -1 ? 'https://' + raw : raw).hostname;\n } catch (err) {\n return raw;\n }\n}\n\nfunction hostnameAllowed(origin: unknown, allowHosts: string[]): boolean {\n if (!origin || origin === 'null' || typeof origin !== 'string') return false;\n let host: string;\n try {\n host = new URL(origin).hostname.toLowerCase();\n } catch (err) {\n return false;\n }\n for (let i = 0; i < allowHosts.length; i++) {\n const allowed = allowHosts[i];\n // exact host, or a subdomain of an allowed host (\".allowed\")\n if (host === allowed || host.slice(-(allowed.length + 1)) === '.' + allowed) return true;\n }\n return false;\n}\n\n/**\n * Verify a host attestation: shape, freshness, the LOAD-BEARING sender\n * check (the postMessage carrying it must come from the origin it attests —\n * event.origin is browser-authenticated, so a stolen attestation replayed\n * from another site fails here), then the ECDSA signature over\n * \"<origin>:<ts>\". Resolves boolean; never throws.\n */\nfunction verifyHostAttestation(att: unknown, senderOrigin: string): Promise<boolean> {\n const a = att as HostAttestation | null | undefined;\n if (!a || typeof a.origin !== 'string' || typeof a.ts !== 'number' || typeof a.sig !== 'string')\n return Promise.resolve(false);\n if (a.origin !== senderOrigin) return Promise.resolve(false);\n if (Math.abs(Date.now() - a.ts) > SITELOCK_MAX_SKEW_MS) return Promise.resolve(false);\n try {\n return window.crypto.subtle\n .importKey(\n 'spki',\n b64ToBytes(SITELOCK_PUBLIC_KEY_B64),\n { name: 'ECDSA', namedCurve: 'P-256' },\n false,\n ['verify']\n )\n .then(function (key) {\n return window.crypto.subtle.verify(\n { name: 'ECDSA', hash: 'SHA-256' },\n key,\n b64ToBytes(a.sig),\n new TextEncoder().encode(a.origin + ':' + a.ts)\n );\n })\n .then(\n function (ok) {\n return ok === true;\n },\n function () {\n return false;\n }\n );\n } catch (err) {\n return Promise.resolve(false);\n }\n}\n\n// Normalize the host-sent player identity. Only a non-empty string name\n// counts; the avatar is a plain URL string or null. Anything malformed\n// collapses to null so games can rely on the { name, avatarUrl } shape.\nfunction sanitizePlayer(value: unknown): BBArcadePlayer | null {\n if (!value || typeof value !== 'object') return null;\n const raw = value as { name?: unknown; avatarUrl?: unknown };\n const name = typeof raw.name === 'string' ? raw.name.trim().slice(0, 120) : '';\n if (!name) return null;\n const avatarUrl =\n typeof raw.avatarUrl === 'string' && raw.avatarUrl.trim() ? raw.avatarUrl : null;\n return { name: name, avatarUrl: avatarUrl };\n}\n\n/**\n * Build one SDK instance. Attaches this instance's `message` listeners to\n * `window` immediately (the host pushes its config at load time, so listener\n * timing is part of the protocol). Browser-only — the module entry substitutes\n * an inert stub when `window` is undefined (SSR-safety for bundled games).\n */\nexport function createBBArcade(): BBArcadeSDK {\n let adPlacementLoad: Promise<AdsWindow['adBreak'] | null> | null = null;\n let adPreloadConfigured = false;\n let rewardedBreakActive = false;\n let rewardedBreakSequence = 0;\n\n function isLocalAdHost(): boolean {\n try {\n const protocol = window.location && window.location.protocol;\n const host = window.location && window.location.hostname;\n return (\n protocol === 'file:' ||\n host === 'localhost' ||\n host === '127.0.0.1' ||\n host === '::1' ||\n host === '[::1]'\n );\n } catch (err) {\n return false;\n }\n }\n\n const localAdHost = isLocalAdHost();\n const config = {\n rewardedAds: {\n enabled: true,\n adChannel: '',\n testMode: localAdHost,\n loadTimeoutMs: DEFAULT_AD_LOAD_TIMEOUT_MS,\n preload: false,\n },\n };\n const hostConfig = {\n rewardedAds: {\n received: false,\n enabled: localAdHost,\n adChannel: '',\n testMode: localAdHost,\n preload: false,\n },\n };\n // True once ANY valid host config message has arrived — this (not the\n // rewarded-ads sub-flag) is what resolves the init()/getPlayer() handshake.\n let hostConfigReceived = false;\n // The logged-in player's display identity from the host config:\n // { name, avatarUrl } or null for guests. Display name + avatar ONLY — the\n // host never sends ids, emails, or roles.\n let hostPlayer: BBArcadePlayer | null = null;\n\n // Set once lockToHost() decides the game is running somewhere it shouldn't.\n // After that the SDK goes silent so a scraped copy can't keep posting.\n let blocked = false;\n\n const pending: Record<string, PendingEntry> = {};\n let seq = 0;\n\n // The game can be embedded by any Bounty Board environment (prod, staging,\n // previews), so target '*' — the payload carries nothing sensitive and the\n // parent page validates the message's source window + origin itself.\n function post(type: string, score?: number, extra?: object): void {\n if (blocked) return;\n const message: Record<string, unknown> = { source: SDK_MESSAGE_SOURCE, v: VERSION, type: type };\n if (typeof score === 'number' && isFinite(score)) message.score = Math.floor(score);\n if (extra && typeof extra === 'object') {\n const fields = extra as Record<string, unknown>;\n for (const key in fields) {\n if (Object.prototype.hasOwnProperty.call(fields, key) && fields[key] !== undefined) {\n message[key] = fields[key];\n }\n }\n }\n try {\n window.parent.postMessage(message, '*');\n } catch (err) {\n /* not embedded — standalone play is fine */\n }\n }\n\n function isEmbedded(): boolean {\n try {\n return window.parent != null && window.parent !== window;\n } catch (err) {\n return true; // touching a cross-origin parent threw → we are embedded\n }\n }\n\n // ── Request/response over postMessage (cloud save, experiments, host) ──────\n // Cloud saves only work for Bounty-Board-hosted build uploads: those run in a\n // sandbox with no localStorage/IndexedDB, so saves go through the embedding\n // page (which holds the player's login). save/load return a Promise; the\n // parent posts back a result for the matching requestId. Rejections are Error\n // objects that also carry a machine-readable `code` property.\n function request(type: string, payload?: unknown): Promise<unknown> {\n return new Promise(function (resolve, reject) {\n if (blocked) return reject(sdkError('error'));\n // Standalone play (no embedding page): nothing will ever answer, so fail\n // fast instead of hanging until the timeout.\n if (!isEmbedded()) return reject(sdkError('unsupported'));\n const requestId = type + '_' + ++seq + '_' + Date.now();\n const timer = setTimeout(function () {\n if (pending[requestId]) {\n delete pending[requestId];\n reject(sdkError('error'));\n }\n }, SAVE_TIMEOUT_MS);\n pending[requestId] = { resolve: resolve, reject: reject, timer: timer };\n try {\n window.parent.postMessage(\n {\n source: SDK_MESSAGE_SOURCE,\n v: VERSION,\n type: type,\n requestId: requestId,\n payload: payload,\n },\n '*'\n );\n } catch (err) {\n clearTimeout(timer);\n delete pending[requestId];\n reject(sdkError('error'));\n }\n });\n }\n\n window.addEventListener('message', function (event: MessageEvent) {\n // Replies come from the embedding page only; ignore anything else (e.g. a\n // co-resident ad/nested frame, or a null-source synthetic event) so it\n // can't resolve a pending request with a forged payload. Mirrors the\n // host-config listener's source check below.\n if (event.source !== window.parent) return;\n const data = event.data as\n | {\n source?: string;\n type?: string;\n requestId?: string;\n ok?: boolean;\n code?: BBArcadeErrorCode;\n data?: unknown;\n attestation?: unknown;\n variant?: unknown;\n }\n | null\n | undefined;\n if (!data || data.source !== SDK_MESSAGE_SOURCE) return;\n // Any '<type>_result' with a pending requestId is a legitimate reply: the\n // sender is already proven to be the embedding host (source check above)\n // and requestIds are per-request — so enumerating reply types here would\n // only create a synchronized-edit hazard with the host (a forgotten entry\n // = that request silently timing out after 15s).\n if (typeof data.type !== 'string' || !data.type.endsWith('_result')) return;\n const entry = pending[data.requestId as string];\n if (!entry) return;\n clearTimeout(entry.timer);\n delete pending[data.requestId as string];\n // The browser-authenticated sender origin is authoritative. Never trust a\n // parent-supplied origin string: an arbitrary embedder could claim to be\n // bountyboard.gg and enable host-only SDK features.\n if (data.type === 'host_result') return entry.resolve({ origin: event.origin });\n if (data.type === 'host_attest_result')\n // Keep the browser-authenticated sender origin alongside the claimed\n // attestation — the verifier requires them to MATCH.\n return entry.resolve({ origin: event.origin, attestation: data.attestation || null });\n if (data.type === 'experiment_result')\n return entry.resolve(typeof data.variant === 'string' ? data.variant : null);\n // Generic ok/code convention (save_result, load_result, mp_ticket_result,\n // and any future reply type): resolve the carried data — load()'s \"no\n // save yet\" stays null, save()'s bare ack stays undefined.\n if (data.ok)\n entry.resolve(\n data.type === 'load_result' ? (data.data != null ? data.data : null) : data.data\n );\n else entry.reject(sdkError(data.code || 'error'));\n });\n\n // ── Site lock (anti scrape-and-reupload) ───────────────────────────────────\n\n // The origin of the page that embeds this game, read from the browser (which\n // the embedding page can't forge). Returns null when it can't be determined\n // synchronously (opaque-origin builds with no referrer) — callers fall back to\n // the host handshake then.\n function embeddingOriginSync(): string | null {\n try {\n if (window.top === window.self) return window.location.origin; // not embedded\n } catch (err) {\n /* cross-origin top → we are embedded; keep probing */\n }\n try {\n const ancestors = window.location.ancestorOrigins;\n if (ancestors && ancestors.length && ancestors[0] && ancestors[0] !== 'null')\n return ancestors[0]; // the immediate embedder\n } catch (err) {\n /* not supported (Firefox) → fall through to referrer */\n }\n if (document.referrer) {\n try {\n return new URL(document.referrer).origin;\n } catch (err) {\n /* unparseable referrer */\n }\n }\n return null;\n }\n\n function blockHost(options: BBArcadeLockToHostOptions): void {\n if (blocked) return;\n blocked = true;\n if (typeof options.onBlocked === 'function') {\n try {\n options.onBlocked();\n } catch (err) {\n /* the game's own handler threw — nothing more we can do */\n }\n return;\n }\n if (options.redirect) {\n try {\n (window.top as Window).location.href = options.redirect; // escape the framing if allowed\n return;\n } catch (err) {\n try {\n window.location.href = options.redirect;\n return;\n } catch (err2) {\n /* navigation blocked (sandbox) → fall through to the splash */\n }\n }\n }\n try {\n // Link the splash out to Bounty Board so a player who lands on a scraped\n // copy can reach the real game. target=\"_blank\" works even from a\n // sandboxed re-host iframe that can't navigate its top; the canonical\n // production URL is intentional (a copy blocked anywhere points home).\n document.documentElement.innerHTML =\n '<div style=\"position:fixed;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;' +\n 'font-family:system-ui,-apple-system,sans-serif;background:#1a1206;color:#fff;text-align:center;padding:24px;\">' +\n '<div style=\"font-size:18px;font-weight:700;\">This game isn\\'t available here</div>' +\n '<a href=\"' +\n BOUNTY_BOARD_URL +\n '\" target=\"_blank\" rel=\"noopener\" ' +\n 'style=\"display:inline-block;background:#f5b942;color:#1a1206;font-weight:700;font-size:14px;' +\n 'text-decoration:none;padding:10px 20px;border-radius:999px;\">Play the original on Bounty Board</a>' +\n '</div>';\n } catch (err) {\n /* document not writable — the silent `blocked` flag still stops SDK posts */\n }\n }\n\n /** The original best-effort check (browser signals + host handshake). */\n function lockToHostBestEffort(options: BBArcadeLockToHostOptions, allow: string[]): void {\n const origin = embeddingOriginSync();\n if (origin != null) {\n if (!hostnameAllowed(origin, allow)) blockHost(options);\n return; // conclusive without the parent\n }\n // Opaque-origin build with no referrer: ask the parent where we're hosted.\n request('host').then(\n function (res) {\n const r = res as { origin?: string } | null;\n if (!hostnameAllowed(r && r.origin, allow)) blockHost(options);\n },\n function () {\n blockHost(options); // no Bounty Board parent answered\n }\n );\n }\n\n function lockToHost(options?: BBArcadeLockToHostOptions): void {\n const opts = options || {};\n const allow = DEFAULT_ALLOW.slice();\n if (opts.allow && opts.allow.length) {\n for (let i = 0; i < opts.allow.length; i++) {\n const host = toAllowedHost(opts.allow[i]);\n if (host) allow.push(host);\n }\n }\n // Signed mode ({ signed: true }): demand a server-signed origin\n // attestation from the parent and verify it cryptographically. Graceful\n // degradation is deliberate and narrow: no crypto.subtle (insecure dev\n // context) or an honest \"not configured\" reply falls back to the\n // best-effort check; a PRESENT attestation that fails verification, or no\n // parent answering at all, blocks.\n if (opts.signed) {\n if (!(window.crypto && window.crypto.subtle)) {\n lockToHostBestEffort(opts, allow);\n return;\n }\n request('host_attest').then(\n function (res) {\n const r = res as { origin: string; attestation: HostAttestation | null } | null;\n if (!r || !r.attestation) {\n lockToHostBestEffort(opts, allow); // host has no signing key yet\n return;\n }\n verifyHostAttestation(r.attestation, r.origin).then(function (ok) {\n if (!ok || !hostnameAllowed(r.attestation && r.attestation.origin, allow))\n blockHost(opts);\n });\n },\n function () {\n blockHost(opts); // no Bounty Board parent answered\n }\n );\n return;\n }\n lockToHostBestEffort(opts, allow);\n }\n\n // ── Rewarded ads (Google H5 placement API, host-gated) ─────────────────────\n\n function nextAdBreakId(): string {\n rewardedBreakSequence += 1;\n return [\n 'bbad',\n Date.now().toString(36),\n rewardedBreakSequence.toString(36),\n Math.random().toString(36).slice(2, 10),\n ].join('_');\n }\n\n function configure(nextConfig?: BBArcadeConfig): void {\n if (!nextConfig || typeof nextConfig !== 'object') return;\n const rewardedAds = nextConfig.rewardedAds;\n if (!rewardedAds || typeof rewardedAds !== 'object') return;\n\n if (rewardedAds.enabled !== undefined) {\n config.rewardedAds.enabled = rewardedAds.enabled !== false;\n }\n if (rewardedAds.adChannel !== undefined) {\n config.rewardedAds.adChannel = cleanText(rewardedAds.adChannel);\n }\n if (rewardedAds.testMode !== undefined) {\n config.rewardedAds.testMode = toBoolean(rewardedAds.testMode);\n }\n if (rewardedAds.preload !== undefined) {\n config.rewardedAds.preload = toBoolean(rewardedAds.preload);\n }\n if (\n typeof rewardedAds.loadTimeoutMs === 'number' &&\n isFinite(rewardedAds.loadTimeoutMs) &&\n rewardedAds.loadTimeoutMs > 0\n ) {\n config.rewardedAds.loadTimeoutMs = Math.min(15000, Math.floor(rewardedAds.loadTimeoutMs));\n }\n if (config.rewardedAds.preload) preloadRewardedAds();\n }\n\n // init() promises waiting on the host's config message (the real handshake:\n // the host re-sends its config whenever the game posts init/ready, so a\n // late-loading SDK can't miss the load-time push).\n let configWaiters: Array<() => void> = [];\n\n function notifyConfigReceived(): void {\n const waiters = configWaiters;\n configWaiters = [];\n for (let i = 0; i < waiters.length; i++) safeCall(waiters[i]);\n }\n\n function applyHostConfig(message: unknown): void {\n if (!message || typeof message !== 'object') return;\n const msg = message as {\n source?: string;\n type?: string;\n player?: unknown;\n rewardedAds?: {\n enabled?: unknown;\n adChannel?: unknown;\n testMode?: unknown;\n preload?: unknown;\n };\n };\n if (msg.source !== HOST_MESSAGE_SOURCE || msg.type !== 'config') return;\n\n hostConfigReceived = true;\n\n // Player display identity (name + avatar only; null for guests). Only\n // applied when the key is present, so an older host that doesn't send it\n // can't clear a value a newer message already delivered.\n if (msg.player !== undefined) {\n hostPlayer = sanitizePlayer(msg.player);\n }\n\n const rewardedAds = msg.rewardedAds;\n if (rewardedAds && typeof rewardedAds === 'object') {\n hostConfig.rewardedAds.received = true;\n if (rewardedAds.enabled !== undefined) {\n hostConfig.rewardedAds.enabled = toBoolean(rewardedAds.enabled);\n }\n if (rewardedAds.adChannel !== undefined) {\n hostConfig.rewardedAds.adChannel = cleanText(rewardedAds.adChannel);\n }\n if (rewardedAds.testMode !== undefined) {\n hostConfig.rewardedAds.testMode = toBoolean(rewardedAds.testMode);\n }\n if (rewardedAds.preload !== undefined) {\n hostConfig.rewardedAds.preload = toBoolean(rewardedAds.preload);\n }\n\n if (\n hostConfig.rewardedAds.enabled &&\n (hostConfig.rewardedAds.preload || config.rewardedAds.preload)\n ) {\n preloadRewardedAds();\n }\n }\n\n notifyConfigReceived();\n }\n\n function areRewardedAdsEnabled(): boolean {\n return config.rewardedAds.enabled !== false && hostConfig.rewardedAds.enabled === true;\n }\n\n function installAdPlacementShim(): void {\n const w = window as unknown as AdsWindow;\n w.adsbygoogle = w.adsbygoogle || [];\n if (typeof w.adBreak !== 'function') {\n w.adBreak = function (placement) {\n (w.adsbygoogle as unknown[]).push(placement);\n };\n }\n if (typeof w.adConfig !== 'function') {\n w.adConfig = function (settings) {\n (w.adsbygoogle as unknown[]).push(settings);\n };\n }\n }\n\n function ensureAdPlacement(\n options: NormalizedRewardedOptions\n ): Promise<AdsWindow['adBreak'] | null> {\n if (typeof document === 'undefined') return Promise.resolve(null);\n installAdPlacementShim();\n const w = window as unknown as AdsWindow;\n if (typeof w.adBreak !== 'function') return Promise.resolve(null);\n if (adPlacementLoad) return adPlacementLoad;\n\n adPlacementLoad = new Promise(function (resolve) {\n let script = document.getElementById(AD_PLACEMENT_SCRIPT_ID);\n if (!script) {\n const el = document.createElement('script');\n el.id = AD_PLACEMENT_SCRIPT_ID;\n el.async = true;\n el.src = AD_PLACEMENT_SRC;\n el.crossOrigin = 'anonymous';\n el.setAttribute('data-ad-client', ADSENSE_CLIENT_ID);\n if (options.adChannel) el.setAttribute('data-ad-channel', options.adChannel);\n if (options.testMode) el.setAttribute('data-adbreak-test', 'on');\n (document.head || document.documentElement).appendChild(el);\n script = el;\n }\n resolve(w.adBreak);\n });\n\n return adPlacementLoad;\n }\n\n function requestAdPreload(): void {\n const w = window as unknown as AdsWindow;\n if (adPreloadConfigured || typeof w.adConfig !== 'function') return;\n adPreloadConfigured = true;\n try {\n w.adConfig({ preloadAdBreaks: 'on' });\n } catch (err) {\n // Preloading is best-effort; the rewarded placement can still report\n // availability through adBreakDone.\n }\n }\n\n function normalizeRewardedOptions(\n options?: BBArcadeRewardedAdOptions\n ): NormalizedRewardedOptions {\n const opts = options && typeof options === 'object' ? options : {};\n const hostHasConfig = hostConfig.rewardedAds.received;\n return {\n placement: cleanText(opts.placement || opts.name, 'rewarded'),\n reward: cleanText(opts.reward, 'reward'),\n adBreakId: cleanText(opts.adBreakId, nextAdBreakId(), 128),\n size: cleanRewardedSize(opts.size),\n adChannel: cleanText(\n hostHasConfig\n ? hostConfig.rewardedAds.adChannel\n : opts.adChannel || config.rewardedAds.adChannel\n ),\n testMode: hostHasConfig\n ? hostConfig.rewardedAds.testMode\n : opts.testMode !== undefined\n ? toBoolean(opts.testMode)\n : config.rewardedAds.testMode || hostConfig.rewardedAds.testMode,\n loadTimeoutMs:\n typeof opts.loadTimeoutMs === 'number' && isFinite(opts.loadTimeoutMs)\n ? Math.min(15000, Math.max(1, Math.floor(opts.loadTimeoutMs)))\n : config.rewardedAds.loadTimeoutMs,\n beforeReward: opts.beforeReward,\n adViewed: opts.adViewed,\n adDismissed: opts.adDismissed,\n adBreakDone: opts.adBreakDone,\n onReward: opts.onReward,\n onDismissed: opts.onDismissed,\n onDone: opts.onDone,\n onError: opts.onError,\n onUnavailable: opts.onUnavailable,\n };\n }\n\n function rewardedAd(rawOptions?: BBArcadeRewardedAdOptions): Promise<BBArcadeRewardedAdResult> {\n const options = normalizeRewardedOptions(rawOptions);\n const base: AdResultBase = {\n placement: options.placement,\n reward: options.reward,\n adBreakId: options.adBreakId,\n };\n if (options.size) base.size = options.size;\n\n post('rewarded_ad', undefined, Object.assign({ event: 'requested' }, base));\n if (!areRewardedAdsEnabled()) {\n const disabled: BBArcadeRewardedAdResult = Object.assign(\n { status: 'unavailable' as const, error: 'host_disabled' },\n base\n );\n post('rewarded_ad', undefined, Object.assign({ event: 'unavailable' }, disabled));\n safeCall(options.onUnavailable, disabled);\n safeCall(options.onDone, disabled);\n return Promise.resolve(disabled);\n }\n\n return ensureAdPlacement(options).then(function (adBreak) {\n if (typeof adBreak !== 'function') {\n const unavailable: BBArcadeRewardedAdResult = Object.assign(\n { status: 'unavailable' as const, error: 'ad_break_unavailable' },\n base\n );\n post('rewarded_ad', undefined, Object.assign({ event: 'unavailable' }, unavailable));\n safeCall(options.onUnavailable, unavailable);\n safeCall(options.onDone, unavailable);\n return unavailable;\n }\n requestAdPreload();\n\n return new Promise<BBArcadeRewardedAdResult>(function (resolve) {\n let resolved = false;\n let status: BBArcadeRewardedAdResult['status'] = 'unavailable';\n let rewardOffered = false;\n const waitTimer = setTimeout(function () {\n if (rewardOffered || resolved) return;\n const timeout: BBArcadeRewardedAdResult = Object.assign(\n { status: 'unavailable' as const, error: 'ad_break_timeout' },\n base\n );\n post('rewarded_ad', undefined, Object.assign({ event: 'unavailable' }, timeout));\n safeCall(options.onUnavailable, timeout);\n done(timeout);\n }, options.loadTimeoutMs);\n\n function done(result?: Partial<BBArcadeRewardedAdResult>): void {\n if (resolved) return;\n resolved = true;\n clearTimeout(waitTimer);\n const finalResult = Object.assign(\n { status: 'unavailable' as BBArcadeRewardedAdResult['status'] },\n base,\n result || {}\n );\n post('rewarded_ad', undefined, Object.assign({ event: 'done' }, finalResult));\n safeCall(options.onDone, finalResult);\n resolve(finalResult);\n }\n\n function startAd(showAdFn: () => void): void {\n // A late beforeReward (ad becomes ready after the load timeout already\n // resolved the placement 'unavailable') must not still show an ad — the\n // game has moved on, so it would be an unrewarded, involuntary impression.\n if (resolved) return;\n rewardOffered = true;\n clearTimeout(waitTimer);\n status = 'ready';\n let shown = false;\n function show(): void {\n if (shown) return;\n shown = true;\n post('rewarded_ad', undefined, Object.assign({ event: 'started' }, base));\n try {\n showAdFn();\n } catch (err) {\n const showError: BBArcadeRewardedAdResult = Object.assign(\n { status: 'error' as const, error: 'show_ad_error' },\n base\n );\n post('rewarded_ad', undefined, Object.assign({ event: 'error' }, showError));\n safeCall(options.onError, showError);\n done(showError);\n }\n }\n\n post('rewarded_ad', undefined, Object.assign({ event: 'ready' }, base));\n try {\n if (typeof options.beforeReward === 'function') options.beforeReward(show);\n else show();\n } catch (err) {\n const beforeError: BBArcadeRewardedAdResult = Object.assign(\n { status: 'error' as const, error: 'before_reward_error' },\n base\n );\n post('rewarded_ad', undefined, Object.assign({ event: 'error' }, beforeError));\n safeCall(options.onError, beforeError);\n done(beforeError);\n }\n }\n\n try {\n adBreak({\n type: 'reward',\n name: options.placement,\n size: options.size || undefined,\n beforeReward: startAd,\n adViewed: function () {\n status = 'viewed';\n const viewed: BBArcadeRewardedAdResult = Object.assign({ status: status }, base);\n post('rewarded_ad', undefined, Object.assign({ event: 'viewed' }, viewed));\n safeCall(options.adViewed, viewed);\n safeCall(options.onReward, viewed);\n },\n adDismissed: function () {\n if (status !== 'viewed') status = 'dismissed';\n const dismissed: BBArcadeRewardedAdResult = Object.assign({ status: status }, base);\n post('rewarded_ad', undefined, Object.assign({ event: 'dismissed' }, dismissed));\n safeCall(options.adDismissed, dismissed);\n safeCall(options.onDismissed, dismissed);\n },\n adBreakDone: function (placementInfo: unknown) {\n const result: Partial<BBArcadeRewardedAdResult> =\n rewardOffered || status !== 'unavailable'\n ? { status: status }\n : { status: 'unavailable', error: 'no_rewarded_ad' };\n if (placementInfo && typeof placementInfo === 'object') {\n result.breakStatus = cleanText(\n (placementInfo as { breakStatus?: unknown }).breakStatus\n );\n }\n if (result.status === 'unavailable') {\n post(\n 'rewarded_ad',\n undefined,\n Object.assign({ event: 'unavailable' }, base, result)\n );\n safeCall(\n options.onUnavailable,\n Object.assign({ status: 'unavailable' as const }, base, result)\n );\n }\n safeCall(options.adBreakDone, placementInfo);\n done(result);\n },\n });\n } catch (err) {\n const error: BBArcadeRewardedAdResult = Object.assign(\n { status: 'error' as const, error: 'ad_break_error' },\n base\n );\n post('rewarded_ad', undefined, Object.assign({ event: 'error' }, error));\n safeCall(options.onError, error);\n done(error);\n }\n });\n });\n }\n\n function preloadRewardedAds(rawOptions?: BBArcadeRewardedAdOptions): Promise<boolean> {\n const options = normalizeRewardedOptions(rawOptions);\n if (!areRewardedAdsEnabled()) return Promise.resolve(false);\n return ensureAdPlacement(options).then(function (adBreak) {\n if (typeof adBreak !== 'function') return false;\n requestAdPreload();\n return true;\n });\n }\n\n function whenHostConfig(graceMs: number): Promise<void> {\n if (hostConfigReceived || !isEmbedded()) return Promise.resolve();\n return new Promise(function (resolve) {\n const timer = setTimeout(resolve, graceMs);\n configWaiters.push(function () {\n clearTimeout(timer);\n resolve();\n });\n });\n }\n\n // The player's display identity, delivered with the host's config message.\n // Waits on the same handshake (and grace) as init(), so it resolves null —\n // never hangs — for guests, standalone play, or when no host ever answers.\n function getPlayer(): Promise<BBArcadePlayer | null> {\n if (blocked) return Promise.resolve(null);\n return whenHostConfig(INIT_CONFIG_GRACE_MS).then(function () {\n // Hand out a copy so a game can't mutate the SDK's own record.\n return hostPlayer ? { name: hostPlayer.name, avatarUrl: hostPlayer.avatarUrl } : null;\n });\n }\n\n function init(options?: BBArcadeConfig): Promise<void> {\n configure(options);\n // Announce to the host. A Bounty Board host replies to init/ready with its\n // config message, which resolves this promise — so config delivery doesn't\n // depend on the host's load-time push racing the SDK attaching a listener.\n post('init');\n return whenHostConfig(INIT_CONFIG_GRACE_MS);\n }\n\n function ready(): void {\n post('ready');\n }\n\n function normalizeRewardedBreakInput(\n optionsOrOnStart?: BBArcadeRewardedBreakOptions | (() => void)\n ): BBArcadeRewardedBreakOptions {\n if (typeof optionsOrOnStart === 'function') return { onStart: optionsOrOnStart };\n return optionsOrOnStart && typeof optionsOrOnStart === 'object' ? optionsOrOnStart : {};\n }\n\n function rewardedBreak(\n optionsOrOnStart?: BBArcadeRewardedBreakOptions | (() => void)\n ): Promise<boolean> {\n const rawOptions = normalizeRewardedBreakInput(optionsOrOnStart);\n const normalized = normalizeRewardedOptions(rawOptions);\n const base: AdResultBase = {\n adBreakId: normalized.adBreakId,\n placement: normalized.placement,\n reward: normalized.reward,\n };\n if (normalized.size) base.size = normalized.size;\n\n if (rewardedBreakActive) {\n post(\n 'rewarded_ad',\n undefined,\n Object.assign(\n { event: 'unavailable', status: 'unavailable', error: 'ad_in_progress' },\n base\n )\n );\n return Promise.resolve(false);\n }\n\n rewardedBreakActive = true;\n let startCalled = false;\n return rewardedAd(\n Object.assign({}, rawOptions, {\n beforeReward: function (showAd: () => void) {\n if (startCalled) return;\n startCalled = true;\n safeCall(rawOptions.onStart);\n showAd();\n },\n })\n ).then(\n function (result) {\n rewardedBreakActive = false;\n return Boolean(result && result.status === 'viewed');\n },\n function () {\n rewardedBreakActive = false;\n return false;\n }\n );\n }\n\n window.addEventListener('message', function (event: MessageEvent) {\n // Host config must come from the embedding page itself — a null/other\n // source (nested frame, synthetic event) must not be able to flip flags.\n if (event.source !== window.parent) return;\n if (!hostnameAllowed(event.origin, DEFAULT_ALLOW)) return;\n applyHostConfig(event.data);\n });\n\n const sdk: BBArcadeSDK = {\n lockToHost: lockToHost,\n init: init,\n configure: configure,\n preloadRewardedAds: preloadRewardedAds,\n preloadRewardedAd: preloadRewardedAds,\n ready: ready,\n gameLoadingFinished: ready,\n gameplayStart: function () {\n post('gameplay_start');\n },\n gameplayStop: function () {\n post('gameplay_stop');\n },\n submitScore: function (score, opts) {\n post('score', score, opts && opts.mode === 'daily' ? { mode: 'daily' } : undefined);\n },\n gameOver: function (score, opts) {\n post('gameover', score, opts && opts.mode === 'daily' ? { mode: 'daily' } : undefined);\n },\n xrSessionStart: function () {\n post('xr_session_start');\n },\n xrSessionEnd: function () {\n post('xr_session_end');\n },\n rewardedAd: rewardedAd,\n showRewardedAd: rewardedAd,\n rewardedBreak: rewardedBreak,\n save: function (blob) {\n return request('save', String(blob)) as Promise<void>;\n },\n load: function () {\n return request('load') as Promise<string | null>;\n },\n getPlayer: getPlayer,\n getVariant: function (key, variants) {\n const sorted = Array.isArray(variants) ? variants.slice().sort() : [];\n const fallback = sorted.length > 0 ? sorted[0] : null;\n if (typeof key !== 'string' || !key || sorted.length < 2) {\n return Promise.resolve(fallback);\n }\n return request('experiment', { key: key, variants: sorted }).then(\n function (variant) {\n return typeof variant === 'string' ? variant : fallback;\n },\n function () {\n return fallback;\n }\n );\n },\n version: VERSION,\n };\n\n // Internal, non-public hook used by the multiplayer module to ride the same\n // request/response transport (mp_ticket). Hidden behind a symbol-free\n // underscore name and excluded from BBArcadeSDK so it never becomes API.\n (sdk as BBArcadeSDK & { _request?: typeof request })._request = request;\n\n return sdk;\n}\n","/**\n * Inert BBArcade used when the module is evaluated without a `window` (SSR,\n * tests, bundler prerender). Mirrors the real SDK's standalone semantics:\n * fire-and-forget calls no-op, save/load reject fast with 'unsupported',\n * getPlayer resolves null, getVariant resolves its alphabetical control.\n */\nimport { VERSION } from './protocol';\nimport type {\n BBArcadeError,\n BBArcadeErrorCode,\n BBArcadeRewardedAdResult,\n BBArcadeSDK,\n} from './types';\n\nfunction sdkError(code: BBArcadeErrorCode): BBArcadeError {\n const err = new Error(code) as BBArcadeError;\n err.code = code;\n return err;\n}\n\nexport function createInertBBArcade(): BBArcadeSDK {\n const noop = () => {};\n const unavailable = (): Promise<BBArcadeRewardedAdResult> =>\n Promise.resolve({\n status: 'unavailable',\n error: 'ad_break_unavailable',\n placement: 'rewarded',\n reward: 'reward',\n adBreakId: 'bbad_inert',\n });\n return {\n lockToHost: noop,\n init: () => Promise.resolve(),\n configure: noop,\n preloadRewardedAds: () => Promise.resolve(false),\n preloadRewardedAd: () => Promise.resolve(false),\n ready: noop,\n gameLoadingFinished: noop,\n gameplayStart: noop,\n gameplayStop: noop,\n submitScore: noop,\n gameOver: noop,\n xrSessionStart: noop,\n xrSessionEnd: noop,\n rewardedAd: unavailable,\n showRewardedAd: unavailable,\n rewardedBreak: () => Promise.resolve(false),\n save: () => Promise.reject(sdkError('unsupported')),\n load: () => Promise.reject(sdkError('unsupported')),\n getPlayer: () => Promise.resolve(null),\n getVariant: (key, variants) => {\n const sorted = Array.isArray(variants) ? variants.slice().sort() : [];\n return Promise.resolve(sorted.length > 0 ? sorted[0] : null);\n },\n version: VERSION,\n };\n}\n"],"mappings":"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","names":["sdkError"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/protocol.ts","../src/core.ts","../src/inert.ts"],"sourcesContent":["/**\n * @bountyboard/arcade-sdk — module entry.\n *\n * import { BBArcade } from '@bountyboard/arcade-sdk';\n *\n * Importing attaches the SDK's postMessage listeners immediately (the Bounty\n * Board host pushes its config at load time, so listener timing matters) but\n * does NOT install a window.BBArcade global — that's the script-tag build\n * (https://www.bountyboard.gg/arcade-sdk/v1.js, or the './global' subpath).\n * Evaluated without a window (SSR/prerender) it exports an inert instance with\n * standalone semantics, so importing is always safe.\n */\nimport { createBBArcade } from './core';\nimport { createInertBBArcade } from './inert';\nimport type { BBArcadeSDK } from './types';\n\nexport const BBArcade: BBArcadeSDK =\n typeof window === 'undefined' ? createInertBBArcade() : createBBArcade();\n\nexport default BBArcade;\n\nexport { VERSION as PROTOCOL_VERSION } from './protocol';\nexport type {\n BBArcadeConfig,\n BBArcadeError,\n BBArcadeErrorCode,\n BBArcadeLockToHostOptions,\n BBArcadePlayer,\n BBArcadePreparedRewardedAd,\n BBArcadePrepareRewardedAdOptions,\n BBArcadeRewardedAdOptions,\n BBArcadeRewardedAdPreparation,\n BBArcadeRewardedAdPrepareFailure,\n BBArcadeRewardedAdResult,\n BBArcadeRewardedAdStatus,\n BBArcadeRewardedAdsConfig,\n BBArcadeRewardedBreakOptions,\n BBArcadeSDK,\n} from './types';\n","/**\n * Wire-protocol constants for the bb-arcade postMessage protocol. The protocol\n * version is deliberately decoupled from the npm package's semver: every\n * message carries `v: VERSION`, and the host accepts all messages of the same\n * major protocol. Bump VERSION only for a breaking wire change (which also\n * means a new /arcade-sdk/v2.js URL).\n */\nexport const VERSION = 1;\n\n/** `source` field on every message the game/SDK posts to the embedding page. */\nexport const SDK_MESSAGE_SOURCE = 'bb-arcade';\n\n/** `source` field on every message the Bounty Board host posts to the game. */\nexport const HOST_MESSAGE_SOURCE = 'bb-arcade-host';\n","/**\n * Bounty Board Arcade SDK core — a faithful, typed port of the original\n * public/arcade-sdk.js IIFE. The whole SDK is one factory so every piece of\n * state (blocked flag, pending requests, ad config, host config) lives in one\n * closure per instance, exactly like the original script. Behavior parity with\n * the shipped v1 script is the hard requirement here; the v1 behavior test\n * suite (src/__tests__/arcade-sdk.test.ts at the repo root) runs against the\n * generated artifact and must pass unchanged.\n */\nimport { HOST_MESSAGE_SOURCE, SDK_MESSAGE_SOURCE, VERSION } from './protocol';\nimport type {\n BBArcadeConfig,\n BBArcadeError,\n BBArcadeErrorCode,\n BBArcadeLockToHostOptions,\n BBArcadePlayer,\n BBArcadePreparedRewardedAd,\n BBArcadePrepareRewardedAdOptions,\n BBArcadeRewardedAdOptions,\n BBArcadeRewardedAdPreparation,\n BBArcadeRewardedAdPrepareFailure,\n BBArcadeRewardedAdResult,\n BBArcadeRewardedBreakOptions,\n BBArcadeSDK,\n} from './types';\n\n// Canonical production home, used for the site-lock \"play the original\" link.\nconst BOUNTY_BOARD_URL = 'https://www.bountyboard.gg/arcade';\nconst ADSENSE_CLIENT_ID = 'ca-pub-7727110228190547';\nconst AD_PLACEMENT_SRC =\n 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=' + ADSENSE_CLIENT_ID;\nconst AD_PLACEMENT_SCRIPT_ID = 'bb-arcade-h5-ads';\nconst DEFAULT_AD_LOAD_TIMEOUT_MS = 6000;\nconst SAVE_TIMEOUT_MS = 15000;\n// How long init() waits for the host's config reply before resolving anyway.\n// Standalone play resolves immediately (there is no host to answer), so this\n// grace only delays games embedded somewhere that isn't a Bounty Board host.\nconst INIT_CONFIG_GRACE_MS = 1500;\n\n// Allowed by default: bountyboard.gg (and any *.bountyboard.gg subdomain),\n// Bounty Board's fixed staging alias, and localhost/127.0.0.1 for local\n// development — i.e. every environment Bounty Board itself serves the game\n// from. The staging alias is a single PINNED Bounty Board deployment, so\n// hardcoding that one host is safe; we still deliberately DON'T trust shared\n// or dynamic preview domains broadly (e.g. *.vercel.app) — a per-deploy\n// preview host or your own site must be added via the `allow` option.\n// This list gates BOTH the sitelock AND which parent origin may send the host\n// config (player identity / rewarded-ads), so a missing environment here\n// silently breaks the whole SDK handshake there, not just the sitelock.\nconst DEFAULT_ALLOW = [\n 'bountyboard.gg',\n 'bountyboard-staging.vercel.app',\n 'localhost',\n '127.0.0.1',\n];\n\n// Public half of the sitelock attestation keypair (ECDSA P-256, SPKI). The\n// matching private key lives ONLY in Bounty Board server env\n// (ARCADE_SITELOCK_PRIVATE_KEY); a re-hosting site can neither sign a fresh\n// attestation nor replay a captured one (the sender-origin check below).\nconst SITELOCK_PUBLIC_KEY_B64 =\n 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE6WC8fJweDpfKRcZW9Q9eOLxPXmFCO8R8lY1kfZbuAQt65E0CTu2rM80XfW3nYrSAqO+Eev8gxrGS0bAnNaMDGg==';\n/** Attestations older/newer than this are stale (replay window). */\nconst SITELOCK_MAX_SKEW_MS = 5 * 60 * 1000;\n\n/**\n * Google H5 ads globals the SDK shims/loads on demand. A standalone shape\n * (not `extends Window`) so host apps that augment Window themselves (e.g.\n * test files declaring `adBreak?: jest.Mock`) can't create a conflicting\n * interface under a shared tsconfig.\n */\ntype AdsWindow = {\n adsbygoogle?: unknown[];\n adBreak?: (placement: Record<string, unknown>) => void;\n adConfig?: (settings: Record<string, unknown>) => void;\n};\n\ninterface HostAttestation {\n origin: string;\n ts: number;\n sig: string;\n}\n\n/** The identifying fields every rewarded-ad result/lifecycle event carries. */\ninterface AdResultBase {\n placement: string;\n reward: string;\n adBreakId: string;\n size?: 'small' | 'medium' | 'large';\n}\n\ninterface PendingEntry {\n resolve: (value: unknown) => void;\n reject: (err: BBArcadeError) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\ninterface NormalizedRewardedOptions {\n placement: string;\n reward: string;\n adBreakId: string;\n size: '' | 'small' | 'medium' | 'large';\n adChannel: string;\n testMode: boolean;\n loadTimeoutMs: number;\n beforeReward?: (showAd: () => void) => void;\n adViewed?: (result: BBArcadeRewardedAdResult) => void;\n adDismissed?: (result: BBArcadeRewardedAdResult) => void;\n adBreakDone?: (placementInfo: unknown) => void;\n onReward?: (result: BBArcadeRewardedAdResult) => void;\n onDismissed?: (result: BBArcadeRewardedAdResult) => void;\n onDone?: (result: BBArcadeRewardedAdResult) => void;\n onError?: (result: BBArcadeRewardedAdResult) => void;\n onUnavailable?: (result: BBArcadeRewardedAdResult) => void;\n}\n\nfunction sdkError(code: BBArcadeErrorCode): BBArcadeError {\n const err = new Error(code) as BBArcadeError;\n err.code = code;\n return err;\n}\n\nfunction b64ToBytes(b64: string): Uint8Array {\n const bin = atob(b64);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\n return bytes;\n}\n\nfunction cleanText(value: unknown, fallback?: string, max?: number): string {\n if (typeof value !== 'string') return fallback || '';\n return value.replace(/[^\\w:.-]+/g, '_').slice(0, max || 80) || fallback || '';\n}\n\nfunction toBoolean(value: unknown): boolean {\n return value === true || value === 'true' || value === '1';\n}\n\nfunction cleanRewardedSize(value: unknown): '' | 'small' | 'medium' | 'large' {\n return value === 'small' || value === 'medium' || value === 'large' ? value : '';\n}\n\n/**\n * Google requires showAdFn to run while the browser still has transient user\n * activation from the player's direct click/tap. Fail closed when the browser\n * cannot positively prove that activation is active; showing without it is\n * both unreliable and contrary to the placement API contract.\n */\nfunction hasTransientUserActivation(): boolean {\n if (typeof navigator === 'undefined') return false;\n const activation = (\n navigator as Navigator & {\n userActivation?: { isActive?: boolean };\n }\n ).userActivation;\n return activation?.isActive === true;\n}\n\nfunction safeCall<T>(fn: ((arg: T) => void) | undefined, arg?: T): void {\n if (typeof fn !== 'function') return;\n try {\n fn(arg as T);\n } catch (err) {\n setTimeout(function () {\n throw err;\n }, 0);\n }\n}\n\n// Normalize an allow-list entry to a bare hostname, so a game author can pass a\n// plain host (\"mygame.com\"), a full URL (\"https://mygame.com/play\"), or a\n// host:port and still match against the embedder's hostname.\nfunction toAllowedHost(value: unknown): string {\n const raw = String(value).toLowerCase().trim();\n if (!raw) return '';\n try {\n return new URL(raw.indexOf('//') === -1 ? 'https://' + raw : raw).hostname;\n } catch (err) {\n return raw;\n }\n}\n\nfunction hostnameAllowed(origin: unknown, allowHosts: string[]): boolean {\n if (!origin || origin === 'null' || typeof origin !== 'string') return false;\n let host: string;\n try {\n host = new URL(origin).hostname.toLowerCase();\n } catch (err) {\n return false;\n }\n for (let i = 0; i < allowHosts.length; i++) {\n const allowed = allowHosts[i];\n // exact host, or a subdomain of an allowed host (\".allowed\")\n if (host === allowed || host.slice(-(allowed.length + 1)) === '.' + allowed) return true;\n }\n return false;\n}\n\n/**\n * Verify a host attestation: shape, freshness, the LOAD-BEARING sender\n * check (the postMessage carrying it must come from the origin it attests —\n * event.origin is browser-authenticated, so a stolen attestation replayed\n * from another site fails here), then the ECDSA signature over\n * \"<origin>:<ts>\". Resolves boolean; never throws.\n */\nfunction verifyHostAttestation(att: unknown, senderOrigin: string): Promise<boolean> {\n const a = att as HostAttestation | null | undefined;\n if (!a || typeof a.origin !== 'string' || typeof a.ts !== 'number' || typeof a.sig !== 'string')\n return Promise.resolve(false);\n if (a.origin !== senderOrigin) return Promise.resolve(false);\n if (Math.abs(Date.now() - a.ts) > SITELOCK_MAX_SKEW_MS) return Promise.resolve(false);\n try {\n return window.crypto.subtle\n .importKey(\n 'spki',\n b64ToBytes(SITELOCK_PUBLIC_KEY_B64),\n { name: 'ECDSA', namedCurve: 'P-256' },\n false,\n ['verify']\n )\n .then(function (key) {\n return window.crypto.subtle.verify(\n { name: 'ECDSA', hash: 'SHA-256' },\n key,\n b64ToBytes(a.sig),\n new TextEncoder().encode(a.origin + ':' + a.ts)\n );\n })\n .then(\n function (ok) {\n return ok === true;\n },\n function () {\n return false;\n }\n );\n } catch (err) {\n return Promise.resolve(false);\n }\n}\n\n// Normalize the host-sent player identity. Only a non-empty string name\n// counts; the avatar is a plain URL string or null. Anything malformed\n// collapses to null so games can rely on the { name, avatarUrl } shape.\nfunction sanitizePlayer(value: unknown): BBArcadePlayer | null {\n if (!value || typeof value !== 'object') return null;\n const raw = value as { name?: unknown; avatarUrl?: unknown };\n const name = typeof raw.name === 'string' ? raw.name.trim().slice(0, 120) : '';\n if (!name) return null;\n const avatarUrl =\n typeof raw.avatarUrl === 'string' && raw.avatarUrl.trim() ? raw.avatarUrl : null;\n return { name: name, avatarUrl: avatarUrl };\n}\n\n/**\n * Build one SDK instance. Attaches this instance's `message` listeners to\n * `window` immediately (the host pushes its config at load time, so listener\n * timing is part of the protocol). Browser-only — the module entry substitutes\n * an inert stub when `window` is undefined (SSR-safety for bundled games).\n */\nexport function createBBArcade(): BBArcadeSDK {\n let adPlacementLoad: Promise<AdsWindow['adBreak'] | null> | null = null;\n let adPreloadConfigured = false;\n let rewardedBreakActive: { state: 'loading' | 'ready' | 'showing' } | null = null;\n let rewardedBreakSequence = 0;\n\n function isLocalAdHost(): boolean {\n try {\n const protocol = window.location && window.location.protocol;\n const host = window.location && window.location.hostname;\n return (\n protocol === 'file:' ||\n host === 'localhost' ||\n host === '127.0.0.1' ||\n host === '::1' ||\n host === '[::1]'\n );\n } catch (err) {\n return false;\n }\n }\n\n const localAdHost = isLocalAdHost();\n const config = {\n rewardedAds: {\n enabled: true,\n adChannel: '',\n testMode: localAdHost,\n loadTimeoutMs: DEFAULT_AD_LOAD_TIMEOUT_MS,\n preload: false,\n },\n };\n const hostConfig = {\n rewardedAds: {\n received: false,\n enabled: localAdHost,\n adChannel: '',\n testMode: localAdHost,\n preload: false,\n },\n };\n // True once ANY valid host config message has arrived — this (not the\n // rewarded-ads sub-flag) is what resolves the init()/getPlayer() handshake.\n let hostConfigReceived = false;\n // The logged-in player's display identity from the host config:\n // { name, avatarUrl } or null for guests. Display name + avatar ONLY — the\n // host never sends ids, emails, or roles.\n let hostPlayer: BBArcadePlayer | null = null;\n\n // Set once lockToHost() decides the game is running somewhere it shouldn't.\n // After that the SDK goes silent so a scraped copy can't keep posting.\n let blocked = false;\n\n const pending: Record<string, PendingEntry> = {};\n let seq = 0;\n\n // The game can be embedded by any Bounty Board environment (prod, staging,\n // previews), so target '*' — the payload carries nothing sensitive and the\n // parent page validates the message's source window + origin itself.\n function post(type: string, score?: number, extra?: object): void {\n if (blocked) return;\n const message: Record<string, unknown> = { source: SDK_MESSAGE_SOURCE, v: VERSION, type: type };\n if (typeof score === 'number' && isFinite(score)) message.score = Math.floor(score);\n if (extra && typeof extra === 'object') {\n const fields = extra as Record<string, unknown>;\n for (const key in fields) {\n if (Object.prototype.hasOwnProperty.call(fields, key) && fields[key] !== undefined) {\n message[key] = fields[key];\n }\n }\n }\n try {\n window.parent.postMessage(message, '*');\n } catch (err) {\n /* not embedded — standalone play is fine */\n }\n }\n\n function isEmbedded(): boolean {\n try {\n return window.parent != null && window.parent !== window;\n } catch (err) {\n return true; // touching a cross-origin parent threw → we are embedded\n }\n }\n\n // ── Request/response over postMessage (cloud save, experiments, host) ──────\n // Cloud saves only work for Bounty-Board-hosted build uploads: those run in a\n // sandbox with no localStorage/IndexedDB, so saves go through the embedding\n // page (which holds the player's login). save/load return a Promise; the\n // parent posts back a result for the matching requestId. Rejections are Error\n // objects that also carry a machine-readable `code` property.\n function request(type: string, payload?: unknown): Promise<unknown> {\n return new Promise(function (resolve, reject) {\n if (blocked) return reject(sdkError('error'));\n // Standalone play (no embedding page): nothing will ever answer, so fail\n // fast instead of hanging until the timeout.\n if (!isEmbedded()) return reject(sdkError('unsupported'));\n const requestId = type + '_' + ++seq + '_' + Date.now();\n const timer = setTimeout(function () {\n if (pending[requestId]) {\n delete pending[requestId];\n reject(sdkError('error'));\n }\n }, SAVE_TIMEOUT_MS);\n pending[requestId] = { resolve: resolve, reject: reject, timer: timer };\n try {\n window.parent.postMessage(\n {\n source: SDK_MESSAGE_SOURCE,\n v: VERSION,\n type: type,\n requestId: requestId,\n payload: payload,\n },\n '*'\n );\n } catch (err) {\n clearTimeout(timer);\n delete pending[requestId];\n reject(sdkError('error'));\n }\n });\n }\n\n window.addEventListener('message', function (event: MessageEvent) {\n // Replies come from the embedding page only; ignore anything else (e.g. a\n // co-resident ad/nested frame, or a null-source synthetic event) so it\n // can't resolve a pending request with a forged payload. Mirrors the\n // host-config listener's source check below.\n if (event.source !== window.parent) return;\n const data = event.data as\n | {\n source?: string;\n type?: string;\n requestId?: string;\n ok?: boolean;\n code?: BBArcadeErrorCode;\n data?: unknown;\n attestation?: unknown;\n variant?: unknown;\n }\n | null\n | undefined;\n if (!data || data.source !== SDK_MESSAGE_SOURCE) return;\n // Any '<type>_result' with a pending requestId is a legitimate reply: the\n // sender is already proven to be the embedding host (source check above)\n // and requestIds are per-request — so enumerating reply types here would\n // only create a synchronized-edit hazard with the host (a forgotten entry\n // = that request silently timing out after 15s).\n if (typeof data.type !== 'string' || !data.type.endsWith('_result')) return;\n const entry = pending[data.requestId as string];\n if (!entry) return;\n clearTimeout(entry.timer);\n delete pending[data.requestId as string];\n // The browser-authenticated sender origin is authoritative. Never trust a\n // parent-supplied origin string: an arbitrary embedder could claim to be\n // bountyboard.gg and enable host-only SDK features.\n if (data.type === 'host_result') return entry.resolve({ origin: event.origin });\n if (data.type === 'host_attest_result')\n // Keep the browser-authenticated sender origin alongside the claimed\n // attestation — the verifier requires them to MATCH.\n return entry.resolve({ origin: event.origin, attestation: data.attestation || null });\n if (data.type === 'experiment_result')\n return entry.resolve(typeof data.variant === 'string' ? data.variant : null);\n // Generic ok/code convention (save_result, load_result, mp_ticket_result,\n // and any future reply type): resolve the carried data — load()'s \"no\n // save yet\" stays null, save()'s bare ack stays undefined.\n if (data.ok)\n entry.resolve(\n data.type === 'load_result' ? (data.data != null ? data.data : null) : data.data\n );\n else entry.reject(sdkError(data.code || 'error'));\n });\n\n // ── Site lock (anti scrape-and-reupload) ───────────────────────────────────\n\n // The origin of the page that embeds this game, read from the browser (which\n // the embedding page can't forge). Returns null when it can't be determined\n // synchronously (opaque-origin builds with no referrer) — callers fall back to\n // the host handshake then.\n function embeddingOriginSync(): string | null {\n try {\n if (window.top === window.self) return window.location.origin; // not embedded\n } catch (err) {\n /* cross-origin top → we are embedded; keep probing */\n }\n try {\n const ancestors = window.location.ancestorOrigins;\n if (ancestors && ancestors.length && ancestors[0] && ancestors[0] !== 'null')\n return ancestors[0]; // the immediate embedder\n } catch (err) {\n /* not supported (Firefox) → fall through to referrer */\n }\n if (document.referrer) {\n try {\n return new URL(document.referrer).origin;\n } catch (err) {\n /* unparseable referrer */\n }\n }\n return null;\n }\n\n function blockHost(options: BBArcadeLockToHostOptions): void {\n if (blocked) return;\n blocked = true;\n if (typeof options.onBlocked === 'function') {\n try {\n options.onBlocked();\n } catch (err) {\n /* the game's own handler threw — nothing more we can do */\n }\n return;\n }\n if (options.redirect) {\n try {\n (window.top as Window).location.href = options.redirect; // escape the framing if allowed\n return;\n } catch (err) {\n try {\n window.location.href = options.redirect;\n return;\n } catch (err2) {\n /* navigation blocked (sandbox) → fall through to the splash */\n }\n }\n }\n try {\n // Link the splash out to Bounty Board so a player who lands on a scraped\n // copy can reach the real game. target=\"_blank\" works even from a\n // sandboxed re-host iframe that can't navigate its top; the canonical\n // production URL is intentional (a copy blocked anywhere points home).\n document.documentElement.innerHTML =\n '<div style=\"position:fixed;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;' +\n 'font-family:system-ui,-apple-system,sans-serif;background:#1a1206;color:#fff;text-align:center;padding:24px;\">' +\n '<div style=\"font-size:18px;font-weight:700;\">This game isn\\'t available here</div>' +\n '<a href=\"' +\n BOUNTY_BOARD_URL +\n '\" target=\"_blank\" rel=\"noopener\" ' +\n 'style=\"display:inline-block;background:#f5b942;color:#1a1206;font-weight:700;font-size:14px;' +\n 'text-decoration:none;padding:10px 20px;border-radius:999px;\">Play the original on Bounty Board</a>' +\n '</div>';\n } catch (err) {\n /* document not writable — the silent `blocked` flag still stops SDK posts */\n }\n }\n\n /** The original best-effort check (browser signals + host handshake). */\n function lockToHostBestEffort(options: BBArcadeLockToHostOptions, allow: string[]): void {\n const origin = embeddingOriginSync();\n if (origin != null) {\n if (!hostnameAllowed(origin, allow)) blockHost(options);\n return; // conclusive without the parent\n }\n // Opaque-origin build with no referrer: ask the parent where we're hosted.\n request('host').then(\n function (res) {\n const r = res as { origin?: string } | null;\n if (!hostnameAllowed(r && r.origin, allow)) blockHost(options);\n },\n function () {\n blockHost(options); // no Bounty Board parent answered\n }\n );\n }\n\n function lockToHost(options?: BBArcadeLockToHostOptions): void {\n const opts = options || {};\n const allow = DEFAULT_ALLOW.slice();\n if (opts.allow && opts.allow.length) {\n for (let i = 0; i < opts.allow.length; i++) {\n const host = toAllowedHost(opts.allow[i]);\n if (host) allow.push(host);\n }\n }\n // Signed mode ({ signed: true }): demand a server-signed origin\n // attestation from the parent and verify it cryptographically. Graceful\n // degradation is deliberate and narrow: no crypto.subtle (insecure dev\n // context) or an honest \"not configured\" reply falls back to the\n // best-effort check; a PRESENT attestation that fails verification, or no\n // parent answering at all, blocks.\n if (opts.signed) {\n if (!(window.crypto && window.crypto.subtle)) {\n lockToHostBestEffort(opts, allow);\n return;\n }\n request('host_attest').then(\n function (res) {\n const r = res as { origin: string; attestation: HostAttestation | null } | null;\n if (!r || !r.attestation) {\n lockToHostBestEffort(opts, allow); // host has no signing key yet\n return;\n }\n verifyHostAttestation(r.attestation, r.origin).then(function (ok) {\n if (!ok || !hostnameAllowed(r.attestation && r.attestation.origin, allow))\n blockHost(opts);\n });\n },\n function () {\n blockHost(opts); // no Bounty Board parent answered\n }\n );\n return;\n }\n lockToHostBestEffort(opts, allow);\n }\n\n // ── Rewarded ads (Google H5 placement API, host-gated) ─────────────────────\n\n function nextAdBreakId(): string {\n rewardedBreakSequence += 1;\n return [\n 'bbad',\n Date.now().toString(36),\n rewardedBreakSequence.toString(36),\n Math.random().toString(36).slice(2, 10),\n ].join('_');\n }\n\n function configure(nextConfig?: BBArcadeConfig): void {\n if (!nextConfig || typeof nextConfig !== 'object') return;\n const rewardedAds = nextConfig.rewardedAds;\n if (!rewardedAds || typeof rewardedAds !== 'object') return;\n\n if (rewardedAds.enabled !== undefined) {\n config.rewardedAds.enabled = rewardedAds.enabled !== false;\n }\n if (rewardedAds.adChannel !== undefined) {\n config.rewardedAds.adChannel = cleanText(rewardedAds.adChannel);\n }\n if (rewardedAds.testMode !== undefined) {\n config.rewardedAds.testMode = toBoolean(rewardedAds.testMode);\n }\n if (rewardedAds.preload !== undefined) {\n config.rewardedAds.preload = toBoolean(rewardedAds.preload);\n }\n if (\n typeof rewardedAds.loadTimeoutMs === 'number' &&\n isFinite(rewardedAds.loadTimeoutMs) &&\n rewardedAds.loadTimeoutMs > 0\n ) {\n config.rewardedAds.loadTimeoutMs = Math.min(15000, Math.floor(rewardedAds.loadTimeoutMs));\n }\n if (config.rewardedAds.preload) preloadRewardedAds();\n }\n\n // init() promises waiting on the host's config message (the real handshake:\n // the host re-sends its config whenever the game posts init/ready, so a\n // late-loading SDK can't miss the load-time push).\n let configWaiters: Array<() => void> = [];\n\n function notifyConfigReceived(): void {\n const waiters = configWaiters;\n configWaiters = [];\n for (let i = 0; i < waiters.length; i++) safeCall(waiters[i]);\n }\n\n function applyHostConfig(message: unknown): void {\n if (!message || typeof message !== 'object') return;\n const msg = message as {\n source?: string;\n type?: string;\n player?: unknown;\n rewardedAds?: {\n enabled?: unknown;\n adChannel?: unknown;\n testMode?: unknown;\n preload?: unknown;\n };\n };\n if (msg.source !== HOST_MESSAGE_SOURCE || msg.type !== 'config') return;\n\n hostConfigReceived = true;\n\n // Player display identity (name + avatar only; null for guests). Only\n // applied when the key is present, so an older host that doesn't send it\n // can't clear a value a newer message already delivered.\n if (msg.player !== undefined) {\n hostPlayer = sanitizePlayer(msg.player);\n }\n\n const rewardedAds = msg.rewardedAds;\n if (rewardedAds && typeof rewardedAds === 'object') {\n hostConfig.rewardedAds.received = true;\n if (rewardedAds.enabled !== undefined) {\n hostConfig.rewardedAds.enabled = toBoolean(rewardedAds.enabled);\n }\n if (rewardedAds.adChannel !== undefined) {\n hostConfig.rewardedAds.adChannel = cleanText(rewardedAds.adChannel);\n }\n if (rewardedAds.testMode !== undefined) {\n hostConfig.rewardedAds.testMode = toBoolean(rewardedAds.testMode);\n }\n if (rewardedAds.preload !== undefined) {\n hostConfig.rewardedAds.preload = toBoolean(rewardedAds.preload);\n }\n\n if (\n hostConfig.rewardedAds.enabled &&\n (hostConfig.rewardedAds.preload || config.rewardedAds.preload)\n ) {\n preloadRewardedAds();\n }\n }\n\n notifyConfigReceived();\n }\n\n function areRewardedAdsEnabled(): boolean {\n return config.rewardedAds.enabled !== false && hostConfig.rewardedAds.enabled === true;\n }\n\n function installAdPlacementShim(): void {\n const w = window as unknown as AdsWindow;\n w.adsbygoogle = w.adsbygoogle || [];\n if (typeof w.adBreak !== 'function') {\n w.adBreak = function (placement) {\n (w.adsbygoogle as unknown[]).push(placement);\n };\n }\n if (typeof w.adConfig !== 'function') {\n w.adConfig = function (settings) {\n (w.adsbygoogle as unknown[]).push(settings);\n };\n }\n }\n\n function ensureAdPlacement(\n options: NormalizedRewardedOptions\n ): Promise<AdsWindow['adBreak'] | null> {\n if (typeof document === 'undefined') return Promise.resolve(null);\n installAdPlacementShim();\n const w = window as unknown as AdsWindow;\n if (typeof w.adBreak !== 'function') return Promise.resolve(null);\n if (adPlacementLoad) return adPlacementLoad;\n\n adPlacementLoad = new Promise(function (resolve) {\n let script = document.getElementById(AD_PLACEMENT_SCRIPT_ID);\n if (!script) {\n const el = document.createElement('script');\n el.id = AD_PLACEMENT_SCRIPT_ID;\n el.async = true;\n el.src = AD_PLACEMENT_SRC;\n el.crossOrigin = 'anonymous';\n el.setAttribute('data-ad-client', ADSENSE_CLIENT_ID);\n if (options.adChannel) el.setAttribute('data-ad-channel', options.adChannel);\n if (options.testMode) el.setAttribute('data-adbreak-test', 'on');\n (document.head || document.documentElement).appendChild(el);\n script = el;\n }\n resolve(w.adBreak);\n });\n\n return adPlacementLoad;\n }\n\n function requestAdPreload(): void {\n const w = window as unknown as AdsWindow;\n if (adPreloadConfigured || typeof w.adConfig !== 'function') return;\n adPreloadConfigured = true;\n try {\n w.adConfig({ preloadAdBreaks: 'on' });\n } catch (err) {\n // Preloading is best-effort; the rewarded placement can still report\n // availability through adBreakDone.\n }\n }\n\n function normalizeRewardedOptions(\n options?: BBArcadeRewardedAdOptions\n ): NormalizedRewardedOptions {\n const opts = options && typeof options === 'object' ? options : {};\n const hostHasConfig = hostConfig.rewardedAds.received;\n return {\n placement: cleanText(opts.placement || opts.name, 'rewarded'),\n reward: cleanText(opts.reward, 'reward'),\n adBreakId: cleanText(opts.adBreakId, nextAdBreakId(), 128),\n size: cleanRewardedSize(opts.size),\n adChannel: cleanText(\n hostHasConfig\n ? hostConfig.rewardedAds.adChannel\n : opts.adChannel || config.rewardedAds.adChannel\n ),\n testMode: hostHasConfig\n ? hostConfig.rewardedAds.testMode\n : opts.testMode !== undefined\n ? toBoolean(opts.testMode)\n : config.rewardedAds.testMode || hostConfig.rewardedAds.testMode,\n loadTimeoutMs:\n typeof opts.loadTimeoutMs === 'number' && isFinite(opts.loadTimeoutMs)\n ? Math.min(15000, Math.max(1, Math.floor(opts.loadTimeoutMs)))\n : config.rewardedAds.loadTimeoutMs,\n beforeReward: opts.beforeReward,\n adViewed: opts.adViewed,\n adDismissed: opts.adDismissed,\n adBreakDone: opts.adBreakDone,\n onReward: opts.onReward,\n onDismissed: opts.onDismissed,\n onDone: opts.onDone,\n onError: opts.onError,\n onUnavailable: opts.onUnavailable,\n };\n }\n\n function rewardedAd(rawOptions?: BBArcadeRewardedAdOptions): Promise<BBArcadeRewardedAdResult> {\n const options = normalizeRewardedOptions(rawOptions);\n const base: AdResultBase = {\n placement: options.placement,\n reward: options.reward,\n adBreakId: options.adBreakId,\n };\n if (options.size) base.size = options.size;\n\n post('rewarded_ad', undefined, Object.assign({ event: 'requested' }, base));\n if (!areRewardedAdsEnabled()) {\n const disabled: BBArcadeRewardedAdResult = Object.assign(\n { status: 'unavailable' as const, error: 'host_disabled' },\n base\n );\n post('rewarded_ad', undefined, Object.assign({ event: 'unavailable' }, disabled));\n safeCall(options.onUnavailable, disabled);\n safeCall(options.onDone, disabled);\n return Promise.resolve(disabled);\n }\n\n return ensureAdPlacement(options).then(function (adBreak) {\n if (typeof adBreak !== 'function') {\n const unavailable: BBArcadeRewardedAdResult = Object.assign(\n { status: 'unavailable' as const, error: 'ad_break_unavailable' },\n base\n );\n post('rewarded_ad', undefined, Object.assign({ event: 'unavailable' }, unavailable));\n safeCall(options.onUnavailable, unavailable);\n safeCall(options.onDone, unavailable);\n return unavailable;\n }\n requestAdPreload();\n\n return new Promise<BBArcadeRewardedAdResult>(function (resolve) {\n let resolved = false;\n let status: BBArcadeRewardedAdResult['status'] = 'unavailable';\n let rewardOffered = false;\n const waitTimer = setTimeout(function () {\n if (rewardOffered || resolved) return;\n const timeout: BBArcadeRewardedAdResult = Object.assign(\n { status: 'unavailable' as const, error: 'ad_break_timeout' },\n base\n );\n post('rewarded_ad', undefined, Object.assign({ event: 'unavailable' }, timeout));\n safeCall(options.onUnavailable, timeout);\n done(timeout);\n }, options.loadTimeoutMs);\n\n function done(result?: Partial<BBArcadeRewardedAdResult>): void {\n if (resolved) return;\n resolved = true;\n clearTimeout(waitTimer);\n const finalResult = Object.assign(\n { status: 'unavailable' as BBArcadeRewardedAdResult['status'] },\n base,\n result || {}\n );\n post('rewarded_ad', undefined, Object.assign({ event: 'done' }, finalResult));\n safeCall(options.onDone, finalResult);\n resolve(finalResult);\n }\n\n function startAd(showAdFn: () => void): void {\n // A late beforeReward (ad becomes ready after the load timeout already\n // resolved the placement 'unavailable') must not still show an ad — the\n // game has moved on, so it would be an unrewarded, involuntary impression.\n if (resolved) return;\n rewardOffered = true;\n clearTimeout(waitTimer);\n status = 'ready';\n let shown = false;\n function show(): void {\n if (shown) return;\n shown = true;\n if (!hasTransientUserActivation()) {\n const activationError: BBArcadeRewardedAdResult = Object.assign(\n { status: 'error' as const, error: 'direct_user_action_required' },\n base\n );\n post('rewarded_ad', undefined, Object.assign({ event: 'error' }, activationError));\n safeCall(options.onError, activationError);\n done(activationError);\n return;\n }\n post('rewarded_ad', undefined, Object.assign({ event: 'started' }, base));\n try {\n showAdFn();\n } catch (err) {\n const showError: BBArcadeRewardedAdResult = Object.assign(\n { status: 'error' as const, error: 'show_ad_error' },\n base\n );\n post('rewarded_ad', undefined, Object.assign({ event: 'error' }, showError));\n safeCall(options.onError, showError);\n done(showError);\n }\n }\n\n post('rewarded_ad', undefined, Object.assign({ event: 'ready' }, base));\n try {\n if (typeof options.beforeReward === 'function') options.beforeReward(show);\n else show();\n } catch (err) {\n const beforeError: BBArcadeRewardedAdResult = Object.assign(\n { status: 'error' as const, error: 'before_reward_error' },\n base\n );\n post('rewarded_ad', undefined, Object.assign({ event: 'error' }, beforeError));\n // If the callback called show() before throwing, Google's ad is\n // already in flight. Keep the placement alive so a later adViewed\n // can still grant the reward; this error is diagnostic only.\n if (shown) return;\n safeCall(options.onError, beforeError);\n done(beforeError);\n }\n }\n\n try {\n adBreak({\n type: 'reward',\n name: options.placement,\n beforeReward: startAd,\n adViewed: function () {\n if (resolved) return;\n status = 'viewed';\n const viewed: BBArcadeRewardedAdResult = Object.assign({ status: status }, base);\n post('rewarded_ad', undefined, Object.assign({ event: 'viewed' }, viewed));\n safeCall(options.adViewed, viewed);\n safeCall(options.onReward, viewed);\n },\n adDismissed: function () {\n if (resolved) return;\n if (status !== 'viewed') status = 'dismissed';\n const dismissed: BBArcadeRewardedAdResult = Object.assign({ status: status }, base);\n post('rewarded_ad', undefined, Object.assign({ event: 'dismissed' }, dismissed));\n safeCall(options.adDismissed, dismissed);\n safeCall(options.onDismissed, dismissed);\n },\n adBreakDone: function (placementInfo: unknown) {\n if (resolved) return;\n const result: Partial<BBArcadeRewardedAdResult> =\n rewardOffered || status !== 'unavailable'\n ? { status: status }\n : { status: 'unavailable', error: 'no_rewarded_ad' };\n if (placementInfo && typeof placementInfo === 'object') {\n result.breakStatus = cleanText(\n (placementInfo as { breakStatus?: unknown }).breakStatus\n );\n }\n if (result.status === 'unavailable') {\n post(\n 'rewarded_ad',\n undefined,\n Object.assign({ event: 'unavailable' }, base, result)\n );\n safeCall(\n options.onUnavailable,\n Object.assign({ status: 'unavailable' as const }, base, result)\n );\n }\n safeCall(options.adBreakDone, placementInfo);\n done(result);\n },\n });\n } catch (err) {\n const error: BBArcadeRewardedAdResult = Object.assign(\n { status: 'error' as const, error: 'ad_break_error' },\n base\n );\n post('rewarded_ad', undefined, Object.assign({ event: 'error' }, error));\n safeCall(options.onError, error);\n done(error);\n }\n });\n });\n }\n\n /**\n * Two-stage rewarded flow. Google's beforeReward callback can arrive after\n * the original request stack, when the browser's transient user activation\n * is already gone. Retain the SDK's one-shot show function here and hand it\n * back to the game so show() itself can be invoked synchronously by the\n * player's later click/tap.\n *\n * The existing rewardedAd implementation remains the single lifecycle\n * engine: this wrapper only owns beforeReward, so callbacks, structured\n * errors, Google's breakStatus, and the viewed-only reward signal cannot\n * drift between the legacy and prepared APIs.\n */\n function prepareRewardedAd(\n rawOptions?: BBArcadePrepareRewardedAdOptions\n ): Promise<BBArcadeRewardedAdPreparation> {\n const normalized = normalizeRewardedOptions(rawOptions);\n const base: AdResultBase = {\n placement: normalized.placement,\n reward: normalized.reward,\n adBreakId: normalized.adBreakId,\n };\n if (normalized.size) base.size = normalized.size;\n\n let ready = false;\n let finalPromise: Promise<BBArcadeRewardedAdResult>;\n\n return new Promise<BBArcadeRewardedAdPreparation>(function (resolvePreparation) {\n finalPromise = rewardedAd(\n Object.assign({}, rawOptions, {\n // Preserve the id used by the ready handle and every lifecycle event;\n // rewardedAd normalizes again, but this explicit id keeps both stages\n // tied to the same placement.\n adBreakId: normalized.adBreakId,\n beforeReward: function (showAd: () => void) {\n if (ready) return;\n ready = true;\n let shown = false;\n const prepared: BBArcadePreparedRewardedAd = Object.assign(\n { status: 'ready' as const },\n base,\n {\n show: function (): Promise<BBArcadeRewardedAdResult> {\n // The first meaningful operation is synchronous. A click\n // handler can call prepared.show() without an await/microtask\n // stealing the browser's transient user activation.\n if (!shown) {\n shown = true;\n // Do not pause the game/audio when the display attempt is\n // about to fail closed for missing activation. showAd()\n // still runs so the caller receives the structured error.\n if (hasTransientUserActivation()) {\n safeCall(rawOptions && rawOptions.onStart);\n }\n showAd();\n }\n return finalPromise;\n },\n }\n );\n resolvePreparation(prepared);\n },\n })\n );\n\n finalPromise.then(function (result) {\n // No beforeReward means Google never offered an ad. Return the exact\n // structured terminal result, including error + breakStatus, rather\n // than collapsing the preparation to a boolean.\n if (!ready) resolvePreparation(result as BBArcadeRewardedAdPrepareFailure);\n });\n });\n }\n\n function preloadRewardedAds(rawOptions?: BBArcadeRewardedAdOptions): Promise<boolean> {\n const options = normalizeRewardedOptions(rawOptions);\n if (!areRewardedAdsEnabled()) return Promise.resolve(false);\n return ensureAdPlacement(options).then(function (adBreak) {\n if (typeof adBreak !== 'function') return false;\n requestAdPreload();\n return true;\n });\n }\n\n function whenHostConfig(graceMs: number): Promise<void> {\n if (hostConfigReceived || !isEmbedded()) return Promise.resolve();\n return new Promise(function (resolve) {\n const timer = setTimeout(resolve, graceMs);\n configWaiters.push(function () {\n clearTimeout(timer);\n resolve();\n });\n });\n }\n\n // The player's display identity, delivered with the host's config message.\n // Waits on the same handshake (and grace) as init(), so it resolves null —\n // never hangs — for guests, standalone play, or when no host ever answers.\n function getPlayer(): Promise<BBArcadePlayer | null> {\n if (blocked) return Promise.resolve(null);\n return whenHostConfig(INIT_CONFIG_GRACE_MS).then(function () {\n // Hand out a copy so a game can't mutate the SDK's own record.\n return hostPlayer ? { name: hostPlayer.name, avatarUrl: hostPlayer.avatarUrl } : null;\n });\n }\n\n function init(options?: BBArcadeConfig): Promise<void> {\n configure(options);\n // Announce to the host. A Bounty Board host replies to init/ready with its\n // config message, which resolves this promise — so config delivery doesn't\n // depend on the host's load-time push racing the SDK attaching a listener.\n post('init');\n return whenHostConfig(INIT_CONFIG_GRACE_MS);\n }\n\n function ready(): void {\n post('ready');\n }\n\n function normalizeRewardedBreakInput(\n optionsOrOnStart?: BBArcadeRewardedBreakOptions | (() => void)\n ): BBArcadeRewardedBreakOptions {\n if (typeof optionsOrOnStart === 'function') return { onStart: optionsOrOnStart };\n return optionsOrOnStart && typeof optionsOrOnStart === 'object' ? optionsOrOnStart : {};\n }\n\n function rewardedBreak(\n optionsOrOnStart?: BBArcadeRewardedBreakOptions | (() => void)\n ): Promise<boolean> {\n const rawOptions = normalizeRewardedBreakInput(optionsOrOnStart);\n const normalized = normalizeRewardedOptions(rawOptions);\n const base: AdResultBase = {\n adBreakId: normalized.adBreakId,\n placement: normalized.placement,\n reward: normalized.reward,\n };\n if (normalized.size) base.size = normalized.size;\n\n if (rewardedBreakActive && rewardedBreakActive.state !== 'ready') {\n post(\n 'rewarded_ad',\n undefined,\n Object.assign(\n { event: 'unavailable', status: 'unavailable', error: 'ad_in_progress' },\n base\n )\n );\n return Promise.resolve(false);\n }\n\n const activeBreak: NonNullable<typeof rewardedBreakActive> = { state: 'loading' };\n rewardedBreakActive = activeBreak;\n let startCalled = false;\n const callerBeforeReward = rawOptions.beforeReward;\n return rewardedAd(\n Object.assign({}, rawOptions, {\n beforeReward: function (showAd: () => void) {\n if (rewardedBreakActive === activeBreak) activeBreak.state = 'ready';\n const showWithStart = function (): void {\n // A newer unshown rewardedBreak supersedes this retained offer.\n // Ignore a stale click so it cannot pause the game or emit a\n // misleading started event after Google has invalidated it.\n if (startCalled || rewardedBreakActive !== activeBreak) return;\n startCalled = true;\n activeBreak.state = 'showing';\n if (hasTransientUserActivation()) safeCall(rawOptions.onStart);\n showAd();\n };\n // Preserve the caller's two-stage readiness UI. Legacy callers that\n // omitted beforeReward keep their original one-call behavior, but the\n // guarded show wrapper above now fails closed if activation is gone.\n if (typeof callerBeforeReward === 'function') callerBeforeReward(showWithStart);\n else showWithStart();\n },\n })\n ).then(\n function (result) {\n if (rewardedBreakActive === activeBreak) rewardedBreakActive = null;\n return Boolean(result && result.status === 'viewed');\n },\n function () {\n if (rewardedBreakActive === activeBreak) rewardedBreakActive = null;\n return false;\n }\n );\n }\n\n window.addEventListener('message', function (event: MessageEvent) {\n // Host config must come from the embedding page itself — a null/other\n // source (nested frame, synthetic event) must not be able to flip flags.\n if (event.source !== window.parent) return;\n if (!hostnameAllowed(event.origin, DEFAULT_ALLOW)) return;\n applyHostConfig(event.data);\n });\n\n const sdk: BBArcadeSDK = {\n lockToHost: lockToHost,\n init: init,\n configure: configure,\n preloadRewardedAds: preloadRewardedAds,\n preloadRewardedAd: preloadRewardedAds,\n ready: ready,\n gameLoadingFinished: ready,\n gameplayStart: function () {\n post('gameplay_start');\n },\n gameplayStop: function () {\n post('gameplay_stop');\n },\n submitScore: function (score, opts) {\n post('score', score, opts && opts.mode === 'daily' ? { mode: 'daily' } : undefined);\n },\n gameOver: function (score, opts) {\n post('gameover', score, opts && opts.mode === 'daily' ? { mode: 'daily' } : undefined);\n },\n xrSessionStart: function () {\n post('xr_session_start');\n },\n xrSessionEnd: function () {\n post('xr_session_end');\n },\n rewardedAd: rewardedAd,\n showRewardedAd: rewardedAd,\n prepareRewardedAd: prepareRewardedAd,\n prepareRewardedBreak: prepareRewardedAd,\n rewardedBreak: rewardedBreak,\n save: function (blob) {\n return request('save', String(blob)) as Promise<void>;\n },\n load: function () {\n return request('load') as Promise<string | null>;\n },\n getPlayer: getPlayer,\n getVariant: function (key, variants) {\n const sorted = Array.isArray(variants) ? variants.slice().sort() : [];\n const fallback = sorted.length > 0 ? sorted[0] : null;\n if (typeof key !== 'string' || !key || sorted.length < 2) {\n return Promise.resolve(fallback);\n }\n return request('experiment', { key: key, variants: sorted }).then(\n function (variant) {\n return typeof variant === 'string' ? variant : fallback;\n },\n function () {\n return fallback;\n }\n );\n },\n version: VERSION,\n };\n\n // Internal, non-public hook used by the multiplayer module to ride the same\n // request/response transport (mp_ticket). Hidden behind a symbol-free\n // underscore name and excluded from BBArcadeSDK so it never becomes API.\n (sdk as BBArcadeSDK & { _request?: typeof request })._request = request;\n\n return sdk;\n}\n","/**\n * Inert BBArcade used when the module is evaluated without a `window` (SSR,\n * tests, bundler prerender). Mirrors the real SDK's standalone semantics:\n * fire-and-forget calls no-op, save/load reject fast with 'unsupported',\n * getPlayer resolves null, getVariant resolves its alphabetical control.\n */\nimport { VERSION } from './protocol';\nimport type {\n BBArcadeError,\n BBArcadeErrorCode,\n BBArcadeRewardedAdPreparation,\n BBArcadeRewardedAdResult,\n BBArcadeSDK,\n} from './types';\n\nfunction sdkError(code: BBArcadeErrorCode): BBArcadeError {\n const err = new Error(code) as BBArcadeError;\n err.code = code;\n return err;\n}\n\nexport function createInertBBArcade(): BBArcadeSDK {\n const noop = () => {};\n const unavailable = (): Promise<BBArcadeRewardedAdResult> =>\n Promise.resolve({\n status: 'unavailable',\n error: 'ad_break_unavailable',\n placement: 'rewarded',\n reward: 'reward',\n adBreakId: 'bbad_inert',\n });\n const prepareUnavailable = (): Promise<BBArcadeRewardedAdPreparation> =>\n Promise.resolve({\n status: 'unavailable',\n error: 'ad_break_unavailable',\n placement: 'rewarded',\n reward: 'reward',\n adBreakId: 'bbad_inert',\n });\n return {\n lockToHost: noop,\n init: () => Promise.resolve(),\n configure: noop,\n preloadRewardedAds: () => Promise.resolve(false),\n preloadRewardedAd: () => Promise.resolve(false),\n ready: noop,\n gameLoadingFinished: noop,\n gameplayStart: noop,\n gameplayStop: noop,\n submitScore: noop,\n gameOver: noop,\n xrSessionStart: noop,\n xrSessionEnd: noop,\n rewardedAd: unavailable,\n showRewardedAd: unavailable,\n prepareRewardedAd: prepareUnavailable,\n prepareRewardedBreak: prepareUnavailable,\n rewardedBreak: () => Promise.resolve(false),\n save: () => Promise.reject(sdkError('unsupported')),\n load: () => Promise.reject(sdkError('unsupported')),\n getPlayer: () => Promise.resolve(null),\n getVariant: (key, variants) => {\n const sorted = Array.isArray(variants) ? variants.slice().sort() : [];\n return Promise.resolve(sorted.length > 0 ? sorted[0] : null);\n },\n version: VERSION,\n };\n}\n"],"mappings":"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","names":["ready","sdkError"]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { B as BBArcadeSDK } from './types-B6xH-lDi.cjs';
2
- export { a as BBArcadeConfig, b as BBArcadeError, c as BBArcadeErrorCode, d as BBArcadeLockToHostOptions, e as BBArcadePlayer, f as BBArcadeRewardedAdOptions, g as BBArcadeRewardedAdResult, h as BBArcadeRewardedAdStatus, i as BBArcadeRewardedAdsConfig, j as BBArcadeRewardedBreakOptions } from './types-B6xH-lDi.cjs';
1
+ import { B as BBArcadeSDK } from './types-BKChtV3H.cjs';
2
+ export { a as BBArcadeConfig, b as BBArcadeError, c as BBArcadeErrorCode, d as BBArcadeLockToHostOptions, e as BBArcadePlayer, f as BBArcadePrepareRewardedAdOptions, g as BBArcadePreparedRewardedAd, h as BBArcadeRewardedAdOptions, i as BBArcadeRewardedAdPreparation, j as BBArcadeRewardedAdPrepareFailure, k as BBArcadeRewardedAdResult, l as BBArcadeRewardedAdStatus, m as BBArcadeRewardedAdsConfig, n as BBArcadeRewardedBreakOptions } from './types-BKChtV3H.cjs';
3
3
 
4
4
  /**
5
5
  * Wire-protocol constants for the bb-arcade postMessage protocol. The protocol
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { B as BBArcadeSDK } from './types-B6xH-lDi.js';
2
- export { a as BBArcadeConfig, b as BBArcadeError, c as BBArcadeErrorCode, d as BBArcadeLockToHostOptions, e as BBArcadePlayer, f as BBArcadeRewardedAdOptions, g as BBArcadeRewardedAdResult, h as BBArcadeRewardedAdStatus, i as BBArcadeRewardedAdsConfig, j as BBArcadeRewardedBreakOptions } from './types-B6xH-lDi.js';
1
+ import { B as BBArcadeSDK } from './types-BKChtV3H.js';
2
+ export { a as BBArcadeConfig, b as BBArcadeError, c as BBArcadeErrorCode, d as BBArcadeLockToHostOptions, e as BBArcadePlayer, f as BBArcadePrepareRewardedAdOptions, g as BBArcadePreparedRewardedAd, h as BBArcadeRewardedAdOptions, i as BBArcadeRewardedAdPreparation, j as BBArcadeRewardedAdPrepareFailure, k as BBArcadeRewardedAdResult, l as BBArcadeRewardedAdStatus, m as BBArcadeRewardedAdsConfig, n as BBArcadeRewardedBreakOptions } from './types-BKChtV3H.js';
3
3
 
4
4
  /**
5
5
  * Wire-protocol constants for the bb-arcade postMessage protocol. The protocol
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  BBArcade,
3
3
  VERSION,
4
4
  src_default
5
- } from "./chunk-WCGBR3MI.js";
5
+ } from "./chunk-OWOESH4X.js";
6
6
  export {
7
7
  BBArcade,
8
8
  VERSION as PROTOCOL_VERSION,
@@ -67,6 +67,11 @@ function toBoolean(value) {
67
67
  function cleanRewardedSize(value) {
68
68
  return value === "small" || value === "medium" || value === "large" ? value : "";
69
69
  }
70
+ function hasTransientUserActivation() {
71
+ if (typeof navigator === "undefined") return false;
72
+ const activation = navigator.userActivation;
73
+ return (activation == null ? void 0 : activation.isActive) === true;
74
+ }
70
75
  function safeCall(fn, arg) {
71
76
  if (typeof fn !== "function") return;
72
77
  try {
@@ -143,7 +148,7 @@ function sanitizePlayer(value) {
143
148
  function createBBArcade() {
144
149
  let adPlacementLoad = null;
145
150
  let adPreloadConfigured = false;
146
- let rewardedBreakActive = false;
151
+ let rewardedBreakActive = null;
147
152
  let rewardedBreakSequence = 0;
148
153
  function isLocalAdHost() {
149
154
  try {
@@ -554,6 +559,16 @@ function createBBArcade() {
554
559
  function show() {
555
560
  if (shown) return;
556
561
  shown = true;
562
+ if (!hasTransientUserActivation()) {
563
+ const activationError = Object.assign(
564
+ { status: "error", error: "direct_user_action_required" },
565
+ base
566
+ );
567
+ post("rewarded_ad", void 0, Object.assign({ event: "error" }, activationError));
568
+ safeCall(options.onError, activationError);
569
+ done(activationError);
570
+ return;
571
+ }
557
572
  post("rewarded_ad", void 0, Object.assign({ event: "started" }, base));
558
573
  try {
559
574
  showAdFn();
@@ -577,6 +592,7 @@ function createBBArcade() {
577
592
  base
578
593
  );
579
594
  post("rewarded_ad", void 0, Object.assign({ event: "error" }, beforeError));
595
+ if (shown) return;
580
596
  safeCall(options.onError, beforeError);
581
597
  done(beforeError);
582
598
  }
@@ -585,9 +601,9 @@ function createBBArcade() {
585
601
  adBreak({
586
602
  type: "reward",
587
603
  name: options.placement,
588
- size: options.size || void 0,
589
604
  beforeReward: startAd,
590
605
  adViewed: function() {
606
+ if (resolved) return;
591
607
  status = "viewed";
592
608
  const viewed = Object.assign({ status }, base);
593
609
  post("rewarded_ad", void 0, Object.assign({ event: "viewed" }, viewed));
@@ -595,6 +611,7 @@ function createBBArcade() {
595
611
  safeCall(options.onReward, viewed);
596
612
  },
597
613
  adDismissed: function() {
614
+ if (resolved) return;
598
615
  if (status !== "viewed") status = "dismissed";
599
616
  const dismissed = Object.assign({ status }, base);
600
617
  post("rewarded_ad", void 0, Object.assign({ event: "dismissed" }, dismissed));
@@ -602,6 +619,7 @@ function createBBArcade() {
602
619
  safeCall(options.onDismissed, dismissed);
603
620
  },
604
621
  adBreakDone: function(placementInfo) {
622
+ if (resolved) return;
605
623
  const result = rewardOffered || status !== "unavailable" ? { status } : { status: "unavailable", error: "no_rewarded_ad" };
606
624
  if (placementInfo && typeof placementInfo === "object") {
607
625
  result.breakStatus = cleanText(
@@ -635,6 +653,52 @@ function createBBArcade() {
635
653
  });
636
654
  });
637
655
  }
656
+ function prepareRewardedAd(rawOptions) {
657
+ const normalized = normalizeRewardedOptions(rawOptions);
658
+ const base = {
659
+ placement: normalized.placement,
660
+ reward: normalized.reward,
661
+ adBreakId: normalized.adBreakId
662
+ };
663
+ if (normalized.size) base.size = normalized.size;
664
+ let ready2 = false;
665
+ let finalPromise;
666
+ return new Promise(function(resolvePreparation) {
667
+ finalPromise = rewardedAd(
668
+ Object.assign({}, rawOptions, {
669
+ // Preserve the id used by the ready handle and every lifecycle event;
670
+ // rewardedAd normalizes again, but this explicit id keeps both stages
671
+ // tied to the same placement.
672
+ adBreakId: normalized.adBreakId,
673
+ beforeReward: function(showAd) {
674
+ if (ready2) return;
675
+ ready2 = true;
676
+ let shown = false;
677
+ const prepared = Object.assign(
678
+ { status: "ready" },
679
+ base,
680
+ {
681
+ show: function() {
682
+ if (!shown) {
683
+ shown = true;
684
+ if (hasTransientUserActivation()) {
685
+ safeCall(rawOptions && rawOptions.onStart);
686
+ }
687
+ showAd();
688
+ }
689
+ return finalPromise;
690
+ }
691
+ }
692
+ );
693
+ resolvePreparation(prepared);
694
+ }
695
+ })
696
+ );
697
+ finalPromise.then(function(result) {
698
+ if (!ready2) resolvePreparation(result);
699
+ });
700
+ });
701
+ }
638
702
  function preloadRewardedAds(rawOptions) {
639
703
  const options = normalizeRewardedOptions(rawOptions);
640
704
  if (!areRewardedAdsEnabled()) return Promise.resolve(false);
@@ -681,7 +745,7 @@ function createBBArcade() {
681
745
  reward: normalized.reward
682
746
  };
683
747
  if (normalized.size) base.size = normalized.size;
684
- if (rewardedBreakActive) {
748
+ if (rewardedBreakActive && rewardedBreakActive.state !== "ready") {
685
749
  post(
686
750
  "rewarded_ad",
687
751
  void 0,
@@ -692,24 +756,32 @@ function createBBArcade() {
692
756
  );
693
757
  return Promise.resolve(false);
694
758
  }
695
- rewardedBreakActive = true;
759
+ const activeBreak = { state: "loading" };
760
+ rewardedBreakActive = activeBreak;
696
761
  let startCalled = false;
762
+ const callerBeforeReward = rawOptions.beforeReward;
697
763
  return rewardedAd(
698
764
  Object.assign({}, rawOptions, {
699
765
  beforeReward: function(showAd) {
700
- if (startCalled) return;
701
- startCalled = true;
702
- safeCall(rawOptions.onStart);
703
- showAd();
766
+ if (rewardedBreakActive === activeBreak) activeBreak.state = "ready";
767
+ const showWithStart = function() {
768
+ if (startCalled || rewardedBreakActive !== activeBreak) return;
769
+ startCalled = true;
770
+ activeBreak.state = "showing";
771
+ if (hasTransientUserActivation()) safeCall(rawOptions.onStart);
772
+ showAd();
773
+ };
774
+ if (typeof callerBeforeReward === "function") callerBeforeReward(showWithStart);
775
+ else showWithStart();
704
776
  }
705
777
  })
706
778
  ).then(
707
779
  function(result) {
708
- rewardedBreakActive = false;
780
+ if (rewardedBreakActive === activeBreak) rewardedBreakActive = null;
709
781
  return Boolean(result && result.status === "viewed");
710
782
  },
711
783
  function() {
712
- rewardedBreakActive = false;
784
+ if (rewardedBreakActive === activeBreak) rewardedBreakActive = null;
713
785
  return false;
714
786
  }
715
787
  );
@@ -747,6 +819,8 @@ function createBBArcade() {
747
819
  },
748
820
  rewardedAd,
749
821
  showRewardedAd: rewardedAd,
822
+ prepareRewardedAd,
823
+ prepareRewardedBreak: prepareRewardedAd,
750
824
  rewardedBreak,
751
825
  save: function(blob) {
752
826
  return request("save", String(blob));
@@ -792,6 +866,13 @@ function createInertBBArcade() {
792
866
  reward: "reward",
793
867
  adBreakId: "bbad_inert"
794
868
  });
869
+ const prepareUnavailable = () => Promise.resolve({
870
+ status: "unavailable",
871
+ error: "ad_break_unavailable",
872
+ placement: "rewarded",
873
+ reward: "reward",
874
+ adBreakId: "bbad_inert"
875
+ });
795
876
  return {
796
877
  lockToHost: noop,
797
878
  init: () => Promise.resolve(),
@@ -808,6 +889,8 @@ function createInertBBArcade() {
808
889
  xrSessionEnd: noop,
809
890
  rewardedAd: unavailable,
810
891
  showRewardedAd: unavailable,
892
+ prepareRewardedAd: prepareUnavailable,
893
+ prepareRewardedBreak: prepareUnavailable,
811
894
  rewardedBreak: () => Promise.resolve(false),
812
895
  save: () => Promise.reject(sdkError2("unsupported")),
813
896
  load: () => Promise.reject(sdkError2("unsupported")),