@dashgram/javascript 1.0.0 → 1.0.1

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 (46) hide show
  1. package/README.md +117 -174
  2. package/dist/core/config.d.ts +1 -0
  3. package/dist/core/config.d.ts.map +1 -1
  4. package/dist/core/config.js +5 -4
  5. package/dist/core/context.d.ts +4 -8
  6. package/dist/core/context.d.ts.map +1 -1
  7. package/dist/core/context.js +6 -17
  8. package/dist/core/event-queue.d.ts +4 -4
  9. package/dist/core/event-queue.d.ts.map +1 -1
  10. package/dist/dashgram.min.js +1 -0
  11. package/dist/errors.d.ts +0 -3
  12. package/dist/errors.d.ts.map +1 -1
  13. package/dist/errors.js +0 -10
  14. package/dist/index.d.ts +3 -6
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +20 -32
  17. package/dist/trackers/base-tracker.d.ts +3 -3
  18. package/dist/trackers/base-tracker.d.ts.map +1 -1
  19. package/dist/trackers/base-tracker.js +1 -4
  20. package/dist/trackers/core-tracker.d.ts +3 -3
  21. package/dist/trackers/core-tracker.d.ts.map +1 -1
  22. package/dist/trackers/core-tracker.js +19 -21
  23. package/dist/trackers/deep-tracker.d.ts +6 -0
  24. package/dist/trackers/deep-tracker.d.ts.map +1 -1
  25. package/dist/trackers/deep-tracker.js +562 -12
  26. package/dist/trackers/interaction-tracker.d.ts +7 -3
  27. package/dist/trackers/interaction-tracker.d.ts.map +1 -1
  28. package/dist/trackers/interaction-tracker.js +142 -37
  29. package/dist/transport/batch-processor.d.ts +4 -4
  30. package/dist/transport/batch-processor.d.ts.map +1 -1
  31. package/dist/transport/batch-processor.js +8 -8
  32. package/dist/transport/transport.d.ts +4 -3
  33. package/dist/transport/transport.d.ts.map +1 -1
  34. package/dist/transport/transport.js +17 -24
  35. package/dist/types/index.d.ts +100 -25
  36. package/dist/types/index.d.ts.map +1 -1
  37. package/dist/utils/device.d.ts +3 -7
  38. package/dist/utils/device.d.ts.map +1 -1
  39. package/dist/utils/device.js +19 -53
  40. package/dist/utils/telegram.d.ts +4 -6
  41. package/dist/utils/telegram.d.ts.map +1 -1
  42. package/dist/utils/telegram.js +45 -29
  43. package/package.json +5 -3
  44. package/dist/core/session.d.ts +0 -13
  45. package/dist/core/session.d.ts.map +0 -1
  46. package/dist/core/session.js +0 -63
