tab-bridge 0.1.1 → 0.2.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 +74 -11
- package/dist/{chunk-42VOZR6E.js → chunk-4JDWAUYM.js} +216 -93
- package/dist/{chunk-BQCNBNBT.cjs → chunk-TGEXRVAL.cjs} +219 -92
- package/dist/index.cjs +41 -25
- package/dist/index.d.cts +110 -5
- package/dist/index.d.ts +110 -5
- package/dist/index.js +2 -2
- package/dist/{types-BtK4ixKz.d.cts → instance-5LIItazN.d.cts} +58 -80
- package/dist/{types-BtK4ixKz.d.ts → instance-5LIItazN.d.ts} +58 -80
- package/dist/react/index.cjs +82 -9
- package/dist/react/index.d.cts +47 -2
- package/dist/react/index.d.ts +47 -2
- package/dist/react/index.js +79 -9
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
[](https://www.npmjs.com/package/tab-bridge)
|
|
18
18
|
[](https://bundlephobia.com/package/tab-bridge)
|
|
19
19
|
[](https://www.typescriptlang.org)
|
|
20
|
-
[](./LICENSE)
|
|
21
|
+
[](https://github.com/serbi2012/tab-bridge)
|
|
22
22
|
|
|
23
23
|
<br />
|
|
24
24
|
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
|
|
27
27
|
<br />
|
|
28
28
|
|
|
29
|
-
[**Getting Started**](#-getting-started) · [**API**](#-api-reference) · [**React**](#%EF%B8%8F-react) · [**Architecture**](#-architecture) · [**Examples**](#-examples)
|
|
29
|
+
[**Getting Started**](#-getting-started) · [**API**](#-api-reference) · [**React**](#%EF%B8%8F-react) · [**Architecture**](#-architecture) · [**Examples**](#-examples) · [**Live Demo**](https://serbi2012.github.io/tab-bridge/)
|
|
30
30
|
|
|
31
31
|
</div>
|
|
32
32
|
|
|
@@ -59,23 +59,23 @@ LWW conflict resolution with batched broadcasts and custom merge strategies
|
|
|
59
59
|
Bully algorithm with heartbeat monitoring and automatic failover
|
|
60
60
|
|
|
61
61
|
#### 📡 Cross-Tab RPC
|
|
62
|
-
Fully typed arguments, Promise-based calls with
|
|
62
|
+
Fully typed arguments, Promise-based calls with `callAll` broadcast support
|
|
63
63
|
|
|
64
|
-
####
|
|
65
|
-
|
|
64
|
+
#### 🔄 Atomic Transactions
|
|
65
|
+
`transaction()` for safe multi-key updates with abort support
|
|
66
66
|
|
|
67
67
|
</td>
|
|
68
68
|
<td width="50%" valign="top">
|
|
69
69
|
|
|
70
|
+
#### ⚛️ React Hooks
|
|
71
|
+
7 hooks built on `useSyncExternalStore` — zero-tear concurrent rendering
|
|
72
|
+
|
|
70
73
|
#### 🛡️ Middleware Pipeline
|
|
71
74
|
Intercept, validate, and transform state changes before they're applied
|
|
72
75
|
|
|
73
76
|
#### 💾 State Persistence
|
|
74
77
|
Survive page reloads with key whitelisting and custom storage backends
|
|
75
78
|
|
|
76
|
-
#### 🔒 End-to-End Type Safety
|
|
77
|
-
Discriminated unions, full type inference, and generic constraints
|
|
78
|
-
|
|
79
79
|
#### 📦 Zero Dependencies
|
|
80
80
|
Native browser APIs only, ~4KB gzipped, fully tree-shakable
|
|
81
81
|
|
|
@@ -175,6 +175,12 @@ sync.get('theme') // Read single key
|
|
|
175
175
|
sync.getAll() // Read full state (stable reference)
|
|
176
176
|
sync.set('theme', 'dark') // Write single key → broadcasts to all tabs
|
|
177
177
|
sync.patch({ theme: 'dark', count: 5 }) // Write multiple keys in one broadcast
|
|
178
|
+
|
|
179
|
+
// Atomic multi-key update — return null to abort
|
|
180
|
+
sync.transaction((state) => {
|
|
181
|
+
if (state.count >= 100) return null; // abort
|
|
182
|
+
return { count: state.count + 1, lastUpdated: Date.now() };
|
|
183
|
+
});
|
|
178
184
|
```
|
|
179
185
|
|
|
180
186
|
</details>
|
|
@@ -196,6 +202,13 @@ sync.select(
|
|
|
196
202
|
(state) => state.items.filter(i => i.done).length,
|
|
197
203
|
(doneCount) => updateBadge(doneCount),
|
|
198
204
|
);
|
|
205
|
+
|
|
206
|
+
// Debounced derived state — callback fires at most once per 200ms
|
|
207
|
+
sync.select(
|
|
208
|
+
(state) => state.items.length,
|
|
209
|
+
(count) => analytics.track('item_count', count),
|
|
210
|
+
{ debounce: 200 },
|
|
211
|
+
);
|
|
199
212
|
```
|
|
200
213
|
|
|
201
214
|
</details>
|
|
@@ -248,6 +261,10 @@ sync.handle('getServerTime', () => ({
|
|
|
248
261
|
|
|
249
262
|
const { iso } = await sync.call('leader', 'getServerTime');
|
|
250
263
|
const result = await sync.call(tabId, 'compute', payload, 10_000);
|
|
264
|
+
|
|
265
|
+
// Broadcast RPC to ALL other tabs and collect responses
|
|
266
|
+
const results = await sync.callAll('getStatus');
|
|
267
|
+
// results: Array<{ tabId: string; result?: T; error?: string }>
|
|
251
268
|
```
|
|
252
269
|
|
|
253
270
|
</details>
|
|
@@ -359,7 +376,8 @@ First-class React integration built on `useSyncExternalStore` for **zero-tear co
|
|
|
359
376
|
|
|
360
377
|
```tsx
|
|
361
378
|
import {
|
|
362
|
-
TabSyncProvider, useTabSync, useTabSyncValue, useTabSyncSelector,
|
|
379
|
+
TabSyncProvider, useTabSync, useTabSyncValue, useTabSyncSelector,
|
|
380
|
+
useIsLeader, useTabs, useLeaderInfo, useTabSyncActions,
|
|
363
381
|
} from 'tab-bridge/react';
|
|
364
382
|
```
|
|
365
383
|
|
|
@@ -444,6 +462,51 @@ function LeaderIndicator() {
|
|
|
444
462
|
|
|
445
463
|
</details>
|
|
446
464
|
|
|
465
|
+
<details open>
|
|
466
|
+
<summary><b><code>useTabs()</code> — Active tab list</b></summary>
|
|
467
|
+
|
|
468
|
+
<br />
|
|
469
|
+
|
|
470
|
+
```tsx
|
|
471
|
+
function TabList() {
|
|
472
|
+
const tabs = useTabs();
|
|
473
|
+
return <p>{tabs.length} tab(s) open</p>;
|
|
474
|
+
}
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
</details>
|
|
478
|
+
|
|
479
|
+
<details open>
|
|
480
|
+
<summary><b><code>useLeaderInfo()</code> — Leader tab info</b></summary>
|
|
481
|
+
|
|
482
|
+
<br />
|
|
483
|
+
|
|
484
|
+
```tsx
|
|
485
|
+
function LeaderDisplay() {
|
|
486
|
+
const leader = useLeaderInfo();
|
|
487
|
+
if (!leader) return <p>No leader yet</p>;
|
|
488
|
+
return <p>Leader: {leader.id}</p>;
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
</details>
|
|
493
|
+
|
|
494
|
+
<details open>
|
|
495
|
+
<summary><b><code>useTabSyncActions()</code> — Write-only (no re-renders)</b></summary>
|
|
496
|
+
|
|
497
|
+
<br />
|
|
498
|
+
|
|
499
|
+
```tsx
|
|
500
|
+
function IncrementButton() {
|
|
501
|
+
const { set, patch, transaction } = useTabSyncActions<MyState>();
|
|
502
|
+
return <button onClick={() => set('count', prev => prev + 1)}>+1</button>;
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
Components using only `useTabSyncActions` **never re-render** due to state changes — perfect for write-only controls.
|
|
507
|
+
|
|
508
|
+
</details>
|
|
509
|
+
|
|
447
510
|
<br />
|
|
448
511
|
|
|
449
512
|
---
|
|
@@ -725,7 +788,7 @@ MIT © [serbi2012](https://github.com/serbi2012)
|
|
|
725
788
|
|
|
726
789
|
<br />
|
|
727
790
|
|
|
728
|
-
<a href="https://github.com/serbi2012/tab-
|
|
791
|
+
<a href="https://github.com/serbi2012/tab-bridge">
|
|
729
792
|
<img src="https://img.shields.io/badge/GitHub-tab--bridge-4f46e5?style=for-the-badge&logo=github&logoColor=white" alt="GitHub" />
|
|
730
793
|
</a>
|
|
731
794
|
|