syncorejs 0.2.1 → 0.2.2
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 +2 -1
- package/dist/_vendor/cli/app.d.mts.map +1 -1
- package/dist/_vendor/cli/app.mjs +323 -42
- package/dist/_vendor/cli/app.mjs.map +1 -1
- package/dist/_vendor/cli/context.mjs +27 -9
- package/dist/_vendor/cli/context.mjs.map +1 -1
- package/dist/_vendor/cli/doctor.mjs +513 -46
- package/dist/_vendor/cli/doctor.mjs.map +1 -1
- package/dist/_vendor/cli/messages.mjs +5 -4
- package/dist/_vendor/cli/messages.mjs.map +1 -1
- package/dist/_vendor/cli/project.mjs +110 -12
- package/dist/_vendor/cli/project.mjs.map +1 -1
- package/dist/_vendor/cli/render.mjs +57 -9
- package/dist/_vendor/cli/render.mjs.map +1 -1
- package/dist/_vendor/cli/targets.mjs +4 -3
- package/dist/_vendor/cli/targets.mjs.map +1 -1
- package/dist/_vendor/core/cli.d.mts +13 -3
- package/dist/_vendor/core/cli.d.mts.map +1 -1
- package/dist/_vendor/core/cli.mjs +242 -91
- package/dist/_vendor/core/cli.mjs.map +1 -1
- package/dist/_vendor/core/devtools-auth.mjs +60 -0
- package/dist/_vendor/core/devtools-auth.mjs.map +1 -0
- package/dist/_vendor/core/index.d.mts +5 -3
- package/dist/_vendor/core/index.mjs +22 -2
- package/dist/_vendor/core/index.mjs.map +1 -1
- package/dist/_vendor/core/runtime/components.d.mts +111 -0
- package/dist/_vendor/core/runtime/components.d.mts.map +1 -0
- package/dist/_vendor/core/runtime/components.mjs +186 -0
- package/dist/_vendor/core/runtime/components.mjs.map +1 -0
- package/dist/_vendor/core/runtime/devtools.d.mts +4 -4
- package/dist/_vendor/core/runtime/devtools.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/devtools.mjs +52 -41
- package/dist/_vendor/core/runtime/devtools.mjs.map +1 -1
- package/dist/_vendor/core/runtime/functions.d.mts +10 -10
- package/dist/_vendor/core/runtime/functions.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/functions.mjs +2 -2
- package/dist/_vendor/core/runtime/functions.mjs.map +1 -1
- package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs +77 -0
- package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs +617 -0
- package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs +186 -0
- package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs +220 -0
- package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs +203 -0
- package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/shared.mjs +177 -0
- package/dist/_vendor/core/runtime/internal/engines/shared.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs +144 -0
- package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs +220 -0
- package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/runtimeStatus.mjs +32 -0
- package/dist/_vendor/core/runtime/internal/runtimeStatus.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/systemMeta.mjs +61 -0
- package/dist/_vendor/core/runtime/internal/systemMeta.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs +37 -0
- package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs.map +1 -0
- package/dist/_vendor/core/runtime/runtime.d.mts +159 -205
- package/dist/_vendor/core/runtime/runtime.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/runtime.mjs +16 -1371
- package/dist/_vendor/core/runtime/runtime.mjs.map +1 -1
- package/dist/_vendor/core/transport.d.mts +111 -0
- package/dist/_vendor/core/transport.d.mts.map +1 -0
- package/dist/_vendor/core/transport.mjs +419 -0
- package/dist/_vendor/core/transport.mjs.map +1 -0
- package/dist/_vendor/devtools-protocol/index.d.ts +39 -1
- package/dist/_vendor/devtools-protocol/index.d.ts.map +1 -1
- package/dist/_vendor/devtools-protocol/index.js +25 -9
- package/dist/_vendor/devtools-protocol/index.js.map +1 -1
- package/dist/_vendor/next/index.d.ts +1 -1
- package/dist/_vendor/next/index.d.ts.map +1 -1
- package/dist/_vendor/next/index.js +31 -13
- package/dist/_vendor/next/index.js.map +1 -1
- package/dist/_vendor/platform-expo/index.d.ts +12 -12
- package/dist/_vendor/platform-expo/index.d.ts.map +1 -1
- package/dist/_vendor/platform-expo/index.js +4 -2
- package/dist/_vendor/platform-expo/index.js.map +1 -1
- package/dist/_vendor/platform-expo/react.d.ts.map +1 -1
- package/dist/_vendor/platform-expo/react.js +11 -10
- package/dist/_vendor/platform-expo/react.js.map +1 -1
- package/dist/_vendor/platform-node/index.d.mts +23 -19
- package/dist/_vendor/platform-node/index.d.mts.map +1 -1
- package/dist/_vendor/platform-node/index.mjs +13 -5
- package/dist/_vendor/platform-node/index.mjs.map +1 -1
- package/dist/_vendor/platform-node/ipc-react.d.mts.map +1 -1
- package/dist/_vendor/platform-node/ipc-react.mjs +15 -2
- package/dist/_vendor/platform-node/ipc-react.mjs.map +1 -1
- package/dist/_vendor/platform-node/ipc.d.mts +11 -35
- package/dist/_vendor/platform-node/ipc.d.mts.map +1 -1
- package/dist/_vendor/platform-node/ipc.mjs +3 -273
- package/dist/_vendor/platform-node/ipc.mjs.map +1 -1
- package/dist/_vendor/platform-web/external-change.d.ts +2 -1
- package/dist/_vendor/platform-web/external-change.d.ts.map +1 -1
- package/dist/_vendor/platform-web/external-change.js +2 -1
- package/dist/_vendor/platform-web/external-change.js.map +1 -1
- package/dist/_vendor/platform-web/index.d.ts +21 -21
- package/dist/_vendor/platform-web/index.d.ts.map +1 -1
- package/dist/_vendor/platform-web/index.js +44 -7
- package/dist/_vendor/platform-web/index.js.map +1 -1
- package/dist/_vendor/platform-web/react.d.ts.map +1 -1
- package/dist/_vendor/platform-web/react.js +29 -13
- package/dist/_vendor/platform-web/react.js.map +1 -1
- package/dist/_vendor/platform-web/worker.d.ts +11 -35
- package/dist/_vendor/platform-web/worker.d.ts.map +1 -1
- package/dist/_vendor/platform-web/worker.js +3 -267
- package/dist/_vendor/platform-web/worker.js.map +1 -1
- package/dist/_vendor/react/index.d.ts +36 -20
- package/dist/_vendor/react/index.d.ts.map +1 -1
- package/dist/_vendor/react/index.js +279 -57
- package/dist/_vendor/react/index.js.map +1 -1
- package/dist/_vendor/schema/definition.d.ts +48 -63
- package/dist/_vendor/schema/definition.d.ts.map +1 -1
- package/dist/_vendor/schema/definition.js +22 -39
- package/dist/_vendor/schema/definition.js.map +1 -1
- package/dist/_vendor/schema/index.d.ts +4 -4
- package/dist/_vendor/schema/index.js +2 -2
- package/dist/_vendor/schema/planner.d.ts +19 -2
- package/dist/_vendor/schema/planner.d.ts.map +1 -1
- package/dist/_vendor/schema/planner.js +79 -3
- package/dist/_vendor/schema/planner.js.map +1 -1
- package/dist/_vendor/schema/validators.d.ts +141 -121
- package/dist/_vendor/schema/validators.d.ts.map +1 -1
- package/dist/_vendor/schema/validators.js +300 -42
- package/dist/_vendor/schema/validators.js.map +1 -1
- package/dist/_vendor/svelte/index.d.ts +47 -19
- package/dist/_vendor/svelte/index.d.ts.map +1 -1
- package/dist/_vendor/svelte/index.js +250 -20
- package/dist/_vendor/svelte/index.js.map +1 -1
- package/dist/components.d.ts +2 -0
- package/dist/components.js +2 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/package.json +8 -3
|
@@ -2,16 +2,17 @@ import { createContext, useContext, useEffect, useMemo, useState } from "react";
|
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
//#region src/index.tsx
|
|
4
4
|
/**
|
|
5
|
-
* Pass `"skip"` as the args argument to `useQuery`
|
|
6
|
-
*
|
|
5
|
+
* Pass `"skip"` as the args argument to `useQuery`, `useQueryState`,
|
|
6
|
+
* `useQueries`, or `usePaginatedQuery` to suppress the subscription entirely.
|
|
7
7
|
*/
|
|
8
8
|
const skip = "skip";
|
|
9
|
+
const defaultRuntimeStatus = {
|
|
10
|
+
kind: "starting",
|
|
11
|
+
reason: "booting"
|
|
12
|
+
};
|
|
9
13
|
const SyncoreContext = createContext(null);
|
|
10
14
|
/**
|
|
11
15
|
* Provide a Syncore client to React descendants.
|
|
12
|
-
*
|
|
13
|
-
* Wrap your app with this component to use Syncore hooks like `useQuery` and
|
|
14
|
-
* `useMutation`.
|
|
15
16
|
*/
|
|
16
17
|
function SyncoreProvider({ client, children }) {
|
|
17
18
|
return /* @__PURE__ */ jsx(SyncoreContext.Provider, {
|
|
@@ -21,8 +22,6 @@ function SyncoreProvider({ client, children }) {
|
|
|
21
22
|
}
|
|
22
23
|
/**
|
|
23
24
|
* Read the active Syncore client from React context.
|
|
24
|
-
*
|
|
25
|
-
* Throws if used outside of {@link SyncoreProvider}.
|
|
26
25
|
*/
|
|
27
26
|
function useSyncore() {
|
|
28
27
|
const client = useContext(SyncoreContext);
|
|
@@ -30,15 +29,40 @@ function useSyncore() {
|
|
|
30
29
|
return client;
|
|
31
30
|
}
|
|
32
31
|
/**
|
|
33
|
-
*
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
* Subscribe to the active Syncore client's runtime lifecycle status.
|
|
33
|
+
*/
|
|
34
|
+
function useSyncoreStatus() {
|
|
35
|
+
const client = useSyncore();
|
|
36
|
+
const watch = useMemo(() => client.watchRuntimeStatus(), [client]);
|
|
37
|
+
const [status, setStatus] = useState(() => readRuntimeStatusSnapshot(watch));
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
const sync = () => {
|
|
40
|
+
setStatus(readRuntimeStatusSnapshot(watch));
|
|
41
|
+
};
|
|
42
|
+
sync();
|
|
43
|
+
return watch.onUpdate(sync);
|
|
44
|
+
}, [watch]);
|
|
45
|
+
useEffect(() => () => {
|
|
46
|
+
watch.dispose?.();
|
|
47
|
+
}, [watch]);
|
|
48
|
+
return status;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Load a reactive Syncore query and return only the data for the common case.
|
|
38
52
|
*/
|
|
39
53
|
function useQuery(reference, ...args) {
|
|
54
|
+
const state = useQueryState(reference, ...args);
|
|
55
|
+
if (state.error) throw state.error;
|
|
56
|
+
return state.data;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Load a reactive Syncore query and keep the full local state.
|
|
60
|
+
*/
|
|
61
|
+
function useQueryState(reference, ...args) {
|
|
40
62
|
const isSkipped = args[0] === skip;
|
|
41
|
-
const
|
|
63
|
+
const client = useSyncore();
|
|
64
|
+
const runtimeStatus = useSyncoreStatus();
|
|
65
|
+
const watch = useManagedQueryWatch(client, reference, isSkipped ? void 0 : normalizeOptionalArgs(args), isSkipped);
|
|
42
66
|
const [snapshot, setSnapshot] = useState(() => isSkipped ? noOpSnapshot : readWatchSnapshot(watch));
|
|
43
67
|
useEffect(() => {
|
|
44
68
|
if (isSkipped) {
|
|
@@ -51,18 +75,8 @@ function useQuery(reference, ...args) {
|
|
|
51
75
|
sync();
|
|
52
76
|
return watch.onUpdate(sync);
|
|
53
77
|
}, [watch, isSkipped]);
|
|
54
|
-
|
|
55
|
-
return snapshot.result;
|
|
78
|
+
return toQueryState(snapshot, runtimeStatus, isSkipped);
|
|
56
79
|
}
|
|
57
|
-
const noOpSnapshot = {
|
|
58
|
-
result: void 0,
|
|
59
|
-
error: void 0
|
|
60
|
-
};
|
|
61
|
-
const noOpWatch = {
|
|
62
|
-
onUpdate: () => () => {},
|
|
63
|
-
localQueryResult: () => void 0,
|
|
64
|
-
localQueryError: () => void 0
|
|
65
|
-
};
|
|
66
80
|
/**
|
|
67
81
|
* Construct a stable function that executes a Syncore mutation.
|
|
68
82
|
*/
|
|
@@ -78,51 +92,162 @@ function useAction(reference) {
|
|
|
78
92
|
return (...args) => client.action(reference, normalizeOptionalArgs(args));
|
|
79
93
|
}
|
|
80
94
|
/**
|
|
81
|
-
* Load
|
|
95
|
+
* Load a keyed set of Syncore queries at once with per-entry state.
|
|
82
96
|
*/
|
|
83
97
|
function useQueries(entries) {
|
|
84
98
|
const client = useSyncore();
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
99
|
+
const runtimeStatus = useSyncoreStatus();
|
|
100
|
+
const entriesKey = stableStringify(Object.entries(entries).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => ({
|
|
101
|
+
key,
|
|
102
|
+
referenceName: entry.query.name,
|
|
103
|
+
skipped: entry.args === skip,
|
|
104
|
+
args: entry.args === "skip" ? {} : normalizeOptionalArgs([entry.args ?? {}])
|
|
89
105
|
})));
|
|
90
106
|
const normalizedEntries = useMemo(() => JSON.parse(entriesKey), [entriesKey]);
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
name: entry.referenceName
|
|
96
|
-
}, entry.args)
|
|
97
|
-
})), [client, normalizedEntries]);
|
|
98
|
-
const [snapshot, setSnapshot] = useState(() => readQueriesSnapshot(watches));
|
|
99
|
-
useEffect(() => () => {
|
|
100
|
-
for (const entry of watches) entry.watch.dispose?.();
|
|
101
|
-
}, [watches]);
|
|
107
|
+
const [observer] = useState(() => new ReactQueriesObserver(client));
|
|
108
|
+
const [, setVersion] = useState(0);
|
|
109
|
+
if (observer.client !== client) observer.replaceClient(client);
|
|
110
|
+
useEffect(() => () => observer.destroy(), [observer]);
|
|
102
111
|
useEffect(() => {
|
|
103
|
-
|
|
104
|
-
|
|
112
|
+
observer.setEntries(normalizedEntries);
|
|
113
|
+
setVersion((value) => value + 1);
|
|
114
|
+
return observer.subscribe(() => {
|
|
115
|
+
setVersion((value) => value + 1);
|
|
116
|
+
});
|
|
117
|
+
}, [normalizedEntries, observer]);
|
|
118
|
+
const snapshot = observer.getSnapshot(normalizedEntries);
|
|
119
|
+
return useMemo(() => {
|
|
120
|
+
return Object.fromEntries(normalizedEntries.map((entry) => [entry.key, toQueryState(snapshot[entry.key] ?? noOpSnapshot, runtimeStatus, entry.skipped)]));
|
|
121
|
+
}, [
|
|
122
|
+
normalizedEntries,
|
|
123
|
+
runtimeStatus,
|
|
124
|
+
snapshot
|
|
125
|
+
]);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Load a paginated Syncore query as a growing reactive list.
|
|
129
|
+
*/
|
|
130
|
+
function usePaginatedQuery(reference, args, options) {
|
|
131
|
+
if (typeof options.initialNumItems !== "number" || options.initialNumItems <= 0) throw new Error(`options.initialNumItems must be a positive number. Received ${String(options.initialNumItems)}.`);
|
|
132
|
+
const runtimeStatus = useSyncoreStatus();
|
|
133
|
+
const isSkipped = args === skip;
|
|
134
|
+
const normalizedArgs = isSkipped ? {} : args ?? {};
|
|
135
|
+
const requestKey = stableStringify({
|
|
136
|
+
referenceName: reference.name,
|
|
137
|
+
args: normalizedArgs,
|
|
138
|
+
initialNumItems: options.initialNumItems,
|
|
139
|
+
skipped: isSkipped
|
|
140
|
+
});
|
|
141
|
+
const createInitialState = useMemo(() => () => ({
|
|
142
|
+
requestKey,
|
|
143
|
+
nextPageKey: 1,
|
|
144
|
+
pages: isSkipped ? [] : [{
|
|
145
|
+
key: "0",
|
|
146
|
+
cursor: null,
|
|
147
|
+
numItems: options.initialNumItems
|
|
148
|
+
}]
|
|
149
|
+
}), [
|
|
150
|
+
isSkipped,
|
|
151
|
+
options.initialNumItems,
|
|
152
|
+
requestKey
|
|
153
|
+
]);
|
|
154
|
+
const [state, setState] = useState(createInitialState);
|
|
155
|
+
let currentState = state;
|
|
156
|
+
if (currentState.requestKey !== requestKey) {
|
|
157
|
+
currentState = createInitialState();
|
|
158
|
+
setState(currentState);
|
|
159
|
+
}
|
|
160
|
+
const pageStates = useQueries(useMemo(() => {
|
|
161
|
+
const requests = {};
|
|
162
|
+
for (const page of currentState.pages) requests[page.key] = {
|
|
163
|
+
query: reference,
|
|
164
|
+
args: {
|
|
165
|
+
...normalizedArgs,
|
|
166
|
+
paginationOpts: {
|
|
167
|
+
cursor: page.cursor,
|
|
168
|
+
numItems: page.numItems
|
|
169
|
+
}
|
|
170
|
+
}
|
|
105
171
|
};
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
172
|
+
return requests;
|
|
173
|
+
}, [
|
|
174
|
+
currentState.pages,
|
|
175
|
+
normalizedArgs,
|
|
176
|
+
reference
|
|
177
|
+
]));
|
|
178
|
+
const derived = useMemo(() => {
|
|
179
|
+
const pages = [];
|
|
180
|
+
let error;
|
|
181
|
+
for (const page of currentState.pages) {
|
|
182
|
+
const pageState = pageStates[page.key];
|
|
183
|
+
if (!pageState || pageState.status === "loading") break;
|
|
184
|
+
if (pageState.status === "error") {
|
|
185
|
+
error = pageState.error;
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
if (pageState.data) pages.push(pageState.data);
|
|
189
|
+
}
|
|
190
|
+
const results = pages.flatMap((page) => page.page);
|
|
191
|
+
const lastLoadedPage = pages.at(-1);
|
|
192
|
+
const lastRequestedKey = currentState.pages.at(-1)?.key;
|
|
193
|
+
const lastRequestedState = lastRequestedKey ? pageStates[lastRequestedKey] : void 0;
|
|
194
|
+
const isLoading = !isSkipped && pages.length === 0 && !error;
|
|
195
|
+
const isLoadingMore = currentState.pages.length > pages.length || !!lastRequestedState && lastRequestedState.status === "loading" && pages.length > 0;
|
|
196
|
+
const hasMore = !!lastLoadedPage && !lastLoadedPage.isDone;
|
|
197
|
+
const status = error ? "error" : isSkipped ? "ready" : isLoading ? "loading" : isLoadingMore ? "loadingMore" : hasMore ? "ready" : "exhausted";
|
|
198
|
+
return {
|
|
199
|
+
pages,
|
|
200
|
+
results,
|
|
201
|
+
error,
|
|
202
|
+
isLoading,
|
|
203
|
+
isLoadingMore,
|
|
204
|
+
hasMore,
|
|
205
|
+
cursor: lastLoadedPage?.cursor ?? null,
|
|
206
|
+
status
|
|
110
207
|
};
|
|
111
|
-
}, [
|
|
112
|
-
|
|
208
|
+
}, [
|
|
209
|
+
currentState.pages,
|
|
210
|
+
isSkipped,
|
|
211
|
+
pageStates
|
|
212
|
+
]);
|
|
213
|
+
return {
|
|
214
|
+
...derived,
|
|
215
|
+
runtimeStatus,
|
|
216
|
+
loadMore(numItems = options.initialNumItems) {
|
|
217
|
+
if (isSkipped || derived.error || derived.isLoadingMore || !derived.hasMore || !derived.cursor) return;
|
|
218
|
+
setState((previous) => ({
|
|
219
|
+
...previous,
|
|
220
|
+
nextPageKey: previous.nextPageKey + 1,
|
|
221
|
+
pages: [...previous.pages, {
|
|
222
|
+
key: String(previous.nextPageKey),
|
|
223
|
+
cursor: derived.cursor,
|
|
224
|
+
numItems
|
|
225
|
+
}]
|
|
226
|
+
}));
|
|
227
|
+
}
|
|
228
|
+
};
|
|
113
229
|
}
|
|
114
|
-
|
|
115
|
-
|
|
230
|
+
const noOpSnapshot = {
|
|
231
|
+
data: void 0,
|
|
232
|
+
error: void 0
|
|
233
|
+
};
|
|
234
|
+
const noOpWatch = {
|
|
235
|
+
onUpdate: () => () => void 0,
|
|
236
|
+
localQueryResult: () => void 0,
|
|
237
|
+
localQueryError: () => void 0
|
|
238
|
+
};
|
|
239
|
+
function useManagedQueryWatch(client, reference, args, isSkipped = false) {
|
|
240
|
+
const argsKey = isSkipped ? skip : stableStringify(args ?? {});
|
|
116
241
|
const normalizedArgs = useMemo(() => isSkipped ? void 0 : JSON.parse(argsKey), [argsKey, isSkipped]);
|
|
117
242
|
const watch = useMemo(() => isSkipped ? noOpWatch : client.watchQuery(reference, normalizedArgs), [
|
|
118
243
|
client,
|
|
244
|
+
isSkipped,
|
|
119
245
|
normalizedArgs,
|
|
120
|
-
reference
|
|
121
|
-
isSkipped
|
|
246
|
+
reference
|
|
122
247
|
]);
|
|
123
248
|
useEffect(() => () => {
|
|
124
249
|
if (!isSkipped) watch.dispose?.();
|
|
125
|
-
}, [
|
|
250
|
+
}, [isSkipped, watch]);
|
|
126
251
|
return watch;
|
|
127
252
|
}
|
|
128
253
|
function normalizeOptionalArgs(args) {
|
|
@@ -130,12 +255,36 @@ function normalizeOptionalArgs(args) {
|
|
|
130
255
|
}
|
|
131
256
|
function readWatchSnapshot(watch) {
|
|
132
257
|
return {
|
|
133
|
-
|
|
258
|
+
data: watch.localQueryResult(),
|
|
134
259
|
error: watch.localQueryError()
|
|
135
260
|
};
|
|
136
261
|
}
|
|
137
|
-
function readQueriesSnapshot(
|
|
138
|
-
return Object.fromEntries(
|
|
262
|
+
function readQueriesSnapshot(records) {
|
|
263
|
+
return Object.fromEntries(records.map((entry) => [entry.key, entry.snapshot]));
|
|
264
|
+
}
|
|
265
|
+
function readRuntimeStatusSnapshot(watch) {
|
|
266
|
+
return watch.localQueryResult() ?? defaultRuntimeStatus;
|
|
267
|
+
}
|
|
268
|
+
function toQueryState(snapshot, runtimeStatus, isSkipped) {
|
|
269
|
+
if (isSkipped) return {
|
|
270
|
+
data: void 0,
|
|
271
|
+
error: void 0,
|
|
272
|
+
status: "skipped",
|
|
273
|
+
runtimeStatus,
|
|
274
|
+
isLoading: false,
|
|
275
|
+
isError: false,
|
|
276
|
+
isReady: false
|
|
277
|
+
};
|
|
278
|
+
const status = snapshot.error !== void 0 ? "error" : snapshot.data === void 0 ? "loading" : "success";
|
|
279
|
+
return {
|
|
280
|
+
data: snapshot.data,
|
|
281
|
+
error: snapshot.error,
|
|
282
|
+
status,
|
|
283
|
+
runtimeStatus,
|
|
284
|
+
isLoading: status === "loading",
|
|
285
|
+
isError: status === "error",
|
|
286
|
+
isReady: status === "success"
|
|
287
|
+
};
|
|
139
288
|
}
|
|
140
289
|
function stableStringify(value) {
|
|
141
290
|
return JSON.stringify(sortValue(value));
|
|
@@ -145,7 +294,80 @@ function sortValue(value) {
|
|
|
145
294
|
if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, nested]) => [key, sortValue(nested)]));
|
|
146
295
|
return value;
|
|
147
296
|
}
|
|
297
|
+
var ReactQueriesObserver = class {
|
|
298
|
+
client;
|
|
299
|
+
listeners = /* @__PURE__ */ new Set();
|
|
300
|
+
records = /* @__PURE__ */ new Map();
|
|
301
|
+
constructor(client) {
|
|
302
|
+
this.client = client;
|
|
303
|
+
}
|
|
304
|
+
replaceClient(client) {
|
|
305
|
+
this.destroy();
|
|
306
|
+
this.client = client;
|
|
307
|
+
}
|
|
308
|
+
setEntries(entries) {
|
|
309
|
+
const activeKeys = new Set(entries.map((entry) => entry.key));
|
|
310
|
+
for (const entry of entries) {
|
|
311
|
+
const requestKey = `${entry.referenceName}:${stableStringify(entry.args)}:${String(entry.skipped)}`;
|
|
312
|
+
const current = this.records.get(entry.key);
|
|
313
|
+
if (current?.requestKey === requestKey) continue;
|
|
314
|
+
current?.unsubscribe();
|
|
315
|
+
current?.watch?.dispose?.();
|
|
316
|
+
if (entry.skipped) {
|
|
317
|
+
this.records.set(entry.key, {
|
|
318
|
+
requestKey,
|
|
319
|
+
snapshot: noOpSnapshot,
|
|
320
|
+
unsubscribe: () => void 0
|
|
321
|
+
});
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
const watch = this.client.watchQuery({
|
|
325
|
+
kind: "query",
|
|
326
|
+
name: entry.referenceName
|
|
327
|
+
}, entry.args);
|
|
328
|
+
const record = {
|
|
329
|
+
requestKey,
|
|
330
|
+
snapshot: readWatchSnapshot(watch),
|
|
331
|
+
unsubscribe: () => void 0,
|
|
332
|
+
watch
|
|
333
|
+
};
|
|
334
|
+
record.unsubscribe = watch.onUpdate(() => {
|
|
335
|
+
record.snapshot = readWatchSnapshot(watch);
|
|
336
|
+
this.notify();
|
|
337
|
+
});
|
|
338
|
+
this.records.set(entry.key, record);
|
|
339
|
+
}
|
|
340
|
+
for (const [key, record] of this.records.entries()) {
|
|
341
|
+
if (activeKeys.has(key)) continue;
|
|
342
|
+
record.unsubscribe();
|
|
343
|
+
record.watch?.dispose?.();
|
|
344
|
+
this.records.delete(key);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
getSnapshot(entries) {
|
|
348
|
+
return readQueriesSnapshot(entries.map((entry) => ({
|
|
349
|
+
key: entry.key,
|
|
350
|
+
snapshot: this.records.get(entry.key)?.snapshot ?? noOpSnapshot
|
|
351
|
+
})));
|
|
352
|
+
}
|
|
353
|
+
subscribe(listener) {
|
|
354
|
+
this.listeners.add(listener);
|
|
355
|
+
return () => {
|
|
356
|
+
this.listeners.delete(listener);
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
destroy() {
|
|
360
|
+
for (const record of this.records.values()) {
|
|
361
|
+
record.unsubscribe();
|
|
362
|
+
record.watch?.dispose?.();
|
|
363
|
+
}
|
|
364
|
+
this.records.clear();
|
|
365
|
+
}
|
|
366
|
+
notify() {
|
|
367
|
+
for (const listener of this.listeners) listener();
|
|
368
|
+
}
|
|
369
|
+
};
|
|
148
370
|
//#endregion
|
|
149
|
-
export { SyncoreProvider, skip, useAction, useMutation, useQueries, useQuery, useSyncore };
|
|
371
|
+
export { SyncoreProvider, skip, useAction, useMutation, usePaginatedQuery, useQueries, useQuery, useQueryState, useSyncore, useSyncoreStatus };
|
|
150
372
|
|
|
151
373
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.tsx"],"sourcesContent":["import {\n createContext,\n type ReactNode,\n useContext,\n useEffect,\n useMemo,\n useState\n} from \"react\";\nimport type {\n FunctionReference,\n SyncoreClient,\n SyncoreWatch\n} from \"@syncore/core\";\n\ntype ManagedSyncoreWatch<TResult> = SyncoreWatch<TResult> & {\n dispose?: () => void;\n};\n\ntype OptionalArgsTuple<TArgs> =\n Record<never, never> extends TArgs ? [args?: TArgs] : [args: TArgs];\n\n/**\n * Pass `\"skip\"` as the args argument to `useQuery` to suppress the subscription\n * entirely and return `undefined` without contacting the runtime.\n */\nexport const skip = \"skip\" as const;\ntype Skip = typeof skip;\n\nconst SyncoreContext = createContext<SyncoreClient | null>(null);\n\n/**\n * Provide a Syncore client to React descendants.\n *\n * Wrap your app with this component to use Syncore hooks like `useQuery` and\n * `useMutation`.\n */\nexport function SyncoreProvider({\n client,\n children\n}: {\n client: SyncoreClient;\n children: ReactNode;\n}) {\n return (\n <SyncoreContext.Provider value={client}>{children}</SyncoreContext.Provider>\n );\n}\n\n/**\n * Read the active Syncore client from React context.\n *\n * Throws if used outside of {@link SyncoreProvider}.\n */\nexport function useSyncore(): SyncoreClient {\n const client = useContext(SyncoreContext);\n if (!client) {\n throw new Error(\"SyncoreProvider is missing from the React tree.\");\n }\n return client;\n}\n\n/**\n * Load a reactive Syncore query within a React component.\n *\n * The hook subscribes automatically and re-renders whenever the local query\n * result changes. Pass `\"skip\"` as the second argument to suppress the\n * subscription entirely and return `undefined` without contacting the runtime.\n */\nexport function useQuery<TArgs, TResult>(\n reference: FunctionReference<\"query\", TArgs, TResult>,\n ...args: OptionalArgsTuple<TArgs> | [Skip]\n): TResult | undefined {\n const isSkipped = args[0] === skip;\n const client = useSyncore();\n const watch = useManagedQueryWatch(\n client,\n reference,\n isSkipped\n ? undefined\n : normalizeOptionalArgs(args as OptionalArgsTuple<TArgs>),\n isSkipped\n );\n const [snapshot, setSnapshot] = useState(() =>\n isSkipped ? noOpSnapshot : readWatchSnapshot(watch)\n );\n\n useEffect(() => {\n if (isSkipped) {\n setSnapshot(noOpSnapshot);\n return;\n }\n const sync = () => {\n setSnapshot(readWatchSnapshot(watch));\n };\n sync();\n return watch.onUpdate(sync);\n }, [watch, isSkipped]);\n\n if (snapshot.error) {\n throw snapshot.error;\n }\n\n return snapshot.result;\n}\n\nconst noOpSnapshot = { result: undefined, error: undefined };\n\nconst noOpWatch: ManagedSyncoreWatch<never> = {\n onUpdate: () => () => {},\n localQueryResult: () => undefined,\n localQueryError: () => undefined\n};\n\n/**\n * Construct a stable function that executes a Syncore mutation.\n */\nexport function useMutation<TArgs, TResult>(\n reference: FunctionReference<\"mutation\", TArgs, TResult>\n): (...args: OptionalArgsTuple<TArgs>) => Promise<TResult> {\n const client = useSyncore();\n return (...args) => client.mutation(reference, normalizeOptionalArgs(args));\n}\n\n/**\n * Construct a stable function that executes a Syncore action.\n */\nexport function useAction<TArgs, TResult>(\n reference: FunctionReference<\"action\", TArgs, TResult>\n): (...args: OptionalArgsTuple<TArgs>) => Promise<TResult> {\n const client = useSyncore();\n return (...args) => client.action(reference, normalizeOptionalArgs(args));\n}\n\n/**\n * Load several Syncore queries at once using explicit keys.\n */\nexport function useQueries<TResult>(\n entries: Array<{\n key: string;\n reference: FunctionReference<\"query\">;\n args?: Record<string, unknown>;\n }>\n): Record<string, TResult | undefined> {\n const client = useSyncore();\n const entriesKey = stableStringify(\n entries.map((entry) => ({\n key: entry.key,\n referenceName: entry.reference.name,\n args: entry.args ?? {}\n }))\n );\n const normalizedEntries = useMemo(\n () =>\n JSON.parse(entriesKey) as Array<{\n key: string;\n referenceName: string;\n args: Record<string, unknown>;\n }>,\n [entriesKey]\n );\n const watches = useMemo(\n () =>\n normalizedEntries.map((entry) => ({\n key: entry.key,\n watch: client.watchQuery(\n { kind: \"query\", name: entry.referenceName },\n entry.args\n ) as ManagedSyncoreWatch<TResult>\n })),\n [client, normalizedEntries]\n );\n const [snapshot, setSnapshot] = useState(() => readQueriesSnapshot(watches));\n\n useEffect(\n () => () => {\n for (const entry of watches) {\n entry.watch.dispose?.();\n }\n },\n [watches]\n );\n\n useEffect(() => {\n const sync = () => {\n setSnapshot(readQueriesSnapshot(watches));\n };\n sync();\n const cleanups = watches.map((entry) => entry.watch.onUpdate(sync));\n return () => {\n for (const cleanup of cleanups) {\n cleanup();\n }\n };\n }, [watches]);\n\n return snapshot;\n}\n\nfunction useManagedQueryWatch<TArgs, TResult>(\n client: SyncoreClient,\n reference: FunctionReference<\"query\", TArgs, TResult>,\n args?: TArgs,\n isSkipped?: boolean\n): ManagedSyncoreWatch<TResult> {\n const argsKey = isSkipped ? \"skip\" : stableStringify(args ?? {});\n const normalizedArgs = useMemo(\n () => (isSkipped ? undefined : (JSON.parse(argsKey) as TArgs)),\n [argsKey, isSkipped]\n );\n const watch = useMemo<ManagedSyncoreWatch<TResult>>(\n () =>\n isSkipped\n ? noOpWatch\n : (client.watchQuery(\n reference,\n normalizedArgs!\n ) as ManagedSyncoreWatch<TResult>),\n [client, normalizedArgs, reference, isSkipped]\n );\n\n useEffect(\n () => () => {\n if (!isSkipped) watch.dispose?.();\n },\n [watch, isSkipped]\n );\n\n return watch;\n}\n\nfunction normalizeOptionalArgs<TArgs>(\n args: [] | [TArgs] | readonly unknown[]\n): TArgs {\n return (args[0] ?? {}) as TArgs;\n}\n\nfunction readWatchSnapshot<TResult>(watch: SyncoreWatch<TResult>): {\n result: TResult | undefined;\n error: Error | undefined;\n} {\n return {\n result: watch.localQueryResult(),\n error: watch.localQueryError()\n };\n}\n\nfunction readQueriesSnapshot<TResult>(\n watches: Array<{\n key: string;\n watch: ManagedSyncoreWatch<TResult>;\n }>\n): Record<string, TResult | undefined> {\n return Object.fromEntries(\n watches.map((entry) => [entry.key, entry.watch.localQueryResult()])\n );\n}\n\nfunction stableStringify(value: unknown): string {\n return JSON.stringify(sortValue(value));\n}\n\nfunction sortValue(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(sortValue);\n }\n if (value && typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, nested]) => [key, sortValue(nested)])\n );\n }\n return value;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.tsx"],"sourcesContent":["import {\n createContext,\n type ReactNode,\n useContext,\n useEffect,\n useMemo,\n useState\n} from \"react\";\nimport type {\n FunctionArgs,\n FunctionReference,\n FunctionResult,\n PaginationOptions,\n PaginationResult,\n SyncoreClient,\n SyncorePaginatedQueryStatus,\n SyncoreQueryState,\n SyncoreRuntimeStatus,\n SyncoreWatch,\n UsePaginatedQueryResult\n} from \"@syncore/core\";\n\ntype ManagedSyncoreWatch<TResult> = SyncoreWatch<TResult> & {\n dispose?: () => void;\n};\n\ntype OptionalArgsTuple<TArgs> =\n Record<never, never> extends TArgs ? [args?: TArgs] : [args: TArgs];\n\ntype QueryRequestInput<\n TReference extends FunctionReference<\"query\"> = FunctionReference<\"query\">\n> = Record<never, never> extends FunctionArgs<TReference>\n ? {\n query: TReference;\n args?: FunctionArgs<TReference> | Skip;\n }\n : {\n query: TReference;\n args: FunctionArgs<TReference> | Skip;\n };\n\ntype QueriesRequestInput = Record<string, QueryRequestInput>;\n\ntype QueryStateForEntry<TEntry> = TEntry extends QueryRequestInput<\n infer TReference\n>\n ? SyncoreQueryState<FunctionResult<TReference>>\n : never;\n\nexport type UseQueriesResult<TEntries extends QueriesRequestInput> = {\n [TKey in keyof TEntries]: QueryStateForEntry<TEntries[TKey]>;\n};\n\ntype PaginatedQueryReference = FunctionReference<\n \"query\",\n Record<string, unknown>,\n PaginationResult<unknown>\n>;\n\ntype PaginatedQueryArgs<TReference extends FunctionReference<\"query\">> =\n FunctionArgs<TReference> extends { paginationOpts: PaginationOptions }\n ? Omit<FunctionArgs<TReference>, \"paginationOpts\">\n : never;\n\ntype PaginatedQueryItem<TReference extends FunctionReference<\"query\">> =\n FunctionResult<TReference> extends PaginationResult<infer TItem>\n ? TItem\n : never;\n\ntype QuerySnapshot<TResult> = {\n data: TResult | undefined;\n error: Error | undefined;\n};\n\ntype NormalizedQueryEntry = {\n key: string;\n referenceName: string;\n args: Record<string, unknown>;\n skipped: boolean;\n};\n\ntype PaginatedQueryInternalState = {\n requestKey: string;\n nextPageKey: number;\n pages: Array<{\n key: string;\n cursor: string | null;\n numItems: number;\n }>;\n};\n\ntype QueryObserverRecord = {\n requestKey: string;\n snapshot: QuerySnapshot<unknown>;\n unsubscribe: () => void;\n watch?: ManagedSyncoreWatch<unknown>;\n};\n\n/**\n * Pass `\"skip\"` as the args argument to `useQuery`, `useQueryState`,\n * `useQueries`, or `usePaginatedQuery` to suppress the subscription entirely.\n */\nexport const skip = \"skip\" as const;\ntype Skip = typeof skip;\n\nconst defaultRuntimeStatus: SyncoreRuntimeStatus = {\n kind: \"starting\",\n reason: \"booting\"\n};\n\nconst SyncoreContext = createContext<SyncoreClient | null>(null);\n\n/**\n * Provide a Syncore client to React descendants.\n */\nexport function SyncoreProvider({\n client,\n children\n}: {\n client: SyncoreClient;\n children: ReactNode;\n}) {\n return (\n <SyncoreContext.Provider value={client}>{children}</SyncoreContext.Provider>\n );\n}\n\n/**\n * Read the active Syncore client from React context.\n */\nexport function useSyncore(): SyncoreClient {\n const client = useContext(SyncoreContext);\n if (!client) {\n throw new Error(\"SyncoreProvider is missing from the React tree.\");\n }\n return client;\n}\n\n/**\n * Subscribe to the active Syncore client's runtime lifecycle status.\n */\nexport function useSyncoreStatus(): SyncoreRuntimeStatus {\n const client = useSyncore();\n const watch = useMemo(\n () => client.watchRuntimeStatus() as ManagedSyncoreWatch<SyncoreRuntimeStatus>,\n [client]\n );\n const [status, setStatus] = useState<SyncoreRuntimeStatus>(() =>\n readRuntimeStatusSnapshot(watch)\n );\n\n useEffect(() => {\n const sync = () => {\n setStatus(readRuntimeStatusSnapshot(watch));\n };\n sync();\n return watch.onUpdate(sync);\n }, [watch]);\n\n useEffect(\n () => () => {\n watch.dispose?.();\n },\n [watch]\n );\n\n return status;\n}\n\n/**\n * Load a reactive Syncore query and return only the data for the common case.\n */\nexport function useQuery<TArgs, TResult>(\n reference: FunctionReference<\"query\", TArgs, TResult>,\n ...args: OptionalArgsTuple<TArgs> | [Skip]\n): TResult | undefined {\n const state = useQueryState(reference, ...(args as OptionalArgsTuple<TArgs> | [Skip]));\n if (state.error) {\n throw state.error;\n }\n return state.data;\n}\n\n/**\n * Load a reactive Syncore query and keep the full local state.\n */\nexport function useQueryState<TArgs, TResult>(\n reference: FunctionReference<\"query\", TArgs, TResult>,\n ...args: OptionalArgsTuple<TArgs> | [Skip]\n): SyncoreQueryState<TResult> {\n const isSkipped = args[0] === skip;\n const client = useSyncore();\n const runtimeStatus = useSyncoreStatus();\n const watch = useManagedQueryWatch(\n client,\n reference,\n isSkipped\n ? undefined\n : normalizeOptionalArgs(args as OptionalArgsTuple<TArgs>),\n isSkipped\n );\n const [snapshot, setSnapshot] = useState<QuerySnapshot<TResult>>(() =>\n isSkipped ? noOpSnapshot : readWatchSnapshot(watch)\n );\n\n useEffect(() => {\n if (isSkipped) {\n setSnapshot(noOpSnapshot);\n return;\n }\n const sync = () => {\n setSnapshot(readWatchSnapshot(watch));\n };\n sync();\n return watch.onUpdate(sync);\n }, [watch, isSkipped]);\n\n return toQueryState(snapshot, runtimeStatus, isSkipped);\n}\n\n/**\n * Construct a stable function that executes a Syncore mutation.\n */\nexport function useMutation<TArgs, TResult>(\n reference: FunctionReference<\"mutation\", TArgs, TResult>\n): (...args: OptionalArgsTuple<TArgs>) => Promise<TResult> {\n const client = useSyncore();\n return (...args) => client.mutation(reference, normalizeOptionalArgs(args));\n}\n\n/**\n * Construct a stable function that executes a Syncore action.\n */\nexport function useAction<TArgs, TResult>(\n reference: FunctionReference<\"action\", TArgs, TResult>\n): (...args: OptionalArgsTuple<TArgs>) => Promise<TResult> {\n const client = useSyncore();\n return (...args) => client.action(reference, normalizeOptionalArgs(args));\n}\n\n/**\n * Load a keyed set of Syncore queries at once with per-entry state.\n */\nexport function useQueries<TEntries extends QueriesRequestInput>(\n entries: TEntries\n): UseQueriesResult<TEntries> {\n const client = useSyncore();\n const runtimeStatus = useSyncoreStatus();\n const entriesKey = stableStringify(\n Object.entries(entries)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, entry]) => ({\n key,\n referenceName: entry.query.name,\n skipped: entry.args === skip,\n args:\n entry.args === skip\n ? {}\n : normalizeOptionalArgs([entry.args ?? {}] as [] | [unknown])\n }))\n );\n const normalizedEntries = useMemo(\n () => JSON.parse(entriesKey) as NormalizedQueryEntry[],\n [entriesKey]\n );\n const [observer] = useState(() => new ReactQueriesObserver(client));\n const [, setVersion] = useState(0);\n\n if (observer.client !== client) {\n observer.replaceClient(client);\n }\n\n useEffect(() => () => observer.destroy(), [observer]);\n\n useEffect(() => {\n observer.setEntries(normalizedEntries);\n setVersion((value) => value + 1);\n return observer.subscribe(() => {\n setVersion((value) => value + 1);\n });\n }, [normalizedEntries, observer]);\n\n const snapshot = observer.getSnapshot(normalizedEntries);\n\n return useMemo(() => {\n return Object.fromEntries(\n normalizedEntries.map((entry) => [\n entry.key,\n toQueryState(\n snapshot[entry.key] ?? noOpSnapshot,\n runtimeStatus,\n entry.skipped\n )\n ])\n ) as UseQueriesResult<TEntries>;\n }, [normalizedEntries, runtimeStatus, snapshot]);\n}\n\n/**\n * Load a paginated Syncore query as a growing reactive list.\n */\nexport function usePaginatedQuery<TReference extends PaginatedQueryReference>(\n reference: TReference,\n args: PaginatedQueryArgs<TReference> | Skip,\n options: {\n initialNumItems: number;\n }\n): UsePaginatedQueryResult<PaginatedQueryItem<TReference>> {\n if (\n typeof options.initialNumItems !== \"number\" ||\n options.initialNumItems <= 0\n ) {\n throw new Error(\n `options.initialNumItems must be a positive number. Received ${String(\n options.initialNumItems\n )}.`\n );\n }\n\n const runtimeStatus = useSyncoreStatus();\n const isSkipped = args === skip;\n const normalizedArgs = isSkipped ? {} : (args ?? {});\n const requestKey = stableStringify({\n referenceName: reference.name,\n args: normalizedArgs,\n initialNumItems: options.initialNumItems,\n skipped: isSkipped\n });\n const createInitialState = useMemo(\n () => () =>\n ({\n requestKey,\n nextPageKey: 1,\n pages: isSkipped\n ? []\n : [\n {\n key: \"0\",\n cursor: null,\n numItems: options.initialNumItems\n }\n ]\n }) satisfies PaginatedQueryInternalState,\n [isSkipped, options.initialNumItems, requestKey]\n );\n const [state, setState] = useState<PaginatedQueryInternalState>(\n createInitialState\n );\n\n let currentState = state;\n if (currentState.requestKey !== requestKey) {\n currentState = createInitialState();\n setState(currentState);\n }\n\n const pageQueries = useMemo(() => {\n const requests: Record<string, QueryRequestInput> = {};\n for (const page of currentState.pages) {\n requests[page.key] = {\n query: reference,\n args: {\n ...(normalizedArgs as Record<string, unknown>),\n paginationOpts: {\n cursor: page.cursor,\n numItems: page.numItems\n }\n }\n };\n }\n return requests;\n }, [currentState.pages, normalizedArgs, reference]);\n const pageStates = useQueries(pageQueries);\n\n const derived = useMemo(() => {\n const pages: Array<PaginationResult<PaginatedQueryItem<TReference>>> = [];\n let error: Error | undefined;\n\n for (const page of currentState.pages) {\n const pageState =\n pageStates[page.key as keyof typeof pageStates] as\n | SyncoreQueryState<PaginationResult<PaginatedQueryItem<TReference>>>\n | undefined;\n if (!pageState || pageState.status === \"loading\") {\n break;\n }\n if (pageState.status === \"error\") {\n error = pageState.error;\n break;\n }\n if (pageState.data) {\n pages.push(pageState.data);\n }\n }\n\n const results = pages.flatMap((page) => page.page);\n const lastLoadedPage = pages.at(-1);\n const lastRequestedKey = currentState.pages.at(-1)?.key;\n const lastRequestedState = lastRequestedKey\n ? (pageStates[lastRequestedKey as keyof typeof pageStates] as\n | SyncoreQueryState<PaginationResult<PaginatedQueryItem<TReference>>>\n | undefined)\n : undefined;\n const isLoading = !isSkipped && pages.length === 0 && !error;\n const isLoadingMore =\n currentState.pages.length > pages.length ||\n (!!lastRequestedState && lastRequestedState.status === \"loading\" && pages.length > 0);\n const hasMore = !!lastLoadedPage && !lastLoadedPage.isDone;\n const status: SyncorePaginatedQueryStatus = error\n ? \"error\"\n : isSkipped\n ? \"ready\"\n : isLoading\n ? \"loading\"\n : isLoadingMore\n ? \"loadingMore\"\n : hasMore\n ? \"ready\"\n : \"exhausted\";\n\n return {\n pages,\n results,\n error,\n isLoading,\n isLoadingMore,\n hasMore,\n cursor: lastLoadedPage?.cursor ?? null,\n status\n };\n }, [currentState.pages, isSkipped, pageStates]);\n\n return {\n ...derived,\n runtimeStatus,\n loadMore(numItems = options.initialNumItems) {\n if (\n isSkipped ||\n derived.error ||\n derived.isLoadingMore ||\n !derived.hasMore ||\n !derived.cursor\n ) {\n return;\n }\n\n setState((previous) => ({\n ...previous,\n nextPageKey: previous.nextPageKey + 1,\n pages: [\n ...previous.pages,\n {\n key: String(previous.nextPageKey),\n cursor: derived.cursor,\n numItems\n }\n ]\n }));\n }\n };\n}\n\nconst noOpSnapshot: QuerySnapshot<never> = {\n data: undefined,\n error: undefined\n};\n\nconst noOpWatch: ManagedSyncoreWatch<never> = {\n onUpdate: () => () => undefined,\n localQueryResult: () => undefined,\n localQueryError: () => undefined\n};\n\nfunction useManagedQueryWatch<TArgs, TResult>(\n client: SyncoreClient,\n reference: FunctionReference<\"query\", TArgs, TResult>,\n args?: TArgs,\n isSkipped = false\n): ManagedSyncoreWatch<TResult> {\n const argsKey = isSkipped ? skip : stableStringify(args ?? {});\n const normalizedArgs = useMemo(\n () => (isSkipped ? undefined : (JSON.parse(argsKey) as TArgs)),\n [argsKey, isSkipped]\n );\n const watch = useMemo<ManagedSyncoreWatch<TResult>>(\n () =>\n isSkipped\n ? noOpWatch\n : (client.watchQuery(\n reference,\n normalizedArgs as TArgs\n ) as ManagedSyncoreWatch<TResult>),\n [client, isSkipped, normalizedArgs, reference]\n );\n\n useEffect(\n () => () => {\n if (!isSkipped) {\n watch.dispose?.();\n }\n },\n [isSkipped, watch]\n );\n\n return watch;\n}\n\nfunction normalizeOptionalArgs<TArgs>(\n args: [] | [TArgs] | readonly unknown[]\n): TArgs {\n return (args[0] ?? {}) as TArgs;\n}\n\nfunction readWatchSnapshot<TResult>(\n watch: SyncoreWatch<TResult>\n): QuerySnapshot<TResult> {\n return {\n data: watch.localQueryResult(),\n error: watch.localQueryError()\n };\n}\n\nfunction readQueriesSnapshot(\n records: Array<{\n key: string;\n snapshot: QuerySnapshot<unknown>;\n }>\n): Record<string, QuerySnapshot<unknown>> {\n return Object.fromEntries(\n records.map((entry) => [entry.key, entry.snapshot])\n );\n}\n\nfunction readRuntimeStatusSnapshot(\n watch: SyncoreWatch<SyncoreRuntimeStatus>\n): SyncoreRuntimeStatus {\n return watch.localQueryResult() ?? defaultRuntimeStatus;\n}\n\nfunction toQueryState<TResult>(\n snapshot: QuerySnapshot<TResult>,\n runtimeStatus: SyncoreRuntimeStatus,\n isSkipped: boolean\n): SyncoreQueryState<TResult> {\n if (isSkipped) {\n return {\n data: undefined,\n error: undefined,\n status: \"skipped\",\n runtimeStatus,\n isLoading: false,\n isError: false,\n isReady: false\n };\n }\n\n const status =\n snapshot.error !== undefined\n ? \"error\"\n : snapshot.data === undefined\n ? \"loading\"\n : \"success\";\n\n return {\n data: snapshot.data,\n error: snapshot.error,\n status,\n runtimeStatus,\n isLoading: status === \"loading\",\n isError: status === \"error\",\n isReady: status === \"success\"\n };\n}\n\nfunction stableStringify(value: unknown): string {\n return JSON.stringify(sortValue(value));\n}\n\nfunction sortValue(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(sortValue);\n }\n if (value && typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, nested]) => [key, sortValue(nested)])\n );\n }\n return value;\n}\n\nclass ReactQueriesObserver {\n readonly client: SyncoreClient;\n private readonly listeners = new Set<() => void>();\n private readonly records = new Map<string, QueryObserverRecord>();\n\n constructor(client: SyncoreClient) {\n this.client = client;\n }\n\n replaceClient(client: SyncoreClient): void {\n this.destroy();\n (this as { client: SyncoreClient }).client = client;\n }\n\n setEntries(entries: NormalizedQueryEntry[]): void {\n const activeKeys = new Set(entries.map((entry) => entry.key));\n\n for (const entry of entries) {\n const requestKey = `${entry.referenceName}:${stableStringify(entry.args)}:${String(\n entry.skipped\n )}`;\n const current = this.records.get(entry.key);\n if (current?.requestKey === requestKey) {\n continue;\n }\n\n current?.unsubscribe();\n current?.watch?.dispose?.();\n\n if (entry.skipped) {\n this.records.set(entry.key, {\n requestKey,\n snapshot: noOpSnapshot,\n unsubscribe: () => undefined\n });\n continue;\n }\n\n const watch = this.client.watchQuery(\n { kind: \"query\", name: entry.referenceName },\n entry.args\n ) as ManagedSyncoreWatch<unknown>;\n const record: QueryObserverRecord = {\n requestKey,\n snapshot: readWatchSnapshot(watch),\n unsubscribe: () => undefined,\n watch\n };\n record.unsubscribe = watch.onUpdate(() => {\n record.snapshot = readWatchSnapshot(watch);\n this.notify();\n });\n this.records.set(entry.key, record);\n }\n\n for (const [key, record] of this.records.entries()) {\n if (activeKeys.has(key)) {\n continue;\n }\n record.unsubscribe();\n record.watch?.dispose?.();\n this.records.delete(key);\n }\n }\n\n getSnapshot(entries: NormalizedQueryEntry[]): Record<string, QuerySnapshot<unknown>> {\n return readQueriesSnapshot(\n entries.map((entry) => ({\n key: entry.key,\n snapshot: this.records.get(entry.key)?.snapshot ?? noOpSnapshot\n }))\n );\n }\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n destroy(): void {\n for (const record of this.records.values()) {\n record.unsubscribe();\n record.watch?.dispose?.();\n }\n this.records.clear();\n }\n\n private notify(): void {\n for (const listener of this.listeners) {\n listener();\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Infer, ObjectValidator, ObjectValidatorShape, Validator } from "./validators.js";
|
|
1
|
+
import { FieldPaths, Infer, InferStorage, ObjectValidator, ObjectValidatorShape, Validator, ValidatorDescription } from "./validators.js";
|
|
2
2
|
|
|
3
3
|
//#region src/definition.d.ts
|
|
4
|
+
type Expand<T> = { [TKey in keyof T]: T[TKey] } & {};
|
|
4
5
|
interface IndexDefinition {
|
|
5
6
|
name: string;
|
|
6
7
|
fields: string[];
|
|
@@ -12,87 +13,71 @@ interface SearchIndexDefinition {
|
|
|
12
13
|
}
|
|
13
14
|
interface TableDefinitionOptions {
|
|
14
15
|
tableName?: string;
|
|
16
|
+
componentPath?: string;
|
|
17
|
+
componentName?: string;
|
|
15
18
|
}
|
|
16
19
|
interface TableDocumentSystemFields {
|
|
17
20
|
_id: string;
|
|
18
21
|
_creationTime: number;
|
|
19
22
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
declare class TableDefinition<TValidator extends Validator<unknown>> {
|
|
23
|
+
type GenericTableIndexes = Record<string, readonly string[]>;
|
|
24
|
+
type GenericTableSearchIndexes = Record<string, {
|
|
25
|
+
searchField: string;
|
|
26
|
+
filterFields: string;
|
|
27
|
+
}>;
|
|
28
|
+
declare class TableDefinition<TValidator extends Validator<Record<string, unknown>, Record<string, unknown>, string>, TIndexes = Record<never, never>, TSearchIndexes = Record<never, never>> {
|
|
27
29
|
readonly validator: TValidator;
|
|
28
30
|
readonly indexes: IndexDefinition[];
|
|
29
31
|
readonly searchIndexes: SearchIndexDefinition[];
|
|
30
32
|
readonly options: TableDefinitionOptions;
|
|
33
|
+
readonly document: Infer<TValidator>;
|
|
34
|
+
readonly storageDocument: InferStorage<TValidator>;
|
|
35
|
+
readonly fieldPaths: FieldPaths<TValidator>;
|
|
36
|
+
readonly indexesByName: TIndexes;
|
|
37
|
+
readonly searchIndexesByName: TSearchIndexes;
|
|
31
38
|
constructor(validator: TValidator, options?: TableDefinitionOptions);
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
* @returns The same table definition for chaining.
|
|
46
|
-
*/
|
|
47
|
-
searchIndex(name: string, config: {
|
|
48
|
-
searchField: string;
|
|
49
|
-
filterFields?: string[];
|
|
50
|
-
}): this;
|
|
39
|
+
index<const TIndexName extends string, TFirstField extends FieldPaths<TValidator>, TRestFields extends FieldPaths<TValidator>[]>(name: TIndexName, fields: [TFirstField, ...TRestFields]): TableDefinition<TValidator, Expand<TIndexes & Record<TIndexName, readonly [TFirstField, ...TRestFields]>>, TSearchIndexes>;
|
|
40
|
+
searchIndex<const TIndexName extends string, TSearchField extends FieldPaths<TValidator>, TFilterField extends FieldPaths<TValidator> = never>(name: TIndexName, config: {
|
|
41
|
+
searchField: TSearchField;
|
|
42
|
+
filterFields?: TFilterField[];
|
|
43
|
+
}): TableDefinition<TValidator, TIndexes, Expand<TSearchIndexes & Record<TIndexName, {
|
|
44
|
+
searchField: TSearchField;
|
|
45
|
+
filterFields: TFilterField;
|
|
46
|
+
}>>>;
|
|
47
|
+
parse(value: unknown): Infer<TValidator>;
|
|
48
|
+
serialize(value: Infer<TValidator>): InferStorage<TValidator>;
|
|
49
|
+
deserialize(value: unknown): Infer<TValidator>;
|
|
50
|
+
parseAndSerialize(value: unknown): InferStorage<TValidator>;
|
|
51
|
+
describe(): ValidatorDescription;
|
|
51
52
|
}
|
|
52
|
-
type AnyTableDefinition = TableDefinition<Validator<unknown
|
|
53
|
+
type AnyTableDefinition = TableDefinition<Validator<Record<string, unknown>, Record<string, unknown>, string>, GenericTableIndexes, GenericTableSearchIndexes>;
|
|
53
54
|
type InferDocument<TTable extends AnyTableDefinition> = Infer<TTable["validator"]> & TableDocumentSystemFields;
|
|
54
|
-
type InferTableInput<TTable extends AnyTableDefinition> =
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
declare function defineTable<
|
|
70
|
-
declare function defineTable<TValidator extends Validator<unknown>>(validator: TValidator): TableDefinition<TValidator>;
|
|
55
|
+
type InferTableInput<TTable extends AnyTableDefinition> = Infer<TTable["validator"]>;
|
|
56
|
+
type TableFieldPaths<TTable> = TTable extends TableDefinition<infer TValidator, unknown, unknown> ? FieldPaths<TValidator> : never;
|
|
57
|
+
type TableIndexes<TTable> = TTable extends TableDefinition<Validator<Record<string, unknown>, Record<string, unknown>, string>, infer TIndexes, unknown> ? TIndexes : never;
|
|
58
|
+
type TableSearchIndexes<TTable> = TTable extends TableDefinition<Validator<Record<string, unknown>, Record<string, unknown>, string>, unknown, infer TSearchIndexes> ? TSearchIndexes : never;
|
|
59
|
+
type TableIndexNames<TTable> = Extract<keyof TableIndexes<TTable>, string>;
|
|
60
|
+
type TableSearchIndexNames<TTable> = Extract<keyof TableSearchIndexes<TTable>, string>;
|
|
61
|
+
type TableIndexFields<TTable, TIndexName extends TableIndexNames<TTable>> = TableIndexes<TTable>[TIndexName];
|
|
62
|
+
type TableSearchIndexConfig<TTable, TIndexName extends TableSearchIndexNames<TTable>> = TableSearchIndexes<TTable>[TIndexName];
|
|
63
|
+
type TableFieldDefinitionSummary = {
|
|
64
|
+
name: string;
|
|
65
|
+
validator: ReturnType<AnyTableDefinition["describe"]>;
|
|
66
|
+
storage: ReturnType<AnyTableDefinition["describe"]>;
|
|
67
|
+
optional: boolean;
|
|
68
|
+
};
|
|
69
|
+
declare function defineTable<const TShape extends ObjectValidatorShape>(validator: TShape): TableDefinition<ObjectValidator<TShape>>;
|
|
70
|
+
declare function defineTable<TValidator extends Validator<Record<string, unknown>, Record<string, unknown>, string>>(validator: TValidator): TableDefinition<TValidator>;
|
|
71
71
|
interface SyncoreSchemaDefinition {
|
|
72
72
|
[tableName: string]: AnyTableDefinition;
|
|
73
73
|
}
|
|
74
|
-
declare class SyncoreSchema<TTables
|
|
74
|
+
declare class SyncoreSchema<TTables> {
|
|
75
75
|
readonly tables: TTables;
|
|
76
76
|
constructor(tables: TTables);
|
|
77
77
|
getTable<TTableName extends Extract<keyof TTables, string>>(tableName: TTableName): TTables[TTableName];
|
|
78
78
|
tableNames(): Array<Extract<keyof TTables, string>>;
|
|
79
79
|
}
|
|
80
|
-
|
|
81
|
-
* Define the tables that make up your Syncore app.
|
|
82
|
-
*
|
|
83
|
-
* The returned schema is used by runtimes, code generation, and type inference.
|
|
84
|
-
*
|
|
85
|
-
* @example
|
|
86
|
-
* ```ts
|
|
87
|
-
* export default defineSchema({
|
|
88
|
-
* tasks: defineTable({
|
|
89
|
-
* text: v.string(),
|
|
90
|
-
* done: v.boolean()
|
|
91
|
-
* })
|
|
92
|
-
* });
|
|
93
|
-
* ```
|
|
94
|
-
*/
|
|
95
|
-
declare function defineSchema<TTables extends SyncoreSchemaDefinition>(tables: TTables): SyncoreSchema<TTables>;
|
|
80
|
+
declare function defineSchema<const TTables extends SyncoreSchemaDefinition>(tables: TTables): SyncoreSchema<TTables>;
|
|
96
81
|
//#endregion
|
|
97
|
-
export { AnyTableDefinition, IndexDefinition, InferDocument, InferTableInput, SearchIndexDefinition, SyncoreSchema, SyncoreSchemaDefinition, TableDefinition, TableDefinitionOptions, TableDocumentSystemFields, defineSchema, defineTable };
|
|
82
|
+
export { AnyTableDefinition, GenericTableIndexes, GenericTableSearchIndexes, IndexDefinition, InferDocument, InferTableInput, SearchIndexDefinition, SyncoreSchema, SyncoreSchemaDefinition, TableDefinition, TableDefinitionOptions, TableDocumentSystemFields, TableFieldDefinitionSummary, TableFieldPaths, TableIndexFields, TableIndexNames, TableIndexes, TableSearchIndexConfig, TableSearchIndexNames, TableSearchIndexes, defineSchema, defineTable };
|
|
98
83
|
//# sourceMappingURL=definition.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition.d.ts","names":[],"sources":["../src/definition.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"definition.d.ts","names":[],"sources":["../src/definition.ts"],"mappings":"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"}
|