@notix-hub/sdk 0.3.0 → 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.
package/dist/index.cjs CHANGED
@@ -301,7 +301,12 @@ class Notix {
301
301
  if (config.autoCapture !== false) {
302
302
  this.capture();
303
303
  }
304
- this.trackErrors();
304
+ if (config.metricEnabled) {
305
+ this.sendPageview();
306
+ }
307
+ if (config.errorTrackingEnabled) {
308
+ this.enableErrorTracking();
309
+ }
305
310
  }
306
311
  async notify(payload) {
307
312
  if (!payload.title) {
@@ -353,7 +358,7 @@ class Notix {
353
358
  this.notify(payload).catch(() => { });
354
359
  this.log('Pageview sent:', page || location.pathname);
355
360
  }
356
- trackErrors() {
361
+ enableErrorTracking() {
357
362
  if (typeof window === 'undefined')
358
363
  return;
359
364
  new ErrorBatcher((errors) => {
@@ -400,11 +405,15 @@ if (typeof document !== 'undefined') {
400
405
  const timeout = thisScript.dataset.timeout ? parseInt(thisScript.dataset.timeout, 10) : undefined;
401
406
  const ready = document.readyState !== 'loading';
402
407
  const init = () => {
408
+ const metricEnabled = thisScript.dataset.metric === 'true';
409
+ const errorTrackingEnabled = thisScript.dataset.errors === 'true';
403
410
  const notix = new Notix({
404
411
  token,
405
412
  ...(endpoint && { endpoint }),
406
413
  autoCapture,
407
414
  debug,
415
+ metricEnabled,
416
+ errorTrackingEnabled,
408
417
  ...(timeout && { timeout }),
409
418
  });
410
419
  window.notix = notix;
package/dist/index.mjs CHANGED
@@ -299,7 +299,12 @@ class Notix {
299
299
  if (config.autoCapture !== false) {
300
300
  this.capture();
301
301
  }
302
- this.trackErrors();
302
+ if (config.metricEnabled) {
303
+ this.sendPageview();
304
+ }
305
+ if (config.errorTrackingEnabled) {
306
+ this.enableErrorTracking();
307
+ }
303
308
  }
304
309
  async notify(payload) {
305
310
  if (!payload.title) {
@@ -351,7 +356,7 @@ class Notix {
351
356
  this.notify(payload).catch(() => { });
352
357
  this.log('Pageview sent:', page || location.pathname);
353
358
  }
354
- trackErrors() {
359
+ enableErrorTracking() {
355
360
  if (typeof window === 'undefined')
356
361
  return;
357
362
  new ErrorBatcher((errors) => {
@@ -398,11 +403,15 @@ if (typeof document !== 'undefined') {
398
403
  const timeout = thisScript.dataset.timeout ? parseInt(thisScript.dataset.timeout, 10) : undefined;
399
404
  const ready = document.readyState !== 'loading';
400
405
  const init = () => {
406
+ const metricEnabled = thisScript.dataset.metric === 'true';
407
+ const errorTrackingEnabled = thisScript.dataset.errors === 'true';
401
408
  const notix = new Notix({
402
409
  token,
403
410
  ...(endpoint && { endpoint }),
404
411
  autoCapture,
405
412
  debug,
413
+ metricEnabled,
414
+ errorTrackingEnabled,
406
415
  ...(timeout && { timeout }),
407
416
  });
408
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,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}({});
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
@@ -14,7 +14,7 @@ export declare class Notix {
14
14
  capture(root?: Element | Document): void;
15
15
  destroy(): void;
16
16
  sendPageview(page?: string, referrer?: string): void;
17
- trackErrors(): void;
17
+ enableErrorTracking(): void;
18
18
  static getVisitorId(): string;
19
19
  private log;
20
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.3.0",
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",