@bountyboard/arcade-sdk 1.4.9 → 1.4.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/protocol.ts","../src/storage.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 BBArcadeStorage,\n BBArcadeStorageMode,\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 * localStorage compatibility shim for Bounty-Board-hosted builds.\n *\n * Hosted uploads run in an opaque-origin sandbox (`allow-scripts` with NO\n * `allow-same-origin`), where touching `localStorage` doesn't return empty — it\n * THROWS a SecurityError. Hand-written games can just call `save()`/`load()`,\n * but engine exports (GameMaker `ini_*`, Godot, Unity, Construct) bake\n * synchronous localStorage into their runtime and can't be rewired without\n * patching engine internals.\n *\n * So: when native storage is unavailable, install a Storage-shaped object that\n * reads/writes an in-memory map and persists that map through the SDK's own\n * cloud save. Progress then follows the player across devices instead of\n * dying with the tab.\n *\n * The one honest limitation: `getItem` is synchronous but the cloud read is\n * not. Hydration starts the moment the shim installs, and a game that reads\n * storage during boot should await `BBArcade.storage.ready()` first. Writes\n * made before hydration are kept (last write wins, exactly like real\n * localStorage) and merged with whatever the cloud read returns, and nothing is\n * pushed to the server until that read has SUCCEEDED — a failed read is\n * retried, and a write that still can't confirm what the player had is refused\n * rather than allowed to overwrite it blind.\n */\nimport type { BBArcadeStorage, BBArcadeStorageMode } from './types';\n\n/** Debounce window for coalescing writes into one cloud save. */\nconst FLUSH_DELAY_MS = 400;\n\n/**\n * Envelope tag + version. The player has ONE save slot per game, so when the\n * shim is active it has to share that slot with any direct `save()` the game\n * also makes. Readers are tolerant: anything that isn't a tagged envelope is\n * treated as a legacy raw blob, so turning the shim on never orphans a save\n * written before it existed.\n */\nconst ENVELOPE_TAG = '__bbArcadeStorage';\nconst ENVELOPE_VERSION = 1;\n\nexport interface StorageEnvelope {\n /** The shimmed localStorage key/value map. */\n ls: Record<string, string>;\n /** Whatever the game passed to `save()` directly, or null. */\n app: string | null;\n}\n\nfunction hasOwn(target: object, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(target, key);\n}\n\n/**\n * A plain `{}` inherits the `__proto__` accessor, which silently swallows\n * `map['__proto__'] = 'x'` instead of storing it — a real Storage keeps that\n * key like any other. Null-prototype maps make every string key ordinary.\n */\nfunction emptyMap<T>(): Record<string, T> {\n return Object.create(null) as Record<string, T>;\n}\n\n/** Error carrying the same machine-readable `code` as the rest of the SDK. */\nfunction storageError(code: string): Error & { code: string } {\n const err = new Error(code) as Error & { code: string };\n err.code = code;\n return err;\n}\n\n/**\n * Read a save slot into its two halves. A raw (non-envelope) blob is returned\n * as `app` untouched, which is what makes this safe to run on saves written\n * before the shim shipped.\n */\nexport function parseEnvelope(raw: string | null | undefined): StorageEnvelope {\n if (raw == null) return { ls: {}, app: null };\n // Cheap reject: an envelope is always a JSON object.\n if (raw.charAt(0) !== '{') return { ls: {}, app: raw };\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n return { ls: {}, app: raw };\n }\n if (!parsed || typeof parsed !== 'object') return { ls: {}, app: raw };\n const record = parsed as Record<string, unknown>;\n if (record[ENVELOPE_TAG] !== ENVELOPE_VERSION) return { ls: {}, app: raw };\n const ls: Record<string, string> = emptyMap<string>();\n const source = record.ls;\n if (source && typeof source === 'object') {\n const entries = source as Record<string, unknown>;\n for (const key in entries) {\n if (hasOwn(entries, key) && typeof entries[key] === 'string') {\n ls[key] = entries[key] as string;\n }\n }\n }\n return { ls: ls, app: typeof record.app === 'string' ? record.app : null };\n}\n\n/** Serialize both halves back into the single save slot. */\nexport function buildEnvelope(ls: Record<string, string>, app: string | null): string {\n const envelope: Record<string, unknown> = {};\n envelope[ENVELOPE_TAG] = ENVELOPE_VERSION;\n envelope.ls = ls;\n envelope.app = app;\n return JSON.stringify(envelope);\n}\n\n/**\n * A real localStorage throws `QuotaExceededError` when it's full; engines\n * (and the odd hand-written game) branch on that name, so the shim raises the\n * same shape rather than a bare Error.\n */\nfunction quotaError(): Error {\n try {\n return new DOMException('Cloud save quota exceeded', 'QuotaExceededError');\n } catch (err) {\n // No DOMException constructor (older engines' polyfilled environments).\n const fallback = new Error('Cloud save quota exceeded');\n fallback.name = 'QuotaExceededError';\n return fallback;\n }\n}\n\n/** Storage members that must stay reachable through the named-property proxy. */\nconst RESERVED: Record<string, true> = {\n getItem: true,\n setItem: true,\n removeItem: true,\n clear: true,\n key: true,\n length: true,\n};\n\nexport interface StorageShimBackend {\n /** Called whenever the map changed and should eventually be persisted. */\n onChange?: () => void;\n /** Rejects the write (throws QuotaExceededError) when it would overflow. */\n wouldOverflow?: (key: string, value: string) => boolean;\n}\n\nexport interface StorageShimHandle {\n /** The Storage-shaped object to install as window.localStorage. */\n storage: Storage;\n /** Current key/value snapshot (a copy). */\n entries(): Record<string, string>;\n /** Adopt cloud values for keys the game hasn't written itself. */\n hydrate(values: Record<string, string>): void;\n}\n\n/**\n * A Storage-compatible object over a plain map. Wrapped in a Proxy so named\n * access (`localStorage.progress`) behaves like the real thing and not just\n * `getItem`/`setItem` — engine runtimes use both.\n */\nexport function createStorageShim(backend: StorageShimBackend = {}): StorageShimHandle {\n const map: Record<string, string> = emptyMap<string>();\n // Keys the GAME has written. Cloud hydration must not clobber these: the\n // game's own write is newer than the blob we're still fetching.\n const localWrites: Record<string, true> = emptyMap<true>();\n\n function keys(): string[] {\n return Object.keys(map);\n }\n\n function changed(): void {\n if (backend.onChange) backend.onChange();\n }\n\n const api = {\n getItem: function (key: string): string | null {\n const name = String(key);\n return hasOwn(map, name) ? map[name] : null;\n },\n setItem: function (key: string, value: string): void {\n const name = String(key);\n const next = String(value);\n if (backend.wouldOverflow && backend.wouldOverflow(name, next)) throw quotaError();\n map[name] = next;\n localWrites[name] = true;\n changed();\n },\n removeItem: function (key: string): void {\n const name = String(key);\n // Record the intent even when the key isn't there yet: the cloud read may\n // still be in flight, and a delete must not be undone by hydration.\n localWrites[name] = true;\n if (!hasOwn(map, name)) return; // nothing to persist\n delete map[name];\n changed();\n },\n clear: function (): void {\n const existing = keys();\n for (let i = 0; i < existing.length; i++) {\n delete map[existing[i]];\n localWrites[existing[i]] = true;\n }\n changed();\n },\n key: function (index: number): string | null {\n const existing = keys();\n const at = Number(index);\n return at >= 0 && at < existing.length ? existing[at] : null;\n },\n get length(): number {\n return keys().length;\n },\n };\n\n const storage = new Proxy(api, {\n get(target, prop, receiver) {\n if (typeof prop !== 'string') return Reflect.get(target, prop, receiver);\n if (hasOwn(RESERVED, prop)) return Reflect.get(target, prop, receiver);\n return hasOwn(map, prop) ? map[prop] : undefined;\n },\n set(target, prop, value) {\n if (typeof prop !== 'string' || hasOwn(RESERVED, prop)) return true;\n api.setItem(prop, value as string);\n return true;\n },\n has(target, prop) {\n if (typeof prop !== 'string') return Reflect.has(target, prop);\n return hasOwn(RESERVED, prop) || hasOwn(map, prop);\n },\n deleteProperty(target, prop) {\n if (typeof prop === 'string' && !hasOwn(RESERVED, prop)) api.removeItem(prop);\n return true;\n },\n ownKeys() {\n return keys();\n },\n getOwnPropertyDescriptor(target, prop) {\n if (typeof prop !== 'string' || !hasOwn(map, prop)) return undefined;\n return { value: map[prop], writable: true, enumerable: true, configurable: true };\n },\n }) as unknown as Storage;\n\n return {\n storage: storage,\n entries: function () {\n const copy: Record<string, string> = emptyMap<string>();\n const existing = keys();\n for (let i = 0; i < existing.length; i++) copy[existing[i]] = map[existing[i]];\n return copy;\n },\n hydrate: function (values: Record<string, string>) {\n for (const key in values) {\n // The game's own writes (including deletes) are newer than the blob we\n // were fetching, so they win.\n if (hasOwn(values, key) && !hasOwn(localWrites, key)) map[key] = values[key];\n }\n },\n };\n}\n\n/**\n * Wait out a promise without propagating its outcome. Folds a write attempt\n * into a chain that must itself never reject, so a failed write can't break\n * the ordering of the ones after it and callers don't see an\n * unhandled-rejection warning for a result nothing reads.\n */\nfunction settled<T>(promise: Promise<T>): Promise<void> {\n return promise.then(\n function () {},\n function () {}\n );\n}\n\n/**\n * sessionStorage throws in the same opaque-origin sandbox as localStorage,\n * but it's per-session by definition: shim it as memory-only rather than\n * syncing it to the cloud. Independent of (and simpler than) the\n * localStorage/cloud-save state machine in createStorageController, so it's\n * its own step rather than a special case inside install().\n */\nfunction installSessionStorageShim(): void {\n if (nativeStorageWorks('sessionStorage')) return;\n try {\n Object.defineProperty(window, 'sessionStorage', {\n value: createStorageShim().storage,\n configurable: true,\n });\n } catch (err) {\n /* couldn't redefine — leave the native (throwing) one alone */\n }\n}\n\n/** Probe whether a real, writable Storage is available under this origin. */\nexport function nativeStorageWorks(area: 'localStorage' | 'sessionStorage'): boolean {\n try {\n const store = (window as unknown as Record<string, Storage | undefined>)[area];\n if (!store) return false;\n const probe = '__bb_arcade_probe__';\n // Presence isn't enough: Safari private mode exposes a Storage that throws\n // on write, and an opaque origin throws on the property read above.\n store.setItem(probe, '1');\n store.removeItem(probe);\n return true;\n } catch (err) {\n return false;\n }\n}\n\nexport interface CloudStorageOptions {\n /** Raw save transport (NOT the public save(), which wraps through here). */\n save: (blob: string) => Promise<void>;\n /** Raw load transport. */\n load: () => Promise<string | null>;\n /** UTF-8 byte length, shared with the core's save-size precheck. */\n byteLength: (value: string) => number;\n /** Per-save byte cap mirrored from the server. */\n maxBytes: number;\n}\n\n/**\n * The SDK-facing storage controller: owns the shimmed map, the app-side save\n * blob, and the single writer that serializes both into the player's one save\n * slot.\n */\nexport interface StorageController extends BBArcadeStorage {\n /** True once the shim owns window.localStorage. */\n active(): boolean;\n /** Replace the direct-save() half of the envelope and persist immediately. */\n writeApp(blob: string): Promise<void>;\n}\n\nexport function createStorageController(options: CloudStorageOptions): StorageController {\n let shim: StorageShimHandle | null = null;\n let mode: BBArcadeStorageMode = 'native';\n let appBlob: string | null = null;\n let hydration: Promise<BBArcadeStorageMode> | null = null;\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\n let inFlight: Promise<void> = Promise.resolve();\n let dirty = false;\n // A cloud read has SUCCEEDED. Distinct from \"hydration settled\": a failed\n // read also settles, and writing after one would replace a save we have\n // never seen with only this session's keys.\n let hydrated = false;\n\n function serialize(): string {\n return buildEnvelope(shim ? shim.entries() : {}, appBlob);\n }\n\n /**\n * Read the player's slot and merge it in. Retryable: `persist()` calls this\n * again when an earlier read failed, so one transport blip on boot doesn't\n * cost the session its cloud save.\n */\n function hydrateFromCloud(): Promise<BBArcadeStorageMode> {\n hydration = options.load().then(\n function (raw) {\n const envelope = parseEnvelope(raw);\n if (shim) shim.hydrate(envelope.ls);\n if (appBlob === null) appBlob = envelope.app;\n hydrated = true;\n return mode;\n },\n function (err: { code?: string }) {\n // No cloud slot to sync with (guest, standalone, off-host): keep the\n // shim so the game still gets a working localStorage, but never try to\n // persist. Any other code is transient, so `hydrated` stays false and\n // persist() retries rather than writing over an unread save.\n const code = err && err.code;\n if (code === 'unsupported' || code === 'unauthenticated') mode = 'memory';\n return mode;\n }\n );\n return hydration;\n }\n\n /**\n * Guard setItem against the server's byte cap. Measures the real serialized\n * envelope so the answer matches what the save would actually reject.\n */\n function wouldOverflow(key: string, value: string): boolean {\n if (!shim) return false;\n const next = shim.entries();\n next[key] = value;\n return options.byteLength(buildEnvelope(next, appBlob)) > options.maxBytes;\n }\n\n /**\n * Wait for hydration, then persist. Used as both the success and failure\n * handler of `inFlight.then(...)` below: a write must run whether the\n * previous one succeeded or failed, so both arms do the same thing.\n *\n * The `hydrated` gate is the load-bearing part. A read that FAILED still\n * settles `hydration`, and saving then would serialize a map holding only\n * this session's keys — silently wiping everything else the player had. So a\n * write that finds no successful read retries the read first, and gives up\n * (leaving the cloud save untouched) rather than overwrite it blind.\n */\n function persist(): Promise<void> {\n return whenHydrated()\n .then(function () {\n if (mode === 'memory') return; // nothing to persist to\n if (hydrated) return options.save(serialize());\n return hydrateFromCloud().then(function () {\n if (mode === 'memory') return;\n if (!hydrated) throw storageError('error');\n return options.save(serialize());\n });\n })\n .then(undefined, function (err) {\n // Nothing reached the server, so the map is still unsaved: let a later\n // flush (or pagehide) try again instead of dropping the write.\n dirty = true;\n throw err;\n });\n }\n\n /** Persist now, after a successful read, so we never overwrite unseen data. */\n function flushNow(): Promise<void> {\n if (flushTimer !== null) {\n clearTimeout(flushTimer);\n flushTimer = null;\n }\n dirty = false;\n // Chain onto the previous write so two flushes can't land out of order.\n const next = inFlight.then(persist, persist);\n // Keep the chain alive but unhandled-rejection-free; callers see the real\n // promise (and its BBArcadeError code) from the value we return.\n inFlight = settled(next);\n return next;\n }\n\n function scheduleFlush(): void {\n dirty = true;\n if (flushTimer !== null) return;\n flushTimer = setTimeout(function () {\n flushTimer = null;\n void settled(flushNow());\n }, FLUSH_DELAY_MS);\n }\n\n function whenHydrated(): Promise<BBArcadeStorageMode> {\n return hydration ? hydration : Promise.resolve(mode);\n }\n\n /** Write anything still pending when the page is going away. */\n function attachUnloadFlush(): void {\n const flushIfDirty = function (): void {\n if (dirty) void settled(flushNow());\n };\n try {\n window.addEventListener('pagehide', flushIfDirty);\n window.addEventListener('visibilitychange', function () {\n if (document.visibilityState === 'hidden') flushIfDirty();\n });\n } catch (err) {\n /* no window/document event support — the debounce still covers normal play */\n }\n }\n\n function install(): BBArcadeStorageMode {\n if (shim) return mode;\n installSessionStorageShim();\n if (nativeStorageWorks('localStorage')) {\n mode = 'native';\n return mode;\n }\n const handle = createStorageShim({ onChange: scheduleFlush, wouldOverflow: wouldOverflow });\n try {\n Object.defineProperty(window, 'localStorage', {\n value: handle.storage,\n configurable: true,\n });\n } catch (err) {\n // Can't redefine the property: leave the throwing native one in place\n // rather than half-installing something the game can't reach.\n return mode;\n }\n shim = handle;\n mode = 'cloud';\n attachUnloadFlush();\n // Start the read immediately: the sooner it lands, the smaller the window\n // in which a boot-time getItem sees an empty map.\n void hydrateFromCloud();\n return mode;\n }\n\n return {\n install: install,\n active: function () {\n return shim !== null;\n },\n ready: function () {\n return whenHydrated();\n },\n flush: function () {\n if (!shim && appBlob === null) return Promise.resolve();\n return flushNow();\n },\n writeApp: function (blob: string) {\n // Same guard setItem gets, for the same reason: the SERVER measures the\n // whole envelope, so a blob that fits alone can still overflow once the\n // shimmed map is wrapped around it. Check BEFORE committing — a rejected\n // save would otherwise leave appBlob oversized for the rest of the\n // session, and every later setItem would inherit the overflow.\n if (options.byteLength(buildEnvelope(shim ? shim.entries() : {}, blob)) > options.maxBytes) {\n return Promise.reject(storageError('too_large'));\n }\n appBlob = blob;\n return flushNow();\n },\n get mode() {\n return mode;\n },\n };\n}\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 { createStorageController, parseEnvelope } from './storage';\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// The site-lock handshake (host / host_attest) gets a shorter fuse than data\n// requests: when nothing answers, the game is a scraped copy and every second\n// of delay is free playtime for the re-hosting site.\nconst LOCK_TIMEOUT_MS = 5000;\n// Client-side mirror of the server's per-save byte cap\n// (MAX_SAVE_BYTES in src/lib/arcade/buildAssets.ts) so an oversized blob is\n// rejected with 'too_large' immediately instead of after a host round trip.\nconst MAX_SAVE_BYTES = 1024 * 1024;\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\n// Lazy: the SDK must import cleanly even where TextEncoder is missing (some\n// test/SSR shims); Blob gives the same exact UTF-8 byte count as a fallback.\nlet cachedTextEncoder: TextEncoder | null = null;\n\nfunction utf8ByteLength(value: string): number {\n if (typeof TextEncoder !== 'undefined') {\n cachedTextEncoder = cachedTextEncoder || new TextEncoder();\n return cachedTextEncoder.encode(value).length;\n }\n return new Blob([value]).size;\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 // Subscribers notified when the host delivers a CHANGED player identity\n // (login/logout mid-session). Change-only: subscribing does not replay the\n // current value, and a config message that repeats the same identity stays\n // silent.\n const playerChangeHandlers: Array<(player: BBArcadePlayer | null) => void> = [];\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.trunc(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(\n type: string,\n payload?: unknown,\n timeoutMs: number = SAVE_TIMEOUT_MS\n ): 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 }, timeoutMs);\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 // Shorter fuse than data requests — an unanswered lock handshake means a\n // scraped copy, and it should not get 15s of free play before the block.\n request('host', undefined, LOCK_TIMEOUT_MS).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', undefined, LOCK_TIMEOUT_MS).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 const nextPlayer = sanitizePlayer(msg.player);\n const changed =\n nextPlayer === null\n ? hostPlayer !== null\n : hostPlayer === null ||\n nextPlayer.name !== hostPlayer.name ||\n nextPlayer.avatarUrl !== hostPlayer.avatarUrl;\n hostPlayer = nextPlayer;\n if (changed) {\n // Hand out a copy so a handler can't mutate the SDK's own record.\n const snapshot = nextPlayer\n ? { name: nextPlayer.name, avatarUrl: nextPlayer.avatarUrl }\n : null;\n for (let i = 0; i < playerChangeHandlers.length; i++) {\n safeCall(playerChangeHandlers[i], snapshot);\n }\n }\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 // True once Google's showAdFn was actually invoked. Distinguishes \"the\n // break ended with the ad on screen but no view/dismiss callback\" (a\n // terminal 'ready', kept for v1 compatibility) from \"a prepared ad was\n // never shown before the break ended\" (terminal 'dismissed').\n let adShown = 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 adShown = true;\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 ? {\n // A reward was offered but the ad never reached the screen\n // (the game retained show() and let the break lapse): the\n // break is over without a view, so resolve 'dismissed',\n // not the non-terminal-looking 'ready'.\n status: status === 'ready' && !adShown ? 'dismissed' : status,\n }\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 // localStorage compatibility for hosted builds, which run on an opaque origin\n // where a real Storage isn't just empty — it throws. The controller talks to\n // the RAW save/load transport, not sdk.save(), because sdk.save() routes back\n // through it once the shim owns the slot. The script-tag build installs it at\n // load; module consumers call BBArcade.storage.install() before boot.\n const storage = createStorageController({\n save: function (blob: string) {\n return request('save', blob) as Promise<void>;\n },\n load: function () {\n return request('load') as Promise<string | null>;\n },\n byteLength: utf8ByteLength,\n maxBytes: MAX_SAVE_BYTES,\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 const data = String(blob);\n // Fail fast on an oversized blob instead of waiting out a host round\n // trip that can only end in the same 'too_large' rejection.\n if (utf8ByteLength(data) > MAX_SAVE_BYTES) {\n return Promise.reject(sdkError('too_large'));\n }\n // With the shim installed both halves share the player's one save slot,\n // so the write has to go through the controller's single writer. Without\n // it the bytes on the wire are exactly what they always were.\n if (storage.active()) return storage.writeApp(data);\n return request('save', data) as Promise<void>;\n },\n load: function () {\n return (request('load') as Promise<string | null>).then(function (raw) {\n // Tolerant unwrap: a raw pre-shim blob comes back untouched, so a game\n // that starts using the shim never loses the save it wrote before.\n return parseEnvelope(raw).app;\n });\n },\n storage: storage,\n getPlayer: getPlayer,\n onPlayerChange: function (handler) {\n if (typeof handler !== 'function') return function () {};\n playerChangeHandlers.push(handler);\n return function () {\n const idx = playerChangeHandlers.indexOf(handler);\n if (idx !== -1) playerChangeHandlers.splice(idx, 1);\n };\n },\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 BBArcadeStorageMode,\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 // No window to shim and nothing to persist to: report the honest mode\n // rather than pretending an install succeeded.\n storage: {\n install: (): BBArcadeStorageMode => 'memory',\n ready: (): Promise<BBArcadeStorageMode> => Promise.resolve('memory'),\n flush: () => Promise.resolve(),\n mode: 'memory' as BBArcadeStorageMode,\n },\n getPlayer: () => Promise.resolve(null),\n onPlayerChange: () => () => {},\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"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/protocol.ts","../src/storage.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 BBArcadeStorage,\n BBArcadeStorageMode,\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 * localStorage compatibility shim for Bounty-Board-hosted builds.\n *\n * Hosted uploads run in an opaque-origin sandbox (`allow-scripts` with NO\n * `allow-same-origin`), where touching `localStorage` doesn't return empty — it\n * THROWS a SecurityError. Hand-written games can just call `save()`/`load()`,\n * but engine exports (GameMaker `ini_*`, Godot, Unity, Construct) bake\n * synchronous localStorage into their runtime and can't be rewired without\n * patching engine internals.\n *\n * So: when native storage is unavailable, install a Storage-shaped object that\n * reads/writes an in-memory map and persists that map through the SDK's own\n * cloud save. Progress then follows the player across devices instead of\n * dying with the tab.\n *\n * The one honest limitation: `getItem` is synchronous but the cloud read is\n * not. Hydration starts the moment the shim installs, and a game that reads\n * storage during boot should await `BBArcade.storage.ready()` first. Writes\n * made before hydration are kept (last write wins, exactly like real\n * localStorage) and merged with whatever the cloud read returns, and nothing is\n * pushed to the server until that read has SUCCEEDED — a failed read is\n * retried, and a write that still can't confirm what the player had is refused\n * rather than allowed to overwrite it blind.\n */\nimport type { BBArcadeStorage, BBArcadeStorageMode } from './types';\n\n/** Debounce window for coalescing writes into one cloud save. */\nconst FLUSH_DELAY_MS = 400;\n\n/**\n * Envelope tag + version. The player has ONE save slot per game, so when the\n * shim is active it has to share that slot with any direct `save()` the game\n * also makes. Readers are tolerant: anything that isn't a tagged envelope is\n * treated as a legacy raw blob, so turning the shim on never orphans a save\n * written before it existed.\n */\nconst ENVELOPE_TAG = '__bbArcadeStorage';\nconst ENVELOPE_VERSION = 1;\n\nexport interface StorageEnvelope {\n /** The shimmed localStorage key/value map. */\n ls: Record<string, string>;\n /** Whatever the game passed to `save()` directly, or null. */\n app: string | null;\n}\n\nfunction hasOwn(target: object, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(target, key);\n}\n\n/**\n * A plain `{}` inherits the `__proto__` accessor, which silently swallows\n * `map['__proto__'] = 'x'` instead of storing it — a real Storage keeps that\n * key like any other. Null-prototype maps make every string key ordinary.\n */\nfunction emptyMap<T>(): Record<string, T> {\n return Object.create(null) as Record<string, T>;\n}\n\n/** Error carrying the same machine-readable `code` as the rest of the SDK. */\nfunction storageError(code: string): Error & { code: string } {\n const err = new Error(code) as Error & { code: string };\n err.code = code;\n return err;\n}\n\n/**\n * Read a save slot into its two halves. A raw (non-envelope) blob is returned\n * as `app` untouched, which is what makes this safe to run on saves written\n * before the shim shipped.\n */\nexport function parseEnvelope(raw: string | null | undefined): StorageEnvelope {\n if (raw == null) return { ls: {}, app: null };\n // Cheap reject: an envelope is always a JSON object.\n if (raw.charAt(0) !== '{') return { ls: {}, app: raw };\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n return { ls: {}, app: raw };\n }\n if (!parsed || typeof parsed !== 'object') return { ls: {}, app: raw };\n const record = parsed as Record<string, unknown>;\n if (record[ENVELOPE_TAG] !== ENVELOPE_VERSION) return { ls: {}, app: raw };\n const ls: Record<string, string> = emptyMap<string>();\n const source = record.ls;\n if (source && typeof source === 'object') {\n const entries = source as Record<string, unknown>;\n for (const key in entries) {\n if (hasOwn(entries, key) && typeof entries[key] === 'string') {\n ls[key] = entries[key] as string;\n }\n }\n }\n return { ls: ls, app: typeof record.app === 'string' ? record.app : null };\n}\n\n/** Serialize both halves back into the single save slot. */\nexport function buildEnvelope(ls: Record<string, string>, app: string | null): string {\n const envelope: Record<string, unknown> = {};\n envelope[ENVELOPE_TAG] = ENVELOPE_VERSION;\n envelope.ls = ls;\n envelope.app = app;\n return JSON.stringify(envelope);\n}\n\n/**\n * A real localStorage throws `QuotaExceededError` when it's full; engines\n * (and the odd hand-written game) branch on that name, so the shim raises the\n * same shape rather than a bare Error.\n */\nfunction quotaError(): Error {\n try {\n return new DOMException('Cloud save quota exceeded', 'QuotaExceededError');\n } catch (err) {\n // No DOMException constructor (older engines' polyfilled environments).\n const fallback = new Error('Cloud save quota exceeded');\n fallback.name = 'QuotaExceededError';\n return fallback;\n }\n}\n\n/** Storage members that must stay reachable through the named-property proxy. */\nconst RESERVED: Record<string, true> = {\n getItem: true,\n setItem: true,\n removeItem: true,\n clear: true,\n key: true,\n length: true,\n};\n\nexport interface StorageShimBackend {\n /** Called whenever the map changed and should eventually be persisted. */\n onChange?: () => void;\n /** Rejects the write (throws QuotaExceededError) when it would overflow. */\n wouldOverflow?: (key: string, value: string) => boolean;\n}\n\nexport interface StorageShimHandle {\n /** The Storage-shaped object to install as window.localStorage. */\n storage: Storage;\n /** Current key/value snapshot (a copy). */\n entries(): Record<string, string>;\n /** Adopt cloud values for keys the game hasn't written itself. */\n hydrate(values: Record<string, string>): void;\n}\n\n/**\n * A Storage-compatible object over a plain map. Wrapped in a Proxy so named\n * access (`localStorage.progress`) behaves like the real thing and not just\n * `getItem`/`setItem` — engine runtimes use both.\n */\nexport function createStorageShim(backend: StorageShimBackend = {}): StorageShimHandle {\n const map: Record<string, string> = emptyMap<string>();\n // Keys the GAME has written. Cloud hydration must not clobber these: the\n // game's own write is newer than the blob we're still fetching.\n const localWrites: Record<string, true> = emptyMap<true>();\n\n function keys(): string[] {\n return Object.keys(map);\n }\n\n function changed(): void {\n if (backend.onChange) backend.onChange();\n }\n\n const api = {\n getItem: function (key: string): string | null {\n const name = String(key);\n return hasOwn(map, name) ? map[name] : null;\n },\n setItem: function (key: string, value: string): void {\n const name = String(key);\n const next = String(value);\n if (backend.wouldOverflow && backend.wouldOverflow(name, next)) throw quotaError();\n map[name] = next;\n localWrites[name] = true;\n changed();\n },\n removeItem: function (key: string): void {\n const name = String(key);\n // Record the intent even when the key isn't there yet: the cloud read may\n // still be in flight, and a delete must not be undone by hydration.\n localWrites[name] = true;\n if (!hasOwn(map, name)) return; // nothing to persist\n delete map[name];\n changed();\n },\n clear: function (): void {\n const existing = keys();\n for (let i = 0; i < existing.length; i++) {\n delete map[existing[i]];\n localWrites[existing[i]] = true;\n }\n changed();\n },\n key: function (index: number): string | null {\n const existing = keys();\n const at = Number(index);\n return at >= 0 && at < existing.length ? existing[at] : null;\n },\n get length(): number {\n return keys().length;\n },\n };\n\n const storage = new Proxy(api, {\n get(target, prop, receiver) {\n if (typeof prop !== 'string') return Reflect.get(target, prop, receiver);\n if (hasOwn(RESERVED, prop)) return Reflect.get(target, prop, receiver);\n return hasOwn(map, prop) ? map[prop] : undefined;\n },\n set(target, prop, value) {\n if (typeof prop !== 'string' || hasOwn(RESERVED, prop)) return true;\n api.setItem(prop, value as string);\n return true;\n },\n has(target, prop) {\n if (typeof prop !== 'string') return Reflect.has(target, prop);\n return hasOwn(RESERVED, prop) || hasOwn(map, prop);\n },\n deleteProperty(target, prop) {\n if (typeof prop === 'string' && !hasOwn(RESERVED, prop)) api.removeItem(prop);\n return true;\n },\n ownKeys() {\n return keys();\n },\n getOwnPropertyDescriptor(target, prop) {\n if (typeof prop !== 'string' || !hasOwn(map, prop)) return undefined;\n return { value: map[prop], writable: true, enumerable: true, configurable: true };\n },\n }) as unknown as Storage;\n\n return {\n storage: storage,\n entries: function () {\n const copy: Record<string, string> = emptyMap<string>();\n const existing = keys();\n for (let i = 0; i < existing.length; i++) copy[existing[i]] = map[existing[i]];\n return copy;\n },\n hydrate: function (values: Record<string, string>) {\n for (const key in values) {\n // The game's own writes (including deletes) are newer than the blob we\n // were fetching, so they win.\n if (hasOwn(values, key) && !hasOwn(localWrites, key)) map[key] = values[key];\n }\n },\n };\n}\n\n/**\n * Wait out a promise without propagating its outcome. Folds a write attempt\n * into a chain that must itself never reject, so a failed write can't break\n * the ordering of the ones after it and callers don't see an\n * unhandled-rejection warning for a result nothing reads.\n */\nfunction settled<T>(promise: Promise<T>): Promise<void> {\n return promise.then(\n function () {},\n function () {}\n );\n}\n\n/**\n * sessionStorage throws in the same opaque-origin sandbox as localStorage,\n * but it's per-session by definition: shim it as memory-only rather than\n * syncing it to the cloud. Independent of (and simpler than) the\n * localStorage/cloud-save state machine in createStorageController, so it's\n * its own step rather than a special case inside install().\n */\nfunction installSessionStorageShim(): void {\n if (nativeStorageWorks('sessionStorage')) return;\n try {\n Object.defineProperty(window, 'sessionStorage', {\n value: createStorageShim().storage,\n configurable: true,\n });\n } catch (err) {\n /* couldn't redefine — leave the native (throwing) one alone */\n }\n}\n\n/** Probe whether a real, writable Storage is available under this origin. */\nexport function nativeStorageWorks(area: 'localStorage' | 'sessionStorage'): boolean {\n try {\n const store = (window as unknown as Record<string, Storage | undefined>)[area];\n if (!store) return false;\n const probe = '__bb_arcade_probe__';\n // Presence isn't enough: Safari private mode exposes a Storage that throws\n // on write, and an opaque origin throws on the property read above.\n store.setItem(probe, '1');\n store.removeItem(probe);\n return true;\n } catch (err) {\n return false;\n }\n}\n\nexport interface CloudStorageOptions {\n /** Raw save transport (NOT the public save(), which wraps through here). */\n save: (blob: string) => Promise<void>;\n /** Raw load transport. */\n load: () => Promise<string | null>;\n /** UTF-8 byte length, shared with the core's save-size precheck. */\n byteLength: (value: string) => number;\n /** Per-save byte cap mirrored from the server. */\n maxBytes: number;\n}\n\n/**\n * The SDK-facing storage controller: owns the shimmed map, the app-side save\n * blob, and the single writer that serializes both into the player's one save\n * slot.\n */\nexport interface StorageController extends BBArcadeStorage {\n /** True once the shim owns window.localStorage. */\n active(): boolean;\n /** Replace the direct-save() half of the envelope and persist immediately. */\n writeApp(blob: string): Promise<void>;\n}\n\nexport function createStorageController(options: CloudStorageOptions): StorageController {\n let shim: StorageShimHandle | null = null;\n let mode: BBArcadeStorageMode = 'native';\n let appBlob: string | null = null;\n let hydration: Promise<BBArcadeStorageMode> | null = null;\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\n let inFlight: Promise<void> = Promise.resolve();\n let dirty = false;\n // A cloud read has SUCCEEDED. Distinct from \"hydration settled\": a failed\n // read also settles, and writing after one would replace a save we have\n // never seen with only this session's keys.\n let hydrated = false;\n\n function serialize(): string {\n return buildEnvelope(shim ? shim.entries() : {}, appBlob);\n }\n\n /**\n * Read the player's slot and merge it in. Retryable: `persist()` calls this\n * again when an earlier read failed, so one transport blip on boot doesn't\n * cost the session its cloud save.\n */\n function hydrateFromCloud(): Promise<BBArcadeStorageMode> {\n hydration = options.load().then(\n function (raw) {\n const envelope = parseEnvelope(raw);\n if (shim) shim.hydrate(envelope.ls);\n if (appBlob === null) appBlob = envelope.app;\n hydrated = true;\n return mode;\n },\n function (err: { code?: string }) {\n // No cloud slot to sync with (guest, standalone, off-host): keep the\n // shim so the game still gets a working localStorage, but never try to\n // persist. Any other code is transient, so `hydrated` stays false and\n // persist() retries rather than writing over an unread save.\n const code = err && err.code;\n if (code === 'unsupported' || code === 'unauthenticated') mode = 'memory';\n return mode;\n }\n );\n return hydration;\n }\n\n /**\n * Guard setItem against the server's byte cap. Measures the real serialized\n * envelope so the answer matches what the save would actually reject.\n */\n function wouldOverflow(key: string, value: string): boolean {\n if (!shim) return false;\n const next = shim.entries();\n next[key] = value;\n return options.byteLength(buildEnvelope(next, appBlob)) > options.maxBytes;\n }\n\n /**\n * Wait for hydration, then persist. Used as both the success and failure\n * handler of `inFlight.then(...)` below: a write must run whether the\n * previous one succeeded or failed, so both arms do the same thing.\n *\n * The `hydrated` gate is the load-bearing part. A read that FAILED still\n * settles `hydration`, and saving then would serialize a map holding only\n * this session's keys — silently wiping everything else the player had. So a\n * write that finds no successful read retries the read first, and gives up\n * (leaving the cloud save untouched) rather than overwrite it blind.\n */\n function persist(): Promise<void> {\n return whenHydrated()\n .then(function () {\n if (mode === 'memory') return; // nothing to persist to\n if (hydrated) return options.save(serialize());\n return hydrateFromCloud().then(function () {\n if (mode === 'memory') return;\n if (!hydrated) throw storageError('error');\n return options.save(serialize());\n });\n })\n .then(undefined, function (err) {\n // Nothing reached the server, so the map is still unsaved: let a later\n // flush (or pagehide) try again instead of dropping the write.\n dirty = true;\n throw err;\n });\n }\n\n /** Persist now, after a successful read, so we never overwrite unseen data. */\n function flushNow(): Promise<void> {\n if (flushTimer !== null) {\n clearTimeout(flushTimer);\n flushTimer = null;\n }\n dirty = false;\n // Chain onto the previous write so two flushes can't land out of order.\n const next = inFlight.then(persist, persist);\n // Keep the chain alive but unhandled-rejection-free; callers see the real\n // promise (and its BBArcadeError code) from the value we return.\n inFlight = settled(next);\n return next;\n }\n\n function scheduleFlush(): void {\n dirty = true;\n if (flushTimer !== null) return;\n flushTimer = setTimeout(function () {\n flushTimer = null;\n void settled(flushNow());\n }, FLUSH_DELAY_MS);\n }\n\n function whenHydrated(): Promise<BBArcadeStorageMode> {\n return hydration ? hydration : Promise.resolve(mode);\n }\n\n /** Write anything still pending when the page is going away. */\n function attachUnloadFlush(): void {\n const flushIfDirty = function (): void {\n if (dirty) void settled(flushNow());\n };\n try {\n window.addEventListener('pagehide', flushIfDirty);\n window.addEventListener('visibilitychange', function () {\n if (document.visibilityState === 'hidden') flushIfDirty();\n });\n } catch (err) {\n /* no window/document event support — the debounce still covers normal play */\n }\n }\n\n function install(): BBArcadeStorageMode {\n if (shim) return mode;\n installSessionStorageShim();\n if (nativeStorageWorks('localStorage')) {\n mode = 'native';\n return mode;\n }\n const handle = createStorageShim({ onChange: scheduleFlush, wouldOverflow: wouldOverflow });\n try {\n Object.defineProperty(window, 'localStorage', {\n value: handle.storage,\n configurable: true,\n });\n } catch (err) {\n // Can't redefine the property: leave the throwing native one in place\n // rather than half-installing something the game can't reach.\n return mode;\n }\n shim = handle;\n mode = 'cloud';\n attachUnloadFlush();\n // Start the read immediately: the sooner it lands, the smaller the window\n // in which a boot-time getItem sees an empty map.\n void hydrateFromCloud();\n return mode;\n }\n\n return {\n install: install,\n active: function () {\n return shim !== null;\n },\n ready: function () {\n return whenHydrated();\n },\n flush: function () {\n if (!shim && appBlob === null) return Promise.resolve();\n return flushNow();\n },\n writeApp: function (blob: string) {\n // Same guard setItem gets, for the same reason: the SERVER measures the\n // whole envelope, so a blob that fits alone can still overflow once the\n // shimmed map is wrapped around it. Check BEFORE committing — a rejected\n // save would otherwise leave appBlob oversized for the rest of the\n // session, and every later setItem would inherit the overflow.\n if (options.byteLength(buildEnvelope(shim ? shim.entries() : {}, blob)) > options.maxBytes) {\n return Promise.reject(storageError('too_large'));\n }\n appBlob = blob;\n return flushNow();\n },\n get mode() {\n return mode;\n },\n };\n}\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 { createStorageController, parseEnvelope } from './storage';\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// The site-lock handshake (host / host_attest) gets a shorter fuse than data\n// requests: when nothing answers, the game is a scraped copy and every second\n// of delay is free playtime for the re-hosting site.\nconst LOCK_TIMEOUT_MS = 5000;\n// Client-side mirror of the server's per-save byte cap\n// (MAX_SAVE_BYTES in src/lib/arcade/buildAssets.ts) so an oversized blob is\n// rejected with 'too_large' immediately instead of after a host round trip.\nconst MAX_SAVE_BYTES = 1024 * 1024;\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// Parents that might answer the SDK's requests: Bounty Board's own hosts plus\n// per-deploy Vercel previews, which the sitelock and the config gate don't\n// trust but whose player page still answers saves. Any other named parent (an\n// itch.io or Newgrounds page) never will, so requests fail fast there.\nconst REQUEST_HOSTS = DEFAULT_ALLOW.concat(['vercel.app']);\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\n// Lazy: the SDK must import cleanly even where TextEncoder is missing (some\n// test/SSR shims); Blob gives the same exact UTF-8 byte count as a fallback.\nlet cachedTextEncoder: TextEncoder | null = null;\n\nfunction utf8ByteLength(value: string): number {\n if (typeof TextEncoder !== 'undefined') {\n cachedTextEncoder = cachedTextEncoder || new TextEncoder();\n return cachedTextEncoder.encode(value).length;\n }\n return new Blob([value]).size;\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 // Subscribers notified when the host delivers a CHANGED player identity\n // (login/logout mid-session). Change-only: subscribing does not replay the\n // current value, and a config message that repeats the same identity stays\n // silent.\n const playerChangeHandlers: Array<(player: BBArcadePlayer | null) => void> = [];\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.trunc(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 // True only when the browser itself names the parent page (ancestorOrigins,\n // which the embedder can't forge) and it's an ordinary web site that can't\n // be a Bounty Board host. Unknown parents (Firefox, opaque or file: pages)\n // return false and keep the full wait, so a real host is never cut off.\n function parentIsForeignSite(): boolean {\n try {\n const ancestors = window.location.ancestorOrigins;\n const parentOrigin = ancestors && ancestors.length ? ancestors[0] : '';\n if (!/^https?:\\/\\//.test(parentOrigin)) return false;\n return !hostnameAllowed(parentOrigin, REQUEST_HOSTS);\n } catch (err) {\n return false;\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(\n type: string,\n payload?: unknown,\n timeoutMs: number = SAVE_TIMEOUT_MS\n ): Promise<unknown> {\n return new Promise(function (resolve, reject) {\n if (blocked) return reject(sdkError('error'));\n // Standalone play, or an embed on another site (itch.io, Newgrounds):\n // nothing will ever answer, so fail fast instead of hanging until the\n // timeout.\n if (!isEmbedded() || parentIsForeignSite()) 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 }, timeoutMs);\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 // Shorter fuse than data requests — an unanswered lock handshake means a\n // scraped copy, and it should not get 15s of free play before the block.\n request('host', undefined, LOCK_TIMEOUT_MS).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', undefined, LOCK_TIMEOUT_MS).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 const nextPlayer = sanitizePlayer(msg.player);\n const changed =\n nextPlayer === null\n ? hostPlayer !== null\n : hostPlayer === null ||\n nextPlayer.name !== hostPlayer.name ||\n nextPlayer.avatarUrl !== hostPlayer.avatarUrl;\n hostPlayer = nextPlayer;\n if (changed) {\n // Hand out a copy so a handler can't mutate the SDK's own record.\n const snapshot = nextPlayer\n ? { name: nextPlayer.name, avatarUrl: nextPlayer.avatarUrl }\n : null;\n for (let i = 0; i < playerChangeHandlers.length; i++) {\n safeCall(playerChangeHandlers[i], snapshot);\n }\n }\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 // True once Google's showAdFn was actually invoked. Distinguishes \"the\n // break ended with the ad on screen but no view/dismiss callback\" (a\n // terminal 'ready', kept for v1 compatibility) from \"a prepared ad was\n // never shown before the break ended\" (terminal 'dismissed').\n let adShown = 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 adShown = true;\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 ? {\n // A reward was offered but the ad never reached the screen\n // (the game retained show() and let the break lapse): the\n // break is over without a view, so resolve 'dismissed',\n // not the non-terminal-looking 'ready'.\n status: status === 'ready' && !adShown ? 'dismissed' : status,\n }\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() || parentIsForeignSite()) 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 // localStorage compatibility for hosted builds, which run on an opaque origin\n // where a real Storage isn't just empty — it throws. The controller talks to\n // the RAW save/load transport, not sdk.save(), because sdk.save() routes back\n // through it once the shim owns the slot. The script-tag build installs it at\n // load; module consumers call BBArcade.storage.install() before boot.\n const storage = createStorageController({\n save: function (blob: string) {\n return request('save', blob) as Promise<void>;\n },\n load: function () {\n return request('load') as Promise<string | null>;\n },\n byteLength: utf8ByteLength,\n maxBytes: MAX_SAVE_BYTES,\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 const data = String(blob);\n // Fail fast on an oversized blob instead of waiting out a host round\n // trip that can only end in the same 'too_large' rejection.\n if (utf8ByteLength(data) > MAX_SAVE_BYTES) {\n return Promise.reject(sdkError('too_large'));\n }\n // With the shim installed both halves share the player's one save slot,\n // so the write has to go through the controller's single writer. Without\n // it the bytes on the wire are exactly what they always were.\n if (storage.active()) return storage.writeApp(data);\n return request('save', data) as Promise<void>;\n },\n load: function () {\n return (request('load') as Promise<string | null>).then(function (raw) {\n // Tolerant unwrap: a raw pre-shim blob comes back untouched, so a game\n // that starts using the shim never loses the save it wrote before.\n return parseEnvelope(raw).app;\n });\n },\n storage: storage,\n getPlayer: getPlayer,\n onPlayerChange: function (handler) {\n if (typeof handler !== 'function') return function () {};\n playerChangeHandlers.push(handler);\n return function () {\n const idx = playerChangeHandlers.indexOf(handler);\n if (idx !== -1) playerChangeHandlers.splice(idx, 1);\n };\n },\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 BBArcadeStorageMode,\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 // No window to shim and nothing to persist to: report the honest mode\n // rather than pretending an install succeeded.\n storage: {\n install: (): BBArcadeStorageMode => 'memory',\n ready: (): Promise<BBArcadeStorageMode> => Promise.resolve('memory'),\n flush: () => Promise.resolve(),\n mode: 'memory' as BBArcadeStorageMode,\n },\n getPlayer: () => Promise.resolve(null),\n onPlayerChange: () => () => {},\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.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  BBArcade,
3
3
  VERSION,
4
4
  src_default
5
- } from "./chunk-PYW5F45R.js";
5
+ } from "./chunk-CWSX76FK.js";
6
6
  export {
7
7
  BBArcade,
8
8
  VERSION as PROTOCOL_VERSION,
@@ -356,6 +356,7 @@ var DEFAULT_ALLOW = [
356
356
  "localhost",
357
357
  "127.0.0.1"
358
358
  ];
359
+ var REQUEST_HOSTS = DEFAULT_ALLOW.concat(["vercel.app"]);
359
360
  var SITELOCK_PUBLIC_KEY_B64 = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE6WC8fJweDpfKRcZW9Q9eOLxPXmFCO8R8lY1kfZbuAQt65E0CTu2rM80XfW3nYrSAqO+Eev8gxrGS0bAnNaMDGg==";
360
361
  var SITELOCK_MAX_SKEW_MS = 5 * 60 * 1e3;
361
362
  function sdkError(code) {
@@ -528,10 +529,20 @@ function createBBArcade() {
528
529
  return true;
529
530
  }
530
531
  }
532
+ function parentIsForeignSite() {
533
+ try {
534
+ const ancestors = window.location.ancestorOrigins;
535
+ const parentOrigin = ancestors && ancestors.length ? ancestors[0] : "";
536
+ if (!/^https?:\/\//.test(parentOrigin)) return false;
537
+ return !hostnameAllowed(parentOrigin, REQUEST_HOSTS);
538
+ } catch (err) {
539
+ return false;
540
+ }
541
+ }
531
542
  function request(type, payload, timeoutMs = SAVE_TIMEOUT_MS) {
532
543
  return new Promise(function(resolve, reject) {
533
544
  if (blocked) return reject(sdkError("error"));
534
- if (!isEmbedded()) return reject(sdkError("unsupported"));
545
+ if (!isEmbedded() || parentIsForeignSite()) return reject(sdkError("unsupported"));
535
546
  const requestId = type + "_" + ++seq + "_" + Date.now();
536
547
  const timer = setTimeout(function() {
537
548
  if (pending[requestId]) {
@@ -1046,7 +1057,7 @@ function createBBArcade() {
1046
1057
  });
1047
1058
  }
1048
1059
  function whenHostConfig(graceMs) {
1049
- if (hostConfigReceived || !isEmbedded()) return Promise.resolve();
1060
+ if (hostConfigReceived || !isEmbedded() || parentIsForeignSite()) return Promise.resolve();
1050
1061
  return new Promise(function(resolve) {
1051
1062
  const timer = setTimeout(resolve, graceMs);
1052
1063
  configWaiters.push(function() {