@stakeplate/core 0.3.0 → 0.4.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.
package/README.md CHANGED
@@ -55,6 +55,31 @@ config.rules = built.menu; // → the white HTML menu
55
55
  config.socialMessages = { en: built.socialEn }; // auto-derived social wording
56
56
  ```
57
57
 
58
+ ## Networking — real RGS vs. the mock
59
+
60
+ `createStakeGame` picks the transport from the **launch URL**, so the same build runs
61
+ locally and on Stake with no code change:
62
+
63
+ | Launch | Transport |
64
+ |---|---|
65
+ | a real `rgs_url` is present (a Stake launch, incl. the dashboard's "local redirect") | the **real Stake RGS** — authenticates with the launch `sessionID`, pulls the real balance/config, spins + buys with real requests |
66
+ | `?demo=true` **with** a real `rgs_url` (Stake **fun-play**) | still the **real RGS** — `demo` is a demo *wallet*, not a fake backend |
67
+ | no `rgs_url` (bare `pnpm dev`), or `?mock=true` | the in-process **mock RGS** |
68
+
69
+ So a game gates its local dev mock on **`!isStakeLaunch()`** (a `readRuntime` helper) and
70
+ passes `network:` only in that case; a real launch then falls through to the real RGS. The
71
+ Stake "local redirect" opens a tab like
72
+ `…?sessionID=…&rgs_url=rgsd.stake-engine.com&lang=en&currency=USD&demo=true` — and that
73
+ authorizes + plays against `rgsd.stake-engine.com`.
74
+
75
+ ```ts
76
+ import { createStakeGame, isStakeLaunch } from '@stakeplate/core';
77
+ createStakeGame({
78
+ /* … */
79
+ ...(isStakeLaunch() ? {} : { network: myLocalMock }), // real RGS on a Stake launch
80
+ });
81
+ ```
82
+
58
83
  ## Subpaths
59
84
 
60
85
  - `@stakeplate/core` — the one-call API + engine (turbo, autoplay, buy-features).
package/dist/audio.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as SfxBus, c as createGameAudio, d as bindInputSounds, f as MixerGroup, i as MusicBus, l as InputSoundMap, m as bindMixerToHud, n as GameAudio, o as SoundEntry, p as MixerLike, r as GameAudioOptions, s as bindAudioToHud, t as BusName, u as InputSoundOptions } from "./index-BXD-eK1I.js";
1
+ import { a as SfxBus, c as createGameAudio, d as bindInputSounds, f as MixerGroup, i as MusicBus, l as InputSoundMap, m as bindMixerToHud, n as GameAudio, o as SoundEntry, p as MixerLike, r as GameAudioOptions, s as bindAudioToHud, t as BusName, u as InputSoundOptions } from "./index-BpPekNWF.js";
2
2
  export { BusName, GameAudio, GameAudioOptions, type InputSoundMap, type InputSoundOptions, type MixerGroup, type MixerLike, MusicBus, SfxBus, SoundEntry, bindAudioToHud, bindInputSounds, bindMixerToHud, createGameAudio };
@@ -1,5 +1,5 @@
1
1
  import { m as Round } from "./protocol-C1KamF3t.js";
2
- import { t as NetworkManager } from "./network-pBW8CX1o.js";
2
+ import { t as NetworkManager } from "./network-CBxKQzeb.js";
3
3
  import { n as RootStore } from "./index-BBlN97RY.js";
4
4
  import { a as Ticker, t as HudPort } from "./hud-port-DNfotn4U.js";
5
5
  import { BootedHud } from "@open-slot-ui/pixi";
@@ -354,4 +354,4 @@ declare function bindAudioToHud(audio: GameAudio, hud: BootedHud, opts?: {
354
354
  }): () => void;
355
355
  //#endregion
356
356
  export { TurboState as A, modeCostOf as C, roundInfo as D, RoundInfo as E, DEFAULT_TURBO_SPEEDS as O, ModeConfig as S, InterpretBook as T, FSM as _, SfxBus as a, PhaseContext as b, createGameAudio as c, bindInputSounds as d, MixerGroup as f, AudioValue as g, AudioPort as h, MusicBus as i, TurboClock as k, InputSoundMap as l, bindMixerToHud as m, GameAudio as n, SoundEntry as o, MixerLike as p, GameAudioOptions as r, bindAudioToHud as s, BusName as t, InputSoundOptions as u, LoaderPort as v, GameRound as w, GameConfig as x, Phase as y };
357
- //# sourceMappingURL=index-BXD-eK1I.d.ts.map
357
+ //# sourceMappingURL=index-BpPekNWF.d.ts.map
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { a as Balance, c as JurisdictionConfig, d as ReplayParams, f as RgsConfig, h as roundEvents, i as BOOK_AMOUNT_MULTIPLIER, l as PlayRequest, m as Round, n as AuthenticateRequest, o as EndRoundRequest, p as RgsError, r as AuthenticateResponse, s as EndRoundResponse, t as API_AMOUNT_MULTIPLIER, u as PlayResponse } from "./protocol-C1KamF3t.js";
2
- import { a as MockOptions, c as RuntimeConfig, i as MockNetworkManager, l as readRuntime, n as PlayArgs, o as ScriptedRound, r as createNetwork, s as ReplayLaunch, t as NetworkManager, u as urlParam } from "./network-pBW8CX1o.js";
2
+ import { a as MockOptions, c as RuntimeConfig, d as urlParam, i as MockNetworkManager, l as isStakeLaunch, n as PlayArgs, o as ScriptedRound, r as createNetwork, s as ReplayLaunch, t as NetworkManager, u as readRuntime } from "./network-CBxKQzeb.js";
3
3
  import { i as UiStore, n as RootStore, r as SessionStore, t as BalanceStore } from "./index-BBlN97RY.js";
4
4
  import { a as Ticker, i as RealTicker, n as ReplayInfo, r as InstantTicker, t as HudPort } from "./hud-port-DNfotn4U.js";
5
- import { A as TurboState, C as modeCostOf, D as roundInfo, E as RoundInfo, O as DEFAULT_TURBO_SPEEDS, S as ModeConfig, T as InterpretBook, _ as FSM, b as PhaseContext, g as AudioValue, h as AudioPort, k as TurboClock, l as InputSoundMap, o as SoundEntry, r as GameAudioOptions, v as LoaderPort, w as GameRound, x as GameConfig, y as Phase } from "./index-BXD-eK1I.js";
5
+ import { A as TurboState, C as modeCostOf, D as roundInfo, E as RoundInfo, O as DEFAULT_TURBO_SPEEDS, S as ModeConfig, T as InterpretBook, _ as FSM, b as PhaseContext, g as AudioValue, h as AudioPort, k as TurboClock, l as InputSoundMap, o as SoundEntry, r as GameAudioOptions, v as LoaderPort, w as GameRound, x as GameConfig, y as Phase } from "./index-BpPekNWF.js";
6
6
  import { StakeNetworkManager, StakeNetworkOptions } from "./rgs.js";
7
7
  import { BootedHud } from "@open-slot-ui/pixi";
8
8
  import { CurrencySpec } from "@open-slot-ui/core";
@@ -209,5 +209,5 @@ declare const EXTRA_DECIMALS: Readonly<Record<string, {
209
209
  */
210
210
  declare function currencyFor(code: string): CurrencySpec;
211
211
  //#endregion
212
- export { API_AMOUNT_MULTIPLIER, AudioPort, AudioSpec, AudioValue, AuthenticateRequest, AuthenticateResponse, BOOK_AMOUNT_MULTIPLIER, Balance, BalanceStore, BeatClock, BeatOptions, CreateStakeGameOptions, DEFAULT_TURBO_SPEEDS, EXTRA_DECIMALS, EndRoundRequest, EndRoundResponse, FSM, FeatureItem, GameConfig, GameLoader, GameRound, GameSnapshot, HudPort, IdlePhase, InstantTicker, InterpretBook, JurisdictionConfig, LoaderConfig, LoaderPort, MockNetworkManager, MockOptions, ModeConfig, NetworkManager, Phase, PhaseContext, PlayArgs, PlayRequest, PlayResponse, PresentPhase, RealTicker, ReplayInfo, ReplayLaunch, ReplayParams, RgsConfig, RgsError, RootStore, Round, RoundInfo, RuntimeConfig, ScriptedRound, SessionStore, SettlePhase, SpinPhase, StakeGame, StakeNetworkManager, StakeNetworkOptions, Ticker, TurboClock, TurboState, UiStore, ViewContext, blockingBeat, createLoader, createNetwork, createStakeGame, currencyFor, defaultPhases, modeCostOf, readRuntime, roundEvents, roundInfo, urlParam };
212
+ export { API_AMOUNT_MULTIPLIER, AudioPort, AudioSpec, AudioValue, AuthenticateRequest, AuthenticateResponse, BOOK_AMOUNT_MULTIPLIER, Balance, BalanceStore, BeatClock, BeatOptions, CreateStakeGameOptions, DEFAULT_TURBO_SPEEDS, EXTRA_DECIMALS, EndRoundRequest, EndRoundResponse, FSM, FeatureItem, GameConfig, GameLoader, GameRound, GameSnapshot, HudPort, IdlePhase, InstantTicker, InterpretBook, JurisdictionConfig, LoaderConfig, LoaderPort, MockNetworkManager, MockOptions, ModeConfig, NetworkManager, Phase, PhaseContext, PlayArgs, PlayRequest, PlayResponse, PresentPhase, RealTicker, ReplayInfo, ReplayLaunch, ReplayParams, RgsConfig, RgsError, RootStore, Round, RoundInfo, RuntimeConfig, ScriptedRound, SessionStore, SettlePhase, SpinPhase, StakeGame, StakeNetworkManager, StakeNetworkOptions, Ticker, TurboClock, TurboState, UiStore, ViewContext, blockingBeat, createLoader, createNetwork, createStakeGame, currencyFor, defaultPhases, isStakeLaunch, modeCostOf, readRuntime, roundEvents, roundInfo, urlParam };
213
213
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { i as roundEvents, n as API_AMOUNT_MULTIPLIER, r as BOOK_AMOUNT_MULTIPLIER, t as MockNetworkManager } from "./MockNetworkManager-cj8WT5v0.js";
2
- import { StakeNetworkManager, createNetwork, readRuntime, urlParam } from "./rgs.js";
2
+ import { StakeNetworkManager, createNetwork, isStakeLaunch, readRuntime, urlParam } from "./rgs.js";
3
3
  import { n as RealTicker, t as InstantTicker } from "./ticker-A-XgayZv.js";
4
4
  import { BalanceStore, RootStore, SessionStore, UiStore } from "./stores.js";
5
5
  import { n as bindMixerToHud, t as bindInputSounds } from "./inputs-X3Tc_HTV.js";
@@ -907,6 +907,6 @@ function buyFeaturesOf(config) {
907
907
  return out;
908
908
  }
909
909
  //#endregion
910
- export { API_AMOUNT_MULTIPLIER, BOOK_AMOUNT_MULTIPLIER, BalanceStore, DEFAULT_TURBO_SPEEDS, EXTRA_DECIMALS, FSM, IdlePhase, InstantTicker, MockNetworkManager, PresentPhase, RealTicker, RootStore, SessionStore, SettlePhase, SpinPhase, StakeNetworkManager, TurboClock, UiStore, blockingBeat, createLoader, createNetwork, createStakeGame, currencyFor, defaultPhases, modeCostOf, readRuntime, roundEvents, roundInfo, urlParam };
910
+ export { API_AMOUNT_MULTIPLIER, BOOK_AMOUNT_MULTIPLIER, BalanceStore, DEFAULT_TURBO_SPEEDS, EXTRA_DECIMALS, FSM, IdlePhase, InstantTicker, MockNetworkManager, PresentPhase, RealTicker, RootStore, SessionStore, SettlePhase, SpinPhase, StakeNetworkManager, TurboClock, UiStore, blockingBeat, createLoader, createNetwork, createStakeGame, currencyFor, defaultPhases, isStakeLaunch, modeCostOf, readRuntime, roundEvents, roundInfo, urlParam };
911
911
 
912
912
  //# sourceMappingURL=index.js.map
@@ -17,6 +17,13 @@ interface ReplayLaunch {
17
17
  }
18
18
  interface RuntimeConfig {
19
19
  rgsUrl: string;
20
+ /**
21
+ * True when a real `rgs_url`/`rgsUrl` launch param was present (vs falling back to the
22
+ * local default). A provided host means "talk to it" — this is what tells the transport
23
+ * picker to use the REAL Stake RGS, even for a `demo` fun-play launch. Set it in
24
+ * `overrides` to force the real transport when you supply `rgsUrl` programmatically.
25
+ */
26
+ rgsUrlProvided: boolean;
20
27
  sessionId: string;
21
28
  /** BCP-47-ish language for `/wallet/authenticate` + the HUD locale ('br' → 'pt'). */
22
29
  language: string;
@@ -26,8 +33,18 @@ interface RuntimeConfig {
26
33
  social: boolean;
27
34
  /** `?device=` — Stake's viewport hint ('' | 'desktop' | 'mobile' | a small popout). */
28
35
  device: string;
29
- /** `?demo=true` — run against the built-in mock RGS, no real backend. */
36
+ /**
37
+ * `?demo=true` — Stake FUN-PLAY: a demo (non-cash) wallet on the REAL RGS. This is NOT a
38
+ * "use a fake backend" switch — Stake's own local-redirect dev tool launches
39
+ * `…?rgs_url=rgsd.stake-engine.com&sessionID=…&demo=true`, and that session still
40
+ * authenticates + plays against the real RGS. To run the in-process mock, use `?mock=true`.
41
+ */
30
42
  demo: boolean;
43
+ /**
44
+ * `?mock=true` — force the built-in in-process mock RGS (no backend). For pure client dev
45
+ * without a real session; distinct from Stake's `demo` fun-play. Overrides `rgs_url`.
46
+ */
47
+ mock: boolean;
31
48
  replay: ReplayLaunch;
32
49
  }
33
50
  type ParamSource = (name: string) => string | undefined;
@@ -43,6 +60,16 @@ declare function readRuntime(opts?: {
43
60
  overrides?: Partial<RuntimeConfig>;
44
61
  defaultRgsUrl?: string;
45
62
  }): RuntimeConfig;
63
+ /**
64
+ * True when the game was launched by the Stake platform — i.e. a real `rgs_url` was provided
65
+ * (the dev dashboard's "local redirect", or a live launch) and the in-process mock wasn't
66
+ * forced with `?mock=true`. This holds for `demo=true` fun-play launches too: they still run
67
+ * against the real RGS.
68
+ *
69
+ * A game gates its local dev mock on `!isStakeLaunch()` — so bare `pnpm dev` uses the mock,
70
+ * while a Stake launch auto-connects to the real RGS with the launch `sessionID`, no code edit.
71
+ */
72
+ declare function isStakeLaunch(runtime?: RuntimeConfig): boolean;
46
73
  //#endregion
47
74
  //#region src/rgs/MockNetworkManager.d.ts
48
75
  interface MockOptions {
@@ -111,10 +138,22 @@ interface NetworkManager {
111
138
  dispose?(): void;
112
139
  }
113
140
  /**
114
- * Pick the transport from the runtime: `?demo=true` (or a supplied `mock`) → the
115
- * in-process mock RGS; otherwise the real Stake transport.
141
+ * Pick the transport from the launch runtime:
142
+ *
143
+ * - a supplied `mock` instance, or `?mock=true` → the in-process mock RGS (no backend)
144
+ * - a real `rgs_url` was provided → the REAL Stake RGS. This INCLUDES a
145
+ * `?demo=true` fun-play launch: a Stake demo session still authenticates + plays
146
+ * against `rgs_url`, so `demo` must NOT force the mock.
147
+ * - `?demo=true` with NO host → the mock (bare local click-around)
148
+ * - otherwise → the real transport at the default
149
+ * (local emulator) host
150
+ *
151
+ * This is the key fix over the old `demo → mock`: Stake's own local-redirect dev tool opens
152
+ * `…?rgs_url=rgsd.stake-engine.com&sessionID=…&demo=true`. Under the old rule that demo
153
+ * session was hijacked by the in-process mock and never reached the RGS; now it authorizes
154
+ * on Stake, pulls the real balance/config, and spins/buys with real requests.
116
155
  */
117
156
  declare function createNetwork(runtime: RuntimeConfig, mock?: MockNetworkManager): NetworkManager;
118
157
  //#endregion
119
- export { MockOptions as a, RuntimeConfig as c, MockNetworkManager as i, readRuntime as l, PlayArgs as n, ScriptedRound as o, createNetwork as r, ReplayLaunch as s, NetworkManager as t, urlParam as u };
120
- //# sourceMappingURL=network-pBW8CX1o.d.ts.map
158
+ export { MockOptions as a, RuntimeConfig as c, urlParam as d, MockNetworkManager as i, isStakeLaunch as l, PlayArgs as n, ScriptedRound as o, createNetwork as r, ReplayLaunch as s, NetworkManager as t, readRuntime as u };
159
+ //# sourceMappingURL=network-CBxKQzeb.d.ts.map
package/dist/rgs.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { a as Balance, c as JurisdictionConfig, d as ReplayParams, f as RgsConfig, h as roundEvents, i as BOOK_AMOUNT_MULTIPLIER, l as PlayRequest, m as Round, n as AuthenticateRequest, o as EndRoundRequest, p as RgsError, r as AuthenticateResponse, s as EndRoundResponse, t as API_AMOUNT_MULTIPLIER, u as PlayResponse } from "./protocol-C1KamF3t.js";
2
- import { a as MockOptions, c as RuntimeConfig, i as MockNetworkManager, l as readRuntime, n as PlayArgs, o as ScriptedRound, r as createNetwork, s as ReplayLaunch, t as NetworkManager, u as urlParam } from "./network-pBW8CX1o.js";
2
+ import { a as MockOptions, c as RuntimeConfig, d as urlParam, i as MockNetworkManager, l as isStakeLaunch, n as PlayArgs, o as ScriptedRound, r as createNetwork, s as ReplayLaunch, t as NetworkManager, u as readRuntime } from "./network-CBxKQzeb.js";
3
3
  //#region src/rgs/StakeNetworkManager.d.ts
4
4
  interface StakeNetworkOptions {
5
5
  rgsUrl: string;
@@ -21,5 +21,5 @@ declare class StakeNetworkManager implements NetworkManager {
21
21
  private get;
22
22
  }
23
23
  //#endregion
24
- export { API_AMOUNT_MULTIPLIER, AuthenticateRequest, AuthenticateResponse, BOOK_AMOUNT_MULTIPLIER, Balance, EndRoundRequest, EndRoundResponse, JurisdictionConfig, MockNetworkManager, MockOptions, NetworkManager, PlayArgs, PlayRequest, PlayResponse, ReplayLaunch, ReplayParams, RgsConfig, RgsError, Round, RuntimeConfig, ScriptedRound, StakeNetworkManager, StakeNetworkOptions, createNetwork, readRuntime, roundEvents, urlParam };
24
+ export { API_AMOUNT_MULTIPLIER, AuthenticateRequest, AuthenticateResponse, BOOK_AMOUNT_MULTIPLIER, Balance, EndRoundRequest, EndRoundResponse, JurisdictionConfig, MockNetworkManager, MockOptions, NetworkManager, PlayArgs, PlayRequest, PlayResponse, ReplayLaunch, ReplayParams, RgsConfig, RgsError, Round, RuntimeConfig, ScriptedRound, StakeNetworkManager, StakeNetworkOptions, createNetwork, isStakeLaunch, readRuntime, roundEvents, urlParam };
25
25
  //# sourceMappingURL=rgs.d.ts.map
package/dist/rgs.js CHANGED
@@ -14,14 +14,17 @@ function readRuntime(opts = {}) {
14
14
  const param = opts.param ?? urlParam;
15
15
  const rawLang = param("lang");
16
16
  const language = rawLang === "br" ? "pt" : rawLang || "en";
17
+ const rgsUrlParam = param("rgs_url") ?? param("rgsUrl");
17
18
  const base = {
18
- rgsUrl: param("rgs_url") ?? param("rgsUrl") ?? opts.defaultRgsUrl ?? "http://localhost:4758",
19
+ rgsUrl: rgsUrlParam ?? opts.defaultRgsUrl ?? "http://localhost:4758",
20
+ rgsUrlProvided: rgsUrlParam != null,
19
21
  sessionId: param("sessionID") ?? param("sessionId") ?? "dev",
20
22
  language,
21
23
  currency: param("currency") ?? "USD",
22
24
  social: param("social") === "true",
23
25
  device: param("device") ?? "",
24
26
  demo: param("demo") === "true",
27
+ mock: param("mock") === "true",
25
28
  replay: {
26
29
  active: param("replay") === "true",
27
30
  amount: Number(param("amount")) || 0,
@@ -40,6 +43,18 @@ function readRuntime(opts = {}) {
40
43
  }
41
44
  };
42
45
  }
46
+ /**
47
+ * True when the game was launched by the Stake platform — i.e. a real `rgs_url` was provided
48
+ * (the dev dashboard's "local redirect", or a live launch) and the in-process mock wasn't
49
+ * forced with `?mock=true`. This holds for `demo=true` fun-play launches too: they still run
50
+ * against the real RGS.
51
+ *
52
+ * A game gates its local dev mock on `!isStakeLaunch()` — so bare `pnpm dev` uses the mock,
53
+ * while a Stake launch auto-connects to the real RGS with the launch `sessionID`, no code edit.
54
+ */
55
+ function isStakeLaunch(runtime = readRuntime()) {
56
+ return runtime.rgsUrlProvided && !runtime.mock;
57
+ }
43
58
  //#endregion
44
59
  //#region src/rgs/StakeNetworkManager.ts
45
60
  var StakeNetworkManager = class {
@@ -102,11 +117,29 @@ var StakeNetworkManager = class {
102
117
  //#endregion
103
118
  //#region src/rgs/network.ts
104
119
  /**
105
- * Pick the transport from the runtime: `?demo=true` (or a supplied `mock`) → the
106
- * in-process mock RGS; otherwise the real Stake transport.
120
+ * Pick the transport from the launch runtime:
121
+ *
122
+ * - a supplied `mock` instance, or `?mock=true` → the in-process mock RGS (no backend)
123
+ * - a real `rgs_url` was provided → the REAL Stake RGS. This INCLUDES a
124
+ * `?demo=true` fun-play launch: a Stake demo session still authenticates + plays
125
+ * against `rgs_url`, so `demo` must NOT force the mock.
126
+ * - `?demo=true` with NO host → the mock (bare local click-around)
127
+ * - otherwise → the real transport at the default
128
+ * (local emulator) host
129
+ *
130
+ * This is the key fix over the old `demo → mock`: Stake's own local-redirect dev tool opens
131
+ * `…?rgs_url=rgsd.stake-engine.com&sessionID=…&demo=true`. Under the old rule that demo
132
+ * session was hijacked by the in-process mock and never reached the RGS; now it authorizes
133
+ * on Stake, pulls the real balance/config, and spins/buys with real requests.
107
134
  */
108
135
  function createNetwork(runtime, mock) {
109
- if (runtime.demo || mock) return mock ?? new MockNetworkManager();
136
+ if (mock) return mock;
137
+ if (runtime.mock) return new MockNetworkManager();
138
+ if (runtime.rgsUrlProvided) return stakeTransport(runtime);
139
+ if (runtime.demo) return new MockNetworkManager();
140
+ return stakeTransport(runtime);
141
+ }
142
+ function stakeTransport(runtime) {
110
143
  return new StakeNetworkManager({
111
144
  rgsUrl: runtime.rgsUrl,
112
145
  sessionId: runtime.sessionId,
@@ -114,6 +147,6 @@ function createNetwork(runtime, mock) {
114
147
  });
115
148
  }
116
149
  //#endregion
117
- export { API_AMOUNT_MULTIPLIER, BOOK_AMOUNT_MULTIPLIER, MockNetworkManager, StakeNetworkManager, createNetwork, readRuntime, roundEvents, urlParam };
150
+ export { API_AMOUNT_MULTIPLIER, BOOK_AMOUNT_MULTIPLIER, MockNetworkManager, StakeNetworkManager, createNetwork, isStakeLaunch, readRuntime, roundEvents, urlParam };
118
151
 
119
152
  //# sourceMappingURL=rgs.js.map
package/dist/rgs.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"rgs.js","names":[],"sources":["../src/rgs/runtime.ts","../src/rgs/StakeNetworkManager.ts","../src/rgs/network.ts"],"sourcesContent":["/**\n * Stake launch parameters (mirrors `StakeEngine/web-sdk`\n * `packages/state-shared/src/stateUrl`): sessionID, rgs_url, lang, currency, device,\n * social, demo — plus the REPLAY set: replay, amount, game, version, mode, event.\n * `lang` is REQUIRED by `/wallet/authenticate` (its absence 400s the RGS).\n */\n\nexport interface ReplayLaunch {\n /** `?replay=true` — launch into replay (fetch + play back a recorded round). */\n active: boolean;\n amount: number;\n game: string;\n version: string;\n mode: string;\n event: string;\n}\n\nexport interface RuntimeConfig {\n rgsUrl: string;\n sessionId: string;\n /** BCP-47-ish language for `/wallet/authenticate` + the HUD locale ('br' → 'pt'). */\n language: string;\n /** `?currency=` — currency code (used for replay, where there's no wallet to read it). */\n currency: string;\n /** `?social=true` — force Stake US social/sweepstakes wording. */\n social: boolean;\n /** `?device=` — Stake's viewport hint ('' | 'desktop' | 'mobile' | a small popout). */\n device: string;\n /** `?demo=true` — run against the built-in mock RGS, no real backend. */\n demo: boolean;\n replay: ReplayLaunch;\n}\n\ntype ParamSource = (name: string) => string | undefined;\n\n/** Read a URL param from `window.location.search` (undefined off-DOM). */\nexport function urlParam(name: string): string | undefined {\n if (typeof window === 'undefined') return undefined;\n return new URLSearchParams(window.location.search).get(name) ?? undefined;\n}\n\n/**\n * Parse the Stake launch params into a {@link RuntimeConfig}. Pass `overrides` (or a\n * custom `param` reader) for tests/embedding; otherwise reads the page URL. `rgsUrl`\n * defaults to a local emulator so `pnpm dev` works out of the box.\n */\nexport function readRuntime(opts: { param?: ParamSource; overrides?: Partial<RuntimeConfig>; defaultRgsUrl?: string } = {}): RuntimeConfig {\n const param = opts.param ?? urlParam;\n const rawLang = param('lang');\n const language = rawLang === 'br' ? 'pt' : rawLang || 'en';\n const base: RuntimeConfig = {\n rgsUrl: param('rgs_url') ?? param('rgsUrl') ?? opts.defaultRgsUrl ?? 'http://localhost:4758',\n sessionId: param('sessionID') ?? param('sessionId') ?? 'dev',\n language,\n currency: param('currency') ?? 'USD',\n social: param('social') === 'true',\n device: param('device') ?? '',\n demo: param('demo') === 'true',\n replay: {\n active: param('replay') === 'true',\n amount: Number(param('amount')) || 0,\n game: param('game') ?? '',\n version: param('version') ?? '',\n mode: param('mode') ?? '',\n event: param('event') ?? '',\n },\n };\n return { ...base, ...opts.overrides, replay: { ...base.replay, ...opts.overrides?.replay } };\n}\n","// StakeNetworkManager — the ONLY thing that speaks the Stake RGS wire. Thin: it\n// returns RAW protocol shapes; the engine (SpinPhase/boot) owns the end-round settle\n// + active-round resume. Money: RGS = API units (×1e6); the game's book = BOOK units.\n\nimport {\n API_AMOUNT_MULTIPLIER,\n type AuthenticateResponse,\n type EndRoundResponse,\n type PlayResponse,\n type ReplayParams,\n type Round,\n} from './protocol';\nimport type { NetworkManager, PlayArgs } from './network';\n\nexport interface StakeNetworkOptions {\n rgsUrl: string;\n sessionId: string;\n /** REQUIRED — `/wallet/authenticate` 400s without it. */\n language: string;\n}\n\nexport class StakeNetworkManager implements NetworkManager {\n private readonly base: string;\n /** Currency learned at authenticate; sent on every `/wallet/play`. */\n private currency = 'USD';\n\n constructor(private readonly opts: StakeNetworkOptions) {\n this.base = /^https?:\\/\\//.test(opts.rgsUrl) ? opts.rgsUrl : `https://${opts.rgsUrl}`;\n }\n\n async authenticate(): Promise<AuthenticateResponse> {\n const res = await this.post<AuthenticateResponse>('/wallet/authenticate', {\n sessionID: this.opts.sessionId,\n language: this.opts.language,\n });\n this.currency = res.balance.currency;\n return res;\n }\n\n async play(args: PlayArgs): Promise<PlayResponse> {\n return this.post<PlayResponse>('/wallet/play', {\n sessionID: this.opts.sessionId,\n currency: args.currency ?? this.currency,\n amount: Math.round(args.bet * API_AMOUNT_MULTIPLIER),\n mode: args.mode,\n });\n }\n\n async endRound(): Promise<EndRoundResponse> {\n return this.post<EndRoundResponse>('/wallet/end-round', { sessionID: this.opts.sessionId });\n }\n\n async replay(p: ReplayParams): Promise<Round> {\n const path = `/bet/replay/${encodeURIComponent(p.game)}/${encodeURIComponent(p.version)}/${encodeURIComponent(p.mode)}/${encodeURIComponent(p.event)}`;\n const res = await this.get<Record<string, unknown>>(path);\n // The RGS may return `{ round }` or the round object directly.\n return (res.round ?? res) as Round;\n }\n\n private async post<T>(path: string, body: unknown): Promise<T> {\n const res = await fetch(this.base + path, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(`[StakeNetworkManager] ${path} -> ${res.status} ${text}`);\n }\n return (await res.json()) as T;\n }\n\n private async get<T>(path: string): Promise<T> {\n const res = await fetch(this.base + path, { method: 'GET', headers: { accept: 'application/json' } });\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(`[StakeNetworkManager] ${path} -> ${res.status} ${text}`);\n }\n return (await res.json()) as T;\n }\n}\n","// The transport seam. Adapters return RAW protocol shapes; the engine applies the\n// game's `interpretBook` and owns the round lifecycle (settle / resume).\n\nimport type { AuthenticateResponse, EndRoundResponse, PlayResponse, ReplayParams, Round } from './protocol';\nimport type { RuntimeConfig } from './runtime';\nimport { StakeNetworkManager } from './StakeNetworkManager';\nimport { MockNetworkManager } from './MockNetworkManager';\n\nexport interface PlayArgs {\n /** Base bet in MAJOR units (the transport converts to API units). */\n bet: number;\n /** Mode key — base / a boost / a bonus buy. The platform applies its cost. */\n mode: string;\n /** Currency code; defaults to the one learned at authenticate. */\n currency?: string;\n}\n\nexport interface NetworkManager {\n authenticate(): Promise<AuthenticateResponse>;\n play(args: PlayArgs): Promise<PlayResponse>;\n endRound(): Promise<EndRoundResponse>;\n /** Optional — fetch a recorded round for read-only replay. */\n replay?(params: ReplayParams): Promise<Round>;\n dispose?(): void;\n}\n\n/**\n * Pick the transport from the runtime: `?demo=true` (or a supplied `mock`) → the\n * in-process mock RGS; otherwise the real Stake transport.\n */\nexport function createNetwork(runtime: RuntimeConfig, mock?: MockNetworkManager): NetworkManager {\n if (runtime.demo || mock) return mock ?? new MockNetworkManager();\n return new StakeNetworkManager({\n rgsUrl: runtime.rgsUrl,\n sessionId: runtime.sessionId,\n language: runtime.language,\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"rgs.js","names":[],"sources":["../src/rgs/runtime.ts","../src/rgs/StakeNetworkManager.ts","../src/rgs/network.ts"],"sourcesContent":["/**\n * Stake launch parameters (mirrors `StakeEngine/web-sdk`\n * `packages/state-shared/src/stateUrl`): sessionID, rgs_url, lang, currency, device,\n * social, demo — plus the REPLAY set: replay, amount, game, version, mode, event.\n * `lang` is REQUIRED by `/wallet/authenticate` (its absence 400s the RGS).\n */\n\nexport interface ReplayLaunch {\n /** `?replay=true` — launch into replay (fetch + play back a recorded round). */\n active: boolean;\n amount: number;\n game: string;\n version: string;\n mode: string;\n event: string;\n}\n\nexport interface RuntimeConfig {\n rgsUrl: string;\n /**\n * True when a real `rgs_url`/`rgsUrl` launch param was present (vs falling back to the\n * local default). A provided host means \"talk to it\" — this is what tells the transport\n * picker to use the REAL Stake RGS, even for a `demo` fun-play launch. Set it in\n * `overrides` to force the real transport when you supply `rgsUrl` programmatically.\n */\n rgsUrlProvided: boolean;\n sessionId: string;\n /** BCP-47-ish language for `/wallet/authenticate` + the HUD locale ('br' → 'pt'). */\n language: string;\n /** `?currency=` — currency code (used for replay, where there's no wallet to read it). */\n currency: string;\n /** `?social=true` — force Stake US social/sweepstakes wording. */\n social: boolean;\n /** `?device=` — Stake's viewport hint ('' | 'desktop' | 'mobile' | a small popout). */\n device: string;\n /**\n * `?demo=true` — Stake FUN-PLAY: a demo (non-cash) wallet on the REAL RGS. This is NOT a\n * \"use a fake backend\" switch — Stake's own local-redirect dev tool launches\n * `…?rgs_url=rgsd.stake-engine.com&sessionID=…&demo=true`, and that session still\n * authenticates + plays against the real RGS. To run the in-process mock, use `?mock=true`.\n */\n demo: boolean;\n /**\n * `?mock=true` — force the built-in in-process mock RGS (no backend). For pure client dev\n * without a real session; distinct from Stake's `demo` fun-play. Overrides `rgs_url`.\n */\n mock: boolean;\n replay: ReplayLaunch;\n}\n\ntype ParamSource = (name: string) => string | undefined;\n\n/** Read a URL param from `window.location.search` (undefined off-DOM). */\nexport function urlParam(name: string): string | undefined {\n if (typeof window === 'undefined') return undefined;\n return new URLSearchParams(window.location.search).get(name) ?? undefined;\n}\n\n/**\n * Parse the Stake launch params into a {@link RuntimeConfig}. Pass `overrides` (or a\n * custom `param` reader) for tests/embedding; otherwise reads the page URL. `rgsUrl`\n * defaults to a local emulator so `pnpm dev` works out of the box.\n */\nexport function readRuntime(opts: { param?: ParamSource; overrides?: Partial<RuntimeConfig>; defaultRgsUrl?: string } = {}): RuntimeConfig {\n const param = opts.param ?? urlParam;\n const rawLang = param('lang');\n const language = rawLang === 'br' ? 'pt' : rawLang || 'en';\n const rgsUrlParam = param('rgs_url') ?? param('rgsUrl');\n const base: RuntimeConfig = {\n rgsUrl: rgsUrlParam ?? opts.defaultRgsUrl ?? 'http://localhost:4758',\n rgsUrlProvided: rgsUrlParam != null,\n sessionId: param('sessionID') ?? param('sessionId') ?? 'dev',\n language,\n currency: param('currency') ?? 'USD',\n social: param('social') === 'true',\n device: param('device') ?? '',\n demo: param('demo') === 'true',\n mock: param('mock') === 'true',\n replay: {\n active: param('replay') === 'true',\n amount: Number(param('amount')) || 0,\n game: param('game') ?? '',\n version: param('version') ?? '',\n mode: param('mode') ?? '',\n event: param('event') ?? '',\n },\n };\n return { ...base, ...opts.overrides, replay: { ...base.replay, ...opts.overrides?.replay } };\n}\n\n/**\n * True when the game was launched by the Stake platform — i.e. a real `rgs_url` was provided\n * (the dev dashboard's \"local redirect\", or a live launch) and the in-process mock wasn't\n * forced with `?mock=true`. This holds for `demo=true` fun-play launches too: they still run\n * against the real RGS.\n *\n * A game gates its local dev mock on `!isStakeLaunch()` — so bare `pnpm dev` uses the mock,\n * while a Stake launch auto-connects to the real RGS with the launch `sessionID`, no code edit.\n */\nexport function isStakeLaunch(runtime: RuntimeConfig = readRuntime()): boolean {\n return runtime.rgsUrlProvided && !runtime.mock;\n}\n","// StakeNetworkManager — the ONLY thing that speaks the Stake RGS wire. Thin: it\n// returns RAW protocol shapes; the engine (SpinPhase/boot) owns the end-round settle\n// + active-round resume. Money: RGS = API units (×1e6); the game's book = BOOK units.\n\nimport {\n API_AMOUNT_MULTIPLIER,\n type AuthenticateResponse,\n type EndRoundResponse,\n type PlayResponse,\n type ReplayParams,\n type Round,\n} from './protocol';\nimport type { NetworkManager, PlayArgs } from './network';\n\nexport interface StakeNetworkOptions {\n rgsUrl: string;\n sessionId: string;\n /** REQUIRED — `/wallet/authenticate` 400s without it. */\n language: string;\n}\n\nexport class StakeNetworkManager implements NetworkManager {\n private readonly base: string;\n /** Currency learned at authenticate; sent on every `/wallet/play`. */\n private currency = 'USD';\n\n constructor(private readonly opts: StakeNetworkOptions) {\n this.base = /^https?:\\/\\//.test(opts.rgsUrl) ? opts.rgsUrl : `https://${opts.rgsUrl}`;\n }\n\n async authenticate(): Promise<AuthenticateResponse> {\n const res = await this.post<AuthenticateResponse>('/wallet/authenticate', {\n sessionID: this.opts.sessionId,\n language: this.opts.language,\n });\n this.currency = res.balance.currency;\n return res;\n }\n\n async play(args: PlayArgs): Promise<PlayResponse> {\n return this.post<PlayResponse>('/wallet/play', {\n sessionID: this.opts.sessionId,\n currency: args.currency ?? this.currency,\n amount: Math.round(args.bet * API_AMOUNT_MULTIPLIER),\n mode: args.mode,\n });\n }\n\n async endRound(): Promise<EndRoundResponse> {\n return this.post<EndRoundResponse>('/wallet/end-round', { sessionID: this.opts.sessionId });\n }\n\n async replay(p: ReplayParams): Promise<Round> {\n const path = `/bet/replay/${encodeURIComponent(p.game)}/${encodeURIComponent(p.version)}/${encodeURIComponent(p.mode)}/${encodeURIComponent(p.event)}`;\n const res = await this.get<Record<string, unknown>>(path);\n // The RGS may return `{ round }` or the round object directly.\n return (res.round ?? res) as Round;\n }\n\n private async post<T>(path: string, body: unknown): Promise<T> {\n const res = await fetch(this.base + path, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(`[StakeNetworkManager] ${path} -> ${res.status} ${text}`);\n }\n return (await res.json()) as T;\n }\n\n private async get<T>(path: string): Promise<T> {\n const res = await fetch(this.base + path, { method: 'GET', headers: { accept: 'application/json' } });\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(`[StakeNetworkManager] ${path} -> ${res.status} ${text}`);\n }\n return (await res.json()) as T;\n }\n}\n","// The transport seam. Adapters return RAW protocol shapes; the engine applies the\n// game's `interpretBook` and owns the round lifecycle (settle / resume).\n\nimport type { AuthenticateResponse, EndRoundResponse, PlayResponse, ReplayParams, Round } from './protocol';\nimport type { RuntimeConfig } from './runtime';\nimport { StakeNetworkManager } from './StakeNetworkManager';\nimport { MockNetworkManager } from './MockNetworkManager';\n\nexport interface PlayArgs {\n /** Base bet in MAJOR units (the transport converts to API units). */\n bet: number;\n /** Mode key — base / a boost / a bonus buy. The platform applies its cost. */\n mode: string;\n /** Currency code; defaults to the one learned at authenticate. */\n currency?: string;\n}\n\nexport interface NetworkManager {\n authenticate(): Promise<AuthenticateResponse>;\n play(args: PlayArgs): Promise<PlayResponse>;\n endRound(): Promise<EndRoundResponse>;\n /** Optional — fetch a recorded round for read-only replay. */\n replay?(params: ReplayParams): Promise<Round>;\n dispose?(): void;\n}\n\n/**\n * Pick the transport from the launch runtime:\n *\n * - a supplied `mock` instance, or `?mock=true` → the in-process mock RGS (no backend)\n * - a real `rgs_url` was provided → the REAL Stake RGS. This INCLUDES a\n * `?demo=true` fun-play launch: a Stake demo session still authenticates + plays\n * against `rgs_url`, so `demo` must NOT force the mock.\n * - `?demo=true` with NO host → the mock (bare local click-around)\n * - otherwise → the real transport at the default\n * (local emulator) host\n *\n * This is the key fix over the old `demo → mock`: Stake's own local-redirect dev tool opens\n * `…?rgs_url=rgsd.stake-engine.com&sessionID=…&demo=true`. Under the old rule that demo\n * session was hijacked by the in-process mock and never reached the RGS; now it authorizes\n * on Stake, pulls the real balance/config, and spins/buys with real requests.\n */\nexport function createNetwork(runtime: RuntimeConfig, mock?: MockNetworkManager): NetworkManager {\n if (mock) return mock;\n if (runtime.mock) return new MockNetworkManager();\n if (runtime.rgsUrlProvided) return stakeTransport(runtime);\n if (runtime.demo) return new MockNetworkManager();\n return stakeTransport(runtime);\n}\n\nfunction stakeTransport(runtime: RuntimeConfig): StakeNetworkManager {\n return new StakeNetworkManager({\n rgsUrl: runtime.rgsUrl,\n sessionId: runtime.sessionId,\n language: runtime.language,\n });\n}\n"],"mappings":"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"}
package/dist/testing.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as MockOptions, i as MockNetworkManager, o as ScriptedRound } from "./network-pBW8CX1o.js";
1
+ import { a as MockOptions, i as MockNetworkManager, o as ScriptedRound } from "./network-CBxKQzeb.js";
2
2
  import { r as InstantTicker, t as HudPort } from "./hud-port-DNfotn4U.js";
3
3
  //#region src/testing/index.d.ts
4
4
  /** A recording no-op HudPort — inspect `.calls` in tests. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stakeplate/core",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Batteries-included Stake Engine game core — RGS transport, boot, round FSM, HUD binding, audio, i18n and a compliant rules builder. Bring a scene, a Present phase and a pure interpretBook; the core does the rest.",
5
5
  "keywords": [
6
6
  "stake",