@effect-app/vue 2.14.0 → 2.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/_cjs/index.cjs +0 -22
- package/_cjs/index.cjs.map +1 -1
- package/_cjs/makeClient.cjs +169 -72
- package/_cjs/makeClient.cjs.map +1 -1
- package/_cjs/mutate.cjs +84 -101
- package/_cjs/mutate.cjs.map +1 -1
- package/_cjs/query.cjs +9 -52
- package/_cjs/query.cjs.map +1 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/makeClient.d.ts +87 -70
- package/dist/makeClient.d.ts.map +1 -1
- package/dist/makeClient.js +164 -84
- package/dist/mutate.d.ts +18 -26
- package/dist/mutate.d.ts.map +1 -1
- package/dist/mutate.js +67 -84
- package/dist/query.d.ts +10 -24
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +13 -55
- package/package.json +8 -48
- package/src/index.ts +0 -2
- package/src/makeClient.ts +463 -227
- package/src/mutate.ts +111 -141
- package/src/query.ts +30 -116
- package/_cjs/hooks.cjs +0 -28
- package/_cjs/hooks.cjs.map +0 -1
- package/_cjs/makeClient2.cjs +0 -221
- package/_cjs/makeClient2.cjs.map +0 -1
- package/_cjs/mutate2.cjs +0 -118
- package/_cjs/mutate2.cjs.map +0 -1
- package/_cjs/query2.cjs +0 -105
- package/_cjs/query2.cjs.map +0 -1
- package/dist/hooks.d.ts +0 -3
- package/dist/hooks.d.ts.map +0 -1
- package/dist/hooks.js +0 -4
- package/dist/makeClient2.d.ts +0 -74
- package/dist/makeClient2.d.ts.map +0 -1
- package/dist/makeClient2.js +0 -187
- package/dist/mutate2.d.ts +0 -42
- package/dist/mutate2.d.ts.map +0 -1
- package/dist/mutate2.js +0 -88
- package/dist/query2.d.ts +0 -23
- package/dist/query2.d.ts.map +0 -1
- package/dist/query2.js +0 -97
- package/src/hooks.ts +0 -4
- package/src/makeClient2.ts +0 -353
- package/src/mutate2.ts +0 -197
- package/src/query2.ts +0 -205
package/src/makeClient.ts
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import * as Sentry from "@sentry/browser"
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
3
|
+
import { Cause, Effect, Exit, Match, Option, Runtime, S, Struct } from "effect-app"
|
|
4
|
+
import { CauseException, type SupportedErrors } from "effect-app/client"
|
|
5
|
+
import type { RequestHandler, RequestHandlerWithInput, TaggedRequestClassAny } from "effect-app/client/clientFor"
|
|
6
|
+
import { constant, pipe, tuple } from "effect-app/Function"
|
|
7
7
|
import type { OperationFailure } from "effect-app/Operations"
|
|
8
8
|
import { OperationSuccess } from "effect-app/Operations"
|
|
9
|
+
import type { Schema } from "effect-app/Schema"
|
|
9
10
|
import { dropUndefinedT } from "effect-app/utils"
|
|
10
|
-
import {
|
|
11
|
+
import type { ComputedRef, Ref, ShallowRef } from "vue"
|
|
12
|
+
import { computed, ref, watch } from "vue"
|
|
13
|
+
import { buildFieldInfoFromFieldsRoot } from "./form.js"
|
|
14
|
+
import { getRuntime } from "./lib.js"
|
|
11
15
|
import type { MakeIntlReturn } from "./makeIntl.js"
|
|
12
|
-
import
|
|
13
|
-
import {
|
|
16
|
+
import { makeMutation2, mutationResultToVue } from "./mutate.js"
|
|
17
|
+
import type { MutationOptions, Res } from "./mutate.js"
|
|
18
|
+
import { makeQuery2 } from "./query.js"
|
|
14
19
|
|
|
15
20
|
/**
|
|
16
21
|
* Use this after handling an error yourself, still continueing on the Error track, but the error will not be reported.
|
|
@@ -21,86 +26,55 @@ export class SuppressErrors extends Cause.YieldableError {
|
|
|
21
26
|
|
|
22
27
|
export type ResponseErrors = S.ParseResult.ParseError | SupportedErrors | SuppressErrors | OperationFailure
|
|
23
28
|
|
|
24
|
-
export interface Opts<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
export interface Opts<
|
|
30
|
+
A,
|
|
31
|
+
E,
|
|
32
|
+
I = void,
|
|
33
|
+
ESuccess = never,
|
|
34
|
+
RSuccess = never,
|
|
35
|
+
EError = never,
|
|
36
|
+
RError = never,
|
|
37
|
+
EDefect = never,
|
|
38
|
+
RDefect = never
|
|
39
|
+
> extends MutationOptions {
|
|
40
|
+
/** set to `undefined` to use default message */
|
|
41
|
+
successMessage?: ((a: A, i: I) => Effect<string | undefined, ESuccess, RSuccess>) | undefined
|
|
42
|
+
/** set to `undefined` to use default message */
|
|
43
|
+
failMessage?: ((e: E, i: I) => Effect<string | undefined, EError, RError>) | undefined
|
|
44
|
+
/** set to `undefined` to use default message */
|
|
45
|
+
defectMessage?: ((e: Cause.Cause<E>, i: I) => Effect<string | undefined, EDefect, RDefect>) | undefined
|
|
28
46
|
}
|
|
29
47
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
) => Effect<any, any, any>
|
|
61
|
-
)(i),
|
|
62
|
-
Effect.flatMap((_) =>
|
|
63
|
-
Effect.promise(() => onSuccess(_, i)).pipe(
|
|
64
|
-
Effect.withSpan("onSuccess")
|
|
65
|
-
)
|
|
66
|
-
)
|
|
67
|
-
)
|
|
68
|
-
: Effect.flatMap(self.handler, (_) => Effect.promise(() => onSuccess(_)).pipe(Effect.withSpan("onSuccess")))
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
/** @deprecated - use mapHandler */
|
|
72
|
-
export const withSuccessE: {
|
|
73
|
-
<I, E, A, E2, X, R>(
|
|
74
|
-
self: {
|
|
75
|
-
handler: (i: I) => Effect<A, E, R>
|
|
76
|
-
name: string
|
|
77
|
-
},
|
|
78
|
-
onSuccessE: (_: A, i: I) => Effect<X, E2>
|
|
79
|
-
): {
|
|
80
|
-
handler: (i: I) => Effect<X, E | E2, R>
|
|
81
|
-
name: string
|
|
82
|
-
}
|
|
83
|
-
<E, A, E2, X, R>(
|
|
84
|
-
self: {
|
|
85
|
-
handler: Effect<A, E, R>
|
|
86
|
-
name: string
|
|
87
|
-
},
|
|
88
|
-
onSuccessE: (_: A) => Effect<X, E2>
|
|
89
|
-
): {
|
|
90
|
-
handler: Effect<X, E | E2, R>
|
|
91
|
-
name: string
|
|
92
|
-
}
|
|
93
|
-
} = (self: any, onSuccessE: any): any => {
|
|
94
|
-
return {
|
|
95
|
-
...self,
|
|
96
|
-
handler: typeof self.handler === "function"
|
|
97
|
-
? (i: any) =>
|
|
98
|
-
pipe(
|
|
99
|
-
self.handler(i),
|
|
100
|
-
Effect.flatMap((_) => onSuccessE(_, i))
|
|
101
|
-
)
|
|
102
|
-
: Effect.flatMap(self.handler, (_) => onSuccessE(_))
|
|
103
|
-
}
|
|
48
|
+
export interface LowOpts<
|
|
49
|
+
A,
|
|
50
|
+
E,
|
|
51
|
+
I = void,
|
|
52
|
+
ESuccess = never,
|
|
53
|
+
RSuccess = never,
|
|
54
|
+
EError = never,
|
|
55
|
+
RError = never,
|
|
56
|
+
EDefect = never,
|
|
57
|
+
RDefect = never
|
|
58
|
+
> {
|
|
59
|
+
onSuccess: (a: A, i: I) => Effect<void, ESuccess, RSuccess>
|
|
60
|
+
onFail: (e: E, i: I) => Effect<void, EError, RError>
|
|
61
|
+
onDefect: (e: Cause.Cause<E>, i: I) => Effect<void, EDefect, RDefect>
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface LowOptsOptional<
|
|
65
|
+
A,
|
|
66
|
+
E,
|
|
67
|
+
I = void,
|
|
68
|
+
ESuccess = never,
|
|
69
|
+
RSuccess = never,
|
|
70
|
+
EError = never,
|
|
71
|
+
RError = never,
|
|
72
|
+
EDefect = never,
|
|
73
|
+
RDefect = never
|
|
74
|
+
> extends MutationOptions {
|
|
75
|
+
onSuccess?: (a: A, i: I) => Effect<void, ESuccess, RSuccess>
|
|
76
|
+
onFail?: (e: E, i: I) => Effect<void, EError, RError>
|
|
77
|
+
onDefect?: (e: Cause.Cause<E>, i: I) => Effect<void, EDefect, RDefect>
|
|
104
78
|
}
|
|
105
79
|
|
|
106
80
|
type WithAction<A> = A & {
|
|
@@ -109,26 +83,113 @@ type WithAction<A> = A & {
|
|
|
109
83
|
|
|
110
84
|
// computed() takes a getter function and returns a readonly reactive ref
|
|
111
85
|
// object for the returned value from the getter.
|
|
112
|
-
type Resp<I, E,
|
|
86
|
+
type Resp<I, A, E, R> = readonly [
|
|
113
87
|
ComputedRef<Res<A, E>>,
|
|
114
|
-
WithAction<(I: I) =>
|
|
88
|
+
WithAction<(I: I) => Effect<Exit<A, E>, never, R>>
|
|
115
89
|
]
|
|
116
90
|
|
|
117
|
-
type ActResp<E,
|
|
91
|
+
type ActResp<A, E, R> = readonly [
|
|
118
92
|
ComputedRef<Res<A, E>>,
|
|
119
|
-
WithAction<
|
|
93
|
+
WithAction<Effect<Exit<A, E>, never, R>>
|
|
120
94
|
]
|
|
121
95
|
|
|
122
|
-
export const
|
|
96
|
+
export const suppressToast = constant(Effect.succeed(undefined))
|
|
97
|
+
|
|
98
|
+
export function handleRequest<
|
|
99
|
+
E extends ResponseErrors,
|
|
100
|
+
A,
|
|
101
|
+
R,
|
|
102
|
+
I = void,
|
|
103
|
+
ESuccess = never,
|
|
104
|
+
RSuccess = never,
|
|
105
|
+
EError = never,
|
|
106
|
+
RError = never,
|
|
107
|
+
EDefect = never,
|
|
108
|
+
RDefect = never
|
|
109
|
+
>(
|
|
110
|
+
f: Effect<A, E, R> | ((i: I) => Effect<A, E, R>),
|
|
111
|
+
action: string,
|
|
112
|
+
options: {
|
|
113
|
+
onSuccess: (a: A, i: I) => Effect<void, ESuccess, RSuccess>
|
|
114
|
+
onFail: (e: E, i: I) => Effect<void, EError, RError>
|
|
115
|
+
onDefect: (e: Cause.Cause<E>, i: I) => Effect<void, EDefect, RDefect>
|
|
116
|
+
}
|
|
117
|
+
) {
|
|
118
|
+
const handleEffect = (i: any) => (self: Effect<A, E, R>) =>
|
|
119
|
+
self.pipe(
|
|
120
|
+
Effect.exit,
|
|
121
|
+
Effect.tap(
|
|
122
|
+
Exit.matchEffect({
|
|
123
|
+
onSuccess: (r) => options.onSuccess(r, i),
|
|
124
|
+
onFailure: (cause) =>
|
|
125
|
+
Effect.gen(function*() {
|
|
126
|
+
if (Cause.isInterruptedOnly(cause)) {
|
|
127
|
+
console.info(`Interrupted while trying to ${action}`)
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const fail = Cause.failureOption(cause)
|
|
132
|
+
if (Option.isSome(fail)) {
|
|
133
|
+
if (fail.value._tag === "SuppressErrors") {
|
|
134
|
+
console.info(`Suppressed error trying to ${action}`, fail.value)
|
|
135
|
+
return
|
|
136
|
+
}
|
|
137
|
+
const message = `Failure trying to ${action}`
|
|
138
|
+
console.warn(message, fail.value)
|
|
139
|
+
Sentry.captureMessage(message, { extra: { action, error: fail.value } })
|
|
140
|
+
yield* options.onFail(fail.value, i)
|
|
141
|
+
return
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const extra = {
|
|
145
|
+
action,
|
|
146
|
+
message: `Unexpected Error trying to ${action}`
|
|
147
|
+
}
|
|
148
|
+
console.error(extra.message, cause)
|
|
149
|
+
Sentry.captureException(new CauseException(cause, "defect"), { extra })
|
|
150
|
+
|
|
151
|
+
yield* options.onDefect(cause, i)
|
|
152
|
+
})
|
|
153
|
+
})
|
|
154
|
+
),
|
|
155
|
+
Effect.tapErrorCause((cause) =>
|
|
156
|
+
Effect.sync(() => {
|
|
157
|
+
const extra = {
|
|
158
|
+
action,
|
|
159
|
+
message: `Unexpected Error trying to handle errors for ${action}`
|
|
160
|
+
}
|
|
161
|
+
Sentry.captureException(new CauseException(cause, "unhandled"), { extra })
|
|
162
|
+
console.error(Cause.pretty(cause), extra)
|
|
163
|
+
})
|
|
164
|
+
)
|
|
165
|
+
)
|
|
166
|
+
return Object.assign(
|
|
167
|
+
Effect.isEffect(f)
|
|
168
|
+
? pipe(
|
|
169
|
+
f,
|
|
170
|
+
handleEffect(void 0)
|
|
171
|
+
)
|
|
172
|
+
: (i: I) =>
|
|
173
|
+
pipe(
|
|
174
|
+
f(i),
|
|
175
|
+
handleEffect(i)
|
|
176
|
+
),
|
|
177
|
+
{ action }
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export const makeClient2 = <Locale extends string, R>(
|
|
123
182
|
useIntl: MakeIntlReturn<Locale>["useIntl"],
|
|
124
183
|
useToast: () => {
|
|
125
184
|
error: (message: string) => void
|
|
126
185
|
warning: (message: string) => void
|
|
127
186
|
success: (message: string) => void
|
|
128
187
|
},
|
|
129
|
-
|
|
188
|
+
runtime: ShallowRef<Runtime.Runtime<R> | undefined>,
|
|
130
189
|
messages: Record<string, string | undefined> = {}
|
|
131
190
|
) => {
|
|
191
|
+
const useSafeMutation = makeMutation2()
|
|
192
|
+
const useSafeQuery = makeQuery2(runtime)
|
|
132
193
|
const useHandleRequestWithToast = () => {
|
|
133
194
|
const toast = useToast()
|
|
134
195
|
const { intl } = useIntl()
|
|
@@ -141,91 +202,78 @@ export const makeClient = <Locale extends string, R>(
|
|
|
141
202
|
function handleRequestWithToast<
|
|
142
203
|
E extends ResponseErrors,
|
|
143
204
|
A,
|
|
144
|
-
|
|
205
|
+
R,
|
|
206
|
+
I = void,
|
|
207
|
+
ESuccess = never,
|
|
208
|
+
RSuccess = never,
|
|
209
|
+
EError = never,
|
|
210
|
+
RError = never,
|
|
211
|
+
EDefect = never,
|
|
212
|
+
RDefect = never
|
|
145
213
|
>(
|
|
146
|
-
f: (
|
|
214
|
+
f: Effect<A, E, R> | ((i: I) => Effect<A, E, R>),
|
|
147
215
|
action: string,
|
|
148
|
-
options: Opts<A> = {
|
|
216
|
+
options: Opts<A, E, I, ESuccess, RSuccess, EError, RError, EDefect, RDefect> = {}
|
|
149
217
|
) {
|
|
150
|
-
const
|
|
151
|
-
const
|
|
218
|
+
const actionMessage = messages[action] ?? action
|
|
219
|
+
const defaultWarnMessage = intl.value.formatMessage(
|
|
152
220
|
{ id: "handle.with_warnings" },
|
|
153
|
-
{ action:
|
|
221
|
+
{ action: actionMessage }
|
|
154
222
|
)
|
|
155
|
-
const
|
|
223
|
+
const defaultSuccessMessage = intl.value.formatMessage(
|
|
156
224
|
{ id: "handle.success" },
|
|
157
|
-
{ action:
|
|
225
|
+
{ action: actionMessage }
|
|
158
226
|
)
|
|
159
|
-
const
|
|
227
|
+
const defaultErrorMessage = intl.value.formatMessage(
|
|
160
228
|
{ id: "handle.with_errors" },
|
|
161
|
-
{ action:
|
|
229
|
+
{ action: actionMessage }
|
|
162
230
|
)
|
|
163
|
-
return Object.assign(
|
|
164
|
-
flow(f, (p) =>
|
|
165
|
-
p.then(
|
|
166
|
-
(r) => {
|
|
167
|
-
if (r._tag === "Right") {
|
|
168
|
-
if (options.suppressSuccessToast) {
|
|
169
|
-
return
|
|
170
|
-
}
|
|
171
|
-
return Promise
|
|
172
|
-
.resolve(
|
|
173
|
-
toast.success(
|
|
174
|
-
successMessage
|
|
175
|
-
+ (S.is(OperationSuccess)(r.right) && r.right.message
|
|
176
|
-
? "\n" + r.right.message
|
|
177
|
-
: "")
|
|
178
|
-
)
|
|
179
|
-
)
|
|
180
|
-
.then((_) => {})
|
|
181
|
-
}
|
|
182
|
-
if (r.left._tag === "SuppressErrors") {
|
|
183
|
-
return Promise.resolve(void 0)
|
|
184
|
-
}
|
|
185
231
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
232
|
+
return handleRequest<E, A, R, any, ESuccess, RSuccess, EError, RError, EDefect, RDefect>(f, action, {
|
|
233
|
+
onSuccess: (a, i) =>
|
|
234
|
+
Effect.gen(function*() {
|
|
235
|
+
const message = options.successMessage ? yield* options.successMessage(a, i) : defaultSuccessMessage
|
|
236
|
+
+ (S.is(OperationSuccess)(a) && a.message
|
|
237
|
+
? "\n" + a.message
|
|
238
|
+
: "")
|
|
239
|
+
if (message) {
|
|
240
|
+
toast.success(message)
|
|
241
|
+
}
|
|
242
|
+
}),
|
|
243
|
+
onFail: (e, i) =>
|
|
244
|
+
Effect.gen(function*() {
|
|
245
|
+
if (!options.failMessage && e._tag === "OperationFailure") {
|
|
246
|
+
toast.warning(
|
|
247
|
+
defaultWarnMessage + e.message
|
|
248
|
+
? "\n" + e.message
|
|
249
|
+
: ""
|
|
250
|
+
)
|
|
251
|
+
return
|
|
252
|
+
}
|
|
196
253
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
console.error(err, extra)
|
|
215
|
-
|
|
216
|
-
return toast.error(
|
|
217
|
-
intl.value.formatMessage(
|
|
218
|
-
{ id: "handle.unexpected_error" },
|
|
219
|
-
{
|
|
220
|
-
action: message,
|
|
221
|
-
error: JSON.stringify(err, undefined, 2)
|
|
222
|
-
}
|
|
223
|
-
)
|
|
254
|
+
const message = options.failMessage
|
|
255
|
+
? yield* options.failMessage(e, i)
|
|
256
|
+
: `${defaultErrorMessage}:\n` + renderError(e)
|
|
257
|
+
if (message) {
|
|
258
|
+
toast.error(message)
|
|
259
|
+
}
|
|
260
|
+
}),
|
|
261
|
+
onDefect: (cause, i) =>
|
|
262
|
+
Effect.gen(function*() {
|
|
263
|
+
const message = options.defectMessage
|
|
264
|
+
? yield* options.defectMessage(cause, i)
|
|
265
|
+
: intl.value.formatMessage(
|
|
266
|
+
{ id: "handle.unexpected_error" },
|
|
267
|
+
{
|
|
268
|
+
action: actionMessage,
|
|
269
|
+
error: Cause.pretty(cause)
|
|
270
|
+
}
|
|
224
271
|
)
|
|
272
|
+
if (message) {
|
|
273
|
+
toast.error(message)
|
|
225
274
|
}
|
|
226
|
-
)
|
|
227
|
-
|
|
228
|
-
)
|
|
275
|
+
})
|
|
276
|
+
})
|
|
229
277
|
}
|
|
230
278
|
|
|
231
279
|
function renderError(e: ResponseErrors): string {
|
|
@@ -283,44 +331,58 @@ export const makeClient = <Locale extends string, R>(
|
|
|
283
331
|
}
|
|
284
332
|
|
|
285
333
|
/**
|
|
286
|
-
* Pass a function that returns an Effect, e.g from a client action, give it a name
|
|
287
|
-
* Returns a tuple with state ref and execution function which reports errors as Toast.
|
|
334
|
+
* Pass a function that returns an Effect, e.g from a client action, give it a name.
|
|
335
|
+
* Returns a tuple with state ref and execution function which reports success and errors as Toast.
|
|
288
336
|
*/
|
|
289
337
|
const useAndHandleMutation: {
|
|
290
|
-
<
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
338
|
+
<
|
|
339
|
+
I,
|
|
340
|
+
E extends ResponseErrors,
|
|
341
|
+
A,
|
|
342
|
+
R,
|
|
343
|
+
Request extends TaggedRequestClassAny,
|
|
344
|
+
ESuccess = never,
|
|
345
|
+
RSuccess = never,
|
|
346
|
+
EError = never,
|
|
347
|
+
RError = never,
|
|
348
|
+
EDefect = never,
|
|
349
|
+
RDefect = never
|
|
350
|
+
>(
|
|
351
|
+
self: RequestHandlerWithInput<I, A, E, R, Request>,
|
|
295
352
|
action: string,
|
|
296
|
-
options?: Opts<A, I>
|
|
297
|
-
): Resp<I,
|
|
298
|
-
<
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
353
|
+
options?: Opts<A, E, I, ESuccess, RSuccess, EError, RError, EDefect, RDefect>
|
|
354
|
+
): Resp<I, void, never, R>
|
|
355
|
+
<
|
|
356
|
+
E extends ResponseErrors,
|
|
357
|
+
A,
|
|
358
|
+
R,
|
|
359
|
+
Request extends TaggedRequestClassAny,
|
|
360
|
+
ESuccess = never,
|
|
361
|
+
RSuccess = never,
|
|
362
|
+
EError = never,
|
|
363
|
+
RError = never,
|
|
364
|
+
EDefect = never,
|
|
365
|
+
RDefect = never
|
|
366
|
+
>(
|
|
367
|
+
self: RequestHandler<A, E, R, Request>,
|
|
303
368
|
action: string,
|
|
304
|
-
options?: Opts<A>
|
|
305
|
-
): ActResp<
|
|
306
|
-
} = (self: any, action: any, options?: Opts<any>) => {
|
|
369
|
+
options?: Opts<A, E, void, ESuccess, RSuccess, EError, RError, EDefect, RDefect>
|
|
370
|
+
): ActResp<void, never, R>
|
|
371
|
+
} = (self: any, action: any, options?: Opts<any, any, any, any, any, any, any, any, any>): any => {
|
|
307
372
|
const handleRequestWithToast = useHandleRequestWithToast()
|
|
308
|
-
const [a, b] = useSafeMutation(
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
373
|
+
const [a, b] = useSafeMutation({
|
|
374
|
+
...self,
|
|
375
|
+
handler: Effect.isEffect(self.handler)
|
|
376
|
+
? (pipe(
|
|
377
|
+
Effect.annotateCurrentSpan({ action }),
|
|
378
|
+
Effect.andThen(self.handler)
|
|
379
|
+
) as any)
|
|
380
|
+
: (...args: any[]) =>
|
|
381
|
+
pipe(
|
|
312
382
|
Effect.annotateCurrentSpan({ action }),
|
|
313
|
-
Effect.andThen(self.handler)
|
|
314
|
-
)
|
|
315
|
-
|
|
316
|
-
pipe(
|
|
317
|
-
Effect.annotateCurrentSpan({ action }),
|
|
318
|
-
Effect.andThen(self.handler(...args))
|
|
319
|
-
),
|
|
320
|
-
name: self.name
|
|
321
|
-
},
|
|
322
|
-
options ? dropUndefinedT(options) : undefined
|
|
323
|
-
)
|
|
383
|
+
Effect.andThen(self.handler(...args))
|
|
384
|
+
)
|
|
385
|
+
}, options ? dropUndefinedT(options) : undefined)
|
|
324
386
|
|
|
325
387
|
return tuple(
|
|
326
388
|
computed(() => mutationResultToVue(a.value)),
|
|
@@ -328,49 +390,162 @@ export const makeClient = <Locale extends string, R>(
|
|
|
328
390
|
)
|
|
329
391
|
}
|
|
330
392
|
|
|
393
|
+
/**
|
|
394
|
+
* The same as @see useAndHandleMutation, but does not display any toasts by default.
|
|
395
|
+
* Messages for success, error and defect toasts can be provided in the Options.
|
|
396
|
+
*/
|
|
397
|
+
const useAndHandleMutationSilently: {
|
|
398
|
+
<
|
|
399
|
+
I,
|
|
400
|
+
E extends ResponseErrors,
|
|
401
|
+
A,
|
|
402
|
+
R,
|
|
403
|
+
Request extends TaggedRequestClassAny,
|
|
404
|
+
ESuccess = never,
|
|
405
|
+
RSuccess = never,
|
|
406
|
+
EError = never,
|
|
407
|
+
RError = never,
|
|
408
|
+
EDefect = never,
|
|
409
|
+
RDefect = never
|
|
410
|
+
>(
|
|
411
|
+
self: RequestHandlerWithInput<I, A, E, R, Request>,
|
|
412
|
+
action: string,
|
|
413
|
+
options?: Opts<A, E, I, ESuccess, RSuccess, EError, RError, EDefect, RDefect>
|
|
414
|
+
): Resp<I, void, never, R>
|
|
415
|
+
<
|
|
416
|
+
E extends ResponseErrors,
|
|
417
|
+
A,
|
|
418
|
+
R,
|
|
419
|
+
Request extends TaggedRequestClassAny,
|
|
420
|
+
ESuccess = never,
|
|
421
|
+
RSuccess = never,
|
|
422
|
+
EError = never,
|
|
423
|
+
RError = never,
|
|
424
|
+
EDefect = never,
|
|
425
|
+
RDefect = never
|
|
426
|
+
>(
|
|
427
|
+
self: RequestHandler<A, E, R, Request>,
|
|
428
|
+
action: string,
|
|
429
|
+
options?: Opts<A, E, void, ESuccess, RSuccess, EError, RError, EDefect, RDefect>
|
|
430
|
+
): ActResp<void, never, R>
|
|
431
|
+
} = makeUseAndHandleMutation({
|
|
432
|
+
successMessage: suppressToast,
|
|
433
|
+
failMessage: suppressToast,
|
|
434
|
+
defectMessage: suppressToast
|
|
435
|
+
}) as any
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* The same as @see useAndHandleMutation, but does not act on success, error or defect by default.
|
|
439
|
+
* Actions for success, error and defect can be provided in the Options.
|
|
440
|
+
*/
|
|
441
|
+
const useAndHandleMutationCustom: {
|
|
442
|
+
<
|
|
443
|
+
I,
|
|
444
|
+
E extends ResponseErrors,
|
|
445
|
+
A,
|
|
446
|
+
R,
|
|
447
|
+
Request extends TaggedRequestClassAny,
|
|
448
|
+
ESuccess = never,
|
|
449
|
+
RSuccess = never,
|
|
450
|
+
EError = never,
|
|
451
|
+
RError = never,
|
|
452
|
+
EDefect = never,
|
|
453
|
+
RDefect = never
|
|
454
|
+
>(
|
|
455
|
+
self: RequestHandlerWithInput<I, A, E, R, Request>,
|
|
456
|
+
action: string,
|
|
457
|
+
options?: LowOptsOptional<A, E, I, ESuccess, RSuccess, EError, RError, EDefect, RDefect>
|
|
458
|
+
): Resp<I, void, never, R>
|
|
459
|
+
<
|
|
460
|
+
E extends ResponseErrors,
|
|
461
|
+
A,
|
|
462
|
+
R,
|
|
463
|
+
Request extends TaggedRequestClassAny,
|
|
464
|
+
ESuccess = never,
|
|
465
|
+
RSuccess = never,
|
|
466
|
+
EError = never,
|
|
467
|
+
RError = never,
|
|
468
|
+
EDefect = never,
|
|
469
|
+
RDefect = never
|
|
470
|
+
>(
|
|
471
|
+
self: RequestHandler<A, E, R, Request>,
|
|
472
|
+
action: string,
|
|
473
|
+
options?: LowOptsOptional<A, E, void, ESuccess, RSuccess, EError, RError, EDefect, RDefect>
|
|
474
|
+
): ActResp<void, never, R>
|
|
475
|
+
} = (self: any, action: string, options: any) => {
|
|
476
|
+
const [a, b] = useSafeMutation({
|
|
477
|
+
...self,
|
|
478
|
+
handler: Effect.isEffect(self.handler)
|
|
479
|
+
? (pipe(
|
|
480
|
+
Effect.annotateCurrentSpan({ action }),
|
|
481
|
+
Effect.andThen(self.handler)
|
|
482
|
+
) as any)
|
|
483
|
+
: (...args: any[]) =>
|
|
484
|
+
pipe(
|
|
485
|
+
Effect.annotateCurrentSpan({ action }),
|
|
486
|
+
Effect.andThen(self.handler(...args))
|
|
487
|
+
)
|
|
488
|
+
}, options ? dropUndefinedT(options) : undefined)
|
|
489
|
+
|
|
490
|
+
return tuple(
|
|
491
|
+
computed(() => mutationResultToVue(a.value)),
|
|
492
|
+
handleRequest(b as any, action, {
|
|
493
|
+
onSuccess: suppressToast,
|
|
494
|
+
onDefect: suppressToast,
|
|
495
|
+
onFail: suppressToast,
|
|
496
|
+
...options
|
|
497
|
+
})
|
|
498
|
+
) as any
|
|
499
|
+
}
|
|
500
|
+
|
|
331
501
|
function makeUseAndHandleMutation(
|
|
332
|
-
|
|
333
|
-
defaultOptions?: Opts<any>
|
|
502
|
+
defaultOptions?: Opts<any, any, any, any, any, any, any, any, any>
|
|
334
503
|
) {
|
|
335
504
|
return ((self: any, action: any, options: any) => {
|
|
336
505
|
return useAndHandleMutation(
|
|
337
|
-
|
|
338
|
-
handler: typeof self.handler === "function"
|
|
339
|
-
? onSuccess
|
|
340
|
-
? (i: any) => Effect.tap(self.handler(i), () => Effect.promise(onSuccess))
|
|
341
|
-
: self.handler
|
|
342
|
-
: onSuccess
|
|
343
|
-
? (Effect.tap(self.handler, () => Effect.promise(onSuccess)) as any)
|
|
344
|
-
: self.handler,
|
|
345
|
-
name: self.name
|
|
346
|
-
},
|
|
506
|
+
self,
|
|
347
507
|
action,
|
|
348
508
|
{ ...defaultOptions, ...options }
|
|
349
509
|
)
|
|
350
|
-
}) as {
|
|
351
|
-
<
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
510
|
+
}) as unknown as {
|
|
511
|
+
<
|
|
512
|
+
I,
|
|
513
|
+
E extends ResponseErrors,
|
|
514
|
+
A,
|
|
515
|
+
R,
|
|
516
|
+
Request extends TaggedRequestClassAny,
|
|
517
|
+
ESuccess = never,
|
|
518
|
+
RSuccess = never,
|
|
519
|
+
EError = never,
|
|
520
|
+
RError = never,
|
|
521
|
+
EDefect = never,
|
|
522
|
+
RDefect = never
|
|
523
|
+
>(
|
|
524
|
+
self: RequestHandlerWithInput<I, A, E, R, Request>,
|
|
356
525
|
action: string,
|
|
357
|
-
options?: Opts<A, I>
|
|
358
|
-
): Resp<I, A, E>
|
|
359
|
-
<
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
526
|
+
options?: Opts<A, E, I, ESuccess, RSuccess, EError, RError, EDefect, RDefect>
|
|
527
|
+
): Resp<I, A, E, R>
|
|
528
|
+
<
|
|
529
|
+
E extends ResponseErrors,
|
|
530
|
+
A,
|
|
531
|
+
Request extends TaggedRequestClassAny,
|
|
532
|
+
ESuccess = never,
|
|
533
|
+
RSuccess = never,
|
|
534
|
+
EError = never,
|
|
535
|
+
RError = never,
|
|
536
|
+
EDefect = never,
|
|
537
|
+
RDefect = never
|
|
538
|
+
>(
|
|
539
|
+
self: RequestHandler<A, E, R, Request>,
|
|
364
540
|
action: string,
|
|
365
|
-
options?: Opts<A>
|
|
366
|
-
): ActResp<E,
|
|
541
|
+
options?: Opts<A, E, void, ESuccess, RSuccess, EError, RError, EDefect, RDefect>
|
|
542
|
+
): ActResp<A, E, R>
|
|
367
543
|
}
|
|
368
544
|
}
|
|
369
545
|
|
|
370
|
-
const useSafeMutationWithState = <I, E, A>(
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
}) => {
|
|
546
|
+
const useSafeMutationWithState = <I, E, A, Request extends TaggedRequestClassAny>(
|
|
547
|
+
self: RequestHandlerWithInput<I, A, E, R, Request>
|
|
548
|
+
) => {
|
|
374
549
|
const [a, b] = useSafeMutation(self)
|
|
375
550
|
|
|
376
551
|
return tuple(
|
|
@@ -379,10 +554,71 @@ export const makeClient = <Locale extends string, R>(
|
|
|
379
554
|
)
|
|
380
555
|
}
|
|
381
556
|
|
|
557
|
+
const buildFormFromSchema = <
|
|
558
|
+
From extends Record<PropertyKey, any>,
|
|
559
|
+
To extends Record<PropertyKey, any>,
|
|
560
|
+
C extends Record<PropertyKey, any>,
|
|
561
|
+
OnSubmitA
|
|
562
|
+
>(
|
|
563
|
+
s:
|
|
564
|
+
& Schema<
|
|
565
|
+
To,
|
|
566
|
+
From,
|
|
567
|
+
R
|
|
568
|
+
>
|
|
569
|
+
& { new(c: C): any; fields: S.Struct.Fields },
|
|
570
|
+
state: Ref<Omit<From, "_tag">>,
|
|
571
|
+
onSubmit: (a: To) => Effect<OnSubmitA, never, R>
|
|
572
|
+
) => {
|
|
573
|
+
const fields = buildFieldInfoFromFieldsRoot(s).fields
|
|
574
|
+
const schema = S.Struct(Struct.omit(s.fields, "_tag")) as any
|
|
575
|
+
const parse = S.decodeUnknown<any, any, R>(schema)
|
|
576
|
+
const isDirty = ref(false)
|
|
577
|
+
const isValid = ref(true)
|
|
578
|
+
const runPromise = Runtime.runPromise(getRuntime(runtime))
|
|
579
|
+
|
|
580
|
+
const submit1 =
|
|
581
|
+
(onSubmit: (a: To) => Effect<OnSubmitA, never, R>) => async <T extends Promise<{ valid: boolean }>>(e: T) => {
|
|
582
|
+
const r = await e
|
|
583
|
+
if (!r.valid) return
|
|
584
|
+
return runPromise(onSubmit(new s(await runPromise(parse(state.value)))))
|
|
585
|
+
}
|
|
586
|
+
const submit = submit1(onSubmit)
|
|
587
|
+
|
|
588
|
+
watch(
|
|
589
|
+
state,
|
|
590
|
+
(v) => {
|
|
591
|
+
// TODO: do better
|
|
592
|
+
isDirty.value = JSON.stringify(v) !== JSON.stringify(state.value)
|
|
593
|
+
},
|
|
594
|
+
{ deep: true }
|
|
595
|
+
)
|
|
596
|
+
|
|
597
|
+
const submitFromState = Effect.gen(function*() {
|
|
598
|
+
if (!isValid.value) return
|
|
599
|
+
return yield* onSubmit(yield* parse(state.value))
|
|
600
|
+
}) // () => submit(Promise.resolve({ valid: isValid.value }))
|
|
601
|
+
|
|
602
|
+
return {
|
|
603
|
+
fields,
|
|
604
|
+
/** optimized for Vuetify v-form submit callback */
|
|
605
|
+
submit,
|
|
606
|
+
/** optimized for Native form submit callback or general use */
|
|
607
|
+
submitFromState,
|
|
608
|
+
isDirty,
|
|
609
|
+
isValid
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
382
613
|
return {
|
|
383
614
|
useSafeMutationWithState,
|
|
384
615
|
useAndHandleMutation,
|
|
616
|
+
useAndHandleMutationSilently,
|
|
617
|
+
useAndHandleMutationCustom,
|
|
385
618
|
makeUseAndHandleMutation,
|
|
386
|
-
useHandleRequestWithToast
|
|
619
|
+
useHandleRequestWithToast,
|
|
620
|
+
buildFormFromSchema,
|
|
621
|
+
useSafeQuery,
|
|
622
|
+
useSafeMutation
|
|
387
623
|
}
|
|
388
624
|
}
|