@tracelog/lib 0.0.8 → 0.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 (228) hide show
  1. package/README.md +58 -24
  2. package/dist/browser/tracelog.js +1934 -3226
  3. package/dist/cjs/api.d.ts +33 -19
  4. package/dist/cjs/api.js +111 -156
  5. package/dist/cjs/app.constants.d.ts +80 -1
  6. package/dist/cjs/app.constants.js +90 -3
  7. package/dist/cjs/app.d.ts +29 -44
  8. package/dist/cjs/app.js +114 -212
  9. package/dist/cjs/app.types.d.ts +2 -7
  10. package/dist/cjs/app.types.js +10 -21
  11. package/dist/cjs/constants/api.constants.js +11 -5
  12. package/dist/cjs/constants/config.constants.d.ts +75 -0
  13. package/dist/cjs/constants/config.constants.js +178 -0
  14. package/dist/cjs/constants/error.constants.d.ts +29 -0
  15. package/dist/cjs/constants/error.constants.js +50 -0
  16. package/dist/cjs/constants/index.d.ts +3 -6
  17. package/dist/cjs/constants/index.js +3 -6
  18. package/dist/cjs/constants/performance.constants.d.ts +28 -0
  19. package/dist/cjs/constants/performance.constants.js +43 -0
  20. package/dist/cjs/handlers/click.handler.d.ts +1 -0
  21. package/dist/cjs/handlers/click.handler.js +30 -49
  22. package/dist/cjs/handlers/error.handler.d.ts +11 -6
  23. package/dist/cjs/handlers/error.handler.js +91 -51
  24. package/dist/cjs/handlers/page-view.handler.js +38 -29
  25. package/dist/cjs/handlers/performance.handler.d.ts +3 -0
  26. package/dist/cjs/handlers/performance.handler.js +76 -37
  27. package/dist/cjs/handlers/scroll.handler.d.ts +15 -0
  28. package/dist/cjs/handlers/scroll.handler.js +105 -31
  29. package/dist/cjs/handlers/session.handler.d.ts +6 -20
  30. package/dist/cjs/handlers/session.handler.js +38 -326
  31. package/dist/cjs/integrations/google-analytics.integration.d.ts +0 -1
  32. package/dist/cjs/integrations/google-analytics.integration.js +27 -98
  33. package/dist/cjs/listeners/input-listener-managers.d.ts +18 -9
  34. package/dist/cjs/listeners/input-listener-managers.js +24 -33
  35. package/dist/cjs/listeners/touch-listener-manager.d.ts +1 -3
  36. package/dist/cjs/listeners/touch-listener-manager.js +1 -23
  37. package/dist/cjs/listeners/visibility-listener-manager.d.ts +1 -4
  38. package/dist/cjs/listeners/visibility-listener-manager.js +6 -42
  39. package/dist/cjs/managers/api.manager.d.ts +13 -3
  40. package/dist/cjs/managers/api.manager.js +35 -5
  41. package/dist/cjs/managers/config.manager.d.ts +53 -3
  42. package/dist/cjs/managers/config.manager.js +131 -62
  43. package/dist/cjs/managers/event.manager.d.ts +57 -36
  44. package/dist/cjs/managers/event.manager.js +266 -417
  45. package/dist/cjs/managers/sender.manager.d.ts +40 -22
  46. package/dist/cjs/managers/sender.manager.js +200 -198
  47. package/dist/cjs/managers/session.manager.d.ts +80 -66
  48. package/dist/cjs/managers/session.manager.js +267 -522
  49. package/dist/cjs/managers/state.manager.d.ts +33 -0
  50. package/dist/cjs/managers/state.manager.js +79 -6
  51. package/dist/cjs/managers/storage.manager.d.ts +26 -2
  52. package/dist/cjs/managers/storage.manager.js +67 -34
  53. package/dist/cjs/managers/tags.manager.d.ts +31 -7
  54. package/dist/cjs/managers/tags.manager.js +123 -241
  55. package/dist/cjs/managers/user.manager.d.ts +14 -5
  56. package/dist/cjs/managers/user.manager.js +17 -9
  57. package/dist/cjs/public-api.d.ts +10 -1
  58. package/dist/cjs/public-api.js +18 -24
  59. package/dist/cjs/test-bridge.d.ts +48 -0
  60. package/dist/cjs/test-bridge.js +110 -0
  61. package/dist/cjs/types/api.types.d.ts +21 -6
  62. package/dist/cjs/types/api.types.js +21 -6
  63. package/dist/cjs/types/config.types.d.ts +22 -84
  64. package/dist/cjs/types/emitter.types.d.ts +11 -0
  65. package/dist/cjs/types/emitter.types.js +8 -0
  66. package/dist/cjs/types/event.types.d.ts +8 -11
  67. package/dist/cjs/types/index.d.ts +3 -1
  68. package/dist/cjs/types/index.js +3 -1
  69. package/dist/cjs/types/queue.types.d.ts +1 -0
  70. package/dist/cjs/types/session.types.d.ts +0 -64
  71. package/dist/cjs/types/state.types.d.ts +1 -0
  72. package/dist/cjs/types/test-bridge.types.d.ts +38 -0
  73. package/dist/cjs/types/validation-error.types.d.ts +7 -0
  74. package/dist/cjs/types/validation-error.types.js +11 -1
  75. package/dist/cjs/types/window.types.d.ts +1 -8
  76. package/dist/cjs/utils/data/uuid.utils.d.ts +1 -1
  77. package/dist/cjs/utils/data/uuid.utils.js +7 -5
  78. package/dist/cjs/utils/emitter.utils.d.ts +8 -0
  79. package/dist/cjs/utils/emitter.utils.js +33 -0
  80. package/dist/cjs/utils/index.d.ts +1 -0
  81. package/dist/cjs/utils/index.js +1 -0
  82. package/dist/cjs/utils/logging/debug-logger.utils.d.ts +10 -51
  83. package/dist/cjs/utils/logging/debug-logger.utils.js +36 -127
  84. package/dist/cjs/utils/network/fetch-with-timeout.utils.d.ts +4 -0
  85. package/dist/cjs/utils/network/fetch-with-timeout.utils.js +25 -0
  86. package/dist/cjs/utils/network/index.d.ts +1 -0
  87. package/dist/cjs/utils/network/index.js +1 -0
  88. package/dist/cjs/utils/network/url.utils.js +2 -42
  89. package/dist/cjs/utils/security/sanitize.utils.d.ts +1 -8
  90. package/dist/cjs/utils/security/sanitize.utils.js +7 -41
  91. package/dist/cjs/utils/validations/config-validations.utils.d.ts +7 -0
  92. package/dist/cjs/utils/validations/config-validations.utils.js +77 -22
  93. package/dist/esm/api.d.ts +33 -19
  94. package/dist/esm/api.js +105 -118
  95. package/dist/esm/app.constants.d.ts +80 -1
  96. package/dist/esm/app.constants.js +89 -1
  97. package/dist/esm/app.d.ts +29 -44
  98. package/dist/esm/app.js +115 -213
  99. package/dist/esm/app.types.d.ts +2 -7
  100. package/dist/esm/app.types.js +1 -7
  101. package/dist/esm/constants/api.constants.js +10 -4
  102. package/dist/esm/constants/config.constants.d.ts +75 -0
  103. package/dist/esm/constants/config.constants.js +174 -0
  104. package/dist/esm/constants/error.constants.d.ts +29 -0
  105. package/dist/esm/constants/error.constants.js +47 -0
  106. package/dist/esm/constants/index.d.ts +3 -6
  107. package/dist/esm/constants/index.js +3 -6
  108. package/dist/esm/constants/performance.constants.d.ts +28 -0
  109. package/dist/esm/constants/performance.constants.js +40 -0
  110. package/dist/esm/handlers/click.handler.d.ts +1 -0
  111. package/dist/esm/handlers/click.handler.js +30 -49
  112. package/dist/esm/handlers/error.handler.d.ts +11 -6
  113. package/dist/esm/handlers/error.handler.js +91 -51
  114. package/dist/esm/handlers/page-view.handler.js +38 -29
  115. package/dist/esm/handlers/performance.handler.d.ts +3 -0
  116. package/dist/esm/handlers/performance.handler.js +71 -32
  117. package/dist/esm/handlers/scroll.handler.d.ts +15 -0
  118. package/dist/esm/handlers/scroll.handler.js +106 -32
  119. package/dist/esm/handlers/session.handler.d.ts +6 -20
  120. package/dist/esm/handlers/session.handler.js +38 -326
  121. package/dist/esm/integrations/google-analytics.integration.d.ts +0 -1
  122. package/dist/esm/integrations/google-analytics.integration.js +27 -98
  123. package/dist/esm/listeners/input-listener-managers.d.ts +18 -9
  124. package/dist/esm/listeners/input-listener-managers.js +23 -32
  125. package/dist/esm/listeners/touch-listener-manager.d.ts +1 -3
  126. package/dist/esm/listeners/touch-listener-manager.js +1 -23
  127. package/dist/esm/listeners/visibility-listener-manager.d.ts +1 -4
  128. package/dist/esm/listeners/visibility-listener-manager.js +6 -42
  129. package/dist/esm/managers/api.manager.d.ts +13 -3
  130. package/dist/esm/managers/api.manager.js +34 -3
  131. package/dist/esm/managers/config.manager.d.ts +53 -3
  132. package/dist/esm/managers/config.manager.js +133 -64
  133. package/dist/esm/managers/event.manager.d.ts +57 -36
  134. package/dist/esm/managers/event.manager.js +268 -419
  135. package/dist/esm/managers/sender.manager.d.ts +40 -22
  136. package/dist/esm/managers/sender.manager.js +201 -199
  137. package/dist/esm/managers/session.manager.d.ts +80 -66
  138. package/dist/esm/managers/session.manager.js +269 -524
  139. package/dist/esm/managers/state.manager.d.ts +33 -0
  140. package/dist/esm/managers/state.manager.js +78 -6
  141. package/dist/esm/managers/storage.manager.d.ts +26 -2
  142. package/dist/esm/managers/storage.manager.js +66 -33
  143. package/dist/esm/managers/tags.manager.d.ts +31 -7
  144. package/dist/esm/managers/tags.manager.js +124 -242
  145. package/dist/esm/managers/user.manager.d.ts +14 -5
  146. package/dist/esm/managers/user.manager.js +17 -9
  147. package/dist/esm/public-api.d.ts +10 -1
  148. package/dist/esm/public-api.js +14 -1
  149. package/dist/esm/test-bridge.d.ts +48 -0
  150. package/dist/esm/test-bridge.js +106 -0
  151. package/dist/esm/types/api.types.d.ts +21 -6
  152. package/dist/esm/types/api.types.js +21 -6
  153. package/dist/esm/types/config.types.d.ts +22 -84
  154. package/dist/esm/types/emitter.types.d.ts +11 -0
  155. package/dist/esm/types/emitter.types.js +5 -0
  156. package/dist/esm/types/event.types.d.ts +8 -11
  157. package/dist/esm/types/index.d.ts +3 -1
  158. package/dist/esm/types/index.js +3 -1
  159. package/dist/esm/types/queue.types.d.ts +1 -0
  160. package/dist/esm/types/session.types.d.ts +0 -64
  161. package/dist/esm/types/state.types.d.ts +1 -0
  162. package/dist/esm/types/test-bridge.types.d.ts +38 -0
  163. package/dist/esm/types/validation-error.types.d.ts +7 -0
  164. package/dist/esm/types/validation-error.types.js +9 -0
  165. package/dist/esm/types/window.types.d.ts +1 -8
  166. package/dist/esm/utils/data/uuid.utils.d.ts +1 -1
  167. package/dist/esm/utils/data/uuid.utils.js +7 -5
  168. package/dist/esm/utils/emitter.utils.d.ts +8 -0
  169. package/dist/esm/utils/emitter.utils.js +29 -0
  170. package/dist/esm/utils/index.d.ts +1 -0
  171. package/dist/esm/utils/index.js +1 -0
  172. package/dist/esm/utils/logging/debug-logger.utils.d.ts +10 -51
  173. package/dist/esm/utils/logging/debug-logger.utils.js +36 -127
  174. package/dist/esm/utils/network/fetch-with-timeout.utils.d.ts +4 -0
  175. package/dist/esm/utils/network/fetch-with-timeout.utils.js +22 -0
  176. package/dist/esm/utils/network/index.d.ts +1 -0
  177. package/dist/esm/utils/network/index.js +1 -0
  178. package/dist/esm/utils/network/url.utils.js +2 -42
  179. package/dist/esm/utils/security/sanitize.utils.d.ts +1 -8
  180. package/dist/esm/utils/security/sanitize.utils.js +6 -39
  181. package/dist/esm/utils/validations/config-validations.utils.d.ts +7 -0
  182. package/dist/esm/utils/validations/config-validations.utils.js +76 -22
  183. package/package.json +23 -16
  184. package/dist/browser/web-vitals-CCnqwnC8.mjs +0 -198
  185. package/dist/cjs/constants/browser.constants.d.ts +0 -3
  186. package/dist/cjs/constants/browser.constants.js +0 -41
  187. package/dist/cjs/constants/initialization.constants.d.ts +0 -40
  188. package/dist/cjs/constants/initialization.constants.js +0 -48
  189. package/dist/cjs/constants/limits.constants.d.ts +0 -25
  190. package/dist/cjs/constants/limits.constants.js +0 -40
  191. package/dist/cjs/constants/security.constants.d.ts +0 -1
  192. package/dist/cjs/constants/security.constants.js +0 -12
  193. package/dist/cjs/constants/timing.constants.d.ts +0 -22
  194. package/dist/cjs/constants/timing.constants.js +0 -34
  195. package/dist/cjs/constants/validation.constants.d.ts +0 -13
  196. package/dist/cjs/constants/validation.constants.js +0 -31
  197. package/dist/cjs/handlers/network.handler.d.ts +0 -16
  198. package/dist/cjs/handlers/network.handler.js +0 -136
  199. package/dist/cjs/managers/cross-tab-session.manager.d.ts +0 -170
  200. package/dist/cjs/managers/cross-tab-session.manager.js +0 -730
  201. package/dist/cjs/managers/sampling.manager.d.ts +0 -8
  202. package/dist/cjs/managers/sampling.manager.js +0 -53
  203. package/dist/cjs/managers/session-recovery.manager.d.ts +0 -65
  204. package/dist/cjs/managers/session-recovery.manager.js +0 -237
  205. package/dist/cjs/types/web-vitals.types.d.ts +0 -6
  206. package/dist/esm/constants/browser.constants.d.ts +0 -3
  207. package/dist/esm/constants/browser.constants.js +0 -38
  208. package/dist/esm/constants/initialization.constants.d.ts +0 -40
  209. package/dist/esm/constants/initialization.constants.js +0 -45
  210. package/dist/esm/constants/limits.constants.d.ts +0 -25
  211. package/dist/esm/constants/limits.constants.js +0 -37
  212. package/dist/esm/constants/security.constants.d.ts +0 -1
  213. package/dist/esm/constants/security.constants.js +0 -9
  214. package/dist/esm/constants/timing.constants.d.ts +0 -22
  215. package/dist/esm/constants/timing.constants.js +0 -31
  216. package/dist/esm/constants/validation.constants.d.ts +0 -13
  217. package/dist/esm/constants/validation.constants.js +0 -28
  218. package/dist/esm/handlers/network.handler.d.ts +0 -16
  219. package/dist/esm/handlers/network.handler.js +0 -132
  220. package/dist/esm/managers/cross-tab-session.manager.d.ts +0 -170
  221. package/dist/esm/managers/cross-tab-session.manager.js +0 -726
  222. package/dist/esm/managers/sampling.manager.d.ts +0 -8
  223. package/dist/esm/managers/sampling.manager.js +0 -49
  224. package/dist/esm/managers/session-recovery.manager.d.ts +0 -65
  225. package/dist/esm/managers/session-recovery.manager.js +0 -233
  226. package/dist/esm/types/web-vitals.types.d.ts +0 -6
  227. /package/dist/cjs/types/{web-vitals.types.js → test-bridge.types.js} +0 -0
  228. /package/dist/esm/types/{web-vitals.types.js → test-bridge.types.js} +0 -0
