mini-effect 0.0.4 → 0.0.6

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/README.md CHANGED
@@ -19,7 +19,17 @@ npm install mini-effect
19
19
  ## Core
20
20
 
21
21
  ```typescript
22
- import { fn, succeed, fail, gen, pipe, run, catchSome } from "mini-effect";
22
+ import {
23
+ fn,
24
+ succeed,
25
+ fail,
26
+ gen,
27
+ pipe,
28
+ run,
29
+ catchSome,
30
+ dependency,
31
+ retry,
32
+ } from "mini-effect";
23
33
  ```
24
34
 
25
35
  ### Create Effects
@@ -74,6 +84,24 @@ pipe(
74
84
  );
75
85
  ```
76
86
 
87
+ ### Retry
88
+
89
+ ```typescript
90
+ // Retry up to 3 times before failing
91
+ const resilient = retry(
92
+ 3,
93
+ fn(() => fetchUnreliableData()),
94
+ );
95
+
96
+ // Retry forever until success
97
+ const persistent = retry(
98
+ "forever",
99
+ fn(() => pollUntilReady()),
100
+ );
101
+ ```
102
+
103
+ When `times` is a number, the effect is retried up to that many times; if it still fails, the last error propagates. When `times` is `"forever"`, retries are unlimited and the error type narrows to `never`.
104
+
77
105
  ### Execution
78
106
 
79
107
  ```typescript
@@ -81,6 +109,60 @@ const result = await run(effect);
81
109
  const result = await run(effect, abortController.signal);
82
110
  ```
83
111
 
112
+ ## Dependencies
113
+
114
+ ```typescript
115
+ import { dependency, gen, run } from "mini-effect";
116
+ ```
117
+
118
+ `dependency` creates a typed tag that represents a value your effects need at runtime. Use `yield*` to read a dependency and `.provide()` to supply it.
119
+
120
+ ### Define a Dependency
121
+
122
+ ```typescript
123
+ const UserName = dependency("UserName")<string>();
124
+ const Logger = dependency("Logger")<{ log: (msg: string) => void }>();
125
+ ```
126
+
127
+ ### Read Dependencies in Effects
128
+
129
+ ```typescript
130
+ const sayHello = gen(function* () {
131
+ const name = yield* UserName;
132
+ return `Hello, ${name}`;
133
+ });
134
+ ```
135
+
136
+ ### Provide Dependencies via Pipe
137
+
138
+ ```typescript
139
+ const result = await run(sayHello.pipe(UserName.provide("Alice")));
140
+ // => "Hello, Alice"
141
+ ```
142
+
143
+ ### Compose Across Effects
144
+
145
+ Dependencies propagate through `yield*` — provide them at any level:
146
+
147
+ ```typescript
148
+ const program = gen(function* () {
149
+ const message = yield* sayHello;
150
+ return message;
151
+ }).pipe(UserName.provide("GPT"));
152
+
153
+ await run(program);
154
+ // => "Hello, GPT"
155
+ ```
156
+
157
+ ### Missing Dependencies
158
+
159
+ If a dependency is not provided, the effect fails with an `Error`:
160
+
161
+ ```typescript
162
+ await run(sayHello);
163
+ // throws Error("Missing dependency: UserName")
164
+ ```
165
+
84
166
  ## Concurrency
85
167
 
86
168
  ```typescript
