@livequery/react 2.0.151 → 2.0.152

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/README.md CHANGED
@@ -20,6 +20,7 @@ npm install @livequery/react @livequery/client react rxjs
20
20
 
21
21
  - `LivequeryClientProvider`
22
22
  - `useLivequeryClient`
23
+ - `useLivequeryContext`
23
24
  - `useCollection`
24
25
  - `useDocument`
25
26
  - `useObservable`
@@ -74,6 +75,18 @@ Use it when:
74
75
 
75
76
  The provider currently expects a `core` prop. Passing `client` will not work unless the implementation is changed.
76
77
 
78
+ ### Provider-level `context`
79
+
80
+ The provider also accepts an optional `context` prop — an arbitrary bag forwarded with every collection operation down to the transporter's `onRequest` hook (see [`@livequery/client` → context](../client/README.md#context)). The canonical use is per-tab multi-account routing: set `{ account_id }` once at the provider and every `useCollection()` below it inherits it.
81
+
82
+ ```tsx
83
+ <LivequeryClientProvider core={client} context={{ account_id: currentAccountId }}>
84
+ <TodoList />
85
+ </LivequeryClientProvider>
86
+ ```
87
+
88
+ Changing the provider `context` (e.g. switching account) re-creates every descendant collection under the new context — old subscriptions tear down and re-subscribe. A per-call `options.context` on `useCollection` overrides the provider one (shallow merge, per-call wins).
89
+
77
90
  ### SharedWorker
78
91
 
79
92
  If your app uses a SharedWorker via `@livequery/rpc`, the setup inside the worker is different — but from React's perspective nothing changes. You still construct a `LivequeryClient` and pass it to `LivequeryClientProvider` exactly as shown above. Read the `@livequery/rpc` documentation for how to expose the client from a SharedWorker; the React layer stays the same.
