@luckystack/sync 0.8.2 → 0.8.4

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/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.8.4] - 2026-08-17
11
+
12
+ ### Changed
13
+
14
+ - Corrected dependency, generated-typing, error-tracker, and transport-span documentation, including the current root no-cast rule and HTTP-only automatic sync request span.
15
+
10
16
  ## [0.8.1] - 2026-07-27
11
17
 
12
18
  ### Fixed
package/CLAUDE.md CHANGED
@@ -106,11 +106,12 @@ None directly. Inherits socket transport config from `@luckystack/server` and Re
106
106
  ## Peer dependencies
107
107
 
108
108
  - **Required**: `@luckystack/core`, `@luckystack/error-tracking`. **`@luckystack/login` is NOT a dependency** (0.2.0 decoupling) — sessions resolve through core's `readSession` / session-provider registry (`handleSyncRequest` imports `readSession` from `@luckystack/core`), with login as the default *provider* (optional package), not a hard runtime dep.
109
- - **Peer (canonical ranges, 2026-05-07)**:
110
- - `@prisma/client@^6.19.0` (transitively required via `@luckystack/core`)
111
- - `react@^19.2.0` (only the `/client` subpath)
109
+ - **Required peers**:
112
110
  - `socket.io@^4.8.0` (server entry)
113
111
  - `socket.io-client@^4.8.0` (client entry)
112
+ - **Optional peers**:
113
+ - `@prisma/client@^6.19.0` (only for the default Prisma-backed session/user provider)
114
+ - `react@^19.2.0` (only the `/client` subpath)
114
115
  - Redis adapter (required for cross-instance fanout) wired by `@luckystack/server`; see `/docs/ARCHITECTURE_SOCKET.md`.
115
116
 
116
117
  ## Related
package/README.md CHANGED
@@ -5,7 +5,8 @@
5
5
  ## Install
6
6
 
7
7
  ```bash
8
- npm install @luckystack/sync @luckystack/core @luckystack/login @luckystack/error-tracking react socket.io socket.io-client
8
+ npm install @luckystack/sync socket.io socket.io-client
9
+ # Optional React client helpers: npm install react
9
10
  ```
10
11
 
11
12
  ## Quickstart
@@ -143,12 +144,9 @@ Client entry (`@luckystack/sync/client`):
143
144
 
144
145
  ## Dependencies
145
146
 
146
- - Runtime: `@luckystack/core`, `@luckystack/login`, `@luckystack/error-tracking`
147
- - Peer (canonical ranges, standardized 2026-05-07):
148
- - `@prisma/client@^6.19.0` (transitively required via `@luckystack/core`)
149
- - `react@^19.2.0` (`/client` entry only)
150
- - `socket.io@^4.8.0`
151
- - `socket.io-client@^4.8.0`
147
+ - Runtime: `@luckystack/core`, `@luckystack/error-tracking` (`@luckystack/login` is an optional session provider, not a runtime dependency)
148
+ - Required peers: `socket.io@^4.8.0`, `socket.io-client@^4.8.0`
149
+ - Optional peers: `@prisma/client@^6.19.0` (only for the default Prisma-backed session/user provider), `react@^19.2.0` (`/client` entry only).
152
150
 
153
151
  ## License
154
152
 
@@ -66,7 +66,7 @@ upsertSyncEventCallback<F, V>(params: {
66
66
  }): () => void // returns unsubscribe function
67
67
  ```
68
68
 
69
- ### Typed payloads (rule 16, no casts)
69
+ ### Typed payloads (root contract rule 21, no casts)
70
70
 
71
71
  Both `clientOutput` and `serverOutput` are typed via the generated `SyncTypeMap`. The framework's discriminated unions surface every possible status:
72
72
 
@@ -83,7 +83,7 @@ upsertSyncEventCallback({
83
83
  });
84
84
  ```
85
85
 
86
- Never cast these to `unknown` or `any` (root `CLAUDE.md` rule 16). If inference fails, regenerate the type map (`npm run ai:index`) — that's the source of truth.
86
+ Never cast these to `unknown` or `any` (root `CLAUDE.md` rule 21). If inference fails, run `npm run generateArtifacts`; if generated output is wrong, fix the generator rather than casting around it.
87
87
 
