@effect-app/vue 4.0.0-beta.33 → 4.0.0-beta.331
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/CHANGELOG.md +2463 -0
- package/dist/atomQuery.d.ts +120 -0
- package/dist/atomQuery.d.ts.map +1 -0
- package/dist/atomQuery.js +434 -0
- package/dist/commander.d.ts +634 -0
- package/dist/commander.d.ts.map +1 -0
- package/dist/commander.js +1068 -0
- package/dist/{experimental/confirm.d.ts → confirm.d.ts} +6 -4
- package/dist/confirm.d.ts.map +1 -0
- package/dist/confirm.js +26 -0
- package/dist/dependencyMetadata.d.ts +18 -0
- package/dist/dependencyMetadata.d.ts.map +1 -0
- package/dist/dependencyMetadata.js +67 -0
- package/dist/errorReporter.d.ts +6 -4
- package/dist/errorReporter.d.ts.map +1 -1
- package/dist/errorReporter.js +14 -19
- package/dist/form.d.ts +5 -5
- package/dist/form.d.ts.map +1 -1
- package/dist/form.js +42 -16
- package/dist/internal/tanstackQuery.d.ts +9 -0
- package/dist/internal/tanstackQuery.d.ts.map +1 -0
- package/dist/internal/tanstackQuery.js +204 -0
- package/dist/intl.d.ts +15 -0
- package/dist/intl.d.ts.map +1 -0
- package/dist/intl.js +9 -0
- package/dist/lib.d.ts +7 -9
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +35 -10
- package/dist/liveQueryInvalidation.d.ts +16 -0
- package/dist/liveQueryInvalidation.d.ts.map +1 -0
- package/dist/liveQueryInvalidation.js +115 -0
- package/dist/makeClient.d.ts +236 -336
- package/dist/makeClient.d.ts.map +1 -1
- package/dist/makeClient.js +417 -408
- package/dist/makeContext.d.ts.map +1 -1
- package/dist/makeIntl.d.ts.map +1 -1
- package/dist/{experimental/makeUseCommand.d.ts → makeUseCommand.d.ts} +4 -3
- package/dist/makeUseCommand.d.ts.map +1 -0
- package/dist/makeUseCommand.js +13 -0
- package/dist/mutate.d.ts +109 -40
- package/dist/mutate.d.ts.map +1 -1
- package/dist/mutate.js +235 -58
- package/dist/query.d.ts +158 -45
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +380 -122
- package/dist/queryLifetime.d.ts +25 -0
- package/dist/queryLifetime.d.ts.map +1 -0
- package/dist/queryLifetime.js +54 -0
- package/dist/routeParams.d.ts +4 -4
- package/dist/routeParams.d.ts.map +1 -1
- package/dist/routeParams.js +4 -3
- package/dist/runtime.d.ts +1 -14
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +2 -26
- package/dist/suspense.d.ts +19 -0
- package/dist/suspense.d.ts.map +1 -0
- package/dist/suspense.js +38 -0
- package/dist/toast.d.ts +2 -0
- package/dist/toast.d.ts.map +1 -0
- package/dist/toast.js +2 -0
- package/dist/withToast.d.ts +2 -0
- package/dist/withToast.d.ts.map +1 -0
- package/dist/withToast.js +2 -0
- package/docs/atom-query-api-redesign.md +207 -0
- package/docs/mutation-command-atoms.md +40 -0
- package/docs/query-key-invalidation.md +107 -0
- package/examples/streamMutation.ts +72 -0
- package/package.json +36 -95
- package/src/atomQuery.ts +600 -0
- package/src/commander.ts +3408 -0
- package/src/{experimental/confirm.ts → confirm.ts} +13 -15
- package/src/dependencyMetadata.ts +84 -0
- package/src/errorReporter.ts +65 -75
- package/src/form.ts +57 -21
- package/src/index.ts +7 -7
- package/src/internal/tanstackQuery.ts +308 -0
- package/src/intl.ts +12 -0
- package/src/lib.ts +49 -21
- package/src/liveQueryInvalidation.ts +138 -0
- package/src/makeClient.ts +971 -1159
- package/src/makeIntl.ts +2 -2
- package/src/{experimental/makeUseCommand.ts → makeUseCommand.ts} +9 -6
- package/src/mutate.ts +406 -153
- package/src/query.ts +763 -260
- package/src/queryLifetime.ts +74 -0
- package/src/routeParams.ts +7 -7
- package/src/runtime.ts +1 -31
- package/src/suspense.ts +43 -0
- package/src/toast.ts +1 -0
- package/src/withToast.ts +1 -0
- package/test/Mutation.test.ts +181 -24
- package/test/dependencyInvalidation.test.ts +444 -0
- package/test/dist/dependencyInvalidation.test.d.ts.map +1 -0
- package/test/dist/form.test.d.ts.map +1 -1
- package/test/dist/inactiveInvalidation.test.d.ts.map +1 -0
- package/test/dist/interrupt-refetch-repro.test.d.ts.map +1 -0
- package/test/dist/lib.test.d.ts.map +1 -0
- package/test/dist/liveQueryInvalidation.test.d.ts.map +1 -0
- package/test/dist/query-span.test.d.ts.map +1 -0
- package/test/dist/queryOptions.test.d.ts.map +1 -0
- package/test/dist/streamFinal.test.d.ts.map +1 -0
- package/test/dist/streamFn.test.d.ts.map +1 -0
- package/test/dist/stubs.d.ts +3751 -120
- package/test/dist/stubs.d.ts.map +1 -1
- package/test/dist/stubs.js +190 -30
- package/test/dist/suspense-regression.test.d.ts.map +1 -0
- package/test/dist/suspense.test.d.ts.map +1 -0
- package/test/form-validation-errors.test.ts +24 -19
- package/test/form.test.ts +25 -6
- package/test/inactiveInvalidation.test.ts +172 -0
- package/test/interrupt-refetch-repro.test.ts +625 -0
- package/test/lib.test.ts +240 -0
- package/test/liveQueryInvalidation.test.ts +108 -0
- package/test/makeClient.test.ts +437 -38
- package/test/query-span.test.ts +92 -0
- package/test/queryOptions.test.ts +88 -0
- package/test/streamFinal.test.ts +64 -0
- package/test/streamFn.test.ts +457 -0
- package/test/stubs.ts +227 -42
- package/test/suspense-regression.test.ts +168 -0
- package/test/suspense.test.ts +160 -0
- package/tsconfig.examples.json +20 -0
- package/tsconfig.json +9 -2
- package/tsconfig.src.json +34 -34
- package/tsconfig.test.json +2 -2
- package/vitest.config.ts +5 -5
- package/dist/experimental/commander.d.ts +0 -359
- package/dist/experimental/commander.d.ts.map +0 -1
- package/dist/experimental/commander.js +0 -557
- package/dist/experimental/confirm.d.ts.map +0 -1
- package/dist/experimental/confirm.js +0 -28
- package/dist/experimental/intl.d.ts +0 -16
- package/dist/experimental/intl.d.ts.map +0 -1
- package/dist/experimental/intl.js +0 -5
- package/dist/experimental/makeUseCommand.d.ts.map +0 -1
- package/dist/experimental/makeUseCommand.js +0 -13
- package/dist/experimental/toast.d.ts +0 -47
- package/dist/experimental/toast.d.ts.map +0 -1
- package/dist/experimental/toast.js +0 -41
- package/dist/experimental/withToast.d.ts +0 -25
- package/dist/experimental/withToast.d.ts.map +0 -1
- package/dist/experimental/withToast.js +0 -45
- package/eslint.config.mjs +0 -24
- package/src/experimental/commander.ts +0 -1835
- package/src/experimental/intl.ts +0 -9
- package/src/experimental/toast.ts +0 -66
- package/src/experimental/withToast.ts +0 -99
- package/tsconfig.json.bak +0 -12
package/src/makeClient.ts
CHANGED
|
@@ -1,162 +1,351 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { type InvalidateOptions, type InvalidateQueryFilters, isCancelledError, type QueryObserverResult, type RefetchOptions, type UseQueryReturnType } from "@tanstack/vue-query"
|
|
3
2
|
import { camelCase } from "change-case"
|
|
4
|
-
import { Cause, Data, Effect, Exit, Layer, type ManagedRuntime, Match, Option, S, ServiceMap, Struct } from "effect-app"
|
|
5
3
|
import { type ApiClientFactory, type Req } from "effect-app/client"
|
|
6
|
-
import type {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
10
|
-
import
|
|
4
|
+
import type { ExtractModuleName, HandlerInput, RequestHandlers, RequestHandlerWithInput, RequestsAny, RequestStreamHandlerWithInput } from "effect-app/client/clientFor"
|
|
5
|
+
import type { CauseException } from "effect-app/client/errors"
|
|
6
|
+
import type { InvalidationCallback } from "effect-app/client/makeClient"
|
|
7
|
+
import * as Context from "effect-app/Context"
|
|
8
|
+
import * as Effect from "effect-app/Effect"
|
|
9
|
+
import * as Layer from "effect-app/Layer"
|
|
10
|
+
import * as S from "effect-app/Schema"
|
|
11
|
+
import * as Cause from "effect/Cause"
|
|
12
|
+
import * as Data from "effect/Data"
|
|
13
|
+
import * as Exit from "effect/Exit"
|
|
11
14
|
import { type Fiber } from "effect/Fiber"
|
|
12
|
-
import * as
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import { type
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
15
|
+
import * as Hash from "effect/Hash"
|
|
16
|
+
import type * as ManagedRuntime from "effect/ManagedRuntime"
|
|
17
|
+
import type * as Stream from "effect/Stream"
|
|
18
|
+
import * as Struct from "effect/Struct"
|
|
19
|
+
import type * as AsyncResult from "effect/unstable/reactivity/AsyncResult"
|
|
20
|
+
import * as Reactivity from "effect/unstable/reactivity/Reactivity"
|
|
21
|
+
import { type ComputedRef, effectScope, onBeforeUnmount, onScopeDispose, ref, type WatchSource } from "vue"
|
|
22
|
+
import { type AtomClientRuntime, invalidateAndAwait, invalidateSoft, makeAtomClientRuntime } from "./atomQuery.ts"
|
|
23
|
+
import { type Commander, CommanderStatic, type Progress } from "./commander.ts"
|
|
24
|
+
import { makeTanstackQuery, makeTanstackQueryCacheUpdater, makeTanstackQueryClient, makeTanstackQueryInvalidator } from "./internal/tanstackQuery.ts"
|
|
25
|
+
import { type I18n } from "./intl.ts"
|
|
26
|
+
import { type CommanderResolved, makeUseCommand } from "./makeUseCommand.ts"
|
|
27
|
+
import { atomQueryInvalidator, combineQueryInvalidators, type InvalidationEntry, makeMutation, makeStreamMutation2, type MutationOptionsBase, type QueryInvalidator, useMakeMutation } from "./mutate.ts"
|
|
28
|
+
import { atomQueryCacheUpdater, type AtomQueryNewOptions, combineQueryCacheUpdaters, type CustomUndefinedInitialQueryOptions, makeQuery, makeQueryAtom, makeQueryFamily, makeQueryNew, makeStreamQuery, makeStreamQueryAtom, makeStreamQueryFamily, makeStreamQueryNew, optionalAtomQueryCacheUpdater, type QueryObserverResult, type RefetchOptions, setQueryCacheUpdater, type StreamQueryAtomFamily, type SuspenseQueryView, type UseQueryReturnType } from "./query.ts"
|
|
29
|
+
import { makeRunPromise } from "./runtime.ts"
|
|
30
|
+
import { latestDefined } from "./suspense.ts"
|
|
31
|
+
import { type Toast } from "./toast.ts"
|
|
32
|
+
|
|
33
|
+
export type { Progress }
|
|
34
|
+
|
|
35
|
+
const useScopedSuspenseSetup = <A>(setup: () => A) => {
|
|
36
|
+
const scope = effectScope()
|
|
37
|
+
const controller = new AbortController()
|
|
38
|
+
const value = scope.run(setup)
|
|
39
|
+
if (value === undefined) {
|
|
40
|
+
throw new Error("Internal Error: suspense setup scope did not initialize")
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const isMounted = ref(true)
|
|
44
|
+
let stopped = false
|
|
45
|
+
const stop = () => {
|
|
46
|
+
if (stopped) return
|
|
47
|
+
stopped = true
|
|
48
|
+
isMounted.value = false
|
|
49
|
+
controller.abort()
|
|
50
|
+
scope.stop()
|
|
51
|
+
}
|
|
52
|
+
onBeforeUnmount(stop)
|
|
53
|
+
onScopeDispose(stop)
|
|
54
|
+
|
|
55
|
+
return [value, isMounted, controller.signal] as const
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* A suspense query settled with an interrupt-only cause while its component was still MOUNTED.
|
|
60
|
+
*
|
|
61
|
+
* That combination classifies the interrupt's origin: a navigation/unmount cancel interrupts the
|
|
62
|
+
* suspense *fiber* (via the scope's AbortSignal) or is hidden by effect-core before it can settle —
|
|
63
|
+
* it never yields a still-mounted `Failure` exit. A `Failure(interrupt-only)` observed while mounted
|
|
64
|
+
* therefore came from the QUERY side — e.g. the server returned an RPC interrupt `Exit` (over a 200),
|
|
65
|
+
* or the fetch was superseded — and silencing it leaves the user staring at a blank page.
|
|
66
|
+
*
|
|
67
|
+
* Error boundaries can rely on this split: keep silencing raw interrupt-only causes (those are
|
|
68
|
+
* genuinely "user navigated away"), and render this error as "the request was interrupted — reload?".
|
|
69
|
+
*/
|
|
70
|
+
export class SuspenseInterruptedError extends Data.TaggedError("SuspenseInterruptedError")<{
|
|
71
|
+
readonly originalCause: Cause.Cause<unknown>
|
|
72
|
+
readonly source: "suspense" | "suspenseNew"
|
|
73
|
+
}> {
|
|
74
|
+
override get message() {
|
|
75
|
+
return "The request was interrupted while the page was still active"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Structural check (by `_tag`) so consumers compiled against older published types can detect it. */
|
|
80
|
+
export const isSuspenseInterruptedError = (e: unknown): e is SuspenseInterruptedError =>
|
|
81
|
+
typeof e === "object" && e !== null && "_tag" in e && e._tag === "SuspenseInterruptedError"
|
|
82
|
+
|
|
83
|
+
// TODO: optimize - work from encoded shape directly
|
|
84
|
+
const projectHandler = <
|
|
85
|
+
I,
|
|
86
|
+
A,
|
|
87
|
+
E,
|
|
88
|
+
R,
|
|
89
|
+
SuccessSchema extends S.Top & { readonly "EncodingServices": R },
|
|
90
|
+
ProjSchema extends S.Top & { readonly "DecodingServices": R }
|
|
91
|
+
>(
|
|
92
|
+
handler: (i: I) => Effect.Effect<A, E, R>,
|
|
93
|
+
successSchema: SuccessSchema,
|
|
94
|
+
projectionSchema: ProjSchema
|
|
95
|
+
) => {
|
|
96
|
+
const encode = S.encodeUnknownEffect(successSchema)
|
|
97
|
+
const decode = S.decodeUnknownEffect(projectionSchema)
|
|
98
|
+
return (i: I) => handler(i).pipe(Effect.flatMap(encode), Effect.flatMap(decode))
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const projectionSchemaHash = (schema: S.Top) => String(Hash.hash(schema.ast))
|
|
102
|
+
|
|
103
|
+
export interface CommandRequestExtensions<RT, Id extends string, I, A, E, R> {
|
|
30
104
|
/** Defines a Command based on this call, taking the `id` of the call as the `id` of the Command.
|
|
31
105
|
* The Request function will be taken as the first member of the Command, the Command required input will be the Request input.
|
|
32
106
|
* see Command.wrap for details */
|
|
33
|
-
wrap:
|
|
107
|
+
wrap: <I18nKey extends string = Id, State extends Commander.IntlRecord | undefined = undefined>(
|
|
108
|
+
options?: Commander.FnOptions<Id, I18nKey, State>
|
|
109
|
+
) => Commander.CommanderWrap<RT, Id, I18nKey, State, I, A, E, R>
|
|
34
110
|
/** Defines a Command based on this call, taking the `id` of the call as the `id` of the Command.
|
|
35
111
|
* see Command.fn for details */
|
|
36
|
-
fn:
|
|
112
|
+
fn: <I18nKey extends string = Id, State extends Commander.IntlRecord | undefined = undefined>(
|
|
113
|
+
options?: Commander.FnOptions<Id, I18nKey, State>
|
|
114
|
+
) => Commander.CommanderFn<RT, Id, I18nKey, State>
|
|
37
115
|
}
|
|
38
116
|
|
|
39
117
|
/** my other doc */
|
|
40
|
-
export interface
|
|
118
|
+
export interface RequestExt<
|
|
41
119
|
RT,
|
|
42
120
|
Id extends string,
|
|
43
121
|
I,
|
|
44
122
|
A,
|
|
45
123
|
E,
|
|
46
124
|
R
|
|
47
|
-
> extends
|
|
125
|
+
> extends
|
|
126
|
+
Commander.CommandContextLocal<Id, Id>,
|
|
127
|
+
Commander.CommanderWrap<RT, Id, Id, undefined, I, A, E, R>,
|
|
128
|
+
CommandRequestExtensions<RT, Id, I, A, E, R>
|
|
129
|
+
{
|
|
48
130
|
/**
|
|
49
|
-
*
|
|
131
|
+
* Send the request to the endpoint and return the raw Effect response.
|
|
132
|
+
* This does not perform query cache invalidation.
|
|
50
133
|
*/
|
|
51
|
-
(i: I)
|
|
134
|
+
request: (i: I) => Effect.Effect<A, E, R>
|
|
52
135
|
}
|
|
53
136
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
>
|
|
64
|
-
Commander.CommandContextLocal<Id, Id>,
|
|
65
|
-
Commander.CommanderWrap<RT, Id, Id, undefined, void, A, E, R>,
|
|
66
|
-
RequestExtensions<RT, Id, void, A, E, R>,
|
|
67
|
-
Effect.Effect<A, E, R>
|
|
68
|
-
{
|
|
137
|
+
export type CommandRequestWithExtensions<RT, Req> = Req extends
|
|
138
|
+
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer _Request, infer Id> ? RequestExt<RT, Id, I, A, E, R>
|
|
139
|
+
: never
|
|
140
|
+
|
|
141
|
+
export interface QueryExtensions<I, A, E, R> {
|
|
142
|
+
/**
|
|
143
|
+
* Send the request to the endpoint and return the raw Effect response.
|
|
144
|
+
* This does not set up query state tracking.
|
|
145
|
+
*/
|
|
146
|
+
request: (i: I) => Effect.Effect<A, E, R>
|
|
69
147
|
}
|
|
70
148
|
|
|
71
|
-
export type
|
|
72
|
-
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer _Request, infer
|
|
73
|
-
|
|
74
|
-
|
|
149
|
+
export type QueryRequestWithExtensions<Req> = Req extends
|
|
150
|
+
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer _Request, infer _Id> ? QueryExtensions<I, A, E, R>
|
|
151
|
+
: never
|
|
152
|
+
|
|
153
|
+
type QueryHandler<Req> = Req extends
|
|
154
|
+
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id>
|
|
155
|
+
? Request["type"] extends "query" ? RequestHandlerWithInput<I, A, E, R, Request, Id> : never
|
|
156
|
+
: never
|
|
157
|
+
|
|
158
|
+
type CommandHandler<Req> = Req extends
|
|
159
|
+
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id>
|
|
160
|
+
? Request["type"] extends "command" ? RequestHandlerWithInput<I, A, E, R, Request, Id> : never
|
|
161
|
+
: never
|
|
162
|
+
|
|
163
|
+
type QueryStreamHandler<Req> = Req extends
|
|
164
|
+
RequestStreamHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id, infer Final>
|
|
165
|
+
? [Request["stream"], Request["type"]] extends [true, "query"]
|
|
166
|
+
? RequestStreamHandlerWithInput<I, A, E, R, Request, Id, Final>
|
|
167
|
+
: never
|
|
168
|
+
: never
|
|
169
|
+
|
|
170
|
+
type CommandStreamHandler<Req> = Req extends
|
|
171
|
+
RequestStreamHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id, infer Final>
|
|
172
|
+
? [Request["stream"], Request["type"]] extends [true, "command"]
|
|
173
|
+
? RequestStreamHandlerWithInput<I, A, E, R, Request, Id, Final>
|
|
174
|
+
: never
|
|
75
175
|
: never
|
|
76
176
|
|
|
77
177
|
export interface MutationExtensions<RT, Id extends string, I, A, E, R> {
|
|
78
178
|
/** Defines a Command based on this mutation, taking the `id` of the mutation as the `id` of the Command.
|
|
79
179
|
* The Mutation function will be taken as the first member of the Command, the Command required input will be the Mutation input.
|
|
80
180
|
* see Command.wrap for details */
|
|
81
|
-
wrap:
|
|
82
|
-
|
|
181
|
+
wrap: <I18nKey extends string = Id, State extends Commander.IntlRecord | undefined = undefined>(
|
|
182
|
+
options?: Commander.FnOptions<Id, I18nKey, State>
|
|
183
|
+
) => Commander.CommanderWrap<RT, Id, I18nKey, State, I, A, E, R>
|
|
184
|
+
/** Defines a Command based on this call, taking the `id` of the mutation as the `id` of the Command.
|
|
83
185
|
* see Command.fn for details */
|
|
84
|
-
fn:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
/** my other doc */
|
|
88
|
-
export interface MutationExtWithInput<
|
|
89
|
-
RT,
|
|
90
|
-
Id extends string,
|
|
91
|
-
I,
|
|
92
|
-
A,
|
|
93
|
-
E,
|
|
94
|
-
R
|
|
95
|
-
> extends Commander.CommandContextLocal<Id, Id>, MutationExtensions<RT, Id, I, A, E, R> {
|
|
96
|
-
/**
|
|
97
|
-
* Call the endpoint with input
|
|
98
|
-
* Invalidate queries based on namespace of this mutation.
|
|
99
|
-
* Do not use for queries.
|
|
100
|
-
*/
|
|
101
|
-
(i: I): Effect.Effect<A, E, R>
|
|
186
|
+
fn: <I18nKey extends string = Id, State extends Commander.IntlRecord | undefined = undefined>(
|
|
187
|
+
options?: Commander.FnOptions<Id, I18nKey, State>
|
|
188
|
+
) => Commander.CommanderFn<RT, Id, I18nKey, State>
|
|
102
189
|
}
|
|
103
190
|
|
|
104
191
|
/**
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
192
|
+
* Send the request to the endpoint and return the raw Effect response.
|
|
193
|
+
* Also invalidates query caches using the request namespace by default.
|
|
194
|
+
* Namespace invalidation targets parent namespace keys
|
|
195
|
+
* (for example `$project/$configuration.get` invalidates `$project`).
|
|
196
|
+
* Override invalidation in client options via `queryInvalidation`.
|
|
197
|
+
*
|
|
198
|
+
* Pass `options` to attach a `select` Effect that runs after the mutation
|
|
199
|
+
* succeeds (its output is returned to the caller) and/or override the default
|
|
200
|
+
* `queryInvalidation`.
|
|
201
|
+
*
|
|
202
|
+
* When `I = void` the input argument may be omitted.
|
|
108
203
|
*/
|
|
109
204
|
export interface MutationExt<
|
|
110
205
|
RT,
|
|
111
206
|
Id extends string,
|
|
207
|
+
I,
|
|
112
208
|
A,
|
|
113
209
|
E,
|
|
114
|
-
R
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
210
|
+
R,
|
|
211
|
+
EA = unknown
|
|
212
|
+
> extends MutationExtensions<RT, Id, I, A, E, R> {
|
|
213
|
+
<B = A, E2 = never, R2 = never>(
|
|
214
|
+
input: I,
|
|
215
|
+
options?: MutationOptionsBase<A, B, E2, R2>
|
|
216
|
+
): Effect.Effect<B, E | E2, R | R2>
|
|
217
|
+
|
|
218
|
+
project: <ProjSchema extends S.Top>(
|
|
219
|
+
schema: EA extends ProjSchema["Encoded"] ? ProjSchema : never
|
|
220
|
+
) => MutationExt<
|
|
221
|
+
RT,
|
|
222
|
+
Id,
|
|
223
|
+
I,
|
|
224
|
+
ProjSchema["Type"],
|
|
225
|
+
E | S.SchemaError,
|
|
226
|
+
R | ProjSchema["DecodingServices"],
|
|
227
|
+
ProjSchema["Encoded"]
|
|
228
|
+
>
|
|
121
229
|
}
|
|
122
230
|
|
|
123
231
|
export type MutationWithExtensions<RT, Req> = Req extends
|
|
124
|
-
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer
|
|
125
|
-
?
|
|
126
|
-
:
|
|
232
|
+
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id>
|
|
233
|
+
? MutationExt<RT, Id, I, A, E, R, Request["success"]["Encoded"]>
|
|
234
|
+
: never
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* The `streamFn` builder for a stream-type request handler, using the stream-specific overloads.
|
|
238
|
+
*/
|
|
239
|
+
export type StreamFnStreamExtension<RT, Req> = Req extends
|
|
240
|
+
RequestStreamHandlerWithInput<infer _I, infer _A, infer _E, infer _R, infer _Request, infer Id, infer _Final>
|
|
241
|
+
? <I18nKey extends string = Id, State extends Commander.IntlRecord | undefined = undefined>(
|
|
242
|
+
options?: Commander.FnOptions<Id, I18nKey, State>
|
|
243
|
+
) => Commander.StreamGen<RT, Id, I18nKey, State> & Commander.NonGenStream<RT, Id, I18nKey, State>
|
|
244
|
+
: never
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* `mutate` factory — wraps per-invocation invalidation scaffolding
|
|
248
|
+
* into the stream itself (via `Stream.unwrap`) for use with `streamFn` combinators.
|
|
249
|
+
*/
|
|
250
|
+
export type StreamMutation2WithExtensions<RT, Req> = Req extends
|
|
251
|
+
RequestStreamHandlerWithInput<infer I, infer A, infer E, infer R, infer _Request, infer Id, infer _Final> ?
|
|
252
|
+
& ((input: I) => Stream.Stream<A, E, R>)
|
|
253
|
+
& {
|
|
254
|
+
readonly id: Id
|
|
255
|
+
readonly wrap: <I18nKey extends string = Id, State extends Commander.IntlRecord | undefined = undefined>(
|
|
256
|
+
options?: Commander.FnOptions<Id, I18nKey, State>
|
|
257
|
+
) => Commander.StreamerWrap<RT, Id, I18nKey, State, I, A, E, R>
|
|
258
|
+
}
|
|
127
259
|
: never
|
|
128
260
|
|
|
129
261
|
// we don't really care about the RT, as we are in charge of ensuring runtime safety anyway
|
|
130
262
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
131
263
|
declare const useQuery_: QueryImpl<any>["useQuery"]
|
|
132
264
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
265
|
+
declare const useQueryNew_: QueryImpl<any>["useQueryNew"]
|
|
266
|
+
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
267
|
+
declare const useQueryAtom_: QueryImpl<any>["useQueryAtom"]
|
|
268
|
+
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
269
|
+
declare const useQueryFamily_: QueryImpl<any>["useQueryFamily"]
|
|
270
|
+
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
271
|
+
declare const useSuspenseQueryNew_: QueryImpl<any>["useSuspenseQueryNew"]
|
|
272
|
+
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
133
273
|
declare const useSuspenseQuery_: QueryImpl<any>["useSuspenseQuery"]
|
|
274
|
+
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
275
|
+
declare const useStreamQuery_: QueryImpl<any>["useStreamQuery"]
|
|
276
|
+
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
277
|
+
declare const useStreamQueryFamily_: QueryImpl<any>["useStreamQueryFamily"]
|
|
278
|
+
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
279
|
+
declare const useStreamQueryAtom_: QueryImpl<any>["useStreamQueryAtom"]
|
|
280
|
+
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
281
|
+
declare const useStreamQueryNew_: QueryImpl<any>["useStreamQueryNew"]
|
|
282
|
+
|
|
283
|
+
export interface ProjectResult<RT, I, B, E, R, Request extends Req, Id extends string> {
|
|
284
|
+
request: (i: I) => Effect.Effect<B, E, R>
|
|
285
|
+
family: Exclude<R, RT> extends never ? ReturnType<typeof useQueryFamily_<I, E, B, Request, Id>>
|
|
286
|
+
: MissingDependencies<RT, R> & {}
|
|
287
|
+
query: Exclude<R, RT> extends never ? ReturnType<typeof useQuery_<I, E, B, Request, Id>>
|
|
288
|
+
: MissingDependencies<RT, R> & {}
|
|
289
|
+
queryNew: Exclude<R, RT> extends never ? ReturnType<typeof useQueryNew_<I, E, B, Request, Id>>
|
|
290
|
+
: MissingDependencies<RT, R> & {}
|
|
291
|
+
suspense: Exclude<R, RT> extends never ? ReturnType<typeof useSuspenseQuery_<I, E, B, Request, Id>>
|
|
292
|
+
: MissingDependencies<RT, R> & {}
|
|
293
|
+
suspenseNew: Exclude<R, RT> extends never ? ReturnType<typeof useSuspenseQueryNew_<I, E, B, Request, Id>>
|
|
294
|
+
: MissingDependencies<RT, R> & {}
|
|
295
|
+
atom: Exclude<R, RT> extends never ? ReturnType<typeof useQueryAtom_<I, E, B, Request, Id>>
|
|
296
|
+
: MissingDependencies<RT, R> & {}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export type QueryProjection<RT, HandlerReq> = HandlerReq extends
|
|
300
|
+
RequestHandlerWithInput<infer I, infer _A, infer E, infer R, infer Request, infer Id>
|
|
301
|
+
? Request["type"] extends "query" ? {
|
|
302
|
+
project: <ProjSchema extends S.Top>(
|
|
303
|
+
schema: Request["success"]["Encoded"] extends ProjSchema["Encoded"] ? ProjSchema : never
|
|
304
|
+
) => ProjectResult<
|
|
305
|
+
RT,
|
|
306
|
+
I,
|
|
307
|
+
ProjSchema["Type"],
|
|
308
|
+
E | S.SchemaError,
|
|
309
|
+
R | ProjSchema["DecodingServices"],
|
|
310
|
+
Request,
|
|
311
|
+
Id
|
|
312
|
+
>
|
|
313
|
+
}
|
|
314
|
+
: {}
|
|
315
|
+
: {}
|
|
134
316
|
|
|
135
|
-
export interface
|
|
317
|
+
export interface QueryResultExtensions<Request extends Req, Id extends string, I, A, E> {
|
|
136
318
|
/**
|
|
137
|
-
*
|
|
319
|
+
* Read helper for query requests.
|
|
320
|
+
* Runs as a tracked Vue Query and returns reactive state.
|
|
321
|
+
* Queries read state and should not be used to mutate it.
|
|
322
|
+
* When `I = void` the input argument may be omitted.
|
|
138
323
|
*/
|
|
139
324
|
query: ReturnType<typeof useQuery_<I, E, A, Request, Id>>
|
|
325
|
+
/**
|
|
326
|
+
* Atom-native query helper with object return shape.
|
|
327
|
+
* Additive migration surface; `.query()` remains the compatibility tuple API.
|
|
328
|
+
*/
|
|
329
|
+
queryNew: ReturnType<typeof useQueryNew_<I, E, A, Request, Id>>
|
|
140
330
|
// TODO or suspense as Option?
|
|
141
331
|
/**
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
* So that Suspense and error boundaries can be used.
|
|
332
|
+
* Like `.query`, but returns a Promise for setup-time awaiting.
|
|
333
|
+
* Use this when integrating with Vue Suspense / error boundaries.
|
|
145
334
|
*/
|
|
146
335
|
suspense: ReturnType<typeof useSuspenseQuery_<I, E, A, Request, Id>>
|
|
147
|
-
}
|
|
148
|
-
export interface QueriesWithoutInput<Request extends Req, Id extends string, A, E> {
|
|
149
336
|
/**
|
|
150
|
-
*
|
|
337
|
+
* Promise-based setup helper with object return shape.
|
|
338
|
+
* Additive migration surface; `.suspense()` remains the compatibility tuple API.
|
|
151
339
|
*/
|
|
152
|
-
|
|
153
|
-
// TODO or suspense as Option?
|
|
340
|
+
suspenseNew: ReturnType<typeof useSuspenseQueryNew_<I, E, A, Request, Id>>
|
|
154
341
|
/**
|
|
155
|
-
*
|
|
156
|
-
|
|
157
|
-
|
|
342
|
+
* Raw query atom for composition outside Vue refs.
|
|
343
|
+
*/
|
|
344
|
+
atom: ReturnType<typeof useQueryAtom_<I, E, A, Request, Id>>
|
|
345
|
+
/**
|
|
346
|
+
* Raw query atom family for composing query graphs before choosing a Vue observer.
|
|
158
347
|
*/
|
|
159
|
-
|
|
348
|
+
family: ReturnType<typeof useQueryFamily_<I, E, A, Request, Id>>
|
|
160
349
|
}
|
|
161
350
|
|
|
162
351
|
export type MissingDependencies<RT, R> = {
|
|
@@ -166,184 +355,59 @@ export type MissingDependencies<RT, R> = {
|
|
|
166
355
|
|
|
167
356
|
export type Queries<RT, Req> = Req extends
|
|
168
357
|
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id>
|
|
169
|
-
? Exclude<R, RT> extends never ?
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
358
|
+
? Request["type"] extends "query" ? Exclude<R, RT> extends never ? QueryResultExtensions<Request, Id, I, A, E>
|
|
359
|
+
: {
|
|
360
|
+
atom: MissingDependencies<RT, R> & {}
|
|
361
|
+
family: MissingDependencies<RT, R> & {}
|
|
362
|
+
query: MissingDependencies<RT, R> & {}
|
|
363
|
+
queryNew: MissingDependencies<RT, R> & {}
|
|
364
|
+
suspense: MissingDependencies<RT, R> & {}
|
|
365
|
+
suspenseNew: MissingDependencies<RT, R> & {}
|
|
366
|
+
}
|
|
367
|
+
: never
|
|
177
368
|
: never
|
|
178
369
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
E2 = E,
|
|
195
|
-
R2 = R,
|
|
196
|
-
ESuccess = never,
|
|
197
|
-
RSuccess = never,
|
|
198
|
-
EError = never,
|
|
199
|
-
RError = never,
|
|
200
|
-
EDefect = never,
|
|
201
|
-
RDefect = never
|
|
202
|
-
> extends MutationOptions<A, E, R, A2, E2, R2, I> {
|
|
203
|
-
/** set to `undefined` to use default message */
|
|
204
|
-
successMessage?: ((a: A2, i: I) => Effect.Effect<string | undefined, ESuccess, RSuccess>) | undefined
|
|
205
|
-
/** set to `undefined` to use default message */
|
|
206
|
-
failMessage?: ((e: E2, i: I) => Effect.Effect<string | undefined, EError, RError>) | undefined
|
|
207
|
-
/** set to `undefined` to use default message */
|
|
208
|
-
defectMessage?: ((e: Cause.Cause<E2>, i: I) => Effect.Effect<string | undefined, EDefect, RDefect>) | undefined
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
export interface LowOpts<
|
|
212
|
-
A,
|
|
213
|
-
E,
|
|
214
|
-
I = void,
|
|
215
|
-
ESuccess = never,
|
|
216
|
-
RSuccess = never,
|
|
217
|
-
EError = never,
|
|
218
|
-
RError = never,
|
|
219
|
-
EDefect = never,
|
|
220
|
-
RDefect = never
|
|
221
|
-
> {
|
|
222
|
-
onSuccess: (a: A, i: I) => Effect.Effect<void, ESuccess, RSuccess>
|
|
223
|
-
onFail: (e: E, i: I) => Effect.Effect<void, EError, RError>
|
|
224
|
-
onDefect: (e: Cause.Cause<E>, i: I) => Effect.Effect<void, EDefect, RDefect>
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
export interface LowOptsOptional<
|
|
228
|
-
A,
|
|
229
|
-
E,
|
|
230
|
-
R,
|
|
231
|
-
I = void,
|
|
232
|
-
A2 = A,
|
|
233
|
-
E2 = E,
|
|
234
|
-
R2 = R,
|
|
235
|
-
ESuccess = never,
|
|
236
|
-
RSuccess = never,
|
|
237
|
-
EError = never,
|
|
238
|
-
RError = never,
|
|
239
|
-
EDefect = never,
|
|
240
|
-
RDefect = never
|
|
241
|
-
> extends MutationOptions<A, E, R, A2, E2, R2, I> {
|
|
242
|
-
onSuccess?: (a: A, i: I) => Effect.Effect<void, ESuccess, RSuccess>
|
|
243
|
-
onFail?: (e: E, i: I) => Effect.Effect<void, EError, RError>
|
|
244
|
-
onDefect?: (e: Cause.Cause<E>, i: I) => Effect.Effect<void, EDefect, RDefect>
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
type WithAction<A> = A & {
|
|
248
|
-
action: string
|
|
370
|
+
export interface StreamQueryExtensions<Request extends Req, Id extends string, I, A, E> {
|
|
371
|
+
atom: ReturnType<typeof useStreamQueryAtom_<I, E, A, Request, Id>>
|
|
372
|
+
family: StreamQueryAtomFamily<I, A, E>
|
|
373
|
+
/**
|
|
374
|
+
* Stream helper for query-stream requests.
|
|
375
|
+
* Legacy compatibility helper. Collects the whole stream into an array before
|
|
376
|
+
* publishing data.
|
|
377
|
+
* When `I = void` the input argument may be omitted.
|
|
378
|
+
*/
|
|
379
|
+
query: ReturnType<typeof useStreamQuery_<I, E, A, Request, Id>>
|
|
380
|
+
/**
|
|
381
|
+
* Atom-native stream query helper. Exposes incremental pull state and a `pull`
|
|
382
|
+
* command instead of collecting the whole stream first.
|
|
383
|
+
*/
|
|
384
|
+
queryNew: ReturnType<typeof useStreamQueryNew_<I, E, A, Request, Id>>
|
|
249
385
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
type ActResp<A, E, R, V = ComputedRef<Res<A, E>>> = readonly [
|
|
260
|
-
V,
|
|
261
|
-
WithAction<Effect.Effect<Exit.Exit<A, E>, never, R>>
|
|
262
|
-
]
|
|
263
|
-
|
|
264
|
-
export const suppressToast = constant(Effect.succeed(undefined))
|
|
265
|
-
|
|
266
|
-
/** handles errors as specified and reports defects */
|
|
267
|
-
function handleRequest<
|
|
268
|
-
E extends ResponseErrors,
|
|
269
|
-
A,
|
|
270
|
-
R,
|
|
271
|
-
I = void,
|
|
272
|
-
ESuccess = never,
|
|
273
|
-
RSuccess = never,
|
|
274
|
-
EError = never,
|
|
275
|
-
RError = never,
|
|
276
|
-
EDefect = never,
|
|
277
|
-
RDefect = never
|
|
278
|
-
>(
|
|
279
|
-
f: Effect.Effect<Exit.Exit<A, E>, never, R> | ((i: I) => Effect.Effect<Exit.Exit<A, E>, never, R>),
|
|
280
|
-
id: string,
|
|
281
|
-
action: string,
|
|
282
|
-
options: {
|
|
283
|
-
onSuccess: (a: A, i: I) => Effect.Effect<void, ESuccess, RSuccess>
|
|
284
|
-
onFail: (e: E, i: I) => Effect.Effect<void, EError, RError>
|
|
285
|
-
onDefect: (e: Cause.Cause<E>, i: I) => Effect.Effect<void, EDefect, RDefect>
|
|
386
|
+
export type StreamQueries<RT, HandlerReq> = HandlerReq extends
|
|
387
|
+
RequestStreamHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id, infer _Final>
|
|
388
|
+
? Exclude<R, RT> extends never ? StreamQueryExtensions<Request, Id, I, A, E>
|
|
389
|
+
: {
|
|
390
|
+
atom: MissingDependencies<RT, R> & {}
|
|
391
|
+
family: MissingDependencies<RT, R> & {}
|
|
392
|
+
query: MissingDependencies<RT, R> & {}
|
|
393
|
+
queryNew: MissingDependencies<RT, R> & {}
|
|
286
394
|
}
|
|
287
|
-
|
|
288
|
-
const handleEffect = (i: any) => (self: Effect.Effect<Exit.Exit<A, E>, never, R>) =>
|
|
289
|
-
self.pipe(
|
|
290
|
-
Effect.tap(
|
|
291
|
-
Effect.matchCauseEffect({
|
|
292
|
-
onSuccess: (r) => options.onSuccess(r, i),
|
|
293
|
-
onFailure: (cause) =>
|
|
294
|
-
Effect.gen(function*() {
|
|
295
|
-
if (Cause.hasInterruptsOnly(cause)) {
|
|
296
|
-
console.info(`Interrupted while trying to ${action}`)
|
|
297
|
-
return
|
|
298
|
-
}
|
|
395
|
+
: never
|
|
299
396
|
|
|
300
|
-
|
|
301
|
-
if (Option.isSome(fail)) {
|
|
302
|
-
if (fail.value._tag === "SuppressErrors") {
|
|
303
|
-
console.info(`Suppressed error trying to ${action}`, fail.value)
|
|
304
|
-
return
|
|
305
|
-
}
|
|
306
|
-
const message = `Failure trying to ${action}`
|
|
307
|
-
yield* reportMessage(message, { action, error: fail.value })
|
|
308
|
-
yield* options.onFail(fail.value, i)
|
|
309
|
-
return
|
|
310
|
-
}
|
|
397
|
+
const _useMutation = makeMutation(atomQueryInvalidator)
|
|
311
398
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
yield* reportRuntimeError(cause, extra)
|
|
317
|
-
|
|
318
|
-
yield* options.onDefect(cause, i)
|
|
319
|
-
})
|
|
320
|
-
})
|
|
321
|
-
),
|
|
322
|
-
Effect.withSpan(`mutation ${id}`, {}, { captureStackTrace: false })
|
|
323
|
-
)
|
|
324
|
-
return Object.assign(
|
|
325
|
-
Effect.isEffect(f)
|
|
326
|
-
? pipe(
|
|
327
|
-
f,
|
|
328
|
-
handleEffect(void 0)
|
|
329
|
-
)
|
|
330
|
-
: (i: I) =>
|
|
331
|
-
pipe(
|
|
332
|
-
f(i),
|
|
333
|
-
handleEffect(i)
|
|
334
|
-
),
|
|
335
|
-
{ action }
|
|
336
|
-
)
|
|
399
|
+
const wrapWithSpan = (self: { id: string }, mut: any) => {
|
|
400
|
+
const span = (eff: Effect.Effect<any, any, any>) =>
|
|
401
|
+
Effect.withSpan(`mutation ${self.id}`, {}, { captureStackTrace: false })(eff)
|
|
402
|
+
return (input: any, options?: MutationOptionsBase) => span(mut(input, options))
|
|
337
403
|
}
|
|
338
404
|
|
|
339
|
-
const _useMutation = makeMutation()
|
|
340
|
-
|
|
341
405
|
/**
|
|
342
406
|
* Pass an Effect or a function that returns an Effect, e.g from a client action
|
|
343
407
|
* Executes query cache invalidation based on default rules or provided option.
|
|
344
408
|
* adds a span with the mutation id
|
|
345
409
|
*/
|
|
346
|
-
export const useMutation: typeof _useMutation = <
|
|
410
|
+
export const useMutation: typeof _useMutation = (<
|
|
347
411
|
I,
|
|
348
412
|
E,
|
|
349
413
|
A,
|
|
@@ -351,25 +415,21 @@ export const useMutation: typeof _useMutation = <
|
|
|
351
415
|
Request extends Req,
|
|
352
416
|
Name extends string
|
|
353
417
|
>(
|
|
354
|
-
self: RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
355
|
-
options?: MutationOptionsBase
|
|
418
|
+
self: RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
356
419
|
) =>
|
|
357
420
|
Object.assign(
|
|
358
|
-
|
|
359
|
-
_useMutation(self as any, options),
|
|
360
|
-
Effect.withSpan(`mutation ${self.id}`, {}, { captureStackTrace: false })
|
|
361
|
-
) as any,
|
|
421
|
+
wrapWithSpan(self, _useMutation(self as any)),
|
|
362
422
|
{ id: self.id }
|
|
363
|
-
)
|
|
423
|
+
)) as any
|
|
364
424
|
|
|
365
425
|
/**
|
|
366
426
|
* Pass an Effect or a function that returns an Effect, e.g from a client action
|
|
367
427
|
* Executes query cache invalidation based on default rules or provided option.
|
|
368
428
|
* adds a span with the mutation id
|
|
369
429
|
*/
|
|
370
|
-
export const useMutationInt = (): typeof _useMutation => {
|
|
371
|
-
const _useMutation = useMakeMutation()
|
|
372
|
-
return <
|
|
430
|
+
export const useMutationInt = (queryInvalidator: QueryInvalidator): typeof _useMutation => {
|
|
431
|
+
const _useMutation = useMakeMutation(queryInvalidator)
|
|
432
|
+
return (<
|
|
373
433
|
I,
|
|
374
434
|
E,
|
|
375
435
|
A,
|
|
@@ -377,721 +437,65 @@ export const useMutationInt = (): typeof _useMutation => {
|
|
|
377
437
|
Request extends Req,
|
|
378
438
|
Name extends string
|
|
379
439
|
>(
|
|
380
|
-
self: RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
381
|
-
options?: MutationOptionsBase
|
|
440
|
+
self: RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
382
441
|
) =>
|
|
383
442
|
Object.assign(
|
|
384
|
-
|
|
385
|
-
_useMutation(self as any, options),
|
|
386
|
-
Effect.withSpan(`mutation ${self.id}`, {}, { captureStackTrace: false })
|
|
387
|
-
) as any,
|
|
443
|
+
wrapWithSpan(self, _useMutation(self as any)),
|
|
388
444
|
{ id: self.id }
|
|
389
|
-
)
|
|
445
|
+
)) as any
|
|
390
446
|
}
|
|
391
447
|
|
|
392
|
-
export
|
|
393
|
-
constructor(
|
|
394
|
-
private readonly getRuntime: () => ServiceMap.ServiceMap<RT>,
|
|
395
|
-
private readonly toast: Toast,
|
|
396
|
-
private readonly intl: I18n
|
|
397
|
-
) {}
|
|
448
|
+
export type ClientFrom<M extends RequestsAny> = RequestHandlers<never, never, M, ExtractModuleName<M>>
|
|
398
449
|
|
|
450
|
+
export interface MakeClientOptions {
|
|
399
451
|
/**
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
* @deprecated use `Command.fn` and friends instead
|
|
452
|
+
* Selects the engine behind legacy `.query()` / `.suspense()` helpers.
|
|
453
|
+
* Atom-native `.atom()` / `.family()` / `.queryNew()` / `.suspenseNew()` always use Atom.
|
|
403
454
|
*/
|
|
404
|
-
readonly
|
|
405
|
-
|
|
406
|
-
* Effect results are converted to Exit, so errors are ignored by default.
|
|
407
|
-
* you should use the result ref to render errors!
|
|
408
|
-
* @deprecated use `Command.fn` and friends instead
|
|
409
|
-
*/
|
|
410
|
-
<I, E, A, R, Request extends Req, Name extends string, A2 = A, E2 = E, R2 = R>(
|
|
411
|
-
self: RequestHandlerWithInput<I, A, E, R, Request, Name>,
|
|
412
|
-
options?: MutationOptions<A, E, R, A2, E2, R2, I>
|
|
413
|
-
): readonly [
|
|
414
|
-
ComputedRef<AsyncResult.AsyncResult<A2, E2>>,
|
|
415
|
-
(i: I) => Effect.Effect<Exit.Exit<A2, E2>, never, R2>
|
|
416
|
-
]
|
|
417
|
-
/**
|
|
418
|
-
* Effect results are converted to Exit, so errors are ignored by default.
|
|
419
|
-
* you should use the result ref to render errors!
|
|
420
|
-
* @deprecated use `Command.fn` and friends instead
|
|
421
|
-
*/
|
|
422
|
-
<E, A, R, Request extends Req, Name extends string, A2 = A, E2 = E, R2 = R>(
|
|
423
|
-
self: RequestHandler<A, E, R, Request, Name>,
|
|
424
|
-
options?: MutationOptions<A, E, R, A2, E2, R2>
|
|
425
|
-
): readonly [
|
|
426
|
-
ComputedRef<AsyncResult.AsyncResult<A2, E2>>,
|
|
427
|
-
Effect.Effect<Exit.Exit<A2, E2>, never, R2>
|
|
428
|
-
]
|
|
429
|
-
} = <I, E, A, R, Request extends Req, Name extends string, A2 = A, E2 = E, R2 = R>(
|
|
430
|
-
self: RequestHandlerWithInput<I, A, E, R, Request, Name> | RequestHandler<A, E, R, Request, Name>,
|
|
431
|
-
options?: MutationOptions<A, E, R, A2, E2, R2, I>
|
|
432
|
-
) => {
|
|
433
|
-
const unsafe = _useMutation(self as any, options)
|
|
434
|
-
|
|
435
|
-
type MH = NonNullable<NonNullable<typeof options>["mapHandler"]>
|
|
436
|
-
const mh = options?.mapHandler ?? identity as MH
|
|
437
|
-
|
|
438
|
-
const [a, b] = asResult(
|
|
439
|
-
mapHandler(
|
|
440
|
-
mapHandler(unsafe as any, mh),
|
|
441
|
-
Effect.tapCauseIf(Cause.hasDies, (cause) => reportRuntimeError(cause))
|
|
442
|
-
) as any
|
|
443
|
-
)
|
|
444
|
-
return [
|
|
445
|
-
a,
|
|
446
|
-
mapHandler(
|
|
447
|
-
b,
|
|
448
|
-
Effect.withSpan(`mutation ${self.id}`, {}, { captureStackTrace: false })
|
|
449
|
-
)
|
|
450
|
-
] as const as any
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
/** handles errors as toasts and reports defects
|
|
454
|
-
* @deprecated use `Command.fn` and friends instead
|
|
455
|
-
*/
|
|
456
|
-
readonly useHandleRequestWithToast = () => {
|
|
457
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
458
|
-
const self = this
|
|
459
|
-
return handleRequestWithToast
|
|
460
|
-
/**
|
|
461
|
-
* Pass a function that returns a Promise.
|
|
462
|
-
* Returns an execution function which reports errors as Toast.
|
|
463
|
-
*/
|
|
464
|
-
function handleRequestWithToast<
|
|
465
|
-
A,
|
|
466
|
-
E extends ResponseErrors,
|
|
467
|
-
R,
|
|
468
|
-
I = void,
|
|
469
|
-
A2 = A,
|
|
470
|
-
E2 extends ResponseErrors = E,
|
|
471
|
-
R2 = R,
|
|
472
|
-
ESuccess = never,
|
|
473
|
-
RSuccess = never,
|
|
474
|
-
EError = never,
|
|
475
|
-
RError = never,
|
|
476
|
-
EDefect = never,
|
|
477
|
-
RDefect = never
|
|
478
|
-
>(
|
|
479
|
-
f: Effect.Effect<Exit.Exit<A2, E2>, never, R2> | ((i: I) => Effect.Effect<Exit.Exit<A2, E2>, never, R2>),
|
|
480
|
-
id: string,
|
|
481
|
-
action: string,
|
|
482
|
-
options: Opts<A, E, R, I, A2, E2, R2, ESuccess, RSuccess, EError, RError, EDefect, RDefect> = {}
|
|
483
|
-
) {
|
|
484
|
-
const actionMessage = self.intl.formatMessage({ id: `action.${action}`, defaultMessage: action })
|
|
485
|
-
const defaultWarnMessage = self.intl.formatMessage(
|
|
486
|
-
{ id: "handle.with_warnings" },
|
|
487
|
-
{ action: actionMessage }
|
|
488
|
-
)
|
|
489
|
-
const defaultSuccessMessage = self.intl.formatMessage(
|
|
490
|
-
{ id: "handle.success" },
|
|
491
|
-
{ action: actionMessage }
|
|
492
|
-
)
|
|
493
|
-
const defaultErrorMessage = self.intl.formatMessage(
|
|
494
|
-
{ id: "handle.with_errors" },
|
|
495
|
-
{ action: actionMessage }
|
|
496
|
-
)
|
|
497
|
-
|
|
498
|
-
return handleRequest<E2, A2, R2, any, ESuccess, RSuccess, EError, RError, EDefect, RDefect>(f, id, action, {
|
|
499
|
-
onSuccess: Effect.fnUntraced(function*(a, i) {
|
|
500
|
-
const message = options.successMessage ? yield* options.successMessage(a, i) : defaultSuccessMessage
|
|
501
|
-
+ (S.is(OperationSuccess)(a) && a.message
|
|
502
|
-
? "\n" + a.message
|
|
503
|
-
: "")
|
|
504
|
-
if (message) {
|
|
505
|
-
yield* self.toast.success(message)
|
|
506
|
-
}
|
|
507
|
-
}),
|
|
508
|
-
onFail: Effect.fnUntraced(function*(e, i) {
|
|
509
|
-
if (!options.failMessage && e._tag === "OperationFailure") {
|
|
510
|
-
yield* self.toast.warning(
|
|
511
|
-
defaultWarnMessage + e.message
|
|
512
|
-
? "\n" + e.message
|
|
513
|
-
: ""
|
|
514
|
-
)
|
|
515
|
-
return
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
const message = options.failMessage
|
|
519
|
-
? yield* options.failMessage(e, i)
|
|
520
|
-
: `${defaultErrorMessage}:\n` + renderError(e)
|
|
521
|
-
if (message) {
|
|
522
|
-
yield* self.toast.error(message)
|
|
523
|
-
}
|
|
524
|
-
}),
|
|
525
|
-
onDefect: Effect.fnUntraced(function*(cause, i) {
|
|
526
|
-
const message = options.defectMessage
|
|
527
|
-
? yield* options.defectMessage(cause, i)
|
|
528
|
-
: self.intl.formatMessage(
|
|
529
|
-
{ id: "handle.unexpected_error" },
|
|
530
|
-
{
|
|
531
|
-
action: actionMessage,
|
|
532
|
-
error: Cause.pretty(cause)
|
|
533
|
-
}
|
|
534
|
-
)
|
|
535
|
-
if (message) {
|
|
536
|
-
yield* self.toast.error(message)
|
|
537
|
-
}
|
|
538
|
-
})
|
|
539
|
-
})
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
function renderError(e: ResponseErrors): string {
|
|
543
|
-
return Match.value(e as any).pipe(
|
|
544
|
-
Match.tags({
|
|
545
|
-
// HttpErrorRequest: e =>
|
|
546
|
-
// this.intl.value.formatMessage(
|
|
547
|
-
// { id: "handle.request_error" },
|
|
548
|
-
// { error: `${e.error}` },
|
|
549
|
-
// ),
|
|
550
|
-
// HttpErrorResponse: e =>
|
|
551
|
-
// e.response.status >= 500 ||
|
|
552
|
-
// e.response.body._tag !== "Some" ||
|
|
553
|
-
// !e.response.body.value
|
|
554
|
-
// ? this.intl.value.formatMessage(
|
|
555
|
-
// { id: "handle.error_response" },
|
|
556
|
-
// {
|
|
557
|
-
// error: `${
|
|
558
|
-
// e.response.body._tag === "Some" && e.response.body.value
|
|
559
|
-
// ? parseError(e.response.body.value)
|
|
560
|
-
// : "Unknown"
|
|
561
|
-
// } (${e.response.status})`,
|
|
562
|
-
// },
|
|
563
|
-
// )
|
|
564
|
-
// : this.intl.value.formatMessage(
|
|
565
|
-
// { id: "handle.unexpected_error" },
|
|
566
|
-
// {
|
|
567
|
-
// error:
|
|
568
|
-
// JSON.stringify(e.response.body, undefined, 2) +
|
|
569
|
-
// "( " +
|
|
570
|
-
// e.response.status +
|
|
571
|
-
// ")",
|
|
572
|
-
// },
|
|
573
|
-
// ),
|
|
574
|
-
// ResponseError: e =>
|
|
575
|
-
// this.intl.value.formatMessage(
|
|
576
|
-
// { id: "handle.response_error" },
|
|
577
|
-
// { error: `${e.error}` },
|
|
578
|
-
// ),
|
|
579
|
-
SchemaError: (e: any) => {
|
|
580
|
-
console.warn(e.toString())
|
|
581
|
-
return self.intl.formatMessage({ id: "validation.failed" })
|
|
582
|
-
}
|
|
583
|
-
}),
|
|
584
|
-
Match.orElse((e: any) => `${e.message ?? e._tag ?? e}`)
|
|
585
|
-
)
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
/**
|
|
590
|
-
* Pass a function that returns an Effect, e.g from a client action, give it a name.
|
|
591
|
-
* Returns a tuple with raw Result and execution function which reports success and errors as Toast.
|
|
592
|
-
* @deprecated use `Command.fn` and friends instead
|
|
593
|
-
*/
|
|
594
|
-
readonly useAndHandleMutationResult: {
|
|
595
|
-
/**
|
|
596
|
-
* Pass a function that returns an Effect, e.g from a client action, give it a name.
|
|
597
|
-
* Returns a tuple with raw Result and execution function which reports success and errors as Toast.
|
|
598
|
-
* @deprecated use `Command.fn` and friends instead
|
|
599
|
-
*/
|
|
600
|
-
<
|
|
601
|
-
I,
|
|
602
|
-
E extends ResponseErrors,
|
|
603
|
-
A,
|
|
604
|
-
R,
|
|
605
|
-
Request extends Req,
|
|
606
|
-
Name extends string,
|
|
607
|
-
A2 = A,
|
|
608
|
-
E2 extends ResponseErrors = E,
|
|
609
|
-
R2 = R,
|
|
610
|
-
ESuccess = never,
|
|
611
|
-
RSuccess = never,
|
|
612
|
-
EError = never,
|
|
613
|
-
RError = never,
|
|
614
|
-
EDefect = never,
|
|
615
|
-
RDefect = never
|
|
616
|
-
>(
|
|
617
|
-
self: RequestHandlerWithInput<I, A, E, R, Request, Name>,
|
|
618
|
-
action: string,
|
|
619
|
-
options?: Opts<A, E, R, I, A2, E2, R2, ESuccess, RSuccess, EError, RError, EDefect, RDefect>
|
|
620
|
-
): Resp<I, A2, E2, R2, ComputedRef<AsyncResult.AsyncResult<A2, E2>>>
|
|
621
|
-
/**
|
|
622
|
-
* Pass a function that returns an Effect, e.g from a client action, give it a name.
|
|
623
|
-
* Returns a tuple with raw Result and execution function which reports success and errors as Toast.
|
|
624
|
-
* @deprecated use `Command.fn` and friends instead
|
|
625
|
-
*/
|
|
626
|
-
<
|
|
627
|
-
E extends ResponseErrors,
|
|
628
|
-
A,
|
|
629
|
-
R,
|
|
630
|
-
Request extends Req,
|
|
631
|
-
Name extends string,
|
|
632
|
-
A2 = A,
|
|
633
|
-
E2 extends ResponseErrors = E,
|
|
634
|
-
R2 = R,
|
|
635
|
-
ESuccess = never,
|
|
636
|
-
RSuccess = never,
|
|
637
|
-
EError = never,
|
|
638
|
-
RError = never,
|
|
639
|
-
EDefect = never,
|
|
640
|
-
RDefect = never
|
|
641
|
-
>(
|
|
642
|
-
self: RequestHandler<A, E, R, Request, Name>,
|
|
643
|
-
action: string,
|
|
644
|
-
options?: Opts<A, E, R, void, A2, E2, R2, ESuccess, RSuccess, EError, RError, EDefect, RDefect>
|
|
645
|
-
): ActResp<A2, E2, R2, ComputedRef<AsyncResult.AsyncResult<A2, E2>>>
|
|
646
|
-
} = <E extends ResponseErrors, A, R, Request extends Req, Name extends string, I>(
|
|
647
|
-
self: RequestHandlerWithInput<I, A, E, R, Request, Name> | RequestHandler<A, E, R, Request, Name>,
|
|
648
|
-
action: any,
|
|
649
|
-
options?: Opts<any, any, any, any, any, any, any, any, any, any, any, any, any>
|
|
650
|
-
): any => {
|
|
651
|
-
const handleRequestWithToast = this.useHandleRequestWithToast()
|
|
652
|
-
const handler = self.handler
|
|
653
|
-
const unsafe = _useMutation({
|
|
654
|
-
...self,
|
|
655
|
-
handler: Effect.isEffect(handler)
|
|
656
|
-
? (pipe(
|
|
657
|
-
Effect.annotateCurrentSpan({ action }),
|
|
658
|
-
Effect.andThen(handler)
|
|
659
|
-
) as any)
|
|
660
|
-
: (...args: [any]) =>
|
|
661
|
-
pipe(
|
|
662
|
-
Effect.annotateCurrentSpan({ action }),
|
|
663
|
-
Effect.andThen(handler(...args))
|
|
664
|
-
)
|
|
665
|
-
}, options ? dropUndefinedT(options) : undefined)
|
|
666
|
-
|
|
667
|
-
type MH = NonNullable<NonNullable<typeof options>["mapHandler"]>
|
|
668
|
-
const mh = options?.mapHandler ?? identity as MH
|
|
669
|
-
|
|
670
|
-
// Effect.tapDefect(reportRuntimeError) handled in toast handler,
|
|
671
|
-
const [a, b] = asResult(mapHandler(unsafe, mh) as any)
|
|
455
|
+
readonly legacyQueryEngine?: "atom" | "tanstack"
|
|
456
|
+
}
|
|
672
457
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
handleRequestWithToast(b as any, self.id, action, options)
|
|
676
|
-
)
|
|
677
|
-
}
|
|
678
|
-
//
|
|
458
|
+
export class QueryImpl<R> {
|
|
459
|
+
readonly getRuntime: () => Context.Context<R>
|
|
679
460
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
I,
|
|
695
|
-
E extends ResponseErrors,
|
|
696
|
-
A,
|
|
697
|
-
R,
|
|
698
|
-
Request extends Req,
|
|
699
|
-
Name extends string,
|
|
700
|
-
A2 = A,
|
|
701
|
-
E2 extends ResponseErrors = E,
|
|
702
|
-
R2 = R,
|
|
703
|
-
ESuccess = never,
|
|
704
|
-
RSuccess = never,
|
|
705
|
-
EError = never,
|
|
706
|
-
RError = never,
|
|
707
|
-
EDefect = never,
|
|
708
|
-
RDefect = never
|
|
709
|
-
>(
|
|
710
|
-
self: RequestHandlerWithInput<I, A, E, R, Request, Name>,
|
|
711
|
-
action: string,
|
|
712
|
-
options?: Opts<A, E, R, I, A2, E2, R2, ESuccess, RSuccess, EError, RError, EDefect, RDefect>
|
|
713
|
-
): Resp<I, A2, E2, R2>
|
|
714
|
-
/**
|
|
715
|
-
* Pass a function that returns an Effect, e.g from a client action, give it a name.
|
|
716
|
-
* Returns a tuple with state ref and execution function which reports success and errors as Toast.
|
|
717
|
-
*
|
|
718
|
-
* @deprecated use `Command.fn` and friends instead
|
|
719
|
-
*/
|
|
720
|
-
<
|
|
721
|
-
E extends ResponseErrors,
|
|
722
|
-
A,
|
|
723
|
-
R,
|
|
724
|
-
Request extends Req,
|
|
725
|
-
Name extends string,
|
|
726
|
-
A2 = A,
|
|
727
|
-
E2 extends ResponseErrors = E,
|
|
728
|
-
R2 = R,
|
|
729
|
-
ESuccess = never,
|
|
730
|
-
RSuccess = never,
|
|
731
|
-
EError = never,
|
|
732
|
-
RError = never,
|
|
733
|
-
EDefect = never,
|
|
734
|
-
RDefect = never
|
|
735
|
-
>(
|
|
736
|
-
self: RequestHandler<A, E, R, Request, Name>,
|
|
737
|
-
action: string,
|
|
738
|
-
options?: Opts<A, E, R, void, A2, E2, R2, ESuccess, RSuccess, EError, RError, EDefect, RDefect>
|
|
739
|
-
): ActResp<A2, E2, R2>
|
|
740
|
-
} = (
|
|
741
|
-
self: any,
|
|
742
|
-
action: any,
|
|
743
|
-
options?: Opts<any, any, any, any, any, any, any, any, any, any, any, any, any>
|
|
744
|
-
): any => {
|
|
745
|
-
const [a, b] = this.useAndHandleMutationResult(self, action, options)
|
|
746
|
-
|
|
747
|
-
return tuple(
|
|
748
|
-
computed(() => mutationResultToVue(a.value)),
|
|
749
|
-
b
|
|
750
|
-
)
|
|
461
|
+
constructor(
|
|
462
|
+
getRuntime: () => Context.Context<R>,
|
|
463
|
+
getAtomRt: () => AtomClientRuntime,
|
|
464
|
+
legacyUseQuery?: ReturnType<typeof makeQuery<R>>
|
|
465
|
+
) {
|
|
466
|
+
this.getRuntime = getRuntime
|
|
467
|
+
this.useQuery = legacyUseQuery ?? makeQuery(this.getRuntime, getAtomRt)
|
|
468
|
+
this.useQueryNew = makeQueryNew(this.getRuntime, getAtomRt)
|
|
469
|
+
this.useQueryAtom = makeQueryAtom(this.getRuntime, getAtomRt)
|
|
470
|
+
this.useQueryFamily = makeQueryFamily(this.getRuntime, getAtomRt)
|
|
471
|
+
this.useStreamQuery = makeStreamQuery(this.getRuntime, getAtomRt)
|
|
472
|
+
this.useStreamQueryFamily = makeStreamQueryFamily(this.getRuntime, getAtomRt)
|
|
473
|
+
this.useStreamQueryAtom = makeStreamQueryAtom(this.getRuntime, getAtomRt)
|
|
474
|
+
this.useStreamQueryNew = makeStreamQueryNew(this.getRuntime, getAtomRt)
|
|
751
475
|
}
|
|
752
|
-
|
|
753
|
-
/** @deprecated use `Command.fn` and friends instead */
|
|
754
|
-
readonly makeUseAndHandleMutation = (
|
|
755
|
-
defaultOptions?: Opts<any, any, any, any, any, any, any, any, any>
|
|
756
|
-
) =>
|
|
757
|
-
((self: any, action: any, options: any) => {
|
|
758
|
-
return this.useAndHandleMutation(
|
|
759
|
-
self,
|
|
760
|
-
action,
|
|
761
|
-
{ ...defaultOptions, ...options }
|
|
762
|
-
)
|
|
763
|
-
}) as unknown as {
|
|
764
|
-
<
|
|
765
|
-
I,
|
|
766
|
-
E extends ResponseErrors,
|
|
767
|
-
A,
|
|
768
|
-
R,
|
|
769
|
-
Request extends Req,
|
|
770
|
-
Name extends string,
|
|
771
|
-
A2 = A,
|
|
772
|
-
E2 extends ResponseErrors = E,
|
|
773
|
-
R2 = R,
|
|
774
|
-
ESuccess = never,
|
|
775
|
-
RSuccess = never,
|
|
776
|
-
EError = never,
|
|
777
|
-
RError = never,
|
|
778
|
-
EDefect = never,
|
|
779
|
-
RDefect = never
|
|
780
|
-
>(
|
|
781
|
-
self: RequestHandlerWithInput<I, A, E, R, Request, Name>,
|
|
782
|
-
action: string,
|
|
783
|
-
options?: Opts<A, E, R, I, A2, E2, R2, ESuccess, RSuccess, EError, RError, EDefect, RDefect>
|
|
784
|
-
): Resp<I, A2, E2, R2>
|
|
785
|
-
<
|
|
786
|
-
E extends ResponseErrors,
|
|
787
|
-
A,
|
|
788
|
-
R,
|
|
789
|
-
Request extends Req,
|
|
790
|
-
Name extends string,
|
|
791
|
-
A2 = A,
|
|
792
|
-
E2 extends ResponseErrors = E,
|
|
793
|
-
R2 = R,
|
|
794
|
-
ESuccess = never,
|
|
795
|
-
RSuccess = never,
|
|
796
|
-
EError = never,
|
|
797
|
-
RError = never,
|
|
798
|
-
EDefect = never,
|
|
799
|
-
RDefect = never
|
|
800
|
-
>(
|
|
801
|
-
self: RequestHandler<A, E, R, Request, Name>,
|
|
802
|
-
action: string,
|
|
803
|
-
options?: Opts<A, E, R, void, A2, E2, R2, ESuccess, RSuccess, EError, RError, EDefect, RDefect>
|
|
804
|
-
): ActResp<A2, E2, R2>
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
/**
|
|
808
|
-
* The same as @see useAndHandleMutation, but does not display any toasts by default.
|
|
809
|
-
* Messages for success, error and defect toasts can be provided in the Options.
|
|
810
|
-
* @deprecated use `Command.fn` and friends instead
|
|
811
|
-
*/
|
|
812
|
-
readonly useAndHandleMutationSilently: {
|
|
813
|
-
/**
|
|
814
|
-
* The same as @see useAndHandleMutation, but does not display any toasts by default.
|
|
815
|
-
* Messages for success, error and defect toasts can be provided in the Options.
|
|
816
|
-
* @deprecated use `Command.fn` and friends instead
|
|
817
|
-
*/
|
|
818
|
-
<
|
|
819
|
-
I,
|
|
820
|
-
E extends ResponseErrors,
|
|
821
|
-
A,
|
|
822
|
-
R,
|
|
823
|
-
Request extends Req,
|
|
824
|
-
Name extends string,
|
|
825
|
-
A2 = A,
|
|
826
|
-
E2 extends ResponseErrors = E,
|
|
827
|
-
R2 = R,
|
|
828
|
-
ESuccess = never,
|
|
829
|
-
RSuccess = never,
|
|
830
|
-
EError = never,
|
|
831
|
-
RError = never,
|
|
832
|
-
EDefect = never,
|
|
833
|
-
RDefect = never
|
|
834
|
-
>(
|
|
835
|
-
self: RequestHandlerWithInput<I, A, E, R, Request, Name>,
|
|
836
|
-
action: string,
|
|
837
|
-
options?: Opts<A, E, R, I, A2, E2, R2, ESuccess, RSuccess, EError, RError, EDefect, RDefect>
|
|
838
|
-
): Resp<I, A2, E2, R>
|
|
839
|
-
/**
|
|
840
|
-
* The same as @see useAndHandleMutation, but does not display any toasts by default.
|
|
841
|
-
* Messages for success, error and defect toasts can be provided in the Options.
|
|
842
|
-
* @deprecated use `Command.fn` and friends instead
|
|
843
|
-
*/
|
|
844
|
-
<
|
|
845
|
-
E extends ResponseErrors,
|
|
846
|
-
A,
|
|
847
|
-
R,
|
|
848
|
-
Request extends Req,
|
|
849
|
-
Name extends string,
|
|
850
|
-
A2 = A,
|
|
851
|
-
E2 extends ResponseErrors = E,
|
|
852
|
-
R2 = R,
|
|
853
|
-
ESuccess = never,
|
|
854
|
-
RSuccess = never,
|
|
855
|
-
EError = never,
|
|
856
|
-
RError = never,
|
|
857
|
-
EDefect = never,
|
|
858
|
-
RDefect = never
|
|
859
|
-
>(
|
|
860
|
-
self: RequestHandler<A, E, R, Request, Name>,
|
|
861
|
-
action: string,
|
|
862
|
-
options?: Opts<A, E, R, void, A2, E2, R2, ESuccess, RSuccess, EError, RError, EDefect, RDefect>
|
|
863
|
-
): ActResp<void, never, R>
|
|
864
|
-
} = this.makeUseAndHandleMutation({
|
|
865
|
-
successMessage: suppressToast,
|
|
866
|
-
failMessage: suppressToast,
|
|
867
|
-
defectMessage: suppressToast
|
|
868
|
-
}) as any
|
|
869
|
-
|
|
870
476
|
/**
|
|
871
|
-
*
|
|
872
|
-
*
|
|
873
|
-
* @deprecated use `Command.fn` and friends instead
|
|
477
|
+
* Effect results are passed to the caller, including errors.
|
|
478
|
+
* @deprecated use client helpers instead (.query())
|
|
874
479
|
*/
|
|
875
|
-
readonly
|
|
876
|
-
/**
|
|
877
|
-
* The same as @see useAndHandleMutation, but does not act on success, error or defect by default.
|
|
878
|
-
* Actions for success, error and defect can be provided in the Options.
|
|
879
|
-
* @deprecated use `Command.fn` and friends instead
|
|
880
|
-
*/
|
|
881
|
-
<
|
|
882
|
-
I,
|
|
883
|
-
E extends ResponseErrors,
|
|
884
|
-
A,
|
|
885
|
-
R,
|
|
886
|
-
Request extends Req,
|
|
887
|
-
Name extends string,
|
|
888
|
-
A2 = A,
|
|
889
|
-
E2 extends ResponseErrors = E,
|
|
890
|
-
R2 = R,
|
|
891
|
-
ESuccess = never,
|
|
892
|
-
RSuccess = never,
|
|
893
|
-
EError = never,
|
|
894
|
-
RError = never,
|
|
895
|
-
EDefect = never,
|
|
896
|
-
RDefect = never
|
|
897
|
-
>(
|
|
898
|
-
self: RequestHandlerWithInput<I, A, E, R, Request, Name>,
|
|
899
|
-
action: string,
|
|
900
|
-
options?: LowOptsOptional<A, E, R, I, A2, E2, R2, ESuccess, RSuccess, EError, RError, EDefect, RDefect>
|
|
901
|
-
): Resp<I, A2, E2, R2>
|
|
902
|
-
/**
|
|
903
|
-
* The same as @see useAndHandleMutation, but does not act on success, error or defect by default.
|
|
904
|
-
* Actions for success, error and defect can be provided in the Options.
|
|
905
|
-
* @deprecated use `Command.fn` and friends instead
|
|
906
|
-
*/
|
|
907
|
-
<
|
|
908
|
-
E extends ResponseErrors,
|
|
909
|
-
A,
|
|
910
|
-
R,
|
|
911
|
-
Request extends Req,
|
|
912
|
-
Name extends string,
|
|
913
|
-
A2 = A,
|
|
914
|
-
E2 extends ResponseErrors = E,
|
|
915
|
-
R2 = R,
|
|
916
|
-
ESuccess = never,
|
|
917
|
-
RSuccess = never,
|
|
918
|
-
EError = never,
|
|
919
|
-
RError = never,
|
|
920
|
-
EDefect = never,
|
|
921
|
-
RDefect = never
|
|
922
|
-
>(
|
|
923
|
-
self: RequestHandler<A, E, R, Request, Name>,
|
|
924
|
-
action: string,
|
|
925
|
-
options?: LowOptsOptional<A, E, R, void, A2, E2, R2, ESuccess, RSuccess, EError, RError, EDefect, RDefect>
|
|
926
|
-
): ActResp<A2, E2, R2>
|
|
927
|
-
} = (self: any, action: string, options: any) => {
|
|
928
|
-
const unsafe = _useMutation({
|
|
929
|
-
...self,
|
|
930
|
-
handler: Effect.isEffect(self.handler)
|
|
931
|
-
? (pipe(
|
|
932
|
-
Effect.annotateCurrentSpan({ action }),
|
|
933
|
-
Effect.andThen(self.handler)
|
|
934
|
-
) as any)
|
|
935
|
-
: (...args: any[]) =>
|
|
936
|
-
pipe(
|
|
937
|
-
Effect.annotateCurrentSpan({ action }),
|
|
938
|
-
Effect.andThen(self.handler(...args))
|
|
939
|
-
)
|
|
940
|
-
}, options ? dropUndefinedT(options) : undefined)
|
|
480
|
+
readonly useQuery: ReturnType<typeof makeQuery<R>>
|
|
941
481
|
|
|
942
|
-
|
|
943
|
-
const mh = options?.mapHandler ?? identity as MH
|
|
482
|
+
readonly useQueryNew: ReturnType<typeof makeQueryNew<R>>
|
|
944
483
|
|
|
945
|
-
|
|
946
|
-
mapHandler(
|
|
947
|
-
mapHandler(unsafe as any, mh),
|
|
948
|
-
Effect.tapCauseIf(Cause.hasDies, (cause) => reportRuntimeError(cause))
|
|
949
|
-
) as any
|
|
950
|
-
)
|
|
484
|
+
readonly useQueryAtom: ReturnType<typeof makeQueryAtom<R>>
|
|
951
485
|
|
|
952
|
-
|
|
953
|
-
computed(() => mutationResultToVue(a.value)),
|
|
954
|
-
handleRequest(b as any, self.id, action, {
|
|
955
|
-
onSuccess: suppressToast,
|
|
956
|
-
onDefect: suppressToast,
|
|
957
|
-
onFail: suppressToast,
|
|
958
|
-
...options
|
|
959
|
-
})
|
|
960
|
-
) as any
|
|
961
|
-
}
|
|
486
|
+
readonly useQueryFamily: ReturnType<typeof makeQueryFamily<R>>
|
|
962
487
|
|
|
963
488
|
/**
|
|
964
|
-
*
|
|
965
|
-
*
|
|
966
|
-
* @deprecated use `Command.fn` and friends instead
|
|
489
|
+
* Stream results are accumulated as an array of chunks and returned as reactive state.
|
|
490
|
+
* @deprecated use client helpers instead (.query())
|
|
967
491
|
*/
|
|
968
|
-
readonly
|
|
969
|
-
/**
|
|
970
|
-
* Effect results are converted to Exit, so errors are ignored by default.
|
|
971
|
-
* you should use the result ref to render errors!
|
|
972
|
-
* @deprecated use `Command.fn` and friends instead
|
|
973
|
-
*/
|
|
974
|
-
<I, E, A, R, Request extends Req, Name extends string, A2 = A, E2 = E, R2 = R>(
|
|
975
|
-
self: RequestHandlerWithInput<I, A, E, R, Request, Name>,
|
|
976
|
-
options?: MutationOptions<A, E, R, A2, E2, R2, I>
|
|
977
|
-
): readonly [
|
|
978
|
-
ComputedRef<Res<A, E>>,
|
|
979
|
-
(i: I) => Effect.Effect<Exit.Exit<A2, E2>, never, R2>
|
|
980
|
-
]
|
|
981
|
-
/**
|
|
982
|
-
* Effect results are converted to Exit, so errors are ignored by default.
|
|
983
|
-
* you should use the result ref to render errors!
|
|
984
|
-
* @deprecated use `Command.fn` and friends instead
|
|
985
|
-
*/
|
|
986
|
-
<E, A, R, Request extends Req, Name extends string, A2 = A, E2 = E, R2 = R>(
|
|
987
|
-
self: RequestHandler<A, E, R, Request, Name>,
|
|
988
|
-
options?: MutationOptions<A, E, R, A2, E2, R2>
|
|
989
|
-
): readonly [
|
|
990
|
-
ComputedRef<Res<A, E>>,
|
|
991
|
-
Effect.Effect<Exit.Exit<A2, E2>, never, R2>
|
|
992
|
-
]
|
|
993
|
-
} = <I, E, A, R, Request extends Req, Name extends string, A2 = A, E2 = E, R2 = R>(
|
|
994
|
-
self: RequestHandlerWithInput<I, A, E, R, Request, Name> | RequestHandler<A, E, R, Request, Name>,
|
|
995
|
-
options?: MutationOptions<A, E, R, A2, E2, R2, I>
|
|
996
|
-
) => {
|
|
997
|
-
const [a, b] = this.useSafeMutation(self as any, options)
|
|
492
|
+
readonly useStreamQuery: ReturnType<typeof makeStreamQuery<R>>
|
|
998
493
|
|
|
999
|
-
|
|
1000
|
-
computed(() => mutationResultToVue(a.value)),
|
|
1001
|
-
b
|
|
1002
|
-
) as any
|
|
1003
|
-
}
|
|
494
|
+
readonly useStreamQueryFamily: ReturnType<typeof makeStreamQueryFamily<R>>
|
|
1004
495
|
|
|
1005
|
-
|
|
1006
|
-
readonly buildFormFromSchema = <
|
|
1007
|
-
From extends Record<PropertyKey, any>,
|
|
1008
|
-
To extends Record<PropertyKey, any>,
|
|
1009
|
-
C extends Record<PropertyKey, any>,
|
|
1010
|
-
OnSubmitA
|
|
1011
|
-
>(
|
|
1012
|
-
s:
|
|
1013
|
-
& S.Codec<To>
|
|
1014
|
-
& { new(c: C): any; extend: any; fields: S.Struct.Fields },
|
|
1015
|
-
state: Ref<Omit<From, "_tag">>,
|
|
1016
|
-
onSubmit: (a: To) => Effect.Effect<OnSubmitA, never, RT>
|
|
1017
|
-
) => {
|
|
1018
|
-
const fields = buildFieldInfoFromFieldsRoot(s).fields
|
|
1019
|
-
const schema = S.Struct(Struct.omit(s.fields, ["_tag"])) as unknown as S.Codec<any> & {
|
|
1020
|
-
readonly DecodingServices: never
|
|
1021
|
-
}
|
|
1022
|
-
const parse = S.decodeUnknownSync(schema)
|
|
1023
|
-
const isDirty = ref(false)
|
|
1024
|
-
const isValid = ref(true)
|
|
1025
|
-
const isLoading = ref(false)
|
|
1026
|
-
const runPromise = Effect.runPromiseWith(this.getRuntime())
|
|
1027
|
-
|
|
1028
|
-
const submit1 =
|
|
1029
|
-
(onSubmit: (a: To) => Effect.Effect<OnSubmitA, never, never>) =>
|
|
1030
|
-
async <T extends Promise<{ valid: boolean }>>(e: T) => {
|
|
1031
|
-
isLoading.value = true
|
|
1032
|
-
try {
|
|
1033
|
-
const r = await e
|
|
1034
|
-
if (!r.valid) return
|
|
1035
|
-
return await runPromise(onSubmit(new (s as any)(await runPromise(parse(state.value)))) as any)
|
|
1036
|
-
} finally {
|
|
1037
|
-
isLoading.value = false
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
const submit = submit1(onSubmit as any)
|
|
1041
|
-
|
|
1042
|
-
watch(
|
|
1043
|
-
state,
|
|
1044
|
-
(v) => {
|
|
1045
|
-
// TODO: do better
|
|
1046
|
-
isDirty.value = JSON.stringify(v) !== JSON.stringify(state.value)
|
|
1047
|
-
},
|
|
1048
|
-
{ deep: true }
|
|
1049
|
-
)
|
|
496
|
+
readonly useStreamQueryAtom: ReturnType<typeof makeStreamQueryAtom<R>>
|
|
1050
497
|
|
|
1051
|
-
|
|
1052
|
-
return yield* (onSubmit(yield* parse(state.value)) as any)
|
|
1053
|
-
})
|
|
1054
|
-
|
|
1055
|
-
const submitFromStatePromise = () => runPromise(submitFromState as any)
|
|
1056
|
-
|
|
1057
|
-
return {
|
|
1058
|
-
fields,
|
|
1059
|
-
/** optimized for Vuetify v-form submit callback */
|
|
1060
|
-
submit,
|
|
1061
|
-
/** optimized for Native form submit callback or general use */
|
|
1062
|
-
submitFromState,
|
|
1063
|
-
submitFromStatePromise,
|
|
1064
|
-
isDirty,
|
|
1065
|
-
isValid,
|
|
1066
|
-
isLoading
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
// @effect-diagnostics-next-line missingEffectServiceDependency:off
|
|
1072
|
-
export class LegacyMutation extends ServiceMap.Service<LegacyMutation>()("LegacyMutation", {
|
|
1073
|
-
make: Effect.gen(function*() {
|
|
1074
|
-
const intl = yield* I18n
|
|
1075
|
-
const toast = yield* Toast
|
|
1076
|
-
|
|
1077
|
-
return <R>(getRuntime: () => ServiceMap.ServiceMap<R>) => new LegacyMutationImpl(getRuntime, toast, intl)
|
|
1078
|
-
})
|
|
1079
|
-
}) {
|
|
1080
|
-
static readonly DefaultWithoutDependencies = Layer.effect(this, this.make)
|
|
1081
|
-
static readonly Default = this.DefaultWithoutDependencies
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
|
-
export type ClientFrom<M extends Requests> = RequestHandlers<never, never, M, M["meta"]["moduleName"]>
|
|
1085
|
-
|
|
1086
|
-
export class QueryImpl<R> {
|
|
1087
|
-
constructor(readonly getRuntime: () => ServiceMap.ServiceMap<R>) {
|
|
1088
|
-
this.useQuery = makeQuery(this.getRuntime)
|
|
1089
|
-
}
|
|
1090
|
-
/**
|
|
1091
|
-
* Effect results are passed to the caller, including errors.
|
|
1092
|
-
* @deprecated use client helpers instead (.query())
|
|
1093
|
-
*/
|
|
1094
|
-
readonly useQuery: ReturnType<typeof makeQuery<R>>
|
|
498
|
+
readonly useStreamQueryNew: ReturnType<typeof makeStreamQueryNew<R>>
|
|
1095
499
|
|
|
1096
500
|
/**
|
|
1097
501
|
* The difference with useQuery is that this function will return a Promise you can await in the Setup,
|
|
@@ -1104,22 +508,21 @@ export class QueryImpl<R> {
|
|
|
1104
508
|
* The difference with useQuery is that this function will return a Promise you can await in the Setup,
|
|
1105
509
|
* which ensures that either there always is a latest value, or an error occurs on load.
|
|
1106
510
|
* So that Suspense and error boundaries can be used.
|
|
1107
|
-
*
|
|
511
|
+
* When `I = void` the input argument may be omitted.
|
|
1108
512
|
*/
|
|
1109
513
|
<
|
|
514
|
+
I,
|
|
1110
515
|
E,
|
|
1111
516
|
A,
|
|
1112
517
|
Request extends Req,
|
|
1113
518
|
Name extends string
|
|
1114
519
|
>(
|
|
1115
|
-
self:
|
|
520
|
+
self: RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
1116
521
|
): {
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
*/
|
|
1122
|
-
<TData = A>(options?: CustomUndefinedInitialQueryOptions<A, E, TData>): Promise<
|
|
522
|
+
<TData = A>(
|
|
523
|
+
arg: I | WatchSource<I>,
|
|
524
|
+
options?: CustomUndefinedInitialQueryOptions<A, CauseException<E>, TData>
|
|
525
|
+
): Promise<
|
|
1123
526
|
readonly [
|
|
1124
527
|
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
1125
528
|
ComputedRef<TData>,
|
|
@@ -1130,221 +533,537 @@ export class QueryImpl<R> {
|
|
|
1130
533
|
]
|
|
1131
534
|
>
|
|
1132
535
|
}
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
536
|
+
} = <I, E, A, Request extends Req, Name extends string>(
|
|
537
|
+
self: RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
538
|
+
) => {
|
|
539
|
+
const runPromise = makeRunPromise(this.getRuntime())
|
|
540
|
+
const q = this.useQuery(self)
|
|
541
|
+
return <TData = A>(
|
|
542
|
+
argOrOptions: I | WatchSource<I>,
|
|
543
|
+
options?: CustomUndefinedInitialQueryOptions<A, CauseException<E>, TData>
|
|
544
|
+
) => {
|
|
545
|
+
const [
|
|
546
|
+
[resultRef, latestDefinedRef, fetch, uqrt],
|
|
547
|
+
isMounted,
|
|
548
|
+
signal
|
|
549
|
+
] = useScopedSuspenseSetup(() => {
|
|
550
|
+
const [resultRef, latestRef, fetch, uqrt] = q<TData>(argOrOptions, options)
|
|
551
|
+
const latestDefinedRef = latestDefined(() => latestRef.value, "suspense")
|
|
552
|
+
return [resultRef, latestDefinedRef, fetch, uqrt] as const
|
|
553
|
+
})
|
|
554
|
+
|
|
555
|
+
// @effect-diagnostics effect/missingEffectError:off
|
|
556
|
+
const eff = Effect.gen(function*() {
|
|
557
|
+
const exit = yield* uqrt.awaitResult().pipe(Effect.exit)
|
|
558
|
+
if (!isMounted.value) {
|
|
559
|
+
return yield* Effect.interrupt
|
|
560
|
+
}
|
|
561
|
+
if (Exit.isFailure(exit)) {
|
|
562
|
+
// Still mounted, so this interrupt came from the query side (e.g. a server RPC interrupt
|
|
563
|
+
// Exit), not from navigation/unmount — surface it as a renderable typed error instead of a
|
|
564
|
+
// raw interrupt the error boundary would silence into a blank page.
|
|
565
|
+
if (Cause.hasInterruptsOnly(exit.cause)) {
|
|
566
|
+
return yield* new SuspenseInterruptedError({ originalCause: exit.cause, source: "suspense" })
|
|
567
|
+
}
|
|
568
|
+
return yield* Exit.failCause(exit.cause)
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
return [resultRef, latestDefinedRef, fetch, uqrt] as const
|
|
572
|
+
})
|
|
573
|
+
|
|
574
|
+
return runPromise(eff, { signal })
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
readonly useSuspenseQueryNew: {
|
|
1138
579
|
<
|
|
1139
|
-
|
|
580
|
+
I,
|
|
1140
581
|
E,
|
|
1141
582
|
A,
|
|
1142
583
|
Request extends Req,
|
|
1143
584
|
Name extends string
|
|
1144
585
|
>(
|
|
1145
|
-
self: RequestHandlerWithInput<
|
|
586
|
+
self: RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
1146
587
|
): {
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
*/
|
|
1152
|
-
<TData = A>(arg: Arg | WatchSource<Arg>, options?: CustomUndefinedInitialQueryOptions<A, E, TData>): Promise<
|
|
1153
|
-
readonly [
|
|
1154
|
-
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
1155
|
-
ComputedRef<TData>,
|
|
1156
|
-
(
|
|
1157
|
-
options?: RefetchOptions
|
|
1158
|
-
) => Effect.Effect<QueryObserverResult<TData, E>>,
|
|
1159
|
-
UseQueryReturnType<any, any>
|
|
1160
|
-
]
|
|
1161
|
-
>
|
|
588
|
+
<TData = A>(
|
|
589
|
+
arg: I | WatchSource<I>,
|
|
590
|
+
options?: AtomQueryNewOptions<A, TData>
|
|
591
|
+
): Promise<SuspenseQueryView<TData, E>>
|
|
1162
592
|
}
|
|
1163
|
-
} = <
|
|
1164
|
-
self: RequestHandlerWithInput<
|
|
593
|
+
} = <I, E, A, Request extends Req, Name extends string>(
|
|
594
|
+
self: RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
1165
595
|
) => {
|
|
1166
|
-
const runPromise =
|
|
1167
|
-
const q = this.
|
|
1168
|
-
return
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
const isMounted =
|
|
1173
|
-
|
|
1174
|
-
|
|
596
|
+
const runPromise = makeRunPromise(this.getRuntime())
|
|
597
|
+
const q = this.useQueryNew(self)
|
|
598
|
+
return <TData = A>(
|
|
599
|
+
argOrOptions: I | WatchSource<I>,
|
|
600
|
+
options?: AtomQueryNewOptions<A, TData>
|
|
601
|
+
) => {
|
|
602
|
+
const [{ view, data }, isMounted, signal] = useScopedSuspenseSetup(() => {
|
|
603
|
+
const view = q<TData>(argOrOptions, options)
|
|
604
|
+
const data = latestDefined(() => view.data.value, "suspenseNew")
|
|
605
|
+
return { view, data }
|
|
1175
606
|
})
|
|
1176
607
|
|
|
1177
608
|
// @effect-diagnostics effect/missingEffectError:off
|
|
1178
609
|
const eff = Effect.gen(function*() {
|
|
1179
|
-
|
|
1180
|
-
// what's the difference with just calling `fetch` ?
|
|
1181
|
-
// we will receive a CancelledError which we will have to ignore in our ErrorBoundary, otherwise the user ends up on an error page even if the user e.g cancelled a navigation
|
|
1182
|
-
const r = yield* Effect.tryPromise(() => uqrt.suspense()).pipe(
|
|
1183
|
-
Effect.catchTag("UnknownError", (err) =>
|
|
1184
|
-
isCancelledError(err.cause)
|
|
1185
|
-
? Effect.interrupt
|
|
1186
|
-
: Effect.die(err.cause))
|
|
1187
|
-
)
|
|
610
|
+
const exit = yield* view.awaitResult().pipe(Effect.exit)
|
|
1188
611
|
if (!isMounted.value) {
|
|
1189
612
|
return yield* Effect.interrupt
|
|
1190
613
|
}
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
r,
|
|
1198
|
-
resultRef
|
|
1199
|
-
})
|
|
1200
|
-
return yield* Effect.die(
|
|
1201
|
-
"Internal Error: Promise should be resolved already"
|
|
1202
|
-
)
|
|
1203
|
-
}
|
|
1204
|
-
if (AsyncResult.isFailure(result)) {
|
|
1205
|
-
return yield* Exit.failCause(result.cause)
|
|
614
|
+
if (Exit.isFailure(exit)) {
|
|
615
|
+
// Still mounted → query-side interrupt (see SuspenseInterruptedError) — render, don't silence.
|
|
616
|
+
if (Cause.hasInterruptsOnly(exit.cause)) {
|
|
617
|
+
return yield* new SuspenseInterruptedError({ originalCause: exit.cause, source: "suspenseNew" })
|
|
618
|
+
}
|
|
619
|
+
return yield* Exit.failCause(exit.cause)
|
|
1206
620
|
}
|
|
1207
621
|
|
|
1208
|
-
|
|
622
|
+
const fetch = (_options?: RefetchOptions) => view.refetch()
|
|
623
|
+
const handle = {
|
|
624
|
+
awaitResult: view.awaitResult,
|
|
625
|
+
refetch: view.refetch,
|
|
626
|
+
refresh: view.refresh,
|
|
627
|
+
registry: view.registry,
|
|
628
|
+
atom: view.atom
|
|
629
|
+
}
|
|
630
|
+
return Object.assign(
|
|
631
|
+
[
|
|
632
|
+
view.result,
|
|
633
|
+
data,
|
|
634
|
+
fetch,
|
|
635
|
+
handle
|
|
636
|
+
] as const,
|
|
637
|
+
{
|
|
638
|
+
...view,
|
|
639
|
+
data
|
|
640
|
+
}
|
|
641
|
+
)
|
|
1209
642
|
})
|
|
1210
643
|
|
|
1211
|
-
return runPromise(eff)
|
|
644
|
+
return runPromise(eff, { signal })
|
|
1212
645
|
}
|
|
1213
646
|
}
|
|
1214
647
|
}
|
|
1215
648
|
|
|
1216
649
|
// somehow mrt.runtimeEffect doesnt work sync, but this workaround works fine? not sure why though as the layers are generally only sync
|
|
1217
|
-
const managedRuntimeRt = <A, E>(mrt: ManagedRuntime.ManagedRuntime<A, E>) => mrt.runSync(Effect.
|
|
650
|
+
const managedRuntimeRt = <A, E>(mrt: ManagedRuntime.ManagedRuntime<A, E>) => mrt.runSync(Effect.context<A>())
|
|
1218
651
|
|
|
1219
652
|
type Base = I18n | Toast
|
|
1220
|
-
type Mix = ApiClientFactory | Commander |
|
|
653
|
+
type Mix = ApiClientFactory | Commander | Base
|
|
654
|
+
|
|
655
|
+
type InvalidationResources = Record<string, Record<string, unknown>>
|
|
656
|
+
type UnionToIntersection<U> = (U extends unknown ? (arg: U) => void : never) extends ((arg: infer I) => void) ? I
|
|
657
|
+
: never
|
|
658
|
+
|
|
659
|
+
type CommandInvalidationResources<Req> = Req extends {
|
|
660
|
+
readonly type: "command"
|
|
661
|
+
readonly "~invalidationResources"?: infer Resources
|
|
662
|
+
} ? NonNullable<Resources> extends InvalidationResources ? NonNullable<Resources> : never
|
|
663
|
+
: Req extends {
|
|
664
|
+
readonly type: "command"
|
|
665
|
+
readonly config?: infer Config
|
|
666
|
+
} ? Config extends {
|
|
667
|
+
readonly invalidationResources?: infer LegacyResources
|
|
668
|
+
} ? NonNullable<LegacyResources> extends InvalidationResources ? NonNullable<LegacyResources> : never
|
|
669
|
+
: Config extends {
|
|
670
|
+
readonly invalidatesQueries?: InvalidationCallback<infer LegacyResources, any, any, any>
|
|
671
|
+
} ? NonNullable<LegacyResources> extends InvalidationResources ? NonNullable<LegacyResources> : never
|
|
672
|
+
: never
|
|
673
|
+
: never
|
|
674
|
+
|
|
675
|
+
type InvalidationResourcesForUnion<M extends RequestsAny> = {
|
|
676
|
+
[K in keyof M]: CommandInvalidationResources<M[K]>
|
|
677
|
+
}[keyof M]
|
|
678
|
+
|
|
679
|
+
type InvalidationResourcesFor<M extends RequestsAny> = [InvalidationResourcesForUnion<M>] extends [never] ? never
|
|
680
|
+
: UnionToIntersection<InvalidationResourcesForUnion<M>> extends infer R ? R extends InvalidationResources ? R
|
|
681
|
+
: never
|
|
682
|
+
: never
|
|
683
|
+
|
|
684
|
+
type QueryInvalidationFactory<M extends RequestsAny> = (client: ClientFrom<M>) => QueryInvalidation<M>
|
|
685
|
+
|
|
686
|
+
type StrictResourcesArg<Shape, Actual extends Shape = Shape> =
|
|
687
|
+
& Actual
|
|
688
|
+
& Record<Exclude<keyof Actual, keyof Shape>, never>
|
|
689
|
+
|
|
690
|
+
type ClientForArgs<
|
|
691
|
+
M extends RequestsAny,
|
|
692
|
+
Resources extends InvalidationResourcesFor<M> = InvalidationResourcesFor<M>
|
|
693
|
+
> = [InvalidationResourcesFor<M>] extends [never] ? [
|
|
694
|
+
queryInvalidation?: QueryInvalidationFactory<M>,
|
|
695
|
+
invalidationResources?: StrictResourcesArg<
|
|
696
|
+
InvalidationResourcesFor<M>,
|
|
697
|
+
Resources
|
|
698
|
+
>
|
|
699
|
+
]
|
|
700
|
+
: [
|
|
701
|
+
queryInvalidation: QueryInvalidationFactory<M> | undefined,
|
|
702
|
+
invalidationResources: StrictResourcesArg<
|
|
703
|
+
InvalidationResourcesFor<M>,
|
|
704
|
+
Resources
|
|
705
|
+
>
|
|
706
|
+
]
|
|
707
|
+
|
|
708
|
+
const makeResolvedAtomQueryInvalidator = <R>(getContext: () => Context.Context<R>): QueryInvalidator => {
|
|
709
|
+
let reactivity: Context.Service.Shape<typeof Reactivity.Reactivity> | undefined
|
|
710
|
+
const getReactivity = () => {
|
|
711
|
+
if (reactivity !== undefined) return reactivity
|
|
712
|
+
const service = Context.getOrUndefined(getContext(), Reactivity.Reactivity)
|
|
713
|
+
if (service === undefined) {
|
|
714
|
+
throw new Error("Reactivity service is missing from the client runtime")
|
|
715
|
+
}
|
|
716
|
+
return reactivity = service
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
return {
|
|
720
|
+
invalidateAndAwait: (keys) =>
|
|
721
|
+
invalidateAndAwait(keys).pipe(
|
|
722
|
+
Effect.provideService(Reactivity.Reactivity, getReactivity())
|
|
723
|
+
),
|
|
724
|
+
invalidateSoft: (keys) =>
|
|
725
|
+
invalidateSoft(keys).pipe(
|
|
726
|
+
Effect.provideService(Reactivity.Reactivity, getReactivity())
|
|
727
|
+
)
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
1221
731
|
export const makeClient = <RT_, RTHooks>(
|
|
1222
732
|
// global, but only accessible after startup has completed
|
|
1223
733
|
getBaseMrt: () => ManagedRuntime.ManagedRuntime<RT_ | Mix, never>,
|
|
1224
734
|
clientFor_: ReturnType<typeof ApiClientFactory["makeFor"]>,
|
|
1225
|
-
rtHooks: Layer.Layer<RTHooks, never, Mix
|
|
735
|
+
rtHooks: Layer.Layer<RTHooks, never, Mix>,
|
|
736
|
+
options?: MakeClientOptions
|
|
1226
737
|
) => {
|
|
1227
738
|
type RT = RT_ | Mix
|
|
1228
|
-
const getRt = Effect.services<RT>()
|
|
1229
739
|
const getBaseRt = () => managedRuntimeRt(getBaseMrt())
|
|
1230
740
|
const makeCommand = makeUseCommand<RT, RTHooks>(rtHooks)
|
|
1231
|
-
const makeMutation = Effect.gen(function*() {
|
|
1232
|
-
const mut = yield* LegacyMutation
|
|
1233
|
-
|
|
1234
|
-
return mut(() => getBaseMrt().runSync(getRt))
|
|
1235
|
-
})
|
|
1236
741
|
let cmd: Effect.Success<typeof makeCommand>
|
|
1237
742
|
const useCommand = () => cmd ??= getBaseMrt().runSync(makeCommand)
|
|
1238
|
-
let mut: Effect.Success<typeof makeMutation>
|
|
1239
|
-
const getMutation = () => mut ??= getBaseMrt().runSync(makeMutation)
|
|
1240
743
|
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
const
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
}) as any
|
|
1262
|
-
return prev
|
|
1263
|
-
},
|
|
1264
|
-
{} as Pick<LegacyMutationImpl<RT>, typeof keys[number]>
|
|
744
|
+
// one AtomRuntime for the query engine, built lazily from the live app context;
|
|
745
|
+
// shares the ManagedRuntime memoMap so layers + Reactivity are the same instances.
|
|
746
|
+
let atomRt: AtomClientRuntime | undefined
|
|
747
|
+
const getAtomRt =
|
|
748
|
+
() => (atomRt ??= makeAtomClientRuntime(() => Layer.succeedContext(getBaseRt()), getBaseMrt().memoMap))
|
|
749
|
+
|
|
750
|
+
const legacyQueryEngine = options?.legacyQueryEngine ?? "tanstack"
|
|
751
|
+
let tanstackQueryClient: ReturnType<typeof makeTanstackQueryClient> | undefined
|
|
752
|
+
const getTanstackQueryClient = () => tanstackQueryClient ??= makeTanstackQueryClient()
|
|
753
|
+
const atomInvalidator = makeResolvedAtomQueryInvalidator(getBaseRt)
|
|
754
|
+
const queryInvalidator = legacyQueryEngine === "tanstack"
|
|
755
|
+
? combineQueryInvalidators(atomInvalidator, makeTanstackQueryInvalidator(getTanstackQueryClient()))
|
|
756
|
+
: atomInvalidator
|
|
757
|
+
setQueryCacheUpdater(
|
|
758
|
+
legacyQueryEngine === "tanstack"
|
|
759
|
+
? combineQueryCacheUpdaters(
|
|
760
|
+
makeTanstackQueryCacheUpdater(getTanstackQueryClient()),
|
|
761
|
+
optionalAtomQueryCacheUpdater
|
|
762
|
+
)
|
|
763
|
+
: atomQueryCacheUpdater
|
|
1265
764
|
)
|
|
1266
765
|
|
|
1267
|
-
|
|
766
|
+
let m: ReturnType<typeof useMutationInt>
|
|
767
|
+
const useMutation = () => m ??= useMutationInt(queryInvalidator)
|
|
768
|
+
|
|
769
|
+
let sm2: ReturnType<typeof makeStreamMutation2>
|
|
770
|
+
const useStreamMutation2 = () => sm2 ??= makeStreamMutation2(queryInvalidator)
|
|
771
|
+
|
|
772
|
+
const legacyUseQuery = legacyQueryEngine === "tanstack"
|
|
773
|
+
? makeTanstackQuery(getBaseRt, getTanstackQueryClient())
|
|
774
|
+
: undefined
|
|
775
|
+
const query = new QueryImpl(getBaseRt, getAtomRt, legacyUseQuery)
|
|
1268
776
|
const useQuery = query.useQuery
|
|
777
|
+
const useQueryNew = query.useQueryNew
|
|
778
|
+
const useQueryAtom = query.useQueryAtom
|
|
779
|
+
const useQueryFamily = query.useQueryFamily
|
|
1269
780
|
const useSuspenseQuery = query.useSuspenseQuery
|
|
781
|
+
const useSuspenseQueryNew = query.useSuspenseQueryNew
|
|
782
|
+
const useStreamQuery = query.useStreamQuery
|
|
783
|
+
const useStreamQueryFamily = query.useStreamQueryFamily
|
|
784
|
+
const useStreamQueryAtom = query.useStreamQueryAtom
|
|
785
|
+
const useStreamQueryNew = query.useStreamQueryNew
|
|
786
|
+
|
|
787
|
+
const isQueryHandler = <H extends { readonly Request: Req }>(handler: H): handler is QueryHandler<H> =>
|
|
788
|
+
handler.Request.type === "query" && !handler.Request.stream
|
|
789
|
+
|
|
790
|
+
const isStreamQueryHandler = <H extends { readonly Request: Req }>(handler: H): handler is QueryStreamHandler<H> =>
|
|
791
|
+
handler.Request.type === "query" && handler.Request.stream
|
|
792
|
+
|
|
793
|
+
const queryHelpersFor = <I, A, E, Request extends Req, Name extends string>(
|
|
794
|
+
handler: RequestHandlerWithInput<I, A, E, RT, Request, Name>
|
|
795
|
+
) => ({
|
|
796
|
+
family: useQueryFamily(handler),
|
|
797
|
+
atom: useQueryAtom(handler),
|
|
798
|
+
query: useQuery(handler),
|
|
799
|
+
queryNew: useQueryNew(handler),
|
|
800
|
+
suspense: useSuspenseQuery(handler),
|
|
801
|
+
suspenseNew: useSuspenseQueryNew(handler)
|
|
802
|
+
})
|
|
803
|
+
|
|
804
|
+
const streamQueryHelpersFor = <I, A, E, Request extends Req, Name extends string>(
|
|
805
|
+
handler: RequestStreamHandlerWithInput<I, A, E, RT, Request, Name>
|
|
806
|
+
) => ({
|
|
807
|
+
family: useStreamQueryFamily(handler),
|
|
808
|
+
atom: useStreamQueryAtom(handler),
|
|
809
|
+
query: useStreamQuery(handler),
|
|
810
|
+
queryNew: useStreamQueryNew(handler)
|
|
811
|
+
})
|
|
812
|
+
|
|
813
|
+
const projectQueryFor = <
|
|
814
|
+
I,
|
|
815
|
+
A,
|
|
816
|
+
E,
|
|
817
|
+
Request extends Req & { readonly success: S.Top & { readonly "EncodingServices": RT } },
|
|
818
|
+
Name extends string
|
|
819
|
+
>(
|
|
820
|
+
handler: RequestHandlerWithInput<I, A, E, RT, Request, Name>
|
|
821
|
+
) =>
|
|
822
|
+
<ProjSchema extends S.Top & { readonly "DecodingServices": RT }>(projectionSchema: ProjSchema) => {
|
|
823
|
+
const successSchema = handler.Request.success
|
|
824
|
+
const projectionHash = projectionSchemaHash(projectionSchema)
|
|
825
|
+
const projected = projectHandler(handler.handler, successSchema, projectionSchema)
|
|
826
|
+
const projectedHandler = {
|
|
827
|
+
handler: projected,
|
|
828
|
+
id: handler.id,
|
|
829
|
+
Request: handler.Request,
|
|
830
|
+
queryKeyProjectionHash: projectionHash
|
|
831
|
+
}
|
|
832
|
+
if (handler.options) {
|
|
833
|
+
return {
|
|
834
|
+
request: projected,
|
|
835
|
+
...queryHelpersFor({ ...projectedHandler, options: handler.options })
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
return {
|
|
839
|
+
request: projected,
|
|
840
|
+
...queryHelpersFor(projectedHandler)
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
const mergeInvalidation = (
|
|
845
|
+
a?: MutationOptionsBase["queryInvalidation"],
|
|
846
|
+
b?: MutationOptionsBase["queryInvalidation"]
|
|
847
|
+
): MutationOptionsBase["queryInvalidation"] | undefined => {
|
|
848
|
+
if (!a && !b) {
|
|
849
|
+
return undefined
|
|
850
|
+
}
|
|
851
|
+
return (defaultKey, name, input, output) => [
|
|
852
|
+
...(a?.(defaultKey, name, input, output) ?? []),
|
|
853
|
+
...(b?.(defaultKey, name, input, output) ?? [])
|
|
854
|
+
]
|
|
855
|
+
}
|
|
1270
856
|
|
|
1271
|
-
const
|
|
857
|
+
const withDefaultInvalidation = (
|
|
858
|
+
mut: any,
|
|
859
|
+
defaultInvalidation?: MutationOptionsBase["queryInvalidation"]
|
|
860
|
+
) => {
|
|
861
|
+
if (!defaultInvalidation) return mut
|
|
862
|
+
const apply = (callerOpts?: MutationOptionsBase) => ({
|
|
863
|
+
...callerOpts,
|
|
864
|
+
queryInvalidation: callerOpts?.queryInvalidation
|
|
865
|
+
? mergeInvalidation(defaultInvalidation, callerOpts.queryInvalidation)
|
|
866
|
+
: defaultInvalidation
|
|
867
|
+
})
|
|
868
|
+
return (input: any, callerOpts?: MutationOptionsBase) => mut(input, apply(callerOpts))
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
const makeQueryResources = <Resources extends InvalidationResources>(resources: Resources | undefined) => {
|
|
872
|
+
if (!resources) {
|
|
873
|
+
return {} as Record<string, Record<string, unknown>>
|
|
874
|
+
}
|
|
875
|
+
return resources as Record<string, Record<string, unknown>>
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
const mapQuery = <M extends RequestsAny>(
|
|
1272
879
|
client: ClientFrom<M>
|
|
1273
880
|
) => {
|
|
1274
881
|
const queries = Struct.keys(client).reduce(
|
|
1275
882
|
(acc, key) => {
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
883
|
+
const handler = client[key]
|
|
884
|
+
if (isQueryHandler(handler)) {
|
|
885
|
+
Object.assign(acc, {
|
|
886
|
+
[camelCase(key) + "QueryFamily"]: Object.assign(useQueryFamily(handler), {
|
|
887
|
+
id: client[key].id
|
|
888
|
+
})
|
|
889
|
+
})
|
|
890
|
+
;(acc as any)[camelCase(key) + "Query"] = Object.assign(useQuery(handler), {
|
|
891
|
+
id: client[key].id
|
|
892
|
+
})
|
|
893
|
+
;(acc as any)[camelCase(key) + "QueryNew"] = Object.assign(useQueryNew(handler), {
|
|
894
|
+
id: client[key].id
|
|
895
|
+
})
|
|
896
|
+
;(acc as any)[camelCase(key) + "SuspenseQuery"] = Object.assign(useSuspenseQuery(handler), {
|
|
897
|
+
id: client[key].id
|
|
898
|
+
})
|
|
899
|
+
;(acc as any)[camelCase(key) + "SuspenseQueryNew"] = Object.assign(
|
|
900
|
+
useSuspenseQueryNew(handler),
|
|
901
|
+
{
|
|
902
|
+
id: client[key].id
|
|
903
|
+
}
|
|
904
|
+
)
|
|
905
|
+
} else if (isStreamQueryHandler(handler)) {
|
|
906
|
+
const streamHelpers = streamQueryHelpersFor(handler)
|
|
907
|
+
Object.assign(acc, {
|
|
908
|
+
[camelCase(key) + "QueryFamily"]: Object.assign(streamHelpers.family, {
|
|
909
|
+
id: client[key].id
|
|
910
|
+
}),
|
|
911
|
+
[camelCase(key) + "Query"]: Object.assign(streamHelpers.query, {
|
|
912
|
+
id: client[key].id
|
|
913
|
+
}),
|
|
914
|
+
[camelCase(key) + "QueryNew"]: Object.assign(streamHelpers.queryNew, {
|
|
915
|
+
id: client[key].id
|
|
916
|
+
})
|
|
917
|
+
})
|
|
918
|
+
}
|
|
1282
919
|
return acc
|
|
1283
920
|
},
|
|
1284
921
|
{} as
|
|
922
|
+
& {
|
|
923
|
+
[
|
|
924
|
+
Key in keyof typeof client as QueryHandler<typeof client[Key]> extends never ? never
|
|
925
|
+
: `${ToCamel<string & Key>}QueryFamily`
|
|
926
|
+
]: Queries<RT, QueryHandler<typeof client[Key]>>["family"]
|
|
927
|
+
}
|
|
1285
928
|
& {
|
|
1286
929
|
// apparently can't get JSDoc in here..
|
|
1287
|
-
[
|
|
930
|
+
[
|
|
931
|
+
Key in keyof typeof client as QueryHandler<typeof client[Key]> extends never ? never
|
|
932
|
+
: `${ToCamel<string & Key>}Query`
|
|
933
|
+
]: Queries<RT, QueryHandler<typeof client[Key]>>["query"]
|
|
934
|
+
}
|
|
935
|
+
& {
|
|
936
|
+
[
|
|
937
|
+
Key in keyof typeof client as QueryHandler<typeof client[Key]> extends never ? never
|
|
938
|
+
: `${ToCamel<string & Key>}QueryNew`
|
|
939
|
+
]: Queries<RT, QueryHandler<typeof client[Key]>>["queryNew"]
|
|
1288
940
|
}
|
|
1289
941
|
// todo: or suspense as an Option?
|
|
1290
942
|
& {
|
|
1291
943
|
// apparently can't get JSDoc in here..
|
|
1292
|
-
[
|
|
944
|
+
[
|
|
945
|
+
Key in keyof typeof client as QueryHandler<typeof client[Key]> extends never ? never
|
|
946
|
+
: `${ToCamel<string & Key>}SuspenseQuery`
|
|
947
|
+
]: Queries<
|
|
1293
948
|
RT,
|
|
1294
|
-
typeof client[Key]
|
|
949
|
+
QueryHandler<typeof client[Key]>
|
|
1295
950
|
>["suspense"]
|
|
1296
951
|
}
|
|
952
|
+
& {
|
|
953
|
+
[
|
|
954
|
+
Key in keyof typeof client as QueryHandler<typeof client[Key]> extends never ? never
|
|
955
|
+
: `${ToCamel<string & Key>}SuspenseQueryNew`
|
|
956
|
+
]: Queries<
|
|
957
|
+
RT,
|
|
958
|
+
QueryHandler<typeof client[Key]>
|
|
959
|
+
>["suspenseNew"]
|
|
960
|
+
}
|
|
961
|
+
& {
|
|
962
|
+
[
|
|
963
|
+
Key in keyof typeof client as QueryStreamHandler<typeof client[Key]> extends never ? never
|
|
964
|
+
: `${ToCamel<string & Key>}QueryFamily`
|
|
965
|
+
]: StreamQueries<RT, QueryStreamHandler<typeof client[Key]>>["family"]
|
|
966
|
+
}
|
|
967
|
+
& {
|
|
968
|
+
[
|
|
969
|
+
Key in keyof typeof client as QueryStreamHandler<typeof client[Key]> extends never ? never
|
|
970
|
+
: `${ToCamel<string & Key>}Query`
|
|
971
|
+
]: StreamQueries<RT, QueryStreamHandler<typeof client[Key]>>["query"]
|
|
972
|
+
}
|
|
973
|
+
& {
|
|
974
|
+
[
|
|
975
|
+
Key in keyof typeof client as QueryStreamHandler<typeof client[Key]> extends never ? never
|
|
976
|
+
: `${ToCamel<string & Key>}QueryNew`
|
|
977
|
+
]: StreamQueries<RT, QueryStreamHandler<typeof client[Key]>>["queryNew"]
|
|
978
|
+
}
|
|
1297
979
|
)
|
|
1298
980
|
return queries
|
|
1299
981
|
}
|
|
1300
982
|
|
|
1301
|
-
const mapRequest = <M extends
|
|
983
|
+
const mapRequest = <M extends RequestsAny>(
|
|
1302
984
|
client: ClientFrom<M>
|
|
1303
985
|
) => {
|
|
1304
986
|
const Command = useCommand()
|
|
1305
987
|
const mutations = Struct.keys(client).reduce(
|
|
1306
988
|
(acc, key) => {
|
|
989
|
+
if (!(client[key].Request.type === "command" && !client[key].Request.stream)) {
|
|
990
|
+
return acc
|
|
991
|
+
}
|
|
1307
992
|
const mut = client[key].handler
|
|
1308
|
-
const
|
|
1309
|
-
const
|
|
993
|
+
const request = mut
|
|
994
|
+
const fn = (options?: any) => Command.fn(client[key].id, options)
|
|
995
|
+
const wrap = (options?: any) => Command.wrap({ mutate: request, id: client[key].id }, options)
|
|
1310
996
|
;(acc as any)[camelCase(key) + "Request"] = Object.assign(
|
|
1311
997
|
mut,
|
|
1312
|
-
fn, // to get the i18n key etc.
|
|
1313
|
-
{ wrap, fn }
|
|
998
|
+
Command.fn(client[key].id), // to get the i18n key etc.
|
|
999
|
+
{ wrap, fn, request }
|
|
1314
1000
|
)
|
|
1315
1001
|
return acc
|
|
1316
1002
|
},
|
|
1317
1003
|
{} as {
|
|
1318
|
-
[
|
|
1004
|
+
[
|
|
1005
|
+
Key in keyof typeof client as CommandHandler<typeof client[Key]> extends never ? never
|
|
1006
|
+
: `${ToCamel<string & Key>}Request`
|
|
1007
|
+
]: CommandRequestWithExtensions<
|
|
1319
1008
|
RT | RTHooks,
|
|
1320
|
-
typeof client[Key]
|
|
1009
|
+
CommandHandler<typeof client[Key]>
|
|
1321
1010
|
>
|
|
1322
1011
|
}
|
|
1323
1012
|
)
|
|
1324
1013
|
return mutations
|
|
1325
1014
|
}
|
|
1326
1015
|
|
|
1327
|
-
const mapMutation = <M extends
|
|
1328
|
-
client: ClientFrom<M
|
|
1016
|
+
const mapMutation = <M extends RequestsAny>(
|
|
1017
|
+
client: ClientFrom<M>,
|
|
1018
|
+
queryInvalidation?: (client: ClientFrom<M>) => QueryInvalidation<M>,
|
|
1019
|
+
invalidationResources?: InvalidationResourcesFor<M>
|
|
1329
1020
|
) => {
|
|
1330
1021
|
const Command = useCommand()
|
|
1331
1022
|
const mutation = useMutation()
|
|
1023
|
+
const invalidation = queryInvalidation?.(client)
|
|
1024
|
+
const queryResources = makeQueryResources(invalidationResources)
|
|
1332
1025
|
const mutations = Struct.keys(client).reduce(
|
|
1333
1026
|
(acc, key) => {
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1027
|
+
if (!(client[key].Request.type === "command" && !client[key].Request.stream)) {
|
|
1028
|
+
return acc
|
|
1029
|
+
}
|
|
1030
|
+
const fromRequestConfig = client[key].Request.config?.["invalidatesQueries"] as
|
|
1031
|
+
| InvalidationCallback<InvalidationResourcesFor<M>>
|
|
1032
|
+
| undefined
|
|
1033
|
+
const fromRequest = fromRequestConfig
|
|
1034
|
+
? ((defaultKey: string[], _name: string, input?: unknown, output?: unknown) =>
|
|
1035
|
+
fromRequestConfig(
|
|
1036
|
+
defaultKey,
|
|
1037
|
+
queryResources as never,
|
|
1038
|
+
input,
|
|
1039
|
+
output as never
|
|
1040
|
+
) as InvalidationEntry[])
|
|
1041
|
+
: undefined
|
|
1042
|
+
const mergedInvalidation = mergeInvalidation(fromRequest, invalidation?.[key])
|
|
1043
|
+
const makeProjectedMutation = (handler: any): any => {
|
|
1044
|
+
const mut: any = withDefaultInvalidation(mutation(handler), mergedInvalidation)
|
|
1045
|
+
return Object.assign(mut, {
|
|
1046
|
+
wrap: (options?: any) => Command.wrap({ mutate: mut, id: client[key].id }, options),
|
|
1047
|
+
fn: (options?: any) => Command.fn(client[key].id, options),
|
|
1048
|
+
project: (projectionSchema: any) => {
|
|
1049
|
+
const projected = {
|
|
1050
|
+
...handler,
|
|
1051
|
+
handler: projectHandler(handler.handler, client[key].Request.success, projectionSchema)
|
|
1052
|
+
}
|
|
1053
|
+
return makeProjectedMutation(projected)
|
|
1054
|
+
}
|
|
1055
|
+
})
|
|
1056
|
+
}
|
|
1057
|
+
;(acc as any)[camelCase(key) + "Mutation"] = makeProjectedMutation(client[key] as any)
|
|
1342
1058
|
return acc
|
|
1343
1059
|
},
|
|
1344
1060
|
{} as {
|
|
1345
|
-
[
|
|
1061
|
+
[
|
|
1062
|
+
Key in keyof typeof client as CommandHandler<typeof client[Key]> extends never ? never
|
|
1063
|
+
: `${ToCamel<string & Key>}Mutation`
|
|
1064
|
+
]: MutationWithExtensions<
|
|
1346
1065
|
RT | RTHooks,
|
|
1347
|
-
typeof client[Key]
|
|
1066
|
+
CommandHandler<typeof client[Key]>
|
|
1348
1067
|
>
|
|
1349
1068
|
}
|
|
1350
1069
|
)
|
|
@@ -1353,8 +1072,9 @@ export const makeClient = <RT_, RTHooks>(
|
|
|
1353
1072
|
|
|
1354
1073
|
// make available .query, .suspense and .mutate for each operation
|
|
1355
1074
|
// and a .helpers with all mutations and queries
|
|
1356
|
-
const mapClient = <M extends
|
|
1357
|
-
queryInvalidation?: (client: ClientFrom<M>) => QueryInvalidation<M
|
|
1075
|
+
const mapClient = <M extends RequestsAny>(
|
|
1076
|
+
queryInvalidation?: (client: ClientFrom<M>) => QueryInvalidation<M>,
|
|
1077
|
+
invalidationResources?: InvalidationResourcesFor<M>
|
|
1358
1078
|
) =>
|
|
1359
1079
|
(
|
|
1360
1080
|
client: ClientFrom<M>
|
|
@@ -1362,71 +1082,167 @@ export const makeClient = <RT_, RTHooks>(
|
|
|
1362
1082
|
const Command = useCommand()
|
|
1363
1083
|
const mutation = useMutation()
|
|
1364
1084
|
const invalidation = queryInvalidation?.(client)
|
|
1085
|
+
const queryResources = makeQueryResources(invalidationResources)
|
|
1365
1086
|
const extended = Struct.keys(client).reduce(
|
|
1366
1087
|
(acc, key) => {
|
|
1088
|
+
const handler = client[key]
|
|
1089
|
+
const requestType = handler.Request.type
|
|
1090
|
+
const isStream = handler.Request.stream
|
|
1367
1091
|
const fn = Command.fn(client[key].id)
|
|
1368
|
-
const
|
|
1369
|
-
|
|
1370
|
-
client[key] as any,
|
|
1371
|
-
invalidation?.[key] ? { queryInvalidation: invalidation[key] } : undefined
|
|
1372
|
-
),
|
|
1373
|
-
(mutate) =>
|
|
1374
|
-
Object.assign(
|
|
1375
|
-
mutate,
|
|
1376
|
-
fn, // to get the i18n key etc.
|
|
1377
|
-
{
|
|
1378
|
-
wrap: Command.wrap({ mutate: Effect.isEffect(mutate) ? () => mutate : mutate, id: client[key].id }),
|
|
1379
|
-
fn
|
|
1380
|
-
}
|
|
1381
|
-
)
|
|
1382
|
-
)
|
|
1383
|
-
|
|
1384
|
-
const h_ = client[key].handler
|
|
1385
|
-
const h = Effect.isEffect(h_)
|
|
1386
|
-
? () => h_
|
|
1387
|
-
: (...args: [any]) => h_(...args)
|
|
1092
|
+
const h_ = handler.handler
|
|
1093
|
+
const request = h_
|
|
1388
1094
|
;(acc as any)[key] = Object.assign(
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1095
|
+
isQueryHandler(handler)
|
|
1096
|
+
? {
|
|
1097
|
+
...handler,
|
|
1098
|
+
request,
|
|
1099
|
+
...queryHelpersFor(handler),
|
|
1100
|
+
project: projectQueryFor(handler)
|
|
1101
|
+
}
|
|
1102
|
+
: isStreamQueryHandler(handler)
|
|
1103
|
+
? {
|
|
1104
|
+
...client[key],
|
|
1105
|
+
request,
|
|
1106
|
+
...streamQueryHelpersFor(handler)
|
|
1107
|
+
}
|
|
1108
|
+
: requestType === "command" && isStream
|
|
1109
|
+
? (() => {
|
|
1110
|
+
const fromRequestConfig = client[key].Request.config?.["invalidatesQueries"] as
|
|
1111
|
+
| InvalidationCallback<InvalidationResourcesFor<M>>
|
|
1112
|
+
| undefined
|
|
1113
|
+
const fromRequest = fromRequestConfig
|
|
1114
|
+
? ((defaultKey: string[], _name: string, input?: unknown, output?: unknown) =>
|
|
1115
|
+
fromRequestConfig(
|
|
1116
|
+
defaultKey,
|
|
1117
|
+
queryResources as never,
|
|
1118
|
+
input,
|
|
1119
|
+
output as never
|
|
1120
|
+
) as InvalidationEntry[])
|
|
1121
|
+
: undefined
|
|
1122
|
+
const mergedInvalidation = mergeInvalidation(fromRequest, invalidation?.[key])
|
|
1123
|
+
const streamCmd = useCommand()
|
|
1124
|
+
return {
|
|
1125
|
+
...client[key],
|
|
1126
|
+
request,
|
|
1127
|
+
query: useStreamQuery(client[key] as any),
|
|
1128
|
+
fn: (options?: any) => streamCmd.streamFn(client[key].id as any, options),
|
|
1129
|
+
mutate: (() => {
|
|
1130
|
+
const sm2Act = useStreamMutation2()(client[key] as any, mergedInvalidation)
|
|
1131
|
+
const sm2Handler = (input: any, _ctx: any) => (sm2Act as (i: any) => any)(input)
|
|
1132
|
+
return Object.assign(sm2Act, {
|
|
1133
|
+
id: client[key].id,
|
|
1134
|
+
wrap: (options?: any) => streamCmd.streamWrap(sm2Handler, client[key].id as any, options)
|
|
1135
|
+
})
|
|
1136
|
+
})()
|
|
1137
|
+
}
|
|
1138
|
+
})()
|
|
1139
|
+
: {
|
|
1140
|
+
mutate: ((handler: any) => {
|
|
1141
|
+
const fromRequestConfig = client[key].Request.config?.["invalidatesQueries"] as
|
|
1142
|
+
| InvalidationCallback<InvalidationResourcesFor<M>>
|
|
1143
|
+
| undefined
|
|
1144
|
+
const fromRequest = fromRequestConfig
|
|
1145
|
+
? ((defaultKey: string[], _name: string, input?: unknown, output?: unknown) =>
|
|
1146
|
+
fromRequestConfig(
|
|
1147
|
+
defaultKey,
|
|
1148
|
+
queryResources as never,
|
|
1149
|
+
input,
|
|
1150
|
+
output as never
|
|
1151
|
+
) as InvalidationEntry[])
|
|
1152
|
+
: undefined
|
|
1153
|
+
const mergedInvalidation = mergeInvalidation(fromRequest, invalidation?.[key])
|
|
1154
|
+
const makeProjectedMutation = (h: any): any => {
|
|
1155
|
+
const mutate = withDefaultInvalidation(mutation(h), mergedInvalidation)
|
|
1156
|
+
return Object.assign(
|
|
1157
|
+
mutate,
|
|
1158
|
+
{
|
|
1159
|
+
wrap: (options?: any) =>
|
|
1160
|
+
Command.wrap({
|
|
1161
|
+
mutate,
|
|
1162
|
+
id: client[key].id
|
|
1163
|
+
}, options),
|
|
1164
|
+
fn: (options?: any) => Command.fn(client[key].id, options),
|
|
1165
|
+
project: (projectionSchema: any) => {
|
|
1166
|
+
const projected = {
|
|
1167
|
+
...h,
|
|
1168
|
+
handler: projectHandler(h.handler, client[key].Request.success, projectionSchema)
|
|
1169
|
+
}
|
|
1170
|
+
return makeProjectedMutation(projected)
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
)
|
|
1174
|
+
}
|
|
1175
|
+
return makeProjectedMutation(handler)
|
|
1176
|
+
})(client[key] as any),
|
|
1177
|
+
...client[key],
|
|
1178
|
+
...fn, // to get the i18n key etc.
|
|
1179
|
+
request,
|
|
1180
|
+
fn: (options?: any) => Command.fn(client[key].id, options),
|
|
1181
|
+
wrap: (options?: any) => Command.wrap({ mutate: h_, id: client[key].id }, options)
|
|
1182
|
+
}
|
|
1399
1183
|
)
|
|
1400
1184
|
return acc
|
|
1401
1185
|
},
|
|
1402
1186
|
{} as {
|
|
1403
1187
|
[Key in keyof typeof client]:
|
|
1404
1188
|
& typeof client[Key]
|
|
1405
|
-
&
|
|
1406
|
-
|
|
1407
|
-
|
|
1189
|
+
& (QueryHandler<typeof client[Key]> extends never ? {}
|
|
1190
|
+
:
|
|
1191
|
+
& QueryRequestWithExtensions<QueryHandler<typeof client[Key]>>
|
|
1192
|
+
& Queries<RT, QueryHandler<typeof client[Key]>>
|
|
1193
|
+
& QueryProjection<RT, QueryHandler<typeof client[Key]>>)
|
|
1194
|
+
& (QueryStreamHandler<typeof client[Key]> extends never ? {}
|
|
1195
|
+
: StreamQueries<RT, QueryStreamHandler<typeof client[Key]>>)
|
|
1196
|
+
& (CommandHandler<typeof client[Key]> extends never ? {}
|
|
1197
|
+
: CommandRequestWithExtensions<RT | RTHooks, CommandHandler<typeof client[Key]>>)
|
|
1198
|
+
& (CommandHandler<typeof client[Key]> extends never ? {}
|
|
1199
|
+
: { mutate: MutationWithExtensions<RT | RTHooks, CommandHandler<typeof client[Key]>> })
|
|
1200
|
+
& (CommandStreamHandler<typeof client[Key]> extends never ? {}
|
|
1201
|
+
: {
|
|
1202
|
+
fn: StreamFnStreamExtension<RT | RTHooks, CommandStreamHandler<typeof client[Key]>>
|
|
1203
|
+
mutate: StreamMutation2WithExtensions<RT | RTHooks, CommandStreamHandler<typeof client[Key]>>
|
|
1204
|
+
})
|
|
1205
|
+
& {
|
|
1206
|
+
Input: typeof client[Key] extends RequestStreamHandlerWithInput<infer I, any, any, any, any, any, any> ? I
|
|
1207
|
+
: typeof client[Key] extends RequestHandlerWithInput<infer I, any, any, any, any, any> ? I
|
|
1208
|
+
: never
|
|
1209
|
+
}
|
|
1408
1210
|
}
|
|
1409
1211
|
)
|
|
1410
|
-
return Object.assign(extended, {
|
|
1212
|
+
return Object.assign(extended, {
|
|
1213
|
+
helpers: {
|
|
1214
|
+
...mapRequest(client),
|
|
1215
|
+
...mapMutation(client, queryInvalidation, invalidationResources),
|
|
1216
|
+
...mapQuery(client)
|
|
1217
|
+
}
|
|
1218
|
+
})
|
|
1411
1219
|
}
|
|
1412
1220
|
|
|
1413
1221
|
// TODO: Clean up this delay initialisation messs
|
|
1414
1222
|
// TODO; invalidateQueries should perhaps be configured in the Request impl themselves?
|
|
1415
|
-
const clientFor__ = <M extends
|
|
1223
|
+
const clientFor__ = <M extends RequestsAny>(
|
|
1416
1224
|
m: M,
|
|
1417
|
-
queryInvalidation?:
|
|
1418
|
-
|
|
1225
|
+
queryInvalidation?: QueryInvalidationFactory<M>,
|
|
1226
|
+
invalidationResources?: InvalidationResourcesFor<M>
|
|
1227
|
+
) => getBaseMrt().runSync(clientFor_(m).pipe(Effect.map(mapClient(queryInvalidation, invalidationResources))))
|
|
1419
1228
|
|
|
1420
1229
|
// delay client creation until first access
|
|
1421
1230
|
// the idea is that we don't need the useNuxtApp().$runtime (only available at later initialisation stage)
|
|
1422
1231
|
// until we are at a place where it is available..
|
|
1423
|
-
const clientFor = <
|
|
1232
|
+
const clientFor = <
|
|
1233
|
+
M extends RequestsAny,
|
|
1234
|
+
Resources extends InvalidationResourcesFor<M> = InvalidationResourcesFor<M>
|
|
1235
|
+
>(
|
|
1424
1236
|
m: M,
|
|
1425
|
-
|
|
1237
|
+
...args: ClientForArgs<M, Resources>
|
|
1426
1238
|
) => {
|
|
1239
|
+
const [queryInvalidation, invalidationResources] = args as [
|
|
1240
|
+
QueryInvalidationFactory<M> | undefined,
|
|
1241
|
+
InvalidationResourcesFor<M> | undefined
|
|
1242
|
+
]
|
|
1427
1243
|
type Client = ReturnType<typeof clientFor__<M>>
|
|
1428
1244
|
let client: Client | undefined = undefined
|
|
1429
|
-
const getOrMakeClient = () => (client ??= clientFor__(m, queryInvalidation))
|
|
1245
|
+
const getOrMakeClient = () => (client ??= clientFor__(m, queryInvalidation, invalidationResources))
|
|
1430
1246
|
|
|
1431
1247
|
// initialize on first use..
|
|
1432
1248
|
const proxy = Struct.keys(m).concat(["helpers"]).reduce((acc, key) => {
|
|
@@ -1444,16 +1260,12 @@ export const makeClient = <RT_, RTHooks>(
|
|
|
1444
1260
|
return proxy
|
|
1445
1261
|
}
|
|
1446
1262
|
|
|
1447
|
-
const legacy: Legacy<RT> = {
|
|
1448
|
-
...mutations,
|
|
1449
|
-
...query
|
|
1450
|
-
}
|
|
1451
|
-
|
|
1452
1263
|
const Command: CommanderResolved<RT, RTHooks> = {
|
|
1453
1264
|
...{
|
|
1454
1265
|
// delay initialisation until first use...
|
|
1455
1266
|
fn: (...args: [any]) => useCommand().fn(...args),
|
|
1456
1267
|
wrap: (...args: [any]) => useCommand().wrap(...args),
|
|
1268
|
+
streamFn: (...args: [any]) => useCommand().streamFn(...args),
|
|
1457
1269
|
alt: (...args: [any]) => useCommand().alt(...args),
|
|
1458
1270
|
alt2: (...args: [any]) => useCommand().alt2(...args)
|
|
1459
1271
|
} as ReturnType<typeof useCommand>,
|
|
@@ -1464,21 +1276,17 @@ export const makeClient = <RT_, RTHooks>(
|
|
|
1464
1276
|
Command,
|
|
1465
1277
|
useCommand,
|
|
1466
1278
|
clientFor,
|
|
1467
|
-
|
|
1279
|
+
tanstackQueryClient: getTanstackQueryClient()
|
|
1468
1280
|
}
|
|
1469
1281
|
}
|
|
1470
1282
|
|
|
1471
|
-
export interface Legacy<R>
|
|
1472
|
-
extends
|
|
1473
|
-
Pick<QueryImpl<R>, "useQuery" | "useSuspenseQuery">,
|
|
1474
|
-
Omit<LegacyMutationImpl<R>, "getRuntime" | "toast" | "intl">
|
|
1475
|
-
{}
|
|
1476
|
-
|
|
1477
1283
|
export type QueryInvalidation<M> = {
|
|
1478
|
-
[K in keyof M]?: (
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1284
|
+
[K in keyof M]?: (
|
|
1285
|
+
defaultKey: string[],
|
|
1286
|
+
name: string,
|
|
1287
|
+
input?: unknown,
|
|
1288
|
+
output?: Exit.Exit<unknown, unknown>
|
|
1289
|
+
) => InvalidationEntry[]
|
|
1482
1290
|
}
|
|
1483
1291
|
|
|
1484
1292
|
export type ToCamel<S extends string | number | symbol> = S extends string
|
|
@@ -1486,17 +1294,21 @@ export type ToCamel<S extends string | number | symbol> = S extends string
|
|
|
1486
1294
|
: Uncapitalize<S>
|
|
1487
1295
|
: never
|
|
1488
1296
|
|
|
1489
|
-
export interface CommandBase<I = void, A = void> {
|
|
1297
|
+
export interface CommandBase<I = void, A = void, RA = unknown, RE = unknown> {
|
|
1490
1298
|
handle: (input: I) => A
|
|
1491
1299
|
waiting: boolean
|
|
1492
1300
|
blocked: boolean
|
|
1493
1301
|
allowed: boolean
|
|
1494
1302
|
action: string
|
|
1495
1303
|
label: string
|
|
1304
|
+
/** formatted progress info for current `running` state, when `progress` was supplied */
|
|
1305
|
+
progress?: Progress | undefined
|
|
1306
|
+
/** reactive result state, available on stream-backed commands */
|
|
1307
|
+
result?: AsyncResult.AsyncResult<RA, RE>
|
|
1496
1308
|
}
|
|
1497
1309
|
|
|
1498
|
-
export interface EffectCommand<I = void, A = unknown, E = unknown> extends CommandBase<I, Fiber<A, E
|
|
1310
|
+
export interface EffectCommand<I = void, A = unknown, E = unknown> extends CommandBase<I, Fiber<A, E>, A, E> {}
|
|
1499
1311
|
|
|
1500
|
-
export interface CommandFromRequest<I extends
|
|
1501
|
-
extends EffectCommand<
|
|
1312
|
+
export interface CommandFromRequest<I extends { readonly make: (...args: any[]) => any }, A = unknown, E = unknown>
|
|
1313
|
+
extends EffectCommand<HandlerInput<I>, A, E>
|
|
1502
1314
|
{}
|