@effect-app/vue 4.0.0-beta.22 → 4.0.0-beta.221
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 +1613 -0
- package/dist/commander.d.ts +634 -0
- package/dist/commander.d.ts.map +1 -0
- package/dist/commander.js +1070 -0
- package/dist/confirm.d.ts +21 -0
- package/dist/confirm.d.ts.map +1 -0
- package/dist/confirm.js +26 -0
- package/dist/errorReporter.d.ts +7 -5
- package/dist/errorReporter.d.ts.map +1 -1
- package/dist/errorReporter.js +14 -19
- package/dist/form.d.ts +15 -6
- package/dist/form.d.ts.map +1 -1
- package/dist/form.js +46 -13
- package/dist/index.d.ts +1 -1
- package/dist/intl.d.ts +15 -0
- package/dist/intl.d.ts.map +1 -0
- package/dist/intl.js +9 -0
- package/dist/lib.d.ts +8 -10
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +35 -10
- package/dist/makeClient.d.ts +156 -339
- package/dist/makeClient.d.ts.map +1 -1
- package/dist/makeClient.js +225 -376
- package/dist/makeContext.d.ts +1 -1
- package/dist/makeContext.d.ts.map +1 -1
- package/dist/makeIntl.d.ts +1 -1
- package/dist/makeIntl.d.ts.map +1 -1
- package/dist/makeUseCommand.d.ts +9 -0
- package/dist/makeUseCommand.d.ts.map +1 -0
- package/dist/makeUseCommand.js +13 -0
- package/dist/mutate.d.ts +54 -34
- package/dist/mutate.d.ts.map +1 -1
- package/dist/mutate.js +139 -46
- package/dist/query.d.ts +20 -39
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +133 -72
- package/dist/routeParams.d.ts +3 -2
- package/dist/routeParams.d.ts.map +1 -1
- package/dist/routeParams.js +4 -3
- package/dist/runtime.d.ts +10 -6
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +32 -18
- package/dist/toast.d.ts +51 -0
- package/dist/toast.d.ts.map +1 -0
- package/dist/toast.js +34 -0
- package/dist/withToast.d.ts +30 -0
- package/dist/withToast.d.ts.map +1 -0
- package/dist/withToast.js +64 -0
- package/examples/streamMutation.ts +72 -0
- package/package.json +48 -50
- package/src/commander.ts +3406 -0
- package/src/{experimental/confirm.ts → confirm.ts} +12 -14
- package/src/errorReporter.ts +65 -75
- package/src/form.ts +61 -18
- package/src/intl.ts +12 -0
- package/src/lib.ts +48 -20
- package/src/makeClient.ts +574 -1134
- package/src/{experimental/makeUseCommand.ts → makeUseCommand.ts} +8 -5
- package/src/mutate.ts +268 -127
- package/src/query.ts +203 -183
- package/src/routeParams.ts +3 -2
- package/src/runtime.ts +46 -21
- package/src/{experimental/toast.ts → toast.ts} +15 -27
- package/src/{experimental/withToast.ts → withToast.ts} +46 -12
- 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 +3531 -122
- package/test/dist/stubs.d.ts.map +1 -1
- package/test/dist/stubs.js +187 -32
- 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 +292 -38
- package/test/streamFinal.test.ts +64 -0
- package/test/streamFn.test.ts +457 -0
- package/test/stubs.ts +223 -43
- package/tsconfig.examples.json +20 -0
- package/tsconfig.json +0 -1
- package/tsconfig.json.bak +5 -2
- package/tsconfig.src.json +34 -34
- package/tsconfig.test.json +2 -2
- package/vitest.config.ts +5 -5
- package/dist/experimental/commander.d.ts +0 -359
- package/dist/experimental/commander.d.ts.map +0 -1
- package/dist/experimental/commander.js +0 -557
- package/dist/experimental/confirm.d.ts +0 -19
- package/dist/experimental/confirm.d.ts.map +0 -1
- package/dist/experimental/confirm.js +0 -28
- package/dist/experimental/intl.d.ts +0 -16
- package/dist/experimental/intl.d.ts.map +0 -1
- package/dist/experimental/intl.js +0 -5
- package/dist/experimental/makeUseCommand.d.ts +0 -8
- package/dist/experimental/makeUseCommand.d.ts.map +0 -1
- package/dist/experimental/makeUseCommand.js +0 -13
- package/dist/experimental/toast.d.ts +0 -47
- package/dist/experimental/toast.d.ts.map +0 -1
- package/dist/experimental/toast.js +0 -41
- package/dist/experimental/withToast.d.ts +0 -25
- package/dist/experimental/withToast.d.ts.map +0 -1
- package/dist/experimental/withToast.js +0 -45
- package/eslint.config.mjs +0 -24
- package/src/experimental/commander.ts +0 -1835
- package/src/experimental/intl.ts +0 -9
package/src/query.ts
CHANGED
|
@@ -2,16 +2,28 @@
|
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
3
3
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
4
4
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
5
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
6
|
+
import { type DefaultError, type Enabled, experimental_streamedQuery as streamedQuery, type InitialDataFunction, type NonUndefinedGuard, type PlaceholderDataFunction, type QueryKey, type QueryObserverOptions, type QueryObserverResult, type RefetchOptions, useQuery as useTanstackQuery, useQueryClient, type UseQueryDefinedReturnType, type UseQueryReturnType } from "@tanstack/vue-query"
|
|
7
|
+
import * as Array from "effect-app/Array"
|
|
8
|
+
import { makeQueryKey, type Req } from "effect-app/client"
|
|
9
|
+
import type { RequestHandlerWithInput, RequestStreamHandlerWithInput } from "effect-app/client/clientFor"
|
|
10
|
+
import { CauseException, ServiceUnavailableError } from "effect-app/client/errors"
|
|
11
|
+
import type * as Context from "effect-app/Context"
|
|
12
|
+
import * as Effect from "effect-app/Effect"
|
|
13
|
+
import * as Option from "effect-app/Option"
|
|
14
|
+
import * as S from "effect-app/Schema"
|
|
15
|
+
import * as Cause from "effect/Cause"
|
|
16
|
+
import * as Channel from "effect/Channel"
|
|
17
|
+
import * as Exit from "effect/Exit"
|
|
18
|
+
import * as Pull from "effect/Pull"
|
|
19
|
+
import * as Scope from "effect/Scope"
|
|
20
|
+
import type * as Stream from "effect/Stream"
|
|
10
21
|
import { type Span } from "effect/Tracer"
|
|
11
22
|
import { isHttpClientError } from "effect/unstable/http/HttpClientError"
|
|
12
23
|
import * as AsyncResult from "effect/unstable/reactivity/AsyncResult"
|
|
13
24
|
import { computed, type ComputedRef, type MaybeRefOrGetter, ref, shallowRef, watch, type WatchSource } from "vue"
|
|
14
|
-
import {
|
|
25
|
+
import { reportRuntimeError } from "./lib.js"
|
|
26
|
+
import { makeRunPromise } from "./runtime.js"
|
|
15
27
|
|
|
16
28
|
// we must use interface extends, or we get the dreaded typescript error of isn't portable blabla @tanstack/vue-query/build/modern/types.js
|
|
17
29
|
// but because how they are dealing with some extends clause, we loose all properties except initialData
|
|
@@ -74,20 +86,68 @@ export interface CustomDefinedPlaceholderQueryOptions<
|
|
|
74
86
|
| PlaceholderDataFunction<NonFunctionGuard<TQueryData>, TError, NonFunctionGuard<TQueryData>, TQueryKey>
|
|
75
87
|
}
|
|
76
88
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
89
|
+
function swrToQuery<E, A>(r: {
|
|
90
|
+
error: CauseException<E> | undefined
|
|
91
|
+
data: A | undefined
|
|
92
|
+
isValidating: boolean
|
|
93
|
+
}): AsyncResult.AsyncResult<A, E> {
|
|
94
|
+
if (r.error !== undefined) {
|
|
95
|
+
return AsyncResult.failureWithPrevious(
|
|
96
|
+
r.error.originalCause,
|
|
97
|
+
{
|
|
98
|
+
previous: r.data === undefined ? Option.none() : Option.some(AsyncResult.success(r.data)),
|
|
99
|
+
waiting: r.isValidating
|
|
100
|
+
}
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
if (r.data !== undefined) {
|
|
104
|
+
return AsyncResult.success<A, E>(r.data, { waiting: r.isValidating })
|
|
82
105
|
}
|
|
106
|
+
|
|
107
|
+
return AsyncResult.initial(r.isValidating)
|
|
83
108
|
}
|
|
84
109
|
|
|
85
|
-
|
|
110
|
+
function streamToAsyncIterableWithCauseException<A, E, R>(
|
|
111
|
+
self: Stream.Stream<A, E, R>,
|
|
112
|
+
context: Context.Context<R>,
|
|
113
|
+
id: string
|
|
114
|
+
): AsyncIterable<A> {
|
|
115
|
+
return {
|
|
116
|
+
[Symbol.asyncIterator]() {
|
|
117
|
+
const runPromise = Effect.runPromiseWith(context)
|
|
118
|
+
const runPromiseExit = Effect.runPromiseExitWith(context)
|
|
119
|
+
const scope = Scope.makeUnsafe()
|
|
120
|
+
let pull: any
|
|
121
|
+
let currentIter: Iterator<A> | undefined
|
|
122
|
+
return {
|
|
123
|
+
async next(): Promise<IteratorResult<A>> {
|
|
124
|
+
if (currentIter) {
|
|
125
|
+
const next = currentIter.next()
|
|
126
|
+
if (!next.done) return next
|
|
127
|
+
currentIter = undefined
|
|
128
|
+
}
|
|
129
|
+
pull ??= await runPromise(Channel.toPullScoped((self as any).channel, scope))
|
|
130
|
+
const exit = await runPromiseExit(pull)
|
|
131
|
+
if (Exit.isSuccess(exit)) {
|
|
132
|
+
currentIter = (exit.value as any)[Symbol.iterator]()
|
|
133
|
+
return currentIter!.next()
|
|
134
|
+
} else if (Pull.isDoneCause((exit as any).cause)) {
|
|
135
|
+
return { done: true, value: undefined }
|
|
136
|
+
}
|
|
137
|
+
throw new CauseException((exit as any).cause, id)
|
|
138
|
+
},
|
|
139
|
+
return(_) {
|
|
140
|
+
return runPromise(Effect.as(Scope.close(scope, Exit.void), { done: true, value: undefined }) as any)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export const makeQuery = <R>(getRuntime: () => Context.Context<R>) => {
|
|
86
148
|
const useQuery_: {
|
|
87
149
|
<I, A, E, Request extends Req, Name extends string>(
|
|
88
|
-
q:
|
|
89
|
-
| RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
90
|
-
| RequestHandler<A, E, R, Request, Name>
|
|
150
|
+
q: RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
91
151
|
): {
|
|
92
152
|
<TData = A>(
|
|
93
153
|
arg: I | WatchSource<I> | undefined,
|
|
@@ -95,8 +155,8 @@ export const makeQuery = <R>(getRuntime: () => ServiceMap.ServiceMap<R>) => {
|
|
|
95
155
|
): readonly [
|
|
96
156
|
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
97
157
|
ComputedRef<TData | undefined>,
|
|
98
|
-
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData,
|
|
99
|
-
UseQueryDefinedReturnType<TData,
|
|
158
|
+
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, CauseException<E>>>,
|
|
159
|
+
UseQueryDefinedReturnType<TData, CauseException<E>>
|
|
100
160
|
]
|
|
101
161
|
|
|
102
162
|
<TData = A>(
|
|
@@ -105,8 +165,8 @@ export const makeQuery = <R>(getRuntime: () => ServiceMap.ServiceMap<R>) => {
|
|
|
105
165
|
): readonly [
|
|
106
166
|
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
107
167
|
ComputedRef<TData>,
|
|
108
|
-
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData,
|
|
109
|
-
UseQueryDefinedReturnType<TData,
|
|
168
|
+
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, CauseException<E>>>,
|
|
169
|
+
UseQueryDefinedReturnType<TData, CauseException<E>>
|
|
110
170
|
]
|
|
111
171
|
|
|
112
172
|
<TData = A>(
|
|
@@ -115,14 +175,12 @@ export const makeQuery = <R>(getRuntime: () => ServiceMap.ServiceMap<R>) => {
|
|
|
115
175
|
): readonly [
|
|
116
176
|
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
117
177
|
ComputedRef<TData>,
|
|
118
|
-
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData,
|
|
119
|
-
UseQueryDefinedReturnType<TData,
|
|
178
|
+
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, CauseException<E>>>,
|
|
179
|
+
UseQueryDefinedReturnType<TData, CauseException<E>>
|
|
120
180
|
]
|
|
121
181
|
}
|
|
122
182
|
} = <I, A, E, Request extends Req, Name extends string>(
|
|
123
|
-
q:
|
|
124
|
-
| RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
125
|
-
| RequestHandler<A, E, R, Request, Name>
|
|
183
|
+
q: RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
126
184
|
) =>
|
|
127
185
|
<TData = A>(
|
|
128
186
|
arg: I | WatchSource<I> | undefined,
|
|
@@ -130,26 +188,20 @@ export const makeQuery = <R>(getRuntime: () => ServiceMap.ServiceMap<R>) => {
|
|
|
130
188
|
options?: any
|
|
131
189
|
// TODO
|
|
132
190
|
) => {
|
|
133
|
-
// we wrap into
|
|
134
|
-
const runPromise =
|
|
135
|
-
_.then(
|
|
136
|
-
Exit.match({
|
|
137
|
-
onFailure: (cause) => Promise.reject(new KnownFiberFailure(cause)),
|
|
138
|
-
onSuccess: (value) => Promise.resolve(value)
|
|
139
|
-
})
|
|
140
|
-
))
|
|
191
|
+
// we wrap into CauseException because we want to keep the full cause of the failure.
|
|
192
|
+
const runPromise = makeRunPromise(getRuntime())
|
|
141
193
|
const arr = arg
|
|
142
|
-
const req: { value: I } = !arg
|
|
194
|
+
const req: { value: I } | undefined = !arg
|
|
143
195
|
? undefined
|
|
144
196
|
: typeof arr === "function"
|
|
145
197
|
? ({
|
|
146
198
|
get value() {
|
|
147
199
|
return (arr as any)()
|
|
148
200
|
}
|
|
149
|
-
}
|
|
150
|
-
: ref(arg)
|
|
201
|
+
})
|
|
202
|
+
: ref(arg) as any
|
|
151
203
|
const queryKey = makeQueryKey(q)
|
|
152
|
-
const
|
|
204
|
+
const projectionHash = (q as { queryKeyProjectionHash?: string }).queryKeyProjectionHash
|
|
153
205
|
|
|
154
206
|
const defaultOptions = {
|
|
155
207
|
// we do not want to throw errors, because we turn the success and error responses into a Result type
|
|
@@ -161,57 +213,31 @@ export const makeQuery = <R>(getRuntime: () => ServiceMap.ServiceMap<R>) => {
|
|
|
161
213
|
throwOnError: false
|
|
162
214
|
}
|
|
163
215
|
|
|
164
|
-
const r = useTanstackQuery<A,
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return false
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return retryCount < 5
|
|
177
|
-
},
|
|
178
|
-
queryKey,
|
|
179
|
-
queryFn: ({ meta, signal }) =>
|
|
180
|
-
runPromise(
|
|
181
|
-
handler
|
|
182
|
-
.pipe(
|
|
183
|
-
Effect.tapCauseIf(Cause.hasDies, (cause) => reportRuntimeError(cause)),
|
|
184
|
-
Effect.withSpan(`query ${q.id}`, {}, { captureStackTrace: false }),
|
|
185
|
-
meta?.["span"] ? Effect.withParentSpan(meta["span"] as Span) : (_) => _
|
|
186
|
-
),
|
|
187
|
-
{ signal }
|
|
188
|
-
)
|
|
216
|
+
const r = useTanstackQuery<A, CauseException<E>, TData>({
|
|
217
|
+
...defaultOptions,
|
|
218
|
+
...options,
|
|
219
|
+
retry: (retryCount, error) => {
|
|
220
|
+
if (error instanceof CauseException) {
|
|
221
|
+
if (!isHttpClientError(error.cause) && !S.is(ServiceUnavailableError)(error.cause)) {
|
|
222
|
+
return false
|
|
223
|
+
}
|
|
189
224
|
}
|
|
190
|
-
: {
|
|
191
|
-
...defaultOptions,
|
|
192
|
-
...options,
|
|
193
|
-
retry: (retryCount, error) => {
|
|
194
|
-
if (error instanceof KnownFiberFailure) {
|
|
195
|
-
if (!isHttpClientError(error.error) && !S.is(ServiceUnavailableError)(error.error)) {
|
|
196
|
-
return false
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
225
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
)
|
|
226
|
+
return retryCount < 5
|
|
227
|
+
},
|
|
228
|
+
queryKey: projectionHash === undefined ? [...queryKey, req] : [...queryKey, req, projectionHash],
|
|
229
|
+
queryFn: ({ meta, signal }) =>
|
|
230
|
+
runPromise(
|
|
231
|
+
q
|
|
232
|
+
.handler(req?.value as I)
|
|
233
|
+
.pipe(
|
|
234
|
+
Effect.tapCauseIf(Cause.hasDies, (cause) => reportRuntimeError(cause)),
|
|
235
|
+
Effect.withSpan(`query ${q.id}`, {}, { captureStackTrace: false }),
|
|
236
|
+
meta?.["span"] ? Effect.withParentSpan(meta["span"] as Span) : (_) => _
|
|
237
|
+
),
|
|
238
|
+
{ signal }
|
|
239
|
+
)
|
|
240
|
+
})
|
|
215
241
|
|
|
216
242
|
const latestSuccess = shallowRef<TData>()
|
|
217
243
|
const result = computed((): AsyncResult.AsyncResult<TData, E> =>
|
|
@@ -239,129 +265,130 @@ export const makeQuery = <R>(getRuntime: () => ServiceMap.ServiceMap<R>) => {
|
|
|
239
265
|
] as any
|
|
240
266
|
}
|
|
241
267
|
|
|
242
|
-
function swrToQuery<E, A>(r: {
|
|
243
|
-
error: KnownFiberFailure<E> | undefined
|
|
244
|
-
data: A | undefined
|
|
245
|
-
isValidating: boolean
|
|
246
|
-
}): AsyncResult.AsyncResult<A, E> {
|
|
247
|
-
if (r.error !== undefined) {
|
|
248
|
-
return AsyncResult.failureWithPrevious(
|
|
249
|
-
r.error.effectCause,
|
|
250
|
-
{
|
|
251
|
-
previous: r.data === undefined ? Option.none() : Option.some(AsyncResult.success(r.data)),
|
|
252
|
-
waiting: r.isValidating
|
|
253
|
-
}
|
|
254
|
-
)
|
|
255
|
-
}
|
|
256
|
-
if (r.data !== undefined) {
|
|
257
|
-
return AsyncResult.success<A, E>(r.data, { waiting: r.isValidating })
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return AsyncResult.initial(r.isValidating)
|
|
261
|
-
}
|
|
262
|
-
|
|
263
268
|
const useQuery: {
|
|
264
269
|
/**
|
|
265
270
|
* Effect results are passed to the caller, including errors.
|
|
271
|
+
* When `I = void` the input argument may be omitted.
|
|
266
272
|
* @deprecated use client helpers instead (.query())
|
|
267
273
|
*/
|
|
268
|
-
<E, A, Request extends Req, Name extends string>(
|
|
269
|
-
self:
|
|
270
|
-
): {
|
|
271
|
-
// required options, with initialData
|
|
272
|
-
/**
|
|
273
|
-
* Effect results are passed to the caller, including errors.
|
|
274
|
-
*/
|
|
275
|
-
<TData = A>(
|
|
276
|
-
options: CustomDefinedInitialQueryOptions<A, KnownFiberFailure<E>, TData>
|
|
277
|
-
): readonly [
|
|
278
|
-
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
279
|
-
ComputedRef<TData>,
|
|
280
|
-
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, KnownFiberFailure<E>>>,
|
|
281
|
-
UseQueryReturnType<any, any>
|
|
282
|
-
]
|
|
283
|
-
<TData = A>(
|
|
284
|
-
options: CustomDefinedPlaceholderQueryOptions<A, E, TData>
|
|
285
|
-
): readonly [
|
|
286
|
-
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
287
|
-
ComputedRef<TData>,
|
|
288
|
-
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, KnownFiberFailure<E>>, never, never>,
|
|
289
|
-
UseQueryDefinedReturnType<TData, KnownFiberFailure<E>>
|
|
290
|
-
]
|
|
291
|
-
// optional options, optional A
|
|
292
|
-
/**
|
|
293
|
-
* Effect results are passed to the caller, including errors.
|
|
294
|
-
*/
|
|
295
|
-
<TData = A>(options?: CustomUndefinedInitialQueryOptions<A, KnownFiberFailure<E>, TData>): readonly [
|
|
296
|
-
ComputedRef<AsyncResult.AsyncResult<A, E>>,
|
|
297
|
-
ComputedRef<A | undefined>,
|
|
298
|
-
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, KnownFiberFailure<E>>>,
|
|
299
|
-
UseQueryReturnType<any, any>
|
|
300
|
-
]
|
|
301
|
-
}
|
|
302
|
-
/**
|
|
303
|
-
* Effect results are passed to the caller, including errors.
|
|
304
|
-
* @deprecated use client helpers instead (.query())
|
|
305
|
-
*/
|
|
306
|
-
<Arg, E, A, Request extends Req, Name extends string>(
|
|
307
|
-
self: RequestHandlerWithInput<Arg, A, E, R, Request, Name>
|
|
274
|
+
<I, E, A, Request extends Req, Name extends string>(
|
|
275
|
+
self: RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
308
276
|
): {
|
|
309
|
-
// required options, with initialData
|
|
310
|
-
/**
|
|
311
|
-
* Effect results are passed to the caller, including errors.
|
|
312
|
-
*/
|
|
313
277
|
<TData = A>(
|
|
314
|
-
arg:
|
|
315
|
-
options: CustomDefinedInitialQueryOptions<A,
|
|
278
|
+
arg: I | WatchSource<I>,
|
|
279
|
+
options: CustomDefinedInitialQueryOptions<A, CauseException<E>, TData>
|
|
316
280
|
): readonly [
|
|
317
281
|
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
318
282
|
ComputedRef<TData>,
|
|
319
|
-
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData,
|
|
283
|
+
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, CauseException<E>>>,
|
|
320
284
|
UseQueryReturnType<any, any>
|
|
321
285
|
]
|
|
322
|
-
// required options, with placeholderData
|
|
323
|
-
/**
|
|
324
|
-
* Effect results are passed to the caller, including errors.
|
|
325
|
-
*/
|
|
326
286
|
<TData = A>(
|
|
327
|
-
arg:
|
|
328
|
-
options: CustomDefinedPlaceholderQueryOptions<A,
|
|
287
|
+
arg: I | WatchSource<I>,
|
|
288
|
+
options: CustomDefinedPlaceholderQueryOptions<A, CauseException<E>, TData>
|
|
329
289
|
): readonly [
|
|
330
290
|
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
331
291
|
ComputedRef<TData>,
|
|
332
|
-
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData,
|
|
292
|
+
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, CauseException<E>>>,
|
|
333
293
|
UseQueryReturnType<any, any>
|
|
334
294
|
]
|
|
335
|
-
// optional options, optional A
|
|
336
|
-
/**
|
|
337
|
-
* Effect results are passed to the caller, including errors.
|
|
338
|
-
*/
|
|
339
295
|
<TData = A>(
|
|
340
|
-
arg:
|
|
341
|
-
options?: CustomUndefinedInitialQueryOptions<A,
|
|
296
|
+
arg: I | WatchSource<I>,
|
|
297
|
+
options?: CustomUndefinedInitialQueryOptions<A, CauseException<E>, TData>
|
|
342
298
|
): readonly [
|
|
343
299
|
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
344
300
|
ComputedRef<TData | undefined>,
|
|
345
|
-
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData,
|
|
301
|
+
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, CauseException<E>>>,
|
|
346
302
|
UseQueryReturnType<any, any>
|
|
347
303
|
]
|
|
348
304
|
}
|
|
349
|
-
} = (
|
|
305
|
+
} = ((
|
|
350
306
|
self: any
|
|
351
307
|
) => {
|
|
352
308
|
const q = useQuery_(self)
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
Effect.isEffect(self.handler)
|
|
356
|
-
? q(undefined, argOrOptions)
|
|
357
|
-
: q(argOrOptions, options)
|
|
358
|
-
}
|
|
309
|
+
return (arg?: any, options?: any) => q(arg, options)
|
|
310
|
+
}) as any
|
|
359
311
|
return useQuery
|
|
360
312
|
}
|
|
361
313
|
|
|
362
314
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
363
315
|
export interface MakeQuery2<R> extends ReturnType<typeof makeQuery<R>> {}
|
|
364
316
|
|
|
317
|
+
type StreamQueryResult<A, E> = readonly [
|
|
318
|
+
ComputedRef<AsyncResult.AsyncResult<A[], E>>,
|
|
319
|
+
ComputedRef<A[] | undefined>,
|
|
320
|
+
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<A[], CauseException<E>>>,
|
|
321
|
+
UseQueryReturnType<any, any>
|
|
322
|
+
]
|
|
323
|
+
|
|
324
|
+
export const makeStreamQuery = <R>(getRuntime: () => Context.Context<R>) => {
|
|
325
|
+
const streamQuery_: {
|
|
326
|
+
<I, E, A, Request extends Req, Name extends string>(
|
|
327
|
+
q: RequestStreamHandlerWithInput<I, A, E, R, Request, Name>
|
|
328
|
+
): (arg: I | WatchSource<I>) => StreamQueryResult<A, E>
|
|
329
|
+
} = (q: any) => (arg?: any) => {
|
|
330
|
+
const context = getRuntime()
|
|
331
|
+
const arr = arg
|
|
332
|
+
const req: { value: any } | undefined = !arg
|
|
333
|
+
? undefined
|
|
334
|
+
: typeof arr === "function"
|
|
335
|
+
? ({
|
|
336
|
+
get value() {
|
|
337
|
+
return arr()
|
|
338
|
+
}
|
|
339
|
+
})
|
|
340
|
+
: ref(arg)
|
|
341
|
+
const queryKey = makeQueryKey(q)
|
|
342
|
+
|
|
343
|
+
const r = useTanstackQuery<any[], CauseException<any>, any[]>(
|
|
344
|
+
{
|
|
345
|
+
throwOnError: false,
|
|
346
|
+
retry: (retryCount: number, error: unknown) => {
|
|
347
|
+
if (error instanceof CauseException) {
|
|
348
|
+
if (!isHttpClientError(error.cause) && !S.is(ServiceUnavailableError)(error.cause)) {
|
|
349
|
+
return false
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return retryCount < 5
|
|
353
|
+
},
|
|
354
|
+
queryKey: [...queryKey, req],
|
|
355
|
+
queryFn: streamedQuery({
|
|
356
|
+
streamFn: () => {
|
|
357
|
+
const stream = q.handler(req?.value)
|
|
358
|
+
return streamToAsyncIterableWithCauseException(stream, context, q.id)
|
|
359
|
+
}
|
|
360
|
+
})
|
|
361
|
+
}
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
const latestSuccess = shallowRef<any[]>()
|
|
365
|
+
const result = computed((): AsyncResult.AsyncResult<any[], any> =>
|
|
366
|
+
swrToQuery({
|
|
367
|
+
error: r.error.value ?? undefined,
|
|
368
|
+
data: r.data.value === undefined ? latestSuccess.value : r.data.value,
|
|
369
|
+
isValidating: r.isFetching.value
|
|
370
|
+
})
|
|
371
|
+
)
|
|
372
|
+
watch(result, (value) => latestSuccess.value = Option.getOrUndefined(AsyncResult.value(value)), { immediate: true })
|
|
373
|
+
|
|
374
|
+
return [
|
|
375
|
+
result,
|
|
376
|
+
computed(() => latestSuccess.value),
|
|
377
|
+
(options?: RefetchOptions) =>
|
|
378
|
+
Effect.currentSpan.pipe(
|
|
379
|
+
Effect.orElseSucceed(() => null),
|
|
380
|
+
Effect.flatMap((span) => Effect.promise(() => r.refetch({ ...options, updateMeta: { span } })))
|
|
381
|
+
),
|
|
382
|
+
r
|
|
383
|
+
] as any
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return streamQuery_
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
390
|
+
export interface MakeStreamQuery2<R> extends ReturnType<typeof makeStreamQuery<R>> {}
|
|
391
|
+
|
|
365
392
|
function orPrevious<E, A>(result: AsyncResult.AsyncResult<A, E>) {
|
|
366
393
|
return AsyncResult.isFailure(result) && Option.isSome(result.previousSuccess)
|
|
367
394
|
? AsyncResult.success(result.previousSuccess.value, { waiting: result.waiting })
|
|
@@ -412,20 +439,13 @@ export const useUpdateQuery = () => {
|
|
|
412
439
|
const queryClient = useQueryClient()
|
|
413
440
|
|
|
414
441
|
const f: {
|
|
415
|
-
<A>(
|
|
416
|
-
query: RequestHandler<A, any, any, any, any>,
|
|
417
|
-
updater: (data: NoInfer<A>) => NoInfer<A>
|
|
418
|
-
): void
|
|
419
442
|
<I, A>(
|
|
420
443
|
query: RequestHandlerWithInput<I, A, any, any, any, any>,
|
|
421
444
|
input: I,
|
|
422
445
|
updater: (data: NoInfer<A>) => NoInfer<A>
|
|
423
446
|
): void
|
|
424
|
-
} = (query: any,
|
|
425
|
-
const
|
|
426
|
-
const key = updaterMaybe !== undefined
|
|
427
|
-
? [...makeQueryKey(query), updateOrInput]
|
|
428
|
-
: makeQueryKey(query)
|
|
447
|
+
} = (query: any, input: any, updater: any) => {
|
|
448
|
+
const key = [...makeQueryKey(query), input]
|
|
429
449
|
const data = queryClient.getQueryData(key)
|
|
430
450
|
if (data) {
|
|
431
451
|
queryClient.setQueryData(key, updater)
|
package/src/routeParams.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import * as Option from "effect-app/Option"
|
|
2
|
+
import * as S from "effect-app/Schema"
|
|
3
3
|
import type { Schema } from "effect-app/Schema"
|
|
4
4
|
import { typedKeysOf } from "effect-app/utils"
|
|
5
|
+
import { flow } from "effect/Function"
|
|
5
6
|
import type { ParsedQuery } from "query-string"
|
|
6
7
|
|
|
7
8
|
export function getQueryParam(search: ParsedQuery, param: string) {
|
package/src/runtime.ts
CHANGED
|
@@ -1,31 +1,56 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { CauseException } from "effect-app/client/errors"
|
|
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"
|
|
3
9
|
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
},
|
|
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
|
+
},
|
|
15
20
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
21
|
+
[Symbol.asyncDispose]() {
|
|
22
|
+
return mrt.dispose()
|
|
23
|
+
}
|
|
24
|
+
}) // as we initialise here, there is no more error left.
|
|
25
|
+
})
|
|
22
26
|
|
|
23
|
-
export function initializeSync<A, E>(layer: Layer.Layer<A, E
|
|
27
|
+
export function initializeSync<A, E>(layer: Layer.Layer<A, E>) {
|
|
24
28
|
const runtime = Effect.runSync(makeAppRuntime(layer))
|
|
25
29
|
return runtime
|
|
26
30
|
}
|
|
27
31
|
|
|
28
|
-
export function initializeAsync<A, E>(layer: Layer.Layer<A, E
|
|
32
|
+
export function initializeAsync<A, E>(layer: Layer.Layer<A, E>) {
|
|
29
33
|
return Effect
|
|
30
34
|
.runPromise(makeAppRuntime(layer))
|
|
31
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,9 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import * as Context from "effect-app/Context"
|
|
2
|
+
import { accessEffectFn } from "effect-app/Context"
|
|
3
|
+
import * as Effect from "effect-app/Effect"
|
|
4
|
+
import * as Option from "effect-app/Option"
|
|
3
5
|
|
|
4
6
|
export type ToastId = string | number
|
|
5
|
-
export type ToastOpts = { id?: ToastId; timeout?: number }
|
|
6
|
-
export type ToastOptsInternal = { id?: ToastId | null; timeout?: 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 }
|
|
7
9
|
|
|
8
10
|
export type UseToast = () => {
|
|
9
11
|
error: (this: void, message: string, options?: ToastOpts) => ToastId
|
|
@@ -13,7 +15,7 @@ export type UseToast = () => {
|
|
|
13
15
|
dismiss: (this: void, id: ToastId) => void
|
|
14
16
|
}
|
|
15
17
|
|
|
16
|
-
export class CurrentToastId extends
|
|
18
|
+
export class CurrentToastId extends Context.Opaque<CurrentToastId, { toastId: ToastId }>()("CurrentToastId") {}
|
|
17
19
|
|
|
18
20
|
/** fallback to CurrentToastId when available unless id is explicitly set to a value or null */
|
|
19
21
|
export const wrap = (toast: ReturnType<UseToast>) => {
|
|
@@ -41,26 +43,12 @@ export const wrap = (toast: ReturnType<UseToast>) => {
|
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
extends proxify(ServiceMap.Opaque<Toast, ReturnType<typeof wrap>>()("Toast"))<Toast, ReturnType<typeof wrap>>()
|
|
46
|
-
{
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// const a = Layer.effect(Toast, Effect.sync(() => Toast.of(null as any)))
|
|
50
|
-
|
|
51
|
-
// const A = Toast.of({
|
|
52
|
-
// error: () => Effect.succeed(null as any),
|
|
53
|
-
// info: () => Effect.succeed(null as any),
|
|
54
|
-
// success: () => Effect.succeed(null as any),
|
|
55
|
-
// warning: () => Effect.succeed(null as any),
|
|
56
|
-
// dismiss: () => Effect.succeed(null as any)
|
|
57
|
-
// })
|
|
46
|
+
type ToastShape = ReturnType<typeof wrap>
|
|
58
47
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
// })
|
|
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
|
+
}
|