pulse-analytics 0.1.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 ADDED
@@ -0,0 +1,72 @@
1
+ # @pulse/sdk
2
+
3
+ JavaScript/TypeScript SDK for [Pulse Analytics](https://github.com/akdevv/pulse-analytics).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @pulse/sdk
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Vanilla JS / TypeScript
14
+
15
+ ```ts
16
+ import { Pulse } from "@pulse/sdk";
17
+
18
+ Pulse.init({
19
+ siteId: "your-site-id",
20
+ apiHost: "https://api.pulse.com",
21
+ });
22
+ ```
23
+
24
+ ### React
25
+
26
+ ```tsx
27
+ import { usePulse } from "@pulse/sdk/react";
28
+
29
+ function App() {
30
+ usePulse({
31
+ siteId: "your-site-id",
32
+ apiHost: "https://api.pulse.com",
33
+ });
34
+
35
+ return <YourApp />;
36
+ }
37
+ ```
38
+
39
+ ## API
40
+
41
+ ### `Pulse.init(config)`
42
+
43
+ Initializes the SDK, sends an initial pageview, and enables automatic SPA route tracking.
44
+
45
+ | Option | Type | Required | Description |
46
+ |--------|------|----------|-------------|
47
+ | `siteId` | `string` | Yes | Your site tracking ID |
48
+ | `apiHost` | `string` | No | Your Pulse backend URL |
49
+ | `debug` | `boolean` | No | Enable debug logging (default: `false`) |
50
+
51
+ ### `Pulse.trackPageview(options?)`
52
+
53
+ Manually track a pageview. Useful when automatic SPA tracking doesn't capture a route change.
54
+
55
+ ```ts
56
+ Pulse.trackPageview();
57
+ Pulse.trackPageview({ url: "/checkout", title: "Checkout" });
58
+ ```
59
+
60
+ ### `Pulse.trackEvent(eventName, properties?)`
61
+
62
+ Track a custom event with an optional properties payload.
63
+
64
+ ```ts
65
+ Pulse.trackEvent("signup", { plan: "pro", source: "landing_page" });
66
+ Pulse.trackEvent("purchase", { amount: 49, currency: "USD" });
67
+ Pulse.trackEvent("video_play");
68
+ ```
69
+
70
+ ## License
71
+
72
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";var l=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var E=Object.getOwnPropertyNames;var I=Object.prototype.hasOwnProperty;var m=(t,e)=>{for(var n in e)l(t,n,{get:e[n],enumerable:!0})},w=(t,e,n,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of E(e))!I.call(t,r)&&r!==n&&l(t,r,{get:()=>e[r],enumerable:!(i=h(e,r))||i.enumerable});return t};var y=t=>w(l({},"__esModule",{value:!0}),t);var O={};m(O,{Pulse:()=>b,getSessionId:()=>d,getVisitorId:()=>g});module.exports=y(O);var u="pulse_cid",x="pulse_sid";function c(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{let e=Math.random()*16|0;return(t==="x"?e:e&3|8).toString(16)})}function g(){try{let t=localStorage.getItem(u);return t||(t=c(),localStorage.setItem(u,t)),t}catch{return c()}}function d(){try{let t=sessionStorage.getItem(x);return t||(t=c(),sessionStorage.setItem(x,t)),t}catch{return c()}}var s=null;function p(t){s=t}function o(t,e,n,i){if(!s){console.warn("@pulse: init() not called. Run Pulse.init({ siteId, apiHost }) before tracking.");return}let r=e?.url??window.location.href,P=e?.title??document.title,v=e?.referrer??document.referrer,a=new URLSearchParams({v:"1",tid:s.siteId,t,dl:r,dr:v,dt:P,ul:navigator.language,sr:`${screen.width}x${screen.height}`,vp:`${window.innerWidth}x${window.innerHeight}`,cid:g(),sid:d(),ts:String(Date.now()),z:String(Math.random())});i&&a.set("en",i),n&&Object.keys(n).length>0&&a.set("ep",JSON.stringify(n));let S=`${s.apiHost?.replace(/\/$/,"")??""}/api/v1/track?${a.toString()}`;s.debug&&console.log("@pulse [debug]:",t,Object.fromEntries(a));try{fetch(S,{method:"POST",keepalive:!0}).catch(()=>{})}catch{}}function f(){window.addEventListener("popstate",()=>{o("PAGEVIEW")});let t=history.pushState.bind(history);history.pushState=function(n,i,r){t(n,i,r),o("PAGEVIEW")};let e=history.replaceState.bind(history);history.replaceState=function(n,i,r){e(n,i,r),o("PAGEVIEW")}}var b={init(t){p(t),f(),o("PAGEVIEW")},trackPageview(t){o("PAGEVIEW",t)},trackEvent(t,e){o("CUSTOM",void 0,e,t)}};0&&(module.exports={Pulse,getSessionId,getVisitorId});
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/session.ts","../src/tracker.ts","../src/spa.ts"],"sourcesContent":["import type {\n PulseConfig,\n PageviewOptions,\n EventProperties,\n} from \"./tracker.ts\";\nimport { enableSPA } from \"./spa.ts\";\nimport { configure, sendEvent } from \"./tracker.ts\";\n\nconst Pulse = {\n /**\n * Initialize Pulse Analytics. Must be called once before any tracking.\n * Sends an initial pageview and enables automatic SPA route tracking.\n *\n * @param config - Configuration options\n * @param config.siteId - Your site tracking ID\n * @param config.apiHost - Your Pulse backend URL\n * @param config.debug - Enable debug logging (default: false)\n *\n * @example\n * Pulse.init({ siteId: 'pk-abc123', apiHost: 'https://api.pulse.com' })\n */\n init(config: PulseConfig): void {\n configure(config);\n enableSPA();\n\n // Send the first pageview immediately on initialization\n sendEvent(\"PAGEVIEW\");\n },\n\n /**\n * Track a pageview. Useful for manual control or when automatic SPA\n * tracking doesn't capture a route change.\n *\n * @param options - Optional overrides for the current page\n * @param options.url - Override the page URL\n * @param options.title - Override the page title\n * @param options.referrer - Override the referrer\n *\n * @example\n * Pulse.trackPageview()\n * Pulse.trackPageview({ url: '/checkout', title: 'Checkout' })\n */\n trackPageview(options?: PageviewOptions): void {\n sendEvent(\"PAGEVIEW\", options);\n },\n\n /**\n * Track a custom event with an optional payload.\n *\n * @param eventName - Event identifier, use snake_case or camelCase\n * @param properties - Optional key-value metadata for the event\n *\n * @example\n * Pulse.trackEvent('signup', { plan: 'pro', source: 'landing_page' })\n * Pulse.trackEvent('purchase', { amount: 49, currency: 'USD' })\n * Pulse.trackEvent('video_play')\n */\n trackEvent(eventName: string, properties?: EventProperties): void {\n sendEvent(\"CUSTOM\", undefined, properties, eventName);\n },\n};\n\nexport { Pulse };\nexport type { PulseConfig, PageviewOptions, EventProperties };\nexport { getVisitorId, getSessionId } from \"./session.js\";\n","const VISITOR_KEY = \"pulse_cid\";\nconst SESSION_KEY = \"pulse_sid\";\n\nfunction generateUUID() {\n // crypto.randomUUID() is available in all modern browsers and Node 19+\n // Fallback for older environments\n\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n\n // Fallback: manual UUID v4\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\nexport function getVisitorId(): string {\n try {\n let id = localStorage.getItem(VISITOR_KEY);\n if (!id) {\n id = generateUUID();\n localStorage.setItem(VISITOR_KEY, id);\n }\n return id;\n } catch {\n return generateUUID();\n }\n}\n\nexport function getSessionId(): string {\n try {\n let id = sessionStorage.getItem(SESSION_KEY);\n if (!id) {\n id = generateUUID();\n sessionStorage.setItem(SESSION_KEY, id);\n }\n return id;\n } catch {\n return generateUUID();\n }\n}\n","import { getVisitorId, getSessionId } from \"./session.js\";\n\nexport interface PulseConfig {\n siteId: string;\n apiHost?: string;\n debug?: boolean;\n}\n\nexport interface PageviewOptions {\n url?: string;\n title?: string;\n referrer?: string;\n}\n\nexport type EventProperties = Record<string, string | number | boolean>;\n\nlet _config: PulseConfig | null = null;\n\nexport function configure(config: PulseConfig): void {\n _config = config;\n}\n\nexport function sendEvent(\n eventType: \"PAGEVIEW\" | \"CLICK\" | \"CUSTOM\",\n pageOptions?: PageviewOptions,\n properties?: EventProperties,\n eventName?: string,\n): void {\n if (!_config) {\n console.warn(\n \"@pulse: init() not called. Run Pulse.init({ siteId, apiHost }) before tracking.\",\n );\n return;\n }\n\n const url = pageOptions?.url ?? window.location.href;\n const title = pageOptions?.title ?? document.title;\n const referrer = pageOptions?.referrer ?? document.referrer;\n\n const params = new URLSearchParams({\n v: \"1\",\n tid: _config.siteId,\n t: eventType,\n dl: url,\n dr: referrer,\n dt: title,\n ul: navigator.language,\n sr: `${screen.width}x${screen.height}`,\n vp: `${window.innerWidth}x${window.innerHeight}`,\n cid: getVisitorId(),\n sid: getSessionId(),\n ts: String(Date.now()),\n z: String(Math.random()),\n });\n\n if (eventName) {\n params.set(\"en\", eventName);\n }\n\n if (properties && Object.keys(properties).length > 0) {\n params.set(\"ep\", JSON.stringify(properties));\n }\n\n const host = _config.apiHost?.replace(/\\/$/, \"\") ?? \"\";\n const endpoint = `${host}/api/v1/track?${params.toString()}`;\n\n if (_config.debug) {\n console.log(\"@pulse [debug]:\", eventType, Object.fromEntries(params));\n }\n\n try {\n fetch(endpoint, {\n method: \"POST\",\n keepalive: true,\n }).catch(() => {\n // silently swallow — analytics must never throw on the host page\n });\n } catch {\n // fetch itself can throw in some environments (old browsers, CSP blocks)\n }\n}\n","import { sendEvent } from \"./tracker.ts\";\n\nexport function enableSPA(): void {\n // Handle back/forward browser navigation\n window.addEventListener(\"popstate\", () => {\n sendEvent(\"PAGEVIEW\");\n });\n\n // Monkey-patch history.pushState\n const originalPushState = history.pushState.bind(history);\n\n history.pushState = function (\n state: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n originalPushState(state, unused, url);\n sendEvent(\"PAGEVIEW\");\n };\n\n // Monkey-patch history.replaceState\n const originalReplaceState = history.replaceState.bind(history);\n\n history.replaceState = function (\n state: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n originalReplaceState(state, unused, url);\n sendEvent(\"PAGEVIEW\");\n };\n}\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,WAAAE,EAAA,iBAAAC,EAAA,iBAAAC,IAAA,eAAAC,EAAAL,GCAA,IAAMM,EAAc,YACdC,EAAc,YAEpB,SAASC,GAAe,CAItB,OAAI,OAAO,OAAW,KAAe,OAAO,WACnC,OAAO,WAAW,EAIpB,uCAAuC,QAAQ,QAAUC,GAAM,CACpE,IAAMC,EAAK,KAAK,OAAO,EAAI,GAAM,EAEjC,OADUD,IAAM,IAAMC,EAAKA,EAAI,EAAO,GAC7B,SAAS,EAAE,CACtB,CAAC,CACH,CAEO,SAASC,GAAuB,CACrC,GAAI,CACF,IAAIC,EAAK,aAAa,QAAQN,CAAW,EACzC,OAAKM,IACHA,EAAKJ,EAAa,EAClB,aAAa,QAAQF,EAAaM,CAAE,GAE/BA,CACT,MAAQ,CACN,OAAOJ,EAAa,CACtB,CACF,CAEO,SAASK,GAAuB,CACrC,GAAI,CACF,IAAID,EAAK,eAAe,QAAQL,CAAW,EAC3C,OAAKK,IACHA,EAAKJ,EAAa,EAClB,eAAe,QAAQD,EAAaK,CAAE,GAEjCA,CACT,MAAQ,CACN,OAAOJ,EAAa,CACtB,CACF,CC3BA,IAAIM,EAA8B,KAE3B,SAASC,EAAUC,EAA2B,CACnDF,EAAUE,CACZ,CAEO,SAASC,EACdC,EACAC,EACAC,EACAC,EACM,CACN,GAAI,CAACP,EAAS,CACZ,QAAQ,KACN,iFACF,EACA,MACF,CAEA,IAAMQ,EAAMH,GAAa,KAAO,OAAO,SAAS,KAC1CI,EAAQJ,GAAa,OAAS,SAAS,MACvCK,EAAWL,GAAa,UAAY,SAAS,SAE7CM,EAAS,IAAI,gBAAgB,CACjC,EAAG,IACH,IAAKX,EAAQ,OACbI,EACA,GAAII,EACJ,GAAIE,EACJ,GAAID,EACJ,GAAI,UAAU,SACd,GAAI,GAAG,OAAO,KAAK,IAAI,OAAO,MAAM,GACpC,GAAI,GAAG,OAAO,UAAU,IAAI,OAAO,WAAW,GAC9C,IAAKG,EAAa,EAClB,IAAKC,EAAa,EAClB,GAAI,OAAO,KAAK,IAAI,CAAC,EACrB,EAAG,OAAO,KAAK,OAAO,CAAC,CACzB,CAAC,EAEGN,GACFI,EAAO,IAAI,KAAMJ,CAAS,EAGxBD,GAAc,OAAO,KAAKA,CAAU,EAAE,OAAS,GACjDK,EAAO,IAAI,KAAM,KAAK,UAAUL,CAAU,CAAC,EAI7C,IAAMQ,EAAW,GADJd,EAAQ,SAAS,QAAQ,MAAO,EAAE,GAAK,EAC5B,iBAAiBW,EAAO,SAAS,CAAC,GAEtDX,EAAQ,OACV,QAAQ,IAAI,kBAAmBI,EAAW,OAAO,YAAYO,CAAM,CAAC,EAGtE,GAAI,CACF,MAAMG,EAAU,CACd,OAAQ,OACR,UAAW,EACb,CAAC,EAAE,MAAM,IAAM,CAEf,CAAC,CACH,MAAQ,CAER,CACF,CC9EO,SAASC,GAAkB,CAEhC,OAAO,iBAAiB,WAAY,IAAM,CACxCC,EAAU,UAAU,CACtB,CAAC,EAGD,IAAMC,EAAoB,QAAQ,UAAU,KAAK,OAAO,EAExD,QAAQ,UAAY,SAClBC,EACAC,EACAC,EACM,CACNH,EAAkBC,EAAOC,EAAQC,CAAG,EACpCJ,EAAU,UAAU,CACtB,EAGA,IAAMK,EAAuB,QAAQ,aAAa,KAAK,OAAO,EAE9D,QAAQ,aAAe,SACrBH,EACAC,EACAC,EACM,CACNC,EAAqBH,EAAOC,EAAQC,CAAG,EACvCJ,EAAU,UAAU,CACtB,CACF,CHvBA,IAAMM,EAAQ,CAaZ,KAAKC,EAA2B,CAC9BC,EAAUD,CAAM,EAChBE,EAAU,EAGVC,EAAU,UAAU,CACtB,EAeA,cAAcC,EAAiC,CAC7CD,EAAU,WAAYC,CAAO,CAC/B,EAaA,WAAWC,EAAmBC,EAAoC,CAChEH,EAAU,SAAU,OAAWG,EAAYD,CAAS,CACtD,CACF","names":["index_exports","__export","Pulse","getSessionId","getVisitorId","__toCommonJS","VISITOR_KEY","SESSION_KEY","generateUUID","c","r","getVisitorId","id","getSessionId","_config","configure","config","sendEvent","eventType","pageOptions","properties","eventName","url","title","referrer","params","getVisitorId","getSessionId","endpoint","enableSPA","sendEvent","originalPushState","state","unused","url","originalReplaceState","Pulse","config","configure","enableSPA","sendEvent","options","eventName","properties"]}
@@ -0,0 +1,58 @@
1
+ interface PulseConfig {
2
+ siteId: string;
3
+ apiHost?: string;
4
+ debug?: boolean;
5
+ }
6
+ interface PageviewOptions {
7
+ url?: string;
8
+ title?: string;
9
+ referrer?: string;
10
+ }
11
+ type EventProperties = Record<string, string | number | boolean>;
12
+
13
+ declare function getVisitorId(): string;
14
+ declare function getSessionId(): string;
15
+
16
+ declare const Pulse: {
17
+ /**
18
+ * Initialize Pulse Analytics. Must be called once before any tracking.
19
+ * Sends an initial pageview and enables automatic SPA route tracking.
20
+ *
21
+ * @param config - Configuration options
22
+ * @param config.siteId - Your site tracking ID
23
+ * @param config.apiHost - Your Pulse backend URL
24
+ * @param config.debug - Enable debug logging (default: false)
25
+ *
26
+ * @example
27
+ * Pulse.init({ siteId: 'pk-abc123', apiHost: 'https://api.pulse.com' })
28
+ */
29
+ init(config: PulseConfig): void;
30
+ /**
31
+ * Track a pageview. Useful for manual control or when automatic SPA
32
+ * tracking doesn't capture a route change.
33
+ *
34
+ * @param options - Optional overrides for the current page
35
+ * @param options.url - Override the page URL
36
+ * @param options.title - Override the page title
37
+ * @param options.referrer - Override the referrer
38
+ *
39
+ * @example
40
+ * Pulse.trackPageview()
41
+ * Pulse.trackPageview({ url: '/checkout', title: 'Checkout' })
42
+ */
43
+ trackPageview(options?: PageviewOptions): void;
44
+ /**
45
+ * Track a custom event with an optional payload.
46
+ *
47
+ * @param eventName - Event identifier, use snake_case or camelCase
48
+ * @param properties - Optional key-value metadata for the event
49
+ *
50
+ * @example
51
+ * Pulse.trackEvent('signup', { plan: 'pro', source: 'landing_page' })
52
+ * Pulse.trackEvent('purchase', { amount: 49, currency: 'USD' })
53
+ * Pulse.trackEvent('video_play')
54
+ */
55
+ trackEvent(eventName: string, properties?: EventProperties): void;
56
+ };
57
+
58
+ export { type EventProperties, type PageviewOptions, Pulse, type PulseConfig, getSessionId, getVisitorId };
@@ -0,0 +1,58 @@
1
+ interface PulseConfig {
2
+ siteId: string;
3
+ apiHost?: string;
4
+ debug?: boolean;
5
+ }
6
+ interface PageviewOptions {
7
+ url?: string;
8
+ title?: string;
9
+ referrer?: string;
10
+ }
11
+ type EventProperties = Record<string, string | number | boolean>;
12
+
13
+ declare function getVisitorId(): string;
14
+ declare function getSessionId(): string;
15
+
16
+ declare const Pulse: {
17
+ /**
18
+ * Initialize Pulse Analytics. Must be called once before any tracking.
19
+ * Sends an initial pageview and enables automatic SPA route tracking.
20
+ *
21
+ * @param config - Configuration options
22
+ * @param config.siteId - Your site tracking ID
23
+ * @param config.apiHost - Your Pulse backend URL
24
+ * @param config.debug - Enable debug logging (default: false)
25
+ *
26
+ * @example
27
+ * Pulse.init({ siteId: 'pk-abc123', apiHost: 'https://api.pulse.com' })
28
+ */
29
+ init(config: PulseConfig): void;
30
+ /**
31
+ * Track a pageview. Useful for manual control or when automatic SPA
32
+ * tracking doesn't capture a route change.
33
+ *
34
+ * @param options - Optional overrides for the current page
35
+ * @param options.url - Override the page URL
36
+ * @param options.title - Override the page title
37
+ * @param options.referrer - Override the referrer
38
+ *
39
+ * @example
40
+ * Pulse.trackPageview()
41
+ * Pulse.trackPageview({ url: '/checkout', title: 'Checkout' })
42
+ */
43
+ trackPageview(options?: PageviewOptions): void;
44
+ /**
45
+ * Track a custom event with an optional payload.
46
+ *
47
+ * @param eventName - Event identifier, use snake_case or camelCase
48
+ * @param properties - Optional key-value metadata for the event
49
+ *
50
+ * @example
51
+ * Pulse.trackEvent('signup', { plan: 'pro', source: 'landing_page' })
52
+ * Pulse.trackEvent('purchase', { amount: 49, currency: 'USD' })
53
+ * Pulse.trackEvent('video_play')
54
+ */
55
+ trackEvent(eventName: string, properties?: EventProperties): void;
56
+ };
57
+
58
+ export { type EventProperties, type PageviewOptions, Pulse, type PulseConfig, getSessionId, getVisitorId };
@@ -0,0 +1,2 @@
1
+ "use strict";var Pulse=(()=>{var l=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var E=Object.getOwnPropertyNames;var I=Object.prototype.hasOwnProperty;var m=(t,e)=>{for(var n in e)l(t,n,{get:e[n],enumerable:!0})},w=(t,e,n,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of E(e))!I.call(t,r)&&r!==n&&l(t,r,{get:()=>e[r],enumerable:!(i=h(e,r))||i.enumerable});return t};var y=t=>w(l({},"__esModule",{value:!0}),t);var O={};m(O,{Pulse:()=>b,getSessionId:()=>d,getVisitorId:()=>g});var u="pulse_cid",x="pulse_sid";function c(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{let e=Math.random()*16|0;return(t==="x"?e:e&3|8).toString(16)})}function g(){try{let t=localStorage.getItem(u);return t||(t=c(),localStorage.setItem(u,t)),t}catch{return c()}}function d(){try{let t=sessionStorage.getItem(x);return t||(t=c(),sessionStorage.setItem(x,t)),t}catch{return c()}}var s=null;function p(t){s=t}function o(t,e,n,i){if(!s){console.warn("@pulse: init() not called. Run Pulse.init({ siteId, apiHost }) before tracking.");return}let r=e?.url??window.location.href,P=e?.title??document.title,v=e?.referrer??document.referrer,a=new URLSearchParams({v:"1",tid:s.siteId,t,dl:r,dr:v,dt:P,ul:navigator.language,sr:`${screen.width}x${screen.height}`,vp:`${window.innerWidth}x${window.innerHeight}`,cid:g(),sid:d(),ts:String(Date.now()),z:String(Math.random())});i&&a.set("en",i),n&&Object.keys(n).length>0&&a.set("ep",JSON.stringify(n));let S=`${s.apiHost?.replace(/\/$/,"")??""}/api/v1/track?${a.toString()}`;s.debug&&console.log("@pulse [debug]:",t,Object.fromEntries(a));try{fetch(S,{method:"POST",keepalive:!0}).catch(()=>{})}catch{}}function f(){window.addEventListener("popstate",()=>{o("PAGEVIEW")});let t=history.pushState.bind(history);history.pushState=function(n,i,r){t(n,i,r),o("PAGEVIEW")};let e=history.replaceState.bind(history);history.replaceState=function(n,i,r){e(n,i,r),o("PAGEVIEW")}}var b={init(t){p(t),f(),o("PAGEVIEW")},trackPageview(t){o("PAGEVIEW",t)},trackEvent(t,e){o("CUSTOM",void 0,e,t)}};return y(O);})();
2
+ //# sourceMappingURL=index.global.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/session.ts","../src/tracker.ts","../src/spa.ts"],"sourcesContent":["import type {\n PulseConfig,\n PageviewOptions,\n EventProperties,\n} from \"./tracker.ts\";\nimport { enableSPA } from \"./spa.ts\";\nimport { configure, sendEvent } from \"./tracker.ts\";\n\nconst Pulse = {\n /**\n * Initialize Pulse Analytics. Must be called once before any tracking.\n * Sends an initial pageview and enables automatic SPA route tracking.\n *\n * @param config - Configuration options\n * @param config.siteId - Your site tracking ID\n * @param config.apiHost - Your Pulse backend URL\n * @param config.debug - Enable debug logging (default: false)\n *\n * @example\n * Pulse.init({ siteId: 'pk-abc123', apiHost: 'https://api.pulse.com' })\n */\n init(config: PulseConfig): void {\n configure(config);\n enableSPA();\n\n // Send the first pageview immediately on initialization\n sendEvent(\"PAGEVIEW\");\n },\n\n /**\n * Track a pageview. Useful for manual control or when automatic SPA\n * tracking doesn't capture a route change.\n *\n * @param options - Optional overrides for the current page\n * @param options.url - Override the page URL\n * @param options.title - Override the page title\n * @param options.referrer - Override the referrer\n *\n * @example\n * Pulse.trackPageview()\n * Pulse.trackPageview({ url: '/checkout', title: 'Checkout' })\n */\n trackPageview(options?: PageviewOptions): void {\n sendEvent(\"PAGEVIEW\", options);\n },\n\n /**\n * Track a custom event with an optional payload.\n *\n * @param eventName - Event identifier, use snake_case or camelCase\n * @param properties - Optional key-value metadata for the event\n *\n * @example\n * Pulse.trackEvent('signup', { plan: 'pro', source: 'landing_page' })\n * Pulse.trackEvent('purchase', { amount: 49, currency: 'USD' })\n * Pulse.trackEvent('video_play')\n */\n trackEvent(eventName: string, properties?: EventProperties): void {\n sendEvent(\"CUSTOM\", undefined, properties, eventName);\n },\n};\n\nexport { Pulse };\nexport type { PulseConfig, PageviewOptions, EventProperties };\nexport { getVisitorId, getSessionId } from \"./session.js\";\n","const VISITOR_KEY = \"pulse_cid\";\nconst SESSION_KEY = \"pulse_sid\";\n\nfunction generateUUID() {\n // crypto.randomUUID() is available in all modern browsers and Node 19+\n // Fallback for older environments\n\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n\n // Fallback: manual UUID v4\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\nexport function getVisitorId(): string {\n try {\n let id = localStorage.getItem(VISITOR_KEY);\n if (!id) {\n id = generateUUID();\n localStorage.setItem(VISITOR_KEY, id);\n }\n return id;\n } catch {\n return generateUUID();\n }\n}\n\nexport function getSessionId(): string {\n try {\n let id = sessionStorage.getItem(SESSION_KEY);\n if (!id) {\n id = generateUUID();\n sessionStorage.setItem(SESSION_KEY, id);\n }\n return id;\n } catch {\n return generateUUID();\n }\n}\n","import { getVisitorId, getSessionId } from \"./session.js\";\n\nexport interface PulseConfig {\n siteId: string;\n apiHost?: string;\n debug?: boolean;\n}\n\nexport interface PageviewOptions {\n url?: string;\n title?: string;\n referrer?: string;\n}\n\nexport type EventProperties = Record<string, string | number | boolean>;\n\nlet _config: PulseConfig | null = null;\n\nexport function configure(config: PulseConfig): void {\n _config = config;\n}\n\nexport function sendEvent(\n eventType: \"PAGEVIEW\" | \"CLICK\" | \"CUSTOM\",\n pageOptions?: PageviewOptions,\n properties?: EventProperties,\n eventName?: string,\n): void {\n if (!_config) {\n console.warn(\n \"@pulse: init() not called. Run Pulse.init({ siteId, apiHost }) before tracking.\",\n );\n return;\n }\n\n const url = pageOptions?.url ?? window.location.href;\n const title = pageOptions?.title ?? document.title;\n const referrer = pageOptions?.referrer ?? document.referrer;\n\n const params = new URLSearchParams({\n v: \"1\",\n tid: _config.siteId,\n t: eventType,\n dl: url,\n dr: referrer,\n dt: title,\n ul: navigator.language,\n sr: `${screen.width}x${screen.height}`,\n vp: `${window.innerWidth}x${window.innerHeight}`,\n cid: getVisitorId(),\n sid: getSessionId(),\n ts: String(Date.now()),\n z: String(Math.random()),\n });\n\n if (eventName) {\n params.set(\"en\", eventName);\n }\n\n if (properties && Object.keys(properties).length > 0) {\n params.set(\"ep\", JSON.stringify(properties));\n }\n\n const host = _config.apiHost?.replace(/\\/$/, \"\") ?? \"\";\n const endpoint = `${host}/api/v1/track?${params.toString()}`;\n\n if (_config.debug) {\n console.log(\"@pulse [debug]:\", eventType, Object.fromEntries(params));\n }\n\n try {\n fetch(endpoint, {\n method: \"POST\",\n keepalive: true,\n }).catch(() => {\n // silently swallow — analytics must never throw on the host page\n });\n } catch {\n // fetch itself can throw in some environments (old browsers, CSP blocks)\n }\n}\n","import { sendEvent } from \"./tracker.ts\";\n\nexport function enableSPA(): void {\n // Handle back/forward browser navigation\n window.addEventListener(\"popstate\", () => {\n sendEvent(\"PAGEVIEW\");\n });\n\n // Monkey-patch history.pushState\n const originalPushState = history.pushState.bind(history);\n\n history.pushState = function (\n state: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n originalPushState(state, unused, url);\n sendEvent(\"PAGEVIEW\");\n };\n\n // Monkey-patch history.replaceState\n const originalReplaceState = history.replaceState.bind(history);\n\n history.replaceState = function (\n state: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n originalReplaceState(state, unused, url);\n sendEvent(\"PAGEVIEW\");\n };\n}\n"],"mappings":"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","names":["index_exports","__export","Pulse","getSessionId","getVisitorId","VISITOR_KEY","SESSION_KEY","generateUUID","c","r","getVisitorId","id","getSessionId","_config","configure","config","sendEvent","eventType","pageOptions","properties","eventName","url","title","referrer","params","getVisitorId","getSessionId","endpoint","enableSPA","sendEvent","originalPushState","state","unused","url","originalReplaceState","Pulse","config","configure","enableSPA","sendEvent","options","eventName","properties"]}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ var l="pulse_cid",u="pulse_sid";function c(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{let e=Math.random()*16|0;return(t==="x"?e:e&3|8).toString(16)})}function g(){try{let t=localStorage.getItem(l);return t||(t=c(),localStorage.setItem(l,t)),t}catch{return c()}}function d(){try{let t=sessionStorage.getItem(u);return t||(t=c(),sessionStorage.setItem(u,t)),t}catch{return c()}}var s=null;function x(t){s=t}function r(t,e,n,i){if(!s){console.warn("@pulse: init() not called. Run Pulse.init({ siteId, apiHost }) before tracking.");return}let o=e?.url??window.location.href,f=e?.title??document.title,P=e?.referrer??document.referrer,a=new URLSearchParams({v:"1",tid:s.siteId,t,dl:o,dr:P,dt:f,ul:navigator.language,sr:`${screen.width}x${screen.height}`,vp:`${window.innerWidth}x${window.innerHeight}`,cid:g(),sid:d(),ts:String(Date.now()),z:String(Math.random())});i&&a.set("en",i),n&&Object.keys(n).length>0&&a.set("ep",JSON.stringify(n));let v=`${s.apiHost?.replace(/\/$/,"")??""}/api/v1/track?${a.toString()}`;s.debug&&console.log("@pulse [debug]:",t,Object.fromEntries(a));try{fetch(v,{method:"POST",keepalive:!0}).catch(()=>{})}catch{}}function p(){window.addEventListener("popstate",()=>{r("PAGEVIEW")});let t=history.pushState.bind(history);history.pushState=function(n,i,o){t(n,i,o),r("PAGEVIEW")};let e=history.replaceState.bind(history);history.replaceState=function(n,i,o){e(n,i,o),r("PAGEVIEW")}}var O={init(t){x(t),p(),r("PAGEVIEW")},trackPageview(t){r("PAGEVIEW",t)},trackEvent(t,e){r("CUSTOM",void 0,e,t)}};export{O as Pulse,d as getSessionId,g as getVisitorId};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/session.ts","../src/tracker.ts","../src/spa.ts","../src/index.ts"],"sourcesContent":["const VISITOR_KEY = \"pulse_cid\";\nconst SESSION_KEY = \"pulse_sid\";\n\nfunction generateUUID() {\n // crypto.randomUUID() is available in all modern browsers and Node 19+\n // Fallback for older environments\n\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n\n // Fallback: manual UUID v4\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\nexport function getVisitorId(): string {\n try {\n let id = localStorage.getItem(VISITOR_KEY);\n if (!id) {\n id = generateUUID();\n localStorage.setItem(VISITOR_KEY, id);\n }\n return id;\n } catch {\n return generateUUID();\n }\n}\n\nexport function getSessionId(): string {\n try {\n let id = sessionStorage.getItem(SESSION_KEY);\n if (!id) {\n id = generateUUID();\n sessionStorage.setItem(SESSION_KEY, id);\n }\n return id;\n } catch {\n return generateUUID();\n }\n}\n","import { getVisitorId, getSessionId } from \"./session.js\";\n\nexport interface PulseConfig {\n siteId: string;\n apiHost?: string;\n debug?: boolean;\n}\n\nexport interface PageviewOptions {\n url?: string;\n title?: string;\n referrer?: string;\n}\n\nexport type EventProperties = Record<string, string | number | boolean>;\n\nlet _config: PulseConfig | null = null;\n\nexport function configure(config: PulseConfig): void {\n _config = config;\n}\n\nexport function sendEvent(\n eventType: \"PAGEVIEW\" | \"CLICK\" | \"CUSTOM\",\n pageOptions?: PageviewOptions,\n properties?: EventProperties,\n eventName?: string,\n): void {\n if (!_config) {\n console.warn(\n \"@pulse: init() not called. Run Pulse.init({ siteId, apiHost }) before tracking.\",\n );\n return;\n }\n\n const url = pageOptions?.url ?? window.location.href;\n const title = pageOptions?.title ?? document.title;\n const referrer = pageOptions?.referrer ?? document.referrer;\n\n const params = new URLSearchParams({\n v: \"1\",\n tid: _config.siteId,\n t: eventType,\n dl: url,\n dr: referrer,\n dt: title,\n ul: navigator.language,\n sr: `${screen.width}x${screen.height}`,\n vp: `${window.innerWidth}x${window.innerHeight}`,\n cid: getVisitorId(),\n sid: getSessionId(),\n ts: String(Date.now()),\n z: String(Math.random()),\n });\n\n if (eventName) {\n params.set(\"en\", eventName);\n }\n\n if (properties && Object.keys(properties).length > 0) {\n params.set(\"ep\", JSON.stringify(properties));\n }\n\n const host = _config.apiHost?.replace(/\\/$/, \"\") ?? \"\";\n const endpoint = `${host}/api/v1/track?${params.toString()}`;\n\n if (_config.debug) {\n console.log(\"@pulse [debug]:\", eventType, Object.fromEntries(params));\n }\n\n try {\n fetch(endpoint, {\n method: \"POST\",\n keepalive: true,\n }).catch(() => {\n // silently swallow — analytics must never throw on the host page\n });\n } catch {\n // fetch itself can throw in some environments (old browsers, CSP blocks)\n }\n}\n","import { sendEvent } from \"./tracker.ts\";\n\nexport function enableSPA(): void {\n // Handle back/forward browser navigation\n window.addEventListener(\"popstate\", () => {\n sendEvent(\"PAGEVIEW\");\n });\n\n // Monkey-patch history.pushState\n const originalPushState = history.pushState.bind(history);\n\n history.pushState = function (\n state: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n originalPushState(state, unused, url);\n sendEvent(\"PAGEVIEW\");\n };\n\n // Monkey-patch history.replaceState\n const originalReplaceState = history.replaceState.bind(history);\n\n history.replaceState = function (\n state: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n originalReplaceState(state, unused, url);\n sendEvent(\"PAGEVIEW\");\n };\n}\n","import type {\n PulseConfig,\n PageviewOptions,\n EventProperties,\n} from \"./tracker.ts\";\nimport { enableSPA } from \"./spa.ts\";\nimport { configure, sendEvent } from \"./tracker.ts\";\n\nconst Pulse = {\n /**\n * Initialize Pulse Analytics. Must be called once before any tracking.\n * Sends an initial pageview and enables automatic SPA route tracking.\n *\n * @param config - Configuration options\n * @param config.siteId - Your site tracking ID\n * @param config.apiHost - Your Pulse backend URL\n * @param config.debug - Enable debug logging (default: false)\n *\n * @example\n * Pulse.init({ siteId: 'pk-abc123', apiHost: 'https://api.pulse.com' })\n */\n init(config: PulseConfig): void {\n configure(config);\n enableSPA();\n\n // Send the first pageview immediately on initialization\n sendEvent(\"PAGEVIEW\");\n },\n\n /**\n * Track a pageview. Useful for manual control or when automatic SPA\n * tracking doesn't capture a route change.\n *\n * @param options - Optional overrides for the current page\n * @param options.url - Override the page URL\n * @param options.title - Override the page title\n * @param options.referrer - Override the referrer\n *\n * @example\n * Pulse.trackPageview()\n * Pulse.trackPageview({ url: '/checkout', title: 'Checkout' })\n */\n trackPageview(options?: PageviewOptions): void {\n sendEvent(\"PAGEVIEW\", options);\n },\n\n /**\n * Track a custom event with an optional payload.\n *\n * @param eventName - Event identifier, use snake_case or camelCase\n * @param properties - Optional key-value metadata for the event\n *\n * @example\n * Pulse.trackEvent('signup', { plan: 'pro', source: 'landing_page' })\n * Pulse.trackEvent('purchase', { amount: 49, currency: 'USD' })\n * Pulse.trackEvent('video_play')\n */\n trackEvent(eventName: string, properties?: EventProperties): void {\n sendEvent(\"CUSTOM\", undefined, properties, eventName);\n },\n};\n\nexport { Pulse };\nexport type { PulseConfig, PageviewOptions, EventProperties };\nexport { getVisitorId, getSessionId } from \"./session.js\";\n"],"mappings":"AAAA,IAAMA,EAAc,YACdC,EAAc,YAEpB,SAASC,GAAe,CAItB,OAAI,OAAO,OAAW,KAAe,OAAO,WACnC,OAAO,WAAW,EAIpB,uCAAuC,QAAQ,QAAUC,GAAM,CACpE,IAAMC,EAAK,KAAK,OAAO,EAAI,GAAM,EAEjC,OADUD,IAAM,IAAMC,EAAKA,EAAI,EAAO,GAC7B,SAAS,EAAE,CACtB,CAAC,CACH,CAEO,SAASC,GAAuB,CACrC,GAAI,CACF,IAAIC,EAAK,aAAa,QAAQN,CAAW,EACzC,OAAKM,IACHA,EAAKJ,EAAa,EAClB,aAAa,QAAQF,EAAaM,CAAE,GAE/BA,CACT,MAAQ,CACN,OAAOJ,EAAa,CACtB,CACF,CAEO,SAASK,GAAuB,CACrC,GAAI,CACF,IAAID,EAAK,eAAe,QAAQL,CAAW,EAC3C,OAAKK,IACHA,EAAKJ,EAAa,EAClB,eAAe,QAAQD,EAAaK,CAAE,GAEjCA,CACT,MAAQ,CACN,OAAOJ,EAAa,CACtB,CACF,CC3BA,IAAIM,EAA8B,KAE3B,SAASC,EAAUC,EAA2B,CACnDF,EAAUE,CACZ,CAEO,SAASC,EACdC,EACAC,EACAC,EACAC,EACM,CACN,GAAI,CAACP,EAAS,CACZ,QAAQ,KACN,iFACF,EACA,MACF,CAEA,IAAMQ,EAAMH,GAAa,KAAO,OAAO,SAAS,KAC1CI,EAAQJ,GAAa,OAAS,SAAS,MACvCK,EAAWL,GAAa,UAAY,SAAS,SAE7CM,EAAS,IAAI,gBAAgB,CACjC,EAAG,IACH,IAAKX,EAAQ,OACbI,EACA,GAAII,EACJ,GAAIE,EACJ,GAAID,EACJ,GAAI,UAAU,SACd,GAAI,GAAG,OAAO,KAAK,IAAI,OAAO,MAAM,GACpC,GAAI,GAAG,OAAO,UAAU,IAAI,OAAO,WAAW,GAC9C,IAAKG,EAAa,EAClB,IAAKC,EAAa,EAClB,GAAI,OAAO,KAAK,IAAI,CAAC,EACrB,EAAG,OAAO,KAAK,OAAO,CAAC,CACzB,CAAC,EAEGN,GACFI,EAAO,IAAI,KAAMJ,CAAS,EAGxBD,GAAc,OAAO,KAAKA,CAAU,EAAE,OAAS,GACjDK,EAAO,IAAI,KAAM,KAAK,UAAUL,CAAU,CAAC,EAI7C,IAAMQ,EAAW,GADJd,EAAQ,SAAS,QAAQ,MAAO,EAAE,GAAK,EAC5B,iBAAiBW,EAAO,SAAS,CAAC,GAEtDX,EAAQ,OACV,QAAQ,IAAI,kBAAmBI,EAAW,OAAO,YAAYO,CAAM,CAAC,EAGtE,GAAI,CACF,MAAMG,EAAU,CACd,OAAQ,OACR,UAAW,EACb,CAAC,EAAE,MAAM,IAAM,CAEf,CAAC,CACH,MAAQ,CAER,CACF,CC9EO,SAASC,GAAkB,CAEhC,OAAO,iBAAiB,WAAY,IAAM,CACxCC,EAAU,UAAU,CACtB,CAAC,EAGD,IAAMC,EAAoB,QAAQ,UAAU,KAAK,OAAO,EAExD,QAAQ,UAAY,SAClBC,EACAC,EACAC,EACM,CACNH,EAAkBC,EAAOC,EAAQC,CAAG,EACpCJ,EAAU,UAAU,CACtB,EAGA,IAAMK,EAAuB,QAAQ,aAAa,KAAK,OAAO,EAE9D,QAAQ,aAAe,SACrBH,EACAC,EACAC,EACM,CACNC,EAAqBH,EAAOC,EAAQC,CAAG,EACvCJ,EAAU,UAAU,CACtB,CACF,CCvBA,IAAMM,EAAQ,CAaZ,KAAKC,EAA2B,CAC9BC,EAAUD,CAAM,EAChBE,EAAU,EAGVC,EAAU,UAAU,CACtB,EAeA,cAAcC,EAAiC,CAC7CD,EAAU,WAAYC,CAAO,CAC/B,EAaA,WAAWC,EAAmBC,EAAoC,CAChEH,EAAU,SAAU,OAAWG,EAAYD,CAAS,CACtD,CACF","names":["VISITOR_KEY","SESSION_KEY","generateUUID","c","r","getVisitorId","id","getSessionId","_config","configure","config","sendEvent","eventType","pageOptions","properties","eventName","url","title","referrer","params","getVisitorId","getSessionId","endpoint","enableSPA","sendEvent","originalPushState","state","unused","url","originalReplaceState","Pulse","config","configure","enableSPA","sendEvent","options","eventName","properties"]}
package/dist/react.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";var l=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var y=(t,e)=>{for(var n in e)l(t,n,{get:e[n],enumerable:!0})},w=(t,e,n,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of P(e))!v.call(t,r)&&r!==n&&l(t,r,{get:()=>e[r],enumerable:!(i=E(e,r))||i.enumerable});return t};var b=t=>w(l({},"__esModule",{value:!0}),t);var C={};y(C,{usePulse:()=>U});module.exports=b(C);var a=require("react");var d="pulse_cid",g="pulse_sid";function u(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{let e=Math.random()*16|0;return(t==="x"?e:e&3|8).toString(16)})}function f(){try{let t=localStorage.getItem(d);return t||(t=u(),localStorage.setItem(d,t)),t}catch{return u()}}function x(){try{let t=sessionStorage.getItem(g);return t||(t=u(),sessionStorage.setItem(g,t)),t}catch{return u()}}var s=null;function p(t){s=t}function o(t,e,n,i){if(!s){console.warn("@pulse: init() not called. Run Pulse.init({ siteId, apiHost }) before tracking.");return}let r=e?.url??window.location.href,S=e?.title??document.title,m=e?.referrer??document.referrer,c=new URLSearchParams({v:"1",tid:s.siteId,t,dl:r,dr:m,dt:S,ul:navigator.language,sr:`${screen.width}x${screen.height}`,vp:`${window.innerWidth}x${window.innerHeight}`,cid:f(),sid:x(),ts:String(Date.now()),z:String(Math.random())});i&&c.set("en",i),n&&Object.keys(n).length>0&&c.set("ep",JSON.stringify(n));let I=`${s.apiHost?.replace(/\/$/,"")??""}/api/v1/track?${c.toString()}`;s.debug&&console.log("@pulse [debug]:",t,Object.fromEntries(c));try{fetch(I,{method:"POST",keepalive:!0}).catch(()=>{})}catch{}}function h(){window.addEventListener("popstate",()=>{o("PAGEVIEW")});let t=history.pushState.bind(history);history.pushState=function(n,i,r){t(n,i,r),o("PAGEVIEW")};let e=history.replaceState.bind(history);history.replaceState=function(n,i,r){e(n,i,r),o("PAGEVIEW")}}function U(t){let e=(0,a.useRef)(!1);(0,a.useEffect)(()=>{e.current||(e.current=!0,p(t),h(),o("PAGEVIEW"))},[])}0&&(module.exports={usePulse});
2
+ //# sourceMappingURL=react.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react.ts","../src/session.ts","../src/tracker.ts","../src/spa.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\";\nimport { enableSPA } from \"./spa.ts\";\nimport { configure, sendEvent, type PulseConfig } from \"./tracker.ts\";\n\nexport function usePulse(config: PulseConfig): void {\n const initialized = useRef(false);\n\n useEffect(() => {\n if (initialized.current) return;\n initialized.current = true;\n\n configure(config);\n enableSPA();\n sendEvent(\"PAGEVIEW\");\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n}\n","const VISITOR_KEY = \"pulse_cid\";\nconst SESSION_KEY = \"pulse_sid\";\n\nfunction generateUUID() {\n // crypto.randomUUID() is available in all modern browsers and Node 19+\n // Fallback for older environments\n\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n\n // Fallback: manual UUID v4\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\nexport function getVisitorId(): string {\n try {\n let id = localStorage.getItem(VISITOR_KEY);\n if (!id) {\n id = generateUUID();\n localStorage.setItem(VISITOR_KEY, id);\n }\n return id;\n } catch {\n return generateUUID();\n }\n}\n\nexport function getSessionId(): string {\n try {\n let id = sessionStorage.getItem(SESSION_KEY);\n if (!id) {\n id = generateUUID();\n sessionStorage.setItem(SESSION_KEY, id);\n }\n return id;\n } catch {\n return generateUUID();\n }\n}\n","import { getVisitorId, getSessionId } from \"./session.js\";\n\nexport interface PulseConfig {\n siteId: string;\n apiHost?: string;\n debug?: boolean;\n}\n\nexport interface PageviewOptions {\n url?: string;\n title?: string;\n referrer?: string;\n}\n\nexport type EventProperties = Record<string, string | number | boolean>;\n\nlet _config: PulseConfig | null = null;\n\nexport function configure(config: PulseConfig): void {\n _config = config;\n}\n\nexport function sendEvent(\n eventType: \"PAGEVIEW\" | \"CLICK\" | \"CUSTOM\",\n pageOptions?: PageviewOptions,\n properties?: EventProperties,\n eventName?: string,\n): void {\n if (!_config) {\n console.warn(\n \"@pulse: init() not called. Run Pulse.init({ siteId, apiHost }) before tracking.\",\n );\n return;\n }\n\n const url = pageOptions?.url ?? window.location.href;\n const title = pageOptions?.title ?? document.title;\n const referrer = pageOptions?.referrer ?? document.referrer;\n\n const params = new URLSearchParams({\n v: \"1\",\n tid: _config.siteId,\n t: eventType,\n dl: url,\n dr: referrer,\n dt: title,\n ul: navigator.language,\n sr: `${screen.width}x${screen.height}`,\n vp: `${window.innerWidth}x${window.innerHeight}`,\n cid: getVisitorId(),\n sid: getSessionId(),\n ts: String(Date.now()),\n z: String(Math.random()),\n });\n\n if (eventName) {\n params.set(\"en\", eventName);\n }\n\n if (properties && Object.keys(properties).length > 0) {\n params.set(\"ep\", JSON.stringify(properties));\n }\n\n const host = _config.apiHost?.replace(/\\/$/, \"\") ?? \"\";\n const endpoint = `${host}/api/v1/track?${params.toString()}`;\n\n if (_config.debug) {\n console.log(\"@pulse [debug]:\", eventType, Object.fromEntries(params));\n }\n\n try {\n fetch(endpoint, {\n method: \"POST\",\n keepalive: true,\n }).catch(() => {\n // silently swallow — analytics must never throw on the host page\n });\n } catch {\n // fetch itself can throw in some environments (old browsers, CSP blocks)\n }\n}\n","import { sendEvent } from \"./tracker.ts\";\n\nexport function enableSPA(): void {\n // Handle back/forward browser navigation\n window.addEventListener(\"popstate\", () => {\n sendEvent(\"PAGEVIEW\");\n });\n\n // Monkey-patch history.pushState\n const originalPushState = history.pushState.bind(history);\n\n history.pushState = function (\n state: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n originalPushState(state, unused, url);\n sendEvent(\"PAGEVIEW\");\n };\n\n // Monkey-patch history.replaceState\n const originalReplaceState = history.replaceState.bind(history);\n\n history.replaceState = function (\n state: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n originalReplaceState(state, unused, url);\n sendEvent(\"PAGEVIEW\");\n };\n}\n"],"mappings":"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","names":["react_exports","__export","usePulse","__toCommonJS","import_react","VISITOR_KEY","SESSION_KEY","generateUUID","c","r","getVisitorId","id","getSessionId","_config","configure","config","sendEvent","eventType","pageOptions","properties","eventName","url","title","referrer","params","getVisitorId","getSessionId","endpoint","enableSPA","sendEvent","originalPushState","state","unused","url","originalReplaceState","usePulse","config","initialized","configure","enableSPA","sendEvent"]}
@@ -0,0 +1,9 @@
1
+ interface PulseConfig {
2
+ siteId: string;
3
+ apiHost?: string;
4
+ debug?: boolean;
5
+ }
6
+
7
+ declare function usePulse(config: PulseConfig): void;
8
+
9
+ export { usePulse };
@@ -0,0 +1,9 @@
1
+ interface PulseConfig {
2
+ siteId: string;
3
+ apiHost?: string;
4
+ debug?: boolean;
5
+ }
6
+
7
+ declare function usePulse(config: PulseConfig): void;
8
+
9
+ export { usePulse };
package/dist/react.js ADDED
@@ -0,0 +1,2 @@
1
+ import{useEffect as m,useRef as I}from"react";var a="pulse_cid",l="pulse_sid";function u(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{let e=Math.random()*16|0;return(t==="x"?e:e&3|8).toString(16)})}function d(){try{let t=localStorage.getItem(a);return t||(t=u(),localStorage.setItem(a,t)),t}catch{return u()}}function g(){try{let t=sessionStorage.getItem(l);return t||(t=u(),sessionStorage.setItem(l,t)),t}catch{return u()}}var s=null;function f(t){s=t}function i(t,e,n,r){if(!s){console.warn("@pulse: init() not called. Run Pulse.init({ siteId, apiHost }) before tracking.");return}let o=e?.url??window.location.href,p=e?.title??document.title,h=e?.referrer??document.referrer,c=new URLSearchParams({v:"1",tid:s.siteId,t,dl:o,dr:h,dt:p,ul:navigator.language,sr:`${screen.width}x${screen.height}`,vp:`${window.innerWidth}x${window.innerHeight}`,cid:d(),sid:g(),ts:String(Date.now()),z:String(Math.random())});r&&c.set("en",r),n&&Object.keys(n).length>0&&c.set("ep",JSON.stringify(n));let S=`${s.apiHost?.replace(/\/$/,"")??""}/api/v1/track?${c.toString()}`;s.debug&&console.log("@pulse [debug]:",t,Object.fromEntries(c));try{fetch(S,{method:"POST",keepalive:!0}).catch(()=>{})}catch{}}function x(){window.addEventListener("popstate",()=>{i("PAGEVIEW")});let t=history.pushState.bind(history);history.pushState=function(n,r,o){t(n,r,o),i("PAGEVIEW")};let e=history.replaceState.bind(history);history.replaceState=function(n,r,o){e(n,r,o),i("PAGEVIEW")}}function V(t){let e=I(!1);m(()=>{e.current||(e.current=!0,f(t),x(),i("PAGEVIEW"))},[])}export{V as usePulse};
2
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react.ts","../src/session.ts","../src/tracker.ts","../src/spa.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\";\nimport { enableSPA } from \"./spa.ts\";\nimport { configure, sendEvent, type PulseConfig } from \"./tracker.ts\";\n\nexport function usePulse(config: PulseConfig): void {\n const initialized = useRef(false);\n\n useEffect(() => {\n if (initialized.current) return;\n initialized.current = true;\n\n configure(config);\n enableSPA();\n sendEvent(\"PAGEVIEW\");\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n}\n","const VISITOR_KEY = \"pulse_cid\";\nconst SESSION_KEY = \"pulse_sid\";\n\nfunction generateUUID() {\n // crypto.randomUUID() is available in all modern browsers and Node 19+\n // Fallback for older environments\n\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n\n // Fallback: manual UUID v4\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\nexport function getVisitorId(): string {\n try {\n let id = localStorage.getItem(VISITOR_KEY);\n if (!id) {\n id = generateUUID();\n localStorage.setItem(VISITOR_KEY, id);\n }\n return id;\n } catch {\n return generateUUID();\n }\n}\n\nexport function getSessionId(): string {\n try {\n let id = sessionStorage.getItem(SESSION_KEY);\n if (!id) {\n id = generateUUID();\n sessionStorage.setItem(SESSION_KEY, id);\n }\n return id;\n } catch {\n return generateUUID();\n }\n}\n","import { getVisitorId, getSessionId } from \"./session.js\";\n\nexport interface PulseConfig {\n siteId: string;\n apiHost?: string;\n debug?: boolean;\n}\n\nexport interface PageviewOptions {\n url?: string;\n title?: string;\n referrer?: string;\n}\n\nexport type EventProperties = Record<string, string | number | boolean>;\n\nlet _config: PulseConfig | null = null;\n\nexport function configure(config: PulseConfig): void {\n _config = config;\n}\n\nexport function sendEvent(\n eventType: \"PAGEVIEW\" | \"CLICK\" | \"CUSTOM\",\n pageOptions?: PageviewOptions,\n properties?: EventProperties,\n eventName?: string,\n): void {\n if (!_config) {\n console.warn(\n \"@pulse: init() not called. Run Pulse.init({ siteId, apiHost }) before tracking.\",\n );\n return;\n }\n\n const url = pageOptions?.url ?? window.location.href;\n const title = pageOptions?.title ?? document.title;\n const referrer = pageOptions?.referrer ?? document.referrer;\n\n const params = new URLSearchParams({\n v: \"1\",\n tid: _config.siteId,\n t: eventType,\n dl: url,\n dr: referrer,\n dt: title,\n ul: navigator.language,\n sr: `${screen.width}x${screen.height}`,\n vp: `${window.innerWidth}x${window.innerHeight}`,\n cid: getVisitorId(),\n sid: getSessionId(),\n ts: String(Date.now()),\n z: String(Math.random()),\n });\n\n if (eventName) {\n params.set(\"en\", eventName);\n }\n\n if (properties && Object.keys(properties).length > 0) {\n params.set(\"ep\", JSON.stringify(properties));\n }\n\n const host = _config.apiHost?.replace(/\\/$/, \"\") ?? \"\";\n const endpoint = `${host}/api/v1/track?${params.toString()}`;\n\n if (_config.debug) {\n console.log(\"@pulse [debug]:\", eventType, Object.fromEntries(params));\n }\n\n try {\n fetch(endpoint, {\n method: \"POST\",\n keepalive: true,\n }).catch(() => {\n // silently swallow — analytics must never throw on the host page\n });\n } catch {\n // fetch itself can throw in some environments (old browsers, CSP blocks)\n }\n}\n","import { sendEvent } from \"./tracker.ts\";\n\nexport function enableSPA(): void {\n // Handle back/forward browser navigation\n window.addEventListener(\"popstate\", () => {\n sendEvent(\"PAGEVIEW\");\n });\n\n // Monkey-patch history.pushState\n const originalPushState = history.pushState.bind(history);\n\n history.pushState = function (\n state: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n originalPushState(state, unused, url);\n sendEvent(\"PAGEVIEW\");\n };\n\n // Monkey-patch history.replaceState\n const originalReplaceState = history.replaceState.bind(history);\n\n history.replaceState = function (\n state: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n originalReplaceState(state, unused, url);\n sendEvent(\"PAGEVIEW\");\n };\n}\n"],"mappings":"AAAA,OAAS,aAAAA,EAAW,UAAAC,MAAc,QCAlC,IAAMC,EAAc,YACdC,EAAc,YAEpB,SAASC,GAAe,CAItB,OAAI,OAAO,OAAW,KAAe,OAAO,WACnC,OAAO,WAAW,EAIpB,uCAAuC,QAAQ,QAAUC,GAAM,CACpE,IAAMC,EAAK,KAAK,OAAO,EAAI,GAAM,EAEjC,OADUD,IAAM,IAAMC,EAAKA,EAAI,EAAO,GAC7B,SAAS,EAAE,CACtB,CAAC,CACH,CAEO,SAASC,GAAuB,CACrC,GAAI,CACF,IAAIC,EAAK,aAAa,QAAQN,CAAW,EACzC,OAAKM,IACHA,EAAKJ,EAAa,EAClB,aAAa,QAAQF,EAAaM,CAAE,GAE/BA,CACT,MAAQ,CACN,OAAOJ,EAAa,CACtB,CACF,CAEO,SAASK,GAAuB,CACrC,GAAI,CACF,IAAID,EAAK,eAAe,QAAQL,CAAW,EAC3C,OAAKK,IACHA,EAAKJ,EAAa,EAClB,eAAe,QAAQD,EAAaK,CAAE,GAEjCA,CACT,MAAQ,CACN,OAAOJ,EAAa,CACtB,CACF,CC3BA,IAAIM,EAA8B,KAE3B,SAASC,EAAUC,EAA2B,CACnDF,EAAUE,CACZ,CAEO,SAASC,EACdC,EACAC,EACAC,EACAC,EACM,CACN,GAAI,CAACP,EAAS,CACZ,QAAQ,KACN,iFACF,EACA,MACF,CAEA,IAAMQ,EAAMH,GAAa,KAAO,OAAO,SAAS,KAC1CI,EAAQJ,GAAa,OAAS,SAAS,MACvCK,EAAWL,GAAa,UAAY,SAAS,SAE7CM,EAAS,IAAI,gBAAgB,CACjC,EAAG,IACH,IAAKX,EAAQ,OACbI,EACA,GAAII,EACJ,GAAIE,EACJ,GAAID,EACJ,GAAI,UAAU,SACd,GAAI,GAAG,OAAO,KAAK,IAAI,OAAO,MAAM,GACpC,GAAI,GAAG,OAAO,UAAU,IAAI,OAAO,WAAW,GAC9C,IAAKG,EAAa,EAClB,IAAKC,EAAa,EAClB,GAAI,OAAO,KAAK,IAAI,CAAC,EACrB,EAAG,OAAO,KAAK,OAAO,CAAC,CACzB,CAAC,EAEGN,GACFI,EAAO,IAAI,KAAMJ,CAAS,EAGxBD,GAAc,OAAO,KAAKA,CAAU,EAAE,OAAS,GACjDK,EAAO,IAAI,KAAM,KAAK,UAAUL,CAAU,CAAC,EAI7C,IAAMQ,EAAW,GADJd,EAAQ,SAAS,QAAQ,MAAO,EAAE,GAAK,EAC5B,iBAAiBW,EAAO,SAAS,CAAC,GAEtDX,EAAQ,OACV,QAAQ,IAAI,kBAAmBI,EAAW,OAAO,YAAYO,CAAM,CAAC,EAGtE,GAAI,CACF,MAAMG,EAAU,CACd,OAAQ,OACR,UAAW,EACb,CAAC,EAAE,MAAM,IAAM,CAEf,CAAC,CACH,MAAQ,CAER,CACF,CC9EO,SAASC,GAAkB,CAEhC,OAAO,iBAAiB,WAAY,IAAM,CACxCC,EAAU,UAAU,CACtB,CAAC,EAGD,IAAMC,EAAoB,QAAQ,UAAU,KAAK,OAAO,EAExD,QAAQ,UAAY,SAClBC,EACAC,EACAC,EACM,CACNH,EAAkBC,EAAOC,EAAQC,CAAG,EACpCJ,EAAU,UAAU,CACtB,EAGA,IAAMK,EAAuB,QAAQ,aAAa,KAAK,OAAO,EAE9D,QAAQ,aAAe,SACrBH,EACAC,EACAC,EACM,CACNC,EAAqBH,EAAOC,EAAQC,CAAG,EACvCJ,EAAU,UAAU,CACtB,CACF,CH3BO,SAASM,EAASC,EAA2B,CAClD,IAAMC,EAAcC,EAAO,EAAK,EAEhCC,EAAU,IAAM,CACVF,EAAY,UAChBA,EAAY,QAAU,GAEtBG,EAAUJ,CAAM,EAChBK,EAAU,EACVC,EAAU,UAAU,EACtB,EAAG,CAAC,CAAC,CACP","names":["useEffect","useRef","VISITOR_KEY","SESSION_KEY","generateUUID","c","r","getVisitorId","id","getSessionId","_config","configure","config","sendEvent","eventType","pageOptions","properties","eventName","url","title","referrer","params","getVisitorId","getSessionId","endpoint","enableSPA","sendEvent","originalPushState","state","unused","url","originalReplaceState","usePulse","config","initialized","useRef","useEffect","configure","enableSPA","sendEvent"]}
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "pulse-analytics",
3
+ "version": "0.1.0",
4
+ "description": "SDK for Pulse Analytics",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ },
14
+ "./react": {
15
+ "types": "./dist/react.d.ts",
16
+ "import": "./dist/react.js",
17
+ "require": "./dist/react.cjs"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "scripts": {
24
+ "build": "tsup",
25
+ "dev": "tsup --watch",
26
+ "typecheck": "tsc --noEmit",
27
+ "prepublishOnly": "npm run build"
28
+ },
29
+ "keywords": [
30
+ "analytics",
31
+ "sdk",
32
+ "javascript",
33
+ "typescript",
34
+ "web"
35
+ ],
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/akdevv/pulse-analytics.git",
39
+ "directory": "sdk"
40
+ },
41
+ "homepage": "https://github.com/akdevv/pulse-analytics/tree/main/sdk#readme",
42
+ "bugs": {
43
+ "url": "https://github.com/akdevv/pulse-analytics/issues"
44
+ },
45
+ "author": "akdevv",
46
+ "license": "MIT",
47
+ "type": "module",
48
+ "publishConfig": {
49
+ "access": "public"
50
+ },
51
+ "peerDependencies": {
52
+ "react": ">=16"
53
+ },
54
+ "peerDependenciesMeta": {
55
+ "react": {
56
+ "optional": true
57
+ }
58
+ },
59
+ "devDependencies": {
60
+ "@types/node": "^24.10.0",
61
+ "@types/react": "^19.2.14",
62
+ "tsup": "^8.5.1",
63
+ "typescript": "^5.9.3"
64
+ }
65
+ }