@effect-app/vue 4.0.0-beta.22 → 4.0.0-beta.220

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 (103) hide show
  1. package/CHANGELOG.md +1605 -0
  2. package/dist/commander.d.ts +628 -0
  3. package/dist/commander.d.ts.map +1 -0
  4. package/dist/commander.js +1060 -0
  5. package/dist/confirm.d.ts +19 -0
  6. package/dist/confirm.d.ts.map +1 -0
  7. package/dist/confirm.js +24 -0
  8. package/dist/errorReporter.d.ts +4 -4
  9. package/dist/errorReporter.d.ts.map +1 -1
  10. package/dist/errorReporter.js +12 -18
  11. package/dist/form.d.ts +14 -5
  12. package/dist/form.d.ts.map +1 -1
  13. package/dist/form.js +41 -12
  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 +6 -9
  19. package/dist/lib.d.ts.map +1 -1
  20. package/dist/lib.js +35 -10
  21. package/dist/makeClient.d.ts +152 -339
  22. package/dist/makeClient.d.ts.map +1 -1
  23. package/dist/makeClient.js +221 -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 +8 -0
  29. package/dist/makeUseCommand.d.ts.map +1 -0
  30. package/dist/makeUseCommand.js +13 -0
  31. package/dist/mutate.d.ts +52 -34
  32. package/dist/mutate.d.ts.map +1 -1
  33. package/dist/mutate.js +137 -46
  34. package/dist/query.d.ts +19 -39
  35. package/dist/query.d.ts.map +1 -1
  36. package/dist/query.js +128 -72
  37. package/dist/routeParams.d.ts +1 -1
  38. package/dist/runtime.d.ts +7 -4
  39. package/dist/runtime.d.ts.map +1 -1
  40. package/dist/runtime.js +27 -17
  41. package/dist/toast.d.ts +50 -0
  42. package/dist/toast.d.ts.map +1 -0
  43. package/dist/toast.js +32 -0
  44. package/dist/withToast.d.ts +27 -0
  45. package/dist/withToast.d.ts.map +1 -0
  46. package/dist/withToast.js +59 -0
  47. package/examples/streamMutation.ts +70 -0
  48. package/package.json +48 -50
  49. package/src/commander.ts +3393 -0
  50. package/src/{experimental/confirm.ts → confirm.ts} +10 -14
  51. package/src/errorReporter.ts +62 -74
  52. package/src/form.ts +56 -17
  53. package/src/intl.ts +12 -0
  54. package/src/lib.ts +47 -20
  55. package/src/makeClient.ts +568 -1134
  56. package/src/{experimental/makeUseCommand.ts → makeUseCommand.ts} +6 -4
  57. package/src/mutate.ts +265 -127
  58. package/src/query.ts +197 -183
  59. package/src/runtime.ts +41 -20
  60. package/src/{experimental/toast.ts → toast.ts} +13 -27
  61. package/src/{experimental/withToast.ts → withToast.ts} +40 -12
  62. package/test/Mutation.test.ts +176 -23
  63. package/test/dist/form.test.d.ts.map +1 -1
  64. package/test/dist/lib.test.d.ts.map +1 -0
  65. package/test/dist/streamFinal.test.d.ts.map +1 -0
  66. package/test/dist/streamFn.test.d.ts.map +1 -0
  67. package/test/dist/stubs.d.ts +3529 -122
  68. package/test/dist/stubs.d.ts.map +1 -1
  69. package/test/dist/stubs.js +182 -31
  70. package/test/form-validation-errors.test.ts +23 -19
  71. package/test/form.test.ts +20 -2
  72. package/test/lib.test.ts +240 -0
  73. package/test/makeClient.test.ts +292 -38
  74. package/test/streamFinal.test.ts +63 -0
  75. package/test/streamFn.test.ts +455 -0
  76. package/test/stubs.ts +218 -42
  77. package/tsconfig.examples.json +20 -0
  78. package/tsconfig.json +0 -1
  79. package/tsconfig.json.bak +5 -2
  80. package/tsconfig.src.json +34 -34
  81. package/tsconfig.test.json +2 -2
  82. package/vitest.config.ts +5 -5
  83. package/dist/experimental/commander.d.ts +0 -359
  84. package/dist/experimental/commander.d.ts.map +0 -1
  85. package/dist/experimental/commander.js +0 -557
  86. package/dist/experimental/confirm.d.ts +0 -19
  87. package/dist/experimental/confirm.d.ts.map +0 -1
  88. package/dist/experimental/confirm.js +0 -28
  89. package/dist/experimental/intl.d.ts +0 -16
  90. package/dist/experimental/intl.d.ts.map +0 -1
  91. package/dist/experimental/intl.js +0 -5
  92. package/dist/experimental/makeUseCommand.d.ts +0 -8
  93. package/dist/experimental/makeUseCommand.d.ts.map +0 -1
  94. package/dist/experimental/makeUseCommand.js +0 -13
  95. package/dist/experimental/toast.d.ts +0 -47
  96. package/dist/experimental/toast.d.ts.map +0 -1
  97. package/dist/experimental/toast.js +0 -41
  98. package/dist/experimental/withToast.d.ts +0 -25
  99. package/dist/experimental/withToast.d.ts.map +0 -1
  100. package/dist/experimental/withToast.js +0 -45
  101. package/eslint.config.mjs +0 -24
  102. package/src/experimental/commander.ts +0 -1835
  103. package/src/experimental/intl.ts +0 -9