88
88
  ### Validation rules
89
89
 
@@ -199,7 +199,7 @@ Idempotent: if `initSyncRequest` is called again later, the previous handlers ar
199
199
 
200
200
  ## 6. Why callbacks must never cast `serverOutput` / `clientOutput`
201
201
 
202
- Rule 16 in the repo root `CLAUDE.md`: generated types are mandatory; no `unknown` / `any` casts on typed transports.
202
+ Rule 21 in the repository-root `CLAUDE.md`: generated types are mandatory; no `unknown` / `any` casts on typed transports.
203
203
 
204
204
  Both `upsertSyncEventCallback` and `upsertSyncEventStreamCallback` give you fully typed payloads via the generated `SyncTypeMap`. The framework's discriminated unions handle the status branching cleanly:
205
205
 
@@ -253,5 +253,5 @@ When inference fails:
253
253
  - Originator API: [`./sync-request.md`](./sync-request.md)
254
254
  - Stream payload shapes: [`./streaming.md`](./streaming.md)
255
255
  - Server / client handler contracts (what produces the payloads): [`./server-vs-client-handlers.md`](./server-vs-client-handlers.md)
256
- - Type-generation contract (rule 16): repo root [`.claude/CLAUDE.md`](../../../.claude/CLAUDE.md)
256
+ - Type-generation contract (rule 21): repository-root [`CLAUDE.md`](../../../CLAUDE.md)
257
257
  - `SocketStatusProvider` wiring: `src/_providers/SocketStatusProvider.tsx` (installer side)
@@ -1,6 +1,6 @@
1
1
  # error-states
2
2
 
3
- > Authoritative catalog of error codes emitted by `syncRequest` (client) and `handleSyncRequest` / `handleHttpSyncRequest` (server). Documents HTTP-status mapping, locale-aware message normalization, `errorParams` interpolation slots, the `rateLimitExceeded` hook payload, and Sentry capture behavior.
3
+ > Authoritative catalog of error codes emitted by `syncRequest` (client) and `handleSyncRequest` / `handleHttpSyncRequest` (server). Documents HTTP-status mapping, locale-aware message normalization, `errorParams` interpolation slots, the `rateLimitExceeded` hook payload, and registered error-tracker capture behavior.
4
4
 
5
5
  For the originator response envelope shape see [`./sync-request.md`](./sync-request.md). For the full lifecycle these errors slot into see [`./server-vs-client-handlers.md`](./server-vs-client-handlers.md).
6
6
 
@@ -167,14 +167,14 @@ Recipients (per-recipient errors during fanout) use **their own** headers, not t
167
167
 
168
168
  ---
169
169
 
170
- ## 9. Sentry capture via `tryCatch`
170
+ ## 9. Error-tracker capture via `tryCatch`
171
171
 
172
172
  Every `_server` and `_client` execution is wrapped in `tryCatch(..., undefined, { handler, sync, stage, userId, ... })`. The fourth argument is the breadcrumb context that gets attached when `tryCatch` captures an exception.
173
173
 
174
174
  Captured automatically:
175
175
 
176
- - `_server` thrown errors -> Sentry breadcrumb: `{ handler: 'handleSyncRequest', sync: <route>, stage: 'server', userId, receiver, transport: 'socket' | 'http' }`.
177
- - `_client` thrown errors -> Sentry breadcrumb: `{ handler: 'handleSyncRequest', sync: <route>, stage: 'client', sourceUserId, targetToken, receiver, transport }`.
176
+ - `_server` thrown errors -> a breadcrumb/event for the registered tracker(s): `{ handler: 'handleSyncRequest', sync: <route>, stage: 'server', userId, receiver, transport: 'socket' | 'http' }`.
177
+ - `_client` thrown errors -> a breadcrumb/event for the registered tracker(s): `{ handler: 'handleSyncRequest', sync: <route>, stage: 'client', sourceUserId, targetToken, receiver, transport }`.
178
178
 
179
179
  NOT captured (returned as `status: 'error'` envelopes only):
180
180
 
