@linkedrecords/react 0.5.0 → 0.6.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 +20 -3
- package/dist/index.d.ts +20 -3
- package/dist/index.js +64 -8
- package/dist/index.mjs +61 -8
- package/package.json +1 -1
- package/src/index.tsx +2 -0
- package/src/queryKey.ts +6 -0
- package/src/useActorId.ts +24 -0
- package/src/useFacts.ts +39 -0
- package/src/useRecords.ts +18 -10
package/dist/index.d.mts
CHANGED
|
@@ -27,12 +27,27 @@ interface LinkedRecordsProviderProps {
|
|
|
27
27
|
declare function LinkedRecordsProvider({ children, serverUrl, config }: LinkedRecordsProviderProps): react_jsx_runtime.JSX.Element;
|
|
28
28
|
|
|
29
29
|
interface KVValue {
|
|
30
|
-
[key: string]: KVValue | string | boolean | number | undefined;
|
|
30
|
+
[key: string]: KVValue | string | boolean | number | Date | undefined;
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
interface KVRecord extends KVValue {
|
|
33
|
+
_id?: string;
|
|
34
|
+
_createdAt?: Date;
|
|
35
|
+
}
|
|
36
|
+
declare function useKeyValueRecordsWithStatus(query: any[]): {
|
|
37
|
+
records: KVRecord[];
|
|
38
|
+
isLoading: boolean;
|
|
39
|
+
};
|
|
40
|
+
declare function useKeyValueRecords(query: any[]): KVRecord[];
|
|
33
41
|
/** @deprecated Use useKeyValueRecords instead. */
|
|
34
42
|
declare const useKeyValueAttributes: typeof useKeyValueRecords;
|
|
35
43
|
|
|
44
|
+
type FactQuery = Parameters<LinkedRecords['Fact']['findAll']>[0];
|
|
45
|
+
type Fact = Awaited<ReturnType<LinkedRecords['Fact']['findAll']>>[number];
|
|
46
|
+
declare function useFacts(query: FactQuery): {
|
|
47
|
+
facts: Fact[];
|
|
48
|
+
reload: () => void;
|
|
49
|
+
};
|
|
50
|
+
|
|
36
51
|
declare function useLinkedRecords(): LinkedRecordsContextType;
|
|
37
52
|
|
|
38
53
|
type UserInfo = {
|
|
@@ -40,4 +55,6 @@ type UserInfo = {
|
|
|
40
55
|
};
|
|
41
56
|
declare function useUserInfo(): UserInfo | null;
|
|
42
57
|
|
|
43
|
-
|
|
58
|
+
declare function useActorId(): string | undefined;
|
|
59
|
+
|
|
60
|
+
export { type KVRecord, type LinkedRecordsConfig, LinkedRecordsContext, type LinkedRecordsContextType, LinkedRecordsProvider, useActorId, useFacts, useKeyValueAttributes, useKeyValueRecords, useKeyValueRecordsWithStatus, useLinkedRecords, useUserInfo };
|
package/dist/index.d.ts
CHANGED
|
@@ -27,12 +27,27 @@ interface LinkedRecordsProviderProps {
|
|
|
27
27
|
declare function LinkedRecordsProvider({ children, serverUrl, config }: LinkedRecordsProviderProps): react_jsx_runtime.JSX.Element;
|
|
28
28
|
|
|
29
29
|
interface KVValue {
|
|
30
|
-
[key: string]: KVValue | string | boolean | number | undefined;
|
|
30
|
+
[key: string]: KVValue | string | boolean | number | Date | undefined;
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
interface KVRecord extends KVValue {
|
|
33
|
+
_id?: string;
|
|
34
|
+
_createdAt?: Date;
|
|
35
|
+
}
|
|
36
|
+
declare function useKeyValueRecordsWithStatus(query: any[]): {
|
|
37
|
+
records: KVRecord[];
|
|
38
|
+
isLoading: boolean;
|
|
39
|
+
};
|
|
40
|
+
declare function useKeyValueRecords(query: any[]): KVRecord[];
|
|
33
41
|
/** @deprecated Use useKeyValueRecords instead. */
|
|
34
42
|
declare const useKeyValueAttributes: typeof useKeyValueRecords;
|
|
35
43
|
|
|
44
|
+
type FactQuery = Parameters<LinkedRecords['Fact']['findAll']>[0];
|
|
45
|
+
type Fact = Awaited<ReturnType<LinkedRecords['Fact']['findAll']>>[number];
|
|
46
|
+
declare function useFacts(query: FactQuery): {
|
|
47
|
+
facts: Fact[];
|
|
48
|
+
reload: () => void;
|
|
49
|
+
};
|
|
50
|
+
|
|
36
51
|
declare function useLinkedRecords(): LinkedRecordsContextType;
|
|
37
52
|
|
|
38
53
|
type UserInfo = {
|
|
@@ -40,4 +55,6 @@ type UserInfo = {
|
|
|
40
55
|
};
|
|
41
56
|
declare function useUserInfo(): UserInfo | null;
|
|
42
57
|
|
|
43
|
-
|
|
58
|
+
declare function useActorId(): string | undefined;
|
|
59
|
+
|
|
60
|
+
export { type KVRecord, type LinkedRecordsConfig, LinkedRecordsContext, type LinkedRecordsContextType, LinkedRecordsProvider, useActorId, useFacts, useKeyValueAttributes, useKeyValueRecords, useKeyValueRecordsWithStatus, useLinkedRecords, useUserInfo };
|
package/dist/index.js
CHANGED
|
@@ -32,8 +32,11 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
LinkedRecordsContext: () => LinkedRecordsContext,
|
|
34
34
|
LinkedRecordsProvider: () => LinkedRecordsProvider,
|
|
35
|
+
useActorId: () => useActorId,
|
|
36
|
+
useFacts: () => useFacts,
|
|
35
37
|
useKeyValueAttributes: () => useKeyValueAttributes,
|
|
36
38
|
useKeyValueRecords: () => useKeyValueRecords,
|
|
39
|
+
useKeyValueRecordsWithStatus: () => useKeyValueRecordsWithStatus,
|
|
37
40
|
useLinkedRecords: () => useLinkedRecords,
|
|
38
41
|
useUserInfo: () => useUserInfo
|
|
39
42
|
});
|
|
@@ -79,16 +82,20 @@ function useLinkedRecords() {
|
|
|
79
82
|
return context;
|
|
80
83
|
}
|
|
81
84
|
|
|
82
|
-
// src/
|
|
83
|
-
var import_browser2 = require("@linkedrecords/browser");
|
|
85
|
+
// src/queryKey.ts
|
|
84
86
|
function getQueryKey(query) {
|
|
85
87
|
return JSON.stringify(query, (_, v) => typeof v === "function" ? `fn:${v.name}` : v);
|
|
86
88
|
}
|
|
87
|
-
|
|
89
|
+
|
|
90
|
+
// src/useRecords.ts
|
|
91
|
+
var import_browser2 = require("@linkedrecords/browser");
|
|
92
|
+
function useKeyValueRecordsWithStatus(query) {
|
|
88
93
|
const { lr } = useLinkedRecords();
|
|
89
94
|
const [records, setRecords] = (0, import_react4.useState)([]);
|
|
95
|
+
const [isLoading, setIsLoading] = (0, import_react4.useState)(true);
|
|
90
96
|
const queryKey = getQueryKey(query);
|
|
91
97
|
(0, import_react4.useEffect)(() => {
|
|
98
|
+
setIsLoading(true);
|
|
92
99
|
let cancelled = false;
|
|
93
100
|
const subscribedRecordIds = /* @__PURE__ */ new Set();
|
|
94
101
|
const unsubscribeFnPromise = new Promise((resolve) => {
|
|
@@ -112,12 +119,14 @@ function useKeyValueRecords(query) {
|
|
|
112
119
|
}, async ({ records: records2 }) => {
|
|
113
120
|
const values = await Promise.all(records2.map(async (r) => ({
|
|
114
121
|
_id: r.id,
|
|
122
|
+
_createdAt: r.createdAt,
|
|
115
123
|
...await r.getValue()
|
|
116
124
|
})));
|
|
117
125
|
if (cancelled) {
|
|
118
126
|
return;
|
|
119
127
|
}
|
|
120
128
|
setRecords(values);
|
|
129
|
+
setIsLoading(false);
|
|
121
130
|
records2.forEach((r) => {
|
|
122
131
|
if (subscribedRecordIds.has(r.id)) {
|
|
123
132
|
return;
|
|
@@ -132,7 +141,7 @@ function useKeyValueRecords(query) {
|
|
|
132
141
|
return;
|
|
133
142
|
}
|
|
134
143
|
setRecords((prev) => prev.map(
|
|
135
|
-
(v) => v._id === r.id ? { _id: r.id, ...newValue } : v
|
|
144
|
+
(v) => v._id === r.id ? { _id: r.id, _createdAt: r.createdAt, ...newValue } : v
|
|
136
145
|
));
|
|
137
146
|
});
|
|
138
147
|
});
|
|
@@ -146,26 +155,73 @@ function useKeyValueRecords(query) {
|
|
|
146
155
|
unsubscribeFnPromise.then((fn) => fn());
|
|
147
156
|
};
|
|
148
157
|
}, [lr, queryKey]);
|
|
149
|
-
return records;
|
|
158
|
+
return { records, isLoading };
|
|
159
|
+
}
|
|
160
|
+
function useKeyValueRecords(query) {
|
|
161
|
+
return useKeyValueRecordsWithStatus(query).records;
|
|
150
162
|
}
|
|
151
163
|
var useKeyValueAttributes = useKeyValueRecords;
|
|
152
164
|
|
|
153
|
-
// src/
|
|
165
|
+
// src/useFacts.ts
|
|
154
166
|
var import_react5 = require("react");
|
|
155
|
-
function
|
|
167
|
+
function useFacts(query) {
|
|
156
168
|
const { lr } = useLinkedRecords();
|
|
157
|
-
const [
|
|
169
|
+
const [facts, setFacts] = (0, import_react5.useState)([]);
|
|
170
|
+
const [reloadCount, setReloadCount] = (0, import_react5.useState)(0);
|
|
171
|
+
const queryKey = getQueryKey(query);
|
|
158
172
|
(0, import_react5.useEffect)(() => {
|
|
173
|
+
let cancelled = false;
|
|
174
|
+
lr.Fact.findAll(query).then((result) => {
|
|
175
|
+
if (!cancelled) {
|
|
176
|
+
setFacts(result);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
return () => {
|
|
180
|
+
cancelled = true;
|
|
181
|
+
};
|
|
182
|
+
}, [lr, queryKey, reloadCount]);
|
|
183
|
+
const reload = (0, import_react5.useCallback)(() => setReloadCount((c) => c + 1), []);
|
|
184
|
+
return { facts, reload };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// src/useUserInfo.ts
|
|
188
|
+
var import_react6 = require("react");
|
|
189
|
+
function useUserInfo() {
|
|
190
|
+
const { lr } = useLinkedRecords();
|
|
191
|
+
const [userInfo, setUserInfo] = (0, import_react6.useState)(null);
|
|
192
|
+
(0, import_react6.useEffect)(() => {
|
|
159
193
|
lr.getCurrentUserEmail().then((email) => setUserInfo({ email })).catch(() => setUserInfo(null));
|
|
160
194
|
}, [lr]);
|
|
161
195
|
return userInfo;
|
|
162
196
|
}
|
|
197
|
+
|
|
198
|
+
// src/useActorId.ts
|
|
199
|
+
var import_react7 = require("react");
|
|
200
|
+
function useActorId() {
|
|
201
|
+
const { lr } = useLinkedRecords();
|
|
202
|
+
const [actorId, setActorId] = (0, import_react7.useState)(lr.actorId);
|
|
203
|
+
(0, import_react7.useEffect)(() => {
|
|
204
|
+
let cancelled = false;
|
|
205
|
+
lr.ensureUserIdIsKnown().then((id) => {
|
|
206
|
+
if (!cancelled) {
|
|
207
|
+
setActorId(id);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
return () => {
|
|
211
|
+
cancelled = true;
|
|
212
|
+
};
|
|
213
|
+
}, [lr]);
|
|
214
|
+
return actorId;
|
|
215
|
+
}
|
|
163
216
|
// Annotate the CommonJS export names for ESM import in node:
|
|
164
217
|
0 && (module.exports = {
|
|
165
218
|
LinkedRecordsContext,
|
|
166
219
|
LinkedRecordsProvider,
|
|
220
|
+
useActorId,
|
|
221
|
+
useFacts,
|
|
167
222
|
useKeyValueAttributes,
|
|
168
223
|
useKeyValueRecords,
|
|
224
|
+
useKeyValueRecordsWithStatus,
|
|
169
225
|
useLinkedRecords,
|
|
170
226
|
useUserInfo
|
|
171
227
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -38,16 +38,20 @@ function useLinkedRecords() {
|
|
|
38
38
|
return context;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
// src/
|
|
42
|
-
import { KeyValueRecord } from "@linkedrecords/browser";
|
|
41
|
+
// src/queryKey.ts
|
|
43
42
|
function getQueryKey(query) {
|
|
44
43
|
return JSON.stringify(query, (_, v) => typeof v === "function" ? `fn:${v.name}` : v);
|
|
45
44
|
}
|
|
46
|
-
|
|
45
|
+
|
|
46
|
+
// src/useRecords.ts
|
|
47
|
+
import { KeyValueRecord } from "@linkedrecords/browser";
|
|
48
|
+
function useKeyValueRecordsWithStatus(query) {
|
|
47
49
|
const { lr } = useLinkedRecords();
|
|
48
50
|
const [records, setRecords] = useState2([]);
|
|
51
|
+
const [isLoading, setIsLoading] = useState2(true);
|
|
49
52
|
const queryKey = getQueryKey(query);
|
|
50
53
|
useEffect(() => {
|
|
54
|
+
setIsLoading(true);
|
|
51
55
|
let cancelled = false;
|
|
52
56
|
const subscribedRecordIds = /* @__PURE__ */ new Set();
|
|
53
57
|
const unsubscribeFnPromise = new Promise((resolve) => {
|
|
@@ -71,12 +75,14 @@ function useKeyValueRecords(query) {
|
|
|
71
75
|
}, async ({ records: records2 }) => {
|
|
72
76
|
const values = await Promise.all(records2.map(async (r) => ({
|
|
73
77
|
_id: r.id,
|
|
78
|
+
_createdAt: r.createdAt,
|
|
74
79
|
...await r.getValue()
|
|
75
80
|
})));
|
|
76
81
|
if (cancelled) {
|
|
77
82
|
return;
|
|
78
83
|
}
|
|
79
84
|
setRecords(values);
|
|
85
|
+
setIsLoading(false);
|
|
80
86
|
records2.forEach((r) => {
|
|
81
87
|
if (subscribedRecordIds.has(r.id)) {
|
|
82
88
|
return;
|
|
@@ -91,7 +97,7 @@ function useKeyValueRecords(query) {
|
|
|
91
97
|
return;
|
|
92
98
|
}
|
|
93
99
|
setRecords((prev) => prev.map(
|
|
94
|
-
(v) => v._id === r.id ? { _id: r.id, ...newValue } : v
|
|
100
|
+
(v) => v._id === r.id ? { _id: r.id, _createdAt: r.createdAt, ...newValue } : v
|
|
95
101
|
));
|
|
96
102
|
});
|
|
97
103
|
});
|
|
@@ -105,25 +111,72 @@ function useKeyValueRecords(query) {
|
|
|
105
111
|
unsubscribeFnPromise.then((fn) => fn());
|
|
106
112
|
};
|
|
107
113
|
}, [lr, queryKey]);
|
|
108
|
-
return records;
|
|
114
|
+
return { records, isLoading };
|
|
115
|
+
}
|
|
116
|
+
function useKeyValueRecords(query) {
|
|
117
|
+
return useKeyValueRecordsWithStatus(query).records;
|
|
109
118
|
}
|
|
110
119
|
var useKeyValueAttributes = useKeyValueRecords;
|
|
111
120
|
|
|
121
|
+
// src/useFacts.ts
|
|
122
|
+
import { useCallback, useEffect as useEffect2, useState as useState3 } from "react";
|
|
123
|
+
function useFacts(query) {
|
|
124
|
+
const { lr } = useLinkedRecords();
|
|
125
|
+
const [facts, setFacts] = useState3([]);
|
|
126
|
+
const [reloadCount, setReloadCount] = useState3(0);
|
|
127
|
+
const queryKey = getQueryKey(query);
|
|
128
|
+
useEffect2(() => {
|
|
129
|
+
let cancelled = false;
|
|
130
|
+
lr.Fact.findAll(query).then((result) => {
|
|
131
|
+
if (!cancelled) {
|
|
132
|
+
setFacts(result);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
return () => {
|
|
136
|
+
cancelled = true;
|
|
137
|
+
};
|
|
138
|
+
}, [lr, queryKey, reloadCount]);
|
|
139
|
+
const reload = useCallback(() => setReloadCount((c) => c + 1), []);
|
|
140
|
+
return { facts, reload };
|
|
141
|
+
}
|
|
142
|
+
|
|
112
143
|
// src/useUserInfo.ts
|
|
113
|
-
import { useEffect as
|
|
144
|
+
import { useEffect as useEffect3, useState as useState4 } from "react";
|
|
114
145
|
function useUserInfo() {
|
|
115
146
|
const { lr } = useLinkedRecords();
|
|
116
|
-
const [userInfo, setUserInfo] =
|
|
117
|
-
|
|
147
|
+
const [userInfo, setUserInfo] = useState4(null);
|
|
148
|
+
useEffect3(() => {
|
|
118
149
|
lr.getCurrentUserEmail().then((email) => setUserInfo({ email })).catch(() => setUserInfo(null));
|
|
119
150
|
}, [lr]);
|
|
120
151
|
return userInfo;
|
|
121
152
|
}
|
|
153
|
+
|
|
154
|
+
// src/useActorId.ts
|
|
155
|
+
import { useEffect as useEffect4, useState as useState5 } from "react";
|
|
156
|
+
function useActorId() {
|
|
157
|
+
const { lr } = useLinkedRecords();
|
|
158
|
+
const [actorId, setActorId] = useState5(lr.actorId);
|
|
159
|
+
useEffect4(() => {
|
|
160
|
+
let cancelled = false;
|
|
161
|
+
lr.ensureUserIdIsKnown().then((id) => {
|
|
162
|
+
if (!cancelled) {
|
|
163
|
+
setActorId(id);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
return () => {
|
|
167
|
+
cancelled = true;
|
|
168
|
+
};
|
|
169
|
+
}, [lr]);
|
|
170
|
+
return actorId;
|
|
171
|
+
}
|
|
122
172
|
export {
|
|
123
173
|
LinkedRecordsContext,
|
|
124
174
|
LinkedRecordsProvider,
|
|
175
|
+
useActorId,
|
|
176
|
+
useFacts,
|
|
125
177
|
useKeyValueAttributes,
|
|
126
178
|
useKeyValueRecords,
|
|
179
|
+
useKeyValueRecordsWithStatus,
|
|
127
180
|
useLinkedRecords,
|
|
128
181
|
useUserInfo
|
|
129
182
|
};
|
package/package.json
CHANGED
package/src/index.tsx
CHANGED
package/src/queryKey.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Callers usually pass a new query on every render, so effects depend on a
|
|
2
|
+
// serialized key instead of the query identity. Functions (e.g. record
|
|
3
|
+
// classes) would serialize to null, so they are keyed by name.
|
|
4
|
+
export function getQueryKey(query: unknown): string {
|
|
5
|
+
return JSON.stringify(query, (_, v) => (typeof v === 'function' ? `fn:${v.name}` : v));
|
|
6
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import { useLinkedRecords } from "./useLinkedRecords";
|
|
3
|
+
|
|
4
|
+
// The id of the logged in user, undefined until it is known.
|
|
5
|
+
export function useActorId(): string | undefined {
|
|
6
|
+
const { lr } = useLinkedRecords();
|
|
7
|
+
const [ actorId, setActorId ] = useState<string | undefined>(lr.actorId);
|
|
8
|
+
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
let cancelled = false;
|
|
11
|
+
|
|
12
|
+
lr.ensureUserIdIsKnown().then((id) => {
|
|
13
|
+
if (!cancelled) {
|
|
14
|
+
setActorId(id);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
return () => {
|
|
19
|
+
cancelled = true;
|
|
20
|
+
}
|
|
21
|
+
}, [ lr ]);
|
|
22
|
+
|
|
23
|
+
return actorId;
|
|
24
|
+
}
|
package/src/useFacts.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from "react";
|
|
2
|
+
import type LinkedRecords from '@linkedrecords/browser';
|
|
3
|
+
import { useLinkedRecords } from "./useLinkedRecords";
|
|
4
|
+
import { getQueryKey } from "./queryKey";
|
|
5
|
+
|
|
6
|
+
type FactQuery = Parameters<LinkedRecords['Fact']['findAll']>[0];
|
|
7
|
+
type Fact = Awaited<ReturnType<LinkedRecords['Fact']['findAll']>>[number];
|
|
8
|
+
|
|
9
|
+
// The SDK can not subscribe to facts, so the facts are fetched whenever the
|
|
10
|
+
// query changes. Call reload after writing facts which affect the result.
|
|
11
|
+
export function useFacts(query: FactQuery): { facts: Fact[], reload: () => void } {
|
|
12
|
+
const { lr } = useLinkedRecords();
|
|
13
|
+
const [ facts, setFacts ] = useState<Fact[]>([]);
|
|
14
|
+
const [ reloadCount, setReloadCount ] = useState(0);
|
|
15
|
+
const queryKey = getQueryKey(query);
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
// Ignore responses which arrive after the query changed or the
|
|
19
|
+
// component unmounted.
|
|
20
|
+
let cancelled = false;
|
|
21
|
+
|
|
22
|
+
lr.Fact.findAll(query).then((result) => {
|
|
23
|
+
if (!cancelled) {
|
|
24
|
+
setFacts(result);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return () => {
|
|
29
|
+
cancelled = true;
|
|
30
|
+
}
|
|
31
|
+
// query is represented by queryKey; depending on the object itself would
|
|
32
|
+
// refetch on every render.
|
|
33
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
34
|
+
}, [ lr, queryKey, reloadCount ]);
|
|
35
|
+
|
|
36
|
+
const reload = useCallback(() => setReloadCount((c) => c + 1), []);
|
|
37
|
+
|
|
38
|
+
return { facts, reload };
|
|
39
|
+
}
|
package/src/useRecords.ts
CHANGED
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import { useEffect, useState } from "react";
|
|
3
3
|
import { useLinkedRecords } from "./useLinkedRecords";
|
|
4
|
+
import { getQueryKey } from "./queryKey";
|
|
4
5
|
import { KeyValueRecord } from '@linkedrecords/browser';
|
|
5
6
|
|
|
6
7
|
interface KVValue {
|
|
7
|
-
[key: string]: KVValue | string | boolean | number | undefined;
|
|
8
|
+
[key: string]: KVValue | string | boolean | number | Date | undefined;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
function getQueryKey(query: any[]): string {
|
|
14
|
-
return JSON.stringify(query, (_, v) => (typeof v === 'function' ? `fn:${v.name}` : v));
|
|
11
|
+
export interface KVRecord extends KVValue {
|
|
12
|
+
_id?: string;
|
|
13
|
+
_createdAt?: Date;
|
|
15
14
|
}
|
|
16
15
|
|
|
17
|
-
export function
|
|
16
|
+
export function useKeyValueRecordsWithStatus(query: any[]): { records: KVRecord[], isLoading: boolean } {
|
|
18
17
|
const { lr } = useLinkedRecords();
|
|
19
|
-
const [ records, setRecords ] = useState<
|
|
18
|
+
const [ records, setRecords ] = useState<KVRecord[]>([]);
|
|
19
|
+
const [ isLoading, setIsLoading ] = useState(true);
|
|
20
20
|
const queryKey = getQueryKey(query);
|
|
21
21
|
|
|
22
22
|
useEffect(() => {
|
|
23
|
+
setIsLoading(true);
|
|
24
|
+
|
|
23
25
|
// The SDK has no way to remove a record observer, so observers registered
|
|
24
26
|
// by this effect run check this flag and become no-ops after cleanup.
|
|
25
27
|
let cancelled = false;
|
|
@@ -49,6 +51,7 @@ export function useKeyValueRecords(query: any[]): KVValue[] {
|
|
|
49
51
|
}, async ({ records }) => {
|
|
50
52
|
const values = await Promise.all(records.map(async (r) => ({
|
|
51
53
|
_id: r.id,
|
|
54
|
+
_createdAt: r.createdAt,
|
|
52
55
|
...(await r.getValue()),
|
|
53
56
|
})));
|
|
54
57
|
|
|
@@ -57,6 +60,7 @@ export function useKeyValueRecords(query: any[]): KVValue[] {
|
|
|
57
60
|
}
|
|
58
61
|
|
|
59
62
|
setRecords(values);
|
|
63
|
+
setIsLoading(false);
|
|
60
64
|
|
|
61
65
|
records.forEach((r) => {
|
|
62
66
|
if (subscribedRecordIds.has(r.id)) {
|
|
@@ -79,7 +83,7 @@ export function useKeyValueRecords(query: any[]): KVValue[] {
|
|
|
79
83
|
// Use functional update to avoid stale closure
|
|
80
84
|
setRecords(prev => prev.map(v =>
|
|
81
85
|
v._id === r.id
|
|
82
|
-
? { _id: r.id, ...newValue }
|
|
86
|
+
? { _id: r.id, _createdAt: r.createdAt, ...newValue }
|
|
83
87
|
: v
|
|
84
88
|
));
|
|
85
89
|
});
|
|
@@ -100,7 +104,11 @@ export function useKeyValueRecords(query: any[]): KVValue[] {
|
|
|
100
104
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
101
105
|
}, [ lr, queryKey ]);
|
|
102
106
|
|
|
103
|
-
return records;
|
|
107
|
+
return { records, isLoading };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function useKeyValueRecords(query: any[]): KVRecord[] {
|
|
111
|
+
return useKeyValueRecordsWithStatus(query).records;
|
|
104
112
|
}
|
|
105
113
|
|
|
106
114
|
/** @deprecated Use useKeyValueRecords instead. */
|