npm package: @sessionvision/core
Description: Session Vision client-side tracking library
Author: Session Vision
Latest version: 0.6.0

# Session Vision Core SDK

The `@sessionvision/core` package is the canonical JavaScript SDK used across the product.
It powers the inline HTML snippet **and** provides lightweight React/Vue wrappers via
subpath exports:

- `@sessionvision/core` – vanilla SDK used by the HTML snippet or custom loaders
- `@sessionvision/core/react` – `<SessionVisionProvider>` + React hooks
- `@sessionvision/core/vue` – Vue plugin + composables

A single npm release now covers all browser integrations while keeping bundle sizes tiny.

> **Tip:** To start all services including the snippet demo, run `./scripts/dev` from the repository root. This starts the snippet manual test page at http://localhost:3001/tests/manual/index.html along with all other development services.

## Prerequisites

- Node.js >= 18.0.0
- npm

## Usage

```bash
npm install @sessionvision/core
```

### Vanilla / HTML Snippet

```ts
import sessionvision from '@sessionvision/core';

sessionvision.init('proj_abc123', {
  autocapture: true,
  debug: true,
});
```

### React

```tsx
import { SessionVisionProvider, useCapture } from '@sessionvision/core/react';

function TrackButton() {
  const capture = useCapture();
  return <button onClick={() => capture('cta_clicked')}>Track</button>;
}

function App() {
  return (
    <SessionVisionProvider apiKey="your_project_token">
      <TrackButton />
    </SessionVisionProvider>
  );
}
```

### Vue

```ts
import { createApp } from 'vue';
import { createSessionVision } from '@sessionvision/core/vue';
import App from './App.vue';

const app = createApp(App);
app.use(createSessionVision('your_project_token'));
app.mount('#app');
```

## Building

Build the SDK for development or production:

```bash
# Build all outputs (UMD, ESM, minified, stub)
npm run build

# Build and watch for changes during development
npm run build:watch
```

Build outputs are written to `dist/`:
- `sessionvision.js` / `sessionvision.min.js` - UMD bundles for CDN snippet
- `sessionvision.esm.js` - ESM entry point
- `sessionvision.cjs.js` - CommonJS build for Node/bundlers
- `react/index.{esm,cjs}.js` - React provider + hooks
- `vue/index.{esm,cjs}.js` - Vue plugin + composables
- `stub.min.js` / `stub-template.ts` - Inline stub script + TypeScript helper

## Testing

### Unit Tests (Jest)

Unit tests cover core functionality like UUID generation, PII masking, event buffering, and identity management.

```bash
# Run all unit tests
npm test

# Run tests in watch mode (re-runs on file changes)
npm run test:watch

# Run tests with coverage report
npm run test:coverage
```

Unit tests are located in `tests/unit/` and use jsdom for browser API mocking.

### End-to-End Tests (Playwright)

E2E tests verify the SDK works correctly in real browsers, including pageview tracking, click capture, form submissions, SPA navigation, and user identification.

```bash
# Run all E2E tests (headless)
npm run test:e2e

# Run with Playwright UI (interactive test runner)
npm run test:e2e:ui

# Run with visible browser windows
npm run test:e2e:headed

# Debug mode (step through tests)
npm run test:e2e:debug
```

E2E tests are located in `tests/e2e/` and run against:
- Chromium (Desktop)
- Chrome Mobile (Pixel 5 emulation)

#### E2E Test Infrastructure

The E2E tests use a local test server (`tests/e2e/server.mjs`) that:
- Serves the built SDK at `http://localhost:3333/sessionvision.js`
- Serves test fixtures at `http://localhost:3333/`
- Provides mock API endpoints for event ingestion
- Exposes test control endpoints for inspecting captured events

The server starts automatically when you run Playwright tests.

## Local Development

### Manual Testing Page

For interactive development and debugging, use the manual test page:

1. **Build the SDK first:**
   ```bash
   npm run build
   ```

2. **Start a local server** (from the snippet directory):
   ```bash
   npx serve .
   ```
   Or use any static file server of your choice.

3. **Open the manual test page:**
   ```
   http://localhost:3001/tests/manual/index.html
   ```

The manual test page (`tests/manual/index.html`) provides:
- Real-time display of captured events in a console overlay
- Buttons to test custom events (purchase, signup, etc.)
- Form submission testing with input masking
- User identification testing (identify/reset)
- SPA navigation simulation
- Property registration testing

**Note:** By default, the manual test page points to `http://localhost:3000` for the API. Update the `apiHost` in the page's initialization code if your backend runs on a different port.

### E2E Test Fixture Page

For quick testing against the E2E fixture page:

1. **Build the SDK:**
   ```bash
   npm run build
   ```

2. **Start the test server manually:**
   ```bash
   node tests/e2e/server.mjs
   ```

3. **Open the fixture page:**
   ```
   http://localhost:3333/
   ```

This page is simpler than the manual test page and is designed for automated testing, but can be useful for quick checks.

### Inspecting Captured Events (E2E Server)