@@ -95,10 +108,35 @@ export function ClientStatus() {
95
108
 
96
109
  The hook must be used under a matching provider. If it is called outside the provider tree, the generated context hook throws `Context provider is missing`.
97
110
 
111
+ ## `useLivequeryContext`
112
+
113
+ `useLivequeryContext()` reads the optional `context` bag passed to `LivequeryClientProvider`. Returns `undefined` when no `context` prop was provided.
114
+
115
+ ```tsx
116
+ import { useLivequeryContext } from '@livequery/react'
117
+
118
+ export function CurrentAccount() {
119
+ const context = useLivequeryContext()
120
+ return <span>account: {context?.account_id ?? 'none'}</span>
121
+ }
122
+ ```
123
+
124
+ Most code never calls this directly — `useCollection()` already merges this provider context into the collections it creates. Use it only when you need to read the active context for display or branching.
125
+
98
126
  ## `useCollection`
99
127
 
100
128
  `useCollection<T>(ref, options)` creates a `LivequeryCollection<T>` for the current `ref`, initializes it when `ref` is truthy, and returns the collection instance. When `ref` changes, a fresh collection is created — its state is reset and reloaded for the new ref.
101
129
 
130
+ The collection's `context` is the provider `context` shallow-merged with `options.context` (per-call wins). `useCollection` keys the collection on both `ref` **and** the resolved context, so changing either creates a fresh instance — switching account therefore tears down the old subscription and re-subscribes under the new context.
131
+
132
+ ```tsx
133
+ // inherits provider context (e.g. { account_id })
134
+ const todos = useCollection<Todo>('todos', { lazy: false })
135
+
136
+ // override / extend context for this collection only
137
+ const orders = useCollection<Order>('orders', { lazy: false, context: { account_id: otherId } })
138
+ ```
139
+
102
140
  Use it when a component needs the full collection API: reactive state plus methods such as querying or mutations.
103
141
 
104
142
  ```tsx
@@ -1,5 +1,9 @@
1
1
  import type { LivequeryClient } from "@livequery/client";
2
- export declare const useLivequeryClient: () => LivequeryClient, LivequeryClientProvider: (props: import("react").PropsWithChildren<{
2
+ declare const LivequeryClientProvider: (props: import("react").PropsWithChildren<{
3
3
  core: any;
4
+ context?: Record<string, any>;
4
5
  }>) => import("react").JSX.Element;
6
+ export { LivequeryClientProvider };
7
+ export declare const useLivequeryClient: () => LivequeryClient;
8
+ export declare const useLivequeryContext: () => Record<string, any> | undefined;
5
9
  //# sourceMappingURL=LivequeryClientContext.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LivequeryClientContext.d.ts","sourceRoot":"","sources":["../src/LivequeryClientContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGzD,eAAO,MAAO,kBAAkB,yBAAE,uBAAuB;UACrC,GAAG;kCACtB,CAAA"}
1
+ {"version":3,"file":"LivequeryClientContext.d.ts","sourceRoot":"","sources":["../src/LivequeryClientContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAMzD,QAAA,MAAyB,uBAAuB;UAC5B,GAAG;cAAY,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;kCAIrD,CAAA;AAED,OAAO,EAAE,uBAAuB,EAAE,CAAA;AAClC,eAAO,MAAM,kBAAkB,uBAAgC,CAAA;AAC/D,eAAO,MAAM,mBAAmB,uCAAmC,CAAA"}
@@ -1,3 +1,12 @@
1
1
  import { createContextFromHook } from "./createContextFromHook.js";
2
- export const [useLivequeryClient, LivequeryClientProvider] = createContextFromHook((props) => props.core);
2
+ // The provider now carries both the client (`core`) and an optional `context` —
3
+ // an arbitrary bag forwarded with every collection operation down to the
4
+ // transporter's onRequest hook (e.g. { account_id } for per-tab multi-account).
5
+ const [useLivequeryRoot, LivequeryClientProvider] = createContextFromHook((props) => ({
6
+ core: props.core,
7
+ context: props.context
8
+ }));
9
+ export { LivequeryClientProvider };
10
+ export const useLivequeryClient = () => useLivequeryRoot().core;
11
+ export const useLivequeryContext = () => useLivequeryRoot().context;
3
12
  //# sourceMappingURL=LivequeryClientContext.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LivequeryClientContext.js","sourceRoot":"","sources":["../src/LivequeryClientContext.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,MAAM,CAAC,MAAM,CAAC,kBAAkB,EAAE,uBAAuB,CAAC,GAAG,qBAAqB,CAC9E,CAAC,KAAoB,EAAE,EAAE,CAAC,KAAK,CAAC,IAAuB,CAC1D,CAAA"}
1
+ {"version":3,"file":"LivequeryClientContext.js","sourceRoot":"","sources":["../src/LivequeryClientContext.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,gFAAgF;AAChF,yEAAyE;AACzE,gFAAgF;AAChF,MAAM,CAAC,gBAAgB,EAAE,uBAAuB,CAAC,GAAG,qBAAqB,CACrE,CAAC,KAAmD,EAAE,EAAE,CAAC,CAAC;IACtD,IAAI,EAAE,KAAK,CAAC,IAAuB;IACnC,OAAO,EAAE,KAAK,CAAC,OAA0C;CAC5D,CAAC,CACL,CAAA;AAED,OAAO,EAAE,uBAAuB,EAAE,CAAA;AAClC,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,EAAE,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAAA;AAC/D,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,EAAE,CAAC,gBAAgB,EAAE,CAAC,OAAO,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"useCollection.d.ts","sourceRoot":"","sources":["../src/useCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,KAAK,GAAG,EAAE,KAAK,0BAA0B,EAAE,MAAM,mBAAmB,CAAA;AAMlG,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,GAAG,EAAE,KAAK,MAAM,GAAG,SAAS,GAAG,EAAE,GAAG,IAAI,GAAG,KAAK,EAAE,UAAS,OAAO,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAM,2BAe7I,CAAA"}
1
+ {"version":3,"file":"useCollection.d.ts","sourceRoot":"","sources":["../src/useCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,KAAK,GAAG,EAAE,KAAK,0BAA0B,EAAE,MAAM,mBAAmB,CAAA;AAMlG,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,GAAG,EAAE,KAAK,MAAM,GAAG,SAAS,GAAG,EAAE,GAAG,IAAI,GAAG,KAAK,EAAE,UAAS,OAAO,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAM,2BAoB7I,CAAA"}
@@ -1,13 +1,18 @@
1
1
  import { LivequeryCollection } from "@livequery/client";
2
2
  import { useMemo, useEffect } from "react";
3
- import { useLivequeryClient } from "./LivequeryClientContext.js";
3
+ import { useLivequeryClient, useLivequeryContext } from "./LivequeryClientContext.js";
4
4
  export const useCollection = (ref, options = {}) => {
5
5
  const client = useLivequeryClient();
6
- // Recreate the collection whenever the ref changes so each ref gets a fresh, fully-reset
7
- // instance. The client is stable (provided once via context), so it is intentionally NOT a
6
+ // Provider-level context (e.g. { account_id }); a per-call options.context overrides it.
7
+ const providerContext = useLivequeryContext();
8
+ const context = { ...providerContext, ...options.context };
9
+ const contextKey = JSON.stringify(context);
10
+ // Recreate the collection whenever the ref OR the context changes so each (ref, context)
11
+ // pair gets a fresh, fully-reset instance — switching account re-subscribes under the new
12
+ // context. The client is stable (provided once via context), so it is intentionally NOT a
8
13
  // dependency — keying on it would rebuild the collection on every render if a caller ever
9
14
  // passed an unstable client.
10
- const collection = useMemo(() => new LivequeryCollection(client, options), [ref]);
15
+ const collection = useMemo(() => new LivequeryCollection(client, { ...options, context }), [ref, contextKey]);
11
16
  useEffect(() => {
12
17
  if (!client || !ref)
13
18
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"useCollection.js","sourceRoot":"","sources":["../src/useCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAA6C,MAAM,mBAAmB,CAAA;AAClG,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAIhE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAgB,GAA2C,EAAE,UAAkD,EAAE,EAAE,EAAE;IAC9I,MAAM,MAAM,GAAG,kBAAkB,EAAE,CAAA;IACnC,yFAAyF;IACzF,2FAA2F;IAC3F,0FAA0F;IAC1F,6BAA6B;IAC7B,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,mBAAmB,CAAI,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;IACpF,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG;YAAE,OAAM;QAC3B,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;QACzC,OAAO,GAAG,EAAE;YACR,MAAM,EAAE,WAAW,EAAE,CAAA;QACzB,CAAC,CAAA;IACL,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAA;IAChB,OAAO,UAAU,CAAA;AACrB,CAAC,CAAA"}
1
+ {"version":3,"file":"useCollection.js","sourceRoot":"","sources":["../src/useCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAA6C,MAAM,mBAAmB,CAAA;AAClG,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAC1C,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAIrF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAgB,GAA2C,EAAE,UAAkD,EAAE,EAAE,EAAE;IAC9I,MAAM,MAAM,GAAG,kBAAkB,EAAE,CAAA;IACnC,yFAAyF;IACzF,MAAM,eAAe,GAAG,mBAAmB,EAAE,CAAA;IAC7C,MAAM,OAAO,GAAG,EAAE,GAAG,eAAe,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAA;IAC1D,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;IAC1C,yFAAyF;IACzF,0FAA0F;IAC1F,0FAA0F;IAC1F,0FAA0F;IAC1F,6BAA6B;IAC7B,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,mBAAmB,CAAI,MAAM,EAAE,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,CAAA;IAChH,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG;YAAE,OAAM;QAC3B,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;QACzC,OAAO,GAAG,EAAE;YACR,MAAM,EAAE,WAAW,EAAE,CAAA;QACzB,CAAC,CAAA;IACL,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAA;IAChB,OAAO,UAAU,CAAA;AACrB,CAAC,CAAA"}
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "url": "https://github.com/livequery/react"
5
5
  },
6
6
  "type": "module",
7
- "version": "2.0.151",
7
+ "version": "2.0.152",
8
8
  "description": "",
9
9
  "main": "./dist/index.js",
10
10
  "types": "./dist/index.d.ts",
@@ -49,14 +49,14 @@
49
49
  "dist/**/*"
50
50
  ],
51
51
  "devDependencies": {
52
- "@livequery/client": "^2.0.151",
52
+ "@livequery/client": "^2.0.152",
53
53
  "@types/bun": "^1.3.14",
54
54
  "@types/react": "^19.2.14",
55
55
  "@types/react-test-renderer": "^19.1.0",
56
56
  "react-test-renderer": "^19.2.6"
57
57
  },
58
58
  "peerDependencies": {
59
- "@livequery/client": "^2.0.151",
59
+ "@livequery/client": "^2.0.152",
60
60
  "react": "^19.2.5",
61
61
  "rxjs": "^7.8.2"
62
62
  },