@effect-app/vue 4.0.0-beta.19 → 4.0.0-beta.190

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