@notix-hub/sdk 0.2.0 → 0.3.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.
package/README.md CHANGED
@@ -7,7 +7,7 @@ JavaScript SDK для **Notix (Нотикс)** — сервиса агрегац
7
7
  ### npm
8
8
 
9
9
  ```bash
10
- npm install @notix/sdk
10
+ npm install @notix-hub/sdk
11
11
  ```
12
12
 
13
13
  ```js
@@ -34,7 +34,7 @@ await notix.notify({
34
34
  Без своего домена — через jsdelivr:
35
35
 
36
36
  ```html
37
- <script src="https://cdn.jsdelivr.net/npm/@notix/sdk/dist/notify.min.js" data-token="ntx_..."></script>
37
+ <script src="https://cdn.jsdelivr.net/npm/@notix-hub/sdk/dist/notify.min.js" data-token="ntx_..."></script>
38
38
  ```
39
39
 
40
40
  ## API
@@ -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,7 @@ class Notix {
239
301
  if (config.autoCapture !== false) {
240
302
  this.capture();
241
303
  }
304
+ this.trackErrors();
242
305
  }
243
306
  async notify(payload) {
244
307
  if (!payload.title) {
@@ -274,12 +337,57 @@ class Notix {
274
337
  this.captureActive = false;
275
338
  this.log('Notix destroyed');
276
339
  }
340
+ sendPageview(page, referrer) {
341
+ const visitorId = getOrCreateVisitorId();
342
+ const payload = {
343
+ title: 'Посетитель на сайте',
344
+ type: 'metric',
345
+ payload: {
346
+ event_type: 'pageview',
347
+ visitor_id: visitorId,
348
+ page: page || location.pathname,
349
+ referrer: referrer || document.referrer || undefined,
350
+ value: 1,
351
+ },
352
+ };
353
+ this.notify(payload).catch(() => { });
354
+ this.log('Pageview sent:', page || location.pathname);
355
+ }
356
+ trackErrors() {
357
+ if (typeof window === 'undefined')
358
+ return;
359
+ new ErrorBatcher((errors) => {
360
+ this.notify({
361
+ title: `Ошибки на странице (${errors.length})`,
362
+ type: 'error_batch',
363
+ payload: { errors },
364
+ }).catch(() => { });
365
+ });
366
+ this.log('Error tracking activated');
367
+ }
368
+ static getVisitorId() {
369
+ return getOrCreateVisitorId();
370
+ }
277
371
  log(...args) {
278
372
  if (this.debug) {
279
373
  console.log('[Notix]', ...args);
280
374
  }
281
375
  }
282
376
  }
377
+ const VISITOR_KEY = 'notix_vid';
378
+ function getOrCreateVisitorId() {
379
+ try {
380
+ let vid = localStorage.getItem(VISITOR_KEY);
381
+ if (!vid) {
382
+ vid = crypto.randomUUID();
383
+ localStorage.setItem(VISITOR_KEY, vid);
384
+ }
385
+ return vid;
386
+ }
387
+ catch {
388
+ return 'unknown';
389
+ }
390
+ }
283
391
 
284
392
  if (typeof document !== 'undefined') {
285
393
  const thisScript = document.currentScript;
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,7 @@ class Notix {
237
299
  if (config.autoCapture !== false) {
238
300
  this.capture();
239
301
  }
302
+ this.trackErrors();
240
303
  }
241
304
  async notify(payload) {
242
305
  if (!payload.title) {
@@ -272,12 +335,57 @@ class Notix {
272
335
  this.captureActive = false;
273
336
  this.log('Notix destroyed');
274
337
  }
338
+ sendPageview(page, referrer) {
339
+ const visitorId = getOrCreateVisitorId();
340
+ const payload = {
341
+ title: 'Посетитель на сайте',
342
+ type: 'metric',
343
+ payload: {
344
+ event_type: 'pageview',
345
+ visitor_id: visitorId,
346
+ page: page || location.pathname,
347
+ referrer: referrer || document.referrer || undefined,
348
+ value: 1,
349
+ },
350
+ };
351
+ this.notify(payload).catch(() => { });
352
+ this.log('Pageview sent:', page || location.pathname);
353
+ }
354
+ trackErrors() {
355
+ if (typeof window === 'undefined')
356
+ return;
357
+ new ErrorBatcher((errors) => {
358
+ this.notify({
359
+ title: `Ошибки на странице (${errors.length})`,
360
+ type: 'error_batch',
361
+ payload: { errors },
362
+ }).catch(() => { });
363
+ });
364
+ this.log('Error tracking activated');
365
+ }
366
+ static getVisitorId() {
367
+ return getOrCreateVisitorId();
368
+ }
275
369
  log(...args) {
276
370
  if (this.debug) {
277
371
  console.log('[Notix]', ...args);
278
372
  }
279
373
  }
280
374
  }
375
+ const VISITOR_KEY = 'notix_vid';
376
+ function getOrCreateVisitorId() {
377
+ try {
378
+ let vid = localStorage.getItem(VISITOR_KEY);
379
+ if (!vid) {
380
+ vid = crypto.randomUUID();
381
+ localStorage.setItem(VISITOR_KEY, vid);
382
+ }
383
+ return vid;
384
+ }
385
+ catch {
386
+ return 'unknown';
387
+ }
388
+ }
281
389
 
282
390
  if (typeof document !== 'undefined') {
283
391
  const thisScript = document.currentScript;
@@ -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,i,r=1e4){const o={title:i.title,...void 0!==i.body&&{body:i.body},...void 0!==i.type&&{notification_type:i.type},...void 0!==i.priority&&{priority:i.priority},...void 0!==i.tag&&{tag:i.tag},...void 0!==i.payload&&{payload:i.payload}},n=new AbortController,a=setTimeout(()=>n.abort(),r);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,i,r){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=r,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(i))})}(t,e,o,r)}const i=new WeakMap;function r(t,e,r){e.querySelectorAll("form[data-notify]").forEach(e=>{e.dataset.notixBound||(e.dataset.notixBound="1",e.addEventListener("submit",o=>{const n=Date.now();if(n-(i.get(e)??0)<500)o.preventDefault();else{i.set(e,n);try{const i=function(t){const e=t.dataset.notifyTitle??t.dataset.notify_title??document.title,i=t.dataset.notifyType??t.dataset.notify_type,r=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,...i&&{type:i},...r&&{tag:r},...o&&{priority:o}};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,i)=>{if(c.has(i))return c.get(i);const r=t.elements.namedItem(i);return r?.value||`{${i}}`}):c.size>0&&(u=Array.from(c,([t,e])=>`${t}: ${e}`).join("\n"));return{title:e,...u&&{body:u},...i&&{type:i},...r&&{tag:r},...o&&{priority:o}}}(e);r&&console.log("[Notix] Form captured:",i.title),t(i,{title:i.title,fieldsCount:Object.keys(e.elements).length})}catch(t){r&&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 i=t?.counterId;return!i&&e&&(i=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}()),i?new n(i,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(),this.trackErrors()}async notify(t){if(!t.title)throw new Error("Notix: title is required");this.log("Sending notification:",t.title);try{const i=await e(this.endpoint,this.token,t,this.timeout);return this.log("Notification sent:",i.id),this.metrika?.trackSent(i),i}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||(r((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 i={title:"Посетитель на сайте",type:"metric",payload:{event_type:"pageview",visitor_id:c(),page:t||location.pathname,referrer:e||document.referrer||void 0,value:1}};this.notify(i).catch(()=>{}),this.log("Pageview sent:",t||location.pathname)}trackErrors(){"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 i=t.dataset.endpoint,r="false"!==t.dataset.autoCapture,o="true"===t.dataset.debug,n=t.dataset.timeout?parseInt(t.dataset.timeout,10):void 0,a=()=>{const t=new s({token:e,...i&&{endpoint:i},autoCapture:r,debug:o,...n&&{timeout:n}});window.notix=t};"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
+ trackErrors(): void;
18
+ static getVisitorId(): string;
16
19
  private log;
17
20
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@notix-hub/sdk",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "JavaScript SDK for Notix (Нотикс) — notification aggregation service",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",