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

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