@escapenavigator/types 1.10.168 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,44 @@
1
+ import { WidgetFunnelKindEnum } from './widget-funnel-kind.enum';
2
+ import { WidgetFunnelStepEnum } from './widget-funnel-step.enum';
3
+ /**
4
+ * Реестр «измерений» (dimensions) воронки — параметров шага, по которым
5
+ * мы режем конверсию (например: сколько доп.услуг предложено на шаге
6
+ * выбора игроков). ЕДИНЫЙ источник правды:
7
+ * • бэк (`rollupDay`) использует `bucketize`, чтобы сгруппировать сырое
8
+ * значение `meta[metaKey]` в низко-кардинальный бакет;
9
+ * • фронт админки использует `label` / `buckets[].label` для отрисовки.
10
+ *
11
+ * Значение измерения кладётся виджетом в `meta` события того шага, где
12
+ * параметр уже известен (см. funnelTracker.track(kind, step, meta)).
13
+ * Бакетирование делаем на бэке, чтобы менять границы без передеплоя
14
+ * embed-виджета.
15
+ */
16
+ export type WidgetFunnelDimensionBucket = {
17
+ /** Канонический ключ бакета (хранится в БД, стабилен). */
18
+ value: string;
19
+ /** Подпись для админ-UI. */
20
+ label: string;
21
+ };
22
+ export type WidgetFunnelDimensionDef = {
23
+ /** Стабильный id измерения (ключ в dim-кэше). */
24
+ id: string;
25
+ kind: WidgetFunnelKindEnum;
26
+ /** Шаг, на котором параметр известен и берётся из meta. */
27
+ step: WidgetFunnelStepEnum;
28
+ /** Ключ в объекте meta события этого шага. */
29
+ metaKey: string;
30
+ /** Заголовок измерения для UI. */
31
+ label: string;
32
+ /** Упорядоченный список бакетов (порядок = порядок отрисовки). */
33
+ buckets: WidgetFunnelDimensionBucket[];
34
+ /** Сырое значение meta → ключ бакета (или null = пропустить сессию). */
35
+ bucketize: (raw: unknown) => string | null;
36
+ };
37
+ /**
38
+ * Все измерения. Сейчас покрыта booking-воронка (три шага из примеров +
39
+ * близкие параметры оплаты). Сертификатная воронка добавляется сюда же
40
+ * по мере появления эмиссии meta на её шагах.
41
+ */
42
+ export declare const WIDGET_FUNNEL_DIMENSIONS: WidgetFunnelDimensionDef[];
43
+ /** Измерения, привязанные к конкретному виду воронки. */
44
+ export declare const getDimensionsForKind: (kind: WidgetFunnelKindEnum) => WidgetFunnelDimensionDef[];
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getDimensionsForKind = exports.WIDGET_FUNNEL_DIMENSIONS = void 0;
4
+ const widget_funnel_kind_enum_1 = require("./widget-funnel-kind.enum");
5
+ const widget_funnel_step_enum_1 = require("./widget-funnel-step.enum");
6
+ /** Бакетер чисел по списку правил «первое подходящее». */
7
+ const numberBucketizer = (rules) => (raw) => {
8
+ var _a, _b;
9
+ const n = typeof raw === 'number' ? raw : Number(raw);
10
+ if (!Number.isFinite(n))
11
+ return null;
12
+ return (_b = (_a = rules.find((r) => r.test(n))) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : null;
13
+ };
14
+ /** Бакетер булева флага (принимает boolean ИЛИ 'true'/'false'). */
15
+ const boolBucketizer = (raw) => {
16
+ if (typeof raw === 'boolean')
17
+ return raw ? 'yes' : 'no';
18
+ if (raw === 'true' || raw === 'false')
19
+ return raw === 'true' ? 'yes' : 'no';
20
+ return null;
21
+ };
22
+ const YES_NO_BUCKETS = [
23
+ { value: 'yes', label: 'Есть' },
24
+ { value: 'no', label: 'Нет' },
25
+ ];
26
+ /**
27
+ * Все измерения. Сейчас покрыта booking-воронка (три шага из примеров +
28
+ * близкие параметры оплаты). Сертификатная воронка добавляется сюда же
29
+ * по мере появления эмиссии meta на её шагах.
30
+ */
31
+ exports.WIDGET_FUNNEL_DIMENSIONS = [
32
+ {
33
+ id: 'upsellsOffered',
34
+ kind: widget_funnel_kind_enum_1.WidgetFunnelKindEnum.BOOKING,
35
+ step: widget_funnel_step_enum_1.WidgetFunnelStepEnum.PLAYERS_STEP,
36
+ metaKey: 'upsellsOffered',
37
+ label: 'Доп. услуги предложено',
38
+ buckets: [
39
+ { value: 'none', label: 'Нет доп. услуг' },
40
+ { value: '1-3', label: '1–3 услуги' },
41
+ { value: '3+', label: 'Больше трёх' },
42
+ ],
43
+ bucketize: numberBucketizer([
44
+ { test: (n) => n <= 0, value: 'none' },
45
+ { test: (n) => n <= 3, value: '1-3' },
46
+ { test: () => true, value: '3+' },
47
+ ]),
48
+ },
49
+ {
50
+ id: 'seatsUrgency',
51
+ kind: widget_funnel_kind_enum_1.WidgetFunnelKindEnum.BOOKING,
52
+ step: widget_funnel_step_enum_1.WidgetFunnelStepEnum.PLAYERS_STEP,
53
+ metaKey: 'seatsUrgency',
54
+ label: 'Показана срочность («осталось N мест»)',
55
+ buckets: YES_NO_BUCKETS,
56
+ bucketize: boolBucketizer,
57
+ },
58
+ {
59
+ id: 'clientFieldsCount',
60
+ kind: widget_funnel_kind_enum_1.WidgetFunnelKindEnum.BOOKING,
61
+ step: widget_funnel_step_enum_1.WidgetFunnelStepEnum.CLIENT_STEP,
62
+ metaKey: 'clientFieldsCount',
63
+ label: 'Полей в форме контактов',
64
+ buckets: [
65
+ { value: '0-3', label: '≤ 3 поля' },
66
+ { value: '4-6', label: '4–6 полей' },
67
+ { value: '6+', label: '> 6 полей' },
68
+ ],
69
+ bucketize: numberBucketizer([
70
+ { test: (n) => n <= 3, value: '0-3' },
71
+ { test: (n) => n <= 6, value: '4-6' },
72
+ { test: () => true, value: '6+' },
73
+ ]),
74
+ },
75
+ {
76
+ id: 'payWithoutPayment',
77
+ kind: widget_funnel_kind_enum_1.WidgetFunnelKindEnum.BOOKING,
78
+ step: widget_funnel_step_enum_1.WidgetFunnelStepEnum.PAYMENT_STEP,
79
+ metaKey: 'payWithoutPayment',
80
+ label: 'Доступно «записаться без оплаты»',
81
+ buckets: YES_NO_BUCKETS,
82
+ bucketize: boolBucketizer,
83
+ },
84
+ {
85
+ id: 'paymentMethodsCount',
86
+ kind: widget_funnel_kind_enum_1.WidgetFunnelKindEnum.BOOKING,
87
+ step: widget_funnel_step_enum_1.WidgetFunnelStepEnum.PAYMENT_STEP,
88
+ metaKey: 'paymentMethodsCount',
89
+ label: 'Способов оплаты',
90
+ buckets: [
91
+ { value: '1', label: '1 способ' },
92
+ { value: '2', label: '2 способа' },
93
+ { value: '3+', label: '3 и более' },
94
+ ],
95
+ bucketize: numberBucketizer([
96
+ { test: (n) => n <= 1, value: '1' },
97
+ { test: (n) => n === 2, value: '2' },
98
+ { test: () => true, value: '3+' },
99
+ ]),
100
+ },
101
+ {
102
+ id: 'prepaymentAvailable',
103
+ kind: widget_funnel_kind_enum_1.WidgetFunnelKindEnum.BOOKING,
104
+ step: widget_funnel_step_enum_1.WidgetFunnelStepEnum.PAYMENT_STEP,
105
+ metaKey: 'prepaymentAvailable',
106
+ label: 'Доступна предоплата (half)',
107
+ buckets: YES_NO_BUCKETS,
108
+ bucketize: boolBucketizer,
109
+ },
110
+ ];
111
+ /** Измерения, привязанные к конкретному виду воронки. */
112
+ const getDimensionsForKind = (kind) => exports.WIDGET_FUNNEL_DIMENSIONS.filter((d) => d.kind === kind);
113
+ exports.getDimensionsForKind = getDimensionsForKind;
@@ -14,6 +14,37 @@ export type WidgetFunnelStepRO = {
14
14
  /** P90 stepConversion по компаниям — только в cross-company. */
15
15
  benchmarkP90?: number | null;
16
16
  };
17
+ /** Один бакет измерения с локальной и сквозной конверсией. */
18
+ export type WidgetFunnelDimensionBucketRO = {
19
+ /** Канонический ключ бакета (см. реестр измерений). */
20
+ value: string;
21
+ /** Подпись бакета для UI. */
22
+ label: string;
23
+ /** Сессий на шаге измерения с этим значением. */
24
+ sessions: number;
25
+ /** Из них дошли до следующего шага. */
26
+ nextStepSessions: number;
27
+ /** Из них дошли до покупки (последний шаг воронки). */
28
+ purchasedSessions: number;
29
+ /** Локальная конверсия: nextStepSessions / sessions (0..1). */
30
+ stepConversion: number | null;
31
+ /** Сквозная конверсия: purchasedSessions / sessions (0..1). */
32
+ overallConversion: number | null;
33
+ };
34
+ /** Разрез одного шага воронки по значениям параметра. */
35
+ export type WidgetFunnelDimensionRO = {
36
+ /** id измерения из реестра. */
37
+ id: string;
38
+ /** Шаг, к которому привязано измерение. */
39
+ step: WidgetFunnelStepEnum;
40
+ /** Заголовок измерения. */
41
+ label: string;
42
+ /** Базовая (по всем бакетам) локальная конверсия шага — для дельт. */
43
+ baselineStepConversion: number | null;
44
+ /** Базовая сквозная конверсия шага → покупка. */
45
+ baselineOverallConversion: number | null;
46
+ buckets: WidgetFunnelDimensionBucketRO[];
47
+ };
17
48
  /** Воронка одной компании (или платформы) за период. */
18
49
  export type WidgetFunnelRO = {
19
50
  profileId: number;
@@ -28,6 +59,8 @@ export type WidgetFunnelRO = {
28
59
  conversions: number;
29
60
  /** conversions / entries (0..1). */
30
61
  overallConversion: number | null;
62
+ /** Разрезы шагов по параметрам (если запрошены/доступны). */
63
+ dimensions?: WidgetFunnelDimensionRO[];
31
64
  };
32
65
  /** Строка кросс-компанийной таблицы: одна компания + где она «течёт». */
33
66
  export type WidgetFunnelCompanyRO = {
@@ -50,3 +83,51 @@ export type WidgetFunnelCrossCompanyRO = {
50
83
  /** Список компаний, отсортированный по overallConversion. */
51
84
  companies: WidgetFunnelCompanyRO[];
52
85
  };
86
+ /** Период сравнения: границы + воронка за этот период. */
87
+ export type WidgetFunnelComparePeriodRO = {
88
+ /** YYYY-MM-DD (UTC). */
89
+ from: string;
90
+ /** YYYY-MM-DD (UTC). */
91
+ to: string;
92
+ funnel: WidgetFunnelRO;
93
+ };
94
+ /** Дельта конверсии одного шага между текущим и базовым периодами. */
95
+ export type WidgetFunnelStepDeltaRO = {
96
+ step: WidgetFunnelStepEnum;
97
+ /** Локальная конверсия шага в текущем периоде. */
98
+ current: number | null;
99
+ /** Локальная конверсия шага в базовом периоде. */
100
+ previous: number | null;
101
+ /** current - previous в долях (умножить на 100 для п.п.). */
102
+ delta: number | null;
103
+ };
104
+ /**
105
+ * Сравнение двух периодов (по умолчанию текущая неделя vs прошлая) —
106
+ * чтобы оценивать эффект апдейтов. Платформа (profileId=0) или компания.
107
+ */
108
+ export type WidgetFunnelCompareRO = {
109
+ kind: WidgetFunnelKindEnum;
110
+ profileId: number;
111
+ current: WidgetFunnelComparePeriodRO;
112
+ previous: WidgetFunnelComparePeriodRO;
113
+ stepDeltas: WidgetFunnelStepDeltaRO[];
114
+ /** Δ общей конверсии (current - previous) в долях. */
115
+ overallDelta: number | null;
116
+ };
117
+ /** Точка недельного тренда. */
118
+ export type WidgetFunnelTrendPointRO = {
119
+ /** Понедельник недели, YYYY-MM-DD (UTC). */
120
+ weekStart: string;
121
+ /** Сессий-входов (первый шаг). */
122
+ entries: number;
123
+ /** Сессий-покупок (последний шаг). */
124
+ conversions: number;
125
+ /** conversions / entries (0..1). */
126
+ overallConversion: number | null;
127
+ };
128
+ /** Недельный тренд конверсии за N недель. */
129
+ export type WidgetFunnelTrendRO = {
130
+ kind: WidgetFunnelKindEnum;
131
+ profileId: number;
132
+ points: WidgetFunnelTrendPointRO[];
133
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@escapenavigator/types",
3
- "version": "1.10.168",
3
+ "version": "2.0.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -23,7 +23,7 @@
23
23
  "reflect-metadata": "^0.1.13",
24
24
  "rxjs": "^7.5.5"
25
25
  },
26
- "gitHead": "5302a068ed1d8bbc5508278412432af4c3accf33",
26
+ "gitHead": "4bc136046ad634699417e72afff25e7b28dfbe7a",
27
27
  "devDependencies": {
28
28
  "@types/validator": "13.0.0",
29
29
  "typescript": "^5.6"