@effect-app/vue 4.0.0-beta.247 → 4.0.0-beta.249
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 +24 -0
- package/dist/makeClient.d.ts +4 -4
- package/dist/makeClient.d.ts.map +1 -1
- package/dist/routeParams.d.ts +3 -4
- package/dist/routeParams.d.ts.map +1 -1
- package/dist/routeParams.js +1 -1
- package/dist/runtime.d.ts +2 -19
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +2 -40
- package/dist/toast.d.ts +2 -51
- package/dist/toast.d.ts.map +1 -1
- package/dist/toast.js +2 -34
- package/dist/withToast.d.ts +2 -30
- package/dist/withToast.d.ts.map +1 -1
- package/dist/withToast.js +2 -64
- package/package.json +2 -2
- package/src/makeClient.ts +5 -5
- package/src/routeParams.ts +4 -5
- package/src/runtime.ts +1 -56
- package/src/toast.ts +1 -54
- package/src/withToast.ts +1 -133
- package/test/dist/stubs.d.ts +192 -192
package/src/makeClient.ts
CHANGED
|
@@ -160,16 +160,16 @@ export interface MutationExt<
|
|
|
160
160
|
RT,
|
|
161
161
|
Id,
|
|
162
162
|
I,
|
|
163
|
-
|
|
163
|
+
ProjSchema["Type"],
|
|
164
164
|
E | S.SchemaError,
|
|
165
165
|
R | ProjSchema["DecodingServices"],
|
|
166
|
-
|
|
166
|
+
ProjSchema["Encoded"]
|
|
167
167
|
>
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
export type MutationWithExtensions<RT, Req> = Req extends
|
|
171
171
|
RequestHandlerWithInput<infer I, infer A, infer E, infer R, infer Request, infer Id>
|
|
172
|
-
? MutationExt<RT, Id, I, A, E, R,
|
|
172
|
+
? MutationExt<RT, Id, I, A, E, R, Request["success"]["Encoded"]>
|
|
173
173
|
: never
|
|
174
174
|
|
|
175
175
|
/**
|
|
@@ -217,11 +217,11 @@ export type QueryProjection<RT, HandlerReq> = HandlerReq extends
|
|
|
217
217
|
RequestHandlerWithInput<infer I, infer _A, infer E, infer R, infer Request, infer Id>
|
|
218
218
|
? Request["type"] extends "query" ? {
|
|
219
219
|
project: <ProjSchema extends S.Top>(
|
|
220
|
-
schema:
|
|
220
|
+
schema: Request["success"]["Encoded"] extends ProjSchema["Encoded"] ? ProjSchema : never
|
|
221
221
|
) => ProjectResult<
|
|
222
222
|
RT,
|
|
223
223
|
I,
|
|
224
|
-
|
|
224
|
+
ProjSchema["Type"],
|
|
225
225
|
E | S.SchemaError,
|
|
226
226
|
R | ProjSchema["DecodingServices"],
|
|
227
227
|
Request,
|
package/src/routeParams.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as Option from "effect-app/Option"
|
|
2
2
|
import * as S from "effect-app/Schema"
|
|
3
|
-
import type { Schema } from "effect-app/Schema"
|
|
4
3
|
import { typedKeysOf } from "effect-app/utils"
|
|
5
4
|
import { flow } from "effect/Function"
|
|
6
5
|
import type { ParsedQuery } from "query-string"
|
|
@@ -17,7 +16,7 @@ export const getQueryParamO = flow(getQueryParam, Option.fromNullishOr)
|
|
|
17
16
|
|
|
18
17
|
export function parseRouteParamsOption<NER extends Record<string, S.Codec<any, any>>>(query: Record<string, any>, t: NER // enforce non empty
|
|
19
18
|
): {
|
|
20
|
-
[K in keyof NER]: Option.Option<
|
|
19
|
+
[K in keyof NER]: Option.Option<NER[K]["Type"]>
|
|
21
20
|
} {
|
|
22
21
|
return typedKeysOf(t).reduce(
|
|
23
22
|
(prev, cur) => {
|
|
@@ -29,7 +28,7 @@ export function parseRouteParamsOption<NER extends Record<string, S.Codec<any, a
|
|
|
29
28
|
return prev
|
|
30
29
|
},
|
|
31
30
|
{} as {
|
|
32
|
-
[K in keyof NER]: Option.Option<
|
|
31
|
+
[K in keyof NER]: Option.Option<NER[K]["Type"]>
|
|
33
32
|
}
|
|
34
33
|
)
|
|
35
34
|
}
|
|
@@ -38,7 +37,7 @@ export function parseRouteParams<NER extends Record<string, S.Codec<any, any>>>(
|
|
|
38
37
|
query: Record<string, any>,
|
|
39
38
|
t: NER // enforce non empty
|
|
40
39
|
): {
|
|
41
|
-
[K in keyof NER]:
|
|
40
|
+
[K in keyof NER]: NER[K]["Type"]
|
|
42
41
|
} {
|
|
43
42
|
return typedKeysOf(t).reduce(
|
|
44
43
|
(prev, cur) => {
|
|
@@ -50,7 +49,7 @@ export function parseRouteParams<NER extends Record<string, S.Codec<any, any>>>(
|
|
|
50
49
|
return prev
|
|
51
50
|
},
|
|
52
51
|
{} as {
|
|
53
|
-
[K in keyof NER]:
|
|
52
|
+
[K in keyof NER]: NER[K]["Type"]
|
|
54
53
|
}
|
|
55
54
|
)
|
|
56
55
|
}
|
package/src/runtime.ts
CHANGED
|
@@ -1,56 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { type Context } from "effect-app/Context"
|
|
3
|
-
import * as Effect from "effect-app/Effect"
|
|
4
|
-
import * as Layer from "effect-app/Layer"
|
|
5
|
-
import * as Exit from "effect/Exit"
|
|
6
|
-
import { flow } from "effect/Function"
|
|
7
|
-
import * as Logger from "effect/Logger"
|
|
8
|
-
import * as ManagedRuntime from "effect/ManagedRuntime"
|
|
9
|
-
|
|
10
|
-
export const makeAppRuntime = Effect.fnUntraced(function*<A, E>(layer: Layer.Layer<A, E>) {
|
|
11
|
-
const l = layer.pipe(
|
|
12
|
-
Layer.provide(Logger.layer([Logger.consolePretty()]))
|
|
13
|
-
) as Layer.Layer<A>
|
|
14
|
-
const mrt = ManagedRuntime.make(l)
|
|
15
|
-
yield* mrt.contextEffect
|
|
16
|
-
return Object.assign(mrt, {
|
|
17
|
-
[Symbol.dispose]() {
|
|
18
|
-
return Effect.runSync(mrt.disposeEffect)
|
|
19
|
-
},
|
|
20
|
-
|
|
21
|
-
[Symbol.asyncDispose]() {
|
|
22
|
-
return mrt.dispose()
|
|
23
|
-
}
|
|
24
|
-
}) // as we initialise here, there is no more error left.
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
export function initializeSync<A, E>(layer: Layer.Layer<A, E>) {
|
|
28
|
-
const runtime = Effect.runSync(makeAppRuntime(layer))
|
|
29
|
-
return runtime
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function initializeAsync<A, E>(layer: Layer.Layer<A, E>) {
|
|
33
|
-
return Effect
|
|
34
|
-
.runPromise(makeAppRuntime(layer))
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// we wrap into CauseException because we want to keep the full cause of the failure.
|
|
38
|
-
export const makeRunPromise = <T>(services: Context<T>) =>
|
|
39
|
-
flow(Effect.runPromiseExitWith(services), (_) =>
|
|
40
|
-
_.then(
|
|
41
|
-
Exit.match({
|
|
42
|
-
onFailure: (cause) => Promise.reject(new CauseException(cause, "runPromise")),
|
|
43
|
-
onSuccess: (value) => Promise.resolve(value)
|
|
44
|
-
})
|
|
45
|
-
))
|
|
46
|
-
|
|
47
|
-
export const makeRunSync = <T>(services: Context<T>) =>
|
|
48
|
-
flow(
|
|
49
|
-
Effect.runSyncExitWith(services),
|
|
50
|
-
Exit.match({
|
|
51
|
-
onFailure: (cause) => {
|
|
52
|
-
throw new CauseException(cause, "runSync")
|
|
53
|
-
},
|
|
54
|
-
onSuccess: (value) => value
|
|
55
|
-
})
|
|
56
|
-
)
|
|
1
|
+
export * from "effect-app/runtime"
|
package/src/toast.ts
CHANGED
|
@@ -1,54 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { accessEffectFn } from "effect-app/Context"
|
|
3
|
-
import * as Effect from "effect-app/Effect"
|
|
4
|
-
import * as Option from "effect-app/Option"
|
|
5
|
-
|
|
6
|
-
export type ToastId = string | number
|
|
7
|
-
export type ToastOpts = { id?: ToastId; timeout?: number; groupId?: string; requestId?: string }
|
|
8
|
-
export type ToastOptsInternal = { id?: ToastId | null; timeout?: number; groupId?: string; requestId?: string }
|
|
9
|
-
|
|
10
|
-
export type UseToast = () => {
|
|
11
|
-
error: (this: void, message: string, options?: ToastOpts) => ToastId
|
|
12
|
-
warning: (this: void, message: string, options?: ToastOpts) => ToastId
|
|
13
|
-
success: (this: void, message: string, options?: ToastOpts) => ToastId
|
|
14
|
-
info: (this: void, message: string, options?: ToastOpts) => ToastId
|
|
15
|
-
dismiss: (this: void, id: ToastId) => void
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export class CurrentToastId extends Context.Opaque<CurrentToastId, { toastId: ToastId }>()("CurrentToastId") {}
|
|
19
|
-
|
|
20
|
-
/** fallback to CurrentToastId when available unless id is explicitly set to a value or null */
|
|
21
|
-
export const wrap = (toast: ReturnType<UseToast>) => {
|
|
22
|
-
const wrap = (toastHandler: (message: string, options?: ToastOpts) => ToastId) => {
|
|
23
|
-
return (message: string, options?: ToastOptsInternal) =>
|
|
24
|
-
Effect.serviceOption(CurrentToastId).pipe(
|
|
25
|
-
Effect.flatMap((currentToast) =>
|
|
26
|
-
Effect.sync(() => {
|
|
27
|
-
const { id: _id, ...rest } = options ?? {}
|
|
28
|
-
const id = _id !== undefined
|
|
29
|
-
? _id ?? undefined
|
|
30
|
-
: Option.getOrUndefined(Option.map(currentToast, (_) => _.toastId))
|
|
31
|
-
// when id is undefined, we may end up with no toast at all..
|
|
32
|
-
return toastHandler(message, id !== undefined ? { ...rest, id } : rest)
|
|
33
|
-
})
|
|
34
|
-
)
|
|
35
|
-
)
|
|
36
|
-
}
|
|
37
|
-
return {
|
|
38
|
-
error: wrap(toast.error),
|
|
39
|
-
info: wrap(toast.info),
|
|
40
|
-
success: wrap(toast.success),
|
|
41
|
-
warning: wrap(toast.warning),
|
|
42
|
-
dismiss: (toastId: ToastId) => Effect.sync(() => toast.dismiss(toastId))
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
type ToastShape = ReturnType<typeof wrap>
|
|
47
|
-
|
|
48
|
-
export class Toast extends Context.Opaque<Toast, ToastShape>()("Toast") {
|
|
49
|
-
static readonly error = accessEffectFn(this, "error")
|
|
50
|
-
static readonly info = accessEffectFn(this, "info")
|
|
51
|
-
static readonly success = accessEffectFn(this, "success")
|
|
52
|
-
static readonly warning = accessEffectFn(this, "warning")
|
|
53
|
-
static readonly dismiss = accessEffectFn(this, "dismiss")
|
|
54
|
-
}
|
|
1
|
+
export * from "effect-app/toast"
|
package/src/withToast.ts
CHANGED
|
@@ -1,133 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import * as Effect from "effect-app/Effect"
|
|
3
|
-
import * as Layer from "effect-app/Layer"
|
|
4
|
-
import type * as Option from "effect-app/Option"
|
|
5
|
-
import * as S from "effect-app/Schema"
|
|
6
|
-
import { wrapEffect } from "effect-app/utils"
|
|
7
|
-
import * as Cause from "effect/Cause"
|
|
8
|
-
import * as Fiber from "effect/Fiber"
|
|
9
|
-
import { CurrentToastId, Toast, type ToastId } from "./toast.js"
|
|
10
|
-
|
|
11
|
-
export interface ToastOptions<A, E, Args extends ReadonlyArray<unknown>, WaiR, SucR, ErrR> {
|
|
12
|
-
stableToastId?: undefined | string | ((...args: Args) => string | undefined)
|
|
13
|
-
timeout?: number
|
|
14
|
-
showSpanInfo?: false
|
|
15
|
-
groupId?: string
|
|
16
|
-
onWaiting:
|
|
17
|
-
| string
|
|
18
|
-
| ((...args: Args) => string | null)
|
|
19
|
-
| null
|
|
20
|
-
| ((
|
|
21
|
-
...args: Args
|
|
22
|
-
) => Effect.Effect<string | null, never, WaiR>)
|
|
23
|
-
onSuccess:
|
|
24
|
-
| string
|
|
25
|
-
| ((a: A, ...args: Args) => string | null)
|
|
26
|
-
| null
|
|
27
|
-
| ((
|
|
28
|
-
a: A,
|
|
29
|
-
...args: Args
|
|
30
|
-
) => Effect.Effect<string | null, never, SucR>)
|
|
31
|
-
onFailure:
|
|
32
|
-
| string
|
|
33
|
-
| ((
|
|
34
|
-
error: Option.Option<E>,
|
|
35
|
-
...args: Args
|
|
36
|
-
) => string | { level: "warn" | "error"; message: string })
|
|
37
|
-
| ((
|
|
38
|
-
error: Option.Option<E>,
|
|
39
|
-
...args: Args
|
|
40
|
-
) => Effect.Effect<string | { level: "warn" | "error"; message: string }, never, ErrR>)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// @effect-diagnostics-next-line missingEffectServiceDependency:off
|
|
44
|
-
export class WithToast extends Context.Service<WithToast>()("WithToast", {
|
|
45
|
-
make: Effect.gen(function*() {
|
|
46
|
-
const toast = yield* Toast
|
|
47
|
-
return <A, E, Args extends readonly unknown[], R, WaiR = never, SucR = never, ErrR = never>(
|
|
48
|
-
options: ToastOptions<A, E, Args, WaiR, SucR, ErrR>
|
|
49
|
-
) =>
|
|
50
|
-
Effect.fnUntraced(function*(self: Effect.Effect<A, E, R>, ...args: Args) {
|
|
51
|
-
const baseTimeout = options.timeout ?? 3_000
|
|
52
|
-
|
|
53
|
-
const stableToastId = typeof options.stableToastId === "function"
|
|
54
|
-
? options.stableToastId(...args)
|
|
55
|
-
: options.stableToastId
|
|
56
|
-
|
|
57
|
-
const requestId: string = yield* Effect.currentSpan.pipe(
|
|
58
|
-
Effect.map((span) => span.traceId),
|
|
59
|
-
Effect.orElseSucceed(() => S.StringId.make())
|
|
60
|
-
)
|
|
61
|
-
const groupId = options.groupId
|
|
62
|
-
const meta = { ...(groupId !== undefined ? { groupId } : {}), requestId }
|
|
63
|
-
|
|
64
|
-
const t = yield* wrapEffect(options.onWaiting)(...args)
|
|
65
|
-
const toastId: ToastId | undefined = t === null
|
|
66
|
-
? stableToastId
|
|
67
|
-
: stableToastId ?? `wait-${Math.random().toString(36).slice(2)}`
|
|
68
|
-
|
|
69
|
-
const waitingFiber = t === null ? undefined : yield* Effect.forkChild(
|
|
70
|
-
Effect.sleep("1 seconds").pipe(
|
|
71
|
-
Effect.andThen(toast.info(t, { id: toastId!, timeout: Infinity, ...meta }))
|
|
72
|
-
)
|
|
73
|
-
)
|
|
74
|
-
const interruptWaiting = waitingFiber ? Fiber.interrupt(waitingFiber) : Effect.void
|
|
75
|
-
|
|
76
|
-
return yield* self.pipe(
|
|
77
|
-
Effect.tap(Effect.fnUntraced(function*(a) {
|
|
78
|
-
yield* interruptWaiting
|
|
79
|
-
const t = yield* wrapEffect(options.onSuccess)(a, ...args)
|
|
80
|
-
if (t === null) {
|
|
81
|
-
return
|
|
82
|
-
}
|
|
83
|
-
yield* toast.success(
|
|
84
|
-
t,
|
|
85
|
-
toastId !== undefined
|
|
86
|
-
? { id: toastId, timeout: baseTimeout, ...meta }
|
|
87
|
-
: { timeout: baseTimeout, ...meta }
|
|
88
|
-
)
|
|
89
|
-
})),
|
|
90
|
-
Effect.tapCause(Effect.fnUntraced(function*(cause) {
|
|
91
|
-
yield* interruptWaiting
|
|
92
|
-
yield* Effect.logDebug(
|
|
93
|
-
"WithToast - caught error cause: " + Cause.squash(cause),
|
|
94
|
-
Cause.hasInterruptsOnly(cause),
|
|
95
|
-
cause
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
if (Cause.hasInterruptsOnly(cause)) {
|
|
99
|
-
if (toastId) yield* toast.dismiss(toastId)
|
|
100
|
-
return
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const spanInfo = options.showSpanInfo !== false
|
|
104
|
-
? yield* Effect.currentSpan.pipe(
|
|
105
|
-
Effect.map((span) => `\nTrace: ${span.traceId}\nSpan: ${span.spanId}`),
|
|
106
|
-
Effect.orElseSucceed(() => "")
|
|
107
|
-
)
|
|
108
|
-
: ""
|
|
109
|
-
|
|
110
|
-
const t = yield* wrapEffect(options.onFailure)(Cause.findErrorOption(cause), ...args)
|
|
111
|
-
const opts = { timeout: baseTimeout * 2, ...meta }
|
|
112
|
-
|
|
113
|
-
if (typeof t === "object") {
|
|
114
|
-
const message = t.message + spanInfo
|
|
115
|
-
return t.level === "warn"
|
|
116
|
-
? yield* toast.warning(message, toastId !== undefined ? { ...opts, id: toastId } : opts)
|
|
117
|
-
: yield* toast.error(message, toastId !== undefined ? { ...opts, id: toastId } : opts)
|
|
118
|
-
}
|
|
119
|
-
yield* toast.error(t + spanInfo, toastId !== undefined ? { ...opts, id: toastId } : opts)
|
|
120
|
-
}, Effect.uninterruptible)),
|
|
121
|
-
toastId !== undefined ? Effect.provideService(CurrentToastId, CurrentToastId.of({ toastId })) : (_) => _
|
|
122
|
-
)
|
|
123
|
-
})
|
|
124
|
-
})
|
|
125
|
-
}) {
|
|
126
|
-
static readonly DefaultWithoutDependencies = Layer.effect(this, this.make)
|
|
127
|
-
static readonly Default = this.DefaultWithoutDependencies
|
|
128
|
-
|
|
129
|
-
static readonly handle = <A, E, Args extends Array<unknown>, R, WaiR = never, SucR = never, ErrR = never>(
|
|
130
|
-
options: ToastOptions<A, E, Args, WaiR, SucR, ErrR>
|
|
131
|
-
): (self: Effect.Effect<A, E, R>, ...args: Args) => Effect.Effect<A, E, R | WaiR | SucR | ErrR | WithToast> =>
|
|
132
|
-
(self, ...args) => this.use((_) => _<A, E, Args, R, WaiR, SucR, ErrR>(options)(self, ...args))
|
|
133
|
-
}
|
|
1
|
+
export * from "effect-app/withToast"
|