@effect-app/vue 4.0.0-beta.20 → 4.0.0-beta.201

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 +1486 -0
  2. package/dist/commander.d.ts +628 -0
  3. package/dist/commander.d.ts.map +1 -0
  4. package/dist/commander.js +1055 -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 +46 -0
  42. package/dist/toast.d.ts.map +1 -0
  43. package/dist/toast.js +32 -0
  44. package/dist/withToast.d.ts +26 -0
  45. package/dist/withToast.d.ts.map +1 -0
  46. package/dist/withToast.js +54 -0
  47. package/examples/streamMutation.ts +70 -0
  48. package/package.json +48 -50
  49. package/src/commander.ts +3384 -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} +11 -25
  61. package/src/{experimental/withToast.ts → withToast.ts} +28 -10
  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 +3274 -122
  68. package/test/dist/stubs.d.ts.map +1 -1
  69. package/test/dist/stubs.js +178 -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 +214 -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,3384 @@
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
+ ...options?.showSpanInfo === false ? { showSpanInfo: options.showSpanInfo } : {}
2247
+ })(_, ...args)
2248
+ )
2249
+ }),
2250
+
2251
+ /**
2252
+ * Stream-aware version of `withDefaultToast`. Use this as a combinator inside `streamFn`
2253
+ * (or anywhere a `Stream` needs toast lifecycle handling) instead of `withDefaultToast`.
2254
+ *
2255
+ * Unlike `withDefaultToast` (which only wraps the initial `Effect`), this combinator:
2256
+ * - Shows the "waiting" toast **before** the stream starts
2257
+ * - Updates the waiting toast with progress text when `progress` is set and a new element arrives
2258
+ * - Shows the "success" toast only **after** the stream drains fully without error
2259
+ * - Shows the "failure" toast if the stream errors or fails
2260
+ *
2261
+ * Accepts either a `Stream<A, E, R>` or an `Effect<Stream<A, E, R>, EE, ER>` as input,
2262
+ * so it works in both the `NonGenStream` and `StreamGen` overloads of `streamFn`.
2263
+ *
2264
+ * @example
2265
+ * ```ts
2266
+ * Command.streamFn("exportData")(
2267
+ * function*(arg, ctx) { return makeExportStream(arg.id) },
2268
+ * Command.withDefaultToastStream({
2269
+ * progress: (r) =>
2270
+ * AsyncResult.isSuccess(r) && r.value._tag === "OperationProgress"
2271
+ * ? { text: `${r.value.completed}/${r.value.total}`, percentage: r.value.completed / r.value.total * 100 }
2272
+ * : undefined
2273
+ * })
2274
+ * )
2275
+ * ```
2276
+ */
2277
+ withDefaultToastStream: <A, E, R, Args extends Array<unknown>>(
2278
+ options?: {
2279
+ stableToastId?:
2280
+ | undefined
2281
+ | true
2282
+ | string
2283
+ | ((id: string, arg: NoInfer<Args>[0], ctx: NoInfer<Args>[1]) => true | string | undefined)
2284
+ errorRenderer?: (e: E, action: string, arg: NoInfer<Args>[0], ctx: NoInfer<Args>[1]) => string | undefined
2285
+ showSpanInfo?: false
2286
+ onWaiting?:
2287
+ | null
2288
+ | undefined
2289
+ | string
2290
+ | ((id: string, arg: NoInfer<Args>[0], ctx: NoInfer<Args>[1]) => string | null | undefined)
2291
+ onSuccess?:
2292
+ | null
2293
+ | undefined
2294
+ | string
2295
+ | ((a: A, action: string, arg: NoInfer<Args>[0], ctx: NoInfer<Args>[1]) => string | null | undefined)
2296
+ /** 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). */
2297
+ progress?: (result: AsyncResult.AsyncResult<A, E>) => Progress | undefined
2298
+ }
2299
+ ) =>
2300
+ (
2301
+ self: Stream.Stream<A, E, R> | Effect.Effect<Stream.Stream<A, E, R>, any, any>,
2302
+ ...args: Args
2303
+ ): Stream.Stream<A, E, R | I18n | Toast | CommandContext> => {
2304
+ const rawStream: Stream.Stream<A, E, R> = Stream.isStream(self)
2305
+ ? self
2306
+ : Stream.unwrap(self)
2307
+
2308
+ return Stream.unwrap(Effect.gen(function*() {
2309
+ const cc = yield* CommandContext
2310
+ const { intl } = yield* I18n
2311
+ const toast = yield* Toast
2312
+
2313
+ const customWaiting = cc.namespaced("waiting")
2314
+ const hasCustomWaiting = !!intl.messages[customWaiting]
2315
+ const customSuccess = cc.namespaced("success")
2316
+ const hasCustomSuccess = !!intl.messages[customSuccess]
2317
+ const customFailure = cc.namespaced("failure")
2318
+ const hasCustomFailure = !!intl.messages[customFailure]
2319
+
2320
+ const stableToastId: string | undefined = options?.stableToastId
2321
+ ? typeof options.stableToastId === "string"
2322
+ ? options.stableToastId
2323
+ : typeof options.stableToastId === "boolean"
2324
+ ? cc.id
2325
+ : typeof options.stableToastId === "function"
2326
+ ? (() => {
2327
+ const r = (options.stableToastId as (...a: any[]) => true | string | undefined)(cc.id, ...args)
2328
+ if (typeof r === "string") return r
2329
+ if (r === true) return cc.id
2330
+ return undefined
2331
+ })()
2332
+ : undefined
2333
+ : undefined
2334
+
2335
+ const baseTimeout = 3_000
2336
+
2337
+ const waitingMsg: string | null = options?.onWaiting === null
2338
+ ? null
2339
+ : typeof options?.onWaiting === "string"
2340
+ ? options.onWaiting
2341
+ : typeof options?.onWaiting === "function"
2342
+ ? (options.onWaiting as (...a: any[]) => string | null | undefined)(cc.id, ...args) ?? null
2343
+ : hasCustomWaiting
2344
+ ? intl.formatMessage({ id: customWaiting }, cc.state)
2345
+ : intl.formatMessage({ id: "handle.waiting" }, { action: cc.action })
2346
+
2347
+ const toastId: string | number | undefined = waitingMsg === null
2348
+ ? stableToastId
2349
+ : stableToastId ?? `wait-${Math.random().toString(36).slice(2)}`
2350
+
2351
+ if (waitingMsg !== null) {
2352
+ yield* toast.info(waitingMsg, { id: toastId!, timeout: Infinity })
2353
+ }
2354
+
2355
+ const failureHandler = defaultFailureMessageHandler<E, [], never, never>(
2356
+ hasCustomFailure ? intl.formatMessage({ id: customFailure }, cc.state) : cc.action,
2357
+ options?.errorRenderer as ErrorRenderer<E, []> | undefined
2358
+ )
2359
+
2360
+ let lastValue: A | undefined = undefined
2361
+ let didFail = false
2362
+
2363
+ const composed = rawStream.pipe(
2364
+ Stream.tap((v) =>
2365
+ Effect.gen(function*() {
2366
+ lastValue = v
2367
+ if (options?.progress !== undefined) {
2368
+ const p = options.progress(AsyncResult.success(v, { waiting: true }))
2369
+ if (p !== undefined) {
2370
+ // Update CommandProgress so CommandButton progress indicator is also driven
2371
+ yield* CommandProgress.use((s) => s.update(p))
2372
+ if (toastId !== undefined) {
2373
+ const progressText = typeof p === "string" ? p : p.text
2374
+ const msg = waitingMsg ? `${waitingMsg}\n${progressText}` : progressText
2375
+ yield* toast.info(msg, { id: toastId, timeout: Infinity })
2376
+ }
2377
+ }
2378
+ }
2379
+ })
2380
+ ),
2381
+ Stream.tapCause(Effect.fnUntraced(function*(cause) {
2382
+ didFail = true
2383
+ if (Cause.hasInterruptsOnly(cause)) {
2384
+ if (toastId !== undefined) yield* toast.dismiss(toastId)
2385
+ return
2386
+ }
2387
+
2388
+ const spanInfo = options?.showSpanInfo !== false
2389
+ ? yield* Effect.currentSpan.pipe(
2390
+ Effect.map((span) => `\nTrace: ${span.traceId}\nSpan: ${span.spanId}`),
2391
+ Effect.orElseSucceed(() => "")
2392
+ )
2393
+ : ""
2394
+
2395
+ const t = yield* failureHandler(Cause.findErrorOption(cause))
2396
+ const opts = { timeout: baseTimeout * 2 }
2397
+
2398
+ if (typeof t === "object") {
2399
+ const message = t.message + spanInfo
2400
+ yield* t.level === "warn"
2401
+ ? toast.warning(message, toastId !== undefined ? { ...opts, id: toastId } : opts)
2402
+ : toast.error(message, toastId !== undefined ? { ...opts, id: toastId } : opts)
2403
+ } else {
2404
+ yield* toast.error(t + spanInfo, toastId !== undefined ? { ...opts, id: toastId } : opts)
2405
+ }
2406
+ }, Effect.uninterruptible)),
2407
+ Stream.ensuring(Effect.suspend(() => {
2408
+ if (didFail) return Effect.void
2409
+
2410
+ if (options?.onSuccess === null) return Effect.void
2411
+
2412
+ const successMsg: string | null = typeof options?.onSuccess === "string"
2413
+ ? options.onSuccess
2414
+ : typeof options?.onSuccess === "function"
2415
+ ? (options.onSuccess as (...a: any[]) => string | null | undefined)(lastValue, cc.action, ...args) ?? null
2416
+ : hasCustomSuccess
2417
+ ? intl.formatMessage({ id: customSuccess }, cc.state)
2418
+ : intl.formatMessage({ id: "handle.success" }, { action: cc.action })
2419
+
2420
+ if (successMsg === null) return Effect.void
2421
+
2422
+ return toast.success(
2423
+ successMsg,
2424
+ toastId !== undefined ? { id: toastId, timeout: baseTimeout } : { timeout: baseTimeout }
2425
+ )
2426
+ }))
2427
+ )
2428
+
2429
+ return (toastId !== undefined
2430
+ ? composed.pipe(Stream.provideService(CurrentToastId, CurrentToastId.of({ toastId })))
2431
+ : composed) as unknown as Stream.Stream<A, E, R>
2432
+ }))
2433
+ },
2434
+
2435
+ /** borrowing the idea from Families in Effect Atom */
2436
+ family: <T extends object, Arg, ArgIn = Arg>(
2437
+ maker: (arg: Arg) => T,
2438
+ keyMaker?: (arg: ArgIn) => Arg
2439
+ ): (arg: ArgIn) => T => {
2440
+ const commands = MutableHashMap.empty<Arg, WeakRef<T>>()
2441
+ const registry = new FinalizationRegistry<Arg>((arg) => {
2442
+ MutableHashMap.remove(commands, arg)
2443
+ })
2444
+
2445
+ return (_k: ArgIn) => {
2446
+ const k = keyMaker ? keyMaker(_k) : _k as unknown as Arg
2447
+ // we want to compare structurally, unless custom equal/hash has been implemented
2448
+ const item = MutableHashMap.get(commands, k).pipe(Option.flatMap((r) => Option.fromNullishOr(r.deref())))
2449
+ if (item.value) {
2450
+ return item.value
2451
+ }
2452
+ const v = maker(k)
2453
+ MutableHashMap.set(commands, k, new WeakRef(v))
2454
+
2455
+ registry.register(v, k)
2456
+ return v
2457
+ }
2458
+ }
2459
+ }
2460
+
2461
+ const makeBaseInfo = <const Id extends string, const I18nKey extends string = Id>(
2462
+ id: Id,
2463
+ options?: Pick<FnOptionsInternal<I18nKey>, "i18nCustomKey">
2464
+ ) => {
2465
+ if (!id) throw new Error("must specify an id")
2466
+ const i18nKey: I18nKey = options?.i18nCustomKey ?? id as unknown as I18nKey
2467
+
2468
+ const namespace = `action.${i18nKey}` as const
2469
+
2470
+ const context = {
2471
+ id,
2472
+ i18nKey,
2473
+ namespace,
2474
+ namespaced: <const K extends string>(k: K) => `${namespace}.${k}` as const
2475
+ }
2476
+
2477
+ return context
2478
+ }
2479
+
2480
+ const waitState = ref<Record<string, number>>({})
2481
+ const registerWait = (id: string) => {
2482
+ // console.debug("register wait", id)
2483
+ waitState.value[id] = waitState.value[id] ? waitState.value[id] + 1 : 1
2484
+ }
2485
+ const unregisterWait = (id: string) => {
2486
+ // console.debug("unregister wait", id)
2487
+ if (waitState.value[id]) {
2488
+ waitState.value[id] = waitState.value[id] - 1
2489
+ if (waitState.value[id] <= 0) {
2490
+ delete waitState.value[id]
2491
+ }
2492
+ }
2493
+ }
2494
+
2495
+ const getStateValues = <
2496
+ const Id extends string,
2497
+ const I18nKey extends string,
2498
+ State extends IntlRecord | undefined
2499
+ >(
2500
+ options?: FnOptions<Id, I18nKey, State>
2501
+ ): ComputedRef<State> => {
2502
+ const state_ = options?.state
2503
+ const state = !state_ ? computed(() => undefined as State) : typeof state_ === "function"
2504
+ ? computed(state_)
2505
+ : state_
2506
+ return state
2507
+ }
2508
+
2509
+ // class preserves JSDoc throughout..
2510
+ export class CommanderImpl<RT, RTHooks> {
2511
+ constructor(
2512
+ private readonly rt: Context.Context<RT>,
2513
+ private readonly intl: I18n,
2514
+ private readonly hooks: Layer.Layer<RTHooks, never, RT>
2515
+ ) {
2516
+ }
2517
+
2518
+ readonly makeContext = <const Id extends string, const I18nKey extends string = Id>(
2519
+ id: Id,
2520
+ options?: FnOptionsInternal<I18nKey>
2521
+ ) => {
2522
+ if (!id) throw new Error("must specify an id")
2523
+ const i18nKey: I18nKey = options?.i18nCustomKey ?? id as unknown as I18nKey
2524
+
2525
+ const namespace = `action.${i18nKey}` as const
2526
+
2527
+ // must remain stable through out single call
2528
+ const action = this.intl.formatMessage({
2529
+ id: namespace,
2530
+ defaultMessage: id
2531
+ }, { ...options?.state, _isLabel: false })
2532
+
2533
+ const label = this.intl.formatMessage({
2534
+ id: namespace,
2535
+ defaultMessage: id
2536
+ }, { ...options?.state, _isLabel: true })
2537
+
2538
+ const context = CommandContext.of({
2539
+ ...makeBaseInfo(id, options),
2540
+ action,
2541
+ label,
2542
+ state: options?.state
2543
+ })
2544
+
2545
+ return context
2546
+ }
2547
+
2548
+ readonly makeCommand = <
2549
+ const Id extends string,
2550
+ const State extends IntlRecord | undefined,
2551
+ const I18nKey extends string = Id
2552
+ >(
2553
+ id_: Id | { id: Id },
2554
+ options?: FnOptions<Id, I18nKey, State>,
2555
+ errorDef?: Error
2556
+ ) => {
2557
+ const id = typeof id_ === "string" ? id_ : id_.id
2558
+ const state = getStateValues(options)
2559
+
2560
+ return Object.assign(
2561
+ <Arg, A, E, R extends RT | RTHooks | CommandContext | `Commander.Command.${Id}.state`>(
2562
+ handler: (arg: Arg, ctx: Commander.CommandContextLocal2<Id, I18nKey, State>) => Effect.Effect<A, E, R>
2563
+ ) => {
2564
+ // we capture the definition stack here, so we can append it to later stack traces
2565
+ const limit = Error.stackTraceLimit
2566
+ Error.stackTraceLimit = 2
2567
+ const localErrorDef = new Error()
2568
+ Error.stackTraceLimit = limit
2569
+ if (!errorDef) {
2570
+ errorDef = localErrorDef
2571
+ }
2572
+
2573
+ const key = `Commander.Command.${id}.state` as const
2574
+ const stateTag = Context.Service<typeof key, State>(key)
2575
+
2576
+ const makeContext_ = () => this.makeContext(id, { ...options, state: state?.value })
2577
+ const initialContext = makeContext_()
2578
+ const context = computed(() => makeContext_())
2579
+ const action = computed(() => context.value.action)
2580
+ const label = computed(() => context.value.label)
2581
+
2582
+ const errorReporter = <A, E, R>(self: Effect.Effect<A, E, R>) =>
2583
+ self.pipe(
2584
+ Effect.tapCause(
2585
+ Effect.fnUntraced(function*(cause) {
2586
+ if (Cause.hasInterruptsOnly(cause)) {
2587
+ console.info(`Interrupted while trying to ${id}`)
2588
+ return
2589
+ }
2590
+
2591
+ const fail = Cause.findErrorOption(cause)
2592
+ if (Option.isSome(fail)) {
2593
+ // if (fail.value._tag === "SuppressErrors") {
2594
+ // console.info(
2595
+ // `Suppressed error trying to ${action}`,
2596
+ // fail.value,
2597
+ // )
2598
+ // return
2599
+ // }
2600
+ const message = `Failure trying to ${id}`
2601
+ yield* reportMessage(message, {
2602
+ action: id,
2603
+ error: fail.value
2604
+ })
2605
+ return
2606
+ }
2607
+
2608
+ const context = yield* CommandContext
2609
+ const extra = {
2610
+ action: context.action,
2611
+ message: `Unexpected Error trying to ${id}`
2612
+ }
2613
+ yield* reportRuntimeError(cause, extra)
2614
+ }, Effect.uninterruptible)
2615
+ )
2616
+ )
2617
+
2618
+ const currentState = Effect.sync(() => state.value)
2619
+
2620
+ const theHandler = flow(
2621
+ handler,
2622
+ errorReporter,
2623
+ // all must be within the Effect.fn to fit within the Span
2624
+ Effect.provideServiceEffect(
2625
+ stateTag,
2626
+ currentState
2627
+ ),
2628
+ Effect.provideServiceEffect(
2629
+ CommandContext,
2630
+ Effect.sync(() => makeContext_())
2631
+ )
2632
+ )
2633
+ const waitId = options?.waitKey ? options.waitKey(id) : undefined
2634
+ const blockId = options?.blockKey ? options.blockKey(id) : undefined
2635
+
2636
+ const [result, exec_] = asResult(theHandler)
2637
+
2638
+ const exec = Effect
2639
+ .fnUntraced(
2640
+ function*(...args: [any, any]) {
2641
+ if (waitId !== undefined) registerWait(waitId)
2642
+ if (blockId !== undefined && blockId !== waitId) {
2643
+ registerWait(blockId)
2644
+ }
2645
+ return yield* exec_(...args)
2646
+ },
2647
+ Effect.onExit(() =>
2648
+ Effect.sync(() => {
2649
+ if (waitId !== undefined) unregisterWait(waitId)
2650
+ if (blockId !== undefined && blockId !== waitId) {
2651
+ unregisterWait(blockId)
2652
+ }
2653
+ })
2654
+ )
2655
+ )
2656
+
2657
+ const waiting = waitId !== undefined
2658
+ ? computed(() => result.value.waiting || (waitState.value[waitId] ?? 0) > 0)
2659
+ : computed(() => result.value.waiting)
2660
+
2661
+ const blocked = blockId !== undefined
2662
+ ? computed(() => waiting.value || (waitState.value[blockId] ?? 0) > 0)
2663
+ : computed(() => waiting.value)
2664
+
2665
+ const computeAllowed = options?.allowed
2666
+ const allowed = computeAllowed ? computed(() => computeAllowed(id, state)) : true
2667
+
2668
+ const rt = Effect.context<RT | RTHooks>().pipe(Effect.provide(this.hooks)).pipe(Effect.runSyncWith(this.rt))
2669
+ const runFork = Effect.runForkWith(rt)
2670
+
2671
+ const handle = Object.assign((arg: Arg) => {
2672
+ arg = toRaw(arg) // remove outside vue proxy bs
2673
+ // we capture the call site stack here
2674
+ const limit = Error.stackTraceLimit
2675
+ Error.stackTraceLimit = 2
2676
+ const errorCall = new Error()
2677
+ Error.stackTraceLimit = limit
2678
+
2679
+ let cache: false | string = false
2680
+ const captureStackTrace = () => {
2681
+ // in case of an error, we want to append the definition stack to the call site stack,
2682
+ // so we can see where the handler was defined too
2683
+
2684
+ if (cache !== false) {
2685
+ return cache
2686
+ }
2687
+ if (errorCall.stack) {
2688
+ const stackDef = errorDef!.stack!.trim().split("\n")
2689
+ const stackCall = errorCall.stack.trim().split("\n")
2690
+ let endStackDef = stackDef.slice(2).join("\n").trim()
2691
+ if (!endStackDef.includes(`(`)) {
2692
+ endStackDef = endStackDef.replace(/at (.*)/, "at ($1)")
2693
+ }
2694
+ let endStackCall = stackCall.slice(2).join("\n").trim()
2695
+ if (!endStackCall.includes(`(`)) {
2696
+ endStackCall = endStackCall.replace(/at (.*)/, "at ($1)")
2697
+ }
2698
+ cache = `${endStackDef}\n${endStackCall}`
2699
+ return cache
2700
+ }
2701
+ }
2702
+
2703
+ const command = currentState.pipe(Effect.flatMap((state) => {
2704
+ const rawArg = deepToRaw(arg)
2705
+ const rawState = deepToRaw(state)
2706
+ return Effect.withSpan(
2707
+ exec(arg, { ...context.value, state } as any),
2708
+ id,
2709
+ {
2710
+ captureStackTrace,
2711
+ attributes: {
2712
+ input: rawArg,
2713
+ state: rawState,
2714
+ action: initialContext.action,
2715
+ label: initialContext.label,
2716
+ id: initialContext.id,
2717
+ i18nKey: initialContext.i18nKey
2718
+ }
2719
+ }
2720
+ )
2721
+ }))
2722
+
2723
+ return runFork(command)
2724
+ }, { action, label })
2725
+
2726
+ return reactive({
2727
+ /** static */
2728
+ id,
2729
+
2730
+ /** the base i18n key, based on id by default. static */
2731
+ i18nKey: initialContext.i18nKey,
2732
+ /** the `action.` namespace based on i18nKey.. static */
2733
+ namespace: initialContext.namespace,
2734
+
2735
+ /** easy generate namespaced 18n keys, based on namespace. static */
2736
+ namespaced: initialContext.namespaced,
2737
+
2738
+ /** reactive */
2739
+ result,
2740
+ /** always undefined for non-stream commands */
2741
+ progress: undefined,
2742
+ /** reactive */
2743
+ waiting,
2744
+ /** reactive */
2745
+ blocked,
2746
+ /** reactive */
2747
+ allowed,
2748
+ /** reactive */
2749
+ action,
2750
+ /** reactive */
2751
+ label,
2752
+ /** reactive */
2753
+ state,
2754
+
2755
+ handle
2756
+ })
2757
+ },
2758
+ { id }
2759
+ )
2760
+ }
2761
+
2762
+ // /** @experimental */
2763
+ // takeOver:
2764
+ // <Args extends any[], A, E, R, const Id extends string>(command: Commander.CommandOut<Args, A, E, R, Id,I18nKey>) =>
2765
+ // (...args: Args) => {
2766
+ // // we capture the call site stack here
2767
+ // const limit = Error.stackTraceLimit
2768
+ // Error.stackTraceLimit = 2
2769
+ // const errorCall = new Error()
2770
+ // const localErrorDef = new Error()
2771
+ // Error.stackTraceLimit = limit
2772
+
2773
+ // // TODO
2774
+ // const errorDef = localErrorDef
2775
+
2776
+ // let cache: false | string = false
2777
+ // const captureStackTrace = () => {
2778
+ // // in case of an error, we want to append the definition stack to the call site stack,
2779
+ // // so we can see where the handler was defined too
2780
+
2781
+ // if (cache !== false) {
2782
+ // return cache
2783
+ // }
2784
+ // if (errorCall.stack) {
2785
+ // const stackDef = errorDef.stack!.trim().split("\n")
2786
+ // const stackCall = errorCall.stack.trim().split("\n")
2787
+ // let endStackDef = stackDef.slice(2).join("\n").trim()
2788
+ // if (!endStackDef.includes(`(`)) {
2789
+ // endStackDef = endStackDef.replace(/at (.*)/, "at ($1)")
2790
+ // }
2791
+ // let endStackCall = stackCall.slice(2).join("\n").trim()
2792
+ // if (!endStackCall.includes(`(`)) {
2793
+ // endStackCall = endStackCall.replace(/at (.*)/, "at ($1)")
2794
+ // }
2795
+ // cache = `${endStackDef}\n${endStackCall}`
2796
+ // return cache
2797
+ // }
2798
+ // }
2799
+
2800
+ // return Effect.gen(function*() {
2801
+ // const ctx = yield* CommandContext
2802
+ // ctx.action = command.action
2803
+ // return yield* command.exec(...args).pipe(
2804
+ // Effect.flatten,
2805
+ // Effect.withSpan(
2806
+ // command.action,
2807
+ // { captureStackTrace }
2808
+ // )
2809
+ // )
2810
+ // })
2811
+ // },
2812
+
2813
+ /**
2814
+ * Define a Command for handling user actions with built-in error reporting and state management.
2815
+ *
2816
+ * @param id The internal identifier for the action. Used as a tracing span and to lookup
2817
+ * the user-facing name via internationalization (`action.${id}`).
2818
+ * @param options Optional configuration for internationalization and state.
2819
+ * @param options.i18nCustomKey Custom i18n key to use instead of `id` (e.g., for grouping similar actions)
2820
+ * @param options.state Optional reactive state object (or function returning one) that is
2821
+ * made available to the command effects and can be used for i18n interpolation.
2822
+ * The state is captured at the start of each command execution and remains stable throughout.
2823
+ * @returns A function that executes the command when called (e.g., directly in `@click` handlers).
2824
+ * Built-in error reporting handles failures automatically.
2825
+ *
2826
+ * **Effect Context**: Effects have access to the `CommandContext` service, which provides
2827
+ * the user-facing action name.
2828
+ *
2829
+ * **Returned Properties**:
2830
+ * - `action`: User-facing action name from intl messages (useful for button labels)
2831
+ * - `result`: The command result state
2832
+ * - `waiting`: Boolean indicating if the command is in progress (shorthand for `result.waiting`)
2833
+ * - `handle`: Function to execute the command
2834
+ * - `exec`: The raw Effect that will be executed when calling `handle` (for advanced use cases)
2835
+ * - `i18nKey`, `namespace`, `namespaced`: Helpers for internationalization keys
2836
+ *
2837
+ * **User Feedback**: Use the `withDefaultToast` helper for status notifications, or render
2838
+ * the `result` inline for custom UI feedback.
2839
+ */
2840
+ fn = <
2841
+ const Id extends string,
2842
+ const State extends IntlRecord = IntlRecord,
2843
+ const I18nKey extends string = Id
2844
+ >(
2845
+ id: Id | { id: Id },
2846
+ options?: FnOptions<Id, I18nKey, State>
2847
+ ): Commander.Gen<RT | RTHooks, Id, I18nKey, State> & Commander.NonGen<RT | RTHooks, Id, I18nKey, State> & {
2848
+ state: Context.Service<`Commander.Command.${Id}.state`, State>
2849
+ } => {
2850
+ const resolvedId: Id = typeof id === "string" ? id : id.id
2851
+ return Object.assign(
2852
+ (
2853
+ fn: any,
2854
+ ...combinators: any[]
2855
+ ): any => {
2856
+ // we capture the definition stack here, so we can append it to later stack traces
2857
+ const limit = Error.stackTraceLimit
2858
+ Error.stackTraceLimit = 2
2859
+ const errorDef = new Error()
2860
+ Error.stackTraceLimit = limit
2861
+
2862
+ return this.makeCommand(resolvedId, options, errorDef)(
2863
+ Effect.fnUntraced(
2864
+ // fnUntraced only supports generators as first arg, so we convert to generator if needed
2865
+ isGeneratorFunction(fn) ? fn : function*(...args) {
2866
+ return yield* fn(...args)
2867
+ },
2868
+ ...combinators as [any]
2869
+ ) as any
2870
+ )
2871
+ },
2872
+ makeBaseInfo(resolvedId, options),
2873
+ {
2874
+ state: Context.Service<`Commander.Command.${Id}.state`, State>(
2875
+ `Commander.Command.${resolvedId}.state`
2876
+ )
2877
+ }
2878
+ )
2879
+ }
2880
+
2881
+ /**
2882
+ * Internal factory for stream-backed commands. Accepts a handler that returns a `Stream` directly.
2883
+ * Services (`CommandContext`, `stateTag`) are provided to the stream via `Stream.provideServiceEffect`.
2884
+ */
2885
+ readonly makeStreamCommand = <
2886
+ const Id extends string,
2887
+ const State extends IntlRecord | undefined,
2888
+ const I18nKey extends string = Id
2889
+ >(
2890
+ id_: Id | { id: Id },
2891
+ options?: FnOptions<Id, I18nKey, State>,
2892
+ errorDef?: Error
2893
+ ) => {
2894
+ const id = typeof id_ === "string" ? id_ : id_.id
2895
+ const state = getStateValues(options)
2896
+
2897
+ return Object.assign(
2898
+ <Arg, SA, SE, SR>(
2899
+ handler: (arg: Arg, ctx: Commander.CommandContextLocal2<Id, I18nKey, State>) => Stream.Stream<SA, SE, SR>
2900
+ ) => {
2901
+ const limit = Error.stackTraceLimit
2902
+ Error.stackTraceLimit = 2
2903
+ const localErrorDef = new Error()
2904
+ Error.stackTraceLimit = limit
2905
+ if (!errorDef) {
2906
+ errorDef = localErrorDef
2907
+ }
2908
+
2909
+ const key = `Commander.Command.${id}.state` as const
2910
+ const stateTag = Context.Service<typeof key, State>(key)
2911
+
2912
+ const makeContext_ = () => this.makeContext(id, { ...options, state: state?.value })
2913
+ const initialContext = makeContext_()
2914
+ const context = computed(() => makeContext_())
2915
+ const action = computed(() => context.value.action)
2916
+ const label = computed(() => context.value.label)
2917
+
2918
+ const currentState = Effect.sync(() => state.value)
2919
+
2920
+ // Reactive ref driven by the CommandProgress service — updated imperatively
2921
+ // from inside the stream via `Command.mapProgress(fn)` or `Command.updateProgress(p)`.
2922
+ const progressRef = ref<Progress | undefined>(undefined)
2923
+ const commandProgressService = {
2924
+ update: (p: Progress | undefined) =>
2925
+ Effect.sync(() => {
2926
+ progressRef.value = p
2927
+ })
2928
+ }
2929
+
2930
+ const streamErrorReporter = <A, E, R>(self: Stream.Stream<A, E, R>) =>
2931
+ self.pipe(
2932
+ Stream.tapCause(
2933
+ Effect.fnUntraced(function*(cause) {
2934
+ if (Cause.hasInterruptsOnly(cause)) {
2935
+ console.info(`Interrupted while trying to ${id}`)
2936
+ return
2937
+ }
2938
+
2939
+ const fail = Cause.findErrorOption(cause)
2940
+ if (Option.isSome(fail)) {
2941
+ const message = `Failure trying to ${id}`
2942
+ yield* reportMessage(message, {
2943
+ action: id,
2944
+ error: fail.value
2945
+ })
2946
+ return
2947
+ }
2948
+
2949
+ const ctx = yield* CommandContext
2950
+ const extra = {
2951
+ action: ctx.action,
2952
+ message: `Unexpected Error trying to ${id}`
2953
+ }
2954
+ yield* reportRuntimeError(cause, extra)
2955
+ }, Effect.uninterruptible)
2956
+ )
2957
+ )
2958
+
2959
+ const theStreamHandler = (arg: Arg, ctx: Commander.CommandContextLocal2<Id, I18nKey, State>) =>
2960
+ handler(arg, ctx).pipe(
2961
+ streamErrorReporter,
2962
+ Stream.provideService(CommandProgress, commandProgressService),
2963
+ Stream.provideServiceEffect(stateTag, currentState),
2964
+ Stream.provideServiceEffect(CommandContext, Effect.sync(() => makeContext_()))
2965
+ )
2966
+
2967
+ const waitId = options?.waitKey ? options.waitKey(id) : undefined
2968
+ const blockId = options?.blockKey ? options.blockKey(id) : undefined
2969
+
2970
+ const [result, exec_] = asStreamResult(theStreamHandler)
2971
+
2972
+ const exec = Effect
2973
+ .fnUntraced(
2974
+ function*(...args: [any, any]) {
2975
+ if (waitId !== undefined) registerWait(waitId)
2976
+ if (blockId !== undefined && blockId !== waitId) {
2977
+ registerWait(blockId)
2978
+ }
2979
+ return yield* exec_(...args)
2980
+ },
2981
+ Effect.onExit(() =>
2982
+ Effect.sync(() => {
2983
+ if (waitId !== undefined) unregisterWait(waitId)
2984
+ if (blockId !== undefined && blockId !== waitId) {
2985
+ unregisterWait(blockId)
2986
+ }
2987
+ })
2988
+ )
2989
+ )
2990
+
2991
+ const waiting = waitId !== undefined
2992
+ ? computed(() => result.value.waiting || (waitState.value[waitId] ?? 0) > 0)
2993
+ : computed(() => result.value.waiting)
2994
+
2995
+ const blocked = blockId !== undefined
2996
+ ? computed(() => waiting.value || (waitState.value[blockId] ?? 0) > 0)
2997
+ : computed(() => waiting.value)
2998
+
2999
+ const computeAllowed = options?.allowed
3000
+ const allowed = computeAllowed ? computed(() => computeAllowed(id, state)) : true
3001
+
3002
+ const rt = Effect.context<RT | RTHooks>().pipe(Effect.provide(this.hooks)).pipe(Effect.runSyncWith(this.rt))
3003
+ const runFork = Effect.runForkWith(rt)
3004
+
3005
+ const progress = progressRef
3006
+
3007
+ const handle = Object.assign((arg: Arg) => {
3008
+ arg = toRaw(arg)
3009
+ progressRef.value = undefined // reset progress on new invocation
3010
+ const limit = Error.stackTraceLimit
3011
+ Error.stackTraceLimit = 2
3012
+ const errorCall = new Error()
3013
+ Error.stackTraceLimit = limit
3014
+
3015
+ let cache: false | string = false
3016
+ const captureStackTrace = () => {
3017
+ if (cache !== false) {
3018
+ return cache
3019
+ }
3020
+ if (errorCall.stack) {
3021
+ const stackDef = errorDef!.stack!.trim().split("\n")
3022
+ const stackCall = errorCall.stack.trim().split("\n")
3023
+ let endStackDef = stackDef.slice(2).join("\n").trim()
3024
+ if (!endStackDef.includes(`(`)) {
3025
+ endStackDef = endStackDef.replace(/at (.*)/, "at ($1)")
3026
+ }
3027
+ let endStackCall = stackCall.slice(2).join("\n").trim()
3028
+ if (!endStackCall.includes(`(`)) {
3029
+ endStackCall = endStackCall.replace(/at (.*)/, "at ($1)")
3030
+ }
3031
+ cache = `${endStackDef}\n${endStackCall}`
3032
+ return cache
3033
+ }
3034
+ }
3035
+
3036
+ const command = currentState.pipe(Effect.flatMap((state) => {
3037
+ const rawArg = deepToRaw(arg)
3038
+ const rawState = deepToRaw(state)
3039
+ return Effect.withSpan(
3040
+ exec(arg, { ...context.value, state } as any),
3041
+ id,
3042
+ {
3043
+ captureStackTrace,
3044
+ attributes: {
3045
+ input: rawArg,
3046
+ state: rawState,
3047
+ action: initialContext.action,
3048
+ label: initialContext.label,
3049
+ id: initialContext.id,
3050
+ i18nKey: initialContext.i18nKey
3051
+ }
3052
+ }
3053
+ )
3054
+ }))
3055
+
3056
+ return runFork(command as any)
3057
+ }, { action, label })
3058
+
3059
+ return reactive({
3060
+ id,
3061
+ i18nKey: initialContext.i18nKey,
3062
+ namespace: initialContext.namespace,
3063
+ namespaced: initialContext.namespaced,
3064
+ result,
3065
+ /** reactive – progress driven by `Command.mapProgress` or `Command.updateProgress` inside the stream */
3066
+ progress,
3067
+ waiting,
3068
+ blocked,
3069
+ allowed,
3070
+ action,
3071
+ label,
3072
+ state,
3073
+ handle
3074
+ })
3075
+ },
3076
+ { id }
3077
+ )
3078
+ }
3079
+
3080
+ /**
3081
+ * Define a stream-backed Command for handling user actions.
3082
+ *
3083
+ * Like `fn`, but the body generator (or function) must **return** a `Stream` rather than
3084
+ * an `Effect`. The command's `waiting` state stays `true` while the stream is running and
3085
+ * is set to `false` once it terminates. The reactive `result` ref is updated for every
3086
+ * value emitted by the stream.
3087
+ *
3088
+ * Three handler shapes are accepted:
3089
+ * 1. **Generator returning a Stream** (primary) — may yield Effects freely before returning the stream:
3090
+ * ```ts
3091
+ * Command.streamFn("exportData")(
3092
+ * function*(arg, ctx) {
3093
+ * const token = yield* getAuthToken
3094
+ * return Stream.fromEffect(startExport(token, arg.id)).pipe(
3095
+ * Stream.flatMap((job) => pollProgress(job.id))
3096
+ * )
3097
+ * }
3098
+ * )
3099
+ * ```
3100
+ * 2. **Function returning a Stream directly**: `(arg, ctx) => Stream.make(1, 2, 3)`
3101
+ * 3. **Function returning `Effect<Stream>`**: `(arg, ctx) => Effect.map(setup, (s) => s.stream)`
3102
+ *
3103
+ * @param id The internal identifier for the action (used for tracing and i18n lookup).
3104
+ * @param options Same options as `fn` (`state`, `blockKey`, `waitKey`, `allowed`, `i18nCustomKey`).
3105
+ *
3106
+ * **Progress** — use `Command.mapProgress(fn)` as a stream pipe operator; the mapper receives
3107
+ * `AsyncResult<A, E>` (each value wrapped as `AsyncResult.success(v, { waiting: true })`),
3108
+ * matching the same shape as CommandButton’s `:progress-map` prop. Or call
3109
+ * `Command.updateProgress(p)` for imperative control:
3110
+ *
3111
+ * ```ts
3112
+ * // mapProgress as a combinator arg (outside the handler):
3113
+ * Command.streamFn("exportData")(
3114
+ * function*(arg, ctx) { return makeExportStream(arg.id) },
3115
+ * (s) => s.pipe(Command.mapProgress((r) => AsyncResult.isSuccess(r) && r.value._tag === "OperationProgress" ? { text: `${r.value.completed}/${r.value.total}` } : undefined))
3116
+ * )
3117
+ *
3118
+ * // Or inline inside the handler body:
3119
+ * Command.streamFn("exportData")(function*(arg, ctx) {
3120
+ * return makeExportStream(arg.id).pipe(Command.mapProgress((r) => AsyncResult.isSuccess(r) ? ... : undefined))
3121
+ * })
3122
+ * ```
3123
+ *
3124
+ * **Pipeable combinators** — the 2nd–Nth args follow the same pattern as `fn`: each combinator
3125
+ * receives `(stream, arg, ctx)` and returns a transformed stream:
3126
+ * ```ts
3127
+ * Command.streamFn("exportData")(
3128
+ * handler,
3129
+ * (s, arg, ctx) => s.pipe(Command.mapProgress(fn), Stream.take(100))
3130
+ * )
3131
+ * ```
3132
+ *
3133
+ * **Returned Properties**: `action`, `label`, `result`, `progress`, `waiting`, `blocked`,
3134
+ * `allowed`, `handle`, `i18nKey`, `namespace`, `namespaced`.
3135
+ */
3136
+ streamFn = <
3137
+ const Id extends string,
3138
+ const State extends IntlRecord = IntlRecord,
3139
+ const I18nKey extends string = Id
3140
+ >(
3141
+ id: Id | { id: Id },
3142
+ options?: FnOptions<Id, I18nKey, State>
3143
+ ):
3144
+ & Commander.StreamGen<RT | RTHooks, Id, I18nKey, State>
3145
+ & Commander.NonGenStream<RT | RTHooks, Id, I18nKey, State>
3146
+ & {
3147
+ state: Context.Service<`Commander.Command.${Id}.state`, State>
3148
+ } =>
3149
+ {
3150
+ const resolvedId = typeof id === "string" ? id : id.id
3151
+
3152
+ type StreamOrEffect = Stream.Stream<any, any, any> | Effect.Effect<Stream.Stream<any, any, any>, any, any>
3153
+
3154
+ const toRawHandler = (fn: any): (arg: any, ctx: any) => StreamOrEffect => {
3155
+ if (isGeneratorFunction(fn)) {
3156
+ return Effect.fnUntraced(function*(arg: any, ctx: any) {
3157
+ return yield* (fn as (arg: any, ctx: any) => Generator<any, Stream.Stream<any, any, any>>)(arg, ctx)
3158
+ })
3159
+ }
3160
+ return fn
3161
+ }
3162
+
3163
+ const toFinalStream = (value: StreamOrEffect): Stream.Stream<any, any, any> =>
3164
+ Stream.isStream(value) ? value : Stream.unwrap(value as Effect.Effect<Stream.Stream<any, any, any>, any, any>)
3165
+
3166
+ return Object.assign(
3167
+ (fn: any, ...combinators: Array<(s: any, arg: any, ctx: any) => any>): any => {
3168
+ const limit = Error.stackTraceLimit
3169
+ Error.stackTraceLimit = 2
3170
+ const errorDef = new Error()
3171
+ Error.stackTraceLimit = limit
3172
+
3173
+ const rawHandler = toRawHandler(fn)
3174
+ const handler = (arg: any, ctx: any) => {
3175
+ let current: any = rawHandler(arg, ctx)
3176
+ for (const combinator of combinators) {
3177
+ current = combinator(current, arg, ctx)
3178
+ }
3179
+ return toFinalStream(current)
3180
+ }
3181
+
3182
+ return this.makeStreamCommand(id, options, errorDef)(handler)
3183
+ },
3184
+ makeBaseInfo(resolvedId, options),
3185
+ {
3186
+ state: Context.Service<`Commander.Command.${Id}.state`, State>(
3187
+ `Commander.Command.${resolvedId}.state`
3188
+ )
3189
+ }
3190
+ )
3191
+ }
3192
+
3193
+ /** @deprecated */
3194
+
3195
+ alt2: <
3196
+ const Id extends string,
3197
+ MutArg,
3198
+ MutA,
3199
+ MutE,
3200
+ MutR,
3201
+ const I18nKey extends string = Id,
3202
+ State extends IntlRecord | undefined = undefined
3203
+ >(
3204
+ id:
3205
+ | Id
3206
+ | { id: Id; mutate: (arg: MutArg) => Effect.Effect<MutA, MutE, MutR> }
3207
+ | ((arg: MutArg) => Effect.Effect<MutA, MutE, MutR>) & { id: Id },
3208
+ options?: FnOptions<Id, I18nKey, State>
3209
+ ) =>
3210
+ & Commander.CommandContextLocal<Id, I18nKey>
3211
+ & (<A, E, R extends RT | RTHooks | CommandContext | `Commander.Command.${Id}.state`, Arg = void>(
3212
+ handler: (
3213
+ ctx: Effect.fn.Traced & Effect.fn.Untraced & Commander.CommandContextLocal<Id, I18nKey> & {
3214
+ // todo: only if we passed in one
3215
+ mutate: (arg: Arg) => Effect.Effect<MutA, MutE, MutR>
3216
+ }
3217
+ ) => (arg: Arg, ctx: Commander.CommandContextLocal2<Id, I18nKey, State>) => Effect.Effect<A, E, R>
3218
+ ) => Commander.CommandOut<Arg, A, E, R, Id, I18nKey, State>) = (
3219
+ _id,
3220
+ options?
3221
+ ) => {
3222
+ const isObject = Predicate.isObjectKeyword(_id)
3223
+ const id = isObject ? _id.id : _id
3224
+ const baseInfo = makeBaseInfo(id, options)
3225
+ const idCmd = this.makeCommand(id, options)
3226
+ // TODO: implement proper tracing stack
3227
+ return Object.assign((cb: any) =>
3228
+ idCmd(cb(
3229
+ Object.assign(
3230
+ (fn: any, ...combinators: any[]) =>
3231
+ Effect.fnUntraced(
3232
+ // fnUntraced only supports generators as first arg, so we convert to generator if needed
3233
+ isGeneratorFunction(fn) ? fn : function*(...args) {
3234
+ return yield* fn(...args)
3235
+ },
3236
+ ...combinators as [any]
3237
+ ),
3238
+ baseInfo,
3239
+ isObject
3240
+ ? { mutate: "mutate" in _id ? _id.mutate : typeof _id === "function" ? _id : undefined }
3241
+ : {}
3242
+ )
3243
+ )), baseInfo) as any
3244
+ }
3245
+
3246
+ alt = this.makeCommand as unknown as <
3247
+ const Id extends string,
3248
+ const I18nKey extends string = Id,
3249
+ State extends IntlRecord | undefined = undefined
3250
+ >(
3251
+ id: Id,
3252
+ customI18nKey?: I18nKey
3253
+ ) =>
3254
+ & Commander.CommandContextLocal<Id, I18nKey>
3255
+ & (<A, E, R extends RT | CommandContext | `Commander.Command.${Id}.state`, Arg = void>(
3256
+ handler: (arg: Arg, ctx: Commander.CommandContextLocal2<Id, I18nKey, State>) => Effect.Effect<A, E, R>
3257
+ ) => Commander.CommandOut<Arg, A, E, R, Id, I18nKey, State>)
3258
+
3259
+ /**
3260
+ * Define a Command for handling user actions with built-in error reporting and state management.
3261
+ *
3262
+ * @param mutation The mutation function to take the identifier and initial handler from. Used as a tracing span and to lookup
3263
+ * the user-facing name via internationalization (`action.${id}`).
3264
+ * @param options Optional configuration for internationalization and state.
3265
+ * @param options.i18nCustomKey Custom i18n key to use instead of `id` (e.g., for grouping similar actions)
3266
+ * @param options.state Optional reactive state object (or function returning one) that is
3267
+ * made available to the command effects and can be used for i18n interpolation.
3268
+ * The state is captured at the start of each command execution and remains stable throughout.
3269
+ * @returns A function that executes the command when called (e.g., directly in `@click` handlers).
3270
+ * Built-in error reporting handles failures automatically.
3271
+ *
3272
+ * **Effect Context**: Effects have access to the `CommandContext` service, which provides
3273
+ * the user-facing action name.
3274
+ *
3275
+ * **Returned Properties**:
3276
+ * - `action`: User-facing action name from intl messages (useful for button labels)
3277
+ * - `result`: The command result state
3278
+ * - `waiting`: Boolean indicating if the command is in progress (shorthand for `result.waiting`)
3279
+ * - `handle`: Function to execute the command
3280
+ * - `exec`: The raw Effect that will be executed when calling `handle` (for advanced use cases)
3281
+ * - `i18nKey`, `namespace`, `namespaced`: Helpers for internationalization keys
3282
+ *
3283
+ * **User Feedback**: Use the `withDefaultToast` helper for status notifications, or render
3284
+ * the `result` inline for custom UI feedback.
3285
+ */
3286
+ streamWrap = <
3287
+ const Id extends string,
3288
+ Arg,
3289
+ SA,
3290
+ SE,
3291
+ SR,
3292
+ const State extends IntlRecord = IntlRecord,
3293
+ I18nKey extends string = Id
3294
+ >(
3295
+ handler: (arg: Arg, ctx: Commander.CommandContextLocal2<Id, I18nKey, State>) => Stream.Stream<SA, SE, SR>,
3296
+ id: Id,
3297
+ options?: FnOptions<Id, I18nKey, State>
3298
+ ): Commander.StreamerWrap<RT | RTHooks, Id, I18nKey, State, Arg, SA, SE, SR> => {
3299
+ return Object.assign(
3300
+ (...combinators: any[]): any => {
3301
+ const limit = Error.stackTraceLimit
3302
+ Error.stackTraceLimit = 2
3303
+ const errorDef = new Error()
3304
+ Error.stackTraceLimit = limit
3305
+ return this.makeStreamCommand(id, options, errorDef)(
3306
+ combinators.length === 0
3307
+ ? handler
3308
+ : (arg: Arg, ctx: Commander.CommandContextLocal2<Id, I18nKey, State>) => {
3309
+ let current: any = handler(arg, ctx)
3310
+ for (const combinator of combinators) {
3311
+ current = combinator(current, arg, ctx)
3312
+ }
3313
+ return current
3314
+ }
3315
+ )
3316
+ },
3317
+ makeBaseInfo(id, options),
3318
+ {
3319
+ state: Context.Service<`Commander.Command.${Id}.state`, State>(
3320
+ `Commander.Command.${id}.state`
3321
+ )
3322
+ }
3323
+ )
3324
+ }
3325
+
3326
+ wrap = <
3327
+ const Id extends string,
3328
+ Arg,
3329
+ A,
3330
+ E,
3331
+ R,
3332
+ const State extends IntlRecord = IntlRecord,
3333
+ I18nKey extends string = Id
3334
+ >(
3335
+ mutation:
3336
+ | { mutate: (arg: Arg) => Effect.Effect<A, E, R>; id: Id }
3337
+ | ((arg: Arg) => Effect.Effect<A, E, R>) & { id: Id },
3338
+ options?: FnOptions<Id, I18nKey, State>
3339
+ ): Commander.CommanderWrap<RT | RTHooks, Id, I18nKey, State, Arg, A, E, R> => {
3340
+ const callMutation = mutation
3341
+ return Object.assign(
3342
+ (
3343
+ ...combinators: any[]
3344
+ ): any => {
3345
+ // we capture the definition stack here, so we can append it to later stack traces
3346
+ const limit = Error.stackTraceLimit
3347
+ Error.stackTraceLimit = 2
3348
+ const errorDef = new Error()
3349
+ Error.stackTraceLimit = limit
3350
+ const mutate = "mutate" in callMutation
3351
+ ? callMutation.mutate
3352
+ : callMutation
3353
+
3354
+ return this.makeCommand(callMutation.id, options, errorDef)(
3355
+ Effect.fnUntraced(
3356
+ // fnUntraced only supports generators as first arg, so we convert to generator if needed
3357
+ isGeneratorFunction(mutate) ? mutate : function*(arg: Arg) {
3358
+ return yield* mutate(arg)
3359
+ },
3360
+ ...combinators as [any]
3361
+ ) as any
3362
+ )
3363
+ },
3364
+ makeBaseInfo(callMutation.id, options),
3365
+ {
3366
+ state: Context.Service<`Commander.Command.${Id}.state`, State>(
3367
+ `Commander.Command.${callMutation.id}.state`
3368
+ )
3369
+ }
3370
+ )
3371
+ }
3372
+ }
3373
+
3374
+ // @effect-diagnostics-next-line missingEffectServiceDependency:off
3375
+ export class Commander extends Context.Service<Commander>()("Commander", {
3376
+ make: Effect.gen(function*() {
3377
+ const i18n = yield* I18n
3378
+ return <RT, RTHooks>(rt: Context.Context<RT>, rtHooks: Layer.Layer<RTHooks, never, RT>) =>
3379
+ new CommanderImpl(rt, i18n, rtHooks)
3380
+ })
3381
+ }) {
3382
+ static readonly DefaultWithoutDependencies = Layer.effect(this, this.make)
3383
+ static readonly Default = this.DefaultWithoutDependencies
3384
+ }