@series-inc/rundot-game-sdk 5.23.0-beta.0 → 5.23.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/dist/{AdsApi-25-HRS5D.d.ts → AdsApi-Bfb7_Weu.d.ts} +50 -8
- package/dist/{callRemoteFunction-D-Ah7AxA.d.ts → callRemoteFunction-NBIrdLoa.d.ts} +2 -2
- package/dist/{chunk-BJGV6WIK.js → chunk-57DREBKB.js} +2 -2
- package/dist/chunk-57DREBKB.js.map +1 -0
- package/dist/{chunk-TNBSGNJ2.js → chunk-LKE6IJ4M.js} +3 -3
- package/dist/chunk-LKE6IJ4M.js.map +1 -0
- package/dist/{chunk-NTONRZFO.js → chunk-T7HMDUMX.js} +146 -9
- package/dist/chunk-T7HMDUMX.js.map +1 -0
- package/dist/{chunk-APR46OZQ.js → chunk-ZUEAIFOZ.js} +273 -53
- package/dist/chunk-ZUEAIFOZ.js.map +1 -0
- package/dist/host-http.d.ts +4 -4
- package/dist/host-http.js +1 -1
- package/dist/index.d.ts +35 -17
- package/dist/index.js +2 -2
- package/dist/{sandbox → playground}/index.js +102 -101
- package/dist/playground/index.js.map +1 -0
- package/dist/rundot-game-api/index.d.ts +2 -2
- package/dist/rundot-game-api/index.js +3 -3
- package/dist/rundot-game-api/index.js.map +1 -1
- package/dist/tabCoordinator-2BPJNWVV.js +3 -0
- package/dist/{tabCoordinator-SPKWPZDQ.js.map → tabCoordinator-2BPJNWVV.js.map} +1 -1
- package/dist/vite/index.css +1 -1
- package/dist/vite/index.css.map +1 -1
- package/dist/vite/index.d.ts +151 -86
- package/dist/vite/index.js +4319 -4298
- package/dist/vite/index.js.map +1 -1
- package/docs/README.md +97 -0
- package/docs/SUMMARY.md +67 -0
- package/docs/agents-index.txt +1 -0
- package/docs/rundot-developer-platform/api/ACCESS_GATE.md +218 -0
- package/docs/rundot-developer-platform/api/ADS.md +167 -0
- package/docs/rundot-developer-platform/api/ADVANCED-MULTIPLAYER.md +386 -0
- package/docs/rundot-developer-platform/api/AI.md +434 -0
- package/docs/rundot-developer-platform/api/ANALYTICS.md +98 -0
- package/docs/rundot-developer-platform/api/APP.md +610 -0
- package/docs/rundot-developer-platform/api/ASSETS.md +441 -0
- package/docs/rundot-developer-platform/api/ATTRIBUTION.md +93 -0
- package/docs/rundot-developer-platform/api/AUDIO_GEN.md +283 -0
- package/docs/rundot-developer-platform/api/AVATAR_3D.md +210 -0
- package/docs/rundot-developer-platform/api/BIGNUMBERS.md +161 -0
- package/docs/rundot-developer-platform/api/BUILDING_TIMERS.md +591 -0
- package/docs/rundot-developer-platform/api/CLIPS.md +466 -0
- package/docs/rundot-developer-platform/api/COLLECTIBLES.md +89 -0
- package/docs/rundot-developer-platform/api/CONTEXT.md +99 -0
- package/docs/rundot-developer-platform/api/CREDITS.md +137 -0
- package/docs/rundot-developer-platform/api/EMBEDDED_LIBRARIES.md +152 -0
- package/docs/rundot-developer-platform/api/ENERGY_SYSTEM.md +508 -0
- package/docs/rundot-developer-platform/api/ENTITLEMENTS.md +267 -0
- package/docs/rundot-developer-platform/api/ENVIRONMENT.md +369 -0
- package/docs/rundot-developer-platform/api/EXPERIMENTS.md +118 -0
- package/docs/rundot-developer-platform/api/FILES.md +677 -0
- package/docs/rundot-developer-platform/api/GACHA_SYSTEM.md +695 -0
- package/docs/rundot-developer-platform/api/GAMEPAD.md +155 -0
- package/docs/rundot-developer-platform/api/HAPTICS.md +65 -0
- package/docs/rundot-developer-platform/api/IMAGE_GEN.md +308 -0
- package/docs/rundot-developer-platform/api/IN_APP_MESSAGING.md +162 -0
- package/docs/rundot-developer-platform/api/LEADERBOARD.md +673 -0
- package/docs/rundot-developer-platform/api/LIFECYCLES.md +159 -0
- package/docs/rundot-developer-platform/api/LOGGING.md +107 -0
- package/docs/rundot-developer-platform/api/MULTIPLAYER.md +985 -0
- package/docs/rundot-developer-platform/api/NAVIGATION.md +217 -0
- package/docs/rundot-developer-platform/api/NOTIFICATIONS.md +310 -0
- package/docs/rundot-developer-platform/api/PRELOADER.md +93 -0
- package/docs/rundot-developer-platform/api/PROFILE.md +74 -0
- package/docs/rundot-developer-platform/api/PURCHASES.md +349 -0
- package/docs/rundot-developer-platform/api/PVP_SYSTEM.md +376 -0
- package/docs/rundot-developer-platform/api/RATE_LIMITS.md +65 -0
- package/docs/rundot-developer-platform/api/RELEASE_NOTES.md +131 -0
- package/docs/rundot-developer-platform/api/SAFE_AREA.md +90 -0
- package/docs/rundot-developer-platform/api/SERVER_AUTHORITATIVE.md +617 -0
- package/docs/rundot-developer-platform/api/SHARED_ASSETS.md +109 -0
- package/docs/rundot-developer-platform/api/SHARING.md +308 -0
- package/docs/rundot-developer-platform/api/SHOP.md +533 -0
- package/docs/rundot-developer-platform/api/SIMULATION_CONFIG.md +1147 -0
- package/docs/rundot-developer-platform/api/SPRITE_GEN.md +308 -0
- package/docs/rundot-developer-platform/api/STATS.md +162 -0
- package/docs/rundot-developer-platform/api/STORAGE.md +268 -0
- package/docs/rundot-developer-platform/api/SYSTEM.md +128 -0
- package/docs/rundot-developer-platform/api/THREE_D_GEN.md +507 -0
- package/docs/rundot-developer-platform/api/TIME.md +164 -0
- package/docs/rundot-developer-platform/api/UGC.md +1435 -0
- package/docs/rundot-developer-platform/api/VIDEO.md +155 -0
- package/docs/rundot-developer-platform/api/VIDEO_GEN.md +327 -0
- package/docs/rundot-developer-platform/cli-reference.md +525 -0
- package/docs/rundot-developer-platform/deploying-your-game.md +342 -0
- package/docs/rundot-developer-platform/error-handling.md +94 -0
- package/docs/rundot-developer-platform/getting-started.md +150 -0
- package/docs/rundot-developer-platform/initializing-your-game.md +41 -0
- package/docs/rundot-developer-platform/marketing-your-game.md +455 -0
- package/docs/rundot-developer-platform/playground.md +302 -0
- package/docs/rundot-developer-platform/runtime-environment.md +76 -0
- package/docs/rundot-developer-platform/setting-your-game-thumbnail.md +37 -0
- package/docs/rundot-developer-platform/troubleshooting.md +124 -0
- package/package.json +18 -7
- package/scripts/copy-docs.mjs +52 -0
- package/scripts/install-hint.mjs +10 -0
- package/scripts/setup.mjs +378 -0
- package/dist/chunk-APR46OZQ.js.map +0 -1
- package/dist/chunk-BJGV6WIK.js.map +0 -1
- package/dist/chunk-NTONRZFO.js.map +0 -1
- package/dist/chunk-TNBSGNJ2.js.map +0 -1
- package/dist/sandbox/index.js.map +0 -1
- package/dist/tabCoordinator-SPKWPZDQ.js +0 -3
- package/scripts/postinstall.mjs +0 -463
- /package/dist/{sandbox → playground}/index.d.ts +0 -0
package/README.md
CHANGED
|
@@ -15,6 +15,17 @@ Build connected HTML5 games that integrate deeply with the RUN.game platform. Th
|
|
|
15
15
|
npm install @series-inc/rundot-game-sdk@latest
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
+
Installing the package only prints a hint — it makes no changes to your project.
|
|
19
|
+
To copy the SDK docs into your project and configure your AI agent files
|
|
20
|
+
(`AGENTS.md`/`CLAUDE.md`/`GEMINI.md`, `.gitignore`, and CLI hooks), run the
|
|
21
|
+
explicit, consent-gated setup command:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx rundot-sdk-setup
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
It prompts before each change (pass `-y` to accept all, `--no` to skip all).
|
|
28
|
+
|
|
18
29
|
### Initialize
|
|
19
30
|
|
|
20
31
|
```typescript
|
|
@@ -427,18 +427,40 @@ interface EnvironmentInfo {
|
|
|
427
427
|
* `HostEnvironmentApi` then defaults each capability to `true`.
|
|
428
428
|
*/
|
|
429
429
|
readonly capabilities: PlatformCapabilities;
|
|
430
|
+
/**
|
|
431
|
+
* Whether the game is running on the Steam channel on a desktop/laptop PC
|
|
432
|
+
* (the Steam client, NOT Steam Deck hardware). Channel-static for the
|
|
433
|
+
* session — branch UX on it (Steam-specific copy, hiding app-store prompts,
|
|
434
|
+
* etc.). Mutually exclusive with `isSteamDeck`: both are `false` off Steam,
|
|
435
|
+
* and exactly one is `true` on Steam. To ask "am I on Steam at all?", check
|
|
436
|
+
* `isSteamDesktop || isSteamDeck`. Also exposed as `system.isSteamDesktop()`. A host
|
|
437
|
+
* that predates this field omits it on the wire; `HostEnvironmentApi` then
|
|
438
|
+
* defaults it to `false`.
|
|
439
|
+
*/
|
|
440
|
+
readonly isSteamDesktop: boolean;
|
|
441
|
+
/**
|
|
442
|
+
* Whether the game is running on Steam Deck hardware. Device-static for the
|
|
443
|
+
* session — branch UX on it (gamepad-first navigation, handheld layout,
|
|
444
|
+
* larger touch targets). Mutually exclusive with `isSteamDesktop` (see above).
|
|
445
|
+
* Also exposed as `system.isSteamDeck()`. A host that predates this field
|
|
446
|
+
* omits it on the wire; `HostEnvironmentApi` then defaults it to `false`.
|
|
447
|
+
*/
|
|
448
|
+
readonly isSteamDeck: boolean;
|
|
430
449
|
}
|
|
431
450
|
/**
|
|
432
451
|
* The INIT_SDK environment payload as it arrives over the wire / is stored on
|
|
433
|
-
* `_environmentData`. Identical to `EnvironmentInfo` except `capabilities
|
|
434
|
-
*
|
|
435
|
-
* omits
|
|
452
|
+
* `_environmentData`. Identical to `EnvironmentInfo` except `capabilities`,
|
|
453
|
+
* `isSteamDesktop`, and `isSteamDeck` are optional, because a host older than those
|
|
454
|
+
* fields omits them. `HostEnvironmentApi` upgrades this into a full
|
|
455
|
+
* `EnvironmentInfo`.
|
|
436
456
|
*/
|
|
437
|
-
interface RawEnvironmentInfo extends Omit<EnvironmentInfo, 'capabilities'> {
|
|
457
|
+
interface RawEnvironmentInfo extends Omit<EnvironmentInfo, 'capabilities' | 'isSteamDesktop' | 'isSteamDeck'> {
|
|
438
458
|
readonly capabilities?: {
|
|
439
459
|
readonly ads?: boolean;
|
|
440
460
|
readonly purchases?: boolean;
|
|
441
461
|
};
|
|
462
|
+
readonly isSteamDesktop?: boolean;
|
|
463
|
+
readonly isSteamDeck?: boolean;
|
|
442
464
|
}
|
|
443
465
|
interface EnvironmentApi {
|
|
444
466
|
getEnvironment(): EnvironmentInfo;
|
|
@@ -490,6 +512,20 @@ interface SystemApi {
|
|
|
490
512
|
* @returns true if on web platform
|
|
491
513
|
*/
|
|
492
514
|
isWeb(): boolean;
|
|
515
|
+
/**
|
|
516
|
+
* Check if running on the Steam channel on a desktop/laptop PC (the Steam
|
|
517
|
+
* client, NOT Steam Deck hardware). Mutually exclusive with `isSteamDeck()`;
|
|
518
|
+
* to ask "am I on Steam at all?", check `isSteamDesktop() || isSteamDeck()`.
|
|
519
|
+
* @returns true on Steam desktop/laptop (non-Deck)
|
|
520
|
+
*/
|
|
521
|
+
isSteamDesktop(): boolean;
|
|
522
|
+
/**
|
|
523
|
+
* Check if running on Steam Deck hardware. Mutually exclusive with
|
|
524
|
+
* `isSteamDesktop()`. Use to branch UX for the handheld (gamepad-first
|
|
525
|
+
* navigation, handheld layout, larger touch targets).
|
|
526
|
+
* @returns true on Steam Deck
|
|
527
|
+
*/
|
|
528
|
+
isSteamDeck(): boolean;
|
|
493
529
|
/**
|
|
494
530
|
* Check whether the current platform can present an "Add to Home Screen"
|
|
495
531
|
* prompt for the running game right now.
|
|
@@ -2671,11 +2707,14 @@ interface SocialApi {
|
|
|
2671
2707
|
*
|
|
2672
2708
|
* @param options.shareParams Arbitrary share parameters for your game.
|
|
2673
2709
|
* @param options.metadata Optional OpenGraph metadata for rich previews.
|
|
2710
|
+
* @param options.slug Optional cosmetic slug appended to the share URL (e.g.
|
|
2711
|
+
* "boss-level"). Sanitized server-side; non-unique; does not affect resolution.
|
|
2674
2712
|
* @returns The generated share URL.
|
|
2675
2713
|
*/
|
|
2676
2714
|
shareLinkAsync(options: {
|
|
2677
2715
|
shareParams: Record<string, string>;
|
|
2678
2716
|
metadata?: ShareMetadata;
|
|
2717
|
+
slug?: string;
|
|
2679
2718
|
}): Promise<ShareLinkResult>;
|
|
2680
2719
|
/**
|
|
2681
2720
|
* Create a share document and return both the URL and a QR code image.
|
|
@@ -2685,12 +2724,15 @@ interface SocialApi {
|
|
|
2685
2724
|
* @param options.shareParams Arbitrary share parameters for your game.
|
|
2686
2725
|
* @param options.metadata Optional OpenGraph metadata for the share.
|
|
2687
2726
|
* @param options.qrOptions Customisation for the generated QR code.
|
|
2727
|
+
* @param options.slug Optional cosmetic slug appended to the share URL (e.g.
|
|
2728
|
+
* "boss-level"). Sanitized server-side; non-unique; does not affect resolution.
|
|
2688
2729
|
* @returns The generated share URL, QR code (as a data URL), and shareLinkId.
|
|
2689
2730
|
*/
|
|
2690
2731
|
createQRCodeAsync(options: {
|
|
2691
2732
|
shareParams: Record<string, string>;
|
|
2692
2733
|
metadata?: ShareMetadata;
|
|
2693
2734
|
qrOptions?: SocialQRCodeOptions;
|
|
2735
|
+
slug?: string;
|
|
2694
2736
|
}): Promise<QRCodeResult>;
|
|
2695
2737
|
/**
|
|
2696
2738
|
* Write click metadata to a share as the current user (clicker).
|
|
@@ -4015,7 +4057,7 @@ interface Host {
|
|
|
4015
4057
|
* registers the `onNotificationParamsUpdate` subscription. Lets the host
|
|
4016
4058
|
* tell "SDK booted past READY" apart from "SDK has a live notification
|
|
4017
4059
|
* subscriber" — the latter is the precise signal for "a live push WILL be
|
|
4018
|
-
* received". Optional: Mock /
|
|
4060
|
+
* received". Optional: Mock / Playground hosts have no remote peer and so
|
|
4019
4061
|
* don't implement it.
|
|
4020
4062
|
*/
|
|
4021
4063
|
notifyNotificationParamsSubscribeReady?(): void;
|
|
@@ -4024,9 +4066,9 @@ interface Host {
|
|
|
4024
4066
|
/**
|
|
4025
4067
|
* Create a Host instance based on the runtime environment.
|
|
4026
4068
|
*
|
|
4027
|
-
*
|
|
4028
|
-
* which registers a factory on `globalThis.
|
|
4029
|
-
* The Vite
|
|
4069
|
+
* PlaygroundHost is loaded via a separate entry point (`@series-inc/rundot-game-sdk/playground`)
|
|
4070
|
+
* which registers a factory on `globalThis.__RUNDOT_PLAYGROUND_HOST_FACTORY__`.
|
|
4071
|
+
* The Vite playground plugin injects this import automatically, keeping Firebase
|
|
4030
4072
|
* completely out of the main bundle's dependency graph.
|
|
4031
4073
|
*/
|
|
4032
4074
|
declare function createHost(rundotGameApi: RundotGameAPI, isMock: boolean): Promise<Host>;
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
* })
|
|
12
12
|
* ```
|
|
13
13
|
*
|
|
14
|
-
* ⚠️
|
|
15
|
-
* and other
|
|
14
|
+
* ⚠️ PLAYGROUND-ONLY: This file depends on Firebase and should ONLY be imported by PlaygroundHost
|
|
15
|
+
* and other playground-only modules. Do NOT import from barrel exports (http/index.ts).
|
|
16
16
|
* This ensures Firebase is not bundled in production builds.
|
|
17
17
|
*/
|
|
18
18
|
/**
|
|
@@ -403,5 +403,5 @@ var HttpLeaderboardApi = class {
|
|
|
403
403
|
};
|
|
404
404
|
|
|
405
405
|
export { HttpAudioGenApi, HttpImageGenApi, HttpLeaderboardApi, HttpSpriteGenApi, HttpThreeDGenApi, HttpVideoGenApi };
|
|
406
|
-
//# sourceMappingURL=chunk-
|
|
407
|
-
//# sourceMappingURL=chunk-
|
|
406
|
+
//# sourceMappingURL=chunk-57DREBKB.js.map
|
|
407
|
+
//# sourceMappingURL=chunk-57DREBKB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/imageGen/HttpImageGenApi.ts","../src/audioGen/HttpAudioGenApi.ts","../src/videoGen/HttpVideoGenApi.ts","../src/spriteGen/HttpSpriteGenApi.ts","../src/threeDGen/HttpThreeDGenApi.ts","../src/leaderboard/normalizeScores.ts","../src/leaderboard/HttpLeaderboardApi.ts"],"names":[],"mappings":";;;AAOO,IAAM,kBAAN,MAA6C;AAAA,EACjC,KAAA;AAAA,EACA,IAAA;AAAA,EAEjB,WAAA,CAAY,OAAe,IAAA,EAAuB;AAChD,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACd;AAAA,EAEA,MAAc,UAAA,CAAc,IAAA,EAAc,IAAA,EAA2C;AACnF,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,IAAA,CAAK,UAAA,EAAW;AAC3C,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,IAAA,CAAK,cAAA,EAAe;AACzC,IAAA,MAAM,MAAM,CAAA,EAAG,OAAO,gBAAgB,IAAA,CAAK,KAAK,IAAI,IAAI,CAAA,CAAA;AAExD,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,MAChC,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,kBAAA;AAAA,QAChB,eAAA,EAAiB,UAAU,OAAO,CAAA,CAAA;AAAA,QAClC,YAAA,EAAc;AAAA,OAChB;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,IAAI;AAAA,KAC1B,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,SAAA,GAAY,MAAM,QAAA,CAAS,IAAA,EAAK;AACtC,MAAA,IAAI,YAAA,GAAe,CAAA,gBAAA,EAAmB,QAAA,CAAS,MAAM,CAAA,CAAA,CAAA;AACrD,MAAA,IAAI;AACF,QAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,SAAS,CAAA;AACtC,QAAA,YAAA,GAAe,SAAA,CAAU,KAAA,IAAS,SAAA,CAAU,OAAA,IAAW,YAAA;AAAA,MACzD,CAAA,CAAA,MAAQ;AACN,QAAA,IAAI,WAAW,YAAA,GAAe,SAAA;AAAA,MAChC;AACA,MAAA,MAAM,IAAI,MAAM,YAAY,CAAA;AAAA,IAC9B;AAEA,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA,EAEA,MAAM,SAAS,MAAA,EAAiD;AAC9D,IAAA,OAAO,IAAA,CAAK,UAAA,CAA2B,UAAA,EAAY,MAA4C,CAAA;AAAA,EACjG;AAAA,EAEA,MAAM,cAAc,MAAA,EAA+D;AACjF,IAAA,OAAO,IAAA,CAAK,UAAA,CAAkC,gBAAA,EAAkB,MAA4C,CAAA;AAAA,EAC9G;AAAA,EAEA,MAAM,iBAAiB,MAAA,EAAiE;AACtF,IAAA,OAAO,IAAA,CAAK,UAAA,CAAmC,mBAAA,EAAqB,MAA4C,CAAA;AAAA,EAClH;AAAA,EAEA,MAAM,aAAa,MAAA,EAAyD;AAC1E,IAAA,OAAO,IAAA,CAAK,UAAA,CAA+B,eAAA,EAAiB,MAA4C,CAAA;AAAA,EAC1G;AAAA,EAEA,MAAM,gBAAA,GAAgD;AACpD,IAAA,OAAO,EAAC;AAAA,EACV;AACF;;;AC/CO,IAAM,kBAAN,MAA6C;AAAA,EACjC,KAAA;AAAA,EACA,IAAA;AAAA,EAEjB,WAAA,CAAY,OAAe,IAAA,EAAuB;AAChD,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACd;AAAA,EAEA,MAAc,WAAA,CAAY,IAAA,EAAc,MAAA,EAAgB,IAAA,EAAmC;AACzF,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,IAAA,CAAK,UAAA,EAAW;AAC3C,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,IAAA,CAAK,cAAA,EAAe;AACzC,IAAA,MAAM,MAAM,CAAA,EAAG,OAAO,gBAAgB,IAAA,CAAK,KAAK,IAAI,IAAI,CAAA,CAAA;AAExD,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,MAChC,MAAA;AAAA,MACA,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,kBAAA;AAAA,QAChB,eAAA,EAAiB,UAAU,OAAO,CAAA;AAAA,OACpC;AAAA,MACA,GAAI,IAAA,KAAS,MAAA,GAAY,EAAE,IAAA,EAAM,KAAK,SAAA,CAAU,IAAI,CAAA,EAAE,GAAI;AAAC,KAC5D,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,QAAA,MAAM,aAAA,GAAgB,SAAS,QAAA,CAAS,OAAA,CAAQ,IAAI,aAAa,CAAA,IAAK,MAAM,EAAE,CAAA;AAC9E,QAAA,MAAM,IAAI,gBAAA,CAAiB,aAAA,GAAgB,GAAI,CAAA;AAAA,MACjD;AACA,MAAA,MAAM,SAAA,GAAY,MAAM,QAAA,CAAS,IAAA,EAAK;AACtC,MAAA,IAAI,YAAA,GAAe,CAAA,yBAAA,EAA4B,QAAA,CAAS,MAAM,CAAA,CAAA,CAAA;AAC9D,MAAA,IAAI,SAAA,GAAY,SAAA;AAChB,MAAA,IAAI;AACF,QAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,SAAS,CAAA;AACtC,QAAA,YAAA,GAAgB,SAAA,CAAU,KAAA,IAAS,SAAA,CAAU,OAAA,IAAW,YAAA;AACxD,QAAA,IAAI,OAAO,SAAA,CAAU,IAAA,KAAS,QAAA,cAAsB,SAAA,CAAU,IAAA;AAAA,MAChE,CAAA,CAAA,MAAQ;AACN,QAAA,IAAI,WAAW,YAAA,GAAe,SAAA;AAAA,MAChC;AACA,MAAA,MAAM,IAAI,cAAA,CAAe,SAAA,EAAW,YAAA,EAAc,SAAS,MAAM,CAAA;AAAA,IACnE;AAEA,IAAA,OAAO,QAAA;AAAA,EACT;AAAA,EAEA,MAAM,SAAS,MAAA,EAAiD;AAC9D,IAAA,MAAM,WAAW,MAAM,IAAA,CAAK,WAAA,CAAY,UAAA,EAAY,QAAQ,MAAM,CAAA;AAClE,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA,EAEA,MAAM,gBAAA,GAAgD;AACpD,IAAA,OAAO,EAAC;AAAA,EACV;AAAA,EAEA,MAAM,UAAA,GAAwC;AAC5C,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,WAAA,CAAY,UAAU,KAAK,CAAA;AACvD,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA,EAEA,MAAM,aAAa,MAAA,EAAyD;AAC1E,IAAA,MAAM,WAAW,MAAM,IAAA,CAAK,WAAA,CAAY,eAAA,EAAiB,QAAQ,MAAM,CAAA;AACvE,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA,EAEA,MAAM,kBAAkB,MAAA,EAAmE;AACzF,IAAA,MAAM,WAAW,MAAM,IAAA,CAAK,WAAA,CAAY,aAAA,EAAe,QAAQ,MAAM,CAAA;AACrE,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AACF;;;AC9EO,IAAM,kBAAN,MAA6C;AAAA,EACjC,KAAA;AAAA,EACA,IAAA;AAAA,EAEjB,WAAA,CAAY,OAAe,IAAA,EAAuB;AAChD,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACd;AAAA,EAEA,MAAM,SAAS,MAAA,EAAiD;AAC9D,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,IAAA,CAAK,UAAA,EAAW;AAC3C,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,IAAA,CAAK,cAAA,EAAe;AACzC,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,OAAO,CAAA,aAAA,EAAgB,KAAK,KAAK,CAAA,cAAA,CAAA;AAEhD,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,MAChC,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,kBAAA;AAAA,QAChB,eAAA,EAAiB,UAAU,OAAO,CAAA;AAAA,OACpC;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,MAAM;AAAA,KAC5B,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,SAAA,GAAY,MAAM,QAAA,CAAS,IAAA,EAAK;AACtC,MAAA,IAAI,YAAA,GAAe,CAAA,yBAAA,EAA4B,QAAA,CAAS,MAAM,CAAA,CAAA,CAAA;AAC9D,MAAA,IAAI;AACF,QAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,SAAS,CAAA;AACtC,QAAA,YAAA,GAAe,SAAA,CAAU,KAAA,IAAS,SAAA,CAAU,OAAA,IAAW,YAAA;AAAA,MACzD,CAAA,CAAA,MAAQ;AACN,QAAA,IAAI,WAAW,YAAA,GAAe,SAAA;AAAA,MAChC;AACA,MAAA,MAAM,IAAI,MAAM,YAAY,CAAA;AAAA,IAC9B;AAEA,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA,EAEA,MAAM,gBAAA,GAAgD;AACpD,IAAA,OAAO,EAAC;AAAA,EACV;AAAA,EAEA,MAAM,OAAO,KAAA,EAA8B;AACzC,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,IAAA,CAAK,UAAA,EAAW;AAC3C,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,IAAA,CAAK,cAAA,EAAe;AACzC,IAAA,MAAM,MAAM,CAAA,EAAG,OAAO,YAAY,IAAA,CAAK,KAAK,IAAI,KAAK,CAAA,OAAA,CAAA;AAErD,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,MAChC,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,kBAAA;AAAA,QAChB,eAAA,EAAiB,UAAU,OAAO,CAAA;AAAA;AACpC,KACD,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,SAAA,GAAY,MAAM,QAAA,CAAS,IAAA,EAAK;AACtC,MAAA,IAAI,YAAA,GAAe,CAAA,yBAAA,EAA4B,QAAA,CAAS,MAAM,CAAA,CAAA,CAAA;AAC9D,MAAA,IAAI;AACF,QAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,SAAS,CAAA;AACtC,QAAA,YAAA,GAAe,SAAA,CAAU,KAAA,IAAS,SAAA,CAAU,OAAA,IAAW,YAAA;AAAA,MACzD,CAAA,CAAA,MAAQ;AACN,QAAA,IAAI,WAAW,YAAA,GAAe,SAAA;AAAA,MAChC;AACA,MAAA,MAAM,IAAI,MAAM,YAAY,CAAA;AAAA,IAC9B;AAAA,EACF;AAAA,EAEA,aAAa,SAAA,EAAkF;AAC7F,IAAA,OAAO,EAAE,aAAa,MAAM;AAAA,IAAC,CAAA,EAAE;AAAA,EACjC;AACF;;;ACxEO,IAAM,mBAAN,MAA+C;AAAA,EACnC,KAAA;AAAA,EACA,IAAA;AAAA,EAEjB,WAAA,CAAY,OAAe,IAAA,EAAuB;AAChD,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACd;AAAA,EAEA,MAAM,SAAS,MAAA,EAAmD;AAChE,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,IAAA,CAAK,UAAA,EAAW;AAC3C,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,IAAA,CAAK,cAAA,EAAe;AACzC,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,OAAO,CAAA,cAAA,EAAiB,KAAK,KAAK,CAAA,SAAA,CAAA;AAEjD,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,MAChC,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,kBAAA;AAAA,QAChB,eAAA,EAAiB,UAAU,OAAO,CAAA;AAAA,OACpC;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,MAAM;AAAA,KAC5B,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,SAAA,GAAY,MAAM,QAAA,CAAS,IAAA,EAAK;AACtC,MAAA,IAAI,YAAA,GAAe,CAAA,0BAAA,EAA6B,QAAA,CAAS,MAAM,CAAA,CAAA,CAAA;AAC/D,MAAA,IAAI;AACF,QAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,SAAS,CAAA;AACtC,QAAA,YAAA,GAAe,SAAA,CAAU,KAAA,IAAS,SAAA,CAAU,OAAA,IAAW,YAAA;AAAA,MACzD,CAAA,CAAA,MAAQ;AACN,QAAA,IAAI,WAAW,YAAA,GAAe,SAAA;AAAA,MAChC;AACA,MAAA,MAAM,IAAI,MAAM,YAAY,CAAA;AAAA,IAC9B;AAEA,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA,EAEA,MAAM,QAAQ,MAAA,EAA2D;AACvE,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,IAAA,CAAK,UAAA,EAAW;AAC3C,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,IAAA,CAAK,cAAA,EAAe;AACzC,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,OAAO,CAAA,cAAA,EAAiB,KAAK,KAAK,CAAA,QAAA,CAAA;AAEjD,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,MAChC,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,kBAAA;AAAA,QAChB,eAAA,EAAiB,UAAU,OAAO,CAAA;AAAA,OACpC;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,MAAM;AAAA,KAC5B,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,SAAA,GAAY,MAAM,QAAA,CAAS,IAAA,EAAK;AACtC,MAAA,IAAI,YAAA,GAAe,CAAA,yBAAA,EAA4B,QAAA,CAAS,MAAM,CAAA,CAAA,CAAA;AAC9D,MAAA,IAAI;AACF,QAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,SAAS,CAAA;AACtC,QAAA,YAAA,GAAe,SAAA,CAAU,KAAA,IAAS,SAAA,CAAU,OAAA,IAAW,YAAA;AAAA,MACzD,CAAA,CAAA,MAAQ;AACN,QAAA,IAAI,WAAW,YAAA,GAAe,SAAA;AAAA,MAChC;AACA,MAAA,MAAM,IAAI,MAAM,YAAY,CAAA;AAAA,IAC9B;AAEA,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA,EAEA,MAAM,gBAAA,GAAiD;AACrD,IAAA,OAAO,EAAC;AAAA,EACV;AACF;;;ACzDO,IAAM,mBAAN,MAA+C;AAAA,EACnC,KAAA;AAAA,EACA,IAAA;AAAA,EAEjB,WAAA,CAAY,OAAe,IAAA,EAAuB;AAChD,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACd;AAAA,EAEA,MAAM,SAAS,MAAA,EAAmD;AAChE,IAAA,OAAO,IAAA,CAAK,IAAA,CAAsB,eAAA,EAAiB,MAAM,CAAA;AAAA,EAC3D;AAAA,EAEA,MAAM,OAAO,MAAA,EAA6C;AACxD,IAAA,OAAO,IAAA,CAAK,IAAA,CAAmB,aAAA,EAAe,MAAM,CAAA;AAAA,EACtD;AAAA,EAEA,MAAM,IAAI,MAAA,EAAuC;AAC/C,IAAA,OAAO,IAAA,CAAK,IAAA,CAAgB,UAAA,EAAY,MAAM,CAAA;AAAA,EAChD;AAAA,EAEA,MAAM,QAAQ,MAAA,EAA+C;AAC3D,IAAA,OAAO,IAAA,CAAK,IAAA,CAAoB,cAAA,EAAgB,MAAM,CAAA;AAAA,EACxD;AAAA,EAEA,MAAM,gBAAA,GAAiD;AACrD,IAAA,OAAO,EAAC;AAAA,EACV;AAAA,EAEA,MAAc,IAAA,CAAQ,QAAA,EAAkB,IAAA,EAA2B;AACjE,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,IAAA,CAAK,UAAA,EAAW;AAC3C,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,IAAA,CAAK,cAAA,EAAe;AACzC,IAAA,MAAM,MAAM,CAAA,EAAG,OAAO,iBAAiB,IAAA,CAAK,KAAK,IAAI,QAAQ,CAAA,CAAA;AAE7D,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,MAChC,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,kBAAA;AAAA,QAChB,eAAA,EAAiB,UAAU,OAAO,CAAA;AAAA,OACpC;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,IAAI;AAAA,KAC1B,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,SAAA,GAAY,MAAM,QAAA,CAAS,IAAA,EAAK;AACtC,MAAA,IAAI,YAAA,GAAe,CAAA,sBAAA,EAAyB,QAAA,CAAS,MAAM,CAAA,CAAA,CAAA;AAC3D,MAAA,IAAI,SAAA,GAAY,SAAA;AAChB,MAAA,IAAI,MAAA;AACJ,MAAA,IAAI;AACF,QAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,SAAS,CAAA;AACtC,QAAA,YAAA,GAAgB,SAAA,CAAU,KAAA,IAAS,SAAA,CAAU,OAAA,IAAW,YAAA;AACxD,QAAA,IAAI,OAAO,SAAA,CAAU,IAAA,KAAS,QAAA,cAAsB,SAAA,CAAU,IAAA;AAC9D,QAAA,IAAI,OAAO,SAAA,CAAU,MAAA,KAAW,QAAA,WAAmB,SAAA,CAAU,MAAA;AAAA,MAC/D,CAAA,CAAA,MAAQ;AACN,QAAA,IAAI,WAAW,YAAA,GAAe,SAAA;AAAA,MAChC;AACA,MAAA,MAAM,IAAI,cAAA,CAAe,SAAA,EAAW,YAAA,EAAc,QAAA,CAAS,QAAQ,MAAM,CAAA;AAAA,IAC3E;AAEA,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AACF;;;ACzEA,SAAS,SAAS,KAAA,EAAyB;AACzC,EAAA,IAAI,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,EAAU;AACtC,IAAA,MAAM,CAAA,GAAI,KAAA;AAIV,IAAA,IAAI,OAAO,CAAA,CAAE,QAAA,KAAa,UAAA,EAAY;AACpC,MAAA,IAAI;AACF,QAAA,OAAQ,EAAE,QAAA,EAA0B;AAAA,MACtC,CAAA,CAAA,MAAQ;AACN,QAAA,OAAO,KAAA;AAAA,MACT;AAAA,IACF;AACA,IAAA,MAAM,OAAA,GAAW,CAAA,CAAE,OAAA,IAAW,CAAA,CAAE,QAAA;AAChC,IAAA,MAAM,KAAA,GAAS,CAAA,CAAE,WAAA,IAAe,CAAA,CAAE,YAAA;AAClC,IAAA,IAAI,OAAO,OAAA,KAAY,QAAA,IAAY,OAAO,UAAU,QAAA,EAAU;AAC5D,MAAA,OAAO,OAAA,GAAU,GAAA,GAAO,IAAA,CAAK,KAAA,CAAM,QAAQ,GAAS,CAAA;AAAA,IACtD;AAAA,EACF;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,eAAe,KAAA,EAAyB;AAC/C,EAAA,IAAI,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,UAAU,OAAO,KAAA;AAChD,EAAA,MAAM,CAAA,GAAI,KAAA;AACV,EAAA,OAAO,EAAE,GAAG,CAAA,EAAG,WAAA,EAAa,QAAA,CAAS,CAAA,CAAE,WAAW,CAAA,EAAG,SAAA,EAAW,QAAA,CAAS,CAAA,CAAE,SAAS,CAAA,EAAE;AACxF;AAEO,SAAS,wBAA2B,OAAA,EAAe;AACxD,EAAA,IAAI,CAAC,OAAA,IAAW,OAAO,OAAA,KAAY,UAAU,OAAO,OAAA;AACpD,EAAA,MAAM,CAAA,GAAI,OAAA;AACV,EAAA,MAAM,MAAA,GAAkC,EAAE,GAAG,CAAA,EAAE;AAC/C,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,CAAA,CAAE,OAAO,CAAA,SAAU,OAAA,GAAU,CAAA,CAAE,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA;AAC3E,EAAA,IAAI,CAAA,CAAE,OAAA,IAAW,OAAO,CAAA,CAAE,YAAY,QAAA,EAAU;AAC9C,IAAA,MAAM,IAAI,CAAA,CAAE,OAAA;AACZ,IAAA,MAAA,CAAO,OAAA,GAAU;AAAA,MACf,GAAG,CAAA;AAAA,MACH,UAAA,EAAY,KAAA,CAAM,OAAA,CAAQ,CAAA,CAAE,UAAU,CAAA,GAAI,CAAA,CAAE,UAAA,CAAW,GAAA,CAAI,cAAc,CAAA,GAAI,CAAA,CAAE,UAAA;AAAA,MAC/E,YAAA,EAAc,KAAA,CAAM,OAAA,CAAQ,CAAA,CAAE,YAAY,CAAA,GAAI,CAAA,CAAE,YAAA,CAAa,GAAA,CAAI,cAAc,CAAA,GAAI,CAAA,CAAE,YAAA;AAAA,MACrF,aAAa,CAAA,CAAE,WAAA,GAAc,eAAe,CAAA,CAAE,WAAW,IAAI,CAAA,CAAE,WAAA;AAAA,MAC/D,WAAA,EAAa,KAAA,CAAM,OAAA,CAAQ,CAAA,CAAE,WAAW,CAAA,GAAI,CAAA,CAAE,WAAA,CAAY,GAAA,CAAI,cAAc,CAAA,GAAI,CAAA,CAAE;AAAA,KACpF;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;;;ACzBO,IAAM,qBAAN,MAAmD;AAAA,EACvC,KAAA;AAAA,EACA,UAAA;AAAA,EAEjB,WAAA,CACE,OACA,OAAA,EAGA;AACA,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AACb,IAAA,IAAA,CAAK,aAAa,OAAA,CAAQ,UAAA;AAAA,EAC5B;AAAA,EAEA,MAAM,iBAAiB,IAAA,EAAoC;AACzD,IAAA,OAAO,IAAA,CAAK,WAAuB,qBAAA,EAAuB;AAAA,MACxD,OAAO,IAAA,CAAK,KAAA;AAAA,MACZ,MAAM,IAAA,IAAQ;AAAA,KACf,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,YAAY,MAAA,EAAuD;AACvE,IAAA,OAAO,IAAA,CAAK,WAA8B,gBAAA,EAAkB;AAAA,MAC1D,OAAO,IAAA,CAAK,KAAA;AAAA,MACZ,OAAO,MAAA,CAAO,KAAA;AAAA,MACd,OAAO,MAAA,CAAO,KAAA;AAAA,MACd,UAAU,MAAA,CAAO,QAAA;AAAA,MACjB,IAAA,EAAM,OAAO,IAAA,IAAQ,SAAA;AAAA,MACrB,QAAQ,MAAA,CAAO,MAAA;AAAA,MACf,WAAW,MAAA,CAAO,SAAA;AAAA,MAClB,UAAU,MAAA,CAAO,QAAA;AAAA;AAAA;AAAA,MAGjB,MAAM,MAAA,CAAO;AAAA,KACd,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,eAAe,OAAA,EAA+D;AAClF,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,UAAA,CAAgC,mBAAA,EAAqB;AAAA,MAC1E,OAAO,IAAA,CAAK,KAAA;AAAA,MACZ,IAAA,EAAM,SAAS,IAAA,IAAQ,SAAA;AAAA,MACvB,MAAA,EAAQ,SAAS,MAAA,IAAU,SAAA;AAAA,MAC3B,YAAY,OAAA,EAAS,UAAA;AAAA,MACrB,QAAQ,OAAA,EAAS,MAAA;AAAA,MACjB,OAAO,OAAA,EAAS,KAAA;AAAA,MAChB,OAAA,EAAS,SAAS,OAAA,IAAW,UAAA;AAAA,MAC7B,UAAU,OAAA,EAAS,QAAA;AAAA,MACnB,cAAc,OAAA,EAAS,YAAA;AAAA,MACvB,eAAe,OAAA,EAAS;AAAA,KACzB,CAAA;AACD,IAAA,OAAO,wBAAwB,GAAG,CAAA;AAAA,EACpC;AAAA,EAEA,MAAM,UAAU,OAAA,EAAwD;AACtE,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,UAAA,CAA6B,cAAA,EAAgB;AAAA,MAClE,OAAO,IAAA,CAAK,KAAA;AAAA,MACZ,IAAA,EAAM,SAAS,IAAA,IAAQ,SAAA;AAAA,MACvB,MAAA,EAAQ,SAAS,MAAA,IAAU,SAAA;AAAA,MAC3B,YAAY,OAAA,EAAS;AAAA,KACtB,CAAA;AACD,IAAA,OAAO,wBAAwB,GAAG,CAAA;AAAA,EACpC;AAAA,EAEA,MAAM,gBAAgB,OAAA,EAAiE;AACrF,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,UAAA,CAAiC,oBAAA,EAAsB;AAAA,MAC5E,OAAO,IAAA,CAAK,KAAA;AAAA,MACZ,IAAA,EAAM,SAAS,IAAA,IAAQ,SAAA;AAAA,MACvB,MAAA,EAAQ,SAAS,MAAA,IAAU,SAAA;AAAA,MAC3B,YAAY,OAAA,EAAS,UAAA;AAAA,MACrB,UAAU,OAAA,EAAS,QAAA;AAAA,MACnB,cAAc,OAAA,EAAS,YAAA;AAAA,MACvB,eAAe,OAAA,EAAS;AAAA,KACzB,CAAA;AACD,IAAA,OAAO,wBAAwB,GAAG,CAAA;AAAA,EACpC;AACF","file":"chunk-57DREBKB.js","sourcesContent":["// Host-facing HTTP implementation of ImageGenApi. Firebase-free: auth + base URL\n// come from the injected BackendHttpDeps, so any host (PlaygroundHost, Telegram/Steam\n// shells) can construct it. Do NOT import from barrel exports (imageGen/index.ts).\n\nimport { ImageGenApi, ImageGenParams, ImageGenResult, ImageGenJobEvent, DepthEstimationParams, DepthEstimationResult, RemoveBackgroundParams, RemoveBackgroundResult, UpscaleImageParams, UpscaleImageResult } from './ImageGenApi';\nimport type { BackendHttpDeps } from '../http/backendHttpDeps';\n\nexport class HttpImageGenApi implements ImageGenApi {\n private readonly appId: string;\n private readonly deps: BackendHttpDeps;\n\n constructor(appId: string, deps: BackendHttpDeps) {\n this.appId = appId;\n this.deps = deps;\n }\n\n private async authedPost<T>(path: string, body: Record<string, unknown>): Promise<T> {\n const idToken = await this.deps.getIdToken();\n const baseUrl = this.deps.getCloudRunUrl();\n const url = `${baseUrl}/v1/imagegen/${this.appId}/${path}`;\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${idToken}`,\n 'x-consumer': 'sdk',\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage = `Request failed (${response.status})`;\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.error || errorJson.message || errorMessage;\n } catch {\n if (errorText) errorMessage = errorText;\n }\n throw new Error(errorMessage);\n }\n\n return response.json();\n }\n\n async generate(params: ImageGenParams): Promise<ImageGenResult> {\n return this.authedPost<ImageGenResult>('generate', params as unknown as Record<string, unknown>);\n }\n\n async estimateDepth(params: DepthEstimationParams): Promise<DepthEstimationResult> {\n return this.authedPost<DepthEstimationResult>('estimate-depth', params as unknown as Record<string, unknown>);\n }\n\n async removeBackground(params: RemoveBackgroundParams): Promise<RemoveBackgroundResult> {\n return this.authedPost<RemoveBackgroundResult>('remove-background', params as unknown as Record<string, unknown>);\n }\n\n async upscaleImage(params: UpscaleImageParams): Promise<UpscaleImageResult> {\n return this.authedPost<UpscaleImageResult>('upscale-image', params as unknown as Record<string, unknown>);\n }\n\n async getCompletedJobs(): Promise<ImageGenJobEvent[]> {\n return [];\n }\n}\n","// Host-facing HTTP implementation of AudioGenApi. Firebase-free: auth + base URL\n// come from the injected BackendHttpDeps. Do NOT import from barrel exports\n// (audioGen/index.ts).\n\nimport {\n AudioGenApi,\n AudioGenParams,\n AudioGenResult,\n AudioGenJobEvent,\n ListVoicesResult,\n DesignVoicesParams,\n DesignVoicesResult,\n SaveDesignedVoiceParams,\n SaveDesignedVoiceResult,\n} from './AudioGenApi';\nimport { RundotApiError, RateLimitedError } from '../errors';\nimport type { BackendHttpDeps } from '../http/backendHttpDeps';\n\nexport class HttpAudioGenApi implements AudioGenApi {\n private readonly appId: string;\n private readonly deps: BackendHttpDeps;\n\n constructor(appId: string, deps: BackendHttpDeps) {\n this.appId = appId;\n this.deps = deps;\n }\n\n private async authedFetch(path: string, method: string, body?: unknown): Promise<Response> {\n const idToken = await this.deps.getIdToken();\n const baseUrl = this.deps.getCloudRunUrl();\n const url = `${baseUrl}/v1/audiogen/${this.appId}/${path}`;\n\n const response = await fetch(url, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${idToken}`,\n },\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n });\n\n if (!response.ok) {\n if (response.status === 429) {\n const retryAfterSec = parseInt(response.headers.get('Retry-After') ?? '60', 10);\n throw new RateLimitedError(retryAfterSec * 1000);\n }\n const errorText = await response.text();\n let errorMessage = `Audio generation failed (${response.status})`;\n let errorCode = 'UNKNOWN';\n try {\n const errorJson = JSON.parse(errorText) as Record<string, unknown>;\n errorMessage = (errorJson.error ?? errorJson.message ?? errorMessage) as string;\n if (typeof errorJson.code === 'string') errorCode = errorJson.code;\n } catch {\n if (errorText) errorMessage = errorText;\n }\n throw new RundotApiError(errorCode, errorMessage, response.status);\n }\n\n return response;\n }\n\n async generate(params: AudioGenParams): Promise<AudioGenResult> {\n const response = await this.authedFetch('generate', 'POST', params);\n return response.json();\n }\n\n async getCompletedJobs(): Promise<AudioGenJobEvent[]> {\n return [];\n }\n\n async listVoices(): Promise<ListVoicesResult> {\n const response = await this.authedFetch('voices', 'GET');\n return response.json();\n }\n\n async designVoices(params: DesignVoicesParams): Promise<DesignVoicesResult> {\n const response = await this.authedFetch('voices/design', 'POST', params);\n return response.json();\n }\n\n async saveDesignedVoice(params: SaveDesignedVoiceParams): Promise<SaveDesignedVoiceResult> {\n const response = await this.authedFetch('voices/save', 'POST', params);\n return response.json();\n }\n}\n","// Host-facing HTTP implementation of VideoGenApi. Firebase-free: auth + base URL\n// come from the injected BackendHttpDeps. Do NOT import from barrel exports\n// (videoGen/index.ts).\n\nimport { VideoGenApi, VideoGenParams, VideoGenResult, VideoGenJobEvent, VideoGenJobStartedEvent } from './VideoGenApi'\nimport type { BackendHttpDeps } from '../http/backendHttpDeps'\n\nexport class HttpVideoGenApi implements VideoGenApi {\n private readonly appId: string\n private readonly deps: BackendHttpDeps\n\n constructor(appId: string, deps: BackendHttpDeps) {\n this.appId = appId\n this.deps = deps\n }\n\n async generate(params: VideoGenParams): Promise<VideoGenResult> {\n const idToken = await this.deps.getIdToken()\n const baseUrl = this.deps.getCloudRunUrl()\n const url = `${baseUrl}/v1/videogen/${this.appId}/sync-generate`\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${idToken}`,\n },\n body: JSON.stringify(params),\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n let errorMessage = `Video generation failed (${response.status})`\n try {\n const errorJson = JSON.parse(errorText)\n errorMessage = errorJson.error || errorJson.message || errorMessage\n } catch {\n if (errorText) errorMessage = errorText\n }\n throw new Error(errorMessage)\n }\n\n return response.json()\n }\n\n async getCompletedJobs(): Promise<VideoGenJobEvent[]> {\n return []\n }\n\n async cancel(jobId: string): Promise<void> {\n const idToken = await this.deps.getIdToken()\n const baseUrl = this.deps.getCloudRunUrl()\n const url = `${baseUrl}/v1/jobs/${this.appId}/${jobId}/cancel`\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${idToken}`,\n },\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n let errorMessage = `Job cancellation failed (${response.status})`\n try {\n const errorJson = JSON.parse(errorText)\n errorMessage = errorJson.error || errorJson.message || errorMessage\n } catch {\n if (errorText) errorMessage = errorText\n }\n throw new Error(errorMessage)\n }\n }\n\n onJobStarted(_callback: (event: VideoGenJobStartedEvent) => void): { unsubscribe: () => void } {\n return { unsubscribe: () => {} }\n }\n}\n","// Host-facing HTTP implementation of SpriteGenApi. Firebase-free: auth + base URL\n// come from the injected BackendHttpDeps.\n\nimport { SpriteGenApi, SpriteGenParams, SpriteGenResult, AnimateSpriteParams, AnimateSpriteResult, SpriteGenJobEvent } from './SpriteGenApi';\nimport type { BackendHttpDeps } from '../http/backendHttpDeps';\n\nexport class HttpSpriteGenApi implements SpriteGenApi {\n private readonly appId: string;\n private readonly deps: BackendHttpDeps;\n\n constructor(appId: string, deps: BackendHttpDeps) {\n this.appId = appId;\n this.deps = deps;\n }\n\n async generate(params: SpriteGenParams): Promise<SpriteGenResult> {\n const idToken = await this.deps.getIdToken();\n const baseUrl = this.deps.getCloudRunUrl();\n const url = `${baseUrl}/v1/spritegen/${this.appId}/generate`;\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${idToken}`,\n },\n body: JSON.stringify(params),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage = `Sprite generation failed (${response.status})`;\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.error || errorJson.message || errorMessage;\n } catch {\n if (errorText) errorMessage = errorText;\n }\n throw new Error(errorMessage);\n }\n\n return response.json();\n }\n\n async animate(params: AnimateSpriteParams): Promise<AnimateSpriteResult> {\n const idToken = await this.deps.getIdToken();\n const baseUrl = this.deps.getCloudRunUrl();\n const url = `${baseUrl}/v1/spritegen/${this.appId}/animate`;\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${idToken}`,\n },\n body: JSON.stringify(params),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage = `Sprite animation failed (${response.status})`;\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.error || errorJson.message || errorMessage;\n } catch {\n if (errorText) errorMessage = errorText;\n }\n throw new Error(errorMessage);\n }\n\n return response.json();\n }\n\n async getCompletedJobs(): Promise<SpriteGenJobEvent[]> {\n return [];\n }\n}\n","// Host-facing HTTP implementation of ThreeDGenApi. Firebase-free: auth + base URL\n// come from the injected BackendHttpDeps. Do NOT import from barrel exports\n// (threeDGen/index.ts).\n\nimport {\n ThreeDGenApi,\n ThreeDGenParams,\n ThreeDGenResult,\n RemeshParams,\n RemeshResult,\n RigParams,\n RigResult,\n AnimateParams,\n AnimateResult,\n ThreeDGenJobEvent,\n} from './ThreeDGenApi'\nimport { RundotApiError } from '../errors'\nimport type { BackendHttpDeps } from '../http/backendHttpDeps'\n\nexport class HttpThreeDGenApi implements ThreeDGenApi {\n private readonly appId: string\n private readonly deps: BackendHttpDeps\n\n constructor(appId: string, deps: BackendHttpDeps) {\n this.appId = appId\n this.deps = deps\n }\n\n async generate(params: ThreeDGenParams): Promise<ThreeDGenResult> {\n return this.post<ThreeDGenResult>('sync-generate', params)\n }\n\n async remesh(params: RemeshParams): Promise<RemeshResult> {\n return this.post<RemeshResult>('sync-remesh', params)\n }\n\n async rig(params: RigParams): Promise<RigResult> {\n return this.post<RigResult>('sync-rig', params)\n }\n\n async animate(params: AnimateParams): Promise<AnimateResult> {\n return this.post<AnimateResult>('sync-animate', params)\n }\n\n async getCompletedJobs(): Promise<ThreeDGenJobEvent[]> {\n return []\n }\n\n private async post<T>(endpoint: string, body: unknown): Promise<T> {\n const idToken = await this.deps.getIdToken()\n const baseUrl = this.deps.getCloudRunUrl()\n const url = `${baseUrl}/v1/threedgen/${this.appId}/${endpoint}`\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${idToken}`,\n },\n body: JSON.stringify(body),\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n let errorMessage = `3D generation failed (${response.status})`\n let errorCode = 'UNKNOWN'\n let detail: string | undefined\n try {\n const errorJson = JSON.parse(errorText) as Record<string, unknown>\n errorMessage = (errorJson.error ?? errorJson.message ?? errorMessage) as string\n if (typeof errorJson.code === 'string') errorCode = errorJson.code\n if (typeof errorJson.detail === 'string') detail = errorJson.detail\n } catch {\n if (errorText) errorMessage = errorText\n }\n throw new RundotApiError(errorCode, errorMessage, response.status, detail)\n }\n\n return response.json()\n }\n}\n","/**\n * Idempotently convert Firestore-serialized timestamps to epoch millis on\n * leaderboard score responses. Leaderboard endpoints serialize Firestore\n * Timestamps as `{ seconds, nanoseconds }` (or `{ _seconds, _nanoseconds }`),\n * but `LeaderboardEntry` declares `submittedAt`/`expiresAt` as epoch millis.\n * Already-millis values pass through unchanged.\n */\nfunction toMillis(value: unknown): unknown {\n if (value && typeof value === 'object') {\n const v = value as Record<string, unknown>\n // Firestore Timestamp instance (defensive — survives only in-process, not\n // over HTTP/JSON, but keeps parity with the RN host's normalizer so this can\n // be the single source of truth when that migrates).\n if (typeof v.toMillis === 'function') {\n try {\n return (v.toMillis as () => number)()\n } catch {\n return value\n }\n }\n const seconds = (v.seconds ?? v._seconds) as number | undefined\n const nanos = (v.nanoseconds ?? v._nanoseconds) as number | undefined\n if (typeof seconds === 'number' && typeof nanos === 'number') {\n return seconds * 1000 + Math.floor(nanos / 1_000_000)\n }\n }\n return value\n}\n\nfunction normalizeEntry(entry: unknown): unknown {\n if (!entry || typeof entry !== 'object') return entry\n const e = entry as Record<string, unknown>\n return { ...e, submittedAt: toMillis(e.submittedAt), expiresAt: toMillis(e.expiresAt) }\n}\n\nexport function normalizeScoresResponse<T>(payload: T): T {\n if (!payload || typeof payload !== 'object') return payload\n const p = payload as Record<string, unknown>\n const result: Record<string, unknown> = { ...p }\n if (Array.isArray(p.entries)) result.entries = p.entries.map(normalizeEntry)\n if (p.context && typeof p.context === 'object') {\n const c = p.context as Record<string, unknown>\n result.context = {\n ...c,\n topEntries: Array.isArray(c.topEntries) ? c.topEntries.map(normalizeEntry) : c.topEntries,\n beforePlayer: Array.isArray(c.beforePlayer) ? c.beforePlayer.map(normalizeEntry) : c.beforePlayer,\n playerEntry: c.playerEntry ? normalizeEntry(c.playerEntry) : c.playerEntry,\n afterPlayer: Array.isArray(c.afterPlayer) ? c.afterPlayer.map(normalizeEntry) : c.afterPlayer,\n }\n }\n return result as T\n}\n","/**\n * HTTP-backed {@link LeaderboardApi} implementation usable by any host.\n *\n * Firebase-free: the caller injects `callRemote` (PlaygroundHost passes\n * `callRemoteFunction`; platform shells pass their own authenticated invoker),\n * so importing this file does NOT pull firebase into a host bundle. Do NOT\n * import from barrel exports (leaderboard/index.ts).\n */\nimport {\n LeaderboardApi,\n ScoreToken,\n SubmitScoreParams,\n SubmitScoreResult,\n GetPagedScoresOptions,\n PagedScoresResponse,\n PlayerRankOptions,\n PlayerRankResult,\n GetPodiumScoresOptions,\n PodiumScoresResponse,\n} from './LeaderboardApi'\nimport type { RemoteFunctionInvoker } from '../http/callRemoteFunction'\nimport { normalizeScoresResponse } from './normalizeScores'\n\n/**\n * HTTP-based implementation of LeaderboardApi.\n */\nexport class HttpLeaderboardApi implements LeaderboardApi {\n private readonly appId: string\n private readonly callRemote: RemoteFunctionInvoker\n\n constructor(\n appId: string,\n options: {\n callRemote: RemoteFunctionInvoker\n },\n ) {\n this.appId = appId\n this.callRemote = options.callRemote\n }\n\n async createScoreToken(mode?: string): Promise<ScoreToken> {\n return this.callRemote<ScoreToken>('apiCreateScoreToken', {\n appId: this.appId,\n mode: mode || 'default',\n })\n }\n\n async submitScore(params: SubmitScoreParams): Promise<SubmitScoreResult> {\n return this.callRemote<SubmitScoreResult>('apiSubmitScore', {\n appId: this.appId,\n token: params.token,\n score: params.score,\n duration: params.duration,\n mode: params.mode || 'default',\n period: params.period,\n telemetry: params.telemetry,\n metadata: params.metadata,\n // Score-sealing hash auto-computed by RpcLeaderboardApi; without it sealed\n // leaderboards reject the score.\n hash: params.hash,\n })\n }\n\n async getPagedScores(options?: GetPagedScoresOptions): Promise<PagedScoresResponse> {\n const res = await this.callRemote<PagedScoresResponse>('apiGetPagedScores', {\n appId: this.appId,\n mode: options?.mode || 'default',\n period: options?.period || 'alltime',\n periodDate: options?.periodDate,\n cursor: options?.cursor,\n limit: options?.limit,\n variant: options?.variant || 'standard',\n topCount: options?.topCount,\n contextAhead: options?.contextAhead,\n contextBehind: options?.contextBehind,\n })\n return normalizeScoresResponse(res)\n }\n\n async getMyRank(options?: PlayerRankOptions): Promise<PlayerRankResult> {\n const res = await this.callRemote<PlayerRankResult>('apiGetMyRank', {\n appId: this.appId,\n mode: options?.mode || 'default',\n period: options?.period || 'alltime',\n periodDate: options?.periodDate,\n })\n return normalizeScoresResponse(res)\n }\n\n async getPodiumScores(options?: GetPodiumScoresOptions): Promise<PodiumScoresResponse> {\n const res = await this.callRemote<PodiumScoresResponse>('apiGetPodiumScores', {\n appId: this.appId,\n mode: options?.mode || 'default',\n period: options?.period || 'alltime',\n periodDate: options?.periodDate,\n topCount: options?.topCount,\n contextAhead: options?.contextAhead,\n contextBehind: options?.contextBehind,\n })\n return normalizeScoresResponse(res)\n }\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/
|
|
1
|
+
// src/playground/tabCoordinator.ts
|
|
2
2
|
var REGISTRY_KEY = "rundot-playground-tabs";
|
|
3
3
|
var TAB_ID_KEY = "rundot-playground-tab-id";
|
|
4
4
|
var STALE_THRESHOLD_MS = 3e4;
|
|
@@ -150,5 +150,5 @@ function startHeartbeat(tabId) {
|
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
export { PLAYER_POOL, clearRegistry, getOrAssignSlot, isGoogleSignedIn, onGoogleSignedIn, onGoogleSignedOut, setGoogleSignedIn, setPlayerId, startHeartbeat };
|
|
153
|
-
//# sourceMappingURL=chunk-
|
|
154
|
-
//# sourceMappingURL=chunk-
|
|
153
|
+
//# sourceMappingURL=chunk-LKE6IJ4M.js.map
|
|
154
|
+
//# sourceMappingURL=chunk-LKE6IJ4M.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/playground/tabCoordinator.ts"],"names":[],"mappings":"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","file":"chunk-LKE6IJ4M.js","sourcesContent":["/**\n * Cross-tab slot coordinator for playground mode.\n *\n * Uses localStorage + `storage` events to assign each browser tab a unique slot:\n * Slot 0 = primary tab (Google sign-in)\n * Slot 1+ = secondary tabs (synthetic \"Player N\" profiles)\n * Slot -1 = waiting for primary tab to complete Google sign-in\n *\n * Tab identity is stored in sessionStorage (survives reload, unique per tab).\n * Stale tabs are pruned via a heartbeat mechanism (every 10 s, stale after 30 s).\n */\n\nconst REGISTRY_KEY = 'rundot-playground-tabs'\nconst TAB_ID_KEY = 'rundot-playground-tab-id'\nconst STALE_THRESHOLD_MS = 30_000\nconst HEARTBEAT_INTERVAL_MS = 10_000\n\nexport interface TabRegistry {\n tabs: Record<string, { slot: number; playerId: string | null; timestamp: number }>\n googleSignedIn: boolean\n}\n\nexport const PLAYER_POOL: Array<string | null> = [null, 'player1', 'player2', 'player3']\n\n// ─── Tab ID ─────────────────────────────────────────────────────────────────\n\nfunction getOrCreateTabId(): string {\n try {\n let id = sessionStorage.getItem(TAB_ID_KEY)\n if (id) return id\n id = crypto.randomUUID()\n sessionStorage.setItem(TAB_ID_KEY, id)\n return id\n } catch {\n // Fallback if sessionStorage is unavailable\n return crypto.randomUUID()\n }\n}\n\n// ─── Registry helpers ───────────────────────────────────────────────────────\n\nfunction readRegistry(): TabRegistry {\n try {\n const raw = localStorage.getItem(REGISTRY_KEY)\n if (raw) {\n const parsed = JSON.parse(raw) as TabRegistry\n if (parsed && typeof parsed.tabs === 'object') return parsed\n }\n } catch {\n // corrupt or missing — return default\n }\n return { tabs: {}, googleSignedIn: false }\n}\n\nfunction writeRegistry(registry: TabRegistry): void {\n try {\n localStorage.setItem(REGISTRY_KEY, JSON.stringify(registry))\n } catch {\n // ignore\n }\n}\n\nfunction pruneStale(registry: TabRegistry): void {\n const now = Date.now()\n for (const [tabId, entry] of Object.entries(registry.tabs)) {\n if (now - entry.timestamp > STALE_THRESHOLD_MS) {\n delete registry.tabs[tabId]\n }\n }\n}\n\nfunction claimedSlots(registry: TabRegistry): Set<number> {\n return new Set(Object.values(registry.tabs).map((e) => e.slot))\n}\n\nfunction lowestAvailableSlot(claimed: Set<number>, startFrom: number): number {\n let slot = startFrom\n while (claimed.has(slot)) slot++\n return slot\n}\n\n// ─── Public API ─────────────────────────────────────────────────────────────\n\n/**\n * Assign this tab a slot in the registry.\n *\n * - If no tabs and Google not yet signed in → slot 0 (primary).\n * - If googleSignedIn → lowest unclaimed slot starting from 1.\n * - If not googleSignedIn but other tabs exist → slot -1 (waiting).\n */\nexport function getOrAssignSlot(): { slot: number; tabId: string; playerId: string | null } {\n const tabId = getOrCreateTabId()\n const registry = readRegistry()\n pruneStale(registry)\n\n // If this tab already has a slot, refresh timestamp and return it\n if (registry.tabs[tabId]) {\n registry.tabs[tabId].timestamp = Date.now()\n writeRegistry(registry)\n const entry = registry.tabs[tabId]\n return { slot: entry.slot, tabId, playerId: entry.playerId }\n }\n\n const claimed = claimedSlots(registry)\n let slot: number\n\n if (registry.googleSignedIn) {\n // Google is signed in — assign as secondary (slot 1+)\n // Unless slot 0 is unclaimed, in which case this tab reclaims it\n if (!claimed.has(0)) {\n slot = 0\n } else {\n slot = lowestAvailableSlot(claimed, 1)\n }\n } else if (claimed.size === 0) {\n // First tab, no Google sign-in yet → primary\n slot = 0\n } else {\n // Other tabs exist but Google not signed in → waiting\n slot = -1\n }\n\n // Auto-assign playerId based on slot\n let playerId: string | null = null\n if (slot >= 0) {\n const claimedPlayerIds = new Set(\n Object.entries(registry.tabs)\n .filter(([id]) => id !== tabId)\n .map(([, e]) => e.playerId)\n )\n\n if (slot === 0) {\n // Slot 0 defaults to null (Google/Default)\n playerId = null\n } else {\n // Secondary slots: first unclaimed non-null from pool, or 'anonymous'\n const available = PLAYER_POOL.filter(\n pid => pid !== null && !claimedPlayerIds.has(pid)\n )\n playerId = available.length > 0 ? available[0] : 'anonymous'\n }\n\n registry.tabs[tabId] = { slot, playerId, timestamp: Date.now() }\n writeRegistry(registry)\n }\n\n return { slot, tabId, playerId }\n}\n\n/**\n * Update the playerId for an existing tab entry.\n */\nexport function setPlayerId(tabId: string, playerId: string | null): void {\n const registry = readRegistry()\n if (registry.tabs[tabId]) {\n registry.tabs[tabId].playerId = playerId\n registry.tabs[tabId].timestamp = Date.now()\n writeRegistry(registry)\n }\n}\n\n/**\n * Clear the entire registry (all tabs + googleSignedIn flag).\n * Used on sign-out so every tab starts fresh after reload.\n */\nexport function clearRegistry(): void {\n writeRegistry({ tabs: {}, googleSignedIn: false })\n}\n\n/**\n * Update the `googleSignedIn` flag (called by the primary tab after Google sign-in).\n */\nexport function setGoogleSignedIn(value: boolean): void {\n const registry = readRegistry()\n registry.googleSignedIn = value\n writeRegistry(registry)\n}\n\n/**\n * Read the `googleSignedIn` flag.\n */\nexport function isGoogleSignedIn(): boolean {\n return readRegistry().googleSignedIn\n}\n\n/**\n * Listen for `storage` events to detect when another tab completes Google sign-in.\n * Returns an unsubscribe function.\n */\nexport function onGoogleSignedIn(callback: () => void): () => void {\n const handler = (e: StorageEvent) => {\n if (e.key !== REGISTRY_KEY) return\n try {\n const registry = JSON.parse(e.newValue || '{}') as TabRegistry\n if (registry.googleSignedIn) {\n callback()\n }\n } catch {\n // ignore parse errors\n }\n }\n window.addEventListener('storage', handler)\n return () => window.removeEventListener('storage', handler)\n}\n\n/**\n * Listen for `storage` events to detect when another tab signs out of Google.\n * Returns an unsubscribe function.\n */\nexport function onGoogleSignedOut(callback: () => void): () => void {\n const handler = (e: StorageEvent) => {\n if (e.key !== REGISTRY_KEY) return\n try {\n const newRegistry = JSON.parse(e.newValue || '{}') as TabRegistry\n if (newRegistry.googleSignedIn) return // still signed in — nothing to do\n\n // Only fire if the PREVIOUS state had googleSignedIn === true.\n // Without this guard, any registry write while googleSignedIn is already\n // false (heartbeats, slot claims, clearRegistry) would trigger a reload.\n const oldRegistry = JSON.parse(e.oldValue || '{}') as TabRegistry\n if (oldRegistry.googleSignedIn) {\n callback()\n }\n } catch { /* ignore */ }\n }\n window.addEventListener('storage', handler)\n return () => window.removeEventListener('storage', handler)\n}\n\n/**\n * Start a heartbeat that refreshes this tab's timestamp every 10 s.\n * Returns a stop function.\n */\nexport function startHeartbeat(tabId: string): () => void {\n const interval = setInterval(() => {\n const registry = readRegistry()\n if (registry.tabs[tabId]) {\n registry.tabs[tabId].timestamp = Date.now()\n writeRegistry(registry)\n }\n }, HEARTBEAT_INTERVAL_MS)\n\n return () => clearInterval(interval)\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mapCreditsExhaustion, generateId, createRpcAdminGenApi, createMockAdminGenApi, SHARE_FILE_ALLOWED_MIME_TYPES, SHARE_FILE_MAX_SIZE_BYTES, RpcAdsApi, RpcAnalyticsApi, RpcStorageApi, RpcInboundStorageApi, DualEmitStorageApi, RpcAvatarApi, RpcNavigationApi, RpcNotificationsApi, RpcPopupsApi, HostProfileApi, HostDeviceApi, HostEnvironmentApi, HostSystemApi, HostCdnApi, HostTimeApi, RpcHapticsApi, RpcGamepadApi, RpcFeaturesApi, RpcLifecycleApi, RpcRoomsApi, RpcLoggingApi, RpcCreditsApi, RpcPreloaderApi, ClipsApiImpl, RpcEntitlementApi, RpcStatsApi, RpcCollectiblesApi, RpcShopApi, RpcVideoApi, RpcAttributionApi, RpcSharedAssetsApi, initializeRoomsApi, RpcAccessGateApi, WsMultiplayerApi, applyAccessGates, wireIdentityReplica, sanitizeProfile, MockAdsApi, MockLifecycleApi, MockAnalyticsApi, createMockStorageApi, MockAvatarApi, MockNavigationApi, MockNotificationsApi, MockPopupsApi, MockProfileApi, MockDeviceApi, MockEnvironmentApi, MockSystemApi, MockCdnApi, MockTimeApi, MockHapticsApi, MockGamepadApi, MockFeaturesApi, MockLoggingApi, MockIapApi, MockCreditsApi, MockEntitlementApi, MockStatsApi, MockCollectiblesApi, MockShopApi, MockVideoApi, MockAppApi, MockAttributionApi, MockPreloaderApi, MockSharedAssetsApi, MockAccessGateApi, MockMultiplayerApi, asCreditsExhaustedError } from './chunk-
|
|
1
|
+
import { mapCreditsExhaustion, generateId, createRpcAdminGenApi, createMockAdminGenApi, PlaygroundAppApi, warnRenamed, SHARE_FILE_ALLOWED_MIME_TYPES, SHARE_FILE_MAX_SIZE_BYTES, RpcAdsApi, RpcAnalyticsApi, RpcStorageApi, RpcInboundStorageApi, DualEmitStorageApi, RpcAvatarApi, RpcNavigationApi, RpcNotificationsApi, RpcPopupsApi, HostProfileApi, HostDeviceApi, HostEnvironmentApi, HostSystemApi, HostCdnApi, HostTimeApi, RpcHapticsApi, RpcGamepadApi, RpcFeaturesApi, RpcLifecycleApi, RpcRoomsApi, RpcLoggingApi, RpcCreditsApi, RpcPreloaderApi, ClipsApiImpl, RpcEntitlementApi, RpcStatsApi, RpcCollectiblesApi, RpcShopApi, RpcVideoApi, RpcAttributionApi, RpcSharedAssetsApi, initializeRoomsApi, RpcAccessGateApi, WsMultiplayerApi, applyAccessGates, wireIdentityReplica, sanitizeProfile, utf8ByteLength, MockAdsApi, MockLifecycleApi, MockAnalyticsApi, createMockStorageApi, MockAvatarApi, MockNavigationApi, MockNotificationsApi, MockPopupsApi, MockProfileApi, MockDeviceApi, MockEnvironmentApi, MockSystemApi, MockCdnApi, MockTimeApi, MockHapticsApi, MockGamepadApi, MockFeaturesApi, MockLoggingApi, MockIapApi, MockCreditsApi, MockEntitlementApi, MockStatsApi, MockCollectiblesApi, MockShopApi, MockVideoApi, MockAppApi, MockAttributionApi, MockPreloaderApi, MockSharedAssetsApi, MockAccessGateApi, MockMultiplayerApi, asCreditsExhaustedError } from './chunk-ZUEAIFOZ.js';
|
|
2
2
|
import { RundotApiError } from './chunk-HVVCNDSV.js';
|
|
3
3
|
|
|
4
4
|
// src/ai/RpcAiApi.ts
|
|
@@ -1023,7 +1023,7 @@ function initializeSimulation(rundotGameApi, host) {
|
|
|
1023
1023
|
}
|
|
1024
1024
|
|
|
1025
1025
|
// src/version.ts
|
|
1026
|
-
var SDK_VERSION = "5.23.0-beta.
|
|
1026
|
+
var SDK_VERSION = "5.23.0-beta.1";
|
|
1027
1027
|
|
|
1028
1028
|
// src/leaderboard/utils.ts
|
|
1029
1029
|
var HASH_ALGORITHM_WEB_CRYPTO = "SHA-256";
|
|
@@ -1139,6 +1139,46 @@ var RpcLeaderboardApi = class {
|
|
|
1139
1139
|
}
|
|
1140
1140
|
};
|
|
1141
1141
|
|
|
1142
|
+
// src/leaderboard/validateSubmitScore.ts
|
|
1143
|
+
var MIN_SCORE = 0;
|
|
1144
|
+
var MAX_SCORE = 999999999;
|
|
1145
|
+
var MIN_DURATION_SEC = 10;
|
|
1146
|
+
var MAX_DURATION_SEC = 3600;
|
|
1147
|
+
var MAX_METADATA_BYTES = 20 * 1024;
|
|
1148
|
+
function validateSubmitScore(params) {
|
|
1149
|
+
const { score, duration, metadata } = params;
|
|
1150
|
+
if (typeof score !== "number" || Number.isNaN(score)) {
|
|
1151
|
+
throw new RundotApiError("INVALID_ARGUMENT", "Score must be a valid number", 400);
|
|
1152
|
+
}
|
|
1153
|
+
if (score < MIN_SCORE || score > MAX_SCORE) {
|
|
1154
|
+
throw new RundotApiError("INVALID_ARGUMENT", "Score out of bounds", 400);
|
|
1155
|
+
}
|
|
1156
|
+
if (!Number.isFinite(duration) || duration < 0) {
|
|
1157
|
+
throw new RundotApiError("INVALID_ARGUMENT", "Duration must be a positive number", 400);
|
|
1158
|
+
}
|
|
1159
|
+
if (duration < MIN_DURATION_SEC || duration > MAX_DURATION_SEC) {
|
|
1160
|
+
throw new RundotApiError("INVALID_ARGUMENT", "Duration out of bounds", 400);
|
|
1161
|
+
}
|
|
1162
|
+
if (metadata !== void 0 && metadata !== null) {
|
|
1163
|
+
if (typeof metadata !== "object" || Array.isArray(metadata)) {
|
|
1164
|
+
throw new RundotApiError("INVALID_ARGUMENT", "Metadata must be a plain object", 400);
|
|
1165
|
+
}
|
|
1166
|
+
let serialized;
|
|
1167
|
+
try {
|
|
1168
|
+
serialized = JSON.stringify(metadata);
|
|
1169
|
+
} catch {
|
|
1170
|
+
throw new RundotApiError("INVALID_ARGUMENT", "Metadata must be JSON serializable", 400);
|
|
1171
|
+
}
|
|
1172
|
+
if (utf8ByteLength(serialized) > MAX_METADATA_BYTES) {
|
|
1173
|
+
throw new RundotApiError("INVALID_ARGUMENT", "Metadata exceeds 20KB limit", 400);
|
|
1174
|
+
}
|
|
1175
|
+
const reparsed = JSON.parse(serialized);
|
|
1176
|
+
if (typeof reparsed !== "object" || reparsed === null || Array.isArray(reparsed)) {
|
|
1177
|
+
throw new RundotApiError("INVALID_ARGUMENT", "Metadata must be an object", 400);
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1142
1182
|
// src/leaderboard/MockLeaderboardApi.ts
|
|
1143
1183
|
var MockLeaderboardApi = class {
|
|
1144
1184
|
tokens = /* @__PURE__ */ new Map();
|
|
@@ -1224,6 +1264,7 @@ var MockLeaderboardApi = class {
|
|
|
1224
1264
|
* @throws Error if token not found in cache or validation fails
|
|
1225
1265
|
*/
|
|
1226
1266
|
async submitScore(params) {
|
|
1267
|
+
validateSubmitScore(params);
|
|
1227
1268
|
let hash;
|
|
1228
1269
|
if (params.token) {
|
|
1229
1270
|
const cachedToken = this.tokenCache.get(params.token);
|
|
@@ -1809,11 +1850,94 @@ function initializeUgc(rundotGameApiInstance, host) {
|
|
|
1809
1850
|
rundotGameApiInstance.ugc = host.ugc;
|
|
1810
1851
|
}
|
|
1811
1852
|
|
|
1853
|
+
// src/social/validateShare.ts
|
|
1854
|
+
var SHARE_PARAMS_MAX_KEYS = 20;
|
|
1855
|
+
var SHARE_PARAMS_MAX_VALUE_LENGTH = 100 * 1024;
|
|
1856
|
+
var SHARE_PARAMS_MAX_TOTAL_SIZE = 200 * 1024;
|
|
1857
|
+
var META_MAX_TITLE = 200;
|
|
1858
|
+
var META_MAX_DESCRIPTION = 1e3;
|
|
1859
|
+
var META_MAX_IMAGE_URL = 2048;
|
|
1860
|
+
var CLICK_MAX_KEYS = 20;
|
|
1861
|
+
var CLICK_MAX_KEY_LENGTH = 64;
|
|
1862
|
+
var CLICK_MAX_VALUE_LENGTH = 1024;
|
|
1863
|
+
var CLICK_MAX_TOTAL_SIZE = 4096;
|
|
1864
|
+
function invalid(message) {
|
|
1865
|
+
throw new RundotApiError("UNKNOWN", message, 0);
|
|
1866
|
+
}
|
|
1867
|
+
function validateShareParams(shareParams) {
|
|
1868
|
+
if (shareParams === void 0 || shareParams === null) return;
|
|
1869
|
+
if (typeof shareParams !== "object" || Array.isArray(shareParams)) {
|
|
1870
|
+
invalid("shareParams must be a plain object");
|
|
1871
|
+
}
|
|
1872
|
+
const entries = Object.entries(shareParams);
|
|
1873
|
+
if (entries.length > SHARE_PARAMS_MAX_KEYS) {
|
|
1874
|
+
invalid(`shareParams exceeds maximum of ${SHARE_PARAMS_MAX_KEYS} keys`);
|
|
1875
|
+
}
|
|
1876
|
+
for (const [key, value] of entries) {
|
|
1877
|
+
if (typeof value !== "string") invalid(`shareParams value for key "${key}" must be a string`);
|
|
1878
|
+
if (value.length > SHARE_PARAMS_MAX_VALUE_LENGTH) {
|
|
1879
|
+
invalid(`shareParams value for key "${key}" exceeds maximum length of 100KB`);
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
if (JSON.stringify(shareParams).length > SHARE_PARAMS_MAX_TOTAL_SIZE) {
|
|
1883
|
+
invalid("shareParams exceeds maximum serialized size of 200KB");
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
function validateShareMetadata(metadata) {
|
|
1887
|
+
if (metadata === void 0 || metadata === null) return;
|
|
1888
|
+
if (typeof metadata !== "object" || Array.isArray(metadata)) invalid("metadata must be a plain object");
|
|
1889
|
+
const m = metadata;
|
|
1890
|
+
if (m.title !== void 0 && typeof m.title !== "string") invalid("metadata.title must be a string");
|
|
1891
|
+
if (m.description !== void 0 && typeof m.description !== "string") invalid("metadata.description must be a string");
|
|
1892
|
+
if (m.imageUrl !== void 0 && typeof m.imageUrl !== "string") invalid("metadata.imageUrl must be a string");
|
|
1893
|
+
if (typeof m.title === "string" && m.title.length > META_MAX_TITLE) invalid(`metadata.title exceeds maximum length of ${META_MAX_TITLE}`);
|
|
1894
|
+
if (typeof m.description === "string" && m.description.length > META_MAX_DESCRIPTION) invalid(`metadata.description exceeds maximum length of ${META_MAX_DESCRIPTION}`);
|
|
1895
|
+
if (typeof m.imageUrl === "string" && m.imageUrl.length > META_MAX_IMAGE_URL) invalid(`metadata.imageUrl exceeds maximum length of ${META_MAX_IMAGE_URL}`);
|
|
1896
|
+
}
|
|
1897
|
+
function validateClickMetadata(metadata) {
|
|
1898
|
+
if (typeof metadata !== "object" || metadata === null) invalid("metadata must be a non-null object");
|
|
1899
|
+
const entries = Object.entries(metadata);
|
|
1900
|
+
if (entries.length > CLICK_MAX_KEYS) invalid(`metadata exceeds maximum of ${CLICK_MAX_KEYS} keys`);
|
|
1901
|
+
for (const [key, value] of entries) {
|
|
1902
|
+
if (typeof value !== "string") invalid(`metadata value for key "${key}" must be a string`);
|
|
1903
|
+
if (key.length > CLICK_MAX_KEY_LENGTH) invalid(`metadata key "${key}" exceeds maximum length of ${CLICK_MAX_KEY_LENGTH}`);
|
|
1904
|
+
if (value.length > CLICK_MAX_VALUE_LENGTH) invalid(`metadata value for key "${key}" exceeds maximum length of ${CLICK_MAX_VALUE_LENGTH}`);
|
|
1905
|
+
}
|
|
1906
|
+
if (JSON.stringify(metadata).length > CLICK_MAX_TOTAL_SIZE) {
|
|
1907
|
+
invalid(`metadata total size exceeds maximum of ${CLICK_MAX_TOTAL_SIZE} bytes`);
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
function validateShareFile(options) {
|
|
1911
|
+
const { data, mimeType } = options;
|
|
1912
|
+
if (!SHARE_FILE_ALLOWED_MIME_TYPES.includes(mimeType)) {
|
|
1913
|
+
throw new Error(
|
|
1914
|
+
`unsupported MIME type "${mimeType}". Allowed: ${SHARE_FILE_ALLOWED_MIME_TYPES.join(", ")}`
|
|
1915
|
+
);
|
|
1916
|
+
}
|
|
1917
|
+
let sizeBytes;
|
|
1918
|
+
if (typeof Blob !== "undefined" && data instanceof Blob) {
|
|
1919
|
+
sizeBytes = data.size;
|
|
1920
|
+
} else if (data instanceof ArrayBuffer) {
|
|
1921
|
+
sizeBytes = data.byteLength;
|
|
1922
|
+
} else if (typeof data === "string") {
|
|
1923
|
+
const len = data.length;
|
|
1924
|
+
const paddingChars = (data[len - 1] === "=" ? 1 : 0) + (data[len - 2] === "=" ? 1 : 0);
|
|
1925
|
+
sizeBytes = Math.floor(len * 3 / 4) - paddingChars;
|
|
1926
|
+
} else {
|
|
1927
|
+
return;
|
|
1928
|
+
}
|
|
1929
|
+
if (sizeBytes > SHARE_FILE_MAX_SIZE_BYTES) {
|
|
1930
|
+
throw new Error(`file size (${sizeBytes} bytes) exceeds max allowed (${SHARE_FILE_MAX_SIZE_BYTES} bytes)`);
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1812
1934
|
// src/social/MockSocialApi.ts
|
|
1813
1935
|
var MOCK_QR_CODE = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==";
|
|
1814
1936
|
var MOCK_SHARE_LINK_ID = "mock-share-id";
|
|
1815
1937
|
var MockSocialApi = class {
|
|
1816
1938
|
async shareLinkAsync(options) {
|
|
1939
|
+
validateShareParams(options.shareParams);
|
|
1940
|
+
validateShareMetadata(options.metadata);
|
|
1817
1941
|
const shareUrl = this.createMockUrl(options.shareParams);
|
|
1818
1942
|
if (typeof navigator !== "undefined" && navigator.clipboard) {
|
|
1819
1943
|
try {
|
|
@@ -1828,6 +1952,8 @@ var MockSocialApi = class {
|
|
|
1828
1952
|
return { shareUrl, shareLinkId: MOCK_SHARE_LINK_ID };
|
|
1829
1953
|
}
|
|
1830
1954
|
async createQRCodeAsync(options) {
|
|
1955
|
+
validateShareParams(options.shareParams);
|
|
1956
|
+
validateShareMetadata(options.metadata);
|
|
1831
1957
|
const shareUrl = this.createMockUrl(options.shareParams);
|
|
1832
1958
|
return {
|
|
1833
1959
|
shareUrl,
|
|
@@ -1836,6 +1962,7 @@ var MockSocialApi = class {
|
|
|
1836
1962
|
};
|
|
1837
1963
|
}
|
|
1838
1964
|
async addShareClickDataAsync(options) {
|
|
1965
|
+
validateClickMetadata(options.metadata);
|
|
1839
1966
|
}
|
|
1840
1967
|
async getShareClicksAsync(options) {
|
|
1841
1968
|
return { clicks: [], truncated: false };
|
|
@@ -1843,7 +1970,8 @@ var MockSocialApi = class {
|
|
|
1843
1970
|
async getMyShareClickDataAsync(options) {
|
|
1844
1971
|
return null;
|
|
1845
1972
|
}
|
|
1846
|
-
async shareFileAsync(
|
|
1973
|
+
async shareFileAsync(options) {
|
|
1974
|
+
validateShareFile(options);
|
|
1847
1975
|
console.warn("[RUN:mock] shareFileAsync called \u2014 returning cancelled: false");
|
|
1848
1976
|
return { cancelled: false };
|
|
1849
1977
|
}
|
|
@@ -2497,6 +2625,13 @@ var MockAdminThreeDGenApi = class {
|
|
|
2497
2625
|
};
|
|
2498
2626
|
|
|
2499
2627
|
// src/app/index.ts
|
|
2628
|
+
var SandboxAppApi = class extends PlaygroundAppApi {
|
|
2629
|
+
// @deprecated-alias
|
|
2630
|
+
constructor(...args) {
|
|
2631
|
+
warnRenamed("SandboxAppApi", "PlaygroundAppApi");
|
|
2632
|
+
super(...args);
|
|
2633
|
+
}
|
|
2634
|
+
};
|
|
2500
2635
|
function initializeApp(rundotGameApiInstance, host) {
|
|
2501
2636
|
rundotGameApiInstance.app = host.app;
|
|
2502
2637
|
}
|
|
@@ -2510,7 +2645,8 @@ var RpcSocialApi = class {
|
|
|
2510
2645
|
async shareLinkAsync(options) {
|
|
2511
2646
|
const result = await this.rpcClient.call("H5_SHARE_LINK" /* SHARE_LINK */, {
|
|
2512
2647
|
shareParams: options.shareParams,
|
|
2513
|
-
metadata: options.metadata ?? {}
|
|
2648
|
+
metadata: options.metadata ?? {},
|
|
2649
|
+
slug: options.slug
|
|
2514
2650
|
});
|
|
2515
2651
|
return {
|
|
2516
2652
|
shareUrl: result.shareUrl,
|
|
@@ -2523,7 +2659,8 @@ var RpcSocialApi = class {
|
|
|
2523
2659
|
{
|
|
2524
2660
|
shareParams: options.shareParams,
|
|
2525
2661
|
metadata: options.metadata ?? {},
|
|
2526
|
-
qrOptions: options.qrOptions ?? {}
|
|
2662
|
+
qrOptions: options.qrOptions ?? {},
|
|
2663
|
+
slug: options.slug
|
|
2527
2664
|
}
|
|
2528
2665
|
);
|
|
2529
2666
|
return {
|
|
@@ -3893,7 +4030,7 @@ var MockHost = class {
|
|
|
3893
4030
|
// src/Host.ts
|
|
3894
4031
|
async function createHost(rundotGameApi, isMock) {
|
|
3895
4032
|
if (isMock) {
|
|
3896
|
-
const factory = globalThis.
|
|
4033
|
+
const factory = globalThis.__RUNDOT_PLAYGROUND_HOST_FACTORY__;
|
|
3897
4034
|
if (factory) {
|
|
3898
4035
|
return factory(rundotGameApi);
|
|
3899
4036
|
}
|
|
@@ -3931,6 +4068,6 @@ function initializeClips(rundotGameApi, host) {
|
|
|
3931
4068
|
rundotGameApi.clips = host.clips;
|
|
3932
4069
|
}
|
|
3933
4070
|
|
|
3934
|
-
export { HASH_ALGORITHM_NODE, HASH_ALGORITHM_WEB_CRYPTO, MockAdminImageGenApi, MockAdminSpriteGenApi, MockAdminThreeDGenApi, MockAiApi, MockCaptureConsent, MockClipsApi, MockImageGenApi, MockLeaderboardApi, MockSocialApi, MockSpriteGenApi, RemoteHost, RpcAdminImageGenApi, RpcAdminSpriteGenApi, RpcAdminThreeDGenApi, RpcAdminUgcApi, RpcAiApi, RpcAppApi, RpcCaptureConsent, RpcClient, RpcIapApi, RpcImageGenApi, RpcLeaderboardApi, RpcSimulationApi, RpcSocialApi, RpcSpriteGenApi, SDK_VERSION, buildInitializationContext, computeScoreHash, createHost, initializeAi, initializeApp, initializeAudioGen, initializeClips, initializeFiles, initializeIap, initializeImageGen, initializeLeaderboard, initializeSimulation, initializeSocial, initializeSpriteGen, initializeTextGen, initializeThreeDGen, initializeUgc, initializeVideoGen };
|
|
3935
|
-
//# sourceMappingURL=chunk-
|
|
3936
|
-
//# sourceMappingURL=chunk-
|
|
4071
|
+
export { HASH_ALGORITHM_NODE, HASH_ALGORITHM_WEB_CRYPTO, MockAdminImageGenApi, MockAdminSpriteGenApi, MockAdminThreeDGenApi, MockAiApi, MockCaptureConsent, MockClipsApi, MockImageGenApi, MockLeaderboardApi, MockSocialApi, MockSpriteGenApi, RemoteHost, RpcAdminImageGenApi, RpcAdminSpriteGenApi, RpcAdminThreeDGenApi, RpcAdminUgcApi, RpcAiApi, RpcAppApi, RpcCaptureConsent, RpcClient, RpcIapApi, RpcImageGenApi, RpcLeaderboardApi, RpcSimulationApi, RpcSocialApi, RpcSpriteGenApi, SDK_VERSION, SandboxAppApi, buildInitializationContext, computeScoreHash, createHost, initializeAi, initializeApp, initializeAudioGen, initializeClips, initializeFiles, initializeIap, initializeImageGen, initializeLeaderboard, initializeSimulation, initializeSocial, initializeSpriteGen, initializeTextGen, initializeThreeDGen, initializeUgc, initializeVideoGen };
|
|
4072
|
+
//# sourceMappingURL=chunk-T7HMDUMX.js.map
|
|
4073
|
+
//# sourceMappingURL=chunk-T7HMDUMX.js.map
|