stitchkit 0.72.2 → 0.72.3

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.
@@ -14,6 +14,8 @@
14
14
  */
15
15
  import type { QueryClient, QueryKey } from '@tanstack/react-query';
16
16
  /** Minimal emitter — subscribe to an event, get an unsubscribe back. */
17
+ import type { InferRealtimeEventMap, RealtimeEventRegistry } from '../realtime/contract.js';
18
+ import type { ValidatedRealtimeSocket } from '../realtime/socket.js';
17
19
  export interface CacheBridgeSocket<TEvents> {
18
20
  on<K extends keyof TEvents & string>(event: K, handler: TEvents[K]): () => void;
19
21
  }
@@ -52,6 +54,28 @@ export interface CacheBridge {
52
54
  /** Forget every freshness marker without changing socket subscriptions. */
53
55
  clearFresh(): void;
54
56
  }
57
+ /**
58
+ * The bridge, fed by a validated realtime contract instead of a raw socket.
59
+ *
60
+ * A realtime registry maps an event name to its DEFINITION — `{ args, ack }` — while the bridge's
61
+ * event map wants the handler FUNCTION at that position. Structurally the socket still matched,
62
+ * so the generic bound to the registry and every payload inferred as `never`: the combination
63
+ * `AGENTS.md` prescribes did not compile, and the error pointed at the consumer's own property
64
+ * access rather than at the seam. Naming the mapping is the whole fix; nothing runs differently.
65
+ */
66
+ export interface RealtimeCacheBridgeConfig<TInbound extends RealtimeEventRegistry> extends Omit<CacheBridgeConfig<InferRealtimeEventMap<TInbound>>, 'socket'> {
67
+ socket: ValidatedRealtimeSocket<TInbound, RealtimeEventRegistry>;
68
+ }
55
69
  export declare function createCacheBridge<TEvents>(config: CacheBridgeConfig<TEvents>): CacheBridge;
70
+ /**
71
+ * The same bridge, fed by a validated realtime contract instead of a raw socket.
72
+ *
73
+ * A separate function rather than an overload, deliberately. A validated socket also satisfies
74
+ * the looser `CacheBridgeSocket`, so an overload would be decided structurally — and worse, an
75
+ * existing caller that passes its event map explicitly (`createCacheBridge<NoteEvents>(…)`) would
76
+ * bind to whichever signature came first and stop compiling. Two names cost one line at the call
77
+ * site and break nobody.
78
+ */
79
+ export declare function createRealtimeCacheBridge<TInbound extends RealtimeEventRegistry>(config: RealtimeCacheBridgeConfig<TInbound>): CacheBridge;
56
80
  export {};
57
81
  //# sourceMappingURL=cache-bridge.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache-bridge.d.ts","sourceRoot":"","sources":["../../src/react/cache-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEnE,wEAAwE;AACxE,MAAM,WAAW,iBAAiB,CAAC,OAAO;IACxC,EAAE,CAAC,CAAC,SAAS,MAAM,OAAO,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC;CACjF;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,WAAW,CAAC;IACzB,gFAAgF;IAChF,OAAO,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC;CACjC;AAED,oEAAoE;AACpE,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,OAAO,GAAG,CAAC,GAAG,KAAK,CAAC;AAE3E,MAAM,MAAM,kBAAkB,CAAC,QAAQ,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,kBAAkB,KAAK,IAAI,CAAC;AAE7F,MAAM,MAAM,mBAAmB,CAAC,OAAO,IAAI;KACxC,CAAC,IAAI,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,EAAE,kBAAkB,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;CAC7E,CAAC;AAEF,MAAM,WAAW,iBAAiB,CAAC,OAAO;IACxC,MAAM,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACnC;;;;;OAKG;IACH,WAAW,EAAE,WAAW,GAAG,CAAC,MAAM,WAAW,CAAC,CAAC;IAC/C,QAAQ,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC;IACvC,0FAA0F;IAC1F,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0FAA0F;IAC1F,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,IAAI,IAAI,CAAC;IAChB,UAAU,IAAI,IAAI,CAAC;IACnB;qEACiE;IACjE,SAAS,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC/B,2EAA2E;IAC3E,UAAU,IAAI,IAAI,CAAC;CACpB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,iBAAiB,CAAC,OAAO,CAAC,GAAG,WAAW,CAsF1F"}
