@escapenavigator/utils 2.0.3 → 2.0.5

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,49 @@
1
+ /**
2
+ * Утилиты для standalone booking-страницы (orders-домен) и кнопки
3
+ * «Записаться», которая ведёт на неё с сайта клиента.
4
+ *
5
+ * Задача: сохранить UTM, click-id и (опционально) consent при переходе
6
+ * с клиентского сайта на orders.escapenavigator.com/booking/:uuid.
7
+ */
8
+ export declare const BOOKING_TRACKING_QUERY_PARAMS: readonly ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content", "en_campaign_id", "en_link_id", "gclid", "fbclid", "ttclid", "msclkid"];
9
+ export type BookingTrackingQueryParam = (typeof BOOKING_TRACKING_QUERY_PARAMS)[number];
10
+ export type BookingTrackingParams = Partial<Record<BookingTrackingQueryParam, string>>;
11
+ export type BookingConsentParams = {
12
+ analytics?: boolean;
13
+ ads?: boolean;
14
+ };
15
+ export type BuildBookingPageUrlOptions = {
16
+ ordersDomain: string;
17
+ widgetUuid: string;
18
+ testMode?: boolean;
19
+ lang?: string;
20
+ tracking?: BookingTrackingParams;
21
+ consent?: BookingConsentParams;
22
+ };
23
+ /**
24
+ * Собирает tracking-параметры из URLSearchParams (или строки query).
25
+ * Пустые значения отбрасываются.
26
+ */
27
+ export declare function collectTrackingParamsFromSearch(search: string | URLSearchParams): BookingTrackingParams;
28
+ /**
29
+ * Добавляет tracking/consent-параметры к URL. Существующие ключи в baseUrl
30
+ * не перезаписываются (приоритет у уже заданных в ссылке).
31
+ */
32
+ export declare function appendBookingParamsToUrl(baseUrl: string, options?: {
33
+ tracking?: BookingTrackingParams;
34
+ consent?: BookingConsentParams;
35
+ }): string;
36
+ /**
37
+ * Базовый URL standalone booking-страницы:
38
+ * `{ordersDomain}/booking/{widgetUuid}` + testMode/lang/tracking/consent.
39
+ */
40
+ export declare function buildBookingPageUrl(options: BuildBookingPageUrlOptions): string;
41
+ /**
42
+ * HTML onclick для кнопки «Записаться»: открывает booking-страницу через
43
+ * `EscapeNavigator.openBookingPage` (декорирует UTM + GA linker).
44
+ */
45
+ export declare function buildBookingButtonOnclick(baseUrl: string): string;
46
+ /**
47
+ * Snippet analytics-bridge для `<head>` сайта клиента (iframe/Wix).
48
+ */
49
+ export declare function buildAnalyticsBridgeScriptTag(widgetDomain: string): string;
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ /**
3
+ * Утилиты для standalone booking-страницы (orders-домен) и кнопки
4
+ * «Записаться», которая ведёт на неё с сайта клиента.
5
+ *
6
+ * Задача: сохранить UTM, click-id и (опционально) consent при переходе
7
+ * с клиентского сайта на orders.escapenavigator.com/booking/:uuid.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.BOOKING_TRACKING_QUERY_PARAMS = void 0;
11
+ exports.collectTrackingParamsFromSearch = collectTrackingParamsFromSearch;
12
+ exports.appendBookingParamsToUrl = appendBookingParamsToUrl;
13
+ exports.buildBookingPageUrl = buildBookingPageUrl;
14
+ exports.buildBookingButtonOnclick = buildBookingButtonOnclick;
15
+ exports.buildAnalyticsBridgeScriptTag = buildAnalyticsBridgeScriptTag;
16
+ exports.BOOKING_TRACKING_QUERY_PARAMS = [
17
+ 'utm_source',
18
+ 'utm_medium',
19
+ 'utm_campaign',
20
+ 'utm_term',
21
+ 'utm_content',
22
+ 'en_campaign_id',
23
+ 'en_link_id',
24
+ 'gclid',
25
+ 'fbclid',
26
+ 'ttclid',
27
+ 'msclkid',
28
+ ];
29
+ const normalizeOrdersDomain = (ordersDomain) => ordersDomain.replace(/\/+$/, '');
30
+ /**
31
+ * Собирает tracking-параметры из URLSearchParams (или строки query).
32
+ * Пустые значения отбрасываются.
33
+ */
34
+ function collectTrackingParamsFromSearch(search) {
35
+ const params = typeof search === 'string' ? new URLSearchParams(search) : search;
36
+ const out = {};
37
+ for (const key of exports.BOOKING_TRACKING_QUERY_PARAMS) {
38
+ const value = params.get(key)?.trim();
39
+ if (value)
40
+ out[key] = value;
41
+ }
42
+ return out;
43
+ }
44
+ /**
45
+ * Добавляет tracking/consent-параметры к URL. Существующие ключи в baseUrl
46
+ * не перезаписываются (приоритет у уже заданных в ссылке).
47
+ */
48
+ function appendBookingParamsToUrl(baseUrl, options) {
49
+ const url = new URL(baseUrl);
50
+ if (options?.tracking) {
51
+ for (const [key, value] of Object.entries(options.tracking)) {
52
+ if (!value || url.searchParams.has(key))
53
+ continue;
54
+ url.searchParams.set(key, value);
55
+ }
56
+ }
57
+ if (options?.consent?.analytics && !url.searchParams.has('en_consent_analytics')) {
58
+ url.searchParams.set('en_consent_analytics', '1');
59
+ }
60
+ if (options?.consent?.ads && !url.searchParams.has('en_consent_ads')) {
61
+ url.searchParams.set('en_consent_ads', '1');
62
+ }
63
+ return url.toString();
64
+ }
65
+ /**
66
+ * Базовый URL standalone booking-страницы:
67
+ * `{ordersDomain}/booking/{widgetUuid}` + testMode/lang/tracking/consent.
68
+ */
69
+ function buildBookingPageUrl(options) {
70
+ const { ordersDomain, widgetUuid, testMode, lang, tracking, consent } = options;
71
+ const base = `${normalizeOrdersDomain(ordersDomain)}/booking/${encodeURIComponent(widgetUuid)}`;
72
+ const url = new URL(base);
73
+ if (testMode) {
74
+ url.searchParams.set('testMode', 'true');
75
+ }
76
+ if (lang) {
77
+ url.searchParams.set('lang', lang);
78
+ }
79
+ return appendBookingParamsToUrl(url.toString(), { tracking, consent });
80
+ }
81
+ /**
82
+ * HTML onclick для кнопки «Записаться»: открывает booking-страницу через
83
+ * `EscapeNavigator.openBookingPage` (декорирует UTM + GA linker).
84
+ */
85
+ function buildBookingButtonOnclick(baseUrl) {
86
+ return `event.preventDefault();window.EscapeNavigator&&window.EscapeNavigator.openBookingPage?window.EscapeNavigator.openBookingPage('${baseUrl.replace(/'/g, "\\'")}'):window.open('${baseUrl.replace(/'/g, "\\'")}','_blank','noopener');return false;`;
87
+ }
88
+ /**
89
+ * Snippet analytics-bridge для `<head>` сайта клиента (iframe/Wix).
90
+ */
91
+ function buildAnalyticsBridgeScriptTag(widgetDomain) {
92
+ const src = `${widgetDomain.replace(/\/+$/, '')}/analytics-bridge.js`;
93
+ return `<script src="${src}" async></script>`;
94
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const index_1 = require("./index");
4
+ describe('collectTrackingParamsFromSearch', () => {
5
+ it('collects UTM and click-id params', () => {
6
+ const params = (0, index_1.collectTrackingParamsFromSearch)('?utm_source=google&gclid=abc123&foo=bar');
7
+ expect(params).toEqual({
8
+ utm_source: 'google',
9
+ gclid: 'abc123',
10
+ });
11
+ });
12
+ });
13
+ describe('appendBookingParamsToUrl', () => {
14
+ it('does not overwrite existing query keys', () => {
15
+ const url = (0, index_1.appendBookingParamsToUrl)('https://orders.example.com/booking/u1?utm_source=keep', {
16
+ tracking: { utm_source: 'new', gclid: 'x' },
17
+ consent: { analytics: true },
18
+ });
19
+ expect(url).toContain('utm_source=keep');
20
+ expect(url).toContain('gclid=x');
21
+ expect(url).toContain('en_consent_analytics=1');
22
+ });
23
+ });
24
+ describe('buildBookingPageUrl', () => {
25
+ it('builds booking URL with test mode and lang', () => {
26
+ const url = (0, index_1.buildBookingPageUrl)({
27
+ ordersDomain: 'https://orders.escapenavigator.com/',
28
+ widgetUuid: 'W123',
29
+ testMode: true,
30
+ lang: 'de',
31
+ tracking: { utm_medium: 'email' },
32
+ });
33
+ expect(url).toBe('https://orders.escapenavigator.com/booking/W123?testMode=true&lang=de&utm_medium=email');
34
+ });
35
+ });
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './agreement-config';
2
2
  export * from './booking-lead-time';
3
+ export * from './booking-page-url';
3
4
  export * from './classify-api-error';
4
5
  export * from './convert-hhmm-to-minutes';
5
6
  export * from './convert-minutes-to-hhmm';
package/dist/index.js CHANGED
@@ -16,6 +16,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./agreement-config"), exports);
18
18
  __exportStar(require("./booking-lead-time"), exports);
19
+ __exportStar(require("./booking-page-url"), exports);
19
20
  __exportStar(require("./classify-api-error"), exports);
20
21
  __exportStar(require("./convert-hhmm-to-minutes"), exports);
21
22
  __exportStar(require("./convert-minutes-to-hhmm"), exports);
@@ -18,6 +18,15 @@ export type UtmFields = {
18
18
  * session storage.
19
19
  */
20
20
  enLinkId?: string | null;
21
+ /**
22
+ * Рекламные click-id (last-click, как UTM). В touchpoint-нормализацию
23
+ * НЕ входят — используются только для записи в денорм-колонки заказа /
24
+ * продажи сертификата (серверная атрибуция конверсий).
25
+ */
26
+ gclid?: string | null;
27
+ fbclid?: string | null;
28
+ ttclid?: string | null;
29
+ msclkid?: string | null;
21
30
  };
22
31
  /**
23
32
  * Нормализация одного UTM-поля для индекса/поиска: trim + lowercase.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@escapenavigator/utils",
3
- "version": "2.0.3",
3
+ "version": "2.0.5",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -14,7 +14,7 @@
14
14
  "test": "jest"
15
15
  },
16
16
  "dependencies": {
17
- "@escapenavigator/types": "^2.0.3",
17
+ "@escapenavigator/types": "^2.0.5",
18
18
  "axios": "^0.21.4",
19
19
  "class-transformer": "^0.5.1",
20
20
  "class-validator": "^0.13.2",
@@ -29,5 +29,5 @@
29
29
  "ts-jest": "^29.1.1",
30
30
  "typescript": "^5.6"
31
31
  },
32
- "gitHead": "13a7f625f7f30f2ae4fb84b7344ef2c51112e8b5"
32
+ "gitHead": "353de6475e72710d92abfa449624c818719d7239"
33
33
  }