@@ -155,15 +237,23 @@ Re-exports all of [Valibot](https://valibot.dev/).
155
237
 
156
238
  ### `mini-effect`
157
239
 
158
- | Export | Signature |
159
- | ----------- | ---------------------------------------------------------------- |
160
- | `fn` | `(thunk: (signal: AbortSignal) => T \| Promise<T>) => Effect<T>` |
161
- | `succeed` | `(value: T) => Effect<T, never>` |
162
- | `fail` | `(error: E) => Effect<never, E>` |
163
- | `gen` | `(generator: (signal) => Generator<Effect>) => Effect` |
164
- | `pipe` | `(effect, ...fns) => Effect` |
165
- | `run` | `(effect, signal?) => Promise<T>` |
166
- | `catchSome` | `(handler: (cause) => Effect \| undefined) => WrapEffect` |
240
+ | Export | Signature |
241
+ | ------------ | ---------------------------------------------------------------- |
242
+ | `fn` | `(thunk: (signal: AbortSignal) => T \| Promise<T>) => Effect<T>` |
243
+ | `succeed` | `(value: T) => Effect<T, never>` |
244
+ | `fail` | `(error: E) => Effect<never, E>` |
245
+ | `gen` | `(generator: (signal) => Generator<Effect>) => Effect` |
246
+ | `pipe` | `(effect, ...fns) => Effect` |
247
+ | `run` | `(effect, signal?) => Promise<T>` |
248
+ | `catchSome` | `(handler: (cause) => Effect \| undefined) => WrapEffect` |
249
+ | `dependency` | `(tag: string) => <T>() => Dependency<tag, T>` |
250
+ | `retry` | `(times: number \| "forever", effect) => Effect` |
251
+
252
+ #### `Dependency<D, T>`
253
+
254
+ | Member | Signature |
255
+ | --------- | ------------------------- |
256
+ | `provide` | `(instance: T) => Effect` |
167
257
 
168
258
  ### `mini-effect/concurrency`
169
259
 
@@ -1,10 +1,10 @@
1
- import { Effect, inferError, inferReturn } from "./mini-effect.mjs";
1
+ import { Effect, inferDependency, inferError, inferProvides, inferReturn } from "./mini-effect.mjs";
2
2
 
3
3
  //#region src/concurrency.d.ts
4
- declare const fork: <const E extends Effect<any, any>>(effect: E) => Effect<() => void, never>;
5
- declare const all: <const E extends Effect<any, any>[]>(values: E) => Effect<{ [K in keyof E]: inferReturn<E[K]> }, inferError<E[number]>>;
4
+ declare const fork: <const E extends Effect>(effect: E) => Effect<() => void, never, never, never>;
5
+ declare const all: <const E extends Effect<any, any>[]>(values: E) => Effect<{ [K in keyof E]: inferReturn<E[K]> }, inferError<E[number]>, inferDependency<E[number]>, inferProvides<E[number]>>;
6
6
  declare const allSettled: <const E extends Effect<any, any>[]>(values: E) => Effect<{ [K in keyof E]: PromiseSettledResult<inferReturn<E[K]>> }, inferError<E[number]>>;
7
- declare const any: <const E extends Effect<any, any>[]>(values: E) => Effect<inferReturn<E[number]>, inferError<E[number]>>;
7
+ declare const any: <const E extends Effect[]>(values: E) => Effect<inferReturn<E[number]>, inferError<E[number]>, inferDependency<E[number]>, inferProvides<E[number]>>;
8
8
  declare const race: <const E extends Effect<any, any>[]>(values: E) => Effect<inferReturn<E[number]>, inferError<E[number]>>;
9
9
  //#endregion
10
10
  export { all, allSettled, any, fork, race };
@@ -1,4 +1,4 @@
1
- import { _run as run, fn } from "./mini-effect.mjs";
1
+ import { fn, run } from "./mini-effect.mjs";
2
2
 
3
3
  //#region src/concurrency.ts
4
4
  const localController = (signal) => {
@@ -6,16 +6,16 @@ const localController = (signal) => {
6
6
  signal.addEventListener("abort", () => controller.abort(signal.reason));
7
7
  return controller;
8
8
  };
9
- const fork = (effect) => fn((signal) => {
9
+ const fork = (effect) => fn((signal, ctx) => {
10
10
  const controller = localController(signal);
11
- run(effect, controller.signal).catch();
11
+ run(effect, controller.signal, ctx).catch();
12
12
  return () => controller.abort();
13
13
  });
14
- const promiseMethod = (method, values) => fn(async (signal) => {
14
+ const promiseMethod = (method, values) => fn(async (signal, ctx) => {
15
15
  let controller = localController(signal);
16
16
  let localSignal = controller.signal;
17
17
  try {
18
- return await Promise[method](values.map((effect) => run(effect, localSignal)));
18
+ return await Promise[method](values.map((effect) => run(effect, localSignal, ctx)));
19
19
  } finally {
20
20
  if (!controller.signal.aborted) controller.abort();
21
21
  }
package/dist/fetch.d.mts CHANGED
@@ -5,10 +5,10 @@ import { Failure, FailureConstructor } from "./tag.mjs";
5
5
  declare const FailedToFetchError: FailureConstructor<"FailedToFetch">;
6
6
  declare const FailedToReadError: FailureConstructor<"FailedToRead">;
7
7
  declare const request: (input: string | URL, init?: RequestInit) => Effect<Response, InstanceType<typeof FailedToFetchError>>;
8
- declare const blob: (response: Response) => Effect<Blob, Failure<"FailedToRead">>;
9
- declare const bytes: (response: Response) => Effect<Uint8Array<ArrayBuffer>, Failure<"FailedToRead">>;
10
- declare const formData: (response: Response) => Effect<FormData, Failure<"FailedToRead">>;
11
- declare const json: (response: Response) => Effect<unknown, InstanceType<typeof FailedToReadError>>;
12
- declare const text: (response: Response) => Effect<string, Failure<"FailedToRead">>;
8
+ declare const blob: (response: Response) => Effect<Blob, Failure<"FailedToRead">, never, never>;
9
+ declare const bytes: (response: Response) => Effect<Uint8Array<ArrayBuffer>, Failure<"FailedToRead">, never, never>;
10
+ declare const formData: (response: Response) => Effect<FormData, Failure<"FailedToRead">, never, never>;
11
+ declare const json: (response: Response) => Effect<unknown, InstanceType<typeof FailedToReadError>, never, never>;
12
+ declare const text: (response: Response) => Effect<string, Failure<"FailedToRead">, never, never>;
13
13
  //#endregion
14
14
  export { blob, bytes, formData, json, request, text };
@@ -1,41 +1,57 @@
1
1
  //#region src/mini-effect.d.ts
2
2
  declare const SYMBOL: SymbolConstructor;
3
- declare const REMOVE: unique symbol;
3
+ declare const DEPENDENCY_TYPE: unique symbol;
4
+ declare const DEPENDENCY: unique symbol;
5
+ declare const PROVIDES_TYPE: unique symbol;
6
+ declare const PROVIDER: unique symbol;
7
+ declare const HANDLES_ERROR: unique symbol;
4
8
  declare const RUN: unique symbol;
5
9
  declare const ERROR: unique symbol;
6
- declare const run: <T, E$1>(effect: Effect<T, E$1>, signal?: AbortSignal) => Promise<T>;
7
- declare const fn: <R$1, C = never>(thunk: Thunk<R$1>) => Effect<R$1, C>;
8
- declare const fail: <C>(cause: C) => Effect<never, C>;
9
- declare const succeed: <R$1>(result: R$1) => Effect<R$1, never>;
10
- declare const catchSome: <T = any, C = any, CE = any>(thunk: (cause: unknown) => Effect<T, C> | undefined) => WrapEffect<T, C, CE>;
11
- declare const gen: <T extends Effect<any, any>, TReturn, TNext>(thunk: (signal: AbortSignal) => Generator<T, TReturn, TNext>) => Effect<TReturn, inferError<T>>;
10
+ declare const run: <T, E$1>(effect: Effect<T, E$1>, signal?: AbortSignal, ctx?: Record<string, unknown>) => Promise<T>;
11
+ declare const fn: <R$1, C = never>(thunk: Thunk<R$1>) => Effect<R$1, C, never, never>;
12
+ declare const fail: <C>(cause: C) => Effect<never, C, never, never>;
13
+ declare const succeed: <R$1>(result: R$1) => Effect<R$1, never, never, never>;
14
+ declare const catchSome: <T = any, C = any, CE = any, D$1 = any, P$1 = any>(thunk: (cause: unknown) => Effect<T, C, D$1, P$1> | undefined) => WrapEffect<T, C, CE, D$1, P$1>;
15
+ declare const dependency: <D$1 extends string>(tag: D$1) => <T>() => Dependency<D$1, T>;
16
+ declare const gen: <T extends Effect, TReturn, TNext>(thunk: (signal: AbortSignal, ctx: Record<string, unknown>) => Generator<T, TReturn, TNext>, localContext?: boolean) => Effect<TReturn, inferError<T>, Exclude<inferDependency<T>, inferProvides<T>>, inferProvides<T>>;
12
17
  declare const pipe: <F extends Effect, P$1 extends [Pipeable, ...Pipeable[]]>(first: F, ...pipeable: PipeReturn<[F, ...P$1]> extends never ? never : P$1) => PipeReturn<[F, ...P$1]>;
13
- declare class Effect<T = any, C = any> {
14
- [RUN]?: (signal: AbortSignal) => T | PromiseLike<T>;
18
+ declare const retry: <R$1 extends number | "forever", T, C, D$1, P$1>(times: R$1, effect: Effect<T, C, D$1, P$1>) => Effect<T, R$1 extends "forever" ? never : C, D$1, P$1>;
19
+ declare class Effect<T = any, C = any, D$1 = any, P$1 = any> {
20
+ [RUN]?: Thunk<T>;
15
21
  [ERROR]?: (cause: unknown) => Effect | undefined;
16
- constructor(run?: (signal: AbortSignal) => PromiseLike<T> | T, catchSome?: (cause: unknown) => Effect | undefined);
17
- [SYMBOL.iterator](): Generator<Effect<T, C>, T, any>;
18
- readonly pipe: <P$1 extends [Pipeable, ...Pipeable[]]>(...pipeable: P$1) => PipeReturn<[Effect<T, C>, ...P$1]>;
22
+ [DEPENDENCY_TYPE]: D$1;
23
+ [PROVIDES_TYPE]: P$1;
24
+ constructor(run?: Thunk<T>, catchSome?: (cause: unknown) => Effect | undefined);
25
+ [SYMBOL.iterator](): Generator<Effect<T, C, D$1, P$1>, T, any>;
26
+ readonly pipe: <E$1 extends [Pipeable, ...Pipeable[]]>(...pipeable: E$1) => PipeReturn<[Effect<T, C, D$1, P$1>, ...E$1]>;
19
27
  }
20
- declare class WrapEffect<T = any, C = any, CE = any> {
21
- readonly [RUN]?: (signal: AbortSignal) => PromiseLike<T> | T;
22
- readonly [ERROR]?: (cause: unknown) => Effect<any, any> | undefined;
23
- readonly [REMOVE]: CE;
24
- constructor(run?: (signal: AbortSignal) => PromiseLike<T> | T, catchSome?: (cause: unknown) => Effect | undefined);
25
- [SYMBOL.iterator](): Generator<Effect<T, C>, T, any>;
28
+ declare class WrapEffect<T = any, C = any, CE = any, D$1 = any, P$1 = any> extends Effect<T, C, D$1, P$1> {
29
+ readonly [HANDLES_ERROR]: CE;
26
30
  }
27
- type Thunk<out R$1> = (signal: AbortSignal) => R$1 | PromiseLike<R$1>;
28
- type PipeableThunk<T = any, C = any, I = any> = (next: I) => Effect<T, C>;
31
+ declare class Dependency<D$1 extends string = any, T = any> extends WrapEffect<T, never, Dependency<D$1, T>, Dependency<D$1, T>, never> {
32
+ readonly [DEPENDENCY]: true;
33
+ readonly __tag: D$1;
34
+ constructor(tag: D$1);
35
+ readonly provide: (instance: T) => Provide<D$1, T>;
36
+ }
37
+ declare class Provide<D$1 extends string = any, T = any> extends Effect<void, never, never, Dependency<D$1, T>> {
38
+ readonly [PROVIDER] = true;
39
+ constructor(tag: D$1, instance: T);
40
+ }
41
+ type Thunk<out R$1> = (signal: AbortSignal, ctx: Record<string, unknown>) => R$1 | PromiseLike<R$1>;
42
+ type PipeableThunk<out T = any, out C = any, in I = any, out D$1 = never, out P$1 = never> = (next: I) => Effect<T, C, D$1, P$1>;
29
43
  type Pipeable = PipeableThunk | Effect | WrapEffect;
30
- type inferInput<T> = T extends PipeableThunk<any, any, infer I> ? I : never;
31
- type inferReturn<T> = T extends WrapEffect<infer R> ? R : T extends Effect<infer R> ? R : T extends PipeableThunk<infer R> ? R : never;
44
+ type inferInput<T> = T extends PipeableThunk<any, any, infer I> ? I : T extends Effect ? any : never;
45
+ type inferReturn<T> = T extends PipeableThunk<infer R> ? R : T extends WrapEffect<infer R> ? R : T extends Effect<infer R> ? R : never;
32
46
  type inferError<T> = T extends PipeableThunk<any, infer E> ? E : T extends WrapEffect<any, infer E> ? E : T extends Effect<any, infer E> ? E : never;
33
47
  type inferExclude<T> = T extends WrapEffect<any, any, infer CE> ? CE : never;
34
- type Simplify<T> = T extends Effect<infer R, infer E> ? Effect<R, E> : never;
35
- type PipeReturn<F extends Pipeable[]> = IsNever<CheckPipe<F>> extends true ? never : Simplify<Effect<inferReturn<CheckPipe<F>> | inferReturn<Extract<F[number], WrapEffect>>, Exclude<inferError<F[number]>, inferExclude<Extract<F[number], WrapEffect>>>>>;
36
- type CheckPipe<F extends Pipeable[]> = F extends [Effect, WrapEffect, ...infer R] ? R extends [Pipeable, ...Pipeable[]] ? CheckPipe<R> : F[0] : F extends [Pipeable, Pipeable, ...infer P] ? ExtendsStrict<inferReturn<F[0]>, inferInput<F[1]>> extends true ? P extends Pipeable[] ? CheckPipe<[F[1], ...P]> : never : never : F extends [WrapEffect] ? Effect<inferReturn<F[0]>> : F extends [Pipeable] ? F[0] : never;
48
+ type inferDependency<T> = T extends Dependency<infer A, infer B> ? Dependency<A, B> : T extends Effect<any, any, infer D> ? D : never;
49
+ type inferProvides<T> = T extends Provide<infer D, infer T> ? Dependency<D, T> : T extends Effect<any, any, any, infer D> ? D : never;
50
+ type Simplify<T> = T extends Effect<infer R, infer E, infer D, infer P> ? Effect<R, E, D, P> : never;
51
+ type PipeReturn<F extends Pipeable[]> = IsNever<CheckPipe<F>> extends true ? never : Simplify<Effect<inferReturn<CheckPipe<F>> | inferReturn<Extract<F[number], WrapEffect>>, Exclude<inferError<F[number]>, inferExclude<Extract<F[number], WrapEffect>>>, Exclude<inferDependency<F[number]>, inferProvides<F[number]>>, Exclude<inferProvides<F[number]>, inferDependency<F[number]>>>>;
52
+ type CheckPipe<F extends Pipeable[]> = F extends [Effect, Provide, ...infer R] ? R extends [Pipeable, ...Pipeable[]] ? CheckPipe<R> : F[0] : F extends [Effect, WrapEffect, ...infer R] ? R extends [Pipeable, ...Pipeable[]] ? CheckPipe<R> : F[0] : F extends [Pipeable, Pipeable, ...infer P] ? ExtendsStrict<inferReturn<F[0]>, inferInput<F[1]>> extends true ? P extends Pipeable[] ? CheckPipe<[F[1], ...P]> : never : never : F extends [WrapEffect] ? Effect<inferReturn<F[0]>> : F extends [Pipeable] ? F[0] : never;
37
53
  type IsNever<T> = [T] extends [never] ? true : false;
38
54
  type IsAny<T> = 0 extends 1 & NoInfer<T> ? true : false;
39
55
  type ExtendsStrict<Left, Right> = IsAny<Left | Right> extends true ? true : IsNever<Left> extends true ? IsNever<Right> : [Left] extends [Right] ? true : false;
40
56
  //#endregion
41
- export { Effect, Pipeable, PipeableThunk, Thunk, WrapEffect, run as _run, run, catchSome, fail, fn, gen, inferError, inferExclude, inferInput, inferReturn, pipe, succeed };
57
+ export { Dependency, Effect, Pipeable, PipeableThunk, Thunk, WrapEffect, catchSome, dependency, fail, fn, gen, inferDependency, inferError, inferExclude, inferInput, inferProvides, inferReturn, pipe, retry, run, succeed };
@@ -1,24 +1,33 @@
1
1
  //#region src/mini-effect.ts
2
2
  const SYMBOL = Symbol;
3
- const REMOVE = /* @__PURE__ */ SYMBOL();
3
+ const DEPENDENCY_TYPE = /* @__PURE__ */ SYMBOL();
4
+ const DEPENDENCY = /* @__PURE__ */ SYMBOL();
5
+ const PROVIDES_TYPE = /* @__PURE__ */ SYMBOL();
6
+ const PROVIDER = /* @__PURE__ */ SYMBOL();
7
+ const HANDLES_ERROR = /* @__PURE__ */ SYMBOL();
4
8
  const RUN = SYMBOL();
5
9
  const ERROR = SYMBOL();
6
10
  const DEFAULT_SIGNAL = new AbortController().signal;
7
11
  const isFunction = (value) => typeof value === "function";
8
- const quickYieldResult = (iterator, signal, ret) => {
12
+ const quickYieldResult = (iterator, signal, ctx, ret) => {
9
13
  ret = iterator.next(ret);
10
- return ret.done ? ret.value : run(ret.value, signal).then((r) => quickYieldResult(iterator, signal, r));
14
+ return ret.done ? ret.value : run(ret.value, signal, ctx).then((r) => quickYieldResult(iterator, signal, ctx, r));
11
15
  };
12
- const run = (effect, signal) => new Promise((resolve) => resolve(effect[RUN](signal ?? DEFAULT_SIGNAL)));
16
+ const run = (effect, signal, ctx) => new Promise((resolve) => resolve(effect[RUN](signal ?? DEFAULT_SIGNAL, ctx ?? {})));
13
17
  const fn = (thunk) => new Effect(thunk);
14
18
  const fail = (cause) => fn(() => {
15
19
  throw cause;
16
20
  });
17
21
  const succeed = (result) => fn(() => result);
18
22
  const catchSome = (thunk) => new WrapEffect(void 0, thunk);
19
- const gen = (thunk) => fn((signal) => quickYieldResult(thunk(signal), signal));
23
+ const dependency = (tag) => () => new Dependency(tag);
24
+ const gen = (thunk, localContext) => fn((signal, ctx) => {
25
+ let ctxOverride = localContext ? { ...ctx } : ctx;
26
+ return quickYieldResult(thunk(signal, ctxOverride), signal, ctxOverride);
27
+ });
20
28
  const wrapEffect = (pipe$1, onErr) => new WrapEffect(pipe$1[RUN], (cause) => pipe$1[ERROR]?.(cause) ?? onErr(cause));
21
29
  const pipe = (first, ...pipeable) => {
30
+ let deps = [];
22
31
  let run$1 = [];
23
32
  let wrap = [];
24
33
  let pipe$1;
@@ -31,33 +40,41 @@ const pipe = (first, ...pipeable) => {
31
40
  }
32
41
  };
33
42
  let handler, wrappedFirst = wrapEffect(first, handlePipeError);
34
- for (pipe$1 of pipeable) {
43
+ for (pipe$1 of pipeable) if (pipe$1[PROVIDER]) deps.push(pipe$1);
44
+ else {
35
45
  handler = pipe$1[ERROR];
36
46
  if (isFunction(handler)) wrap.push(handler);
37
47
  if (isFunction(pipe$1) || isFunction(pipe$1[RUN])) run$1.push(pipe$1);
38
48
  }
39
- return gen(function* () {
49
+ return gen(function* (_, ctx) {
50
+ for (pipe$1 of deps) yield* pipe$1;
40
51
  next = yield* wrappedFirst;
41
52
  for (pipe$1 of run$1) {
42
53
  if (isFunction(pipe$1)) pipe$1 = pipe$1(next);
43
54
  if (isFunction(pipe$1[RUN])) next = yield* wrapEffect(pipe$1, handlePipeError);
44
55
  }
45
56
  return next;
46
- });
57
+ }, true);
58
+ };
59
+ const retry = (times, effect) => {
60
+ let step = 0;
61
+ return effect.pipe(catchSome((cause) => typeof times === "number" && ++step > times ? fail(cause) : effect));
47
62
  };
48
63
  var Effect = class {
49
64
  [RUN];
50
65
  [ERROR];
66
+ [DEPENDENCY_TYPE];
67
+ [PROVIDES_TYPE];
51
68
  constructor(run$1, catchSome$1) {
52
- this[RUN] = catchSome$1 && run$1 ? (signal) => {
69
+ this[RUN] = catchSome$1 && run$1 ? (signal, ctx) => {
53
70
  let res;
54
71
  let handleError = (cause) => {
55
72
  const recovery = catchSome$1(cause);
56
- if (recovery) return recovery[RUN]?.(signal);
73
+ if (recovery) return recovery[RUN]?.(signal, ctx);
57
74
  throw cause;
58
75
  };
59
76
  try {
60
- res = run$1(signal);
77
+ res = run$1(signal, ctx);
61
78
  return isFunction(res?.then) ? res.then(void 0, handleError) : res;
62
79
  } catch (cause) {
63
80
  return handleError(cause);
@@ -70,31 +87,29 @@ var Effect = class {
70
87
  }
71
88
  pipe = (...pipeable) => pipe(this, ...pipeable);
72
89
  };
73
- var WrapEffect = class {
74
- [RUN];
75
- [ERROR];
76
- [REMOVE];
77
- constructor(run$1, catchSome$1) {
78
- this[RUN] = catchSome$1 && run$1 ? (signal) => {
79
- let res;
80
- let handleError = (cause) => {
81
- const recovery = catchSome$1(cause);
82
- if (recovery) return recovery[RUN]?.(signal);
83
- throw cause;
84
- };
85
- try {
86
- res = run$1(signal);
87
- return isFunction(res?.then) ? res.then(void 0, handleError) : res;
88
- } catch (cause) {
89
- return handleError(cause);
90
- }
91
- } : run$1;
92
- this[ERROR] = catchSome$1;
90
+ var WrapEffect = class extends Effect {
91
+ [HANDLES_ERROR];
92
+ };
93
+ var Dependency = class extends WrapEffect {
94
+ [DEPENDENCY];
95
+ __tag;
96
+ constructor(tag) {
97
+ super((_, ctx) => {
98
+ if (tag in ctx) return ctx[tag];
99
+ throw new Error(`Missing dependency: ${tag}`);
100
+ });
101
+ this.__tag = tag;
93
102
  }
94
- *[SYMBOL.iterator]() {
95
- return yield this;
103
+ provide = (instance) => new Provide(this.__tag, instance);
104
+ };
105
+ var Provide = class extends Effect {
106
+ [PROVIDER] = true;
107
+ constructor(tag, instance) {
108
+ super((_, ctx) => {
109
+ ctx[tag] = instance;
110
+ });
96
111
  }
97
112
  };
98
113
 
99
114
  //#endregion
100
- export { Effect, WrapEffect, run as _run, run, catchSome, fail, fn, gen, pipe, succeed };
115
+ export { Dependency, Effect, WrapEffect, catchSome, dependency, fail, fn, gen, pipe, retry, run, succeed };
package/dist/schema.d.mts CHANGED
@@ -6,6 +6,6 @@ export * from "valibot";
6
6
  //#region src/schema.d.ts
7
7
  type Schema = v.BaseSchema<unknown, unknown, v.BaseIssue<unknown>> | v.BaseSchemaAsync<unknown, unknown, v.BaseIssue<unknown>>;
8
8
  declare const FaildToValidateError: FailureConstructor<"FailedToValidate">;
9
- declare const validate: <const S extends Schema>(schema: S) => (value: unknown) => Effect<v.InferOutput<S>, InstanceType<typeof FaildToValidateError>>;
9
+ declare const validate: <const S extends Schema>(schema: S) => (value: unknown) => Effect<v.InferOutput<S>, InstanceType<typeof FaildToValidateError>, never, never>;
10
10
  //#endregion
11
11
  export { Schema, validate };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mini-effect",
3
3
  "type": "module",
4
- "version": "0.0.4",
4
+ "version": "0.0.6",
5
5
  "description": "A mini-effect library for TypeScript.",
6
6
  "author": "Jacob Ebey <jacob.ebey@live.com>",
7
7
  "license": "MIT",