@effect-app/vue 4.0.0-beta.26 → 4.0.0-beta.260

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.
Files changed (108) hide show
  1. package/CHANGELOG.md +1923 -0
  2. package/dist/commander.d.ts +634 -0
  3. package/dist/commander.d.ts.map +1 -0
  4. package/dist/commander.js +1070 -0
  5. package/dist/confirm.d.ts +21 -0
  6. package/dist/confirm.d.ts.map +1 -0
  7. package/dist/confirm.js +26 -0
  8. package/dist/errorReporter.d.ts +7 -5
  9. package/dist/errorReporter.d.ts.map +1 -1
  10. package/dist/errorReporter.js +14 -19
  11. package/dist/form.d.ts +15 -6
  12. package/dist/form.d.ts.map +1 -1
  13. package/dist/form.js +46 -13
  14. package/dist/index.d.ts +1 -1
  15. package/dist/intl.d.ts +15 -0
  16. package/dist/intl.d.ts.map +1 -0
  17. package/dist/intl.js +9 -0
  18. package/dist/lib.d.ts +8 -10
  19. package/dist/lib.d.ts.map +1 -1
  20. package/dist/lib.js +35 -10
  21. package/dist/makeClient.d.ts +157 -343
  22. package/dist/makeClient.d.ts.map +1 -1
  23. package/dist/makeClient.js +216 -376
  24. package/dist/makeContext.d.ts +1 -1
  25. package/dist/makeContext.d.ts.map +1 -1
  26. package/dist/makeIntl.d.ts +1 -1
  27. package/dist/makeIntl.d.ts.map +1 -1
  28. package/dist/makeUseCommand.d.ts +9 -0
  29. package/dist/makeUseCommand.d.ts.map +1 -0
  30. package/dist/makeUseCommand.js +13 -0
  31. package/dist/mutate.d.ts +97 -39
  32. package/dist/mutate.d.ts.map +1 -1
  33. package/dist/mutate.js +177 -49
  34. package/dist/query.d.ts +24 -39
  35. package/dist/query.d.ts.map +1 -1
  36. package/dist/query.js +156 -78
  37. package/dist/routeParams.d.ts +5 -5
  38. package/dist/routeParams.d.ts.map +1 -1
  39. package/dist/routeParams.js +4 -3
  40. package/dist/runtime.d.ts +2 -15
  41. package/dist/runtime.d.ts.map +1 -1
  42. package/dist/runtime.js +2 -26
  43. package/dist/toast.d.ts +2 -0
  44. package/dist/toast.d.ts.map +1 -0
  45. package/dist/toast.js +2 -0
  46. package/dist/withToast.d.ts +2 -0
  47. package/dist/withToast.d.ts.map +1 -0
  48. package/dist/withToast.js +2 -0
  49. package/examples/streamMutation.ts +72 -0
  50. package/package.json +29 -90
  51. package/src/commander.ts +3406 -0
  52. package/src/{experimental/confirm.ts → confirm.ts} +12 -14
  53. package/src/errorReporter.ts +65 -75
  54. package/src/form.ts +61 -18
  55. package/src/intl.ts +12 -0
  56. package/src/lib.ts +48 -20
  57. package/src/makeClient.ts +581 -1138
  58. package/src/{experimental/makeUseCommand.ts → makeUseCommand.ts} +8 -5
  59. package/src/mutate.ts +335 -134
  60. package/src/query.ts +241 -183
  61. package/src/routeParams.ts +7 -7
  62. package/src/runtime.ts +1 -31
  63. package/src/toast.ts +1 -0
  64. package/src/withToast.ts +1 -0
  65. package/test/Mutation.test.ts +181 -24
  66. package/test/dist/form.test.d.ts.map +1 -1
  67. package/test/dist/lib.test.d.ts.map +1 -0
  68. package/test/dist/streamFinal.test.d.ts.map +1 -0
  69. package/test/dist/streamFn.test.d.ts.map +1 -0
  70. package/test/dist/stubs.d.ts +3527 -122
  71. package/test/dist/stubs.d.ts.map +1 -1
  72. package/test/dist/stubs.js +187 -32
  73. package/test/form-validation-errors.test.ts +25 -20
  74. package/test/form.test.ts +22 -3
  75. package/test/lib.test.ts +240 -0
  76. package/test/makeClient.test.ts +327 -38
  77. package/test/streamFinal.test.ts +64 -0
  78. package/test/streamFn.test.ts +457 -0
  79. package/test/stubs.ts +223 -43
  80. package/tsconfig.examples.json +20 -0
  81. package/tsconfig.json +2 -1
  82. package/tsconfig.json.bak +5 -2
  83. package/tsconfig.src.json +34 -34
  84. package/tsconfig.test.json +2 -2
  85. package/vitest.config.ts +5 -5
  86. package/dist/experimental/commander.d.ts +0 -359
  87. package/dist/experimental/commander.d.ts.map +0 -1
  88. package/dist/experimental/commander.js +0 -557
  89. package/dist/experimental/confirm.d.ts +0 -19
  90. package/dist/experimental/confirm.d.ts.map +0 -1
  91. package/dist/experimental/confirm.js +0 -28
  92. package/dist/experimental/intl.d.ts +0 -16
  93. package/dist/experimental/intl.d.ts.map +0 -1
  94. package/dist/experimental/intl.js +0 -5
  95. package/dist/experimental/makeUseCommand.d.ts +0 -8
  96. package/dist/experimental/makeUseCommand.d.ts.map +0 -1
  97. package/dist/experimental/makeUseCommand.js +0 -13
  98. package/dist/experimental/toast.d.ts +0 -47
  99. package/dist/experimental/toast.d.ts.map +0 -1
  100. package/dist/experimental/toast.js +0 -41
  101. package/dist/experimental/withToast.d.ts +0 -25
  102. package/dist/experimental/withToast.d.ts.map +0 -1
  103. package/dist/experimental/withToast.js +0 -45
  104. package/eslint.config.mjs +0 -24
  105. package/src/experimental/commander.ts +0 -1835
  106. package/src/experimental/intl.ts +0 -9
  107. package/src/experimental/toast.ts +0 -66
  108. 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