@@ -1,10 +1,12 @@
1
- import { Cause, Effect, Layer, type Option, ServiceMap } from "effect-app"
1
+ import { Cause, Context, Effect, Fiber, Layer, type Option, S } from "effect-app"
2
2
  import { wrapEffect } from "effect-app/utils"
3
- import { CurrentToastId, Toast } from "./toast.js"
3
+ import { CurrentToastId, Toast, type ToastId } from "./toast.js"
4
4
 
5
5
  export interface ToastOptions<A, E, Args extends ReadonlyArray<unknown>, WaiR, SucR, ErrR> {
6
6
  stableToastId?: undefined | string | ((...args: Args) => string | undefined)
7
7
  timeout?: number
8
+ showSpanInfo?: false
9
+ groupId?: string
8
10
  onWaiting:
9
11
  | string
10
12
  | ((...args: Args) => string | null)
@@ -33,10 +35,10 @@ export interface ToastOptions<A, E, Args extends ReadonlyArray<unknown>, WaiR, S
33
35
  }
34
36
 
35
37
  // @effect-diagnostics-next-line missingEffectServiceDependency:off
36
- export class WithToast extends ServiceMap.Service<WithToast>()("WithToast", {
38
+ export class WithToast extends Context.Service<WithToast>()("WithToast", {
37
39
  make: Effect.gen(function*() {
38
40
  const toast = yield* Toast
39
- return <A, E, Args extends Array<unknown>, R, WaiR = never, SucR = never, ErrR = never>(
41
+ return <A, E, Args extends readonly unknown[], R, WaiR = never, SucR = never, ErrR = never>(
40
42
  options: ToastOptions<A, E, Args, WaiR, SucR, ErrR>
41
43
  ) =>
42
44
  Effect.fnUntraced(function*(self: Effect.Effect<A, E, R>, ...args: Args) {
@@ -46,23 +48,41 @@ export class WithToast extends ServiceMap.Service<WithToast>()("WithToast", {
46
48
  ? options.stableToastId(...args)
47
49
  : options.stableToastId
48
50
 
51
+ const requestId: string = yield* Effect.currentSpan.pipe(
52
+ Effect.map((span) => span.traceId),
53
+ Effect.orElseSucceed(() => S.StringId.make())
54
+ )
55
+ const groupId = options.groupId
56
+ const meta = { ...(groupId !== undefined ? { groupId } : {}), requestId }
57
+
49
58
  const t = yield* wrapEffect(options.onWaiting)(...args)
50
- const toastId = t === null ? stableToastId : yield* toast.info(
51
- t,
52
- { id: stableToastId ?? null } // TODO: timeout forever?
59
+ const toastId: ToastId | undefined = t === null
60
+ ? stableToastId
61
+ : stableToastId ?? `wait-${Math.random().toString(36).slice(2)}`
62
+
63
+ const waitingFiber = t === null ? undefined : yield* Effect.forkChild(
64
+ Effect.sleep("1 seconds").pipe(
65
+ Effect.andThen(toast.info(t, { id: toastId!, timeout: Infinity, ...meta }))
66
+ )
53
67
  )
68
+ const interruptWaiting = waitingFiber ? Fiber.interrupt(waitingFiber) : Effect.void
69
+
54
70
  return yield* self.pipe(
55
71
  Effect.tap(Effect.fnUntraced(function*(a) {
72
+ yield* interruptWaiting
56
73
  const t = yield* wrapEffect(options.onSuccess)(a, ...args)
57
74
  if (t === null) {
58
75
  return
59
76
  }
60
77
  yield* toast.success(
61
78
  t,
62
- toastId !== undefined ? { id: toastId, timeout: baseTimeout } : { timeout: baseTimeout }
79
+ toastId !== undefined
80
+ ? { id: toastId, timeout: baseTimeout, ...meta }
81
+ : { timeout: baseTimeout, ...meta }
63
82
  )
64
83
  })),
65
84
  Effect.tapCause(Effect.fnUntraced(function*(cause) {
85
+ yield* interruptWaiting
66
86
  yield* Effect.logDebug(
67
87
  "WithToast - caught error cause: " + Cause.squash(cause),
68
88
  Cause.hasInterruptsOnly(cause),
@@ -74,15 +94,23 @@ export class WithToast extends ServiceMap.Service<WithToast>()("WithToast", {
74
94
  return
75
95
  }
76
96
 
97
+ const spanInfo = options.showSpanInfo !== false
98
+ ? yield* Effect.currentSpan.pipe(
99
+ Effect.map((span) => `\nTrace: ${span.traceId}\nSpan: ${span.spanId}`),
100
+ Effect.orElseSucceed(() => "")
101
+ )
102
+ : ""
103
+
77
104
  const t = yield* wrapEffect(options.onFailure)(Cause.findErrorOption(cause), ...args)
78
- const opts = { timeout: baseTimeout * 2 }
105
+ const opts = { timeout: baseTimeout * 2, ...meta }
79
106
 
80
107
  if (typeof t === "object") {
108
+ const message = t.message + spanInfo
81
109
  return t.level === "warn"
82
- ? yield* toast.warning(t.message, toastId !== undefined ? { ...opts, id: toastId } : opts)
83
- : yield* toast.error(t.message, toastId !== undefined ? { ...opts, id: toastId } : opts)
110
+ ? yield* toast.warning(message, toastId !== undefined ? { ...opts, id: toastId } : opts)
111
+ : yield* toast.error(message, toastId !== undefined ? { ...opts, id: toastId } : opts)
84
112
  }
85
- yield* toast.error(t, toastId !== undefined ? { ...opts, id: toastId } : opts)
113
+ yield* toast.error(t + spanInfo, toastId !== undefined ? { ...opts, id: toastId } : opts)
86
114
  }, Effect.uninterruptible)),
87
115
  toastId !== undefined ? Effect.provideService(CurrentToastId, CurrentToastId.of({ toastId })) : (_) => _
88
116
  )
@@ -1,9 +1,10 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import { it } from "@effect/vitest"
3
3
  import { Cause, Effect, Exit, Fiber, Option } from "effect-app"
4
- import { CommandContext, DefaultIntl } from "../src/experimental/commander.js"
4
+ import { TestClock } from "effect/testing"
5
+ import { CommandContext, DefaultIntl } from "../src/commander.js"
5
6
  import { AsyncResult } from "../src/lib.js"
6
- import { useExperimental } from "./stubs.js"
7
+ import { useExperimental, useExperimentalE } from "./stubs.js"
7
8
 
8
9
  const unwrap = <A, E>(r: Fiber.Fiber<Exit.Exit<A, E>, never>) => Fiber.join(r).pipe(Effect.flatten)
9
10
 
@@ -71,7 +72,10 @@ describe("alt2", () => {
71
72
  expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
72
73
  })),
73
74
  Effect.tap(() =>
74
- Effect.currentSpan.pipe(Effect.map((_) => _.name), Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action"))))
75
+ Effect.currentSpan.pipe(
76
+ Effect.map((_) => _.name),
77
+ Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action")))
78
+ )
75
79
  ),
76
80
  Effect.tap(() => Effect.sync(() => executed = true))
77
81
  )
@@ -125,7 +129,10 @@ it.live("works", () =>
125
129
  expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
126
130
  })),
127
131
  Effect.tap(() =>
128
- Effect.currentSpan.pipe(Effect.map((_) => _.name), Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action"))))
132
+ Effect.currentSpan.pipe(
133
+ Effect.map((_) => _.name),
134
+ Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action")))
135
+ )
129
136
  ),
130
137
  Effect.tap(() => Effect.sync(() => executed = true))
131
138
  )
@@ -175,7 +182,10 @@ it.live("works non-gen", () =>
175
182
  expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
176
183
  })),
177
184
  Effect.tap(() =>
178
- Effect.currentSpan.pipe(Effect.map((_) => _.name), Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action"))))
185
+ Effect.currentSpan.pipe(
186
+ Effect.map((_) => _.name),
187
+ Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action")))
188
+ )
179
189
  ),
180
190
  Effect.tap(() => Effect.sync(() => executed = true))
181
191
  )
@@ -308,8 +318,8 @@ it.live("with toasts", () =>
308
318
  function*() {
309
319
  expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
310
320
 
311
- expect(toasts.length).toBe(1)
312
- expect(toasts[0].message).toBe("Test Action executing...")
321
+ // fast actions complete before the 1s waiting-toast delay, so no waiting toast is shown
322
+ expect(toasts.length).toBe(0)
313
323
 
314
324
  return "test-value"
315
325
  },
@@ -317,7 +327,10 @@ it.live("with toasts", () =>
317
327
  expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
318
328
  })),
319
329
  Effect.tap(() =>
320
- Effect.currentSpan.pipe(Effect.map((_) => _.name), Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action"))))
330
+ Effect.currentSpan.pipe(
331
+ Effect.map((_) => _.name),
332
+ Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action")))
333
+ )
321
334
  ),
322
335
  // WithToast.handle({
323
336
  // onFailure: "failed",
@@ -346,7 +359,7 @@ it.live("interrupted", () =>
346
359
 
347
360
  const command = Command.fn("Test Action")(
348
361
  function*() {
349
- expect(toasts.length).toBe(1)
362
+ expect(toasts.length).toBe(0)
350
363
  yield* Effect.interrupt
351
364
  return "test-value"
352
365
  },
@@ -373,7 +386,7 @@ it.live("fail", () =>
373
386
 
374
387
  const command = Command.fn("Test Action")(
375
388
  function*() {
376
- expect(toasts.length).toBe(1)
389
+ expect(toasts.length).toBe(0)
377
390
  return yield* Effect.fail({ message: "Boom!" })
378
391
  },
379
392
  Command.withDefaultToast(),
@@ -388,9 +401,30 @@ it.live("fail", () =>
388
401
  expect(command.waiting).toBe(false)
389
402
  expect(Exit.isFailure(AsyncResult.toExit(command.result))).toBe(true)
390
403
  expect(toasts.length).toBe(1) // toast should show error
391
- expect(toasts[0].message).toBe("Test Action Failed:\nBoom!")
404
+ expect(toasts[0].type).toBe("warning")
405
+ expect(toasts[0].message).toContain("Test Action Failed:\nBoom!")
406
+ expect(toasts[0].message).toMatch(/Trace: [a-f0-9]{32}/)
407
+ expect(toasts[0].message).toMatch(/Span: [a-f0-9]{16}/)
392
408
  }))
393
409
 
410
+ it.live("fail with showSpanInfo disabled", () =>
411
+ Effect
412
+ .gen(function*() {
413
+ const toasts: any[] = []
414
+ const Command = useExperimental({ toasts, messages: DefaultIntl.en })
415
+
416
+ const command = Command.fn("Test Action")(
417
+ function*() {
418
+ return yield* Effect.fail({ message: "Boom!" })
419
+ },
420
+ Command.withDefaultToast({ showSpanInfo: false })
421
+ )
422
+
423
+ yield* Fiber.join(command.handle())
424
+
425
+ expect(toasts.length).toBe(1)
426
+ expect(toasts[0].message).toBe("Test Action Failed:\nBoom!")
427
+ }))
394
428
  it.live("fail and recover", () =>
395
429
  Effect
396
430
  .gen(function*() {
@@ -400,7 +434,7 @@ it.live("fail and recover", () =>
400
434
 
401
435
  const command = Command.fn("Test Action")(
402
436
  function*() {
403
- expect(toasts.length).toBe(1)
437
+ expect(toasts.length).toBe(0)
404
438
  return yield* Effect.fail({ message: "Boom!" })
405
439
  },
406
440
  Effect.orElseSucceed(() => "recovered"), // we recover from the error here, so the final result is success
@@ -428,7 +462,7 @@ it.live("defect", () =>
428
462
 
429
463
  const command = Command.fn("Test Action")(
430
464
  function*() {
431
- expect(toasts.length).toBe(1)
465
+ expect(toasts.length).toBe(0)
432
466
  return yield* Effect.die({ message: "Boom!" })
433
467
  },
434
468
  Command.withDefaultToast(),
@@ -444,7 +478,8 @@ it.live("defect", () =>
444
478
  expect(command.waiting).toBe(false)
445
479
  expect(Exit.isFailure(AsyncResult.toExit(command.result))).toBe(true)
446
480
  expect(toasts.length).toBe(1) // toast should show error
447
- expect(toasts[0].message).toBe("Test Action unexpected error, please try again shortly.")
481
+ expect(toasts[0].type).toBe("error")
482
+ expect(toasts[0].message).toContain("Test Action unexpected error, please try again shortly.")
448
483
  }))
449
484
 
450
485
  it.live("works with alt", () =>
@@ -471,7 +506,10 @@ it.live("works with alt", () =>
471
506
  expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
472
507
  })),
473
508
  Effect.tap(() =>
474
- Effect.currentSpan.pipe(Effect.map((_) => _.name), Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action"))))
509
+ Effect.currentSpan.pipe(
510
+ Effect.map((_) => _.name),
511
+ Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action")))
512
+ )
475
513
  ),
476
514
  Effect.tap(() => Effect.sync(() => executed = true))
477
515
  )
@@ -615,8 +653,8 @@ it.live("with toasts with alt", () =>
615
653
  function*() {
616
654
  expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
617
655
 
618
- expect(toasts.length).toBe(1)
619
- expect(toasts[0].message).toBe("Test Action executing...")
656
+ // fast actions complete before the 1s waiting-toast delay, so no waiting toast is shown
657
+ expect(toasts.length).toBe(0)
620
658
 
621
659
  return "test-value"
622
660
  },
@@ -624,7 +662,10 @@ it.live("with toasts with alt", () =>
624
662
  expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
625
663
  })),
626
664
  Effect.tap(() =>
627
- Effect.currentSpan.pipe(Effect.map((_) => _.name), Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action"))))
665
+ Effect.currentSpan.pipe(
666
+ Effect.map((_) => _.name),
667
+ Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action")))
668
+ )
628
669
  ),
629
670
  Command.withDefaultToast(),
630
671
  Effect.tap(() => Effect.sync(() => executed = true))
@@ -650,7 +691,7 @@ it.live("interrupted with alt", () =>
650
691
  const command = Command.alt("Test Action")(
651
692
  Effect.fnUntraced(
652
693
  function*() {
653
- expect(toasts.length).toBe(1)
694
+ expect(toasts.length).toBe(0)
654
695
  // @effect-diagnostics-next-line missingReturnYieldStar:off
655
696
  yield* Effect.interrupt
656
697
  return "test-value"
@@ -680,7 +721,7 @@ it.live("fail with alt", () =>
680
721
  const command = Command.alt("Test Action")(
681
722
  Effect.fnUntraced(
682
723
  function*() {
683
- expect(toasts.length).toBe(1)
724
+ expect(toasts.length).toBe(0)
684
725
  return yield* Effect.fail({ message: "Boom!" })
685
726
  },
686
727
  Command.withDefaultToast(),
@@ -696,7 +737,8 @@ it.live("fail with alt", () =>
696
737
  expect(command.waiting).toBe(false)
697
738
  expect(Exit.isFailure(AsyncResult.toExit(command.result))).toBe(true)
698
739
  expect(toasts.length).toBe(1) // toast should show error
699
- expect(toasts[0].message).toBe("Test Action Failed:\nBoom!")
740
+ expect(toasts[0].type).toBe("warning")
741
+ expect(toasts[0].message).toContain("Test Action Failed:\nBoom!")
700
742
  }))
701
743
 
702
744
  it.live("fail and recover with alt", () =>
@@ -709,7 +751,7 @@ it.live("fail and recover with alt", () =>
709
751
  const command = Command.alt("Test Action")(
710
752
  Effect.fnUntraced(
711
753
  function*() {
712
- expect(toasts.length).toBe(1)
754
+ expect(toasts.length).toBe(0)
713
755
  return yield* Effect.fail({ message: "Boom!" })
714
756
  },
715
757
  Effect.orElseSucceed(() => "recovered"), // we recover from the error here, so the final result is success
@@ -729,6 +771,64 @@ it.live("fail and recover with alt", () =>
729
771
  expect(toasts[0].message).toBe("Test Action Success")
730
772
  }))
731
773
 
774
+ it.effect("slow action shows waiting toast after the 1s delay", () =>
775
+ Effect
776
+ .gen(function*() {
777
+ const toasts: any[] = []
778
+ const Command = yield* useExperimentalE({ toasts, messages: DefaultIntl.en })
779
+
780
+ const command = Command.fn("Test Action")(
781
+ function*() {
782
+ // before 1s the waiting toast must NOT have surfaced yet
783
+ expect(toasts.length).toBe(0)
784
+ yield* Effect.sleep("1100 millis")
785
+ // after the delay window the waiting info toast should be visible
786
+ expect(toasts.length).toBe(1)
787
+ expect(toasts[0].type).toBe("info")
788
+ expect(toasts[0].message).toBe("Test Action executing...")
789
+ return "test-value"
790
+ },
791
+ Command.withDefaultToast()
792
+ )
793
+
794
+ const fiber = command.handle()
795
+ yield* TestClock.adjust("2 seconds")
796
+ const r = yield* unwrap(fiber)
797
+
798
+ expect(r).toBe("test-value")
799
+ // waiting toast is replaced (same id) with the success toast
800
+ expect(toasts.length).toBe(1)
801
+ expect(toasts[0].type).toBe("success")
802
+ expect(toasts[0].message).toBe("Test Action Success")
803
+ }))
804
+
805
+ it.effect("slow failing action surfaces waiting toast then shows error", () =>
806
+ Effect
807
+ .gen(function*() {
808
+ const toasts: any[] = []
809
+ const Command = yield* useExperimentalE({ toasts, messages: DefaultIntl.en })
810
+
811
+ const command = Command.fn("Test Action")(
812
+ function*() {
813
+ expect(toasts.length).toBe(0)
814
+ yield* Effect.sleep("1100 millis")
815
+ expect(toasts.length).toBe(1)
816
+ expect(toasts[0].type).toBe("info")
817
+ return yield* Effect.fail({ message: "Boom!" })
818
+ },
819
+ Command.withDefaultToast()
820
+ )
821
+
822
+ const fiber = command.handle()
823
+ yield* TestClock.adjust("2 seconds")
824
+ const r = yield* Fiber.join(fiber)
825
+
826
+ expect(Exit.isFailure(r) && Cause.hasFails(r.cause)).toBe(true)
827
+ expect(toasts.length).toBe(1)
828
+ expect(toasts[0].type).toBe("warning")
829
+ expect(toasts[0].message).toContain("Test Action Failed:\nBoom!")
830
+ }))
831
+
732
832
  it.live("defect with alt", () =>
733
833
  Effect
734
834
  .gen(function*() {
@@ -756,5 +856,58 @@ it.live("defect with alt", () =>
756
856
  expect(command.waiting).toBe(false)
757
857
  expect(Exit.isFailure(AsyncResult.toExit(command.result))).toBe(true)
758
858
  expect(toasts.length).toBe(1) // toast should show error
759
- expect(toasts[0].message).toBe("Test Action unexpected error, please try again shortly.")
859
+ expect(toasts[0].type).toBe("error")
860
+ expect(toasts[0].message).toContain("Test Action unexpected error, please try again shortly.")
760
861
  }))
862
+
863
+ describe("state-in-toast", () => {
864
+ it("works", () => {
865
+ const toasts: any[] = []
866
+ const removeMutation = Object.assign(
867
+ Effect.fn(function*(_item: string) {
868
+ yield* Effect.sleep(1000)
869
+ }),
870
+ { id: "remove_thing" }
871
+ )
872
+
873
+ const item = "x"
874
+
875
+ const Command = useExperimental({ toasts, messages: DefaultIntl.en })
876
+
877
+ Command.fn(removeMutation, {
878
+ state: () => ({ item }),
879
+ waitKey: (id) => `${id}.${item}`,
880
+ blockKey: () => `modify_thing.${item}`
881
+ // allowed: () => role.value === "admin"
882
+ })(
883
+ function*() {
884
+ // yield* Command.confirmOrInterrupt(yield* I18n.formatMessage({ id: "confirm.remove_item" }, { item }))
885
+ yield* removeMutation(item)
886
+ },
887
+ Command.withDefaultToast({
888
+ onSuccess: (a, b, c, d) => {
889
+ console.log("Success", { a, b, c, d })
890
+ expectTypeOf(d.state).toEqualTypeOf<{ readonly item: "x" }>()
891
+ }
892
+ })
893
+ )
894
+
895
+ Command.fn(removeMutation, {
896
+ state: () => ({ item }),
897
+ waitKey: (id) => `${id}.${item}`,
898
+ blockKey: () => `modify_thing.${item}`
899
+ // allowed: () => role.value === "admin"
900
+ })(
901
+ function*() {
902
+ // yield* Command.confirmOrInterrupt(yield* I18n.formatMessage({ id: "confirm.remove_item" }, { item }))
903
+ yield* removeMutation(item)
904
+ },
905
+ Command.withDefaultToast({
906
+ onSuccess: (a, b, c) => {
907
+ console.log("Success", { a, b, c })
908
+ expectTypeOf(c).toEqualTypeOf<undefined>()
909
+ }
910
+ })
911
+ )
912
+ })
913
+ })
@@ -1 +1 @@
1
- {"version":3,"file":"form.test.d.ts","sourceRoot":"","sources":["../form.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,CAAC,EAAE,MAAM,YAAY,CAAA;;;;;;;;;;;;;;;;;AAGtC,qBAAa,YAAa,SAAQ,iBAShC;CAAG;;;;AAEL,qBAAa,mBAAoB,SAAQ,wBAEvC;CAAG;;;;;;;;;;;AAEL,qBAAa,WAAY,SAAQ,gBAK/B;CAAG;;;;;;;;AAEL,cAAM,MAAO,SAAQ,WAEnB;CAAG;;;;;;;;AAEL,cAAM,MAAO,SAAQ,WAEnB;CAAG;;;;;;;;;;;AAEL,cAAM,QAAS,SAAQ,aAGrB;CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqBL,qBAAa,cAAe,SAAQ,mBAGlC;CAAG"}
1
+ {"version":3,"file":"form.test.d.ts","sourceRoot":"","sources":["../form.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,CAAC,EAAE,MAAM,YAAY,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGtC,qBAAa,YAAa,SAAQ,iBAahC;CAAG;;;;AAEL,qBAAa,mBAAoB,SAAQ,wBAEvC;CAAG;;;;;;;;;;;;AAEL,qBAAa,WAAY,SAAQ,gBAK/B;CAAG;;;;;;;;AAEL,cAAM,MAAO,SAAQ,WAEnB;CAAG;;;;;;;;AAEL,cAAM,MAAO,SAAQ,WAEnB;CAAG;;;;;;;;;;;;AAEL,cAAM,QAAS,SAAQ,aAGrB;CAAG;;;;;;;;;;;;;;;;;;;;;;;;AAqBL,qBAAa,cAAe,SAAQ,mBAGlC;CAAG"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lib.test.d.ts","sourceRoot":"","sources":["../lib.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streamFinal.test.d.ts","sourceRoot":"","sources":["../streamFinal.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streamFn.test.d.ts","sourceRoot":"","sources":["../streamFn.test.ts"],"names":[],"mappings":""}