effect-query 0.0.1-alpha.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/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Voidhash s.r.o.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.cjs ADDED
@@ -0,0 +1,140 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+
23
+ //#endregion
24
+ let __tanstack_react_query = require("@tanstack/react-query");
25
+ __tanstack_react_query = __toESM(__tanstack_react_query);
26
+ let effect = require("effect");
27
+ effect = __toESM(effect);
28
+
29
+ //#region \0@oxc-project+runtime@0.95.0/helpers/typeof.js
30
+ function _typeof(o) {
31
+ "@babel/helpers - typeof";
32
+ return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o$1) {
33
+ return typeof o$1;
34
+ } : function(o$1) {
35
+ return o$1 && "function" == typeof Symbol && o$1.constructor === Symbol && o$1 !== Symbol.prototype ? "symbol" : typeof o$1;
36
+ }, _typeof(o);
37
+ }
38
+
39
+ //#endregion
40
+ //#region \0@oxc-project+runtime@0.95.0/helpers/toPrimitive.js
41
+ function toPrimitive(t, r) {
42
+ if ("object" != _typeof(t) || !t) return t;
43
+ var e = t[Symbol.toPrimitive];
44
+ if (void 0 !== e) {
45
+ var i = e.call(t, r || "default");
46
+ if ("object" != _typeof(i)) return i;
47
+ throw new TypeError("@@toPrimitive must return a primitive value.");
48
+ }
49
+ return ("string" === r ? String : Number)(t);
50
+ }
51
+
52
+ //#endregion
53
+ //#region \0@oxc-project+runtime@0.95.0/helpers/toPropertyKey.js
54
+ function toPropertyKey(t) {
55
+ var i = toPrimitive(t, "string");
56
+ return "symbol" == _typeof(i) ? i : i + "";
57
+ }
58
+
59
+ //#endregion
60
+ //#region \0@oxc-project+runtime@0.95.0/helpers/defineProperty.js
61
+ function _defineProperty(e, r, t) {
62
+ return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
63
+ value: t,
64
+ enumerable: !0,
65
+ configurable: !0,
66
+ writable: !0
67
+ }) : e[r] = t, e;
68
+ }
69
+
70
+ //#endregion
71
+ //#region src/errors.ts
72
+ var EffectQueryError = class extends Error {
73
+ constructor(message, cause) {
74
+ super(message);
75
+ _defineProperty(this, "cause", void 0);
76
+ this.cause = cause;
77
+ }
78
+ };
79
+
80
+ //#endregion
81
+ //#region \0@oxc-project+runtime@0.95.0/helpers/objectSpread2.js
82
+ function ownKeys(e, r) {
83
+ var t = Object.keys(e);
84
+ if (Object.getOwnPropertySymbols) {
85
+ var o = Object.getOwnPropertySymbols(e);
86
+ r && (o = o.filter(function(r$1) {
87
+ return Object.getOwnPropertyDescriptor(e, r$1).enumerable;
88
+ })), t.push.apply(t, o);
89
+ }
90
+ return t;
91
+ }
92
+ function _objectSpread2(e) {
93
+ for (var r = 1; r < arguments.length; r++) {
94
+ var t = null != arguments[r] ? arguments[r] : {};
95
+ r % 2 ? ownKeys(Object(t), !0).forEach(function(r$1) {
96
+ _defineProperty(e, r$1, t[r$1]);
97
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function(r$1) {
98
+ Object.defineProperty(e, r$1, Object.getOwnPropertyDescriptor(t, r$1));
99
+ });
100
+ }
101
+ return e;
102
+ }
103
+
104
+ //#endregion
105
+ //#region src/index.ts
106
+ function createEffectQuery(layer) {
107
+ const runtime = effect.ManagedRuntime.make(layer);
108
+ const runner = (span, options = {}) => (effect$1) => runtime.runPromiseExit(effect$1.pipe(effect.Effect.withSpan(span), effect.Effect.scoped, effect.Effect.tapErrorCause(effect.Effect.logError)), { signal: options.signal });
109
+ return {
110
+ queryOptions: (options) => {
111
+ const [spanName] = options.queryKey;
112
+ const queryFn = async (context) => {
113
+ const result = await options.queryFn(context).pipe(runner(spanName, { signal: context.signal }));
114
+ return effect.Exit.match(result, {
115
+ onSuccess: (value) => value,
116
+ onFailure: (cause) => {
117
+ throw new EffectQueryError(effect.Cause.pretty(cause), cause);
118
+ }
119
+ });
120
+ };
121
+ return (0, __tanstack_react_query.queryOptions)(_objectSpread2(_objectSpread2({}, options), {}, { queryFn }));
122
+ },
123
+ mutationOptions: (options) => {
124
+ const spanName = options.mutationKey;
125
+ const mutationFn = async (variables) => {
126
+ const result = await options.mutationFn(variables).pipe(runner(spanName));
127
+ return effect.Exit.match(result, {
128
+ onSuccess: (value) => value,
129
+ onFailure: (cause) => {
130
+ throw new EffectQueryError(effect.Cause.pretty(cause), cause);
131
+ }
132
+ });
133
+ };
134
+ return (0, __tanstack_react_query.mutationOptions)(_objectSpread2(_objectSpread2({}, options), {}, { mutationFn }));
135
+ }
136
+ };
137
+ }
138
+
139
+ //#endregion
140
+ exports.createEffectQuery = createEffectQuery;
@@ -0,0 +1,32 @@
1
+ import * as _tanstack_react_query0 from "@tanstack/react-query";
2
+ import { UseMutationOptions, UseQueryOptions, skipToken } from "@tanstack/react-query";
3
+ import { Cause, Effect, Layer, Scope } from "effect";
4
+
5
+ //#region src/errors.d.ts
6
+ declare class EffectQueryError<TCause extends Cause.Cause<any>> extends Error {
7
+ readonly cause: TCause;
8
+ constructor(message: string, cause: TCause);
9
+ }
10
+ //#endregion
11
+ //#region src/index.d.ts
12
+ declare function createEffectQuery<Input>(layer: Layer.Layer<Input, never, never>): {
13
+ queryOptions: <TData, E, R extends Input | Scope.Scope, TQueryKey extends QueryKey = QueryKey>(options: Omit<UseQueryOptions<TData, E, TData, TQueryKey>, "queryKey" | "queryFn"> & {
14
+ queryKey: TQueryKey;
15
+ queryFn: typeof skipToken | ((context: {
16
+ client: _tanstack_react_query0.QueryClient;
17
+ queryKey: TQueryKey;
18
+ signal: AbortSignal;
19
+ meta: _tanstack_react_query0.QueryMeta | undefined;
20
+ pageParam?: unknown;
21
+ direction?: unknown;
22
+ }) => Effect.Effect<TData, E, R>);
23
+ }) => UseQueryOptions<TData, E extends never ? never : EffectQueryError<Cause.Cause<E>>, TData, TQueryKey>;
24
+ mutationOptions: <TData, E, TVariables, R extends Input | Scope.Scope>(options: Omit<UseMutationOptions<TData, Error, TVariables, unknown>, "mutationKey" | "mutationFn"> & {
25
+ mutationKey: string;
26
+ mutationFn: typeof skipToken | ((variables: TVariables) => Effect.Effect<TData, E, R>);
27
+ }) => UseMutationOptions<TData, E extends never ? never : EffectQueryError<Cause.Cause<E>>, TVariables>;
28
+ };
29
+ type QueryKey = readonly [string, string, Record<string, unknown>?];
30
+ //#endregion
31
+ export { createEffectQuery };
32
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/errors.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;;cAEa,gCAAgC,KAAA,CAAM,oBAAoB,KAAA;kBAC5C;sCACW;;;;iBCgBtB,gCACP,KAAA,CAAM,MAAM;qCA0Ed,QAAA,KAAA,CAAA,yBACiB,WAAQ,mBAAA,KAAA,gBAAA,OAAA,GAAA,OAAA;ID9FnB,QAAA,WAAgB;IAAsB,OAAA,EAAA,gBAAA,GAAA,CAAA,CAAA,OAAA,EAAA;MACxB,MAAA,oCAAA;MACW,QAAA,WAAA;MAFiC,MAAA,aAAA;MAAK,IAAA,qCAAA,SAAA;;;;ECkB5D,CAAA,EAAA,GAsGJ,eAtGqB,CAuGzB,KAvGyB,EAwGzB,CAxGyB,SAAA,KAAA,GAAA,KAAA,GAwGC,gBAxGD,CAwGkB,KAAA,CAAM,KAxGxB,CAwG8B,CAxG9B,CAAA,CAAA,EAyGzB,KAzGyB,EA0GzB,SA1GyB,CAAA;EACZ,eAAA,EAAA,CAAA,KAAA,EAAA,CAAA,EAAA,UAAA,EAAA,UA4GwB,KA5GxB,GA4GwB,KAAA,CAAA,KA5GxB,CAAA,CAAA,OAAA,EA4GwB,IA5GxB,CA4GwB,kBA5GxB,CA4GwB,KA5GxB,EA4GwB,KA5GxB,EA4GwB,UA5GxB,EAAA,OAAA,CAAA,EAAA,aAAA,GAAA,YAAA,CAAA,GAAA;IAAN,WAAA,EAAA,MAAA;IA0ER,UAAA,EAAA,gBAAA,GAAA,CAAA,CAAA,SAAA,YAAA,EAAA,gBAAA,MAAA,GAAA,GAAA,CAAA,CAAA;EAAA,CAAA,EAAA,GA6DK,kBA7DL,CA8DC,KA9DD,EA+DC,CA/DD,SAAA,KAAA,GAAA,KAAA,GA+D2B,gBA/D3B,CA+D4C,KAAA,CAAM,KA/DlD,CA+DwD,CA/DxD,CAAA,CAAA,EAgEC,UAhED,CAAA;CACiB;KAqEnB,QAAA,GArE2B,SAAA,CAAA,MAAA,EAAA,MAAA,EAqEU,MArEV,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,CAAA"}
@@ -0,0 +1,32 @@
1
+ import * as _tanstack_react_query0 from "@tanstack/react-query";
2
+ import { UseMutationOptions, UseQueryOptions, skipToken } from "@tanstack/react-query";
3
+ import { Cause, Effect, Layer, Scope } from "effect";
4
+
5
+ //#region src/errors.d.ts
6
+ declare class EffectQueryError<TCause extends Cause.Cause<any>> extends Error {
7
+ readonly cause: TCause;
8
+ constructor(message: string, cause: TCause);
9
+ }
10
+ //#endregion
11
+ //#region src/index.d.ts
12
+ declare function createEffectQuery<Input>(layer: Layer.Layer<Input, never, never>): {
13
+ queryOptions: <TData, E, R extends Input | Scope.Scope, TQueryKey extends QueryKey = QueryKey>(options: Omit<UseQueryOptions<TData, E, TData, TQueryKey>, "queryKey" | "queryFn"> & {
14
+ queryKey: TQueryKey;
15
+ queryFn: typeof skipToken | ((context: {
16
+ client: _tanstack_react_query0.QueryClient;
17
+ queryKey: TQueryKey;
18
+ signal: AbortSignal;
19
+ meta: _tanstack_react_query0.QueryMeta | undefined;
20
+ pageParam?: unknown;
21
+ direction?: unknown;
22
+ }) => Effect.Effect<TData, E, R>);
23
+ }) => UseQueryOptions<TData, E extends never ? never : EffectQueryError<Cause.Cause<E>>, TData, TQueryKey>;
24
+ mutationOptions: <TData, E, TVariables, R extends Input | Scope.Scope>(options: Omit<UseMutationOptions<TData, Error, TVariables, unknown>, "mutationKey" | "mutationFn"> & {
25
+ mutationKey: string;
26
+ mutationFn: typeof skipToken | ((variables: TVariables) => Effect.Effect<TData, E, R>);
27
+ }) => UseMutationOptions<TData, E extends never ? never : EffectQueryError<Cause.Cause<E>>, TVariables>;
28
+ };
29
+ type QueryKey = readonly [string, string, Record<string, unknown>?];
30
+ //#endregion
31
+ export { createEffectQuery };
32
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/errors.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;;cAEa,gCAAgC,KAAA,CAAM,oBAAoB,KAAA;kBAC5C;sCACW;;;;iBCgBtB,gCACP,KAAA,CAAM,MAAM;qCA0Ed,QAAA,KAAA,CAAA,yBACiB,WAAQ,mBAAA,KAAA,gBAAA,OAAA,GAAA,OAAA;ID9FnB,QAAA,WAAgB;IAAsB,OAAA,EAAA,gBAAA,GAAA,CAAA,CAAA,OAAA,EAAA;MACxB,MAAA,oCAAA;MACW,QAAA,WAAA;MAFiC,MAAA,aAAA;MAAK,IAAA,qCAAA,SAAA;;;;ECkB5D,CAAA,EAAA,GAsGJ,eAtGqB,CAuGzB,KAvGyB,EAwGzB,CAxGyB,SAAA,KAAA,GAAA,KAAA,GAwGC,gBAxGD,CAwGkB,KAAA,CAAM,KAxGxB,CAwG8B,CAxG9B,CAAA,CAAA,EAyGzB,KAzGyB,EA0GzB,SA1GyB,CAAA;EACZ,eAAA,EAAA,CAAA,KAAA,EAAA,CAAA,EAAA,UAAA,EAAA,UA4GwB,KA5GxB,GA4GwB,KAAA,CAAA,KA5GxB,CAAA,CAAA,OAAA,EA4GwB,IA5GxB,CA4GwB,kBA5GxB,CA4GwB,KA5GxB,EA4GwB,KA5GxB,EA4GwB,UA5GxB,EAAA,OAAA,CAAA,EAAA,aAAA,GAAA,YAAA,CAAA,GAAA;IAAN,WAAA,EAAA,MAAA;IA0ER,UAAA,EAAA,gBAAA,GAAA,CAAA,CAAA,SAAA,YAAA,EAAA,gBAAA,MAAA,GAAA,GAAA,CAAA,CAAA;EAAA,CAAA,EAAA,GA6DK,kBA7DL,CA8DC,KA9DD,EA+DC,CA/DD,SAAA,KAAA,GAAA,KAAA,GA+D2B,gBA/D3B,CA+D4C,KAAA,CAAM,KA/DlD,CA+DwD,CA/DxD,CAAA,CAAA,EAgEC,UAhED,CAAA;CACiB;KAqEnB,QAAA,GArE2B,SAAA,CAAA,MAAA,EAAA,MAAA,EAqEU,MArEV,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,CAAA"}
package/dist/index.mjs ADDED
@@ -0,0 +1,116 @@
1
+ import { mutationOptions, queryOptions } from "@tanstack/react-query";
2
+ import { Cause, Effect, Exit, ManagedRuntime } from "effect";
3
+
4
+ //#region \0@oxc-project+runtime@0.95.0/helpers/typeof.js
5
+ function _typeof(o) {
6
+ "@babel/helpers - typeof";
7
+ return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o$1) {
8
+ return typeof o$1;
9
+ } : function(o$1) {
10
+ return o$1 && "function" == typeof Symbol && o$1.constructor === Symbol && o$1 !== Symbol.prototype ? "symbol" : typeof o$1;
11
+ }, _typeof(o);
12
+ }
13
+
14
+ //#endregion
15
+ //#region \0@oxc-project+runtime@0.95.0/helpers/toPrimitive.js
16
+ function toPrimitive(t, r) {
17
+ if ("object" != _typeof(t) || !t) return t;
18
+ var e = t[Symbol.toPrimitive];
19
+ if (void 0 !== e) {
20
+ var i = e.call(t, r || "default");
21
+ if ("object" != _typeof(i)) return i;
22
+ throw new TypeError("@@toPrimitive must return a primitive value.");
23
+ }
24
+ return ("string" === r ? String : Number)(t);
25
+ }
26
+
27
+ //#endregion
28
+ //#region \0@oxc-project+runtime@0.95.0/helpers/toPropertyKey.js
29
+ function toPropertyKey(t) {
30
+ var i = toPrimitive(t, "string");
31
+ return "symbol" == _typeof(i) ? i : i + "";
32
+ }
33
+
34
+ //#endregion
35
+ //#region \0@oxc-project+runtime@0.95.0/helpers/defineProperty.js
36
+ function _defineProperty(e, r, t) {
37
+ return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
38
+ value: t,
39
+ enumerable: !0,
40
+ configurable: !0,
41
+ writable: !0
42
+ }) : e[r] = t, e;
43
+ }
44
+
45
+ //#endregion
46
+ //#region src/errors.ts
47
+ var EffectQueryError = class extends Error {
48
+ constructor(message, cause) {
49
+ super(message);
50
+ _defineProperty(this, "cause", void 0);
51
+ this.cause = cause;
52
+ }
53
+ };
54
+
55
+ //#endregion
56
+ //#region \0@oxc-project+runtime@0.95.0/helpers/objectSpread2.js
57
+ function ownKeys(e, r) {
58
+ var t = Object.keys(e);
59
+ if (Object.getOwnPropertySymbols) {
60
+ var o = Object.getOwnPropertySymbols(e);
61
+ r && (o = o.filter(function(r$1) {
62
+ return Object.getOwnPropertyDescriptor(e, r$1).enumerable;
63
+ })), t.push.apply(t, o);
64
+ }
65
+ return t;
66
+ }
67
+ function _objectSpread2(e) {
68
+ for (var r = 1; r < arguments.length; r++) {
69
+ var t = null != arguments[r] ? arguments[r] : {};
70
+ r % 2 ? ownKeys(Object(t), !0).forEach(function(r$1) {
71
+ _defineProperty(e, r$1, t[r$1]);
72
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function(r$1) {
73
+ Object.defineProperty(e, r$1, Object.getOwnPropertyDescriptor(t, r$1));
74
+ });
75
+ }
76
+ return e;
77
+ }
78
+
79
+ //#endregion
80
+ //#region src/index.ts
81
+ function createEffectQuery(layer) {
82
+ const runtime = ManagedRuntime.make(layer);
83
+ const runner = (span, options = {}) => (effect) => runtime.runPromiseExit(effect.pipe(Effect.withSpan(span), Effect.scoped, Effect.tapErrorCause(Effect.logError)), { signal: options.signal });
84
+ return {
85
+ queryOptions: (options) => {
86
+ const [spanName] = options.queryKey;
87
+ const queryFn = async (context) => {
88
+ const result = await options.queryFn(context).pipe(runner(spanName, { signal: context.signal }));
89
+ return Exit.match(result, {
90
+ onSuccess: (value) => value,
91
+ onFailure: (cause) => {
92
+ throw new EffectQueryError(Cause.pretty(cause), cause);
93
+ }
94
+ });
95
+ };
96
+ return queryOptions(_objectSpread2(_objectSpread2({}, options), {}, { queryFn }));
97
+ },
98
+ mutationOptions: (options) => {
99
+ const spanName = options.mutationKey;
100
+ const mutationFn = async (variables) => {
101
+ const result = await options.mutationFn(variables).pipe(runner(spanName));
102
+ return Exit.match(result, {
103
+ onSuccess: (value) => value,
104
+ onFailure: (cause) => {
105
+ throw new EffectQueryError(Cause.pretty(cause), cause);
106
+ }
107
+ });
108
+ };
109
+ return mutationOptions(_objectSpread2(_objectSpread2({}, options), {}, { mutationFn }));
110
+ }
111
+ };
112
+ }
113
+
114
+ //#endregion
115
+ export { createEffectQuery };
116
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["queryFn: QueryFunction<TData, TQueryKey>","mutationFn: MutationFunction<TData, TVariables>"],"sources":["../src/errors.ts","../src/index.ts"],"sourcesContent":["import type { Cause } from \"effect\";\n// biome-ignore lint/suspicious/noExplicitAny: Generic type for cause\nexport class EffectQueryError<TCause extends Cause.Cause<any>> extends Error {\n override readonly cause: TCause;\n constructor(message: string, cause: TCause) {\n super(message);\n this.cause = cause;\n }\n}\n","import {\n type MutationFunction,\n mutationOptions,\n type QueryFunction,\n type QueryFunctionContext,\n queryOptions,\n type skipToken,\n type UseMutationOptions,\n type UseQueryOptions,\n} from \"@tanstack/react-query\";\nimport {\n Cause,\n Effect,\n Exit,\n type Layer,\n ManagedRuntime,\n type Scope,\n} from \"effect\";\nimport { EffectQueryError } from \"./errors\";\n\nexport function createEffectQuery<Input>(\n layer: Layer.Layer<Input, never, never>\n) {\n type RuntimeContext = Input | Scope.Scope;\n\n type EffectfulMutationFunction<\n TData,\n E,\n TVariables,\n R extends RuntimeContext,\n > = (variables: TVariables) => Effect.Effect<TData, E, R>;\n\n type EffectfulMutationOptions<\n TData,\n E,\n TVariables,\n R extends RuntimeContext,\n > = Omit<\n UseMutationOptions<TData, Error, TVariables>,\n \"mutationKey\" | \"mutationFn\"\n > & {\n mutationKey: string;\n mutationFn:\n | EffectfulMutationFunction<TData, E, TVariables, R>\n | typeof skipToken;\n };\n\n type EffectfulQueryFunction<\n TData,\n E,\n R,\n TQueryKey extends QueryKey = QueryKey,\n TPageParam = never,\n > = (\n context: QueryFunctionContext<TQueryKey, TPageParam>\n ) => Effect.Effect<TData, E, R>;\n\n type EffectfulQueryOptions<\n TData,\n TError,\n R,\n TQueryKey extends QueryKey = QueryKey,\n TPageParam = never,\n > = Omit<\n UseQueryOptions<TData, TError, TData, TQueryKey>,\n \"queryKey\" | \"queryFn\"\n > & {\n queryKey: TQueryKey;\n queryFn:\n | EffectfulQueryFunction<TData, TError, R, TQueryKey, TPageParam>\n | typeof skipToken;\n };\n\n const runtime = ManagedRuntime.make(layer);\n const runner =\n <A, E, R extends RuntimeContext>(\n span: string,\n options: { signal?: AbortSignal } = {}\n ) =>\n (effect: Effect.Effect<A, E, R>): Promise<Exit.Exit<A, E>> =>\n runtime.runPromiseExit(\n effect.pipe(\n Effect.withSpan(span),\n Effect.scoped,\n Effect.tapErrorCause(Effect.logError)\n ),\n {\n signal: options.signal,\n }\n );\n\n return {\n queryOptions: <\n TData,\n E,\n R extends RuntimeContext,\n TQueryKey extends QueryKey = QueryKey,\n >(\n options: EffectfulQueryOptions<TData, E, R, TQueryKey>\n ) => {\n const [spanName] = options.queryKey;\n\n const queryFn: QueryFunction<TData, TQueryKey> = async (\n context: QueryFunctionContext<TQueryKey>\n ) => {\n const effect = (\n options.queryFn as EffectfulQueryFunction<TData, E, R, TQueryKey>\n )(context);\n const result = await effect.pipe(\n runner(spanName, { signal: context.signal })\n );\n return Exit.match(result, {\n onSuccess: (value) => value,\n onFailure: (cause) => {\n throw new EffectQueryError(Cause.pretty(cause), cause);\n },\n });\n };\n\n return queryOptions({\n ...options,\n queryFn,\n }) as UseQueryOptions<\n TData,\n E extends never ? never : EffectQueryError<Cause.Cause<E>>,\n TData,\n TQueryKey\n >;\n },\n mutationOptions: <TData, E, TVariables, R extends RuntimeContext>(\n options: EffectfulMutationOptions<TData, E, TVariables, R>\n ) => {\n const spanName = options.mutationKey;\n const mutationFn: MutationFunction<TData, TVariables> = async (\n variables: TVariables\n ) => {\n const effect = (\n options.mutationFn as EffectfulMutationFunction<\n TData,\n E,\n TVariables,\n R\n >\n )(variables);\n const result = await effect.pipe(runner(spanName));\n return Exit.match(result, {\n onSuccess: (value) => value,\n onFailure: (cause) => {\n throw new EffectQueryError(Cause.pretty(cause), cause);\n },\n });\n };\n\n return mutationOptions({\n ...options,\n mutationFn,\n }) as UseMutationOptions<\n TData,\n E extends never ? never : EffectQueryError<Cause.Cause<E>>,\n TVariables\n >;\n },\n };\n}\n\ntype QueryKey = readonly [string, string, Record<string, unknown>?];\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,IAAa,mBAAb,cAAuE,MAAM;CAE3E,YAAY,SAAiB,OAAe;AAC1C,QAAM,QAAQ;wBAFE;AAGhB,OAAK,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACcjB,SAAgB,kBACd,OACA;CAmDA,MAAM,UAAU,eAAe,KAAK,MAAM;CAC1C,MAAM,UAEF,MACA,UAAoC,EAAE,MAEvC,WACC,QAAQ,eACN,OAAO,KACL,OAAO,SAAS,KAAK,EACrB,OAAO,QACP,OAAO,cAAc,OAAO,SAAS,CACtC,EACD,EACE,QAAQ,QAAQ,QACjB,CACF;AAEL,QAAO;EACL,eAME,YACG;GACH,MAAM,CAAC,YAAY,QAAQ;GAE3B,MAAMA,UAA2C,OAC/C,YACG;IAIH,MAAM,SAAS,MAFb,QAAQ,QACR,QAAQ,CACkB,KAC1B,OAAO,UAAU,EAAE,QAAQ,QAAQ,QAAQ,CAAC,CAC7C;AACD,WAAO,KAAK,MAAM,QAAQ;KACxB,YAAY,UAAU;KACtB,YAAY,UAAU;AACpB,YAAM,IAAI,iBAAiB,MAAM,OAAO,MAAM,EAAE,MAAM;;KAEzD,CAAC;;AAGJ,UAAO,+CACF,gBACH,WACA;;EAOJ,kBACE,YACG;GACH,MAAM,WAAW,QAAQ;GACzB,MAAMC,aAAkD,OACtD,cACG;IASH,MAAM,SAAS,MAPb,QAAQ,WAMR,UAAU,CACgB,KAAK,OAAO,SAAS,CAAC;AAClD,WAAO,KAAK,MAAM,QAAQ;KACxB,YAAY,UAAU;KACtB,YAAY,UAAU;AACpB,YAAM,IAAI,iBAAiB,MAAM,OAAO,MAAM,EAAE,MAAM;;KAEzD,CAAC;;AAGJ,UAAO,kDACF,gBACH,cACA;;EAML"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "effect-query",
3
+ "version": "0.0.1-alpha.1",
4
+ "description": "Effect adapter for Tanstack Query",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/voidhashcom/effect-query.git"
8
+ },
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.mts",
13
+ "default": "./dist/index.mjs"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "src",
24
+ "README.md",
25
+ "package.json",
26
+ "!**/*.test.*",
27
+ "!**/__tests__"
28
+ ],
29
+ "author": "Dominik Vít <dominik@voidhash.com>",
30
+ "license": "MIT",
31
+ "devDependencies": {
32
+ "@biomejs/biome": "^2.2.6",
33
+ "@tanstack/react-query": "^5.90.5",
34
+ "effect": "^3.18.4",
35
+ "react": "^19.2.0",
36
+ "tsdown": "^0.15.9",
37
+ "ultracite": "^5.6.4",
38
+ "vitest": "^4.0.1"
39
+ },
40
+ "peerDependencies": {
41
+ "@tanstack/react-query": "^5.90.5",
42
+ "effect": "^3.18.4",
43
+ "react": "^19.2.0"
44
+ },
45
+ "scripts": {
46
+ "build": "tsdown",
47
+ "lint": "biome check .",
48
+ "typecheck": "tsc --noEmit --pretty"
49
+ }
50
+ }
package/src/errors.ts ADDED
@@ -0,0 +1,9 @@
1
+ import type { Cause } from "effect";
2
+ // biome-ignore lint/suspicious/noExplicitAny: Generic type for cause
3
+ export class EffectQueryError<TCause extends Cause.Cause<any>> extends Error {
4
+ override readonly cause: TCause;
5
+ constructor(message: string, cause: TCause) {
6
+ super(message);
7
+ this.cause = cause;
8
+ }
9
+ }
package/src/index.ts ADDED
@@ -0,0 +1,166 @@
1
+ import {
2
+ type MutationFunction,
3
+ mutationOptions,
4
+ type QueryFunction,
5
+ type QueryFunctionContext,
6
+ queryOptions,
7
+ type skipToken,
8
+ type UseMutationOptions,
9
+ type UseQueryOptions,
10
+ } from "@tanstack/react-query";
11
+ import {
12
+ Cause,
13
+ Effect,
14
+ Exit,
15
+ type Layer,
16
+ ManagedRuntime,
17
+ type Scope,
18
+ } from "effect";
19
+ import { EffectQueryError } from "./errors";
20
+
21
+ export function createEffectQuery<Input>(
22
+ layer: Layer.Layer<Input, never, never>
23
+ ) {
24
+ type RuntimeContext = Input | Scope.Scope;
25
+
26
+ type EffectfulMutationFunction<
27
+ TData,
28
+ E,
29
+ TVariables,
30
+ R extends RuntimeContext,
31
+ > = (variables: TVariables) => Effect.Effect<TData, E, R>;
32
+
33
+ type EffectfulMutationOptions<
34
+ TData,
35
+ E,
36
+ TVariables,
37
+ R extends RuntimeContext,
38
+ > = Omit<
39
+ UseMutationOptions<TData, Error, TVariables>,
40
+ "mutationKey" | "mutationFn"
41
+ > & {
42
+ mutationKey: string;
43
+ mutationFn:
44
+ | EffectfulMutationFunction<TData, E, TVariables, R>
45
+ | typeof skipToken;
46
+ };
47
+
48
+ type EffectfulQueryFunction<
49
+ TData,
50
+ E,
51
+ R,
52
+ TQueryKey extends QueryKey = QueryKey,
53
+ TPageParam = never,
54
+ > = (
55
+ context: QueryFunctionContext<TQueryKey, TPageParam>
56
+ ) => Effect.Effect<TData, E, R>;
57
+
58
+ type EffectfulQueryOptions<
59
+ TData,
60
+ TError,
61
+ R,
62
+ TQueryKey extends QueryKey = QueryKey,
63
+ TPageParam = never,
64
+ > = Omit<
65
+ UseQueryOptions<TData, TError, TData, TQueryKey>,
66
+ "queryKey" | "queryFn"
67
+ > & {
68
+ queryKey: TQueryKey;
69
+ queryFn:
70
+ | EffectfulQueryFunction<TData, TError, R, TQueryKey, TPageParam>
71
+ | typeof skipToken;
72
+ };
73
+
74
+ const runtime = ManagedRuntime.make(layer);
75
+ const runner =
76
+ <A, E, R extends RuntimeContext>(
77
+ span: string,
78
+ options: { signal?: AbortSignal } = {}
79
+ ) =>
80
+ (effect: Effect.Effect<A, E, R>): Promise<Exit.Exit<A, E>> =>
81
+ runtime.runPromiseExit(
82
+ effect.pipe(
83
+ Effect.withSpan(span),
84
+ Effect.scoped,
85
+ Effect.tapErrorCause(Effect.logError)
86
+ ),
87
+ {
88
+ signal: options.signal,
89
+ }
90
+ );
91
+
92
+ return {
93
+ queryOptions: <
94
+ TData,
95
+ E,
96
+ R extends RuntimeContext,
97
+ TQueryKey extends QueryKey = QueryKey,
98
+ >(
99
+ options: EffectfulQueryOptions<TData, E, R, TQueryKey>
100
+ ) => {
101
+ const [spanName] = options.queryKey;
102
+
103
+ const queryFn: QueryFunction<TData, TQueryKey> = async (
104
+ context: QueryFunctionContext<TQueryKey>
105
+ ) => {
106
+ const effect = (
107
+ options.queryFn as EffectfulQueryFunction<TData, E, R, TQueryKey>
108
+ )(context);
109
+ const result = await effect.pipe(
110
+ runner(spanName, { signal: context.signal })
111
+ );
112
+ return Exit.match(result, {
113
+ onSuccess: (value) => value,
114
+ onFailure: (cause) => {
115
+ throw new EffectQueryError(Cause.pretty(cause), cause);
116
+ },
117
+ });
118
+ };
119
+
120
+ return queryOptions({
121
+ ...options,
122
+ queryFn,
123
+ }) as UseQueryOptions<
124
+ TData,
125
+ E extends never ? never : EffectQueryError<Cause.Cause<E>>,
126
+ TData,
127
+ TQueryKey
128
+ >;
129
+ },
130
+ mutationOptions: <TData, E, TVariables, R extends RuntimeContext>(
131
+ options: EffectfulMutationOptions<TData, E, TVariables, R>
132
+ ) => {
133
+ const spanName = options.mutationKey;
134
+ const mutationFn: MutationFunction<TData, TVariables> = async (
135
+ variables: TVariables
136
+ ) => {
137
+ const effect = (
138
+ options.mutationFn as EffectfulMutationFunction<
139
+ TData,
140
+ E,
141
+ TVariables,
142
+ R
143
+ >
144
+ )(variables);
145
+ const result = await effect.pipe(runner(spanName));
146
+ return Exit.match(result, {
147
+ onSuccess: (value) => value,
148
+ onFailure: (cause) => {
149
+ throw new EffectQueryError(Cause.pretty(cause), cause);
150
+ },
151
+ });
152
+ };
153
+
154
+ return mutationOptions({
155
+ ...options,
156
+ mutationFn,
157
+ }) as UseMutationOptions<
158
+ TData,
159
+ E extends never ? never : EffectQueryError<Cause.Cause<E>>,
160
+ TVariables
161
+ >;
162
+ },
163
+ };
164
+ }
165
+
166
+ type QueryKey = readonly [string, string, Record<string, unknown>?];