@objectstack/client-react 17.0.0-rc.1 → 17.0.0-rc.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.
- package/CHANGELOG.md +232 -0
- package/dist/index.d.mts +72 -2
- package/dist/index.d.ts +72 -2
- package/dist/index.js +162 -84
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +134 -58
- package/dist/index.mjs.map +1 -1
- package/package.json +14 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,237 @@
|
|
|
1
1
|
# @objectstack/client-react
|
|
2
2
|
|
|
3
|
+
## 17.0.0-rc.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [2e284b2]
|
|
8
|
+
- @objectstack/spec@17.0.0-rc.3
|
|
9
|
+
- @objectstack/client@17.0.0-rc.3
|
|
10
|
+
- @objectstack/core@17.0.0-rc.3
|
|
11
|
+
|
|
12
|
+
## 17.0.0-rc.2
|
|
13
|
+
|
|
14
|
+
### Minor Changes
|
|
15
|
+
|
|
16
|
+
- 0884452: feat(client-react): bulk-write hooks, and `useAutoRefresh` now refreshes on predicate writes (#4678)
|
|
17
|
+
|
|
18
|
+
#4639 gave predicate writes (`multi: true` update/delete) their own event
|
|
19
|
+
contract — `data.records.updated` / `data.records.deleted`, carrying a
|
|
20
|
+
`matched` count and no record — and `@objectstack/client` exposes them via
|
|
21
|
+
`subscribeBulkData`. The React hooks never caught up: all three realtime data
|
|
22
|
+
hooks delegated to `subscribeData`, so React consumers could not see bulk
|
|
23
|
+
writes at all.
|
|
24
|
+
|
|
25
|
+
The sharpest edge was **`useAutoRefresh`**. Its whole job is "refetch when the
|
|
26
|
+
data changes", and a predicate write is the case that dirties a list hardest —
|
|
27
|
+
one statement can change or delete every row on screen. It sat still for those
|
|
28
|
+
while refetching dutifully for a single-row edit.
|
|
29
|
+
|
|
30
|
+
- **New `useBulkDataSubscription(object)`** returning the latest
|
|
31
|
+
`BulkDataEvent`, and **`useBulkDataSubscriptionCallback(object, cb)`** for
|
|
32
|
+
the refetch/side-effect case.
|
|
33
|
+
- **`useAutoRefresh` now watches both streams.** Safe here in a way it is not
|
|
34
|
+
for `useDataSubscription`: this hook's output is a refetch signal, not an
|
|
35
|
+
event body, so the shape difference that keeps the two contracts apart never
|
|
36
|
+
reaches the caller. When `options.recordId` narrows it to one record it still
|
|
37
|
+
refetches on a bulk event — a count cannot say whether that record was in the
|
|
38
|
+
match set, and a redundant query beats showing a row a predicate write
|
|
39
|
+
already changed.
|
|
40
|
+
- **`useDataSubscription` / `useDataSubscriptionCallback` are unchanged** and
|
|
41
|
+
still per-record only. Their callbacks are typed `(event: DataEvent) => void`;
|
|
42
|
+
letting a `BulkDataEvent` through would hand them an object whose `recordId`
|
|
43
|
+
and record body are `undefined` — the defect #4626 removed.
|
|
44
|
+
|
|
45
|
+
### Patch Changes
|
|
46
|
+
|
|
47
|
+
- 21855f8: fix(client-react): stop five hooks from looping on dependency identity (#4693, #4694)
|
|
48
|
+
|
|
49
|
+
Five hooks keyed a `useCallback`/`useEffect` on values the caller supplies
|
|
50
|
+
inline — `where` / `fields` / `orderBy` objects, `onSuccess` / `onError`
|
|
51
|
+
handlers, and the `fetcher` `useMetadata` takes as a required positional
|
|
52
|
+
argument. Inline means a fresh identity on every render, so the effect re-ran on
|
|
53
|
+
every render; because the fetch hooks call `setState`, that render caused
|
|
54
|
+
another. The result was an unbounded request loop under the hooks' own
|
|
55
|
+
documented usage.
|
|
56
|
+
|
|
57
|
+
Requests issued in 250ms by a single mounted component, measured before and
|
|
58
|
+
after:
|
|
59
|
+
|
|
60
|
+
| hook | before | after |
|
|
61
|
+
| ----------------------------------- | -----: | ----: |
|
|
62
|
+
| `useQuery` (inline `where`) | 4691 | 1 |
|
|
63
|
+
| `useInfiniteQuery` (inline `where`) | 6611 | 1 |
|
|
64
|
+
| `useObject` (no options at all) | 4306 | 1 |
|
|
65
|
+
| `useView` (inline `onSuccess`) | 8197 | 1 |
|
|
66
|
+
| `useMetadata` (inline `fetcher`) | 7654 | 1 |
|
|
67
|
+
|
|
68
|
+
`useObject` and `useMetadata` needed no particular usage to loop: the former
|
|
69
|
+
depended on its own `data` and `etag` state while writing both, and the latter
|
|
70
|
+
takes its fetcher positionally, so there is no non-inline way to call it.
|
|
71
|
+
`useMutation` was never affected — no effect drives it.
|
|
72
|
+
|
|
73
|
+
The same root cause churned the realtime subscriptions (#4694):
|
|
74
|
+
`useAutoRefresh` with an unmemoized `refetch` — which is what `useQuery`
|
|
75
|
+
returned on every render — resubscribed on both streams every render, losing any
|
|
76
|
+
event delivered in the unsubscribe/resubscribe gap.
|
|
77
|
+
|
|
78
|
+
Two internal primitives fix both halves: `stableKey` derives a dependency from a
|
|
79
|
+
structural value (sorted keys, array order preserved) so a rebuilt-but-equal
|
|
80
|
+
object is a no-op, and `useEventCallback` gives a handler a fixed identity while
|
|
81
|
+
always invoking its latest version. Neither is exported.
|
|
82
|
+
|
|
83
|
+
A changed _value_ still refetches, and every stabilized handler is asserted to
|
|
84
|
+
run its newest version rather than the one captured when the effect first ran —
|
|
85
|
+
the ref indirection would otherwise trade a loop for a stale closure. 13 tests
|
|
86
|
+
cover this, each verified by reverting the fix it guards.
|
|
87
|
+
|
|
88
|
+
- bbb1192: test(client-react): give the package a test harness and pin the realtime hooks' behavior (#4682)
|
|
89
|
+
|
|
90
|
+
`packages/client-react` shipped 8 public hooks with `build` and `typecheck` as
|
|
91
|
+
its only scripts and not a single test file. `tsc --noEmit` cannot see any of
|
|
92
|
+
what actually breaks in a hook: a dependency array is a value, not a type, so a
|
|
93
|
+
missing entry, a missing cleanup, and a callback that never fires all typecheck
|
|
94
|
+
perfectly. #4678 was precisely that shape — `useAutoRefresh` ignored predicate
|
|
95
|
+
writes, the one case that dirties a list hardest, and no type noticed.
|
|
96
|
+
|
|
97
|
+
Adds the workspace's first DOM test environment (`jsdom` + `@testing-library/
|
|
98
|
+
react`, `environment: 'jsdom'` — every other package runs `node`) and 17 tests
|
|
99
|
+
over the realtime hooks, covering the three things the type checker is blind to:
|
|
100
|
+
|
|
101
|
+
- **Re-subscription on dependency change** — changing `object` opens a
|
|
102
|
+
subscription on the new name and releases the old one; a re-render that
|
|
103
|
+
changes nothing must not churn. Also pins that the hooks key on the primitive
|
|
104
|
+
`options?.recordId` / `options?.packageId` rather than on the options object's
|
|
105
|
+
identity, so an equal-but-new object stays a no-op.
|
|
106
|
+
- **Release on unmount** — every subscription hook unsubscribes, including
|
|
107
|
+
`useAutoRefresh`, which holds two.
|
|
108
|
+
- **Delivery** — events reach state and callbacks, and `useAutoRefresh`
|
|
109
|
+
refetches on the per-record _and_ the bulk stream (the #4678 regression pin).
|
|
110
|
+
|
|
111
|
+
Each assertion was verified by sabotage: dropping the `object` dep, deleting a
|
|
112
|
+
cleanup, and reverting `useAutoRefresh` to the single-stream version each turn
|
|
113
|
+
the suite red, and only reverting turns it green again.
|
|
114
|
+
|
|
115
|
+
The package is picked up by CI's `Test Core` shards automatically — they
|
|
116
|
+
partition by package off `turbo ls`, so a `test` script is all that was needed.
|
|
117
|
+
|
|
118
|
+
No runtime code changed.
|
|
119
|
+
|
|
120
|
+
- Updated dependencies [430dcc2]
|
|
121
|
+
- Updated dependencies [e6ac4bd]
|
|
122
|
+
- Updated dependencies [80334c7]
|
|
123
|
+
- Updated dependencies [ce5242c]
|
|
124
|
+
- Updated dependencies [a7163ea]
|
|
125
|
+
- Updated dependencies [e6e9379]
|
|
126
|
+
- Updated dependencies [98877c9]
|
|
127
|
+
- Updated dependencies [98877c9]
|
|
128
|
+
- Updated dependencies [e6b1b69]
|
|
129
|
+
- Updated dependencies [ad047d2]
|
|
130
|
+
- Updated dependencies [2826d1e]
|
|
131
|
+
- Updated dependencies [5a84d41]
|
|
132
|
+
- Updated dependencies [20b1a9e]
|
|
133
|
+
- Updated dependencies [203a449]
|
|
134
|
+
- Updated dependencies [ac37fc6]
|
|
135
|
+
- Updated dependencies [4820f55]
|
|
136
|
+
- Updated dependencies [462d9c4]
|
|
137
|
+
- Updated dependencies [7d21581]
|
|
138
|
+
- Updated dependencies [f2445c9]
|
|
139
|
+
- Updated dependencies [23338c3]
|
|
140
|
+
- Updated dependencies [84b4a3a]
|
|
141
|
+
- Updated dependencies [5b843fb]
|
|
142
|
+
- Updated dependencies [b4487aa]
|
|
143
|
+
- Updated dependencies [65ca83a]
|
|
144
|
+
- Updated dependencies [67bf2e2]
|
|
145
|
+
- Updated dependencies [c6d1cb4]
|
|
146
|
+
- Updated dependencies [462b713]
|
|
147
|
+
- Updated dependencies [36030ff]
|
|
148
|
+
- Updated dependencies [6117f7b]
|
|
149
|
+
- Updated dependencies [e533b0b]
|
|
150
|
+
- Updated dependencies [cdf4d9a]
|
|
151
|
+
- Updated dependencies [aee1806]
|
|
152
|
+
- Updated dependencies [c13350b]
|
|
153
|
+
- Updated dependencies [c13350b]
|
|
154
|
+
- Updated dependencies [9ca2d85]
|
|
155
|
+
- Updated dependencies [c13350b]
|
|
156
|
+
- Updated dependencies [891d345]
|
|
157
|
+
- Updated dependencies [a52e2ef]
|
|
158
|
+
- Updated dependencies [5293114]
|
|
159
|
+
- Updated dependencies [20bc357]
|
|
160
|
+
- Updated dependencies [5966c2a]
|
|
161
|
+
- Updated dependencies [2382580]
|
|
162
|
+
- Updated dependencies [d9fa683]
|
|
163
|
+
- Updated dependencies [3c7bcc0]
|
|
164
|
+
- Updated dependencies [4b6cac7]
|
|
165
|
+
- Updated dependencies [7631964]
|
|
166
|
+
- Updated dependencies [ac471a0]
|
|
167
|
+
- Updated dependencies [60ae58e]
|
|
168
|
+
- Updated dependencies [ce92674]
|
|
169
|
+
- Updated dependencies [9f601e8]
|
|
170
|
+
- Updated dependencies [51c5227]
|
|
171
|
+
- Updated dependencies [a4a85c8]
|
|
172
|
+
- Updated dependencies [07a4e26]
|
|
173
|
+
- Updated dependencies [ec975f1]
|
|
174
|
+
- Updated dependencies [eb4204b]
|
|
175
|
+
- Updated dependencies [4f13be2]
|
|
176
|
+
- Updated dependencies [61cc079]
|
|
177
|
+
- Updated dependencies [0e96e46]
|
|
178
|
+
- Updated dependencies [d52d4fe]
|
|
179
|
+
- Updated dependencies [742cebb]
|
|
180
|
+
- Updated dependencies [ce92674]
|
|
181
|
+
- Updated dependencies [cf2c9b7]
|
|
182
|
+
- Updated dependencies [833b512]
|
|
183
|
+
- Updated dependencies [0f9faa2]
|
|
184
|
+
- Updated dependencies [7cf42fe]
|
|
185
|
+
- Updated dependencies [5966c2a]
|
|
186
|
+
- Updated dependencies [8aacf94]
|
|
187
|
+
- Updated dependencies [f78dd83]
|
|
188
|
+
- Updated dependencies [a2cd18a]
|
|
189
|
+
- Updated dependencies [4638aaa]
|
|
190
|
+
- Updated dependencies [0222d3c]
|
|
191
|
+
- Updated dependencies [071d0dc]
|
|
192
|
+
- Updated dependencies [0a936ea]
|
|
193
|
+
- Updated dependencies [023c00b]
|
|
194
|
+
- Updated dependencies [155507e]
|
|
195
|
+
- Updated dependencies [7bba90b]
|
|
196
|
+
- Updated dependencies [7e05d8e]
|
|
197
|
+
- Updated dependencies [061406d]
|
|
198
|
+
- Updated dependencies [c1f344b]
|
|
199
|
+
- Updated dependencies [9c93465]
|
|
200
|
+
- Updated dependencies [ebb209c]
|
|
201
|
+
- Updated dependencies [63b33e6]
|
|
202
|
+
- Updated dependencies [2a44c1d]
|
|
203
|
+
- Updated dependencies [695cfbd]
|
|
204
|
+
- Updated dependencies [7445149]
|
|
205
|
+
- Updated dependencies [071d0dc]
|
|
206
|
+
- Updated dependencies [0848bea]
|
|
207
|
+
- Updated dependencies [d51bed2]
|
|
208
|
+
- Updated dependencies [b8b3c64]
|
|
209
|
+
- Updated dependencies [0c0fbd9]
|
|
210
|
+
- Updated dependencies [f3141d8]
|
|
211
|
+
- Updated dependencies [5a84d41]
|
|
212
|
+
- Updated dependencies [fd3013a]
|
|
213
|
+
- Updated dependencies [21676eb]
|
|
214
|
+
- Updated dependencies [e336549]
|
|
215
|
+
- Updated dependencies [d40f43a]
|
|
216
|
+
- Updated dependencies [e5e7ee0]
|
|
217
|
+
- Updated dependencies [a2ebea2]
|
|
218
|
+
- Updated dependencies [800bdb0]
|
|
219
|
+
- Updated dependencies [04f1182]
|
|
220
|
+
- Updated dependencies [5647006]
|
|
221
|
+
- Updated dependencies [38f7e4f]
|
|
222
|
+
- Updated dependencies [c57f3cf]
|
|
223
|
+
- Updated dependencies [97faca3]
|
|
224
|
+
- Updated dependencies [ad5fe25]
|
|
225
|
+
- Updated dependencies [ea90179]
|
|
226
|
+
- Updated dependencies [ce92674]
|
|
227
|
+
- Updated dependencies [5ef0b5b]
|
|
228
|
+
- Updated dependencies [48fbacb]
|
|
229
|
+
- Updated dependencies [355e951]
|
|
230
|
+
- Updated dependencies [dadb43f]
|
|
231
|
+
- @objectstack/spec@17.0.0-rc.2
|
|
232
|
+
- @objectstack/core@17.0.0-rc.2
|
|
233
|
+
- @objectstack/client@17.0.0-rc.2
|
|
234
|
+
|
|
3
235
|
## 17.0.0-rc.1
|
|
4
236
|
|
|
5
237
|
### Patch Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -3,7 +3,7 @@ import { ReactNode } from 'react';
|
|
|
3
3
|
import { ObjectStackClient, PaginatedResult } from '@objectstack/client';
|
|
4
4
|
export { ClientConfig, ObjectStackClient } from '@objectstack/client';
|
|
5
5
|
import { QueryAST, FilterCondition } from '@objectstack/spec/data';
|
|
6
|
-
import { DataEvent, MetadataEvent } from '@objectstack/spec/api';
|
|
6
|
+
import { BulkDataEvent, DataEvent, MetadataEvent } from '@objectstack/spec/api';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* ObjectStack React Context
|
|
@@ -527,6 +527,64 @@ declare function useMetadataSubscriptionCallback(type: string, callback: (event:
|
|
|
527
527
|
declare function useDataSubscriptionCallback(object: string, callback: (event: DataEvent) => void, options?: {
|
|
528
528
|
recordId?: string;
|
|
529
529
|
}): void;
|
|
530
|
+
/**
|
|
531
|
+
* Hook to subscribe to bulk (predicate-write) data events
|
|
532
|
+
*
|
|
533
|
+
* A `multi: true` update/delete reaches the driver's `updateMany`/`deleteMany`,
|
|
534
|
+
* which report an affected COUNT and name no rows — so it publishes
|
|
535
|
+
* `data.records.updated` / `data.records.deleted` rather than the per-record
|
|
536
|
+
* events {@link useDataSubscription} delivers (#4639).
|
|
537
|
+
*
|
|
538
|
+
* The event carries `object` and `matched` — there is no `recordId` and no
|
|
539
|
+
* record body, which is why this is a separate hook rather than more types
|
|
540
|
+
* flowing through `useDataSubscription`: a `DataEvent` callback receiving one
|
|
541
|
+
* of these would read `undefined` for every field it expects.
|
|
542
|
+
*
|
|
543
|
+
* Use it to invalidate a list, show "40 records changed", or trigger a
|
|
544
|
+
* refetch — not to patch a per-record cache, which a count cannot drive.
|
|
545
|
+
*
|
|
546
|
+
* @param object - Object name to subscribe to
|
|
547
|
+
* @returns Latest bulk data event or null
|
|
548
|
+
*
|
|
549
|
+
* @example
|
|
550
|
+
* ```tsx
|
|
551
|
+
* function TaskList() {
|
|
552
|
+
* const bulk = useBulkDataSubscription('project_task');
|
|
553
|
+
*
|
|
554
|
+
* useEffect(() => {
|
|
555
|
+
* if (bulk) {
|
|
556
|
+
* console.log(`${bulk.matched} tasks changed in one write`);
|
|
557
|
+
* }
|
|
558
|
+
* }, [bulk]);
|
|
559
|
+
*
|
|
560
|
+
* return <div>...</div>;
|
|
561
|
+
* }
|
|
562
|
+
* ```
|
|
563
|
+
*/
|
|
564
|
+
declare function useBulkDataSubscription(object: string): BulkDataEvent | null;
|
|
565
|
+
/**
|
|
566
|
+
* Hook to subscribe to bulk data events with a callback
|
|
567
|
+
*
|
|
568
|
+
* The callback variant of {@link useBulkDataSubscription} — no state, no
|
|
569
|
+
* re-render, for triggering refetches and side effects.
|
|
570
|
+
*
|
|
571
|
+
* @param object - Object name to subscribe to
|
|
572
|
+
* @param callback - Callback to invoke on events
|
|
573
|
+
*
|
|
574
|
+
* @example
|
|
575
|
+
* ```tsx
|
|
576
|
+
* function TaskList() {
|
|
577
|
+
* const { refetch } = useQuery(...);
|
|
578
|
+
*
|
|
579
|
+
* useBulkDataSubscriptionCallback('project_task', () => {
|
|
580
|
+
* refetch(); // a predicate write touched an unknown set of rows
|
|
581
|
+
* });
|
|
582
|
+
*
|
|
583
|
+
* return <div>...</div>;
|
|
584
|
+
* }
|
|
585
|
+
* ```
|
|
586
|
+
*/
|
|
587
|
+
declare function useBulkDataSubscriptionCallback(object: string, callback: (event: BulkDataEvent) => void): void;
|
|
530
588
|
/**
|
|
531
589
|
* Hook to get connection status of realtime events
|
|
532
590
|
*
|
|
@@ -551,6 +609,18 @@ declare function useRealtimeConnection(): boolean;
|
|
|
551
609
|
*
|
|
552
610
|
* Combines data subscription with query refetch.
|
|
553
611
|
*
|
|
612
|
+
* Watches BOTH event streams (#4678): per-record `data.record.*` writes and
|
|
613
|
+
* the aggregate `data.records.*` a predicate (`multi: true`) write publishes.
|
|
614
|
+
* A bulk write is the case that dirties a list hardest — one statement can
|
|
615
|
+
* change or delete every row on screen — so a refresh hook that ignored it
|
|
616
|
+
* would sit still exactly when it matters most, while still refreshing for a
|
|
617
|
+
* single-row edit.
|
|
618
|
+
*
|
|
619
|
+
* Mixing the two streams is safe here in a way it is not for
|
|
620
|
+
* {@link useDataSubscription}: this hook's output is a refetch signal, not an
|
|
621
|
+
* event body, so the shape difference that keeps the two contracts apart
|
|
622
|
+
* (no `recordId`, no record) never reaches the caller.
|
|
623
|
+
*
|
|
554
624
|
* @param object - Object name to watch
|
|
555
625
|
* @param refetch - Refetch function from useQuery
|
|
556
626
|
* @param options - Optional filters
|
|
@@ -570,4 +640,4 @@ declare function useAutoRefresh(object: string, refetch: () => void, options?: {
|
|
|
570
640
|
recordId?: string;
|
|
571
641
|
}): void;
|
|
572
642
|
|
|
573
|
-
export { ObjectStackContext, ObjectStackLocaleContext, ObjectStackProvider, type ObjectStackProviderProps, type UseInfiniteQueryOptions, type UseInfiniteQueryResult, type UseMetadataOptions, type UseMetadataResult, type UseMutationOptions, type UseMutationResult, type UsePaginationOptions, type UsePaginationResult, type UseQueryOptions, type UseQueryResult, useAutoRefresh, useClient, useDataSubscription, useDataSubscriptionCallback, useFields, useInfiniteQuery, useMetadata, useMetadataSubscription, useMetadataSubscriptionCallback, useMutation, useObject, useObjectStackLocale, usePagination, useQuery, useRealtimeConnection, useView };
|
|
643
|
+
export { ObjectStackContext, ObjectStackLocaleContext, ObjectStackProvider, type ObjectStackProviderProps, type UseInfiniteQueryOptions, type UseInfiniteQueryResult, type UseMetadataOptions, type UseMetadataResult, type UseMutationOptions, type UseMutationResult, type UsePaginationOptions, type UsePaginationResult, type UseQueryOptions, type UseQueryResult, useAutoRefresh, useBulkDataSubscription, useBulkDataSubscriptionCallback, useClient, useDataSubscription, useDataSubscriptionCallback, useFields, useInfiniteQuery, useMetadata, useMetadataSubscription, useMetadataSubscriptionCallback, useMutation, useObject, useObjectStackLocale, usePagination, useQuery, useRealtimeConnection, useView };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { ReactNode } from 'react';
|
|
|
3
3
|
import { ObjectStackClient, PaginatedResult } from '@objectstack/client';
|
|
4
4
|
export { ClientConfig, ObjectStackClient } from '@objectstack/client';
|
|
5
5
|
import { QueryAST, FilterCondition } from '@objectstack/spec/data';
|
|
6
|
-
import { DataEvent, MetadataEvent } from '@objectstack/spec/api';
|
|
6
|
+
import { BulkDataEvent, DataEvent, MetadataEvent } from '@objectstack/spec/api';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* ObjectStack React Context
|
|
@@ -527,6 +527,64 @@ declare function useMetadataSubscriptionCallback(type: string, callback: (event:
|
|
|
527
527
|
declare function useDataSubscriptionCallback(object: string, callback: (event: DataEvent) => void, options?: {
|
|
528
528
|
recordId?: string;
|
|
529
529
|
}): void;
|
|
530
|
+
/**
|
|
531
|
+
* Hook to subscribe to bulk (predicate-write) data events
|
|
532
|
+
*
|
|
533
|
+
* A `multi: true` update/delete reaches the driver's `updateMany`/`deleteMany`,
|
|
534
|
+
* which report an affected COUNT and name no rows — so it publishes
|
|
535
|
+
* `data.records.updated` / `data.records.deleted` rather than the per-record
|
|
536
|
+
* events {@link useDataSubscription} delivers (#4639).
|
|
537
|
+
*
|
|
538
|
+
* The event carries `object` and `matched` — there is no `recordId` and no
|
|
539
|
+
* record body, which is why this is a separate hook rather than more types
|
|
540
|
+
* flowing through `useDataSubscription`: a `DataEvent` callback receiving one
|
|
541
|
+
* of these would read `undefined` for every field it expects.
|
|
542
|
+
*
|
|
543
|
+
* Use it to invalidate a list, show "40 records changed", or trigger a
|
|
544
|
+
* refetch — not to patch a per-record cache, which a count cannot drive.
|
|
545
|
+
*
|
|
546
|
+
* @param object - Object name to subscribe to
|
|
547
|
+
* @returns Latest bulk data event or null
|
|
548
|
+
*
|
|
549
|
+
* @example
|
|
550
|
+
* ```tsx
|
|
551
|
+
* function TaskList() {
|
|
552
|
+
* const bulk = useBulkDataSubscription('project_task');
|
|
553
|
+
*
|
|
554
|
+
* useEffect(() => {
|
|
555
|
+
* if (bulk) {
|
|
556
|
+
* console.log(`${bulk.matched} tasks changed in one write`);
|
|
557
|
+
* }
|
|
558
|
+
* }, [bulk]);
|
|
559
|
+
*
|
|
560
|
+
* return <div>...</div>;
|
|
561
|
+
* }
|
|
562
|
+
* ```
|
|
563
|
+
*/
|
|
564
|
+
declare function useBulkDataSubscription(object: string): BulkDataEvent | null;
|
|
565
|
+
/**
|
|
566
|
+
* Hook to subscribe to bulk data events with a callback
|
|
567
|
+
*
|
|
568
|
+
* The callback variant of {@link useBulkDataSubscription} — no state, no
|
|
569
|
+
* re-render, for triggering refetches and side effects.
|
|
570
|
+
*
|
|
571
|
+
* @param object - Object name to subscribe to
|
|
572
|
+
* @param callback - Callback to invoke on events
|
|
573
|
+
*
|
|
574
|
+
* @example
|
|
575
|
+
* ```tsx
|
|
576
|
+
* function TaskList() {
|
|
577
|
+
* const { refetch } = useQuery(...);
|
|
578
|
+
*
|
|
579
|
+
* useBulkDataSubscriptionCallback('project_task', () => {
|
|
580
|
+
* refetch(); // a predicate write touched an unknown set of rows
|
|
581
|
+
* });
|
|
582
|
+
*
|
|
583
|
+
* return <div>...</div>;
|
|
584
|
+
* }
|
|
585
|
+
* ```
|
|
586
|
+
*/
|
|
587
|
+
declare function useBulkDataSubscriptionCallback(object: string, callback: (event: BulkDataEvent) => void): void;
|
|
530
588
|
/**
|
|
531
589
|
* Hook to get connection status of realtime events
|
|
532
590
|
*
|
|
@@ -551,6 +609,18 @@ declare function useRealtimeConnection(): boolean;
|
|
|
551
609
|
*
|
|
552
610
|
* Combines data subscription with query refetch.
|
|
553
611
|
*
|
|
612
|
+
* Watches BOTH event streams (#4678): per-record `data.record.*` writes and
|
|
613
|
+
* the aggregate `data.records.*` a predicate (`multi: true`) write publishes.
|
|
614
|
+
* A bulk write is the case that dirties a list hardest — one statement can
|
|
615
|
+
* change or delete every row on screen — so a refresh hook that ignored it
|
|
616
|
+
* would sit still exactly when it matters most, while still refreshing for a
|
|
617
|
+
* single-row edit.
|
|
618
|
+
*
|
|
619
|
+
* Mixing the two streams is safe here in a way it is not for
|
|
620
|
+
* {@link useDataSubscription}: this hook's output is a refetch signal, not an
|
|
621
|
+
* event body, so the shape difference that keeps the two contracts apart
|
|
622
|
+
* (no `recordId`, no record) never reaches the caller.
|
|
623
|
+
*
|
|
554
624
|
* @param object - Object name to watch
|
|
555
625
|
* @param refetch - Refetch function from useQuery
|
|
556
626
|
* @param options - Optional filters
|
|
@@ -570,4 +640,4 @@ declare function useAutoRefresh(object: string, refetch: () => void, options?: {
|
|
|
570
640
|
recordId?: string;
|
|
571
641
|
}): void;
|
|
572
642
|
|
|
573
|
-
export { ObjectStackContext, ObjectStackLocaleContext, ObjectStackProvider, type ObjectStackProviderProps, type UseInfiniteQueryOptions, type UseInfiniteQueryResult, type UseMetadataOptions, type UseMetadataResult, type UseMutationOptions, type UseMutationResult, type UsePaginationOptions, type UsePaginationResult, type UseQueryOptions, type UseQueryResult, useAutoRefresh, useClient, useDataSubscription, useDataSubscriptionCallback, useFields, useInfiniteQuery, useMetadata, useMetadataSubscription, useMetadataSubscriptionCallback, useMutation, useObject, useObjectStackLocale, usePagination, useQuery, useRealtimeConnection, useView };
|
|
643
|
+
export { ObjectStackContext, ObjectStackLocaleContext, ObjectStackProvider, type ObjectStackProviderProps, type UseInfiniteQueryOptions, type UseInfiniteQueryResult, type UseMetadataOptions, type UseMetadataResult, type UseMutationOptions, type UseMutationResult, type UsePaginationOptions, type UsePaginationResult, type UseQueryOptions, type UseQueryResult, useAutoRefresh, useBulkDataSubscription, useBulkDataSubscriptionCallback, useClient, useDataSubscription, useDataSubscriptionCallback, useFields, useInfiniteQuery, useMetadata, useMetadataSubscription, useMetadataSubscriptionCallback, useMutation, useObject, useObjectStackLocale, usePagination, useQuery, useRealtimeConnection, useView };
|