@effect-app/vue 4.0.0-beta.183 → 4.0.0-beta.185
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 +19 -0
- package/dist/commander.d.ts +39 -11
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +122 -10
- package/dist/makeClient.d.ts +12 -12
- package/dist/makeClient.d.ts.map +1 -1
- package/dist/makeClient.js +3 -3
- package/dist/mutate.d.ts +3 -3
- package/dist/mutate.d.ts.map +1 -1
- package/dist/mutate.js +4 -4
- package/examples/streamMutation.ts +5 -5
- package/package.json +2 -2
- package/src/commander.ts +175 -13
- package/src/makeClient.ts +13 -13
- package/src/mutate.ts +3 -3
- package/test/dist/stubs.d.ts +2 -2
- package/test/makeClient.test.ts +2 -2
- package/test/streamFinal.test.ts +7 -7
package/src/commander.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { type FormatXMLElementFn, type PrimitiveType } from "intl-messageformat"
|
|
|
12
12
|
import { computed, type ComputedRef, reactive, ref, toRaw } from "vue"
|
|
13
13
|
import { Confirm } from "./confirm.js"
|
|
14
14
|
import { I18n } from "./intl.js"
|
|
15
|
+
import { CurrentToastId, Toast } from "./toast.js"
|
|
15
16
|
import { WithToast } from "./withToast.js"
|
|
16
17
|
|
|
17
18
|
type IntlRecord = Record<string, PrimitiveType | FormatXMLElementFn<string, string>>
|
|
@@ -33,7 +34,7 @@ export type StreamMutationCallOptions<A, E> = {
|
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
/**
|
|
36
|
-
* The result of invoking a `
|
|
37
|
+
* The result of invoking a `mutateToResult` factory: the `execute` function (or
|
|
37
38
|
* `Effect`, when the request takes no input) carries `id`, plus `running` and
|
|
38
39
|
* `progress` when the factory was called with a `progress` formatter. Pass
|
|
39
40
|
* directly to `Command.fn` / `Command.wrap` / `Command.wrapStream`, or invoke
|
|
@@ -217,7 +218,7 @@ export declare namespace Commander {
|
|
|
217
218
|
/** reactive */
|
|
218
219
|
result: AsyncResult.AsyncResult<A, E>
|
|
219
220
|
/**
|
|
220
|
-
* reactive – set when the command wraps a stream (`wrapStream` / `wrap` with `
|
|
221
|
+
* reactive – set when the command wraps a stream (`wrapStream` / `wrap` with `mutateToResult`)
|
|
221
222
|
* or when the `progress` option is provided to `fn`.
|
|
222
223
|
* Reflects the live AsyncResult of the underlying stream.
|
|
223
224
|
*/
|
|
@@ -2197,6 +2198,167 @@ export const CommanderStatic = {
|
|
|
2197
2198
|
)
|
|
2198
2199
|
}),
|
|
2199
2200
|
|
|
2201
|
+
/**
|
|
2202
|
+
* Stream-aware version of `withDefaultToast`. Use this as a combinator inside `streamFn`
|
|
2203
|
+
* (or anywhere a `Stream` needs toast lifecycle handling) instead of `withDefaultToast`.
|
|
2204
|
+
*
|
|
2205
|
+
* Unlike `withDefaultToast` (which only wraps the initial `Effect`), this combinator:
|
|
2206
|
+
* - Shows the "waiting" toast **before** the stream starts
|
|
2207
|
+
* - Shows the "success" toast only **after** the stream drains fully without error
|
|
2208
|
+
* - Shows the "failure" toast if the stream errors or fails
|
|
2209
|
+
*
|
|
2210
|
+
* Accepts either a `Stream<A, E, R>` or an `Effect<Stream<A, E, R>, EE, ER>` as input,
|
|
2211
|
+
* so it works in both the `NonGenStream` and `StreamGen` overloads of `streamFn`.
|
|
2212
|
+
*
|
|
2213
|
+
* @example
|
|
2214
|
+
* ```ts
|
|
2215
|
+
* Command.streamFn("exportData")(
|
|
2216
|
+
* function*(arg, ctx) { return makeExportStream(arg.id) },
|
|
2217
|
+
* Command.withDefaultToastStream()
|
|
2218
|
+
* )
|
|
2219
|
+
* ```
|
|
2220
|
+
*/
|
|
2221
|
+
withDefaultToastStream: <A, E, R, Args extends Array<unknown>>(
|
|
2222
|
+
options?: {
|
|
2223
|
+
stableToastId?:
|
|
2224
|
+
| undefined
|
|
2225
|
+
| true
|
|
2226
|
+
| string
|
|
2227
|
+
| ((id: string, arg: NoInfer<Args>[0], ctx: NoInfer<Args>[1]) => true | string | undefined)
|
|
2228
|
+
errorRenderer?: (e: E, action: string, arg: NoInfer<Args>[0], ctx: NoInfer<Args>[1]) => string | undefined
|
|
2229
|
+
showSpanInfo?: false
|
|
2230
|
+
onWaiting?:
|
|
2231
|
+
| null
|
|
2232
|
+
| undefined
|
|
2233
|
+
| string
|
|
2234
|
+
| ((id: string, arg: NoInfer<Args>[0], ctx: NoInfer<Args>[1]) => string | null | undefined)
|
|
2235
|
+
onSuccess?:
|
|
2236
|
+
| null
|
|
2237
|
+
| undefined
|
|
2238
|
+
| string
|
|
2239
|
+
| ((a: A, action: string, arg: NoInfer<Args>[0], ctx: NoInfer<Args>[1]) => string | null | undefined)
|
|
2240
|
+
}
|
|
2241
|
+
) =>
|
|
2242
|
+
(
|
|
2243
|
+
self: Stream.Stream<A, E, R> | Effect.Effect<Stream.Stream<A, E, R>, any, any>,
|
|
2244
|
+
...args: Args
|
|
2245
|
+
): Stream.Stream<A, E, R | I18n | Toast | CommandContext> => {
|
|
2246
|
+
const rawStream: Stream.Stream<A, E, R> = Stream.isStream(self)
|
|
2247
|
+
? self
|
|
2248
|
+
: Stream.unwrap(self)
|
|
2249
|
+
|
|
2250
|
+
return Stream.unwrap(Effect.gen(function*() {
|
|
2251
|
+
const cc = yield* CommandContext
|
|
2252
|
+
const { intl } = yield* I18n
|
|
2253
|
+
const toast = yield* Toast
|
|
2254
|
+
|
|
2255
|
+
const customWaiting = cc.namespaced("waiting")
|
|
2256
|
+
const hasCustomWaiting = !!intl.messages[customWaiting]
|
|
2257
|
+
const customSuccess = cc.namespaced("success")
|
|
2258
|
+
const hasCustomSuccess = !!intl.messages[customSuccess]
|
|
2259
|
+
const customFailure = cc.namespaced("failure")
|
|
2260
|
+
const hasCustomFailure = !!intl.messages[customFailure]
|
|
2261
|
+
|
|
2262
|
+
const stableToastId: string | undefined = options?.stableToastId
|
|
2263
|
+
? typeof options.stableToastId === "string"
|
|
2264
|
+
? options.stableToastId
|
|
2265
|
+
: typeof options.stableToastId === "boolean"
|
|
2266
|
+
? cc.id
|
|
2267
|
+
: typeof options.stableToastId === "function"
|
|
2268
|
+
? (() => {
|
|
2269
|
+
const r = (options.stableToastId as (...a: any[]) => true | string | undefined)(cc.id, ...args)
|
|
2270
|
+
if (typeof r === "string") return r
|
|
2271
|
+
if (r === true) return cc.id
|
|
2272
|
+
return undefined
|
|
2273
|
+
})()
|
|
2274
|
+
: undefined
|
|
2275
|
+
: undefined
|
|
2276
|
+
|
|
2277
|
+
const baseTimeout = 3_000
|
|
2278
|
+
|
|
2279
|
+
const waitingMsg: string | null = options?.onWaiting === null
|
|
2280
|
+
? null
|
|
2281
|
+
: typeof options?.onWaiting === "string"
|
|
2282
|
+
? options.onWaiting
|
|
2283
|
+
: typeof options?.onWaiting === "function"
|
|
2284
|
+
? (options.onWaiting as (...a: any[]) => string | null | undefined)(cc.id, ...args) ?? null
|
|
2285
|
+
: hasCustomWaiting
|
|
2286
|
+
? intl.formatMessage({ id: customWaiting }, cc.state)
|
|
2287
|
+
: intl.formatMessage({ id: "handle.waiting" }, { action: cc.action })
|
|
2288
|
+
|
|
2289
|
+
const toastId: string | number | undefined = waitingMsg === null
|
|
2290
|
+
? stableToastId
|
|
2291
|
+
: yield* toast.info(waitingMsg, { id: stableToastId ?? null })
|
|
2292
|
+
|
|
2293
|
+
const failureHandler = defaultFailureMessageHandler<E, [], never, never>(
|
|
2294
|
+
hasCustomFailure ? intl.formatMessage({ id: customFailure }, cc.state) : cc.action,
|
|
2295
|
+
options?.errorRenderer as ErrorRenderer<E, []> | undefined
|
|
2296
|
+
)
|
|
2297
|
+
|
|
2298
|
+
let lastValue: A | undefined = undefined
|
|
2299
|
+
let didFail = false
|
|
2300
|
+
|
|
2301
|
+
const composed = rawStream.pipe(
|
|
2302
|
+
Stream.tap((v) =>
|
|
2303
|
+
Effect.sync(() => {
|
|
2304
|
+
lastValue = v
|
|
2305
|
+
})
|
|
2306
|
+
),
|
|
2307
|
+
Stream.tapCause(Effect.fnUntraced(function*(cause) {
|
|
2308
|
+
didFail = true
|
|
2309
|
+
if (Cause.hasInterruptsOnly(cause)) {
|
|
2310
|
+
if (toastId !== undefined) yield* toast.dismiss(toastId)
|
|
2311
|
+
return
|
|
2312
|
+
}
|
|
2313
|
+
|
|
2314
|
+
const spanInfo = options?.showSpanInfo !== false
|
|
2315
|
+
? yield* Effect.currentSpan.pipe(
|
|
2316
|
+
Effect.map((span) => `\nTrace: ${span.traceId}\nSpan: ${span.spanId}`),
|
|
2317
|
+
Effect.orElseSucceed(() => "")
|
|
2318
|
+
)
|
|
2319
|
+
: ""
|
|
2320
|
+
|
|
2321
|
+
const t = yield* failureHandler(Cause.findErrorOption(cause))
|
|
2322
|
+
const opts = { timeout: baseTimeout * 2 }
|
|
2323
|
+
|
|
2324
|
+
if (typeof t === "object") {
|
|
2325
|
+
const message = t.message + spanInfo
|
|
2326
|
+
yield* t.level === "warn"
|
|
2327
|
+
? toast.warning(message, toastId !== undefined ? { ...opts, id: toastId } : opts)
|
|
2328
|
+
: toast.error(message, toastId !== undefined ? { ...opts, id: toastId } : opts)
|
|
2329
|
+
} else {
|
|
2330
|
+
yield* toast.error(t + spanInfo, toastId !== undefined ? { ...opts, id: toastId } : opts)
|
|
2331
|
+
}
|
|
2332
|
+
}, Effect.uninterruptible)),
|
|
2333
|
+
Stream.ensuring(Effect.suspend(() => {
|
|
2334
|
+
if (didFail) return Effect.void
|
|
2335
|
+
|
|
2336
|
+
if (options?.onSuccess === null) return Effect.void
|
|
2337
|
+
|
|
2338
|
+
const successMsg: string | null = typeof options?.onSuccess === "string"
|
|
2339
|
+
? options.onSuccess
|
|
2340
|
+
: typeof options?.onSuccess === "function"
|
|
2341
|
+
? (options.onSuccess as (...a: any[]) => string | null | undefined)(lastValue, cc.action, ...args) ?? null
|
|
2342
|
+
: hasCustomSuccess
|
|
2343
|
+
? intl.formatMessage({ id: customSuccess }, cc.state)
|
|
2344
|
+
: intl.formatMessage({ id: "handle.success" }, { action: cc.action })
|
|
2345
|
+
+ (S.is(OperationSuccess)(lastValue) && lastValue.message ? "\n" + lastValue.message : "")
|
|
2346
|
+
|
|
2347
|
+
if (successMsg === null) return Effect.void
|
|
2348
|
+
|
|
2349
|
+
return toast.success(
|
|
2350
|
+
successMsg,
|
|
2351
|
+
toastId !== undefined ? { id: toastId, timeout: baseTimeout } : { timeout: baseTimeout }
|
|
2352
|
+
)
|
|
2353
|
+
}))
|
|
2354
|
+
)
|
|
2355
|
+
|
|
2356
|
+
return (toastId !== undefined
|
|
2357
|
+
? composed.pipe(Stream.provideService(CurrentToastId, CurrentToastId.of({ toastId })))
|
|
2358
|
+
: composed) as unknown as Stream.Stream<A, E, R>
|
|
2359
|
+
}))
|
|
2360
|
+
},
|
|
2361
|
+
|
|
2200
2362
|
/** borrowing the idea from Families in Effect Atom */
|
|
2201
2363
|
family: <T extends object, Arg, ArgIn = Arg>(
|
|
2202
2364
|
maker: (arg: Arg) => T,
|
|
@@ -3103,14 +3265,14 @@ export class CommanderImpl<RT, RTHooks> {
|
|
|
3103
3265
|
| StreamMutationFactory<Id, Arg, A, E, R>
|
|
3104
3266
|
| {
|
|
3105
3267
|
id: Id
|
|
3106
|
-
|
|
3268
|
+
mutateToResult:
|
|
3107
3269
|
| StreamMutationFactory<Id, Arg, A, E, R>
|
|
3108
3270
|
| StreamMutationCallable<Id, Arg, A, E, R>
|
|
3109
3271
|
}
|
|
3110
3272
|
| StreamMutationCallable<Id, Arg, A, E, R>,
|
|
3111
3273
|
options?: FnOptions<Id, I18nKey, State>
|
|
3112
3274
|
): Commander.CommanderWrap<RT | RTHooks, Id, I18nKey, State, Arg, A, E, R> => {
|
|
3113
|
-
if (mutation !== null && typeof mutation === "object" && "
|
|
3275
|
+
if (mutation !== null && typeof mutation === "object" && "mutateToResult" in mutation) {
|
|
3114
3276
|
return this.wrapStream(mutation as any, options) as any
|
|
3115
3277
|
}
|
|
3116
3278
|
if (isStreamCallable(mutation) || isStreamFactory(mutation)) {
|
|
@@ -3153,18 +3315,18 @@ export class CommanderImpl<RT, RTHooks> {
|
|
|
3153
3315
|
}
|
|
3154
3316
|
|
|
3155
3317
|
/**
|
|
3156
|
-
* Define a Command from a stream-type mutation (`
|
|
3318
|
+
* Define a Command from a stream-type mutation (`mutateToResult` factory).
|
|
3157
3319
|
* The stream's reactive `AsyncResult` ref is exposed as `running` for independent progress tracking.
|
|
3158
3320
|
* The command's own `result` reflects the execution outcome of the `execute` function.
|
|
3159
3321
|
* Supports the same combinator pipeline as `wrap` (e.g. `withDefaultToast`).
|
|
3160
3322
|
*
|
|
3161
3323
|
* Each invocation of the resulting wrap call produces a fresh `[ref, execute]` pair
|
|
3162
|
-
* (the `
|
|
3324
|
+
* (the `mutateToResult` factory is called once per build), so independent commands
|
|
3163
3325
|
* don't share progress state.
|
|
3164
3326
|
*
|
|
3165
3327
|
* Accepts either:
|
|
3166
|
-
* - An object with `id` and `
|
|
3167
|
-
* - The `
|
|
3328
|
+
* - An object with `id` and `mutateToResult` factory (e.g. a client entry)
|
|
3329
|
+
* - The `mutateToResult` factory directly (callable, with `id`)
|
|
3168
3330
|
* - An already-called factory result (`[resultRef, execute] & { id }`) — shared ref across builds
|
|
3169
3331
|
*
|
|
3170
3332
|
* @example
|
|
@@ -3173,10 +3335,10 @@ export class CommanderImpl<RT, RTHooks> {
|
|
|
3173
3335
|
* const exportCmd = Command.wrapStream(client.myExport)()
|
|
3174
3336
|
*
|
|
3175
3337
|
* // Via factory directly:
|
|
3176
|
-
* const exportCmd = Command.wrapStream(client.myExport.
|
|
3338
|
+
* const exportCmd = Command.wrapStream(client.myExport.mutateToResult)()
|
|
3177
3339
|
*
|
|
3178
3340
|
* // Via already-called factory (shared ref):
|
|
3179
|
-
* const stream = client.myExport.
|
|
3341
|
+
* const stream = client.myExport.mutateToResult()
|
|
3180
3342
|
* const exportCmd = Command.wrapStream(stream)()
|
|
3181
3343
|
* ```
|
|
3182
3344
|
*/
|
|
@@ -3192,7 +3354,7 @@ export class CommanderImpl<RT, RTHooks> {
|
|
|
3192
3354
|
mutation:
|
|
3193
3355
|
| {
|
|
3194
3356
|
id: Id
|
|
3195
|
-
|
|
3357
|
+
mutateToResult:
|
|
3196
3358
|
| StreamMutationFactory<Id, Arg, A, E, R>
|
|
3197
3359
|
| StreamMutationCallable<Id, Arg, A, E, R>
|
|
3198
3360
|
}
|
|
@@ -3203,8 +3365,8 @@ export class CommanderImpl<RT, RTHooks> {
|
|
|
3203
3365
|
const id = mutation.id
|
|
3204
3366
|
// Resolve `source` to the factory or already-invoked callable.
|
|
3205
3367
|
const source: StreamMutationFactory<Id, Arg, A, E, R> | StreamMutationCallable<Id, Arg, A, E, R> =
|
|
3206
|
-
mutation !== null && typeof mutation === "object" && "
|
|
3207
|
-
? (mutation.
|
|
3368
|
+
mutation !== null && typeof mutation === "object" && "mutateToResult" in mutation
|
|
3369
|
+
? (mutation.mutateToResult as any)
|
|
3208
3370
|
: (mutation as any)
|
|
3209
3371
|
const resolveCallable = (): StreamMutationCallable<Id, Arg, A, E, R> =>
|
|
3210
3372
|
(isStreamFactory(source)
|
package/src/makeClient.ts
CHANGED
|
@@ -228,7 +228,7 @@ export type MutationWithExtensions<RT, Req> = Req extends
|
|
|
228
228
|
: never
|
|
229
229
|
|
|
230
230
|
/**
|
|
231
|
-
* Options for invoking a `
|
|
231
|
+
* Options for invoking a `mutateToResult` factory. Supplying `progress` produces
|
|
232
232
|
* a tuple-with-id that carries `running` (the live AsyncResult ref) and
|
|
233
233
|
* `progress` (a `ComputedRef<Progress | undefined>` formatted from each value),
|
|
234
234
|
* which `Command.fn` / `Command.wrapStream` surface as the command's `running`
|
|
@@ -239,7 +239,7 @@ export type MutateStreamCallOptions<A, E> = {
|
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
/**
|
|
242
|
-
* The `
|
|
242
|
+
* The `mutateToResult` factory for a stream-type request handler. Always invoke
|
|
243
243
|
* (optionally with `{ progress }`) to get a fresh callable `execute` — each call
|
|
244
244
|
* produces a new state + execute pair so independent invocations don't share
|
|
245
245
|
* state. The callable updates its underlying ref live with each emitted value
|
|
@@ -306,18 +306,18 @@ export type StreamFnStreamExtension<RT, Req> = Req extends
|
|
|
306
306
|
: never
|
|
307
307
|
|
|
308
308
|
/**
|
|
309
|
-
* `
|
|
310
|
-
* for use with `streamFn` combinators.
|
|
309
|
+
* `mutate` factory — like `mutateToResult` but wraps per-invocation invalidation scaffolding
|
|
310
|
+
* into the stream itself (via `Stream.unwrap`) for use with `streamFn` combinators.
|
|
311
311
|
*/
|
|
312
312
|
export type StreamMutation2WithExtensions<RT, Req> = Req extends
|
|
313
313
|
RequestStreamHandlerWithInput<infer I, infer A, infer E, infer R, infer _Request, infer Id, infer _Final> ?
|
|
314
|
-
& ((input: I) =>
|
|
314
|
+
& ((input: I) => Stream.Stream<A, E, R>)
|
|
315
315
|
& {
|
|
316
316
|
readonly id: Id
|
|
317
317
|
readonly wrapStream: Commander.StreamGen<RT, Id, Id, undefined> & Commander.NonGenStream<RT, Id, Id, undefined>
|
|
318
318
|
}
|
|
319
319
|
: Req extends RequestStreamHandler<infer A, infer E, infer R, infer _Request, infer Id, infer _Final> ?
|
|
320
|
-
&
|
|
320
|
+
& Stream.Stream<A, E, R>
|
|
321
321
|
& {
|
|
322
322
|
readonly id: Id
|
|
323
323
|
readonly wrapStream: Commander.StreamGen<RT, Id, Id, undefined> & Commander.NonGenStream<RT, Id, Id, undefined>
|
|
@@ -1043,11 +1043,11 @@ export const makeClient = <RT_, RTHooks>(
|
|
|
1043
1043
|
...client[key],
|
|
1044
1044
|
request: h_,
|
|
1045
1045
|
streamQuery: useStreamQuery(client[key] as any),
|
|
1046
|
-
|
|
1046
|
+
mutateToResult: streamMutFactory,
|
|
1047
1047
|
wrapStream: Command.wrapStream(streamMutFactory),
|
|
1048
1048
|
fn: Command.fn(client[key].id),
|
|
1049
1049
|
streamFn: useCommand().streamFn(client[key].id as any) as any,
|
|
1050
|
-
|
|
1050
|
+
mutate: (() => {
|
|
1051
1051
|
const sm2Act = useStreamMutation2()(client[key] as any, mergedInvalidation)
|
|
1052
1052
|
const originalHandler = (client[key] as any).handler
|
|
1053
1053
|
const sm2Handler = Stream.isStream(originalHandler)
|
|
@@ -1125,11 +1125,11 @@ export const makeClient = <RT_, RTHooks>(
|
|
|
1125
1125
|
: { mutate: MutationWithExtensions<RT | RTHooks, CommandHandler<typeof client[Key]>> })
|
|
1126
1126
|
& (StreamHandler<typeof client[Key]> extends never ? {}
|
|
1127
1127
|
: {
|
|
1128
|
-
|
|
1128
|
+
mutateToResult: StreamMutationWithExtensions<StreamHandler<typeof client[Key]>>
|
|
1129
1129
|
wrapStream: StreamCommandWithExtensions<RT | RTHooks, StreamHandler<typeof client[Key]>>
|
|
1130
1130
|
fn: StreamFnExtension<RT | RTHooks, StreamHandler<typeof client[Key]>>
|
|
1131
1131
|
streamFn: StreamFnStreamExtension<RT | RTHooks, StreamHandler<typeof client[Key]>>
|
|
1132
|
-
|
|
1132
|
+
mutate: StreamMutation2WithExtensions<RT | RTHooks, StreamHandler<typeof client[Key]>>
|
|
1133
1133
|
})
|
|
1134
1134
|
& { Input: typeof client[Key] extends RequestHandlerWithInput<infer I, any, any, any, any, any> ? I : never }
|
|
1135
1135
|
}
|
|
@@ -1223,7 +1223,7 @@ export type ToCamel<S extends string | number | symbol> = S extends string
|
|
|
1223
1223
|
: Uncapitalize<S>
|
|
1224
1224
|
: never
|
|
1225
1225
|
|
|
1226
|
-
export interface CommandBase<I = void, A = void> {
|
|
1226
|
+
export interface CommandBase<I = void, A = void, RA = unknown, RE = unknown> {
|
|
1227
1227
|
handle: (input: I) => A
|
|
1228
1228
|
waiting: boolean
|
|
1229
1229
|
blocked: boolean
|
|
@@ -1233,10 +1233,10 @@ export interface CommandBase<I = void, A = void> {
|
|
|
1233
1233
|
/** formatted progress info for current `running` state, when `progress` was supplied */
|
|
1234
1234
|
progress?: Progress | undefined
|
|
1235
1235
|
/** reactive result state, available on stream-backed commands */
|
|
1236
|
-
result?: AsyncResult.AsyncResult<
|
|
1236
|
+
result?: AsyncResult.AsyncResult<RA, RE>
|
|
1237
1237
|
}
|
|
1238
1238
|
|
|
1239
|
-
export interface EffectCommand<I = void, A = unknown, E = unknown> extends CommandBase<I, Fiber<A, E
|
|
1239
|
+
export interface EffectCommand<I = void, A = unknown, E = unknown> extends CommandBase<I, Fiber<A, E>, A, E> {}
|
|
1240
1240
|
|
|
1241
1241
|
export interface CommandFromRequest<I extends { readonly make: (...args: any[]) => any }, A = unknown, E = unknown>
|
|
1242
1242
|
extends EffectCommand<RequestInputFromMake<I>, A, E>
|
package/src/mutate.ts
CHANGED
|
@@ -418,7 +418,7 @@ export const useMakeMutation = () => {
|
|
|
418
418
|
* `[ref, execute]` tuple. The outer Effect sets up per-invocation invalidation scaffolding
|
|
419
419
|
* and returns a stream that triggers query invalidation via `Stream.ensuring` when it completes.
|
|
420
420
|
*
|
|
421
|
-
* Use this with `streamFn` / `Command.streamFn(id)(
|
|
421
|
+
* Use this with `streamFn` / `Command.streamFn(id)(mutateHandler, ...combinators)` so that
|
|
422
422
|
* the command manages its own reactive state internally. Unlike `makeStreamMutation`, no external
|
|
423
423
|
* reactive result ref is created.
|
|
424
424
|
*
|
|
@@ -457,8 +457,8 @@ export const makeStreamMutation2 = () => {
|
|
|
457
457
|
|
|
458
458
|
const handler = self.handler
|
|
459
459
|
const act = Stream.isStream(handler)
|
|
460
|
-
? makeInvocationEffect(undefined, handler)
|
|
461
|
-
: (i: any) => makeInvocationEffect(i, (handler as (i: any) => Stream.Stream<any, any, any>)(i))
|
|
460
|
+
? Stream.unwrap(makeInvocationEffect(undefined, handler))
|
|
461
|
+
: (i: any) => Stream.unwrap(makeInvocationEffect(i, (handler as (i: any) => Stream.Stream<any, any, any>)(i)))
|
|
462
462
|
|
|
463
463
|
return act
|
|
464
464
|
}
|
package/test/dist/stubs.d.ts
CHANGED
|
@@ -2968,7 +2968,7 @@ export declare const useClient: (options?: {
|
|
|
2968
2968
|
readonly type: "command" | "query" | "stream";
|
|
2969
2969
|
readonly "~decodingServices"?: unknown;
|
|
2970
2970
|
}, infer Id_3 extends string, infer Final_1> ? Request_3["type"] extends "stream" ? import("effect-app/client").RequestStreamHandler<A_3, E_3, R_4, Request_3, Id_3, Final_1> : never : never : never : never) extends never ? {} : {
|
|
2971
|
-
|
|
2971
|
+
mutateToResult: import("../src/makeClient.js").StreamMutationWithExtensions<import("effect-app/client").RequestHandlers<never, never, M, import("effect-app/client").ExtractModuleName<M>>[Key] extends infer T_2 ? T_2 extends import("effect-app/client").RequestHandlers<never, never, M, import("effect-app/client").ExtractModuleName<M>>[Key] ? T_2 extends import("effect-app/client").RequestStreamHandlerWithInput<infer I_2, infer A_2, infer E_2, infer R_3, infer Request_2 extends S.Top & {
|
|
2972
2972
|
readonly make: (...args: any[]) => any;
|
|
2973
2973
|
_tag: string;
|
|
2974
2974
|
fields: S.Struct.Fields;
|
|
@@ -3068,7 +3068,7 @@ export declare const useClient: (options?: {
|
|
|
3068
3068
|
readonly type: "command" | "query" | "stream";
|
|
3069
3069
|
readonly "~decodingServices"?: unknown;
|
|
3070
3070
|
}, infer Id_3 extends string, infer Final_1> ? Request_3["type"] extends "stream" ? import("effect-app/client").RequestStreamHandler<A_3, E_3, R_4, Request_3, Id_3, Final_1> : never : never : never : never>;
|
|
3071
|
-
|
|
3071
|
+
mutate: import("../src/makeClient.js").StreamMutation2WithExtensions<WithToast | (ApiClientFactory | Commander | (I18n | Toast.Toast)), import("effect-app/client").RequestHandlers<never, never, M, import("effect-app/client").ExtractModuleName<M>>[Key] extends infer T_2 ? T_2 extends import("effect-app/client").RequestHandlers<never, never, M, import("effect-app/client").ExtractModuleName<M>>[Key] ? T_2 extends import("effect-app/client").RequestStreamHandlerWithInput<infer I_2, infer A_2, infer E_2, infer R_3, infer Request_2 extends S.Top & {
|
|
3072
3072
|
readonly make: (...args: any[]) => any;
|
|
3073
3073
|
_tag: string;
|
|
3074
3074
|
fields: S.Struct.Fields;
|
package/test/makeClient.test.ts
CHANGED
|
@@ -278,8 +278,8 @@ it.skip("stream final type tests", () => {
|
|
|
278
278
|
const { clientFor } = useClient()
|
|
279
279
|
const client = clientFor(Something, undefined, somethingInvalidationResources)
|
|
280
280
|
|
|
281
|
-
const execNoFinal = client.StreamWithoutFinal.
|
|
282
|
-
const execWithFinal = client.StreamWithFinal.
|
|
281
|
+
const execNoFinal = client.StreamWithoutFinal.mutateToResult()
|
|
282
|
+
const execWithFinal = client.StreamWithFinal.mutateToResult()
|
|
283
283
|
|
|
284
284
|
// Without `final`: execute input is {id: string} and resolves with void
|
|
285
285
|
const _execNoFinalResult: ReturnType<typeof execNoFinal> = execNoFinal({ id: "test" })
|
package/test/streamFinal.test.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The `final` option on a stream request schema lets callers model which type
|
|
5
5
|
* the last emitted stream element is. When present, the execute effect returned
|
|
6
|
-
* by `
|
|
6
|
+
* by `mutateToResult` resolves with that final value instead of `void`.
|
|
7
7
|
*/
|
|
8
8
|
import { expect, it } from "@effect/vitest"
|
|
9
9
|
import { Effect, S } from "effect-app"
|
|
@@ -40,14 +40,14 @@ it.live("asStreamResult returns void and updates ref with each element", () =>
|
|
|
40
40
|
}))
|
|
41
41
|
|
|
42
42
|
// ---------------------------------------------------------------------------
|
|
43
|
-
//
|
|
43
|
+
// mutateToResult with no `final` — execute resolves with void (type-level)
|
|
44
44
|
// ---------------------------------------------------------------------------
|
|
45
45
|
|
|
46
|
-
it.skip("
|
|
46
|
+
it.skip("mutateToResult without final: execute resolves void (type-level)", () => {
|
|
47
47
|
const { clientFor } = useClient()
|
|
48
48
|
const client = clientFor(Something, undefined, somethingInvalidationResources)
|
|
49
49
|
|
|
50
|
-
const execute = client.StreamWithoutFinal.
|
|
50
|
+
const execute = client.StreamWithoutFinal.mutateToResult()
|
|
51
51
|
|
|
52
52
|
// execute returns void — assigning to ExportComplete Effect should fail
|
|
53
53
|
const result = execute({ id: "test" })
|
|
@@ -57,14 +57,14 @@ it.skip("mutateStream without final: execute resolves void (type-level)", () =>
|
|
|
57
57
|
})
|
|
58
58
|
|
|
59
59
|
// ---------------------------------------------------------------------------
|
|
60
|
-
//
|
|
60
|
+
// mutateToResult with `final` — execute resolves with Final type (type-level)
|
|
61
61
|
// ---------------------------------------------------------------------------
|
|
62
62
|
|
|
63
|
-
it.skip("
|
|
63
|
+
it.skip("mutateToResult with final: execute resolves with ExportComplete (type-level)", () => {
|
|
64
64
|
const { clientFor } = useClient()
|
|
65
65
|
const client = clientFor(Something, undefined, somethingInvalidationResources)
|
|
66
66
|
|
|
67
|
-
const execute = client.StreamWithFinal.
|
|
67
|
+
const execute = client.StreamWithFinal.mutateToResult()
|
|
68
68
|
|
|
69
69
|
// execute returns ExportComplete — assignment should compile cleanly
|
|
70
70
|
const result = execute({ id: "test" })
|