@orpc/tanstack-query 1.14.9 → 1.14.11
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 +52 -48
- package/dist/index.d.mts +312 -152
- package/dist/index.d.ts +312 -152
- package/dist/index.mjs +484 -165
- package/package.json +17 -15
package/dist/index.mjs
CHANGED
|
@@ -1,35 +1,55 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveBasePathMeta, getRouterContract, ProcedureContract } from '@orpc/contract';
|
|
2
|
+
import { sortPlugins, stringifyJSON, resolveMaybeOptionalOptions, intercept, toArray, isAsyncIteratorObject, isTypescriptObject, bindMethods, getOrBind, get } from '@orpc/shared';
|
|
3
|
+
import { RECURSIVE_CLIENT_UNWRAP_KEYS } from '@orpc/client';
|
|
2
4
|
import { skipToken } from '@tanstack/query-core';
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
class CompositeRouterUtilsPlugin {
|
|
7
|
+
constructor(plugins = []) {
|
|
8
|
+
this.plugins = plugins;
|
|
9
|
+
this.plugins = sortPlugins(plugins);
|
|
10
|
+
}
|
|
11
|
+
name = "~composite";
|
|
12
|
+
init(options) {
|
|
13
|
+
for (const plugin of this.plugins) {
|
|
14
|
+
if (plugin.init) {
|
|
15
|
+
options = plugin.init(options);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return options;
|
|
19
|
+
}
|
|
20
|
+
initProcedureOptions(path, options) {
|
|
21
|
+
for (const plugin of this.plugins) {
|
|
22
|
+
if (plugin.initProcedureOptions) {
|
|
23
|
+
options = plugin.initProcedureOptions(path, options);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return options;
|
|
27
|
+
}
|
|
10
28
|
}
|
|
11
29
|
|
|
12
|
-
function
|
|
13
|
-
return
|
|
14
|
-
|
|
15
|
-
|
|
30
|
+
function generateOperationKey(path, options = {}) {
|
|
31
|
+
return [
|
|
32
|
+
...options.prefix !== void 0 ? [options.prefix] : [],
|
|
33
|
+
path,
|
|
34
|
+
{
|
|
35
|
+
...options.input !== void 0 ? { input: options.input } : {},
|
|
36
|
+
...options.type !== void 0 ? { type: options.type } : {},
|
|
37
|
+
...options.fnOptions !== void 0 ? { fnOptions: options.fnOptions } : {}
|
|
16
38
|
}
|
|
17
|
-
|
|
39
|
+
];
|
|
18
40
|
}
|
|
19
41
|
|
|
20
|
-
function
|
|
42
|
+
function liveQuery(queryFn) {
|
|
21
43
|
return async (context) => {
|
|
22
44
|
const stream = await queryFn(context);
|
|
23
45
|
let last;
|
|
24
46
|
for await (const chunk of stream) {
|
|
25
|
-
|
|
26
|
-
throw context.signal.reason;
|
|
27
|
-
}
|
|
47
|
+
context.signal?.throwIfAborted();
|
|
28
48
|
last = { chunk };
|
|
29
49
|
context.client.setQueryData(context.queryKey, chunk);
|
|
30
50
|
}
|
|
31
51
|
if (!last) {
|
|
32
|
-
throw new
|
|
52
|
+
throw new TypeError(
|
|
33
53
|
`Live query for ${stringifyJSON(context.queryKey)} did not yield any data. Ensure the query function returns an AsyncIterable with at least one chunk.`
|
|
34
54
|
);
|
|
35
55
|
}
|
|
@@ -37,7 +57,20 @@ function experimental_liveQuery(queryFn) {
|
|
|
37
57
|
};
|
|
38
58
|
}
|
|
39
59
|
|
|
40
|
-
|
|
60
|
+
class SharedUtils {
|
|
61
|
+
constructor(path, options) {
|
|
62
|
+
this.path = path;
|
|
63
|
+
this.options = options;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Generate a **partial matching** key for actions like revalidating queries, checking mutation status, etc.
|
|
67
|
+
*/
|
|
68
|
+
key(options = {}) {
|
|
69
|
+
return generateOperationKey(this.path, { ...options, prefix: this.options.prefix });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function serializableStreamedQuery(queryFn, { refetchMode = "reset", maxChunks = Number.POSITIVE_INFINITY } = {}) {
|
|
41
74
|
return async (context) => {
|
|
42
75
|
const query = context.client.getQueryCache().find({ queryKey: context.queryKey, exact: true });
|
|
43
76
|
const hasPreviousData = !!query && query.state.data !== void 0;
|
|
@@ -93,194 +126,430 @@ function limitArraySize(items, maxSize) {
|
|
|
93
126
|
return items.slice(items.length - maxSize);
|
|
94
127
|
}
|
|
95
128
|
|
|
96
|
-
const OPERATION_CONTEXT_SYMBOL = Symbol("
|
|
129
|
+
const OPERATION_CONTEXT_SYMBOL = Symbol.for("ORPC_TANSTACK_QUERY_OPERATION_CONTEXT");
|
|
97
130
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
131
|
+
const PROCEDURE_UTILS_INTERCEPTOR_KEYS = [
|
|
132
|
+
"queryInterceptors",
|
|
133
|
+
"streamedInterceptors",
|
|
134
|
+
"liveInterceptors",
|
|
135
|
+
"infiniteInterceptors",
|
|
136
|
+
"mutationInterceptors"
|
|
137
|
+
];
|
|
138
|
+
const PROCEDURE_UTILS_MODIFIER_KEYS = [
|
|
139
|
+
"queryKey",
|
|
140
|
+
"queryOptions",
|
|
141
|
+
"streamedKey",
|
|
142
|
+
"streamedOptions",
|
|
143
|
+
"liveKey",
|
|
144
|
+
"liveOptions",
|
|
145
|
+
"infiniteKey",
|
|
146
|
+
"infiniteOptions",
|
|
147
|
+
"mutationKey",
|
|
148
|
+
"mutationOptions"
|
|
149
|
+
];
|
|
150
|
+
function isProcedureUtilsOptions(value) {
|
|
151
|
+
if (!isTypescriptObject(value)) {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
for (const key in value) {
|
|
155
|
+
if (value[key] === void 0) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (key === "prefix") {
|
|
159
|
+
if (typeof value[key] !== "string") {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
} else if (PROCEDURE_UTILS_INTERCEPTOR_KEYS.includes(key)) {
|
|
163
|
+
if (!Array.isArray(value[key]) || value[key].some((i) => typeof i !== "function")) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
} else if (PROCEDURE_UTILS_MODIFIER_KEYS.includes(key)) {
|
|
167
|
+
if (!isTypescriptObject(value[key])) {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
function mergeProcedureUtilsModifier(base, override) {
|
|
175
|
+
if (typeof base !== "function" && typeof override !== "function") {
|
|
176
|
+
return { ...base, ...override };
|
|
177
|
+
}
|
|
178
|
+
const applyBase = typeof base === "function" ? base : (options) => ({ ...base, ...options });
|
|
179
|
+
const applyOverride = typeof override === "function" ? override : (options) => ({ ...override, ...options });
|
|
180
|
+
return (options) => applyOverride(applyBase(options));
|
|
181
|
+
}
|
|
182
|
+
function mergeProcedureUtilsOptions(base, override) {
|
|
183
|
+
const merged = { ...base, ...override };
|
|
184
|
+
for (const key of PROCEDURE_UTILS_INTERCEPTOR_KEYS) {
|
|
185
|
+
const baseValue = base[key];
|
|
186
|
+
const overrideValue = override[key];
|
|
187
|
+
if (baseValue && overrideValue) {
|
|
188
|
+
merged[key] = [...baseValue, ...overrideValue];
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
for (const key of PROCEDURE_UTILS_MODIFIER_KEYS) {
|
|
192
|
+
const baseValue = base[key];
|
|
193
|
+
const overrideValue = override[key];
|
|
194
|
+
if (baseValue && overrideValue) {
|
|
195
|
+
merged[key] = mergeProcedureUtilsModifier(baseValue, overrideValue);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return merged;
|
|
199
|
+
}
|
|
200
|
+
class ProcedureUtils extends SharedUtils {
|
|
201
|
+
/**
|
|
202
|
+
* Calling corresponding procedure client
|
|
203
|
+
*/
|
|
204
|
+
call;
|
|
205
|
+
constructor(path, client, options = {}) {
|
|
206
|
+
super(path, options);
|
|
207
|
+
this.call = client;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Generate a **full matching** key for [Query Options](https://orpc.dev/docs/integrations/tanstack-query#query-options).
|
|
211
|
+
*/
|
|
212
|
+
queryKey(...rest) {
|
|
213
|
+
let optionsIn = resolveMaybeOptionalOptions(rest);
|
|
214
|
+
if (typeof this.options.queryKey === "function") {
|
|
215
|
+
optionsIn = this.options.queryKey(optionsIn);
|
|
216
|
+
} else if (this.options.queryKey) {
|
|
217
|
+
optionsIn = { ...this.options.queryKey, ...optionsIn };
|
|
218
|
+
}
|
|
219
|
+
const queryKey = optionsIn.queryKey ?? generateOperationKey(this.path, { prefix: this.options.prefix, type: "query", input: optionsIn.input });
|
|
220
|
+
return queryKey;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Generate options used for useQuery/useSuspenseQuery/prefetchQuery/...
|
|
224
|
+
*/
|
|
225
|
+
queryOptions(...rest) {
|
|
226
|
+
let optionsIn = resolveMaybeOptionalOptions(rest);
|
|
227
|
+
if (typeof this.options.queryOptions === "function") {
|
|
228
|
+
optionsIn = this.options.queryOptions(optionsIn);
|
|
229
|
+
} else if (this.options.queryOptions) {
|
|
230
|
+
optionsIn = { ...this.options.queryOptions, ...optionsIn };
|
|
231
|
+
}
|
|
232
|
+
const queryKey = this.queryKey(optionsIn);
|
|
233
|
+
return {
|
|
234
|
+
...optionsIn,
|
|
235
|
+
queryKey,
|
|
236
|
+
queryFn: (fnContext) => {
|
|
237
|
+
return intercept(
|
|
238
|
+
this.options.queryInterceptors,
|
|
239
|
+
{
|
|
240
|
+
path: this.path,
|
|
116
241
|
context: {
|
|
117
242
|
[OPERATION_CONTEXT_SYMBOL]: {
|
|
118
243
|
key: queryKey,
|
|
119
244
|
type: "query"
|
|
120
245
|
},
|
|
121
246
|
...optionsIn.context
|
|
247
|
+
},
|
|
248
|
+
input: optionsIn.input,
|
|
249
|
+
fnContext
|
|
250
|
+
},
|
|
251
|
+
({ context, input, fnContext: fnContext2 }) => {
|
|
252
|
+
if (input === skipToken || optionsIn.queryFn === skipToken) {
|
|
253
|
+
throw new Error("queryFn should not be called when skipToken used for skipping");
|
|
122
254
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
...optionsIn.input === skipToken ? { enabled: false } : {},
|
|
126
|
-
...optionsIn,
|
|
127
|
-
queryKey
|
|
128
|
-
};
|
|
129
|
-
},
|
|
130
|
-
experimental_streamedKey(...[optionsIn = {}]) {
|
|
131
|
-
optionsIn = { ...options.experimental_defaults?.experimental_streamedKey, ...optionsIn };
|
|
132
|
-
const queryKey = optionsIn.queryKey ?? generateOperationKey(options.path, { type: "streamed", input: optionsIn.input, fnOptions: optionsIn.queryFnOptions });
|
|
133
|
-
return queryKey;
|
|
134
|
-
},
|
|
135
|
-
experimental_streamedOptions(...[optionsIn = {}]) {
|
|
136
|
-
optionsIn = { ...options.experimental_defaults?.experimental_streamedOptions, ...optionsIn };
|
|
137
|
-
const queryKey = utils.experimental_streamedKey(optionsIn);
|
|
138
|
-
return {
|
|
139
|
-
queryFn: experimental_serializableStreamedQuery(
|
|
140
|
-
async ({ signal }) => {
|
|
141
|
-
if (optionsIn.input === skipToken) {
|
|
142
|
-
throw new Error("queryFn should not be called with skipToken used as input");
|
|
143
|
-
}
|
|
144
|
-
const output = await client(optionsIn.input, {
|
|
145
|
-
signal,
|
|
146
|
-
context: {
|
|
147
|
-
[OPERATION_CONTEXT_SYMBOL]: {
|
|
148
|
-
key: queryKey,
|
|
149
|
-
type: "streamed"
|
|
150
|
-
},
|
|
151
|
-
...optionsIn.context
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
if (!isAsyncIteratorObject(output)) {
|
|
155
|
-
throw new Error("streamedQuery requires an event iterator output");
|
|
255
|
+
if (optionsIn.queryFn) {
|
|
256
|
+
return optionsIn.queryFn(fnContext2);
|
|
156
257
|
}
|
|
157
|
-
return
|
|
258
|
+
return this.call(input, { signal: fnContext2.signal, context });
|
|
259
|
+
}
|
|
260
|
+
);
|
|
261
|
+
},
|
|
262
|
+
...optionsIn.input === skipToken || optionsIn.queryFn === skipToken ? { enabled: false } : {}
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Generate a **full matching** key for [Streamed Query Options](https://orpc.dev/docs/integrations/tanstack-query#streamed-query-options).
|
|
267
|
+
*/
|
|
268
|
+
streamedKey(...rest) {
|
|
269
|
+
let optionsIn = resolveMaybeOptionalOptions(rest);
|
|
270
|
+
if (typeof this.options.streamedKey === "function") {
|
|
271
|
+
optionsIn = this.options.streamedKey(optionsIn);
|
|
272
|
+
} else if (this.options.streamedKey) {
|
|
273
|
+
optionsIn = { ...this.options.streamedKey, ...optionsIn };
|
|
274
|
+
}
|
|
275
|
+
const queryKey = optionsIn.queryKey ?? generateOperationKey(this.path, { prefix: this.options.prefix, type: "streamed", input: optionsIn.input, fnOptions: optionsIn.queryFnOptions });
|
|
276
|
+
return queryKey;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Configure queries for [AsyncIteratorObject](https://orpc.dev/docs/async-iterator-object).
|
|
280
|
+
* This is built on [TanStack Query streamedQuery](https://tanstack.com/query/latest/docs/reference/streamedQuery)
|
|
281
|
+
* and works with hooks like `useQuery`, `useSuspenseQuery`, or `prefetchQuery`.
|
|
282
|
+
*/
|
|
283
|
+
streamedOptions(...rest) {
|
|
284
|
+
let optionsIn = resolveMaybeOptionalOptions(rest);
|
|
285
|
+
if (typeof this.options.streamedOptions === "function") {
|
|
286
|
+
optionsIn = this.options.streamedOptions(optionsIn);
|
|
287
|
+
} else if (this.options.streamedOptions) {
|
|
288
|
+
optionsIn = { ...this.options.streamedOptions, ...optionsIn };
|
|
289
|
+
}
|
|
290
|
+
const queryKey = this.streamedKey(optionsIn);
|
|
291
|
+
return {
|
|
292
|
+
...optionsIn,
|
|
293
|
+
queryKey,
|
|
294
|
+
queryFn: (fnContext) => {
|
|
295
|
+
return intercept(
|
|
296
|
+
toArray(this.options.streamedInterceptors),
|
|
297
|
+
{
|
|
298
|
+
path: this.path,
|
|
299
|
+
context: {
|
|
300
|
+
[OPERATION_CONTEXT_SYMBOL]: {
|
|
301
|
+
key: queryKey,
|
|
302
|
+
type: "streamed"
|
|
303
|
+
},
|
|
304
|
+
...optionsIn.context
|
|
305
|
+
},
|
|
306
|
+
input: optionsIn.input,
|
|
307
|
+
fnContext
|
|
158
308
|
},
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if (optionsIn.input === skipToken) {
|
|
177
|
-
throw new Error("queryFn should not be called with skipToken used as input");
|
|
309
|
+
({ context, fnContext: fnContext2, input }) => {
|
|
310
|
+
if (input === skipToken || optionsIn.queryFn === skipToken) {
|
|
311
|
+
throw new Error("queryFn should not be called when skipToken used for skipping");
|
|
312
|
+
}
|
|
313
|
+
if (optionsIn.queryFn) {
|
|
314
|
+
return optionsIn.queryFn(fnContext2);
|
|
315
|
+
}
|
|
316
|
+
return serializableStreamedQuery(
|
|
317
|
+
async (queryContext) => {
|
|
318
|
+
const output = await this.call(input, { signal: queryContext.signal, context });
|
|
319
|
+
if (!isAsyncIteratorObject(output)) {
|
|
320
|
+
throw new Error("streamedQuery requires an AsyncIteratorObject output");
|
|
321
|
+
}
|
|
322
|
+
return output;
|
|
323
|
+
},
|
|
324
|
+
optionsIn.queryFnOptions
|
|
325
|
+
)(fnContext2);
|
|
178
326
|
}
|
|
179
|
-
|
|
180
|
-
|
|
327
|
+
);
|
|
328
|
+
},
|
|
329
|
+
...optionsIn.input === skipToken || optionsIn.queryFn === skipToken ? { enabled: false } : {}
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Generate a **full matching** key for [Live Query Options](https://orpc.dev/docs/integrations/tanstack-query#live-query-options).
|
|
334
|
+
*/
|
|
335
|
+
liveKey(...rest) {
|
|
336
|
+
let optionsIn = resolveMaybeOptionalOptions(rest);
|
|
337
|
+
if (typeof this.options.liveKey === "function") {
|
|
338
|
+
optionsIn = this.options.liveKey(optionsIn);
|
|
339
|
+
} else if (this.options.liveKey) {
|
|
340
|
+
optionsIn = { ...this.options.liveKey, ...optionsIn };
|
|
341
|
+
}
|
|
342
|
+
const queryKey = optionsIn.queryKey ?? generateOperationKey(this.path, { prefix: this.options.prefix, type: "live", input: optionsIn.input });
|
|
343
|
+
return queryKey;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Configure live queries for [AsyncIteratorObject](https://orpc.dev/docs/async-iterator-object).
|
|
347
|
+
* Unlike `.streamedOptions` which accumulates chunks, live queries replace the entire result with each new chunk received.
|
|
348
|
+
* Works with hooks like `useQuery`, `useSuspenseQuery`, or `prefetchQuery`.
|
|
349
|
+
*/
|
|
350
|
+
liveOptions(...rest) {
|
|
351
|
+
let optionsIn = resolveMaybeOptionalOptions(rest);
|
|
352
|
+
if (typeof this.options.liveOptions === "function") {
|
|
353
|
+
optionsIn = this.options.liveOptions(optionsIn);
|
|
354
|
+
} else if (this.options.liveOptions) {
|
|
355
|
+
optionsIn = { ...this.options.liveOptions, ...optionsIn };
|
|
356
|
+
}
|
|
357
|
+
const queryKey = this.liveKey(optionsIn);
|
|
358
|
+
return {
|
|
359
|
+
...optionsIn,
|
|
360
|
+
queryKey,
|
|
361
|
+
queryFn: (fnContext) => {
|
|
362
|
+
return intercept(
|
|
363
|
+
toArray(this.options.liveInterceptors),
|
|
364
|
+
{
|
|
365
|
+
path: this.path,
|
|
181
366
|
context: {
|
|
182
367
|
[OPERATION_CONTEXT_SYMBOL]: {
|
|
183
368
|
key: queryKey,
|
|
184
369
|
type: "live"
|
|
185
370
|
},
|
|
186
371
|
...optionsIn.context
|
|
372
|
+
},
|
|
373
|
+
input: optionsIn.input,
|
|
374
|
+
fnContext
|
|
375
|
+
},
|
|
376
|
+
({ fnContext: fnContext2, input, context }) => {
|
|
377
|
+
if (input === skipToken || optionsIn.queryFn === skipToken) {
|
|
378
|
+
throw new Error("queryFn should not be called when skipToken used for skipping");
|
|
187
379
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const queryKey = optionsIn.queryKey ?? generateOperationKey(options.path, {
|
|
202
|
-
type: "infinite",
|
|
203
|
-
input: optionsIn.input === skipToken ? skipToken : optionsIn.input(optionsIn.initialPageParam)
|
|
204
|
-
});
|
|
205
|
-
return queryKey;
|
|
206
|
-
},
|
|
207
|
-
infiniteOptions(optionsIn) {
|
|
208
|
-
optionsIn = { ...options.experimental_defaults?.infiniteOptions, ...optionsIn };
|
|
209
|
-
const queryKey = utils.infiniteKey(optionsIn);
|
|
210
|
-
return {
|
|
211
|
-
queryFn: ({ pageParam, signal }) => {
|
|
212
|
-
if (optionsIn.input === skipToken) {
|
|
213
|
-
throw new Error("queryFn should not be called with skipToken used as input");
|
|
380
|
+
if (optionsIn.queryFn) {
|
|
381
|
+
return optionsIn.queryFn(fnContext2);
|
|
382
|
+
}
|
|
383
|
+
return liveQuery(async (queryContext) => {
|
|
384
|
+
const output = await this.call(input, {
|
|
385
|
+
signal: queryContext.signal,
|
|
386
|
+
context
|
|
387
|
+
});
|
|
388
|
+
if (!isAsyncIteratorObject(output)) {
|
|
389
|
+
throw new Error("liveQuery requires an AsyncIteratorObject output");
|
|
390
|
+
}
|
|
391
|
+
return output;
|
|
392
|
+
})(fnContext2);
|
|
214
393
|
}
|
|
215
|
-
|
|
216
|
-
|
|
394
|
+
);
|
|
395
|
+
},
|
|
396
|
+
...optionsIn.input === skipToken || optionsIn.queryFn === skipToken ? { enabled: false } : {}
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Generate a **full matching** key for [Infinite Query Options](https://orpc.dev/docs/integrations/tanstack-query#infinite-query-options).
|
|
401
|
+
*/
|
|
402
|
+
infiniteKey(optionsIn) {
|
|
403
|
+
if (typeof this.options.infiniteKey === "function") {
|
|
404
|
+
optionsIn = this.options.infiniteKey(optionsIn);
|
|
405
|
+
} else if (this.options.infiniteKey) {
|
|
406
|
+
optionsIn = { ...this.options.infiniteKey, ...optionsIn };
|
|
407
|
+
}
|
|
408
|
+
const queryKey = optionsIn.queryKey ?? generateOperationKey(this.path, {
|
|
409
|
+
prefix: this.options.prefix,
|
|
410
|
+
type: "infinite",
|
|
411
|
+
input: optionsIn.input === skipToken ? skipToken : optionsIn.input(optionsIn.initialPageParam)
|
|
412
|
+
});
|
|
413
|
+
return queryKey;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Generate options used for useInfiniteQuery/useSuspenseInfiniteQuery/prefetchInfiniteQuery/...
|
|
417
|
+
*/
|
|
418
|
+
infiniteOptions(optionsIn) {
|
|
419
|
+
if (typeof this.options.infiniteOptions === "function") {
|
|
420
|
+
optionsIn = this.options.infiniteOptions(optionsIn);
|
|
421
|
+
} else if (this.options.infiniteOptions) {
|
|
422
|
+
optionsIn = { ...this.options.infiniteOptions, ...optionsIn };
|
|
423
|
+
}
|
|
424
|
+
const queryKey = this.infiniteKey(optionsIn);
|
|
425
|
+
return {
|
|
426
|
+
...optionsIn,
|
|
427
|
+
queryKey,
|
|
428
|
+
queryFn: (fnContext) => {
|
|
429
|
+
return intercept(
|
|
430
|
+
toArray(this.options.infiniteInterceptors),
|
|
431
|
+
{
|
|
432
|
+
path: this.path,
|
|
217
433
|
context: {
|
|
218
434
|
[OPERATION_CONTEXT_SYMBOL]: {
|
|
219
435
|
key: queryKey,
|
|
220
436
|
type: "infinite"
|
|
221
437
|
},
|
|
222
438
|
...optionsIn.context
|
|
223
|
-
}
|
|
224
|
-
});
|
|
225
|
-
},
|
|
226
|
-
...optionsIn.input === skipToken ? { enabled: false } : {},
|
|
227
|
-
...optionsIn,
|
|
228
|
-
queryKey
|
|
229
|
-
};
|
|
230
|
-
},
|
|
231
|
-
mutationKey(...[optionsIn = {}]) {
|
|
232
|
-
optionsIn = { ...options.experimental_defaults?.mutationKey, ...optionsIn };
|
|
233
|
-
const mutationKey = optionsIn.mutationKey ?? generateOperationKey(options.path, { type: "mutation" });
|
|
234
|
-
return mutationKey;
|
|
235
|
-
},
|
|
236
|
-
mutationOptions(...[optionsIn = {}]) {
|
|
237
|
-
optionsIn = { ...options.experimental_defaults?.mutationOptions, ...optionsIn };
|
|
238
|
-
const mutationKey = utils.mutationKey(optionsIn);
|
|
239
|
-
return {
|
|
240
|
-
mutationFn: (input) => client(input, {
|
|
241
|
-
context: {
|
|
242
|
-
[OPERATION_CONTEXT_SYMBOL]: {
|
|
243
|
-
key: mutationKey,
|
|
244
|
-
type: "mutation"
|
|
245
439
|
},
|
|
246
|
-
|
|
440
|
+
input: optionsIn.input === skipToken ? skipToken : optionsIn.input(fnContext.pageParam),
|
|
441
|
+
fnContext
|
|
442
|
+
},
|
|
443
|
+
({ context, input, fnContext: fnContext2 }) => {
|
|
444
|
+
if (input === skipToken || optionsIn.queryFn === skipToken) {
|
|
445
|
+
throw new Error("queryFn should not be called when skipToken used for skipping");
|
|
446
|
+
}
|
|
447
|
+
if (optionsIn.queryFn) {
|
|
448
|
+
return optionsIn.queryFn(fnContext2);
|
|
449
|
+
}
|
|
450
|
+
return this.call(input, { signal: fnContext2.signal, context });
|
|
247
451
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
452
|
+
);
|
|
453
|
+
},
|
|
454
|
+
...optionsIn.input === skipToken || optionsIn.queryFn === skipToken ? { enabled: false } : {}
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Generate a **full matching** key for [Mutation Options](https://orpc.dev/docs/integrations/tanstack-query#mutation-options).
|
|
459
|
+
*/
|
|
460
|
+
mutationKey(optionsIn = {}) {
|
|
461
|
+
if (typeof this.options.mutationKey === "function") {
|
|
462
|
+
optionsIn = this.options.mutationKey(optionsIn);
|
|
463
|
+
} else if (this.options.mutationKey) {
|
|
464
|
+
optionsIn = { ...this.options.mutationKey, ...optionsIn };
|
|
252
465
|
}
|
|
253
|
-
|
|
254
|
-
|
|
466
|
+
const mutationKey = optionsIn.mutationKey ?? generateOperationKey(this.path, { prefix: this.options.prefix, type: "mutation" });
|
|
467
|
+
return mutationKey;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Generate options used for useMutation/...
|
|
471
|
+
*/
|
|
472
|
+
mutationOptions(...rest) {
|
|
473
|
+
let optionsIn = resolveMaybeOptionalOptions(rest);
|
|
474
|
+
if (typeof this.options.mutationOptions === "function") {
|
|
475
|
+
optionsIn = this.options.mutationOptions(optionsIn);
|
|
476
|
+
} else if (this.options.mutationOptions) {
|
|
477
|
+
optionsIn = { ...this.options.mutationOptions, ...optionsIn };
|
|
478
|
+
}
|
|
479
|
+
const mutationKey = this.mutationKey(optionsIn);
|
|
480
|
+
return {
|
|
481
|
+
...optionsIn,
|
|
482
|
+
mutationKey,
|
|
483
|
+
mutationFn: (input, fnContext) => {
|
|
484
|
+
return intercept(
|
|
485
|
+
toArray(this.options.mutationInterceptors),
|
|
486
|
+
{
|
|
487
|
+
path: this.path,
|
|
488
|
+
context: {
|
|
489
|
+
[OPERATION_CONTEXT_SYMBOL]: {
|
|
490
|
+
key: mutationKey,
|
|
491
|
+
type: "mutation"
|
|
492
|
+
},
|
|
493
|
+
...optionsIn.context
|
|
494
|
+
},
|
|
495
|
+
fnContext,
|
|
496
|
+
input
|
|
497
|
+
},
|
|
498
|
+
({ input: input2, fnContext: fnContext2, context }) => {
|
|
499
|
+
if (optionsIn.mutationFn) {
|
|
500
|
+
return optionsIn.mutationFn(input2, fnContext2);
|
|
501
|
+
}
|
|
502
|
+
return this.call(input2, { context });
|
|
503
|
+
}
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
}
|
|
255
508
|
}
|
|
256
509
|
|
|
257
510
|
function createRouterUtils(client, options = {}) {
|
|
511
|
+
const plugin = new CompositeRouterUtilsPlugin(options.plugins);
|
|
512
|
+
options = plugin.init(options);
|
|
513
|
+
return createRouterUtilsInternal(client, options, plugin);
|
|
514
|
+
}
|
|
515
|
+
function createRouterUtilsInternal(client, options, plugin) {
|
|
258
516
|
const path = toArray(options.path);
|
|
259
|
-
const
|
|
260
|
-
const procedureUtils = createProcedureUtils(client, {
|
|
517
|
+
const utils = typeof client === "function" && (options.scoped === void 0 || isProcedureUtilsOptions(options.scoped)) ? bindMethods(new ProcedureUtils(
|
|
261
518
|
path,
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
519
|
+
client,
|
|
520
|
+
plugin.initProcedureOptions(path, mergeProcedureUtilsOptions(
|
|
521
|
+
{
|
|
522
|
+
prefix: options.prefix,
|
|
523
|
+
queryInterceptors: options.queryInterceptors,
|
|
524
|
+
streamedInterceptors: options.streamedInterceptors,
|
|
525
|
+
liveInterceptors: options.liveInterceptors,
|
|
526
|
+
infiniteInterceptors: options.infiniteInterceptors,
|
|
527
|
+
mutationInterceptors: options.mutationInterceptors
|
|
528
|
+
},
|
|
529
|
+
options.scoped ?? {}
|
|
530
|
+
))
|
|
531
|
+
)) : bindMethods(new SharedUtils(path, options));
|
|
532
|
+
const recursive = new Proxy(utils, {
|
|
268
533
|
get(target, prop) {
|
|
269
|
-
const value =
|
|
270
|
-
|
|
534
|
+
const value = getOrBind(target, prop);
|
|
535
|
+
const nextClient = client[prop];
|
|
536
|
+
if (typeof prop !== "string" || RECURSIVE_CLIENT_UNWRAP_KEYS.has(prop) || !isTypescriptObject(nextClient)) {
|
|
271
537
|
return value;
|
|
272
538
|
}
|
|
273
|
-
const nextUtils =
|
|
539
|
+
const nextUtils = createRouterUtilsInternal(nextClient, {
|
|
274
540
|
...options,
|
|
275
541
|
path: [...path, prop],
|
|
276
|
-
|
|
277
|
-
});
|
|
542
|
+
scoped: get(options.scoped, [prop])
|
|
543
|
+
}, plugin);
|
|
278
544
|
if (typeof value !== "function") {
|
|
279
545
|
return nextUtils;
|
|
280
546
|
}
|
|
281
547
|
return new Proxy(value, {
|
|
282
|
-
get(
|
|
283
|
-
|
|
548
|
+
get(target2, prop2) {
|
|
549
|
+
if (typeof prop2 !== "string" || RECURSIVE_CLIENT_UNWRAP_KEYS.has(prop2)) {
|
|
550
|
+
return getOrBind(target2, prop2);
|
|
551
|
+
}
|
|
552
|
+
return getOrBind(nextUtils, prop2);
|
|
284
553
|
}
|
|
285
554
|
});
|
|
286
555
|
}
|
|
@@ -288,4 +557,54 @@ function createRouterUtils(client, options = {}) {
|
|
|
288
557
|
return recursive;
|
|
289
558
|
}
|
|
290
559
|
|
|
291
|
-
|
|
560
|
+
function createContractUtilsFactory(clientFactory, options) {
|
|
561
|
+
const factory = (contract) => {
|
|
562
|
+
const client = clientFactory(contract);
|
|
563
|
+
const path = resolveBasePathMeta(contract);
|
|
564
|
+
if (path === void 0) {
|
|
565
|
+
throw new TypeError(
|
|
566
|
+
"ContractUtilsFactory: procedure contract must define `meta.path` that matches its path in the root router contract."
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
return createRouterUtils(client, { ...options, path, scoped: get(options.scoped, path) });
|
|
570
|
+
};
|
|
571
|
+
return factory;
|
|
572
|
+
}
|
|
573
|
+
function createContractJsonifiedUtilsFactory(clientFactory, options) {
|
|
574
|
+
return createContractUtilsFactory(clientFactory, options);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
function tanstackQuery(options) {
|
|
578
|
+
return {
|
|
579
|
+
name: "~tanstack-query",
|
|
580
|
+
init(meta) {
|
|
581
|
+
const current = meta["~tanstack-query"];
|
|
582
|
+
return {
|
|
583
|
+
...meta,
|
|
584
|
+
"~tanstack-query": current ? mergeProcedureUtilsOptions(current, options) : options
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
function getTanstackQueryMeta(procedureOrLazy) {
|
|
590
|
+
return procedureOrLazy["~orpc"].meta["~tanstack-query"];
|
|
591
|
+
}
|
|
592
|
+
class ContractOptionsUtilsPlugin {
|
|
593
|
+
constructor(contract) {
|
|
594
|
+
this.contract = contract;
|
|
595
|
+
}
|
|
596
|
+
name = "~contract-options";
|
|
597
|
+
initProcedureOptions(path, options) {
|
|
598
|
+
const procedure = getRouterContract(this.contract, path);
|
|
599
|
+
if (!(procedure instanceof ProcedureContract)) {
|
|
600
|
+
return options;
|
|
601
|
+
}
|
|
602
|
+
const base = getTanstackQueryMeta(procedure);
|
|
603
|
+
if (!base) {
|
|
604
|
+
return options;
|
|
605
|
+
}
|
|
606
|
+
return mergeProcedureUtilsOptions(base, options);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
export { CompositeRouterUtilsPlugin, ContractOptionsUtilsPlugin, OPERATION_CONTEXT_SYMBOL, ProcedureUtils, SharedUtils, OPERATION_CONTEXT_SYMBOL as TANSTACK_QUERY_OPERATION_CONTEXT_SYMBOL, createContractJsonifiedUtilsFactory, createContractUtilsFactory, createRouterUtils, createRouterUtils as createTanstackQueryUtils, generateOperationKey, getTanstackQueryMeta, isProcedureUtilsOptions, mergeProcedureUtilsOptions, serializableStreamedQuery, tanstackQuery };
|