@instantdb/react 0.22.155 → 0.22.156
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/commonjs/next-ssr/HydrationStreamProvider.js +0 -1
- package/dist/commonjs/next-ssr/HydrationStreamProvider.js.map +1 -1
- package/dist/commonjs/next-ssr/InstantSuspenseProvider.d.ts +2 -5
- package/dist/commonjs/next-ssr/InstantSuspenseProvider.d.ts.map +1 -1
- package/dist/commonjs/next-ssr/InstantSuspenseProvider.js +116 -48
- package/dist/commonjs/next-ssr/InstantSuspenseProvider.js.map +1 -1
- package/dist/esm/next-ssr/HydrationStreamProvider.js +0 -1
- package/dist/esm/next-ssr/HydrationStreamProvider.js.map +1 -1
- package/dist/esm/next-ssr/InstantSuspenseProvider.d.ts +2 -5
- package/dist/esm/next-ssr/InstantSuspenseProvider.d.ts.map +1 -1
- package/dist/esm/next-ssr/InstantSuspenseProvider.js +117 -49
- package/dist/esm/next-ssr/InstantSuspenseProvider.js.map +1 -1
- package/dist/standalone/index.js +126 -116
- package/dist/standalone/index.umd.cjs +6 -6
- package/package.json +4 -4
- package/src/next-ssr/HydrationStreamProvider.tsx +1 -1
- package/src/next-ssr/InstantSuspenseProvider.tsx +172 -71
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@instantdb/react",
|
|
3
|
-
"version": "0.22.
|
|
3
|
+
"version": "0.22.156",
|
|
4
4
|
"description": "Instant DB for React",
|
|
5
5
|
"homepage": "https://github.com/instantdb/instant/tree/main/client/packages/react",
|
|
6
6
|
"repository": {
|
|
@@ -66,9 +66,9 @@
|
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"eventsource": "^4.0.0",
|
|
69
|
-
"@instantdb/core": "0.22.
|
|
70
|
-
"@instantdb/react-common": "0.22.
|
|
71
|
-
"@instantdb/version": "0.22.
|
|
69
|
+
"@instantdb/core": "0.22.156",
|
|
70
|
+
"@instantdb/react-common": "0.22.156",
|
|
71
|
+
"@instantdb/version": "0.22.156"
|
|
72
72
|
},
|
|
73
73
|
"scripts": {
|
|
74
74
|
"test": "vitest",
|
|
@@ -131,7 +131,7 @@ export function createHydrationStreamProvider<TShape>() {
|
|
|
131
131
|
if (!stream.length) {
|
|
132
132
|
return null;
|
|
133
133
|
}
|
|
134
|
-
|
|
134
|
+
|
|
135
135
|
const serializedCacheArgs = stream
|
|
136
136
|
.map((entry) => transformer.serialize(entry))
|
|
137
137
|
.map((entry) => JSON.stringify(entry))
|
|
@@ -16,18 +16,26 @@ import {
|
|
|
16
16
|
createHydrationStreamProvider,
|
|
17
17
|
isServer,
|
|
18
18
|
} from './HydrationStreamProvider.tsx';
|
|
19
|
-
import {
|
|
20
|
-
|
|
19
|
+
import {
|
|
20
|
+
createContext,
|
|
21
|
+
useCallback,
|
|
22
|
+
useContext,
|
|
23
|
+
useMemo,
|
|
24
|
+
useRef,
|
|
25
|
+
useState,
|
|
26
|
+
useEffect,
|
|
27
|
+
} from 'react';
|
|
28
|
+
import {
|
|
29
|
+
InstantReactAbstractDatabase,
|
|
30
|
+
useQueryInternal,
|
|
31
|
+
} from '@instantdb/react-common';
|
|
21
32
|
|
|
22
33
|
type InstantSuspenseProviderProps<
|
|
23
34
|
Schema extends InstantSchemaDef<any, any, any>,
|
|
24
35
|
> = {
|
|
25
36
|
nonce?: string;
|
|
26
37
|
children: React.ReactNode;
|
|
27
|
-
db
|
|
28
|
-
config?: Omit<InstantConfig<any, any>, 'schema'> & {
|
|
29
|
-
schema: string;
|
|
30
|
-
};
|
|
38
|
+
db: InstantReactWebDatabase<Schema, any>;
|
|
31
39
|
user?: User | null;
|
|
32
40
|
};
|
|
33
41
|
|
|
@@ -71,95 +79,188 @@ type SuspenseQueryOpts = {
|
|
|
71
79
|
ruleParams: RuleParams;
|
|
72
80
|
};
|
|
73
81
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const clientRef = useRef<FrameworkClient | null>(null);
|
|
82
|
+
function makeUseSuspenseQueryServer(client: FrameworkClient) {
|
|
83
|
+
return function useSuspenseQueryServer(query: any, opts: SuspenseQueryOpts) {
|
|
84
|
+
let entry = client.getExistingResultForQuery(query, opts);
|
|
78
85
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const db = useRef<InstantReactAbstractDatabase<any, any>>(props.db);
|
|
86
|
+
if (!entry) {
|
|
87
|
+
entry = client.query(query, opts);
|
|
88
|
+
}
|
|
86
89
|
|
|
87
|
-
|
|
90
|
+
if (entry.status === 'pending') {
|
|
91
|
+
throw entry.promise;
|
|
92
|
+
}
|
|
88
93
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
throw new Error(
|
|
92
|
-
'User must have a refresh_token field. Recieved: ' +
|
|
93
|
-
JSON.stringify(props.user, null, 2),
|
|
94
|
-
);
|
|
94
|
+
if (entry.status === 'error') {
|
|
95
|
+
throw entry.error;
|
|
95
96
|
}
|
|
96
|
-
clientRef.current = new FrameworkClient({
|
|
97
|
-
token: props.user?.refresh_token,
|
|
98
|
-
db: db.current.core,
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
97
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
98
|
+
if (entry.status === 'success') {
|
|
99
|
+
switch (entry.type) {
|
|
100
|
+
case 'session': {
|
|
101
|
+
return entry.data;
|
|
102
|
+
}
|
|
103
|
+
case 'http': {
|
|
104
|
+
const data = entry.data;
|
|
105
|
+
const result = client.completeIsomorphic(
|
|
106
|
+
query,
|
|
107
|
+
data.triples,
|
|
108
|
+
data.attrs,
|
|
109
|
+
data.pageInfo,
|
|
110
|
+
);
|
|
108
111
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
113
118
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
+
function makeUseSuspenseQueryClient(
|
|
120
|
+
db: InstantReactAbstractDatabase<any, any>,
|
|
121
|
+
client: FrameworkClient,
|
|
122
|
+
) {
|
|
123
|
+
function getEntry(query: any, opts: SuspenseQueryOpts, allowFetch: boolean) {
|
|
124
|
+
const entry = client.getExistingResultForQuery(query, opts);
|
|
125
|
+
|
|
126
|
+
if (entry?.status === 'pending') {
|
|
127
|
+
throw entry.promise;
|
|
119
128
|
}
|
|
120
129
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
throw new Error('Client ref not set up');
|
|
130
|
+
if (entry?.status === 'error') {
|
|
131
|
+
throw entry.error;
|
|
124
132
|
}
|
|
125
133
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
134
|
+
if (entry?.status === 'success') {
|
|
135
|
+
switch (entry.type) {
|
|
136
|
+
case 'session': {
|
|
137
|
+
return entry.data;
|
|
138
|
+
}
|
|
139
|
+
case 'http': {
|
|
140
|
+
const data = entry.data;
|
|
141
|
+
const result = client.completeIsomorphic(
|
|
142
|
+
query,
|
|
143
|
+
data.triples,
|
|
144
|
+
data.attrs,
|
|
145
|
+
data.pageInfo,
|
|
146
|
+
);
|
|
129
147
|
|
|
130
|
-
|
|
131
|
-
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
132
151
|
}
|
|
133
152
|
|
|
134
|
-
if (
|
|
135
|
-
|
|
153
|
+
if (allowFetch) {
|
|
154
|
+
const promise = client.queryClient(query, opts);
|
|
155
|
+
throw promise;
|
|
136
156
|
}
|
|
157
|
+
}
|
|
137
158
|
|
|
138
|
-
|
|
139
|
-
|
|
159
|
+
return function useSuspenseQueryClient(query: any, opts: SuspenseQueryOpts) {
|
|
160
|
+
const useQueryResult = useQueryInternal(
|
|
161
|
+
db.core,
|
|
162
|
+
query,
|
|
163
|
+
opts,
|
|
164
|
+
// Returns the server result for useSyncExternalStore
|
|
165
|
+
() => {
|
|
166
|
+
try {
|
|
167
|
+
const res = getEntry(query, opts, false);
|
|
168
|
+
return res;
|
|
169
|
+
} catch (throwable) {
|
|
170
|
+
return { error: throwable };
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
const hasData = !!useQueryResult.state.data;
|
|
176
|
+
const queryHash = useQueryResult.queryHash;
|
|
177
|
+
|
|
178
|
+
useEffect(() => {
|
|
179
|
+
if (hasData) {
|
|
180
|
+
// We have a newer result, so remove the cached SSR or suspended
|
|
181
|
+
// result from the framework client cache
|
|
182
|
+
client.removeCachedQueryResult(queryHash);
|
|
183
|
+
}
|
|
184
|
+
}, [hasData, queryHash]);
|
|
185
|
+
|
|
186
|
+
if (useQueryResult.state.data) {
|
|
187
|
+
return {
|
|
188
|
+
data: useQueryResult.state.data,
|
|
189
|
+
pageInfo: useQueryResult.state.pageInfo,
|
|
190
|
+
};
|
|
140
191
|
}
|
|
141
192
|
|
|
142
|
-
if (
|
|
143
|
-
|
|
193
|
+
if (useQueryResult.state.error) {
|
|
194
|
+
throw useQueryResult.state.error;
|
|
144
195
|
}
|
|
145
196
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
query,
|
|
150
|
-
data.triples,
|
|
151
|
-
data.attrs,
|
|
152
|
-
data.pageInfo,
|
|
153
|
-
);
|
|
197
|
+
return getEntry(query, opts, true);
|
|
198
|
+
};
|
|
199
|
+
}
|
|
154
200
|
|
|
155
|
-
|
|
201
|
+
function createFrameworkClient(
|
|
202
|
+
db: InstantReactAbstractDatabase<any, any>,
|
|
203
|
+
user: User | null | undefined,
|
|
204
|
+
) {
|
|
205
|
+
if (isServer) {
|
|
206
|
+
if (user && !user.refresh_token) {
|
|
207
|
+
throw new Error(
|
|
208
|
+
'User must have a refresh_token field. Recieved: ' +
|
|
209
|
+
JSON.stringify(user, null, 2),
|
|
210
|
+
);
|
|
156
211
|
}
|
|
157
|
-
|
|
212
|
+
return new FrameworkClient({
|
|
213
|
+
token: user?.refresh_token,
|
|
214
|
+
db: db.core,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// On the client, make sure we only have a single framework
|
|
219
|
+
// in case our suspense provider gets unmounted
|
|
220
|
+
const existing = db.core._reactor._frameworkClient;
|
|
221
|
+
if (existing) {
|
|
222
|
+
return existing;
|
|
223
|
+
}
|
|
224
|
+
const client = new FrameworkClient({ db: db.core });
|
|
225
|
+
db.core._reactor.setFrameworkClient(client);
|
|
226
|
+
return client;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export const InstantSuspenseProvider = (
|
|
230
|
+
props: InstantSuspenseProviderProps<any>,
|
|
231
|
+
) => {
|
|
232
|
+
if (!props.db) {
|
|
233
|
+
throw new Error('Must provide db to InstantSuspenseProvider');
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const db = props.db;
|
|
237
|
+
|
|
238
|
+
const [trackedKeys] = useState(() => new Set<string>());
|
|
239
|
+
|
|
240
|
+
const clientRef = useRef<FrameworkClient>(
|
|
241
|
+
createFrameworkClient(props.db, props.user),
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
if (isServer) {
|
|
245
|
+
clientRef.current.subscribe((result) => {
|
|
246
|
+
const { queryHash } = result;
|
|
247
|
+
trackedKeys.add(queryHash);
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const useSuspenseQuery = useCallback(
|
|
252
|
+
isServer
|
|
253
|
+
? makeUseSuspenseQueryServer(clientRef.current)
|
|
254
|
+
: makeUseSuspenseQueryClient(db, clientRef.current),
|
|
255
|
+
[],
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
const contextValue = useMemo(() => {
|
|
259
|
+
return { useSuspenseQuery, ssrUser: props.user };
|
|
260
|
+
}, [useSuspenseQuery, props.user]);
|
|
158
261
|
|
|
159
262
|
return (
|
|
160
|
-
<SuspsenseQueryContext.Provider
|
|
161
|
-
value={{ useSuspenseQuery, ssrUser: props.user }}
|
|
162
|
-
>
|
|
263
|
+
<SuspsenseQueryContext.Provider value={contextValue}>
|
|
163
264
|
<stream.Provider
|
|
164
265
|
nonce={props.nonce}
|
|
165
266
|
onFlush={() => {
|