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

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 (106) hide show
  1. package/CHANGELOG.md +1613 -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 +156 -339
  22. package/dist/makeClient.d.ts.map +1 -1
  23. package/dist/makeClient.js +225 -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 +54 -34
  32. package/dist/mutate.d.ts.map +1 -1
  33. package/dist/mutate.js +139 -46
  34. package/dist/query.d.ts +20 -39
  35. package/dist/query.d.ts.map +1 -1
  36. package/dist/query.js +133 -72
  37. package/dist/routeParams.d.ts +3 -2
  38. package/dist/routeParams.d.ts.map +1 -1
  39. package/dist/routeParams.js +4 -3
  40. package/dist/runtime.d.ts +10 -6
  41. package/dist/runtime.d.ts.map +1 -1
  42. package/dist/runtime.js +32 -18
  43. package/dist/toast.d.ts +51 -0
  44. package/dist/toast.d.ts.map +1 -0
  45. package/dist/toast.js +34 -0
  46. package/dist/withToast.d.ts +30 -0
  47. package/dist/withToast.d.ts.map +1 -0
  48. package/dist/withToast.js +64 -0
  49. package/examples/streamMutation.ts +72 -0
  50. package/package.json +48 -50
  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 +574 -1134
  58. package/src/{experimental/makeUseCommand.ts → makeUseCommand.ts} +8 -5
  59. package/src/mutate.ts +268 -127
  60. package/src/query.ts +203 -183
  61. package/src/routeParams.ts +3 -2
  62. package/src/runtime.ts +46 -21
  63. package/src/{experimental/toast.ts → toast.ts} +15 -27
  64. package/src/{experimental/withToast.ts → withToast.ts} +46 -12
  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 +3531 -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 +292 -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 +0 -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
@@ -1,10 +1,18 @@
1
- import { Cause, Effect, Layer, type Option, ServiceMap } from "effect-app"
1
+ import * as Context from "effect-app/Context"
2
+ import * as Effect from "effect-app/Effect"
3
+ import * as Layer from "effect-app/Layer"
4
+ import type * as Option from "effect-app/Option"
5
+ import * as S from "effect-app/Schema"
2
6
  import { wrapEffect } from "effect-app/utils"
3
- import { CurrentToastId, Toast } from "./toast.js"
7
+ import * as Cause from "effect/Cause"
8
+ import * as Fiber from "effect/Fiber"
9
+ import { CurrentToastId, Toast, type ToastId } from "./toast.js"
4
10
 
5
11
  export interface ToastOptions<A, E, Args extends ReadonlyArray<unknown>, WaiR, SucR, ErrR> {
6
12
  stableToastId?: undefined | string | ((...args: Args) => string | undefined)
7
13
  timeout?: number
14
+ showSpanInfo?: false
15
+ groupId?: string
8
16
  onWaiting:
9
17
  | string
10
18
  | ((...args: Args) => string | null)
@@ -33,10 +41,10 @@ export interface ToastOptions<A, E, Args extends ReadonlyArray<unknown>, WaiR, S
33
41
  }
34
42
 
35
43
  // @effect-diagnostics-next-line missingEffectServiceDependency:off
