You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Switch from explicit path lists to `prettier .` (matching
ably-js's approach) and reformat all files that had drifted.
Submodules (ably-common, specification) are excluded via
.prettierignore.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@@ -67,11 +66,11 @@ Header/event/message-name constants and Ably message utilities used by both laye
67
66
68
67
The client-side architecture separates three concerns:
69
68
70
-
| Component | Owns | Events |
71
-
|---|---|---|
72
-
|**Tree**| Complete conversation state — every node from live messages and history. Turn tracking (active turn → clientId). |`update` (any structural change), `ably-message` (every raw message), `turn` (start/end) — unfiltered, fires for all changes |
73
-
|**View**| Pagination window — which history-loaded nodes are visible vs withheld. | Same event names, but **scoped to the visible window** — only fires when the visible output changes |
74
-
|**Transport**| Write path (send/regenerate/edit/cancel), channel subscription, stream routing, decode loop. |`error` only — all data events moved to Tree/View |
|**Tree**| Complete conversation state — every node from live messages and history. Turn tracking (active turn → clientId). |`update` (any structural change), `ably-message` (every raw message), `turn` (start/end) — unfiltered, fires for all changes |
72
+
|**View**| Pagination window — which history-loaded nodes are visible vs withheld. | Same event names, but **scoped to the visible window** — only fires when the visible output changes|
73
+
|**Transport**| Write path (send/regenerate/edit/cancel), channel subscription, stream routing, decode loop. |`error` only — all data events moved to Tree/View|
75
74
76
75
The Tree is the source of truth. The View subscribes to Tree events and re-emits them filtered to what's visible. The Transport wires the channel to the Tree and exposes both as `transport.tree` and `transport.view`.
77
76
@@ -146,8 +145,8 @@ Public-facing entry points (e.g. `createClientTransport()`) are factory function
146
145
147
146
1.**Two-layer split**: Generic transport/codec knows nothing about Vercel. Vercel layer implements the codec and provides convenience wrappers.
148
147
2.**Codec-parameterized**: All generic components are parameterized by `<TEvent, TMessage>` via the `Codec` interface.
149
-
4.**Constructor/option injection**: All dependencies passed explicitly — no singletons, no globals.
150
-
3.**Composition, not inheritance**: Transports compose features; no class hierarchies.
148
+
3.**Constructor/option injection**: All dependencies passed explicitly — no singletons, no globals.
149
+
4.**Composition, not inheritance**: Transports compose features; no class hierarchies.
151
150
5.**Interface-first**: Public contracts are TypeScript interfaces. Implementations are internal `Default*` classes, exposed to consumers via factory functions.
152
151
6.**Header discipline**: Generic layer uses only `x-ably-*` headers. Domain-specific headers (e.g. `x-domain-*`) belong in the Vercel layer.
153
152
7.**Explicit exports**: Only types and functions listed in `index.ts` files are public API.
Copy file name to clipboardExpand all lines: .claude/rules/ERRORS.md
+8-8Lines changed: 8 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -11,7 +11,7 @@ Every error should either be handled internally with a clear recovery strategy,
11
11
-**Isolate handler callbacks**: When the SDK invokes developer-provided callbacks (event listeners, hooks), wrap each in try/catch. One bad handler shouldn't kill internal machinery or prevent other handlers from firing.
12
12
-**Define recovery semantics explicitly**: For every internal operation that can fail, decide upfront: retry, degrade, or propagate. Document the choice.
13
13
-**Preserve the original error**: When wrapping errors, always attach the original as `cause`. Developers debugging production issues need the full chain.
14
-
-**Best-effort operations should be labeled**: If something is fire-and-forget (e.g. cleanup publish on close), comment it as such. Swallowing an error is only acceptable when failure is unrecoverable *and* non-impactful.
14
+
-**Best-effort operations should be labeled**: If something is fire-and-forget (e.g. cleanup publish on close), comment it as such. Swallowing an error is only acceptable when failure is unrecoverable _and_ non-impactful.
15
15
16
16
### Surfacing errors to developers
17
17
@@ -145,12 +145,12 @@ reject(
145
145
146
146
Use the custom Vitest matchers in a test helper (`test/helper/expectations.ts`):
147
147
148
-
| Matcher | Usage |
149
-
|---|---|
150
-
|`toBeErrorInfo({ code?, statusCode?, message?, cause? })`| Assert a value is an `Ably.ErrorInfo` matching the given fields |
151
-
|`toThrowErrorInfo({ code?, statusCode?, message? })`| Assert a sync function throws a matching `Ably.ErrorInfo`|
152
-
|`toBeErrorInfoWithCode(code)`| Shorthand — assert value is `Ably.ErrorInfo` with a specific code |
153
-
|`toThrowErrorInfoWithCode(code)`| Shorthand — assert sync function throws with a specific code |
154
-
|`toBeErrorInfoWithCauseCode(code)`| Assert value is `Ably.ErrorInfo` whose `.cause.code` matches |
0 commit comments