pure-effect 0.6.0 → 0.8.0

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.
package/index.d.ts CHANGED
@@ -10,96 +10,213 @@ export type FailureState<E = unknown> = {
10
10
  initialInput?: unknown;
11
11
  };
12
12
 
13
- export type CommandState<R, T, E = unknown> = {
13
+ export type CommandState<R, T, E = unknown, Ctx = unknown> = {
14
14
  type: 'Command';
15
15
  cmd: () => Promise<R> | R;
16
- next: (result: R) => Effect<T, E>;
16
+ next: (result: R) => Effect<T, E, Ctx>;
17
17
  meta?: unknown;
18
18
  initialInput?: unknown;
19
19
  };
20
20
 
21
- export type AskState<T, E = unknown> = {
21
+ export type AskState<T, E = unknown, Ctx = unknown> = {
22
22
  type: 'Ask';
23
- next: (context: unknown) => Effect<T, E>;
23
+ next: (context: Ctx) => Effect<T, E, Ctx>;
24
24
  initialInput?: unknown;
25
25
  };
26
26
 
27
- export type Effect<T, E = unknown> = SuccessState<T> | FailureState<E> | CommandState<any, T, E> | AskState<T, E>;
27
+ export type RetryOptions = {
28
+ attempts?: number;
29
+ delay?: number;
30
+ backoff?: number;
31
+ };
32
+
33
+ export type RetryState<T, E = unknown, Ctx = unknown> = {
34
+ type: 'Retry';
35
+ effect: Effect<T, E, Ctx>;
36
+ options: RetryOptions;
37
+ next: (value: T) => Effect<T, E, Ctx>;
38
+ initialInput?: unknown;
39
+ };
40
+
41
+ export type RetryExhaustedError<E = unknown> = {
42
+ retryExhausted: true;
43
+ lastError: E;
44
+ attempts: number;
45
+ };
46
+
47
+ export type ParallelState<T extends readonly unknown[], R, E = unknown, Ctx = unknown> = {
48
+ type: 'Parallel';
49
+ effects: { [K in keyof T]: Effect<T[K], E, Ctx> };
50
+ next: (values: [...T]) => Effect<R, E, Ctx>;
51
+ initialInput?: unknown;
52
+ };
53
+
54
+ export type Effect<T, E = unknown, Ctx = unknown> =
55
+ | SuccessState<T>
56
+ | FailureState<E>
57
+ | CommandState<any, T, E, Ctx>
58
+ | AskState<T, E, Ctx>
59
+ | RetryState<T, E, Ctx>
60
+ | ParallelState<any, T, E, Ctx>;
28
61
 
29
62
  export declare function Success<T>(value: T): SuccessState<T>;
30
63
 
31
64
  export declare function Failure<E = unknown>(error: E, initialInput?: unknown): FailureState<E>;
32
65
 
33
- export declare function Command<R, T, E = unknown>(
66
+ export declare function Command<R, T, E = unknown, Ctx = unknown>(
34
67
  cmd: () => Promise<R> | R,
35
- next: (result: R) => Effect<T, E>,
68
+ next: (result: R) => Effect<T, E, Ctx>,
36
69
  meta?: unknown
37
- ): CommandState<R, T, E>;
38
-
39
- export declare function Ask<T, E = unknown>(next: (context: unknown) => Effect<T, E>): AskState<T, E>;
40
-
41
- export declare function effectPipe<A, B, E = unknown>(f1: (a: A) => Effect<B, E>): (start: A) => Effect<B, E>;
42
-
43
- export declare function effectPipe<A, B, C, E = unknown>(
44
- f1: (a: A) => Effect<B, E>,
45
- f2: (b: B) => Effect<C, E>
46
- ): (start: A) => Effect<C, E>;
47
-
48
- export declare function effectPipe<A, B, C, D, E = unknown>(
49
- f1: (a: A) => Effect<B, E>,
50
- f2: (b: B) => Effect<C, E>,
51
- f3: (c: C) => Effect<D, E>
52
- ): (start: A) => Effect<D, E>;
53
-
54
- export declare function effectPipe<A, B, C, D, F, E = unknown>(
55
- f1: (a: A) => Effect<B, E>,
56
- f2: (b: B) => Effect<C, E>,
57
- f3: (c: C) => Effect<D, E>,
58
- f4: (d: D) => Effect<F, E>
59
- ): (start: A) => Effect<F, E>;
60
-
61
- export declare function effectPipe<A, B, C, D, F, G, E = unknown>(
62
- f1: (a: A) => Effect<B, E>,
63
- f2: (b: B) => Effect<C, E>,
64
- f3: (c: C) => Effect<D, E>,
65
- f4: (d: D) => Effect<F, E>,
66
- f5: (f: F) => Effect<G, E>
67
- ): (start: A) => Effect<G, E>;
68
-
69
- export declare function effectPipe<A, B, C, D, F, G, H, E = unknown>(
70
- f1: (a: A) => Effect<B, E>,
71
- f2: (b: B) => Effect<C, E>,
72
- f3: (c: C) => Effect<D, E>,
73
- f4: (d: D) => Effect<F, E>,
74
- f5: (f: F) => Effect<G, E>,
75
- f6: (g: G) => Effect<H, E>
76
- ): (start: A) => Effect<H, E>;
77
-
78
- export declare function effectPipe<A, B, C, D, F, G, H, I, E = unknown>(
79
- f1: (a: A) => Effect<B, E>,
80
- f2: (b: B) => Effect<C, E>,
81
- f3: (c: C) => Effect<D, E>,
82
- f4: (d: D) => Effect<F, E>,
83
- f5: (f: F) => Effect<G, E>,
84
- f6: (g: G) => Effect<H, E>,
85
- f7: (h: H) => Effect<I, E>
86
- ): (start: A) => Effect<I, E>;
87
-
88
- export declare function effectPipe<A, B, C, D, F, G, H, I, J, E = unknown>(
89
- f1: (a: A) => Effect<B, E>,
90
- f2: (b: B) => Effect<C, E>,
91
- f3: (c: C) => Effect<D, E>,
92
- f4: (d: D) => Effect<F, E>,
93
- f5: (f: F) => Effect<G, E>,
94
- f6: (g: G) => Effect<H, E>,
95
- f7: (h: H) => Effect<I, E>,
96
- f8: (i: I) => Effect<J, E>
97
- ): (start: A) => Effect<J, E>;
98
-
99
- export declare function runEffect<T, E = unknown>(
100
- effect: Effect<T, E>,
101
- context?: unknown
102
- ): Promise<SuccessState<T> | FailureState<E>>;
70
+ ): CommandState<R, T, E, Ctx>;
71
+
72
+ export declare function Ask<T, E = unknown, Ctx = unknown>(
73
+ next: (context: Ctx) => Effect<T, E, Ctx>
74
+ ): AskState<T, E, Ctx>;
75
+
76
+ export declare function Retry<T, E = unknown, Ctx = unknown>(
77
+ effect: Effect<T, E, Ctx>,
78
+ options?: RetryOptions
79
+ ): RetryState<T, E, Ctx>;
80
+
81
+ export declare function Parallel<T extends readonly unknown[], R, E = unknown, Ctx = unknown>(
82
+ effects: { [K in keyof T]: Effect<T[K], E, Ctx> },
83
+ next: (values: [...T]) => Effect<R, E, Ctx>
84
+ ): ParallelState<[...T], R, E, Ctx>;
85
+
86
+ export declare function effectPipe<A, B, E1 = unknown, Ctx = unknown>(
87
+ f1: (a: A) => Effect<B, E1, Ctx>
88
+ ): (start: A) => Effect<B, E1, Ctx>;
89
+
90
+ export declare function effectPipe<A, B, C, E1 = unknown, E2 = unknown, Ctx = unknown>(
91
+ f1: (a: A) => Effect<B, E1, Ctx>,
92
+ f2: (b: B) => Effect<C, E2, Ctx>
93
+ ): (start: A) => Effect<C, E1 | E2, Ctx>;
94
+
95
+ export declare function effectPipe<A, B, C, D, E1 = unknown, E2 = unknown, E3 = unknown, Ctx = unknown>(
96
+ f1: (a: A) => Effect<B, E1, Ctx>,
97
+ f2: (b: B) => Effect<C, E2, Ctx>,
98
+ f3: (c: C) => Effect<D, E3, Ctx>
99
+ ): (start: A) => Effect<D, E1 | E2 | E3, Ctx>;
100
+
101
+ export declare function effectPipe<
102
+ A,
103
+ B,
104
+ C,
105
+ D,
106
+ F,
107
+ E1 = unknown,
108
+ E2 = unknown,
109
+ E3 = unknown,
110
+ E4 = unknown,
111
+ Ctx = unknown
112
+ >(
113
+ f1: (a: A) => Effect<B, E1, Ctx>,
114
+ f2: (b: B) => Effect<C, E2, Ctx>,
115
+ f3: (c: C) => Effect<D, E3, Ctx>,
116
+ f4: (d: D) => Effect<F, E4, Ctx>
117
+ ): (start: A) => Effect<F, E1 | E2 | E3 | E4, Ctx>;
118
+
119
+ export declare function effectPipe<
120
+ A,
121
+ B,
122
+ C,
123
+ D,
124
+ F,
125
+ G,
126
+ E1 = unknown,
127
+ E2 = unknown,
128
+ E3 = unknown,
129
+ E4 = unknown,
130
+ E5 = unknown,
131
+ Ctx = unknown
132
+ >(
133
+ f1: (a: A) => Effect<B, E1, Ctx>,
134
+ f2: (b: B) => Effect<C, E2, Ctx>,
135
+ f3: (c: C) => Effect<D, E3, Ctx>,
136
+ f4: (d: D) => Effect<F, E4, Ctx>,
137
+ f5: (f: F) => Effect<G, E5, Ctx>
138
+ ): (start: A) => Effect<G, E1 | E2 | E3 | E4 | E5, Ctx>;
139
+
140
+ export declare function effectPipe<
141
+ A,
142
+ B,
143
+ C,
144
+ D,
145
+ F,
146
+ G,
147
+ H,
148
+ E1 = unknown,
149
+ E2 = unknown,
150
+ E3 = unknown,
151
+ E4 = unknown,
152
+ E5 = unknown,
153
+ E6 = unknown,
154
+ Ctx = unknown
155
+ >(
156
+ f1: (a: A) => Effect<B, E1, Ctx>,
157
+ f2: (b: B) => Effect<C, E2, Ctx>,
158
+ f3: (c: C) => Effect<D, E3, Ctx>,
159
+ f4: (d: D) => Effect<F, E4, Ctx>,
160
+ f5: (f: F) => Effect<G, E5, Ctx>,
161
+ f6: (g: G) => Effect<H, E6, Ctx>
162
+ ): (start: A) => Effect<H, E1 | E2 | E3 | E4 | E5 | E6, Ctx>;
163
+
164
+ export declare function effectPipe<
165
+ A,
166
+ B,
167
+ C,
168
+ D,
169
+ F,
170
+ G,
171
+ H,
172
+ I,
173
+ E1 = unknown,
174
+ E2 = unknown,
175
+ E3 = unknown,
176
+ E4 = unknown,
177
+ E5 = unknown,
178
+ E6 = unknown,
179
+ E7 = unknown,
180
+ Ctx = unknown
181
+ >(
182
+ f1: (a: A) => Effect<B, E1, Ctx>,
183
+ f2: (b: B) => Effect<C, E2, Ctx>,
184
+ f3: (c: C) => Effect<D, E3, Ctx>,
185
+ f4: (d: D) => Effect<F, E4, Ctx>,
186
+ f5: (f: F) => Effect<G, E5, Ctx>,
187
+ f6: (g: G) => Effect<H, E6, Ctx>,
188
+ f7: (h: H) => Effect<I, E7, Ctx>
189
+ ): (start: A) => Effect<I, E1 | E2 | E3 | E4 | E5 | E6 | E7, Ctx>;
190
+
191
+ export declare function effectPipe<
192
+ A,
193
+ B,
194
+ C,
195
+ D,
196
+ F,
197
+ G,
198
+ H,
199
+ I,
200
+ J,
201
+ E1 = unknown,
202
+ E2 = unknown,
203
+ E3 = unknown,
204
+ E4 = unknown,
205
+ E5 = unknown,
206
+ E6 = unknown,
207
+ E7 = unknown,
208
+ E8 = unknown,
209
+ Ctx = unknown
210
+ >(
211
+ f1: (a: A) => Effect<B, E1, Ctx>,
212
+ f2: (b: B) => Effect<C, E2, Ctx>,
213
+ f3: (c: C) => Effect<D, E3, Ctx>,
214
+ f4: (d: D) => Effect<F, E4, Ctx>,
215
+ f5: (f: F) => Effect<G, E5, Ctx>,
216
+ f6: (g: G) => Effect<H, E6, Ctx>,
217
+ f7: (h: H) => Effect<I, E7, Ctx>,
218
+ f8: (i: I) => Effect<J, E8, Ctx>
219
+ ): (start: A) => Effect<J, E1 | E2 | E3 | E4 | E5 | E6 | E7 | E8, Ctx>;
103
220
 
104
221
  export type StepRunner = (name: string, type: string, op: () => Promise<unknown>) => Promise<unknown>;
105
222
 
@@ -115,6 +232,13 @@ export interface EffectConfiguration {
115
232
  onStep?: StepRunner;
116
233
  onRun?: RunWrapper;
117
234
  onBeforeCommand?: CommandInterceptor;
235
+ retry?: RetryOptions;
118
236
  }
119
237
 
120
238
  export declare function configureEffect(options: EffectConfiguration): void;
239
+
240
+ export declare function runEffect<T, E = unknown, Ctx = unknown>(
241
+ effect: Effect<T, E, Ctx>,
242
+ context?: Ctx,
243
+ callConfig?: EffectConfiguration
244
+ ): Promise<SuccessState<T> | FailureState<E>>;
package/index.js CHANGED
@@ -19,9 +19,28 @@
19
19
  * }} AskState
