use-effect-ts 0.0.1 → 0.0.3

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
@@ -1,3 +1,3 @@
1
1
  # use-effect-ts
2
2
 
3
- Effect.TS hooks for React.
3
+ React hooks for Effect.TS 🚀
package/dist/index.d.ts CHANGED
@@ -1,2 +1,7 @@
1
- export {};
1
+ export { useComponentLifecycle } from "./use-component-lifecycle.js";
2
+ export { useRunEffect } from "./use-run-effect.js";
3
+ export { useRunEffectLatest } from "./use-run-effect-latest.js";
4
+ export { useRunEffectQueue } from "./use-run-effect-queue.js";
5
+ export { useComponentScope } from "./use-component-scope.js";
6
+ export { useLiveRef } from "./use-live-ref.js";
2
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,6 @@
1
- console.log("Hello, World!");
2
- export {};
1
+ export { useComponentLifecycle } from "./use-component-lifecycle.js";
2
+ export { useRunEffect } from "./use-run-effect.js";
3
+ export { useRunEffectLatest } from "./use-run-effect-latest.js";
4
+ export { useRunEffectQueue } from "./use-run-effect-queue.js";
5
+ export { useComponentScope } from "./use-component-scope.js";
6
+ export { useLiveRef } from "./use-live-ref.js";
@@ -0,0 +1,5 @@
1
+ import { Effect, Scope } from "effect";
2
+ export declare function useComponentLifecycle(effect: Effect.Effect<unknown, unknown, Scope.Scope>, { deps, }?: {
3
+ deps?: unknown[];
4
+ }): void;
5
+ //# sourceMappingURL=use-component-lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-component-lifecycle.d.ts","sourceRoot":"","sources":["../src/use-component-lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAS,KAAK,EAAE,MAAM,QAAQ,CAAC;AAI9C,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,EACpD,EACE,IAAS,GACV,GAAE;IACD,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;CACb,QAkBP"}
@@ -0,0 +1,17 @@
1
+ import { Effect, Fiber, Scope } from "effect";
2
+ import { useEffect } from "react";
3
+ import { useLiveRef } from "./use-live-ref.js";
4
+ export function useComponentLifecycle(effect, { deps = [], } = {}) {
5
+ const effectRef = useLiveRef(effect);
6
+ useEffect(() => {
7
+ const scope = Effect.runSync(Scope.make());
8
+ const fiber = Effect.runFork(effectRef.current.pipe(Scope.extend(scope)));
9
+ return () => {
10
+ Effect.runFork(Effect.gen(function* () {
11
+ const exit = yield* Fiber.interrupt(fiber);
12
+ yield* Scope.close(scope, exit);
13
+ }));
14
+ void Effect.runPromise(Fiber.interrupt(fiber));
15
+ };
16
+ }, [effectRef, ...deps]);
17
+ }
@@ -0,0 +1,3 @@
1
+ import { Scope } from "effect";
2
+ export declare function useComponentScope(setup?: (scope: Scope.CloseableScope) => void): Scope.CloseableScope | undefined;
3
+ //# sourceMappingURL=use-component-scope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-component-scope.d.ts","sourceRoot":"","sources":["../src/use-component-scope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,EAAE,MAAM,QAAQ,CAAC;AAG7C,wBAAgB,iBAAiB,CAC/B,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,cAAc,KAAK,IAAI,GAC5C,KAAK,CAAC,cAAc,GAAG,SAAS,CAclC"}
@@ -0,0 +1,14 @@
1
+ import { Effect, Exit, Scope } from "effect";
2
+ import { useEffect, useState } from "react";
3
+ export function useComponentScope(setup) {
4
+ const [scope, setScope] = useState();
5
+ useEffect(() => {
6
+ const s = Effect.runSync(Scope.make());
7
+ setScope(s);
8
+ setup?.(s);
9
+ return () => {
10
+ void Effect.runPromise(Scope.close(s, Exit.void));
11
+ };
12
+ }, []);
13
+ return scope;
14
+ }
@@ -0,0 +1,4 @@
1
+ export declare function useLiveRef<T>(value: T): {
2
+ current: T;
3
+ };
4
+ //# sourceMappingURL=use-live-ref.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-live-ref.d.ts","sourceRoot":"","sources":["../src/use-live-ref.ts"],"names":[],"mappings":"AAEA,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG;IAAE,OAAO,EAAE,CAAC,CAAA;CAAE,CAKtD"}
@@ -0,0 +1,6 @@
1
+ import { useRef } from "react";
2
+ export function useLiveRef(value) {
3
+ const ref = useRef(value);
4
+ ref.current = value;
5
+ return ref;
6
+ }
@@ -0,0 +1,3 @@
1
+ import { Effect } from "effect";
2
+ export declare function useRunEffectLatest<Args extends any[], A, E>(fn: (...args: Args) => Effect.Effect<A, E, never>): (...args: Args) => Promise<import("effect/Exit").Exit<import("effect/Fiber").RuntimeFiber<A, E>, never>>;
3
+ //# sourceMappingURL=use-run-effect-latest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-run-effect-latest.d.ts","sourceRoot":"","sources":["../src/use-run-effect-latest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAsB,MAAM,QAAQ,CAAC;AAIpD,wBAAgB,kBAAkB,CAAC,IAAI,SAAS,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,EACzD,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,IAYzC,GAAG,MAAM,IAAI,2FAStB"}
@@ -0,0 +1,16 @@
1
+ import { Effect, FiberHandle, Scope } from "effect";
2
+ import { useComponentScope } from "./use-component-scope.js";
3
+ import { useState } from "react";
4
+ export function useRunEffectLatest(fn) {
5
+ const [fiberHandle, setFiberHandle] = useState(null);
6
+ useComponentScope((scope) => {
7
+ const fiberHandle = Effect.runSync(FiberHandle.make().pipe(Scope.extend(scope)));
8
+ setFiberHandle(fiberHandle);
9
+ });
10
+ return (...args) => {
11
+ if (!fiberHandle) {
12
+ throw new Error("useRunEffectLatest: No scope available, effect will not run. Consider using useComponentLifecycle to call initial run.");
13
+ }
14
+ return Effect.runPromiseExit(FiberHandle.run(fiberHandle, fn(...args)));
15
+ };
16
+ }
@@ -0,0 +1,3 @@
1
+ import { Effect } from "effect";
2
+ export declare function useRunEffectQueue<Args extends any[], A, E>(fn: (...args: Args) => Effect.Effect<A, E, never>): (...args: Args) => void;
3
+ //# sourceMappingURL=use-run-effect-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-run-effect-queue.d.ts","sourceRoot":"","sources":["../src/use-run-effect-queue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAA6B,MAAM,QAAQ,CAAC;AAI3D,wBAAgB,iBAAiB,CAAC,IAAI,SAAS,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,EACxD,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,IA8BzC,GAAG,MAAM,IAAI,UAItB"}
@@ -0,0 +1,29 @@
1
+ import { Effect, Fiber, FiberHandle, Scope } from "effect";
2
+ import { useComponentScope } from "./use-component-scope.js";
3
+ import { useEffect, useRef } from "react";
4
+ export function useRunEffectQueue(fn) {
5
+ const queue = useRef([]);
6
+ const scope = useComponentScope();
7
+ const isExecuting = useRef(false);
8
+ const runFromQueue = () => {
9
+ const [first, ...rest] = queue.current;
10
+ if (!scope || !first || isExecuting.current) {
11
+ return;
12
+ }
13
+ queue.current = rest;
14
+ isExecuting.current = true;
15
+ Effect.runPromiseExit(Effect.gen(function* () {
16
+ const fiberHandle = yield* FiberHandle.make().pipe(Scope.extend(scope));
17
+ const fiber = yield* FiberHandle.run(fiberHandle)(fn(...first));
18
+ yield* Fiber.join(fiber);
19
+ })).finally(() => {
20
+ isExecuting.current = false;
21
+ runFromQueue();
22
+ });
23
+ };
24
+ useEffect(runFromQueue, [scope]);
25
+ return (...args) => {
26
+ queue.current.push(args);
27
+ runFromQueue();
28
+ };
29
+ }
@@ -0,0 +1,3 @@
1
+ import { Effect } from "effect";
2
+ export declare function useRunEffect<Args extends any[], A, E>(fn: (...args: Args) => Effect.Effect<A, E, never>): (...args: Args) => Promise<import("effect/Exit").Exit<import("effect/Fiber").RuntimeFiber<A, E>, never>>;
3
+ //# sourceMappingURL=use-run-effect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-run-effect.d.ts","sourceRoot":"","sources":["../src/use-run-effect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAmB,MAAM,QAAQ,CAAC;AAIjD,wBAAgB,YAAY,CAAC,IAAI,SAAS,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,EACnD,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,IAQzC,GAAG,MAAM,IAAI,2FAStB"}
@@ -0,0 +1,16 @@
1
+ import { Effect, FiberSet, Scope } from "effect";
2
+ import { useComponentScope } from "./use-component-scope.js";
3
+ import { useState } from "react";
4
+ export function useRunEffect(fn) {
5
+ const [fiberSet, setFiberSet] = useState(null);
6
+ useComponentScope((scope) => {
7
+ const fiberSet = Effect.runSync(FiberSet.make().pipe(Scope.extend(scope)));
8
+ setFiberSet(fiberSet);
9
+ });
10
+ return (...args) => {
11
+ if (!fiberSet) {
12
+ throw new Error("useRunEffect: No scope available, effect will not run. Consider using useComponentLifecycle to call initial run.");
13
+ }
14
+ return Effect.runPromiseExit(FiberSet.run(fiberSet, fn(...args)));
15
+ };
16
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "use-effect-ts",
3
3
  "type": "module",
4
- "version": "0.0.1",
4
+ "version": "0.0.3",
5
5
  "exports": {
6
6
  ".": "./dist/index.js",
7
7
  "./*": "./dist/*"
@@ -12,14 +12,15 @@
12
12
  "README.md",
13
13
  "LICENCE"
14
14
  ],
15
- "dependencies": {
16
- "effect": "3.16.9"
17
- },
18
15
  "devDependencies": {
19
16
  "@tsconfig/node22": "22.0.2",
17
+ "@types/react": "^19.1.8",
18
+ "effect": "3.16.12",
19
+ "react": "19.1.0",
20
20
  "typescript": "5.8.3"
21
21
  },
22
22
  "peerDependencies": {
23
+ "effect": ">=3.0.0",
23
24
  "react": ">=18.0.0"
24
25
  },
25
26
  "scripts": {
package/src/index.ts CHANGED
@@ -1 +1,6 @@
1
- console.log("Hello, World!");
1
+ export { useComponentLifecycle } from "./use-component-lifecycle.js";
2
+ export { useRunEffect } from "./use-run-effect.js";
3
+ export { useRunEffectLatest } from "./use-run-effect-latest.js";
4
+ export { useRunEffectQueue } from "./use-run-effect-queue.js";
5
+ export { useComponentScope } from "./use-component-scope.js";
6
+ export { useLiveRef } from "./use-live-ref.js";
@@ -0,0 +1,29 @@
1
+ import { Effect, Fiber, Scope } from "effect";
2
+ import { useEffect } from "react";
3
+ import { useLiveRef } from "./use-live-ref.js";
4
+
5
+ export function useComponentLifecycle(
6
+ effect: Effect.Effect<unknown, unknown, Scope.Scope>,
7
+ {
8
+ deps = [],
9
+ }: {
10
+ deps?: unknown[];
11
+ } = {},
12
+ ) {
13
+ const effectRef = useLiveRef(effect);
14
+
15
+ useEffect(() => {
16
+ const scope = Effect.runSync(Scope.make());
17
+ const fiber = Effect.runFork(effectRef.current.pipe(Scope.extend(scope)));
18
+
19
+ return () => {
20
+ Effect.runFork(
21
+ Effect.gen(function* () {
22
+ const exit = yield* Fiber.interrupt(fiber);
23
+ yield* Scope.close(scope, exit);
24
+ }),
25
+ );
26
+ void Effect.runPromise(Fiber.interrupt(fiber));
27
+ };
28
+ }, [effectRef, ...deps]);
29
+ }
@@ -0,0 +1,20 @@
1
+ import { Effect, Exit, Scope } from "effect";
2
+ import { useEffect, useState } from "react";
3
+
4
+ export function useComponentScope(
5
+ setup?: (scope: Scope.CloseableScope) => void,
6
+ ): Scope.CloseableScope | undefined {
7
+ const [scope, setScope] = useState<Scope.CloseableScope>();
8
+
9
+ useEffect(() => {
10
+ const s = Effect.runSync(Scope.make());
11
+ setScope(s);
12
+ setup?.(s);
13
+
14
+ return () => {
15
+ void Effect.runPromise(Scope.close(s, Exit.void));
16
+ };
17
+ }, []);
18
+
19
+ return scope;
20
+ }
@@ -0,0 +1,8 @@
1
+ import { useRef } from "react";
2
+
3
+ export function useLiveRef<T>(value: T): { current: T } {
4
+ const ref = useRef(value);
5
+ ref.current = value;
6
+
7
+ return ref;
8
+ }
@@ -0,0 +1,27 @@
1
+ import { Effect, FiberHandle, Scope } from "effect";
2
+ import { useComponentScope } from "./use-component-scope.js";
3
+ import { useState } from "react";
4
+
5
+ export function useRunEffectLatest<Args extends any[], A, E>(
6
+ fn: (...args: Args) => Effect.Effect<A, E, never>,
7
+ ) {
8
+ const [fiberHandle, setFiberHandle] =
9
+ useState<FiberHandle.FiberHandle | null>(null);
10
+
11
+ useComponentScope((scope) => {
12
+ const fiberHandle = Effect.runSync(
13
+ FiberHandle.make().pipe(Scope.extend(scope)),
14
+ );
15
+ setFiberHandle(fiberHandle);
16
+ });
17
+
18
+ return (...args: Args) => {
19
+ if (!fiberHandle) {
20
+ throw new Error(
21
+ "useRunEffectLatest: No scope available, effect will not run. Consider using useComponentLifecycle to call initial run.",
22
+ );
23
+ }
24
+
25
+ return Effect.runPromiseExit(FiberHandle.run(fiberHandle, fn(...args)));
26
+ };
27
+ }
@@ -0,0 +1,40 @@
1
+ import { Effect, Fiber, FiberHandle, Scope } from "effect";
2
+ import { useComponentScope } from "./use-component-scope.js";
3
+ import { useEffect, useRef } from "react";
4
+
5
+ export function useRunEffectQueue<Args extends any[], A, E>(
6
+ fn: (...args: Args) => Effect.Effect<A, E, never>,
7
+ ) {
8
+ const queue = useRef<Args[]>([]);
9
+ const scope = useComponentScope();
10
+
11
+ const isExecuting = useRef(false);
12
+ const runFromQueue = () => {
13
+ const [first, ...rest] = queue.current;
14
+ if (!scope || !first || isExecuting.current) {
15
+ return;
16
+ }
17
+
18
+ queue.current = rest;
19
+ isExecuting.current = true;
20
+ Effect.runPromiseExit(
21
+ Effect.gen(function* () {
22
+ const fiberHandle = yield* FiberHandle.make().pipe(Scope.extend(scope));
23
+
24
+ const fiber = yield* FiberHandle.run(fiberHandle)(fn(...first));
25
+
26
+ yield* Fiber.join(fiber);
27
+ }),
28
+ ).finally(() => {
29
+ isExecuting.current = false;
30
+ runFromQueue();
31
+ });
32
+ };
33
+
34
+ useEffect(runFromQueue, [scope]);
35
+
36
+ return (...args: Args) => {
37
+ queue.current.push(args);
38
+ runFromQueue();
39
+ };
40
+ }
@@ -0,0 +1,23 @@
1
+ import { Effect, FiberSet, Scope } from "effect";
2
+ import { useComponentScope } from "./use-component-scope.js";
3
+ import { useState } from "react";
4
+
5
+ export function useRunEffect<Args extends any[], A, E>(
6
+ fn: (...args: Args) => Effect.Effect<A, E, never>,
7
+ ) {
8
+ const [fiberSet, setFiberSet] = useState<FiberSet.FiberSet | null>(null);
9
+ useComponentScope((scope) => {
10
+ const fiberSet = Effect.runSync(FiberSet.make().pipe(Scope.extend(scope)));
11
+ setFiberSet(fiberSet);
12
+ });
13
+
14
+ return (...args: Args) => {
15
+ if (!fiberSet) {
16
+ throw new Error(
17
+ "useRunEffect: No scope available, effect will not run. Consider using useComponentLifecycle to call initial run.",
18
+ );
19
+ }
20
+
21
+ return Effect.runPromiseExit(FiberSet.run(fiberSet, fn(...args)));
22
+ };
23
+ }