@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.
- package/AGENTS.md +10 -5
- package/README.md +36 -1
- package/dist/{chunk-WCGBR3MI.js → chunk-OWOESH4X.js} +94 -11
- package/dist/chunk-OWOESH4X.js.map +1 -0
- package/dist/global-sdk.d.ts +65 -10
- package/dist/global.js +93 -10
- package/dist/index.cjs +93 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/multiplayer.cjs +93 -10
- package/dist/multiplayer.cjs.map +1 -1
- package/dist/multiplayer.d.cts +2 -2
- package/dist/multiplayer.d.ts +2 -2
- package/dist/multiplayer.js +1 -1
- package/dist/{types-B6xH-lDi.d.cts → types-BKChtV3H.d.cts} +56 -11
- package/dist/{types-B6xH-lDi.d.ts → types-BKChtV3H.d.ts} +56 -11
- package/docs/game-design-playbook.md +5 -3
- package/package.json +1 -1
- package/dist/chunk-WCGBR3MI.js.map +0 -1
package/dist/index.cjs.map
CHANGED
|
@@ -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-
|
|
2
|
-
export { a as BBArcadeConfig, b as BBArcadeError, c as BBArcadeErrorCode, d as BBArcadeLockToHostOptions, e as BBArcadePlayer, f as
|
|
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-
|
|
2
|
-
export { a as BBArcadeConfig, b as BBArcadeError, c as BBArcadeErrorCode, d as BBArcadeLockToHostOptions, e as BBArcadePlayer, f as
|
|
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
package/dist/multiplayer.cjs
CHANGED
|
@@ -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 =
|
|
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
|
-
|
|
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 (
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
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 =
|
|
780
|
+
if (rewardedBreakActive === activeBreak) rewardedBreakActive = null;
|
|
709
781
|
return Boolean(result && result.status === "viewed");
|
|
710
782
|
},
|
|
711
783
|
function() {
|
|
712
|
-
rewardedBreakActive =
|
|
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")),
|