@@ -1,256 +1,116 @@
1
- import { EventType, TagConditionOperator, TagConditionType, TagLogicalOperator, } from '../types';
1
+ import { TagConditionOperator, TagConditionType, TagLogicalOperator, } from '../types';
2
2
  import { StateManager } from './state.manager';
3
3
  export class TagsManager extends StateManager {
4
+ /**
5
+ * Gets matching tag IDs for an event based on configured tag conditions
6
+ */
4
7
  getEventTagsIds(event, deviceType) {
5
- switch (event.type) {
6
- case EventType.PAGE_VIEW: {
7
- return this.checkEventTypePageView(event, deviceType);
8
- }
9
- case EventType.CLICK: {
10
- return this.checkEventTypeClick(event, deviceType);
11
- }
12
- default: {
13
- return [];
14
- }
15
- }
16
- }
17
- checkEventTypePageView(event, deviceType) {
18
- const tags = this.get('config')?.tags?.filter((tag) => tag.triggerType === EventType.PAGE_VIEW) ?? [];
8
+ const tags = this.get('config')?.tags?.filter((tag) => tag.triggerType === event.type) ?? [];
19
9
  if (tags.length === 0) {
20
10
  return [];
21
11
  }
22
- const matchedTagIds = [];
23
- for (const tag of tags) {
24
- const { id, logicalOperator, conditions } = tag;
25
- const results = [];
26
- for (const condition of conditions) {
27
- switch (condition.type) {
28
- case TagConditionType.URL_MATCHES: {
29
- results.push(this.matchUrlMatches(condition, event.page_url));
30
- break;
31
- }
32
- case TagConditionType.DEVICE_TYPE: {
33
- results.push(this.matchDeviceType(condition, deviceType));
34
- break;
35
- }
36
- case TagConditionType.UTM_SOURCE: {
37
- results.push(this.matchUtmCondition(condition, event.utm?.source));
38
- break;
39
- }
40
- case TagConditionType.UTM_MEDIUM: {
41
- results.push(this.matchUtmCondition(condition, event.utm?.medium));
42
- break;
43
- }
44
- case TagConditionType.UTM_CAMPAIGN: {
45
- results.push(this.matchUtmCondition(condition, event.utm?.campaign));
46
- break;
47
- }
48
- }
49
- }
50
- let isMatch = false;
51
- isMatch = logicalOperator === TagLogicalOperator.AND ? results.every(Boolean) : results.some(Boolean);
52
- if (isMatch) {
53
- matchedTagIds.push(id);
54
- }
55
- }
56
- return matchedTagIds;
12
+ const context = {
13
+ event,
14
+ deviceType,
15
+ clickData: event.click_data,
16
+ };
17
+ return tags.filter((tag) => this.evaluateTagConditions(tag, context)).map((tag) => tag.id);
57
18
  }
58
- checkEventTypeClick(event, deviceType) {
59
- const tags = this.get('config')?.tags?.filter((tag) => tag.triggerType === EventType.CLICK) ?? [];
60
- if (tags.length === 0) {
61
- return [];
62
- }
63
- const matchedTagIds = [];
64
- for (const tag of tags) {
65
- const { id, logicalOperator, conditions } = tag;
66
- const results = [];
67
- for (const condition of conditions) {
68
- if (!event.click_data) {
69
- results.push(false);
70
- continue;
71
- }
72
- const clickData = event.click_data;
73
- switch (condition.type) {
74
- case TagConditionType.ELEMENT_MATCHES: {
75
- results.push(this.matchElementSelector(condition, clickData));
76
- break;
77
- }
78
- case TagConditionType.DEVICE_TYPE: {
79
- results.push(this.matchDeviceType(condition, deviceType));
80
- break;
81
- }
82
- case TagConditionType.URL_MATCHES: {
83
- results.push(this.matchUrlMatches(condition, event.page_url));
84
- break;
85
- }
86
- case TagConditionType.UTM_SOURCE: {
87
- results.push(this.matchUtmCondition(condition, event.utm?.source));
88
- break;
89
- }
90
- case TagConditionType.UTM_MEDIUM: {
91
- results.push(this.matchUtmCondition(condition, event.utm?.medium));
92
- break;
93
- }
94
- case TagConditionType.UTM_CAMPAIGN: {
95
- results.push(this.matchUtmCondition(condition, event.utm?.campaign));
96
- break;
97
- }
98
- }
99
- }
100
- let isMatch = false;
101
- isMatch = logicalOperator === TagLogicalOperator.AND ? results.every(Boolean) : results.some(Boolean);
102
- if (isMatch) {
103
- matchedTagIds.push(id);
104
- }
105
- }
106
- return matchedTagIds;
107
- }
108
- matchUrlMatches(condition, url) {
109
- if (condition.type !== TagConditionType.URL_MATCHES) {
19
+ /**
20
+ * Evaluates all conditions for a tag using logical operators
21
+ */
22
+ evaluateTagConditions(tag, context) {
23
+ const { conditions, logicalOperator = TagLogicalOperator.OR } = tag;
24
+ if (!conditions || conditions.length === 0) {
110
25
  return false;
111
26
  }
112
- const targetValue = condition.value.toLowerCase();
113
- const targetUrl = url.toLowerCase();
114
- switch (condition.operator) {
115
- case TagConditionOperator.EQUALS: {
116
- return targetUrl === targetValue;
117
- }
118
- case TagConditionOperator.CONTAINS: {
119
- return targetUrl.includes(targetValue);
120
- }
121
- case TagConditionOperator.STARTS_WITH: {
122
- return targetUrl.startsWith(targetValue);
123
- }
124
- case TagConditionOperator.ENDS_WITH: {
125
- return targetUrl.endsWith(targetValue);
126
- }
127
- case TagConditionOperator.REGEX: {
128
- try {
129
- const regex = new RegExp(targetValue, 'gi');
130
- return regex.test(targetUrl);
131
- }
132
- catch {
27
+ const results = conditions.map((condition) => this.evaluateCondition(condition, context));
28
+ return logicalOperator === TagLogicalOperator.AND ? results.every(Boolean) : results.some(Boolean);
29
+ }
30
+ /**
31
+ * Evaluates a single tag condition
32
+ */
33
+ evaluateCondition(condition, context) {
34
+ try {
35
+ switch (condition.type) {
36
+ case TagConditionType.URL_MATCHES:
37
+ return this.matchStringCondition(condition, context.event.page_url);
38
+ case TagConditionType.DEVICE_TYPE:
39
+ return this.matchStringCondition(condition, context.deviceType);
40
+ case TagConditionType.UTM_SOURCE:
41
+ return this.matchStringCondition(condition, context.event.utm?.source ?? '');
42
+ case TagConditionType.UTM_MEDIUM:
43
+ return this.matchStringCondition(condition, context.event.utm?.medium ?? '');
44
+ case TagConditionType.UTM_CAMPAIGN:
45
+ return this.matchStringCondition(condition, context.event.utm?.campaign ?? '');
46
+ case TagConditionType.ELEMENT_MATCHES:
47
+ return context.clickData ? this.matchElementCondition(condition, context.clickData) : false;
48
+ default:
133
49
  return false;
134
- }
135
- }
136
- default: {
137
- return false;
138
50
  }
139
51
  }
140
- }
141
- matchDeviceType(condition, deviceType) {
142
- if (condition.type !== TagConditionType.DEVICE_TYPE) {
52
+ catch {
143
53
  return false;
144
54
  }
145
- const targetValue = condition.value.toLowerCase();
146
- const targetDevice = deviceType.toLowerCase();
147
- switch (condition.operator) {
148
- case TagConditionOperator.EQUALS: {
149
- return targetDevice === targetValue;
150
- }
151
- case TagConditionOperator.CONTAINS: {
152
- return targetDevice.includes(targetValue);
153
- }
154
- case TagConditionOperator.STARTS_WITH: {
155
- return targetDevice.startsWith(targetValue);
156
- }
157
- case TagConditionOperator.ENDS_WITH: {
158
- return targetDevice.endsWith(targetValue);
159
- }
160
- case TagConditionOperator.REGEX: {
161
- try {
162
- const regex = new RegExp(targetValue, 'gi');
163
- return regex.test(targetDevice);
164
- }
165
- catch {
166
- return false;
167
- }
168
- }
169
- default: {
170
- return false;
171
- }
172
- }
173
55
  }
174
- matchElementSelector(condition, clickData) {
175
- if (condition.type !== TagConditionType.ELEMENT_MATCHES) {
56
+ /**
57
+ * Unified string matching logic for all string-based conditions
58
+ */
59
+ matchStringCondition(condition, value) {
60
+ if (!value &&
61
+ condition.operator !== TagConditionOperator.EXISTS &&
62
+ condition.operator !== TagConditionOperator.NOT_EXISTS) {
176
63
  return false;
177
64
  }
178
- const elementData = [
179
- clickData.id ?? '',
180
- clickData.class ?? '',
181
- clickData.tag ?? '',
182
- clickData.text ?? '',
183
- clickData.href ?? '',
184
- clickData.title ?? '',
185
- clickData.alt ?? '',
186
- clickData.role ?? '',
187
- clickData.ariaLabel ?? '',
188
- ...Object.values(clickData.dataAttributes ?? {}),
189
- ].join(' ');
190
- const targetValue = condition.value.toLowerCase();
191
- const targetElementData = elementData.toLowerCase();
65
+ const conditionValue = condition.value.toLowerCase();
66
+ const targetValue = value.toLowerCase();
192
67
  switch (condition.operator) {
193
- case TagConditionOperator.EQUALS: {
194
- return this.checkElementFieldEquals(clickData, targetValue);
195
- }
196
- case TagConditionOperator.CONTAINS: {
197
- return targetElementData.includes(targetValue);
198
- }
199
- case TagConditionOperator.STARTS_WITH: {
200
- return targetElementData.startsWith(targetValue);
201
- }
202
- case TagConditionOperator.ENDS_WITH: {
203
- return targetElementData.endsWith(targetValue);
204
- }
205
- case TagConditionOperator.REGEX: {
206
- try {
207
- const regex = new RegExp(targetValue, 'gi');
208
- return regex.test(targetElementData);
209
- }
210
- catch {
211
- return false;
212
- }
213
- }
214
- default: {
68
+ case TagConditionOperator.EQUALS:
69
+ return targetValue === conditionValue;
70
+ case TagConditionOperator.CONTAINS:
71
+ return targetValue.includes(conditionValue);
72
+ case TagConditionOperator.STARTS_WITH:
73
+ return targetValue.startsWith(conditionValue);
74
+ case TagConditionOperator.ENDS_WITH:
75
+ return targetValue.endsWith(conditionValue);
76
+ case TagConditionOperator.REGEX:
77
+ return this.testRegex(conditionValue, targetValue);
78
+ case TagConditionOperator.EXISTS:
79
+ return !!value;
80
+ case TagConditionOperator.NOT_EXISTS:
81
+ return !value;
82
+ default:
215
83
  return false;
216
- }
217
84
  }
218
85
  }
219
- matchUtmCondition(condition, utmValue) {
220
- if (![TagConditionType.UTM_SOURCE, TagConditionType.UTM_MEDIUM, TagConditionType.UTM_CAMPAIGN].includes(condition.type)) {
221
- return false;
86
+ /**
87
+ * Element-specific matching logic with optimized data extraction
88
+ */
89
+ matchElementCondition(condition, clickData) {
90
+ if (condition.operator === TagConditionOperator.EQUALS) {
91
+ return this.matchElementFieldExact(condition, clickData);
222
92
  }
223
- const value = utmValue ?? '';
224
- const targetValue = condition.value.toLowerCase();
225
- const targetUtmValue = value.toLowerCase();
93
+ // Build searchable element data string once
94
+ const elementData = this.buildElementDataString(clickData).toLowerCase();
95
+ const conditionValue = condition.value.toLowerCase();
226
96
  switch (condition.operator) {
227
- case TagConditionOperator.EQUALS: {
228
- return targetUtmValue === targetValue;
229
- }
230
- case TagConditionOperator.CONTAINS: {
231
- return targetUtmValue.includes(targetValue);
232
- }
233
- case TagConditionOperator.STARTS_WITH: {
234
- return targetUtmValue.startsWith(targetValue);
235
- }
236
- case TagConditionOperator.ENDS_WITH: {
237
- return targetUtmValue.endsWith(targetValue);
238
- }
239
- case TagConditionOperator.REGEX: {
240
- try {
241
- const regex = new RegExp(targetValue, 'gi');
242
- return regex.test(targetUtmValue);
243
- }
244
- catch {
245
- return false;
246
- }
247
- }
248
- default: {
97
+ case TagConditionOperator.CONTAINS:
98
+ return elementData.includes(conditionValue);
99
+ case TagConditionOperator.STARTS_WITH:
100
+ return elementData.startsWith(conditionValue);
101
+ case TagConditionOperator.ENDS_WITH:
102
+ return elementData.endsWith(conditionValue);
103
+ case TagConditionOperator.REGEX:
104
+ return this.testRegex(conditionValue, elementData);
105
+ default:
249
106
  return false;
250
- }
251
107
  }
252
108
  }
253
- checkElementFieldEquals(clickData, targetValue) {
109
+ /**
110
+ * Exact field matching for element EQUALS operations
111
+ */
112
+ matchElementFieldExact(condition, clickData) {
113
+ const conditionValue = condition.value.toLowerCase();
254
114
  const fields = [
255
115
  clickData.id,
256
116
  clickData.class,
@@ -262,24 +122,46 @@ export class TagsManager extends StateManager {
262
122
  clickData.role,
263
123
  clickData.ariaLabel,
264
124
  ];
265
- for (const field of fields) {
266
- if (field) {
267
- const fieldValue = field.toLowerCase();
268
- const target = targetValue.toLowerCase();
269
- if (fieldValue === target) {
270
- return true;
271
- }
272
- }
125
+ // Check standard fields
126
+ if (fields.some((field) => field && field.toLowerCase() === conditionValue)) {
127
+ return true;
273
128
  }
129
+ // Check data attributes
274
130
  if (clickData.dataAttributes) {
275
- for (const dataValue of Object.values(clickData.dataAttributes)) {
276
- const fieldValue = dataValue.toLowerCase();
277
- const target = targetValue.toLowerCase();
278
- if (fieldValue === target) {
279
- return true;
280
- }
281
- }
131
+ return Object.values(clickData.dataAttributes).some((value) => value.toLowerCase() === conditionValue);
282
132
  }
283
133
  return false;
284
134
  }
135
+ /**
136
+ * Builds searchable element data string with null safety
137
+ */
138
+ buildElementDataString(clickData) {
139
+ const parts = [
140
+ clickData.id,
141
+ clickData.class,
142
+ clickData.tag,
143
+ clickData.text,
144
+ clickData.href,
145
+ clickData.title,
146
+ clickData.alt,
147
+ clickData.role,
148
+ clickData.ariaLabel,
149
+ ].filter(Boolean);
150
+ if (clickData.dataAttributes) {
151
+ parts.push(...Object.values(clickData.dataAttributes));
152
+ }
153
+ return parts.join(' ');
154
+ }
155
+ /**
156
+ * Safe regex testing with error handling
157
+ */
158
+ testRegex(pattern, text) {
159
+ try {
160
+ const regex = new RegExp(pattern, 'gi');
161
+ return regex.test(text);
162
+ }
163
+ catch {
164
+ return false;
165
+ }
166
+ }
285
167
  }
@@ -1,7 +1,16 @@
1
- import { StateManager } from './state.manager';
2
1
  import { StorageManager } from './storage.manager';
3
- export declare class UserManager extends StateManager {
4
- private readonly storageManager;
5
- constructor(storageManager: StorageManager);
6
- getId(): string;
2
+ /**
3
+ * Simple utility for managing user identification.
4
+ * Generates and persists unique user IDs per project.
5
+ */
6
+ export declare class UserManager {
7
+ /**
8
+ * Gets or creates a unique user ID for the given project.
9
+ * The user ID is persisted in localStorage and reused across sessions.
10
+ *
11
+ * @param storageManager - Storage manager instance
12
+ * @param projectId - Project identifier for namespacing
13
+ * @returns Persistent unique user ID
14
+ */
15
+ static getId(storageManager: StorageManager, projectId?: string): string;
7
16
  }
@@ -1,18 +1,26 @@
1
1
  import { USER_ID_KEY } from '../constants';
2
2
  import { generateUUID } from '../utils';
3
- import { StateManager } from './state.manager';
4
- export class UserManager extends StateManager {
5
- constructor(storageManager) {
6
- super();
7
- this.storageManager = storageManager;
8
- }
9
- getId() {
10
- const storedUserId = this.storageManager.getItem(USER_ID_KEY(this.get('config')?.id));
3
+ /**
4
+ * Simple utility for managing user identification.
5
+ * Generates and persists unique user IDs per project.
6
+ */
7
+ export class UserManager {
8
+ /**
9
+ * Gets or creates a unique user ID for the given project.
10
+ * The user ID is persisted in localStorage and reused across sessions.
11
+ *
12
+ * @param storageManager - Storage manager instance
13
+ * @param projectId - Project identifier for namespacing
14
+ * @returns Persistent unique user ID
15
+ */
16
+ static getId(storageManager, projectId) {
17
+ const storageKey = USER_ID_KEY(projectId ?? '');
18
+ const storedUserId = storageManager.getItem(storageKey);
11
19
  if (storedUserId) {
12
20
  return storedUserId;
13
21
  }
14
22
  const newUserId = generateUUID();
15
- this.storageManager.setItem(USER_ID_KEY(this.get('config')?.id), newUserId);
23
+ storageManager.setItem(storageKey, newUserId);
16
24
  return newUserId;
17
25
  }
18
26
  }
@@ -1 +1,10 @@
1
- export * as TraceLog from './api';
1
+ export * from './app.constants';
2
+ export * from './app.types';
3
+ export declare const tracelog: {
4
+ init: (appConfig: import("./app.types").AppConfig) => Promise<void>;
5
+ event: (name: string, metadata?: Record<string, import("./app.types").MetadataType>) => void;
6
+ on: <K extends keyof import("./types").EmitterMap>(event: K, callback: import("./types").EmitterCallback<import("./types").EmitterMap[K]>) => void;
7
+ off: <K extends keyof import("./types").EmitterMap>(event: K, callback: import("./types").EmitterCallback<import("./types").EmitterMap[K]>) => void;
8
+ isInitialized: () => boolean;
9
+ destroy: () => Promise<void>;
10
+ };
@@ -1 +1,14 @@
1
- export * as TraceLog from './api';
1
+ import { init, event, on, off, isInitialized, destroy } from './api';
2
+ // Constants
3
+ export * from './app.constants';
4
+ // Types
5
+ export * from './app.types';
6
+ // TraceLog namespace containing all API methods
7
+ export const tracelog = {
8
+ init,
9
+ event,
10
+ on,
11
+ off,
12
+ isInitialized,
13
+ destroy,
14
+ };
@@ -0,0 +1,48 @@
1
+ import { App } from './app';
2
+ import { ClickHandler } from './handlers/click.handler';
3
+ import { ErrorHandler } from './handlers/error.handler';
4
+ import { PageViewHandler } from './handlers/page-view.handler';
5
+ import { PerformanceHandler } from './handlers/performance.handler';
6
+ import { ScrollHandler } from './handlers/scroll.handler';
7
+ import { SessionHandler } from './handlers/session.handler';
8
+ import { GoogleAnalyticsIntegration } from './integrations/google-analytics.integration';
9
+ import { EventManager } from './managers/event.manager';
10
+ import { StorageManager } from './managers/storage.manager';
11
+ import { State, TraceLogTestBridge } from './types';
12
+ /**
13
+ * Test bridge for E2E testing
14
+ */
15
+ export declare class TestBridge extends App implements TraceLogTestBridge {
16
+ private _isInitializing;
17
+ private _isDestroying;
18
+ constructor(isInitializing: boolean, isDestroying: boolean);
19
+ isInitializing(): boolean;
20
+ sendCustomEvent(name: string, data?: Record<string, unknown>): void;
21
+ getSessionData(): Record<string, unknown> | null;
22
+ setSessionTimeout(timeout: number): void;
23
+ getQueueLength(): number;
24
+ forceInitLock(enabled?: boolean): void;
25
+ get<T extends keyof State>(key: T): State[T];
26
+ getStorageManager(): StorageManager | null;
27
+ getEventManager(): EventManager | null;
28
+ getSessionHandler(): SessionHandler | null;
29
+ getPageViewHandler(): PageViewHandler | null;
30
+ getClickHandler(): ClickHandler | null;
31
+ getScrollHandler(): ScrollHandler | null;
32
+ getPerformanceHandler(): PerformanceHandler | null;
33
+ getErrorHandler(): ErrorHandler | null;
34
+ getGoogleAnalytics(): GoogleAnalyticsIntegration | null;
35
+ destroy(): Promise<void>;
36
+ /**
37
+ * Helper to safely access managers/handlers and convert undefined to null
38
+ */
39
+ private safeAccess;
40
+ /**
41
+ * Ensures the app is initialized, throws if not
42
+ */
43
+ private ensureInitialized;
44
+ /**
45
+ * Ensures destroy operation is not in progress, throws if it is
46
+ */
47
+ private ensureNotDestroying;
48
+ }
@@ -0,0 +1,106 @@
1
+ import { App } from './app';
2
+ import { normalizeConfig } from './utils';
3
+ /**
4
+ * Test bridge for E2E testing
5
+ */
6
+ export class TestBridge extends App {
7
+ constructor(isInitializing, isDestroying) {
8
+ super();
9
+ this._isDestroying = false;
10
+ this._isInitializing = isInitializing;
11
+ this._isDestroying = isDestroying;
12
+ }
13
+ isInitializing() {
14
+ return this._isInitializing;
15
+ }
16
+ sendCustomEvent(name, data) {
17
+ this.ensureInitialized();
18
+ super.sendCustomEvent(name, data);
19
+ }
20
+ getSessionData() {
21
+ return {
22
+ id: this.get('sessionId'),
23
+ isActive: !!this.get('sessionId'),
24
+ timeout: this.get('config')?.sessionTimeout ?? 15 * 60 * 1000,
25
+ };
26
+ }
27
+ setSessionTimeout(timeout) {
28
+ const config = this.get('config');
29
+ if (config) {
30
+ const { config: normalizedConfig } = normalizeConfig({ ...config, sessionTimeout: timeout });
31
+ this.set('config', normalizedConfig);
32
+ }
33
+ }
34
+ getQueueLength() {
35
+ return this.managers.event?.getQueueLength() ?? 0;
36
+ }
37
+ forceInitLock(enabled = true) {
38
+ this._isInitializing = enabled;
39
+ }
40
+ get(key) {
41
+ return super.get(key);
42
+ }
43
+ // Manager accessors
44
+ getStorageManager() {
45
+ return this.safeAccess(this.managers?.storage);
46
+ }
47
+ getEventManager() {
48
+ return this.safeAccess(this.managers?.event);
49
+ }
50
+ // Handler accessors
51
+ getSessionHandler() {
52
+ return this.safeAccess(this.handlers?.session);
53
+ }
54
+ getPageViewHandler() {
55
+ return this.safeAccess(this.handlers?.pageView);
56
+ }
57
+ getClickHandler() {
58
+ return this.safeAccess(this.handlers?.click);
59
+ }
60
+ getScrollHandler() {
61
+ return this.safeAccess(this.handlers?.scroll);
62
+ }
63
+ getPerformanceHandler() {
64
+ return this.safeAccess(this.handlers?.performance);
65
+ }
66
+ getErrorHandler() {
67
+ return this.safeAccess(this.handlers?.error);
68
+ }
69
+ // Integration accessors
70
+ getGoogleAnalytics() {
71
+ return this.safeAccess(this.integrations?.googleAnalytics);
72
+ }
73
+ async destroy() {
74
+ this.ensureInitialized();
75
+ this.ensureNotDestroying();
76
+ this._isDestroying = true;
77
+ try {
78
+ await super.destroy();
79
+ }
80
+ finally {
81
+ this._isDestroying = false;
82
+ }
83
+ }
84
+ /**
85
+ * Helper to safely access managers/handlers and convert undefined to null
86
+ */
87
+ safeAccess(value) {
88
+ return value ?? null;
89
+ }
90
+ /**
91
+ * Ensures the app is initialized, throws if not
92
+ */
93
+ ensureInitialized() {
94
+ if (!this.initialized) {
95
+ throw new Error('App not initialized');
96
+ }
97
+ }
98
+ /**
99
+ * Ensures destroy operation is not in progress, throws if it is
100
+ */
101
+ ensureNotDestroying() {
102
+ if (this._isDestroying) {
103
+ throw new Error('Destroy operation already in progress');
104
+ }
105
+ }
106
+ }