@notix-hub/sdk 0.2.1 → 0.3.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.
@@ -0,0 +1,18 @@
1
+ interface ErrorEntry {
2
+ message: string;
3
+ file: string;
4
+ line: number;
5
+ col: number;
6
+ stack: string;
7
+ ts: string;
8
+ }
9
+ export declare class ErrorBatcher {
10
+ private sendFn;
11
+ private errors;
12
+ private timer;
13
+ constructor(sendFn: (errors: ErrorEntry[]) => void);
14
+ private bindGlobal;
15
+ private startTimer;
16
+ flush(): void;
17
+ }
18
+ export {};
package/dist/index.cjs CHANGED
@@ -224,6 +224,68 @@ class MetrikaTracker {
224
224
  }
225
225
  }
226
226
 
227
+ const BATCH_SIZE = 10;
228
+ const FLUSH_INTERVAL = 60000;
229
+ class ErrorBatcher {
230
+ constructor(sendFn) {
231
+ this.sendFn = sendFn;
232
+ this.errors = [];
233
+ this.timer = null;
234
+ this.bindGlobal();
235
+ }
236
+ bindGlobal() {
237
+ if (typeof window === 'undefined')
238
+ return;
239
+ const collect = (ev) => {
240
+ this.errors.push({
241
+ message: ev.message || 'Unknown error',
242
+ file: ev.filename || '',
243
+ line: ev.lineno || 0,
244
+ col: ev.colno || 0,
245
+ stack: ev.error?.stack || '',
246
+ ts: new Date().toISOString(),
247
+ });
248
+ if (this.errors.length >= BATCH_SIZE)
249
+ this.flush();
250
+ this.startTimer();
251
+ };
252
+ window.addEventListener('error', collect);
253
+ window.addEventListener('unhandledrejection', (ev) => {
254
+ this.errors.push({
255
+ message: ev.reason?.message || String(ev.reason),
256
+ file: '',
257
+ line: 0,
258
+ col: 0,
259
+ stack: ev.reason?.stack || '',
260
+ ts: new Date().toISOString(),
261
+ });
262
+ if (this.errors.length >= BATCH_SIZE)
263
+ this.flush();
264
+ this.startTimer();
265
+ });
266
+ window.addEventListener('beforeunload', () => this.flush());
267
+ document.addEventListener('visibilitychange', () => {
268
+ if (document.visibilityState === 'hidden')
269
+ this.flush();
270
+ });
271
+ }
272
+ startTimer() {
273
+ if (this.timer)
274
+ return;
275
+ this.timer = setTimeout(() => this.flush(), FLUSH_INTERVAL);
276
+ }
277
+ flush() {
278
+ if (this.errors.length === 0)
279
+ return;
280
+ this.sendFn([...this.errors]);
281
+ this.errors = [];
282
+ if (this.timer) {
283
+ clearTimeout(this.timer);
284
+ this.timer = null;
285
+ }
286
+ }
287
+ }
288
+
227
289
  const DEFAULT_ENDPOINT = 'https://notix-hub.ru/api/v1/webhook';