@@ -1,15 +1,16 @@
1
- import { BaseTracker } from './base-tracker';
2
- import { throttle } from '../utils/helpers';
3
- import { getElementSelector, getElementText } from '../utils/helpers';
4
- import { getCurrentPath, getPageTitle, getCurrentUrl } from '../utils/device';
1
+ import { BaseTracker } from "./base-tracker";
2
+ import { throttle } from "../utils/helpers";
3
+ import { getElementSelector, getElementText } from "../utils/helpers";
4
+ import { getCurrentPath, getPageTitle, getCurrentUrl } from "../utils/device";
5
5
  export class InteractionTracker extends BaseTracker {
6
6
  constructor(config, trackCallback) {
7
7
  super(config, trackCallback, 2);
8
8
  this.unsubscribers = [];
9
- this.lastPath = '';
9
+ this.lastPath = "";
10
+ this.inputValues = new Map();
10
11
  }
11
12
  setup() {
12
- if (typeof window === 'undefined') {
13
+ if (typeof window === "undefined") {
13
14
  return;
14
15
  }
15
16
  this.trackScreenView();
@@ -17,10 +18,12 @@ export class InteractionTracker extends BaseTracker {
17
18
  this.setupClickTracking();
18
19
  this.setupFormTracking();
19
20
  this.setupInputTracking();
21
+ this.setupClipboardTracking();
22
+ this.setupSelectionTracking();
20
23
  this.setupErrorTracking();
21
24
  }
22
25
  teardown() {
23
- this.unsubscribers.forEach((unsubscribe) => unsubscribe());
26
+ this.unsubscribers.forEach(unsubscribe => unsubscribe());
24
27
  this.unsubscribers = [];
25
28
  }
26
29
  trackScreenView() {
@@ -29,11 +32,11 @@ export class InteractionTracker extends BaseTracker {
29
32
  return;
30
33
  }
31
34
  this.lastPath = path;
32
- this.track('screen_view', {
35
+ this.track("screen_view", {
33
36
  path,
34
37
  url: getCurrentUrl(),
35
38
  title: getPageTitle(),
36
- referrer: document.referrer || 'direct',
39
+ referrer: document.referrer || "direct"
37
40
  });
38
41
  }
39
42
  setupHistoryTracking() {
@@ -50,11 +53,11 @@ export class InteractionTracker extends BaseTracker {
50
53
  originalReplaceState.apply(history, args);
51
54
  trackOnHistoryChange();
52
55
  };
53
- window.addEventListener('popstate', trackOnHistoryChange);
56
+ window.addEventListener("popstate", trackOnHistoryChange);
54
57
  this.unsubscribers.push(() => {
55
58
  history.pushState = originalPushState;
56
59
  history.replaceState = originalReplaceState;
57
- window.removeEventListener('popstate', trackOnHistoryChange);
60
+ window.removeEventListener("popstate", trackOnHistoryChange);
58
61
  });
59
62
  }
60
63
  setupClickTracking() {
@@ -65,35 +68,57 @@ export class InteractionTracker extends BaseTracker {
65
68
  const button = target.closest('button, [role="button"], a');
66
69
  if (button) {
67
70
  const tagName = button.tagName.toLowerCase();
68
- const isLink = tagName === 'a';
69
- this.track(isLink ? 'link_click' : 'button_click', {
70
- element: getElementSelector(button),
71
- text: getElementText(button),
72
- href: isLink ? button.href : undefined,
73
- target: isLink ? button.target : undefined,
74
- });
71
+ const isLink = tagName === "a";
72
+ if (isLink) {
73
+ const anchor = button;
74
+ const href = anchor.href;
75
+ const isExternal = href ? this.isExternalLink(href) : false;
76
+ this.track("link_click", {
77
+ element: getElementSelector(button),
78
+ text: getElementText(button),
79
+ href: href || undefined,
80
+ target: anchor.target || undefined,
81
+ is_external: isExternal,
82
+ is_download: anchor.hasAttribute("download")
83
+ });
84
+ }
85
+ else {
86
+ this.track("button_click", {
87
+ element: getElementSelector(button),
88
+ text: getElementText(button)
89
+ });
90
+ }
75
91
  }
76
92
  };
77
- document.addEventListener('click', handleClick, { capture: true });
93
+ document.addEventListener("click", handleClick, { capture: true });
78
94
  this.unsubscribers.push(() => {
79
- document.removeEventListener('click', handleClick, { capture: true });
95
+ document.removeEventListener("click", handleClick, { capture: true });
80
96
  });
81
97
  }
98
+ isExternalLink(url) {
99
+ try {
100
+ const linkUrl = new URL(url, window.location.href);
101
+ return linkUrl.origin !== window.location.origin;
102
+ }
103
+ catch {
104
+ return false;
105
+ }
106
+ }
82
107
  setupFormTracking() {
83
108
  const handleSubmit = (event) => {
84
109
  const form = event.target;
85
110
  if (!form)
86
111
  return;
87
- this.track('form_submit', {
112
+ this.track("form_submit", {
88
113
  form_id: form.id || undefined,
89
114
  form_name: form.name || undefined,
90
115
  form_action: form.action || undefined,
91
- form_method: form.method || undefined,
116
+ form_method: form.method || undefined
92
117
  });
93
118
  };
94
- document.addEventListener('submit', handleSubmit, { capture: true });
119
+ document.addEventListener("submit", handleSubmit, { capture: true });
95
120
  this.unsubscribers.push(() => {
96
- document.removeEventListener('submit', handleSubmit, { capture: true });
121
+ document.removeEventListener("submit", handleSubmit, { capture: true });
97
122
  });
98
123
  }
99
124
  setupInputTracking() {
@@ -102,44 +127,124 @@ export class InteractionTracker extends BaseTracker {
102
127
  if (!target)
103
128
  return;
104
129
  const tagName = target.tagName.toLowerCase();
105
- if (['input', 'textarea', 'select'].includes(tagName)) {
130
+ if (["input", "textarea", "select"].includes(tagName)) {
106
131
  const input = target;
107
- this.track('input_focus', {
132
+ this.inputValues.set(target, input.value || "");
133
+ this.track("input_focus", {
108
134
  element: getElementSelector(input),
109
135
  input_type: input.type || tagName,
110
136
  input_name: input.name || undefined,
111
- input_id: input.id || undefined,
137
+ input_id: input.id || undefined
112
138
  });
113
139
  }
114
140
  }, 1000);
115
- document.addEventListener('focus', handleFocus, { capture: true });
141
+ const handleBlur = (event) => {
142
+ const target = event.target;
143
+ if (!target)
144
+ return;
145
+ const tagName = target.tagName.toLowerCase();
146
+ if (["input", "textarea", "select"].includes(tagName)) {
147
+ const input = target;
148
+ const previousValue = this.inputValues.get(target);
149
+ const currentValue = input.value || "";
150
+ if (previousValue !== undefined && previousValue !== currentValue) {
151
+ this.track("input_change", {
152
+ element: getElementSelector(input),
153
+ input_type: input.type || tagName,
154
+ input_name: input.name || undefined,
155
+ input_id: input.id || undefined,
156
+ had_value: previousValue.length > 0,
157
+ has_value: currentValue.length > 0
158
+ });
159
+ }
160
+ this.inputValues.delete(target);
161
+ }
162
+ };
163
+ document.addEventListener("focus", handleFocus, { capture: true });
164
+ document.addEventListener("blur", handleBlur, { capture: true });
165
+ this.unsubscribers.push(() => {
166
+ document.removeEventListener("focus", handleFocus, { capture: true });
167
+ document.removeEventListener("blur", handleBlur, { capture: true });
168
+ this.inputValues.clear();
169
+ });
170
+ }
171
+ setupClipboardTracking() {
172
+ const handleCopy = (_event) => {
173
+ const selection = window.getSelection();
174
+ const selectedText = selection?.toString() || "";
175
+ this.track("copy", {
176
+ text_length: selectedText.length,
177
+ has_selection: selectedText.length > 0
178
+ });
179
+ };
180
+ const handleCut = (_event) => {
181
+ const selection = window.getSelection();
182
+ const selectedText = selection?.toString() || "";
183
+ this.track("cut", {
184
+ text_length: selectedText.length,
185
+ has_selection: selectedText.length > 0
186
+ });
187
+ };
188
+ const handlePaste = (event) => {
189
+ const pastedText = event.clipboardData?.getData("text") || "";
190
+ const target = event.target;
191
+ this.track("paste", {
192
+ text_length: pastedText.length,
193
+ target_element: target ? getElementSelector(target) : undefined
194
+ });
195
+ };
196
+ document.addEventListener("copy", handleCopy);
197
+ document.addEventListener("cut", handleCut);
198
+ document.addEventListener("paste", handlePaste);
199
+ this.unsubscribers.push(() => {
200
+ document.removeEventListener("copy", handleCopy);
201
+ document.removeEventListener("cut", handleCut);
202
+ document.removeEventListener("paste", handlePaste);
203
+ });
204
+ }
205
+ setupSelectionTracking() {
206
+ let selectionTimeout;
207
+ const handleSelectionChange = () => {
208
+ clearTimeout(selectionTimeout);
209
+ selectionTimeout = setTimeout(() => {
210
+ const selection = window.getSelection();
211
+ const selectedText = selection?.toString() || "";
212
+ if (selectedText.length > 0) {
213
+ this.track("text_select", {
214
+ text_length: selectedText.length
215
+ });
216
+ }
217
+ }, 500);
218
+ };
219
+ document.addEventListener("selectionchange", handleSelectionChange);
116
220
  this.unsubscribers.push(() => {
117
- document.removeEventListener('focus', handleFocus, { capture: true });
221
+ document.removeEventListener("selectionchange", handleSelectionChange);
222
+ clearTimeout(selectionTimeout);
118
223
  });
119
224
  }
120
225
  setupErrorTracking() {
121
226
  const handleError = (event) => {
122
- this.track('js_error', {
227
+ this.track("js_error", {
123
228
  message: event.message,
124
229
  filename: event.filename,
125
230
  lineno: event.lineno,
126
231
  colno: event.colno,
127
- stack: event.error?.stack,
232
+ stack: event.error?.stack
128
233
  });
129
234
  };
130
- window.addEventListener('error', handleError);
235
+ window.addEventListener("error", handleError);
131
236
  this.unsubscribers.push(() => {
132
- window.removeEventListener('error', handleError);
237
+ window.removeEventListener("error", handleError);
133
238
  });
134
239
  const handleRejection = (event) => {
135
- this.track('unhandled_rejection', {
240
+ this.track("unhandled_rejection", {
136
241
  reason: String(event.reason),
137
- promise: String(event.promise),
242
+ promise: String(event.promise)
138
243
  });
139
244
  };
140
- window.addEventListener('unhandledrejection', handleRejection);
245
+ window.addEventListener("unhandledrejection", handleRejection);
141
246
  this.unsubscribers.push(() => {
142
- window.removeEventListener('unhandledrejection', handleRejection);
247
+ window.removeEventListener("unhandledrejection", handleRejection);
143
248
  });
144
249
  }
145
250
  }
@@ -1,6 +1,6 @@
1
- import type { DashgramEvent } from '../types';
2
- import type { Config } from '../core/config';
3
- import { Transport } from './transport';
1
+ import type { WebAppEvent } from "../types";
2
+ import type { Config } from "../core/config";
3
+ import { Transport } from "./transport";
4
4
  export declare class BatchProcessor {
5
5
  private config;
6
6
  private queue;
@@ -10,7 +10,7 @@ export declare class BatchProcessor {
10
10
  constructor(config: Config, transport: Transport);
11
11
  start(): void;
12
12
  stop(): void;
13
- addEvent(event: DashgramEvent): void;
13
+ addEvent(event: WebAppEvent): void;
14
14
  private scheduleFlush;
15
15
  flush(): void;
16
16
  flushAsync(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"batch-processor.d.ts","sourceRoot":"","sources":["../../src/transport/batch-processor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAKxC,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,SAAS,CAAkB;gBAEvB,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS;IAShD,KAAK,IAAI,IAAI;IAab,IAAI,IAAI,IAAI;IAYZ,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAapC,OAAO,CAAC,aAAa;IAkBrB,KAAK,IAAI,IAAI;IAWP,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAajC,OAAO,CAAC,sBAAsB;CAwB/B"}
1
+ {"version":3,"file":"batch-processor.d.ts","sourceRoot":"","sources":["../../src/transport/batch-processor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAE5C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAKvC,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,SAAS,CAAW;IAC5B,OAAO,CAAC,UAAU,CAA6C;IAC/D,OAAO,CAAC,SAAS,CAAiB;gBAEtB,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS;IAShD,KAAK,IAAI,IAAI;IAab,IAAI,IAAI,IAAI;IAYZ,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAalC,OAAO,CAAC,aAAa;IAkBrB,KAAK,IAAI,IAAI;IAWP,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAajC,OAAO,CAAC,sBAAsB;CAqB/B"}
@@ -1,4 +1,4 @@
1
- import { EventQueue } from '../core/event-queue';
1
+ import { EventQueue } from "../core/event-queue";
2
2
  export class BatchProcessor {
3
3
  constructor(config, transport) {
4
4
  this.flushTimer = null;
@@ -24,7 +24,7 @@ export class BatchProcessor {
24
24
  }
25
25
  addEvent(event) {
26
26
  this.queue.enqueue(event);
27
- const batchSize = this.config.get('batchSize');
27
+ const batchSize = this.config.get("batchSize");
28
28
  if (this.queue.size() >= batchSize) {
29
29
  this.flush();
30
30
  }
@@ -33,7 +33,7 @@ export class BatchProcessor {
33
33
  if (this.flushTimer) {
34
34
  clearTimeout(this.flushTimer);
35
35
  }
36
- const interval = this.config.get('flushInterval');
36
+ const interval = this.config.get("flushInterval");
37
37
  this.flushTimer = setTimeout(() => {
38
38
  this.flush();
39
39
  if (this.isStarted) {
@@ -55,7 +55,7 @@ export class BatchProcessor {
55
55
  await this.transport.flush();
56
56
  }
57
57
  setupPageUnloadHandler() {
58
- if (typeof window === 'undefined') {
58
+ if (typeof window === "undefined") {
59
59
  return;
60
60
  }
61
61
  const handleUnload = () => {
@@ -64,12 +64,12 @@ export class BatchProcessor {
64
64
  this.transport.sendBeacon(events);
65
65
  }
66
66
  };
67
- window.addEventListener('visibilitychange', () => {
68
- if (document.visibilityState === 'hidden') {
67
+ window.addEventListener("visibilitychange", () => {
68
+ if (document.visibilityState === "hidden") {
69
69
  handleUnload();
70
70
  }
71
71
  });
72
- window.addEventListener('pagehide', handleUnload);
73
- window.addEventListener('beforeunload', handleUnload);
72
+ window.addEventListener("pagehide", handleUnload);
73
+ window.addEventListener("beforeunload", handleUnload);
74
74
  }
75
75
  }
@@ -1,4 +1,4 @@
1
- import type { DashgramEvent } from "../types";
1
+ import type { WebAppEvent } from "../types";
2
2
  import type { Config } from "../core/config";
3
3
  export declare class Transport {
4
4
  private config;
@@ -6,9 +6,10 @@ export declare class Transport {
6
6
  private pendingRequests;
7
7
  constructor(config: Config);
8
8
  private setupOnlineListener;
9
- send(events: DashgramEvent[]): Promise<void>;
9
+ private buildPayload;
10
+ send(events: WebAppEvent[]): Promise<void>;
10
11
  private sendRequest;
11
- sendBeacon(events: DashgramEvent[]): boolean;
12
+ sendBeacon(events: WebAppEvent[]): boolean;
12
13
  flush(): Promise<void>;
13
14
  private log;
14
15
  private logError;
@@ -1 +1 @@
1
- {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/transport/transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAO5C,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,eAAe,CAAgC;gBAE3C,MAAM,EAAE,MAAM;IAQ1B,OAAO,CAAC,mBAAmB;IAuBrB,IAAI,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;YAuDpC,WAAW;IAqDzB,UAAU,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO;IAmCtC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAO5B,OAAO,CAAC,GAAG;IASX,OAAO,CAAC,QAAQ;CAKjB"}
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/transport/transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAsB,MAAM,UAAU,CAAA;AAC/D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAQ5C,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,eAAe,CAAgC;gBAE3C,MAAM,EAAE,MAAM;IAQ1B,OAAO,CAAC,mBAAmB;IAqB3B,OAAO,CAAC,YAAY;IAUd,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;YA2ClC,WAAW;IA2CzB,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO;IA2BpC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAO5B,OAAO,CAAC,GAAG;IASX,OAAO,CAAC,QAAQ;CAKjB"}
@@ -1,5 +1,6 @@
1
1
  import { safeStringify } from "../utils/helpers";
2
- import { InvalidCredentialsError, DashgramAPIError, NetworkError } from "../errors";
2
+ import { DashgramAPIError, NetworkError } from "../errors";
3
+ import { getCurrentOrigin } from "../utils/device";
3
4
  export class Transport {
4
5
  constructor(config) {
5
6
  this.isOnline = true;
@@ -21,6 +22,12 @@ export class Transport {
21
22
  });
22
23
  this.isOnline = navigator.onLine;
23
24
  }
25
+ buildPayload(events) {
26
+ return {
27
+ origin: getCurrentOrigin() || undefined,
28
+ updates: events
29
+ };
30
+ }
24
31
  async send(events) {
25
32
  if (events.length === 0) {
26
33
  return;
@@ -43,9 +50,7 @@ export class Transport {
43
50
  const onError = this.config.getOnError();
44
51
  if (onError) {
45
52
  try {
46
- if (error instanceof InvalidCredentialsError ||
47
- error instanceof DashgramAPIError ||
48
- error instanceof NetworkError) {
53
+ if (error instanceof DashgramAPIError || error instanceof NetworkError) {
49
54
  onError(error);
50
55
  }
51
56
  else if (error instanceof Error) {
@@ -62,23 +67,17 @@ export class Transport {
62
67
  }
63
68
  }
64
69
  async sendRequest(events) {
65
- const url = this.config.get("apiUrl");
66
- const apiKey = this.config.get("apiKey");
67
- const projectId = this.config.get("projectId");
70
+ const url = this.config.getTrackUrl();
71
+ const payload = this.buildPayload(events);
68
72
  try {
69
73
  const response = await fetch(url, {
70
74
  method: "POST",
71
75
  headers: {
72
- "Content-Type": "application/json",
73
- "X-API-Key": apiKey,
74
- "X-Project-ID": projectId
76
+ "Content-Type": "application/json"
75
77
  },
76
- body: safeStringify({ events }),
78
+ body: safeStringify(payload),
77
79
  keepalive: true
78
80
  });
79
- if (response.status === 403) {
80
- throw new InvalidCredentialsError();
81
- }
82
81
  if (!response.ok) {
83
82
  let details = response.statusText;
84
83
  try {
@@ -92,7 +91,7 @@ export class Transport {
92
91
  this.log(`Sent ${events.length} events successfully`);
93
92
  }
94
93
  catch (error) {
95
- if (error instanceof InvalidCredentialsError || error instanceof DashgramAPIError) {
94
+ if (error instanceof DashgramAPIError) {
96
95
  throw error;
97
96
  }
98
97
  if (error instanceof Error) {
@@ -111,15 +110,9 @@ export class Transport {
111
110
  if (typeof navigator === "undefined" || !navigator.sendBeacon) {
112
111
  return false;
113
112
  }
114
- const url = this.config.get("apiUrl");
115
- const apiKey = this.config.get("apiKey");
116
- const projectId = this.config.get("projectId");
117
- const payload = safeStringify({
118
- events,
119
- apiKey,
120
- projectId
121
- });
122
- const blob = new Blob([payload], { type: "application/json" });
113
+ const url = this.config.getTrackUrl();
114
+ const payload = this.buildPayload(events);
115
+ const blob = new Blob([safeStringify(payload)], { type: "application/json" });
123
116
  const sent = navigator.sendBeacon(url, blob);
124
117
  this.log(`sendBeacon ${sent ? "succeeded" : "failed"} for ${events.length} events`);
125
118
  return sent;
@@ -3,7 +3,6 @@ export type TrackLevel = 1 | 2 | 3;
3
3
  export type EventSource = "auto" | "manual";
4
4
  export interface DashgramConfig {
5
5
  projectId: string;
6
- apiKey: string;
7
6
  trackLevel?: TrackLevel;
8
7
  apiUrl?: string;
9
8
  batchSize?: number;
@@ -12,32 +11,30 @@ export interface DashgramConfig {
12
11
  disabled?: boolean;
13
12
  onError?: (error: DashgramError) => void;
14
13
  }
15
- export interface EventContext {
16
- platform: string;
17
- app_version: string;
18
- language: string;
19
- screen_width: number;
20
- screen_height: number;
21
- viewport_width: number;
22
- viewport_height: number;
23
- user_agent: string;
24
- timezone: string;
25
- telegram_version?: string;
14
+ export interface Telemetry {
15
+ ip?: string;
16
+ platform?: string;
17
+ user_agent?: string;
18
+ timezone?: string;
26
19
  theme?: string;
27
20
  }
28
- export type EventProperties = Record<string, any>;
29
- export interface DashgramEvent {
30
- event: string;
31
- properties: EventProperties;
32
- timestamp: string;
33
- source: EventSource;
34
- level: TrackLevel;
35
- session_id: string;
36
- user_id: string | null;
37
- context: EventContext;
21
+ export type EventProperties = Record<string, unknown>;
22
+ export interface WebAppEvent {
23
+ eventId: string;
24
+ type: string;
25
+ initData: string;
26
+ properties?: unknown;
27
+ telemetry?: Telemetry;
28
+ source?: string;
29
+ level?: number;
30
+ timestamp: number;
31
+ }
32
+ export interface WebAppTrackRequest {
33
+ origin?: string;
34
+ updates: WebAppEvent[];
38
35
  }
39
- export type UserTraits = Record<string, any>;
40
36
  export interface TelegramWebApp {
37
+ initData?: string;
41
38
  initDataUnsafe?: {
42
39
  user?: {
43
40
  id: number;
@@ -50,8 +47,86 @@ export interface TelegramWebApp {
50
47
  platform?: string;
51
48
  version?: string;
52
49
  themeParams?: Record<string, string>;
53
- onEvent?: (event: string, callback: () => void) => void;
54
- offEvent?: (event: string, callback: () => void) => void;
50
+ colorScheme?: "light" | "dark";
51
+ isExpanded?: boolean;
52
+ viewportHeight?: number;
53
+ viewportStableHeight?: number;
54
+ safeAreaInset?: {
55
+ top: number;
56
+ bottom: number;
57
+ left: number;
58
+ right: number;
59
+ };
60
+ contentSafeAreaInset?: {
61
+ top: number;
62
+ bottom: number;
63
+ left: number;
64
+ right: number;
65
+ };
66
+ MainButton?: {
67
+ text?: string;
68
+ isVisible?: boolean;
69
+ isActive?: boolean;
70
+ isProgressVisible?: boolean;
71
+ };
72
+ SecondaryButton?: {
73
+ text?: string;
74
+ isVisible?: boolean;
75
+ isActive?: boolean;
76
+ isProgressVisible?: boolean;
77
+ };
78
+ BiometricManager?: {
79
+ isInited?: boolean;
80
+ isBiometricAvailable?: boolean;
81
+ biometricType?: "finger" | "face" | "unknown";
82
+ isAccessRequested?: boolean;
83
+ isAccessGranted?: boolean;
84
+ isBiometricTokenSaved?: boolean;
85
+ deviceId?: string;
86
+ };
87
+ LocationManager?: {
88
+ isInited?: boolean;
89
+ isLocationAvailable?: boolean;
90
+ isAccessRequested?: boolean;
91
+ isAccessGranted?: boolean;
92
+ };
93
+ Accelerometer?: {
94
+ isStarted?: boolean;
95
+ x?: number;
96
+ y?: number;
97
+ z?: number;
98
+ };
99
+ Gyroscope?: {
100
+ isStarted?: boolean;
101
+ x?: number;
102
+ y?: number;
103
+ z?: number;
104
+ };
105
+ DeviceOrientation?: {
106
+ isStarted?: boolean;
107
+ absolute?: boolean;
108
+ alpha?: number;
109
+ beta?: number;
110
+ gamma?: number;
111
+ };
112
+ onEvent?: (event: string, callback: (eventType: string, eventData?: unknown) => void) => void;
113
+ offEvent?: (event: string, callback: (eventType: string, eventData?: unknown) => void) => void;
114
+ openLink?: (url: string, options?: {
115
+ try_instant_view?: boolean;
116
+ }) => void;
117
+ openTelegramLink?: (url: string) => void;
118
+ switchInlineQuery?: (query: string, chooseChatTypes?: string[]) => void;
119
+ shareToStory?: (mediaUrl: string, params?: unknown) => void;
120
+ close?: (options?: {
121
+ return_back?: boolean;
122
+ }) => void;
123
+ exitFullscreen?: () => void;
124
+ openInvoice?: (slug: string, callback?: (status: string) => void) => void;
125
+ requestAccess?: (accessType: string, callback?: (status: string) => void) => void;
126
+ requestContact?: (callback?: (status: string) => void) => void;
127
+ requestPhone?: (callback?: (status: string) => void) => void;
128
+ requestLocation?: (callback?: (status: string, location?: unknown) => void) => void;
129
+ checkLocation?: (callback?: (isAvailable: boolean, location?: unknown) => void) => void;
55
130
  }
56
131
  export interface TelegramWindow extends Window {
57
132
  Telegram?: {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAK9C,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;AAKlC,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,CAAA;AAK3C,MAAM,WAAW,cAAc;IAE7B,SAAS,EAAE,MAAM,CAAA;IAGjB,MAAM,EAAE,MAAM,CAAA;IAGd,UAAU,CAAC,EAAE,UAAU,CAAA;IAGvB,MAAM,CAAC,EAAE,MAAM,CAAA;IAGf,SAAS,CAAC,EAAE,MAAM,CAAA;IAGlB,aAAa,CAAC,EAAE,MAAM,CAAA;IAGtB,KAAK,CAAC,EAAE,OAAO,CAAA;IAGf,QAAQ,CAAC,EAAE,OAAO,CAAA;IAGlB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;CACzC;AAKD,MAAM,WAAW,YAAY;IAE3B,QAAQ,EAAE,MAAM,CAAA;IAGhB,WAAW,EAAE,MAAM,CAAA;IAGnB,QAAQ,EAAE,MAAM,CAAA;IAGhB,YAAY,EAAE,MAAM,CAAA;IAGpB,aAAa,EAAE,MAAM,CAAA;IAGrB,cAAc,EAAE,MAAM,CAAA;IAGtB,eAAe,EAAE,MAAM,CAAA;IAGvB,UAAU,EAAE,MAAM,CAAA;IAGlB,QAAQ,EAAE,MAAM,CAAA;IAGhB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAGzB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAKD,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;AAKjD,MAAM,WAAW,aAAa;IAE5B,KAAK,EAAE,MAAM,CAAA;IAGb,UAAU,EAAE,eAAe,CAAA;IAG3B,SAAS,EAAE,MAAM,CAAA;IAGjB,MAAM,EAAE,WAAW,CAAA;IAGnB,KAAK,EAAE,UAAU,CAAA;IAGjB,UAAU,EAAE,MAAM,CAAA;IAGlB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAGtB,OAAO,EAAE,YAAY,CAAA;CACtB;AAKD,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;AAK5C,MAAM,WAAW,cAAc;IAC7B,cAAc,CAAC,EAAE;QACf,IAAI,CAAC,EAAE;YACL,EAAE,EAAE,MAAM,CAAA;YACV,UAAU,CAAC,EAAE,MAAM,CAAA;YACnB,SAAS,CAAC,EAAE,MAAM,CAAA;YAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;YACjB,aAAa,CAAC,EAAE,MAAM,CAAA;SACvB,CAAA;KACF,CAAA;IACD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACpC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAA;IACvD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAA;CACzD;AAKD,MAAM,WAAW,cAAe,SAAQ,MAAM;IAC5C,QAAQ,CAAC,EAAE;QACT,MAAM,CAAC,EAAE,cAAc,CAAA;KACxB,CAAA;CACF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,7 @@
1
- import type { EventContext } from '../types';
2
- export declare function getDeviceContext(): EventContext;
3
- export declare function getViewportSize(): {
4
- width: number;
5
- height: number;
6
- };
7
- export declare function getScrollDepth(): number;
1
+ import type { Telemetry } from "../types";
2
+ export declare function getTelemetry(): Telemetry;
8
3
  export declare function getCurrentUrl(): string;
9
4
  export declare function getCurrentPath(): string;
10
5
  export declare function getPageTitle(): string;
6
+ export declare function getCurrentOrigin(): string;
11
7
  //# sourceMappingURL=device.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../src/utils/device.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAW7C,wBAAgB,gBAAgB,IAAI,YAAY,CA+B/C;AAKD,wBAAgB,eAAe,IAAI;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CASnE;AAKD,wBAAgB,cAAc,IAAI,MAAM,CAiBvC;AAKD,wBAAgB,aAAa,IAAI,MAAM,CAMtC;AAKD,wBAAgB,cAAc,IAAI,MAAM,CAMvC;AAKD,wBAAgB,YAAY,IAAI,MAAM,CAMrC"}
1
+ {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../src/utils/device.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAMzC,wBAAgB,YAAY,IAAI,SAAS,CAaxC;AAKD,wBAAgB,aAAa,IAAI,MAAM,CAMtC;AAKD,wBAAgB,cAAc,IAAI,MAAM,CAMvC;AAKD,wBAAgB,YAAY,IAAI,MAAM,CAMrC;AAKD,wBAAgB,gBAAgB,IAAI,MAAM,CAMzC"}