1
+ {"version":3,"file":"cache-bridge.d.ts","sourceRoot":"","sources":["../../src/react/cache-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEnE,wEAAwE;AACxE,OAAO,KAAK,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AACzF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAElE,MAAM,WAAW,iBAAiB,CAAC,OAAO;IACxC,EAAE,CAAC,CAAC,SAAS,MAAM,OAAO,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC;CACjF;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,WAAW,CAAC;IACzB,gFAAgF;IAChF,OAAO,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC;CACjC;AAED,oEAAoE;AACpE,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,OAAO,GAAG,CAAC,GAAG,KAAK,CAAC;AAE3E,MAAM,MAAM,kBAAkB,CAAC,QAAQ,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,kBAAkB,KAAK,IAAI,CAAC;AAE7F,MAAM,MAAM,mBAAmB,CAAC,OAAO,IAAI;KACxC,CAAC,IAAI,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,EAAE,kBAAkB,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;CAC7E,CAAC;AAEF,MAAM,WAAW,iBAAiB,CAAC,OAAO;IACxC,MAAM,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACnC;;;;;OAKG;IACH,WAAW,EAAE,WAAW,GAAG,CAAC,MAAM,WAAW,CAAC,CAAC;IAC/C,QAAQ,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC;IACvC,0FAA0F;IAC1F,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0FAA0F;IAC1F,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,IAAI,IAAI,CAAC;IAChB,UAAU,IAAI,IAAI,CAAC;IACnB;qEACiE;IACjE,SAAS,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC/B,2EAA2E;IAC3E,UAAU,IAAI,IAAI,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,yBAAyB,CAAC,QAAQ,SAAS,qBAAqB,CAC/E,SAAQ,IAAI,CAAC,iBAAiB,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC;IAC1E,MAAM,EAAE,uBAAuB,CAAC,QAAQ,EAAE,qBAAqB,CAAC,CAAC;CAClE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,iBAAiB,CAAC,OAAO,CAAC,GAAG,WAAW,CAsF1F;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,SAAS,qBAAqB,EAC9E,MAAM,EAAE,yBAAyB,CAAC,QAAQ,CAAC,GAC1C,WAAW,CAKb"}
package/dist/react.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { type CacheBridge, type CacheBridgeConfig, type CacheBridgeContext, type CacheBridgeHandler, type CacheBridgeHandlers, type CacheBridgeSocket, createCacheBridge, } from './react/cache-bridge.js';
1
+ export { type CacheBridge, type CacheBridgeConfig, type CacheBridgeContext, type CacheBridgeHandler, type CacheBridgeHandlers, type CacheBridgeSocket, createCacheBridge, createRealtimeCacheBridge, type RealtimeCacheBridgeConfig, } from './react/cache-bridge.js';
2
2
  export { type CursorQueryConfig, createCursorQuery } from './react/cursor-query.js';
3
3
  export { createEntityCacheHandlers, type DeletedPayload, type EntityCacheConfig, type EntityCacheEvent, type EntityCacheHandlers, type EntityCacheKey, type EntityCacheListConfig, type EntityCacheListShape, type EntityCacheMembership, type EntityCacheMembershipPolicy, type EntityCacheTotalDeltaInput, type EntityCacheTotalPolicy, } from './react/entity-cache.js';
4
4
  //# sourceMappingURL=react.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,KAAK,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,EACL,yBAAyB,EACzB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,GAC5B,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,iBAAiB,EACjB,yBAAyB,EACzB,KAAK,yBAAyB,GAC/B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,KAAK,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,EACL,yBAAyB,EACzB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,GAC5B,MAAM,sBAAsB,CAAC"}
package/dist/react.js CHANGED
@@ -78,6 +78,9 @@ function createCacheBridge(config) {
78
78
  clearFresh
79
79
  };
80
80
  }
81
+ function createRealtimeCacheBridge(config) {
82
+ return createCacheBridge(config);
83
+ }
81
84
  // src/react/cursor-query.ts