20
20
  */
21
21
 
22
+ /**
23
+ * @typedef {{
24
+ * type: 'Retry',
25
+ * effect: Effect,
26
+ * options: { attempts?: number, delay?: number, backoff?: number },
27
+ * next: (value: any) => Effect,
28
+ * initialInput?: any
29
+ * }} RetryState
30
+ */
31
+
32
+ /**
33
+ * @typedef {{
34
+ * type: 'Parallel',
35
+ * effects: Effect[],
36
+ * next: (values: any[]) => Effect,
37
+ * initialInput?: any
38
+ * }} ParallelState
39
+ */
40
+
22
41
  /**
23
42
  * The Union type for all possible states
24
- * @typedef {SuccessState | FailureState | CommandState | AskState} Effect
43
+ * @typedef {SuccessState | FailureState | CommandState | AskState | RetryState | ParallelState} Effect
25
44
  */
26
45
 
27
46
  /**
@@ -59,27 +78,68 @@ const Command = (cmd, next, meta) => ({ type: 'Command', cmd, next, meta });
59
78
  */
60
79
  const Ask = (next) => ({ type: 'Ask', next });
61
80
 
81
+ /**
82
+ * Wraps an Effect tree with retry-on-failure semantics.
83
+ * @param {Effect} effect - The inner Effect tree to retry
84
+ * @param {Object} [options] - Per-use retry options; merged over global defaults at runtime
85
+ * @param {number} [options.attempts] - Max retries (not counting first try)
86
+ * @param {number} [options.delay] - Ms before first retry
87
+ * @param {number} [options.backoff] - Multiplier applied to delay on each subsequent retry
88
+ * @returns {RetryState}
89
+ */
90
+ const Retry = (effect, options = {}) => ({
91
+ type: 'Retry',
92
+ effect,
93
+ options,
94
+ next: (value) => Success(value)
95
+ });
96
+
97
+ /**
98
+ * Runs multiple Effect trees concurrently. If any effect fails, returns the first Failure by array order and skips next.
99
+ * @param {Effect[]} effects - Array of Effect trees to run concurrently
100
+ * @param {(values: any[]) => Effect} next - Receives array of success values in order, returns next Effect
101
+ * @returns {ParallelState}
102
+ */
103
+ const Parallel = (effects, next) => ({ type: 'Parallel', effects, next });
104
+
62
105
  /**
63
106
  * Connects an Effect to the next function in the pipeline.
64
- * Handles the branching logic for Success, Failure, Command, and Ask.
107
+ * Handles the branching logic for Success, Failure, Command, Ask, and Retry.
65
108
  *
66
109
  * @param {Effect} effect - The current Effect object
67
110
  * @param {(value: any) => Effect} fn - The next function to run if the current effect is a Success
68
111
  * @returns {Effect} The composed Effect
69
112
  */
