@truelab/truelogic 4.3.0-9 → 4.3.2-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.
Files changed (25) hide show
  1. package/dist/628.min.js +1 -1
  2. package/dist/preloader.html +1 -1
  3. package/dist/truelogic.min.css +1 -1
  4. package/dist/truelogic.min.js +1 -1
  5. package/dist/types/src/app/lib/hooks/useGameLoadAnalytics.d.ts +11 -0
  6. package/dist/types/src/features/play/ui/PanelPlay/PanelPlay.d.ts +7 -1
  7. package/dist/types/src/features/play/ui/PanelPlay/PanelPlay.test.d.ts +1 -0
  8. package/dist/types/src/shared/lib/classes/analyticsService.d.ts +17 -4
  9. package/dist/types/src/shared/lib/classes/emitter.d.ts +2 -0
  10. package/dist/types/src/shared/lib/classes/emitter.test.d.ts +1 -0
  11. package/dist/types/src/shared/lib/classes/gameLoadTracker.d.ts +67 -0
  12. package/dist/types/src/shared/lib/classes/gameLoadTracker.test.d.ts +1 -0
  13. package/dist/types/src/shared/lib/functions/getLoadEnvironment.d.ts +12 -0
  14. package/dist/types/src/shared/lib/functions/getLoadEnvironment.test.d.ts +1 -0
  15. package/dist/types/src/shared/lib/functions/index.d.ts +1 -0
  16. package/dist/types/src/shared/lib/hooks/index.d.ts +2 -1
  17. package/dist/types/src/shared/lib/hooks/useHold.d.ts +26 -0
  18. package/dist/types/src/shared/lib/hooks/useHold.test.d.ts +1 -0
  19. package/dist/types/src/shared/lib/singletones/analyticsEmitter.d.ts +6 -0
  20. package/dist/types/src/shared/lib/singletones/gameLoadTracker.d.ts +2 -0
  21. package/dist/types/src/shared/lib/singletones/index.d.ts +1 -0
  22. package/dist/types/src/shared/modules/menuInnerPage.d.ts +7 -0
  23. package/package.json +6 -2
  24. package/dist/types/src/shared/lib/hooks/useHoldDown.d.ts +0 -1
  25. /package/dist/types/src/{shared/lib/hooks/useHoldDown.test.d.ts → app/lib/hooks/useGameLoadAnalytics.test.d.ts} +0 -0
@@ -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;
@@ -5,6 +5,12 @@ type TPanelPlayProps = {
5
5
  ref: RefObject<HTMLButtonElement>;
6
6
  /** Rendered as `data-state` so e2e tests can tell play from stop/skip without guessing by `disabled` */
7
7
  state?: TPanelPlayState;
8
+ /**
9
+ * The spin is held — a pointer on the button or a hotkey down; the panel owns the hold (useHold).
10
+ * Not `:active`: Blink sets that for a touch too late for a quick tap to show, and On_tap must
11
+ * stay until the player lets go even once the round it started has disabled the button (GTT-2754)
12
+ */
13
+ isPressed?: boolean;
8
14
  } & ButtonHTMLAttributes<HTMLButtonElement>;
9
- export declare const PanelPlay: ({ onClick, className, disabled, state, ref, ...props }: TPanelPlayProps) => import("react/jsx-runtime").JSX.Element;
15
+ export declare const PanelPlay: ({ onPointerDown, className, disabled, state, isPressed, ref, ...props }: TPanelPlayProps) => import("react/jsx-runtime").JSX.Element;
10
16
  export {};
@@ -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';
@@ -4,7 +4,8 @@ export { useElementInViewPort } from './useElementInViewPort';
4
4
  export { useElementsBottomCssVar } from './useElementsBottomCssVar';
5
5
  export { useEnv } from './useEnv';
6
6
  export { useGameTime } from './useGameTime';
