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
Document broadcast config and fill in missing retrieveById row
Adds a "Syncing External Updates" section covering the AdapterStoreBroadcast
contract — what it's for, the subscribe/unsubscribe shape, the rationale
for not exposing raw mutation methods, and the lifecycle split between
store (one-shot subscribe) and transport layer (connection join/leave).
Also backfills the retrieveById row in the Store Module Methods table,
which was missed when that method was added.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/packages/adapter-store.md
+69-14Lines changed: 69 additions & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -181,6 +181,59 @@ try {
181
181
182
182
The store automatically persists state to the provided storage service. When the page reloads, stored data is available immediately while `retrieveAll()` fetches fresh data from the API. This provides a fast initial render without loading spinners.
183
183
184
+
## Syncing External Updates
185
+
186
+
Some resources are updated outside of the store's own CRUD calls — by another user over a WebSocket, by a background job, by an in-process event emitter. The `broadcast` config slot is the single, narrow bridge for feeding those updates into the store without going through HTTP.
The store calls `subscribe` exactly once at construction and wires the handlers straight into its internal mutation path. `onUpdate(item)` replaces or inserts; `onDelete(id)` removes. Both update reactive state, refresh adapted views, and persist to storage — identical to what `update()` / `delete()` do after a successful HTTP call.
213
+
214
+
::: tip Why isn't there a public `setById` / `applyUpdate` method?
215
+
By design. Exposing a raw mutation method would let any caller bypass HTTP, which is almost always a bug (you'd end up with stale server state). The `broadcast` contract forces the bridge to be declared explicitly at store construction, scoped to one event source per store.
216
+
:::
217
+
218
+
### Lifecycle
219
+
220
+
The `subscribe` call happens once, when the store is created. The unsubscribe return is retained internally and never exposed. In practice stores live for the app's lifetime, so teardown isn't needed — but if your event source has its own lifecycle (e.g., a channel you join and leave), manage that _outside_ the store. The store only cares about incoming events, not which channel they came from.
221
+
222
+
A common pattern is a small in-process emitter as a middleman: your transport layer (WebSocket, SSE, channel service, whatever) joins and leaves connections as views mount/unmount, and forwards incoming payloads onto an emitter that the store subscribes to. The store stays agnostic of transport and lifecycle.
223
+
224
+
### The Contract
225
+
226
+
```typescript
227
+
typeAdapterStoreBroadcast<T> = {
228
+
subscribe: (handlers: {
229
+
onUpdate: (item:T) =>void;
230
+
onDelete: (id:number) =>void;
231
+
}) => () =>void; // unsubscribe
232
+
};
233
+
```
234
+
235
+
That's it. Any event source that can emit "updated" and "deleted" events for your resource type can implement this.
236
+
184
237
## Custom New Types
185
238
186
239
By default, `generateNew()` creates an object with all fields except `id`. You can customize this with a third type parameter:
0 commit comments