@effect-app/vue 4.0.0-beta.19 → 4.0.0-beta.191
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 +1398 -0
- package/dist/commander.d.ts +620 -0
- package/dist/commander.d.ts.map +1 -0
- package/dist/commander.js +1056 -0
- package/dist/confirm.d.ts +19 -0
- package/dist/confirm.d.ts.map +1 -0
- package/dist/confirm.js +24 -0
- package/dist/errorReporter.d.ts +4 -4
- package/dist/errorReporter.d.ts.map +1 -1
- package/dist/errorReporter.js +12 -18
- package/dist/form.d.ts +14 -5
- package/dist/form.d.ts.map +1 -1
- package/dist/form.js +41 -12
- package/dist/index.d.ts +1 -1
- 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 +6 -8
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +34 -7
- package/dist/makeClient.d.ts +191 -292
- package/dist/makeClient.d.ts.map +1 -1
- package/dist/makeClient.js +217 -369
- package/dist/makeContext.d.ts +1 -1
- package/dist/makeContext.d.ts.map +1 -1
- package/dist/makeIntl.d.ts +1 -1
- package/dist/makeIntl.d.ts.map +1 -1
- package/dist/makeUseCommand.d.ts +8 -0
- package/dist/makeUseCommand.d.ts.map +1 -0
- package/dist/makeUseCommand.js +13 -0
- package/dist/mutate.d.ts +56 -25
- package/dist/mutate.d.ts.map +1 -1
- package/dist/mutate.js +132 -33
- package/dist/query.d.ts +24 -16
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +119 -37
- package/dist/routeParams.d.ts +1 -1
- package/dist/runtime.d.ts +7 -4
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +27 -17
- package/dist/toast.d.ts +46 -0
- package/dist/toast.d.ts.map +1 -0
- package/dist/toast.js +32 -0
- package/dist/withToast.d.ts +26 -0
- package/dist/withToast.d.ts.map +1 -0
- package/dist/withToast.js +54 -0
- package/examples/streamMutation.ts +70 -0
- package/package.json +47 -49
- package/src/commander.ts +3378 -0
- package/src/{experimental/confirm.ts → confirm.ts} +10 -14
- package/src/errorReporter.ts +62 -74
- package/src/form.ts +56 -17
- package/src/intl.ts +12 -0
- package/src/lib.ts +46 -13
- package/src/makeClient.ts +623 -1043
- package/src/{experimental/makeUseCommand.ts → makeUseCommand.ts} +6 -4
- package/src/mutate.ts +273 -72
- package/src/query.ts +181 -68
- package/src/runtime.ts +41 -20
- package/src/{experimental/toast.ts → toast.ts} +11 -25
- package/src/{experimental/withToast.ts → withToast.ts} +28 -10
- package/test/Mutation.test.ts +176 -23
- package/test/dist/form.test.d.ts.map +1 -1
- package/test/dist/lib.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 +3294 -115
- package/test/dist/stubs.d.ts.map +1 -1
- package/test/dist/stubs.js +177 -31
- package/test/form-validation-errors.test.ts +23 -19
- package/test/form.test.ts +20 -2
- package/test/lib.test.ts +240 -0
- package/test/makeClient.test.ts +286 -38
- package/test/streamFinal.test.ts +63 -0
- package/test/streamFn.test.ts +455 -0
- package/test/stubs.ts +213 -42
- package/tsconfig.examples.json +20 -0
- package/tsconfig.json +0 -1
- package/tsconfig.json.bak +5 -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 +0 -19
- 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 +0 -8
- 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/makeClient.ts
CHANGED
|
@@ -1,32 +1,48 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import { type InvalidateOptions, type InvalidateQueryFilters, isCancelledError, type QueryObserverResult, type RefetchOptions, type UseQueryReturnType } from "@tanstack/vue-query"
|
|
3
3
|
import { camelCase } from "change-case"
|
|
4
|
-
import {
|
|
4
|
+
import { type Context, Effect, Exit, Hash, type Layer, type ManagedRuntime, S, Struct } from "effect-app"
|
|
5
5
|
import { type ApiClientFactory, type Req } from "effect-app/client"
|
|
6
|
-
import type { RequestHandler, RequestHandlers, RequestHandlerWithInput,
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
import { type OperationFailure, OperationSuccess } from "effect-app/Operations"
|
|
10
|
-
import { dropUndefinedT, extendM } from "effect-app/utils"
|
|
6
|
+
import type { ExtractModuleName, HandlerInput, RequestHandler, RequestHandlers, RequestHandlerWithInput, RequestsAny, RequestStreamHandler, RequestStreamHandlerWithInput } from "effect-app/client/clientFor"
|
|
7
|
+
import type { InvalidationCallback } from "effect-app/client/makeClient"
|
|
8
|
+
import type * as ExitResult from "effect/Exit"
|
|
11
9
|
import { type Fiber } from "effect/Fiber"
|
|
10
|
+
import * as Stream from "effect/Stream"
|
|
12
11
|
import * as AsyncResult from "effect/unstable/reactivity/AsyncResult"
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { type
|
|
16
|
-
import {
|
|
17
|
-
import { type
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
import { type ComputedRef, onBeforeUnmount, ref, type WatchSource } from "vue"
|
|
13
|
+
import { type Commander, CommanderStatic, type Progress } from "./commander.js"
|
|
14
|
+
import { type I18n } from "./intl.js"
|
|
15
|
+
import { type CommanderResolved, makeUseCommand } from "./makeUseCommand.js"
|
|
16
|
+
import { makeMutation, makeStreamMutation2, type MutationOptionsBase, useMakeMutation } from "./mutate.js"
|
|
17
|
+
import { type CustomUndefinedInitialQueryOptions, makeQuery, makeStreamQuery } from "./query.js"
|
|
18
|
+
import { makeRunPromise } from "./runtime.js"
|
|
19
|
+
import { type Toast } from "./toast.js"
|
|
20
|
+
|
|
21
|
+
export type { Progress }
|
|
23
22
|
|
|
24
23
|
const mapHandler = <A, E, R, I = void, A2 = A, E2 = E, R2 = R>(
|
|
25
24
|
handler: Effect.Effect<A, E, R> | ((i: I) => Effect.Effect<A, E, R>),
|
|
26
25
|
map: (self: Effect.Effect<A, E, R>, i: I) => Effect.Effect<A2, E2, R2>
|
|
27
26
|
) => Effect.isEffect(handler) ? map(handler, undefined as any) : (i: I) => map(handler(i), i)
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
// TODO: optimize - work from encoded shape directly
|
|
29
|
+
const projectHandler = (
|
|
30
|
+
handler: Effect.Effect<any, any, any> | ((i: any) => Effect.Effect<any, any, any>),
|
|
31
|
+
successSchema: S.Top,
|
|
32
|
+
projectionSchema: S.Top
|
|
33
|
+
) => {
|
|
34
|
+
const encode = S.encodeEffect(successSchema)
|
|
35
|
+
const decode = S.decodeEffectConcurrently(projectionSchema)
|
|
36
|
+
return mapHandler(handler, (self) =>
|
|
37
|
+
self.pipe(
|
|
38
|
+
Effect.flatMap(encode),
|
|
39
|
+
Effect.flatMap(decode)
|
|
40
|
+
))
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const projectionSchemaHash = (schema: S.Top) => String(Hash.hash(schema.ast))
|
|
44
|
+
|
|
45
|
+
export interface CommandRequestExtensions<RT, Id extends string, I, A, E, R> {
|
|
30
46
|
/** Defines a Command based on this call, taking the `id` of the call as the `id` of the Command.
|
|
31
47
|
* The Request function will be taken as the first member of the Command, the Command required input will be the Request input.
|
|
32
48
|
* see Command.wrap for details */
|
|
@@ -44,16 +60,14 @@ export interface RequestExtWithInput<
|
|
|
44
60
|
A,
|
|
45
61
|
E,
|
|
46
62
|
R
|
|
47
|
-
> extends Commander.CommandContextLocal<Id, Id>,
|
|
63
|
+
> extends Commander.CommandContextLocal<Id, Id>, CommandRequestExtensions<RT, Id, I, A, E, R> {
|
|
48
64
|
/**
|
|
49
|
-
*
|
|
65
|
+
* Send the request to the endpoint and return the raw Effect response.
|
|
66
|
+
* This does not perform query cache invalidation.
|
|
50
67
|
*/
|
|
51
|
-
(i: I)
|
|
68
|
+
request: (i: I) => Effect.Effect<A, E, R>
|
|
52
69
|
}
|
|
53
70
|
|
|
54
|
-
/**
|
|
55
|
-
* Request the endpoint
|
|
56
|
-
*/
|
|
57
71
|
export interface RequestExt<
|
|
58
72
|
RT,
|
|
59
73
|
Id extends string,
|
|
@@ -63,25 +77,69 @@ export interface RequestExt<
|
|
|
63
77
|
> extends
|
|
64
78
|
Commander.CommandContextLocal<Id, Id>,
|
|
65
79
|
Commander.CommanderWrap<RT, Id, Id, undefined, void, A, E, R>,
|
|
66
|
-
|
|
67
|
-
Effect.Effect<A, E, R>
|
|
80
|
+
CommandRequestExtensions<RT, Id, void, A, E, R>
|
|
68
81
|
{
|
|
82
|
+
/**
|
|
83
|
+
* Send the request to the endpoint and return the raw Effect response.
|
|
84
|
+
* This does not perform query cache invalidation.
|
|
85
|
+
*/
|
|
86
|
+
request: Effect.Effect<A, E, R>
|
|
69
87
|
}
|
|
70
88
|
|
|
71
|
-
export type
|
|
89
|
+
export type CommandRequestWithExtensions<RT, Req> = Req extends
|
|
72
90
|
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer _Request, infer Id>
|
|
73
91
|
? RequestExtWithInput<RT, Id, I, A, E, R>
|
|
74
92
|
: Req extends RequestHandler<infer A, infer E, infer R, infer _Request, infer Id> ? RequestExt<RT, Id, A, E, R>
|
|
75
93
|
: never
|
|
76
94
|
|
|
95
|
+
export interface QueryExtensionsWithInput<I, A, E, R> {
|
|
96
|
+
/**
|
|
97
|
+
* Send the request to the endpoint and return the raw Effect response.
|
|
98
|
+
* This does not set up query state tracking.
|
|
99
|
+
*/
|
|
100
|
+
request: (i: I) => Effect.Effect<A, E, R>
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface QueryExtensions<A, E, R> {
|
|
104
|
+
/**
|
|
105
|
+
* Send the request to the endpoint and return the raw Effect response.
|
|
106
|
+
* This does not set up query state tracking.
|
|
107
|
+
*/
|
|
108
|
+
request: Effect.Effect<A, E, R>
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export type QueryRequestWithExtensions<Req> = Req extends
|
|
112
|
+
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer _Request, infer _Id>
|
|
113
|
+
? QueryExtensionsWithInput<I, A, E, R>
|
|
114
|
+
: Req extends RequestHandler<infer A, infer E, infer R, infer _Request, infer _Id> ? QueryExtensions<A, E, R>
|
|
115
|
+
: never
|
|
116
|
+
|
|
117
|
+
type QueryHandler<Req> = Req extends
|
|
118
|
+
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id>
|
|
119
|
+
? Request["type"] extends "query" ? RequestHandlerWithInput<I, A, E, R, Request, Id> : never
|
|
120
|
+
: Req extends RequestHandler<infer A, infer E, infer R, infer Request, infer Id>
|
|
121
|
+
? Request["type"] extends "query" ? RequestHandler<A, E, R, Request, Id> : never
|
|
122
|
+
: never
|
|
123
|
+
|
|
124
|
+
type CommandHandler<Req> = Req extends
|
|
125
|
+
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id>
|
|
126
|
+
? Request["type"] extends "command" ? RequestHandlerWithInput<I, A, E, R, Request, Id> : never
|
|
127
|
+
: Req extends RequestHandler<infer A, infer E, infer R, infer Request, infer Id>
|
|
128
|
+
? Request["type"] extends "command" ? RequestHandler<A, E, R, Request, Id> : never
|
|
129
|
+
: never
|
|
130
|
+
|
|
131
|
+
type StreamHandler<Req> = Req extends
|
|
132
|
+
RequestStreamHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id, infer Final>
|
|
133
|
+
? Request["type"] extends "stream" ? RequestStreamHandlerWithInput<I, A, E, R, Request, Id, Final> : never
|
|
134
|
+
: Req extends RequestStreamHandler<infer A, infer E, infer R, infer Request, infer Id, infer Final>
|
|
135
|
+
? Request["type"] extends "stream" ? RequestStreamHandler<A, E, R, Request, Id, Final> : never
|
|
136
|
+
: never
|
|
137
|
+
|
|
77
138
|
export interface MutationExtensions<RT, Id extends string, I, A, E, R> {
|
|
78
139
|
/** Defines a Command based on this mutation, taking the `id` of the mutation as the `id` of the Command.
|
|
79
140
|
* The Mutation function will be taken as the first member of the Command, the Command required input will be the Mutation input.
|
|
80
141
|
* see Command.wrap for details */
|
|
81
142
|
wrap: Commander.CommanderWrap<RT, Id, Id, undefined, I, A, E, R>
|
|
82
|
-
/** Defines a Command based on this mutation, taking the `id` of the mutation as the `id` of the Command.
|
|
83
|
-
* see Command.fn for details */
|
|
84
|
-
fn: Commander.CommanderFn<RT, Id, Id, undefined>
|
|
85
143
|
}
|
|
86
144
|
|
|
87
145
|
/** my other doc */
|
|
@@ -91,39 +149,111 @@ export interface MutationExtWithInput<
|
|
|
91
149
|
I,
|
|
92
150
|
A,
|
|
93
151
|
E,
|
|
94
|
-
R
|
|
95
|
-
|
|
152
|
+
R,
|
|
153
|
+
EA = unknown
|
|
154
|
+
> extends MutationExtensions<RT, Id, I, A, E, R> {
|
|
96
155
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
156
|
+
* Send the request to the endpoint and return the raw Effect response.
|
|
157
|
+
* Also invalidates query caches using the request namespace by default.
|
|
158
|
+
* Namespace invalidation targets parent namespace keys
|
|
159
|
+
* (for example `$project/$configuration.get` invalidates `$project`).
|
|
160
|
+
* Override invalidation in client options via `queryInvalidation`.
|
|
161
|
+
*
|
|
162
|
+
* Pass `options` to attach a `select` Effect that runs after the mutation
|
|
163
|
+
* succeeds (its output is returned to the caller) and/or override the default
|
|
164
|
+
* `queryInvalidation`.
|
|
100
165
|
*/
|
|
101
|
-
|
|
166
|
+
<B = A, E2 = never, R2 = never>(
|
|
167
|
+
input: I,
|
|
168
|
+
options?: MutationOptionsBase<A, B, E2, R2>
|
|
169
|
+
): Effect.Effect<B, E | E2, R | R2>
|
|
170
|
+
|
|
171
|
+
project: <ProjSchema extends S.Top>(
|
|
172
|
+
schema: EA extends ProjSchema["Encoded"] ? ProjSchema : never
|
|
173
|
+
) => MutationExtWithInput<
|
|
174
|
+
RT,
|
|
175
|
+
Id,
|
|
176
|
+
I,
|
|
177
|
+
S.Schema.Type<ProjSchema>,
|
|
178
|
+
E | S.SchemaError,
|
|
179
|
+
R | S.Codec.DecodingServices<ProjSchema>,
|
|
180
|
+
S.Codec.Encoded<ProjSchema>
|
|
181
|
+
>
|
|
102
182
|
}
|
|
103
183
|
|
|
104
184
|
/**
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
185
|
+
* Send the request to the endpoint and return the raw Effect response.
|
|
186
|
+
* Also invalidates query caches using the request namespace by default.
|
|
187
|
+
* Namespace invalidation targets parent namespace keys
|
|
188
|
+
* (for example `$project/$configuration.get` invalidates `$project`).
|
|
189
|
+
* Override invalidation in client options via `queryInvalidation`.
|
|
108
190
|
*/
|
|
109
191
|
export interface MutationExt<
|
|
110
192
|
RT,
|
|
111
193
|
Id extends string,
|
|
112
194
|
A,
|
|
113
195
|
E,
|
|
114
|
-
R
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
196
|
+
R,
|
|
197
|
+
EA = unknown
|
|
198
|
+
> extends MutationExtensions<RT, Id, void, A, E, R> {
|
|
199
|
+
/**
|
|
200
|
+
* Send the request to the endpoint and return the raw Effect response.
|
|
201
|
+
* Also invalidates query caches using the request namespace by default.
|
|
202
|
+
*
|
|
203
|
+
* Pass `options` to attach a `select` Effect that runs after the mutation
|
|
204
|
+
* succeeds (its output is returned to the caller) and/or override the default
|
|
205
|
+
* `queryInvalidation`.
|
|
206
|
+
*/
|
|
207
|
+
<B = A, E2 = never, R2 = never>(
|
|
208
|
+
options?: MutationOptionsBase<A, B, E2, R2>
|
|
209
|
+
): Effect.Effect<B, E | E2, R | R2>
|
|
210
|
+
|
|
211
|
+
project: <ProjSchema extends S.Top>(
|
|
212
|
+
schema: EA extends ProjSchema["Encoded"] ? ProjSchema : never
|
|
213
|
+
) => MutationExt<
|
|
214
|
+
RT,
|
|
215
|
+
Id,
|
|
216
|
+
S.Schema.Type<ProjSchema>,
|
|
217
|
+
E | S.SchemaError,
|
|
218
|
+
R | S.Codec.DecodingServices<ProjSchema>,
|
|
219
|
+
S.Codec.Encoded<ProjSchema>
|
|
220
|
+
>
|
|
121
221
|
}
|
|
122
222
|
|
|
123
223
|
export type MutationWithExtensions<RT, Req> = Req extends
|
|
124
|
-
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer
|
|
125
|
-
? MutationExtWithInput<RT, Id, I, A, E, R
|
|
126
|
-
: Req extends RequestHandler<infer A, infer E, infer R, infer
|
|
224
|
+
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id>
|
|
225
|
+
? MutationExtWithInput<RT, Id, I, A, E, R, S.Codec.Encoded<Request["success"]>>
|
|
226
|
+
: Req extends RequestHandler<infer A, infer E, infer R, infer Request, infer Id>
|
|
227
|
+
? MutationExt<RT, Id, A, E, R, S.Codec.Encoded<Request["success"]>>
|
|
228
|
+
: never
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* The `streamFn` builder for a stream-type request handler, using the stream-specific overloads.
|
|
232
|
+
*/
|
|
233
|
+
export type StreamFnStreamExtension<RT, Req> = Req extends
|
|
234
|
+
RequestStreamHandlerWithInput<infer _I, infer _A, infer _E, infer _R, infer _Request, infer Id, infer _Final>
|
|
235
|
+
? Commander.StreamGen<RT, Id, Id, undefined> & Commander.NonGenStream<RT, Id, Id, undefined>
|
|
236
|
+
: Req extends RequestStreamHandler<infer _A, infer _E, infer _R, infer _Request, infer Id, infer _Final>
|
|
237
|
+
? Commander.StreamGen<RT, Id, Id, undefined> & Commander.NonGenStream<RT, Id, Id, undefined>
|
|
238
|
+
: never
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* `mutate` factory — wraps per-invocation invalidation scaffolding
|
|
242
|
+
* into the stream itself (via `Stream.unwrap`) for use with `streamFn` combinators.
|
|
243
|
+
*/
|
|
244
|
+
export type StreamMutation2WithExtensions<RT, Req> = Req extends
|
|
245
|
+
RequestStreamHandlerWithInput<infer I, infer A, infer E, infer R, infer _Request, infer Id, infer _Final> ?
|
|
246
|
+
& ((input: I) => Stream.Stream<A, E, R>)
|
|
247
|
+
& {
|
|
248
|
+
readonly id: Id
|
|
249
|
+
readonly wrap: Commander.StreamerWrap<RT, Id, Id, undefined, I, A, E, R>
|
|
250
|
+
}
|
|
251
|
+
: Req extends RequestStreamHandler<infer A, infer E, infer R, infer _Request, infer Id, infer _Final> ?
|
|
252
|
+
& Stream.Stream<A, E, R>
|
|
253
|
+
& {
|
|
254
|
+
readonly id: Id
|
|
255
|
+
readonly wrap: Commander.StreamerWrap<RT, Id, Id, undefined, void, A, E, R>
|
|
256
|
+
}
|
|
127
257
|
: never
|
|
128
258
|
|
|
129
259
|
// we don't really care about the RT, as we are in charge of ensuring runtime safety anyway
|
|
@@ -131,30 +261,75 @@ export type MutationWithExtensions<RT, Req> = Req extends
|
|
|
131
261
|
declare const useQuery_: QueryImpl<any>["useQuery"]
|
|
132
262
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
133
263
|
declare const useSuspenseQuery_: QueryImpl<any>["useSuspenseQuery"]
|
|
264
|
+
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
265
|
+
declare const useStreamQuery_: QueryImpl<any>["useStreamQuery"]
|
|
266
|
+
|
|
267
|
+
export interface ProjectResult<RT, I, B, E, R, Request extends Req, Id extends string> {
|
|
268
|
+
request: (i: I) => Effect.Effect<B, E, R>
|
|
269
|
+
query: Exclude<R, RT> extends never ? ReturnType<typeof useQuery_<I, E, B, Request, Id>>
|
|
270
|
+
: MissingDependencies<RT, R> & {}
|
|
271
|
+
suspense: Exclude<R, RT> extends never ? ReturnType<typeof useSuspenseQuery_<I, E, B, Request, Id>>
|
|
272
|
+
: MissingDependencies<RT, R> & {}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export type QueryProjection<RT, HandlerReq> = HandlerReq extends
|
|
276
|
+
RequestHandlerWithInput<infer I, infer _A, infer E, infer R, infer Request, infer Id>
|
|
277
|
+
? Request["type"] extends "query" ? {
|
|
278
|
+
project: <ProjSchema extends S.Top>(
|
|
279
|
+
schema: S.Codec.Encoded<Request["success"]> extends ProjSchema["Encoded"] ? ProjSchema : never
|
|
280
|
+
) => ProjectResult<
|
|
281
|
+
RT,
|
|
282
|
+
I,
|
|
283
|
+
S.Schema.Type<ProjSchema>,
|
|
284
|
+
E | S.SchemaError,
|
|
285
|
+
R | S.Codec.DecodingServices<ProjSchema>,
|
|
286
|
+
Request,
|
|
287
|
+
Id
|
|
288
|
+
>
|
|
289
|
+
}
|
|
290
|
+
: {}
|
|
291
|
+
: HandlerReq extends RequestHandler<infer _A, infer E, infer R, infer Request, infer Id>
|
|
292
|
+
? Request["type"] extends "query" ? {
|
|
293
|
+
project: <ProjSchema extends S.Top>(
|
|
294
|
+
schema: S.Codec.Encoded<Request["success"]> extends ProjSchema["Encoded"] ? ProjSchema : never
|
|
295
|
+
) => ProjectResult<
|
|
296
|
+
RT,
|
|
297
|
+
void,
|
|
298
|
+
S.Schema.Type<ProjSchema>,
|
|
299
|
+
E | S.SchemaError,
|
|
300
|
+
R | S.Codec.DecodingServices<ProjSchema>,
|
|
301
|
+
Request,
|
|
302
|
+
Id
|
|
303
|
+
>
|
|
304
|
+
}
|
|
305
|
+
: {}
|
|
306
|
+
: {}
|
|
134
307
|
|
|
135
308
|
export interface QueriesWithInput<Request extends Req, Id extends string, I, A, E> {
|
|
136
309
|
/**
|
|
137
|
-
*
|
|
310
|
+
* Read helper for query requests.
|
|
311
|
+
* Runs as a tracked Vue Query and returns reactive state.
|
|
312
|
+
* Queries read state and should not be used to mutate it.
|
|
138
313
|
*/
|
|
139
314
|
query: ReturnType<typeof useQuery_<I, E, A, Request, Id>>
|
|
140
315
|
// TODO or suspense as Option?
|
|
141
316
|
/**
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
* So that Suspense and error boundaries can be used.
|
|
317
|
+
* Like `.query`, but returns a Promise for setup-time awaiting.
|
|
318
|
+
* Use this when integrating with Vue Suspense / error boundaries.
|
|
145
319
|
*/
|
|
146
320
|
suspense: ReturnType<typeof useSuspenseQuery_<I, E, A, Request, Id>>
|
|
147
321
|
}
|
|
148
322
|
export interface QueriesWithoutInput<Request extends Req, Id extends string, A, E> {
|
|
149
323
|
/**
|
|
150
|
-
*
|
|
324
|
+
* Read helper for query requests.
|
|
325
|
+
* Runs as a tracked Vue Query and returns reactive state.
|
|
326
|
+
* Queries read state and should not be used to mutate it.
|
|
151
327
|
*/
|
|
152
328
|
query: ReturnType<typeof useQuery_<E, A, Request, Id>>
|
|
153
329
|
// TODO or suspense as Option?
|
|
154
330
|
/**
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
* So that Suspense and error boundaries can be used.
|
|
331
|
+
* Like `.query`, but returns a Promise for setup-time awaiting.
|
|
332
|
+
* Use this when integrating with Vue Suspense / error boundaries.
|
|
158
333
|
*/
|
|
159
334
|
suspense: ReturnType<typeof useSuspenseQuery_<E, A, Request, Id>>
|
|
160
335
|
}
|
|
@@ -166,184 +341,60 @@ export type MissingDependencies<RT, R> = {
|
|
|
166
341
|
|
|
167
342
|
export type Queries<RT, Req> = Req extends
|
|
168
343
|
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id>
|
|
169
|
-
? Exclude<R, RT> extends never ? QueriesWithInput<Request, Id, I, A, E>
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
344
|
+
? Request["type"] extends "query" ? Exclude<R, RT> extends never ? QueriesWithInput<Request, Id, I, A, E>
|
|
345
|
+
: {
|
|
346
|
+
query: MissingDependencies<RT, R> & {}
|
|
347
|
+
suspense: MissingDependencies<RT, R> & {}
|
|
348
|
+
}
|
|
349
|
+
: never
|
|
174
350
|
: Req extends RequestHandler<infer A, infer E, infer R, infer Request, infer Id>
|
|
175
|
-
? Exclude<R, RT> extends never ? QueriesWithoutInput<Request, Id, A, E>
|
|
176
|
-
|
|
351
|
+
? Request["type"] extends "query" ? Exclude<R, RT> extends never ? QueriesWithoutInput<Request, Id, A, E>
|
|
352
|
+
: { query: MissingDependencies<RT, R> & {}; suspense: MissingDependencies<RT, R> & {} }
|
|
353
|
+
: never
|
|
177
354
|
: never
|
|
178
355
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
export type ResponseErrors = S.SchemaError | SupportedErrors | SuppressErrors | OperationFailure
|
|
187
|
-
|
|
188
|
-
export interface Opts<
|
|
189
|
-
A,
|
|
190
|
-
E,
|
|
191
|
-
R,
|
|
192
|
-
I = void,
|
|
193
|
-
A2 = A,
|
|
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>
|
|
356
|
+
export interface StreamQueriesWithInput<Request extends Req, Id extends string, I, A, E> {
|
|
357
|
+
/**
|
|
358
|
+
* Stream helper for stream requests.
|
|
359
|
+
* Runs as a tracked Vue Query and returns reactive state with accumulated chunks.
|
|
360
|
+
* Data is an array of all chunks received so far.
|
|
361
|
+
*/
|
|
362
|
+
streamQuery: ReturnType<typeof useStreamQuery_<I, E, A, Request, Id>>
|
|
245
363
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
364
|
+
export interface StreamQueriesWithoutInput<Request extends Req, Id extends string, A, E> {
|
|
365
|
+
/**
|
|
366
|
+
* Stream helper for stream requests.
|
|
367
|
+
* Runs as a tracked Vue Query and returns reactive state with accumulated chunks.
|
|
368
|
+
* Data is an array of all chunks received so far.
|
|
369
|
+
*/
|
|
370
|
+
streamQuery: ReturnType<typeof useStreamQuery_<E, A, Request, Id>>
|
|
249
371
|
}
|
|
250
372
|
|
|
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>
|
|
286
|
-
}
|
|
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
|
-
}
|
|
299
|
-
|
|
300
|
-
const fail = Cause.findErrorOption(cause)
|
|
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
|
-
}
|
|
373
|
+
export type StreamQueries<RT, HandlerReq> = HandlerReq extends
|
|
374
|
+
RequestStreamHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id, infer _Final>
|
|
375
|
+
? Exclude<R, RT> extends never ? StreamQueriesWithInput<Request, Id, I, A, E>
|
|
376
|
+
: { streamQuery: MissingDependencies<RT, R> & {} }
|
|
377
|
+
: HandlerReq extends RequestStreamHandler<infer A, infer E, infer R, infer Request, infer Id, infer _Final>
|
|
378
|
+
? Exclude<R, RT> extends never ? StreamQueriesWithoutInput<Request, Id, A, E>
|
|
379
|
+
: { streamQuery: MissingDependencies<RT, R> & {} }
|
|
380
|
+
: never
|
|
311
381
|
|
|
312
|
-
|
|
313
|
-
action,
|
|
314
|
-
message: `Unexpected Error trying to ${action}`
|
|
315
|
-
}
|
|
316
|
-
yield* reportRuntimeError(cause, extra)
|
|
382
|
+
const _useMutation = makeMutation()
|
|
317
383
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
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
|
-
)
|
|
384
|
+
const wrapWithSpan = (self: { id: string; handler: any }, mut: any) => {
|
|
385
|
+
const span = (eff: Effect.Effect<any, any, any>) =>
|
|
386
|
+
Effect.withSpan(`mutation ${self.id}`, {}, { captureStackTrace: false })(eff)
|
|
387
|
+
return Effect.isEffect(self.handler)
|
|
388
|
+
? (options?: MutationOptionsBase) => span(mut(options))
|
|
389
|
+
: (input: any, options?: MutationOptionsBase) => span(mut(input, options))
|
|
337
390
|
}
|
|
338
391
|
|
|
339
|
-
const _useMutation = makeMutation()
|
|
340
|
-
|
|
341
392
|
/**
|
|
342
393
|
* Pass an Effect or a function that returns an Effect, e.g from a client action
|
|
343
394
|
* Executes query cache invalidation based on default rules or provided option.
|
|
344
395
|
* adds a span with the mutation id
|
|
345
396
|
*/
|
|
346
|
-
export const useMutation: typeof _useMutation = <
|
|
397
|
+
export const useMutation: typeof _useMutation = (<
|
|
347
398
|
I,
|
|
348
399
|
E,
|
|
349
400
|
A,
|
|
@@ -351,16 +402,12 @@ export const useMutation: typeof _useMutation = <
|
|
|
351
402
|
Request extends Req,
|
|
352
403
|
Name extends string
|
|
353
404
|
>(
|
|
354
|
-
self: RequestHandlerWithInput<I, A, E, R, Request, Name> | RequestHandler<A, E, R, Request, Name
|
|
355
|
-
options?: MutationOptionsBase
|
|
405
|
+
self: RequestHandlerWithInput<I, A, E, R, Request, Name> | RequestHandler<A, E, R, Request, Name>
|
|
356
406
|
) =>
|
|
357
407
|
Object.assign(
|
|
358
|
-
|
|
359
|
-
_useMutation(self as any, options),
|
|
360
|
-
Effect.withSpan(`mutation ${self.id}`, {}, { captureStackTrace: false })
|
|
361
|
-
) as any,
|
|
408
|
+
wrapWithSpan(self, _useMutation(self as any)),
|
|
362
409
|
{ id: self.id }
|
|
363
|
-
)
|
|
410
|
+
)) as any
|
|
364
411
|
|
|
365
412
|
/**
|
|
366
413
|
* Pass an Effect or a function that returns an Effect, e.g from a client action
|
|
@@ -369,7 +416,7 @@ export const useMutation: typeof _useMutation = <
|
|
|
369
416
|
*/
|
|
370
417
|
export const useMutationInt = (): typeof _useMutation => {
|
|
371
418
|
const _useMutation = useMakeMutation()
|
|
372
|
-
return <
|
|
419
|
+
return (<
|
|
373
420
|
I,
|
|
374
421
|
E,
|
|
375
422
|
A,
|
|
@@ -377,715 +424,20 @@ export const useMutationInt = (): typeof _useMutation => {
|
|
|
377
424
|
Request extends Req,
|
|
378
425
|
Name extends string
|
|
379
426
|
>(
|
|
380
|
-
self: RequestHandlerWithInput<I, A, E, R, Request, Name> | RequestHandler<A, E, R, Request, Name
|
|
381
|
-
options?: MutationOptionsBase
|
|
427
|
+
self: RequestHandlerWithInput<I, A, E, R, Request, Name> | RequestHandler<A, E, R, Request, Name>
|
|
382
428
|
) =>
|
|
383
429
|
Object.assign(
|
|
384
|
-
|
|
385
|
-
_useMutation(self as any, options),
|
|
386
|
-
Effect.withSpan(`mutation ${self.id}`, {}, { captureStackTrace: false })
|
|
387
|
-
) as any,
|
|
430
|
+
wrapWithSpan(self, _useMutation(self as any)),
|
|
388
431
|
{ id: self.id }
|
|
389
|
-
)
|
|
432
|
+
)) as any
|
|
390
433
|
}
|
|
391
434
|
|
|
392
|
-
export
|
|
393
|
-
constructor(
|
|
394
|
-
private readonly getRuntime: () => ServiceMap.ServiceMap<RT>,
|
|
395
|
-
private readonly toast: Toast,
|
|
396
|
-
private readonly intl: I18n
|
|
397
|
-
) {}
|
|
398
|
-
|
|
399
|
-
/**
|
|
400
|
-
* Effect results are converted to Exit, so errors are ignored by default.
|
|
401
|
-
* you should use the result ref to render errors!
|
|
402
|
-
* @deprecated use `Command.fn` and friends instead
|
|
403
|
-
*/
|
|
404
|
-
readonly useSafeMutation: {
|
|
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)
|
|
672
|
-
|
|
673
|
-
return tuple(
|
|
674
|
-
a,
|
|
675
|
-
handleRequestWithToast(b as any, self.id, action, options)
|
|
676
|
-
)
|
|
677
|
-
}
|
|
678
|
-
//
|
|
679
|
-
|
|
680
|
-
/**
|
|
681
|
-
* Pass a function that returns an Effect, e.g from a client action, give it a name.
|
|
682
|
-
* Returns a tuple with state ref and execution function which reports success and errors as Toast.
|
|
683
|
-
*
|
|
684
|
-
* @deprecated use `Command.fn` and friends instead
|
|
685
|
-
*/
|
|
686
|
-
readonly useAndHandleMutation: {
|
|
687
|
-
/**
|
|
688
|
-
* Pass a function that returns an Effect, e.g from a client action, give it a name.
|
|
689
|
-
* Returns a tuple with state ref and execution function which reports success and errors as Toast.
|
|
690
|
-
*
|
|
691
|
-
* @deprecated use `Command.fn` and friends instead
|
|
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
|
-
)
|
|
751
|
-
}
|
|
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
|
-
/**
|
|
871
|
-
* The same as @see useAndHandleMutation, but does not act on success, error or defect by default.
|
|
872
|
-
* Actions for success, error and defect can be provided in the Options.
|
|
873
|
-
* @deprecated use `Command.fn` and friends instead
|
|
874
|
-
*/
|
|
875
|
-
readonly useAndHandleMutationCustom: {
|
|
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)
|
|
941
|
-
|
|
942
|
-
type MH = NonNullable<NonNullable<typeof options>["mapHandler"]>
|
|
943
|
-
const mh = options?.mapHandler ?? identity as MH
|
|
944
|
-
|
|
945
|
-
const [a, b] = asResult(
|
|
946
|
-
mapHandler(
|
|
947
|
-
mapHandler(unsafe as any, mh),
|
|
948
|
-
Effect.tapCauseIf(Cause.hasDies, (cause) => reportRuntimeError(cause))
|
|
949
|
-
) as any
|
|
950
|
-
)
|
|
951
|
-
|
|
952
|
-
return tuple(
|
|
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
|
-
}
|
|
962
|
-
|
|
963
|
-
/**
|
|
964
|
-
* Effect results are converted to Exit, so errors are ignored by default.
|
|
965
|
-
* you should use the result ref to render errors!
|
|
966
|
-
* @deprecated use `Command.fn` and friends instead
|
|
967
|
-
*/
|
|
968
|
-
readonly useSafeMutationWithState: {
|
|
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)
|
|
998
|
-
|
|
999
|
-
return tuple(
|
|
1000
|
-
computed(() => mutationResultToVue(a.value)),
|
|
1001
|
-
b
|
|
1002
|
-
) as any
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
|
-
/** @deprecated use OmegaForm */
|
|
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
|
-
)
|
|
1050
|
-
|
|
1051
|
-
const submitFromState = Effect.gen(function*() {
|
|
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"]>
|
|
435
|
+
export type ClientFrom<M extends RequestsAny> = RequestHandlers<never, never, M, ExtractModuleName<M>>
|
|
1085
436
|
|
|
1086
437
|
export class QueryImpl<R> {
|
|
1087
|
-
constructor(readonly getRuntime: () =>
|
|
438
|
+
constructor(readonly getRuntime: () => Context.Context<R>) {
|
|
1088
439
|
this.useQuery = makeQuery(this.getRuntime)
|
|
440
|
+
this.useStreamQuery = makeStreamQuery(this.getRuntime)
|
|
1089
441
|
}
|
|
1090
442
|
/**
|
|
1091
443
|
* Effect results are passed to the caller, including errors.
|
|
@@ -1093,6 +445,12 @@ export class QueryImpl<R> {
|
|
|
1093
445
|
*/
|
|
1094
446
|
readonly useQuery: ReturnType<typeof makeQuery<R>>
|
|
1095
447
|
|
|
448
|
+
/**
|
|
449
|
+
* Stream results are accumulated as an array of chunks and returned as reactive state.
|
|
450
|
+
* @deprecated use client helpers instead (.streamQuery())
|
|
451
|
+
*/
|
|
452
|
+
readonly useStreamQuery: ReturnType<typeof makeStreamQuery<R>>
|
|
453
|
+
|
|
1096
454
|
/**
|
|
1097
455
|
* The difference with useQuery is that this function will return a Promise you can await in the Setup,
|
|
1098
456
|
* which ensures that either there always is a latest value, or an error occurs on load.
|
|
@@ -1163,7 +521,7 @@ export class QueryImpl<R> {
|
|
|
1163
521
|
} = <Arg, E, A, Request extends Req, Name extends string>(
|
|
1164
522
|
self: RequestHandlerWithInput<Arg, A, E, R, Request, Name> | RequestHandler<A, E, R, Request, Name>
|
|
1165
523
|
) => {
|
|
1166
|
-
const runPromise =
|
|
524
|
+
const runPromise = makeRunPromise(this.getRuntime())
|
|
1167
525
|
const q = this.useQuery(self as any) as any
|
|
1168
526
|
return (argOrOptions?: any, options?: any) => {
|
|
1169
527
|
const [resultRef, latestRef, fetch, uqrt] = q(argOrOptions, { ...options, suspense: true } // experimental_prefetchInRender: true }
|
|
@@ -1214,10 +572,64 @@ export class QueryImpl<R> {
|
|
|
1214
572
|
}
|
|
1215
573
|
|
|
1216
574
|
// 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.
|
|
575
|
+
const managedRuntimeRt = <A, E>(mrt: ManagedRuntime.ManagedRuntime<A, E>) => mrt.runSync(Effect.context<A>())
|
|
1218
576
|
|
|
1219
577
|
type Base = I18n | Toast
|
|
1220
|
-
type Mix = ApiClientFactory | Commander |
|
|
578
|
+
type Mix = ApiClientFactory | Commander | Base
|
|
579
|
+
|
|
580
|
+
type InvalidationResources = Record<string, Record<string, unknown>>
|
|
581
|
+
type UnionToIntersection<U> = (U extends unknown ? (arg: U) => void : never) extends ((arg: infer I) => void) ? I
|
|
582
|
+
: never
|
|
583
|
+
|
|
584
|
+
type CommandInvalidationResources<Req> = Req extends {
|
|
585
|
+
readonly type: "command"
|
|
586
|
+
readonly "~invalidationResources"?: infer Resources
|
|
587
|
+
} ? NonNullable<Resources> extends InvalidationResources ? NonNullable<Resources> : never
|
|
588
|
+
: Req extends {
|
|
589
|
+
readonly type: "command"
|
|
590
|
+
readonly config?: infer Config
|
|
591
|
+
} ? Config extends {
|
|
592
|
+
readonly invalidationResources?: infer LegacyResources
|
|
593
|
+
} ? NonNullable<LegacyResources> extends InvalidationResources ? NonNullable<LegacyResources> : never
|
|
594
|
+
: Config extends {
|
|
595
|
+
readonly invalidatesQueries?: InvalidationCallback<infer LegacyResources, any, any, any>
|
|
596
|
+
} ? NonNullable<LegacyResources> extends InvalidationResources ? NonNullable<LegacyResources> : never
|
|
597
|
+
: never
|
|
598
|
+
: never
|
|
599
|
+
|
|
600
|
+
type InvalidationResourcesForUnion<M extends RequestsAny> = {
|
|
601
|
+
[K in keyof M]: CommandInvalidationResources<M[K]>
|
|
602
|
+
}[keyof M]
|
|
603
|
+
|
|
604
|
+
type InvalidationResourcesFor<M extends RequestsAny> = [InvalidationResourcesForUnion<M>] extends [never] ? never
|
|
605
|
+
: UnionToIntersection<InvalidationResourcesForUnion<M>> extends infer R ? R extends InvalidationResources ? R
|
|
606
|
+
: never
|
|
607
|
+
: never
|
|
608
|
+
|
|
609
|
+
type QueryInvalidationFactory<M extends RequestsAny> = (client: ClientFrom<M>) => QueryInvalidation<M>
|
|
610
|
+
|
|
611
|
+
type StrictResourcesArg<Shape, Actual extends Shape = Shape> =
|
|
612
|
+
& Actual
|
|
613
|
+
& Record<Exclude<keyof Actual, keyof Shape>, never>
|
|
614
|
+
|
|
615
|
+
type ClientForArgs<
|
|
616
|
+
M extends RequestsAny,
|
|
617
|
+
Resources extends InvalidationResourcesFor<M> = InvalidationResourcesFor<M>
|
|
618
|
+
> = [InvalidationResourcesFor<M>] extends [never] ? [
|
|
619
|
+
queryInvalidation?: QueryInvalidationFactory<M>,
|
|
620
|
+
invalidationResources?: StrictResourcesArg<
|
|
621
|
+
InvalidationResourcesFor<M>,
|
|
622
|
+
Resources
|
|
623
|
+
>
|
|
624
|
+
]
|
|
625
|
+
: [
|
|
626
|
+
queryInvalidation: QueryInvalidationFactory<M> | undefined,
|
|
627
|
+
invalidationResources: StrictResourcesArg<
|
|
628
|
+
InvalidationResourcesFor<M>,
|
|
629
|
+
Resources
|
|
630
|
+
>
|
|
631
|
+
]
|
|
632
|
+
|
|
1221
633
|
export const makeClient = <RT_, RTHooks>(
|
|
1222
634
|
// global, but only accessible after startup has completed
|
|
1223
635
|
getBaseMrt: () => ManagedRuntime.ManagedRuntime<RT_ | Mix, never>,
|
|
@@ -1225,85 +637,117 @@ export const makeClient = <RT_, RTHooks>(
|
|
|
1225
637
|
rtHooks: Layer.Layer<RTHooks, never, Mix>
|
|
1226
638
|
) => {
|
|
1227
639
|
type RT = RT_ | Mix
|
|
1228
|
-
const getRt = Effect.services<RT>()
|
|
1229
640
|
const getBaseRt = () => managedRuntimeRt(getBaseMrt())
|
|
1230
641
|
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
642
|
let cmd: Effect.Success<typeof makeCommand>
|
|
1237
643
|
const useCommand = () => cmd ??= getBaseMrt().runSync(makeCommand)
|
|
1238
|
-
let mut: Effect.Success<typeof makeMutation>
|
|
1239
|
-
const getMutation = () => mut ??= getBaseMrt().runSync(makeMutation)
|
|
1240
644
|
|
|
1241
645
|
let m: ReturnType<typeof useMutationInt>
|
|
1242
646
|
const useMutation = () => m ??= useMutationInt()
|
|
1243
647
|
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
"useAndHandleMutation",
|
|
1247
|
-
"useAndHandleMutationResult",
|
|
1248
|
-
"useAndHandleMutationSilently",
|
|
1249
|
-
"useAndHandleMutationCustom",
|
|
1250
|
-
"makeUseAndHandleMutation",
|
|
1251
|
-
"useHandleRequestWithToast",
|
|
1252
|
-
"buildFormFromSchema",
|
|
1253
|
-
"useSafeMutation"
|
|
1254
|
-
] as const satisfies readonly (keyof ReturnType<typeof getMutation>)[]
|
|
1255
|
-
type mut = Pick<LegacyMutationImpl<RT>, typeof keys[number]>
|
|
1256
|
-
|
|
1257
|
-
const mutations = keys.reduce(
|
|
1258
|
-
(prev, cur) => {
|
|
1259
|
-
;(prev as any)[cur] = ((...args: [any]) => {
|
|
1260
|
-
return (getMutation() as any)[cur](...args)
|
|
1261
|
-
}) as any
|
|
1262
|
-
return prev
|
|
1263
|
-
},
|
|
1264
|
-
{} as Pick<LegacyMutationImpl<RT>, typeof keys[number]>
|
|
1265
|
-
)
|
|
648
|
+
let sm2: ReturnType<typeof makeStreamMutation2>
|
|
649
|
+
const useStreamMutation2 = () => sm2 ??= makeStreamMutation2()
|
|
1266
650
|
|
|
1267
651
|
const query = new QueryImpl(getBaseRt)
|
|
1268
652
|
const useQuery = query.useQuery
|
|
1269
653
|
const useSuspenseQuery = query.useSuspenseQuery
|
|
654
|
+
const useStreamQuery = query.useStreamQuery
|
|
655
|
+
|
|
656
|
+
const mergeInvalidation = (
|
|
657
|
+
a?: MutationOptionsBase["queryInvalidation"],
|
|
658
|
+
b?: MutationOptionsBase["queryInvalidation"]
|
|
659
|
+
): MutationOptionsBase["queryInvalidation"] | undefined => {
|
|
660
|
+
if (!a && !b) {
|
|
661
|
+
return undefined
|
|
662
|
+
}
|
|
663
|
+
return (defaultKey, name, input, output) => [
|
|
664
|
+
...(a?.(defaultKey, name, input, output) ?? []),
|
|
665
|
+
...(b?.(defaultKey, name, input, output) ?? [])
|
|
666
|
+
]
|
|
667
|
+
}
|
|
1270
668
|
|
|
1271
|
-
const
|
|
669
|
+
const withDefaultInvalidation = (
|
|
670
|
+
mut: any,
|
|
671
|
+
isWithInput: boolean,
|
|
672
|
+
defaultInvalidation?: MutationOptionsBase["queryInvalidation"]
|
|
673
|
+
) => {
|
|
674
|
+
if (!defaultInvalidation) return mut
|
|
675
|
+
const apply = (callerOpts?: MutationOptionsBase) => ({
|
|
676
|
+
...callerOpts,
|
|
677
|
+
queryInvalidation: callerOpts?.queryInvalidation
|
|
678
|
+
? mergeInvalidation(defaultInvalidation, callerOpts.queryInvalidation)
|
|
679
|
+
: defaultInvalidation
|
|
680
|
+
})
|
|
681
|
+
return isWithInput
|
|
682
|
+
? (input: any, callerOpts?: MutationOptionsBase) => mut(input, apply(callerOpts))
|
|
683
|
+
: (callerOpts?: MutationOptionsBase) => mut(apply(callerOpts))
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
const makeQueryResources = <Resources extends InvalidationResources>(resources: Resources | undefined) => {
|
|
687
|
+
if (!resources) {
|
|
688
|
+
return {} as Record<string, Record<string, unknown>>
|
|
689
|
+
}
|
|
690
|
+
return resources as Record<string, Record<string, unknown>>
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
const mapQuery = <M extends RequestsAny>(
|
|
1272
694
|
client: ClientFrom<M>
|
|
1273
695
|
) => {
|
|
1274
696
|
const queries = Struct.keys(client).reduce(
|
|
1275
697
|
(acc, key) => {
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
698
|
+
const requestType = client[key].Request.type
|
|
699
|
+
if (requestType === "query") {
|
|
700
|
+
;(acc as any)[camelCase(key) + "Query"] = Object.assign(useQuery(client[key] as any), {
|
|
701
|
+
id: client[key].id
|
|
702
|
+
})
|
|
703
|
+
;(acc as any)[camelCase(key) + "SuspenseQuery"] = Object.assign(useSuspenseQuery(client[key] as any), {
|
|
704
|
+
id: client[key].id
|
|
705
|
+
})
|
|
706
|
+
} else if (requestType === "stream") {
|
|
707
|
+
;(acc as any)[camelCase(key) + "StreamQuery"] = Object.assign(useStreamQuery(client[key] as any), {
|
|
708
|
+
id: client[key].id
|
|
709
|
+
})
|
|
710
|
+
}
|
|
1282
711
|
return acc
|
|
1283
712
|
},
|
|
1284
713
|
{} as
|
|
1285
714
|
& {
|
|
1286
715
|
// apparently can't get JSDoc in here..
|
|
1287
|
-
[
|
|
716
|
+
[
|
|
717
|
+
Key in keyof typeof client as QueryHandler<typeof client[Key]> extends never ? never
|
|
718
|
+
: `${ToCamel<string & Key>}Query`
|
|
719
|
+
]: Queries<RT, QueryHandler<typeof client[Key]>>["query"]
|
|
1288
720
|
}
|
|
1289
721
|
// todo: or suspense as an Option?
|
|
1290
722
|
& {
|
|
1291
723
|
// apparently can't get JSDoc in here..
|
|
1292
|
-
[
|
|
724
|
+
[
|
|
725
|
+
Key in keyof typeof client as QueryHandler<typeof client[Key]> extends never ? never
|
|
726
|
+
: `${ToCamel<string & Key>}SuspenseQuery`
|
|
727
|
+
]: Queries<
|
|
1293
728
|
RT,
|
|
1294
|
-
typeof client[Key]
|
|
729
|
+
QueryHandler<typeof client[Key]>
|
|
1295
730
|
>["suspense"]
|
|
1296
731
|
}
|
|
732
|
+
& {
|
|
733
|
+
[
|
|
734
|
+
Key in keyof typeof client as StreamHandler<typeof client[Key]> extends never ? never
|
|
735
|
+
: `${ToCamel<string & Key>}StreamQuery`
|
|
736
|
+
]: StreamQueries<RT, StreamHandler<typeof client[Key]>>["streamQuery"]
|
|
737
|
+
}
|
|
1297
738
|
)
|
|
1298
739
|
return queries
|
|
1299
740
|
}
|
|
1300
741
|
|
|
1301
|
-
const mapRequest = <M extends
|
|
742
|
+
const mapRequest = <M extends RequestsAny>(
|
|
1302
743
|
client: ClientFrom<M>
|
|
1303
744
|
) => {
|
|
1304
745
|
const Command = useCommand()
|
|
1305
746
|
const mutations = Struct.keys(client).reduce(
|
|
1306
747
|
(acc, key) => {
|
|
748
|
+
if (client[key].Request.type !== "command") {
|
|
749
|
+
return acc
|
|
750
|
+
}
|
|
1307
751
|
const mut = client[key].handler
|
|
1308
752
|
const fn = Command.fn(client[key].id)
|
|
1309
753
|
const wrap = Command.wrap({ mutate: Effect.isEffect(mut) ? () => mut : mut, id: client[key].id })
|
|
@@ -1315,36 +759,68 @@ export const makeClient = <RT_, RTHooks>(
|
|
|
1315
759
|
return acc
|
|
1316
760
|
},
|
|
1317
761
|
{} as {
|
|
1318
|
-
[
|
|
762
|
+
[
|
|
763
|
+
Key in keyof typeof client as CommandHandler<typeof client[Key]> extends never ? never
|
|
764
|
+
: `${ToCamel<string & Key>}Request`
|
|
765
|
+
]: CommandRequestWithExtensions<
|
|
1319
766
|
RT | RTHooks,
|
|
1320
|
-
typeof client[Key]
|
|
767
|
+
CommandHandler<typeof client[Key]>
|
|
1321
768
|
>
|
|
1322
769
|
}
|
|
1323
770
|
)
|
|
1324
771
|
return mutations
|
|
1325
772
|
}
|
|
1326
773
|
|
|
1327
|
-
const mapMutation = <M extends
|
|
1328
|
-
client: ClientFrom<M
|
|
774
|
+
const mapMutation = <M extends RequestsAny>(
|
|
775
|
+
client: ClientFrom<M>,
|
|
776
|
+
queryInvalidation?: (client: ClientFrom<M>) => QueryInvalidation<M>,
|
|
777
|
+
invalidationResources?: InvalidationResourcesFor<M>
|
|
1329
778
|
) => {
|
|
1330
779
|
const Command = useCommand()
|
|
1331
780
|
const mutation = useMutation()
|
|
781
|
+
const invalidation = queryInvalidation?.(client)
|
|
782
|
+
const queryResources = makeQueryResources(invalidationResources)
|
|
1332
783
|
const mutations = Struct.keys(client).reduce(
|
|
1333
784
|
(acc, key) => {
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
785
|
+
if (client[key].Request.type !== "command") {
|
|
786
|
+
return acc
|
|
787
|
+
}
|
|
788
|
+
const fromRequestConfig = client[key].Request.config?.["invalidatesQueries"] as
|
|
789
|
+
| InvalidationCallback<InvalidationResourcesFor<M>>
|
|
790
|
+
| undefined
|
|
791
|
+
const fromRequest = fromRequestConfig
|
|
792
|
+
? ((defaultKey: string[], _name: string, input?: unknown, output?: unknown) =>
|
|
793
|
+
fromRequestConfig(defaultKey, queryResources as never, input as never, output as never).map((entry) => ({
|
|
794
|
+
filters: entry.filters,
|
|
795
|
+
options: entry.options
|
|
796
|
+
})))
|
|
797
|
+
: undefined
|
|
798
|
+
const mergedInvalidation = mergeInvalidation(fromRequest, invalidation?.[key])
|
|
799
|
+
const makeProjectedMutation = (handler: any): any => {
|
|
800
|
+
const isWithInput = !Effect.isEffect(handler.handler)
|
|
801
|
+
const mut: any = withDefaultInvalidation(mutation(handler), isWithInput, mergedInvalidation)
|
|
802
|
+
const wrap = Command.wrap({ mutate: mut, id: client[key].id })
|
|
803
|
+
return Object.assign(mut, {
|
|
804
|
+
wrap,
|
|
805
|
+
project: (projectionSchema: any) => {
|
|
806
|
+
const projected = {
|
|
807
|
+
...handler,
|
|
808
|
+
handler: projectHandler(handler.handler, client[key].Request.success, projectionSchema)
|
|
809
|
+
}
|
|
810
|
+
return makeProjectedMutation(projected)
|
|
811
|
+
}
|
|
812
|
+
})
|
|
813
|
+
}
|
|
814
|
+
;(acc as any)[camelCase(key) + "Mutation"] = makeProjectedMutation(client[key] as any)
|
|
1342
815
|
return acc
|
|
1343
816
|
},
|
|
1344
817
|
{} as {
|
|
1345
|
-
[
|
|
818
|
+
[
|
|
819
|
+
Key in keyof typeof client as CommandHandler<typeof client[Key]> extends never ? never
|
|
820
|
+
: `${ToCamel<string & Key>}Mutation`
|
|
821
|
+
]: MutationWithExtensions<
|
|
1346
822
|
RT | RTHooks,
|
|
1347
|
-
typeof client[Key]
|
|
823
|
+
CommandHandler<typeof client[Key]>
|
|
1348
824
|
>
|
|
1349
825
|
}
|
|
1350
826
|
)
|
|
@@ -1353,8 +829,9 @@ export const makeClient = <RT_, RTHooks>(
|
|
|
1353
829
|
|
|
1354
830
|
// make available .query, .suspense and .mutate for each operation
|
|
1355
831
|
// and a .helpers with all mutations and queries
|
|
1356
|
-
const mapClient = <M extends
|
|
1357
|
-
queryInvalidation?: (client: ClientFrom<M>) => QueryInvalidation<M
|
|
832
|
+
const mapClient = <M extends RequestsAny>(
|
|
833
|
+
queryInvalidation?: (client: ClientFrom<M>) => QueryInvalidation<M>,
|
|
834
|
+
invalidationResources?: InvalidationResourcesFor<M>
|
|
1358
835
|
) =>
|
|
1359
836
|
(
|
|
1360
837
|
client: ClientFrom<M>
|
|
@@ -1362,71 +839,176 @@ export const makeClient = <RT_, RTHooks>(
|
|
|
1362
839
|
const Command = useCommand()
|
|
1363
840
|
const mutation = useMutation()
|
|
1364
841
|
const invalidation = queryInvalidation?.(client)
|
|
842
|
+
const queryResources = makeQueryResources(invalidationResources)
|
|
1365
843
|
const extended = Struct.keys(client).reduce(
|
|
1366
844
|
(acc, key) => {
|
|
845
|
+
const requestType = client[key].Request.type
|
|
1367
846
|
const fn = Command.fn(client[key].id)
|
|
1368
|
-
const mutate = extendM(
|
|
1369
|
-
mutation(
|
|
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
847
|
const h_ = client[key].handler
|
|
1385
|
-
const
|
|
848
|
+
const wrapInput = Effect.isEffect(h_)
|
|
1386
849
|
? () => h_
|
|
1387
850
|
: (...args: [any]) => h_(...args)
|
|
851
|
+
const request = Effect.isEffect(h_) ? h_ : wrapInput
|
|
1388
852
|
;(acc as any)[key] = Object.assign(
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
853
|
+
requestType === "query"
|
|
854
|
+
? {
|
|
855
|
+
...client[key],
|
|
856
|
+
request,
|
|
857
|
+
query: useQuery(client[key] as any),
|
|
858
|
+
suspense: useSuspenseQuery(client[key] as any),
|
|
859
|
+
project: (projectionSchema: any) => {
|
|
860
|
+
const successSchema = client[key].Request.success
|
|
861
|
+
const projectionHash = projectionSchemaHash(projectionSchema)
|
|
862
|
+
const projected = projectHandler(h_ as any, successSchema, projectionSchema)
|
|
863
|
+
const fakeHandler = {
|
|
864
|
+
handler: projected,
|
|
865
|
+
id: client[key].id,
|
|
866
|
+
Request: client[key].Request,
|
|
867
|
+
options: client[key].options,
|
|
868
|
+
queryKeyProjectionHash: projectionHash
|
|
869
|
+
}
|
|
870
|
+
return {
|
|
871
|
+
request: projected,
|
|
872
|
+
query: useQuery(fakeHandler as any),
|
|
873
|
+
suspense: useSuspenseQuery(fakeHandler as any)
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
: requestType === "stream"
|
|
878
|
+
? (() => {
|
|
879
|
+
const fromRequestConfig = client[key].Request.config?.["invalidatesQueries"] as
|
|
880
|
+
| InvalidationCallback<InvalidationResourcesFor<M>>
|
|
881
|
+
| undefined
|
|
882
|
+
const fromRequest = fromRequestConfig
|
|
883
|
+
? ((defaultKey: string[], _name: string, input?: unknown, output?: unknown) =>
|
|
884
|
+
fromRequestConfig(defaultKey, queryResources as never, input as never, output as never).map((
|
|
885
|
+
entry
|
|
886
|
+
) => ({
|
|
887
|
+
filters: entry.filters,
|
|
888
|
+
options: entry.options
|
|
889
|
+
})))
|
|
890
|
+
: undefined
|
|
891
|
+
const mergedInvalidation = mergeInvalidation(fromRequest, invalidation?.[key])
|
|
892
|
+
return {
|
|
893
|
+
...client[key],
|
|
894
|
+
request: h_,
|
|
895
|
+
streamQuery: useStreamQuery(client[key] as any),
|
|
896
|
+
streamFn: useCommand().streamFn(client[key].id as any) as any,
|
|
897
|
+
mutate: (() => {
|
|
898
|
+
const sm2Act = useStreamMutation2()(client[key] as any, mergedInvalidation)
|
|
899
|
+
const originalHandler = (client[key] as any).handler
|
|
900
|
+
const sm2Handler = Stream.isStream(originalHandler)
|
|
901
|
+
? (_input: any, _ctx: any) => sm2Act
|
|
902
|
+
: (input: any, _ctx: any) => (sm2Act as (i: any) => any)(input)
|
|
903
|
+
return Object.assign(sm2Act, {
|
|
904
|
+
id: client[key].id,
|
|
905
|
+
wrap: useCommand().streamWrap(sm2Handler, client[key].id as any)
|
|
906
|
+
})
|
|
907
|
+
})()
|
|
908
|
+
}
|
|
909
|
+
})()
|
|
910
|
+
: {
|
|
911
|
+
mutate: ((handler: any) => {
|
|
912
|
+
const fromRequestConfig = client[key].Request.config?.["invalidatesQueries"] as
|
|
913
|
+
| InvalidationCallback<InvalidationResourcesFor<M>>
|
|
914
|
+
| undefined
|
|
915
|
+
const fromRequest = fromRequestConfig
|
|
916
|
+
? ((defaultKey: string[], _name: string, input?: unknown, output?: unknown) =>
|
|
917
|
+
fromRequestConfig(defaultKey, queryResources as never, input as never, output as never).map((
|
|
918
|
+
entry
|
|
919
|
+
) => ({
|
|
920
|
+
filters: entry.filters,
|
|
921
|
+
options: entry.options
|
|
922
|
+
})))
|
|
923
|
+
: undefined
|
|
924
|
+
const mergedInvalidation = mergeInvalidation(fromRequest, invalidation?.[key])
|
|
925
|
+
const makeProjectedMutation = (h: any): any => {
|
|
926
|
+
const isWithInput = !Effect.isEffect(h.handler)
|
|
927
|
+
const mutate = withDefaultInvalidation(mutation(h), isWithInput, mergedInvalidation)
|
|
928
|
+
return Object.assign(
|
|
929
|
+
mutate,
|
|
930
|
+
{
|
|
931
|
+
wrap: Command.wrap({
|
|
932
|
+
mutate,
|
|
933
|
+
id: client[key].id
|
|
934
|
+
}),
|
|
935
|
+
project: (projectionSchema: any) => {
|
|
936
|
+
const projected = {
|
|
937
|
+
...h,
|
|
938
|
+
handler: projectHandler(h.handler, client[key].Request.success, projectionSchema)
|
|
939
|
+
}
|
|
940
|
+
return makeProjectedMutation(projected)
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
)
|
|
944
|
+
}
|
|
945
|
+
return makeProjectedMutation(handler)
|
|
946
|
+
})(client[key] as any),
|
|
947
|
+
...client[key],
|
|
948
|
+
...fn, // to get the i18n key etc.
|
|
949
|
+
request,
|
|
950
|
+
fn,
|
|
951
|
+
wrap: Command.wrap({ mutate: wrapInput, id: client[key].id })
|
|
952
|
+
}
|
|
1399
953
|
)
|
|
1400
954
|
return acc
|
|
1401
955
|
},
|
|
1402
956
|
{} as {
|
|
1403
957
|
[Key in keyof typeof client]:
|
|
1404
958
|
& typeof client[Key]
|
|
1405
|
-
&
|
|
1406
|
-
|
|
1407
|
-
|
|
959
|
+
& (QueryHandler<typeof client[Key]> extends never ? {}
|
|
960
|
+
:
|
|
961
|
+
& QueryRequestWithExtensions<QueryHandler<typeof client[Key]>>
|
|
962
|
+
& Queries<RT, QueryHandler<typeof client[Key]>>
|
|
963
|
+
& QueryProjection<RT, QueryHandler<typeof client[Key]>>)
|
|
964
|
+
& (StreamHandler<typeof client[Key]> extends never ? {}
|
|
965
|
+
: StreamQueries<RT, StreamHandler<typeof client[Key]>>)
|
|
966
|
+
& (CommandHandler<typeof client[Key]> extends never ? {}
|
|
967
|
+
: CommandRequestWithExtensions<RT | RTHooks, CommandHandler<typeof client[Key]>>)
|
|
968
|
+
& (CommandHandler<typeof client[Key]> extends never ? {}
|
|
969
|
+
: { mutate: MutationWithExtensions<RT | RTHooks, CommandHandler<typeof client[Key]>> })
|
|
970
|
+
& (StreamHandler<typeof client[Key]> extends never ? {}
|
|
971
|
+
: {
|
|
972
|
+
streamFn: StreamFnStreamExtension<RT | RTHooks, StreamHandler<typeof client[Key]>>
|
|
973
|
+
mutate: StreamMutation2WithExtensions<RT | RTHooks, StreamHandler<typeof client[Key]>>
|
|
974
|
+
})
|
|
975
|
+
& { Input: typeof client[Key] extends RequestHandlerWithInput<infer I, any, any, any, any, any> ? I : never }
|
|
1408
976
|
}
|
|
1409
977
|
)
|
|
1410
|
-
return Object.assign(extended, {
|
|
978
|
+
return Object.assign(extended, {
|
|
979
|
+
helpers: {
|
|
980
|
+
...mapRequest(client),
|
|
981
|
+
...mapMutation(client, queryInvalidation, invalidationResources),
|
|
982
|
+
...mapQuery(client)
|
|
983
|
+
}
|
|
984
|
+
})
|
|
1411
985
|
}
|
|
1412
986
|
|
|
1413
987
|
// TODO: Clean up this delay initialisation messs
|
|
1414
988
|
// TODO; invalidateQueries should perhaps be configured in the Request impl themselves?
|
|
1415
|
-
const clientFor__ = <M extends
|
|
989
|
+
const clientFor__ = <M extends RequestsAny>(
|
|
1416
990
|
m: M,
|
|
1417
|
-
queryInvalidation?:
|
|
1418
|
-
|
|
991
|
+
queryInvalidation?: QueryInvalidationFactory<M>,
|
|
992
|
+
invalidationResources?: InvalidationResourcesFor<M>
|
|
993
|
+
) => getBaseMrt().runSync(clientFor_(m).pipe(Effect.map(mapClient(queryInvalidation, invalidationResources))))
|
|
1419
994
|
|
|
1420
995
|
// delay client creation until first access
|
|
1421
996
|
// the idea is that we don't need the useNuxtApp().$runtime (only available at later initialisation stage)
|
|
1422
997
|
// until we are at a place where it is available..
|
|
1423
|
-
const clientFor = <
|
|
998
|
+
const clientFor = <
|
|
999
|
+
M extends RequestsAny,
|
|
1000
|
+
Resources extends InvalidationResourcesFor<M> = InvalidationResourcesFor<M>
|
|
1001
|
+
>(
|
|
1424
1002
|
m: M,
|
|
1425
|
-
|
|
1003
|
+
...args: ClientForArgs<M, Resources>
|
|
1426
1004
|
) => {
|
|
1005
|
+
const [queryInvalidation, invalidationResources] = args as [
|
|
1006
|
+
QueryInvalidationFactory<M> | undefined,
|
|
1007
|
+
InvalidationResourcesFor<M> | undefined
|
|
1008
|
+
]
|
|
1427
1009
|
type Client = ReturnType<typeof clientFor__<M>>
|
|
1428
1010
|
let client: Client | undefined = undefined
|
|
1429
|
-
const getOrMakeClient = () => (client ??= clientFor__(m, queryInvalidation))
|
|
1011
|
+
const getOrMakeClient = () => (client ??= clientFor__(m, queryInvalidation, invalidationResources))
|
|
1430
1012
|
|
|
1431
1013
|
// initialize on first use..
|
|
1432
1014
|
const proxy = Struct.keys(m).concat(["helpers"]).reduce((acc, key) => {
|
|
@@ -1444,16 +1026,12 @@ export const makeClient = <RT_, RTHooks>(
|
|
|
1444
1026
|
return proxy
|
|
1445
1027
|
}
|
|
1446
1028
|
|
|
1447
|
-
const legacy: Legacy<RT> = {
|
|
1448
|
-
...mutations,
|
|
1449
|
-
...query
|
|
1450
|
-
}
|
|
1451
|
-
|
|
1452
1029
|
const Command: CommanderResolved<RT, RTHooks> = {
|
|
1453
1030
|
...{
|
|
1454
1031
|
// delay initialisation until first use...
|
|
1455
1032
|
fn: (...args: [any]) => useCommand().fn(...args),
|
|
1456
1033
|
wrap: (...args: [any]) => useCommand().wrap(...args),
|
|
1034
|
+
streamFn: (...args: [any]) => useCommand().streamFn(...args),
|
|
1457
1035
|
alt: (...args: [any]) => useCommand().alt(...args),
|
|
1458
1036
|
alt2: (...args: [any]) => useCommand().alt2(...args)
|
|
1459
1037
|
} as ReturnType<typeof useCommand>,
|
|
@@ -1463,19 +1041,17 @@ export const makeClient = <RT_, RTHooks>(
|
|
|
1463
1041
|
return {
|
|
1464
1042
|
Command,
|
|
1465
1043
|
useCommand,
|
|
1466
|
-
clientFor
|
|
1467
|
-
legacy
|
|
1044
|
+
clientFor
|
|
1468
1045
|
}
|
|
1469
1046
|
}
|
|
1470
1047
|
|
|
1471
|
-
export interface Legacy<R>
|
|
1472
|
-
extends
|
|
1473
|
-
Pick<QueryImpl<R>, "useQuery" | "useSuspenseQuery">,
|
|
1474
|
-
Omit<LegacyMutationImpl<R>, "getRuntime" | "toast" | "intl">
|
|
1475
|
-
{}
|
|
1476
|
-
|
|
1477
1048
|
export type QueryInvalidation<M> = {
|
|
1478
|
-
[K in keyof M]?: (
|
|
1049
|
+
[K in keyof M]?: (
|
|
1050
|
+
defaultKey: string[],
|
|
1051
|
+
name: string,
|
|
1052
|
+
input?: unknown,
|
|
1053
|
+
output?: ExitResult.Exit<unknown, unknown>
|
|
1054
|
+
) => {
|
|
1479
1055
|
filters?: InvalidateQueryFilters | undefined
|
|
1480
1056
|
options?: InvalidateOptions | undefined
|
|
1481
1057
|
}[]
|
|
@@ -1486,17 +1062,21 @@ export type ToCamel<S extends string | number | symbol> = S extends string
|
|
|
1486
1062
|
: Uncapitalize<S>
|
|
1487
1063
|
: never
|
|
1488
1064
|
|
|
1489
|
-
export interface CommandBase<I = void, A = void> {
|
|
1065
|
+
export interface CommandBase<I = void, A = void, RA = unknown, RE = unknown> {
|
|
1490
1066
|
handle: (input: I) => A
|
|
1491
1067
|
waiting: boolean
|
|
1492
1068
|
blocked: boolean
|
|
1493
1069
|
allowed: boolean
|
|
1494
1070
|
action: string
|
|
1495
1071
|
label: string
|
|
1072
|
+
/** formatted progress info for current `running` state, when `progress` was supplied */
|
|
1073
|
+
progress?: Progress | undefined
|
|
1074
|
+
/** reactive result state, available on stream-backed commands */
|
|
1075
|
+
result?: AsyncResult.AsyncResult<RA, RE>
|
|
1496
1076
|
}
|
|
1497
1077
|
|
|
1498
|
-
export interface EffectCommand<I = void, A = unknown, E = unknown> extends CommandBase<I, Fiber<A, E
|
|
1078
|
+
export interface EffectCommand<I = void, A = unknown, E = unknown> extends CommandBase<I, Fiber<A, E>, A, E> {}
|
|
1499
1079
|
|
|
1500
|
-
export interface CommandFromRequest<I extends
|
|
1501
|
-
extends EffectCommand<
|
|
1080
|
+
export interface CommandFromRequest<I extends { readonly make: (...args: any[]) => any }, A = unknown, E = unknown>
|
|
1081
|
+
extends EffectCommand<HandlerInput<I>, A, E>
|
|
1502
1082
|
{}
|