npm package: @juanedev/analytics-core
Description: Framework-agnostic core for Web Analytics. Written in TypeScript and usable from any app (React, Vue, Svelte, vanilla JS).
Latest version: 0.1.2

# @juanedev/analytics-core

Framework-agnostic core for Web Analytics. Written in TypeScript and usable from any app (React, Vue, Svelte, vanilla JS).

- ESM + CJS
- No framework dependencies
- HTTP client + WebSocket (Socket.IO)

## Installation

```bash
npm install @juanedev/analytics-core
# o
yarn add @juanedev/analytics-core
# o
pnpm add @juanedev/analytics-core
```

Requirements for the default backend:
- API HTTP (e.g. `http://localhost:4000`) with endpoints `/track/pageview` and `/track/event`.
- Socket.IO Server (e.g. `ws://localhost:4000`).

## Quick usage

```ts
import {
  initSession,
  buildPageviewPayload,
  buildEventPayload,
  trackPageview,
  trackEvent,
  connectWebSocket,
  disconnectWebSocket,
} from '@juanedev/analytics-core';

const apiUrl = 'http://localhost:4000';
const wsUrl = 'http://localhost:4000';
const websiteId = 'YOUR_WEBSITE_ID';

// 1) Create/recover userId, create sessionId and open WebSocket (with heartbeat)
const { userId, sessionId } = await initSession(websiteId, apiUrl, wsUrl);

// 2) Send pageview
await trackPageview(
  apiUrl,
  buildPageviewPayload(websiteId, window.location.href, sessionId, userId)
);

// 3) Send custom event
await trackEvent(
  apiUrl,
  buildEventPayload(websiteId, 'signup', { plan: 'pro' }, sessionId, userId)
);

// 4) Close WebSocket when you want to end the session (optional)
disconnectWebSocket();
```

Suggestion for SPAs: send `trackPageview` on each client navigation.

## API

### Session and WebSocket
- `initSession(websiteId: string, apiUrl: string, wsUrl: string) => Promise<{ userId, sessionId }>`
  - Generates `userId` (persisted in `localStorage` if exists) and `sessionId` (UUID).
  - Opens WebSocket and emits `session:start`. Activates heartbeat (`session:ping`).
- `connectWebSocket(wsUrl: string, sessionData, heartbeatSeconds = 15)`
  - Connects Socket.IO manually if you don't use `initSession`.
- `disconnectWebSocket()`
  - Emits `session:end` and closes the WebSocket connection.

Related types: 
- `SessionData = { websiteId, apiUrl, wsUrl, userId, sessionId }`

### Tracking HTTP
- `trackPageview(apiUrl: string, payload: PageviewPayload)`
- `trackEvent(apiUrl: string, payload: EventPayload)`

Helpers to build standard payloads:
- `buildPageviewPayload(websiteId, url, sessionId, userId)`
- `buildEventPayload(websiteId, eventName, properties, sessionId, userId)`

Payload types:
```ts
type PageviewPayload = {
  websiteId: string;
  userId: string;
  sessionId: string;
  url: string;
  referrer?: string;
  userAgent?: string;
  language?: string;
  screen?: { width?: number; height?: number; colorDepth?: number; devicePixelRatio?: number };
  utm?: { source?: string; medium?: string; campaign?: string; term?: string; content?: string };
  timestamp?: string;
};

type EventPayload = {
  websiteId: string;
  userId: string;
  sessionId: string;
  eventName: string;
  properties?: Record<string, unknown>;
  url?: string;
  referrer?: string;
  utm?: { source?: string; medium?: string; campaign?: string; term?: string; content?: string };
  timestamp?: string;
};
```

### Helpers
- `parseUtmsFromUrl(url?)` → `{ source, medium, campaign, term, content }`
- `getReferrer()`
- `getUserAgent()`
- `getLanguage()`
- `getScreen()` → `{ width, height, colorDepth, devicePixelRatio }`
- `isBrowser()`

## Framework integration
- React/Vue/Svelte: call `initSession` on client mount (e.g. `useEffect` in React). In SSR, invoke these functions only in the browser.
- SPAs: listen to your router events to trigger `trackPageview` when the route changes.

## Notes
- In environments without `window`/`document`, the helpers return `undefined`/empty values safely.
- `fetch` is required to send HTTP data (modern browsers or polyfill).

## Build
The package is delivered compiled to:
- ESM: `dist/index.esm.js`
- CJS: `dist/index.cjs.js`
- Types: `dist/index.d.ts`

## License
MIT