@bountyboard/arcade-sdk 1.0.0

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.
@@ -0,0 +1,328 @@
1
+ /**
2
+ * Public API types for the Bounty Board Arcade SDK.
3
+ *
4
+ * SINGLE SOURCE OF TRUTH for the SDK's public types. The npm module's .d.ts is
5
+ * bundled from here by tsup, and the self-contained global declaration file
6
+ * (served at /arcade-sdk/v1.d.ts for script-tag users) is generated from this
7
+ * file by scripts/build-global-dts.mjs — keep every declaration here
8
+ * self-contained (no imports) so that generation stays a plain text transform.
9
+ */
10
+ /** Machine-readable failure code carried by every SDK rejection (`err.code`). */
11
+ type BBArcadeErrorCode =
12
+ /** Nothing will answer: standalone play, or not a Bounty-Board-hosted build. */
13
+ 'unsupported'
14
+ /** The player isn't logged in to Bounty Board. */
15
+ | 'unauthenticated'
16
+ /** The save blob is over the per-save byte cap (~1MB). */
17
+ | 'too_large'
18
+ /** The host refused the request (bad payload, unknown game, etc.). */
19
+ | 'rejected'
20
+ /** Transport/server failure or timeout. */
21
+ | 'error';
22
+ /** Rejection reason for save()/load(): a real Error that also carries `code`. */
23
+ interface BBArcadeError extends Error {
24
+ code: BBArcadeErrorCode;
25
+ }
26
+ /** Rewarded-ads settings accepted by init()/configure(). */
27
+ interface BBArcadeRewardedAdsConfig {
28
+ /** Master switch for the game's own rewarded-ad calls (default true). Ads still only run when the Bounty Board host enables them for your game. */
29
+ enabled?: boolean;
30
+ /** Legacy AdSense channel label. Ignored on Bounty Board (revenue is attributed by page URL). */
31
+ adChannel?: string;
32
+ /** Force Google's test-ads mode. Defaults to true on localhost/file:, and the Bounty Board host sets it per environment. */
33
+ testMode?: boolean;
34
+ /** Warm up the H5 ads library immediately so the first placement is less likely to be unavailable. */
35
+ preload?: boolean;
36
+ /** How long a rewarded placement waits for an ad before resolving 'unavailable', in ms (default 6000, max 15000). */
37
+ loadTimeoutMs?: number;
38
+ }
39
+ /** Options bag for init() and configure(). */
40
+ interface BBArcadeConfig {
41
+ rewardedAds?: BBArcadeRewardedAdsConfig;
42
+ }
43
+ /**
44
+ * The logged-in player's public display identity, as delivered by the Bounty
45
+ * Board host. Display name + avatar ONLY — the host never sends ids, emails,
46
+ * or roles.
47
+ */
48
+ interface BBArcadePlayer {
49
+ /** Display name for in-game UI (e.g. "Good luck, Grant!"). */
50
+ name: string;
51
+ /** Avatar image URL, or null when the player has no avatar. */
52
+ avatarUrl: string | null;
53
+ }
54
+ /** Options for lockToHost(). */
55
+ interface BBArcadeLockToHostOptions {
56
+ /**
57
+ * Extra hostnames to permit (your own domain, a staging or preview host).
58
+ * Matches the host and its subdomains; added to the bountyboard.gg +
59
+ * localhost defaults. Plain hosts, host:port, or full URLs all work.
60
+ */
61
+ allow?: string[];
62
+ /**
63
+ * Demand a cryptographically signed origin attestation from the host and
64
+ * verify it with the SDK's embedded public key (hardens the check beyond
65
+ * the best-effort browser signals). Falls back to best-effort when the host
66
+ * reports no signing key or the browser lacks Web Crypto; a present-but-
67
+ * invalid attestation — or no host answering at all — blocks.
68
+ */
69
+ signed?: boolean;
70
+ /** Called instead of the default block screen so you can render your own. */
71
+ onBlocked?: () => void;
72
+ /** URL to send the player to when blocked (best effort; a sandboxed build may not be allowed to navigate). */
73
+ redirect?: string;
74
+ }
75
+ /** Outcome of a rewarded placement. */
76
+ type BBArcadeRewardedAdStatus = 'viewed' | 'dismissed' | 'ready' | 'unavailable' | 'error';
77
+ /** Resolution value of rewardedAd()/showRewardedAd(). */
78
+ interface BBArcadeRewardedAdResult {
79
+ /** 'viewed' is the only status that should grant the reward. */
80
+ status: BBArcadeRewardedAdStatus;
81
+ /** Sanitized placement name the ad ran under. */
82
+ placement: string;
83
+ /** Sanitized reward label. */
84
+ reward: string;
85
+ /** Unique id for this ad break (for your own logging/dedup). */
86
+ adBreakId: string;
87
+ /** Present when a size was requested. */
88
+ size?: 'small' | 'medium' | 'large';
89
+ /**
90
+ * Failure detail when status is 'unavailable' or 'error', e.g.
91
+ * 'host_disabled' | 'ad_break_unavailable' | 'ad_break_timeout' |
92
+ * 'no_rewarded_ad' | 'ad_in_progress' | 'show_ad_error' |
93
+ * 'before_reward_error' | 'ad_break_error'.
94
+ */
95
+ error?: string;
96
+ /** Google's H5 breakStatus string, when the placement reported one. */
97
+ breakStatus?: string;
98
+ }
99
+ /** Options for rewardedAd()/showRewardedAd() (all optional). */
100
+ interface BBArcadeRewardedAdOptions {
101
+ /** Placement name for analytics, e.g. 'revive' (alias: name). */
102
+ placement?: string;
103
+ /** Alias for placement. */
104
+ name?: string;
105
+ /** Reward label for analytics, e.g. 'extra_life'. */
106
+ reward?: string;
107
+ /** Supply your own ad-break id instead of the generated one. */
108
+ adBreakId?: string;
109
+ /** Requested ad size. */
110
+ size?: 'small' | 'medium' | 'large';
111
+ /** Legacy AdSense channel label. Ignored on Bounty Board. */
112
+ adChannel?: string;
113
+ /** Force Google's test-ads mode (the Bounty Board host's setting wins when present). */
114
+ testMode?: boolean;
115
+ /** Per-call override of how long to wait for an ad, in ms (max 15000). */
116
+ loadTimeoutMs?: number;
117
+ /**
118
+ * Called when an ad is ready. Pause your game, then call showAd() to run it.
119
+ * When omitted, the ad shows immediately.
120
+ */
121
+ beforeReward?: (showAd: () => void) => void;
122
+ /** The player watched the ad to completion — grant the reward. */
123
+ adViewed?: (result: BBArcadeRewardedAdResult) => void;
124
+ /** The player closed the ad early (or after viewing; check status). */
125
+ adDismissed?: (result: BBArcadeRewardedAdResult) => void;
126
+ /** Google's raw adBreakDone callback, with its placementInfo. */
127
+ adBreakDone?: (placementInfo: unknown) => void;
128
+ /** Alias of adViewed. */
129
+ onReward?: (result: BBArcadeRewardedAdResult) => void;
130
+ /** Alias of adDismissed. */
131
+ onDismissed?: (result: BBArcadeRewardedAdResult) => void;
132
+ /** Always called once with the final result (any status). */
133
+ onDone?: (result: BBArcadeRewardedAdResult) => void;
134
+ /** Called when the placement fails with status 'error'. */
135
+ onError?: (result: BBArcadeRewardedAdResult) => void;
136
+ /** Called when no ad could be shown (status 'unavailable'). */
137
+ onUnavailable?: (result: BBArcadeRewardedAdResult) => void;
138
+ }
139
+ /** Options for rewardedBreak(): everything rewardedAd() takes, plus onStart. */
140
+ interface BBArcadeRewardedBreakOptions extends BBArcadeRewardedAdOptions {
141
+ /** Called once right before the ad shows — pause gameplay/audio here. */
142
+ onStart?: () => void;
143
+ }
144
+ /** A player in a multiplayer room — display identity only, plus the room-scoped id. */
145
+ interface BBArcadeMpPlayer {
146
+ /** Room-scoped player id (stable for the connection, never a Bounty Board account id). */
147
+ id: string;
148
+ name: string;
149
+ avatarUrl: string | null;
150
+ }
151
+ /** One player's final standing in a finished multiplayer match. */
152
+ interface BBArcadeMpResult {
153
+ playerId: string;
154
+ name: string;
155
+ placement: number;
156
+ score: number;
157
+ outcome: 'win' | 'loss' | 'draw';
158
+ }
159
+ /** Options for multiplayer joinRoom(). */
160
+ interface BBArcadeMpJoinOptions {
161
+ /** Join an existing room by its share code. */
162
+ code?: string;
163
+ /** Create a new room (a share code is generated for you). */
164
+ create?: boolean;
165
+ /**
166
+ * Local development only: connect straight to a room server (e.g. wrangler
167
+ * dev with DEV_ALLOW_UNSIGNED=1) instead of asking the Bounty Board host for
168
+ * a ticket. Both must be provided together.
169
+ */
170
+ roomUrl?: string;
171
+ ticket?: string;
172
+ }
173
+ /** Events a multiplayer room emits. */
174
+ interface BBArcadeMpRoomEvents {
175
+ /** Authoritative state snapshot (already filtered to what YOU may see). */
176
+ snapshot: {
177
+ tick: number;
178
+ state: unknown;
179
+ };
180
+ playerJoin: {
181
+ player: BBArcadeMpPlayer;
182
+ };
183
+ playerLeave: {
184
+ playerId: string;
185
+ };
186
+ /** Game-defined server event (tag happened, round started, ...). */
187
+ event: unknown;
188
+ /** The match finished; results were reported by the server, not by clients. */
189
+ end: {
190
+ results: BBArcadeMpResult[];
191
+ };
192
+ error: {
193
+ code: string;
194
+ };
195
+ /** Connection dropped. reconnecting: true means the SDK is retrying. */
196
+ close: {
197
+ reconnecting: boolean;
198
+ };
199
+ }
200
+ /** A live connection to an authoritative multiplayer room. */
201
+ interface BBArcadeMpRoom {
202
+ /** The share code friends use to join this room. */
203
+ code: string;
204
+ /** Your room-scoped player id. */
205
+ playerId: string;
206
+ /** Players currently in the room (kept up to date). */
207
+ players: BBArcadeMpPlayer[];
208
+ /** Latest authoritative state snapshot (as filtered for you). */
209
+ state: unknown;
210
+ /** Send an INPUT to the server (never authoritative state — the server simulates). */
211
+ send(input: unknown): void;
212
+ /** Subscribe to a room event; returns an unsubscribe function. */
213
+ on<K extends keyof BBArcadeMpRoomEvents>(event: K, handler: (data: BBArcadeMpRoomEvents[K]) => void): () => void;
214
+ /** Leave the room and close the connection (no reconnect). */
215
+ leave(): void;
216
+ }
217
+ /** The multiplayer module (BBArcade.multiplayer in script-tag builds). */
218
+ interface BBArcadeMultiplayer {
219
+ /**
220
+ * Create or join an authoritative multiplayer room. Resolves once the room
221
+ * server accepted the signed ticket and sent the welcome state. Rejects with
222
+ * a BBArcadeError ('unsupported' off Bounty Board, 'unauthenticated' /
223
+ * 'rejected' / 'error' from the ticket handshake).
224
+ */
225
+ joinRoom(options?: BBArcadeMpJoinOptions): Promise<BBArcadeMpRoom>;
226
+ }
227
+ /**
228
+ * The Bounty Board Arcade SDK surface (window.BBArcade for script-tag builds,
229
+ * the `BBArcade` export of @bountyboard/arcade-sdk for module builds).
230
+ *
231
+ * Every method is optional to call and safe standalone: off Bounty Board the
232
+ * fire-and-forget signals no-op, and save()/load() reject fast with code
233
+ * 'unsupported' instead of hanging.
234
+ */
235
+ interface BBArcadeSDK {
236
+ /**
237
+ * Refuse to run unless embedded on a Bounty Board host (anti
238
+ * scrape-and-reupload deterrent — not DRM). Call once, early, before boot.
239
+ */
240
+ lockToHost(options?: BBArcadeLockToHostOptions): void;
241
+ /**
242
+ * Configure optional SDK modules and announce the game to the host. Resolves
243
+ * once the host answers with its config, or after a short grace (~1.5s) when
244
+ * nothing answers — so it never blocks your boot and awaiting is optional.
245
+ */
246
+ init(options?: BBArcadeConfig): Promise<void>;
247
+ /** Apply the same options as init() without the host handshake. */
248
+ configure(options?: BBArcadeConfig): void;
249
+ /** Warm up Google's H5 ads library. Resolves true when the placement API is available. */
250
+ preloadRewardedAds(options?: BBArcadeRewardedAdOptions): Promise<boolean>;
251
+ /** Alias of preloadRewardedAds. */
252
+ preloadRewardedAd(options?: BBArcadeRewardedAdOptions): Promise<boolean>;
253
+ /** Signal that the game finished loading and the player can start. */
254
+ ready(): void;
255
+ /** Poki-style alias of ready(). */
256
+ gameLoadingFinished(): void;
257
+ /** Signal that active gameplay started (run begins or resumes). */
258
+ gameplayStart(): void;
259
+ /** Signal that active gameplay stopped (death, pause menu, ad break). */
260
+ gameplayStop(): void;
261
+ /**
262
+ * Report the player's current integer score. Call freely; the host throttles.
263
+ * Pass { mode: 'daily' } when the run is your shared-seed Daily so the Today
264
+ * board can mark it.
265
+ */
266
+ submitScore(score: number, opts?: {
267
+ mode?: 'daily';
268
+ }): void;
269
+ /** Report the final integer score on game over (feeds the leaderboards). */
270
+ gameOver(score: number, opts?: {
271
+ mode?: 'daily';
272
+ }): void;
273
+ /** Signal that an immersive WebXR session started (keeps playtime counting). */
274
+ xrSessionStart(): void;
275
+ /** Signal that the immersive WebXR session ended. */
276
+ xrSessionEnd(): void;
277
+ /**
278
+ * Show a rewarded ad via Google's H5 placement API. Resolves with the full
279
+ * result object; only status 'viewed' should grant the reward. Prefer
280
+ * rewardedBreak() unless you need the low-level callbacks.
281
+ */
282
+ rewardedAd(options?: BBArcadeRewardedAdOptions): Promise<BBArcadeRewardedAdResult>;
283
+ /** Alias of rewardedAd. */
284
+ showRewardedAd(options?: BBArcadeRewardedAdOptions): Promise<BBArcadeRewardedAdResult>;
285
+ /**
286
+ * Developer-standard rewarded break. Show your own "Watch ad for reward" UI
287
+ * first; resolves true only when the ad was actually viewed. Accepts an
288
+ * options bag or a bare onStart callback.
289
+ */
290
+ rewardedBreak(optionsOrOnStart?: BBArcadeRewardedBreakOptions | (() => void)): Promise<boolean>;
291
+ /**
292
+ * Save the player's progress (a string blob, ~1MB max) to their Bounty Board
293
+ * account. Requires a Bounty-Board-hosted build upload and a logged-in
294
+ * player; rejects with a BBArcadeError otherwise (code 'unsupported' /
295
+ * 'unauthenticated' / 'too_large' / 'rejected' / 'error').
296
+ */
297
+ save(blob: string): Promise<void>;
298
+ /**
299
+ * Load the player's saved blob. Resolves with the string, or null when there
300
+ * is no save yet. Rejects like save() ('unauthenticated' when logged out).
301
+ */
302
+ load(): Promise<string | null>;
303
+ /**
304
+ * The logged-in player's display identity for in-game UI. Resolves
305
+ * { name, avatarUrl } once the host's config handshake completes (or after
306
+ * a short grace when nothing answers), and null for guests, standalone
307
+ * play, or off Bounty Board — always handle the null case. Privacy:
308
+ * display name + avatar only, never ids, emails, or roles.
309
+ */
310
+ getPlayer(): Promise<BBArcadePlayer | null>;
311
+ /**
312
+ * Deterministic A/B variant for this player (even split; stable per
313
+ * player+game+key). Resolves the alphabetically-first variant as the
314
+ * fallback/control on standalone play or any host error. Assignments show
315
+ * up split-by-variant in studio analytics.
316
+ */
317
+ getVariant(key: string, variants: string[]): Promise<string | null>;
318
+ /**
319
+ * Multiplayer rooms. Present in the script-tag build; module consumers
320
+ * import { joinRoom } from '@bountyboard/arcade-sdk/multiplayer' instead
321
+ * (keeps the core import lean).
322
+ */
323
+ multiplayer?: BBArcadeMultiplayer;
324
+ /** SDK protocol version (matches the `v` field on every message). */
325
+ version: number;
326
+ }
327
+
328
+ export type { BBArcadeSDK as B, BBArcadeConfig as a, BBArcadeError as b, BBArcadeErrorCode as c, BBArcadeLockToHostOptions as d, BBArcadePlayer as e, BBArcadeRewardedAdOptions as f, BBArcadeRewardedAdResult as g, BBArcadeRewardedAdStatus as h, BBArcadeRewardedAdsConfig as i, BBArcadeRewardedBreakOptions as j, BBArcadeMpJoinOptions as k, BBArcadeMpRoom as l, BBArcadeMultiplayer as m, BBArcadeMpPlayer as n, BBArcadeMpResult as o, BBArcadeMpRoomEvents as p };
@@ -0,0 +1,328 @@
1
+ /**
2
+ * Public API types for the Bounty Board Arcade SDK.
3
+ *
4
+ * SINGLE SOURCE OF TRUTH for the SDK's public types. The npm module's .d.ts is
5
+ * bundled from here by tsup, and the self-contained global declaration file
6
+ * (served at /arcade-sdk/v1.d.ts for script-tag users) is generated from this
7
+ * file by scripts/build-global-dts.mjs — keep every declaration here
8
+ * self-contained (no imports) so that generation stays a plain text transform.
9
+ */
10
+ /** Machine-readable failure code carried by every SDK rejection (`err.code`). */
11
+ type BBArcadeErrorCode =
12
+ /** Nothing will answer: standalone play, or not a Bounty-Board-hosted build. */
13
+ 'unsupported'
14
+ /** The player isn't logged in to Bounty Board. */
15
+ | 'unauthenticated'
16
+ /** The save blob is over the per-save byte cap (~1MB). */
17
+ | 'too_large'
18
+ /** The host refused the request (bad payload, unknown game, etc.). */
19
+ | 'rejected'
20
+ /** Transport/server failure or timeout. */
21
+ | 'error';
22
+ /** Rejection reason for save()/load(): a real Error that also carries `code`. */
23
+ interface BBArcadeError extends Error {
24
+ code: BBArcadeErrorCode;
25
+ }
26
+ /** Rewarded-ads settings accepted by init()/configure(). */
27
+ interface BBArcadeRewardedAdsConfig {
28
+ /** Master switch for the game's own rewarded-ad calls (default true). Ads still only run when the Bounty Board host enables them for your game. */
29
+ enabled?: boolean;
30
+ /** Legacy AdSense channel label. Ignored on Bounty Board (revenue is attributed by page URL). */
31
+ adChannel?: string;
32
+ /** Force Google's test-ads mode. Defaults to true on localhost/file:, and the Bounty Board host sets it per environment. */
33
+ testMode?: boolean;
34
+ /** Warm up the H5 ads library immediately so the first placement is less likely to be unavailable. */
35
+ preload?: boolean;
36
+ /** How long a rewarded placement waits for an ad before resolving 'unavailable', in ms (default 6000, max 15000). */
37
+ loadTimeoutMs?: number;
38
+ }
39
+ /** Options bag for init() and configure(). */
40
+ interface BBArcadeConfig {
41
+ rewardedAds?: BBArcadeRewardedAdsConfig;
42
+ }
43
+ /**
44
+ * The logged-in player's public display identity, as delivered by the Bounty
45
+ * Board host. Display name + avatar ONLY — the host never sends ids, emails,
46
+ * or roles.
47
+ */
48
+ interface BBArcadePlayer {
49
+ /** Display name for in-game UI (e.g. "Good luck, Grant!"). */
50
+ name: string;
51
+ /** Avatar image URL, or null when the player has no avatar. */
52
+ avatarUrl: string | null;
53
+ }
54
+ /** Options for lockToHost(). */
55
+ interface BBArcadeLockToHostOptions {
56
+ /**
57
+ * Extra hostnames to permit (your own domain, a staging or preview host).
58
+ * Matches the host and its subdomains; added to the bountyboard.gg +
59
+ * localhost defaults. Plain hosts, host:port, or full URLs all work.
60
+ */
61
+ allow?: string[];
62
+ /**
63
+ * Demand a cryptographically signed origin attestation from the host and
64
+ * verify it with the SDK's embedded public key (hardens the check beyond
65
+ * the best-effort browser signals). Falls back to best-effort when the host
66
+ * reports no signing key or the browser lacks Web Crypto; a present-but-
67
+ * invalid attestation — or no host answering at all — blocks.
68
+ */
69
+ signed?: boolean;
70
+ /** Called instead of the default block screen so you can render your own. */
71
+ onBlocked?: () => void;
72
+ /** URL to send the player to when blocked (best effort; a sandboxed build may not be allowed to navigate). */
73
+ redirect?: string;
74
+ }
75
+ /** Outcome of a rewarded placement. */
76
+ type BBArcadeRewardedAdStatus = 'viewed' | 'dismissed' | 'ready' | 'unavailable' | 'error';
77
+ /** Resolution value of rewardedAd()/showRewardedAd(). */
78
+ interface BBArcadeRewardedAdResult {
79
+ /** 'viewed' is the only status that should grant the reward. */
80
+ status: BBArcadeRewardedAdStatus;
81
+ /** Sanitized placement name the ad ran under. */
82
+ placement: string;
83
+ /** Sanitized reward label. */
84
+ reward: string;
85
+ /** Unique id for this ad break (for your own logging/dedup). */
86
+ adBreakId: string;
87
+ /** Present when a size was requested. */
88
+ size?: 'small' | 'medium' | 'large';
89
+ /**
90
+ * Failure detail when status is 'unavailable' or 'error', e.g.
91
+ * 'host_disabled' | 'ad_break_unavailable' | 'ad_break_timeout' |
92
+ * 'no_rewarded_ad' | 'ad_in_progress' | 'show_ad_error' |
93
+ * 'before_reward_error' | 'ad_break_error'.
94
+ */
95
+ error?: string;
96
+ /** Google's H5 breakStatus string, when the placement reported one. */
97
+ breakStatus?: string;
98
+ }
99
+ /** Options for rewardedAd()/showRewardedAd() (all optional). */
100
+ interface BBArcadeRewardedAdOptions {
101
+ /** Placement name for analytics, e.g. 'revive' (alias: name). */
102
+ placement?: string;
103
+ /** Alias for placement. */
104
+ name?: string;
105
+ /** Reward label for analytics, e.g. 'extra_life'. */
106
+ reward?: string;
107
+ /** Supply your own ad-break id instead of the generated one. */
108
+ adBreakId?: string;
109
+ /** Requested ad size. */
110
+ size?: 'small' | 'medium' | 'large';
111
+ /** Legacy AdSense channel label. Ignored on Bounty Board. */
112
+ adChannel?: string;
113
+ /** Force Google's test-ads mode (the Bounty Board host's setting wins when present). */
114
+ testMode?: boolean;
115
+ /** Per-call override of how long to wait for an ad, in ms (max 15000). */
116
+ loadTimeoutMs?: number;
117
+ /**
118
+ * Called when an ad is ready. Pause your game, then call showAd() to run it.
119
+ * When omitted, the ad shows immediately.
120
+ */
121
+ beforeReward?: (showAd: () => void) => void;
122
+ /** The player watched the ad to completion — grant the reward. */
123
+ adViewed?: (result: BBArcadeRewardedAdResult) => void;
124
+ /** The player closed the ad early (or after viewing; check status). */
125
+ adDismissed?: (result: BBArcadeRewardedAdResult) => void;
126
+ /** Google's raw adBreakDone callback, with its placementInfo. */
127
+ adBreakDone?: (placementInfo: unknown) => void;
128
+ /** Alias of adViewed. */
129
+ onReward?: (result: BBArcadeRewardedAdResult) => void;
130
+ /** Alias of adDismissed. */
131
+ onDismissed?: (result: BBArcadeRewardedAdResult) => void;
132
+ /** Always called once with the final result (any status). */
133
+ onDone?: (result: BBArcadeRewardedAdResult) => void;
134
+ /** Called when the placement fails with status 'error'. */
135
+ onError?: (result: BBArcadeRewardedAdResult) => void;
136
+ /** Called when no ad could be shown (status 'unavailable'). */
137
+ onUnavailable?: (result: BBArcadeRewardedAdResult) => void;
138
+ }
139
+ /** Options for rewardedBreak(): everything rewardedAd() takes, plus onStart. */
140
+ interface BBArcadeRewardedBreakOptions extends BBArcadeRewardedAdOptions {
141
+ /** Called once right before the ad shows — pause gameplay/audio here. */
142
+ onStart?: () => void;
143
+ }
144
+ /** A player in a multiplayer room — display identity only, plus the room-scoped id. */
145
+ interface BBArcadeMpPlayer {
146
+ /** Room-scoped player id (stable for the connection, never a Bounty Board account id). */
147
+ id: string;
148
+ name: string;
149
+ avatarUrl: string | null;
150
+ }
151
+ /** One player's final standing in a finished multiplayer match. */
152
+ interface BBArcadeMpResult {
153
+ playerId: string;
154
+ name: string;
155
+ placement: number;
156
+ score: number;
157
+ outcome: 'win' | 'loss' | 'draw';
158
+ }
159
+ /** Options for multiplayer joinRoom(). */
160
+ interface BBArcadeMpJoinOptions {
161
+ /** Join an existing room by its share code. */
162
+ code?: string;
163
+ /** Create a new room (a share code is generated for you). */
164
+ create?: boolean;
165
+ /**
166
+ * Local development only: connect straight to a room server (e.g. wrangler
167
+ * dev with DEV_ALLOW_UNSIGNED=1) instead of asking the Bounty Board host for
168
+ * a ticket. Both must be provided together.
169
+ */
170
+ roomUrl?: string;
171
+ ticket?: string;
172
+ }
173
+ /** Events a multiplayer room emits. */
174
+ interface BBArcadeMpRoomEvents {
175
+ /** Authoritative state snapshot (already filtered to what YOU may see). */
176
+ snapshot: {
177
+ tick: number;
178
+ state: unknown;
179
+ };
180
+ playerJoin: {
181
+ player: BBArcadeMpPlayer;
182
+ };
183
+ playerLeave: {
184
+ playerId: string;
185
+ };
186
+ /** Game-defined server event (tag happened, round started, ...). */
187
+ event: unknown;
188
+ /** The match finished; results were reported by the server, not by clients. */
189
+ end: {
190
+ results: BBArcadeMpResult[];
191
+ };
192
+ error: {
193
+ code: string;
194
+ };
195
+ /** Connection dropped. reconnecting: true means the SDK is retrying. */
196
+ close: {
197
+ reconnecting: boolean;
198
+ };
199
+ }
200
+ /** A live connection to an authoritative multiplayer room. */
201
+ interface BBArcadeMpRoom {
202
+ /** The share code friends use to join this room. */
203
+ code: string;
204
+ /** Your room-scoped player id. */
205
+ playerId: string;
206
+ /** Players currently in the room (kept up to date). */
207
+ players: BBArcadeMpPlayer[];
208
+ /** Latest authoritative state snapshot (as filtered for you). */
209
+ state: unknown;
210
+ /** Send an INPUT to the server (never authoritative state — the server simulates). */
211
+ send(input: unknown): void;
212
+ /** Subscribe to a room event; returns an unsubscribe function. */
213
+ on<K extends keyof BBArcadeMpRoomEvents>(event: K, handler: (data: BBArcadeMpRoomEvents[K]) => void): () => void;
214
+ /** Leave the room and close the connection (no reconnect). */
215
+ leave(): void;
216
+ }
217
+ /** The multiplayer module (BBArcade.multiplayer in script-tag builds). */
218
+ interface BBArcadeMultiplayer {
219
+ /**
220
+ * Create or join an authoritative multiplayer room. Resolves once the room
221
+ * server accepted the signed ticket and sent the welcome state. Rejects with
222
+ * a BBArcadeError ('unsupported' off Bounty Board, 'unauthenticated' /
223
+ * 'rejected' / 'error' from the ticket handshake).
224
+ */
225
+ joinRoom(options?: BBArcadeMpJoinOptions): Promise<BBArcadeMpRoom>;
226
+ }
227
+ /**
228
+ * The Bounty Board Arcade SDK surface (window.BBArcade for script-tag builds,
229
+ * the `BBArcade` export of @bountyboard/arcade-sdk for module builds).
230
+ *
231
+ * Every method is optional to call and safe standalone: off Bounty Board the
232
+ * fire-and-forget signals no-op, and save()/load() reject fast with code
233
+ * 'unsupported' instead of hanging.
234
+ */
235
+ interface BBArcadeSDK {
236
+ /**
237
+ * Refuse to run unless embedded on a Bounty Board host (anti
238
+ * scrape-and-reupload deterrent — not DRM). Call once, early, before boot.
239
+ */
240
+ lockToHost(options?: BBArcadeLockToHostOptions): void;
241
+ /**
242
+ * Configure optional SDK modules and announce the game to the host. Resolves
243
+ * once the host answers with its config, or after a short grace (~1.5s) when
244
+ * nothing answers — so it never blocks your boot and awaiting is optional.
245
+ */
246
+ init(options?: BBArcadeConfig): Promise<void>;
247
+ /** Apply the same options as init() without the host handshake. */
248
+ configure(options?: BBArcadeConfig): void;
249
+ /** Warm up Google's H5 ads library. Resolves true when the placement API is available. */
250
+ preloadRewardedAds(options?: BBArcadeRewardedAdOptions): Promise<boolean>;
251
+ /** Alias of preloadRewardedAds. */
252
+ preloadRewardedAd(options?: BBArcadeRewardedAdOptions): Promise<boolean>;
253
+ /** Signal that the game finished loading and the player can start. */
254
+ ready(): void;
255
+ /** Poki-style alias of ready(). */
256
+ gameLoadingFinished(): void;
257
+ /** Signal that active gameplay started (run begins or resumes). */
258
+ gameplayStart(): void;
259
+ /** Signal that active gameplay stopped (death, pause menu, ad break). */
260
+ gameplayStop(): void;
261
+ /**
262
+ * Report the player's current integer score. Call freely; the host throttles.
263
+ * Pass { mode: 'daily' } when the run is your shared-seed Daily so the Today
264
+ * board can mark it.
265
+ */
266
+ submitScore(score: number, opts?: {
267
+ mode?: 'daily';
268
+ }): void;
269
+ /** Report the final integer score on game over (feeds the leaderboards). */
270
+ gameOver(score: number, opts?: {
271
+ mode?: 'daily';
272
+ }): void;
273
+ /** Signal that an immersive WebXR session started (keeps playtime counting). */
274
+ xrSessionStart(): void;
275
+ /** Signal that the immersive WebXR session ended. */
276
+ xrSessionEnd(): void;
277
+ /**
278
+ * Show a rewarded ad via Google's H5 placement API. Resolves with the full
279
+ * result object; only status 'viewed' should grant the reward. Prefer
280
+ * rewardedBreak() unless you need the low-level callbacks.
281
+ */
282
+ rewardedAd(options?: BBArcadeRewardedAdOptions): Promise<BBArcadeRewardedAdResult>;
283
+ /** Alias of rewardedAd. */
284
+ showRewardedAd(options?: BBArcadeRewardedAdOptions): Promise<BBArcadeRewardedAdResult>;
285
+ /**
286
+ * Developer-standard rewarded break. Show your own "Watch ad for reward" UI
287
+ * first; resolves true only when the ad was actually viewed. Accepts an
288
+ * options bag or a bare onStart callback.
289
+ */
290
+ rewardedBreak(optionsOrOnStart?: BBArcadeRewardedBreakOptions | (() => void)): Promise<boolean>;
291
+ /**
292
+ * Save the player's progress (a string blob, ~1MB max) to their Bounty Board
293
+ * account. Requires a Bounty-Board-hosted build upload and a logged-in
294
+ * player; rejects with a BBArcadeError otherwise (code 'unsupported' /
295
+ * 'unauthenticated' / 'too_large' / 'rejected' / 'error').
296
+ */
297
+ save(blob: string): Promise<void>;
298
+ /**
299
+ * Load the player's saved blob. Resolves with the string, or null when there
300
+ * is no save yet. Rejects like save() ('unauthenticated' when logged out).
301
+ */
302
+ load(): Promise<string | null>;
303
+ /**
304
+ * The logged-in player's display identity for in-game UI. Resolves
305
+ * { name, avatarUrl } once the host's config handshake completes (or after
306
+ * a short grace when nothing answers), and null for guests, standalone
307
+ * play, or off Bounty Board — always handle the null case. Privacy:
308
+ * display name + avatar only, never ids, emails, or roles.
309
+ */
310
+ getPlayer(): Promise<BBArcadePlayer | null>;
311
+ /**
312
+ * Deterministic A/B variant for this player (even split; stable per
313
+ * player+game+key). Resolves the alphabetically-first variant as the
314
+ * fallback/control on standalone play or any host error. Assignments show
315
+ * up split-by-variant in studio analytics.
316
+ */
317
+ getVariant(key: string, variants: string[]): Promise<string | null>;
318
+ /**
319
+ * Multiplayer rooms. Present in the script-tag build; module consumers
320
+ * import { joinRoom } from '@bountyboard/arcade-sdk/multiplayer' instead
321
+ * (keeps the core import lean).
322
+ */
323
+ multiplayer?: BBArcadeMultiplayer;
324
+ /** SDK protocol version (matches the `v` field on every message). */
325
+ version: number;
326
+ }
327
+
328
+ export type { BBArcadeSDK as B, BBArcadeConfig as a, BBArcadeError as b, BBArcadeErrorCode as c, BBArcadeLockToHostOptions as d, BBArcadePlayer as e, BBArcadeRewardedAdOptions as f, BBArcadeRewardedAdResult as g, BBArcadeRewardedAdStatus as h, BBArcadeRewardedAdsConfig as i, BBArcadeRewardedBreakOptions as j, BBArcadeMpJoinOptions as k, BBArcadeMpRoom as l, BBArcadeMultiplayer as m, BBArcadeMpPlayer as n, BBArcadeMpResult as o, BBArcadeMpRoomEvents as p };