@@ -183,7 +183,7 @@ NOT captured (returned as `status: 'error'` envelopes only):
183
183
  - Rate-limit rejects — these are noise.
184
184
  - `_server` / `_client` returning `{ status: 'error' }` voluntarily — the handler made a domain decision; nothing threw.
185
185
 
186
- If you need to also Sentry-capture a voluntary error (e.g. "this code path should never trigger in production"), do it explicitly inside the handler via `@luckystack/error-tracking`'s `captureException`.
186
+ If you need to capture a voluntary error (e.g. "this code path should never trigger in production"), do it explicitly inside the handler via `@luckystack/error-tracking`'s `captureException`; it fans out to the registered tracker(s).
187
187
 
188
188
  ---
189
189
 
@@ -235,7 +235,7 @@ These are dev hints, not production behavior. Toggle both to `false` for product
235
235
  | Request reached server but auth rejected | `auth.required`, `auth.forbidden` | `_server`'s `auth` export, [`./server-vs-client-handlers.md`](./server-vs-client-handlers.md) |
236
236
  | 429 rate-limit responses | `sync.rateLimitExceeded` | `projectConfig.rateLimiting` |
237
237
  | Server-side schema fail | `sync.invalidInputType` | `_server`'s `SyncParams.clientInput` interface + generated Zod schema |
238
- | Handler threw | `sync.serverExecutionFailed` / `sync.clientExecutionFailed` | Sentry breadcrumb |
238
+ | Handler threw | `sync.serverExecutionFailed` / `sync.clientExecutionFailed` | Registered error-tracker capture |
239
239
  | Domain logic rejected | `<route-supplied errorCode>` | The `_server` or `_client` file's return path |
240
240
  | Empty room | `sync.noReceiversFound` | `receiver` argument; check room membership |
241
241
  | Offline + caller didn't await | `offline.queueFull` | Bump `offlineQueue.maxSize` or switch `dropPolicy` |
@@ -56,7 +56,7 @@ Key rules:
56
56
  - **Streaming primitives are received as params.** See [`./streaming.md`](./streaming.md) for the audience matrix.
57
57
  - **Optional `export const validation`** toggles runtime input validation, exactly like the API handler. `'strict'` (default, or omit the export) validates `clientInput` against the generated Zod schema; `'relaxed'` or `{ input: 'skip' }` skips validation entirely — use it for routes whose payload shape can't be modelled in TypeScript (third-party webhook fan-in, dynamic blobs). Honored identically by both the Socket.io and HTTP/SSE transports.
58
58
  - **Optional `export const errorFormatter`** overrides the error envelope for this route only (falls back to the global `registerErrorFormatter`, then the framework default). Both transports honor it.
59
- - **Never `try/catch` manually.** Wrap async ops in `functions.tryCatch` (or the destructured `tryCatch` from `functions`) — the framework already wraps the whole `main()` in its own `tryCatch` for Sentry capture, but per-operation `tryCatch` lets you surface targeted error codes.
59
+ - **Never `try/catch` manually.** Wrap async ops in `functions.tryCatch` (or the destructured `tryCatch` from `functions`) — the framework already wraps the whole `main()` in its own `tryCatch` for registered error-tracker capture, but per-operation `tryCatch` lets you surface targeted error codes.
60
60
 
61
61
  ---
62
62
 
@@ -146,7 +146,7 @@ incoming msg (Socket.io 'sync' event)
146
146
  2. parseTransportRouteName(name) -> routing.invalidServiceRouteName
147
147
  3. validate cb -> sync.invalidCallback
148
148
  4. validate receiver -> sync.missingReceiver
149
- 5. getSession(token) -> setSentryUser(...)
149
+ 5. getSession(token) -> propagate identity to registered error trackers
150
150
  6. getRuntimeSyncMaps()
151
151
  no _server AND no _client -> sync.notFound
152
152
  |
package/docs/streaming.md CHANGED
@@ -238,7 +238,7 @@ io.to(receiver).emit(socketEventNames.sync, frame);
238
238
 
239
239
  ### Stream-hook fire-and-forget
240
240
 