7
- export { useHoldDown } from './useHoldDown';
7
+ export type { THoldSource } from './useHold';
8
+ export { useHold } from './useHold';
8
9
  export { useOffline } from './useOffline';
9
10
  export { useOrientationChange } from './useOrientationChange';
10
11
  export { usePageVisibility } from './usePageVisibility';
@@ -0,0 +1,26 @@
1
+ import { PointerEvent as ReactPointerEvent } from 'react';
2
+ export type THoldSource = 'pointer' | 'key';
3
+ type THoldOptions = {
4
+ /** The control is held while one of these keys is down (`KeyboardEvent.code`) */
5
+ keys?: readonly string[];
6
+ /** How long the control must stay held for `onHold` to fire */
7
+ holdDelay: number;
8
+ onPress?: (source: THoldSource) => void;
9
+ onHold?: (source: THoldSource) => void;
10
+ onRelease?: (source: THoldSource) => void;
11
+ /** Turning it off releases a hold in progress: a lock (a modal) must not leave the action stuck on */
12
+ isEnabled?: boolean;
13
+ };
14
+ /**
15
+ * One held state for a control pressed with a pointer (attach `onPointerDown` to it) or with
16
+ * hotkeys. The press fires `onPress`, a hold of `holdDelay` fires `onHold`, the release — pointerup
17
+ * or pointercancel anywhere in the document, keyup, window blur — fires `onRelease`. The latest
18
+ * press owns the hold: a second finger or key takes over instead of piling up. `isHeld` paints the
19
+ * control; it comes from the events themselves, not from `:active`, which Blink sets for a touch
20
+ * too late for a quick tap to show.
21
+ */
22
+ export declare const useHold: ({ keys, holdDelay, onPress, onHold, onRelease, isEnabled }: THoldOptions) => {
23
+ isHeld: boolean;
24
+ onPointerDown: (event: ReactPointerEvent<HTMLElement>) => void;
25
+ };
26
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -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';
@@ -8,6 +8,13 @@ type TMenuInnerPageContext = {
8
8
  page: TMenuInnerPage | null;
9
9
  openPage: (page: TMenuInnerPage) => void;
10
10
  closePage: () => void;
11
+ /**
12
+ * A box over the header row for the toasts of a page, drawn there through a portal. Anything
13
+ * positioned inside the tab content, `fixed` included, travels with it: the tab scroll moves
14
+ * the content with a transform.
15
+ */
16
+ headerOverlay: HTMLElement | null;
17
+ setHeaderOverlay: (element: HTMLElement | null) => void;
11
18
  };
12
19
  type TProps = {
13
20
  children: ReactNode;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truelab/truelogic",
3
- "version": "4.3.0-9",
3
+ "version": "4.3.2-0",
4
4
  "description": "",
5
5
  "main": "./dist/truelogic.min.js",
6
6
  "types": "./dist/types/src/index.d.ts",
@@ -58,7 +58,11 @@
58
58
  "test:e2e:ui": "playwright test --project=sandbox --ui",
59
59
  "test:e2e:ui:game": "playwright test --project=game --ui",
60
60
  "test:e2e:report": "playwright show-report",
61
- "test:e2e:typecheck": "tsc -p tests/e2e/tsconfig.json"
61
+ "test:e2e:typecheck": "tsc -p tests/e2e/tsconfig.json",
62
+ "email:install": "npm install --prefix ./email-letters",
63
+ "email:dev": "npm run dev --prefix ./email-letters",
64
+ "email:export": "npm run export --prefix ./email-letters",
65
+ "email:send-test": "npm run send-test --prefix ./email-letters --"
62
66
  },
63
67
  "browserslist": [
64
68
  "defaults and supports es6-module"
@@ -1 +0,0 @@
1
- export declare const useHoldDown: (button: "Space" | "Enter", onKeyDown: () => void, onKeyUp: () => void, keyDownDelay?: number, isEnabled?: boolean) => void;