@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
@@ -0,0 +1,3406 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { reportMessage } from "@effect-app/vue/errorReporter"
3
+ import { deepToRaw, reportRuntimeError } from "@effect-app/vue/lib"
4
+ import { type MissingDependencies } from "@effect-app/vue/makeClient"
5
+ import { asResult, asStreamResult } from "@effect-app/vue/mutate"
6
+ import { SupportedErrors } from "effect-app/client"
7
+ import * as Context from "effect-app/Context"
8
+ import * as Effect from "effect-app/Effect"
9
+ import * as Layer from "effect-app/Layer"
10
+ import * as Option from "effect-app/Option"
11
+ import * as S from "effect-app/Schema"
12
+ import { isGeneratorFunction, wrapEffect } from "effect-app/utils"
13
+ import * as Cause from "effect/Cause"
14
+ import type * as Exit from "effect/Exit"
15
+ import type * as Fiber from "effect/Fiber"
16
+ import { flow } from "effect/Function"
17
+ import * as Match from "effect/Match"
18
+ import * as MutableHashMap from "effect/MutableHashMap"
19
+ import * as Predicate from "effect/Predicate"
20
+ import { type Refinement } from "effect/Predicate"
21
+ import * as Stream from "effect/Stream"
22
+ import * as AsyncResult from "effect/unstable/reactivity/AsyncResult"
23
+ import { type FormatXMLElementFn, type PrimitiveType } from "intl-messageformat"
24
+ import { computed, type ComputedRef, reactive, ref, toRaw } from "vue"
25
+ import { Confirm } from "./confirm.js"
26
+ import { I18n } from "./intl.js"
27
+ import { CurrentToastId, Toast } from "./toast.js"
28
+ import { WithToast } from "./withToast.js"
29
+
30
+ type IntlRecord = Record<string, PrimitiveType | FormatXMLElementFn<string, string>>
31
+
32
+ /**
33
+ * Progress information surfaced by a stream command. Either a plain text label
34
+ * or a `{ text, percentage }` pair when concrete progress is known.
35
+ */
36
+ export type Progress = string | { readonly text: string; readonly percentage: number }
37
+
38
+ type FnOptions<
39
+ Id extends string,
40
+ I18nCustomKey extends string,
41
+ State extends IntlRecord | undefined
42
+ > = {
43
+ i18nCustomKey?: I18nCustomKey
44
+ /**
45
+ * passed to the i18n formatMessage calls so you can use it in translation messagee
46
+ * including the Command `action` string.
47
+ * Automatically wrapped with Computed if just a thunk.
48
+ * provided as Command.state tag, so you can access it in the function.
49
+ */
50
+ state?: ComputedRef<State> | (() => State)
51
+ // TODO: namespaced keys like reactivity keys: ["modify_thing", item], so that one can block also on "modify_thing" *
52
+ blockKey?: (id: Id) => string | undefined
53
+ waitKey?: (id: Id) => string | undefined
54
+ allowed?: (id: Id, state: ComputedRef<State>) => boolean
55
+ }
56
+
57
+ type FnOptionsInternal<I18nCustomKey extends string> = {
58
+ i18nCustomKey?: I18nCustomKey | undefined
59
+ state?: IntlRecord | undefined
60
+ }
61
+
62
+ export const DefaultIntl = {
63
+ de: {
64
+ "handle.confirmation": "{action} bestätigen?",
65
+ "handle.waiting": "{action} wird ausgeführt...",
66
+ "handle.success": "{action} erfolgreich",
67
+ "handle.with_errors": "{action} fehlgeschlagen",
68
+ "handle.with_warnings": "{action} erfolgreich, mit Warnungen",
69
+ "handle.error_response":
70
+ "Die Anfrage war nicht erfolgreich:\n{error}\nWir wurden benachrichtigt und werden das Problem in Kürze beheben.",
71
+ "handle.response_error": "Die Antwort konnte nicht verarbeitet werden:\n{error}",
72
+ "handle.request_error": "Die Anfrage konnte nicht gesendet werden:\n{error}",
73
+ "handle.unexpected_error2": "{action} unerwarteter Fehler, probieren sie es in kurze nochmals.",
74
+
75
+ "handle.unexpected_error": "Unerwarteter Fehler:\n{error}",
76
+ "handle.not_found": "Das gesuchte war nicht gefunden"
77
+ },
78
+ en: {
79
+ "handle.confirmation": "Confirm {action}?",
80
+ "handle.waiting": "{action} executing...",
81
+ "handle.success": "{action} Success",
82
+ "handle.with_errors": "{action} Failed",
83
+ "handle.with_warnings": "{action}, with warnings",
84
+ "handle.error_response":
85
+ "There was an error in processing the response:\n{error}\nWe have been notified and will fix the problem shortly.",
86
+ "handle.request_error": "There was an error in the request:\n{error}",
87
+ "handle.response_error": "The request was not successful:\n{error}",
88
+ "handle.unexpected_error2": "{action} unexpected error, please try again shortly.",
89
+
90
+ "handle.unexpected_error": "Unexpected Error:\n{error}",
91
+ "handle.not_found": "The requested item was not found."
92
+ }
93
+ }
94
+
95
+ export class CommandContext extends Context.Service<CommandContext, {
96
+ id: string
97
+ i18nKey: string
98
+ action: string
99
+ label: string
100
+ namespace: string
101
+ namespaced: (key: string) => string
102
+ state?: IntlRecord | undefined
103
+ }>()(
104
+ "CommandContext"
105
+ ) {}
106
+
107
+ /**
108
+ * Service available inside `streamFn` stream handlers that lets you imperatively push
109
+ * progress updates to the command's reactive `progress` ref.
110
+ *
111
+ * Use `Command.mapProgress(fn)` or `Command.updateProgress(progress)` to interact with this service.
112
+ *
113
+ * @example
114
+ * ```ts
115
+ * // Using mapProgress (recommended) — applied as a stream pipe operator:
116
+ * const exportCmd = Command.streamFn("exportData")(
117
+ * function*(arg, ctx) {
118
+ * return makeExportStream(arg.id).pipe(
119
+ * Command.mapProgress((r) =>
120
+ * AsyncResult.isSuccess(r) && r.value._tag === "OperationProgress"
121
+ * ? { text: `${r.value.completed}/${r.value.total}`, percentage: r.value.completed / r.value.total * 100 }
122
+ * : undefined
123
+ * )
124
+ * )
125
+ * }
126
+ * )
127
+ * // exportCmd.progress is updated for every OperationProgress event
128
+ * ```
129
+ */
130
+ export class CommandProgress extends Context.Reference<{
131
+ readonly update: (progress: Progress | undefined) => Effect.Effect<void>
132
+ }>("Commander.CommandProgress", {
133
+ defaultValue: () => ({ update: (_progress: Progress | undefined): Effect.Effect<void> => Effect.void })
134
+ }) {}
135
+
136
+ export type EmitWithCallback<A, Event extends string> = (event: Event, value: A, onDone: () => void) => void
137
+
138
+ /**
139
+ * Use to wrap emit calls with a callback to signal completion.
140
+ * Useful when the publisher wants to wait for the subscriber to finish processing.
141
+ */
142
+ export const wrapEmit = <A, Event extends string>(
143
+ emit: EmitWithCallback<A, NoInfer<Event>>,
144
+ event: Event
145
+ ) =>
146
+ (value: A) => new Promise<void>((resolve) => emit(event, value, resolve))
147
+
148
+ export declare namespace Commander {
149
+ export type IntlRecord = Record<string, PrimitiveType | FormatXMLElementFn<string, string>>
150
+ export type FnOptions<
151
+ Id extends string,
152
+ I18nKey extends string,
153
+ State extends IntlRecord | undefined
154
+ > = {
155
+ i18nCustomKey?: I18nKey
156
+ state?: ComputedRef<State> | (() => State)
157
+ blockKey?: (id: Id) => string | undefined
158
+ waitKey?: (id: Id) => string | undefined
159
+ allowed?: (id: Id, state: ComputedRef<State>) => boolean
160
+ }
161
+
162
+ export type CommanderBase<RT, Id extends string, I18nKey extends string, State extends IntlRecord | undefined> =
163
+ & Gen<RT, Id, I18nKey, State>
164
+ & NonGen<RT, Id, I18nKey, State>
165
+ & CommandContextLocal<Id, I18nKey>
166
+ & {
167
+ state: Context.Service<`Commander.Command.${Id}.state`, State>
168
+ }
169
+
170
+ export type CommanderFn<RT, Id extends string, I18nKey extends string, State extends IntlRecord | undefined> =
171
+ CommanderBase<RT, Id, I18nKey, State>
172
+
173
+ export type CommanderWrap<
174
+ RT,
175
+ Id extends string,
176
+ I18nCustomKey extends string,
177
+ State extends IntlRecord | undefined,
178
+ I,
179
+ A,
180
+ E,
181
+ R
182
+ > =
183
+ & CommandContextLocal<Id, I18nCustomKey>
184
+ & GenWrap<RT, Id, I18nCustomKey, I, A, E, R, State>
185
+ & NonGenWrap<RT, Id, I18nCustomKey, I, A, E, R, State>
186
+ & {
187
+ state: Context.Service<`Commander.Command.${Id}.state`, State>
188
+ }
189
+
190
+ export interface CommandContextLocal<Id extends string, I18nKey extends string> {
191
+ id: Id
192
+ i18nKey: I18nKey
193
+ namespace: `action.${I18nKey}`
194
+ namespaced: <K extends string>(k: K) => `action.${I18nKey}.${K}`
195
+ }
196
+
197
+ export interface CommandProps<
198
+ A,
199
+ E,
200
+ Id extends string,
201
+ I18nKey extends string,
202
+ State extends IntlRecord | undefined
203
+ > extends CommandContextLocal<Id, I18nKey> {
204
+ /** reactive */
205
+ action: string
206
+ /** reactive */
207
+ label: string
208
+ /** reactive */
209
+ result: AsyncResult.AsyncResult<A, E>
210
+ /**
211
+ * reactive – formatted progress info driven by `Command.mapProgress` or `Command.updateProgress`
212
+ * inside a `streamFn` handler. Undefined for non-stream commands.
213
+ */
214
+ progress: Progress | undefined
215
+ /** reactive */
216
+ waiting: boolean
217
+ /** reactive */
218
+ blocked: boolean
219
+ /** reactive */
220
+ allowed: boolean
221
+ /** reactive */
222
+ state: State
223
+ }
224
+
225
+ export interface CommandOut<
226
+ Arg,
227
+ A,
228
+ E,
229
+ R,
230
+ Id extends string,
231
+ I18nKey extends string,
232
+ State extends IntlRecord | undefined
233
+ > extends CommandProps<A, E, Id, I18nKey, State> {
234
+ new(): {}
235
+
236
+ /** click handlers */
237
+ handle: ((arg: Arg) => Fiber.Fiber<Exit.Exit<A, E>>) & {
238
+ /** @deprecated don't exist */
239
+ effect: (arg: Arg) => Effect.Effect<A, E, R>
240
+ }
241
+
242
+ // // TODO: if we keep them, it would probably be nicer as an option api, deciding the return value like in Atom?
243
+ // /** @experimental */
244
+ // compose: (arg: Arg) => Effect.Effect<Exit.Exit<A, E>, R>
245
+ // /** @experimental */
246
+ // compose2: (arg: Arg) => Effect.Effect<A, E, R>
247
+ // /**
248
+ // * @experimental
249
+ // * captures the current span and returns an Effect that when run will execute the command
250
+ // */
251
+ // handleEffect: (arg: Arg) => Effect.Effect<Fiber.Fiber<Exit.Exit<A, E>, never>>
252
+ // /**
253
+ // * @experimental
254
+ // */
255
+ // exec: (arg: Arg) => Effect.Effect<Exit.Exit<A, E>, never, Exclude<R, CommandContext>>
256
+ }
257
+
258
+ export interface CommandContextLocal2<Id extends string, I18nKey extends string, State extends IntlRecord | undefined>
259
+ extends CommandContextLocal<Id, I18nKey>
260
+ {
261
+ state: State
262
+ }
263
+
264
+ type ArgForCombinator<Arg> = [Arg] extends [void] ? undefined : NoInfer<Arg>
265
+
266
+ type CommandOutHelper<
267
+ Arg,
268
+ Eff extends Effect.Effect<any, any, any>,
269
+ Id extends string,
270
+ I18nKey extends string,
271
+ State extends IntlRecord | undefined
272
+ > = CommandOut<
273
+ Arg,
274
+ Effect.Success<Eff>,
275
+ Effect.Error<Eff>,
276
+ Effect.Services<Eff>,
277
+ Id,
278
+ I18nKey,
279
+ State
280
+ >
281
+
282
+ export type Gen<RT, Id extends string, I18nKey extends string, State extends IntlRecord | undefined> = {
283
+ <
284
+ Eff extends Effect.Yieldable<any, any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
285
+ AEff,
286
+ Arg = void
287
+ >(
288
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => Generator<Eff, AEff, never>
289
+ ): CommandOut<
290
+ Arg,
291
+ AEff,
292
+ [Eff] extends [never] ? never
293
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer E, infer _R>] ? E
294
+ : never,
295
+ [Eff] extends [never] ? never
296
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer _E, infer R>] ? R
297
+ : never,
298
+ Id,
299
+ I18nKey,
300
+ State
301
+ >
302
+ <
303
+ Eff extends Effect.Yieldable<any, any, any, any>,
304
+ AEff,
305
+ A extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
306
+ Arg = void
307
+ >(
308
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => Generator<Eff, AEff, never>,
309
+ a: (
310
+ _: Effect.Effect<
311
+ AEff,
312
+ [Eff] extends [never] ? never
313
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer E, infer _R>] ? E
314
+ : never,
315
+ [Eff] extends [never] ? never
316
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer _E, infer R>] ? R
317
+ : never
318
+ >,
319
+ arg: ArgForCombinator<Arg>,
320
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
321
+ ) => A
322
+ ): CommandOutHelper<Arg, A, Id, I18nKey, State>
323
+ <
324
+ Eff extends Effect.Yieldable<any, any, any, any>,
325
+ AEff,
326
+ A,
327
+ B extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
328
+ Arg = void
329
+ >(
330
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => Generator<Eff, AEff, never>,
331
+ a: (
332
+ _: Effect.Effect<
333
+ AEff,
334
+ [Eff] extends [never] ? never
335
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer E, infer _R>] ? E
336
+ : never,
337
+ [Eff] extends [never] ? never
338
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer _E, infer R>] ? R
339
+ : never
340
+ >,
341
+ arg: ArgForCombinator<Arg>,
342
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
343
+ ) => A,
344
+ b: (
345
+ _: A,
346
+ arg: ArgForCombinator<Arg>,
347
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
348
+ ) => B
349
+ ): CommandOutHelper<Arg, B, Id, I18nKey, State>
350
+ <
351
+ Eff extends Effect.Yieldable<any, any, any, any>,
352
+ AEff,
353
+ A,
354
+ B,
355
+ C extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
356
+ Arg = void
357
+ >(
358
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => Generator<Eff, AEff, never>,
359
+ a: (
360
+ _: Effect.Effect<
361
+ AEff,
362
+ [Eff] extends [never] ? never
363
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer E, infer _R>] ? E
364
+ : never,
365
+ [Eff] extends [never] ? never
366
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer _E, infer R>] ? R
367
+ : never
368
+ >,
369
+ arg: ArgForCombinator<Arg>,
370
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
371
+ ) => A,
372
+ b: (
373
+ _: A,
374
+ arg: ArgForCombinator<Arg>,
375
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
376
+ ) => B,
377
+ c: (
378
+ _: B,
379
+ arg: ArgForCombinator<Arg>,
380
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
381
+ ) => C
382
+ ): CommandOutHelper<Arg, C, Id, I18nKey, State>
383
+ <
384
+ Eff extends Effect.Yieldable<any, any, any, any>,
385
+ AEff,
386
+ A,
387
+ B,
388
+ C,
389
+ D extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
390
+ Arg = void
391
+ >(
392
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => Generator<Eff, AEff, never>,
393
+ a: (
394
+ _: Effect.Effect<
395
+ AEff,
396
+ [Eff] extends [never] ? never
397
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer E, infer _R>] ? E
398
+ : never,
399
+ [Eff] extends [never] ? never
400
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer _E, infer R>] ? R
401
+ : never
402
+ >,
403
+ arg: ArgForCombinator<Arg>,
404
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
405
+ ) => A,
406
+ b: (
407
+ _: A,
408
+ arg: ArgForCombinator<Arg>,
409
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
410
+ ) => B,
411
+ c: (
412
+ _: B,
413
+ arg: ArgForCombinator<Arg>,
414
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
415
+ ) => C,
416
+ d: (
417
+ _: C,
418
+ arg: ArgForCombinator<Arg>,
419
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
420
+ ) => D
421
+ ): CommandOutHelper<Arg, D, Id, I18nKey, State>
422
+ <
423
+ Eff extends Effect.Yieldable<any, any, any, any>,
424
+ AEff,
425
+ A,
426
+ B,
427
+ C,
428
+ D,
429
+ E extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
430
+ Arg = void
431
+ >(
432
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => Generator<Eff, AEff, never>,
433
+ a: (
434
+ _: Effect.Effect<
435
+ AEff,
436
+ [Eff] extends [never] ? never
437
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer E, infer _R>] ? E
438
+ : never,
439
+ [Eff] extends [never] ? never
440
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer _E, infer R>] ? R
441
+ : never
442
+ >,
443
+ arg: ArgForCombinator<Arg>,
444
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
445
+ ) => A,
446
+ b: (
447
+ _: A,
448
+ arg: ArgForCombinator<Arg>,
449
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
450
+ ) => B,
451
+ c: (
452
+ _: B,
453
+ arg: ArgForCombinator<Arg>,
454
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
455
+ ) => C,
456
+ d: (
457
+ _: C,
458
+ arg: ArgForCombinator<Arg>,
459
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
460
+ ) => D,
461
+ e: (
462
+ _: D,
463
+ arg: ArgForCombinator<Arg>,
464
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
465
+ ) => E
466
+ ): CommandOutHelper<Arg, E, Id, I18nKey, State>
467
+ <
468
+ Eff extends Effect.Yieldable<any, any, any, any>,
469
+ AEff,
470
+ A,
471
+ B,
472
+ C,
473
+ D,
474
+ E,
475
+ F extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
476
+ Arg = void
477
+ >(
478
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => Generator<Eff, AEff, never>,
479
+ a: (
480
+ _: Effect.Effect<
481
+ AEff,
482
+ [Eff] extends [never] ? never
483
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer E, infer _R>] ? E
484
+ : never,
485
+ [Eff] extends [never] ? never
486
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer _E, infer R>] ? R
487
+ : never
488
+ >,
489
+ arg: ArgForCombinator<Arg>,
490
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
491
+ ) => A,
492
+ b: (
493
+ _: A,
494
+ arg: ArgForCombinator<Arg>,
495
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
496
+ ) => B,
497
+ c: (
498
+ _: B,
499
+ arg: ArgForCombinator<Arg>,
500
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
501
+ ) => C,
502
+ d: (
503
+ _: C,
504
+ arg: ArgForCombinator<Arg>,
505
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
506
+ ) => D,
507
+ e: (
508
+ _: D,
509
+ arg: ArgForCombinator<Arg>,
510
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
511
+ ) => E,
512
+ f: (
513
+ _: E,
514
+ arg: ArgForCombinator<Arg>,
515
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
516
+ ) => F
517
+ ): CommandOutHelper<Arg, F, Id, I18nKey, State>
518
+ <
519
+ Eff extends Effect.Yieldable<any, any, any, any>,
520
+ AEff,
521
+ A,
522
+ B,
523
+ C,
524
+ D,
525
+ E,
526
+ F,
527
+ G extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
528
+ Arg = void
529
+ >(
530
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => Generator<Eff, AEff, never>,
531
+ a: (
532
+ _: Effect.Effect<
533
+ AEff,
534
+ [Eff] extends [never] ? never
535
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer E, infer _R>] ? E
536
+ : never,
537
+ [Eff] extends [never] ? never
538
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer _E, infer R>] ? R
539
+ : never
540
+ >,
541
+ arg: ArgForCombinator<Arg>,
542
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
543
+ ) => A,
544
+ b: (
545
+ _: A,
546
+ arg: ArgForCombinator<Arg>,
547
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
548
+ ) => B,
549
+ c: (
550
+ _: B,
551
+ arg: ArgForCombinator<Arg>,
552
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
553
+ ) => C,
554
+ d: (
555
+ _: C,
556
+ arg: ArgForCombinator<Arg>,
557
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
558
+ ) => D,
559
+ e: (
560
+ _: D,
561
+ arg: ArgForCombinator<Arg>,
562
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
563
+ ) => E,
564
+ f: (
565
+ _: E,
566
+ arg: ArgForCombinator<Arg>,
567
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
568
+ ) => F,
569
+ g: (
570
+ _: F,
571
+ arg: ArgForCombinator<Arg>,
572
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
573
+ ) => G
574
+ ): CommandOutHelper<Arg, G, Id, I18nKey, State>
575
+ <
576
+ Eff extends Effect.Yieldable<any, any, any, any>,
577
+ AEff,
578
+ A,
579
+ B,
580
+ C,
581
+ D,
582
+ E,
583
+ F,
584
+ G,
585
+ H extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
586
+ Arg = void
587
+ >(
588
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => Generator<Eff, AEff, never>,
589
+ a: (
590
+ _: Effect.Effect<
591
+ AEff,
592
+ [Eff] extends [never] ? never
593
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer E, infer _R>] ? E
594
+ : never,
595
+ [Eff] extends [never] ? never
596
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer _E, infer R>] ? R
597
+ : never
598
+ >,
599
+ arg: ArgForCombinator<Arg>,
600
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
601
+ ) => A,
602
+ b: (
603
+ _: A,
604
+ arg: ArgForCombinator<Arg>,
605
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
606
+ ) => B,
607
+ c: (
608
+ _: B,
609
+ arg: ArgForCombinator<Arg>,
610
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
611
+ ) => C,
612
+ d: (
613
+ _: C,
614
+ arg: ArgForCombinator<Arg>,
615
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
616
+ ) => D,
617
+ e: (
618
+ _: D,
619
+ arg: ArgForCombinator<Arg>,
620
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
621
+ ) => E,
622
+ f: (
623
+ _: E,
624
+ arg: ArgForCombinator<Arg>,
625
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
626
+ ) => F,
627
+ g: (
628
+ _: F,
629
+ arg: ArgForCombinator<Arg>,
630
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
631
+ ) => G,
632
+ h: (
633
+ _: G,
634
+ arg: ArgForCombinator<Arg>,
635
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
636
+ ) => H
637
+ ): CommandOutHelper<Arg, H, Id, I18nKey, State>
638
+ <
639
+ Eff extends Effect.Yieldable<any, any, any, any>,
640
+ AEff,
641
+ A,
642
+ B,
643
+ C,
644
+ D,
645
+ E,
646
+ F,
647
+ G,
648
+ H,
649
+ I extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
650
+ Arg = void
651
+ >(
652
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => Generator<Eff, AEff, never>,
653
+ a: (
654
+ _: Effect.Effect<
655
+ AEff,
656
+ [Eff] extends [never] ? never
657
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer E, infer _R>] ? E
658
+ : never,
659
+ [Eff] extends [never] ? never
660
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer _E, infer R>] ? R
661
+ : never
662
+ >,
663
+ arg: ArgForCombinator<Arg>,
664
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
665
+ ) => A,
666
+ b: (
667
+ _: A,
668
+ arg: ArgForCombinator<Arg>,
669
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
670
+ ) => B,
671
+ c: (
672
+ _: B,
673
+ arg: ArgForCombinator<Arg>,
674
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
675
+ ) => C,
676
+ d: (
677
+ _: C,
678
+ arg: ArgForCombinator<Arg>,
679
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
680
+ ) => D,
681
+ e: (
682
+ _: D,
683
+ arg: ArgForCombinator<Arg>,
684
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
685
+ ) => E,
686
+ f: (
687
+ _: E,
688
+ arg: ArgForCombinator<Arg>,
689
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
690
+ ) => F,
691
+ g: (
692
+ _: F,
693
+ arg: ArgForCombinator<Arg>,
694
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
695
+ ) => G,
696
+ h: (
697
+ _: G,
698
+ arg: ArgForCombinator<Arg>,
699
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
700
+ ) => H,
701
+ i: (
702
+ _: H,
703
+ arg: ArgForCombinator<Arg>,
704
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
705
+ ) => I
706
+ ): CommandOutHelper<Arg, I, Id, I18nKey, State>
707
+ }
708
+
709
+ export type NonGen<RT, Id extends string, I18nKey extends string, State extends IntlRecord | undefined> = {
710
+ <
711
+ Eff extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
712
+ Arg = void
713
+ >(
714
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => Eff
715
+ ): CommandOutHelper<Arg, Eff, Id, I18nKey, State>
716
+ <
717
+ Eff extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
718
+ A,
719
+ Arg = void
720
+ >(
721
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => A,
722
+ a: (
723
+ _: A,
724
+ arg: ArgForCombinator<Arg>,
725
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
726
+ ) => Eff
727
+ ): CommandOutHelper<Arg, Eff, Id, I18nKey, State>
728
+ <
729
+ Eff extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
730
+ A,
731
+ B,
732
+ Arg = void
733
+ >(
734
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => A,
735
+ a: (
736
+ _: A,
737
+ arg: ArgForCombinator<Arg>,
738
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
739
+ ) => B,
740
+ b: (
741
+ _: B,
742
+ arg: ArgForCombinator<Arg>,
743
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
744
+ ) => Eff
745
+ ): CommandOutHelper<Arg, Eff, Id, I18nKey, State>
746
+ <
747
+ Eff extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
748
+ A,
749
+ B,
750
+ C,
751
+ Arg = void
752
+ >(
753
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => A,
754
+ a: (
755
+ _: A,
756
+ arg: ArgForCombinator<Arg>,
757
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
758
+ ) => B,
759
+ b: (
760
+ _: B,
761
+ arg: ArgForCombinator<Arg>,
762
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
763
+ ) => C,
764
+ c: (
765
+ _: C,
766
+ arg: ArgForCombinator<Arg>,
767
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
768
+ ) => Eff
769
+ ): CommandOutHelper<Arg, Eff, Id, I18nKey, State>
770
+ <
771
+ Eff extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
772
+ A,
773
+ B,
774
+ C,
775
+ D,
776
+ Arg = void
777
+ >(
778
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => A,
779
+ a: (
780
+ _: A,
781
+ arg: ArgForCombinator<Arg>,
782
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
783
+ ) => B,
784
+ b: (
785
+ _: B,
786
+ arg: ArgForCombinator<Arg>,
787
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
788
+ ) => C,
789
+ c: (
790
+ _: C,
791
+ arg: ArgForCombinator<Arg>,
792
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
793
+ ) => D,
794
+ d: (
795
+ _: D,
796
+ arg: ArgForCombinator<Arg>,
797
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
798
+ ) => Eff
799
+ ): CommandOutHelper<Arg, Eff, Id, I18nKey, State>
800
+ <
801
+ Eff extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
802
+ A,
803
+ B,
804
+ C,
805
+ D,
806
+ E,
807
+ Arg = void
808
+ >(
809
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => A,
810
+ a: (
811
+ _: A,
812
+ arg: ArgForCombinator<Arg>,
813
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
814
+ ) => B,
815
+ b: (
816
+ _: B,
817
+ arg: ArgForCombinator<Arg>,
818
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
819
+ ) => C,
820
+ c: (
821
+ _: C,
822
+ arg: ArgForCombinator<Arg>,
823
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
824
+ ) => D,
825
+ d: (
826
+ _: D,
827
+ arg: ArgForCombinator<Arg>,
828
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
829
+ ) => E,
830
+ e: (
831
+ _: E,
832
+ arg: ArgForCombinator<Arg>,
833
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
834
+ ) => Eff
835
+ ): CommandOutHelper<Arg, Eff, Id, I18nKey, State>
836
+ <
837
+ Eff extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
838
+ A,
839
+ B,
840
+ C,
841
+ D,
842
+ E,
843
+ F,
844
+ Arg = void
845
+ >(
846
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => A,
847
+ a: (
848
+ _: A,
849
+ arg: ArgForCombinator<Arg>,
850
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
851
+ ) => B,
852
+ b: (
853
+ _: B,
854
+ arg: ArgForCombinator<Arg>,
855
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
856
+ ) => C,
857
+ c: (
858
+ _: C,
859
+ arg: ArgForCombinator<Arg>,
860
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
861
+ ) => D,
862
+ d: (
863
+ _: D,
864
+ arg: ArgForCombinator<Arg>,
865
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
866
+ ) => E,
867
+ e: (
868
+ _: E,
869
+ arg: ArgForCombinator<Arg>,
870
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
871
+ ) => F,
872
+ f: (
873
+ _: F,
874
+ arg: ArgForCombinator<Arg>,
875
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
876
+ ) => Eff
877
+ ): CommandOutHelper<Arg, Eff, Id, I18nKey, State>
878
+ <
879
+ Eff extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
880
+ A,
881
+ B,
882
+ C,
883
+ D,
884
+ E,
885
+ F,
886
+ G,
887
+ Arg = void
888
+ >(
889
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => A,
890
+ a: (
891
+ _: A,
892
+ arg: ArgForCombinator<Arg>,
893
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
894
+ ) => B,
895
+ b: (
896
+ _: B,
897
+ arg: ArgForCombinator<Arg>,
898
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
899
+ ) => C,
900
+ c: (
901
+ _: C,
902
+ arg: ArgForCombinator<Arg>,
903
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
904
+ ) => D,
905
+ d: (
906
+ _: D,
907
+ arg: ArgForCombinator<Arg>,
908
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
909
+ ) => E,
910
+ e: (
911
+ _: E,
912
+ arg: ArgForCombinator<Arg>,
913
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
914
+ ) => F,
915
+ f: (
916
+ _: F,
917
+ arg: ArgForCombinator<Arg>,
918
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
919
+ ) => G,
920
+ g: (
921
+ _: G,
922
+ arg: ArgForCombinator<Arg>,
923
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
924
+ ) => Eff
925
+ ): CommandOutHelper<Arg, Eff, Id, I18nKey, State>
926
+ <
927
+ Eff extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
928
+ A,
929
+ B,
930
+ C,
931
+ D,
932
+ E,
933
+ F,
934
+ G,
935
+ H,
936
+ Arg = void
937
+ >(
938
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => A,
939
+ a: (
940
+ _: A,
941
+ arg: ArgForCombinator<Arg>,
942
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
943
+ ) => B,
944
+ b: (
945
+ _: B,
946
+ arg: ArgForCombinator<Arg>,
947
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
948
+ ) => C,
949
+ c: (
950
+ _: C,
951
+ arg: ArgForCombinator<Arg>,
952
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
953
+ ) => D,
954
+ d: (
955
+ _: D,
956
+ arg: ArgForCombinator<Arg>,
957
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
958
+ ) => E,
959
+ e: (
960
+ _: E,
961
+ arg: ArgForCombinator<Arg>,
962
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
963
+ ) => F,
964
+ f: (
965
+ _: F,
966
+ arg: ArgForCombinator<Arg>,
967
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
968
+ ) => G,
969
+ g: (
970
+ _: G,
971
+ arg: ArgForCombinator<Arg>,
972
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
973
+ ) => H,
974
+ h: (
975
+ _: H,
976
+ arg: ArgForCombinator<Arg>,
977
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
978
+ ) => Eff
979
+ ): CommandOutHelper<Arg, Eff, Id, I18nKey, State>
980
+ <
981
+ Eff extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
982
+ A,
983
+ B,
984
+ C,
985
+ D,
986
+ E,
987
+ F,
988
+ G,
989
+ H,
990
+ I,
991
+ Arg = void
992
+ >(
993
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => A,
994
+ a: (
995
+ _: A,
996
+ arg: ArgForCombinator<Arg>,
997
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
998
+ ) => B,
999
+ b: (
1000
+ _: B,
1001
+ arg: ArgForCombinator<Arg>,
1002
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1003
+ ) => C,
1004
+ c: (
1005
+ _: C,
1006
+ arg: ArgForCombinator<Arg>,
1007
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1008
+ ) => D,
1009
+ d: (
1010
+ _: D,
1011
+ arg: ArgForCombinator<Arg>,
1012
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1013
+ ) => E,
1014
+ e: (
1015
+ _: E,
1016
+ arg: ArgForCombinator<Arg>,
1017
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1018
+ ) => F,
1019
+ f: (
1020
+ _: F,
1021
+ arg: ArgForCombinator<Arg>,
1022
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1023
+ ) => G,
1024
+ g: (
1025
+ _: G,
1026
+ arg: ArgForCombinator<Arg>,
1027
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1028
+ ) => H,
1029
+ h: (
1030
+ _: H,
1031
+ arg: ArgForCombinator<Arg>,
1032
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1033
+ ) => I,
1034
+ i: (
1035
+ _: H,
1036
+ arg: ArgForCombinator<Arg>,
1037
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1038
+ ) => Eff
1039
+ ): CommandOutHelper<Arg, Eff, Id, I18nKey, State>
1040
+ }
1041
+
1042
+ export type GenWrap<
1043
+ RT,
1044
+ Id extends string,
1045
+ I18nKey extends string,
1046
+ Arg,
1047
+ AEff,
1048
+ EEff,
1049
+ REff,
1050
+ State extends IntlRecord | undefined
1051
+ > = {
1052
+ (): Exclude<REff, RT> extends never ? CommandOut<
1053
+ Arg,
1054
+ AEff,
1055
+ EEff,
1056
+ REff,
1057
+ Id,
1058
+ I18nKey,
1059
+ State
1060
+ >
1061
+ : MissingDependencies<RT, REff> & {}
1062
+ <
1063
+ A extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>
1064
+ >(
1065
+ a: (
1066
+ _: Effect.Effect<
1067
+ AEff,
1068
+ EEff,
1069
+ REff
1070
+ >,
1071
+ arg: ArgForCombinator<Arg>,
1072
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1073
+ ) => A
1074
+ ): CommandOutHelper<Arg, A, Id, I18nKey, State>
1075
+ <
1076
+ A,
1077
+ B extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>
1078
+ >(
1079
+ a: (
1080
+ _: Effect.Effect<
1081
+ AEff,
1082
+ EEff,
1083
+ REff
1084
+ >,
1085
+ arg: ArgForCombinator<Arg>,
1086
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1087
+ ) => A,
1088
+ b: (
1089
+ _: A,
1090
+ arg: ArgForCombinator<Arg>,
1091
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1092
+ ) => B
1093
+ ): CommandOutHelper<Arg, B, Id, I18nKey, State>
1094
+ <
1095
+ A,
1096
+ B,
1097
+ C extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>
1098
+ >(
1099
+ a: (
1100
+ _: Effect.Effect<
1101
+ AEff,
1102
+ EEff,
1103
+ REff
1104
+ >,
1105
+ arg: ArgForCombinator<Arg>,
1106
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1107
+ ) => A,
1108
+ b: (
1109
+ _: A,
1110
+ arg: ArgForCombinator<Arg>,
1111
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1112
+ ) => B,
1113
+ c: (
1114
+ _: B,
1115
+ arg: ArgForCombinator<Arg>,
1116
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1117
+ ) => C
1118
+ ): CommandOutHelper<Arg, C, Id, I18nKey, State>
1119
+ <
1120
+ A,
1121
+ B,
1122
+ C,
1123
+ D extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>
1124
+ >(
1125
+ a: (
1126
+ _: Effect.Effect<
1127
+ AEff,
1128
+ EEff,
1129
+ REff
1130
+ >,
1131
+ arg: ArgForCombinator<Arg>,
1132
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1133
+ ) => A,
1134
+ b: (
1135
+ _: A,
1136
+ arg: ArgForCombinator<Arg>,
1137
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1138
+ ) => B,
1139
+ c: (
1140
+ _: B,
1141
+ arg: ArgForCombinator<Arg>,
1142
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1143
+ ) => C,
1144
+ d: (
1145
+ _: C,
1146
+ arg: ArgForCombinator<Arg>,
1147
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1148
+ ) => D
1149
+ ): CommandOutHelper<Arg, D, Id, I18nKey, State>
1150
+ <
1151
+ A,
1152
+ B,
1153
+ C,
1154
+ D,
1155
+ E extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>
1156
+ >(
1157
+ a: (
1158
+ _: Effect.Effect<
1159
+ AEff,
1160
+ EEff,
1161
+ REff
1162
+ >,
1163
+ arg: ArgForCombinator<Arg>,
1164
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1165
+ ) => A,
1166
+ b: (
1167
+ _: A,
1168
+ arg: ArgForCombinator<Arg>,
1169
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1170
+ ) => B,
1171
+ c: (
1172
+ _: B,
1173
+ arg: ArgForCombinator<Arg>,
1174
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1175
+ ) => C,
1176
+ d: (
1177
+ _: C,
1178
+ arg: ArgForCombinator<Arg>,
1179
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1180
+ ) => D,
1181
+ e: (
1182
+ _: D,
1183
+ arg: ArgForCombinator<Arg>,
1184
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1185
+ ) => E
1186
+ ): CommandOutHelper<Arg, E, Id, I18nKey, State>
1187
+ <
1188
+ A,
1189
+ B,
1190
+ C,
1191
+ D,
1192
+ E,
1193
+ F extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>
1194
+ >(
1195
+ a: (
1196
+ _: Effect.Effect<
1197
+ AEff,
1198
+ EEff,
1199
+ REff
1200
+ >,
1201
+ arg: ArgForCombinator<Arg>,
1202
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1203
+ ) => A,
1204
+ b: (
1205
+ _: A,
1206
+ arg: ArgForCombinator<Arg>,
1207
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1208
+ ) => B,
1209
+ c: (
1210
+ _: B,
1211
+ arg: ArgForCombinator<Arg>,
1212
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1213
+ ) => C,
1214
+ d: (
1215
+ _: C,
1216
+ arg: ArgForCombinator<Arg>,
1217
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1218
+ ) => D,
1219
+ e: (
1220
+ _: D,
1221
+ arg: ArgForCombinator<Arg>,
1222
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1223
+ ) => E,
1224
+ f: (
1225
+ _: E,
1226
+ arg: ArgForCombinator<Arg>,
1227
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1228
+ ) => F
1229
+ ): CommandOutHelper<Arg, F, Id, I18nKey, State>
1230
+ <
1231
+ A,
1232
+ B,
1233
+ C,
1234
+ D,
1235
+ E,
1236
+ F,
1237
+ G extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>
1238
+ >(
1239
+ a: (
1240
+ _: Effect.Effect<
1241
+ AEff,
1242
+ EEff,
1243
+ REff
1244
+ >,
1245
+ arg: ArgForCombinator<Arg>,
1246
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1247
+ ) => A,
1248
+ b: (
1249
+ _: A,
1250
+ arg: ArgForCombinator<Arg>,
1251
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1252
+ ) => B,
1253
+ c: (
1254
+ _: B,
1255
+ arg: ArgForCombinator<Arg>,
1256
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1257
+ ) => C,
1258
+ d: (
1259
+ _: C,
1260
+ arg: ArgForCombinator<Arg>,
1261
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1262
+ ) => D,
1263
+ e: (
1264
+ _: D,
1265
+ arg: ArgForCombinator<Arg>,
1266
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1267
+ ) => E,
1268
+ f: (
1269
+ _: E,
1270
+ arg: ArgForCombinator<Arg>,
1271
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1272
+ ) => F,
1273
+ g: (
1274
+ _: F,
1275
+ arg: ArgForCombinator<Arg>,
1276
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1277
+ ) => G
1278
+ ): CommandOutHelper<Arg, G, Id, I18nKey, State>
1279
+ <A, B, C, D, E, F, G, H extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>>(
1280
+ a: (
1281
+ _: Effect.Effect<
1282
+ AEff,
1283
+ EEff,
1284
+ REff
1285
+ >,
1286
+ arg: ArgForCombinator<Arg>,
1287
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1288
+ ) => A,
1289
+ b: (
1290
+ _: A,
1291
+ arg: ArgForCombinator<Arg>,
1292
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1293
+ ) => B,
1294
+ c: (
1295
+ _: B,
1296
+ arg: ArgForCombinator<Arg>,
1297
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1298
+ ) => C,
1299
+ d: (
1300
+ _: C,
1301
+ arg: ArgForCombinator<Arg>,
1302
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1303
+ ) => D,
1304
+ e: (
1305
+ _: D,
1306
+ arg: ArgForCombinator<Arg>,
1307
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1308
+ ) => E,
1309
+ f: (
1310
+ _: E,
1311
+ arg: ArgForCombinator<Arg>,
1312
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1313
+ ) => F,
1314
+ g: (
1315
+ _: F,
1316
+ arg: ArgForCombinator<Arg>,
1317
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1318
+ ) => G,
1319
+ h: (
1320
+ _: G,
1321
+ arg: ArgForCombinator<Arg>,
1322
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1323
+ ) => H
1324
+ ): CommandOutHelper<Arg, H, Id, I18nKey, State>
1325
+ <A, B, C, D, E, F, G, H, I extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>>(
1326
+ a: (
1327
+ _: Effect.Effect<
1328
+ AEff,
1329
+ EEff,
1330
+ REff
1331
+ >,
1332
+ arg: ArgForCombinator<Arg>,
1333
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1334
+ ) => A,
1335
+ b: (
1336
+ _: A,
1337
+ arg: ArgForCombinator<Arg>,
1338
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1339
+ ) => B,
1340
+ c: (
1341
+ _: B,
1342
+ arg: ArgForCombinator<Arg>,
1343
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1344
+ ) => C,
1345
+ d: (
1346
+ _: C,
1347
+ arg: ArgForCombinator<Arg>,
1348
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1349
+ ) => D,
1350
+ e: (
1351
+ _: D,
1352
+ arg: ArgForCombinator<Arg>,
1353
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1354
+ ) => E,
1355
+ f: (
1356
+ _: E,
1357
+ arg: ArgForCombinator<Arg>,
1358
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1359
+ ) => F,
1360
+ g: (
1361
+ _: F,
1362
+ arg: ArgForCombinator<Arg>,
1363
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1364
+ ) => G,
1365
+ h: (
1366
+ _: G,
1367
+ arg: ArgForCombinator<Arg>,
1368
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1369
+ ) => H,
1370
+ i: (
1371
+ _: H,
1372
+ arg: ArgForCombinator<Arg>,
1373
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1374
+ ) => I
1375
+ ): CommandOutHelper<Arg, I, Id, I18nKey, State>
1376
+ }
1377
+
1378
+ export type NonGenWrap<
1379
+ RT,
1380
+ Id extends string,
1381
+ I18nKey extends string,
1382
+ Arg,
1383
+ AEff,
1384
+ EEff,
1385
+ REff,
1386
+ State extends IntlRecord | undefined
1387
+ > = {
1388
+ (): Exclude<REff, RT> extends never ? CommandOutHelper<Arg, Effect.Effect<AEff, EEff, REff>, Id, I18nKey, State>
1389
+ : MissingDependencies<RT, REff> & {}
1390
+ <
1391
+ Eff extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
1392
+ Arg
1393
+ >(
1394
+ a: (
1395
+ _: Effect.Effect<
1396
+ AEff,
1397
+ EEff,
1398
+ REff
1399
+ >,
1400
+ arg: ArgForCombinator<Arg>,
1401
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1402
+ ) => Eff
1403
+ ): CommandOutHelper<Arg, Eff, Id, I18nKey, State>
1404
+ <
1405
+ Eff extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
1406
+ B,
1407
+ Arg
1408
+ >(
1409
+ a: (
1410
+ _: Effect.Effect<
1411
+ AEff,
1412
+ EEff,
1413
+ REff
1414
+ >,
1415
+ arg: ArgForCombinator<Arg>,
1416
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1417
+ ) => B,
1418
+ b: (
1419
+ _: B,
1420
+ arg: ArgForCombinator<Arg>,
1421
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1422
+ ) => Eff
1423
+ ): CommandOutHelper<Arg, Eff, Id, I18nKey, State>
1424
+ <
1425
+ Eff extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
1426
+ B,
1427
+ C,
1428
+ Arg
1429
+ >(
1430
+ a: (
1431
+ _: Effect.Effect<
1432
+ AEff,
1433
+ EEff,
1434
+ REff
1435
+ >,
1436
+ arg: ArgForCombinator<Arg>,
1437
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1438
+ ) => B,
1439
+ b: (
1440
+ _: B,
1441
+ arg: ArgForCombinator<Arg>,
1442
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1443
+ ) => C,
1444
+ c: (
1445
+ _: C,
1446
+ arg: ArgForCombinator<Arg>,
1447
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1448
+ ) => Eff
1449
+ ): CommandOutHelper<Arg, Eff, Id, I18nKey, State>
1450
+ <
1451
+ Eff extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
1452
+ B,
1453
+ C,
1454
+ D,
1455
+ Arg
1456
+ >(
1457
+ a: (
1458
+ _: Effect.Effect<
1459
+ AEff,
1460
+ EEff,
1461
+ REff
1462
+ >,
1463
+ arg: ArgForCombinator<Arg>,
1464
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1465
+ ) => B,
1466
+ b: (
1467
+ _: B,
1468
+ arg: ArgForCombinator<Arg>,
1469
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1470
+ ) => C,
1471
+ c: (
1472
+ _: C,
1473
+ arg: ArgForCombinator<Arg>,
1474
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1475
+ ) => D,
1476
+ d: (
1477
+ _: D,
1478
+ arg: ArgForCombinator<Arg>,
1479
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1480
+ ) => Eff
1481
+ ): CommandOutHelper<Arg, Eff, Id, I18nKey, State>
1482
+ <
1483
+ Eff extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
1484
+ B,
1485
+ C,
1486
+ D,
1487
+ E,
1488
+ Arg
1489
+ >(
1490
+ a: (
1491
+ _: Effect.Effect<
1492
+ AEff,
1493
+ EEff,
1494
+ REff
1495
+ >,
1496
+ arg: ArgForCombinator<Arg>,
1497
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1498
+ ) => B,
1499
+ b: (
1500
+ _: B,
1501
+ arg: ArgForCombinator<Arg>,
1502
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1503
+ ) => C,
1504
+ c: (
1505
+ _: C,
1506
+ arg: ArgForCombinator<Arg>,
1507
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1508
+ ) => D,
1509
+ d: (
1510
+ _: D,
1511
+ arg: ArgForCombinator<Arg>,
1512
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1513
+ ) => E,
1514
+ e: (
1515
+ _: E,
1516
+ arg: ArgForCombinator<Arg>,
1517
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1518
+ ) => Eff
1519
+ ): CommandOutHelper<Arg, Eff, Id, I18nKey, State>
1520
+ <
1521
+ Eff extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
1522
+ B,
1523
+ C,
1524
+ D,
1525
+ E,
1526
+ F,
1527
+ Arg
1528
+ >(
1529
+ a: (
1530
+ _: Effect.Effect<
1531
+ AEff,
1532
+ EEff,
1533
+ REff
1534
+ >,
1535
+ arg: ArgForCombinator<Arg>,
1536
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1537
+ ) => B,
1538
+ b: (
1539
+ _: B,
1540
+ arg: ArgForCombinator<Arg>,
1541
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1542
+ ) => C,
1543
+ c: (
1544
+ _: C,
1545
+ arg: ArgForCombinator<Arg>,
1546
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1547
+ ) => D,
1548
+ d: (
1549
+ _: D,
1550
+ arg: ArgForCombinator<Arg>,
1551
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1552
+ ) => E,
1553
+ e: (
1554
+ _: E,
1555
+ arg: ArgForCombinator<Arg>,
1556
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1557
+ ) => F,
1558
+ f: (
1559
+ _: F,
1560
+ arg: ArgForCombinator<Arg>,
1561
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1562
+ ) => Eff
1563
+ ): CommandOutHelper<Arg, Eff, Id, I18nKey, State>
1564
+ <
1565
+ Eff extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
1566
+ B,
1567
+ C,
1568
+ D,
1569
+ E,
1570
+ F,
1571
+ G,
1572
+ Arg
1573
+ >(
1574
+ a: (
1575
+ _: Effect.Effect<
1576
+ AEff,
1577
+ EEff,
1578
+ REff
1579
+ >,
1580
+ arg: ArgForCombinator<Arg>,
1581
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1582
+ ) => B,
1583
+ b: (
1584
+ _: B,
1585
+ arg: ArgForCombinator<Arg>,
1586
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1587
+ ) => C,
1588
+ c: (
1589
+ _: C,
1590
+ arg: ArgForCombinator<Arg>,
1591
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1592
+ ) => D,
1593
+ d: (
1594
+ _: D,
1595
+ arg: ArgForCombinator<Arg>,
1596
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1597
+ ) => E,
1598
+ e: (
1599
+ _: E,
1600
+ arg: ArgForCombinator<Arg>,
1601
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1602
+ ) => F,
1603
+ f: (
1604
+ _: F,
1605
+ arg: ArgForCombinator<Arg>,
1606
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1607
+ ) => G,
1608
+ g: (
1609
+ _: G,
1610
+ arg: ArgForCombinator<Arg>,
1611
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1612
+ ) => Eff
1613
+ ): CommandOutHelper<Arg, Eff, Id, I18nKey, State>
1614
+ <
1615
+ Eff extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
1616
+ B,
1617
+ C,
1618
+ D,
1619
+ E,
1620
+ F,
1621
+ G,
1622
+ H,
1623
+ Arg
1624
+ >(
1625
+ a: (
1626
+ _: Effect.Effect<
1627
+ AEff,
1628
+ EEff,
1629
+ REff
1630
+ >,
1631
+ arg: ArgForCombinator<Arg>,
1632
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1633
+ ) => B,
1634
+ b: (
1635
+ _: B,
1636
+ arg: ArgForCombinator<Arg>,
1637
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1638
+ ) => C,
1639
+ c: (
1640
+ _: C,
1641
+ arg: ArgForCombinator<Arg>,
1642
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1643
+ ) => D,
1644
+ d: (
1645
+ _: D,
1646
+ arg: ArgForCombinator<Arg>,
1647
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1648
+ ) => E,
1649
+ e: (
1650
+ _: E,
1651
+ arg: ArgForCombinator<Arg>,
1652
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1653
+ ) => F,
1654
+ f: (
1655
+ _: F,
1656
+ arg: ArgForCombinator<Arg>,
1657
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1658
+ ) => G,
1659
+ g: (
1660
+ _: G,
1661
+ arg: ArgForCombinator<Arg>,
1662
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1663
+ ) => H,
1664
+ h: (
1665
+ _: H,
1666
+ arg: ArgForCombinator<Arg>,
1667
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1668
+ ) => Eff
1669
+ ): CommandOutHelper<Arg, Eff, Id, I18nKey, State>
1670
+ <
1671
+ Eff extends Effect.Effect<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
1672
+ B,
1673
+ C,
1674
+ D,
1675
+ E,
1676
+ F,
1677
+ G,
1678
+ H,
1679
+ I,
1680
+ Arg
1681
+ >(
1682
+ a: (
1683
+ _: Effect.Effect<
1684
+ AEff,
1685
+ EEff,
1686
+ REff
1687
+ >,
1688
+ arg: ArgForCombinator<Arg>,
1689
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1690
+ ) => B,
1691
+ b: (
1692
+ _: B,
1693
+ arg: ArgForCombinator<Arg>,
1694
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1695
+ ) => C,
1696
+ c: (
1697
+ _: C,
1698
+ arg: ArgForCombinator<Arg>,
1699
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1700
+ ) => D,
1701
+ d: (
1702
+ _: D,
1703
+ arg: ArgForCombinator<Arg>,
1704
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1705
+ ) => E,
1706
+ e: (
1707
+ _: E,
1708
+ arg: ArgForCombinator<Arg>,
1709
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1710
+ ) => F,
1711
+ f: (
1712
+ _: F,
1713
+ arg: ArgForCombinator<Arg>,
1714
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1715
+ ) => G,
1716
+ g: (
1717
+ _: G,
1718
+ arg: ArgForCombinator<Arg>,
1719
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1720
+ ) => H,
1721
+ h: (
1722
+ _: H,
1723
+ arg: ArgForCombinator<Arg>,
1724
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1725
+ ) => I,
1726
+ i: (
1727
+ _: H,
1728
+ arg: ArgForCombinator<Arg>,
1729
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1730
+ ) => Eff
1731
+ ): CommandOutHelper<Arg, Eff, Id, I18nKey, State>
1732
+ }
1733
+
1734
+ /**
1735
+ * Type for `streamFn` — generator overload where the body yields Effects and returns a `Stream`.
1736
+ * `waiting` stays `true` while the stream is running, and updates the `result` ref per emitted value.
1737
+ */
1738
+ export type StreamGen<RT, Id extends string, I18nKey extends string, State extends IntlRecord | undefined> = {
1739
+ <
1740
+ Eff extends Effect.Yieldable<any, any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
1741
+ SA,
1742
+ SE,
1743
+ SR,
1744
+ Arg = void
1745
+ >(
1746
+ body: (
1747
+ arg: Arg,
1748
+ ctx: CommandContextLocal2<Id, I18nKey, State>
1749
+ ) => Generator<Eff, Stream.Stream<SA, SE, SR>, never>
1750
+ ): CommandOut<
1751
+ Arg,
1752
+ SA,
1753
+ | SE
1754
+ | ([Eff] extends [never] ? never
1755
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer E, infer _R>] ? E
1756
+ : never),
1757
+ | SR
1758
+ | ([Eff] extends [never] ? never
1759
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer _E, infer R>] ? R
1760
+ : never),
1761
+ Id,
1762
+ I18nKey,
1763
+ State
1764
+ >
1765
+ <
1766
+ Eff extends Effect.Yieldable<any, any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
1767
+ SA,
1768
+ SE,
1769
+ SR,
1770
+ B,
1771
+ Arg = void
1772
+ >(
1773
+ body: (
1774
+ arg: Arg,
1775
+ ctx: CommandContextLocal2<Id, I18nKey, State>
1776
+ ) => Generator<Eff, Stream.Stream<SA, SE, SR>, never>,
1777
+ a: (
1778
+ _: Effect.Effect<
1779
+ Stream.Stream<SA, SE, SR>,
1780
+ ([Eff] extends [never] ? never
1781
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer E, infer _R>] ? E
1782
+ : never),
1783
+ ([Eff] extends [never] ? never
1784
+ : [Eff] extends [Effect.Yieldable<any, infer _A, infer _E, infer R>] ? R
1785
+ : never)
1786
+ >,
1787
+ arg: ArgForCombinator<Arg>,
1788
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1789
+ ) => B
1790
+ ): B extends Stream.Stream<infer SA2, infer SE2, infer SR2> ? CommandOut<Arg, SA2, SE2, SR2, Id, I18nKey, State>
1791
+ : B extends Effect.Effect<Stream.Stream<infer SA2, infer SE2, infer SR2>, infer EE2, infer ER2>
1792
+ ? CommandOut<Arg, SA2, SE2 | EE2, SR2 | ER2, Id, I18nKey, State>
1793
+ : never
1794
+ }
1795
+
1796
+ /**
1797
+ * Type for `streamFn` — non-generator overload accepting a function that returns a `Stream` directly,
1798
+ * or an `Effect` that resolves to a `Stream`.
1799
+ */
1800
+ export type NonGenStream<RT, Id extends string, I18nKey extends string, State extends IntlRecord | undefined> = {
1801
+ <
1802
+ SA,
1803
+ SE,
1804
+ SR extends RT | CommandContext | `Commander.Command.${Id}.state`,
1805
+ Arg = void
1806
+ >(
1807
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => Stream.Stream<SA, SE, SR>
1808
+ ): CommandOut<Arg, SA, SE, SR, Id, I18nKey, State>
1809
+ <
1810
+ SA,
1811
+ SE,
1812
+ SR,
1813
+ A extends Stream.Stream<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>,
1814
+ Arg = void
1815
+ >(
1816
+ body: (arg: Arg, ctx: CommandContextLocal2<Id, I18nKey, State>) => Stream.Stream<SA, SE, SR>,
1817
+ a: (
1818
+ _: Stream.Stream<SA, SE, SR>,
1819
+ arg: ArgForCombinator<Arg>,
1820
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1821
+ ) => A
1822
+ ): CommandOut<Arg, Stream.Success<A>, Stream.Error<A>, Stream.Services<A>, Id, I18nKey, State>
1823
+ <
1824
+ SA,
1825
+ SE,
1826
+ SR,
1827
+ EE,
1828
+ ER extends RT | CommandContext | `Commander.Command.${Id}.state`,
1829
+ Arg = void
1830
+ >(
1831
+ body: (
1832
+ arg: Arg,
1833
+ ctx: CommandContextLocal2<Id, I18nKey, State>
1834
+ ) => Effect.Effect<Stream.Stream<SA, SE, SR>, EE, ER>
1835
+ ): CommandOut<Arg, SA, SE | EE, SR | ER, Id, I18nKey, State>
1836
+ <
1837
+ SA,
1838
+ SE,
1839
+ SR,
1840
+ EE,
1841
+ ER,
1842
+ B,
1843
+ Arg = void
1844
+ >(
1845
+ body: (
1846
+ arg: Arg,
1847
+ ctx: CommandContextLocal2<Id, I18nKey, State>
1848
+ ) => Effect.Effect<Stream.Stream<SA, SE, SR>, EE, ER>,
1849
+ a: (
1850
+ _: Effect.Effect<Stream.Stream<SA, SE, SR>, EE, ER>,
1851
+ arg: ArgForCombinator<Arg>,
1852
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1853
+ ) => B
1854
+ ): B extends Stream.Stream<infer SA2, infer SE2, infer SR2> ? CommandOut<Arg, SA2, SE2, SR2, Id, I18nKey, State>
1855
+ : B extends Effect.Effect<Stream.Stream<infer SA2, infer SE2, infer SR2>, infer EE2, infer ER2>
1856
+ ? CommandOut<Arg, SA2, SE2 | EE2, SR2 | ER2, Id, I18nKey, State>
1857
+ : never
1858
+ }
1859
+
1860
+ /**
1861
+ * Type returned by `mutate.wrap` on a stream handler — analogous to `CommanderWrap` but for streams.
1862
+ * The handler is pre-baked (from the stream mutation), so this is called with only optional combinators.
1863
+ */
1864
+ export type StreamerWrap<
1865
+ RT,
1866
+ Id extends string,
1867
+ I18nKey extends string,
1868
+ State extends IntlRecord | undefined,
1869
+ Arg,
1870
+ SA,
1871
+ SE,
1872
+ SR
1873
+ > =
1874
+ & CommandContextLocal<Id, I18nKey>
1875
+ & { readonly state: Context.Service<`Commander.Command.${Id}.state`, State> }
1876
+ & {
1877
+ (): Exclude<SR, RT> extends never ? CommandOut<Arg, SA, SE, SR, Id, I18nKey, State>
1878
+ : MissingDependencies<RT, SR> & {}
1879
+ <A extends Stream.Stream<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>>(
1880
+ a: (
1881
+ _: Stream.Stream<SA, SE, SR>,
1882
+ arg: ArgForCombinator<Arg>,
1883
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1884
+ ) => A
1885
+ ): CommandOut<Arg, Stream.Success<A>, Stream.Error<A>, Stream.Services<A>, Id, I18nKey, State>
1886
+ <
1887
+ B,
1888
+ A extends Stream.Stream<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>
1889
+ >(
1890
+ a: (
1891
+ _: Stream.Stream<SA, SE, SR>,
1892
+ arg: ArgForCombinator<Arg>,
1893
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1894
+ ) => B,
1895
+ b: (
1896
+ _: B,
1897
+ arg: ArgForCombinator<Arg>,
1898
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1899
+ ) => A
1900
+ ): CommandOut<Arg, Stream.Success<A>, Stream.Error<A>, Stream.Services<A>, Id, I18nKey, State>
1901
+ <
1902
+ B,
1903
+ C,
1904
+ A extends Stream.Stream<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>
1905
+ >(
1906
+ a: (
1907
+ _: Stream.Stream<SA, SE, SR>,
1908
+ arg: ArgForCombinator<Arg>,
1909
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1910
+ ) => B,
1911
+ b: (
1912
+ _: B,
1913
+ arg: ArgForCombinator<Arg>,
1914
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1915
+ ) => C,
1916
+ c: (
1917
+ _: C,
1918
+ arg: ArgForCombinator<Arg>,
1919
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1920
+ ) => A
1921
+ ): CommandOut<Arg, Stream.Success<A>, Stream.Error<A>, Stream.Services<A>, Id, I18nKey, State>
1922
+ <
1923
+ B,
1924
+ C,
1925
+ D,
1926
+ A extends Stream.Stream<any, any, RT | CommandContext | `Commander.Command.${Id}.state`>
1927
+ >(
1928
+ a: (
1929
+ _: Stream.Stream<SA, SE, SR>,
1930
+ arg: ArgForCombinator<Arg>,
1931
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1932
+ ) => B,
1933
+ b: (
1934
+ _: B,
1935
+ arg: ArgForCombinator<Arg>,
1936
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1937
+ ) => C,
1938
+ c: (
1939
+ _: C,
1940
+ arg: ArgForCombinator<Arg>,
1941
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1942
+ ) => D,
1943
+ d: (
1944
+ _: D,
1945
+ arg: ArgForCombinator<Arg>,
1946
+ ctx: CommandContextLocal2<NoInfer<Id>, NoInfer<I18nKey>, NoInfer<State>>
1947
+ ) => A
1948
+ ): CommandOut<Arg, Stream.Success<A>, Stream.Error<A>, Stream.Services<A>, Id, I18nKey, State>
1949
+ }
1950
+ }
1951
+
1952
+ type ErrorRenderer<E, Args extends readonly any[]> = (e: E, action: string, ...args: Args) => string | undefined
1953
+
1954
+ type RegisteredErrorRenderer<A> = {
1955
+ guard: Refinement<unknown, A>
1956
+ render: (guarded: A) => string | undefined
1957
+ }
1958
+
1959
+ export class CommanderErrorRenderers extends Context.Reference("Commander.ErrorRenderers", {
1960
+ defaultValue: () => [] as RegisteredErrorRenderer<any>[]
1961
+ }) {}
1962
+
1963
+ export const makeRegisteredErrorRenderer = <A>(
1964
+ guard: Predicate.Refinement<unknown, A>,
1965
+ render: (guarded: A) => string | undefined
1966
+ ): RegisteredErrorRenderer<A> => ({
1967
+ guard,
1968
+ render
1969
+ })
1970
+
1971
+ const renderErrorMaker = Effect.gen(function*() {
1972
+ const { intl } = yield* I18n
1973
+ const registeredRenderers = yield* CommanderErrorRenderers
1974
+ return (
1975
+ <E, Args extends readonly any[]>(action: string, errorRenderer?: ErrorRenderer<E, Args>) =>
1976
+ (e: E, ...args: Args): string => {
1977
+ if (errorRenderer) {
1978
+ const m = errorRenderer(e, action, ...args)
1979
+ if (m !== undefined) {
1980
+ return m
1981
+ }
1982
+ }
1983
+ for (const entry of registeredRenderers) {
1984
+ if (!entry.guard(e)) {
1985
+ continue
1986
+ }
1987
+ const m = entry.render(e)
1988
+ if (m !== undefined) {
1989
+ return m
1990
+ }
1991
+ }
1992
+ if (!S.is(SupportedErrors)(e) && !S.isSchemaError(e)) {
1993
+ if (typeof e === "object" && e !== null) {
1994
+ if ("message" in e) {
1995
+ return `${e.message}`
1996
+ }
1997
+ if ("_tag" in e) {
1998
+ return `${e._tag}`
1999
+ }
2000
+ }
2001
+ return ""
2002
+ }
2003
+ const e2: SupportedErrors | S.SchemaError = e
2004
+ return Match.value(e2).pipe(
2005
+ Match.tags({
2006
+ NotFoundError: (e) => {
2007
+ return intl.formatMessage({ id: "handle.not_found" }, { type: e.type, id: e.id })
2008
+ },
2009
+ SchemaError: (e) => {
2010
+ console.warn(e.toString())
2011
+ return intl.formatMessage({ id: "validation.failed" })
2012
+ }
2013
+ }),
2014
+ Match.orElse((e) => e.message ?? e._tag ?? e)
2015
+ )
2016
+ }
2017
+ )
2018
+ })
2019
+
2020
+ const defaultFailureMessageHandler = <E, Args extends Array<unknown>, AME, AMR>(
2021
+ actionMaker:
2022
+ | string
2023
+ | ((o: Option.Option<E>, ...args: Args) => string)
2024
+ | ((o: Option.Option<E>, ...args: Args) => Effect.Effect<string, AME, AMR>),
2025
+ errorRenderer?: ErrorRenderer<E, Args>
2026
+ ) =>
2027
+ Effect.fnUntraced(function*(o: Option.Option<E>, ...args: Args) {
2028
+ const action = yield* wrapEffect(actionMaker)(o, ...args)
2029
+ const { intl } = yield* I18n
2030
+ const renderError = yield* renderErrorMaker
2031
+
2032
+ return Option.match(o, {
2033
+ onNone: () =>
2034
+ intl.formatMessage(
2035
+ { id: "handle.unexpected_error2" },
2036
+ {
2037
+ action,
2038
+ error: "" // TODO consider again Cause.pretty(cause), // will be reported to Sentry/Otel anyway.. and we shouldn't bother users with error dumps?
2039
+ }
2040
+ ),
2041
+ onSome: (e) => {
2042
+ const rendered = renderError(action, errorRenderer)(e, ...args)
2043
+ return {
2044
+ level: "warn" as const,
2045
+ message: `${
2046
+ intl.formatMessage(
2047
+ { id: "handle.with_errors" },
2048
+ { action }
2049
+ )
2050
+ }:\n` + rendered
2051
+ }
2052
+ }
2053
+ })
2054
+ })
2055
+
2056
+ export const CommanderStatic = {
2057
+ accessArgs: <In, Out, Arg2, Arg = void>(
2058
+ cb: (a: NoInfer<Arg>, b: NoInfer<Arg2>) => (self: NoInfer<In>) => Out
2059
+ ) =>
2060
+ (self: In, arg: Arg, arg2: Arg2) => cb(arg, arg2)(self),
2061
+
2062
+ /**
2063
+ * Stream pipe operator that maps each emitted value to a `Progress` entry and updates the
2064
+ * command's reactive `progress` ref via the `CommandProgress` service.
2065
+ *
2066
+ * The mapper receives an `AsyncResult<A, E>` (each emitted value wrapped as
2067
+ * `AsyncResult.success(value, { waiting: true })`), matching the same shape used by
2068
+ * `CommandButton`'s `:progress-map` prop.
2069
+ *
2070
+ * Designed to be used inside a `streamFn` handler (either directly with `.pipe()`, or as
2071
+ * a combinator argument):
2072
+ *
2073
+ * @example
2074
+ * ```ts
2075
+ * // Inside the handler body:
2076
+ * Command.streamFn("exportData")(function*(arg, ctx) {
2077
+ * return makeExportStream(arg.id).pipe(
2078
+ * Command.mapProgress((r) =>
2079
+ * AsyncResult.isSuccess(r) && r.value._tag === "OperationProgress"
2080
+ * ? { text: `${r.value.completed}/${r.value.total}`, percentage: r.value.completed / r.value.total * 100 }
2081
+ * : undefined
2082
+ * )
2083
+ * )
2084
+ * })
2085
+ *
2086
+ * // Or as a stream combinator argument:
2087
+ * Command.streamFn("exportData")(
2088
+ * function*(arg, ctx) { return makeExportStream(arg.id) },
2089
+ * (s) => s.pipe(Command.mapProgress((r) => AsyncResult.isSuccess(r) && r.value._tag === "OperationProgress" ? { text: `${r.value.completed}/${r.value.total}` } : undefined))
2090
+ * )
2091
+ * ```
2092
+ */
2093
+ mapProgress:
2094
+ <A, E>(fn: (result: AsyncResult.AsyncResult<A, E>) => Progress | undefined) =>
2095
+ <R>(stream: Stream.Stream<A, E, R>): Stream.Stream<A, E, R> =>
2096
+ stream.pipe(
2097
+ Stream.tap((v) => {
2098
+ const p = fn(AsyncResult.success(v, { waiting: true }))
2099
+ return p !== undefined ? CommandProgress.use((s) => s.update(p)) : Effect.void
2100
+ })
2101
+ ),
2102
+
2103
+ /**
2104
+ * Imperatively push a progress update from inside a `streamFn` handler.
2105
+ * Requires `CommandProgress` to be in context — provided automatically for all `streamFn` streams.
2106
+ *
2107
+ * @example
2108
+ * ```ts
2109
+ * // In a streamFn handler:
2110
+ * stream.pipe(
2111
+ * Stream.tap((event) =>
2112
+ * event._tag === "OperationProgress"
2113
+ * ? Command.updateProgress({ text: `${event.completed}/${event.total}`, percentage: event.completed / event.total * 100 })
2114
+ * : Effect.void
2115
+ * )
2116
+ * )
2117
+ * ```
2118
+ */
2119
+ updateProgress: (progress: Progress | undefined): Effect.Effect<void> =>
2120
+ CommandProgress.use((s) => s.update(progress)),
2121
+
2122
+ /** Version of @see confirmOrInterrupt that automatically includes the action name in the default messages */
2123
+ confirmOrInterrupt: Effect.fnUntraced(function*(
2124
+ message?: string
2125
+ ) {
2126
+ const context = yield* CommandContext
2127
+ const { intl } = yield* I18n
2128
+
2129
+ yield* Confirm.confirmOrInterrupt(
2130
+ message
2131
+ ?? intl.formatMessage(
2132
+ { id: "handle.confirmation" },
2133
+ { action: context.action }
2134
+ )
2135
+ )
2136
+ }),
2137
+ /** Version of @see confirm that automatically includes the action name in the default messages */
2138
+ confirm: Effect.fnUntraced(function*(
2139
+ message?: string
2140
+ ) {
2141
+ const context = yield* CommandContext
2142
+ const { intl } = yield* I18n
2143
+ return yield* Confirm.confirm(
2144
+ message
2145
+ ?? intl.formatMessage(
2146
+ { id: "handle.confirmation" },
2147
+ { action: context.action }
2148
+ )
2149
+ )
2150
+ }),
2151
+ updateAction:
2152
+ <Args extends Array<unknown>>(update: (currentActionId: string, ...args: Args) => string) =>
2153
+ <A, E, R>(_: Effect.Effect<A, E, R>, ...input: Args) =>
2154
+ Effect.updateService(
2155
+ _,
2156
+ CommandContext,
2157
+ (c) => ({ ...c, action: update(c.action, ...input) })
2158
+ ),
2159
+ registerErrorRenderer: <A>(
2160
+ guard: Predicate.Refinement<unknown, A>,
2161
+ render: (guarded: A) => string | undefined
2162
+ ) =>
2163
+ Layer.effect(
2164
+ CommanderErrorRenderers,
2165
+ Effect.gen(function*() {
2166
+ const current = yield* CommanderErrorRenderers
2167
+ return [...current, makeRegisteredErrorRenderer(guard, render)]
2168
+ })
2169
+ ),
2170
+ defaultFailureMessageHandler,
2171
+ renderError: renderErrorMaker,
2172
+ /**
2173
+ * Version of withDefaultToast that automatically includes the action name in the default messages and uses intl.
2174
+ * uses the Command id as i18n namespace. `action.{id}` is the main action name,
2175
+ * and `action.{id}.waiting`, `action.{id}.success`, `action.{id}.failure` can be used to override the default messages for the respective states.
2176
+ *
2177
+ * the computed `state` provided to the Command can be used for interpolation in the i18n messages. (the state is captured at the start of each command execution and remains stable throughout)
2178
+ *
2179
+ * Note: if you provide `onWaiting` or `onSuccess` as `null`, no toast will be shown for that state.
2180
+ * If you provide a string or function, it will be used instead of the i18n message.
2181
+ * If you provide an `errorRenderer`, it will be used to render errors in the failure message.
2182
+ */
2183
+ withDefaultToast: <A, E, R, Args extends Array<unknown>>(
2184
+ options?: {
2185
+ /**
2186
+ * if true, previous toasts with this key will be replaced
2187
+ */
2188
+ stableToastId?:
2189
+ | undefined
2190
+ | true
2191
+ | string
2192
+ | ((id: string, arg: NoInfer<Args>[0], ctx: NoInfer<Args>[1]) => true | string | undefined)
2193
+ errorRenderer?: (e: E, action: string, arg: NoInfer<Args>[0], ctx: NoInfer<Args>[1]) => string | undefined
2194
+ showSpanInfo?: false
2195
+ onWaiting?:
2196
+ | null
2197
+ | undefined
2198
+ | string
2199
+ | ((id: string, arg: NoInfer<Args>[0], ctx: NoInfer<Args>[1]) => string | null | undefined)
2200
+ onSuccess?:
2201
+ | null
2202
+ | undefined
2203
+ | string
2204
+ | ((a: A, action: string, arg: NoInfer<Args>[0], ctx: NoInfer<Args>[1]) => string | null | undefined)
2205
+ }
2206
+ ) =>
2207
+ Effect.fnUntraced(function*(
2208
+ self: Effect.Effect<A, E, R>,
2209
+ ...args: Args
2210
+ ) {
2211
+ const cc = yield* CommandContext
2212
+ const { intl } = yield* I18n
2213
+ const withToast = yield* WithToast
2214
+ const customWaiting = cc.namespaced("waiting")
2215
+ const hasCustomWaiting = !!intl.messages[customWaiting]
2216
+ const customSuccess = cc.namespaced("success")
2217
+ const hasCustomSuccess = !!intl.messages[customSuccess]
2218
+ const customFailure = cc.namespaced("failure")
2219
+ const hasCustomFailure = !!intl.messages[customFailure]
2220
+ const stableToastId = options?.stableToastId
2221
+ ? typeof options.stableToastId === "string"
2222
+ ? options.stableToastId
2223
+ : typeof options.stableToastId === "boolean"
2224
+ ? cc.id
2225
+ : typeof options.stableToastId === "function"
2226
+ ? (...args: Args) => {
2227
+ const r = (options.stableToastId as any)(cc.id, ...args)
2228
+ if (typeof r === "string") return r
2229
+ if (r === true) return cc.id
2230
+ return undefined
2231
+ }
2232
+ : undefined
2233
+ : undefined
2234
+ return yield* self.pipe(
2235
+ (_) =>
2236
+ withToast<A, E, Args, R, never, never, I18n>({
2237
+ onWaiting: options?.onWaiting === null ? null : hasCustomWaiting
2238
+ ? intl.formatMessage({
2239
+ id: customWaiting
2240
+ }, cc.state)
2241
+ : intl.formatMessage(
2242
+ { id: "handle.waiting" },
2243
+ { action: cc.action }
2244
+ ),
2245
+ onSuccess: options?.onSuccess === null
2246
+ ? null
2247
+ : (_a, ..._args) =>
2248
+ hasCustomSuccess
2249
+ ? intl.formatMessage(
2250
+ { id: customSuccess },
2251
+ cc.state
2252
+ )
2253
+ : intl.formatMessage({ id: "handle.success" }, { action: cc.action }),
2254
+ onFailure: defaultFailureMessageHandler(
2255
+ hasCustomFailure ? intl.formatMessage({ id: customFailure }, cc.state) : cc.action,
2256
+ options?.errorRenderer as ErrorRenderer<E, Args> | undefined
2257
+ ),
2258
+ stableToastId,
2259
+ groupId: cc.id,
2260
+ ...options?.showSpanInfo === false ? { showSpanInfo: options.showSpanInfo } : {}
2261
+ })(_, ...args)
2262
+ )
2263
+ }),
2264
+
2265
+ /**
2266
+ * Stream-aware version of `withDefaultToast`. Use this as a combinator inside `streamFn`
2267
+ * (or anywhere a `Stream` needs toast lifecycle handling) instead of `withDefaultToast`.
2268
+ *
2269
+ * Unlike `withDefaultToast` (which only wraps the initial `Effect`), this combinator:
2270
+ * - Shows the "waiting" toast **before** the stream starts
2271
+ * - Updates the waiting toast with progress text when `progress` is set and a new element arrives
2272
+ * - Shows the "success" toast only **after** the stream drains fully without error
2273
+ * - Shows the "failure" toast if the stream errors or fails
2274
+ *
2275
+ * Accepts either a `Stream<A, E, R>` or an `Effect<Stream<A, E, R>, EE, ER>` as input,
2276
+ * so it works in both the `NonGenStream` and `StreamGen` overloads of `streamFn`.
2277
+ *
2278
+ * @example
2279
+ * ```ts
2280
+ * Command.streamFn("exportData")(
2281
+ * function*(arg, ctx) { return makeExportStream(arg.id) },
2282
+ * Command.withDefaultToastStream({
2283
+ * progress: (r) =>
2284
+ * AsyncResult.isSuccess(r) && r.value._tag === "OperationProgress"
2285
+ * ? { text: `${r.value.completed}/${r.value.total}`, percentage: r.value.completed / r.value.total * 100 }
2286
+ * : undefined
2287
+ * })
2288
+ * )
2289
+ * ```
2290
+ */
2291
+ withDefaultToastStream: <A, E, R, Args extends Array<unknown>>(
2292
+ options?: {
2293
+ stableToastId?:
2294
+ | undefined
2295
+ | true
2296
+ | string
2297
+ | ((id: string, arg: NoInfer<Args>[0], ctx: NoInfer<Args>[1]) => true | string | undefined)
2298
+ errorRenderer?: (e: E, action: string, arg: NoInfer<Args>[0], ctx: NoInfer<Args>[1]) => string | undefined
2299
+ showSpanInfo?: false
2300
+ onWaiting?:
2301
+ | null
2302
+ | undefined
2303
+ | string
2304
+ | ((id: string, arg: NoInfer<Args>[0], ctx: NoInfer<Args>[1]) => string | null | undefined)
2305
+ onSuccess?:
2306
+ | null
2307
+ | undefined
2308
+ | string
2309
+ | ((a: A, action: string, arg: NoInfer<Args>[0], ctx: NoInfer<Args>[1]) => string | null | undefined)
2310
+ /** 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). */
2311
+ progress?: (result: AsyncResult.AsyncResult<A, E>) => Progress | undefined
2312
+ }
2313
+ ) =>
2314
+ (
2315
+ self: Stream.Stream<A, E, R> | Effect.Effect<Stream.Stream<A, E, R>, any, any>,
2316
+ ...args: Args
2317
+ ): Stream.Stream<A, E, R | I18n | Toast | CommandContext> => {
2318
+ const rawStream: Stream.Stream<A, E, R> = Stream.isStream(self)
2319
+ ? self
2320
+ : Stream.unwrap(self)
2321
+
2322
+ return Stream.unwrap(Effect.gen(function*() {
2323
+ const cc = yield* CommandContext
2324
+ const { intl } = yield* I18n
2325
+ const toast = yield* Toast
2326
+
2327
+ const customWaiting = cc.namespaced("waiting")
2328
+ const hasCustomWaiting = !!intl.messages[customWaiting]
2329
+ const customSuccess = cc.namespaced("success")
2330
+ const hasCustomSuccess = !!intl.messages[customSuccess]
2331
+ const customFailure = cc.namespaced("failure")
2332
+ const hasCustomFailure = !!intl.messages[customFailure]
2333
+
2334
+ const stableToastId: string | undefined = options?.stableToastId
2335
+ ? typeof options.stableToastId === "string"
2336
+ ? options.stableToastId
2337
+ : typeof options.stableToastId === "boolean"
2338
+ ? cc.id
2339
+ : typeof options.stableToastId === "function"
2340
+ ? (() => {
2341
+ const r = (options.stableToastId as (...a: any[]) => true | string | undefined)(cc.id, ...args)
2342
+ if (typeof r === "string") return r
2343
+ if (r === true) return cc.id
2344
+ return undefined
2345
+ })()
2346
+ : undefined
2347
+ : undefined
2348
+
2349
+ const baseTimeout = 3_000
2350
+
2351
+ const waitingMsg: string | null = options?.onWaiting === null
2352
+ ? null
2353
+ : typeof options?.onWaiting === "string"
2354
+ ? options.onWaiting
2355
+ : typeof options?.onWaiting === "function"
2356
+ ? (options.onWaiting as (...a: any[]) => string | null | undefined)(cc.id, ...args) ?? null
2357
+ : hasCustomWaiting
2358
+ ? intl.formatMessage({ id: customWaiting }, cc.state)
2359
+ : intl.formatMessage({ id: "handle.waiting" }, { action: cc.action })
2360
+
2361
+ const toastId: string | number | undefined = waitingMsg === null
2362
+ ? stableToastId
2363
+ : stableToastId ?? `wait-${Math.random().toString(36).slice(2)}`
2364
+
2365
+ const requestId: string = yield* Effect.currentSpan.pipe(
2366
+ Effect.map((span) => span.traceId),
2367
+ Effect.orElseSucceed(() => S.StringId.make())
2368
+ )
2369
+ const meta = { groupId: cc.id, requestId }
2370
+
2371
+ if (waitingMsg !== null) {
2372
+ yield* toast.info(waitingMsg, { id: toastId!, timeout: Infinity, ...meta })
2373
+ }
2374
+
2375
+ const failureHandler = defaultFailureMessageHandler<E, [], never, never>(
2376
+ hasCustomFailure ? intl.formatMessage({ id: customFailure }, cc.state) : cc.action,
2377
+ options?.errorRenderer as ErrorRenderer<E, []> | undefined
2378
+ )
2379
+
2380
+ let lastValue: A | undefined = undefined
2381
+ let didFail = false
2382
+
2383
+ const composed = rawStream.pipe(
2384
+ Stream.tap((v) =>
2385
+ Effect.gen(function*() {
2386
+ lastValue = v
2387
+ if (options?.progress !== undefined) {
2388
+ const p = options.progress(AsyncResult.success(v, { waiting: true }))
2389
+ if (p !== undefined) {
2390
+ // Update CommandProgress so CommandButton progress indicator is also driven
2391
+ yield* CommandProgress.use((s) => s.update(p))
2392
+ if (toastId !== undefined) {
2393
+ const progressText = typeof p === "string" ? p : p.text
2394
+ const msg = waitingMsg ? `${waitingMsg}\n${progressText}` : progressText
2395
+ yield* toast.info(msg, { id: toastId, timeout: Infinity, ...meta })
2396
+ }
2397
+ }
2398
+ }
2399
+ })
2400
+ ),
2401
+ Stream.tapCause(Effect.fnUntraced(function*(cause) {
2402
+ didFail = true
2403
+ if (Cause.hasInterruptsOnly(cause)) {
2404
+ if (toastId !== undefined) yield* toast.dismiss(toastId)
2405
+ return
2406
+ }
2407
+
2408
+ const spanInfo = options?.showSpanInfo !== false
2409
+ ? yield* Effect.currentSpan.pipe(
2410
+ Effect.map((span) => `\nTrace: ${span.traceId}\nSpan: ${span.spanId}`),
2411
+ Effect.orElseSucceed(() => "")
2412
+ )
2413
+ : ""
2414
+
2415
+ const t = yield* failureHandler(Cause.findErrorOption(cause))
2416
+ const opts = { timeout: baseTimeout * 2, ...meta }
2417
+
2418
+ if (typeof t === "object") {
2419
+ const message = t.message + spanInfo
2420
+ yield* t.level === "warn"
2421
+ ? toast.warning(message, toastId !== undefined ? { ...opts, id: toastId } : opts)
2422
+ : toast.error(message, toastId !== undefined ? { ...opts, id: toastId } : opts)
2423
+ } else {
2424
+ yield* toast.error(t + spanInfo, toastId !== undefined ? { ...opts, id: toastId } : opts)
2425
+ }
2426
+ }, Effect.uninterruptible)),
2427
+ Stream.ensuring(Effect.suspend(() => {
2428
+ if (didFail) return Effect.void
2429
+
2430
+ if (options?.onSuccess === null) return Effect.void
2431
+
2432
+ const successMsg: string | null = typeof options?.onSuccess === "string"
2433
+ ? options.onSuccess
2434
+ : typeof options?.onSuccess === "function"
2435
+ ? (options.onSuccess as (...a: any[]) => string | null | undefined)(lastValue, cc.action, ...args) ?? null
2436
+ : hasCustomSuccess
2437
+ ? intl.formatMessage({ id: customSuccess }, cc.state)
2438
+ : intl.formatMessage({ id: "handle.success" }, { action: cc.action })
2439
+
2440
+ if (successMsg === null) return Effect.void
2441
+
2442
+ return toast.success(
2443
+ successMsg,
2444
+ toastId !== undefined
2445
+ ? { id: toastId, timeout: baseTimeout, ...meta }
2446
+ : { timeout: baseTimeout, ...meta }
2447
+ )
2448
+ }))
2449
+ )
2450
+
2451
+ return (toastId !== undefined
2452
+ ? composed.pipe(Stream.provideService(CurrentToastId, CurrentToastId.of({ toastId })))
2453
+ : composed) as unknown as Stream.Stream<A, E, R>
2454
+ }))
2455
+ },
2456
+
2457
+ /** borrowing the idea from Families in Effect Atom */
2458
+ family: <T extends object, Arg, ArgIn = Arg>(
2459
+ maker: (arg: Arg) => T,
2460
+ keyMaker?: (arg: ArgIn) => Arg
2461
+ ): (arg: ArgIn) => T => {
2462
+ const commands = MutableHashMap.empty<Arg, WeakRef<T>>()
2463
+ const registry = new FinalizationRegistry<Arg>((arg) => {
2464
+ MutableHashMap.remove(commands, arg)
2465
+ })
2466
+
2467
+ return (_k: ArgIn) => {
2468
+ const k = keyMaker ? keyMaker(_k) : _k as unknown as Arg
2469
+ // we want to compare structurally, unless custom equal/hash has been implemented
2470
+ const item = MutableHashMap.get(commands, k).pipe(Option.flatMap((r) => Option.fromNullishOr(r.deref())))
2471
+ if (item.value) {
2472
+ return item.value
2473
+ }
2474
+ const v = maker(k)
2475
+ MutableHashMap.set(commands, k, new WeakRef(v))
2476
+
2477
+ registry.register(v, k)
2478
+ return v
2479
+ }
2480
+ }
2481
+ }
2482
+
2483
+ const makeBaseInfo = <const Id extends string, const I18nKey extends string = Id>(
2484
+ id: Id,
2485
+ options?: Pick<FnOptionsInternal<I18nKey>, "i18nCustomKey">
2486
+ ) => {
2487
+ if (!id) throw new Error("must specify an id")
2488
+ const i18nKey: I18nKey = options?.i18nCustomKey ?? id as unknown as I18nKey
2489
+
2490
+ const namespace = `action.${i18nKey}` as const
2491
+
2492
+ const context = {
2493
+ id,
2494
+ i18nKey,
2495
+ namespace,
2496
+ namespaced: <const K extends string>(k: K) => `${namespace}.${k}` as const
2497
+ }
2498
+
2499
+ return context
2500
+ }
2501
+
2502
+ const waitState = ref<Record<string, number>>({})
2503
+ const registerWait = (id: string) => {
2504
+ // console.debug("register wait", id)
2505
+ waitState.value[id] = waitState.value[id] ? waitState.value[id] + 1 : 1
2506
+ }
2507
+ const unregisterWait = (id: string) => {
2508
+ // console.debug("unregister wait", id)
2509
+ if (waitState.value[id]) {
2510
+ waitState.value[id] = waitState.value[id] - 1
2511
+ if (waitState.value[id] <= 0) {
2512
+ delete waitState.value[id]
2513
+ }
2514
+ }
2515
+ }
2516
+
2517
+ const getStateValues = <
2518
+ const Id extends string,
2519
+ const I18nKey extends string,
2520
+ State extends IntlRecord | undefined
2521
+ >(
2522
+ options?: FnOptions<Id, I18nKey, State>
2523
+ ): ComputedRef<State> => {
2524
+ const state_ = options?.state
2525
+ const state = !state_ ? computed(() => undefined as State) : typeof state_ === "function"
2526
+ ? computed(state_)
2527
+ : state_
2528
+ return state
2529
+ }
2530
+
2531
+ // class preserves JSDoc throughout..
2532
+ export class CommanderImpl<RT, RTHooks> {
2533
+ constructor(
2534
+ private readonly rt: Context.Context<RT>,
2535
+ private readonly intl: I18n,
2536
+ private readonly hooks: Layer.Layer<RTHooks, never, RT>
2537
+ ) {
2538
+ }
2539
+
2540
+ readonly makeContext = <const Id extends string, const I18nKey extends string = Id>(
2541
+ id: Id,
2542
+ options?: FnOptionsInternal<I18nKey>
2543
+ ) => {
2544
+ if (!id) throw new Error("must specify an id")
2545
+ const i18nKey: I18nKey = options?.i18nCustomKey ?? id as unknown as I18nKey
2546
+
2547
+ const namespace = `action.${i18nKey}` as const
2548
+
2549
+ // must remain stable through out single call
2550
+ const action = this.intl.formatMessage({
2551
+ id: namespace,
2552
+ defaultMessage: id
2553
+ }, { ...options?.state, _isLabel: false })
2554
+
2555
+ const label = this.intl.formatMessage({
2556
+ id: namespace,
2557
+ defaultMessage: id
2558
+ }, { ...options?.state, _isLabel: true })
2559
+
2560
+ const context = CommandContext.of({
2561
+ ...makeBaseInfo(id, options),
2562
+ action,
2563
+ label,
2564
+ state: options?.state
2565
+ })
2566
+
2567
+ return context
2568
+ }
2569
+
2570
+ readonly makeCommand = <
2571
+ const Id extends string,
2572
+ const State extends IntlRecord | undefined,
2573
+ const I18nKey extends string = Id
2574
+ >(
2575
+ id_: Id | { id: Id },
2576
+ options?: FnOptions<Id, I18nKey, State>,
2577
+ errorDef?: Error
2578
+ ) => {
2579
+ const id = typeof id_ === "string" ? id_ : id_.id
2580
+ const state = getStateValues(options)
2581
+
2582
+ return Object.assign(
2583
+ <Arg, A, E, R extends RT | RTHooks | CommandContext | `Commander.Command.${Id}.state`>(
2584
+ handler: (arg: Arg, ctx: Commander.CommandContextLocal2<Id, I18nKey, State>) => Effect.Effect<A, E, R>
2585
+ ) => {
2586
+ // we capture the definition stack here, so we can append it to later stack traces
2587
+ const limit = Error.stackTraceLimit
2588
+ Error.stackTraceLimit = 2
2589
+ const localErrorDef = new Error()
2590
+ Error.stackTraceLimit = limit
2591
+ if (!errorDef) {
2592
+ errorDef = localErrorDef
2593
+ }
2594
+
2595
+ const key = `Commander.Command.${id}.state` as const
2596
+ const stateTag = Context.Service<typeof key, State>(key)
2597
+
2598
+ const makeContext_ = () => this.makeContext(id, { ...options, state: state?.value })
2599
+ const initialContext = makeContext_()
2600
+ const context = computed(() => makeContext_())
2601
+ const action = computed(() => context.value.action)
2602
+ const label = computed(() => context.value.label)
2603
+
2604
+ const errorReporter = <A, E, R>(self: Effect.Effect<A, E, R>) =>
2605
+ self.pipe(
2606
+ Effect.tapCause(
2607
+ Effect.fnUntraced(function*(cause) {
2608
+ if (Cause.hasInterruptsOnly(cause)) {
2609
+ console.info(`Interrupted while trying to ${id}`)
2610
+ return
2611
+ }
2612
+
2613
+ const fail = Cause.findErrorOption(cause)
2614
+ if (Option.isSome(fail)) {
2615
+ // if (fail.value._tag === "SuppressErrors") {
2616
+ // console.info(
2617
+ // `Suppressed error trying to ${action}`,
2618
+ // fail.value,
2619
+ // )
2620
+ // return
2621
+ // }
2622
+ const message = `Failure trying to ${id}`
2623
+ yield* reportMessage(message, {
2624
+ action: id,
2625
+ error: fail.value
2626
+ })
2627
+ return
2628
+ }
2629
+
2630
+ const context = yield* CommandContext
2631
+ const extra = {
2632
+ action: context.action,
2633
+ message: `Unexpected Error trying to ${id}`
2634
+ }
2635
+ yield* reportRuntimeError(cause, extra)
2636
+ }, Effect.uninterruptible)
2637
+ )
2638
+ )
2639
+
2640
+ const currentState = Effect.sync(() => state.value)
2641
+
2642
+ const theHandler = flow(
2643
+ handler,
2644
+ errorReporter,
2645
+ // all must be within the Effect.fn to fit within the Span
2646
+ Effect.provideServiceEffect(
2647
+ stateTag,
2648
+ currentState
2649
+ ),
2650
+ Effect.provideServiceEffect(
2651
+ CommandContext,
2652
+ Effect.sync(() => makeContext_())
2653
+ )
2654
+ )
2655
+ const waitId = options?.waitKey ? options.waitKey(id) : undefined
2656
+ const blockId = options?.blockKey ? options.blockKey(id) : undefined
2657
+
2658
+ const [result, exec_] = asResult(theHandler)
2659
+
2660
+ const exec = Effect
2661
+ .fnUntraced(
2662
+ function*(...args: [any, any]) {
2663
+ if (waitId !== undefined) registerWait(waitId)
2664
+ if (blockId !== undefined && blockId !== waitId) {
2665
+ registerWait(blockId)
2666
+ }
2667
+ return yield* exec_(...args)
2668
+ },
2669
+ Effect.onExit(() =>
2670
+ Effect.sync(() => {
2671
+ if (waitId !== undefined) unregisterWait(waitId)
2672
+ if (blockId !== undefined && blockId !== waitId) {
2673
+ unregisterWait(blockId)
2674
+ }
2675
+ })
2676
+ )
2677
+ )
2678
+
2679
+ const waiting = waitId !== undefined
2680
+ ? computed(() => result.value.waiting || (waitState.value[waitId] ?? 0) > 0)
2681
+ : computed(() => result.value.waiting)
2682
+
2683
+ const blocked = blockId !== undefined
2684
+ ? computed(() => waiting.value || (waitState.value[blockId] ?? 0) > 0)
2685
+ : computed(() => waiting.value)
2686
+
2687
+ const computeAllowed = options?.allowed
2688
+ const allowed = computeAllowed ? computed(() => computeAllowed(id, state)) : true
2689
+
2690
+ const rt = Effect.context<RT | RTHooks>().pipe(Effect.provide(this.hooks)).pipe(Effect.runSyncWith(this.rt))
2691
+ const runFork = Effect.runForkWith(rt)
2692
+
2693
+ const handle = Object.assign((arg: Arg) => {
2694
+ arg = toRaw(arg) // remove outside vue proxy bs
2695
+ // we capture the call site stack here
2696
+ const limit = Error.stackTraceLimit
2697
+ Error.stackTraceLimit = 2
2698
+ const errorCall = new Error()
2699
+ Error.stackTraceLimit = limit
2700
+
2701
+ let cache: false | string = false
2702
+ const captureStackTrace = () => {
2703
+ // in case of an error, we want to append the definition stack to the call site stack,
2704
+ // so we can see where the handler was defined too
2705
+
2706
+ if (cache !== false) {
2707
+ return cache
2708
+ }
2709
+ if (errorCall.stack) {
2710
+ const stackDef = errorDef!.stack!.trim().split("\n")
2711
+ const stackCall = errorCall.stack.trim().split("\n")
2712
+ let endStackDef = stackDef.slice(2).join("\n").trim()
2713
+ if (!endStackDef.includes(`(`)) {
2714
+ endStackDef = endStackDef.replace(/at (.*)/, "at ($1)")
2715
+ }
2716
+ let endStackCall = stackCall.slice(2).join("\n").trim()
2717
+ if (!endStackCall.includes(`(`)) {
2718
+ endStackCall = endStackCall.replace(/at (.*)/, "at ($1)")
2719
+ }
2720
+ cache = `${endStackDef}\n${endStackCall}`
2721
+ return cache
2722
+ }
2723
+ }
2724
+
2725
+ const command = currentState.pipe(Effect.flatMap((state) => {
2726
+ const rawArg = deepToRaw(arg)
2727
+ const rawState = deepToRaw(state)
2728
+ return Effect.withSpan(
2729
+ exec(arg, { ...context.value, state } as any),
2730
+ id,
2731
+ {
2732
+ captureStackTrace,
2733
+ attributes: {
2734
+ input: rawArg,
2735
+ state: rawState,
2736
+ action: initialContext.action,
2737
+ label: initialContext.label,
2738
+ id: initialContext.id,
2739
+ i18nKey: initialContext.i18nKey
2740
+ }
2741
+ }
2742
+ )
2743
+ }))
2744
+
2745
+ return runFork(command)
2746
+ }, { action, label })
2747
+
2748
+ return reactive({
2749
+ /** static */
2750
+ id,
2751
+
2752
+ /** the base i18n key, based on id by default. static */
2753
+ i18nKey: initialContext.i18nKey,
2754
+ /** the `action.` namespace based on i18nKey.. static */
2755
+ namespace: initialContext.namespace,
2756
+
2757
+ /** easy generate namespaced 18n keys, based on namespace. static */
2758
+ namespaced: initialContext.namespaced,
2759
+
2760
+ /** reactive */
2761
+ result,
2762
+ /** always undefined for non-stream commands */
2763
+ progress: undefined,
2764
+ /** reactive */
2765
+ waiting,
2766
+ /** reactive */
2767
+ blocked,
2768
+ /** reactive */
2769
+ allowed,
2770
+ /** reactive */
2771
+ action,
2772
+ /** reactive */
2773
+ label,
2774
+ /** reactive */
2775
+ state,
2776
+
2777
+ handle
2778
+ })
2779
+ },
2780
+ { id }
2781
+ )
2782
+ }
2783
+
2784
+ // /** @experimental */
2785
+ // takeOver:
2786
+ // <Args extends any[], A, E, R, const Id extends string>(command: Commander.CommandOut<Args, A, E, R, Id,I18nKey>) =>
2787
+ // (...args: Args) => {
2788
+ // // we capture the call site stack here
2789
+ // const limit = Error.stackTraceLimit
2790
+ // Error.stackTraceLimit = 2
2791
+ // const errorCall = new Error()
2792
+ // const localErrorDef = new Error()
2793
+ // Error.stackTraceLimit = limit
2794
+
2795
+ // // TODO
2796
+ // const errorDef = localErrorDef
2797
+
2798
+ // let cache: false | string = false
2799
+ // const captureStackTrace = () => {
2800
+ // // in case of an error, we want to append the definition stack to the call site stack,
2801
+ // // so we can see where the handler was defined too
2802
+
2803
+ // if (cache !== false) {
2804
+ // return cache
2805
+ // }
2806
+ // if (errorCall.stack) {
2807
+ // const stackDef = errorDef.stack!.trim().split("\n")
2808
+ // const stackCall = errorCall.stack.trim().split("\n")
2809
+ // let endStackDef = stackDef.slice(2).join("\n").trim()
2810
+ // if (!endStackDef.includes(`(`)) {
2811
+ // endStackDef = endStackDef.replace(/at (.*)/, "at ($1)")
2812
+ // }
2813
+ // let endStackCall = stackCall.slice(2).join("\n").trim()
2814
+ // if (!endStackCall.includes(`(`)) {
2815
+ // endStackCall = endStackCall.replace(/at (.*)/, "at ($1)")
2816
+ // }
2817
+ // cache = `${endStackDef}\n${endStackCall}`
2818
+ // return cache
2819
+ // }
2820
+ // }
2821
+
2822
+ // return Effect.gen(function*() {
2823
+ // const ctx = yield* CommandContext
2824
+ // ctx.action = command.action
2825
+ // return yield* command.exec(...args).pipe(
2826
+ // Effect.flatten,
2827
+ // Effect.withSpan(
2828
+ // command.action,
2829
+ // { captureStackTrace }
2830
+ // )
2831
+ // )
2832
+ // })
2833
+ // },
2834
+
2835
+ /**
2836
+ * Define a Command for handling user actions with built-in error reporting and state management.
2837
+ *
2838
+ * @param id The internal identifier for the action. Used as a tracing span and to lookup
2839
+ * the user-facing name via internationalization (`action.${id}`).
2840
+ * @param options Optional configuration for internationalization and state.
2841
+ * @param options.i18nCustomKey Custom i18n key to use instead of `id` (e.g., for grouping similar actions)
2842
+ * @param options.state Optional reactive state object (or function returning one) that is
2843
+ * made available to the command effects and can be used for i18n interpolation.
2844
+ * The state is captured at the start of each command execution and remains stable throughout.
2845
+ * @returns A function that executes the command when called (e.g., directly in `@click` handlers).
2846
+ * Built-in error reporting handles failures automatically.
2847
+ *
2848
+ * **Effect Context**: Effects have access to the `CommandContext` service, which provides
2849
+ * the user-facing action name.
2850
+ *
2851
+ * **Returned Properties**:
2852
+ * - `action`: User-facing action name from intl messages (useful for button labels)
2853
+ * - `result`: The command result state
2854
+ * - `waiting`: Boolean indicating if the command is in progress (shorthand for `result.waiting`)
2855
+ * - `handle`: Function to execute the command
2856
+ * - `exec`: The raw Effect that will be executed when calling `handle` (for advanced use cases)
2857
+ * - `i18nKey`, `namespace`, `namespaced`: Helpers for internationalization keys
2858
+ *
2859
+ * **User Feedback**: Use the `withDefaultToast` helper for status notifications, or render
2860
+ * the `result` inline for custom UI feedback.
2861
+ */
2862
+ fn = <
2863
+ const Id extends string,
2864
+ const State extends IntlRecord = IntlRecord,
2865
+ const I18nKey extends string = Id
2866
+ >(
2867
+ id: Id | { id: Id },
2868
+ options?: FnOptions<Id, I18nKey, State>
2869
+ ): Commander.Gen<RT | RTHooks, Id, I18nKey, State> & Commander.NonGen<RT | RTHooks, Id, I18nKey, State> & {
2870
+ state: Context.Service<`Commander.Command.${Id}.state`, State>
2871
+ } => {
2872
+ const resolvedId: Id = typeof id === "string" ? id : id.id
2873
+ return Object.assign(
2874
+ (
2875
+ fn: any,
2876
+ ...combinators: any[]
2877
+ ): any => {
2878
+ // we capture the definition stack here, so we can append it to later stack traces
2879
+ const limit = Error.stackTraceLimit
2880
+ Error.stackTraceLimit = 2
2881
+ const errorDef = new Error()
2882
+ Error.stackTraceLimit = limit
2883
+
2884
+ return this.makeCommand(resolvedId, options, errorDef)(
2885
+ Effect.fnUntraced(
2886
+ // fnUntraced only supports generators as first arg, so we convert to generator if needed
2887
+ isGeneratorFunction(fn) ? fn : function*(...args) {
2888
+ return yield* fn(...args)
2889
+ },
2890
+ ...combinators as [any]
2891
+ ) as any
2892
+ )
2893
+ },
2894
+ makeBaseInfo(resolvedId, options),
2895
+ {
2896
+ state: Context.Service<`Commander.Command.${Id}.state`, State>(
2897
+ `Commander.Command.${resolvedId}.state`
2898
+ )
2899
+ }
2900
+ )
2901
+ }
2902
+
2903
+ /**
2904
+ * Internal factory for stream-backed commands. Accepts a handler that returns a `Stream` directly.
2905
+ * Services (`CommandContext`, `stateTag`) are provided to the stream via `Stream.provideServiceEffect`.
2906
+ */
2907
+ readonly makeStreamCommand = <
2908
+ const Id extends string,
2909
+ const State extends IntlRecord | undefined,
2910
+ const I18nKey extends string = Id
2911
+ >(
2912
+ id_: Id | { id: Id },
2913
+ options?: FnOptions<Id, I18nKey, State>,
2914
+ errorDef?: Error
2915
+ ) => {
2916
+ const id = typeof id_ === "string" ? id_ : id_.id
2917
+ const state = getStateValues(options)
2918
+
2919
+ return Object.assign(
2920
+ <Arg, SA, SE, SR>(
2921
+ handler: (arg: Arg, ctx: Commander.CommandContextLocal2<Id, I18nKey, State>) => Stream.Stream<SA, SE, SR>
2922
+ ) => {
2923
+ const limit = Error.stackTraceLimit
2924
+ Error.stackTraceLimit = 2
2925
+ const localErrorDef = new Error()
2926
+ Error.stackTraceLimit = limit
2927
+ if (!errorDef) {
2928
+ errorDef = localErrorDef
2929
+ }
2930
+
2931
+ const key = `Commander.Command.${id}.state` as const
2932
+ const stateTag = Context.Service<typeof key, State>(key)
2933
+
2934
+ const makeContext_ = () => this.makeContext(id, { ...options, state: state?.value })
2935
+ const initialContext = makeContext_()
2936
+ const context = computed(() => makeContext_())
2937
+ const action = computed(() => context.value.action)
2938
+ const label = computed(() => context.value.label)
2939
+
2940
+ const currentState = Effect.sync(() => state.value)
2941
+
2942
+ // Reactive ref driven by the CommandProgress service — updated imperatively
2943
+ // from inside the stream via `Command.mapProgress(fn)` or `Command.updateProgress(p)`.
2944
+ const progressRef = ref<Progress | undefined>(undefined)
2945
+ const commandProgressService = {
2946
+ update: (p: Progress | undefined) =>
2947
+ Effect.sync(() => {
2948
+ progressRef.value = p
2949
+ })
2950
+ }
2951
+
2952
+ const streamErrorReporter = <A, E, R>(self: Stream.Stream<A, E, R>) =>
2953
+ self.pipe(
2954
+ Stream.tapCause(
2955
+ Effect.fnUntraced(function*(cause) {
2956
+ if (Cause.hasInterruptsOnly(cause)) {
2957
+ console.info(`Interrupted while trying to ${id}`)
2958
+ return
2959
+ }
2960
+
2961
+ const fail = Cause.findErrorOption(cause)
2962
+ if (Option.isSome(fail)) {
2963
+ const message = `Failure trying to ${id}`
2964
+ yield* reportMessage(message, {
2965
+ action: id,
2966
+ error: fail.value
2967
+ })
2968
+ return
2969
+ }
2970
+
2971
+ const ctx = yield* CommandContext
2972
+ const extra = {
2973
+ action: ctx.action,
2974
+ message: `Unexpected Error trying to ${id}`
2975
+ }
2976
+ yield* reportRuntimeError(cause, extra)
2977
+ }, Effect.uninterruptible)
2978
+ )
2979
+ )
2980
+
2981
+ const theStreamHandler = (arg: Arg, ctx: Commander.CommandContextLocal2<Id, I18nKey, State>) =>
2982
+ handler(arg, ctx).pipe(
2983
+ streamErrorReporter,
2984
+ Stream.provideService(CommandProgress, commandProgressService),
2985
+ Stream.provideServiceEffect(stateTag, currentState),
2986
+ Stream.provideServiceEffect(CommandContext, Effect.sync(() => makeContext_()))
2987
+ )
2988
+
2989
+ const waitId = options?.waitKey ? options.waitKey(id) : undefined
2990
+ const blockId = options?.blockKey ? options.blockKey(id) : undefined
2991
+
2992
+ const [result, exec_] = asStreamResult(theStreamHandler)
2993
+
2994
+ const exec = Effect
2995
+ .fnUntraced(
2996
+ function*(...args: [any, any]) {
2997
+ if (waitId !== undefined) registerWait(waitId)
2998
+ if (blockId !== undefined && blockId !== waitId) {
2999
+ registerWait(blockId)
3000
+ }
3001
+ return yield* exec_(...args)
3002
+ },
3003
+ Effect.onExit(() =>
3004
+ Effect.sync(() => {
3005
+ if (waitId !== undefined) unregisterWait(waitId)
3006
+ if (blockId !== undefined && blockId !== waitId) {
3007
+ unregisterWait(blockId)
3008
+ }
3009
+ })
3010
+ )
3011
+ )
3012
+
3013
+ const waiting = waitId !== undefined
3014
+ ? computed(() => result.value.waiting || (waitState.value[waitId] ?? 0) > 0)
3015
+ : computed(() => result.value.waiting)
3016
+
3017
+ const blocked = blockId !== undefined
3018
+ ? computed(() => waiting.value || (waitState.value[blockId] ?? 0) > 0)
3019
+ : computed(() => waiting.value)
3020
+
3021
+ const computeAllowed = options?.allowed
3022
+ const allowed = computeAllowed ? computed(() => computeAllowed(id, state)) : true
3023
+
3024
+ const rt = Effect.context<RT | RTHooks>().pipe(Effect.provide(this.hooks)).pipe(Effect.runSyncWith(this.rt))
3025
+ const runFork = Effect.runForkWith(rt)
3026
+
3027
+ const progress = progressRef
3028
+
3029
+ const handle = Object.assign((arg: Arg) => {
3030
+ arg = toRaw(arg)
3031
+ progressRef.value = undefined // reset progress on new invocation
3032
+ const limit = Error.stackTraceLimit
3033
+ Error.stackTraceLimit = 2
3034
+ const errorCall = new Error()
3035
+ Error.stackTraceLimit = limit
3036
+
3037
+ let cache: false | string = false
3038
+ const captureStackTrace = () => {
3039
+ if (cache !== false) {
3040
+ return cache
3041
+ }
3042
+ if (errorCall.stack) {
3043
+ const stackDef = errorDef!.stack!.trim().split("\n")
3044
+ const stackCall = errorCall.stack.trim().split("\n")
3045
+ let endStackDef = stackDef.slice(2).join("\n").trim()
3046
+ if (!endStackDef.includes(`(`)) {
3047
+ endStackDef = endStackDef.replace(/at (.*)/, "at ($1)")
3048
+ }
3049
+ let endStackCall = stackCall.slice(2).join("\n").trim()
3050
+ if (!endStackCall.includes(`(`)) {
3051
+ endStackCall = endStackCall.replace(/at (.*)/, "at ($1)")
3052
+ }
3053
+ cache = `${endStackDef}\n${endStackCall}`
3054
+ return cache
3055
+ }
3056
+ }
3057
+
3058
+ const command = currentState.pipe(Effect.flatMap((state) => {
3059
+ const rawArg = deepToRaw(arg)
3060
+ const rawState = deepToRaw(state)
3061
+ return Effect.withSpan(
3062
+ exec(arg, { ...context.value, state } as any),
3063
+ id,
3064
+ {
3065
+ captureStackTrace,
3066
+ attributes: {
3067
+ input: rawArg,
3068
+ state: rawState,
3069
+ action: initialContext.action,
3070
+ label: initialContext.label,
3071
+ id: initialContext.id,
3072
+ i18nKey: initialContext.i18nKey
3073
+ }
3074
+ }
3075
+ )
3076
+ }))
3077
+
3078
+ return runFork(command as any)
3079
+ }, { action, label })
3080
+
3081
+ return reactive({
3082
+ id,
3083
+ i18nKey: initialContext.i18nKey,
3084
+ namespace: initialContext.namespace,
3085
+ namespaced: initialContext.namespaced,
3086
+ result,
3087
+ /** reactive – progress driven by `Command.mapProgress` or `Command.updateProgress` inside the stream */
3088
+ progress,
3089
+ waiting,
3090
+ blocked,
3091
+ allowed,
3092
+ action,
3093
+ label,
3094
+ state,
3095
+ handle
3096
+ })
3097
+ },
3098
+ { id }
3099
+ )
3100
+ }
3101
+
3102
+ /**
3103
+ * Define a stream-backed Command for handling user actions.
3104
+ *
3105
+ * Like `fn`, but the body generator (or function) must **return** a `Stream` rather than
3106
+ * an `Effect`. The command's `waiting` state stays `true` while the stream is running and
3107
+ * is set to `false` once it terminates. The reactive `result` ref is updated for every
3108
+ * value emitted by the stream.
3109
+ *
3110
+ * Three handler shapes are accepted:
3111
+ * 1. **Generator returning a Stream** (primary) — may yield Effects freely before returning the stream:
3112
+ * ```ts
3113
+ * Command.streamFn("exportData")(
3114
+ * function*(arg, ctx) {
3115
+ * const token = yield* getAuthToken
3116
+ * return Stream.fromEffect(startExport(token, arg.id)).pipe(
3117
+ * Stream.flatMap((job) => pollProgress(job.id))
3118
+ * )
3119
+ * }
3120
+ * )
3121
+ * ```
3122
+ * 2. **Function returning a Stream directly**: `(arg, ctx) => Stream.make(1, 2, 3)`
3123
+ * 3. **Function returning `Effect<Stream>`**: `(arg, ctx) => Effect.map(setup, (s) => s.stream)`
3124
+ *
3125
+ * @param id The internal identifier for the action (used for tracing and i18n lookup).
3126
+ * @param options Same options as `fn` (`state`, `blockKey`, `waitKey`, `allowed`, `i18nCustomKey`).
3127
+ *
3128
+ * **Progress** — use `Command.mapProgress(fn)` as a stream pipe operator; the mapper receives
3129
+ * `AsyncResult<A, E>` (each value wrapped as `AsyncResult.success(v, { waiting: true })`),
3130
+ * matching the same shape as CommandButton’s `:progress-map` prop. Or call
3131
+ * `Command.updateProgress(p)` for imperative control:
3132
+ *
3133
+ * ```ts
3134
+ * // mapProgress as a combinator arg (outside the handler):
3135
+ * Command.streamFn("exportData")(
3136
+ * function*(arg, ctx) { return makeExportStream(arg.id) },
3137
+ * (s) => s.pipe(Command.mapProgress((r) => AsyncResult.isSuccess(r) && r.value._tag === "OperationProgress" ? { text: `${r.value.completed}/${r.value.total}` } : undefined))
3138
+ * )
3139
+ *
3140
+ * // Or inline inside the handler body:
3141
+ * Command.streamFn("exportData")(function*(arg, ctx) {
3142
+ * return makeExportStream(arg.id).pipe(Command.mapProgress((r) => AsyncResult.isSuccess(r) ? ... : undefined))
3143
+ * })
3144
+ * ```
3145
+ *
3146
+ * **Pipeable combinators** — the 2nd–Nth args follow the same pattern as `fn`: each combinator
3147
+ * receives `(stream, arg, ctx)` and returns a transformed stream:
3148
+ * ```ts
3149
+ * Command.streamFn("exportData")(
3150
+ * handler,
3151
+ * (s, arg, ctx) => s.pipe(Command.mapProgress(fn), Stream.take(100))
3152
+ * )
3153
+ * ```
3154
+ *
3155
+ * **Returned Properties**: `action`, `label`, `result`, `progress`, `waiting`, `blocked`,
3156
+ * `allowed`, `handle`, `i18nKey`, `namespace`, `namespaced`.
3157
+ */
3158
+ streamFn = <
3159
+ const Id extends string,
3160
+ const State extends IntlRecord = IntlRecord,
3161
+ const I18nKey extends string = Id
3162
+ >(
3163
+ id: Id | { id: Id },
3164
+ options?: FnOptions<Id, I18nKey, State>
3165
+ ):
3166
+ & Commander.StreamGen<RT | RTHooks, Id, I18nKey, State>
3167
+ & Commander.NonGenStream<RT | RTHooks, Id, I18nKey, State>
3168
+ & {
3169
+ state: Context.Service<`Commander.Command.${Id}.state`, State>
3170
+ } =>
3171
+ {
3172
+ const resolvedId = typeof id === "string" ? id : id.id
3173
+
3174
+ type StreamOrEffect = Stream.Stream<any, any, any> | Effect.Effect<Stream.Stream<any, any, any>, any, any>
3175
+
3176
+ const toRawHandler = (fn: any): (arg: any, ctx: any) => StreamOrEffect => {
3177
+ if (isGeneratorFunction(fn)) {
3178
+ return Effect.fnUntraced(function*(arg: any, ctx: any) {
3179
+ return yield* (fn as (arg: any, ctx: any) => Generator<any, Stream.Stream<any, any, any>>)(arg, ctx)
3180
+ })
3181
+ }
3182
+ return fn
3183
+ }
3184
+
3185
+ const toFinalStream = (value: StreamOrEffect): Stream.Stream<any, any, any> =>
3186
+ Stream.isStream(value) ? value : Stream.unwrap(value as Effect.Effect<Stream.Stream<any, any, any>, any, any>)
3187
+
3188
+ return Object.assign(
3189
+ (fn: any, ...combinators: Array<(s: any, arg: any, ctx: any) => any>): any => {
3190
+ const limit = Error.stackTraceLimit
3191
+ Error.stackTraceLimit = 2
3192
+ const errorDef = new Error()
3193
+ Error.stackTraceLimit = limit
3194
+
3195
+ const rawHandler = toRawHandler(fn)
3196
+ const handler = (arg: any, ctx: any) => {
3197
+ let current: any = rawHandler(arg, ctx)
3198
+ for (const combinator of combinators) {
3199
+ current = combinator(current, arg, ctx)
3200
+ }
3201
+ return toFinalStream(current)
3202
+ }
3203
+
3204
+ return this.makeStreamCommand(id, options, errorDef)(handler)
3205
+ },
3206
+ makeBaseInfo(resolvedId, options),
3207
+ {
3208
+ state: Context.Service<`Commander.Command.${Id}.state`, State>(
3209
+ `Commander.Command.${resolvedId}.state`
3210
+ )
3211
+ }
3212
+ )
3213
+ }
3214
+
3215
+ /** @deprecated */
3216
+
3217
+ alt2: <
3218
+ const Id extends string,
3219
+ MutArg,
3220
+ MutA,
3221
+ MutE,
3222
+ MutR,
3223
+ const I18nKey extends string = Id,
3224
+ State extends IntlRecord | undefined = undefined
3225
+ >(
3226
+ id:
3227
+ | Id
3228
+ | { id: Id; mutate: (arg: MutArg) => Effect.Effect<MutA, MutE, MutR> }
3229
+ | ((arg: MutArg) => Effect.Effect<MutA, MutE, MutR>) & { id: Id },
3230
+ options?: FnOptions<Id, I18nKey, State>
3231
+ ) =>
3232
+ & Commander.CommandContextLocal<Id, I18nKey>
3233
+ & (<A, E, R extends RT | RTHooks | CommandContext | `Commander.Command.${Id}.state`, Arg = void>(
3234
+ handler: (
3235
+ ctx: Effect.fn.Traced & Effect.fn.Untraced & Commander.CommandContextLocal<Id, I18nKey> & {
3236
+ // todo: only if we passed in one
3237
+ mutate: (arg: Arg) => Effect.Effect<MutA, MutE, MutR>
3238
+ }
3239
+ ) => (arg: Arg, ctx: Commander.CommandContextLocal2<Id, I18nKey, State>) => Effect.Effect<A, E, R>
3240
+ ) => Commander.CommandOut<Arg, A, E, R, Id, I18nKey, State>) = (
3241
+ _id,
3242
+ options?
3243
+ ) => {
3244
+ const isObject = Predicate.isObjectKeyword(_id)
3245
+ const id = isObject ? _id.id : _id
3246
+ const baseInfo = makeBaseInfo(id, options)
3247
+ const idCmd = this.makeCommand(id, options)
3248
+ // TODO: implement proper tracing stack
3249
+ return Object.assign((cb: any) =>
3250
+ idCmd(cb(
3251
+ Object.assign(
3252
+ (fn: any, ...combinators: any[]) =>
3253
+ Effect.fnUntraced(
3254
+ // fnUntraced only supports generators as first arg, so we convert to generator if needed
3255
+ isGeneratorFunction(fn) ? fn : function*(...args) {
3256
+ return yield* fn(...args)
3257
+ },
3258
+ ...combinators as [any]
3259
+ ),
3260
+ baseInfo,
3261
+ isObject
3262
+ ? { mutate: "mutate" in _id ? _id.mutate : typeof _id === "function" ? _id : undefined }
3263
+ : {}
3264
+ )
3265
+ )), baseInfo) as any
3266
+ }
3267
+
3268
+ alt = this.makeCommand as unknown as <
3269
+ const Id extends string,
3270
+ const I18nKey extends string = Id,
3271
+ State extends IntlRecord | undefined = undefined
3272
+ >(
3273
+ id: Id,
3274
+ customI18nKey?: I18nKey
3275
+ ) =>
3276
+ & Commander.CommandContextLocal<Id, I18nKey>
3277
+ & (<A, E, R extends RT | CommandContext | `Commander.Command.${Id}.state`, Arg = void>(
3278
+ handler: (arg: Arg, ctx: Commander.CommandContextLocal2<Id, I18nKey, State>) => Effect.Effect<A, E, R>
3279
+ ) => Commander.CommandOut<Arg, A, E, R, Id, I18nKey, State>)
3280
+
3281
+ /**
3282
+ * Define a Command for handling user actions with built-in error reporting and state management.
3283
+ *
3284
+ * @param mutation The mutation function to take the identifier and initial handler from. Used as a tracing span and to lookup
3285
+ * the user-facing name via internationalization (`action.${id}`).
3286
+ * @param options Optional configuration for internationalization and state.
3287
+ * @param options.i18nCustomKey Custom i18n key to use instead of `id` (e.g., for grouping similar actions)
3288
+ * @param options.state Optional reactive state object (or function returning one) that is
3289
+ * made available to the command effects and can be used for i18n interpolation.
3290
+ * The state is captured at the start of each command execution and remains stable throughout.
3291
+ * @returns A function that executes the command when called (e.g., directly in `@click` handlers).
3292
+ * Built-in error reporting handles failures automatically.
3293
+ *
3294
+ * **Effect Context**: Effects have access to the `CommandContext` service, which provides
3295
+ * the user-facing action name.
3296
+ *
3297
+ * **Returned Properties**:
3298
+ * - `action`: User-facing action name from intl messages (useful for button labels)
3299
+ * - `result`: The command result state
3300
+ * - `waiting`: Boolean indicating if the command is in progress (shorthand for `result.waiting`)
3301
+ * - `handle`: Function to execute the command
3302
+ * - `exec`: The raw Effect that will be executed when calling `handle` (for advanced use cases)
3303
+ * - `i18nKey`, `namespace`, `namespaced`: Helpers for internationalization keys
3304
+ *
3305
+ * **User Feedback**: Use the `withDefaultToast` helper for status notifications, or render
3306
+ * the `result` inline for custom UI feedback.
3307
+ */
3308
+ streamWrap = <
3309
+ const Id extends string,
3310
+ Arg,
3311
+ SA,
3312
+ SE,
3313
+ SR,
3314
+ const State extends IntlRecord = IntlRecord,
3315
+ I18nKey extends string = Id
3316
+ >(
3317
+ handler: (arg: Arg, ctx: Commander.CommandContextLocal2<Id, I18nKey, State>) => Stream.Stream<SA, SE, SR>,
3318
+ id: Id,
3319
+ options?: FnOptions<Id, I18nKey, State>
3320
+ ): Commander.StreamerWrap<RT | RTHooks, Id, I18nKey, State, Arg, SA, SE, SR> => {
3321
+ return Object.assign(
3322
+ (...combinators: any[]): any => {
3323
+ const limit = Error.stackTraceLimit
3324
+ Error.stackTraceLimit = 2
3325
+ const errorDef = new Error()
3326
+ Error.stackTraceLimit = limit
3327
+ return this.makeStreamCommand(id, options, errorDef)(
3328
+ combinators.length === 0
3329
+ ? handler
3330
+ : (arg: Arg, ctx: Commander.CommandContextLocal2<Id, I18nKey, State>) => {
3331
+ let current: any = handler(arg, ctx)
3332
+ for (const combinator of combinators) {
3333
+ current = combinator(current, arg, ctx)
3334
+ }
3335
+ return current
3336
+ }
3337
+ )
3338
+ },
3339
+ makeBaseInfo(id, options),
3340
+ {
3341
+ state: Context.Service<`Commander.Command.${Id}.state`, State>(
3342
+ `Commander.Command.${id}.state`
3343
+ )
3344
+ }
3345
+ )
3346
+ }
3347
+
3348
+ wrap = <
3349
+ const Id extends string,
3350
+ Arg,
3351
+ A,
3352
+ E,
3353
+ R,
3354
+ const State extends IntlRecord = IntlRecord,
3355
+ I18nKey extends string = Id
3356
+ >(
3357
+ mutation:
3358
+ | { mutate: (arg: Arg) => Effect.Effect<A, E, R>; id: Id }
3359
+ | ((arg: Arg) => Effect.Effect<A, E, R>) & { id: Id },
3360
+ options?: FnOptions<Id, I18nKey, State>
3361
+ ): Commander.CommanderWrap<RT | RTHooks, Id, I18nKey, State, Arg, A, E, R> => {
3362
+ const callMutation = mutation
3363
+ return Object.assign(
3364
+ (
3365
+ ...combinators: any[]
3366
+ ): any => {
3367
+ // we capture the definition stack here, so we can append it to later stack traces
3368
+ const limit = Error.stackTraceLimit
3369
+ Error.stackTraceLimit = 2
3370
+ const errorDef = new Error()
3371
+ Error.stackTraceLimit = limit
3372
+ const mutate = "mutate" in callMutation
3373
+ ? callMutation.mutate
3374
+ : callMutation
3375
+
3376
+ return this.makeCommand(callMutation.id, options, errorDef)(
3377
+ Effect.fnUntraced(
3378
+ // fnUntraced only supports generators as first arg, so we convert to generator if needed
3379
+ isGeneratorFunction(mutate) ? mutate : function*(arg: Arg) {
3380
+ return yield* mutate(arg)
3381
+ },
3382
+ ...combinators as [any]
3383
+ ) as any
3384
+ )
3385
+ },
3386
+ makeBaseInfo(callMutation.id, options),
3387
+ {
3388
+ state: Context.Service<`Commander.Command.${Id}.state`, State>(
3389
+ `Commander.Command.${callMutation.id}.state`
3390
+ )
3391
+ }
3392
+ )
3393
+ }
3394
+ }
3395
+
3396
+ // @effect-diagnostics-next-line missingEffectServiceDependency:off
3397
+ export class Commander extends Context.Service<Commander>()("Commander", {
3398
+ make: Effect.gen(function*() {
3399
+ const i18n = yield* I18n
3400
+ return <RT, RTHooks>(rt: Context.Context<RT>, rtHooks: Layer.Layer<RTHooks, never, RT>) =>
3401
+ new CommanderImpl(rt, i18n, rtHooks)
3402
+ })
3403
+ }) {
3404
+ static readonly DefaultWithoutDependencies = Layer.effect(this, this.make)
3405
+ static readonly Default = this.DefaultWithoutDependencies
3406
+ }