241
- `preSyncStream` and `postSyncStream` hooks dispatch via `void dispatchHook(...)` — chunks never `await` the hook. Hook errors are swallowed by the hook dispatcher's own `tryCatch`. This matters because a slow Sentry breadcrumb (for example) must not delay chunk delivery to the user.
241
+ `preSyncStream` and `postSyncStream` hooks dispatch via `void dispatchHook(...)` — chunks never `await` the hook. Hook errors are swallowed by the hook dispatcher's own `tryCatch`. This matters because a slow error-tracker breadcrumb (for example) must not delay chunk delivery to the user.
242
242
 
243
243
  ### Chunk-index counter
244
244
 
@@ -40,7 +40,7 @@ This is enforced through generated `SyncTypeMap` entries — no runtime check fi
40
40
  - `src/{page}/_sync/{name}_server_v{N}.ts` -> `'{page}/{name}'`
41
41
  - `src/_sync/{name}_server_v{N}.ts` (root-level) -> `'system/{name}'`
42
42
 
43
- Always pass the literal string. Any narrowing layer (`as any`, `as SyncFullName`, manual cast helpers) breaks inference and **violates rule 16** in the root `CLAUDE.md` (no `unknown`/`any` casts on typed transports).
43
+ Always pass the literal string. Any narrowing layer (`as any`, `as SyncFullName`, manual cast helpers) breaks inference and **violates rule 21** in the repository-root `CLAUDE.md` (no `unknown`/`any` casts on typed transports).
44
44
 
45
45
  ### `version: V extends VersionsForFullName<F>`
46
46
 
@@ -222,7 +222,7 @@ When the Socket.io transport is unavailable (corporate firewalls, mobile carrier
222
222
  |---|---|---|
223
223
  | Originator chunks (`stream(payload)`) | `socket.emit(progressEventName, payload)` | `stream?.(payload)` injected callback → SSE writer |
224
224
  | Recipients (`broadcastStream`, `streamTo`) | Socket.io fanout | Socket.io fanout (recipients still on sockets) |
225
- | Sentry span | `'sync.request'` | `'sync.request.http'` |
225
+ | Auto-instrumented error-tracker span | none | `'sync.request.http'` |
226
226
  | Final ack | `socket.emit(buildSyncResponseEventName(responseIndex), envelope)` | HTTP response body (`HttpSyncResponse`) |
227
227
 
228
228
  Signature:
@@ -331,7 +331,7 @@ Allowed by the framework (it just maps `v3` to its own entry), but confusing for
331
331
  await syncRequest({ name: 'board/moveCard' as any, version: someString as any, ... });
332
332
  ```
333
333
 
334
- This violates rule 16 (no `as any` / `as unknown` on typed transports). If you don't know the version statically, the design needs to change — versions are an authoring-time decision, not a runtime one.
334
+ This violates repository contract rule 21 (no `as any` / `as unknown` on typed transports). If you don't know the version statically, the design needs to change — versions are an authoring-time decision, not a runtime one.
335
335
 
336
336
  ---
337
337
 
@@ -359,4 +359,4 @@ This violates rule 16 (no `as any` / `as unknown` on typed transports). If you d
359
359
  - Recipient subscription: [`./callback-registration.md`](./callback-registration.md)
360
360
  - Error contract (including `sync.invalidInputType` from regenerated Zod schemas): [`./error-states.md`](./error-states.md)
361
361
  - Type-map regeneration: `npm run ai:index` (`@luckystack/devkit`)
362
- - Sync type contract: rule 16 in repo root [`.claude/CLAUDE.md`](../../../.claude/CLAUDE.md)
362
+ - Sync type contract: rule 21 in repository-root [`CLAUDE.md`](../../../CLAUDE.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luckystack/sync",
3
- "version": "0.8.2",
3
+ "version": "0.8.4",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -60,8 +60,8 @@
60
60
  "test": "vitest run"
61
61
  },
62
62
  "dependencies": {
63
- "@luckystack/core": "^0.8.2",
64
- "@luckystack/error-tracking": "^0.8.2"
63
+ "@luckystack/core": "^0.8.4",
64
+ "@luckystack/error-tracking": "^0.8.4"
65
65
  },
66
66
  "peerDependencies": {
67
67
  "@prisma/client": "^6.19.0",