npm package: @oxog/pulse
Description: Reactive signals & streams library with TC39 compliance, unified API, and micro-kernel plugin architecture - part of @oxog ecosystem
Author: Ersin Koç
Latest version: 1.0.0

# @oxog/pulse

> ⚡ A modern, high-performance reactive state management library with TC39 Signals compliance

[![npm version](https://img.shields.io/npm/v/@oxog/pulse.svg)](https://www.npmjs.com/package/@oxog/pulse)
[![license](https://img.shields.io/npm/l/@oxog/pulse.svg)](https://github.com/ersinkoc/pulse/blob/main/LICENSE)
[![bundle size](https://img.shields.io/bundlephobia/minzip/@oxog/pulse.svg)](https://bundlephobia.com/package/@oxog/pulse)
[![types](https://img.shields.io/npm/types/@oxog/pulse)](https://www.npmjs.com/package/@oxog/pulse)

Part of the **@oxog** ecosystem: [@oxog/plugin](https://npm.im/@oxog/plugin) · [@oxog/emitter](https://npm.im/@oxog/emitter)

---

## ✨ Features

- 🎯 **TC39 Signals Compliant** - Future-proof API following the upcoming standard
- ⚡ **Zero Dependencies** - Tiny bundle size, maximum performance
- 🔄 **Automatic Dependency Tracking** - No need to manually declare dependencies
- 📦 **Built-in Streams** - RxJS-compatible reactive streams with 30+ operators
- 🎨 **Framework Agnostic** - Works with React, Vue, Svelte, or vanilla JS
- 📦 **Batch Updates** - Automatic batching for optimal performance
- 🔌 **Plugin Architecture** - Extensible via @oxog/plugin micro-kernel
- 💪 **Full TypeScript** - Complete type safety out of the box

---

## 📦 Installation

```bash
# npm
npm install @oxog/pulse

# yarn
yarn add @oxog/pulse

# pnpm
pnpm add @oxog/pulse
```

---

## 🚀 Quick Start

### Signals

```typescript
import { signal, computed, effect } from '@oxog/pulse';

// Create a reactive signal
const count = signal(0);

// Create a computed value (auto-updates when dependencies change)
const doubled = computed(() => count.get() * 2);

// Create an effect (auto-runs when dependencies change)
const dispose = effect(() => {
  console.log(`Count: ${count.get()}, Doubled: ${doubled.get()}`);
});
// Logs: "Count: 0, Doubled: 0"

// Update the signal
count.set(5);
// Logs: "Count: 5, Doubled: 10"

// Cleanup when done
dispose();
```

### Streams

```typescript
import { stream, pipe } from '@oxog/pulse';
import { debounce, filter, map } from '@oxog/pulse/operators';

// Create a stream
const search$ = stream<string>();

// Apply operators
const results$ = pipe(
  search$,
  filter(q => q.length > 2),
  debounce(300),
  map(q => fetch(`/api/search?q=${q}`))
);

// Subscribe to results
results$.subscribe(result => console.log(result));

// Emit values
search$.next('hel');
search$.next('hello'); // Only this one passes through
```

---

## 📖 API Reference

### Signals

| Function | Description |
|----------|-------------|
| `signal(value, options?)` | Create a reactive signal |
| `computed(fn, options?)` | Create a derived computation |
| `effect(fn)` | Create a side effect |
| `untracked(fn)` | Read without dependency tracking |
| `batch(fn)` | Group updates into single propagation |

### Signal Methods

```typescript
const count = signal(0);

count.get();        // Read value (tracks dependency)
count.set(5);       // Set value
count.value;        // Property accessor (get/set)
count.update(n => n + 1);  // Update with function
count.peek();       // Read without tracking
count.subscribe(fn); // Subscribe to changes
count.toStream();   // Convert to Stream
count.dispose();    // Cleanup
```

### Streams

| Function | Description |
|----------|-------------|
| `stream(options?)` | Create a reactive stream |
| `pipe(source, ...ops)` | Compose operators |
| `merge(...streams)` | Merge multiple streams |
| `combineLatest(...)` | Combine latest values |

### Stream Methods

```typescript
const s = stream<number>();

s.next(1);           // Emit value
s.error(err);        // Emit error
s.complete();        // Complete stream
s.subscribe({...});  // Subscribe
s.pipe(op);          // Apply operator
s.toSignal(0);       // Convert to Signal
s.dispose();         // Cleanup
```

### Operators (30+)

```typescript
import {
  // Transformation
  map, mapTo, scan, reduce, buffer, pluck,
  
  // Filtering
  filter, take, skip, takeWhile, skipWhile, 
  distinct, distinctUntilChanged,
  
  // Timing
  debounce, throttle, delay, timeout, sample,
  
  // Combination
  merge, combineLatest, withLatestFrom, zip, race,
  
  // Higher-Order
  switchMap, mergeMap, concatMap, exhaustMap,
  
  // Error Handling
  catchError, retry, retryWhen,
  
  // Utility
  tap, finalize, defaultIfEmpty, count, find, isEmpty
} from '@oxog/pulse/operators';
```

---

## 🎯 Usage Examples

### Reactive Counter

```typescript
import { signal, computed, effect } from '@oxog/pulse';

const count = signal(0);
const doubled = computed(() => count.get() * 2);
const quadrupled = computed(() => doubled.get() * 2);

effect(() => {
  document.getElementById('count').textContent = count.get();
  document.getElementById('doubled').textContent = doubled.get();
  document.getElementById('quadrupled').textContent = quadrupled.get();
});

document.getElementById('increment').addEventListener('click', () => {
  count.update(n => n + 1);
});
```

### Batch Updates

```typescript
import { signal, computed, effect, batch } from '@oxog/pulse';

const firstName = signal('John');
const lastName = signal('Doe');
const fullName = computed(() => `${firstName.get()} ${lastName.get()}`);

effect(() => console.log(fullName.get()));
// Logs: "John Doe"

// Without batch: effect runs twice
firstName.set('Jane');
lastName.set('Smith');
// Logs: "Jane Doe", then "Jane Smith"

// With batch: effect runs once
batch(() => {
  firstName.set('Bob');
  lastName.set('Johnson');
});
// Logs: "Bob Johnson" (only once!)
```

### Search with Debounce

```typescript
import { stream, pipe } from '@oxog/pulse';
import { debounce, filter, switchMap } from '@oxog/pulse/operators';

const search$ = stream<string>();

const results$ = pipe(
  search$,
  filter(q => q.length >= 2),
  debounce(300),
  switchMap(async (q) => {
    const res = await fetch(`/api/search?q=${q}`);
    return res.json();
  })
);

results$.subscribe(results => {
  renderSearchResults(results);
});

// In your input handler
input.addEventListener('input', (e) => {
  search$.next(e.target.value);
});
```

### React Integration

```typescript
import { signal, computed } from '@oxog/pulse';
import { useSignal, useComputed } from '@oxog/pulse/react';

const count = signal(0);
const doubled = computed(() => count.get() * 2);

function Counter() {
  const value = useSignal(count);
  const dbl = useComputed(doubled);
  
  return (
    <div>
      <p>Count: {value}</p>
      <p>Doubled: {dbl}</p>
      <button onClick={() => count.update(n => n + 1)}>
        Increment
      </button>
    </div>
  );
}
```

---

## 🔌 Framework Integrations

| Framework | Import | Description |
|-----------|--------|-------------|
| React | `@oxog/pulse/react` | `useSignal`, `useComputed`, `useStream` |
| Vue | `@oxog/pulse/vue` | `toVueRef`, `useSignal`, `toVueComputed` |
| Svelte | `@oxog/pulse/svelte` | `toSvelteStore`, `fromSvelteStore` |

---

## 🏗️ Plugin Architecture

Built on @oxog/plugin micro-kernel:

```typescript
import { getPulse } from '@oxog/pulse';

const pulse = getPulse();

// Install plugins
pulse.use(myCustomPlugin);

// Listen to events
pulse.on('signal:create', (data) => {
  console.log('Signal created:', data);
});
```

---

## 📊 Comparison

| Feature | @oxog/pulse | Preact Signals | RxJS | MobX |
|---------|-------------|----------------|------|------|
| TC39 Compliant | ✅ | ✅ | ❌ | ❌ |
| Streams Built-in | ✅ | ❌ | ✅ | ❌ |
| Zero Deps | ✅ | ✅ | ❌ | ❌ |
| Bundle Size | ~15KB | ~2KB | ~60KB | ~16KB |
| Framework Agnostic | ✅ | ❌ | ✅ | ✅ |
| Plugin System | ✅ | ❌ | ❌ | ❌ |

---

## 📚 Documentation

- [API Reference](./docs/SPECIFICATION.md)
- [Implementation Guide](./docs/IMPLEMENTATION.md)
- [LLM-Friendly Docs](./docs/llms.txt)

---

## 🤝 Contributing

Contributions are welcome! Please read our contributing guidelines before submitting PRs.

```bash
# Clone and setup
git clone https://github.com/ersinkoc/pulse.git
cd pulse
pnpm install

# Run tests
pnpm test

# Build
pnpm build
```

---

## 📄 License

MIT © [Ersin Koç](https://github.com/ersinkoc)

---

## 🔗 Links

- [GitHub](https://github.com/ersinkoc/pulse)
- [npm](https://www.npmjs.com/package/@oxog/pulse)
- [@oxog Ecosystem](https://oxog.dev)
- [Twitter](https://twitter.com/ersinkoc)