@linkedrecords/react 0.6.0 → 0.7.0

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/dist/index.d.mts CHANGED
@@ -26,18 +26,23 @@ interface LinkedRecordsProviderProps {
26
26
  }
27
27
  declare function LinkedRecordsProvider({ children, serverUrl, config }: LinkedRecordsProviderProps): react_jsx_runtime.JSX.Element;
28
28
 
29
- interface KVValue {
30
- [key: string]: KVValue | string | boolean | number | Date | undefined;
31
- }
32
- interface KVRecord extends KVValue {
29
+ type JSONValue = string | number | boolean | null | JSONValue[] | {
30
+ [key: string]: JSONValue;
31
+ };
32
+ type KVValue = {
33
+ [key: string]: JSONValue | undefined;
34
+ };
35
+ type KVRecord<T extends object = KVValue> = T & {
33
36
  _id?: string;
34
37
  _createdAt?: Date;
35
- }
36
- declare function useKeyValueRecordsWithStatus(query: any[]): {
37
- records: KVRecord[];
38
+ };
39
+ type CompoundRecordQuery = Parameters<LinkedRecords['Record']['subscribeToQuery']>[0];
40
+ type RecordQueryClause = Exclude<CompoundRecordQuery[string], string>[number];
41
+ declare function useKeyValueRecordsWithStatus<T extends object = KVValue>(query: RecordQueryClause[]): {
42
+ records: KVRecord<T>[];
38
43
  isLoading: boolean;
39
44
  };
40
- declare function useKeyValueRecords(query: any[]): KVRecord[];
45
+ declare function useKeyValueRecords<T extends object = KVValue>(query: RecordQueryClause[]): KVRecord<T>[];
41
46
  /** @deprecated Use useKeyValueRecords instead. */
42
47
  declare const useKeyValueAttributes: typeof useKeyValueRecords;
43
48
 
@@ -57,4 +62,4 @@ declare function useUserInfo(): UserInfo | null;
57
62
 
58
63
  declare function useActorId(): string | undefined;
59
64
 
60
- export { type KVRecord, type LinkedRecordsConfig, LinkedRecordsContext, type LinkedRecordsContextType, LinkedRecordsProvider, useActorId, useFacts, useKeyValueAttributes, useKeyValueRecords, useKeyValueRecordsWithStatus, useLinkedRecords, useUserInfo };
65
+ export { type KVRecord, type LinkedRecordsConfig, LinkedRecordsContext, type LinkedRecordsContextType, LinkedRecordsProvider, type RecordQueryClause, useActorId, useFacts, useKeyValueAttributes, useKeyValueRecords, useKeyValueRecordsWithStatus, useLinkedRecords, useUserInfo };
package/dist/index.d.ts CHANGED
@@ -26,18 +26,23 @@ interface LinkedRecordsProviderProps {
26
26
  }
27
27
  declare function LinkedRecordsProvider({ children, serverUrl, config }: LinkedRecordsProviderProps): react_jsx_runtime.JSX.Element;
28
28
 
29
- interface KVValue {
30
- [key: string]: KVValue | string | boolean | number | Date | undefined;
31
- }
32
- interface KVRecord extends KVValue {
29
+ type JSONValue = string | number | boolean | null | JSONValue[] | {
30
+ [key: string]: JSONValue;
31
+ };
32
+ type KVValue = {
33
+ [key: string]: JSONValue | undefined;
34
+ };
35
+ type KVRecord<T extends object = KVValue> = T & {
33
36
  _id?: string;
34
37
  _createdAt?: Date;
35
- }
36
- declare function useKeyValueRecordsWithStatus(query: any[]): {
37
- records: KVRecord[];
38
+ };
39
+ type CompoundRecordQuery = Parameters<LinkedRecords['Record']['subscribeToQuery']>[0];
40
+ type RecordQueryClause = Exclude<CompoundRecordQuery[string], string>[number];
41
+ declare function useKeyValueRecordsWithStatus<T extends object = KVValue>(query: RecordQueryClause[]): {
42
+ records: KVRecord<T>[];
38
43
  isLoading: boolean;
39
44
  };
40
- declare function useKeyValueRecords(query: any[]): KVRecord[];
45
+ declare function useKeyValueRecords<T extends object = KVValue>(query: RecordQueryClause[]): KVRecord<T>[];
41
46
  /** @deprecated Use useKeyValueRecords instead. */
42
47
  declare const useKeyValueAttributes: typeof useKeyValueRecords;
43
48
 
@@ -57,4 +62,4 @@ declare function useUserInfo(): UserInfo | null;
57
62
 
58
63
  declare function useActorId(): string | undefined;
59
64
 
60
- export { type KVRecord, type LinkedRecordsConfig, LinkedRecordsContext, type LinkedRecordsContextType, LinkedRecordsProvider, useActorId, useFacts, useKeyValueAttributes, useKeyValueRecords, useKeyValueRecordsWithStatus, useLinkedRecords, useUserInfo };
65
+ export { type KVRecord, type LinkedRecordsConfig, LinkedRecordsContext, type LinkedRecordsContextType, LinkedRecordsProvider, type RecordQueryClause, useActorId, useFacts, useKeyValueAttributes, useKeyValueRecords, useKeyValueRecordsWithStatus, useLinkedRecords, useUserInfo };
package/dist/index.js CHANGED
@@ -66,11 +66,13 @@ function createClient(serverUrl, config) {
66
66
  }
67
67
  function LinkedRecordsProvider({ children, serverUrl, config }) {
68
68
  const [lr] = (0, import_react2.useState)(() => config ? createClient(serverUrl, config) : import_browser.default.getPublicClient(serverUrl));
69
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LinkedRecordsContext.Provider, { value: { lr }, children });
69
+ const value = (0, import_react2.useMemo)(() => ({ lr }), [lr]);
70
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LinkedRecordsContext.Provider, { value, children });
70
71
  }
