kitcn 0.20.0 → 0.22.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/aggregate/index.d.ts +1 -1
- package/dist/auth/client/index.d.ts +1 -1
- package/dist/auth/client/index.js +99 -31
- package/dist/auth/generated/index.d.ts +1 -1
- package/dist/auth/index.d.ts +24 -20
- package/dist/auth/index.js +75 -37
- package/dist/auth/nextjs/index.js +1 -1
- package/dist/auth/start/server/index.js +1 -1
- package/dist/{auth-store-BHk8eMnX.js → auth-store-BnsWs1xd.js} +2 -1
- package/dist/{auth-store-47WTg13B.d.ts → auth-store-DHEk0ARa.d.ts} +10 -0
- package/dist/{convex-plugin-BHVCqWTH.js → convex-plugin-D8B0oCFq.js} +16 -6
- package/dist/{generated-contract-disabled-BbPCefQM.d.ts → generated-contract-disabled-B-nmd7Ne.d.ts} +29 -16
- package/dist/orm/index.d.ts +1 -1
- package/dist/react/index.d.ts +7 -2
- package/dist/react/index.js +115 -40
- package/dist/solid/index.d.ts +51 -2
- package/dist/solid/index.js +419 -79
- package/dist/{token-oA2EMtPA.js → token-xlpENMVn.js} +1 -1
- package/dist/{where-clause-compiler-BGBNBNit.d.ts → where-clause-compiler-B_H3oio5.d.ts} +8 -8
- package/package.json +1 -1
package/dist/solid/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getFunctionName } from "convex/server";
|
|
2
|
-
import { Show, createComputed, createContext, createEffect, createMemo, createRenderEffect, createSignal, on, onCleanup, onMount, useContext } from "solid-js";
|
|
2
|
+
import { Show, batch, createComputed, createContext, createEffect, createMemo, createRenderEffect, createSignal, on, onCleanup, onMount, useContext } from "solid-js";
|
|
3
3
|
import { createComponent, memo } from "solid-js/web";
|
|
4
4
|
import { createStore } from "solid-js/store";
|
|
5
5
|
import { notifyManager, skipToken, useQueryClient } from "@tanstack/solid-query";
|
|
@@ -78,7 +78,8 @@ const defaultState = {
|
|
|
78
78
|
token: null,
|
|
79
79
|
expiresAt: null,
|
|
80
80
|
isLoading: true,
|
|
81
|
-
isAuthenticated: false
|
|
81
|
+
isAuthenticated: false,
|
|
82
|
+
authEpoch: 0
|
|
82
83
|
};
|
|
83
84
|
const AuthStoreContext = createContext(null);
|
|
84
85
|
function useAuthStore() {
|
|
@@ -91,7 +92,14 @@ function useAuthStore() {
|
|
|
91
92
|
return ctx;
|
|
92
93
|
}
|
|
93
94
|
function useAuthValue(key) {
|
|
94
|
-
|
|
95
|
+
const store = useAuthStore();
|
|
96
|
+
const bridgeAuth = useConvexAuthBridge();
|
|
97
|
+
if (!store.store && bridgeAuth) {
|
|
98
|
+
if (key === "authEpoch") return bridgeAuth.authEpoch;
|
|
99
|
+
if (key === "isAuthenticated") return bridgeAuth.isAuthenticated;
|
|
100
|
+
if (key === "isLoading") return bridgeAuth.isLoading;
|
|
101
|
+
}
|
|
102
|
+
return store.get(key);
|
|
95
103
|
}
|
|
96
104
|
function AuthProvider(props) {
|
|
97
105
|
const [state, setState] = createStore({
|
|
@@ -125,14 +133,17 @@ function useSafeConvexAuth() {
|
|
|
125
133
|
const authStore = useAuthStore();
|
|
126
134
|
const bridgeAuth = useConvexAuthBridge();
|
|
127
135
|
return {
|
|
136
|
+
get identity() {
|
|
137
|
+
return bridgeAuth?.identity ?? null;
|
|
138
|
+
},
|
|
128
139
|
get isAuthenticated() {
|
|
129
|
-
if (authStore.store) return authStore.get("isAuthenticated");
|
|
130
140
|
if (bridgeAuth !== null) return bridgeAuth.isAuthenticated;
|
|
141
|
+
if (authStore.store) return authStore.get("isAuthenticated");
|
|
131
142
|
return false;
|
|
132
143
|
},
|
|
133
144
|
get isLoading() {
|
|
134
|
-
if (authStore.store) return authStore.get("isLoading");
|
|
135
145
|
if (bridgeAuth !== null) return bridgeAuth.isLoading;
|
|
146
|
+
if (authStore.store) return authStore.get("isLoading");
|
|
136
147
|
return false;
|
|
137
148
|
}
|
|
138
149
|
};
|
|
@@ -144,6 +155,12 @@ function useSafeConvexAuth() {
|
|
|
144
155
|
function ConvexAuthBridge(props) {
|
|
145
156
|
return createComponent(ConvexAuthBridgeContext.Provider, {
|
|
146
157
|
value: {
|
|
158
|
+
get authEpoch() {
|
|
159
|
+
return props.authEpoch ?? 0;
|
|
160
|
+
},
|
|
161
|
+
get identity() {
|
|
162
|
+
return props.identity ?? null;
|
|
163
|
+
},
|
|
147
164
|
get isLoading() {
|
|
148
165
|
return props.isLoading;
|
|
149
166
|
},
|
|
@@ -991,6 +1008,19 @@ function convexInfiniteQueryOptions(funcRef, args, opts = {}, meta) {
|
|
|
991
1008
|
/** Symbol key for attaching FunctionReference to options (non-serializable) */
|
|
992
1009
|
const FUNC_REF_SYMBOL = Symbol.for("convex.funcRef");
|
|
993
1010
|
|
|
1011
|
+
//#endregion
|
|
1012
|
+
//#region src/internal/enabled.ts
|
|
1013
|
+
/**
|
|
1014
|
+
* Combine a computed gate with the caller's `enabled` option.
|
|
1015
|
+
* A predicate is preserved (never collapsed to a boolean) so TanStack Query
|
|
1016
|
+
* keeps evaluating it; `allowed: false` always wins.
|
|
1017
|
+
*/
|
|
1018
|
+
function resolveEnabled(allowed, enabled) {
|
|
1019
|
+
if (!allowed) return false;
|
|
1020
|
+
if (typeof enabled === "function") return (query) => enabled(query) !== false;
|
|
1021
|
+
return enabled ?? true;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
994
1024
|
//#endregion
|
|
995
1025
|
//#region src/solid/convex-solid.tsx
|
|
996
1026
|
/** @jsxImportSource solid-js */
|
|
@@ -1018,25 +1048,52 @@ function ConvexProvider(props) {
|
|
|
1018
1048
|
}
|
|
1019
1049
|
function ConvexProviderWithAuth(props) {
|
|
1020
1050
|
const client = props.client;
|
|
1051
|
+
const [authEpoch, setAuthEpoch] = createSignal(0);
|
|
1052
|
+
const [convexIdentity, setConvexIdentity] = createSignal(null);
|
|
1021
1053
|
const [isConvexLoading, setIsConvexLoading] = createSignal(true);
|
|
1022
1054
|
const [isConvexAuthenticated, setIsConvexAuthenticated] = createSignal(false);
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
if (!authenticated) {
|
|
1029
|
-
client.clearAuth();
|
|
1055
|
+
const settleAuth = (nextIdentity, isAuthenticated) => {
|
|
1056
|
+
batch(() => {
|
|
1057
|
+
setConvexIdentity(nextIdentity);
|
|
1058
|
+
setAuthEpoch((epoch) => epoch + 1);
|
|
1059
|
+
setIsConvexAuthenticated(isAuthenticated);
|
|
1030
1060
|
setIsConvexLoading(false);
|
|
1031
|
-
|
|
1061
|
+
});
|
|
1062
|
+
};
|
|
1063
|
+
const authSnapshot = createMemo(() => props.useAuth(), void 0, { equals: false });
|
|
1064
|
+
const isAuthLoading = createMemo(() => authSnapshot().isLoading);
|
|
1065
|
+
const isAuthenticated = createMemo(() => authSnapshot().isAuthenticated);
|
|
1066
|
+
const fetchAccessToken = createMemo(() => authSnapshot().fetchAccessToken);
|
|
1067
|
+
const identity = createMemo(() => {
|
|
1068
|
+
const snapshot = authSnapshot();
|
|
1069
|
+
return snapshot.identity === void 0 ? Symbol("legacy-auth-transition") : snapshot.identity;
|
|
1070
|
+
});
|
|
1071
|
+
let authBindingGeneration = 0;
|
|
1072
|
+
createEffect(on([
|
|
1073
|
+
isAuthLoading,
|
|
1074
|
+
isAuthenticated,
|
|
1075
|
+
fetchAccessToken,
|
|
1076
|
+
identity
|
|
1077
|
+
], () => {
|
|
1078
|
+
const generation = ++authBindingGeneration;
|
|
1079
|
+
if (isAuthLoading()) {
|
|
1080
|
+
setIsConvexLoading(true);
|
|
1032
1081
|
return;
|
|
1033
1082
|
}
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1083
|
+
const nextIdentity = identity();
|
|
1084
|
+
setIsConvexLoading(true);
|
|
1085
|
+
if (!isAuthenticated()) {
|
|
1086
|
+
client.clearAuth();
|
|
1087
|
+
settleAuth(nextIdentity, false);
|
|
1088
|
+
return;
|
|
1089
|
+
}
|
|
1090
|
+
client.setAuth(fetchAccessToken(), (isAuth) => {
|
|
1091
|
+
if (generation !== authBindingGeneration) return;
|
|
1092
|
+
settleAuth(nextIdentity, isAuth);
|
|
1037
1093
|
});
|
|
1038
|
-
});
|
|
1094
|
+
}));
|
|
1039
1095
|
onCleanup(() => {
|
|
1096
|
+
authBindingGeneration += 1;
|
|
1040
1097
|
client.clearAuth();
|
|
1041
1098
|
});
|
|
1042
1099
|
return createComponent(ConvexContext.Provider, {
|
|
@@ -1045,6 +1102,12 @@ function ConvexProviderWithAuth(props) {
|
|
|
1045
1102
|
},
|
|
1046
1103
|
get children() {
|
|
1047
1104
|
return createComponent(ConvexAuthBridge, {
|
|
1105
|
+
get authEpoch() {
|
|
1106
|
+
return authEpoch();
|
|
1107
|
+
},
|
|
1108
|
+
get identity() {
|
|
1109
|
+
return convexIdentity();
|
|
1110
|
+
},
|
|
1048
1111
|
get isAuthenticated() {
|
|
1049
1112
|
return isConvexAuthenticated();
|
|
1050
1113
|
},
|
|
@@ -1110,14 +1173,15 @@ function useConvexQueryOptions(funcRef, args, options) {
|
|
|
1110
1173
|
skipUnauth: options?.skipUnauth
|
|
1111
1174
|
});
|
|
1112
1175
|
const baseOptions = convexQuery(funcRef, isSkipped ? {} : args);
|
|
1113
|
-
const {
|
|
1176
|
+
const { enabled: userEnabled, skipUnauth, subscribe, ...queryOptions } = options ?? {};
|
|
1114
1177
|
return {
|
|
1115
1178
|
...baseOptions,
|
|
1116
1179
|
...queryOptions,
|
|
1117
|
-
enabled: isSkipped
|
|
1180
|
+
enabled: resolveEnabled(!(isSkipped || authSkip.shouldSkip), userEnabled),
|
|
1118
1181
|
meta: {
|
|
1119
1182
|
...baseOptions.meta,
|
|
1120
1183
|
authType: authSkip.authType,
|
|
1184
|
+
skipUnauth,
|
|
1121
1185
|
subscribe: subscribe !== false
|
|
1122
1186
|
}
|
|
1123
1187
|
};
|
|
@@ -1155,13 +1219,15 @@ function useConvexInfiniteQueryOptions(funcRef, args, opts) {
|
|
|
1155
1219
|
enabled: isSkipped ? false : enabledOpt,
|
|
1156
1220
|
skipUnauth: opts.skipUnauth
|
|
1157
1221
|
});
|
|
1158
|
-
const enabled = isSkipped || authSkip.shouldSkip ? false : enabledOpt;
|
|
1159
1222
|
const baseOptions = convexInfiniteQueryOptions(funcRef, isSkipped ? {} : args, {
|
|
1160
1223
|
...opts,
|
|
1161
|
-
enabled
|
|
1224
|
+
enabled: void 0
|
|
1162
1225
|
}, meta);
|
|
1163
1226
|
return {
|
|
1164
1227
|
...baseOptions,
|
|
1228
|
+
get enabled() {
|
|
1229
|
+
return resolveEnabled(!(isSkipped || authSkip.shouldSkip), opts.enabled);
|
|
1230
|
+
},
|
|
1165
1231
|
meta: {
|
|
1166
1232
|
...baseOptions.meta,
|
|
1167
1233
|
authType: authSkip.authType
|
|
@@ -1195,11 +1261,16 @@ function useConvexActionQueryOptions(action, args, options) {
|
|
|
1195
1261
|
skipUnauth: options?.skipUnauth
|
|
1196
1262
|
});
|
|
1197
1263
|
const baseOptions = convexAction(action, isSkipped ? {} : args);
|
|
1198
|
-
const {
|
|
1264
|
+
const { enabled: userEnabled, skipUnauth, ...queryOptions } = options ?? {};
|
|
1199
1265
|
return {
|
|
1200
1266
|
...baseOptions,
|
|
1201
1267
|
...queryOptions,
|
|
1202
|
-
enabled: isSkipped
|
|
1268
|
+
enabled: resolveEnabled(!(isSkipped || authSkip.shouldSkip), userEnabled),
|
|
1269
|
+
meta: {
|
|
1270
|
+
...baseOptions.meta,
|
|
1271
|
+
authType: authSkip.authType,
|
|
1272
|
+
skipUnauth
|
|
1273
|
+
}
|
|
1203
1274
|
};
|
|
1204
1275
|
}
|
|
1205
1276
|
/**
|
|
@@ -1528,7 +1599,39 @@ function createCRPCContext(options) {
|
|
|
1528
1599
|
const HttpProxyContext = createContext(void 0);
|
|
1529
1600
|
function CRPCProvider(props) {
|
|
1530
1601
|
const authStore = useAuthStore();
|
|
1602
|
+
const bridgeAuth = useConvexAuthBridge();
|
|
1603
|
+
const safeAuth = useSafeConvexAuth();
|
|
1604
|
+
const auth = bridgeAuth ?? safeAuth;
|
|
1531
1605
|
const fetchAccessToken = useFetchAccessToken();
|
|
1606
|
+
props.convexQueryClient.updateAuthStore(authStore.store ? authStore : void 0);
|
|
1607
|
+
let previousAuth;
|
|
1608
|
+
let authGeneration = 0;
|
|
1609
|
+
let transitionClear;
|
|
1610
|
+
createEffect(() => {
|
|
1611
|
+
const generation = ++authGeneration;
|
|
1612
|
+
const currentAuth = {
|
|
1613
|
+
identity: auth.identity,
|
|
1614
|
+
isAuthenticated: auth.isAuthenticated,
|
|
1615
|
+
isLoading: auth.isLoading
|
|
1616
|
+
};
|
|
1617
|
+
const previous = previousAuth;
|
|
1618
|
+
previousAuth = currentAuth;
|
|
1619
|
+
if (currentAuth.isLoading) {
|
|
1620
|
+
if (!previous?.isLoading) transitionClear = props.convexQueryClient.resetAuthQueries({ refetch: false });
|
|
1621
|
+
return;
|
|
1622
|
+
}
|
|
1623
|
+
if (previous?.isLoading) {
|
|
1624
|
+
const pendingClear = transitionClear;
|
|
1625
|
+
transitionClear = void 0;
|
|
1626
|
+
(async () => {
|
|
1627
|
+
const clientGeneration = await pendingClear;
|
|
1628
|
+
if (generation !== authGeneration) return;
|
|
1629
|
+
await props.convexQueryClient.resetAuthQueries({ generation: clientGeneration });
|
|
1630
|
+
})();
|
|
1631
|
+
return;
|
|
1632
|
+
}
|
|
1633
|
+
if (!previous || previous.identity !== currentAuth.identity || previous.isAuthenticated !== currentAuth.isAuthenticated) props.convexQueryClient.resetAuthQueries();
|
|
1634
|
+
});
|
|
1532
1635
|
const proxy = createCRPCOptionsProxy(api, meta, options.transformer);
|
|
1533
1636
|
const vanillaClient = createVanillaCRPCProxy(api, meta, props.convexClient, options.transformer);
|
|
1534
1637
|
const httpProxy = (() => {
|
|
@@ -1770,6 +1873,56 @@ function createAuthMutations(authClient) {
|
|
|
1770
1873
|
};
|
|
1771
1874
|
}
|
|
1772
1875
|
|
|
1876
|
+
//#endregion
|
|
1877
|
+
//#region src/internal/auth-reset.ts
|
|
1878
|
+
/**
|
|
1879
|
+
* Erase the cached result of every auth-bound query.
|
|
1880
|
+
*
|
|
1881
|
+
* `queryClient.resetQueries()` is not enough. It restores each query's
|
|
1882
|
+
* `initialState`, and query-core derives that from `initialData` when the query
|
|
1883
|
+
* is built, never re-deriving it once real data lands. An auth-bound entry
|
|
1884
|
+
* therefore comes back holding the previous account's rows marked `success`,
|
|
1885
|
+
* and nothing corrects it: Convex query options set `staleTime: Infinity` with
|
|
1886
|
+
* every refetch trigger off, and `resetQueries` only refetches entries that are
|
|
1887
|
+
* currently active.
|
|
1888
|
+
*
|
|
1889
|
+
* Every entry is removed so query-core forgets both its current state and its
|
|
1890
|
+
* private `initialState`. Mounted observers are rebound with `initialData`
|
|
1891
|
+
* removed, creating a pristine replacement query that future public resets
|
|
1892
|
+
* cannot use to resurrect the previous account's rows.
|
|
1893
|
+
*/
|
|
1894
|
+
async function clearAuthBoundQueries(cache, isAuthBound) {
|
|
1895
|
+
const authQueries = cache.getAll().filter((query) => isAuthBound(query));
|
|
1896
|
+
const restoreObservers = [];
|
|
1897
|
+
await Promise.all(authQueries.map((query) => query.cancel({ silent: true })));
|
|
1898
|
+
for (const query of authQueries) {
|
|
1899
|
+
const observers = [...query.observers];
|
|
1900
|
+
cache.remove(query);
|
|
1901
|
+
for (const observer of observers) {
|
|
1902
|
+
const previousOptions = observer.options;
|
|
1903
|
+
observer.setOptions({
|
|
1904
|
+
...observer.options,
|
|
1905
|
+
enabled: false,
|
|
1906
|
+
initialData: void 0,
|
|
1907
|
+
placeholderData: void 0
|
|
1908
|
+
});
|
|
1909
|
+
const suspendedOptions = observer.options;
|
|
1910
|
+
restoreObservers.push(() => {
|
|
1911
|
+
const currentOptions = observer.options;
|
|
1912
|
+
observer.setOptions({
|
|
1913
|
+
...currentOptions,
|
|
1914
|
+
enabled: observer.options === suspendedOptions ? previousOptions.enabled : currentOptions.enabled,
|
|
1915
|
+
initialData: void 0,
|
|
1916
|
+
placeholderData: void 0
|
|
1917
|
+
});
|
|
1918
|
+
});
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
return () => {
|
|
1922
|
+
for (const restoreObserver of restoreObservers) restoreObserver();
|
|
1923
|
+
};
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1773
1926
|
//#endregion
|
|
1774
1927
|
//#region src/internal/query-key.ts
|
|
1775
1928
|
/**
|
|
@@ -1828,6 +1981,31 @@ function createHashFn(fallback = hashKey) {
|
|
|
1828
1981
|
};
|
|
1829
1982
|
}
|
|
1830
1983
|
|
|
1984
|
+
//#endregion
|
|
1985
|
+
//#region src/internal/subscription-gate.ts
|
|
1986
|
+
/** Read kitcn's meta off a TanStack query. */
|
|
1987
|
+
function readConvexQueryMeta(query) {
|
|
1988
|
+
return query.meta;
|
|
1989
|
+
}
|
|
1990
|
+
/**
|
|
1991
|
+
* Auth-bound queries are cleared and resubscribed on an identity transition so
|
|
1992
|
+
* one account never renders another account's cached rows.
|
|
1993
|
+
*/
|
|
1994
|
+
function isAuthBoundQuery(query) {
|
|
1995
|
+
const authType = readConvexQueryMeta(query)?.authType;
|
|
1996
|
+
return authType === "required" || authType === "optional";
|
|
1997
|
+
}
|
|
1998
|
+
/** Whether a Convex subscription may be opened for this query. */
|
|
1999
|
+
function canSubscribeQuery(query, opts) {
|
|
2000
|
+
if (opts.isSubscribed) return false;
|
|
2001
|
+
const meta = readConvexQueryMeta(query);
|
|
2002
|
+
if (meta?.subscribe === false) return false;
|
|
2003
|
+
if (query.getObserversCount() === 0) return false;
|
|
2004
|
+
if (query.isDisabled()) return false;
|
|
2005
|
+
if (opts.shouldSkipSubscription(meta?.authType)) return false;
|
|
2006
|
+
return true;
|
|
2007
|
+
}
|
|
2008
|
+
|
|
1831
2009
|
//#endregion
|
|
1832
2010
|
//#region src/solid/client.ts
|
|
1833
2011
|
/**
|
|
@@ -1920,6 +2098,12 @@ var ConvexQueryClient = class {
|
|
|
1920
2098
|
ssrQueryMode;
|
|
1921
2099
|
/** Auth store for checking auth state */
|
|
1922
2100
|
authStore;
|
|
2101
|
+
/** In-flight clear shared by overlapping account identity transitions. */
|
|
2102
|
+
authBarrierClear;
|
|
2103
|
+
/** Blocks auth-bound work created while Convex is changing identity. */
|
|
2104
|
+
authSettlementBarrier;
|
|
2105
|
+
/** Latest account transition allowed to restore and refetch observers. */
|
|
2106
|
+
authResetGeneration = 0;
|
|
1923
2107
|
/** Delay before unsubscribing when query has no observers */
|
|
1924
2108
|
unsubscribeDelay;
|
|
1925
2109
|
/** Payload transformer used across request/response boundaries. */
|
|
@@ -1947,6 +2131,18 @@ var ConvexQueryClient = class {
|
|
|
1947
2131
|
sub.unsubscribe();
|
|
1948
2132
|
delete this.subscriptions[queryHash];
|
|
1949
2133
|
}
|
|
2134
|
+
/**
|
|
2135
|
+
* Open a Convex subscription for a query, if the shared gate allows it.
|
|
2136
|
+
* Single owner of the subscribe preconditions for every cache-event branch.
|
|
2137
|
+
*/
|
|
2138
|
+
subscribeQuery(query) {
|
|
2139
|
+
if (!canSubscribeQuery(query, {
|
|
2140
|
+
isSubscribed: !!this.subscriptions[query.queryHash],
|
|
2141
|
+
shouldSkipSubscription: (authType) => this.shouldSkipSubscription(authType)
|
|
2142
|
+
})) return;
|
|
2143
|
+
const [, funcName, args] = query.queryKey;
|
|
2144
|
+
this.createSubscription(query.queryHash, funcName, args, query.queryKey);
|
|
2145
|
+
}
|
|
1950
2146
|
/** Update auth store (for HMR where store may reset) */
|
|
1951
2147
|
updateAuthStore(authStore) {
|
|
1952
2148
|
this.authStore = authStore;
|
|
@@ -1966,12 +2162,30 @@ var ConvexQueryClient = class {
|
|
|
1966
2162
|
* Needed for useSuspenseQuery which ignores enabled: false.
|
|
1967
2163
|
*/
|
|
1968
2164
|
shouldSkipSubscription(authType) {
|
|
1969
|
-
if (!authType
|
|
2165
|
+
if (!authType) return false;
|
|
2166
|
+
if (this.authSettlementBarrier) return true;
|
|
2167
|
+
if (!this.authStore) return false;
|
|
1970
2168
|
const authState = this.getAuthState();
|
|
1971
2169
|
if (authState?.isLoading) return true;
|
|
1972
2170
|
if (authType === "required" && !authState?.isAuthenticated) return true;
|
|
1973
2171
|
return false;
|
|
1974
2172
|
}
|
|
2173
|
+
/** Hold new auth-bound requests until the latest Convex identity settles. */
|
|
2174
|
+
beginAuthSettlementBarrier() {
|
|
2175
|
+
if (this.authSettlementBarrier) return;
|
|
2176
|
+
let resolve = () => {};
|
|
2177
|
+
this.authSettlementBarrier = {
|
|
2178
|
+
promise: new Promise((resolvePromise) => {
|
|
2179
|
+
resolve = resolvePromise;
|
|
2180
|
+
}),
|
|
2181
|
+
resolve
|
|
2182
|
+
};
|
|
2183
|
+
}
|
|
2184
|
+
/** Wait through overlapping barriers and stop canceled requests. */
|
|
2185
|
+
async waitForAuthSettlement(signal) {
|
|
2186
|
+
while (this.authSettlementBarrier) await this.authSettlementBarrier.promise;
|
|
2187
|
+
signal?.throwIfAborted();
|
|
2188
|
+
}
|
|
1975
2189
|
/** Get QueryClient, throwing if not connected */
|
|
1976
2190
|
get queryClient() {
|
|
1977
2191
|
if (!this._queryClient) throw new Error("ConvexQueryClient not connected to TanStack QueryClient.");
|
|
@@ -2034,6 +2248,62 @@ var ConvexQueryClient = class {
|
|
|
2034
2248
|
}
|
|
2035
2249
|
}
|
|
2036
2250
|
/**
|
|
2251
|
+
* Advance the account generation published by the auth store.
|
|
2252
|
+
* Client state that only makes sense inside one account's result set —
|
|
2253
|
+
* paginated cursor chains — keys on it, so it is rebuilt instead of reused.
|
|
2254
|
+
*/
|
|
2255
|
+
bumpAuthEpoch() {
|
|
2256
|
+
if (!this.authStore) return;
|
|
2257
|
+
this.authStore.set("authEpoch", this.authStore.get("authEpoch") + 1);
|
|
2258
|
+
}
|
|
2259
|
+
/** Drop auth-bound data without fetching while Convex changes identity. */
|
|
2260
|
+
async clearAuthQueries() {
|
|
2261
|
+
const queryCache = this.queryClient.getQueryCache();
|
|
2262
|
+
for (const query of queryCache.getAll()) {
|
|
2263
|
+
if (!isAuthBoundQuery(query)) continue;
|
|
2264
|
+
this.cancelPendingUnsubscribe(query.queryHash);
|
|
2265
|
+
this.unsubscribeQueryByHash(query.queryHash);
|
|
2266
|
+
}
|
|
2267
|
+
this.bumpAuthEpoch();
|
|
2268
|
+
return clearAuthBoundQueries(queryCache, (query) => isAuthBoundQuery(query));
|
|
2269
|
+
}
|
|
2270
|
+
/** Refetch and resubscribe auth-bound queries after Convex settles. */
|
|
2271
|
+
async refetchAuthQueries(generation) {
|
|
2272
|
+
const queryCache = this.queryClient.getQueryCache();
|
|
2273
|
+
await this.queryClient.refetchQueries({
|
|
2274
|
+
predicate: (query) => isAuthBoundQuery(query),
|
|
2275
|
+
type: "active"
|
|
2276
|
+
});
|
|
2277
|
+
if (generation !== this.authResetGeneration) return;
|
|
2278
|
+
for (const query of queryCache.getAll()) if (isAuthBoundQuery(query)) this.subscribeQuery(query);
|
|
2279
|
+
}
|
|
2280
|
+
/**
|
|
2281
|
+
* Drop every auth-bound cache entry and resubscribe.
|
|
2282
|
+
* Call after an identity transition when no separate settlement barrier owns
|
|
2283
|
+
* the clear/refetch phases.
|
|
2284
|
+
*/
|
|
2285
|
+
async resetAuthQueries(options = {}) {
|
|
2286
|
+
if (options.refetch === false) {
|
|
2287
|
+
const generation = ++this.authResetGeneration;
|
|
2288
|
+
this.beginAuthSettlementBarrier();
|
|
2289
|
+
this.authBarrierClear ??= this.clearAuthQueries();
|
|
2290
|
+
await this.authBarrierClear;
|
|
2291
|
+
return generation;
|
|
2292
|
+
}
|
|
2293
|
+
const generation = options.generation ?? ++this.authResetGeneration;
|
|
2294
|
+
if (generation !== this.authResetGeneration) return generation;
|
|
2295
|
+
this.authBarrierClear ??= this.clearAuthQueries();
|
|
2296
|
+
const restoreObservers = await this.authBarrierClear;
|
|
2297
|
+
if (generation !== this.authResetGeneration) return generation;
|
|
2298
|
+
this.authBarrierClear = void 0;
|
|
2299
|
+
const settlementBarrier = this.authSettlementBarrier;
|
|
2300
|
+
this.authSettlementBarrier = void 0;
|
|
2301
|
+
settlementBarrier?.resolve();
|
|
2302
|
+
restoreObservers();
|
|
2303
|
+
await this.refetchAuthQueries(generation);
|
|
2304
|
+
return generation;
|
|
2305
|
+
}
|
|
2306
|
+
/**
|
|
2037
2307
|
* Batch update all subscriptions.
|
|
2038
2308
|
* Called internally when Convex client reconnects.
|
|
2039
2309
|
*/
|
|
@@ -2107,26 +2377,13 @@ var ConvexQueryClient = class {
|
|
|
2107
2377
|
this.cancelPendingUnsubscribe(event.query.queryHash);
|
|
2108
2378
|
this.unsubscribeQueryByHash(event.query.queryHash);
|
|
2109
2379
|
break;
|
|
2110
|
-
case "added":
|
|
2111
|
-
|
|
2112
|
-
if (meta?.subscribe === false) break;
|
|
2113
|
-
const [, funcName, args] = event.query.queryKey;
|
|
2114
|
-
if (event.query.getObserversCount() === 0) break;
|
|
2115
|
-
if (this.shouldSkipSubscription(meta?.authType)) break;
|
|
2116
|
-
this.createSubscription(event.query.queryHash, funcName, args, event.query.queryKey);
|
|
2380
|
+
case "added":
|
|
2381
|
+
this.subscribeQuery(event.query);
|
|
2117
2382
|
break;
|
|
2118
|
-
|
|
2119
|
-
case "observerAdded": {
|
|
2383
|
+
case "observerAdded":
|
|
2120
2384
|
this.cancelPendingUnsubscribe(event.query.queryHash);
|
|
2121
|
-
|
|
2122
|
-
if (event.query.options.enabled === false) break;
|
|
2123
|
-
const meta = event.query.meta;
|
|
2124
|
-
if (meta?.subscribe === false) break;
|
|
2125
|
-
const [, funcName, args] = event.query.queryKey;
|
|
2126
|
-
if (this.shouldSkipSubscription(meta?.authType)) break;
|
|
2127
|
-
this.createSubscription(event.query.queryHash, funcName, args, event.query.queryKey);
|
|
2385
|
+
this.subscribeQuery(event.query);
|
|
2128
2386
|
break;
|
|
2129
|
-
}
|
|
2130
2387
|
case "observerRemoved":
|
|
2131
2388
|
if (event.query.getObserversCount() === 0 && this.subscriptions[event.query.queryHash]) {
|
|
2132
2389
|
const queryHash = event.query.queryHash;
|
|
@@ -2142,7 +2399,7 @@ var ConvexQueryClient = class {
|
|
|
2142
2399
|
if (event.action.type === "setState" && event.action.setStateOptions?.meta === "set by ConvexQueryClient") break;
|
|
2143
2400
|
break;
|
|
2144
2401
|
case "observerOptionsUpdated": {
|
|
2145
|
-
const isDisabled = event.query.
|
|
2402
|
+
const isDisabled = event.query.isDisabled();
|
|
2146
2403
|
const isSubscribed = !!this.subscriptions[event.query.queryHash];
|
|
2147
2404
|
if (isDisabled && isSubscribed) {
|
|
2148
2405
|
this.cancelPendingUnsubscribe(event.query.queryHash);
|
|
@@ -2150,11 +2407,7 @@ var ConvexQueryClient = class {
|
|
|
2150
2407
|
break;
|
|
2151
2408
|
}
|
|
2152
2409
|
if (isSubscribed || isDisabled) break;
|
|
2153
|
-
|
|
2154
|
-
if (meta?.subscribe === false) break;
|
|
2155
|
-
const [, funcName, args] = event.query.queryKey;
|
|
2156
|
-
if (this.shouldSkipSubscription(meta?.authType)) break;
|
|
2157
|
-
this.createSubscription(event.query.queryHash, funcName, args, event.query.queryKey);
|
|
2410
|
+
this.subscribeQuery(event.query);
|
|
2158
2411
|
break;
|
|
2159
2412
|
}
|
|
2160
2413
|
}
|
|
@@ -2197,6 +2450,7 @@ var ConvexQueryClient = class {
|
|
|
2197
2450
|
return async (context) => {
|
|
2198
2451
|
const { queryKey, meta: rawMeta } = context;
|
|
2199
2452
|
const meta = rawMeta;
|
|
2453
|
+
if (!isServer && meta?.authType) await this.waitForAuthSettlement(context.signal);
|
|
2200
2454
|
if (isConvexSkipped(queryKey)) throw new Error("Skipped query should not actually run, should { enabled: false }");
|
|
2201
2455
|
if (isConvexQuery(queryKey)) {
|
|
2202
2456
|
const [, funcName, args] = queryKey;
|
|
@@ -2268,6 +2522,38 @@ function throwBecauseNotConvexQuery(context) {
|
|
|
2268
2522
|
throw new Error(`Query key is not for a Convex Query: ${context.queryKey}`);
|
|
2269
2523
|
}
|
|
2270
2524
|
|
|
2525
|
+
//#endregion
|
|
2526
|
+
//#region src/internal/jwt.ts
|
|
2527
|
+
const VOLATILE_JWT_CLAIMS = new Set([
|
|
2528
|
+
"exp",
|
|
2529
|
+
"iat",
|
|
2530
|
+
"jti",
|
|
2531
|
+
"nbf"
|
|
2532
|
+
]);
|
|
2533
|
+
const decodeJwtPayload = (token) => {
|
|
2534
|
+
try {
|
|
2535
|
+
const segment = token.split(".")[1];
|
|
2536
|
+
if (!segment) return null;
|
|
2537
|
+
const binary = atob(segment.replaceAll("-", "+").replaceAll("_", "/"));
|
|
2538
|
+
const payload = JSON.parse(new TextDecoder().decode(Uint8Array.from(binary, (char) => char.charCodeAt(0))));
|
|
2539
|
+
return typeof payload === "object" && payload !== null ? payload : null;
|
|
2540
|
+
} catch {
|
|
2541
|
+
return null;
|
|
2542
|
+
}
|
|
2543
|
+
};
|
|
2544
|
+
const stableStringify = (value) => {
|
|
2545
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
2546
|
+
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
2547
|
+
return `{${Object.entries(value).filter(([, claim]) => claim !== void 0).sort(([a], [b]) => a < b ? -1 : 1).map(([key, claim]) => `${JSON.stringify(key)}:${stableStringify(claim)}`).join(",")}}`;
|
|
2548
|
+
};
|
|
2549
|
+
const decodeJwtIdentity = (token) => {
|
|
2550
|
+
const payload = decodeJwtPayload(token);
|
|
2551
|
+
if (!payload) return null;
|
|
2552
|
+
const claims = {};
|
|
2553
|
+
for (const [key, claim] of Object.entries(payload)) if (!VOLATILE_JWT_CLAIMS.has(key)) claims[key] = claim;
|
|
2554
|
+
return stableStringify(claims);
|
|
2555
|
+
};
|
|
2556
|
+
|
|
2271
2557
|
//#endregion
|
|
2272
2558
|
//#region src/solid/convex-auth-provider.tsx
|
|
2273
2559
|
/** @jsxImportSource solid-js */
|
|
@@ -2287,6 +2573,13 @@ const hasActiveSessionData = (session) => {
|
|
|
2287
2573
|
if (!session || typeof session !== "object") return false;
|
|
2288
2574
|
return Boolean(session.session);
|
|
2289
2575
|
};
|
|
2576
|
+
const getSessionId = (sessionData) => {
|
|
2577
|
+
if (!sessionData || typeof sessionData !== "object") return;
|
|
2578
|
+
const session = sessionData.session;
|
|
2579
|
+
if (!session || typeof session !== "object") return;
|
|
2580
|
+
const id = session.id;
|
|
2581
|
+
return typeof id === "string" ? id : void 0;
|
|
2582
|
+
};
|
|
2290
2583
|
/**
|
|
2291
2584
|
* Unified auth provider for Convex + Better Auth (SolidJS).
|
|
2292
2585
|
* Handles token sync and auth callbacks.
|
|
@@ -2336,21 +2629,40 @@ function ConvexAuthProviderInner(props) {
|
|
|
2336
2629
|
const authStore = useAuthStore();
|
|
2337
2630
|
const sessionAccessor = props.authClient.useSession();
|
|
2338
2631
|
let pendingTokenPromise = null;
|
|
2632
|
+
let pendingTokenSessionId;
|
|
2633
|
+
let authIdentity = null;
|
|
2634
|
+
let identityClaims = null;
|
|
2635
|
+
let identityInitialized = false;
|
|
2636
|
+
let identitySessionId;
|
|
2637
|
+
let tokenSessionId;
|
|
2638
|
+
let tokenSessionInitialized = false;
|
|
2339
2639
|
createEffect(() => {
|
|
2340
2640
|
const sessionState = sessionAccessor();
|
|
2341
2641
|
const session = sessionState.data;
|
|
2342
2642
|
const isPending = sessionState.isPending;
|
|
2643
|
+
const sessionId = getSessionId(session);
|
|
2343
2644
|
if (!hasActiveSessionData(session) && !isPending) {
|
|
2344
2645
|
authStore.set("token", null);
|
|
2345
2646
|
authStore.set("expiresAt", null);
|
|
2346
2647
|
authStore.set("isAuthenticated", false);
|
|
2648
|
+
tokenSessionId = void 0;
|
|
2649
|
+
tokenSessionInitialized = false;
|
|
2650
|
+
} else if (hasActiveSessionData(session)) {
|
|
2651
|
+
if (!tokenSessionInitialized && authStore.get("token") !== null || tokenSessionInitialized && sessionId !== tokenSessionId) {
|
|
2652
|
+
authStore.set("token", null);
|
|
2653
|
+
authStore.set("expiresAt", null);
|
|
2654
|
+
}
|
|
2655
|
+
tokenSessionId = sessionId;
|
|
2656
|
+
tokenSessionInitialized = true;
|
|
2347
2657
|
}
|
|
2348
2658
|
});
|
|
2349
2659
|
const fetchAccessToken = async ({ forceRefreshToken = false } = {}) => {
|
|
2350
2660
|
const sessionState = sessionAccessor();
|
|
2351
2661
|
const currentSession = sessionState.data;
|
|
2352
2662
|
const currentIsPending = sessionState.isPending;
|
|
2353
|
-
|
|
2663
|
+
const hasSession = hasActiveSessionData(currentSession);
|
|
2664
|
+
const currentSessionId = getSessionId(currentSession);
|
|
2665
|
+
if (!hasSession) {
|
|
2354
2666
|
if (!currentIsPending) {
|
|
2355
2667
|
authStore.set("token", null);
|
|
2356
2668
|
authStore.set("expiresAt", null);
|
|
@@ -2360,11 +2672,17 @@ function ConvexAuthProviderInner(props) {
|
|
|
2360
2672
|
const cachedToken = authStore.get("token");
|
|
2361
2673
|
const expiresAt = authStore.get("expiresAt");
|
|
2362
2674
|
const timeRemaining = expiresAt ? expiresAt - Date.now() : 0;
|
|
2363
|
-
if (!forceRefreshToken && cachedToken && expiresAt && timeRemaining >= 6e4) return cachedToken;
|
|
2364
|
-
if (!forceRefreshToken && pendingTokenPromise) return pendingTokenPromise;
|
|
2675
|
+
if (!forceRefreshToken && cachedToken && expiresAt && currentSessionId === tokenSessionId && timeRemaining >= 6e4) return cachedToken;
|
|
2676
|
+
if (!forceRefreshToken && pendingTokenPromise && pendingTokenSessionId === currentSessionId) return pendingTokenPromise;
|
|
2365
2677
|
const fetchOptions = { throw: false };
|
|
2366
|
-
if (cachedToken && decodeJwtExp(cachedToken) === null) fetchOptions.headers = { Authorization: `Bearer ${cachedToken}` };
|
|
2367
|
-
|
|
2678
|
+
if (cachedToken && currentSessionId === tokenSessionId && decodeJwtExp(cachedToken) === null) fetchOptions.headers = { Authorization: `Bearer ${cachedToken}` };
|
|
2679
|
+
const sessionStillOwnsRequest = () => {
|
|
2680
|
+
const latestSession = sessionAccessor().data;
|
|
2681
|
+
return hasActiveSessionData(latestSession) && getSessionId(latestSession) === currentSessionId;
|
|
2682
|
+
};
|
|
2683
|
+
let tokenPromise;
|
|
2684
|
+
tokenPromise = props.authClient.convex.token({ fetchOptions }).then((result) => {
|
|
2685
|
+
if (!sessionStillOwnsRequest()) return null;
|
|
2368
2686
|
const jwt = result.data?.token || null;
|
|
2369
2687
|
if (jwt) {
|
|
2370
2688
|
const exp = decodeJwtExp(jwt);
|
|
@@ -2376,21 +2694,47 @@ function ConvexAuthProviderInner(props) {
|
|
|
2376
2694
|
authStore.set("expiresAt", null);
|
|
2377
2695
|
return null;
|
|
2378
2696
|
}).catch((error) => {
|
|
2697
|
+
if (!sessionStillOwnsRequest()) return null;
|
|
2379
2698
|
authStore.set("token", null);
|
|
2380
2699
|
authStore.set("expiresAt", null);
|
|
2381
2700
|
console.error("[fetchAccessToken] error", error);
|
|
2382
2701
|
return null;
|
|
2383
2702
|
}).finally(() => {
|
|
2384
|
-
pendingTokenPromise
|
|
2703
|
+
if (pendingTokenPromise === tokenPromise) {
|
|
2704
|
+
pendingTokenPromise = null;
|
|
2705
|
+
pendingTokenSessionId = void 0;
|
|
2706
|
+
}
|
|
2385
2707
|
});
|
|
2386
|
-
|
|
2708
|
+
pendingTokenPromise = tokenPromise;
|
|
2709
|
+
pendingTokenSessionId = currentSessionId;
|
|
2710
|
+
return tokenPromise;
|
|
2387
2711
|
};
|
|
2388
2712
|
const useAuth = () => {
|
|
2389
2713
|
const sessionState = sessionAccessor();
|
|
2390
2714
|
const hasSession = hasActiveSessionData(sessionState.data);
|
|
2391
2715
|
const sessionMissing = !hasSession && !sessionState.isPending;
|
|
2392
2716
|
const token = authStore.get("token");
|
|
2717
|
+
const sessionId = getSessionId(sessionState.data);
|
|
2718
|
+
const claims = token && tokenSessionInitialized && sessionId === tokenSessionId ? decodeJwtIdentity(token) : null;
|
|
2719
|
+
const sessionChanged = identityInitialized && sessionId !== identitySessionId;
|
|
2720
|
+
if (!identityInitialized || sessionChanged) {
|
|
2721
|
+
identityInitialized = true;
|
|
2722
|
+
identitySessionId = sessionId;
|
|
2723
|
+
identityClaims = sessionChanged ? null : claims;
|
|
2724
|
+
authIdentity = !sessionChanged && claims ? JSON.stringify({
|
|
2725
|
+
claims,
|
|
2726
|
+
sessionId: sessionId ?? null
|
|
2727
|
+
}) : sessionId ?? null;
|
|
2728
|
+
} else if (claims && identityClaims === null) identityClaims = claims;
|
|
2729
|
+
else if (claims && claims !== identityClaims) {
|
|
2730
|
+
identityClaims = claims;
|
|
2731
|
+
authIdentity = JSON.stringify({
|
|
2732
|
+
claims,
|
|
2733
|
+
sessionId: sessionId ?? null
|
|
2734
|
+
});
|
|
2735
|
+
}
|
|
2393
2736
|
return {
|
|
2737
|
+
identity: authIdentity,
|
|
2394
2738
|
isLoading: sessionState.isPending && !token,
|
|
2395
2739
|
isAuthenticated: sessionMissing ? false : hasSession || token !== null,
|
|
2396
2740
|
fetchAccessToken
|
|
@@ -2543,15 +2887,8 @@ function createQueriesResults(queries) {
|
|
|
2543
2887
|
//#endregion
|
|
2544
2888
|
//#region src/solid/use-infinite-query.ts
|
|
2545
2889
|
const PAGINATION_KEY_PREFIX = "__pagination__";
|
|
2546
|
-
const paginationIdStore = /* @__PURE__ */ new Map();
|
|
2547
2890
|
let paginationIdCounter = 0;
|
|
2548
|
-
const
|
|
2549
|
-
const existing = paginationIdStore.get(storeKey);
|
|
2550
|
-
if (existing !== void 0) return existing;
|
|
2551
|
-
const newId = ++paginationIdCounter;
|
|
2552
|
-
paginationIdStore.set(storeKey, newId);
|
|
2553
|
-
return newId;
|
|
2554
|
-
};
|
|
2891
|
+
const createPaginationId = () => ++paginationIdCounter;
|
|
2555
2892
|
/** Read the identity of a Convex document, tolerating `id` and `_id` shapes */
|
|
2556
2893
|
const getItemId = (item) => {
|
|
2557
2894
|
const doc = item;
|
|
@@ -2682,8 +3019,9 @@ const useStaleCursorRecovery = ({ argsObject, combined, limit, pageResults, setS
|
|
|
2682
3019
|
* Use `useInfiniteQuery` for the public API with auth handling.
|
|
2683
3020
|
*/
|
|
2684
3021
|
const useInfiniteQueryInternal = (query, args, options) => {
|
|
2685
|
-
const { limit, enabled, placeholderData, ...queryOptions } = options;
|
|
3022
|
+
const { limit, authType, enabled, placeholderData, ...queryOptions } = options;
|
|
2686
3023
|
const safeAuth = useSafeConvexAuth();
|
|
3024
|
+
const authEpoch = () => useAuthValue("authEpoch");
|
|
2687
3025
|
const meta = useMeta();
|
|
2688
3026
|
const queryClient = useQueryClient();
|
|
2689
3027
|
const prefetchedFirstPage = createMemo(() => {
|
|
@@ -2698,7 +3036,7 @@ const useInfiniteQueryInternal = (query, args, options) => {
|
|
|
2698
3036
|
];
|
|
2699
3037
|
return queryClient.getQueryData(serverQueryKey) ?? null;
|
|
2700
3038
|
});
|
|
2701
|
-
const skip = createMemo(() => !prefetchedFirstPage() && (safeAuth.isLoading || enabled === false));
|
|
3039
|
+
const skip = createMemo(() => !prefetchedFirstPage() && (safeAuth.isLoading || enabled?.() === false));
|
|
2702
3040
|
const getPaginationState = (key) => {
|
|
2703
3041
|
const queryKey = [PAGINATION_KEY_PREFIX, key];
|
|
2704
3042
|
return queryClient.getQueryData(queryKey);
|
|
@@ -2710,10 +3048,11 @@ const useInfiniteQueryInternal = (query, args, options) => {
|
|
|
2710
3048
|
const argsObject = createMemo(() => skip() ? {} : args);
|
|
2711
3049
|
const storeKey = createMemo(() => JSON.stringify({
|
|
2712
3050
|
query: getFunctionName(query),
|
|
2713
|
-
args: argsObject()
|
|
3051
|
+
args: argsObject(),
|
|
3052
|
+
...authType ? { authEpoch: authEpoch() } : {}
|
|
2714
3053
|
}));
|
|
2715
3054
|
const createInitialState = () => {
|
|
2716
|
-
const id =
|
|
3055
|
+
const id = createPaginationId();
|
|
2717
3056
|
return {
|
|
2718
3057
|
id,
|
|
2719
3058
|
nextPageKey: 1,
|
|
@@ -2790,10 +3129,9 @@ const useInfiniteQueryInternal = (query, args, options) => {
|
|
|
2790
3129
|
const pageArgs = state().queries[key]?.args;
|
|
2791
3130
|
return {
|
|
2792
3131
|
...convexQuery(query, pageArgs ? (({ __paginationId, ...rest }) => rest)(pageArgs) : "skip", meta),
|
|
2793
|
-
enabled: !skip() && !!state().queries[key],
|
|
3132
|
+
enabled: resolveEnabled(!skip() && !!state().queries[key] && (!authType || !safeAuth.isLoading), enabled?.()),
|
|
2794
3133
|
structuralSharing: false,
|
|
2795
3134
|
...queryOptions ?? {},
|
|
2796
|
-
...index === 0 && prefetchedFirstPage() ? { initialData: prefetchedFirstPage() } : {},
|
|
2797
3135
|
...index === 0 && placeholderData ? { placeholderData: {
|
|
2798
3136
|
page: placeholderData,
|
|
2799
3137
|
isDone: false,
|
|
@@ -2941,34 +3279,36 @@ function useInfiniteQuery(infiniteOptions) {
|
|
|
2941
3279
|
const query = infiniteOptions[FUNC_REF_SYMBOL];
|
|
2942
3280
|
const onQueryUnauthorized = useAuthValue("onQueryUnauthorized");
|
|
2943
3281
|
const safeAuth = useSafeConvexAuth();
|
|
2944
|
-
const { queryKey: _queryKey, staleTime: _staleTime, refetchInterval: _refetchInterval, refetchOnMount: _refetchOnMount, refetchOnReconnect: _refetchOnReconnect, refetchOnWindowFocus: _refetchOnWindowFocus, enabled:
|
|
3282
|
+
const { queryKey: _queryKey, staleTime: _staleTime, refetchInterval: _refetchInterval, refetchOnMount: _refetchOnMount, refetchOnReconnect: _refetchOnReconnect, refetchOnWindowFocus: _refetchOnWindowFocus, enabled: _enabled, meta, ...queryOptions } = infiniteOptions;
|
|
2945
3283
|
const { queryName, args, limit, authType, skipUnauth } = meta;
|
|
2946
3284
|
const skipUnauthFinal = skipUnauth ?? false;
|
|
2947
|
-
const
|
|
2948
|
-
const
|
|
3285
|
+
const factoryEnabled = () => infiniteOptions.enabled;
|
|
3286
|
+
const isUnauthorized = createMemo(() => authType === "required" && !safeAuth.isLoading && !safeAuth.isAuthenticated);
|
|
3287
|
+
const shouldSkip = createMemo(() => factoryEnabled() === false || authType === "required" && safeAuth.isLoading || authType === "required" && !safeAuth.isAuthenticated);
|
|
2949
3288
|
const authError = createMemo(() => {
|
|
2950
|
-
if (isUnauthorized && !skipUnauthFinal) return new CRPCClientError({
|
|
3289
|
+
if (isUnauthorized() && !skipUnauthFinal) return new CRPCClientError({
|
|
2951
3290
|
code: "UNAUTHORIZED",
|
|
2952
3291
|
functionName: queryName
|
|
2953
3292
|
});
|
|
2954
3293
|
return null;
|
|
2955
3294
|
});
|
|
2956
3295
|
createEffect(() => {
|
|
2957
|
-
if (isUnauthorized && !skipUnauthFinal) onQueryUnauthorized({ queryName });
|
|
3296
|
+
if (isUnauthorized() && !skipUnauthFinal) onQueryUnauthorized({ queryName });
|
|
2958
3297
|
});
|
|
2959
3298
|
const result = useInfiniteQueryInternal(query, args, {
|
|
3299
|
+
authType,
|
|
2960
3300
|
limit,
|
|
2961
3301
|
...queryOptions,
|
|
2962
|
-
enabled: !shouldSkip
|
|
3302
|
+
enabled: () => resolveEnabled(!shouldSkip(), factoryEnabled())
|
|
2963
3303
|
});
|
|
2964
3304
|
const authLoadingApplies = authType === "optional" || authType === "required";
|
|
2965
|
-
const isSkippedUnauth = isUnauthorized && skipUnauthFinal;
|
|
3305
|
+
const isSkippedUnauth = createMemo(() => isUnauthorized() && skipUnauthFinal);
|
|
2966
3306
|
return {
|
|
2967
3307
|
get data() {
|
|
2968
|
-
return isSkippedUnauth ? [] : result.data;
|
|
3308
|
+
return isSkippedUnauth() ? [] : result.data;
|
|
2969
3309
|
},
|
|
2970
3310
|
get pages() {
|
|
2971
|
-
return isSkippedUnauth ? [] : result.pages;
|
|
3311
|
+
return isSkippedUnauth() ? [] : result.pages;
|
|
2972
3312
|
},
|
|
2973
3313
|
get error() {
|
|
2974
3314
|
return authError() ?? result.error;
|
|
@@ -2977,12 +3317,12 @@ function useInfiniteQuery(infiniteOptions) {
|
|
|
2977
3317
|
return authError() ? true : result.isError;
|
|
2978
3318
|
},
|
|
2979
3319
|
get isPlaceholderData() {
|
|
2980
|
-
return isSkippedUnauth ? false : result.isPlaceholderData;
|
|
3320
|
+
return isSkippedUnauth() ? false : result.isPlaceholderData;
|
|
2981
3321
|
},
|
|
2982
3322
|
get isLoading() {
|
|
2983
3323
|
const ae = authError();
|
|
2984
3324
|
const isClientError = isCRPCClientError(result.error);
|
|
2985
|
-
return authLoadingApplies && safeAuth.isLoading || !isClientError && !ae && !isSkippedUnauth && result.isLoading;
|
|
3325
|
+
return authLoadingApplies && safeAuth.isLoading || !isClientError && !ae && !isSkippedUnauth() && result.isLoading;
|
|
2986
3326
|
},
|
|
2987
3327
|
get isFetching() {
|
|
2988
3328
|
return result.isFetching;
|