@effect-app/vue 2.94.0 → 4.0.0-beta.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 +11 -0
- package/dist/errorReporter.d.ts +2 -2
- package/dist/errorReporter.d.ts.map +1 -1
- package/dist/errorReporter.js +9 -9
- package/dist/experimental/commander.d.ts +46 -66
- package/dist/experimental/commander.d.ts.map +1 -1
- package/dist/experimental/commander.js +27 -29
- package/dist/experimental/confirm.d.ts +11 -5
- package/dist/experimental/confirm.d.ts.map +1 -1
- package/dist/experimental/confirm.js +19 -6
- package/dist/experimental/intl.d.ts +2 -21
- package/dist/experimental/intl.d.ts.map +1 -1
- package/dist/experimental/intl.js +4 -4
- package/dist/experimental/makeUseCommand.js +2 -2
- package/dist/experimental/toast.d.ts +3 -35
- package/dist/experimental/toast.d.ts.map +1 -1
- package/dist/experimental/toast.js +19 -5
- package/dist/experimental/withToast.d.ts +6 -4
- package/dist/experimental/withToast.d.ts.map +1 -1
- package/dist/experimental/withToast.js +10 -8
- package/dist/form.d.ts +2 -2
- package/dist/form.d.ts.map +1 -1
- package/dist/form.js +47 -47
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +11 -9
- package/dist/makeClient.d.ts +24 -21
- package/dist/makeClient.d.ts.map +1 -1
- package/dist/makeClient.js +28 -29
- package/dist/mutate.d.ts.map +1 -1
- package/dist/mutate.js +7 -7
- package/dist/query.d.ts +6 -4
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +26 -17
- package/dist/routeParams.d.ts +2 -4
- package/dist/routeParams.d.ts.map +1 -1
- package/dist/routeParams.js +3 -15
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +4 -4
- package/package.json +20 -20
- package/src/errorReporter.ts +11 -11
- package/src/experimental/commander.ts +81 -84
- package/src/experimental/confirm.ts +21 -6
- package/src/experimental/intl.ts +3 -3
- package/src/experimental/makeUseCommand.ts +1 -1
- package/src/experimental/toast.ts +23 -4
- package/src/experimental/withToast.ts +10 -7
- package/src/form.ts +56 -64
- package/src/lib.ts +10 -8
- package/src/makeClient.ts +61 -54
- package/src/mutate.ts +6 -7
- package/src/query.ts +28 -21
- package/src/routeParams.ts +9 -23
- package/src/runtime.ts +6 -6
- package/test/Mutation.test.ts +41 -42
- package/test/dist/form.test.d.ts.map +1 -1
- package/test/dist/stubs.d.ts +111 -53
- package/test/dist/stubs.d.ts.map +1 -1
- package/test/dist/stubs.js +8 -8
- package/test/form.test.ts +7 -6
- package/test/stubs.ts +43 -41
- package/tsconfig.json +1 -27
package/src/form.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { createIntl, type IntlFormatters } from "@formatjs/intl"
|
|
2
|
-
import * as JSONSchema from "effect/JSONSchema"
|
|
3
|
-
import type { ParseError } from "effect/ParseResult"
|
|
4
2
|
import type {} from "intl-messageformat"
|
|
5
|
-
import {
|
|
3
|
+
import { Cause, Exit, Option, pipe, S } from "effect-app"
|
|
6
4
|
import type { Schema } from "effect-app/Schema"
|
|
7
5
|
import type { Unbranded } from "effect-app/Schema/brand"
|
|
8
6
|
import type { IsUnion } from "effect-app/utils"
|
|
@@ -11,23 +9,18 @@ import { capitalize, ref } from "vue"
|
|
|
11
9
|
// type GetSchemaFromProp<T> = T extends Field<infer S, any, any, any> ? S
|
|
12
10
|
// : never
|
|
13
11
|
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return getTypeLiteralAST(ast.to) ?? getTypeLiteralAST(ast.from)
|
|
23
|
-
}
|
|
24
|
-
case "Refinement": {
|
|
25
|
-
return getTypeLiteralAST(ast.from)
|
|
26
|
-
}
|
|
27
|
-
default: {
|
|
28
|
-
return null
|
|
12
|
+
function getObjectsAST(ast: S.AST.AST): S.AST.Objects | null {
|
|
13
|
+
if (S.AST.isObjects(ast)) {
|
|
14
|
+
return ast
|
|
15
|
+
}
|
|
16
|
+
if (S.AST.isDeclaration(ast)) {
|
|
17
|
+
for (const typeParam of ast.typeParameters) {
|
|
18
|
+
const result = getObjectsAST(typeParam)
|
|
19
|
+
if (result) return result
|
|
29
20
|
}
|
|
21
|
+
return null
|
|
30
22
|
}
|
|
23
|
+
return null
|
|
31
24
|
}
|
|
32
25
|
|
|
33
26
|
export function convertIn(v: string | null, type?: "text" | "float" | "int") {
|
|
@@ -114,29 +107,26 @@ function handlePropertySignature(
|
|
|
114
107
|
{
|
|
115
108
|
const schema = S.make(propertySignature.type)
|
|
116
109
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
propertySignature.name,
|
|
125
|
-
tl,
|
|
126
|
-
propertySignature.isOptional,
|
|
127
|
-
propertySignature.isReadonly,
|
|
128
|
-
propertySignature.annotations
|
|
129
|
-
)
|
|
110
|
+
if (S.AST.isDeclaration(schema.ast)) {
|
|
111
|
+
const tl = getObjectsAST(schema.ast)
|
|
112
|
+
return tl
|
|
113
|
+
? handlePropertySignature(
|
|
114
|
+
new S.AST.PropertySignature(
|
|
115
|
+
propertySignature.name,
|
|
116
|
+
tl
|
|
130
117
|
)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
118
|
+
)
|
|
119
|
+
: buildFieldInfo(propertySignature)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
switch (schema.ast._tag) {
|
|
123
|
+
case "Objects": {
|
|
134
124
|
return buildFieldInfoFromFieldsRoot(
|
|
135
|
-
schema as S.Schema<Record<PropertyKey, any
|
|
125
|
+
schema as S.Schema<Record<PropertyKey, any>>
|
|
136
126
|
)
|
|
137
127
|
}
|
|
138
128
|
case "Union": {
|
|
139
|
-
const allTypeLiterals = schema.ast.types.every(
|
|
129
|
+
const allTypeLiterals = schema.ast.types.every(getObjectsAST)
|
|
140
130
|
|
|
141
131
|
if (allTypeLiterals) {
|
|
142
132
|
const members = schema
|
|
@@ -146,15 +136,12 @@ function handlePropertySignature(
|
|
|
146
136
|
// syntehtic property signature as if each union member were the only member
|
|
147
137
|
new S.AST.PropertySignature(
|
|
148
138
|
propertySignature.name,
|
|
149
|
-
elAst
|
|
150
|
-
propertySignature.isOptional,
|
|
151
|
-
propertySignature.isReadonly,
|
|
152
|
-
propertySignature.annotations
|
|
139
|
+
elAst
|
|
153
140
|
)
|
|
154
141
|
)
|
|
155
142
|
.flatMap((ps) => {
|
|
156
143
|
// try to retrieve the _tag literal to set _infoTag later
|
|
157
|
-
const typeLiteral =
|
|
144
|
+
const typeLiteral = getObjectsAST(ps.type)
|
|
158
145
|
|
|
159
146
|
const tagPropertySignature = typeLiteral?.propertySignatures.find((_) => _.name === "_tag")
|
|
160
147
|
const tagLiteral = tagPropertySignature
|
|
@@ -207,7 +194,7 @@ export function buildFieldInfoFromFields<
|
|
|
207
194
|
From extends Record<PropertyKey, any>,
|
|
208
195
|
To extends Record<PropertyKey, any>
|
|
209
196
|
>(
|
|
210
|
-
schema: Schema<To, From
|
|
197
|
+
schema: (Schema<To> | S.Codec<To, From>) & { fields?: S.Struct.Fields }
|
|
211
198
|
) {
|
|
212
199
|
return buildFieldInfoFromFieldsRoot(schema).fields
|
|
213
200
|
}
|
|
@@ -217,9 +204,9 @@ export function buildFieldInfoFromFieldsRoot<
|
|
|
217
204
|
To extends Record<PropertyKey, any>,
|
|
218
205
|
R
|
|
219
206
|
>(
|
|
220
|
-
schema: Schema<To, From, R> & { fields?: S.Struct.Fields }
|
|
207
|
+
schema: (Schema<To> | S.Codec<To, From, R>) & { fields?: S.Struct.Fields }
|
|
221
208
|
): NestedFieldInfo<To> {
|
|
222
|
-
const ast =
|
|
209
|
+
const ast = getObjectsAST(schema.ast)
|
|
223
210
|
|
|
224
211
|
if (!ast) throw new Error("not a struct type")
|
|
225
212
|
return ast.propertySignatures.reduce(
|
|
@@ -258,25 +245,25 @@ function buildFieldInfo(
|
|
|
258
245
|
property: S.AST.PropertySignature
|
|
259
246
|
): FieldInfo<any> {
|
|
260
247
|
const propertyKey = property.name
|
|
261
|
-
const schema = S.make<unknown
|
|
262
|
-
const metadata = getMetadataFromSchema(property.type)
|
|
263
|
-
const parse = S.
|
|
248
|
+
const schema = S.make<S.Schema<unknown>>(property.type)
|
|
249
|
+
const metadata = getMetadataFromSchema(property.type)
|
|
250
|
+
const parse = S.decodeUnknownExit(schema as S.Schema<unknown> & { readonly DecodingServices: never })
|
|
264
251
|
|
|
265
252
|
const nullableOrUndefined = S.AST.isUnion(property.type)
|
|
266
|
-
&& (property.type.types.includes(S.Null.ast) || property.type.types.some((_) => _._tag === "
|
|
253
|
+
&& (property.type.types.includes(S.Null.ast) || property.type.types.some((_) => _._tag === "Undefined"))
|
|
267
254
|
const realSelf = nullableOrUndefined && S.AST.isUnion(property.type)
|
|
268
|
-
? property.type.types.filter((_) => _ !== S.Null.ast && _._tag !== "
|
|
255
|
+
? property.type.types.filter((_) => _ !== S.Null.ast && _._tag !== "Undefined")[0]!
|
|
269
256
|
: property.type
|
|
270
|
-
const id = S.AST.
|
|
271
|
-
const id2 = S.AST.
|
|
257
|
+
const id = S.AST.resolveIdentifier(property.type)
|
|
258
|
+
const id2 = S.AST.resolveIdentifier(realSelf)
|
|
272
259
|
|
|
273
|
-
function renderError(e:
|
|
260
|
+
function renderError(e: S.SchemaError, v: unknown) {
|
|
274
261
|
const err = e.toString()
|
|
275
262
|
|
|
276
263
|
const custom = customSchemaErrors.value.get(property.type)
|
|
277
264
|
?? customSchemaErrors.value.get(realSelf)
|
|
278
|
-
?? (
|
|
279
|
-
?? (
|
|
265
|
+
?? (id ? customSchemaErrors.value.get(id) : undefined)
|
|
266
|
+
?? (id2 ? customSchemaErrors.value.get(id2) : undefined)
|
|
280
267
|
|
|
281
268
|
if (custom) {
|
|
282
269
|
return custom(err, e, v)
|
|
@@ -366,9 +353,12 @@ function buildFieldInfo(
|
|
|
366
353
|
const parseRule = (v: unknown) =>
|
|
367
354
|
pipe(
|
|
368
355
|
parse(v),
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
356
|
+
Exit.match({
|
|
357
|
+
onFailure: (cause) => {
|
|
358
|
+
const err = Cause.findErrorOption(cause)
|
|
359
|
+
return Option.isSome(err) ? renderError(err.value, v) : "Unknown error"
|
|
360
|
+
},
|
|
361
|
+
onSuccess: () => true
|
|
372
362
|
})
|
|
373
363
|
)
|
|
374
364
|
|
|
@@ -429,14 +419,16 @@ export function getMetadataFromSchema(
|
|
|
429
419
|
|
|
430
420
|
let jschema: any
|
|
431
421
|
try {
|
|
432
|
-
|
|
433
|
-
|
|
422
|
+
const doc = S.toJsonSchemaDocument(S.make<S.Schema<unknown>>(realSelf))
|
|
423
|
+
jschema = doc.schema as any
|
|
424
|
+
const defs = doc.definitions as Record<string, any>
|
|
425
|
+
// resolve $ref against definitions
|
|
426
|
+
while (jschema["$ref"] && jschema["$ref"].startsWith("#/$defs/")) {
|
|
427
|
+
const { $ref: _, ...rest } = jschema
|
|
428
|
+
jschema = { ...defs[jschema["$ref"].replace("#/$defs/", "")], ...rest }
|
|
429
|
+
}
|
|
430
|
+
} catch (_err) {
|
|
434
431
|
jschema = {}
|
|
435
|
-
// console.warn("error getting jsonschema from ", err, ast)
|
|
436
|
-
}
|
|
437
|
-
while (jschema["$ref"] && jschema["$ref"].startsWith("#/$defs/")) {
|
|
438
|
-
const { $ref: _, ...rest } = jschema
|
|
439
|
-
jschema = { ...jschema["$defs"][jschema["$ref"].replace("#/$defs/", "")], ...rest }
|
|
440
432
|
}
|
|
441
433
|
// or we need to add these info directly in the refinement like the minimum
|
|
442
434
|
// or find a jsonschema parser whojoins all of them
|
package/src/lib.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { isHttpClientError } from "@effect/platform/HttpClientError"
|
|
2
1
|
import { type Pausable, useIntervalFn, type UseIntervalFnOptions } from "@vueuse/core"
|
|
3
|
-
import { Cause, type Effect,
|
|
2
|
+
import { Cause, type Effect, pipe } from "effect-app"
|
|
4
3
|
import { type Req } from "effect-app/client"
|
|
5
4
|
import type { ClientForOptions, RequestHandler, RequestHandlerWithInput } from "effect-app/client/clientFor"
|
|
5
|
+
import { isHttpClientError } from "effect/unstable/http/HttpClientError"
|
|
6
6
|
import type { MaybeRefOrGetter } from "vue"
|
|
7
7
|
import { reportError } from "./errorReporter.js"
|
|
8
8
|
|
|
@@ -17,12 +17,14 @@ const determineLevel = (cause: Cause.Cause<unknown>) => {
|
|
|
17
17
|
if (!isHttpClientError(sq)) {
|
|
18
18
|
return undefined
|
|
19
19
|
}
|
|
20
|
-
const causeStr = sq.
|
|
21
|
-
switch (sq._tag) {
|
|
22
|
-
case "
|
|
23
|
-
return
|
|
24
|
-
case "
|
|
25
|
-
return
|
|
20
|
+
const causeStr = sq.reason.message?.toLowerCase()
|
|
21
|
+
switch (sq.reason._tag) {
|
|
22
|
+
case "TransportError":
|
|
23
|
+
return "Info" as const
|
|
24
|
+
case "DecodeError":
|
|
25
|
+
return filters.some((_) => causeStr?.includes(_)) ? "Info" as const : undefined
|
|
26
|
+
default:
|
|
27
|
+
return undefined
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
|
package/src/makeClient.ts
CHANGED
|
@@ -2,15 +2,14 @@
|
|
|
2
2
|
import * as Result from "@effect-atom/atom/Result"
|
|
3
3
|
import { type InvalidateOptions, type InvalidateQueryFilters, isCancelledError, type QueryObserverResult, type RefetchOptions, type UseQueryReturnType } from "@tanstack/vue-query"
|
|
4
4
|
import { camelCase } from "change-case"
|
|
5
|
-
import { Cause, Effect, Exit,
|
|
5
|
+
import { Cause, Data, Effect, Exit, Layer, type ManagedRuntime, Match, Option, S, ServiceMap, Struct } from "effect-app"
|
|
6
6
|
import { type ApiClientFactory, type Req } from "effect-app/client"
|
|
7
7
|
import type { RequestHandler, RequestHandlers, RequestHandlerWithInput, Requests } from "effect-app/client/clientFor"
|
|
8
8
|
import { ErrorSilenced, type SupportedErrors } from "effect-app/client/errors"
|
|
9
9
|
import { constant, identity, pipe, tuple } from "effect-app/Function"
|
|
10
10
|
import { type OperationFailure, OperationSuccess } from "effect-app/Operations"
|
|
11
|
-
import { type Schema } from "effect-app/Schema"
|
|
12
11
|
import { dropUndefinedT, extendM } from "effect-app/utils"
|
|
13
|
-
import { type
|
|
12
|
+
import { type Fiber } from "effect/Fiber"
|
|
14
13
|
import { computed, type ComputedRef, onBeforeUnmount, type Ref, ref, watch, type WatchSource } from "vue"
|
|
15
14
|
import { reportMessage } from "./errorReporter.js"
|
|
16
15
|
import { type Commander, CommanderStatic } from "./experimental/commander.js"
|
|
@@ -20,7 +19,7 @@ import { Toast } from "./experimental/toast.js"
|
|
|
20
19
|
import { buildFieldInfoFromFieldsRoot } from "./form.js"
|
|
21
20
|
import { reportRuntimeError } from "./lib.js"
|
|
22
21
|
import { asResult, makeMutation, type MutationOptions, type MutationOptionsBase, mutationResultToVue, type Res, useMakeMutation } from "./mutate.js"
|
|
23
|
-
import { type CustomUndefinedInitialQueryOptions,
|
|
22
|
+
import { type CustomUndefinedInitialQueryOptions, makeQuery } from "./query.js"
|
|
24
23
|
|
|
25
24
|
const mapHandler = <A, E, R, I = void, A2 = A, E2 = E, R2 = R>(
|
|
26
25
|
handler: Effect.Effect<A, E, R> | ((i: I) => Effect.Effect<A, E, R>),
|
|
@@ -180,12 +179,11 @@ export type Queries<RT, Req> = Req extends
|
|
|
180
179
|
/**
|
|
181
180
|
* Use this after handling an error yourself, still continueing on the Error track, but the error will not be reported.
|
|
182
181
|
*/
|
|
183
|
-
export class SuppressErrors extends
|
|
184
|
-
readonly
|
|
185
|
-
readonly [ErrorSilenced] = true
|
|
182
|
+
export class SuppressErrors extends Data.TaggedError("SuppressErrors")<{}> {
|
|
183
|
+
readonly [ErrorSilenced] = true as const
|
|
186
184
|
}
|
|
187
185
|
|
|
188
|
-
export type ResponseErrors = S.
|
|
186
|
+
export type ResponseErrors = S.SchemaError | SupportedErrors | SuppressErrors | OperationFailure
|
|
189
187
|
|
|
190
188
|
export interface Opts<
|
|
191
189
|
A,
|
|
@@ -290,16 +288,16 @@ function handleRequest<
|
|
|
290
288
|
const handleEffect = (i: any) => (self: Effect.Effect<Exit.Exit<A, E>, never, R>) =>
|
|
291
289
|
self.pipe(
|
|
292
290
|
Effect.tap(
|
|
293
|
-
|
|
291
|
+
Effect.matchCauseEffect({
|
|
294
292
|
onSuccess: (r) => options.onSuccess(r, i),
|
|
295
293
|
onFailure: (cause) =>
|
|
296
294
|
Effect.gen(function*() {
|
|
297
|
-
if (Cause.
|
|
295
|
+
if (Cause.hasInterruptsOnly(cause)) {
|
|
298
296
|
console.info(`Interrupted while trying to ${action}`)
|
|
299
297
|
return
|
|
300
298
|
}
|
|
301
299
|
|
|
302
|
-
const fail = Cause.
|
|
300
|
+
const fail = Cause.findErrorOption(cause)
|
|
303
301
|
if (Option.isSome(fail)) {
|
|
304
302
|
if (fail.value._tag === "SuppressErrors") {
|
|
305
303
|
console.info(`Suppressed error trying to ${action}`, fail.value)
|
|
@@ -321,7 +319,7 @@ function handleRequest<
|
|
|
321
319
|
})
|
|
322
320
|
})
|
|
323
321
|
),
|
|
324
|
-
Effect.withSpan(`mutation ${id}`, { captureStackTrace: false })
|
|
322
|
+
Effect.withSpan(`mutation ${id}`, {}, { captureStackTrace: false })
|
|
325
323
|
)
|
|
326
324
|
return Object.assign(
|
|
327
325
|
Effect.isEffect(f)
|
|
@@ -359,7 +357,7 @@ export const useMutation: typeof _useMutation = <
|
|
|
359
357
|
Object.assign(
|
|
360
358
|
mapHandler(
|
|
361
359
|
_useMutation(self as any, options),
|
|
362
|
-
Effect.withSpan(`mutation ${self.id}`, { captureStackTrace: false })
|
|
360
|
+
Effect.withSpan(`mutation ${self.id}`, {}, { captureStackTrace: false })
|
|
363
361
|
) as any,
|
|
364
362
|
{ id: self.id }
|
|
365
363
|
)
|
|
@@ -385,7 +383,7 @@ export const useMutationInt = (): typeof _useMutation => {
|
|
|
385
383
|
Object.assign(
|
|
386
384
|
mapHandler(
|
|
387
385
|
_useMutation(self as any, options),
|
|
388
|
-
Effect.withSpan(`mutation ${self.id}`, { captureStackTrace: false })
|
|
386
|
+
Effect.withSpan(`mutation ${self.id}`, {}, { captureStackTrace: false })
|
|
389
387
|
) as any,
|
|
390
388
|
{ id: self.id }
|
|
391
389
|
)
|
|
@@ -393,7 +391,7 @@ export const useMutationInt = (): typeof _useMutation => {
|
|
|
393
391
|
|
|
394
392
|
export class LegacyMutationImpl<RT> {
|
|
395
393
|
constructor(
|
|
396
|
-
private readonly getRuntime: () =>
|
|
394
|
+
private readonly getRuntime: () => ServiceMap.ServiceMap<RT>,
|
|
397
395
|
private readonly toast: Toast,
|
|
398
396
|
private readonly intl: I18n
|
|
399
397
|
) {}
|
|
@@ -437,12 +435,17 @@ export class LegacyMutationImpl<RT> {
|
|
|
437
435
|
type MH = NonNullable<NonNullable<typeof options>["mapHandler"]>
|
|
438
436
|
const mh = options?.mapHandler ?? identity as MH
|
|
439
437
|
|
|
440
|
-
const [a, b] = asResult(
|
|
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
|
+
)
|
|
441
444
|
return [
|
|
442
445
|
a,
|
|
443
446
|
mapHandler(
|
|
444
447
|
b,
|
|
445
|
-
Effect.withSpan(`mutation ${self.id}`, { captureStackTrace: false })
|
|
448
|
+
Effect.withSpan(`mutation ${self.id}`, {}, { captureStackTrace: false })
|
|
446
449
|
)
|
|
447
450
|
] as const as any
|
|
448
451
|
}
|
|
@@ -537,7 +540,7 @@ export class LegacyMutationImpl<RT> {
|
|
|
537
540
|
}
|
|
538
541
|
|
|
539
542
|
function renderError(e: ResponseErrors): string {
|
|
540
|
-
return Match.value(e).pipe(
|
|
543
|
+
return Match.value(e as any).pipe(
|
|
541
544
|
Match.tags({
|
|
542
545
|
// HttpErrorRequest: e =>
|
|
543
546
|
// this.intl.value.formatMessage(
|
|
@@ -573,12 +576,12 @@ export class LegacyMutationImpl<RT> {
|
|
|
573
576
|
// { id: "handle.response_error" },
|
|
574
577
|
// { error: `${e.error}` },
|
|
575
578
|
// ),
|
|
576
|
-
|
|
579
|
+
SchemaError: (e: any) => {
|
|
577
580
|
console.warn(e.toString())
|
|
578
581
|
return self.intl.formatMessage({ id: "validation.failed" })
|
|
579
582
|
}
|
|
580
583
|
}),
|
|
581
|
-
Match.orElse((e) => `${e.message ?? e._tag ?? e}`)
|
|
584
|
+
Match.orElse((e: any) => `${e.message ?? e._tag ?? e}`)
|
|
582
585
|
)
|
|
583
586
|
}
|
|
584
587
|
}
|
|
@@ -652,12 +655,12 @@ export class LegacyMutationImpl<RT> {
|
|
|
652
655
|
handler: Effect.isEffect(handler)
|
|
653
656
|
? (pipe(
|
|
654
657
|
Effect.annotateCurrentSpan({ action }),
|
|
655
|
-
Effect.
|
|
658
|
+
Effect.andThen(handler)
|
|
656
659
|
) as any)
|
|
657
660
|
: (...args: [any]) =>
|
|
658
661
|
pipe(
|
|
659
662
|
Effect.annotateCurrentSpan({ action }),
|
|
660
|
-
Effect.
|
|
663
|
+
Effect.andThen(handler(...args))
|
|
661
664
|
)
|
|
662
665
|
}, options ? dropUndefinedT(options) : undefined)
|
|
663
666
|
|
|
@@ -939,7 +942,12 @@ export class LegacyMutationImpl<RT> {
|
|
|
939
942
|
type MH = NonNullable<NonNullable<typeof options>["mapHandler"]>
|
|
940
943
|
const mh = options?.mapHandler ?? identity as MH
|
|
941
944
|
|
|
942
|
-
const [a, b] = asResult(
|
|
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
|
+
)
|
|
943
951
|
|
|
944
952
|
return tuple(
|
|
945
953
|
computed(() => mutationResultToVue(a.value)),
|
|
@@ -1002,36 +1010,34 @@ export class LegacyMutationImpl<RT> {
|
|
|
1002
1010
|
OnSubmitA
|
|
1003
1011
|
>(
|
|
1004
1012
|
s:
|
|
1005
|
-
& Schema<
|
|
1006
|
-
To,
|
|
1007
|
-
From,
|
|
1008
|
-
RT
|
|
1009
|
-
>
|
|
1013
|
+
& S.Schema<To>
|
|
1010
1014
|
& { new(c: C): any; extend: any; fields: S.Struct.Fields },
|
|
1011
1015
|
state: Ref<Omit<From, "_tag">>,
|
|
1012
1016
|
onSubmit: (a: To) => Effect.Effect<OnSubmitA, never, RT>
|
|
1013
1017
|
) => {
|
|
1014
1018
|
const fields = buildFieldInfoFromFieldsRoot(s).fields
|
|
1015
|
-
const schema = S.Struct(Struct.omit(s.fields, "_tag")) as any
|
|
1016
|
-
|
|
1019
|
+
const schema = S.Struct(Struct.omit(s.fields, ["_tag"])) as unknown as S.Schema<any> & {
|
|
1020
|
+
readonly DecodingServices: never
|
|
1021
|
+
}
|
|
1022
|
+
const parse = S.decodeUnknownSync(schema)
|
|
1017
1023
|
const isDirty = ref(false)
|
|
1018
1024
|
const isValid = ref(true)
|
|
1019
1025
|
const isLoading = ref(false)
|
|
1020
|
-
const runPromise =
|
|
1026
|
+
const runPromise = Effect.runPromiseWith(this.getRuntime())
|
|
1021
1027
|
|
|
1022
1028
|
const submit1 =
|
|
1023
|
-
(onSubmit: (a: To) => Effect.Effect<OnSubmitA, never,
|
|
1029
|
+
(onSubmit: (a: To) => Effect.Effect<OnSubmitA, never, never>) =>
|
|
1024
1030
|
async <T extends Promise<{ valid: boolean }>>(e: T) => {
|
|
1025
1031
|
isLoading.value = true
|
|
1026
1032
|
try {
|
|
1027
1033
|
const r = await e
|
|
1028
1034
|
if (!r.valid) return
|
|
1029
|
-
return await runPromise(onSubmit(new s(await runPromise(parse(state.value)))))
|
|
1035
|
+
return await runPromise(onSubmit(new (s as any)(await runPromise(parse(state.value)))) as any)
|
|
1030
1036
|
} finally {
|
|
1031
1037
|
isLoading.value = false
|
|
1032
1038
|
}
|
|
1033
1039
|
}
|
|
1034
|
-
const submit = submit1(onSubmit)
|
|
1040
|
+
const submit = submit1(onSubmit as any)
|
|
1035
1041
|
|
|
1036
1042
|
watch(
|
|
1037
1043
|
state,
|
|
@@ -1043,10 +1049,10 @@ export class LegacyMutationImpl<RT> {
|
|
|
1043
1049
|
)
|
|
1044
1050
|
|
|
1045
1051
|
const submitFromState = Effect.gen(function*() {
|
|
1046
|
-
return yield* onSubmit(yield* parse(state.value))
|
|
1052
|
+
return yield* (onSubmit(yield* parse(state.value)) as any)
|
|
1047
1053
|
})
|
|
1048
1054
|
|
|
1049
|
-
const submitFromStatePromise = () => runPromise(submitFromState)
|
|
1055
|
+
const submitFromStatePromise = () => runPromise(submitFromState as any)
|
|
1050
1056
|
|
|
1051
1057
|
return {
|
|
1052
1058
|
fields,
|
|
@@ -1063,19 +1069,22 @@ export class LegacyMutationImpl<RT> {
|
|
|
1063
1069
|
}
|
|
1064
1070
|
|
|
1065
1071
|
// @effect-diagnostics-next-line missingEffectServiceDependency:off
|
|
1066
|
-
export class LegacyMutation extends
|
|
1067
|
-
|
|
1072
|
+
export class LegacyMutation extends ServiceMap.Service<LegacyMutation>()("LegacyMutation", {
|
|
1073
|
+
make: Effect.gen(function*() {
|
|
1068
1074
|
const intl = yield* I18n
|
|
1069
1075
|
const toast = yield* Toast
|
|
1070
1076
|
|
|
1071
|
-
return <R>(getRuntime: () =>
|
|
1077
|
+
return <R>(getRuntime: () => ServiceMap.ServiceMap<R>) => new LegacyMutationImpl(getRuntime, toast, intl)
|
|
1072
1078
|
})
|
|
1073
|
-
}) {
|
|
1079
|
+
}) {
|
|
1080
|
+
static readonly DefaultWithoutDependencies = Layer.effect(this, this.make)
|
|
1081
|
+
static readonly Default = this.DefaultWithoutDependencies
|
|
1082
|
+
}
|
|
1074
1083
|
|
|
1075
1084
|
export type ClientFrom<M extends Requests> = RequestHandlers<never, never, M, M["meta"]["moduleName"]>
|
|
1076
1085
|
|
|
1077
1086
|
export class QueryImpl<R> {
|
|
1078
|
-
constructor(readonly getRuntime: () =>
|
|
1087
|
+
constructor(readonly getRuntime: () => ServiceMap.ServiceMap<R>) {
|
|
1079
1088
|
this.useQuery = makeQuery(this.getRuntime)
|
|
1080
1089
|
}
|
|
1081
1090
|
/**
|
|
@@ -1116,7 +1125,7 @@ export class QueryImpl<R> {
|
|
|
1116
1125
|
ComputedRef<TData>,
|
|
1117
1126
|
(
|
|
1118
1127
|
options?: RefetchOptions
|
|
1119
|
-
) => Effect.Effect<QueryObserverResult<TData,
|
|
1128
|
+
) => Effect.Effect<QueryObserverResult<TData, E>>,
|
|
1120
1129
|
UseQueryReturnType<any, any>
|
|
1121
1130
|
]
|
|
1122
1131
|
>
|
|
@@ -1146,7 +1155,7 @@ export class QueryImpl<R> {
|
|
|
1146
1155
|
ComputedRef<TData>,
|
|
1147
1156
|
(
|
|
1148
1157
|
options?: RefetchOptions
|
|
1149
|
-
) => Effect.Effect<QueryObserverResult<TData,
|
|
1158
|
+
) => Effect.Effect<QueryObserverResult<TData, E>>,
|
|
1150
1159
|
UseQueryReturnType<any, any>
|
|
1151
1160
|
]
|
|
1152
1161
|
>
|
|
@@ -1154,7 +1163,7 @@ export class QueryImpl<R> {
|
|
|
1154
1163
|
} = <Arg, E, A, Request extends Req, Name extends string>(
|
|
1155
1164
|
self: RequestHandlerWithInput<Arg, A, E, R, Request, Name> | RequestHandler<A, E, R, Request, Name>
|
|
1156
1165
|
) => {
|
|
1157
|
-
const runPromise =
|
|
1166
|
+
const runPromise = Effect.runPromiseWith(this.getRuntime())
|
|
1158
1167
|
const q = this.useQuery(self as any) as any
|
|
1159
1168
|
return (argOrOptions?: any, options?: any) => {
|
|
1160
1169
|
const [resultRef, latestRef, fetch, uqrt] = q(argOrOptions, { ...options, suspense: true } // experimental_prefetchInRender: true }
|
|
@@ -1171,12 +1180,10 @@ export class QueryImpl<R> {
|
|
|
1171
1180
|
// what's the difference with just calling `fetch` ?
|
|
1172
1181
|
// we will receive a CancelledError which we will have to ignore in our ErrorBoundary, otherwise the user ends up on an error page even if the user e.g cancelled a navigation
|
|
1173
1182
|
const r = yield* Effect.tryPromise(() => uqrt.suspense()).pipe(
|
|
1174
|
-
Effect.catchTag("
|
|
1175
|
-
|
|
1176
|
-
? Effect.failCause(err.error[Runtime.FiberFailureCauseId])
|
|
1177
|
-
: isCancelledError(err.error)
|
|
1183
|
+
Effect.catchTag("UnknownError", (err) =>
|
|
1184
|
+
isCancelledError(err.cause)
|
|
1178
1185
|
? Effect.interrupt
|
|
1179
|
-
: Effect.die(err.
|
|
1186
|
+
: Effect.die(err.cause))
|
|
1180
1187
|
)
|
|
1181
1188
|
if (!isMounted.value) {
|
|
1182
1189
|
return yield* Effect.interrupt
|
|
@@ -1207,7 +1214,7 @@ export class QueryImpl<R> {
|
|
|
1207
1214
|
}
|
|
1208
1215
|
|
|
1209
1216
|
// somehow mrt.runtimeEffect doesnt work sync, but this workaround works fine? not sure why though as the layers are generally only sync
|
|
1210
|
-
const managedRuntimeRt = <A, E>(mrt: ManagedRuntime.ManagedRuntime<A, E>) => mrt.runSync(Effect.
|
|
1217
|
+
const managedRuntimeRt = <A, E>(mrt: ManagedRuntime.ManagedRuntime<A, E>) => mrt.runSync(Effect.services<A>())
|
|
1211
1218
|
|
|
1212
1219
|
type Base = I18n | Toast
|
|
1213
1220
|
type Mix = ApiClientFactory | Commander | LegacyMutation | Base
|
|
@@ -1218,7 +1225,7 @@ export const makeClient = <RT_, RTHooks>(
|
|
|
1218
1225
|
rtHooks: Layer.Layer<RTHooks, never, Mix>
|
|
1219
1226
|
) => {
|
|
1220
1227
|
type RT = RT_ | Mix
|
|
1221
|
-
const getRt = Effect.
|
|
1228
|
+
const getRt = Effect.services<RT>()
|
|
1222
1229
|
const getBaseRt = () => managedRuntimeRt(getBaseMrt())
|
|
1223
1230
|
const makeCommand = makeUseCommand<RT, RTHooks>(rtHooks)
|
|
1224
1231
|
const makeMutation = Effect.gen(function*() {
|
|
@@ -1226,9 +1233,9 @@ export const makeClient = <RT_, RTHooks>(
|
|
|
1226
1233
|
|
|
1227
1234
|
return mut(() => getBaseMrt().runSync(getRt))
|
|
1228
1235
|
})
|
|
1229
|
-
let cmd: Effect.
|
|
1236
|
+
let cmd: Effect.Success<typeof makeCommand>
|
|
1230
1237
|
const useCommand = () => cmd ??= getBaseMrt().runSync(makeCommand)
|
|
1231
|
-
let mut: Effect.
|
|
1238
|
+
let mut: Effect.Success<typeof makeMutation>
|
|
1232
1239
|
const getMutation = () => mut ??= getBaseMrt().runSync(makeMutation)
|
|
1233
1240
|
|
|
1234
1241
|
let m: ReturnType<typeof useMutationInt>
|
|
@@ -1488,7 +1495,7 @@ export interface CommandBase<I = void, A = void> {
|
|
|
1488
1495
|
label: string
|
|
1489
1496
|
}
|
|
1490
1497
|
|
|
1491
|
-
export interface EffectCommand<I = void, A = unknown, E = unknown> extends CommandBase<I,
|
|
1498
|
+
export interface EffectCommand<I = void, A = unknown, E = unknown> extends CommandBase<I, Fiber<A, E>> {}
|
|
1492
1499
|
|
|
1493
1500
|
export interface CommandFromRequest<I extends abstract new(...args: any) => any, A = unknown, E = unknown>
|
|
1494
1501
|
extends EffectCommand<ConstructorParameters<I>[0], A, E>
|
package/src/mutate.ts
CHANGED
|
@@ -58,7 +58,7 @@ export function make<A, E, R>(self: Effect.Effect<A, E, R>) {
|
|
|
58
58
|
.pipe(
|
|
59
59
|
Effect.andThen(self),
|
|
60
60
|
Effect.exit,
|
|
61
|
-
Effect.
|
|
61
|
+
Effect.map(Result.fromExit),
|
|
62
62
|
Effect.flatMap((r) => Effect.sync(() => result.value = r))
|
|
63
63
|
)
|
|
64
64
|
|
|
@@ -118,7 +118,7 @@ export const asResult: {
|
|
|
118
118
|
state.value = Result.initial(true)
|
|
119
119
|
})
|
|
120
120
|
.pipe(
|
|
121
|
-
Effect.
|
|
121
|
+
Effect.andThen(Effect.suspend(() =>
|
|
122
122
|
handler.pipe(
|
|
123
123
|
Effect.exit,
|
|
124
124
|
Effect.tap((exit) => Effect.sync(() => (state.value = Result.fromExit(exit))))
|
|
@@ -131,7 +131,7 @@ export const asResult: {
|
|
|
131
131
|
state.value = Result.initial(true)
|
|
132
132
|
})
|
|
133
133
|
.pipe(
|
|
134
|
-
Effect.
|
|
134
|
+
Effect.andThen(Effect.suspend(() =>
|
|
135
135
|
handler(...args).pipe(
|
|
136
136
|
Effect.exit,
|
|
137
137
|
Effect.tap((exit) => Effect.sync(() => (state.value = Result.fromExit(exit))))
|
|
@@ -171,7 +171,7 @@ export const invalidateQueries = (
|
|
|
171
171
|
Effect.annotateCurrentSpan({ queryKey, opts }),
|
|
172
172
|
Effect.forEach(opts, (_) => invalidateQueries(_.filters, _.options), { concurrency: "inherit" })
|
|
173
173
|
)
|
|
174
|
-
.pipe(Effect.withSpan("client.query.invalidation", { captureStackTrace: false }))
|
|
174
|
+
.pipe(Effect.withSpan("client.query.invalidation", {}, { captureStackTrace: false }))
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
if (!queryKey) return Effect.void
|
|
@@ -187,12 +187,11 @@ export const invalidateQueries = (
|
|
|
187
187
|
// TODO: should we do this in general on any mutation, regardless of invalidation?
|
|
188
188
|
Effect.sleep(0)
|
|
189
189
|
),
|
|
190
|
-
Effect.withSpan("client.query.invalidation", { captureStackTrace: false })
|
|
190
|
+
Effect.withSpan("client.query.invalidation", {}, { captureStackTrace: false })
|
|
191
191
|
)
|
|
192
192
|
})
|
|
193
193
|
|
|
194
|
-
const handle = <A, E, R>(self: Effect.Effect<A, E, R>) =>
|
|
195
|
-
Effect.tapBoth(self, { onFailure: () => invalidateCache, onSuccess: () => invalidateCache })
|
|
194
|
+
const handle = <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.ensuring(self, invalidateCache)
|
|
196
195
|
|
|
197
196
|
return handle
|
|
198
197
|
}
|