npm package: @quiltr/lumyr-sdk
Description: Lumyr SDK — structured logging transport and full management client. Zero runtime dependencies.
Latest version: 3.0.1

# @quiltr/lumyr-sdk

Lightweight SDK for structured logging to [Lumyr](https://log-server-nu.vercel.app). High-level logger API, batching transport, correlation tracking. Zero runtime dependencies.

## Install

```bash
npm install @quiltr/lumyr-sdk
```

## Quick Start

```typescript
import {
  createLogger,
  createLogTransport,
  registerTransport,
  configure,
} from '@quiltr/lumyr-sdk';

// 1. Configure the SDK
configure({ appId: 'my-app' });

// 2. Register a transport (ships logs to the server)
registerTransport(
  createLogTransport({
    endpoint: 'https://log-server-nu.vercel.app',
    appId: 'my-app',
    apiKey: 'lsk_...',
  })
);

// 3. Create a scoped logger and use it
const logger = createLogger('BasketPage');
logger.info('addItem', 'Item added to basket', { data: { productId: '123' } });
logger.error('checkout', 'Payment failed', {
  error: { name: 'PaymentError', message: 'Card declined' },
  duration: 1200,
});
```

## High-Level Logger API

### `createLogger(component)`

Returns a scoped logger that auto-fills the component name:

```typescript
const logger = createLogger('AuthForm');
logger.debug(action, message, extra?);
logger.info(action, message, extra?);
logger.warn(action, message, extra?);
logger.error(action, message, extra?);
```

### `log`

Global logger with explicit component parameter:

```typescript
import { log } from '@quiltr/lumyr-sdk';
log.info('Component', 'action', 'message', { data: { key: 'value' } });
```

### `LogExtra`

Optional metadata for any log entry:

```typescript
{
  data?: Record<string, unknown>;   // Arbitrary structured data
  error?: {                          // Error details (for error logs)
    name: string;
    message: string;
    stack?: string;
    httpStatus?: number;
    apiEndpoint?: string;
  };
  duration?: number;                 // Execution time in ms
  correlationId?: string;            // Override auto-generated ID
  userId?: string;                   // Override auto-detected user
}
```

## Correlation IDs

Track requests across frontend → backend → log server:

```typescript
import {
  createCorrelationId,
  setCorrelationId,
  getCorrelationId,
  clearCorrelationId,
  withCorrelation,
} from '@quiltr/lumyr-sdk';

// Generate and set a correlation ID for a user action
const id = createCorrelationId();
setCorrelationId(id);
// All subsequent log entries will include this correlationId

// Or use scoped tracking
withCorrelation(id, () => {
  logger.info('fetchData', 'Loading products...');
  // After this block, the previous correlation ID is restored
});
```

## Transport Configuration

```typescript
interface LogClientConfig {
  endpoint: string;                                    // Log server URL
  appId: string;                                       // App identifier
  apiKey?: string;                                     // API key (lsk_* format)
  minLevel?: 'debug' | 'info' | 'warn' | 'error';     // Default: "debug"
  flushInterval?: number;                              // Default: 3000ms
  maxBatchSize?: number;                               // Default: 50
  maxQueueSize?: number;                               // Default: 500
}
```

The transport validates config on creation and throws with clear messages if invalid.

## Features

### Batched Ingestion
Entries are queued and shipped in batches (default: 50 entries or every 3s). The queue caps at 500 entries, dropping oldest when full.

### Page Unload Safety
Uses `fetch` with `keepalive: true` to flush remaining entries when the user navigates away or switches tabs. Falls back to `sendBeacon` when fetch+keepalive is unavailable.

### Automatic Backoff
After 3 consecutive shipping failures, the transport pauses for 30 seconds before retrying. The backoff resets on the next successful ship.

### Online/Offline Awareness
When the browser goes offline, the transport pauses the flush timer. When connectivity returns, it resumes and immediately flushes any queued entries.

### Level Filtering
Set `minLevel` to drop lower-priority logs:
```typescript
createLogTransport({ ..., minLevel: 'warn' }); // Only ships warn + error
```

### Flush Promise
`flush()` returns a `Promise<void>` that resolves when all pending batches are shipped:
```typescript
const transport = createLogTransport(config);
transport.write(entry);
await transport.flush(); // Wait for entries to ship
```

### Persistent Client ID
Unique device identifier stored in `localStorage`. Survives sessions, tabs, and page refreshes. Returns `"server"` in SSR contexts. Automatically migrates from the legacy `proximity_log_client_id` key.

### Session ID
Per-tab session ID stored in `sessionStorage`. Each tab gets its own session. Automatically injected into all log entries.

### Recent Entries Buffer
Ring buffer of the last 20 log entries, accessible via `getRecentEntries()`. Useful for attaching context to feedback/error reports.

### User ID Provider
Inject the current user's ID into every entry without circular dependencies:
```typescript
import { setUserIdProvider } from '@quiltr/lumyr-sdk';
setUserIdProvider(() => authStore.getState().user?.id);
```

### Environment Detection
Automatically detects deployment environment from `NEXT_PUBLIC_VERCEL_ENV`, `VERCEL_ENV`, or `NODE_ENV`. Override with `configure({ environment: 'staging' })`.

### Debug Mode
Enable internal SDK diagnostics:
```typescript
import { enableDebug } from '@quiltr/lumyr-sdk';
enableDebug();
// Or: localStorage.setItem('lumyr_debug', '1') then reload
```

### Zero Dependencies
No external runtime deps. Works in any browser, Node.js, or edge runtime.

## Transport Interface

The SDK returns a standard transport object compatible with any logger:

```typescript
interface LogTransport {
  name: string;
  write(entry: LogEntry): void;
  flush?(): Promise<void>;
  clear?(): void;
  stop?(): void | Promise<void>;
  start?(): void;
  getClientId?(): string;
}
```

## Multiple Transports

Register multiple transports — entries are written to all of them:

```typescript
import { registerTransport, removeTransport, getTransportNames } from '@quiltr/lumyr-sdk';

// Console transport for development
registerTransport({
  name: 'console',
  write(entry) {
    console[entry.level](`[${entry.level.toUpperCase()}]`, JSON.stringify(entry));
  },
});

// Log server transport
registerTransport(createLogTransport({ ... }));

// List registered transports
console.log(getTransportNames()); // ['console', 'log-server']
```

## Migration from v1.0

v2.0 is backwards-compatible with the v1.0 transport API. The main changes:

- **New exports**: `createLogger`, `log`, `registerTransport`, correlation ID functions, `configure`, `enableDebug`, etc.
- **`flush()` returns Promise**: `LogTransport.flush` is now `() => Promise<void>` (was `void`)
- **`stop()` returns Promise**: `LogTransport.stop` is now `() => void | Promise<void>`
- **Client ID key migrated**: `proximity_log_client_id` → `lumyr_client_id` (automatic migration)
- **Config validation**: `createLogTransport()` now throws on invalid config instead of silently failing

If you were using the v1 transport directly (`transport.write(entry)`), everything still works. The new high-level API (`createLogger`, `log`) is additive.

## License

MIT