Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,122 @@
# Tasks: enterprise-browser-broadcast-channel
**Change ID**: enterprise-browser-broadcast-channel
**Package**: `@suaveplan/broadcast-channel`
**Target path**: `browser/platform/broadcast-channel`
**Prerequisite packages on Verdaccio**: `@suaveplan/events`, `@suaveplan/error`, `@suaveplan/crypto`, `@suaveplan/logger`, `@suaveplan/schema-registry`
---
## 0. Pre-flight (non-negotiable)
- [ ] 0.1 Confirm clean working tree (`git status` reports nothing) and no in-flight worktrees with uncommitted work (`git worktree list` then `git status` in each)
- [ ] 0.2 If any worktrees exist under `.claude/worktrees/`, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (`git worktree remove`) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
- [ ] 0.3 Confirm the package set in `MANIFEST.md` matches `find packages -maxdepth 3 -name package.json` count. Drift here means a prior change archived without regenerating the manifest.
## 1. Scaffold
- [ ] Create directory tree per `proposal.md`.
- [ ] `package.json` v0.0.0, `"sideEffects": false`.
- `dependencies`: `@suaveplan/events workspace:^`, `@suaveplan/error workspace:^`, `@suaveplan/types workspace:^`, `@suaveplan/logger workspace:^`, `@suaveplan/crypto workspace:^`, `@suaveplan/schema-registry workspace:^`, `zod catalog:forms`, `@opentelemetry/api catalog:observability`, `tslib catalog:build`
- `devDependencies`: `vitest catalog:testing`, `@vitest/coverage-istanbul catalog:testing`, `happy-dom catalog:testing`, `@playwright/test catalog:testing`, `@suaveplan/testing workspace:^`
- Subpath exports: `"."`, `"./transport"`, `"./leader"`, `"./types"`
- [ ] `tsconfig.json`, `vitest.config.ts` (pool: forks, happy-dom environment, `fileParallelism: false`).
---
## 2. Error codes
- [ ] `CHANNEL_CLOSED`, `MESSAGE_MALFORMED`, `PAYLOAD_TOO_LARGE`.
- [ ] `registerBroadcastChannelErrorCodes()` — call eagerly.
---
## 3. Types (`src/types/broadcast-channel.types.ts`)
- [ ] `ChannelConfig`, `ChannelMessage`, `TabInfo`, `BroadcastChannelEventMap`, `ChannelHandler`, `ChannelLike` (typed `MessageEvent`), `ChannelTransport`, `AskOptions`.
- [ ] Write `broadcast-channel.types.md`.
---
## 4. Internal ID generator (`src/internal/id.ts`)
- [ ] `generateId(): string` — wraps `@suaveplan/crypto` random bytes → hex string.
- [ ] Replaces duplicate `generateTabId`/`generateMsgId` that existed in the original.
---
## 5. `ChannelMessage` schema (`src/schema/channel-message-schema/`)
- [ ] `channel-message-schema.ts` — Zod `ChannelMessageSchema`; `registerChannelMessageSchema()`.
- [ ] Write `channel-message-schema.md`.
---
## 6. `BroadcastTransport` (`src/transport/broadcast/`)
- [ ] `broadcast.ts` — wraps native `BroadcastChannel`; implements `ChannelTransport`.
- [ ] Write `broadcast.test.ts` (send, receive, close). Write `broadcast.md`.
---
## 7. `LocalStorageTransport` (`src/transport/local-storage/`)
- [ ] `local-storage.ts` — `localStorage` + `storage` event fallback; same `ChannelTransport` interface.
- [ ] Auto-polyfill detection: `typeof BroadcastChannel === 'undefined'`.
- [ ] Write `local-storage.test.ts` (send, receive, close). Write `local-storage.md`.
---
## 8. Leader strategies (`src/leader/leader/`)
- [ ] `leader.ts` — `LeaderStrategy` interface; `LowestIdStrategy` (lowest tab ID wins); `ActiveTabStrategy` (prefers visible tab via `visibilitychange`, tie-break by `joinedAt`).
- [ ] Write `leader.test.ts` (LowestId election, ActiveTab election, disconnect scenario). Write `leader.md`.
---
## 9. `ask` primitive (`src/ask/ask/`)
- [ ] `ask.ts` — `ask<T, R>(channel, type, payload, options): Promise<R>` using correlation IDs and timeout.
- [ ] Reject with `CHANNEL_CLOSED` on close; reject with `WORKER_REQUEST_TIMEOUT` on timeout.
- [ ] Write `ask.test.ts` (success, timeout, channel-close rejection, collision). Write `ask.md`.
---
## 10. `TypedBroadcastChannel` (`src/channel/channel/`)
- [ ] `channel.ts` — composing transport + leader + ask + schema validation.
- [ ] `handleIncoming` validates via `ChannelMessageSchema`; drops + emits `error` on malformed.
- [ ] `send()` guards against `maxMessageBytes`; throws `PAYLOAD_TOO_LARGE`.
- [ ] Wire OTel metrics.
- [ ] Wire `@suaveplan/logger` for dropped frames and stale-tab cleanup.
- [ ] Write `channel.test.ts` (send, receive, malformed drop, payload-too-large, leader election, stale cleanup). Write `channel.md`.
---
## 11. Integration test (`tests/integration.test.ts`)
- [ ] `BroadcastTransport` → `TypedBroadcastChannel` round-trip.
- [ ] `LocalStorageTransport` same API round-trip.
- [ ] `ask` with timeout: verify rejection.
- [ ] Leader election: two channels, close leader, verify re-election.
---
## 12. Playwright E2E (`e2e/broadcast-channel.spec.ts`)
- [ ] Chromium: two browser tabs on same origin; one sends, other receives.
- [ ] WebKit: `LocalStorageTransport` fallback verified (inject config to skip `BroadcastChannel`).
- [ ] Leader election: three tabs, close leader, verify re-election in remaining two.
---
## 13. Docs + verify
- [ ] Write `.md` per module (≥200 words, API reference, examples).
- [ ] Write `README.md` with subpath table, transport guide, leader-election guide, `ask` example.
- [ ] `bunx turbo lint typecheck test --filter=@suaveplan/broadcast-channel` — green.
- [ ] `bunx turbo test:coverage` — 100%.
- [ ] No `@ts-expect-error` in `src/` or tests. No `any` in `ChannelLike`.
- [ ] Playwright E2E green on Chromium and WebKit.
- [ ] `bun scripts/publish.ts --package @suaveplan/broadcast-channel`.
- [ ] Archive to `openspec/archive/2026-04-24-enterprise-browser-broadcast-channel/`.