@effect-app/vue 4.0.0-beta.27 → 4.0.0-beta.271
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 +2001 -0
- package/dist/commander.d.ts +634 -0
- package/dist/commander.d.ts.map +1 -0
- package/dist/commander.js +1070 -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/errorReporter.d.ts +6 -4
- package/dist/errorReporter.d.ts.map +1 -1
- package/dist/errorReporter.js +14 -19
- package/dist/form.d.ts +14 -5
- package/dist/form.d.ts.map +1 -1
- package/dist/form.js +46 -13
- 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/makeClient.d.ts +157 -343
- package/dist/makeClient.d.ts.map +1 -1
- package/dist/makeClient.js +218 -377
- 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 +96 -38
- package/dist/mutate.d.ts.map +1 -1
- package/dist/mutate.js +177 -49
- package/dist/query.d.ts +23 -38
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +156 -78
- 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 +5 -0
- package/dist/suspense.d.ts.map +1 -0
- package/dist/suspense.js +12 -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/examples/streamMutation.ts +72 -0
- package/package.json +30 -91
- package/src/commander.ts +3413 -0
- package/src/{experimental/confirm.ts → confirm.ts} +13 -15
- package/src/errorReporter.ts +65 -75
- package/src/form.ts +61 -18
- package/src/index.ts +7 -7
- package/src/intl.ts +12 -0
- package/src/lib.ts +49 -21
- package/src/makeClient.ts +586 -1139
- package/src/makeIntl.ts +2 -2
- package/src/{experimental/makeUseCommand.ts → makeUseCommand.ts} +9 -6
- package/src/mutate.ts +335 -134
- package/src/query.ts +241 -183
- package/src/routeParams.ts +7 -7
- package/src/runtime.ts +1 -31
- package/src/suspense.ts +17 -0
- package/src/toast.ts +1 -0
- package/src/withToast.ts +1 -0
- package/test/Mutation.test.ts +181 -24
- 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 +3527 -122
- package/test/dist/stubs.d.ts.map +1 -1
- package/test/dist/stubs.js +187 -32
- package/test/dist/suspense.test.d.ts.map +1 -0
- package/test/form-validation-errors.test.ts +25 -20
- package/test/form.test.ts +22 -3
- package/test/lib.test.ts +240 -0
- package/test/makeClient.test.ts +327 -38
- package/test/streamFinal.test.ts +64 -0
- package/test/streamFn.test.ts +457 -0
- package/test/stubs.ts +223 -43
- package/test/suspense.test.ts +20 -0
- package/tsconfig.examples.json +20 -0
- package/tsconfig.json +3 -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.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/src/makeClient.ts
CHANGED
|
@@ -1,129 +1,201 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import {
|
|
2
|
+
import { isCancelledError, type QueryObserverResult, type RefetchOptions, type UseQueryReturnType } from "@tanstack/vue-query"
|
|
3
3
|
import { camelCase } from "change-case"
|
|
4
|
-
import { Cause, Data, Effect, Exit, Layer, type ManagedRuntime, Match, Option, S, ServiceMap, Struct } from "effect-app"
|
|
5
4
|
import { type ApiClientFactory, type Req } from "effect-app/client"
|
|
6
|
-
import type {
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
5
|
+
import type { ExtractModuleName, HandlerInput, RequestHandlers, RequestHandlerWithInput, RequestsAny, RequestStreamHandlerWithInput } from "effect-app/client/clientFor"
|
|
6
|
+
import type { InvalidationCallback } from "effect-app/client/makeClient"
|
|
7
|
+
import type * as Context from "effect-app/Context"
|
|
8
|
+
import * as Effect from "effect-app/Effect"
|
|
9
|
+
import type * as Layer from "effect-app/Layer"
|
|
10
|
+
import * as S from "effect-app/Schema"
|
|
11
|
+
import * as Exit from "effect/Exit"
|
|
11
12
|
import { type Fiber } from "effect/Fiber"
|
|
13
|
+
import * as Hash from "effect/Hash"
|
|
14
|
+
import type * as ManagedRuntime from "effect/ManagedRuntime"
|
|
15
|
+
import type * as Stream from "effect/Stream"
|
|
16
|
+
import * as Struct from "effect/Struct"
|
|
12
17
|
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
|
-
import {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
18
|
+
import { type ComputedRef, onBeforeUnmount, ref, type WatchSource } from "vue"
|
|
19
|
+
import { type Commander, CommanderStatic, type Progress } from "./commander.ts"
|
|
20
|
+
import { type I18n } from "./intl.ts"
|
|
21
|
+
import { type CommanderResolved, makeUseCommand } from "./makeUseCommand.ts"
|
|
22
|
+
import { type InvalidationEntry, makeMutation, makeStreamMutation2, type MutationOptionsBase, useMakeMutation } from "./mutate.ts"
|
|
23
|
+
import { type CustomUndefinedInitialQueryOptions, makeQuery, makeStreamQuery } from "./query.ts"
|
|
24
|
+
import { makeRunPromise } from "./runtime.ts"
|
|
25
|
+
import { awaitResolvedSuspenseResult } from "./suspense.ts"
|
|
26
|
+
import { type Toast } from "./toast.ts"
|
|
27
|
+
|
|
28
|
+
export type { Progress }
|
|
29
|
+
|
|
30
|
+
// TODO: optimize - work from encoded shape directly
|
|
31
|
+
const projectHandler = (
|
|
32
|
+
handler: (i: any) => Effect.Effect<any, any, any>,
|
|
33
|
+
successSchema: S.Top,
|
|
34
|
+
projectionSchema: S.Top
|
|
35
|
+
) => {
|
|
36
|
+
const encode = S.encodeEffect(successSchema)
|
|
37
|
+
const decode = S.decodeEffectConcurrently(projectionSchema)
|
|
38
|
+
return (i: any) => handler(i).pipe(Effect.flatMap(encode), Effect.flatMap(decode))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const projectionSchemaHash = (schema: S.Top) => String(Hash.hash(schema.ast))
|
|
42
|
+
|
|
43
|
+
export interface CommandRequestExtensions<RT, Id extends string, I, A, E, R> {
|
|
30
44
|
/** Defines a Command based on this call, taking the `id` of the call as the `id` of the Command.
|
|
31
45
|
* The Request function will be taken as the first member of the Command, the Command required input will be the Request input.
|
|
32
46
|
* see Command.wrap for details */
|
|
33
|
-
wrap:
|
|
47
|
+
wrap: <I18nKey extends string = Id, State extends Commander.IntlRecord | undefined = undefined>(
|
|
48
|
+
options?: Commander.FnOptions<Id, I18nKey, State>
|
|
49
|
+
) => Commander.CommanderWrap<RT, Id, I18nKey, State, I, A, E, R>
|
|
34
50
|
/** Defines a Command based on this call, taking the `id` of the call as the `id` of the Command.
|
|
35
51
|
* see Command.fn for details */
|
|
36
|
-
fn:
|
|
52
|
+
fn: <I18nKey extends string = Id, State extends Commander.IntlRecord | undefined = undefined>(
|
|
53
|
+
options?: Commander.FnOptions<Id, I18nKey, State>
|
|
54
|
+
) => Commander.CommanderFn<RT, Id, I18nKey, State>
|
|
37
55
|
}
|
|
38
56
|
|
|
39
57
|
/** my other doc */
|
|
40
|
-
export interface
|
|
58
|
+
export interface RequestExt<
|
|
41
59
|
RT,
|
|
42
60
|
Id extends string,
|
|
43
61
|
I,
|
|
44
62
|
A,
|
|
45
63
|
E,
|
|
46
64
|
R
|
|
47
|
-
> extends
|
|
65
|
+
> extends
|
|
66
|
+
Commander.CommandContextLocal<Id, Id>,
|
|
67
|
+
Commander.CommanderWrap<RT, Id, Id, undefined, I, A, E, R>,
|
|
68
|
+
CommandRequestExtensions<RT, Id, I, A, E, R>
|
|
69
|
+
{
|
|
48
70
|
/**
|
|
49
|
-
*
|
|
71
|
+
* Send the request to the endpoint and return the raw Effect response.
|
|
72
|
+
* This does not perform query cache invalidation.
|
|
50
73
|
*/
|
|
51
|
-
(i: I)
|
|
74
|
+
request: (i: I) => Effect.Effect<A, E, R>
|
|
52
75
|
}
|
|
53
76
|
|
|
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
|
-
{
|
|
77
|
+
export type CommandRequestWithExtensions<RT, Req> = Req extends
|
|
78
|
+
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer _Request, infer Id> ? RequestExt<RT, Id, I, A, E, R>
|
|
79
|
+
: never
|
|
80
|
+
|
|
81
|
+
export interface QueryExtensions<I, A, E, R> {
|
|
82
|
+
/**
|
|
83
|
+
* Send the request to the endpoint and return the raw Effect response.
|
|
84
|
+
* This does not set up query state tracking.
|
|
85
|
+
*/
|
|
86
|
+
request: (i: I) => Effect.Effect<A, E, R>
|
|
69
87
|
}
|
|
70
88
|
|
|
71
|
-
export type
|
|
72
|
-
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer _Request, infer
|
|
73
|
-
|
|
74
|
-
|
|
89
|
+
export type QueryRequestWithExtensions<Req> = Req extends
|
|
90
|
+
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer _Request, infer _Id> ? QueryExtensions<I, A, E, R>
|
|
91
|
+
: never
|
|
92
|
+
|
|
93
|
+
type QueryHandler<Req> = Req extends
|
|
94
|
+
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id>
|
|
95
|
+
? Request["type"] extends "query" ? RequestHandlerWithInput<I, A, E, R, Request, Id> : never
|
|
96
|
+
: never
|
|
97
|
+
|
|
98
|
+
type CommandHandler<Req> = Req extends
|
|
99
|
+
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id>
|
|
100
|
+
? Request["type"] extends "command" ? RequestHandlerWithInput<I, A, E, R, Request, Id> : never
|
|
101
|
+
: never
|
|
102
|
+
|
|
103
|
+
type QueryStreamHandler<Req> = Req extends
|
|
104
|
+
RequestStreamHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id, infer Final>
|
|
105
|
+
? [Request["stream"], Request["type"]] extends [true, "query"]
|
|
106
|
+
? RequestStreamHandlerWithInput<I, A, E, R, Request, Id, Final>
|
|
107
|
+
: never
|
|
108
|
+
: never
|
|
109
|
+
|
|
110
|
+
type CommandStreamHandler<Req> = Req extends
|
|
111
|
+
RequestStreamHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id, infer Final>
|
|
112
|
+
? [Request["stream"], Request["type"]] extends [true, "command"]
|
|
113
|
+
? RequestStreamHandlerWithInput<I, A, E, R, Request, Id, Final>
|
|
114
|
+
: never
|
|
75
115
|
: never
|
|
76
116
|
|
|
77
117
|
export interface MutationExtensions<RT, Id extends string, I, A, E, R> {
|
|
78
118
|
/** Defines a Command based on this mutation, taking the `id` of the mutation as the `id` of the Command.
|
|
79
119
|
* The Mutation function will be taken as the first member of the Command, the Command required input will be the Mutation input.
|
|
80
120
|
* see Command.wrap for details */
|
|
81
|
-
wrap:
|
|
82
|
-
|
|
121
|
+
wrap: <I18nKey extends string = Id, State extends Commander.IntlRecord | undefined = undefined>(
|
|
122
|
+
options?: Commander.FnOptions<Id, I18nKey, State>
|
|
123
|
+
) => Commander.CommanderWrap<RT, Id, I18nKey, State, I, A, E, R>
|
|
124
|
+
/** Defines a Command based on this call, taking the `id` of the mutation as the `id` of the Command.
|
|
83
125
|
* 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>
|
|
126
|
+
fn: <I18nKey extends string = Id, State extends Commander.IntlRecord | undefined = undefined>(
|
|
127
|
+
options?: Commander.FnOptions<Id, I18nKey, State>
|
|
128
|
+
) => Commander.CommanderFn<RT, Id, I18nKey, State>
|
|
102
129
|
}
|
|
103
130
|
|
|
104
131
|
/**
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
132
|
+
* Send the request to the endpoint and return the raw Effect response.
|
|
133
|
+
* Also invalidates query caches using the request namespace by default.
|
|
134
|
+
* Namespace invalidation targets parent namespace keys
|
|
135
|
+
* (for example `$project/$configuration.get` invalidates `$project`).
|
|
136
|
+
* Override invalidation in client options via `queryInvalidation`.
|
|
137
|
+
*
|
|
138
|
+
* Pass `options` to attach a `select` Effect that runs after the mutation
|
|
139
|
+
* succeeds (its output is returned to the caller) and/or override the default
|
|
140
|
+
* `queryInvalidation`.
|
|
141
|
+
*
|
|
142
|
+
* When `I = void` the input argument may be omitted.
|
|
108
143
|
*/
|
|
109
144
|
export interface MutationExt<
|
|
110
145
|
RT,
|
|
111
146
|
Id extends string,
|
|
147
|
+
I,
|
|
112
148
|
A,
|
|
113
149
|
E,
|
|
114
|
-
R
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
150
|
+
R,
|
|
151
|
+
EA = unknown
|
|
152
|
+
> extends MutationExtensions<RT, Id, I, A, E, R> {
|
|
153
|
+
<B = A, E2 = never, R2 = never>(
|
|
154
|
+
input: I,
|
|
155
|
+
options?: MutationOptionsBase<A, B, E2, R2>
|
|
156
|
+
): Effect.Effect<B, E | E2, R | R2>
|
|
157
|
+
|
|
158
|
+
project: <ProjSchema extends S.Top>(
|
|
159
|
+
schema: EA extends ProjSchema["Encoded"] ? ProjSchema : never
|
|
160
|
+
) => MutationExt<
|
|
161
|
+
RT,
|
|
162
|
+
Id,
|
|
163
|
+
I,
|
|
164
|
+
ProjSchema["Type"],
|
|
165
|
+
E | S.SchemaError,
|
|
166
|
+
R | ProjSchema["DecodingServices"],
|
|
167
|
+
ProjSchema["Encoded"]
|
|
168
|
+
>
|
|
121
169
|
}
|
|
122
170
|
|
|
123
171
|
export type MutationWithExtensions<RT, Req> = Req extends
|
|
124
|
-
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer
|
|
125
|
-
?
|
|
126
|
-
:
|
|
172
|
+
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id>
|
|
173
|
+
? MutationExt<RT, Id, I, A, E, R, Request["success"]["Encoded"]>
|
|
174
|
+
: never
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* The `streamFn` builder for a stream-type request handler, using the stream-specific overloads.
|
|
178
|
+
*/
|
|
179
|
+
export type StreamFnStreamExtension<RT, Req> = Req extends
|
|
180
|
+
RequestStreamHandlerWithInput<infer _I, infer _A, infer _E, infer _R, infer _Request, infer Id, infer _Final>
|
|
181
|
+
? <I18nKey extends string = Id, State extends Commander.IntlRecord | undefined = undefined>(
|
|
182
|
+
options?: Commander.FnOptions<Id, I18nKey, State>
|
|
183
|
+
) => Commander.StreamGen<RT, Id, I18nKey, State> & Commander.NonGenStream<RT, Id, I18nKey, State>
|
|
184
|
+
: never
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* `mutate` factory — wraps per-invocation invalidation scaffolding
|
|
188
|
+
* into the stream itself (via `Stream.unwrap`) for use with `streamFn` combinators.
|
|
189
|
+
*/
|
|
190
|
+
export type StreamMutation2WithExtensions<RT, Req> = Req extends
|
|
191
|
+
RequestStreamHandlerWithInput<infer I, infer A, infer E, infer R, infer _Request, infer Id, infer _Final> ?
|
|
192
|
+
& ((input: I) => Stream.Stream<A, E, R>)
|
|
193
|
+
& {
|
|
194
|
+
readonly id: Id
|
|
195
|
+
readonly wrap: <I18nKey extends string = Id, State extends Commander.IntlRecord | undefined = undefined>(
|
|
196
|
+
options?: Commander.FnOptions<Id, I18nKey, State>
|
|
197
|
+
) => Commander.StreamerWrap<RT, Id, I18nKey, State, I, A, E, R>
|
|
198
|
+
}
|
|
127
199
|
: never
|
|
128
200
|
|
|
129
201
|
// we don't really care about the RT, as we are in charge of ensuring runtime safety anyway
|
|
@@ -131,33 +203,50 @@ export type MutationWithExtensions<RT, Req> = Req extends
|
|
|
131
203
|
declare const useQuery_: QueryImpl<any>["useQuery"]
|
|
132
204
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
133
205
|
declare const useSuspenseQuery_: QueryImpl<any>["useSuspenseQuery"]
|
|
206
|
+
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
207
|
+
declare const useStreamQuery_: QueryImpl<any>["useStreamQuery"]
|
|
208
|
+
|
|
209
|
+
export interface ProjectResult<RT, I, B, E, R, Request extends Req, Id extends string> {
|
|
210
|
+
request: (i: I) => Effect.Effect<B, E, R>
|
|
211
|
+
query: Exclude<R, RT> extends never ? ReturnType<typeof useQuery_<I, E, B, Request, Id>>
|
|
212
|
+
: MissingDependencies<RT, R> & {}
|
|
213
|
+
suspense: Exclude<R, RT> extends never ? ReturnType<typeof useSuspenseQuery_<I, E, B, Request, Id>>
|
|
214
|
+
: MissingDependencies<RT, R> & {}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export type QueryProjection<RT, HandlerReq> = HandlerReq extends
|
|
218
|
+
RequestHandlerWithInput<infer I, infer _A, infer E, infer R, infer Request, infer Id>
|
|
219
|
+
? Request["type"] extends "query" ? {
|
|
220
|
+
project: <ProjSchema extends S.Top>(
|
|
221
|
+
schema: Request["success"]["Encoded"] extends ProjSchema["Encoded"] ? ProjSchema : never
|
|
222
|
+
) => ProjectResult<
|
|
223
|
+
RT,
|
|
224
|
+
I,
|
|
225
|
+
ProjSchema["Type"],
|
|
226
|
+
E | S.SchemaError,
|
|
227
|
+
R | ProjSchema["DecodingServices"],
|
|
228
|
+
Request,
|
|
229
|
+
Id
|
|
230
|
+
>
|
|
231
|
+
}
|
|
232
|
+
: {}
|
|
233
|
+
: {}
|
|
134
234
|
|
|
135
|
-
export interface
|
|
235
|
+
export interface QueryResultExtensions<Request extends Req, Id extends string, I, A, E> {
|
|
136
236
|
/**
|
|
137
|
-
*
|
|
237
|
+
* Read helper for query requests.
|
|
238
|
+
* Runs as a tracked Vue Query and returns reactive state.
|
|
239
|
+
* Queries read state and should not be used to mutate it.
|
|
240
|
+
* When `I = void` the input argument may be omitted.
|
|
138
241
|
*/
|
|
139
242
|
query: ReturnType<typeof useQuery_<I, E, A, Request, Id>>
|
|
140
243
|
// TODO or suspense as Option?
|
|
141
244
|
/**
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
* So that Suspense and error boundaries can be used.
|
|
245
|
+
* Like `.query`, but returns a Promise for setup-time awaiting.
|
|
246
|
+
* Use this when integrating with Vue Suspense / error boundaries.
|
|
145
247
|
*/
|
|
146
248
|
suspense: ReturnType<typeof useSuspenseQuery_<I, E, A, Request, Id>>
|
|
147
249
|
}
|
|
148
|
-
export interface QueriesWithoutInput<Request extends Req, Id extends string, A, E> {
|
|
149
|
-
/**
|
|
150
|
-
* Effect results are passed to the caller, including errors.
|
|
151
|
-
*/
|
|
152
|
-
query: ReturnType<typeof useQuery_<E, A, Request, Id>>
|
|
153
|
-
// TODO or suspense as Option?
|
|
154
|
-
/**
|
|
155
|
-
* The difference with useQuery is that this function will return a Promise you can await in the Setup,
|
|
156
|
-
* which ensures that either there always is a latest value, or an error occurs on load.
|
|
157
|
-
* So that Suspense and error boundaries can be used.
|
|
158
|
-
*/
|
|
159
|
-
suspense: ReturnType<typeof useSuspenseQuery_<E, A, Request, Id>>
|
|
160
|
-
}
|
|
161
250
|
|
|
162
251
|
export type MissingDependencies<RT, R> = {
|
|
163
252
|
message: "Dependencies required that are not provided by the runtime"
|
|
@@ -166,184 +255,40 @@ export type MissingDependencies<RT, R> = {
|
|
|
166
255
|
|
|
167
256
|
export type Queries<RT, Req> = Req extends
|
|
168
257
|
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id>
|
|
169
|
-
? Exclude<R, RT> extends never ?
|
|
170
|
-
: {
|
|
171
|
-
query: MissingDependencies<RT, R> & {}
|
|
172
|
-
suspense: MissingDependencies<RT, R> & {}
|
|
173
|
-
}
|
|
174
|
-
: Req extends RequestHandler<infer A, infer E, infer R, infer Request, infer Id>
|
|
175
|
-
? Exclude<R, RT> extends never ? QueriesWithoutInput<Request, Id, A, E>
|
|
258
|
+
? Request["type"] extends "query" ? Exclude<R, RT> extends never ? QueryResultExtensions<Request, Id, I, A, E>
|
|
176
259
|
: { query: MissingDependencies<RT, R> & {}; suspense: MissingDependencies<RT, R> & {} }
|
|
177
260
|
: never
|
|
261
|
+
: never
|
|
178
262
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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>
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
type WithAction<A> = A & {
|
|
248
|
-
action: string
|
|
263
|
+
export interface StreamQueryExtensions<Request extends Req, Id extends string, I, A, E> {
|
|
264
|
+
/**
|
|
265
|
+
* Stream helper for query-stream requests.
|
|
266
|
+
* Runs as a tracked Vue Query and returns reactive state with accumulated chunks.
|
|
267
|
+
* Data is an array of all chunks received so far.
|
|
268
|
+
* When `I = void` the input argument may be omitted.
|
|
269
|
+
*/
|
|
270
|
+
query: ReturnType<typeof useStreamQuery_<I, E, A, Request, Id>>
|
|
249
271
|
}
|
|
272
|
+
export type StreamQueries<RT, HandlerReq> = HandlerReq extends
|
|
273
|
+
RequestStreamHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id, infer _Final>
|
|
274
|
+
? Exclude<R, RT> extends never ? StreamQueryExtensions<Request, Id, I, A, E>
|
|
275
|
+
: { query: MissingDependencies<RT, R> & {} }
|
|
276
|
+
: never
|
|
250
277
|
|
|
251
|
-
|
|
252
|
-
// object for the returned value from the getter.
|
|
253
|
-
|
|
254
|
-
type Resp<I, A, E, R, V = ComputedRef<Res<A, E>>> = readonly [
|
|
255
|
-
V,
|
|
256
|
-
WithAction<(I: I) => Effect.Effect<Exit.Exit<A, E>, never, R>>
|
|
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
|
-
}
|
|
311
|
-
|
|
312
|
-
const extra = {
|
|
313
|
-
action,
|
|
314
|
-
message: `Unexpected Error trying to ${action}`
|
|
315
|
-
}
|
|
316
|
-
yield* reportRuntimeError(cause, extra)
|
|
278
|
+
const _useMutation = makeMutation()
|
|
317
279
|
|
|
318
|
-
|
|
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
|
-
)
|
|
280
|
+
const wrapWithSpan = (self: { id: string }, mut: any) => {
|
|
281
|
+
const span = (eff: Effect.Effect<any, any, any>) =>
|
|
282
|
+
Effect.withSpan(`mutation ${self.id}`, {}, { captureStackTrace: false })(eff)
|
|
283
|
+
return (input: any, options?: MutationOptionsBase) => span(mut(input, options))
|
|
337
284
|
}
|
|
338
285
|
|
|
339
|
-
const _useMutation = makeMutation()
|
|
340
|
-
|
|
341
286
|
/**
|
|
342
287
|
* Pass an Effect or a function that returns an Effect, e.g from a client action
|
|
343
288
|
* Executes query cache invalidation based on default rules or provided option.
|
|
344
289
|
* adds a span with the mutation id
|
|
345
290
|
*/
|
|
346
|
-
export const useMutation: typeof _useMutation = <
|
|
291
|
+
export const useMutation: typeof _useMutation = (<
|
|
347
292
|
I,
|
|
348
293
|
E,
|
|
349
294
|
A,
|
|
@@ -351,16 +296,12 @@ export const useMutation: typeof _useMutation = <
|
|
|
351
296
|
Request extends Req,
|
|
352
297
|
Name extends string
|
|
353
298
|
>(
|
|
354
|
-
self: RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
355
|
-
options?: MutationOptionsBase
|
|
299
|
+
self: RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
356
300
|
) =>
|
|
357
301
|
Object.assign(
|
|
358
|
-
|
|
359
|
-
_useMutation(self as any, options),
|
|
360
|
-
Effect.withSpan(`mutation ${self.id}`, {}, { captureStackTrace: false })
|
|
361
|
-
) as any,
|
|
302
|
+
wrapWithSpan(self, _useMutation(self as any)),
|
|
362
303
|
{ id: self.id }
|
|
363
|
-
)
|
|
304
|
+
)) as any
|
|
364
305
|
|
|
365
306
|
/**
|
|
366
307
|
* Pass an Effect or a function that returns an Effect, e.g from a client action
|
|
@@ -369,7 +310,7 @@ export const useMutation: typeof _useMutation = <
|
|
|
369
310
|
*/
|
|
370
311
|
export const useMutationInt = (): typeof _useMutation => {
|
|
371
312
|
const _useMutation = useMakeMutation()
|
|
372
|
-
return <
|
|
313
|
+
return (<
|
|
373
314
|
I,
|
|
374
315
|
E,
|
|
375
316
|
A,
|
|
@@ -377,715 +318,23 @@ export const useMutationInt = (): typeof _useMutation => {
|
|
|
377
318
|
Request extends Req,
|
|
378
319
|
Name extends string
|
|
379
320
|
>(
|
|
380
|
-
self: RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
381
|
-
options?: MutationOptionsBase
|
|
321
|
+
self: RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
382
322
|
) =>
|
|
383
323
|
Object.assign(
|
|
384
|
-
|
|
385
|
-
_useMutation(self as any, options),
|
|
386
|
-
Effect.withSpan(`mutation ${self.id}`, {}, { captureStackTrace: false })
|
|
387
|
-
) as any,
|
|
324
|
+
wrapWithSpan(self, _useMutation(self as any)),
|
|
388
325
|
{ id: self.id }
|
|
389
|
-
)
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
export class LegacyMutationImpl<RT> {
|
|
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
|
|
326
|
+
)) as any
|
|
1082
327
|
}
|
|
1083
328
|
|
|
1084
|
-
export type ClientFrom<M extends
|
|
329
|
+
export type ClientFrom<M extends RequestsAny> = RequestHandlers<never, never, M, ExtractModuleName<M>>
|
|
1085
330
|
|
|
1086
331
|
export class QueryImpl<R> {
|
|
1087
|
-
|
|
332
|
+
readonly getRuntime: () => Context.Context<R>
|
|
333
|
+
|
|
334
|
+
constructor(getRuntime: () => Context.Context<R>) {
|
|
335
|
+
this.getRuntime = getRuntime
|
|
1088
336
|
this.useQuery = makeQuery(this.getRuntime)
|
|
337
|
+
this.useStreamQuery = makeStreamQuery(this.getRuntime)
|
|
1089
338
|
}
|
|
1090
339
|
/**
|
|
1091
340
|
* Effect results are passed to the caller, including errors.
|
|
@@ -1093,6 +342,12 @@ export class QueryImpl<R> {
|
|
|
1093
342
|
*/
|
|
1094
343
|
readonly useQuery: ReturnType<typeof makeQuery<R>>
|
|
1095
344
|
|
|
345
|
+
/**
|
|
346
|
+
* Stream results are accumulated as an array of chunks and returned as reactive state.
|
|
347
|
+
* @deprecated use client helpers instead (.query())
|
|
348
|
+
*/
|
|
349
|
+
readonly useStreamQuery: ReturnType<typeof makeStreamQuery<R>>
|
|
350
|
+
|
|
1096
351
|
/**
|
|
1097
352
|
* The difference with useQuery is that this function will return a Promise you can await in the Setup,
|
|
1098
353
|
* which ensures that either there always is a latest value, or an error occurs on load.
|
|
@@ -1104,52 +359,18 @@ export class QueryImpl<R> {
|
|
|
1104
359
|
* The difference with useQuery is that this function will return a Promise you can await in the Setup,
|
|
1105
360
|
* which ensures that either there always is a latest value, or an error occurs on load.
|
|
1106
361
|
* So that Suspense and error boundaries can be used.
|
|
1107
|
-
*
|
|
1108
|
-
*/
|
|
1109
|
-
<
|
|
1110
|
-
E,
|
|
1111
|
-
A,
|
|
1112
|
-
Request extends Req,
|
|
1113
|
-
Name extends string
|
|
1114
|
-
>(
|
|
1115
|
-
self: RequestHandler<A, E, R, Request, Name>
|
|
1116
|
-
): {
|
|
1117
|
-
/**
|
|
1118
|
-
* The difference with useQuery is that this function will return a Promise you can await in the Setup,
|
|
1119
|
-
* which ensures that either there always is a latest value, or an error occurs on load.
|
|
1120
|
-
* So that Suspense and error boundaries can be used.
|
|
1121
|
-
*/
|
|
1122
|
-
<TData = A>(options?: CustomUndefinedInitialQueryOptions<A, E, TData>): Promise<
|
|
1123
|
-
readonly [
|
|
1124
|
-
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
1125
|
-
ComputedRef<TData>,
|
|
1126
|
-
(
|
|
1127
|
-
options?: RefetchOptions
|
|
1128
|
-
) => Effect.Effect<QueryObserverResult<TData, E>>,
|
|
1129
|
-
UseQueryReturnType<any, any>
|
|
1130
|
-
]
|
|
1131
|
-
>
|
|
1132
|
-
}
|
|
1133
|
-
/**
|
|
1134
|
-
* The difference with useQuery is that this function will return a Promise you can await in the Setup,
|
|
1135
|
-
* which ensures that either there always is a latest value, or an error occurs on load.
|
|
1136
|
-
* So that Suspense and error boundaries can be used.
|
|
362
|
+
* When `I = void` the input argument may be omitted.
|
|
1137
363
|
*/
|
|
1138
364
|
<
|
|
1139
|
-
|
|
365
|
+
I,
|
|
1140
366
|
E,
|
|
1141
367
|
A,
|
|
1142
368
|
Request extends Req,
|
|
1143
369
|
Name extends string
|
|
1144
370
|
>(
|
|
1145
|
-
self: RequestHandlerWithInput<
|
|
371
|
+
self: RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
1146
372
|
): {
|
|
1147
|
-
|
|
1148
|
-
* The difference with useQuery is that this function will return a Promise you can await in the Setup,
|
|
1149
|
-
* which ensures that either there always is a latest value, or an error occurs on load.
|
|
1150
|
-
* So that Suspense and error boundaries can be used.
|
|
1151
|
-
*/
|
|
1152
|
-
<TData = A>(arg: Arg | WatchSource<Arg>, options?: CustomUndefinedInitialQueryOptions<A, E, TData>): Promise<
|
|
373
|
+
<TData = A>(arg: I | WatchSource<I>, options?: CustomUndefinedInitialQueryOptions<A, E, TData>): Promise<
|
|
1153
374
|
readonly [
|
|
1154
375
|
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
1155
376
|
ComputedRef<TData>,
|
|
@@ -1160,10 +381,10 @@ export class QueryImpl<R> {
|
|
|
1160
381
|
]
|
|
1161
382
|
>
|
|
1162
383
|
}
|
|
1163
|
-
} = <
|
|
1164
|
-
self: RequestHandlerWithInput<
|
|
384
|
+
} = <I, E, A, Request extends Req, Name extends string>(
|
|
385
|
+
self: RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
1165
386
|
) => {
|
|
1166
|
-
const runPromise =
|
|
387
|
+
const runPromise = makeRunPromise(this.getRuntime())
|
|
1167
388
|
const q = this.useQuery(self as any) as any
|
|
1168
389
|
return (argOrOptions?: any, options?: any) => {
|
|
1169
390
|
const [resultRef, latestRef, fetch, uqrt] = q(argOrOptions, { ...options, suspense: true } // experimental_prefetchInRender: true }
|
|
@@ -1188,7 +409,7 @@ export class QueryImpl<R> {
|
|
|
1188
409
|
if (!isMounted.value) {
|
|
1189
410
|
return yield* Effect.interrupt
|
|
1190
411
|
}
|
|
1191
|
-
const result = resultRef
|
|
412
|
+
const result = yield* awaitResolvedSuspenseResult(resultRef)
|
|
1192
413
|
if (AsyncResult.isInitial(result)) {
|
|
1193
414
|
console.error("Internal Error: Promise should be resolved already", {
|
|
1194
415
|
self,
|
|
@@ -1214,10 +435,64 @@ export class QueryImpl<R> {
|
|
|
1214
435
|
}
|
|
1215
436
|
|
|
1216
437
|
// 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.
|
|
438
|
+
const managedRuntimeRt = <A, E>(mrt: ManagedRuntime.ManagedRuntime<A, E>) => mrt.runSync(Effect.context<A>())
|
|
1218
439
|
|
|
1219
440
|
type Base = I18n | Toast
|
|
1220
|
-
type Mix = ApiClientFactory | Commander |
|
|
441
|
+
type Mix = ApiClientFactory | Commander | Base
|
|
442
|
+
|
|
443
|
+
type InvalidationResources = Record<string, Record<string, unknown>>
|
|
444
|
+
type UnionToIntersection<U> = (U extends unknown ? (arg: U) => void : never) extends ((arg: infer I) => void) ? I
|
|
445
|
+
: never
|
|
446
|
+
|
|
447
|
+
type CommandInvalidationResources<Req> = Req extends {
|
|
448
|
+
readonly type: "command"
|
|
449
|
+
readonly "~invalidationResources"?: infer Resources
|
|
450
|
+
} ? NonNullable<Resources> extends InvalidationResources ? NonNullable<Resources> : never
|
|
451
|
+
: Req extends {
|
|
452
|
+
readonly type: "command"
|
|
453
|
+
readonly config?: infer Config
|
|
454
|
+
} ? Config extends {
|
|
455
|
+
readonly invalidationResources?: infer LegacyResources
|
|
456
|
+
} ? NonNullable<LegacyResources> extends InvalidationResources ? NonNullable<LegacyResources> : never
|
|
457
|
+
: Config extends {
|
|
458
|
+
readonly invalidatesQueries?: InvalidationCallback<infer LegacyResources, any, any, any>
|
|
459
|
+
} ? NonNullable<LegacyResources> extends InvalidationResources ? NonNullable<LegacyResources> : never
|
|
460
|
+
: never
|
|
461
|
+
: never
|
|
462
|
+
|
|
463
|
+
type InvalidationResourcesForUnion<M extends RequestsAny> = {
|
|
464
|
+
[K in keyof M]: CommandInvalidationResources<M[K]>
|
|
465
|
+
}[keyof M]
|
|
466
|
+
|
|
467
|
+
type InvalidationResourcesFor<M extends RequestsAny> = [InvalidationResourcesForUnion<M>] extends [never] ? never
|
|
468
|
+
: UnionToIntersection<InvalidationResourcesForUnion<M>> extends infer R ? R extends InvalidationResources ? R
|
|
469
|
+
: never
|
|
470
|
+
: never
|
|
471
|
+
|
|
472
|
+
type QueryInvalidationFactory<M extends RequestsAny> = (client: ClientFrom<M>) => QueryInvalidation<M>
|
|
473
|
+
|
|
474
|
+
type StrictResourcesArg<Shape, Actual extends Shape = Shape> =
|
|
475
|
+
& Actual
|
|
476
|
+
& Record<Exclude<keyof Actual, keyof Shape>, never>
|
|
477
|
+
|
|
478
|
+
type ClientForArgs<
|
|
479
|
+
M extends RequestsAny,
|
|
480
|
+
Resources extends InvalidationResourcesFor<M> = InvalidationResourcesFor<M>
|
|
481
|
+
> = [InvalidationResourcesFor<M>] extends [never] ? [
|
|
482
|
+
queryInvalidation?: QueryInvalidationFactory<M>,
|
|
483
|
+
invalidationResources?: StrictResourcesArg<
|
|
484
|
+
InvalidationResourcesFor<M>,
|
|
485
|
+
Resources
|
|
486
|
+
>
|
|
487
|
+
]
|
|
488
|
+
: [
|
|
489
|
+
queryInvalidation: QueryInvalidationFactory<M> | undefined,
|
|
490
|
+
invalidationResources: StrictResourcesArg<
|
|
491
|
+
InvalidationResourcesFor<M>,
|
|
492
|
+
Resources
|
|
493
|
+
>
|
|
494
|
+
]
|
|
495
|
+
|
|
1221
496
|
export const makeClient = <RT_, RTHooks>(
|
|
1222
497
|
// global, but only accessible after startup has completed
|
|
1223
498
|
getBaseMrt: () => ManagedRuntime.ManagedRuntime<RT_ | Mix, never>,
|
|
@@ -1225,126 +500,190 @@ export const makeClient = <RT_, RTHooks>(
|
|
|
1225
500
|
rtHooks: Layer.Layer<RTHooks, never, Mix>
|
|
1226
501
|
) => {
|
|
1227
502
|
type RT = RT_ | Mix
|
|
1228
|
-
const getRt = Effect.services<RT>()
|
|
1229
503
|
const getBaseRt = () => managedRuntimeRt(getBaseMrt())
|
|
1230
504
|
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
505
|
let cmd: Effect.Success<typeof makeCommand>
|
|
1237
506
|
const useCommand = () => cmd ??= getBaseMrt().runSync(makeCommand)
|
|
1238
|
-
let mut: Effect.Success<typeof makeMutation>
|
|
1239
|
-
const getMutation = () => mut ??= getBaseMrt().runSync(makeMutation)
|
|
1240
507
|
|
|
1241
508
|
let m: ReturnType<typeof useMutationInt>
|
|
1242
509
|
const useMutation = () => m ??= useMutationInt()
|
|
1243
510
|
|
|
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
|
-
)
|
|
511
|
+
let sm2: ReturnType<typeof makeStreamMutation2>
|
|
512
|
+
const useStreamMutation2 = () => sm2 ??= makeStreamMutation2()
|
|
1266
513
|
|
|
1267
514
|
const query = new QueryImpl(getBaseRt)
|
|
1268
515
|
const useQuery = query.useQuery
|
|
1269
516
|
const useSuspenseQuery = query.useSuspenseQuery
|
|
517
|
+
const useStreamQuery = query.useStreamQuery
|
|
518
|
+
|
|
519
|
+
const mergeInvalidation = (
|
|
520
|
+
a?: MutationOptionsBase["queryInvalidation"],
|
|
521
|
+
b?: MutationOptionsBase["queryInvalidation"]
|
|
522
|
+
): MutationOptionsBase["queryInvalidation"] | undefined => {
|
|
523
|
+
if (!a && !b) {
|
|
524
|
+
return undefined
|
|
525
|
+
}
|
|
526
|
+
return (defaultKey, name, input, output) => [
|
|
527
|
+
...(a?.(defaultKey, name, input, output) ?? []),
|
|
528
|
+
...(b?.(defaultKey, name, input, output) ?? [])
|
|
529
|
+
]
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
const withDefaultInvalidation = (
|
|
533
|
+
mut: any,
|
|
534
|
+
defaultInvalidation?: MutationOptionsBase["queryInvalidation"]
|
|
535
|
+
) => {
|
|
536
|
+
if (!defaultInvalidation) return mut
|
|
537
|
+
const apply = (callerOpts?: MutationOptionsBase) => ({
|
|
538
|
+
...callerOpts,
|
|
539
|
+
queryInvalidation: callerOpts?.queryInvalidation
|
|
540
|
+
? mergeInvalidation(defaultInvalidation, callerOpts.queryInvalidation)
|
|
541
|
+
: defaultInvalidation
|
|
542
|
+
})
|
|
543
|
+
return (input: any, callerOpts?: MutationOptionsBase) => mut(input, apply(callerOpts))
|
|
544
|
+
}
|
|
1270
545
|
|
|
1271
|
-
const
|
|
546
|
+
const makeQueryResources = <Resources extends InvalidationResources>(resources: Resources | undefined) => {
|
|
547
|
+
if (!resources) {
|
|
548
|
+
return {} as Record<string, Record<string, unknown>>
|
|
549
|
+
}
|
|
550
|
+
return resources as Record<string, Record<string, unknown>>
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
const mapQuery = <M extends RequestsAny>(
|
|
1272
554
|
client: ClientFrom<M>
|
|
1273
555
|
) => {
|
|
1274
556
|
const queries = Struct.keys(client).reduce(
|
|
1275
557
|
(acc, key) => {
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
558
|
+
const requestType = client[key].Request.type
|
|
559
|
+
const isStream = client[key].Request.stream
|
|
560
|
+
if (requestType === "query" && !isStream) {
|
|
561
|
+
;(acc as any)[camelCase(key) + "Query"] = Object.assign(useQuery(client[key] as any), {
|
|
562
|
+
id: client[key].id
|
|
563
|
+
})
|
|
564
|
+
;(acc as any)[camelCase(key) + "SuspenseQuery"] = Object.assign(useSuspenseQuery(client[key] as any), {
|
|
565
|
+
id: client[key].id
|
|
566
|
+
})
|
|
567
|
+
} else if (requestType === "query" && isStream) {
|
|
568
|
+
;(acc as any)[camelCase(key) + "Query"] = Object.assign(useStreamQuery(client[key] as any), {
|
|
569
|
+
id: client[key].id
|
|
570
|
+
})
|
|
571
|
+
}
|
|
1282
572
|
return acc
|
|
1283
573
|
},
|
|
1284
574
|
{} as
|
|
1285
575
|
& {
|
|
1286
576
|
// apparently can't get JSDoc in here..
|
|
1287
|
-
[
|
|
577
|
+
[
|
|
578
|
+
Key in keyof typeof client as QueryHandler<typeof client[Key]> extends never ? never
|
|
579
|
+
: `${ToCamel<string & Key>}Query`
|
|
580
|
+
]: Queries<RT, QueryHandler<typeof client[Key]>>["query"]
|
|
1288
581
|
}
|
|
1289
582
|
// todo: or suspense as an Option?
|
|
1290
583
|
& {
|
|
1291
584
|
// apparently can't get JSDoc in here..
|
|
1292
|
-
[
|
|
585
|
+
[
|
|
586
|
+
Key in keyof typeof client as QueryHandler<typeof client[Key]> extends never ? never
|
|
587
|
+
: `${ToCamel<string & Key>}SuspenseQuery`
|
|
588
|
+
]: Queries<
|
|
1293
589
|
RT,
|
|
1294
|
-
typeof client[Key]
|
|
590
|
+
QueryHandler<typeof client[Key]>
|
|
1295
591
|
>["suspense"]
|
|
1296
592
|
}
|
|
593
|
+
& {
|
|
594
|
+
[
|
|
595
|
+
Key in keyof typeof client as QueryStreamHandler<typeof client[Key]> extends never ? never
|
|
596
|
+
: `${ToCamel<string & Key>}Query`
|
|
597
|
+
]: StreamQueries<RT, QueryStreamHandler<typeof client[Key]>>["query"]
|
|
598
|
+
}
|
|
1297
599
|
)
|
|
1298
600
|
return queries
|
|
1299
601
|
}
|
|
1300
602
|
|
|
1301
|
-
const mapRequest = <M extends
|
|
603
|
+
const mapRequest = <M extends RequestsAny>(
|
|
1302
604
|
client: ClientFrom<M>
|
|
1303
605
|
) => {
|
|
1304
606
|
const Command = useCommand()
|
|
1305
607
|
const mutations = Struct.keys(client).reduce(
|
|
1306
608
|
(acc, key) => {
|
|
609
|
+
if (!(client[key].Request.type === "command" && !client[key].Request.stream)) {
|
|
610
|
+
return acc
|
|
611
|
+
}
|
|
1307
612
|
const mut = client[key].handler
|
|
1308
|
-
const
|
|
1309
|
-
const
|
|
613
|
+
const request = mut
|
|
614
|
+
const fn = (options?: any) => Command.fn(client[key].id, options)
|
|
615
|
+
const wrap = (options?: any) => Command.wrap({ mutate: request, id: client[key].id }, options)
|
|
1310
616
|
;(acc as any)[camelCase(key) + "Request"] = Object.assign(
|
|
1311
617
|
mut,
|
|
1312
|
-
fn, // to get the i18n key etc.
|
|
1313
|
-
{ wrap, fn }
|
|
618
|
+
Command.fn(client[key].id), // to get the i18n key etc.
|
|
619
|
+
{ wrap, fn, request }
|
|
1314
620
|
)
|
|
1315
621
|
return acc
|
|
1316
622
|
},
|
|
1317
623
|
{} as {
|
|
1318
|
-
[
|
|
624
|
+
[
|
|
625
|
+
Key in keyof typeof client as CommandHandler<typeof client[Key]> extends never ? never
|
|
626
|
+
: `${ToCamel<string & Key>}Request`
|
|
627
|
+
]: CommandRequestWithExtensions<
|
|
1319
628
|
RT | RTHooks,
|
|
1320
|
-
typeof client[Key]
|
|
629
|
+
CommandHandler<typeof client[Key]>
|
|
1321
630
|
>
|
|
1322
631
|
}
|
|
1323
632
|
)
|
|
1324
633
|
return mutations
|
|
1325
634
|
}
|
|
1326
635
|
|
|
1327
|
-
const mapMutation = <M extends
|
|
1328
|
-
client: ClientFrom<M
|
|
636
|
+
const mapMutation = <M extends RequestsAny>(
|
|
637
|
+
client: ClientFrom<M>,
|
|
638
|
+
queryInvalidation?: (client: ClientFrom<M>) => QueryInvalidation<M>,
|
|
639
|
+
invalidationResources?: InvalidationResourcesFor<M>
|
|
1329
640
|
) => {
|
|
1330
641
|
const Command = useCommand()
|
|
1331
642
|
const mutation = useMutation()
|
|
643
|
+
const invalidation = queryInvalidation?.(client)
|
|
644
|
+
const queryResources = makeQueryResources(invalidationResources)
|
|
1332
645
|
const mutations = Struct.keys(client).reduce(
|
|
1333
646
|
(acc, key) => {
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
647
|
+
if (!(client[key].Request.type === "command" && !client[key].Request.stream)) {
|
|
648
|
+
return acc
|
|
649
|
+
}
|
|
650
|
+
const fromRequestConfig = client[key].Request.config?.["invalidatesQueries"] as
|
|
651
|
+
| InvalidationCallback<InvalidationResourcesFor<M>>
|
|
652
|
+
| undefined
|
|
653
|
+
const fromRequest = fromRequestConfig
|
|
654
|
+
? ((defaultKey: string[], _name: string, input?: unknown, output?: unknown) =>
|
|
655
|
+
fromRequestConfig(
|
|
656
|
+
defaultKey,
|
|
657
|
+
queryResources as never,
|
|
658
|
+
input as never,
|
|
659
|
+
output as never
|
|
660
|
+
) as InvalidationEntry[])
|
|
661
|
+
: undefined
|
|
662
|
+
const mergedInvalidation = mergeInvalidation(fromRequest, invalidation?.[key])
|
|
663
|
+
const makeProjectedMutation = (handler: any): any => {
|
|
664
|
+
const mut: any = withDefaultInvalidation(mutation(handler), mergedInvalidation)
|
|
665
|
+
return Object.assign(mut, {
|
|
666
|
+
wrap: (options?: any) => Command.wrap({ mutate: mut, id: client[key].id }, options),
|
|
667
|
+
fn: (options?: any) => Command.fn(client[key].id, options),
|
|
668
|
+
project: (projectionSchema: any) => {
|
|
669
|
+
const projected = {
|
|
670
|
+
...handler,
|
|
671
|
+
handler: projectHandler(handler.handler, client[key].Request.success, projectionSchema)
|
|
672
|
+
}
|
|
673
|
+
return makeProjectedMutation(projected)
|
|
674
|
+
}
|
|
675
|
+
})
|
|
676
|
+
}
|
|
677
|
+
;(acc as any)[camelCase(key) + "Mutation"] = makeProjectedMutation(client[key] as any)
|
|
1342
678
|
return acc
|
|
1343
679
|
},
|
|
1344
680
|
{} as {
|
|
1345
|
-
[
|
|
681
|
+
[
|
|
682
|
+
Key in keyof typeof client as CommandHandler<typeof client[Key]> extends never ? never
|
|
683
|
+
: `${ToCamel<string & Key>}Mutation`
|
|
684
|
+
]: MutationWithExtensions<
|
|
1346
685
|
RT | RTHooks,
|
|
1347
|
-
typeof client[Key]
|
|
686
|
+
CommandHandler<typeof client[Key]>
|
|
1348
687
|
>
|
|
1349
688
|
}
|
|
1350
689
|
)
|
|
@@ -1353,8 +692,9 @@ export const makeClient = <RT_, RTHooks>(
|
|
|
1353
692
|
|
|
1354
693
|
// make available .query, .suspense and .mutate for each operation
|
|
1355
694
|
// and a .helpers with all mutations and queries
|
|
1356
|
-
const mapClient = <M extends
|
|
1357
|
-
queryInvalidation?: (client: ClientFrom<M>) => QueryInvalidation<M
|
|
695
|
+
const mapClient = <M extends RequestsAny>(
|
|
696
|
+
queryInvalidation?: (client: ClientFrom<M>) => QueryInvalidation<M>,
|
|
697
|
+
invalidationResources?: InvalidationResourcesFor<M>
|
|
1358
698
|
) =>
|
|
1359
699
|
(
|
|
1360
700
|
client: ClientFrom<M>
|
|
@@ -1362,71 +702,183 @@ export const makeClient = <RT_, RTHooks>(
|
|
|
1362
702
|
const Command = useCommand()
|
|
1363
703
|
const mutation = useMutation()
|
|
1364
704
|
const invalidation = queryInvalidation?.(client)
|
|
705
|
+
const queryResources = makeQueryResources(invalidationResources)
|
|
1365
706
|
const extended = Struct.keys(client).reduce(
|
|
1366
707
|
(acc, key) => {
|
|
708
|
+
const requestType = client[key].Request.type
|
|
709
|
+
const isStream = client[key].Request.stream
|
|
1367
710
|
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
711
|
const h_ = client[key].handler
|
|
1385
|
-
const
|
|
1386
|
-
? () => h_
|
|
1387
|
-
: (...args: [any]) => h_(...args)
|
|
712
|
+
const request = h_
|
|
1388
713
|
;(acc as any)[key] = Object.assign(
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
714
|
+
requestType === "query" && !isStream
|
|
715
|
+
? {
|
|
716
|
+
...client[key],
|
|
717
|
+
request,
|
|
718
|
+
query: useQuery(client[key] as any),
|
|
719
|
+
suspense: useSuspenseQuery(client[key] as any),
|
|
720
|
+
project: (projectionSchema: any) => {
|
|
721
|
+
const successSchema = client[key].Request.success
|
|
722
|
+
const projectionHash = projectionSchemaHash(projectionSchema)
|
|
723
|
+
const projected = projectHandler(h_ as any, successSchema, projectionSchema)
|
|
724
|
+
const fakeHandler = {
|
|
725
|
+
handler: projected,
|
|
726
|
+
id: client[key].id,
|
|
727
|
+
Request: client[key].Request,
|
|
728
|
+
options: client[key].options,
|
|
729
|
+
queryKeyProjectionHash: projectionHash
|
|
730
|
+
}
|
|
731
|
+
return {
|
|
732
|
+
request: projected,
|
|
733
|
+
query: useQuery(fakeHandler as any),
|
|
734
|
+
suspense: useSuspenseQuery(fakeHandler as any)
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
: requestType === "query" && isStream
|
|
739
|
+
? {
|
|
740
|
+
...client[key],
|
|
741
|
+
request,
|
|
742
|
+
query: useStreamQuery(client[key] as any)
|
|
743
|
+
}
|
|
744
|
+
: requestType === "command" && isStream
|
|
745
|
+
? (() => {
|
|
746
|
+
const fromRequestConfig = client[key].Request.config?.["invalidatesQueries"] as
|
|
747
|
+
| InvalidationCallback<InvalidationResourcesFor<M>>
|
|
748
|
+
| undefined
|
|
749
|
+
const fromRequest = fromRequestConfig
|
|
750
|
+
? ((defaultKey: string[], _name: string, input?: unknown, output?: unknown) =>
|
|
751
|
+
fromRequestConfig(
|
|
752
|
+
defaultKey,
|
|
753
|
+
queryResources as never,
|
|
754
|
+
input as never,
|
|
755
|
+
output as never
|
|
756
|
+
) as InvalidationEntry[])
|
|
757
|
+
: undefined
|
|
758
|
+
const mergedInvalidation = mergeInvalidation(fromRequest, invalidation?.[key])
|
|
759
|
+
const streamCmd = useCommand()
|
|
760
|
+
return {
|
|
761
|
+
...client[key],
|
|
762
|
+
request,
|
|
763
|
+
query: useStreamQuery(client[key] as any),
|
|
764
|
+
fn: (options?: any) => streamCmd.streamFn(client[key].id as any, options),
|
|
765
|
+
mutate: (() => {
|
|
766
|
+
const sm2Act = useStreamMutation2()(client[key] as any, mergedInvalidation)
|
|
767
|
+
const sm2Handler = (input: any, _ctx: any) => (sm2Act as (i: any) => any)(input)
|
|
768
|
+
return Object.assign(sm2Act, {
|
|
769
|
+
id: client[key].id,
|
|
770
|
+
wrap: (options?: any) => streamCmd.streamWrap(sm2Handler, client[key].id as any, options)
|
|
771
|
+
})
|
|
772
|
+
})()
|
|
773
|
+
}
|
|
774
|
+
})()
|
|
775
|
+
: {
|
|
776
|
+
mutate: ((handler: any) => {
|
|
777
|
+
const fromRequestConfig = client[key].Request.config?.["invalidatesQueries"] as
|
|
778
|
+
| InvalidationCallback<InvalidationResourcesFor<M>>
|
|
779
|
+
| undefined
|
|
780
|
+
const fromRequest = fromRequestConfig
|
|
781
|
+
? ((defaultKey: string[], _name: string, input?: unknown, output?: unknown) =>
|
|
782
|
+
fromRequestConfig(
|
|
783
|
+
defaultKey,
|
|
784
|
+
queryResources as never,
|
|
785
|
+
input as never,
|
|
786
|
+
output as never
|
|
787
|
+
) as InvalidationEntry[])
|
|
788
|
+
: undefined
|
|
789
|
+
const mergedInvalidation = mergeInvalidation(fromRequest, invalidation?.[key])
|
|
790
|
+
const makeProjectedMutation = (h: any): any => {
|
|
791
|
+
const mutate = withDefaultInvalidation(mutation(h), mergedInvalidation)
|
|
792
|
+
return Object.assign(
|
|
793
|
+
mutate,
|
|
794
|
+
{
|
|
795
|
+
wrap: (options?: any) =>
|
|
796
|
+
Command.wrap({
|
|
797
|
+
mutate,
|
|
798
|
+
id: client[key].id
|
|
799
|
+
}, options),
|
|
800
|
+
fn: (options?: any) => Command.fn(client[key].id, options),
|
|
801
|
+
project: (projectionSchema: any) => {
|
|
802
|
+
const projected = {
|
|
803
|
+
...h,
|
|
804
|
+
handler: projectHandler(h.handler, client[key].Request.success, projectionSchema)
|
|
805
|
+
}
|
|
806
|
+
return makeProjectedMutation(projected)
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
)
|
|
810
|
+
}
|
|
811
|
+
return makeProjectedMutation(handler)
|
|
812
|
+
})(client[key] as any),
|
|
813
|
+
...client[key],
|
|
814
|
+
...fn, // to get the i18n key etc.
|
|
815
|
+
request,
|
|
816
|
+
fn: (options?: any) => Command.fn(client[key].id, options),
|
|
817
|
+
wrap: (options?: any) => Command.wrap({ mutate: h_, id: client[key].id }, options)
|
|
818
|
+
}
|
|
1399
819
|
)
|
|
1400
820
|
return acc
|
|
1401
821
|
},
|
|
1402
822
|
{} as {
|
|
1403
823
|
[Key in keyof typeof client]:
|
|
1404
824
|
& typeof client[Key]
|
|
1405
|
-
&
|
|
1406
|
-
|
|
1407
|
-
|
|
825
|
+
& (QueryHandler<typeof client[Key]> extends never ? {}
|
|
826
|
+
:
|
|
827
|
+
& QueryRequestWithExtensions<QueryHandler<typeof client[Key]>>
|
|
828
|
+
& Queries<RT, QueryHandler<typeof client[Key]>>
|
|
829
|
+
& QueryProjection<RT, QueryHandler<typeof client[Key]>>)
|
|
830
|
+
& (QueryStreamHandler<typeof client[Key]> extends never ? {}
|
|
831
|
+
: StreamQueries<RT, QueryStreamHandler<typeof client[Key]>>)
|
|
832
|
+
& (CommandHandler<typeof client[Key]> extends never ? {}
|
|
833
|
+
: CommandRequestWithExtensions<RT | RTHooks, CommandHandler<typeof client[Key]>>)
|
|
834
|
+
& (CommandHandler<typeof client[Key]> extends never ? {}
|
|
835
|
+
: { mutate: MutationWithExtensions<RT | RTHooks, CommandHandler<typeof client[Key]>> })
|
|
836
|
+
& (CommandStreamHandler<typeof client[Key]> extends never ? {}
|
|
837
|
+
: {
|
|
838
|
+
fn: StreamFnStreamExtension<RT | RTHooks, CommandStreamHandler<typeof client[Key]>>
|
|
839
|
+
mutate: StreamMutation2WithExtensions<RT | RTHooks, CommandStreamHandler<typeof client[Key]>>
|
|
840
|
+
})
|
|
841
|
+
& {
|
|
842
|
+
Input: typeof client[Key] extends RequestStreamHandlerWithInput<infer I, any, any, any, any, any, any> ? I
|
|
843
|
+
: typeof client[Key] extends RequestHandlerWithInput<infer I, any, any, any, any, any> ? I
|
|
844
|
+
: never
|
|
845
|
+
}
|
|
1408
846
|
}
|
|
1409
847
|
)
|
|
1410
|
-
return Object.assign(extended, {
|
|
848
|
+
return Object.assign(extended, {
|
|
849
|
+
helpers: {
|
|
850
|
+
...mapRequest(client),
|
|
851
|
+
...mapMutation(client, queryInvalidation, invalidationResources),
|
|
852
|
+
...mapQuery(client)
|
|
853
|
+
}
|
|
854
|
+
})
|
|
1411
855
|
}
|
|
1412
856
|
|
|
1413
857
|
// TODO: Clean up this delay initialisation messs
|
|
1414
858
|
// TODO; invalidateQueries should perhaps be configured in the Request impl themselves?
|
|
1415
|
-
const clientFor__ = <M extends
|
|
859
|
+
const clientFor__ = <M extends RequestsAny>(
|
|
1416
860
|
m: M,
|
|
1417
|
-
queryInvalidation?:
|
|
1418
|
-
|
|
861
|
+
queryInvalidation?: QueryInvalidationFactory<M>,
|
|
862
|
+
invalidationResources?: InvalidationResourcesFor<M>
|
|
863
|
+
) => getBaseMrt().runSync(clientFor_(m).pipe(Effect.map(mapClient(queryInvalidation, invalidationResources))))
|
|
1419
864
|
|
|
1420
865
|
// delay client creation until first access
|
|
1421
866
|
// the idea is that we don't need the useNuxtApp().$runtime (only available at later initialisation stage)
|
|
1422
867
|
// until we are at a place where it is available..
|
|
1423
|
-
const clientFor = <
|
|
868
|
+
const clientFor = <
|
|
869
|
+
M extends RequestsAny,
|
|
870
|
+
Resources extends InvalidationResourcesFor<M> = InvalidationResourcesFor<M>
|
|
871
|
+
>(
|
|
1424
872
|
m: M,
|
|
1425
|
-
|
|
873
|
+
...args: ClientForArgs<M, Resources>
|
|
1426
874
|
) => {
|
|
875
|
+
const [queryInvalidation, invalidationResources] = args as [
|
|
876
|
+
QueryInvalidationFactory<M> | undefined,
|
|
877
|
+
InvalidationResourcesFor<M> | undefined
|
|
878
|
+
]
|
|
1427
879
|
type Client = ReturnType<typeof clientFor__<M>>
|
|
1428
880
|
let client: Client | undefined = undefined
|
|
1429
|
-
const getOrMakeClient = () => (client ??= clientFor__(m, queryInvalidation))
|
|
881
|
+
const getOrMakeClient = () => (client ??= clientFor__(m, queryInvalidation, invalidationResources))
|
|
1430
882
|
|
|
1431
883
|
// initialize on first use..
|
|
1432
884
|
const proxy = Struct.keys(m).concat(["helpers"]).reduce((acc, key) => {
|
|
@@ -1444,16 +896,12 @@ export const makeClient = <RT_, RTHooks>(
|
|
|
1444
896
|
return proxy
|
|
1445
897
|
}
|
|
1446
898
|
|
|
1447
|
-
const legacy: Legacy<RT> = {
|
|
1448
|
-
...mutations,
|
|
1449
|
-
...query
|
|
1450
|
-
}
|
|
1451
|
-
|
|
1452
899
|
const Command: CommanderResolved<RT, RTHooks> = {
|
|
1453
900
|
...{
|
|
1454
901
|
// delay initialisation until first use...
|
|
1455
902
|
fn: (...args: [any]) => useCommand().fn(...args),
|
|
1456
903
|
wrap: (...args: [any]) => useCommand().wrap(...args),
|
|
904
|
+
streamFn: (...args: [any]) => useCommand().streamFn(...args),
|
|
1457
905
|
alt: (...args: [any]) => useCommand().alt(...args),
|
|
1458
906
|
alt2: (...args: [any]) => useCommand().alt2(...args)
|
|
1459
907
|
} as ReturnType<typeof useCommand>,
|
|
@@ -1463,22 +911,17 @@ export const makeClient = <RT_, RTHooks>(
|
|
|
1463
911
|
return {
|
|
1464
912
|
Command,
|
|
1465
913
|
useCommand,
|
|
1466
|
-
clientFor
|
|
1467
|
-
legacy
|
|
914
|
+
clientFor
|
|
1468
915
|
}
|
|
1469
916
|
}
|
|
1470
917
|
|
|
1471
|
-
export interface Legacy<R>
|
|
1472
|
-
extends
|
|
1473
|
-
Pick<QueryImpl<R>, "useQuery" | "useSuspenseQuery">,
|
|
1474
|
-
Omit<LegacyMutationImpl<R>, "getRuntime" | "toast" | "intl">
|
|
1475
|
-
{}
|
|
1476
|
-
|
|
1477
918
|
export type QueryInvalidation<M> = {
|
|
1478
|
-
[K in keyof M]?: (
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
919
|
+
[K in keyof M]?: (
|
|
920
|
+
defaultKey: string[],
|
|
921
|
+
name: string,
|
|
922
|
+
input?: unknown,
|
|
923
|
+
output?: Exit.Exit<unknown, unknown>
|
|
924
|
+
) => InvalidationEntry[]
|
|
1482
925
|
}
|
|
1483
926
|
|
|
1484
927
|
export type ToCamel<S extends string | number | symbol> = S extends string
|
|
@@ -1486,17 +929,21 @@ export type ToCamel<S extends string | number | symbol> = S extends string
|
|
|
1486
929
|
: Uncapitalize<S>
|
|
1487
930
|
: never
|
|
1488
931
|
|
|
1489
|
-
export interface CommandBase<I = void, A = void> {
|
|
932
|
+
export interface CommandBase<I = void, A = void, RA = unknown, RE = unknown> {
|
|
1490
933
|
handle: (input: I) => A
|
|
1491
934
|
waiting: boolean
|
|
1492
935
|
blocked: boolean
|
|
1493
936
|
allowed: boolean
|
|
1494
937
|
action: string
|
|
1495
938
|
label: string
|
|
939
|
+
/** formatted progress info for current `running` state, when `progress` was supplied */
|
|
940
|
+
progress?: Progress | undefined
|
|
941
|
+
/** reactive result state, available on stream-backed commands */
|
|
942
|
+
result?: AsyncResult.AsyncResult<RA, RE>
|
|
1496
943
|
}
|
|
1497
944
|
|
|
1498
|
-
export interface EffectCommand<I = void, A = unknown, E = unknown> extends CommandBase<I, Fiber<A, E
|
|
945
|
+
export interface EffectCommand<I = void, A = unknown, E = unknown> extends CommandBase<I, Fiber<A, E>, A, E> {}
|
|
1499
946
|
|
|
1500
|
-
export interface CommandFromRequest<I extends
|
|
1501
|
-
extends EffectCommand<
|
|
947
|
+
export interface CommandFromRequest<I extends { readonly make: (...args: any[]) => any }, A = unknown, E = unknown>
|
|
948
|
+
extends EffectCommand<HandlerInput<I>, A, E>
|
|
1502
949
|
{}
|