@series-inc/rundot-game-sdk 5.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,1667 @@
1
+ interface AnalyticsApi {
2
+ recordCustomEvent(eventName: string, payload?: Record<string, any>): Promise<void>;
3
+ trackFunnelStep(stepNumber: number, stepName: string, funnelName?: string): Promise<void>;
4
+ }
5
+
6
+ interface RpcRequest {
7
+ type: 'rpc-request';
8
+ id: string;
9
+ method: string;
10
+ args?: any[];
11
+ }
12
+
13
+ interface RpcResponse {
14
+ type: 'rpc-response';
15
+ id: string;
16
+ method: string;
17
+ result?: any;
18
+ error?: {
19
+ message: string;
20
+ stack?: string;
21
+ };
22
+ }
23
+
24
+ interface RpcNotification {
25
+ type: 'rpc-notification';
26
+ id: string;
27
+ payload?: any;
28
+ }
29
+
30
+ type OnRequestCallback = (request: RpcRequest) => Promise<boolean>;
31
+ type OnResponseCallback = (response: RpcResponse) => Promise<boolean>;
32
+ type OnNotificationCallback = (notification: RpcNotification) => void;
33
+ interface RpcTransport {
34
+ onRequest(callback: OnRequestCallback): Subscription;
35
+ onResponse(callback: OnResponseCallback): Subscription;
36
+ onNotification(callback: OnNotificationCallback): Subscription;
37
+ sendRequest(request: RpcRequest): void;
38
+ sendResponse(response: RpcResponse): void;
39
+ }
40
+
41
+ interface Subscription {
42
+ unsubscribe: () => void;
43
+ }
44
+ declare class RpcClient {
45
+ private readonly pendingCalls;
46
+ private readonly notificationCallbacks;
47
+ private onResponseSub;
48
+ private onNotificationSub;
49
+ private transport;
50
+ start(transport: RpcTransport): void;
51
+ stop(): void;
52
+ onNotification<TPayload>(id: string, callback: (payload: TPayload) => void): Subscription;
53
+ callT<TArgs, TResult>(method: string, args: TArgs, timeout?: number): Promise<TResult>;
54
+ call<TResponse>(method: string, args?: any, timeout?: number): Promise<TResponse>;
55
+ private hasPendingCall;
56
+ private addPendingCall;
57
+ private removePendingCall;
58
+ private getPendingCall;
59
+ private handleRpcResponse;
60
+ private handleRpcNotification;
61
+ }
62
+
63
+ interface StorageApi {
64
+ key(index: number): Promise<string | null>;
65
+ clear(): Promise<void>;
66
+ length(): Promise<number>;
67
+ getAllItems(): Promise<string[]>;
68
+ getAllData(): Promise<Record<string, string>>;
69
+ setMultipleItems(items: {
70
+ key: string;
71
+ value: string;
72
+ }[]): Promise<void>;
73
+ removeMultipleItems(keys: string[]): Promise<void>;
74
+ setItem(key: string, item: string): Promise<void>;
75
+ getItem(key: string): Promise<string | null>;
76
+ removeItem(key: string): Promise<void>;
77
+ }
78
+
79
+ interface NavigationStackInfo {
80
+ isInStack: boolean;
81
+ stackPosition: number;
82
+ isTopOfStack: boolean;
83
+ stackDepth: number;
84
+ parentInstanceId: string;
85
+ }
86
+ interface PushAppOptions {
87
+ contextData?: any;
88
+ appParams?: any;
89
+ }
90
+ interface QuitOptions {
91
+ reason?: string;
92
+ forceClose?: boolean;
93
+ [key: string]: any;
94
+ }
95
+ interface NavigationApi {
96
+ pushApp(appId: string, options?: PushAppOptions): Promise<void>;
97
+ popApp(): Promise<void>;
98
+ getStackInfo(): NavigationStackInfo;
99
+ requestPopOrQuit(options?: QuitOptions): Promise<boolean>;
100
+ }
101
+
102
+ type TimeIntervalTriggerInput = {
103
+ type: 'timeInterval';
104
+ seconds: number;
105
+ repeats?: boolean;
106
+ channelId?: string;
107
+ };
108
+ type NotificationTriggerInput = TimeIntervalTriggerInput | null;
109
+ interface ScheduleNotificationOptions {
110
+ priority?: number;
111
+ groupId?: string;
112
+ payload?: Record<string, any>;
113
+ }
114
+ interface ScheduleLocalNotification {
115
+ id: string;
116
+ title?: string | null;
117
+ body?: string | null;
118
+ payload?: Record<string, any>;
119
+ trigger?: NotificationTriggerInput;
120
+ }
121
+ interface NotificationsApi {
122
+ scheduleAsync(title: string, body: string, seconds: number, notificationId?: string, options?: ScheduleNotificationOptions): Promise<string | null>;
123
+ cancelNotification(notificationId: string): Promise<boolean>;
124
+ getAllScheduledLocalNotifications(): Promise<ScheduleLocalNotification[]>;
125
+ isLocalNotificationsEnabled(): Promise<boolean>;
126
+ setLocalNotificationsEnabled(enabled: boolean): Promise<boolean>;
127
+ }
128
+
129
+ interface ShowToastOptions {
130
+ duration?: number;
131
+ variant?: 'success' | 'error' | 'warning' | 'info';
132
+ action?: {
133
+ label: string;
134
+ };
135
+ }
136
+ interface PopupsApi {
137
+ showToast(message: string, options?: ShowToastOptions): Promise<boolean>;
138
+ }
139
+
140
+ interface ProfileApi {
141
+ getCurrentProfile(): Profile;
142
+ }
143
+
144
+ interface DeviceInfo {
145
+ readonly screenSize: {
146
+ readonly width: number;
147
+ readonly height: number;
148
+ };
149
+ readonly viewportSize: {
150
+ readonly width: number;
151
+ readonly height: number;
152
+ };
153
+ readonly orientation: string;
154
+ readonly pixelRatio: number;
155
+ readonly fontScale: number;
156
+ readonly deviceType: string;
157
+ readonly hapticsEnabled: boolean;
158
+ readonly haptics: {
159
+ readonly supported: boolean;
160
+ readonly enabled: boolean;
161
+ };
162
+ }
163
+ interface DeviceApi {
164
+ getDevice(): DeviceInfo;
165
+ }
166
+
167
+ interface EnvironmentInfo {
168
+ readonly isDevelopment: boolean;
169
+ readonly platform: string;
170
+ readonly platformVersion: string;
171
+ readonly browserInfo?: {
172
+ readonly browser: string;
173
+ readonly userAgent: string;
174
+ readonly isMobile: boolean;
175
+ readonly isTablet: boolean;
176
+ readonly language: string;
177
+ };
178
+ }
179
+ interface EnvironmentApi {
180
+ getEnvironment(): EnvironmentInfo;
181
+ }
182
+
183
+ /**
184
+ * System API provides access to device and environment information.
185
+ * This is a unified namespace for system-level configuration data.
186
+ */
187
+ interface SystemApi {
188
+ /**
189
+ * Get device information (screen size, orientation, capabilities, etc.)
190
+ * @throws Error if called before RundotGameAPI.initializeAsync() completes
191
+ */
192
+ getDevice(): DeviceInfo;
193
+ /**
194
+ * Get environment information (platform, browser, development mode, etc.)
195
+ * @throws Error if called before RundotGameAPI.initializeAsync() completes
196
+ */
197
+ getEnvironment(): EnvironmentInfo;
198
+ /**
199
+ * Get safe area insets (padding to avoid device notches and host UI).
200
+ * This includes the toolbar/feedHeader height plus device safe areas.
201
+ * Safe area is static - it's set once during initialization and doesn't change.
202
+ * @returns SafeArea with top, right, bottom, left padding values in pixels
203
+ * @throws Error if called before RundotGameAPI.initializeAsync() completes
204
+ */
205
+ getSafeArea(): SafeArea;
206
+ /**
207
+ * Check if running on mobile device
208
+ * @returns true if on mobile device (iOS, Android, or mobile browser)
209
+ */
210
+ isMobile(): boolean;
211
+ /**
212
+ * Check if running on web platform
213
+ * @returns true if on web platform
214
+ */
215
+ isWeb(): boolean;
216
+ }
217
+
218
+ type SubPath = string;
219
+ interface FetchFromCdnOptions {
220
+ timeout?: number;
221
+ }
222
+ interface CdnApi {
223
+ resolveAssetUrl(subPath: string): string;
224
+ resolveAvatarAssetUrl(subPath: string): string;
225
+ resolveSharedLibUrl(subPath: string): string;
226
+ getAssetCdnBaseUrl(): string;
227
+ fetchAsset(assetPath: string, options?: FetchFromCdnOptions): Promise<Blob>;
228
+ fetchFromCdn(subPath: string, options?: FetchFromCdnOptions): Promise<Blob>;
229
+ }
230
+
231
+ interface ServerTimeData {
232
+ serverTime: number;
233
+ localTime: number;
234
+ timezoneOffset: number;
235
+ formattedTime: string;
236
+ locale: string;
237
+ }
238
+ interface GetFutureTimeOptions {
239
+ days?: number;
240
+ hours?: number;
241
+ minutes?: number;
242
+ timeOfDay?: {
243
+ hour: number;
244
+ minute: number;
245
+ second: number;
246
+ };
247
+ timezone?: any;
248
+ }
249
+ interface TimeApi {
250
+ requestTimeAsync(): Promise<ServerTimeData>;
251
+ formatTime(timestamp: number, options?: any): string;
252
+ formatNumber(value: number, options?: Intl.NumberFormatOptions): string;
253
+ getFutureTimeAsync(options?: GetFutureTimeOptions): Promise<number>;
254
+ }
255
+
256
+ interface AiMessage {
257
+ /**
258
+ * Depends on the model you are using. Most common is user, system, and assistant.
259
+ * If you are unsure, look up the specific model you are using.
260
+ */
261
+ role: string;
262
+ content: string;
263
+ }
264
+ type AiChatCompletionRequest = {
265
+ model: string;
266
+ messages?: Array<AiMessage>;
267
+ maxTokens?: number;
268
+ temperature?: number;
269
+ topP?: number;
270
+ topK?: number;
271
+ n?: number;
272
+ stop?: string | string[];
273
+ presencePenalty?: number;
274
+ frequencyPenalty?: number;
275
+ logitBias?: Record<string, number>;
276
+ seed?: number;
277
+ /**
278
+ * This is ONLY ever used when running the sdk outside of RUN.game.
279
+ * This gets ignored when the game using the sdk is used within a RUN.game instance.
280
+ *
281
+ * In other words, this should only be uswed when developing a game locally.
282
+ */
283
+ apiKey?: string;
284
+ };
285
+ type AiChatCompletionData = {
286
+ id: string;
287
+ ullm_id: string;
288
+ cost: {
289
+ prompt_cost: number;
290
+ completion_cost: number;
291
+ };
292
+ object: string;
293
+ created: number;
294
+ model: string;
295
+ choices: Array<{
296
+ index: number;
297
+ message: {
298
+ role: string;
299
+ content: string;
300
+ };
301
+ finish_reason: string;
302
+ }>;
303
+ usage: {
304
+ prompt_tokens: number;
305
+ completion_tokens: number;
306
+ total_tokens: number;
307
+ reasoning_tokens?: number;
308
+ cache_read_tokens?: number;
309
+ cache_write_tokens?: number;
310
+ };
311
+ };
312
+ interface AiApi {
313
+ requestChatCompletionAsync(request: AiChatCompletionRequest): Promise<AiChatCompletionData>;
314
+ getAvailableCompletionModels(): Promise<Array<string>>;
315
+ }
316
+
317
+ declare enum HapticFeedbackStyle {
318
+ Light = "light",
319
+ Medium = "medium",
320
+ Heavy = "heavy",
321
+ Success = "success",
322
+ Warning = "warning",
323
+ Error = "error"
324
+ }
325
+ interface HapticsApi {
326
+ triggerHapticAsync(style: HapticFeedbackStyle): Promise<void>;
327
+ }
328
+
329
+ interface Experiment {
330
+ readonly name: string;
331
+ readonly ruleID: string;
332
+ readonly value: Record<string, unknown>;
333
+ readonly groupName: string | null;
334
+ }
335
+ interface FeaturesApi {
336
+ getExperiment(experimentName: string): Promise<Experiment | null>;
337
+ getFeatureFlag(flagName: string): Promise<boolean>;
338
+ getFeatureGate(gateName: string): Promise<boolean>;
339
+ }
340
+
341
+ type AwakeCallback = () => void;
342
+ type SleepCallback = () => void;
343
+ type ResumeCallback = () => void;
344
+ type PauseCallback = () => void;
345
+ type QuitCallback = () => void;
346
+ interface LifecycleApi {
347
+ /**
348
+ * Registers a callback for when the game transitions from "idle" to "active" state.
349
+ *
350
+ * This occurs when the game comes to the foreground. Use this to load heavy resources
351
+ * or resume activities that were paused during sleep.
352
+ *
353
+ * @param callback - Function to execute when the game awakens
354
+ * @returns Subscription object that can be used to unsubscribe from the event
355
+ */
356
+ onAwake(callback: AwakeCallback): Subscription;
357
+ /**
358
+ * Registers a callback for when the game transitions from "active" to "idle" state.
359
+ *
360
+ * This occurs when the game goes to the background. Use this to unload heavy resources,
361
+ * save state, or pause non-essential activities.
362
+ *
363
+ * @param callback - Function to execute when the game goes to sleep
364
+ * @returns Subscription object that can be used to unsubscribe from the event
365
+ */
366
+ onSleep(callback: SleepCallback): Subscription;
367
+ /**
368
+ * Registers a callback for when gameplay should resume.
369
+ *
370
+ * This occurs when the platform dismisses dialogs or overlays, or when players
371
+ * return from a temporary switch. Use this to resume game logic and animations.
372
+ *
373
+ * @param callback - Function to execute when gameplay resumes
374
+ * @returns Subscription object that can be used to unsubscribe from the event
375
+ */
376
+ onResume(callback: ResumeCallback): Subscription;
377
+ /**
378
+ * Registers a callback for when gameplay should pause.
379
+ *
380
+ * This occurs when the platform brings up dialogs or overlays, or when players
381
+ * temporarily switch away. Use this to pause game logic and animations.
382
+ *
383
+ * @param callback - Function to execute when gameplay pauses
384
+ * @returns Subscription object that can be used to unsubscribe from the event
385
+ */
386
+ onPause(callback: PauseCallback): Subscription;
387
+ /**
388
+ * Registers a callback for final teardown before the game instance is destroyed.
389
+ *
390
+ * This is the last chance to clean up resources, save state, and perform any
391
+ * necessary cleanup before the game instance is destroyed or replaced.
392
+ *
393
+ * @param callback - Function to execute during cleanup
394
+ * @returns Subscription object that can be used to unsubscribe from the event
395
+ */
396
+ onQuit(callback: QuitCallback): Subscription;
397
+ }
398
+
399
+ interface ExecuteRecipeOptions {
400
+ roomId?: string;
401
+ batchAmount?: number;
402
+ allowPartialBatch?: boolean;
403
+ entity?: string;
404
+ }
405
+ interface GetActiveRunsOptions {
406
+ roomId?: string;
407
+ }
408
+ interface ExecuteScopedRecipeOptions {
409
+ roomId?: string;
410
+ }
411
+ interface GetAvailableRecipesOptions {
412
+ roomId?: string;
413
+ includeActorRecipes?: boolean;
414
+ }
415
+ interface Recipe {
416
+ recipeId: string;
417
+ entity?: string;
418
+ batchAmount?: number;
419
+ }
420
+ interface TriggerRecipeChainOptions {
421
+ roomId?: string;
422
+ context?: Record<string, unknown>;
423
+ }
424
+ interface CollectRecipeResult {
425
+ success: boolean;
426
+ runId: string;
427
+ rewards: Record<string, unknown>;
428
+ message: string;
429
+ }
430
+ interface ExecuteScopedRecipeResult {
431
+ success: boolean;
432
+ message: string;
433
+ }
434
+ interface RecipeInfo {
435
+ id: string;
436
+ scope: string;
437
+ clientViewable: boolean;
438
+ }
439
+ interface GetAvailableRecipesResult {
440
+ success: boolean;
441
+ recipes: RecipeInfo[];
442
+ }
443
+ interface GetBatchRecipeRequirements {
444
+ success: boolean;
445
+ results: RecipeRequirementResult[];
446
+ }
447
+ interface SimulationPersonalState {
448
+ entities: Record<string, number | string>;
449
+ activeRuns: SimulationRunSummary[];
450
+ disabledRecipes: string[];
451
+ }
452
+ interface SimulationRoomActiveRecipe {
453
+ recipeId: string;
454
+ scope: 'room' | 'actor';
455
+ startedAt: number;
456
+ expiresAt: number;
457
+ commitmentEndsAt?: number;
458
+ }
459
+ interface SimulationRoomState {
460
+ activeRecipes: Record<string, SimulationRoomActiveRecipe>;
461
+ sharedAssets: Record<string, number | string>;
462
+ actors: Array<Record<string, unknown>>;
463
+ activeRuns: SimulationRunSummary[];
464
+ }
465
+ type SimulationState = SimulationPersonalState | SimulationRoomState;
466
+ interface SimulationSlotContainer {
467
+ entityId: string;
468
+ slots: Record<string, unknown>;
469
+ isOwned: boolean;
470
+ powerCalculationRecipe?: string;
471
+ }
472
+ interface SimulationAvailableItem {
473
+ entityId: string;
474
+ quantity: number;
475
+ metadata: Record<string, unknown>;
476
+ tags: string[];
477
+ isCompatible: boolean;
478
+ }
479
+ interface SimulationSlotValidationResult {
480
+ valid: boolean;
481
+ error?: string;
482
+ }
483
+ interface SimulationAssignment {
484
+ id: string;
485
+ containerId: string;
486
+ slotId: string;
487
+ itemId: string | null;
488
+ profileId: string;
489
+ appId: string;
490
+ createdAt: number;
491
+ metadata?: Record<string, unknown>;
492
+ }
493
+ interface SimulationSlotMutationResult {
494
+ success: boolean;
495
+ error?: string;
496
+ association?: SimulationAssignment;
497
+ }
498
+ interface SimulationBatchOperationAssign {
499
+ type: 'assign';
500
+ containerId: string;
501
+ slotId: string;
502
+ itemId: string;
503
+ }
504
+ interface SimulationBatchOperationRemove {
505
+ type: 'remove';
506
+ containerId: string;
507
+ slotId: string;
508
+ itemId?: string;
509
+ }
510
+ type SimulationBatchOperation = SimulationBatchOperationAssign | SimulationBatchOperationRemove;
511
+ interface SimulationBatchOperationResult {
512
+ success: boolean;
513
+ error?: string;
514
+ association?: SimulationAssignment;
515
+ operation: SimulationBatchOperation;
516
+ }
517
+ interface SimulationBatchOperationsResult {
518
+ success: boolean;
519
+ results: SimulationBatchOperationResult[];
520
+ affectedContainers: string[];
521
+ }
522
+ interface SimulationPowerPreview {
523
+ currentPower: number;
524
+ previewPower: number;
525
+ powerDelta: number;
526
+ breakdown: Record<string, number>;
527
+ }
528
+ interface ResetStateOptions {
529
+ /** Optional recipe to run after reset (overrides lifecycle.onReset) */
530
+ initializeRecipe?: string;
531
+ }
532
+ interface ResetStateResult {
533
+ success: boolean;
534
+ /** Number of active runs that were cancelled */
535
+ clearedRuns: number;
536
+ /** Number of slot assignments that were deleted */
537
+ clearedSlots: number;
538
+ /** Recipe that was executed after reset (if any) */
539
+ recipeExecuted: string | null;
540
+ }
541
+ interface ExecuteRecipeResponse {
542
+ success: boolean;
543
+ status?: string;
544
+ runId?: string;
545
+ expiresAt?: string;
546
+ queuePosition?: number;
547
+ outputs?: Record<string, number | string>;
548
+ data?: Record<string, unknown>;
549
+ message?: string;
550
+ amountRequested?: number;
551
+ amountFulfilled?: number;
552
+ partialSuccess?: boolean;
553
+ }
554
+ interface SimulationApi {
555
+ isEnabled(): boolean;
556
+ getStateAsync(roomId?: string): Promise<SimulationState>;
557
+ getConfigAsync(roomId?: string): Promise<RundotGameSimulationConfig>;
558
+ executeRecipeAsync(recipeId: string, inputs?: Record<string, unknown>, options?: ExecuteRecipeOptions): Promise<ExecuteRecipeResponse>;
559
+ getActiveRunsAsync(options?: GetActiveRunsOptions): Promise<SimulationRunSummary[]>;
560
+ collectRecipeAsync(runId: string): Promise<CollectRecipeResult>;
561
+ executeScopedRecipeAsync(recipeId: string, entity: string, inputs?: Record<string, unknown>, options?: ExecuteScopedRecipeOptions): Promise<ExecuteScopedRecipeResult>;
562
+ triggerRecipeChainAsync(recipeId: string, options?: TriggerRecipeChainOptions): Promise<ExecuteRecipeResponse>;
563
+ getAvailableRecipesAsync(options?: GetAvailableRecipesOptions): Promise<GetAvailableRecipesResult>;
564
+ getRecipeRequirementsAsync(recipe: Recipe): Promise<RecipeRequirementResult>;
565
+ getBatchRecipeRequirementsAsync(recipes: Recipe[]): Promise<GetBatchRecipeRequirements>;
566
+ resolveFieldValueAsync(entityId: string, fieldPath: string, entity?: string): Promise<unknown>;
567
+ getEntityMetadataAsync(entityId: string): Promise<Record<string, unknown>>;
568
+ getSlotContainersAsync(): Promise<SimulationSlotContainer[]>;
569
+ getSlotAssignmentsAsync(containerId: string): Promise<SimulationAssignment[]>;
570
+ assignItemToSlotAsync(containerId: string, slotId: string, itemId: string): Promise<SimulationSlotMutationResult>;
571
+ removeItemFromSlotAsync(containerId: string, slotId: string): Promise<SimulationSlotMutationResult>;
572
+ getAvailableItemsAsync(containerId: string, slotId: string): Promise<SimulationAvailableItem[]>;
573
+ calculatePowerPreviewAsync(containerId: string, slotId: string, candidateItemId: string): Promise<SimulationPowerPreview>;
574
+ validateSlotAssignmentAsync(containerId: string, slotId: string, itemId: string): Promise<SimulationSlotValidationResult>;
575
+ executeBatchOperationsAsync(operations: Array<SimulationBatchOperation>, validateOnly?: boolean): Promise<SimulationBatchOperationsResult>;
576
+ subscribeAsync(options: SimulationSubscribeOptions): Promise<() => void>;
577
+ /**
578
+ * Reset all simulation state for the current player.
579
+ * Clears inventory, cancels active runs, and removes slot assignments.
580
+ * Optionally runs an initialization recipe after reset.
581
+ */
582
+ resetStateAsync(options?: ResetStateOptions): Promise<ResetStateResult>;
583
+ }
584
+
585
+ declare const ROOM_GAME_PHASES: readonly ["waiting", "playing", "ended"];
586
+ type RoomGamePhase = (typeof ROOM_GAME_PHASES)[number];
587
+ interface RundotGameRoomRulesGameState extends Record<string, unknown> {
588
+ phase?: RoomGamePhase;
589
+ currentPlayer?: string | null;
590
+ turnOrder?: string[];
591
+ turnCount?: number;
592
+ turnBased?: boolean;
593
+ playerStates?: Record<string, unknown>;
594
+ startParams?: {
595
+ gameConfig: Record<string, unknown>;
596
+ turnOrder?: string[] | null;
597
+ startedBy: string;
598
+ startedAt: unknown;
599
+ };
600
+ }
601
+ interface RundotGameRoomRules extends Record<string, unknown> {
602
+ hostProfileId?: string;
603
+ minPlayers?: number;
604
+ maxPlayers?: number;
605
+ turnBased?: boolean;
606
+ gameState?: RundotGameRoomRulesGameState;
607
+ }
608
+ interface RundotGameRoomCustomMetadata extends Record<string, unknown> {
609
+ rules?: RundotGameRoomRules;
610
+ }
611
+ interface RundotGameRoomPayload extends Record<string, unknown> {
612
+ id: string;
613
+ name?: string;
614
+ currentPlayers?: string[];
615
+ maxPlayers?: number;
616
+ gameType?: string;
617
+ appId?: string;
618
+ type?: string;
619
+ createdBy?: string;
620
+ createdAt?: number;
621
+ updatedAt?: number;
622
+ isPrivate?: boolean;
623
+ status?: string;
624
+ customMetadata?: RundotGameRoomCustomMetadata;
625
+ admins?: string[];
626
+ roomCode?: string;
627
+ description?: string;
628
+ data?: Record<string, unknown>;
629
+ version?: number;
630
+ }
631
+ /**
632
+ * Server API response envelopes.
633
+ * These match the format returned by the H5 Rooms Cloud Functions.
634
+ */
635
+ /**
636
+ * Standard envelope for endpoints that return a single room.
637
+ */
638
+ interface RoomEnvelopeResponse {
639
+ success: boolean;
640
+ room: RundotGameRoomPayload;
641
+ }
642
+ /**
643
+ * Standard envelope for endpoints that return multiple rooms.
644
+ */
645
+ interface RoomsEnvelopeResponse {
646
+ success: boolean;
647
+ rooms: RundotGameRoomPayload[];
648
+ }
649
+ /**
650
+ * Standard envelope for join-or-create room endpoint.
651
+ */
652
+ interface JoinOrCreateRoomEnvelopeResponse {
653
+ success: boolean;
654
+ action: 'created' | 'joined';
655
+ room: RundotGameRoomPayload;
656
+ playersJoined: number;
657
+ }
658
+ declare class RundotGameRoom {
659
+ readonly id: string;
660
+ name?: string;
661
+ players: string[];
662
+ maxPlayers?: number;
663
+ gameType?: string;
664
+ appId?: string;
665
+ type?: string;
666
+ createdBy?: string;
667
+ createdAt?: number;
668
+ updatedAt?: number;
669
+ isPrivate?: boolean;
670
+ status?: string;
671
+ customMetadata: RundotGameRoomCustomMetadata;
672
+ admins: string[];
673
+ roomCode?: string;
674
+ description?: string;
675
+ data: Record<string, unknown>;
676
+ version?: number;
677
+ constructor(roomData: RundotGameRoomPayload);
678
+ }
679
+
680
+ interface CreateRoomOptions {
681
+ maxPlayers?: number;
682
+ gameType?: string;
683
+ isPrivate?: boolean;
684
+ roomCode?: string;
685
+ name?: string;
686
+ description?: string;
687
+ customMetadata?: Record<string, unknown>;
688
+ data?: Record<string, unknown>;
689
+ }
690
+ interface JoinRoomMatchCriteria {
691
+ isPrivate?: boolean;
692
+ hasSpace?: boolean;
693
+ gameType?: string;
694
+ [key: string]: unknown;
695
+ }
696
+ interface JoinOrCreateRoomOptions {
697
+ matchCriteria?: JoinRoomMatchCriteria;
698
+ createOptions: CreateRoomOptions;
699
+ }
700
+ interface JoinOrCreateResult {
701
+ action: 'created' | 'joined';
702
+ room: RundotGameRoom;
703
+ playersJoined: number;
704
+ }
705
+ interface ListRoomsOptions {
706
+ includeArchived?: boolean;
707
+ }
708
+ interface RoomDataUpdate {
709
+ type: 'H5_ROOM_DATA_UPDATED';
710
+ roomId: string;
711
+ roomData: RundotGameRoomPayload;
712
+ timestamp?: number;
713
+ }
714
+ type RoomMessageEventType = 'H5_ROOM_MESSAGE_RECEIVED' | 'H5_ROOM_MESSAGE_UPDATED' | 'H5_ROOM_MESSAGE_DELETED';
715
+ interface RoomMessagePayload extends Record<string, unknown> {
716
+ id?: string;
717
+ roomId?: string;
718
+ senderId?: string;
719
+ type?: string;
720
+ content?: unknown;
721
+ metadata?: Record<string, unknown>;
722
+ timestamp?: unknown;
723
+ }
724
+ interface RoomMessageEvent {
725
+ type: RoomMessageEventType;
726
+ roomId: string;
727
+ message: RoomMessagePayload;
728
+ timestamp?: number;
729
+ }
730
+ interface ProposedMovePayload extends Record<string, unknown> {
731
+ id?: string;
732
+ proposerProfileId?: string;
733
+ timestamp?: unknown;
734
+ gameSpecificState?: Record<string, unknown>;
735
+ clientContext?: Record<string, unknown>;
736
+ moveType?: string;
737
+ clientProposalId?: string;
738
+ serverGenericValidationStatus?: string;
739
+ serverGenericValidationReason?: string;
740
+ serverCustomValidationStatus?: string;
741
+ serverCustomValidationReason?: string;
742
+ clientConsensusStatus?: string;
743
+ clientConsensusDetails?: unknown;
744
+ updatedAt?: unknown;
745
+ }
746
+ interface ProposedMoveEvent {
747
+ type: 'app:h5:proposedMoveValidationUpdated';
748
+ roomId: string;
749
+ proposedMoveData: ProposedMovePayload;
750
+ proposedMoveId?: string;
751
+ changeType?: string;
752
+ timestamp?: number;
753
+ }
754
+ interface RoomSubscriptionOptions {
755
+ onData?: (event: RoomDataUpdate) => void;
756
+ onMessages?: (event: RoomMessageEvent) => void;
757
+ onGameEvents?: (event: ProposedMoveEvent) => void;
758
+ }
759
+ interface ProposeMoveRequest {
760
+ gameSpecificState: Record<string, unknown>;
761
+ moveType: string;
762
+ clientContext?: Record<string, unknown>;
763
+ clientProposalId?: string;
764
+ }
765
+ interface ProposeMoveResult {
766
+ proposedMoveId: string;
767
+ }
768
+ interface ValidateMoveVerdict {
769
+ isValid: boolean;
770
+ reason?: string | null;
771
+ validatorId?: string | null;
772
+ }
773
+ interface ValidateMoveResult {
774
+ success: boolean;
775
+ moveId: string;
776
+ isValid: boolean;
777
+ reason?: string | null;
778
+ }
779
+ interface UpdateRoomDataOptions {
780
+ merge?: boolean;
781
+ }
782
+ interface RoomMessageRequest {
783
+ message: Record<string, unknown>;
784
+ metadata?: Record<string, unknown>;
785
+ }
786
+ interface StartRoomGameOptions {
787
+ gameConfig?: Record<string, unknown>;
788
+ turnOrder?: string[] | null;
789
+ }
790
+ interface RoomsApi {
791
+ createRoomAsync(options: CreateRoomOptions): Promise<RundotGameRoom>;
792
+ joinOrCreateRoomAsync(options: JoinOrCreateRoomOptions): Promise<JoinOrCreateResult>;
793
+ joinRoomByCodeAsync(roomCode: string): Promise<RundotGameRoom>;
794
+ getUserRoomsAsync(options?: ListRoomsOptions): Promise<RundotGameRoom[]>;
795
+ subscribeAsync(room: RundotGameRoom, options?: RoomSubscriptionOptions): Promise<() => void>;
796
+ /**
797
+ * @deprecated Prefer server-authoritative flows (e.g. `proposeMoveAsync` / `startRoomGameAsync`)
798
+ * and treat `customMetadata.rules.gameState` as the canonical room lifecycle state.
799
+ */
800
+ updateRoomDataAsync(room: RundotGameRoom, updates: Record<string, unknown>, options?: UpdateRoomDataOptions): Promise<void>;
801
+ getRoomDataAsync(room: RundotGameRoom): Promise<Record<string, unknown>>;
802
+ sendRoomMessageAsync(room: RundotGameRoom, message: RoomMessageRequest): Promise<string>;
803
+ leaveRoomAsync(room: RundotGameRoom): Promise<void>;
804
+ kickPlayerAsync(room: RundotGameRoom, targetProfileId: string, options?: {
805
+ reason?: string;
806
+ }): Promise<void>;
807
+ startRoomGameAsync(room: RundotGameRoom, options?: StartRoomGameOptions): Promise<void>;
808
+ proposeMoveAsync(room: RundotGameRoom, request: ProposeMoveRequest): Promise<ProposeMoveResult>;
809
+ validateMoveAsync(room: RundotGameRoom, moveId: string, verdict: ValidateMoveVerdict): Promise<ValidateMoveResult>;
810
+ }
811
+
812
+ interface RundotGameMessage {
813
+ type: string;
814
+ direction: string;
815
+ data?: {
816
+ requestId?: string;
817
+ success?: boolean;
818
+ value?: any;
819
+ data?: any;
820
+ error?: string;
821
+ script?: string;
822
+ };
823
+ instanceId: string;
824
+ timestamp: number;
825
+ }
826
+ declare global {
827
+ interface Window {
828
+ _rundotGameInitState?: {
829
+ poolId: string;
830
+ apiInjected: boolean;
831
+ gameInitialized: boolean;
832
+ };
833
+ ReactNativeWebView?: {
834
+ postMessage(message: string): void;
835
+ };
836
+ rundotGame: {
837
+ _config: {
838
+ locale: string;
839
+ instanceId: string;
840
+ context?: any;
841
+ profile?: {
842
+ id?: string;
843
+ username?: string;
844
+ name?: string;
845
+ displayName?: string;
846
+ avatarUrl?: string | null;
847
+ isAnonymous?: boolean;
848
+ };
849
+ environment: {
850
+ browserInfo?: {
851
+ language: string;
852
+ };
853
+ };
854
+ _handlers: Record<string, any>;
855
+ };
856
+ profile?: {
857
+ id?: string;
858
+ username?: string;
859
+ avatarUrl?: string | null;
860
+ name?: string;
861
+ displayName?: string;
862
+ isAnonymous?: boolean;
863
+ } | null;
864
+ _fetchFromCdn: (url: string) => Promise<string>;
865
+ };
866
+ }
867
+ }
868
+ type OnRundotGameMessageCallback = (message: RundotGameMessage) => void;
869
+ declare class RundotGameTransport implements RpcTransport {
870
+ private readonly messageHandler;
871
+ private readonly onNotificationCallbacks;
872
+ private readonly onNotificationCallbacksToRemove;
873
+ private readonly onRundotGameMessageCallbacks;
874
+ private readonly onResponseCallbacks;
875
+ private readonly onResponseCallbacksToRemove;
876
+ private _instanceId;
877
+ private isStarted;
878
+ private isProcessingMessage;
879
+ constructor();
880
+ onNotification(callback: OnNotificationCallback): Subscription;
881
+ onRequest(callback: OnRequestCallback): Subscription;
882
+ onResponse(callback: OnResponseCallback): Subscription;
883
+ get instanceId(): string | null;
884
+ set instanceId(instanceId: string);
885
+ sendRequest(request: RpcRequest): void;
886
+ sendRundotGameMessage(message: RundotGameMessage): void;
887
+ sendResponse(response: RpcResponse): void;
888
+ start(): void;
889
+ stop(): void;
890
+ private handleNotification;
891
+ private handleResponse;
892
+ private removeOnResponseCallback;
893
+ private removeOnNotificationCallback;
894
+ private logInfo;
895
+ private logWarn;
896
+ onRundotGameMessage(callback: OnRundotGameMessageCallback): Subscription;
897
+ private notifyRundotGameMessageReceived;
898
+ }
899
+
900
+ interface LoggingApi {
901
+ logDebug(message: string, ...args: any[]): void;
902
+ logError(message: string, ...args: any[]): void;
903
+ }
904
+
905
+ interface SharedAssetsApi {
906
+ loadAssetsBundle(game: string, bundleKey: string): Promise<ArrayBuffer>;
907
+ }
908
+
909
+ declare class RpcSharedAssetsApi implements SharedAssetsApi {
910
+ private readonly rundotGameApi;
911
+ private readonly rpcClient;
912
+ constructor(rpcClient: RpcClient, rundotGameApi: RundotGameAPI);
913
+ loadAssetsBundle(game: string, bundleKey: string, fileType?: string): Promise<ArrayBuffer>;
914
+ }
915
+ interface LoadEmbeddedAssetsRequest {
916
+ assetKey: string;
917
+ }
918
+ interface LoadEmbeddedAssetsResponse {
919
+ base64Data: string;
920
+ }
921
+
922
+ interface SpendCurrencyOptions {
923
+ screenName?: string;
924
+ }
925
+ interface IapApi {
926
+ getHardCurrencyBalance(): Promise<number>;
927
+ spendCurrency(productId: string, amount: number, options?: SpendCurrencyOptions): Promise<void>;
928
+ openStore(): Promise<void>;
929
+ getCurrencyIcon(): Promise<LoadEmbeddedAssetsResponse>;
930
+ }
931
+
932
+ interface LeaderboardModeConfig {
933
+ displayName: string;
934
+ minDurationSec?: number;
935
+ maxDurationSec?: number;
936
+ minScore?: number;
937
+ maxScore?: number;
938
+ }
939
+ type LeaderboardPeriodType = 'daily' | 'weekly' | 'monthly' | 'alltime';
940
+ interface LeaderboardPeriodConfig {
941
+ displayName: string;
942
+ type: LeaderboardPeriodType;
943
+ }
944
+ interface LeaderboardAntiCheatConfig {
945
+ enableZScoreDetection: boolean;
946
+ zScoreThreshold: number;
947
+ enableRateLimit: boolean;
948
+ minTimeBetweenSubmissionsSec: number;
949
+ trustScoreDecayPerFlag: number;
950
+ shadowBanThreshold: number;
951
+ }
952
+ interface LeaderboardDisplaySettings {
953
+ maxEntriesPerPage: number;
954
+ }
955
+ interface LeaderboardConfig {
956
+ minDurationSec: number;
957
+ maxDurationSec: number;
958
+ minScore: number;
959
+ maxScore: number;
960
+ requiresToken: boolean;
961
+ enableScoreSealing: boolean;
962
+ scoreSealingSecret?: string;
963
+ modes: Record<string, LeaderboardModeConfig>;
964
+ periods: Record<string, LeaderboardPeriodConfig>;
965
+ antiCheat: LeaderboardAntiCheatConfig;
966
+ displaySettings: LeaderboardDisplaySettings;
967
+ }
968
+ interface ScoreToken {
969
+ token: string;
970
+ startTime: number;
971
+ expiresAt: number;
972
+ sealingNonce?: string | null;
973
+ sealingSecret?: string | null;
974
+ mode: string;
975
+ }
976
+ interface SubmitScoreParams {
977
+ token?: string;
978
+ score: number;
979
+ duration: number;
980
+ mode?: string;
981
+ telemetry?: Record<string, any>;
982
+ metadata?: Record<string, any>;
983
+ }
984
+ interface SubmitScoreResult {
985
+ accepted: boolean;
986
+ rank?: number | null;
987
+ zScore?: number | null;
988
+ isAnomaly?: boolean;
989
+ }
990
+ interface GetPagedScoresOptions {
991
+ mode?: string;
992
+ period?: string;
993
+ periodDate?: number | string;
994
+ cursor?: string | null;
995
+ limit?: number;
996
+ variant?: 'standard' | 'highlight';
997
+ topCount?: number;
998
+ contextAhead?: number;
999
+ contextBehind?: number;
1000
+ }
1001
+ interface LeaderboardEntry {
1002
+ profileId: string;
1003
+ username: string;
1004
+ avatarUrl: string | null;
1005
+ score: number;
1006
+ duration: number;
1007
+ submittedAt: number;
1008
+ token?: string;
1009
+ rank: number | null;
1010
+ zScore?: number | null;
1011
+ isAnomaly?: boolean;
1012
+ trustScore?: number | null;
1013
+ isShadowBanned?: boolean;
1014
+ expiresAt?: number | null;
1015
+ metadata?: Record<string, any> | null;
1016
+ isSeed?: boolean;
1017
+ }
1018
+ interface PagedScoresResponse {
1019
+ variant: 'standard' | 'highlight';
1020
+ entries: LeaderboardEntry[];
1021
+ totalEntries: number;
1022
+ nextCursor?: string | null;
1023
+ playerRank: number | null;
1024
+ periodInstance: string;
1025
+ }
1026
+ interface PlayerRankOptions {
1027
+ mode?: string;
1028
+ period?: string;
1029
+ periodDate?: number | string;
1030
+ }
1031
+ interface PlayerRankResult {
1032
+ rank: number | null;
1033
+ score?: number;
1034
+ totalPlayers: number;
1035
+ percentile?: number;
1036
+ trustScore: number;
1037
+ periodInstance: string;
1038
+ }
1039
+ interface PodiumScoresContext {
1040
+ topEntries: LeaderboardEntry[];
1041
+ beforePlayer: LeaderboardEntry[];
1042
+ playerEntry?: LeaderboardEntry | null;
1043
+ afterPlayer: LeaderboardEntry[];
1044
+ totalBefore: number;
1045
+ totalAfter: number;
1046
+ omittedBefore: number;
1047
+ omittedAfter: number;
1048
+ }
1049
+ interface PodiumScoresResponse extends PagedScoresResponse {
1050
+ variant: 'highlight';
1051
+ context: PodiumScoresContext;
1052
+ }
1053
+ interface GetPodiumScoresOptions extends Omit<GetPagedScoresOptions, 'variant'> {
1054
+ }
1055
+ interface LeaderboardApi {
1056
+ createScoreToken(mode?: string): Promise<ScoreToken>;
1057
+ submitScore(params: SubmitScoreParams): Promise<SubmitScoreResult>;
1058
+ getPagedScores(options?: GetPagedScoresOptions): Promise<PagedScoresResponse>;
1059
+ getMyRank(options?: PlayerRankOptions): Promise<PlayerRankResult>;
1060
+ getPodiumScores(options?: GetPodiumScoresOptions): Promise<PodiumScoresResponse>;
1061
+ }
1062
+
1063
+ interface PreloaderApi {
1064
+ showLoadScreen(): Promise<void>;
1065
+ hideLoadScreen(): Promise<void>;
1066
+ setLoaderText(text: string): Promise<void>;
1067
+ setLoaderProgress(progress: number): Promise<void>;
1068
+ }
1069
+
1070
+ /**
1071
+ * OpenGraph metadata for rich social previews.
1072
+ *
1073
+ * H5 games provide these values so social networks can render rich cards when
1074
+ * a share link is posted.
1075
+ */
1076
+ interface ShareMetadata {
1077
+ /** Preview title shown in link cards (e.g. Twitter, iMessage). */
1078
+ title?: string;
1079
+ /** Preview description shown under the title. */
1080
+ description?: string;
1081
+ /** Preview image URL (must be HTTPS for most social platforms). */
1082
+ imageUrl?: string;
1083
+ }
1084
+ interface SocialQRCodeOptions {
1085
+ /** Size of the QR code image in pixels. */
1086
+ size?: number;
1087
+ /** Margin around the QR code in pixels. */
1088
+ margin?: number;
1089
+ /** Output format for the rendered QR code. */
1090
+ format?: 'png' | 'svg';
1091
+ }
1092
+ interface ShareLinkResult {
1093
+ shareUrl: string;
1094
+ }
1095
+ interface QRCodeResult {
1096
+ shareUrl: string;
1097
+ qrCode: string;
1098
+ }
1099
+ /**
1100
+ * Social distribution API used by H5 games.
1101
+ *
1102
+ * This unified API powers both share links and QR codes, backed by a single
1103
+ * Firestore document that stores arbitrary launch parameters supplied by the
1104
+ * game.
1105
+ */
1106
+ interface SocialApi {
1107
+ /**
1108
+ * Create a share link and invoke the host platform's native share UX.
1109
+ *
1110
+ * Platform behaviour:
1111
+ * - iOS / Android: opens the native share sheet.
1112
+ * - Web: copies the generated URL to the clipboard (with fallback toast).
1113
+ *
1114
+ * @param options.shareParams Arbitrary share parameters for your game.
1115
+ * @param options.metadata Optional OpenGraph metadata for rich previews.
1116
+ * @returns The generated share URL.
1117
+ */
1118
+ shareLinkAsync(options: {
1119
+ shareParams: Record<string, string>;
1120
+ metadata?: ShareMetadata;
1121
+ }): Promise<ShareLinkResult>;
1122
+ /**
1123
+ * Create a share document and return both the URL and a QR code image.
1124
+ *
1125
+ * Games can render or print the returned QR image or re-use the share URL.
1126
+ *
1127
+ * @param options.shareParams Arbitrary share parameters for your game.
1128
+ * @param options.metadata Optional OpenGraph metadata for the share.
1129
+ * @param options.qrOptions Customisation for the generated QR code.
1130
+ * @returns The generated share URL and QR code (as a data URL).
1131
+ */
1132
+ createQRCodeAsync(options: {
1133
+ shareParams: Record<string, string>;
1134
+ metadata?: ShareMetadata;
1135
+ qrOptions?: SocialQRCodeOptions;
1136
+ }): Promise<QRCodeResult>;
1137
+ }
1138
+
1139
+ /**
1140
+ * Safe area insets representing padding needed to avoid device notches and host UI.
1141
+ * Includes toolbar/feedHeader height + device safe areas.
1142
+ */
1143
+ interface SafeArea {
1144
+ left: number;
1145
+ top: number;
1146
+ right: number;
1147
+ bottom: number;
1148
+ }
1149
+ /**
1150
+ * @deprecated Use SafeArea instead. Will be removed in v4.0.0
1151
+ */
1152
+ type HudInsets = SafeArea;
1153
+ interface InitializationOptions {
1154
+ helpText?: string;
1155
+ hardDisableMock?: boolean;
1156
+ mock?: Record<string, any>;
1157
+ usePreloader?: boolean;
1158
+ launchParams?: Record<string, string>;
1159
+ shareParams?: Record<string, string>;
1160
+ }
1161
+ interface InitializationContext {
1162
+ /**
1163
+ * Safe area insets from INIT_SDK response.
1164
+ * @deprecated Use RundotGameAPI.system.getSafeArea() instead. Will be removed in v4.0.0
1165
+ */
1166
+ safeArea?: SafeArea;
1167
+ initializeAsleep: boolean;
1168
+ launchParams?: Record<string, string>;
1169
+ shareParams?: Record<string, string>;
1170
+ }
1171
+ interface Host {
1172
+ readonly ads: AdsApi;
1173
+ readonly analytics: AnalyticsApi;
1174
+ readonly deviceCache: StorageApi;
1175
+ readonly appStorage: StorageApi;
1176
+ readonly globalStorage: StorageApi;
1177
+ readonly avatar3d: Avatar3dApi;
1178
+ readonly navigation: NavigationApi;
1179
+ readonly notifications: NotificationsApi;
1180
+ readonly popups: PopupsApi;
1181
+ readonly profile: ProfileApi;
1182
+ readonly system: SystemApi;
1183
+ readonly cdn: CdnApi;
1184
+ readonly time: TimeApi;
1185
+ readonly ai: AiApi;
1186
+ readonly haptics: HapticsApi;
1187
+ readonly features: FeaturesApi;
1188
+ readonly lifecycle: LifecycleApi;
1189
+ readonly simulation: SimulationApi;
1190
+ readonly rooms: RoomsApi;
1191
+ readonly logging: LoggingApi;
1192
+ readonly leaderboard: LeaderboardApi;
1193
+ readonly preloader: PreloaderApi;
1194
+ readonly social: SocialApi;
1195
+ readonly isInitialized: boolean;
1196
+ readonly iap: IapApi;
1197
+ readonly context?: InitializationContext;
1198
+ initialize(options?: InitializationOptions): Promise<InitializationContext>;
1199
+ }
1200
+ /**
1201
+ * Create a Host instance based on the runtime environment.
1202
+ *
1203
+ * ## Why SandboxHost uses dynamic import
1204
+ *
1205
+ * SandboxHost depends on Firebase (~200KB+ gzipped) for authentication and
1206
+ * Firestore. This is ONLY needed during local development when using the
1207
+ * RUN.game sandbox mode (connecting to real Firebase backend via Vite dev server).
1208
+ *
1209
+ * In production builds (H5 games deployed to RUN.game app):
1210
+ * - `window.__RUNDOT_GAME_SANDBOX__` is never set (Vite plugin only runs in dev)
1211
+ * - `isSandboxEnabled()` returns false
1212
+ * - SandboxHost is never instantiated
1213
+ *
1214
+ * Using a static import like `import { SandboxHost } from './SandboxHost.ts'`
1215
+ * would cause Rollup/Vite to bundle SandboxHost AND all its dependencies
1216
+ * (including Firebase) into the production bundle, even though they're unused.
1217
+ *
1218
+ * Dynamic import (`await import('./SandboxHost.ts')`) tells the bundler to
1219
+ * code-split SandboxHost into a separate chunk that's only loaded at runtime
1220
+ * when the condition is true. In production, this chunk is never loaded.
1221
+ *
1222
+ * This keeps production bundles small (~200KB+ smaller) and faster to load.
1223
+ */
1224
+ declare function createHost(rundotGameApi: RundotGameAPI, isMock: boolean): Promise<Host>;
1225
+
1226
+ interface Avatar3dConfig {
1227
+ headAsset: string | null;
1228
+ outfitAsset: string | null;
1229
+ hatAsset: string | null;
1230
+ hairAsset: string | null;
1231
+ faceAccessoryAsset: string | null;
1232
+ animationAsset: string | null;
1233
+ skinColor: string | null;
1234
+ }
1235
+
1236
+ interface Asset {
1237
+ id: string;
1238
+ filename: string;
1239
+ displayName: string;
1240
+ preload?: boolean;
1241
+ tags?: string[];
1242
+ metadata?: Record<string, any>;
1243
+ }
1244
+ interface Category {
1245
+ displayName?: string;
1246
+ type: 'mesh';
1247
+ assets: Asset[];
1248
+ }
1249
+ interface AssetManifest {
1250
+ version: string;
1251
+ generatedAt: string;
1252
+ categories: Record<string, Category>;
1253
+ }
1254
+
1255
+ interface Avatar3dEdits {
1256
+ wasChanged: boolean;
1257
+ config: Avatar3dConfig | null;
1258
+ savedAvatarId: string | null;
1259
+ }
1260
+ interface ShowEditorOptions {
1261
+ currentAvatar?: any;
1262
+ contextData?: any;
1263
+ onSave?: () => void;
1264
+ onCancel?: () => void;
1265
+ }
1266
+ interface Avatar3dApi {
1267
+ loadAvatar(avatarId?: string): Promise<Avatar3dConfig | null>;
1268
+ saveAvatar(config: Avatar3dConfig): Promise<string>;
1269
+ deleteAvatar(): Promise<void>;
1270
+ downloadManifest(): Promise<AssetManifest>;
1271
+ showEditor(options?: ShowEditorOptions): Promise<Avatar3dEdits>;
1272
+ downloadAssetPaths(): Promise<Record<string, string[]>>;
1273
+ }
1274
+
1275
+ declare global {
1276
+ interface Window {
1277
+ RundotGamePrototyping?: {
1278
+ showAvatarEditorOverlay: (options: any, resolve: (args: any) => void) => Promise<void>;
1279
+ };
1280
+ }
1281
+ }
1282
+ declare class MockAvatarApi implements Avatar3dApi {
1283
+ private readonly _rundotGameApi;
1284
+ private cachedAssets;
1285
+ private cachedVersion;
1286
+ constructor(rundotGameApi: RundotGameAPI);
1287
+ downloadAssetPaths(): Promise<Record<string, string[]>>;
1288
+ deleteAvatar(): Promise<void>;
1289
+ loadAvatar(avatar3dId?: string): Promise<Avatar3dConfig | null>;
1290
+ saveAvatar(config: Avatar3dConfig): Promise<string>;
1291
+ downloadManifest(): Promise<AssetManifest>;
1292
+ showEditor(options?: ShowEditorOptions): Promise<Avatar3dEdits>;
1293
+ private getAssets;
1294
+ private loadAssetsManifest;
1295
+ private selectAvatarConfig;
1296
+ private selectAsset;
1297
+ private seededRandom;
1298
+ private simpleHash;
1299
+ private getAllAssetPaths;
1300
+ private log;
1301
+ }
1302
+
1303
+ /**
1304
+ * DEFINITIVE TypeScript definitions for Rundot Game API
1305
+ *
1306
+ * This is the single source of truth for all RUN.game games.
1307
+ *
1308
+ * Usage in RUN.game games:
1309
+ * ```typescript
1310
+ * import type { RundotGameAPI } from '../../rundot-game-api/types';
1311
+ * declare const RundotGameAPI: RundotGameAPI;
1312
+ * ```
1313
+ */
1314
+
1315
+ interface RecipeRequirementResult {
1316
+ recipeId: string;
1317
+ entity: string | null;
1318
+ amount?: number;
1319
+ inputs: Record<string, number | string>;
1320
+ canAfford: boolean;
1321
+ disabled: boolean;
1322
+ }
1323
+ interface SimulationRunSummary {
1324
+ id: string;
1325
+ recipeId: string;
1326
+ status: string;
1327
+ startTime: number;
1328
+ expiresAt: number;
1329
+ entity?: string;
1330
+ inputs?: Record<string, number | string>;
1331
+ outputs?: Record<string, number | string>;
1332
+ commitmentEndsAt?: number;
1333
+ participantCount?: number;
1334
+ }
1335
+ type RundotGameSimulationStateResponse = SimulationPersonalState | SimulationRoomState;
1336
+ type SimulationUpdateType = 'entity' | 'activeRuns' | 'snapshot';
1337
+ interface SimulationUpdateBase {
1338
+ timestamp: number;
1339
+ reason?: 'recipe_completed' | 'auto_restart' | 'manual_update' | 'state_sync';
1340
+ }
1341
+ interface SimulationEntityUpdate extends SimulationUpdateBase {
1342
+ type: 'entity';
1343
+ entities: Array<{
1344
+ entityId: string;
1345
+ quantity: number | string;
1346
+ }>;
1347
+ }
1348
+ interface SimulationActiveRunsUpdate extends SimulationUpdateBase {
1349
+ type: 'activeRuns';
1350
+ activeRuns: Array<{
1351
+ id: string;
1352
+ recipeId: string;
1353
+ status: string;
1354
+ startTime: number;
1355
+ expiresAt: number;
1356
+ entity?: string;
1357
+ inputs?: Record<string, number | string>;
1358
+ outputs?: Record<string, number | string>;
1359
+ }>;
1360
+ }
1361
+ interface SimulationSnapshotUpdate extends SimulationUpdateBase {
1362
+ type: 'snapshot';
1363
+ entities?: Array<{
1364
+ entityId: string;
1365
+ quantity: number | string;
1366
+ }>;
1367
+ activeRuns?: Array<{
1368
+ id: string;
1369
+ recipeId: string;
1370
+ status: string;
1371
+ startTime: number;
1372
+ expiresAt: number;
1373
+ entity?: string;
1374
+ inputs?: Record<string, number | string>;
1375
+ outputs?: Record<string, number | string>;
1376
+ }>;
1377
+ }
1378
+ type SimulationUpdateData = SimulationEntityUpdate | SimulationActiveRunsUpdate | SimulationSnapshotUpdate;
1379
+ interface SimulationSubscribeOptions {
1380
+ entities?: string[];
1381
+ tags?: string[];
1382
+ activeRuns?: boolean;
1383
+ roomId?: string;
1384
+ onUpdate: (data: SimulationUpdateData) => void;
1385
+ }
1386
+ interface RundotGameSimulationEffect {
1387
+ type: string;
1388
+ target: any;
1389
+ value: any;
1390
+ }
1391
+ interface RundotGameSimulationRecipe {
1392
+ scope: 'player' | 'room' | 'actor';
1393
+ inputs: Record<string, any>;
1394
+ autoRestart?: boolean;
1395
+ beginEffects?: RundotGameSimulationEffect[];
1396
+ endEffects?: RundotGameSimulationEffect[];
1397
+ outputs?: Record<string, any>;
1398
+ duration?: number;
1399
+ maxRestartCondition?: any;
1400
+ metadata?: {
1401
+ startsDisabled?: boolean;
1402
+ autoRestart?: boolean;
1403
+ maxRestartCondition?: any;
1404
+ };
1405
+ guards?: Record<string, any>;
1406
+ effects?: Array<any>;
1407
+ clientViewable?: boolean;
1408
+ }
1409
+ interface RundotGameSimulationConfig {
1410
+ version: string;
1411
+ entities: Record<string, {
1412
+ tags?: string[];
1413
+ metadata?: Record<string, any>;
1414
+ stackable?: boolean;
1415
+ neverConsumable?: boolean;
1416
+ clientViewable?: boolean;
1417
+ slots?: Record<string, {
1418
+ allowedTags: string[];
1419
+ maxItems: number;
1420
+ }>;
1421
+ actorTemplate?: {
1422
+ defaultState?: Record<string, any>;
1423
+ availableRecipes?: string[];
1424
+ };
1425
+ }>;
1426
+ recipes: Record<string, RundotGameSimulationRecipe>;
1427
+ fieldResolution?: Record<string, any>;
1428
+ matchmaking?: Record<string, any>;
1429
+ }
1430
+ interface RecipeRequirementQuery {
1431
+ recipeId: string;
1432
+ entity?: string;
1433
+ batchAmount?: number;
1434
+ }
1435
+ interface BatchRecipeRequirementsResult {
1436
+ success: boolean;
1437
+ results: RecipeRequirementResult[];
1438
+ errors?: Array<unknown>;
1439
+ }
1440
+ interface RundotGameExecuteRecipeOptions {
1441
+ roomId?: string;
1442
+ batchAmount?: number;
1443
+ allowPartialBatch?: boolean;
1444
+ entity?: string;
1445
+ }
1446
+ interface RundotGameExecuteScopedRecipeOptions {
1447
+ roomId?: string;
1448
+ }
1449
+ interface RundotGameAvailableRecipe {
1450
+ id: string;
1451
+ scope: string;
1452
+ clientViewable: boolean;
1453
+ }
1454
+ interface RundotGameCollectRecipeResult {
1455
+ success: boolean;
1456
+ runId: string;
1457
+ rewards: Record<string, unknown>;
1458
+ message: string;
1459
+ }
1460
+ interface RundotGameExecuteRecipeResult {
1461
+ success: boolean;
1462
+ status?: string;
1463
+ runId?: string;
1464
+ expiresAt?: string;
1465
+ queuePosition?: number;
1466
+ outputs?: Record<string, number | string>;
1467
+ data?: Record<string, unknown>;
1468
+ message?: string;
1469
+ amountRequested?: number;
1470
+ amountFulfilled?: number;
1471
+ partialSuccess?: boolean;
1472
+ }
1473
+ interface Profile {
1474
+ id: string;
1475
+ username: string;
1476
+ name?: string;
1477
+ avatarUrl?: string | null;
1478
+ isAnonymous?: boolean;
1479
+ }
1480
+ interface RundotGameAPI {
1481
+ /**
1482
+ * @deprecated All config properties have been removed. Use RundotGameAPI methods instead.
1483
+ * Will be removed in v4.0.0
1484
+ */
1485
+ config: Record<string, never>;
1486
+ _profileData?: Profile;
1487
+ _deviceData?: DeviceInfo;
1488
+ _environmentData?: EnvironmentInfo;
1489
+ _safeAreaData?: SafeArea;
1490
+ _localeData?: string;
1491
+ _languageCodeData?: string;
1492
+ _mock: any;
1493
+ _bootstrap: {
1494
+ apiInjected: boolean;
1495
+ rundotGame: any;
1496
+ };
1497
+ /**
1498
+ * @deprecated No longer need to call this method. This will get called on import.
1499
+ */
1500
+ initializeAsync(options?: InitializationOptions): Promise<InitializationContext>;
1501
+ simulation: SimulationApi;
1502
+ leaderboard: LeaderboardApi;
1503
+ log(message: string, ...args: any[]): void;
1504
+ error(message: string, ...args: any[]): void;
1505
+ isAvailable(): boolean;
1506
+ /**
1507
+ * @deprecated Use RundotGameAPI.system.isMobile() instead
1508
+ */
1509
+ isMobile(): boolean;
1510
+ /**
1511
+ * @deprecated Use RundotGameAPI.system.isWeb() instead
1512
+ */
1513
+ isWeb(): boolean;
1514
+ isMock(): boolean;
1515
+ /**
1516
+ * @deprecated Please use the new analytics API. RundotGameAPI.analytics
1517
+ * @param options
1518
+ */
1519
+ logCustomEvent(options: {
1520
+ eventName: string;
1521
+ params?: Record<string, any>;
1522
+ }): Promise<void>;
1523
+ getExperiment(options: {
1524
+ experimentName: string;
1525
+ }): Promise<any>;
1526
+ getFeatureFlag(options: {
1527
+ flagName: string;
1528
+ }): Promise<any>;
1529
+ getFeatureGate(options: {
1530
+ gateName: string;
1531
+ }): Promise<any>;
1532
+ system: SystemApi;
1533
+ getProfile(): Profile;
1534
+ /**
1535
+ * @deprecated Use getProfile() instead
1536
+ */
1537
+ getCurrentProfile(): Profile;
1538
+ getLocale(): string;
1539
+ getLanguageCode(): string;
1540
+ triggerHapticAsync(style: HapticFeedbackStyle): Promise<void>;
1541
+ deviceCache: {
1542
+ setItem(key: string, value: string): Promise<void>;
1543
+ getItem(key: string): Promise<string | null>;
1544
+ removeItem(key: string): Promise<void>;
1545
+ clear(): Promise<void>;
1546
+ length(): Promise<number>;
1547
+ key(index: number): Promise<string | null>;
1548
+ };
1549
+ appStorage: {
1550
+ setItem(key: string, value: string): Promise<void>;
1551
+ getItem(key: string): Promise<string | null>;
1552
+ removeItem(key: string): Promise<void>;
1553
+ clear(): Promise<void>;
1554
+ length(): Promise<number>;
1555
+ key(index: number): Promise<string | null>;
1556
+ getAllItems(): Promise<string[]>;
1557
+ setMultipleItems(items: {
1558
+ key: string;
1559
+ value: string;
1560
+ }[]): Promise<void>;
1561
+ removeMultipleItems(keys: string[]): Promise<void>;
1562
+ };
1563
+ globalStorage: {
1564
+ setItem(key: string, value: string): Promise<void>;
1565
+ getItem(key: string): Promise<string | null>;
1566
+ removeItem(key: string): Promise<void>;
1567
+ clear(): Promise<void>;
1568
+ length(): Promise<number>;
1569
+ key(index: number): Promise<string | null>;
1570
+ };
1571
+ requestPopOrQuit(options?: QuitOptions): Promise<boolean>;
1572
+ /**
1573
+ * @deprecated Please use the ads API. (e.g, RundotGameAPI.ads)
1574
+ */
1575
+ isRewardedAdReadyAsync(): Promise<boolean>;
1576
+ /**
1577
+ * @deprecated Please use the ads API. (e.g, RundotGameAPI.ads)
1578
+ */
1579
+ showRewardedAdAsync(): Promise<boolean>;
1580
+ requestTimeAsync(): Promise<ServerTimeData>;
1581
+ getFutureTimeAsync(options: GetFutureTimeOptions): Promise<number>;
1582
+ formatTime(timestamp: number, options?: any): string;
1583
+ formatNumber(value: number, options?: any): string;
1584
+ loadAsset(url: string, options?: {
1585
+ type?: string;
1586
+ streaming?: boolean;
1587
+ cache?: boolean;
1588
+ timeout?: number;
1589
+ isOptional?: boolean;
1590
+ }): Promise<string>;
1591
+ preloadAssets(assets: Array<string | {
1592
+ url: string;
1593
+ isOptional?: boolean;
1594
+ }>, options?: {
1595
+ onProgress?: (progress: number, info: any) => void;
1596
+ }): Promise<Array<{
1597
+ success: boolean;
1598
+ isOptional?: boolean;
1599
+ }>>;
1600
+ cleanupAssets(): void;
1601
+ assetLoader: {
1602
+ getCached(url: string): string | null;
1603
+ };
1604
+ showAvatar3dEditorAsync(options: {
1605
+ currentAvatar?: any;
1606
+ contextData?: any;
1607
+ }): Promise<Avatar3dEdits>;
1608
+ loadAvatar3dAsync(avatarId?: string): Promise<any>;
1609
+ saveAvatar3dAsync(config: any): Promise<string>;
1610
+ deleteAvatar3dAsync(): Promise<void>;
1611
+ downloadAvatar3dAssetPathsAsync(): Promise<Record<string, string[]>>;
1612
+ downloadAvatar3dManifestAsync(): Promise<AssetManifest>;
1613
+ pushAppAsync(appId: string, options?: {
1614
+ contextData?: any;
1615
+ appParams?: any;
1616
+ }): Promise<any>;
1617
+ popAppAsync(): Promise<void>;
1618
+ getStackInfo(): {
1619
+ isInStack: boolean;
1620
+ stackPosition: number;
1621
+ };
1622
+ rooms: RoomsApi;
1623
+ notifyCleanupComplete(): void;
1624
+ RoomEvents: {
1625
+ OPTIMISTIC_GAME_STATE_UPDATED: string;
1626
+ PROPOSED_MOVE_VALIDATION_UPDATED: string;
1627
+ };
1628
+ numbers: {
1629
+ isBigNumber(value: any): boolean;
1630
+ normalize(value: string | number | any): any;
1631
+ format: {
1632
+ incremental(value: any): string;
1633
+ };
1634
+ calculateGeometricSeriesCost(baseCost: number | string, multiplier: number, currentQuantity: number, purchaseAmount: number): any;
1635
+ calculateMaxAffordableDecimal(availableCash: number | string, baseCost: number | string, multiplier: number, currentQuantity: number): number;
1636
+ formatDecimalCurrency(decimalValue: any): string;
1637
+ Decimal: any;
1638
+ };
1639
+ iap: IapApi;
1640
+ cdn: CdnApi;
1641
+ ads: AdsApi;
1642
+ ai: AiApi;
1643
+ popups: PopupsApi;
1644
+ analytics: AnalyticsApi;
1645
+ sharedAssets: SharedAssetsApi;
1646
+ preloader: PreloaderApi;
1647
+ notifications: NotificationsApi;
1648
+ lifecycles: LifecycleApi;
1649
+ social: SocialApi;
1650
+ context: InitializationContext;
1651
+ }
1652
+
1653
+ interface ShowInterstitialAdOptions {
1654
+ adDisplayId?: string;
1655
+ adDisplayName?: string;
1656
+ }
1657
+ interface ShowRewardedAdOptions {
1658
+ adDisplayId?: string;
1659
+ adDisplayName?: string;
1660
+ }
1661
+ interface AdsApi {
1662
+ isRewardedAdReadyAsync(): Promise<boolean>;
1663
+ showRewardedAdAsync(options?: ShowRewardedAdOptions): Promise<boolean>;
1664
+ showInterstitialAd(options?: ShowInterstitialAdOptions): Promise<boolean>;
1665
+ }
1666
+
1667
+ export { type AiChatCompletionRequest as $, type AnalyticsApi as A, type BatchRecipeRequirementsResult as B, type ScheduleLocalNotification as C, type ScheduleNotificationOptions as D, type PopupsApi as E, type ShowToastOptions as F, type ShowInterstitialAdOptions as G, type Host as H, type ShowRewardedAdOptions as I, type ProfileApi as J, type DeviceApi as K, type DeviceInfo as L, type EnvironmentApi as M, type NavigationApi as N, type EnvironmentInfo as O, type Profile as P, type QuitOptions as Q, type RundotGameAPI as R, type SimulationRunSummary as S, type SystemApi as T, type SafeArea as U, type CdnApi as V, type FetchFromCdnOptions as W, type TimeApi as X, type ServerTimeData as Y, type GetFutureTimeOptions as Z, type AiApi as _, type RecipeRequirementResult as a, type PlayerRankOptions as a$, type AiChatCompletionData as a0, type HapticsApi as a1, HapticFeedbackStyle as a2, type FeaturesApi as a3, type Experiment as a4, type LifecycleApi as a5, type SleepCallback as a6, type Subscription as a7, type AwakeCallback as a8, type PauseCallback as a9, type RoomMessageEvent as aA, type ProposedMoveEvent as aB, RundotGameTransport as aC, type RoomsApi as aD, type CreateRoomOptions as aE, type JoinOrCreateRoomOptions as aF, type JoinOrCreateResult as aG, type ListRoomsOptions as aH, type UpdateRoomDataOptions as aI, type RoomMessageRequest as aJ, type StartRoomGameOptions as aK, type ProposeMoveRequest as aL, type ProposeMoveResult as aM, type ValidateMoveVerdict as aN, type ValidateMoveResult as aO, type RoomSubscriptionOptions as aP, type LoggingApi as aQ, type IapApi as aR, type SpendCurrencyOptions as aS, type LoadEmbeddedAssetsResponse as aT, type SharedAssetsApi as aU, type LeaderboardApi as aV, type ScoreToken as aW, type SubmitScoreParams as aX, type SubmitScoreResult as aY, type GetPagedScoresOptions as aZ, type PagedScoresResponse as a_, type ResumeCallback as aa, type QuitCallback as ab, type SimulationApi as ac, type SimulationSlotValidationResult as ad, type SimulationBatchOperation as ae, type SimulationBatchOperationsResult as af, type SimulationAvailableItem as ag, type SimulationPowerPreview as ah, type SimulationSlotMutationResult as ai, type SimulationSlotContainer as aj, type SimulationAssignment as ak, type SimulationState as al, type ExecuteRecipeOptions as am, type ExecuteRecipeResponse as an, type CollectRecipeResult as ao, type ResetStateOptions as ap, type ResetStateResult as aq, type GetActiveRunsOptions as ar, type ExecuteScopedRecipeOptions as as, type ExecuteScopedRecipeResult as at, type GetAvailableRecipesOptions as au, type GetAvailableRecipesResult as av, type Recipe as aw, type GetBatchRecipeRequirements as ax, type TriggerRecipeChainOptions as ay, type RoomDataUpdate as az, type RundotGameSimulationStateResponse as b, type PlayerRankResult as b0, type GetPodiumScoresOptions as b1, type PodiumScoresResponse as b2, type PreloaderApi as b3, type SocialApi as b4, type ShareMetadata as b5, type ShareLinkResult as b6, type SocialQRCodeOptions as b7, type QRCodeResult as b8, type Avatar3dApi as b9, type RundotGameRoomCustomMetadata as bA, type RundotGameRoomPayload as bB, type RoomEnvelopeResponse as bC, type RoomsEnvelopeResponse as bD, type JoinOrCreateRoomEnvelopeResponse as bE, type RecipeInfo as bF, type SimulationPersonalState as bG, type SimulationRoomActiveRecipe as bH, type SimulationRoomState as bI, type SimulationBatchOperationAssign as bJ, type SimulationBatchOperationRemove as bK, type SimulationBatchOperationResult as bL, RpcSharedAssetsApi as bM, type LoadEmbeddedAssetsRequest as bN, type LeaderboardModeConfig as bO, type LeaderboardPeriodType as bP, type LeaderboardPeriodConfig as bQ, type LeaderboardAntiCheatConfig as bR, type LeaderboardDisplaySettings as bS, type LeaderboardConfig as bT, type LeaderboardEntry as bU, type PodiumScoresContext as bV, type HudInsets as bW, createHost as bX, type AssetManifest as ba, type Avatar3dConfig as bb, type ShowEditorOptions as bc, type Avatar3dEdits as bd, type AdsApi as be, type InitializationContext as bf, type InitializationOptions as bg, type AiMessage as bh, type Asset as bi, type Category as bj, MockAvatarApi as bk, type SubPath as bl, type TimeIntervalTriggerInput as bm, type NotificationTriggerInput as bn, type OnRequestCallback as bo, type OnResponseCallback as bp, type OnNotificationCallback as bq, type RpcTransport as br, type JoinRoomMatchCriteria as bs, type RoomMessageEventType as bt, type RoomMessagePayload as bu, type ProposedMovePayload as bv, ROOM_GAME_PHASES as bw, type RoomGamePhase as bx, type RundotGameRoomRulesGameState as by, type RundotGameRoomRules as bz, type SimulationUpdateType as c, type SimulationEntityUpdate as d, type SimulationActiveRunsUpdate as e, type SimulationSnapshotUpdate as f, type SimulationUpdateData as g, type SimulationSubscribeOptions as h, type RundotGameSimulationEffect as i, type RundotGameSimulationRecipe as j, type RundotGameSimulationConfig as k, type RecipeRequirementQuery as l, type RundotGameExecuteRecipeOptions as m, type RundotGameExecuteScopedRecipeOptions as n, type RundotGameAvailableRecipe as o, type RundotGameCollectRecipeResult as p, type RundotGameExecuteRecipeResult as q, RundotGameRoom as r, type RpcRequest as s, type RpcResponse as t, type RpcNotification as u, RpcClient as v, type StorageApi as w, type NavigationStackInfo as x, type PushAppOptions as y, type NotificationsApi as z };