71
72
 
72
73
  // src/useRecords.ts
73
74
  var import_react4 = require("react");
75
+ var import_browser2 = require("@linkedrecords/browser");
74
76
 
75
77
  // src/useLinkedRecords.ts
76
78
  var import_react3 = require("react");
@@ -88,7 +90,6 @@ function getQueryKey(query) {
88
90
  }
89
91
 
90
92
  // src/useRecords.ts
91
- var import_browser2 = require("@linkedrecords/browser");
92
93
  function useKeyValueRecordsWithStatus(query) {
93
94
  const { lr } = useLinkedRecords();
94
95
  const [records, setRecords] = (0, import_react4.useState)([]);
@@ -97,62 +98,53 @@ function useKeyValueRecordsWithStatus(query) {
97
98
  (0, import_react4.useEffect)(() => {
98
99
  setIsLoading(true);
99
100
  let cancelled = false;
100
- const subscribedRecordIds = /* @__PURE__ */ new Set();
101
- const unsubscribeFnPromise = new Promise((resolve) => {
102
- const checkActorId = () => {
103
- if (cancelled) {
104
- return;
105
- }
106
- if (lr.actorId !== void 0) {
107
- resolve();
108
- } else {
109
- setTimeout(checkActorId, 50);
101
+ const recordUnsubscribes = /* @__PURE__ */ new Map();
102
+ const toKVRecord = async (r) => ({
103
+ _id: r.id,
104
+ _createdAt: r.createdAt,
105
+ ...await r.getValue()
106
+ });
107
+ const queryUnsubscribe = lr.Record.subscribeToQuery({
108
+ records: [
109
+ ["$it", "$hasDataType", import_browser2.KeyValueRecord],
110
+ ...query
111
+ ]
112
+ }, async ({ records: records2 }) => {
113
+ const kvRecords = records2;
114
+ const values = await Promise.all(kvRecords.map(toKVRecord));
115
+ if (cancelled) {
116
+ return;
117
+ }
118
+ setRecords(values);
119
+ setIsLoading(false);
120
+ const ids = new Set(kvRecords.map((r) => r.id));
121
+ recordUnsubscribes.forEach((unsubscribe, id) => {
122
+ if (!ids.has(id)) {
123
+ recordUnsubscribes.delete(id);
124
+ unsubscribe.then((fn) => fn());
110
125
  }
111
- };
112
- checkActorId();
113
- }).then(() => {
114
- const queryUnsubscribe = lr.Record.subscribeToQuery({
115
- records: [
116
- ["$it", "$hasDataType", import_browser2.KeyValueRecord],
117
- ...query
118
- ]
119
- }, async ({ records: records2 }) => {
120
- const values = await Promise.all(records2.map(async (r) => ({
121
- _id: r.id,
122
- _createdAt: r.createdAt,
123
- ...await r.getValue()
124
- })));
125
- if (cancelled) {
126
+ });
127
+ kvRecords.forEach((r) => {
128
+ if (recordUnsubscribes.has(r.id)) {
126
129
  return;
127
130
  }
128
- setRecords(values);
129
- setIsLoading(false);
130
- records2.forEach((r) => {
131
- if (subscribedRecordIds.has(r.id)) {
131
+ recordUnsubscribes.set(r.id, r.subscribe(async () => {
132
+ const newValue = await toKVRecord(r);
133
+ if (cancelled) {
132
134
  return;
133
135
  }
134
- subscribedRecordIds.add(r.id);
135
- r.subscribe(async () => {
136
- if (cancelled) {
137
- return;
138
- }
139
- const newValue = await r.getValue();
140
- if (cancelled) {
141
- return;
142
- }
143
- setRecords((prev) => prev.map(
144
- (v) => v._id === r.id ? { _id: r.id, _createdAt: r.createdAt, ...newValue } : v
145
- ));
146
- });
147
- });
136
+ setRecords((prev) => prev.map((v) => v._id === r.id ? newValue : v));
137
+ }));
148
138
  });
149
- return () => {
150
- queryUnsubscribe.then((unsubscribe) => unsubscribe());
151
- };
139
+ });
140
+ queryUnsubscribe.catch((err) => {
141
+ console.error("useKeyValueRecords: could not subscribe to query", err);
152
142
  });
153
143
  return () => {
154
144
  cancelled = true;
155
- unsubscribeFnPromise.then((fn) => fn());
145
+ queryUnsubscribe.then((unsubscribe) => unsubscribe(), () => {
146
+ });
147
+ recordUnsubscribes.forEach((unsubscribe) => unsubscribe.then((fn) => fn()));
156
148
  };
157
149
  }, [lr, queryKey]);
158
150
  return { records, isLoading };
package/dist/index.mjs CHANGED
@@ -3,7 +3,7 @@ import { createContext } from "react";
3
3
  var LinkedRecordsContext = createContext(void 0);
4
4
 
5
5
  // src/LinkedRecordsProvider.tsx
6
- import { useState } from "react";
6
+ import { useMemo, useState } from "react";
7
7
  import LinkedRecords from "@linkedrecords/browser";
8
8
  import { jsx } from "react/jsx-runtime";
9
9
  function createClient(serverUrl, config) {
@@ -22,11 +22,13 @@ function createClient(serverUrl, config) {
22
22
  }
23
23
  function LinkedRecordsProvider({ children, serverUrl, config }) {
24
24
  const [lr] = useState(() => config ? createClient(serverUrl, config) : LinkedRecords.getPublicClient(serverUrl));
25
- return /* @__PURE__ */ jsx(LinkedRecordsContext.Provider, { value: { lr }, children });
25
+ const value = useMemo(() => ({ lr }), [lr]);
26
+ return /* @__PURE__ */ jsx(LinkedRecordsContext.Provider, { value, children });
26
27
  }
27
28
 
28
29
  // src/useRecords.ts
29
30
  import { useEffect, useState as useState2 } from "react";
31
+ import { KeyValueRecord } from "@linkedrecords/browser";
30
32
 
31
33
  // src/useLinkedRecords.ts
32
34
  import { useContext } from "react";
@@ -44,7 +46,6 @@ function getQueryKey(query) {
44
46
  }
45
47
 
46
48
  // src/useRecords.ts
47
- import { KeyValueRecord } from "@linkedrecords/browser";
48
49
  function useKeyValueRecordsWithStatus(query) {
49
50
  const { lr } = useLinkedRecords();
50
51
  const [records, setRecords] = useState2([]);
@@ -53,62 +54,53 @@ function useKeyValueRecordsWithStatus(query) {
53
54
  useEffect(() => {
54
55
  setIsLoading(true);
55
56
  let cancelled = false;
56
- const subscribedRecordIds = /* @__PURE__ */ new Set();
57
- const unsubscribeFnPromise = new Promise((resolve) => {
58
- const checkActorId = () => {
59
- if (cancelled) {
60
- return;
61
- }
62
- if (lr.actorId !== void 0) {
63
- resolve();
64
- } else {
65
- setTimeout(checkActorId, 50);
57
+ const recordUnsubscribes = /* @__PURE__ */ new Map();
58
+ const toKVRecord = async (r) => ({
59
+ _id: r.id,
60
+ _createdAt: r.createdAt,
61
+ ...await r.getValue()
62
+ });
63
+ const queryUnsubscribe = lr.Record.subscribeToQuery({
64
+ records: [
65
+ ["$it", "$hasDataType", KeyValueRecord],
66
+ ...query
67
+ ]
68
+ }, async ({ records: records2 }) => {
69
+ const kvRecords = records2;
70
+ const values = await Promise.all(kvRecords.map(toKVRecord));
71
+ if (cancelled) {
72
+ return;
73
+ }
74
+ setRecords(values);
75
+ setIsLoading(false);
76
+ const ids = new Set(kvRecords.map((r) => r.id));
77
+ recordUnsubscribes.forEach((unsubscribe, id) => {
78
+ if (!ids.has(id)) {
79
+ recordUnsubscribes.delete(id);
80
+ unsubscribe.then((fn) => fn());
66
81
  }
67
- };
68
- checkActorId();
69
- }).then(() => {
70
- const queryUnsubscribe = lr.Record.subscribeToQuery({
71
- records: [
72
- ["$it", "$hasDataType", KeyValueRecord],
73
- ...query
74
- ]
75
- }, async ({ records: records2 }) => {
76
- const values = await Promise.all(records2.map(async (r) => ({
77
- _id: r.id,
78
- _createdAt: r.createdAt,
79
- ...await r.getValue()
80
- })));
81
- if (cancelled) {
82
+ });
83
+ kvRecords.forEach((r) => {
84
+ if (recordUnsubscribes.has(r.id)) {
82
85
  return;
83
86
  }
84
- setRecords(values);
85
- setIsLoading(false);
86
- records2.forEach((r) => {
87
- if (subscribedRecordIds.has(r.id)) {
87
+ recordUnsubscribes.set(r.id, r.subscribe(async () => {
88
+ const newValue = await toKVRecord(r);
89
+ if (cancelled) {
88
90
  return;
89
91
  }
90
- subscribedRecordIds.add(r.id);
91
- r.subscribe(async () => {
92
- if (cancelled) {
93
- return;
94
- }
95
- const newValue = await r.getValue();
96
- if (cancelled) {
97
- return;
98
- }
99
- setRecords((prev) => prev.map(
100
- (v) => v._id === r.id ? { _id: r.id, _createdAt: r.createdAt, ...newValue } : v
101
- ));
102
- });
103
- });
92
+ setRecords((prev) => prev.map((v) => v._id === r.id ? newValue : v));
93
+ }));
104
94
  });
105
- return () => {
106
- queryUnsubscribe.then((unsubscribe) => unsubscribe());
107
- };
95
+ });
96
+ queryUnsubscribe.catch((err) => {
97
+ console.error("useKeyValueRecords: could not subscribe to query", err);
108
98
  });
109
99
  return () => {
110
100
  cancelled = true;
111
- unsubscribeFnPromise.then((fn) => fn());
101
+ queryUnsubscribe.then((unsubscribe) => unsubscribe(), () => {
102
+ });
103
+ recordUnsubscribes.forEach((unsubscribe) => unsubscribe.then((fn) => fn()));
112
104
  };
113
105
  }, [lr, queryKey]);
114
106
  return { records, isLoading };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linkedrecords/react",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
@@ -25,11 +25,11 @@
25
25
  "license": "MIT",
26
26
  "description": "",
27
27
  "peerDependencies": {
28
- "@linkedrecords/browser": "^0.3.0",
28
+ "@linkedrecords/browser": "^0.4.0",
29
29
  "react": ">=18"
30
30
  },
31
31
  "devDependencies": {
32
- "@linkedrecords/browser": "^0.3.0",
32
+ "@linkedrecords/browser": "^0.4.0",
33
33
  "@types/react": "^19.1.12",
34
34
  "react": "^19.1.1",
35
35
  "tsup": "^8.5.0",
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { type ReactNode, useState } from 'react';
2
+ import { type ReactNode, useMemo, useState } from 'react';
3
3
  import LinkedRecords from '@linkedrecords/browser';
4
4
  import { LinkedRecordsContext } from './linkedRecordsContext';
5
5
 
@@ -47,9 +47,11 @@ export function LinkedRecordsProvider({ children, serverUrl, config }: LinkedRec
47
47
  const [lr] = useState(() => (config
48
48
  ? createClient(serverUrl, config)
49
49
  : LinkedRecords.getPublicClient(serverUrl)));
50
+ // A new context value would re-render every consumer on each render.
51
+ const value = useMemo(() => ({ lr }), [lr]);
50
52
 
51
53
  return (
52
- <LinkedRecordsContext.Provider value={{ lr }}>
54
+ <LinkedRecordsContext.Provider value={value}>
53
55
  {children}
54
56
  </LinkedRecordsContext.Provider>
55
57
  );
package/src/useRecords.ts CHANGED
@@ -1,103 +1,96 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
1
  import { useEffect, useState } from "react";
2
+ import type LinkedRecords from '@linkedrecords/browser';
3
+ import { KeyValueRecord } from '@linkedrecords/browser';
3
4
  import { useLinkedRecords } from "./useLinkedRecords";
4
5
  import { getQueryKey } from "./queryKey";
5
- import { KeyValueRecord } from '@linkedrecords/browser';
6
6
 
7
- interface KVValue {
8
- [key: string]: KVValue | string | boolean | number | Date | undefined;
9
- }
7
+ type JSONValue = string | number | boolean | null | JSONValue[] | { [key: string]: JSONValue };
8
+
9
+ type KVValue = { [key: string]: JSONValue | undefined };
10
10
 
11
- export interface KVRecord extends KVValue {
11
+ export type KVRecord<T extends object = KVValue> = T & {
12
12
  _id?: string;
13
13
  _createdAt?: Date;
14
- }
14
+ };
15
+
16
+ type CompoundRecordQuery = Parameters<LinkedRecords['Record']['subscribeToQuery']>[0];
15
17
 
16
- export function useKeyValueRecordsWithStatus(query: any[]): { records: KVRecord[], isLoading: boolean } {
18
+ // One [subject, predicate, object] clause of a record query, e.g. ['$it', 'isA', 'Todo'].
19
+ export type RecordQueryClause = Exclude<CompoundRecordQuery[string], string>[number];
20
+
21
+ export function useKeyValueRecordsWithStatus<T extends object = KVValue>(query: RecordQueryClause[]): { records: KVRecord<T>[], isLoading: boolean } {
17
22
  const { lr } = useLinkedRecords();
18
- const [ records, setRecords ] = useState<KVRecord[]>([]);
23
+ const [ records, setRecords ] = useState<KVRecord<T>[]>([]);
19
24
  const [ isLoading, setIsLoading ] = useState(true);
20
25
  const queryKey = getQueryKey(query);
21
26
 
22
27
  useEffect(() => {
23
28
  setIsLoading(true);
24
29
 
25
- // The SDK has no way to remove a record observer, so observers registered
26
- // by this effect run check this flag and become no-ops after cleanup.
30
+ // Values are read asynchronously; results which arrive after the query
31
+ // changed or the component unmounted are dropped.
27
32
  let cancelled = false;
28
- // Records this effect run already observes, so repeated query results
29
- // do not stack up observers on the same record.
30
- const subscribedRecordIds = new Set<string | undefined>();
31
-
32
- const unsubscribeFnPromise = new Promise<void>((resolve) => {
33
- const checkActorId = () => {
34
- if (cancelled) {
35
- return;
33
+ // Record observers by record id, so each record in the result is
34
+ // observed once and records which leave the result are unobserved.
35
+ const recordUnsubscribes = new Map<string | undefined, Promise<() => void>>();
36
+
37
+ // T is the value shape declared by the caller; the hook can not check it.
38
+ const toKVRecord = async (r: KeyValueRecord) => ({
39
+ _id: r.id,
40
+ _createdAt: r.createdAt,
41
+ ...(await r.getValue()),
42
+ }) as KVRecord<T>;
43
+
44
+ const queryUnsubscribe = lr.Record.subscribeToQuery({
45
+ records: [
46
+ ['$it', '$hasDataType', KeyValueRecord],
47
+ ...query
48
+ ],
49
+ }, async ({ records }) => {
50
+ const kvRecords = records as KeyValueRecord[];
51
+ const values = await Promise.all(kvRecords.map(toKVRecord));
52
+
53
+ if (cancelled) {
54
+ return;
55
+ }
56
+
57
+ setRecords(values);
58
+ setIsLoading(false);
59
+
60
+ const ids = new Set(kvRecords.map((r) => r.id));
61
+
62
+ recordUnsubscribes.forEach((unsubscribe, id) => {
63
+ if (!ids.has(id)) {
64
+ recordUnsubscribes.delete(id);
65
+ unsubscribe.then((fn) => fn());
36
66
  }
67
+ });
37
68
 
38
- if (lr.actorId !== undefined) {
39
- resolve();
40
- } else {
41
- setTimeout(checkActorId, 50);
42
- }
43
- };
44
- checkActorId();
45
- }).then(() => {
46
- const queryUnsubscribe = lr.Record.subscribeToQuery({
47
- records: [
48
- ['$it', '$hasDataType', KeyValueRecord],
49
- ...query
50
- ],
51
- }, async ({ records }) => {
52
- const values = await Promise.all(records.map(async (r) => ({
53
- _id: r.id,
54
- _createdAt: r.createdAt,
55
- ...(await r.getValue()),
56
- })));
57
-
58
- if (cancelled) {
69
+ kvRecords.forEach((r) => {
70
+ if (recordUnsubscribes.has(r.id)) {
59
71
  return;
60
72
  }
61
73
 
62
- setRecords(values);
63
- setIsLoading(false);
74
+ recordUnsubscribes.set(r.id, r.subscribe(async () => {
75
+ const newValue = await toKVRecord(r);
64
76
 
65
- records.forEach((r) => {
66
- if (subscribedRecordIds.has(r.id)) {
77
+ if (cancelled) {
67
78
  return;
68
79
  }
69
80
 
70
- subscribedRecordIds.add(r.id);
71
-
72
- r.subscribe(async () => {
73
- if (cancelled) {
74
- return;
75
- }
76
-
77
- const newValue = await r.getValue();
78
-
79
- if (cancelled) {
80
- return;
81
- }
82
-
83
- // Use functional update to avoid stale closure
84
- setRecords(prev => prev.map(v =>
85
- v._id === r.id
86
- ? { _id: r.id, _createdAt: r.createdAt, ...newValue }
87
- : v
88
- ));
89
- });
90
- });
81
+ setRecords(prev => prev.map(v => (v._id === r.id ? newValue : v)));
82
+ }));
91
83
  });
84
+ });
92
85
 
93
- return () => {
94
- queryUnsubscribe.then(unsubscribe => unsubscribe());
95
- };
86
+ queryUnsubscribe.catch((err) => {
87
+ console.error('useKeyValueRecords: could not subscribe to query', err);
96
88
  });
97
89
 
98
90
  return () => {
99
91
  cancelled = true;
100
- unsubscribeFnPromise.then(fn => fn());
92
+ queryUnsubscribe.then((unsubscribe) => unsubscribe(), () => {});
93
+ recordUnsubscribes.forEach((unsubscribe) => unsubscribe.then((fn) => fn()));
101
94
  }
102
95
  // query is represented by queryKey; depending on the array itself would
103
96
  // resubscribe on every render.
@@ -107,8 +100,8 @@ export function useKeyValueRecordsWithStatus(query: any[]): { records: KVRecord[
107
100
  return { records, isLoading };
108
101
  }
109
102
 
110
- export function useKeyValueRecords(query: any[]): KVRecord[] {
111
- return useKeyValueRecordsWithStatus(query).records;
103
+ export function useKeyValueRecords<T extends object = KVValue>(query: RecordQueryClause[]): KVRecord<T>[] {
104
+ return useKeyValueRecordsWithStatus<T>(query).records;
112
105
  }
113
106
 
114
107
  /** @deprecated Use useKeyValueRecords instead. */