70
- const chain = (effect, fn) => {
113
+ /**
114
+ * @param {Effect} effect
115
+ * @param {(value: any) => Effect} fn
116
+ * @param {any} [initialInput]
117
+ * @returns {Effect}
118
+ */
119
+ const chain = (effect, fn, initialInput) => {
120
+ const withII = (/** @type {Effect} */ e) =>
121
+ initialInput !== undefined && e.initialInput === undefined ? { ...e, initialInput } : e;
122
+
71
123
  switch (effect.type) {
72
124
  case 'Success':
73
- return fn(effect.value);
125
+ return withII(fn(effect.value));
74
126
  case 'Failure':
75
- return effect;
127
+ return withII(effect);
76
128
  case 'Command': {
77
- const next = (/** @type {any} */ result) => chain(effect.next(result), fn);
78
- return Command(effect.cmd, next, effect.meta);
129
+ const next = (/** @type {any} */ result) => chain(effect.next(result), fn, initialInput);
130
+ return withII(Command(effect.cmd, next, effect.meta));
79
131
  }
80
132
  case 'Ask': {
81
- const next = (/** @type {any} */ ctx) => chain(effect.next(ctx), fn);
82
- return Ask(next);
133
+ const next = (/** @type {any} */ ctx) => chain(effect.next(ctx), fn, initialInput);
134
+ return withII(Ask(next));
135
+ }
136
+ case 'Retry': {
137
+ const next = (/** @type {any} */ result) => chain(effect.next(result), fn, initialInput);
138
+ return withII({ ...effect, next });
139
+ }
140
+ case 'Parallel': {
141
+ const next = (/** @type {any} */ result) => chain(effect.next(result), fn, initialInput);
142
+ return withII({ ...effect, next });
83
143
  }
84
144
  }
85
145
  };
@@ -93,9 +153,8 @@ const chain = (effect, fn) => {
93
153
  */
94
154
  const effectPipe = (...fns) => {
95
155
  return (start) => {
96
- const effect = fns.reduce(chain, /** @type {Effect} */ (Success(start)));
97
- effect.initialInput = start;
98
- return effect;
156
+ const chainWithII = (/** @type {Effect} */ eff, /** @type {(v: any) => Effect} */ fn) => chain(eff, fn, start);
157
+ return fns.reduce(chainWithII, /** @type {Effect} */ (Success(start)));
99
158
  };
100
159
  };
101
160
 
@@ -115,11 +174,15 @@ let stepRunner = defaultStepRunner;
115
174
  let runWrapper = defaultRunWrapper;
116
175
  let commandInterceptor = defaultCommandInterceptor;
117
176
 
177
+ const defaultRetryOptions = { attempts: 3, delay: 100, backoff: 1 };
178
+ let retryDefaults = { ...defaultRetryOptions };
179
+
118
180
  /**
119
181
  * @typedef {Object} EffectConfiguration
120
182
  * @property {StepRunner} [onStep] - Fires once per runEffect call. It wraps the entire workflow execution.
121
183
  * @property {RunWrapper} [onRun] - Fires every time a Command is executed.
122
184
  * @property {CommandInterceptor} [onBeforeCommand] - Intercepts a Command and any context passed to runEffect before execution.
185
+ * @property {{ attempts?: number, delay?: number, backoff?: number }} [retry] - Global Retry defaults; merged under per-use options.
123
186
  */
124
187
 
125
188
  /**
@@ -131,6 +194,7 @@ const configureEffect = (options) => {
131
194
  stepRunner = options.onStep ? options.onStep : defaultStepRunner;
132
195
  runWrapper = options.onRun ? options.onRun : defaultRunWrapper;
133
196
  commandInterceptor = options.onBeforeCommand ? options.onBeforeCommand : defaultCommandInterceptor;
197
+ retryDefaults = options.retry ? { ...defaultRetryOptions, ...options.retry } : defaultRetryOptions;
134
198
  };
135
199
 
136
200
  const runEffect =
@@ -139,34 +203,76 @@ const runEffect =
139
203
  * Iterates through the Effect tree, executing Commands and handling async flow.
140
204
  * Ask effects are resolved synchronously with the context object.
141
205
  *
206
+ * Per-call config takes precedence over global configureEffect defaults.
207
+ * onRun fires exactly once per runEffect call — Retry attempts run inside that
208
+ * single span rather than spawning their own, keeping telemetry non-duplicated.
209
+ *
142
210
  * @param {Effect} effect - The Effect tree returned by a pipeline
143
211
  * @param {any} [context] - Optional context object. Passed to Ask continuations and the Command Interceptor.
212
+ * @param {EffectConfiguration} [callConfig] - Per-call overrides; merged over global configureEffect defaults.
144
213
  * @returns {Promise<SuccessState | FailureState>}
145
214
  */
146
- async function runEffect(effect, context = {}) {
147
- return runWrapper(
148
- effect,
149
- async () => {
150
- while (effect.type === 'Command' || effect.type === 'Ask') {
151
- if (effect.type === 'Ask') {
152
- effect = effect.next(context);
153
- continue;
215
+ async function runEffect(effect, context = {}, callConfig = {}) {
216
+ const localStepRunner = callConfig.onStep ? callConfig.onStep : stepRunner;
217
+ const localRunWrapper = callConfig.onRun ? callConfig.onRun : runWrapper;
218
+ const localCommandInterceptor = callConfig.onBeforeCommand ? callConfig.onBeforeCommand : commandInterceptor;
219
+ const localRetryDefaults = callConfig.retry ? { ...retryDefaults, ...callConfig.retry } : retryDefaults;
220
+
221
+ /**
222
+ * @param {Effect} eff
223
+ * @returns {Promise<SuccessState | FailureState>}
224
+ */
225
+ async function execute(eff) {
226
+ while (eff.type === 'Command' || eff.type === 'Ask' || eff.type === 'Retry' || eff.type === 'Parallel') {
227
+ if (eff.type === 'Ask') {
228
+ eff = eff.next(context);
229
+ continue;
230
+ }
231
+ if (eff.type === 'Retry') {
232
+ const opts = { ...localRetryDefaults, ...eff.options };
233
+ const { attempts } = opts;
234
+ let lastError;
235
+ let succeeded = false;
236
+
237
+ for (let attempt = 0; attempt <= attempts; attempt++) {
238
+ if (attempt > 0) {
239
+ await new Promise((r) => setTimeout(r, opts.delay * Math.pow(opts.backoff, attempt - 1)));
240
+ }
241
+ const result = await execute(eff.effect);
242
+ if (result.type === 'Success') {
243
+ eff = eff.next(result.value);
244
+ succeeded = true;
245
+ break;
246
+ }
247
+ lastError = result.error;
154
248
  }
155
- const cmdName = effect.cmd.name || 'anonymous';
156
- const initialInput = effect.initialInput;
157
- try {
158
- await commandInterceptor(effect, context);
159
- const result = await stepRunner(cmdName, 'Command', effect.cmd);
160
- effect = effect.next(result);
161
- } catch (e) {
162
- return Failure(e, initialInput);
249
+
250
+ if (!succeeded) {
251
+ return Failure({ retryExhausted: true, lastError, attempts }, eff.initialInput);
163
252
  }
253
+ continue;
164
254
  }
255
+ if (eff.type === 'Parallel') {
256
+ const results = await Promise.all(eff.effects.map((e) => execute(e)));
257
+ const failure = results.find((r) => r.type === 'Failure');
258
+ if (failure) return failure;
259
+ eff = eff.next(results.map((r) => /** @type {SuccessState} */ (r).value));
260
+ continue;
261
+ }
262
+ const cmdName = eff.cmd.name || 'anonymous';
263
+ const initialInput = eff.initialInput;
264
+ try {
265
+ await localCommandInterceptor(eff, context);
266
+ const result = await localStepRunner(cmdName, 'Command', eff.cmd);
267
+ eff = eff.next(result);
268
+ } catch (e) {
269
+ return Failure(e, initialInput);
270
+ }
271
+ }
272
+ return eff;
273
+ }
165
274
 
166
- return effect;
167
- },
168
- context?.flowName || ''
169
- );
275
+ return localRunWrapper(effect, () => execute(effect), context?.flowName || '');
170
276
  };
171
277
 
172
- export { Success, Failure, Command, Ask, effectPipe, runEffect, configureEffect };
278
+ export { Success, Failure, Command, Ask, Retry, Parallel, effectPipe, runEffect, configureEffect };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pure-effect",
3
- "version": "0.6.0",
4
- "description": "A tiny, zero-dependency effect system for writing pure, testable JavaScript/TypeScript without mocks.",
3
+ "version": "0.8.0",
4
+ "description": "A zero-dependency effect library for JavaScript and TypeScript with built-in support for dependency injection, retry, and OpenTelemetry where business logic is plain data you can test without mocks.",
5
5
  "type": "module",
6
6
  "exports": "./index.js",
7
7
  "types": "./index.d.ts",