36
- export class WithToast extends ServiceMap.Service<WithToast>()("WithToast", {
44
+ export class WithToast extends Context.Service<WithToast>()("WithToast", {
37
45
  make: Effect.gen(function*() {
38
46
  const toast = yield* Toast
39
- return <A, E, Args extends Array<unknown>, R, WaiR = never, SucR = never, ErrR = never>(
47
+ return <A, E, Args extends readonly unknown[], R, WaiR = never, SucR = never, ErrR = never>(
40
48
  options: ToastOptions<A, E, Args, WaiR, SucR, ErrR>
41
49
  ) =>
42
50
  Effect.fnUntraced(function*(self: Effect.Effect<A, E, R>, ...args: Args) {
@@ -46,23 +54,41 @@ export class WithToast extends ServiceMap.Service<WithToast>()("WithToast", {
46
54
  ? options.stableToastId(...args)
47
55
  : options.stableToastId
48
56
 
57
+ const requestId: string = yield* Effect.currentSpan.pipe(
58
+ Effect.map((span) => span.traceId),
59
+ Effect.orElseSucceed(() => S.StringId.make())
60
+ )
61
+ const groupId = options.groupId
62
+ const meta = { ...(groupId !== undefined ? { groupId } : {}), requestId }
63
+
49
64
  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?
65
+ const toastId: ToastId | undefined = t === null
66
+ ? stableToastId
67
+ : stableToastId ?? `wait-${Math.random().toString(36).slice(2)}`
68
+
69
+ const waitingFiber = t === null ? undefined : yield* Effect.forkChild(
70
+ Effect.sleep("1 seconds").pipe(
71
+ Effect.andThen(toast.info(t, { id: toastId!, timeout: Infinity, ...meta }))
72
+ )
53
73
  )
74
+ const interruptWaiting = waitingFiber ? Fiber.interrupt(waitingFiber) : Effect.void
75
+
54
76
  return yield* self.pipe(
55
77
  Effect.tap(Effect.fnUntraced(function*(a) {
78
+ yield* interruptWaiting
56
79
  const t = yield* wrapEffect(options.onSuccess)(a, ...args)
57
80
  if (t === null) {
58
81
  return
59
82
  }
60
83
  yield* toast.success(
61
84
  t,
62
- toastId !== undefined ? { id: toastId, timeout: baseTimeout } : { timeout: baseTimeout }
85
+ toastId !== undefined
86
+ ? { id: toastId, timeout: baseTimeout, ...meta }
87
+ : { timeout: baseTimeout, ...meta }
63
88
  )
64
89
  })),
65
90
  Effect.tapCause(Effect.fnUntraced(function*(cause) {
91
+ yield* interruptWaiting
66
92
  yield* Effect.logDebug(
67
93
  "WithToast - caught error cause: " + Cause.squash(cause),
68
94
  Cause.hasInterruptsOnly(cause),
@@ -74,15 +100,23 @@ export class WithToast extends ServiceMap.Service<WithToast>()("WithToast", {
74
100
  return
75
101
  }
76
102
 
103
+ const spanInfo = options.showSpanInfo !== false
104
+ ? yield* Effect.currentSpan.pipe(
105
+ Effect.map((span) => `\nTrace: ${span.traceId}\nSpan: ${span.spanId}`),
106
+ Effect.orElseSucceed(() => "")
107
+ )
108
+ : ""
109
+
77
110
  const t = yield* wrapEffect(options.onFailure)(Cause.findErrorOption(cause), ...args)
78
- const opts = { timeout: baseTimeout * 2 }
111
+ const opts = { timeout: baseTimeout * 2, ...meta }
79
112
 
80
113
  if (typeof t === "object") {
114
+ const message = t.message + spanInfo
81
115
  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)
116
+ ? yield* toast.warning(message, toastId !== undefined ? { ...opts, id: toastId } : opts)
117
+ : yield* toast.error(message, toastId !== undefined ? { ...opts, id: toastId } : opts)
84
118
  }
85
- yield* toast.error(t, toastId !== undefined ? { ...opts, id: toastId } : opts)
119
+ yield* toast.error(t + spanInfo, toastId !== undefined ? { ...opts, id: toastId } : opts)
86
120
  }, Effect.uninterruptible)),
87
121
  toastId !== undefined ? Effect.provideService(CurrentToastId, CurrentToastId.of({ toastId })) : (_) => _
88
122
  )
@@ -1,9 +1,14 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import { it } from "@effect/vitest"
3
- import { Cause, Effect, Exit, Fiber, Option } from "effect-app"
4
- import { CommandContext, DefaultIntl } from "../src/experimental/commander.js"
3
+ import * as Effect from "effect-app/Effect"
4
+ import * as Option from "effect-app/Option"
5
+ import * as Cause from "effect/Cause"
6
+ import * as Exit from "effect/Exit"
7
+ import * as Fiber from "effect/Fiber"
8
+ import { TestClock } from "effect/testing"
9
+ import { CommandContext, DefaultIntl } from "../src/commander.js"
5
10
  import { AsyncResult } from "../src/lib.js"
6
- import { useExperimental } from "./stubs.js"
11
+ import { useExperimental, useExperimentalE } from "./stubs.js"
7
12
 
8
13
  const unwrap = <A, E>(r: Fiber.Fiber<Exit.Exit<A, E>, never>) => Fiber.join(r).pipe(Effect.flatten)
9
14
 
@@ -71,7 +76,10 @@ describe("alt2", () => {
71
76
  expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
72
77
  })),
73
78
  Effect.tap(() =>
74
- Effect.currentSpan.pipe(Effect.map((_) => _.name), Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action"))))
79
+ Effect.currentSpan.pipe(
80
+ Effect.map((_) => _.name),
81
+ Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action")))
82
+ )
75
83
  ),
76
84
  Effect.tap(() => Effect.sync(() => executed = true))
77
85
  )
@@ -125,7 +133,10 @@ it.live("works", () =>
125
133
  expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
126
134
  })),
127
135
  Effect.tap(() =>
128
- Effect.currentSpan.pipe(Effect.map((_) => _.name), Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action"))))
136
+ Effect.currentSpan.pipe(
137
+ Effect.map((_) => _.name),
138
+ Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action")))
139
+ )
129
140
  ),
130
141
  Effect.tap(() => Effect.sync(() => executed = true))
131
142
  )
@@ -175,7 +186,10 @@ it.live("works non-gen", () =>
175
186
  expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
176
187
  })),
177
188
  Effect.tap(() =>
178
- Effect.currentSpan.pipe(Effect.map((_) => _.name), Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action"))))
189
+ Effect.currentSpan.pipe(
190
+ Effect.map((_) => _.name),
191
+ Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action")))
192
+ )
179
193
  ),
180
194
  Effect.tap(() => Effect.sync(() => executed = true))
181
195
  )
@@ -308,8 +322,8 @@ it.live("with toasts", () =>
308
322
  function*() {
309
323
  expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
310
324
 
311
- expect(toasts.length).toBe(1)
312
- expect(toasts[0].message).toBe("Test Action executing...")
325
+ // fast actions complete before the 1s waiting-toast delay, so no waiting toast is shown
326
+ expect(toasts.length).toBe(0)
313
327
 
314
328
  return "test-value"
315
329
  },
@@ -317,7 +331,10 @@ it.live("with toasts", () =>
317
331
  expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
318
332
  })),
319
333
  Effect.tap(() =>
320
- Effect.currentSpan.pipe(Effect.map((_) => _.name), Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action"))))
334
+ Effect.currentSpan.pipe(
335
+ Effect.map((_) => _.name),
336
+ Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action")))
337
+ )
321
338
  ),
322
339
  // WithToast.handle({
323
340
  // onFailure: "failed",
@@ -346,7 +363,7 @@ it.live("interrupted", () =>
346
363
 
347
364
  const command = Command.fn("Test Action")(
348
365
  function*() {
349
- expect(toasts.length).toBe(1)
366
+ expect(toasts.length).toBe(0)
350
367
  yield* Effect.interrupt
351
368
  return "test-value"
352
369
  },
@@ -373,7 +390,7 @@ it.live("fail", () =>
373
390
 
374
391
  const command = Command.fn("Test Action")(
375
392
  function*() {
376
- expect(toasts.length).toBe(1)
393
+ expect(toasts.length).toBe(0)
377
394
  return yield* Effect.fail({ message: "Boom!" })
378
395
  },
379
396
  Command.withDefaultToast(),
@@ -388,9 +405,30 @@ it.live("fail", () =>
388
405
  expect(command.waiting).toBe(false)
389
406
  expect(Exit.isFailure(AsyncResult.toExit(command.result))).toBe(true)
390
407
  expect(toasts.length).toBe(1) // toast should show error
391
- expect(toasts[0].message).toBe("Test Action Failed:\nBoom!")
408
+ expect(toasts[0].type).toBe("warning")
409
+ expect(toasts[0].message).toContain("Test Action Failed:\nBoom!")
410
+ expect(toasts[0].message).toMatch(/Trace: [a-f0-9]{32}/)
411
+ expect(toasts[0].message).toMatch(/Span: [a-f0-9]{16}/)
392
412
  }))
393
413
 
414
+ it.live("fail with showSpanInfo disabled", () =>
415
+ Effect
416
+ .gen(function*() {
417
+ const toasts: any[] = []
418
+ const Command = useExperimental({ toasts, messages: DefaultIntl.en })
419
+
420
+ const command = Command.fn("Test Action")(
421
+ function*() {
422
+ return yield* Effect.fail({ message: "Boom!" })
423
+ },
424
+ Command.withDefaultToast({ showSpanInfo: false })
425
+ )
426
+
427
+ yield* Fiber.join(command.handle())
428
+
429
+ expect(toasts.length).toBe(1)
430
+ expect(toasts[0].message).toBe("Test Action Failed:\nBoom!")
431
+ }))
394
432
  it.live("fail and recover", () =>
395
433
  Effect
396
434
  .gen(function*() {
@@ -400,7 +438,7 @@ it.live("fail and recover", () =>
400
438
 
401
439
  const command = Command.fn("Test Action")(
402
440
  function*() {
403
- expect(toasts.length).toBe(1)
441
+ expect(toasts.length).toBe(0)
404
442
  return yield* Effect.fail({ message: "Boom!" })
405
443
  },
406
444
  Effect.orElseSucceed(() => "recovered"), // we recover from the error here, so the final result is success
@@ -428,7 +466,7 @@ it.live("defect", () =>
428
466
 
429
467
  const command = Command.fn("Test Action")(
430
468
  function*() {
431
- expect(toasts.length).toBe(1)
469
+ expect(toasts.length).toBe(0)
432
470
  return yield* Effect.die({ message: "Boom!" })
433
471
  },
434
472
  Command.withDefaultToast(),
@@ -444,7 +482,8 @@ it.live("defect", () =>
444
482
  expect(command.waiting).toBe(false)
445
483
  expect(Exit.isFailure(AsyncResult.toExit(command.result))).toBe(true)
446
484
  expect(toasts.length).toBe(1) // toast should show error
447
- expect(toasts[0].message).toBe("Test Action unexpected error, please try again shortly.")
485
+ expect(toasts[0].type).toBe("error")
486
+ expect(toasts[0].message).toContain("Test Action unexpected error, please try again shortly.")
448
487
  }))
449
488
 
450
489
  it.live("works with alt", () =>
@@ -471,7 +510,10 @@ it.live("works with alt", () =>
471
510
  expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
472
511
  })),
473
512
  Effect.tap(() =>
474
- Effect.currentSpan.pipe(Effect.map((_) => _.name), Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action"))))
513
+ Effect.currentSpan.pipe(
514
+ Effect.map((_) => _.name),
515
+ Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action")))
516
+ )
475
517
  ),
476
518
  Effect.tap(() => Effect.sync(() => executed = true))
477
519
  )
@@ -615,8 +657,8 @@ it.live("with toasts with alt", () =>
615
657
  function*() {
616
658
  expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
617
659
 
618
- expect(toasts.length).toBe(1)
619
- expect(toasts[0].message).toBe("Test Action executing...")
660
+ // fast actions complete before the 1s waiting-toast delay, so no waiting toast is shown
661
+ expect(toasts.length).toBe(0)
620
662
 
621
663
  return "test-value"
622
664
  },
@@ -624,7 +666,10 @@ it.live("with toasts with alt", () =>
624
666
  expect(yield* Effect.currentSpan.pipe(Effect.map((_) => _.name))).toBe("Test Action")
625
667
  })),
626
668
  Effect.tap(() =>
627
- Effect.currentSpan.pipe(Effect.map((_) => _.name), Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action"))))
669
+ Effect.currentSpan.pipe(
670
+ Effect.map((_) => _.name),
671
+ Effect.tap((_) => Effect.sync(() => expect(_).toBe("Test Action")))
672
+ )
628
673
  ),
629
674
  Command.withDefaultToast(),
630
675
  Effect.tap(() => Effect.sync(() => executed = true))
@@ -650,7 +695,7 @@ it.live("interrupted with alt", () =>
650
695
  const command = Command.alt("Test Action")(
651
696
  Effect.fnUntraced(
652
697
  function*() {
653
- expect(toasts.length).toBe(1)
698
+ expect(toasts.length).toBe(0)
654
699
  // @effect-diagnostics-next-line missingReturnYieldStar:off
655
700
  yield* Effect.interrupt
656
701
  return "test-value"
@@ -680,7 +725,7 @@ it.live("fail with alt", () =>
680
725
  const command = Command.alt("Test Action")(
681
726
  Effect.fnUntraced(
682
727
  function*() {
683
- expect(toasts.length).toBe(1)
728
+ expect(toasts.length).toBe(0)
684
729
  return yield* Effect.fail({ message: "Boom!" })
685
730
  },
686
731
  Command.withDefaultToast(),
@@ -696,7 +741,8 @@ it.live("fail with alt", () =>
696
741
  expect(command.waiting).toBe(false)
697
742
  expect(Exit.isFailure(AsyncResult.toExit(command.result))).toBe(true)
698
743
  expect(toasts.length).toBe(1) // toast should show error
699
- expect(toasts[0].message).toBe("Test Action Failed:\nBoom!")
744
+ expect(toasts[0].type).toBe("warning")
745
+ expect(toasts[0].message).toContain("Test Action Failed:\nBoom!")
700
746
  }))
701
747
 
702
748
  it.live("fail and recover with alt", () =>
@@ -709,7 +755,7 @@ it.live("fail and recover with alt", () =>
709
755
  const command = Command.alt("Test Action")(
710
756
  Effect.fnUntraced(
711
757
  function*() {
712
- expect(toasts.length).toBe(1)
758
+ expect(toasts.length).toBe(0)
713
759
  return yield* Effect.fail({ message: "Boom!" })
714
760
  },
715
761
  Effect.orElseSucceed(() => "recovered"), // we recover from the error here, so the final result is success
@@ -729,6 +775,64 @@ it.live("fail and recover with alt", () =>
729
775
  expect(toasts[0].message).toBe("Test Action Success")
730
776
  }))
731
777
 
778
+ it.effect("slow action shows waiting toast after the 1s delay", () =>
779
+ Effect
780
+ .gen(function*() {
781
+ const toasts: any[] = []
782
+ const Command = yield* useExperimentalE({ toasts, messages: DefaultIntl.en })
783
+
784
+ const command = Command.fn("Test Action")(
785
+ function*() {
786
+ // before 1s the waiting toast must NOT have surfaced yet
787
+ expect(toasts.length).toBe(0)
788
+ yield* Effect.sleep("1100 millis")
789
+ // after the delay window the waiting info toast should be visible
790
+ expect(toasts.length).toBe(1)
791
+ expect(toasts[0].type).toBe("info")
792
+ expect(toasts[0].message).toBe("Test Action executing...")
793
+ return "test-value"
794
+ },
795
+ Command.withDefaultToast()
796
+ )
797
+
798
+ const fiber = command.handle()
799
+ yield* TestClock.adjust("2 seconds")
800
+ const r = yield* unwrap(fiber)
801
+
802
+ expect(r).toBe("test-value")
803
+ // waiting toast is replaced (same id) with the success toast
804
+ expect(toasts.length).toBe(1)
805
+ expect(toasts[0].type).toBe("success")
806
+ expect(toasts[0].message).toBe("Test Action Success")
807
+ }))
808
+
809
+ it.effect("slow failing action surfaces waiting toast then shows error", () =>
810
+ Effect
811
+ .gen(function*() {
812
+ const toasts: any[] = []
813
+ const Command = yield* useExperimentalE({ toasts, messages: DefaultIntl.en })
814
+
815
+ const command = Command.fn("Test Action")(
816
+ function*() {
817
+ expect(toasts.length).toBe(0)
818
+ yield* Effect.sleep("1100 millis")
819
+ expect(toasts.length).toBe(1)
820
+ expect(toasts[0].type).toBe("info")
821
+ return yield* Effect.fail({ message: "Boom!" })
822
+ },
823
+ Command.withDefaultToast()
824
+ )
825
+
826
+ const fiber = command.handle()
827
+ yield* TestClock.adjust("2 seconds")
828
+ const r = yield* Fiber.join(fiber)
829
+
830
+ expect(Exit.isFailure(r) && Cause.hasFails(r.cause)).toBe(true)
831
+ expect(toasts.length).toBe(1)
832
+ expect(toasts[0].type).toBe("warning")
833
+ expect(toasts[0].message).toContain("Test Action Failed:\nBoom!")
834
+ }))
835
+
732
836
  it.live("defect with alt", () =>
733
837
  Effect
734
838
  .gen(function*() {
@@ -756,5 +860,58 @@ it.live("defect with alt", () =>
756
860
  expect(command.waiting).toBe(false)
757
861
  expect(Exit.isFailure(AsyncResult.toExit(command.result))).toBe(true)
758
862
  expect(toasts.length).toBe(1) // toast should show error
759
- expect(toasts[0].message).toBe("Test Action unexpected error, please try again shortly.")
863
+ expect(toasts[0].type).toBe("error")
864
+ expect(toasts[0].message).toContain("Test Action unexpected error, please try again shortly.")
760
865
  }))
866
+
867
+ describe("state-in-toast", () => {
868
+ it("works", () => {
869
+ const toasts: any[] = []
870
+ const removeMutation = Object.assign(
871
+ Effect.fn(function*(_item: string) {
872
+ yield* Effect.sleep(1000)
873
+ }),
874
+ { id: "remove_thing" }
875
+ )
876
+
877
+ const item = "x"
878
+
879
+ const Command = useExperimental({ toasts, messages: DefaultIntl.en })
880
+
881
+ Command.fn(removeMutation, {
882
+ state: () => ({ item }),
883
+ waitKey: (id) => `${id}.${item}`,
884
+ blockKey: () => `modify_thing.${item}`
885
+ // allowed: () => role.value === "admin"
886
+ })(
887
+ function*() {
888
+ // yield* Command.confirmOrInterrupt(yield* I18n.formatMessage({ id: "confirm.remove_item" }, { item }))
889
+ yield* removeMutation(item)
890
+ },
891
+ Command.withDefaultToast({
892
+ onSuccess: (a, b, c, d) => {
893
+ console.log("Success", { a, b, c, d })
894
+ expectTypeOf(d.state).toEqualTypeOf<{ readonly item: "x" }>()
895
+ }
896
+ })
897
+ )
898
+
899
+ Command.fn(removeMutation, {
900
+ state: () => ({ item }),
901
+ waitKey: (id) => `${id}.${item}`,
902
+ blockKey: () => `modify_thing.${item}`
903
+ // allowed: () => role.value === "admin"
904
+ })(
905
+ function*() {
906
+ // yield* Command.confirmOrInterrupt(yield* I18n.formatMessage({ id: "confirm.remove_item" }, { item }))
907
+ yield* removeMutation(item)
908
+ },
909
+ Command.withDefaultToast({
910
+ onSuccess: (a, b, c) => {
911
+ console.log("Success", { a, b, c })
912
+ expectTypeOf(c).toEqualTypeOf<undefined>()
913
+ }
914
+ })
915
+ )
916
+ })
917
+ })
@@ -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":"AACA,OAAO,KAAK,CAAC,MAAM,mBAAmB,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":""}