82
85
  import {
83
86
  createInfiniteQuery
@@ -311,6 +314,7 @@ function idOf(payload, getId) {
311
314
  return hasStringId(payload) ? payload.id : getId(payload);
312
315
  }
313
316
  export {
317
+ createRealtimeCacheBridge,
314
318
  createEntityCacheHandlers,
315
319
  createCursorQuery,
316
320
  createCacheBridge
package/llms-full.txt CHANGED
@@ -7071,6 +7071,26 @@ leaving the handshake waiting forever.
7071
7071
 
7072
7072
  ## Cache bridge
7073
7073
 
7074
+ **Using a validated realtime contract? Use `createRealtimeCacheBridge`.** A
7075
+ realtime registry maps an event name to its *definition* (`{ args, ack }`),
7076
+ while the plain bridge's event map expects the *handler function* at that
7077
+ position. A validated socket satisfies the looser type structurally, so passing
7078
+ one to `createCacheBridge` compiled and inferred every payload as `never` —
7079
+ the error then landed on your own property access rather than on the seam.
7080
+ `createRealtimeCacheBridge` performs the mapping; nothing runs differently.
7081
+
7082
+ ```ts
7083
+ import { createRealtimeCacheBridge } from 'stitchkit/react'
7084
+
7085
+ const bridge = createRealtimeCacheBridge<typeof contract.serverToClient>({
7086
+ socket: realtimeClient,
7087
+ queryClient,
7088
+ handlers: {
7089
+ noteUpdated: (note, { queryClient: qc }) => qc.setQueryData(noteKey(note.id), note),
7090
+ },
7091
+ })
7092
+ ```
7093
+
7074
7094
  `createCacheBridge` syncs socket events into the TanStack Query cache — a server
7075
7095
  push updates the UI with no refetch. It is transport-agnostic: it takes any
7076
7096
  emitter with `on(event, handler) => unsubscribe`, which the
@@ -13764,6 +13784,7 @@ and `react-query-kit` peers.
13764
13784
  |--------|------|---------|
13765
13785
  | `createCursorQuery` | function | a cursor-paginated infinite query — [guide](../guide/client.md#cursor-pagination) |
13766
13786
  | `createCacheBridge` | function | sync socket events into the Query cache — [guide](../guide/realtime.md#cache-bridge) |
13787
+ | `createRealtimeCacheBridge` | function | the same bridge fed by a **validated realtime contract**; the payload comes from the contract's args tuple instead of inferring `never` |
13767
13788
  | `createEntityCacheHandlers` | function | created/updated/deleted cache handlers for one entity — [guide](../guide/realtime.md#entity-cache-handlers) |
13768
13789
  | `EntityCacheConfig` | _type_ | config for `createEntityCacheHandlers` |
13769
13790
  | `EntityCacheMembership` / `EntityCacheMembershipPolicy` | _type_ | per-exact-query `include | exclude | unknown` filter decision and unknown invalidation policy |
@@ -13777,6 +13798,7 @@ and `react-query-kit` peers.
13777
13798
  | `CursorQueryConfig` | _type_ | config for `createCursorQuery` |
13778
13799
  | `CacheBridge` | _type_ | the `createCacheBridge` handle |
13779
13800
  | `CacheBridgeConfig` | _type_ | config for `createCacheBridge` |
13801
+ | `RealtimeCacheBridgeConfig` | _type_ | config for `createRealtimeCacheBridge` — same fields, a `ValidatedRealtimeSocket` in place of the raw socket |
13780
13802
  | `CacheBridgeContext` | _type_ | the `ctx` a bridge handler receives |
13781
13803
  | `CacheBridgeHandler` | _type_ | one event-to-cache handler |
13782
13804
  | `CacheBridgeHandlers` | _type_ | the handler map |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stitchkit",
3
- "version": "0.72.2",
3
+ "version": "0.72.3",
4
4
  "description": "Contract-first backend framework — one defineContract() into an HTTP API, MCP tools, AI-agent tools and a typed client. Bun and Node.",
5
5
  "keywords": [
6
6
  "bun",