- import { type DefaultError, type Enabled, 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"
6
- import { Array, Cause, Effect, Exit, flow, Option, S, type ServiceMap } from "effect-app"
7
- import { type Req } from "effect-app/client"
8
- import type { RequestHandler, RequestHandlerWithInput } from "effect-app/client/clientFor"
9
- import { ServiceUnavailableError } from "effect-app/client/errors"
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 { makeQueryKey, reportRuntimeError } from "./lib.js"
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
- export class KnownFiberFailure<E> extends Error {
78
- readonly error: unknown
79
- constructor(public effectCause: Cause.Cause<E>) {
80
- super("Query failed with cause: " + Cause.squash(effectCause))
81
- this.error = Cause.squash(effectCause)
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: () => ServiceMap.ServiceMap<R>) => {
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, KnownFiberFailure<E>>, never, never>,
99
- UseQueryDefinedReturnType<TData, KnownFiberFailure<E>>
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, KnownFiberFailure<E>>, never, never>,
109
- UseQueryDefinedReturnType<TData, KnownFiberFailure<E>>
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, KnownFiberFailure<E>>, never, never>,
119
- UseQueryDefinedReturnType<TData, KnownFiberFailure<E>>
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 KnownFiberFailure because we want to keep the full cause of the failure.
134
- const runPromise = flow(Effect.runPromiseExitWith(getRuntime()), (_) =>
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
- const req: { value: I } = !arg
143
- ? undefined
144
- : typeof arr === "function"
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
- return (arr as any)()
214
+ // getOrUndefined returns undefined when None, but queryFn is only called when enabled (Some)
215
+ return Option.getOrUndefined(getOption()) as I
148
216
  }
149
- } as any)
150
- : ref(arg)
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 handler = q.handler
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, KnownFiberFailure<E>, TData>(
165
- Effect.isEffect(handler)
166
- ? {
167
- ...defaultOptions,
168
- ...options,
169
- retry: (retryCount, error) => {
170
- if (error instanceof KnownFiberFailure) {
171
- if (!isHttpClientError(error.error) && !S.is(ServiceUnavailableError)(error.error)) {
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
- return retryCount < 5
201
- },
202
- queryKey: [...queryKey, req],
203
- queryFn: ({ meta, signal }) =>
204
- runPromise(
205
- handler(req.value)
206
- .pipe(
207
- Effect.tapCauseIf(Cause.hasDies, (cause) => reportRuntimeError(cause)),
208
- Effect.withSpan(`query ${q.id}`, {}, { captureStackTrace: false }),
209
- meta?.["span"] ? Effect.withParentSpan(meta["span"] as Span) : (_) => _
210
- ),
211
- { signal }
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: RequestHandler<A, E, R, Request, Name>
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
- options: CustomDefinedInitialQueryOptions<A, KnownFiberFailure<E>, TData>
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, 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>>>,
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: Arg | WatchSource<Arg>,
315
- options: CustomDefinedInitialQueryOptions<A, KnownFiberFailure<E>, TData>
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, KnownFiberFailure<E>>>,
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: Arg | WatchSource<Arg>,
328
- options: CustomDefinedPlaceholderQueryOptions<A, KnownFiberFailure<E>, TData>
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, KnownFiberFailure<E>>>,
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: Arg | WatchSource<Arg>,
341
- options?: CustomUndefinedInitialQueryOptions<A, KnownFiberFailure<E>, TData>
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, KnownFiberFailure<E>>>,
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
- return (argOrOptions?: any, options?: any) =>
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, updateOrInput: any, updaterMaybe?: any) => {
425
- const updater = updaterMaybe !== undefined ? updaterMaybe : updateOrInput
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)
@@ -1,7 +1,7 @@
1
- import { flow } from "effect"
2
- import { Option, S } from "effect-app"
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<Schema.Type<NER[K]>>
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<Schema.Type<NER[K]>>
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]: Schema.Type<NER[K]>
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]: Schema.Type<NER[K]>
52
+ [K in keyof NER]: NER[K]["Type"]
53
53
  }
54
54
  )
55
55
  }
package/src/runtime.ts CHANGED
@@ -1,31 +1 @@
1
- import { ManagedRuntime } from "effect"
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"
@@ -0,0 +1 @@
1
+ export * from "effect-app/withToast"