Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 0 additions & 29 deletions .github/workflows/release.yml

This file was deleted.

3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ dist/
TASKS.md
playwright-report/*
test-results/*
.last-run.json
.last-run.json
package-lock.json
127 changes: 64 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# 🧩 TabStateSync

[![npm version](https://img.shields.io/npm/v/tabstatesync.svg)](https://www.npmjs.com/package/tabstatesync)
![CI](https://github.com/robertluiz/TabStateSync/actions/workflows/ci.yml/badge.svg)
![Tests](https://github.com/robertluiz/TabStateSync/actions/workflows/ci.yml/badge.svg?label=tests)

**TabStateSync** is a lightweight TypeScript library for synchronizing state across multiple browser tabs.
Expand Down Expand Up @@ -30,7 +29,7 @@ npm install tabstatesync

### Basic Example (Vanilla JS/TS)

Veja também exemplos completos em [`examples/VanillaThemeExample.ts`](examples/VanillaThemeExample.ts) e [`examples/e2e-sync.html`](examples/e2e-sync.html).
See also complete examples in [`examples/VanillaThemeExample.ts`](examples/VanillaThemeExample.ts) and [`examples/e2e-sync.html`](examples/e2e-sync.html).

```ts
import { createTabStateSync } from 'tabstatesync';
Expand All @@ -51,7 +50,7 @@ tabSync.set('dark');

### React Hook Example

Veja também exemplo completo em [`examples/ReactThemeExample.tsx`](examples/ReactThemeExample.tsx).
See also complete example in [`examples/ReactThemeExample.tsx`](examples/ReactThemeExample.tsx).

```tsx
import { useTabStateSync } from 'tabstatesync';
Expand Down Expand Up @@ -80,71 +79,43 @@ function ThemeSwitcher() {

## 📝 API Reference

### `createTabStateSync(key: string): TabStateSync`
Creates a new sync channel for a given key.
### `createTabStateSync(key: string, options?: TabStateSyncOptions): TabStateSync`
Creates a new sync channel for a given key with optional configuration.

### `TabStateSync<T>`
Class for synchronizing state across tabs.

#### Constructor
- `new TabStateSync<T>(key: string)`
- `new TabStateSync<T>(key: string, options?: TabStateSyncOptions)`

#### Methods
- `subscribe(callback: (value: T) => void): void` — Registers a callback for value changes from other tabs.
- `unsubscribe(callback: (value: T) => void): void` — Removes a previously registered callback.
- `set(value: T): void` — Updates the value and notifies other tabs.
- `destroy(): void` — Cleans up listeners and disables the instance.

### `useTabStateSync(key: string, initialValue: any): [any, (v: any) => void]` *(React only)*
Custom React hook for syncing state across tabs.

---
### `TabStateSyncOptions`
Configuration options for `TabStateSync`.

## 🧪 E2E Cross-Browser Testing

TabStateSync is automatically tested in Chromium, Firefox, and WebKit (Safari) using Playwright. This ensures robust cross-browser compatibility, including fallback and edge cases.

### How to run E2E tests locally

1. **Build the JS bundle for browser tests:**
```bash
npm run build:bundle
```
2. **Start a local server:**
```bash
npm run serve:e2e
```
3. **In another terminal, run Playwright tests:**
```bash
npm run test:e2e
```

- The tests will open browsers automatically and check sync between tabs, fallback to localStorage, and edge cases.
- To test the fallback, temporarily comment out or remove `window.BroadcastChannel` in your browser's devtools or in the bundle, then rerun the E2E test. The library will use localStorage events for sync.

#### Available npm scripts for E2E and build

- `npm run build:bundle` — Build browser bundle for E2E/examples
- `npm run serve:e2e` — Serve local files for browser tests
- `npm run test:e2e` — Run Playwright E2E tests

---

## 🚀 Automated Semantic Versioning & Release

This project uses [standard-version](https://github.com/conventional-changelog/standard-version) for automated semantic versioning and changelog generation.

### How to create a new release
```ts
interface TabStateSyncOptions {
// Namespace prefix for localStorage keys to prevent collisions
namespace?: string; // default: 'tss'

// Enable simple encryption for localStorage storage
enableEncryption?: boolean; // default: false

// Secret key for encryption (use a random string)
encryptionKey?: string; // default: 'change-this-key'

// Enable debug logging of errors
debug?: boolean; // default: false
}
```

1. Commit your changes using [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/).
2. Run:
```bash
npm run release
git push --follow-tags origin master
```
3. Create a GitHub release or push a tag (the CI will publish to npm and create the release automatically).
### `useTabStateSync(key: string, initialValue: any, options?: TabStateSyncOptions): [any, (v: any) => void]` *(React only)*
Custom React hook for syncing state across tabs.

---

## ❓ FAQ & Known Limitations

Expand All @@ -160,6 +131,15 @@ This project uses [standard-version](https://github.com/conventional-changelog/s
- Yes, as long as the browser supports BroadcastChannel or localStorage events in that mode. On Safari, the fallback uses polling to ensure sync even when the storage event does not fire.
- **What about memory leaks?**
- Always call `destroy()` when you no longer need a TabStateSync instance (e.g., on component unmount).
- **Is my data secure when stored in localStorage?**
- By default, data in localStorage is stored in plaintext. For improved security, enable the encryption option, but note that this is NOT suitable for highly sensitive data. The library uses a simple XOR encryption that helps prevent casual inspection but is not cryptographically secure.

## Security Considerations

- **Data Security**: The optional encryption feature provides basic protection against casual inspection of localStorage data. However, it is not a replacement for proper encryption and should not be used for highly sensitive information.
- **XSS Protection**: Always sanitize any HTML content before rendering it to the DOM, especially if it was received through TabStateSync.
- **Error Handling**: Enable debug mode during development to catch potential issues with data formatting or transport.
- **Namespace Collisions**: Use the namespace option to prevent key collisions with other applications or libraries using localStorage.

---

Expand All @@ -170,6 +150,13 @@ This project uses [standard-version](https://github.com/conventional-changelog/s

---

## Safari/Apple limitations

**Safari (desktop and iOS) does not reliably fire the `storage` event between tabs.**
To ensure cross-tab sync, TabStateSync automatically enables a polling fallback only on Safari, checking for changes every 500ms. This ensures maximum compatibility, but may have a slight performance impact only on Safari. All other browsers use the more efficient `storage` event.

---

## 📄 License

MIT
Expand All @@ -180,20 +167,34 @@ Contributions and suggestions are welcome!

---

## Safari/Apple limitations
## 🧪 E2E Cross-Browser Testing

**Safari (desktop and iOS) does not reliably fire the `storage` event between tabs.**
To ensure cross-tab sync, TabStateSync automatically enables a polling fallback only on Safari, checking for changes every 500ms. This ensures maximum compatibility, but may have a slight performance impact only on Safari. All other browsers use the more efficient `storage` event.
TabStateSync is automatically tested in Chromium, Firefox, and WebKit (Safari) using Playwright. This ensures robust cross-browser compatibility, including fallback and edge cases.

---
### How to run E2E tests locally

## 📚 Documentation & GitHub Pages
1. **Build the JS bundle for browser tests:**
```bash
npm run build:bundle
```
2. **Start a local server:**
```bash
npm run serve:e2e
```
3. **In another terminal, run Playwright tests:**
```bash
npm run test:e2e
```

Interactive documentation and advanced examples are in the `docs/` folder. To publish to GitHub Pages:
- The tests will open browsers automatically and check sync between tabs, fallback to localStorage, and edge cases.
- To test the fallback, temporarily comment out or remove `window.BroadcastChannel` in your browser's devtools or in the bundle, then rerun the E2E test. The library will use localStorage events for sync.

#### Available npm scripts for E2E and build

1. Build or update your docs in the `docs/` folder.
2. Commit and push to the `main` branch.
3. In your repository settings, set GitHub Pages source to `/docs` folder on `main` branch.
4. Access your documentation at `https://<your-username>.github.io/TabStateSync/`.
- `npm run build:bundle` — Build browser bundle for E2E/examples
- `npm run serve:e2e` — Serve local files for browser tests
- `npm run test:e2e` — Run Playwright E2E tests

---


83 changes: 0 additions & 83 deletions docs/AdvancedExamples.md

This file was deleted.

12 changes: 0 additions & 12 deletions docs/README.md

This file was deleted.

Loading