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 +72 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +58 -0
- package/dist/index.d.ts +58 -0
- package/dist/index.global.js +2 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/react.cjs +2 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +9 -0
- package/dist/react.d.ts +9 -0
- package/dist/react.js +2 -0
- package/dist/react.js.map +1 -0
- package/package.json +65 -0
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":"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","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"]}
|
package/dist/index.d.cts
ADDED
|
@@ -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 };
|
package/dist/index.d.ts
ADDED
|
@@ -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"]}
|
package/dist/react.d.cts
ADDED
package/dist/react.d.ts
ADDED
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
|
+
}
|