When using the E2E test server, you can inspect captured events:

```bash
# Get all captured events
curl http://localhost:3333/__test__/events

# Reset captured events
curl -X POST http://localhost:3333/__test__/reset
```

## Available Scripts

| Script | Description |
|--------|-------------|
| `npm run build` | Build all SDK bundles |
| `npm run build:watch` | Build and watch for changes |
| `npm test` | Run unit tests |
| `npm run test:watch` | Run unit tests in watch mode |
| `npm run test:coverage` | Run unit tests with coverage |
| `npm run test:e2e` | Run Playwright E2E tests |
| `npm run test:e2e:ui` | Run E2E tests with Playwright UI |
| `npm run test:e2e:headed` | Run E2E tests with visible browsers |
| `npm run test:e2e:debug` | Run E2E tests in debug mode |
| `npm run lint` | Lint TypeScript source files |
| `npm run typecheck` | Run TypeScript type checking |
| `npm run clean` | Remove build artifacts |

## Public API

The SDK exposes the following methods on the global `sessionvision` object:

```javascript
// Initialize the SDK
sessionvision.init('your_project_token', {
  apiHost: 'https://api.example.com',
  autocapture: {
    pageview: true,
    click: true,
    formSubmit: true
  }
});

// Track a custom event
sessionvision.capture('button_clicked', { button_name: 'signup' });

// Identify a user
sessionvision.identify('user_123', { email: 'user@example.com', plan: 'pro' });

// Reset user identity (e.g., on logout)
sessionvision.reset();

// Get the current distinct ID
const id = sessionvision.getDistinctId();

// Register persistent properties (sent with every event)
sessionvision.register({ app_version: '2.1.0' });

// Register properties only if not already set
sessionvision.registerOnce({ initial_referrer: document.referrer });

// Manually flush the event buffer (useful before navigation)
await sessionvision.flushEvents();
```

## Architecture

The SDK uses a three-tier loading architecture:

| Layer | File | Size | Purpose |
|-------|------|------|---------|
| 1 | Inline stub | <1KB | Pasted in `<head>`, creates queue, loads SDK |
| 2 | Main SDK | <30KB | Core tracking, identity, autocapture |
| 3 | Recorder | ~50KB | rrweb session recording (loaded conditionally) |

## Key Features

- **Autocapture**: Automatically captures pageviews, clicks, and form submissions
- **Event Buffering**: Batches events (max 10) with 5-second flush intervals
- **PII Masking**: Automatically masks emails, phone numbers, and credit cards
- **Session Management**: 30-minute inactivity timeout
- **SPA Support**: Tracks client-side navigation via History API
- **Retry Logic**: Exponential backoff for failed requests

## Production Deployment

The snippet is deployed to Cloudflare R2 with Cloudflare CDN.

### One-Time Setup

1. **Create R2 bucket in Cloudflare Dashboard:**
   - Go to R2 → Create Bucket
   - Name: `session-vision-cdn` (or your preferred name)
   - Enable public access via custom domain

2. **Configure CORS:**
   ```bash
   export CLOUDFLARE_ACCOUNT_ID=your-account-id
   export CLOUDFLARE_R2_ACCESS_KEY=your-access-key
   export CLOUDFLARE_R2_SECRET_KEY=your-secret-key
   export SNIPPET_BUCKET=session-vision-cdn

   ./scripts/setup-snippet-cors
   ```

3. **Configure custom domain:**
   - In R2 bucket settings, add `cdn.yourdomain.com` as a custom domain
   - Cloudflare automatically handles CDN caching

### Deploying Updates

```bash
# Set credentials
export CLOUDFLARE_ACCOUNT_ID=your-account-id
export CLOUDFLARE_R2_ACCESS_KEY=your-access-key
export CLOUDFLARE_R2_SECRET_KEY=your-secret-key
export SNIPPET_BUCKET=session-vision-cdn

# Preview what will be uploaded
./scripts/deploy-snippet --dry-run

# Deploy
./scripts/deploy-snippet
```

The deploy script builds the snippet and uploads to three paths:

| Path | Cache | Use Case |
|------|-------|----------|
| `/v0.1.0/` | 1 year (immutable) | Production - pin to exact version |
| `/v0/` | 1 hour | Production - auto-update within major |
| `/latest/` | 5 minutes | Development only |

### CDN URLs

After deployment, the snippet is available at:
```
https://your-bucket.your-objectstorage.com/v0/sessionvision.min.js
```

Or via Cloudflare:
```
https://cdn.yourdomain.com/v0/sessionvision.min.js
```

## Troubleshooting

### Build errors

If you encounter build errors, try:
```bash
npm run clean
rm -rf node_modules
npm install
npm run build
```

### E2E tests failing to start

Ensure port 3333 is available. Kill any existing processes:
```bash
lsof -ti:3333 | xargs kill -9
```

### Tests not picking up code changes

Make sure to rebuild before running E2E tests:
```bash
npm run build && npm run test:e2e
```

For unit tests, Jest handles TypeScript transformation automatically.