@effect-app/vue 4.0.0-beta.26 → 4.0.0-beta.261
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 +1929 -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/dependencyMetadata.d.ts +8 -0
- package/dist/dependencyMetadata.d.ts.map +1 -0
- package/dist/dependencyMetadata.js +6 -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 +157 -343
- package/dist/makeClient.d.ts.map +1 -1
- package/dist/makeClient.js +216 -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 +97 -39
- package/dist/mutate.d.ts.map +1 -1
- package/dist/mutate.js +177 -49
- package/dist/query.d.ts +24 -39
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +156 -78
- package/dist/routeParams.d.ts +5 -5
- package/dist/routeParams.d.ts.map +1 -1
- package/dist/routeParams.js +4 -3
- package/dist/runtime.d.ts +2 -15
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +2 -26
- package/dist/toast.d.ts +2 -0
- package/dist/toast.d.ts.map +1 -0
- package/dist/toast.js +2 -0
- package/dist/withToast.d.ts +2 -0
- package/dist/withToast.d.ts.map +1 -0
- package/dist/withToast.js +2 -0
- package/examples/streamMutation.ts +72 -0
- package/package.json +29 -90
- 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 +581 -1138
- package/src/{experimental/makeUseCommand.ts → makeUseCommand.ts} +8 -5
- package/src/mutate.ts +335 -134
- package/src/query.ts +241 -183
- package/src/routeParams.ts +7 -7
- package/src/runtime.ts +1 -31
- package/src/toast.ts +1 -0
- package/src/withToast.ts +1 -0
- package/test/Mutation.test.ts +181 -24
- package/test/dist/dependencyInvalidation.test.d.ts.map +1 -0
- package/test/dist/form.test.d.ts.map +1 -1
- package/test/dist/lib.test.d.ts.map +1 -0
- package/test/dist/streamFinal.test.d.ts.map +1 -0
- package/test/dist/streamFn.test.d.ts.map +1 -0
- package/test/dist/stubs.d.ts +3527 -122
- package/test/dist/stubs.d.ts.map +1 -1
- package/test/dist/stubs.js +187 -32
- package/test/form-validation-errors.test.ts +25 -20
- package/test/form.test.ts +22 -3
- package/test/lib.test.ts +240 -0
- package/test/makeClient.test.ts +327 -38
- package/test/streamFinal.test.ts +64 -0
- package/test/streamFn.test.ts +457 -0
- package/test/stubs.ts +223 -43
- package/tsconfig.examples.json +20 -0
- package/tsconfig.json +2 -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/experimental/toast.ts +0 -66
- package/src/experimental/withToast.ts +0 -99
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,29 +86,87 @@ 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 })
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return AsyncResult.initial(r.isValidating)
|
|
108
|
+
}
|
|
109
|
+
|
|
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
|
+
}
|
|
82
144
|
}
|
|
83
145
|
}
|
|
84
146
|
|
|
85
|
-
export const makeQuery = <R>(getRuntime: () =>
|
|
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
|
): {
|
|
152
|
+
<TData = A>(
|
|
153
|
+
arg: WatchSource<Option.Option<I>>,
|
|
154
|
+
options: Omit<CustomUndefinedInitialQueryOptions<A, E, TData>, "enabled"> & { mode: "optional" }
|
|
155
|
+
): readonly [
|
|
156
|
+
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
157
|
+
ComputedRef<TData | undefined>,
|
|
158
|
+
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, CauseException<E>>>,
|
|
159
|
+
UseQueryDefinedReturnType<TData, CauseException<E>>
|
|
160
|
+
]
|
|
161
|
+
|
|
92
162
|
<TData = A>(
|
|
93
163
|
arg: I | WatchSource<I> | undefined,
|
|
94
164
|
options?: CustomUndefinedInitialQueryOptions<A, E, TData>
|
|
95
165
|
): readonly [
|
|
96
166
|
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
97
167
|
ComputedRef<TData | undefined>,
|
|
98
|
-
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData,
|
|
99
|
-
UseQueryDefinedReturnType<TData,
|
|
168
|
+
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, CauseException<E>>>,
|
|
169
|
+
UseQueryDefinedReturnType<TData, CauseException<E>>
|
|
100
170
|
]
|
|
101
171
|
|
|
102
172
|
<TData = A>(
|
|
@@ -105,8 +175,8 @@ export const makeQuery = <R>(getRuntime: () => ServiceMap.ServiceMap<R>) => {
|
|
|
105
175
|
): readonly [
|
|
106
176
|
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
107
177
|
ComputedRef<TData>,
|
|
108
|
-
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData,
|
|
109
|
-
UseQueryDefinedReturnType<TData,
|
|
178
|
+
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, CauseException<E>>>,
|
|
179
|
+
UseQueryDefinedReturnType<TData, CauseException<E>>
|
|
110
180
|
]
|
|
111
181
|
|
|
112
182
|
<TData = A>(
|
|
@@ -115,41 +185,52 @@ export const makeQuery = <R>(getRuntime: () => ServiceMap.ServiceMap<R>) => {
|
|
|
115
185
|
): readonly [
|
|
116
186
|
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
117
187
|
ComputedRef<TData>,
|
|
118
|
-
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData,
|
|
119
|
-
UseQueryDefinedReturnType<TData,
|
|
188
|
+
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, CauseException<E>>>,
|
|
189
|
+
UseQueryDefinedReturnType<TData, CauseException<E>>
|
|
120
190
|
]
|
|
121
191
|
}
|
|
122
192
|
} = <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>
|
|
193
|
+
q: RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
126
194
|
) =>
|
|
127
195
|
<TData = A>(
|
|
128
|
-
arg: I | WatchSource<I> | undefined
|
|
196
|
+
arg: I | WatchSource<I> | undefined | WatchSource<Option.Option<I>>,
|
|
129
197
|
// todo QueryKey type would be [string, ...string[]], but with I it would be [string, ...string[], I]
|
|
130
198
|
options?: any
|
|
131
199
|
// TODO
|
|
132
200
|
) => {
|
|
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
|
-
))
|
|
201
|
+
// we wrap into CauseException because we want to keep the full cause of the failure.
|
|
202
|
+
const runPromise = makeRunPromise(getRuntime())
|
|
141
203
|
const arr = arg
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
204
|
+
|
|
205
|
+
let req: { value: I } | undefined
|
|
206
|
+
let callerOptions: any = options
|
|
207
|
+
|
|
208
|
+
if (options?.mode === "optional") {
|
|
209
|
+
const getOption: () => Option.Option<I> = typeof arr === "function"
|
|
210
|
+
? arr as () => Option.Option<I>
|
|
211
|
+
: () => (arr as { value: Option.Option<I> }).value
|
|
212
|
+
req = {
|
|
146
213
|
get value() {
|
|
147
|
-
|
|
214
|
+
// getOrUndefined returns undefined when None, but queryFn is only called when enabled (Some)
|
|
215
|
+
return Option.getOrUndefined(getOption()) as I
|
|
148
216
|
}
|
|
149
|
-
}
|
|
150
|
-
:
|
|
217
|
+
}
|
|
218
|
+
const { mode: _mode, enabled: _enabled, ...rest } = options ?? {}
|
|
219
|
+
callerOptions = { ...rest, enabled: computed(() => Option.isSome(getOption())) }
|
|
220
|
+
} else {
|
|
221
|
+
req = !arg
|
|
222
|
+
? undefined
|
|
223
|
+
: typeof arr === "function"
|
|
224
|
+
? ({
|
|
225
|
+
get value() {
|
|
226
|
+
return (arr as any)()
|
|
227
|
+
}
|
|
228
|
+
})
|
|
229
|
+
: ref(arg) as any
|
|
230
|
+
}
|
|
231
|
+
|
|
151
232
|
const queryKey = makeQueryKey(q)
|
|
152
|
-
const
|
|
233
|
+
const projectionHash = (q as { queryKeyProjectionHash?: string }).queryKeyProjectionHash
|
|
153
234
|
|
|
154
235
|
const defaultOptions = {
|
|
155
236
|
// we do not want to throw errors, because we turn the success and error responses into a Result type
|
|
@@ -161,57 +242,31 @@ export const makeQuery = <R>(getRuntime: () => ServiceMap.ServiceMap<R>) => {
|
|
|
161
242
|
throwOnError: false
|
|
162
243
|
}
|
|
163
244
|
|
|
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
|
-
)
|
|
245
|
+
const r = useTanstackQuery<A, CauseException<E>, TData>({
|
|
246
|
+
...defaultOptions,
|
|
247
|
+
...callerOptions,
|
|
248
|
+
retry: (retryCount, error) => {
|
|
249
|
+
if (error instanceof CauseException) {
|
|
250
|
+
if (!isHttpClientError(error.cause) && !S.is(ServiceUnavailableError)(error.cause)) {
|
|
251
|
+
return false
|
|
252
|
+
}
|
|
189
253
|
}
|
|
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
254
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
)
|
|
255
|
+
return retryCount < 5
|
|
256
|
+
},
|
|
257
|
+
queryKey: projectionHash === undefined ? [...queryKey, req] : [...queryKey, req, projectionHash],
|
|
258
|
+
queryFn: ({ meta, signal }) =>
|
|
259
|
+
runPromise(
|
|
260
|
+
q
|
|
261
|
+
.handler(req?.value as I)
|
|
262
|
+
.pipe(
|
|
263
|
+
Effect.tapCauseIf(Cause.hasDies, (cause) => reportRuntimeError(cause)),
|
|
264
|
+
Effect.withSpan(`query ${q.id}`, {}, { captureStackTrace: false }),
|
|
265
|
+
meta?.["span"] ? Effect.withParentSpan(meta["span"] as Span) : (_) => _
|
|
266
|
+
),
|
|
267
|
+
{ signal }
|
|
268
|
+
)
|
|
269
|
+
})
|
|
215
270
|
|
|
216
271
|
const latestSuccess = shallowRef<TData>()
|
|
217
272
|
const result = computed((): AsyncResult.AsyncResult<TData, E> =>
|
|
@@ -239,129 +294,139 @@ export const makeQuery = <R>(getRuntime: () => ServiceMap.ServiceMap<R>) => {
|
|
|
239
294
|
] as any
|
|
240
295
|
}
|
|
241
296
|
|
|
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
297
|
const useQuery: {
|
|
264
298
|
/**
|
|
265
299
|
* Effect results are passed to the caller, including errors.
|
|
300
|
+
* When `I = void` the input argument may be omitted.
|
|
266
301
|
* @deprecated use client helpers instead (.query())
|
|
267
302
|
*/
|
|
268
|
-
<E, A, Request extends Req, Name extends string>(
|
|
269
|
-
self:
|
|
303
|
+
<I, E, A, Request extends Req, Name extends string>(
|
|
304
|
+
self: RequestHandlerWithInput<I, A, E, R, Request, Name>
|
|
270
305
|
): {
|
|
271
|
-
// required options, with initialData
|
|
272
|
-
/**
|
|
273
|
-
* Effect results are passed to the caller, including errors.
|
|
274
|
-
*/
|
|
275
306
|
<TData = A>(
|
|
276
|
-
|
|
307
|
+
arg: WatchSource<Option.Option<I>>,
|
|
308
|
+
options: Omit<CustomUndefinedInitialQueryOptions<A, CauseException<E>, TData>, "enabled"> & { mode: "optional" }
|
|
277
309
|
): readonly [
|
|
278
310
|
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
279
|
-
ComputedRef<TData>,
|
|
280
|
-
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData,
|
|
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>>>,
|
|
311
|
+
ComputedRef<TData | undefined>,
|
|
312
|
+
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, CauseException<E>>>,
|
|
299
313
|
UseQueryReturnType<any, any>
|
|
300
314
|
]
|
|
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>
|
|
308
|
-
): {
|
|
309
|
-
// required options, with initialData
|
|
310
|
-
/**
|
|
311
|
-
* Effect results are passed to the caller, including errors.
|
|
312
|
-
*/
|
|
313
315
|
<TData = A>(
|
|
314
|
-
arg:
|
|
315
|
-
options: CustomDefinedInitialQueryOptions<A,
|
|
316
|
+
arg: I | WatchSource<I>,
|
|
317
|
+
options: CustomDefinedInitialQueryOptions<A, CauseException<E>, TData>
|
|
316
318
|
): readonly [
|
|
317
319
|
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
318
320
|
ComputedRef<TData>,
|
|
319
|
-
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData,
|
|
321
|
+
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, CauseException<E>>>,
|
|
320
322
|
UseQueryReturnType<any, any>
|
|
321
323
|
]
|
|
322
|
-
// required options, with placeholderData
|
|
323
|
-
/**
|
|
324
|
-
* Effect results are passed to the caller, including errors.
|
|
325
|
-
*/
|
|
326
324
|
<TData = A>(
|
|
327
|
-
arg:
|
|
328
|
-
options: CustomDefinedPlaceholderQueryOptions<A,
|
|
325
|
+
arg: I | WatchSource<I>,
|
|
326
|
+
options: CustomDefinedPlaceholderQueryOptions<A, CauseException<E>, TData>
|
|
329
327
|
): readonly [
|
|
330
328
|
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
331
329
|
ComputedRef<TData>,
|
|
332
|
-
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData,
|
|
330
|
+
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, CauseException<E>>>,
|
|
333
331
|
UseQueryReturnType<any, any>
|
|
334
332
|
]
|
|
335
|
-
// optional options, optional A
|
|
336
|
-
/**
|
|
337
|
-
* Effect results are passed to the caller, including errors.
|
|
338
|
-
*/
|
|
339
333
|
<TData = A>(
|
|
340
|
-
arg:
|
|
341
|
-
options?: CustomUndefinedInitialQueryOptions<A,
|
|
334
|
+
arg: I | WatchSource<I>,
|
|
335
|
+
options?: CustomUndefinedInitialQueryOptions<A, CauseException<E>, TData>
|
|
342
336
|
): readonly [
|
|
343
337
|
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
344
338
|
ComputedRef<TData | undefined>,
|
|
345
|
-
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData,
|
|
339
|
+
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, CauseException<E>>>,
|
|
346
340
|
UseQueryReturnType<any, any>
|
|
347
341
|
]
|
|
348
342
|
}
|
|
349
|
-
} = (
|
|
343
|
+
} = ((
|
|
350
344
|
self: any
|
|
351
345
|
) => {
|
|
352
346
|
const q = useQuery_(self)
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
Effect.isEffect(self.handler)
|
|
356
|
-
? q(undefined, argOrOptions)
|
|
357
|
-
: q(argOrOptions, options)
|
|
358
|
-
}
|
|
347
|
+
return (arg?: any, options?: any) => q(arg, options)
|
|
348
|
+
}) as any
|
|
359
349
|
return useQuery
|
|
360
350
|
}
|
|
361
351
|
|
|
362
352
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
363
353
|
export interface MakeQuery2<R> extends ReturnType<typeof makeQuery<R>> {}
|
|
364
354
|
|
|
355
|
+
type StreamQueryResult<A, E> = readonly [
|
|
356
|
+
ComputedRef<AsyncResult.AsyncResult<A[], E>>,
|
|
357
|
+
ComputedRef<A[] | undefined>,
|
|
358
|
+
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<A[], CauseException<E>>>,
|
|
359
|
+
UseQueryReturnType<any, any>
|
|
360
|
+
]
|
|
361
|
+
|
|
362
|
+
export const makeStreamQuery = <R>(getRuntime: () => Context.Context<R>) => {
|
|
363
|
+
const streamQuery_: {
|
|
364
|
+
<I, E, A, Request extends Req, Name extends string>(
|
|
365
|
+
q: RequestStreamHandlerWithInput<I, A, E, R, Request, Name>
|
|
366
|
+
): (arg: I | WatchSource<I>) => StreamQueryResult<A, E>
|
|
367
|
+
} = (q: any) => (arg?: any) => {
|
|
368
|
+
const context = getRuntime()
|
|
369
|
+
const arr = arg
|
|
370
|
+
const req: { value: any } | undefined = !arg
|
|
371
|
+
? undefined
|
|
372
|
+
: typeof arr === "function"
|
|
373
|
+
? ({
|
|
374
|
+
get value() {
|
|
375
|
+
return arr()
|
|
376
|
+
}
|
|
377
|
+
})
|
|
378
|
+
: ref(arg)
|
|
379
|
+
const queryKey = makeQueryKey(q)
|
|
380
|
+
|
|
381
|
+
const r = useTanstackQuery<any[], CauseException<any>, any[]>(
|
|
382
|
+
{
|
|
383
|
+
throwOnError: false,
|
|
384
|
+
retry: (retryCount: number, error: unknown) => {
|
|
385
|
+
if (error instanceof CauseException) {
|
|
386
|
+
if (!isHttpClientError(error.cause) && !S.is(ServiceUnavailableError)(error.cause)) {
|
|
387
|
+
return false
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return retryCount < 5
|
|
391
|
+
},
|
|
392
|
+
queryKey: [...queryKey, req],
|
|
393
|
+
queryFn: streamedQuery({
|
|
394
|
+
streamFn: () => {
|
|
395
|
+
const stream = q.handler(req?.value)
|
|
396
|
+
return streamToAsyncIterableWithCauseException(stream, context, q.id)
|
|
397
|
+
}
|
|
398
|
+
})
|
|
399
|
+
}
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
const latestSuccess = shallowRef<any[]>()
|
|
403
|
+
const result = computed((): AsyncResult.AsyncResult<any[], any> =>
|
|
404
|
+
swrToQuery({
|
|
405
|
+
error: r.error.value ?? undefined,
|
|
406
|
+
data: r.data.value === undefined ? latestSuccess.value : r.data.value,
|
|
407
|
+
isValidating: r.isFetching.value
|
|
408
|
+
})
|
|
409
|
+
)
|
|
410
|
+
watch(result, (value) => latestSuccess.value = Option.getOrUndefined(AsyncResult.value(value)), { immediate: true })
|
|
411
|
+
|
|
412
|
+
return [
|
|
413
|
+
result,
|
|
414
|
+
computed(() => latestSuccess.value),
|
|
415
|
+
(options?: RefetchOptions) =>
|
|
416
|
+
Effect.currentSpan.pipe(
|
|
417
|
+
Effect.orElseSucceed(() => null),
|
|
418
|
+
Effect.flatMap((span) => Effect.promise(() => r.refetch({ ...options, updateMeta: { span } })))
|
|
419
|
+
),
|
|
420
|
+
r
|
|
421
|
+
] as any
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return streamQuery_
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
428
|
+
export interface MakeStreamQuery2<R> extends ReturnType<typeof makeStreamQuery<R>> {}
|
|
429
|
+
|
|
365
430
|
function orPrevious<E, A>(result: AsyncResult.AsyncResult<A, E>) {
|
|
366
431
|
return AsyncResult.isFailure(result) && Option.isSome(result.previousSuccess)
|
|
367
432
|
? AsyncResult.success(result.previousSuccess.value, { waiting: result.waiting })
|
|
@@ -412,20 +477,13 @@ export const useUpdateQuery = () => {
|
|
|
412
477
|
const queryClient = useQueryClient()
|
|
413
478
|
|
|
414
479
|
const f: {
|
|
415
|
-
<A>(
|
|
416
|
-
query: RequestHandler<A, any, any, any, any>,
|
|
417
|
-
updater: (data: NoInfer<A>) => NoInfer<A>
|
|
418
|
-
): void
|
|
419
480
|
<I, A>(
|
|
420
481
|
query: RequestHandlerWithInput<I, A, any, any, any, any>,
|
|
421
482
|
input: I,
|
|
422
483
|
updater: (data: NoInfer<A>) => NoInfer<A>
|
|
423
484
|
): void
|
|
424
|
-
} = (query: any,
|
|
425
|
-
const
|
|
426
|
-
const key = updaterMaybe !== undefined
|
|
427
|
-
? [...makeQueryKey(query), updateOrInput]
|
|
428
|
-
: makeQueryKey(query)
|
|
485
|
+
} = (query: any, input: any, updater: any) => {
|
|
486
|
+
const key = [...makeQueryKey(query), input]
|
|
429
487
|
const data = queryClient.getQueryData(key)
|
|
430
488
|
if (data) {
|
|
431
489
|
queryClient.setQueryData(key, updater)
|
package/src/routeParams.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import type { Schema } from "effect-app/Schema"
|
|
1
|
+
import * as Option from "effect-app/Option"
|
|
2
|
+
import * as S from "effect-app/Schema"
|
|
4
3
|
import { typedKeysOf } from "effect-app/utils"
|
|
4
|
+
import { flow } from "effect/Function"
|
|
5
5
|
import type { ParsedQuery } from "query-string"
|
|
6
6
|
|
|
7
7
|
export function getQueryParam(search: ParsedQuery, param: string) {
|
|
@@ -16,7 +16,7 @@ export const getQueryParamO = flow(getQueryParam, Option.fromNullishOr)
|
|
|
16
16
|
|
|
17
17
|
export function parseRouteParamsOption<NER extends Record<string, S.Codec<any, any>>>(query: Record<string, any>, t: NER // enforce non empty
|
|
18
18
|
): {
|
|
19
|
-
[K in keyof NER]: Option.Option<
|
|
19
|
+
[K in keyof NER]: Option.Option<NER[K]["Type"]>
|
|
20
20
|
} {
|
|
21
21
|
return typedKeysOf(t).reduce(
|
|
22
22
|
(prev, cur) => {
|
|
@@ -28,7 +28,7 @@ export function parseRouteParamsOption<NER extends Record<string, S.Codec<any, a
|
|
|
28
28
|
return prev
|
|
29
29
|
},
|
|
30
30
|
{} as {
|
|
31
|
-
[K in keyof NER]: Option.Option<
|
|
31
|
+
[K in keyof NER]: Option.Option<NER[K]["Type"]>
|
|
32
32
|
}
|
|
33
33
|
)
|
|
34
34
|
}
|
|
@@ -37,7 +37,7 @@ export function parseRouteParams<NER extends Record<string, S.Codec<any, any>>>(
|
|
|
37
37
|
query: Record<string, any>,
|
|
38
38
|
t: NER // enforce non empty
|
|
39
39
|
): {
|
|
40
|
-
[K in keyof NER]:
|
|
40
|
+
[K in keyof NER]: NER[K]["Type"]
|
|
41
41
|
} {
|
|
42
42
|
return typedKeysOf(t).reduce(
|
|
43
43
|
(prev, cur) => {
|
|
@@ -49,7 +49,7 @@ export function parseRouteParams<NER extends Record<string, S.Codec<any, any>>>(
|
|
|
49
49
|
return prev
|
|
50
50
|
},
|
|
51
51
|
{} as {
|
|
52
|
-
[K in keyof NER]:
|
|
52
|
+
[K in keyof NER]: NER[K]["Type"]
|
|
53
53
|
}
|
|
54
54
|
)
|
|
55
55
|
}
|
package/src/runtime.ts
CHANGED
|
@@ -1,31 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { Effect, Layer, Logger } from "effect-app"
|
|
3
|
-
|
|
4
|
-
export function makeAppRuntime<A, E>(layer: Layer.Layer<A, E>) {
|
|
5
|
-
return Effect.gen(function*() {
|
|
6
|
-
const l = layer.pipe(
|
|
7
|
-
Layer.provide(Logger.layer([Logger.consolePretty()]))
|
|
8
|
-
) as Layer.Layer<A, never>
|
|
9
|
-
const mrt = ManagedRuntime.make(l)
|
|
10
|
-
yield* mrt.servicesEffect
|
|
11
|
-
return Object.assign(mrt, {
|
|
12
|
-
[Symbol.dispose]() {
|
|
13
|
-
return Effect.runSync(mrt.disposeEffect)
|
|
14
|
-
},
|
|
15
|
-
|
|
16
|
-
[Symbol.asyncDispose]() {
|
|
17
|
-
return mrt.dispose()
|
|
18
|
-
}
|
|
19
|
-
}) // as we initialise here, there is no more error left.
|
|
20
|
-
})
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function initializeSync<A, E>(layer: Layer.Layer<A, E, never>) {
|
|
24
|
-
const runtime = Effect.runSync(makeAppRuntime(layer))
|
|
25
|
-
return runtime
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function initializeAsync<A, E>(layer: Layer.Layer<A, E, never>) {
|
|
29
|
-
return Effect
|
|
30
|
-
.runPromise(makeAppRuntime(layer))
|
|
31
|
-
}
|
|
1
|
+
export * from "effect-app/runtime"
|
package/src/toast.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "effect-app/toast"
|
package/src/withToast.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "effect-app/withToast"
|