228
290
  class Notix {
229
291
  constructor(config) {
@@ -239,6 +301,12 @@ class Notix {
239
301
  if (config.autoCapture !== false) {
240
302
  this.capture();
241
303
  }
304
+ if (config.metricEnabled) {
305
+ this.sendPageview();
306
+ }
307
+ if (config.errorTrackingEnabled) {
308
+ this.enableErrorTracking();
309
+ }
242
310
  }
243
311
  async notify(payload) {
244
312
  if (!payload.title) {
@@ -274,12 +342,57 @@ class Notix {
274
342
  this.captureActive = false;
275
343
  this.log('Notix destroyed');
276
344
  }
345
+ sendPageview(page, referrer) {
346
+ const visitorId = getOrCreateVisitorId();
347
+ const payload = {
348
+ title: 'Посетитель на сайте',
349
+ type: 'metric',
350
+ payload: {
351
+ event_type: 'pageview',
352
+ visitor_id: visitorId,
353
+ page: page || location.pathname,
354
+ referrer: referrer || document.referrer || undefined,
355
+ value: 1,
356
+ },
357
+ };
358
+ this.notify(payload).catch(() => { });
359
+ this.log('Pageview sent:', page || location.pathname);
360
+ }
361
+ enableErrorTracking() {
362
+ if (typeof window === 'undefined')
363
+ return;
364
+ new ErrorBatcher((errors) => {
365
+ this.notify({
366
+ title: `Ошибки на странице (${errors.length})`,
367
+ type: 'error_batch',
368
+ payload: { errors },
369
+ }).catch(() => { });
370
+ });
371
+ this.log('Error tracking activated');
372
+ }
373
+ static getVisitorId() {
374
+ return getOrCreateVisitorId();
375
+ }
277
376
  log(...args) {
278
377
  if (this.debug) {
279
378
  console.log('[Notix]', ...args);
280
379
  }
281
380
  }
282
381
  }
382
+ const VISITOR_KEY = 'notix_vid';
383
+ function getOrCreateVisitorId() {
384
+ try {
385
+ let vid = localStorage.getItem(VISITOR_KEY);
386
+ if (!vid) {
387
+ vid = crypto.randomUUID();
388
+ localStorage.setItem(VISITOR_KEY, vid);
389
+ }
390
+ return vid;
391
+ }
392
+ catch {
393
+ return 'unknown';
394
+ }
395
+ }
283
396
 
284
397
  if (typeof document !== 'undefined') {
285
398
  const thisScript = document.currentScript;
@@ -292,11 +405,15 @@ if (typeof document !== 'undefined') {
292
405
  const timeout = thisScript.dataset.timeout ? parseInt(thisScript.dataset.timeout, 10) : undefined;
293
406
  const ready = document.readyState !== 'loading';
294
407
  const init = () => {
408
+ const metricEnabled = thisScript.dataset.metric === 'true';
409
+ const errorTrackingEnabled = thisScript.dataset.errors === 'true';
295
410
  const notix = new Notix({
296
411
  token,
297
412
  ...(endpoint && { endpoint }),
298
413
  autoCapture,
299
414
  debug,
415
+ metricEnabled,
416
+ errorTrackingEnabled,
300
417
  ...(timeout && { timeout }),
301
418
  });
302
419
  window.notix = notix;
package/dist/index.mjs CHANGED
@@ -222,6 +222,68 @@ class MetrikaTracker {
222
222
  }
223
223
  }
224
224
 
225
+ const BATCH_SIZE = 10;
226
+ const FLUSH_INTERVAL = 60000;
227
+ class ErrorBatcher {
228
+ constructor(sendFn) {
229
+ this.sendFn = sendFn;
230
+ this.errors = [];
231
+ this.timer = null;
232
+ this.bindGlobal();
233
+ }
234
+ bindGlobal() {
235
+ if (typeof window === 'undefined')
236
+ return;
237
+ const collect = (ev) => {
238
+ this.errors.push({
239
+ message: ev.message || 'Unknown error',
240
+ file: ev.filename || '',
241
+ line: ev.lineno || 0,
242
+ col: ev.colno || 0,
243
+ stack: ev.error?.stack || '',
244
+ ts: new Date().toISOString(),
245
+ });
246
+ if (this.errors.length >= BATCH_SIZE)
247
+ this.flush();
248
+ this.startTimer();
249
+ };
250
+ window.addEventListener('error', collect);
251
+ window.addEventListener('unhandledrejection', (ev) => {
252
+ this.errors.push({
253
+ message: ev.reason?.message || String(ev.reason),
254
+ file: '',
255
+ line: 0,
256
+ col: 0,
257
+ stack: ev.reason?.stack || '',
258
+ ts: new Date().toISOString(),
259
+ });
260
+ if (this.errors.length >= BATCH_SIZE)
261
+ this.flush();
262
+ this.startTimer();
263
+ });
264
+ window.addEventListener('beforeunload', () => this.flush());
265
+ document.addEventListener('visibilitychange', () => {
266
+ if (document.visibilityState === 'hidden')
267
+ this.flush();
268
+ });
269
+ }
270
+ startTimer() {
271
+ if (this.timer)
272
+ return;
273
+ this.timer = setTimeout(() => this.flush(), FLUSH_INTERVAL);
274
+ }
275
+ flush() {
276
+ if (this.errors.length === 0)
277
+ return;
278
+ this.sendFn([...this.errors]);
279
+ this.errors = [];
280
+ if (this.timer) {
281
+ clearTimeout(this.timer);
282
+ this.timer = null;
283
+ }
284
+ }
285
+ }
286
+
225
287
  const DEFAULT_ENDPOINT = 'https://notix-hub.ru/api/v1/webhook';
226
288
  class Notix {
227
289
  constructor(config) {
@@ -237,6 +299,12 @@ class Notix {
237
299
  if (config.autoCapture !== false) {
238
300
  this.capture();
239
301
  }
302
+ if (config.metricEnabled) {
303
+ this.sendPageview();
304
+ }
305
+ if (config.errorTrackingEnabled) {
306
+ this.enableErrorTracking();
307
+ }
240
308
  }
241
309
  async notify(payload) {
242
310
  if (!payload.title) {
@@ -272,12 +340,57 @@ class Notix {
272
340
  this.captureActive = false;
273
341
  this.log('Notix destroyed');
274
342
  }
343
+ sendPageview(page, referrer) {
344
+ const visitorId = getOrCreateVisitorId();
345
+ const payload = {
346
+ title: 'Посетитель на сайте',
347
+ type: 'metric',
348
+ payload: {
349
+ event_type: 'pageview',
350
+ visitor_id: visitorId,
351
+ page: page || location.pathname,
352
+ referrer: referrer || document.referrer || undefined,
353
+ value: 1,
354
+ },
355
+ };
356
+ this.notify(payload).catch(() => { });
357
+ this.log('Pageview sent:', page || location.pathname);
358
+ }
359
+ enableErrorTracking() {
360
+ if (typeof window === 'undefined')
361
+ return;
362
+ new ErrorBatcher((errors) => {
363
+ this.notify({
364
+ title: `Ошибки на странице (${errors.length})`,
365
+ type: 'error_batch',
366
+ payload: { errors },
367
+ }).catch(() => { });
368
+ });
369
+ this.log('Error tracking activated');
370
+ }
371
+ static getVisitorId() {
372
+ return getOrCreateVisitorId();
373
+ }
275
374
  log(...args) {
276
375
  if (this.debug) {
277
376
  console.log('[Notix]', ...args);
278
377
  }
279
378
  }
280
379
  }
380
+ const VISITOR_KEY = 'notix_vid';
381
+ function getOrCreateVisitorId() {
382
+ try {
383
+ let vid = localStorage.getItem(VISITOR_KEY);
384
+ if (!vid) {
385
+ vid = crypto.randomUUID();
386
+ localStorage.setItem(VISITOR_KEY, vid);
387
+ }
388
+ return vid;
389
+ }
390
+ catch {
391
+ return 'unknown';
392
+ }
393
+ }
281
394
 
282
395
  if (typeof document !== 'undefined') {
283
396
  const thisScript = document.currentScript;
@@ -290,11 +403,15 @@ if (typeof document !== 'undefined') {
290
403
  const timeout = thisScript.dataset.timeout ? parseInt(thisScript.dataset.timeout, 10) : undefined;
291
404
  const ready = document.readyState !== 'loading';
292
405
  const init = () => {
406
+ const metricEnabled = thisScript.dataset.metric === 'true';
407
+ const errorTrackingEnabled = thisScript.dataset.errors === 'true';
293
408
  const notix = new Notix({
294
409
  token,
295
410
  ...(endpoint && { endpoint }),
296
411
  autoCapture,
297
412
  debug,
413
+ metricEnabled,
414
+ errorTrackingEnabled,
298
415
  ...(timeout && { timeout }),
299
416
  });
300
417
  window.notix = notix;
@@ -3,4 +3,4 @@
3
3
  * @version <%= pkg.version %>
4
4
  * @license MIT
5
5
  */
6
- var Notix=function(t){"use strict";function e(t,e,o,i=1e4){const n={title:o.title,...void 0!==o.body&&{body:o.body},...void 0!==o.type&&{notification_type:o.type},...void 0!==o.priority&&{priority:o.priority},...void 0!==o.tag&&{tag:o.tag},...void 0!==o.payload&&{payload:o.payload}},r=new AbortController,a=setTimeout(()=>r.abort(),i);return"undefined"!=typeof fetch?fetch(t,{method:"POST",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(n),signal:r.signal}).then(async t=>{clearTimeout(a);const e=await t.json();if(!t.ok)throw new Error(e.error||e.message||`HTTP ${t.status}`);return e}).catch(t=>{throw clearTimeout(a),t}):function(t,e,o,i){return new Promise((n,r)=>{const a=new XMLHttpRequest;a.open("POST",t,!0),a.setRequestHeader("Authorization",`Bearer ${e}`),a.setRequestHeader("Content-Type","application/json"),a.setRequestHeader("Accept","application/json"),a.timeout=i,a.onload=()=>{try{const t=JSON.parse(a.responseText);a.status>=200&&a.status<300?n(t):r(new Error(t.error||t.message||`HTTP ${a.status}`))}catch{r(new Error("Invalid response"))}},a.onerror=()=>r(new Error("Network error")),a.ontimeout=()=>r(new Error("Request timeout")),a.send(JSON.stringify(o))})}(t,e,n,i)}const o=new WeakMap;function i(t,e,i){e.querySelectorAll("form[data-notify]").forEach(e=>{e.dataset.notixBound||(e.dataset.notixBound="1",e.addEventListener("submit",n=>{const r=Date.now();if(r-(o.get(e)??0)<500)n.preventDefault();else{o.set(e,r);try{const o=function(t){const e=t.dataset.notifyTitle??t.dataset.notify_title??document.title,o=t.dataset.notifyType??t.dataset.notify_type,i=t.dataset.notifyTag??t.dataset.notify_tag,n=t.dataset.notifyPriority??t.dataset.notify_priority,r=t.dataset.notifyBody??t.dataset.notify_body,a=t.dataset.notifyTemplate??t.dataset.notify_template,s=(t.dataset.notifyFields??t.dataset.notify_fields)?.split(",").map(t=>t.trim()).filter(Boolean);if(r)return{title:e,body:r,...o&&{type:o},...i&&{tag:i},...n&&{priority:n}};const d=t.querySelectorAll("input[name], textarea[name], select[name]"),c=new Map;let u;d.forEach(t=>{if(!t.name)return;if(("checkbox"===t.type||"radio"===t.type)&&!t.checked)return;if(s&&!s.includes(t.name))return;const e=t.hasAttribute("data-notify-field");if(s||e||!s&&!a){const e=t.getAttribute("data-notify-label")??t.name;c.set(e,t.value||"")}}),a?u=a.replace(/\{(\w+)\}/g,(e,o)=>{if(c.has(o))return c.get(o);const i=t.elements.namedItem(o);return i?.value||`{${o}}`}):c.size>0&&(u=Array.from(c,([t,e])=>`${t}: ${e}`).join("\n"));return{title:e,...u&&{body:u},...o&&{type:o},...i&&{tag:i},...n&&{priority:n}}}(e);i&&console.log("[Notix] Form captured:",o.title),t(o,{title:o.title,fieldsCount:Object.keys(e.elements).length})}catch(t){i&&console.warn("[Notix] Form capture failed:",t)}}}))})}function n(t){if(!1===t?.enabled)return null;const e="undefined"!=typeof window&&"function"==typeof window.ym;if(!e&&!t?.enabled)return null;let o=t?.counterId;return!o&&e&&(o=function(){for(const t of Object.keys(window))if(t.startsWith("yaCounter")){const e=parseInt(t.replace("yaCounter",""),10);if(!isNaN(e))return e}return}()),o?new r(o,t?.prefix??"notix"):null}class r{constructor(t,e){this.counterId=t,this.prefix=e}trackSent(t){this.reachGoal(`${this.prefix}_sent`,{id:t.id,message:t.message})}trackError(t){this.reachGoal(`${this.prefix}_error`,{error:t.message})}trackFormCaptured(t,e){this.reachGoal(`${this.prefix}_form_captured`,{title:t,fields:e})}trackGoal(t){this.reachGoal(t,{})}reachGoal(t,e){"function"==typeof window.ym&&window.ym(this.counterId,"reachGoal",t,e)}}class a{constructor(t){if(this.captureActive=!1,!t.token||!t.token.startsWith("ntx_"))throw new Error('Notix: token must start with "ntx_"');this.token=t.token,this.endpoint=t.endpoint??"https://notix-hub.ru/api/v1/webhook",this.timeout=t.timeout??1e4,this.debug=t.debug??!1,this.metrika=n(t.metrika),!1!==t.autoCapture&&this.capture()}async notify(t){if(!t.title)throw new Error("Notix: title is required");this.log("Sending notification:",t.title);try{const o=await e(this.endpoint,this.token,t,this.timeout);return this.log("Notification sent:",o.id),this.metrika?.trackSent(o),o}catch(t){const e=t instanceof Error?t:new Error(String(t));throw this.log("Error sending notification:",e.message),this.metrika?.trackError(e),e}}capture(t=document){this.captureActive||(i((t,e)=>{this.notify(t).then(()=>{this.metrika?.trackFormCaptured(e.title??t.title,e.fieldsCount)}).catch(()=>{})},t,this.debug),this.captureActive=!0,this.log("Form capture activated"))}destroy(){document.querySelectorAll("form[data-notix-bound]").forEach(t=>{delete t.dataset.notixBound}),this.captureActive=!1,this.log("Notix destroyed")}log(...t){this.debug&&console.log("[Notix]",...t)}}if("undefined"!=typeof document){const t=document.currentScript;if(t){const e=t.dataset.token;if(e){const o=t.dataset.endpoint,i="false"!==t.dataset.autoCapture,n="true"===t.dataset.debug,r=t.dataset.timeout?parseInt(t.dataset.timeout,10):void 0,s=()=>{const t=new a({token:e,...o&&{endpoint:o},autoCapture:i,debug:n,...r&&{timeout:r}});window.notix=t};"loading"!==document.readyState?s():document.addEventListener("DOMContentLoaded",s)}else"true"===t.dataset.debug&&console.warn("[Notix] data-token attribute is required on script tag")}}return t.Notix=a,t}({});
6
+ var Notix=function(t){"use strict";function e(t,e,r,i=1e4){const o={title:r.title,...void 0!==r.body&&{body:r.body},...void 0!==r.type&&{notification_type:r.type},...void 0!==r.priority&&{priority:r.priority},...void 0!==r.tag&&{tag:r.tag},...void 0!==r.payload&&{payload:r.payload}},n=new AbortController,a=setTimeout(()=>n.abort(),i);return"undefined"!=typeof fetch?fetch(t,{method:"POST",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(o),signal:n.signal}).then(async t=>{clearTimeout(a);const e=await t.json();if(!t.ok)throw new Error(e.error||e.message||`HTTP ${t.status}`);return e}).catch(t=>{throw clearTimeout(a),t}):function(t,e,r,i){return new Promise((o,n)=>{const a=new XMLHttpRequest;a.open("POST",t,!0),a.setRequestHeader("Authorization",`Bearer ${e}`),a.setRequestHeader("Content-Type","application/json"),a.setRequestHeader("Accept","application/json"),a.timeout=i,a.onload=()=>{try{const t=JSON.parse(a.responseText);a.status>=200&&a.status<300?o(t):n(new Error(t.error||t.message||`HTTP ${a.status}`))}catch{n(new Error("Invalid response"))}},a.onerror=()=>n(new Error("Network error")),a.ontimeout=()=>n(new Error("Request timeout")),a.send(JSON.stringify(r))})}(t,e,o,i)}const r=new WeakMap;function i(t,e,i){e.querySelectorAll("form[data-notify]").forEach(e=>{e.dataset.notixBound||(e.dataset.notixBound="1",e.addEventListener("submit",o=>{const n=Date.now();if(n-(r.get(e)??0)<500)o.preventDefault();else{r.set(e,n);try{const r=function(t){const e=t.dataset.notifyTitle??t.dataset.notify_title??document.title,r=t.dataset.notifyType??t.dataset.notify_type,i=t.dataset.notifyTag??t.dataset.notify_tag,o=t.dataset.notifyPriority??t.dataset.notify_priority,n=t.dataset.notifyBody??t.dataset.notify_body,a=t.dataset.notifyTemplate??t.dataset.notify_template,s=(t.dataset.notifyFields??t.dataset.notify_fields)?.split(",").map(t=>t.trim()).filter(Boolean);if(n)return{title:e,body:n,...r&&{type:r},...i&&{tag:i},...o&&{priority:o}};const d=t.querySelectorAll("input[name], textarea[name], select[name]"),c=new Map;let l;d.forEach(t=>{if(!t.name)return;if(("checkbox"===t.type||"radio"===t.type)&&!t.checked)return;if(s&&!s.includes(t.name))return;const e=t.hasAttribute("data-notify-field");if(s||e||!s&&!a){const e=t.getAttribute("data-notify-label")??t.name;c.set(e,t.value||"")}}),a?l=a.replace(/\{(\w+)\}/g,(e,r)=>{if(c.has(r))return c.get(r);const i=t.elements.namedItem(r);return i?.value||`{${r}}`}):c.size>0&&(l=Array.from(c,([t,e])=>`${t}: ${e}`).join("\n"));return{title:e,...l&&{body:l},...r&&{type:r},...i&&{tag:i},...o&&{priority:o}}}(e);i&&console.log("[Notix] Form captured:",r.title),t(r,{title:r.title,fieldsCount:Object.keys(e.elements).length})}catch(t){i&&console.warn("[Notix] Form capture failed:",t)}}}))})}function o(t){if(!1===t?.enabled)return null;const e="undefined"!=typeof window&&"function"==typeof window.ym;if(!e&&!t?.enabled)return null;let r=t?.counterId;return!r&&e&&(r=function(){for(const t of Object.keys(window))if(t.startsWith("yaCounter")){const e=parseInt(t.replace("yaCounter",""),10);if(!isNaN(e))return e}return}()),r?new n(r,t?.prefix??"notix"):null}class n{constructor(t,e){this.counterId=t,this.prefix=e}trackSent(t){this.reachGoal(`${this.prefix}_sent`,{id:t.id,message:t.message})}trackError(t){this.reachGoal(`${this.prefix}_error`,{error:t.message})}trackFormCaptured(t,e){this.reachGoal(`${this.prefix}_form_captured`,{title:t,fields:e})}trackGoal(t){this.reachGoal(t,{})}reachGoal(t,e){"function"==typeof window.ym&&window.ym(this.counterId,"reachGoal",t,e)}}class a{constructor(t){this.sendFn=t,this.errors=[],this.timer=null,this.bindGlobal()}bindGlobal(){if("undefined"==typeof window)return;window.addEventListener("error",t=>{this.errors.push({message:t.message||"Unknown error",file:t.filename||"",line:t.lineno||0,col:t.colno||0,stack:t.error?.stack||"",ts:(new Date).toISOString()}),this.errors.length>=10&&this.flush(),this.startTimer()}),window.addEventListener("unhandledrejection",t=>{this.errors.push({message:t.reason?.message||String(t.reason),file:"",line:0,col:0,stack:t.reason?.stack||"",ts:(new Date).toISOString()}),this.errors.length>=10&&this.flush(),this.startTimer()}),window.addEventListener("beforeunload",()=>this.flush()),document.addEventListener("visibilitychange",()=>{"hidden"===document.visibilityState&&this.flush()})}startTimer(){this.timer||(this.timer=setTimeout(()=>this.flush(),6e4))}flush(){0!==this.errors.length&&(this.sendFn([...this.errors]),this.errors=[],this.timer&&(clearTimeout(this.timer),this.timer=null))}}class s{constructor(t){if(this.captureActive=!1,!t.token||!t.token.startsWith("ntx_"))throw new Error('Notix: token must start with "ntx_"');this.token=t.token,this.endpoint=t.endpoint??"https://notix-hub.ru/api/v1/webhook",this.timeout=t.timeout??1e4,this.debug=t.debug??!1,this.metrika=o(t.metrika),!1!==t.autoCapture&&this.capture(),t.metricEnabled&&this.sendPageview(),t.errorTrackingEnabled&&this.enableErrorTracking()}async notify(t){if(!t.title)throw new Error("Notix: title is required");this.log("Sending notification:",t.title);try{const r=await e(this.endpoint,this.token,t,this.timeout);return this.log("Notification sent:",r.id),this.metrika?.trackSent(r),r}catch(t){const e=t instanceof Error?t:new Error(String(t));throw this.log("Error sending notification:",e.message),this.metrika?.trackError(e),e}}capture(t=document){this.captureActive||(i((t,e)=>{this.notify(t).then(()=>{this.metrika?.trackFormCaptured(e.title??t.title,e.fieldsCount)}).catch(()=>{})},t,this.debug),this.captureActive=!0,this.log("Form capture activated"))}destroy(){document.querySelectorAll("form[data-notix-bound]").forEach(t=>{delete t.dataset.notixBound}),this.captureActive=!1,this.log("Notix destroyed")}sendPageview(t,e){const r={title:"Посетитель на сайте",type:"metric",payload:{event_type:"pageview",visitor_id:c(),page:t||location.pathname,referrer:e||document.referrer||void 0,value:1}};this.notify(r).catch(()=>{}),this.log("Pageview sent:",t||location.pathname)}enableErrorTracking(){"undefined"!=typeof window&&(new a(t=>{this.notify({title:`Ошибки на странице (${t.length})`,type:"error_batch",payload:{errors:t}}).catch(()=>{})}),this.log("Error tracking activated"))}static getVisitorId(){return c()}log(...t){this.debug&&console.log("[Notix]",...t)}}const d="notix_vid";function c(){try{let t=localStorage.getItem(d);return t||(t=crypto.randomUUID(),localStorage.setItem(d,t)),t}catch{return"unknown"}}if("undefined"!=typeof document){const t=document.currentScript;if(t){const e=t.dataset.token;if(e){const r=t.dataset.endpoint,i="false"!==t.dataset.autoCapture,o="true"===t.dataset.debug,n=t.dataset.timeout?parseInt(t.dataset.timeout,10):void 0,a=()=>{const a="true"===t.dataset.metric,d="true"===t.dataset.errors,c=new s({token:e,...r&&{endpoint:r},autoCapture:i,debug:o,metricEnabled:a,errorTrackingEnabled:d,...n&&{timeout:n}});window.notix=c};"loading"!==document.readyState?a():document.addEventListener("DOMContentLoaded",a)}else"true"===t.dataset.debug&&console.warn("[Notix] data-token attribute is required on script tag")}}return t.Notix=s,t}({});
package/dist/notix.d.ts CHANGED
@@ -13,5 +13,8 @@ export declare class Notix {
13
13
  }>;
14
14
  capture(root?: Element | Document): void;
15
15
  destroy(): void;
16
+ sendPageview(page?: string, referrer?: string): void;
17
+ enableErrorTracking(): void;
18
+ static getVisitorId(): string;
16
19
  private log;
17
20
  }
package/dist/types.d.ts CHANGED
@@ -24,6 +24,8 @@ export interface NotixConfig {
24
24
  token: string;
25
25
  endpoint?: string;
26
26
  autoCapture?: boolean;
27
+ metricEnabled?: boolean;
28
+ errorTrackingEnabled?: boolean;
27
29
  metrika?: MetrikaConfig;
28
30
  timeout?: number;
29
31
  debug?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@notix-hub/sdk",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "JavaScript SDK for Notix (Нотикс) — notification aggregation service",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",