@truelab/truelogic 4.3.3 → 4.4.0-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Game load telemetry (GTT-2800). Marks the load timeline on the tracker and reports it to analytics:
3
+ * a `gameLoad.phase:completed` event the moment each phase is over (CDN, init, preload, loading, game
4
+ * code), then one terminal event per load — `gameLoad:completed` when the game calls `setGameReady()`,
5
+ * `gameLoad:failed` on the failed screen, `gameLoad:abandoned` when the page is hidden before the
6
+ * main screen — and `gameLoad:finished` once the main screen is reached.
7
+ *
8
+ * Every payload carries `metrics` and the `environment` the tracker reads once on mount, so each
9
+ * event is self-contained. `init` marks are set in `truelogic.init()` itself: the hook mounts inside it.
10
+ */
11
+ export declare const useGameLoadAnalytics: () => void;
@@ -1,5 +1,8 @@
1
- type TAnalyticsParameterValue = boolean | number | string;
2
- export type TAnalyticsCustomParams = Record<string, TAnalyticsParameterValue | undefined>;
1
+ type TAnalyticsParameterValue = boolean | number | string | TAnalyticsCustomParams;
2
+ /** Event parameters; nested objects are allowed — GTM reads them with dot paths (`metrics.init_ms`) */
3
+ export type TAnalyticsCustomParams = {
4
+ [name: string]: TAnalyticsParameterValue | undefined;
5
+ };
3
6
  export declare enum EAnalyticsEvents {
4
7
  modeReal = "mode_real",
5
8
  modeDemo = "mode_demo",
@@ -38,14 +41,24 @@ export declare enum EAnalyticsEvents {
38
41
  spinHold = "spin_hold",
39
42
  bonusPurchase = "bonus_purchase",
40
43
  bonusBetActivate = "bonus_bet_activate",
41
- timeToBuyBonus = "time_to_buy_bonus"
44
+ timeToBuyBonus = "time_to_buy_bonus",
45
+ gameLoadCdn = "game_load_cdn",
46
+ gameLoadInit = "game_load_init",
47
+ gameLoadPreload = "game_load_preload",
48
+ gameLoadLoading = "game_load_loading",
49
+ gameLoadGameCode = "game_load_game_code",
50
+ gameLoadTime = "game_load_time",
51
+ gameLoadFailed = "game_load_failed",
52
+ gameLoadAbandoned = "game_load_abandoned",
53
+ gameLoadEnv = "game_load_env"
42
54
  }
43
55
  export declare enum EAnalyticsCategories {
44
56
  settings = "settings_changes",
45
57
  ui = "ui_interaction",
46
58
  gameplay = "gameplay_events",
47
59
  mode = "game_mode",
48
- config = "session_config"
60
+ config = "session_config",
61
+ performance = "performance"
49
62
  }
50
63
  export type TEventOptions = {
51
64
  value?: number;
@@ -5,6 +5,8 @@ export declare abstract class Emitter<TEvents extends Record<keyof TEvents, TVoi
5
5
  protected listenersOneTime: Map<keyof TEvents, TVoidFunc[]>;
6
6
  on<K extends keyof TEvents>(event: K, listener: TEvents[K]): this;
7
7
  once<K extends keyof TEvents>(event: K, listener: TEvents[K]): this;
8
+ /** Removes a listener added with `on` or `once`; unknown listeners are ignored */
9
+ off<K extends keyof TEvents>(event: K, listener: TEvents[K]): this;
8
10
  emit<K extends keyof TEvents>(event: K, ...args: Parameters<TEvents[K]>): void;
9
11
  abstract log(event: unknown, ...args: unknown[]): void;
10
12
  }
@@ -0,0 +1,67 @@
1
+ import { TAnalyticsCustomParams } from './analyticsService';
2
+ /**
3
+ * Points on the game load timeline, from the bundle evaluation to the main screen.
4
+ * `*:called` marks are the host game calling a public method, the rest are TrueLogic reaching a state.
5
+ */
6
+ export type TGameLoadMark = 'init:called' | 'init:resolved' | 'session:started' | 'session:ended' | 'configure:called' | 'configure:succeed' | 'preload.images:ended' | 'preload.nonCritical:ended' | 'startLoading:called' | 'endLoading:called' | 'loading:ended' | 'ready:called' | 'welcome:shown' | 'main:shown';
7
+ /** The furthest point a load reached — the `stage` of `game_load_failed` and `game_load_abandoned` */
8
+ export type TGameLoadStage = 'script' | 'init' | 'configure' | 'loading' | 'loading_tail' | 'ready_wait' | 'welcome' | 'main';
9
+ /** Load phases reported as separate events the moment they complete — one dashboard row each */
10
+ export type TGameLoadPhase = 'cdn' | 'init' | 'preload' | 'loading' | 'game_code';
11
+ export type TGameLoadError = {
12
+ name?: string;
13
+ message?: string;
14
+ code?: number;
15
+ };
16
+ export type TGameLoadMarkListener = (mark: TGameLoadMark) => void;
17
+ /** Marks left by the inline preloader loader (`src/app/templates/preloader-loader.ts`) around the CDN fetch */
18
+ export declare const GAME_LOAD_LOADER_MARK_START = "truelogic:loader:start";
19
+ export declare const GAME_LOAD_LOADER_MARK_END = "truelogic:loader:end";
20
+ /**
21
+ * Collects the game load timeline (GTT-2800). All times are `performance.now()` values, so they
22
+ * count from the page open (`performance.timeOrigin`), the same origin as the loader marks.
23
+ *
24
+ * Every payload groups the measured values under `metrics` and carries the same `environment`
25
+ * (what the browser reports about the network, the device and the embedding), read once per load.
26
+ * Phases (`completePhase`) go out as soon as they are over. Every load also ends in exactly one
27
+ * terminal payload: `complete()` when the game calls `setGameReady()`, `fail()` on the failed screen
28
+ * or `abandon()` when the page is hidden earlier. The welcome screen comes after `complete()`, so a
29
+ * load can still be abandoned there; `finish()` closes it on the main screen.
30
+ */
31
+ export declare class GameLoadTracker {
32
+ private marks;
33
+ private listeners;
34
+ private sentPhases;
35
+ private environment;
36
+ private scriptStartMs;
37
+ private progressTicks;
38
+ private tabHidden;
39
+ private isCompleted;
40
+ private isClosed;
41
+ constructor();
42
+ /** Records the first occurrence of a mark and notifies the subscribers; later calls are ignored */
43
+ mark(name: TGameLoadMark): void;
44
+ has(name: TGameLoadMark): boolean;
45
+ /** Called on every new mark; returns the unsubscribe function */
46
+ subscribe(listener: TGameLoadMarkListener): () => void;
47
+ /** One `setLoadingProgress()` call of the game */
48
+ tickProgress(): void;
49
+ /** Reads the browser environment once per load; call it early so no event waits for the probes */
50
+ collectEnvironment(): TAnalyticsCustomParams;
51
+ getStage(): TGameLoadStage;
52
+ /** Every measured value known so far; a duration is left out while one of its marks is missing */
53
+ getMetrics(): TAnalyticsCustomParams;
54
+ /** A phase is over: its `game_load_<phase>` payload, once per load and never after the load is closed */
55
+ completePhase(phase: TGameLoadPhase): TAnalyticsCustomParams | null;
56
+ /** The game called `setGameReady()`: the `game_load_time` payload, once per load */
57
+ complete(): TAnalyticsCustomParams | null;
58
+ /** The failed screen before the game was ready: the `game_load_failed` payload, once per load */
59
+ fail(error?: TGameLoadError | null): TAnalyticsCustomParams | null;
60
+ /** The page is hidden before the main screen: the `game_load_abandoned` payload, once per load */
61
+ abandon(): TAnalyticsCustomParams | null;
62
+ /** The main screen is shown: closes the load and returns the welcome screen dwell, once per load */
63
+ finish(): TAnalyticsCustomParams | null;
64
+ /** Test helper: a fresh load on the same instance (subscribers stay) */
65
+ reset(): void;
66
+ private diff;
67
+ }
@@ -0,0 +1,12 @@
1
+ export type TLoadEnvironment = Record<string, boolean | number | string | undefined>;
2
+ /**
3
+ * What the browser reports about the conditions of this game load (GTT-2800): network, HTML and bundle
4
+ * delivery, device capabilities, embedding. Read once per load by `GameLoadTracker` and attached as
5
+ * the `environment` object to every `game_load_*` event.
6
+ *
7
+ * Every field is optional: a browser without the API, or an API that cannot tell, leaves the field
8
+ * out — nothing is reported as `0`, `null` or a guess. See the field docs on the helpers above for
9
+ * units, ranges and browser support; the dashboard-side description lives in
10
+ * `docs/docs/development/analytics.md` → "environment fields".
11
+ */
12
+ export declare const getLoadEnvironment: () => TLoadEnvironment;
@@ -7,6 +7,7 @@ export { formatCount } from './formatCount';
7
7
  export { formatDate } from './formatDate';
8
8
  export { formatTime } from './formatTime';
9
9
  export { getBase64Image } from './getBase64Image';
10
+ export { getLoadEnvironment } from './getLoadEnvironment';
10
11
  export { getSafeLocale } from './getSafeLocale';
11
12
  export { getUrlParam } from './getUrlParam';
12
13
  export { isE2E } from './isE2E';
@@ -12,6 +12,9 @@ import { ForwardedRef, RefObject } from 'react';
12
12
  * is clickable (has a click handler of its own, or `cursor: pointer`); a document-level listener
13
13
  * alone does not make it so. A `click` caller keeps its outside area clickable — the modal scrims
14
14
  * carry `cursor-pointer` for exactly this.
15
+ *
16
+ * A `click` ends a press, and only a press begun after the enabling counts: a spin held while a
17
+ * modal opens (the round error arrives, there are no funds) must not close it with the release.
15
18
  */
16
19
  export type TClickOutsideEvent = 'pointerdown' | 'click';
17
20
  export declare const useClickOutside: (refs: (RefObject<HTMLElement> | ForwardedRef<HTMLElement>)[], onClick: (event: MouseEvent | TouchEvent) => void, isEnabled?: boolean, eventName?: TClickOutsideEvent) => void;
@@ -20,7 +20,8 @@ type THoldOptions = {
20
20
  * One held state for a control pressed with a pointer (attach `onPointerDown` to it) or with
21
21
  * hotkeys. The press fires `onPress`, a hold of `holdDelay` fires `onHold`, the release — pointerup
22
22
  * or pointercancel anywhere in the document, keyup, window blur — fires `onRelease`. The latest
23
- * press owns the hold: a second finger or key takes over instead of piling up. `isHeld` paints the
23
+ * press owns the hold: a second finger or key takes over instead of piling up. A key pressed before
24
+ * the hook got enabled (mounted) is not a press of this control. `isHeld` paints the
24
25
  * control; it comes from the events themselves, not from `:active`, which Blink sets for a touch
25
26
  * too late for a quick tap to show.
26
27
  */
@@ -1,5 +1,6 @@
1
1
  import { TSessionMode } from '../../../shared/api/config';
2
2
  import { TAnalyticsCustomParams } from '../../../shared/lib/classes/analyticsService';
3
+ import { TGameLoadPhase } from '../../../shared/lib/classes/gameLoadTracker';
3
4
  import { Emitter } from '../classes';
4
5
  import { TOrientation } from '../types/viewPort';
5
6
  type TEventOptions = {
@@ -99,6 +100,11 @@ export type TAnalyticsEvents = {
99
100
  ['walletConvertSuccess:continuePlayingClicked']: (params: TAnalyticsCustomParams) => void;
100
101
  ['bonus:purchase']: (options: TEventOptions) => void;
101
102
  ['bonus:betActivate']: (options: TEventOptions) => void;
103
+ ['gameLoad.phase:completed']: (phase: TGameLoadPhase, params: TAnalyticsCustomParams) => void;
104
+ ['gameLoad:completed']: (params: TAnalyticsCustomParams) => void;
105
+ ['gameLoad:failed']: (params: TAnalyticsCustomParams) => void;
106
+ ['gameLoad:abandoned']: (params: TAnalyticsCustomParams) => void;
107
+ ['gameLoad:finished']: (params: TAnalyticsCustomParams) => void;
102
108
  };
103
109
  export declare class AnalyticsEmitter extends Emitter<TAnalyticsEvents> {
104
110
  log(event: string, ...args: unknown[]): void;
@@ -0,0 +1,2 @@
1
+ import { GameLoadTracker } from '../classes/gameLoadTracker';
2
+ export declare const gameLoadTracker: GameLoadTracker;
@@ -4,6 +4,7 @@ export { api } from './api';
4
4
  export { cashService } from './cashService';
5
5
  export type { TStakeResponse } from './gameEmitter';
6
6
  export { gameEmitter } from './gameEmitter';
7
+ export { gameLoadTracker } from './gameLoadTracker';
7
8
  export { logger } from './logger';
8
9
  export { moduleEmitter } from './moduleEmitter';
9
10
  export { utilsService } from './utilsService';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truelab/truelogic",
3
- "version": "4.3.3",
3
+ "version": "4.4.0-2",
4
4
  "description": "",
5
5
  "main": "./dist/truelogic.min.js",
6
6
  "types": "./dist/types/src/index.d.ts",