ff-effect 0.0.1

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/dist/index.cjs ADDED
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ extract: () => extract,
24
+ runPromiseUnwrapped: () => runPromiseUnwrapped
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/extract.ts
29
+ var import_effect = require("effect");
30
+ function extract(effect, options) {
31
+ return import_effect.Effect.gen(function* () {
32
+ const runtime = yield* import_effect.Effect.runtime();
33
+ const context = runtime.context.pipe(
34
+ options?.exclude ? import_effect.Context.omit(...options.exclude) : (e) => e
35
+ );
36
+ return (...params) => (0, import_effect.pipe)(effect(...params), import_effect.Effect.provide(context));
37
+ });
38
+ }
39
+
40
+ // src/run-promise-unwrapped.ts
41
+ var import_effect2 = require("effect");
42
+ async function runPromiseUnwrapped(effect) {
43
+ const exit = await import_effect2.Effect.runPromiseExit(effect);
44
+ return import_effect2.Exit.match(exit, {
45
+ onSuccess: (value) => value,
46
+ onFailure: (cause) => {
47
+ throw import_effect2.Cause.isFailType(cause) ? cause.error : cause;
48
+ }
49
+ });
50
+ }
51
+ // Annotate the CommonJS export names for ESM import in node:
52
+ 0 && (module.exports = {
53
+ extract,
54
+ runPromiseUnwrapped
55
+ });
56
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/extract.ts","../src/run-promise-unwrapped.ts"],"sourcesContent":["export { extract } from './extract.js';\nexport { runPromiseUnwrapped } from './run-promise-unwrapped.js';\n","import { Context, Effect, pipe } from \"effect\";\n\ntype InferClass<T> = T extends new (...args: any[]) => infer R ? R : never;\n\n// biome-ignore lint/suspicious/noExplicitAny: intended\nexport function extract<\n\tP extends any[],\n\tA,\n\tE,\n\tR,\n\tINFERRED_EXCLUDED extends Context.Tag<any, any> = never,\n\tEXCLUDED = InferClass<INFERRED_EXCLUDED>,\n>(\n\teffect: (...params: P) => Effect.Effect<A, E, R>,\n\toptions?: { exclude?: Array<INFERRED_EXCLUDED> }\n): Effect.Effect<\n\t(...params: P) => Effect.Effect<A, E, Extract<R, EXCLUDED>>,\n\tnever,\n\tExclude<R, EXCLUDED>\n> {\n\t// @ts-expect-error quite hard to type, check unit test\n\treturn Effect.gen(function* () {\n\t\tconst runtime = yield* Effect.runtime();\n\n\t\tconst context = runtime.context.pipe(\n\t\t\toptions?.exclude ? Context.omit(...options.exclude) : (e) => e\n\t\t) as Context.Context<Exclude<R, EXCLUDED>>;\n\n\t\treturn (...params: P) =>\n\t\t\tpipe(effect(...params), Effect.provide(context));\n\t});\n}\n","import { Cause, Effect, Exit } from \"effect\";\n\n/**\n * A simple wrapper around Effect.runPromiseExit that throws the error if it's a failure\n **/\nexport async function runPromiseUnwrapped<A, E>(\n\teffect: Effect.Effect<A, E, never>\n) {\n\tconst exit = await Effect.runPromiseExit(effect);\n\treturn Exit.match(exit, {\n\t\tonSuccess: (value) => value,\n\t\tonFailure: (cause) => {\n\t\t\tthrow Cause.isFailType(cause) ? cause.error : cause;\n\t\t},\n\t});\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,oBAAsC;AAK/B,SAAS,QAQf,QACA,SAKC;AAED,SAAO,qBAAO,IAAI,aAAa;AAC9B,UAAM,UAAU,OAAO,qBAAO,QAAQ;AAEtC,UAAM,UAAU,QAAQ,QAAQ;AAAA,MAC/B,SAAS,UAAU,sBAAQ,KAAK,GAAG,QAAQ,OAAO,IAAI,CAAC,MAAM;AAAA,IAC9D;AAEA,WAAO,IAAI,eACV,oBAAK,OAAO,GAAG,MAAM,GAAG,qBAAO,QAAQ,OAAO,CAAC;AAAA,EACjD,CAAC;AACF;;;AC/BA,IAAAA,iBAAoC;AAKpC,eAAsB,oBACrB,QACC;AACD,QAAM,OAAO,MAAM,sBAAO,eAAe,MAAM;AAC/C,SAAO,oBAAK,MAAM,MAAM;AAAA,IACvB,WAAW,CAAC,UAAU;AAAA,IACtB,WAAW,CAAC,UAAU;AACrB,YAAM,qBAAM,WAAW,KAAK,IAAI,MAAM,QAAQ;AAAA,IAC/C;AAAA,EACD,CAAC;AACF;","names":["import_effect"]}
@@ -0,0 +1,13 @@
1
+ import { Context, Effect } from 'effect';
2
+
3
+ type InferClass<T> = T extends new (...args: any[]) => infer R ? R : never;
4
+ declare function extract<P extends any[], A, E, R, INFERRED_EXCLUDED extends Context.Tag<any, any> = never, EXCLUDED = InferClass<INFERRED_EXCLUDED>>(effect: (...params: P) => Effect.Effect<A, E, R>, options?: {
5
+ exclude?: Array<INFERRED_EXCLUDED>;
6
+ }): Effect.Effect<(...params: P) => Effect.Effect<A, E, Extract<R, EXCLUDED>>, never, Exclude<R, EXCLUDED>>;
7
+
8
+ /**
9
+ * A simple wrapper around Effect.runPromiseExit that throws the error if it's a failure
10
+ **/
11
+ declare function runPromiseUnwrapped<A, E>(effect: Effect.Effect<A, E, never>): Promise<A>;
12
+
13
+ export { extract, runPromiseUnwrapped };
@@ -0,0 +1,13 @@
1
+ import { Context, Effect } from 'effect';
2
+
3
+ type InferClass<T> = T extends new (...args: any[]) => infer R ? R : never;
4
+ declare function extract<P extends any[], A, E, R, INFERRED_EXCLUDED extends Context.Tag<any, any> = never, EXCLUDED = InferClass<INFERRED_EXCLUDED>>(effect: (...params: P) => Effect.Effect<A, E, R>, options?: {
5
+ exclude?: Array<INFERRED_EXCLUDED>;
6
+ }): Effect.Effect<(...params: P) => Effect.Effect<A, E, Extract<R, EXCLUDED>>, never, Exclude<R, EXCLUDED>>;
7
+
8
+ /**
9
+ * A simple wrapper around Effect.runPromiseExit that throws the error if it's a failure
10
+ **/
11
+ declare function runPromiseUnwrapped<A, E>(effect: Effect.Effect<A, E, never>): Promise<A>;
12
+
13
+ export { extract, runPromiseUnwrapped };
package/dist/index.js ADDED
@@ -0,0 +1,28 @@
1
+ // src/extract.ts
2
+ import { Context, Effect, pipe } from "effect";
3
+ function extract(effect, options) {
4
+ return Effect.gen(function* () {
5
+ const runtime = yield* Effect.runtime();
6
+ const context = runtime.context.pipe(
7
+ options?.exclude ? Context.omit(...options.exclude) : (e) => e
8
+ );
9
+ return (...params) => pipe(effect(...params), Effect.provide(context));
10
+ });
11
+ }
12
+
13
+ // src/run-promise-unwrapped.ts
14
+ import { Cause, Effect as Effect2, Exit } from "effect";
15
+ async function runPromiseUnwrapped(effect) {
16
+ const exit = await Effect2.runPromiseExit(effect);
17
+ return Exit.match(exit, {
18
+ onSuccess: (value) => value,
19
+ onFailure: (cause) => {
20
+ throw Cause.isFailType(cause) ? cause.error : cause;
21
+ }
22
+ });
23
+ }
24
+ export {
25
+ extract,
26
+ runPromiseUnwrapped
27
+ };
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/extract.ts","../src/run-promise-unwrapped.ts"],"sourcesContent":["import { Context, Effect, pipe } from \"effect\";\n\ntype InferClass<T> = T extends new (...args: any[]) => infer R ? R : never;\n\n// biome-ignore lint/suspicious/noExplicitAny: intended\nexport function extract<\n\tP extends any[],\n\tA,\n\tE,\n\tR,\n\tINFERRED_EXCLUDED extends Context.Tag<any, any> = never,\n\tEXCLUDED = InferClass<INFERRED_EXCLUDED>,\n>(\n\teffect: (...params: P) => Effect.Effect<A, E, R>,\n\toptions?: { exclude?: Array<INFERRED_EXCLUDED> }\n): Effect.Effect<\n\t(...params: P) => Effect.Effect<A, E, Extract<R, EXCLUDED>>,\n\tnever,\n\tExclude<R, EXCLUDED>\n> {\n\t// @ts-expect-error quite hard to type, check unit test\n\treturn Effect.gen(function* () {\n\t\tconst runtime = yield* Effect.runtime();\n\n\t\tconst context = runtime.context.pipe(\n\t\t\toptions?.exclude ? Context.omit(...options.exclude) : (e) => e\n\t\t) as Context.Context<Exclude<R, EXCLUDED>>;\n\n\t\treturn (...params: P) =>\n\t\t\tpipe(effect(...params), Effect.provide(context));\n\t});\n}\n","import { Cause, Effect, Exit } from \"effect\";\n\n/**\n * A simple wrapper around Effect.runPromiseExit that throws the error if it's a failure\n **/\nexport async function runPromiseUnwrapped<A, E>(\n\teffect: Effect.Effect<A, E, never>\n) {\n\tconst exit = await Effect.runPromiseExit(effect);\n\treturn Exit.match(exit, {\n\t\tonSuccess: (value) => value,\n\t\tonFailure: (cause) => {\n\t\t\tthrow Cause.isFailType(cause) ? cause.error : cause;\n\t\t},\n\t});\n}\n"],"mappings":";AAAA,SAAS,SAAS,QAAQ,YAAY;AAK/B,SAAS,QAQf,QACA,SAKC;AAED,SAAO,OAAO,IAAI,aAAa;AAC9B,UAAM,UAAU,OAAO,OAAO,QAAQ;AAEtC,UAAM,UAAU,QAAQ,QAAQ;AAAA,MAC/B,SAAS,UAAU,QAAQ,KAAK,GAAG,QAAQ,OAAO,IAAI,CAAC,MAAM;AAAA,IAC9D;AAEA,WAAO,IAAI,WACV,KAAK,OAAO,GAAG,MAAM,GAAG,OAAO,QAAQ,OAAO,CAAC;AAAA,EACjD,CAAC;AACF;;;AC/BA,SAAS,OAAO,UAAAA,SAAQ,YAAY;AAKpC,eAAsB,oBACrB,QACC;AACD,QAAM,OAAO,MAAMA,QAAO,eAAe,MAAM;AAC/C,SAAO,KAAK,MAAM,MAAM;AAAA,IACvB,WAAW,CAAC,UAAU;AAAA,IACtB,WAAW,CAAC,UAAU;AACrB,YAAM,MAAM,WAAW,KAAK,IAAI,MAAM,QAAQ;AAAA,IAC/C;AAAA,EACD,CAAC;AACF;","names":["Effect"]}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "ff-effect",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "exports": {
6
+ ".": {
7
+ "types": "./dist/index.d.ts",
8
+ "import": "./dist/index.js",
9
+ "require": "./dist/index.cjs"
10
+ }
11
+ },
12
+ "files": [
13
+ "dist",
14
+ "src"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsup",
18
+ "test": "vitest run",
19
+ "dev": "tsup --watch"
20
+ },
21
+ "devDependencies": {
22
+ "@total-typescript/tsconfig": "^1.0.4",
23
+ "@types/bun": "^1.3.2",
24
+ "tsup": "^8.5.0",
25
+ "typescript": "^5.9.3",
26
+ "vitest": "^4.0.10"
27
+ },
28
+ "peerDependencies": {
29
+ "effect": "^3.19.3"
30
+ },
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "homepage": "https://github.com/fdarian/ff.git",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/fdarian/ff.git"
38
+ },
39
+ "bugs": {
40
+ "url": "https://github.com/fdarian/ff/issues"
41
+ },
42
+ "keywords": [
43
+ "effect",
44
+ "utils",
45
+ "tools"
46
+ ]
47
+ }
@@ -0,0 +1,110 @@
1
+ import { Effect, Layer } from 'effect';
2
+ import { expect, expectTypeOf, test } from 'vitest';
3
+ import { extract } from './extract.js';
4
+
5
+ class ServiceA extends Effect.Service<ServiceA>()('A', {
6
+ sync: () => ({ val: 'A' as string }),
7
+ }) {}
8
+
9
+ class ServiceB extends Effect.Service<ServiceB>()('B', {
10
+ sync: () => ({ val: 'B' as string }),
11
+ }) {}
12
+
13
+ test('basic', () =>
14
+ Effect.gen(function* () {
15
+ const getVal = Effect.fn(function* () {
16
+ return (yield* ServiceA).val;
17
+ });
18
+
19
+ const Container_effect = Effect.gen(function* () {
20
+ return {
21
+ getVal: yield* extract(getVal),
22
+ };
23
+ });
24
+ expectTypeOf(Container_effect).toEqualTypeOf<
25
+ Effect.Effect<
26
+ {
27
+ // ServiceA is moved, no longer here
28
+ getVal: () => Effect.Effect<string, never, never>;
29
+ },
30
+ never,
31
+ // ServiceA is now here
32
+ ServiceA
33
+ >
34
+ >();
35
+
36
+ class Container extends Effect.Service<Container>()('Container', {
37
+ dependencies: [ServiceA.Default],
38
+ effect: Container_effect,
39
+ }) {}
40
+
41
+ const main = Effect.gen(function* () {
42
+ const container = yield* Container;
43
+
44
+ expect(yield* container.getVal()).toBe('A');
45
+ }).pipe(Effect.provide(Container.Default));
46
+
47
+ yield* main;
48
+ }).pipe((e) => Effect.runPromise(e)));
49
+
50
+ /** Checks whether we have omitted the `excluded` tags in runtime (not type level) */
51
+ test('with excluded', () =>
52
+ Effect.gen(function* () {
53
+ const getVal = Effect.fn(function* () {
54
+ return {
55
+ a: (yield* ServiceA).val,
56
+ b: (yield* ServiceB).val,
57
+ };
58
+ });
59
+
60
+ const Container_effect = Effect.gen(function* () {
61
+ return {
62
+ getVal: yield* extract(getVal, { exclude: [ServiceB] }),
63
+ };
64
+ });
65
+ expectTypeOf(Container_effect).toEqualTypeOf<
66
+ Effect.Effect<
67
+ {
68
+ getVal: () => Effect.Effect<
69
+ {
70
+ a: string;
71
+ b: string;
72
+ },
73
+ never,
74
+ // ServiceA is moved, no longer here,
75
+ // but ServiceB still, because of the `exclude`
76
+ ServiceB
77
+ >;
78
+ },
79
+ never,
80
+ // ServiceA is now here
81
+ ServiceA
82
+ >
83
+ >();
84
+
85
+ class Container extends Effect.Service<Container>()('Container', {
86
+ dependencies: [
87
+ ServiceA.Default,
88
+ // Assume this is what the service by default provides ServiceB
89
+ Layer.succeed(ServiceB, ServiceB.make({ val: 'not this' })),
90
+ ],
91
+ effect: Container_effect,
92
+ }) {}
93
+
94
+ const main = Effect.gen(function* () {
95
+ const container = yield* Container;
96
+ const result = yield* container.getVal().pipe(
97
+ Effect.provideService(
98
+ ServiceB,
99
+ // The exclusion should use this instead
100
+ ServiceB.make({ val: 'this one' }),
101
+ ),
102
+ );
103
+
104
+ expect(result.a).toBe('A');
105
+ // B is using the new provided
106
+ expect(result.b).toBe('this one');
107
+ }).pipe(Effect.provide(Container.Default));
108
+
109
+ yield* main;
110
+ }).pipe((e) => Effect.runPromise(e)));
package/src/extract.ts ADDED
@@ -0,0 +1,32 @@
1
+ import { Context, Effect, pipe } from "effect";
2
+
3
+ type InferClass<T> = T extends new (...args: any[]) => infer R ? R : never;
4
+
5
+ // biome-ignore lint/suspicious/noExplicitAny: intended
6
+ export function extract<
7
+ P extends any[],
8
+ A,
9
+ E,
10
+ R,
11
+ INFERRED_EXCLUDED extends Context.Tag<any, any> = never,
12
+ EXCLUDED = InferClass<INFERRED_EXCLUDED>,
13
+ >(
14
+ effect: (...params: P) => Effect.Effect<A, E, R>,
15
+ options?: { exclude?: Array<INFERRED_EXCLUDED> }
16
+ ): Effect.Effect<
17
+ (...params: P) => Effect.Effect<A, E, Extract<R, EXCLUDED>>,
18
+ never,
19
+ Exclude<R, EXCLUDED>
20
+ > {
21
+ // @ts-expect-error quite hard to type, check unit test
22
+ return Effect.gen(function* () {
23
+ const runtime = yield* Effect.runtime();
24
+
25
+ const context = runtime.context.pipe(
26
+ options?.exclude ? Context.omit(...options.exclude) : (e) => e
27
+ ) as Context.Context<Exclude<R, EXCLUDED>>;
28
+
29
+ return (...params: P) =>
30
+ pipe(effect(...params), Effect.provide(context));
31
+ });
32
+ }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { extract } from './extract.js';
2
+ export { runPromiseUnwrapped } from './run-promise-unwrapped.js';
@@ -0,0 +1,16 @@
1
+ import { Cause, Effect, Exit } from "effect";
2
+
3
+ /**
4
+ * A simple wrapper around Effect.runPromiseExit that throws the error if it's a failure
5
+ **/
6
+ export async function runPromiseUnwrapped<A, E>(
7
+ effect: Effect.Effect<A, E, never>
8
+ ) {
9
+ const exit = await Effect.runPromiseExit(effect);
10
+ return Exit.match(exit, {
11
+ onSuccess: (value) => value,
12
+ onFailure: (cause) => {
13
+ throw Cause.isFailType(cause) ? cause.error : cause;
14
+ },
15
+ });
16
+ }