@effect-app/vue 4.0.0-beta.184 → 4.0.0-beta.186
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 +14 -0
- package/dist/commander.d.ts +20 -12
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +30 -12
- package/dist/makeClient.d.ts +5 -5
- package/dist/makeClient.js +3 -3
- package/dist/mutate.d.ts +1 -1
- package/dist/mutate.js +1 -1
- package/examples/streamMutation.ts +5 -5
- package/package.json +2 -2
- package/src/commander.ts +35 -15
- package/src/makeClient.ts +7 -7
- package/src/mutate.ts +1 -1
- 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
|
@@ -34,7 +34,7 @@ export type StreamMutationCallOptions<A, E> = {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* The result of invoking a `
|
|
37
|
+
* The result of invoking a `mutateToResult` factory: the `execute` function (or
|
|
38
38
|
* `Effect`, when the request takes no input) carries `id`, plus `running` and
|
|
39
39
|
* `progress` when the factory was called with a `progress` formatter. Pass
|
|
40
40
|
* directly to `Command.fn` / `Command.wrap` / `Command.wrapStream`, or invoke
|
|
@@ -218,7 +218,7 @@ export declare namespace Commander {
|
|
|
218
218
|
/** reactive */
|
|
219
219
|
result: AsyncResult.AsyncResult<A, E>
|
|
220
220
|
/**
|
|
221
|
-
* reactive – set when the command wraps a stream (`wrapStream` / `wrap` with `
|
|
221
|
+
* reactive – set when the command wraps a stream (`wrapStream` / `wrap` with `mutateToResult`)
|
|
222
222
|
* or when the `progress` option is provided to `fn`.
|
|
223
223
|
* Reflects the live AsyncResult of the underlying stream.
|
|
224
224
|
*/
|
|
@@ -2204,6 +2204,7 @@ export const CommanderStatic = {
|
|
|
2204
2204
|
*
|
|
2205
2205
|
* Unlike `withDefaultToast` (which only wraps the initial `Effect`), this combinator:
|
|
2206
2206
|
* - Shows the "waiting" toast **before** the stream starts
|
|
2207
|
+
* - Updates the waiting toast with progress text when `progress` is set and a new element arrives
|
|
2207
2208
|
* - Shows the "success" toast only **after** the stream drains fully without error
|
|
2208
2209
|
* - Shows the "failure" toast if the stream errors or fails
|
|
2209
2210
|
*
|
|
@@ -2214,7 +2215,12 @@ export const CommanderStatic = {
|
|
|
2214
2215
|
* ```ts
|
|
2215
2216
|
* Command.streamFn("exportData")(
|
|
2216
2217
|
* function*(arg, ctx) { return makeExportStream(arg.id) },
|
|
2217
|
-
* Command.withDefaultToastStream(
|
|
2218
|
+
* Command.withDefaultToastStream({
|
|
2219
|
+
* progress: (r) =>
|
|
2220
|
+
* AsyncResult.isSuccess(r) && r.value._tag === "OperationProgress"
|
|
2221
|
+
* ? { text: `${r.value.completed}/${r.value.total}`, percentage: r.value.completed / r.value.total * 100 }
|
|
2222
|
+
* : undefined
|
|
2223
|
+
* })
|
|
2218
2224
|
* )
|
|
2219
2225
|
* ```
|
|
2220
2226
|
*/
|
|
@@ -2237,6 +2243,8 @@ export const CommanderStatic = {
|
|
|
2237
2243
|
| undefined
|
|
2238
2244
|
| string
|
|
2239
2245
|
| ((a: A, action: string, arg: NoInfer<Args>[0], ctx: NoInfer<Args>[1]) => string | null | undefined)
|
|
2246
|
+
/** Map each stream element to a progress label. When non-`undefined`, updates both the active waiting toast and the `CommandProgress` service (for CommandButton progress display). */
|
|
2247
|
+
progress?: (result: AsyncResult.AsyncResult<A, E>) => Progress | undefined
|
|
2240
2248
|
}
|
|
2241
2249
|
) =>
|
|
2242
2250
|
(
|
|
@@ -2300,8 +2308,20 @@ export const CommanderStatic = {
|
|
|
2300
2308
|
|
|
2301
2309
|
const composed = rawStream.pipe(
|
|
2302
2310
|
Stream.tap((v) =>
|
|
2303
|
-
Effect.
|
|
2311
|
+
Effect.gen(function*() {
|
|
2304
2312
|
lastValue = v
|
|
2313
|
+
if (options?.progress !== undefined) {
|
|
2314
|
+
const p = options.progress(AsyncResult.success(v, { waiting: true }))
|
|
2315
|
+
if (p !== undefined) {
|
|
2316
|
+
// Update CommandProgress so CommandButton progress indicator is also driven
|
|
2317
|
+
yield* CommandProgress.use((s) => s.update(p))
|
|
2318
|
+
if (toastId !== undefined) {
|
|
2319
|
+
const progressText = typeof p === "string" ? p : p.text
|
|
2320
|
+
const msg = waitingMsg ? `${waitingMsg}\n${progressText}` : progressText
|
|
2321
|
+
yield* toast.info(msg, { id: toastId })
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2305
2325
|
})
|
|
2306
2326
|
),
|
|
2307
2327
|
Stream.tapCause(Effect.fnUntraced(function*(cause) {
|
|
@@ -3265,14 +3285,14 @@ export class CommanderImpl<RT, RTHooks> {
|
|
|
3265
3285
|
| StreamMutationFactory<Id, Arg, A, E, R>
|
|
3266
3286
|
| {
|
|
3267
3287
|
id: Id
|
|
3268
|
-
|
|
3288
|
+
mutateToResult:
|
|
3269
3289
|
| StreamMutationFactory<Id, Arg, A, E, R>
|
|
3270
3290
|
| StreamMutationCallable<Id, Arg, A, E, R>
|
|
3271
3291
|
}
|
|
3272
3292
|
| StreamMutationCallable<Id, Arg, A, E, R>,
|
|
3273
3293
|
options?: FnOptions<Id, I18nKey, State>
|
|
3274
3294
|
): Commander.CommanderWrap<RT | RTHooks, Id, I18nKey, State, Arg, A, E, R> => {
|
|
3275
|
-
if (mutation !== null && typeof mutation === "object" && "
|
|
3295
|
+
if (mutation !== null && typeof mutation === "object" && "mutateToResult" in mutation) {
|
|
3276
3296
|
return this.wrapStream(mutation as any, options) as any
|
|
3277
3297
|
}
|
|
3278
3298
|
if (isStreamCallable(mutation) || isStreamFactory(mutation)) {
|
|
@@ -3315,18 +3335,18 @@ export class CommanderImpl<RT, RTHooks> {
|
|
|
3315
3335
|
}
|
|
3316
3336
|
|
|
3317
3337
|
/**
|
|
3318
|
-
* Define a Command from a stream-type mutation (`
|
|
3338
|
+
* Define a Command from a stream-type mutation (`mutateToResult` factory).
|
|
3319
3339
|
* The stream's reactive `AsyncResult` ref is exposed as `running` for independent progress tracking.
|
|
3320
3340
|
* The command's own `result` reflects the execution outcome of the `execute` function.
|
|
3321
3341
|
* Supports the same combinator pipeline as `wrap` (e.g. `withDefaultToast`).
|
|
3322
3342
|
*
|
|
3323
3343
|
* Each invocation of the resulting wrap call produces a fresh `[ref, execute]` pair
|
|
3324
|
-
* (the `
|
|
3344
|
+
* (the `mutateToResult` factory is called once per build), so independent commands
|
|
3325
3345
|
* don't share progress state.
|
|
3326
3346
|
*
|
|
3327
3347
|
* Accepts either:
|
|
3328
|
-
* - An object with `id` and `
|
|
3329
|
-
* - The `
|
|
3348
|
+
* - An object with `id` and `mutateToResult` factory (e.g. a client entry)
|
|
3349
|
+
* - The `mutateToResult` factory directly (callable, with `id`)
|
|
3330
3350
|
* - An already-called factory result (`[resultRef, execute] & { id }`) — shared ref across builds
|
|
3331
3351
|
*
|
|
3332
3352
|
* @example
|
|
@@ -3335,10 +3355,10 @@ export class CommanderImpl<RT, RTHooks> {
|
|
|
3335
3355
|
* const exportCmd = Command.wrapStream(client.myExport)()
|
|
3336
3356
|
*
|
|
3337
3357
|
* // Via factory directly:
|
|
3338
|
-
* const exportCmd = Command.wrapStream(client.myExport.
|
|
3358
|
+
* const exportCmd = Command.wrapStream(client.myExport.mutateToResult)()
|
|
3339
3359
|
*
|
|
3340
3360
|
* // Via already-called factory (shared ref):
|
|
3341
|
-
* const stream = client.myExport.
|
|
3361
|
+
* const stream = client.myExport.mutateToResult()
|
|
3342
3362
|
* const exportCmd = Command.wrapStream(stream)()
|
|
3343
3363
|
* ```
|
|
3344
3364
|
*/
|
|
@@ -3354,7 +3374,7 @@ export class CommanderImpl<RT, RTHooks> {
|
|
|
3354
3374
|
mutation:
|
|
3355
3375
|
| {
|
|
3356
3376
|
id: Id
|
|
3357
|
-
|
|
3377
|
+
mutateToResult:
|
|
3358
3378
|
| StreamMutationFactory<Id, Arg, A, E, R>
|
|
3359
3379
|
| StreamMutationCallable<Id, Arg, A, E, R>
|
|
3360
3380
|
}
|
|
@@ -3365,8 +3385,8 @@ export class CommanderImpl<RT, RTHooks> {
|
|
|
3365
3385
|
const id = mutation.id
|
|
3366
3386
|
// Resolve `source` to the factory or already-invoked callable.
|
|
3367
3387
|
const source: StreamMutationFactory<Id, Arg, A, E, R> | StreamMutationCallable<Id, Arg, A, E, R> =
|
|
3368
|
-
mutation !== null && typeof mutation === "object" && "
|
|
3369
|
-
? (mutation.
|
|
3388
|
+
mutation !== null && typeof mutation === "object" && "mutateToResult" in mutation
|
|
3389
|
+
? (mutation.mutateToResult as any)
|
|
3370
3390
|
: (mutation as any)
|
|
3371
3391
|
const resolveCallable = (): StreamMutationCallable<Id, Arg, A, E, R> =>
|
|
3372
3392
|
(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,7 +306,7 @@ export type StreamFnStreamExtension<RT, Req> = Req extends
|
|
|
306
306
|
: never
|
|
307
307
|
|
|
308
308
|
/**
|
|
309
|
-
* `
|
|
309
|
+
* `mutate` factory — like `mutateToResult` but wraps per-invocation invalidation scaffolding
|
|
310
310
|
* into the stream itself (via `Stream.unwrap`) for use with `streamFn` combinators.
|
|
311
311
|
*/
|
|
312
312
|
export type StreamMutation2WithExtensions<RT, Req> = Req extends
|
|
@@ -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
|
}
|
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
|
*
|
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" })
|