@questpie/tanstack-query 3.15.2 → 3.17.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/README.md +7 -0
- package/dist/index.d.mts +14 -9
- package/dist/index.mjs +53 -7
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -219,6 +219,13 @@ export default async function PostsPage() {
|
|
|
219
219
|
}
|
|
220
220
|
```
|
|
221
221
|
|
|
222
|
+
TanStack Query's dehydrated state remains a JavaScript object and retains
|
|
223
|
+
QUESTPIE `Date` values. TanStack Start's Seroval hydration preserves them across
|
|
224
|
+
its serialization boundary. Other hosts must use their documented Date-aware
|
|
225
|
+
transport. If you move the state through an application-owned JSON-only
|
|
226
|
+
boundary, use a Date-aware serializer; never revive all ISO-looking strings
|
|
227
|
+
heuristically because `f.date()` and ordinary string fields must remain strings.
|
|
228
|
+
|
|
222
229
|
## Query Key Structure
|
|
223
230
|
|
|
224
231
|
```ts
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DefaultError, QueryKey, UseMutationOptions, UseQueryOptions } from "@tanstack/react-query";
|
|
2
|
-
import { ApplyQuery, CollectionRelations, CollectionSelect, FindManyOptions, FindOneOptionsBase, FindResult, GetCollection, GetGlobal, GlobalRelations, GlobalSelect, QuestpieApp, QuestpieClient, RealtimeAPI, ResolveRelationsDeep, TopicConfig, With, buildCollectionTopic, buildGlobalTopic } from "questpie/client";
|
|
2
|
+
import { ApplyQuery, CollectionRelations, CollectionSelect, FindManyOptions, FindOneOptionsBase, FindResult, GetCollection, GetGlobal, GlobalRelations, GlobalSelect, QuestpieApp, QuestpieClient, RealtimeAPI, ResolveRelationsDeep, TopicConfig, With, applyRealtimeFindEvent, applyRealtimeScalarEvent, applyRealtimeSingleEvent, buildCollectionTopic, buildGlobalTopic } from "questpie/client";
|
|
3
3
|
import { AnyChannelDefinition, ChannelParamsOf, ChannelPresenceOf } from "questpie/channels";
|
|
4
4
|
|
|
5
5
|
//#region src/index.d.ts
|
|
@@ -18,11 +18,11 @@ type QueryBuilder<TFn extends AnyAsyncFn> = HasArgs<TFn> extends false ? () => U
|
|
|
18
18
|
/**
|
|
19
19
|
* Per-query realtime flag — the second argument to `find` / `count` / `get`.
|
|
20
20
|
*/
|
|
21
|
-
type RealtimeQueryConfig = {
|
|
21
|
+
type RealtimeQueryConfig<TData = unknown> = Omit<UseQueryOptions<TData>, "queryFn" | "queryKey"> & {
|
|
22
22
|
/**
|
|
23
|
-
* Subscribe the query to
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* Subscribe the query to the multiplexed realtime stream. The initial value
|
|
24
|
+
* and later keyed changes share one stream, so realtime mode performs no
|
|
25
|
+
* separate REST fetch.
|
|
26
26
|
*/
|
|
27
27
|
realtime?: boolean;
|
|
28
28
|
};
|
|
@@ -30,7 +30,7 @@ type RealtimeQueryConfig = {
|
|
|
30
30
|
* Builder for reads that also have a live form — same as `QueryBuilder`
|
|
31
31
|
* plus the optional `{ realtime }` second argument.
|
|
32
32
|
*/
|
|
33
|
-
type LiveQueryBuilder<TFn extends AnyAsyncFn> = undefined extends FirstArg<TFn> ? (options?: FirstArg<TFn>, queryConfig?: RealtimeQueryConfig) => UseQueryOptions<QueryData<TFn>> : (options: FirstArg<TFn>, queryConfig?: RealtimeQueryConfig) => UseQueryOptions<QueryData<TFn>>;
|
|
33
|
+
type LiveQueryBuilder<TFn extends AnyAsyncFn> = undefined extends FirstArg<TFn> ? (options?: FirstArg<TFn>, queryConfig?: RealtimeQueryConfig<QueryData<TFn>>) => UseQueryOptions<QueryData<TFn>> : (options: FirstArg<TFn>, queryConfig?: RealtimeQueryConfig<QueryData<TFn>>) => UseQueryOptions<QueryData<TFn>>;
|
|
34
34
|
type KeyBuilder<TFn extends AnyAsyncFn> = HasArgs<TFn> extends false ? () => QueryKey : undefined extends FirstArg<TFn> ? (options?: FirstArg<TFn>) => QueryKey : (options: FirstArg<TFn>) => QueryKey;
|
|
35
35
|
type MutationVariables<TFn extends AnyAsyncFn> = HasArgs<TFn> extends false ? void : undefined extends FirstArg<TFn> ? FirstArg<TFn> | void : FirstArg<TFn>;
|
|
36
36
|
type MutationBuilder<TVariables, TData> = () => UseMutationOptions<TData, DefaultError, TVariables>;
|
|
@@ -64,6 +64,9 @@ type CollectionCreate<TApp extends QuestpieApp, K$1 extends CollectionKeys<TApp>
|
|
|
64
64
|
type CollectionUpdate<TApp extends QuestpieApp, K$1 extends CollectionKeys<TApp>> = QuestpieClient<TApp>["collections"][K$1]["update"];
|
|
65
65
|
type CollectionDelete<TApp extends QuestpieApp, K$1 extends CollectionKeys<TApp>> = QuestpieClient<TApp>["collections"][K$1]["delete"];
|
|
66
66
|
type CollectionRestore<TApp extends QuestpieApp, K$1 extends CollectionKeys<TApp>> = QuestpieClient<TApp>["collections"][K$1]["restore"];
|
|
67
|
+
type CollectionPurgeById<TApp extends QuestpieApp, K$1 extends CollectionKeys<TApp>> = QuestpieClient<TApp>["collections"][K$1] extends {
|
|
68
|
+
purgeById: infer TPurge extends AnyAsyncFn;
|
|
69
|
+
} ? TPurge : never;
|
|
67
70
|
type CollectionFindVersions<TApp extends QuestpieApp, K$1 extends CollectionKeys<TApp>> = QuestpieClient<TApp>["collections"][K$1]["findVersions"];
|
|
68
71
|
type CollectionRevertToVersion<TApp extends QuestpieApp, K$1 extends CollectionKeys<TApp>> = QuestpieClient<TApp>["collections"][K$1]["revertToVersion"];
|
|
69
72
|
type CollectionTransitionStage<TApp extends QuestpieApp, K$1 extends CollectionKeys<TApp>> = QuestpieClient<TApp>["collections"][K$1]["transitionStage"];
|
|
@@ -91,7 +94,7 @@ type CollectionQueryOptionsAPI<TApp extends QuestpieApp, K$1 extends CollectionK
|
|
|
91
94
|
* client's `find()` (a `ReturnType`-based extraction would instantiate the
|
|
92
95
|
* client generic at its constraint and collapse docs to `{}`).
|
|
93
96
|
*/
|
|
94
|
-
find: <TQuery extends FindManyOptions<CollectionSelectOf<TApp, K$1>, CollectionRelationsOf<TApp, K$1>> | undefined = undefined>(options?: TQuery, queryConfig?: RealtimeQueryConfig) => UseQueryOptions<FindResult<CollectionSelectOf<TApp, K$1>, CollectionRelationsOf<TApp, K$1>, TQuery>>;
|
|
97
|
+
find: <TQuery extends FindManyOptions<CollectionSelectOf<TApp, K$1>, CollectionRelationsOf<TApp, K$1>> | undefined = undefined>(options?: TQuery, queryConfig?: RealtimeQueryConfig<FindResult<CollectionSelectOf<TApp, K$1>, CollectionRelationsOf<TApp, K$1>, TQuery>>) => UseQueryOptions<FindResult<CollectionSelectOf<TApp, K$1>, CollectionRelationsOf<TApp, K$1>, TQuery>>;
|
|
95
98
|
count: LiveQueryBuilder<CollectionCount<TApp, K$1>>;
|
|
96
99
|
findOne: <TQuery extends FindOneOptionsBase<CollectionSelectOf<TApp, K$1>, CollectionRelationsOf<TApp, K$1>> | undefined = undefined>(options?: TQuery) => UseQueryOptions<ApplyQuery<CollectionSelectOf<TApp, K$1>, CollectionRelationsOf<TApp, K$1>, TQuery> | null>;
|
|
97
100
|
create: MutationBuilder<FirstArg<CollectionCreate<TApp, K$1>>, QueryData<CollectionCreate<TApp, K$1>>>;
|
|
@@ -111,7 +114,9 @@ type CollectionQueryOptionsAPI<TApp extends QuestpieApp, K$1 extends CollectionK
|
|
|
111
114
|
success: boolean;
|
|
112
115
|
count: number;
|
|
113
116
|
}>;
|
|
114
|
-
}
|
|
117
|
+
} & ([CollectionPurgeById<TApp, K$1>] extends [never] ? {} : {
|
|
118
|
+
purgeById: MutationBuilder<FirstArg<CollectionPurgeById<TApp, K$1>>, QueryData<CollectionPurgeById<TApp, K$1>>>;
|
|
119
|
+
});
|
|
115
120
|
type GlobalQueryOptionsAPI<TApp extends QuestpieApp, K$1 extends GlobalKeys<TApp>> = {
|
|
116
121
|
/** Generic per call — mirrors the direct client's `get()` narrowing. */
|
|
117
122
|
get: <TQuery extends {
|
|
@@ -176,4 +181,4 @@ type QuestpieQueryOptionsProxy<TApp extends QuestpieApp = QuestpieApp> = {
|
|
|
176
181
|
*/
|
|
177
182
|
declare function createQuestpieQueryOptions<TApp extends QuestpieApp = QuestpieApp>(client: QuestpieClient<TApp>, config?: QuestpieQueryOptionsConfig): QuestpieQueryOptionsProxy<TApp>;
|
|
178
183
|
//#endregion
|
|
179
|
-
export { type DefaultError, type QueryKey, QuestpieQueryErrorMap, QuestpieQueryOptionsConfig, QuestpieQueryOptionsProxy, type RealtimeAPI, RealtimeQueryConfig, type TopicConfig, type UseMutationOptions, type UseQueryOptions, buildCollectionTopic, buildGlobalTopic, createQuestpieQueryOptions };
|
|
184
|
+
export { type DefaultError, type QueryKey, QuestpieQueryErrorMap, QuestpieQueryOptionsConfig, QuestpieQueryOptionsProxy, type RealtimeAPI, RealtimeQueryConfig, type TopicConfig, type UseMutationOptions, type UseQueryOptions, applyRealtimeFindEvent, applyRealtimeScalarEvent, applyRealtimeSingleEvent, buildCollectionTopic, buildGlobalTopic, createQuestpieQueryOptions };
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,27 @@
|
|
|
1
1
|
import { experimental_streamedQuery, mutationOptions, queryOptions } from "@tanstack/react-query";
|
|
2
|
-
import { buildCollectionTopic, buildCollectionTopic as buildCollectionTopic$1, buildGlobalTopic, buildGlobalTopic as buildGlobalTopic$1 } from "questpie/client";
|
|
2
|
+
import { applyRealtimeFindEvent, applyRealtimeFindEvent as applyRealtimeFindEvent$1, applyRealtimeScalarEvent, applyRealtimeScalarEvent as applyRealtimeScalarEvent$1, applyRealtimeSingleEvent, applyRealtimeSingleEvent as applyRealtimeSingleEvent$1, buildCollectionTopic, buildCollectionTopic as buildCollectionTopic$1, buildGlobalTopic, buildGlobalTopic as buildGlobalTopic$1 } from "questpie/client";
|
|
3
3
|
|
|
4
4
|
//#region src/index.ts
|
|
5
5
|
const defaultErrorMap = (error) => error instanceof Error ? error : new Error(typeof error === "string" ? error : "Unknown error");
|
|
6
|
+
const isNonRetryableError = (error) => Boolean(error && typeof error === "object" && "retryable" in error && error.retryable === false);
|
|
7
|
+
const mapRealtimeError = (error, errorMap) => {
|
|
8
|
+
const mapped = errorMap(error);
|
|
9
|
+
if (isNonRetryableError(error) && (!mapped || typeof mapped !== "object" || !("retryable" in mapped))) {
|
|
10
|
+
if (mapped && typeof mapped === "object" && Object.isExtensible(mapped)) {
|
|
11
|
+
Object.defineProperty(mapped, "retryable", {
|
|
12
|
+
value: false,
|
|
13
|
+
enumerable: true
|
|
14
|
+
});
|
|
15
|
+
return mapped;
|
|
16
|
+
}
|
|
17
|
+
return Object.assign(/* @__PURE__ */ new Error("Non-retryable realtime query failed"), {
|
|
18
|
+
cause: mapped,
|
|
19
|
+
retryable: false
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return mapped;
|
|
23
|
+
};
|
|
24
|
+
const realtimeRetry = (failureCount, error) => !isNonRetryableError(error) && failureCount < 3;
|
|
6
25
|
const buildKey = (prefix, parts) => prefix.length ? [...prefix, ...parts] : parts;
|
|
7
26
|
const sanitizeKeyPart = (value) => {
|
|
8
27
|
if (value === null || value === void 0) return value;
|
|
@@ -41,9 +60,9 @@ const wrapMutationFn = (mutationFn, errorMap) => {
|
|
|
41
60
|
async function* streamRealtimeQuery(options) {
|
|
42
61
|
const { realtime, topic, signal, errorMap } = options;
|
|
43
62
|
try {
|
|
44
|
-
for await (const
|
|
63
|
+
for await (const event of realtime.streamEvents(topic, signal)) yield event;
|
|
45
64
|
} catch (error) {
|
|
46
|
-
throw
|
|
65
|
+
throw mapRealtimeError(error, errorMap);
|
|
47
66
|
}
|
|
48
67
|
}
|
|
49
68
|
/**
|
|
@@ -87,9 +106,14 @@ function createQuestpieQueryOptions(client, config = {}) {
|
|
|
87
106
|
normalizeQueryKeyOptions(options)
|
|
88
107
|
]);
|
|
89
108
|
if (queryConfig?.realtime && client.realtime) {
|
|
109
|
+
const { realtime: _realtime, ...overrides } = queryConfig;
|
|
90
110
|
const topic = buildCollectionTopic$1(collectionName, options);
|
|
91
111
|
return queryOptions({
|
|
92
112
|
queryKey: qKey,
|
|
113
|
+
retry: realtimeRetry,
|
|
114
|
+
staleTime: 0,
|
|
115
|
+
refetchOnMount: "always",
|
|
116
|
+
...overrides,
|
|
93
117
|
queryFn: experimental_streamedQuery({
|
|
94
118
|
streamFn: ({ signal }) => streamRealtimeQuery({
|
|
95
119
|
realtime: client.realtime,
|
|
@@ -97,7 +121,7 @@ function createQuestpieQueryOptions(client, config = {}) {
|
|
|
97
121
|
signal,
|
|
98
122
|
errorMap
|
|
99
123
|
}),
|
|
100
|
-
reducer:
|
|
124
|
+
reducer: applyRealtimeFindEvent$1,
|
|
101
125
|
initialValue: void 0,
|
|
102
126
|
refetchMode: "append"
|
|
103
127
|
})
|
|
@@ -117,9 +141,14 @@ function createQuestpieQueryOptions(client, config = {}) {
|
|
|
117
141
|
normalizeQueryKeyOptions(options)
|
|
118
142
|
]);
|
|
119
143
|
if (queryConfig?.realtime && client.realtime) {
|
|
144
|
+
const { realtime: _realtime, ...overrides } = queryConfig;
|
|
120
145
|
const topic = buildCollectionTopic$1(collectionName, options, "count");
|
|
121
146
|
return queryOptions({
|
|
122
147
|
queryKey: qKey,
|
|
148
|
+
retry: realtimeRetry,
|
|
149
|
+
staleTime: 0,
|
|
150
|
+
refetchOnMount: "always",
|
|
151
|
+
...overrides,
|
|
123
152
|
queryFn: experimental_streamedQuery({
|
|
124
153
|
streamFn: ({ signal }) => streamRealtimeQuery({
|
|
125
154
|
realtime: client.realtime,
|
|
@@ -127,7 +156,7 @@ function createQuestpieQueryOptions(client, config = {}) {
|
|
|
127
156
|
signal,
|
|
128
157
|
errorMap
|
|
129
158
|
}),
|
|
130
|
-
reducer: (
|
|
159
|
+
reducer: (current, event) => applyRealtimeScalarEvent$1(current, event),
|
|
131
160
|
initialValue: void 0,
|
|
132
161
|
refetchMode: "append"
|
|
133
162
|
})
|
|
@@ -196,6 +225,18 @@ function createQuestpieQueryOptions(client, config = {}) {
|
|
|
196
225
|
...stage ? { stage } : {}
|
|
197
226
|
} : void 0), errorMap)
|
|
198
227
|
}),
|
|
228
|
+
purgeById: () => mutationOptions({
|
|
229
|
+
mutationKey: buildKey(keyPrefix, [
|
|
230
|
+
...baseKey,
|
|
231
|
+
"purgeById",
|
|
232
|
+
locale,
|
|
233
|
+
stage
|
|
234
|
+
]),
|
|
235
|
+
mutationFn: wrapMutationFn((variables) => collection.purgeById(variables, locale || stage ? {
|
|
236
|
+
...locale ? { locale } : {},
|
|
237
|
+
...stage ? { stage } : {}
|
|
238
|
+
} : void 0), errorMap)
|
|
239
|
+
}),
|
|
199
240
|
findVersions: (params) => queryOptions({
|
|
200
241
|
queryKey: buildKey(keyPrefix, [
|
|
201
242
|
...baseKey,
|
|
@@ -273,9 +314,14 @@ function createQuestpieQueryOptions(client, config = {}) {
|
|
|
273
314
|
normalizeQueryKeyOptions(options)
|
|
274
315
|
]);
|
|
275
316
|
if (queryConfig?.realtime && client.realtime) {
|
|
317
|
+
const { realtime: _realtime, ...overrides } = queryConfig;
|
|
276
318
|
const topic = buildGlobalTopic$1(globalName, options);
|
|
277
319
|
return queryOptions({
|
|
278
320
|
queryKey: qKey,
|
|
321
|
+
retry: realtimeRetry,
|
|
322
|
+
staleTime: 0,
|
|
323
|
+
refetchOnMount: "always",
|
|
324
|
+
...overrides,
|
|
279
325
|
queryFn: experimental_streamedQuery({
|
|
280
326
|
streamFn: ({ signal }) => streamRealtimeQuery({
|
|
281
327
|
realtime: client.realtime,
|
|
@@ -283,7 +329,7 @@ function createQuestpieQueryOptions(client, config = {}) {
|
|
|
283
329
|
signal,
|
|
284
330
|
errorMap
|
|
285
331
|
}),
|
|
286
|
-
reducer: (
|
|
332
|
+
reducer: (current, event) => applyRealtimeSingleEvent$1(current, event),
|
|
287
333
|
initialValue: void 0,
|
|
288
334
|
refetchMode: "append"
|
|
289
335
|
})
|
|
@@ -451,4 +497,4 @@ function createQuestpieQueryOptions(client, config = {}) {
|
|
|
451
497
|
}
|
|
452
498
|
|
|
453
499
|
//#endregion
|
|
454
|
-
export { buildCollectionTopic, buildGlobalTopic, createQuestpieQueryOptions };
|
|
500
|
+
export { applyRealtimeFindEvent, applyRealtimeScalarEvent, applyRealtimeSingleEvent, buildCollectionTopic, buildGlobalTopic, createQuestpieQueryOptions };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@questpie/tanstack-query",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.17.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/questpie/questpie.git",
|
|
@@ -32,15 +32,17 @@
|
|
|
32
32
|
},
|
|
33
33
|
"scripts": {
|
|
34
34
|
"build": "tsdown",
|
|
35
|
-
"check-types": "tsc --noEmit"
|
|
35
|
+
"check-types": "tsc --noEmit",
|
|
36
|
+
"test": "bun test"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
39
|
"bun-types": "latest",
|
|
40
|
+
"seroval": "1.5.4",
|
|
39
41
|
"tsdown": "^0.18.3",
|
|
40
42
|
"zod": "^4.2.1"
|
|
41
43
|
},
|
|
42
44
|
"peerDependencies": {
|
|
43
45
|
"@tanstack/react-query": "^5.0.0",
|
|
44
|
-
"questpie": "^3.
|
|
46
|
+
"questpie": "^3.17.0"
|
|
45
47
|
}
|
|
46
48
|
}
|