diff --git a/.changeset/effect-v4.md b/.changeset/effect-v4.md new file mode 100644 index 0000000..8ecb5d0 --- /dev/null +++ b/.changeset/effect-v4.md @@ -0,0 +1,5 @@ +--- +"@spiko-tech/effect-react-query": major +--- + +Migrate to Effect v4. The `runtime` option now accepts a `Context.Context` or a `ManagedRuntime` (v3 `Runtime.Runtime` no longer exists). Cancellation uses Effect's native `signal` run option. diff --git a/README.md b/README.md index 7d7bf3b..10cfa30 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,9 @@ pnpm add @effect-react-query ```ts import { useEffectQuery, useEffectMutation } from "@effect-react-query"; -import { Effect, Schema, Match } from "effect"; +import * as Effect from "effect/Effect"; +import * as Schema from "effect/Schema"; +import * as Match from "effect/Match"; // Define typed errors class NetworkError extends Schema.TaggedError()("NetworkError", { diff --git a/bun.lock b/bun.lock index 52bdae3..7e0bc31 100644 --- a/bun.lock +++ b/bun.lock @@ -21,7 +21,7 @@ }, "peerDependencies": { "@tanstack/react-query": "^5.99.2", - "effect": "^3.21.1", + "effect": "^4.0.0", }, }, }, @@ -372,7 +372,7 @@ "dotenv": ["dotenv@8.6.0", "", {}, "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g=="], - "effect": ["effect@3.21.2", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-rXd2FGDM8KdjSIrc+mqEELo7ScW7xTVxEf1iInmPSpIde9/nyGuFM710cjTo7/EreGXiUX2MOonPpprbz2XHCg=="], + "effect": ["effect@4.0.0", "", {}, "sha512-ooc1TG5t+FfzgYnFz2ff6BBKyZ7EwBRVXC7c4RhQUAD6/TZ2gTXXMeb4WX7a19ozQo4J73/QW+S00YAIresoMQ=="], "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], @@ -396,8 +396,6 @@ "extendable-error": ["extendable-error@0.1.7", "", {}, "sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg=="], - "fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="], - "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], @@ -586,8 +584,6 @@ "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], - "pure-rand": ["pure-rand@6.1.0", "", {}, "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA=="], - "quansync": ["quansync@0.2.11", "", {}, "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA=="], "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], diff --git a/docs/index.md b/docs/index.md index 29875f5..8f008f4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -34,7 +34,7 @@ const query = useEffectQuery({ | Option | Description | | --------- | ----------------------------------------------------------------------------- | | `queryFn` | `(context: QueryFunctionContext) => Effect.Effect` | -| `runtime` | Required when Effect has service requirements (`Runtime` or `ManagedRuntime`) | +| `runtime` | Required when Effect has service requirements (`Context` or `ManagedRuntime`) | | `...` | All standard React Query options (`staleTime`, `gcTime`, `retry`, etc.) | ### With Runtime Dependencies @@ -188,7 +188,7 @@ mutation.mutate({ name: "John", email: "john@example.com" }); | Option | Description | | ------------ | ----------------------------------------------------------------------------- | | `mutationFn` | `(variables: TVariables) => Effect.Effect` | -| `runtime` | Required when Effect has service requirements (`Runtime` or `ManagedRuntime`) | +| `runtime` | Required when Effect has service requirements (`Context` or `ManagedRuntime`) | | `onError` | Callback on error (receives typed error) | | `...` | All standard React Query mutation options | @@ -308,7 +308,8 @@ await queryClient.fetchQuery(toQueryOptions(protectedQueryOptions("123"))); Errors retain their typed structure and can be matched using Effect's `Match.valueTags`: ```ts -import { Schema, Match } from "effect"; +import * as Schema from "effect/Schema"; +import * as Match from "effect/Match"; import { useEffectQuery } from "@effect-react-query"; // Define typed errors @@ -349,17 +350,20 @@ const mutation = useEffectMutation({ # Dependency Injection -When Effects have service requirements, provide a `ManagedRuntime` or `Runtime`: +When Effects have service requirements, provide a `ManagedRuntime` or a `Context`: ```ts -import { Context, Effect, Layer, ManagedRuntime } from "effect"; +import * as Context from "effect/Context"; +import * as Effect from "effect/Effect"; +import * as Layer from "effect/Layer"; +import * as ManagedRuntime from "effect/ManagedRuntime"; import { useEffectQuery } from "@effect-react-query"; // Define a service -class UserService extends Context.Tag("UserService")< +class UserService extends Context.Service< UserService, { readonly getUser: (id: string) => Effect.Effect } ->() {} +>()("UserService") {} // Create the layer const UserServiceLive = Layer.succeed( diff --git a/package.json b/package.json index 6b72b1b..41b5731 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ }, "peerDependencies": { "@tanstack/react-query": "^5.99.2", - "effect": "^3.21.1" + "effect": "^4.0.0" }, "engines": { "node": ">=20" diff --git a/src/effectQueryOptions.ts b/src/effectQueryOptions.ts index 65d2e89..b3f29e9 100644 --- a/src/effectQueryOptions.ts +++ b/src/effectQueryOptions.ts @@ -22,7 +22,7 @@ import type { * @example * ```ts * import { effectQueryOptions, toQueryOptions, useEffectQuery } from "@effect-react-query"; - * import { Effect } from "effect"; + * import * as Effect from "effect/Effect"; * * // Define reusable query options * const userQueryOptions = (userId: string) => effectQueryOptions({ diff --git a/src/infiniteEffectQueryOptions.ts b/src/infiniteEffectQueryOptions.ts index fcdf133..3e261fb 100644 --- a/src/infiniteEffectQueryOptions.ts +++ b/src/infiniteEffectQueryOptions.ts @@ -22,7 +22,7 @@ import type { * @example * ```ts * import { infiniteEffectQueryOptions, useInfiniteEffectQuery } from "@effect-react-query"; - * import { Effect } from "effect"; + * import * as Effect from "effect/Effect"; * * // Define reusable infinite query options * const postsQueryOptions = () => infiniteEffectQueryOptions({ diff --git a/src/internal/createEffectQueryFn.ts b/src/internal/createEffectQueryFn.ts index 0d85d79..30b0426 100644 --- a/src/internal/createEffectQueryFn.ts +++ b/src/internal/createEffectQueryFn.ts @@ -1,5 +1,8 @@ -import { Cause, Effect, Exit, ManagedRuntime, Runtime } from "effect"; -import { hasProperty } from "effect/Predicate"; +import * as Cause from "effect/Cause"; +import * as Context from "effect/Context"; +import * as Effect from "effect/Effect"; +import * as Exit from "effect/Exit"; +import * as ManagedRuntime from "effect/ManagedRuntime"; /** * Creates a query function that wraps an Effect-returning function. @@ -9,40 +12,22 @@ import { hasProperty } from "effect/Predicate"; */ export function createEffectQueryFn( effectFn: (context: TContext) => Effect.Effect, - runtime: Runtime.Runtime | ManagedRuntime.ManagedRuntime | undefined, - getSignal: (context: TContext) => AbortSignal, + runtime: Context.Context | ManagedRuntime.ManagedRuntime | undefined, + getSignal: (context: TContext) => AbortSignal | undefined, ): (context: TContext) => Promise { return async (context: TContext) => { const effect = effectFn(context); - const signal = getSignal(context); + const options = { signal: getSignal(context) }; - // Create an effect that listens to the AbortSignal for cancellation - const withAbort = Effect.raceFirst( - effect, - Effect.async((resume) => { - if (signal.aborted) { - resume(Effect.interrupt); - return; - } - const onAbort = () => resume(Effect.interrupt); - signal.addEventListener("abort", onAbort); - return Effect.sync(() => signal.removeEventListener("abort", onAbort)); - }), - ); - - // Determine how to run the effect based on runtime type // Use unknown for error type since ManagedRuntime can add layer errors - let exit: Exit.Exit; - - if (runtime) { - if (hasProperty(runtime, ManagedRuntime.TypeId)) { - exit = await runtime.runPromiseExit(withAbort); - } else { - exit = await Runtime.runPromiseExit(runtime)(withAbort); - } - } else { - exit = await Effect.runPromiseExit(withAbort as Effect.Effect); - } + const exit: Exit.Exit = Context.isContext(runtime) + ? await Effect.runPromiseExitWith(runtime)(effect, options) + : runtime !== undefined + ? await runtime.runPromiseExit(effect, options) + : await Effect.runPromiseExit( + effect as Effect.Effect, + options, + ); if (Exit.isSuccess(exit)) return exit.value; @@ -50,7 +35,7 @@ export function createEffectQueryFn( // Check for interruption - don't call onError, just hang // React Query will handle cleanup - if (Cause.isInterruptedOnly(cause)) { + if (Cause.hasInterruptsOnly(cause)) { return new Promise(() => { // Never resolves - query is cancelled }); diff --git a/src/toQueryOptions.ts b/src/toQueryOptions.ts index cf6d8bc..ba5eb42 100644 --- a/src/toQueryOptions.ts +++ b/src/toQueryOptions.ts @@ -13,7 +13,7 @@ import type { * @example * ```ts * import { effectQueryOptions, toQueryOptions } from "@effect-react-query"; - * import { Effect } from "effect"; + * import * as Effect from "effect/Effect"; * * // Define reusable query options * const userQueryOptions = (userId: string) => effectQueryOptions({ diff --git a/src/types.ts b/src/types.ts index 915c80b..96f1ce8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -21,7 +21,9 @@ import type { UseSuspenseQueryOptions, UseSuspenseQueryResult, } from "@tanstack/react-query"; -import type { Effect, ManagedRuntime, Runtime } from "effect"; +import type * as Context from "effect/Context"; +import type * as Effect from "effect/Effect"; +import type * as ManagedRuntime from "effect/ManagedRuntime"; /** * Options for useEffectMutation hook. @@ -47,11 +49,11 @@ export type UseEffectMutationOptions< /** * Runtime option - required when R is not never, forbidden when R is never. - * Accepts either a Runtime or a ManagedRuntime. + * Accepts either a Context or a ManagedRuntime. */ export type RuntimeOption = [R] extends [never] ? { runtime?: undefined } - : { runtime: Runtime.Runtime | ManagedRuntime.ManagedRuntime }; + : { runtime: Context.Context | ManagedRuntime.ManagedRuntime }; /** * The result of useEffectMutation hook. @@ -478,14 +480,18 @@ export type UseEffectQueryOptionsForUseQueries< * Infers data and error types from the queryFn's Effect return type. */ export type EffectQueriesResults< - T extends ReadonlyArray<{ queryFn: (...args: any) => Effect.Effect }>, + T extends ReadonlyArray<{ + queryFn: (...args: any) => Effect.Effect; + }>, > = { -readonly [K in keyof T]: T[K] extends { queryFn: (...args: any) => Effect.Effect; select?: (data: any) => infer TSelected; } ? UseQueryResult - : T[K] extends { queryFn: (...args: any) => Effect.Effect } + : T[K] extends { + queryFn: (...args: any) => Effect.Effect; + } ? UseQueryResult : UseQueryResult; }; @@ -526,14 +532,18 @@ export type UseEffectSuspenseQueryOptionsForUseQueries< * Infers data and error types from the queryFn's Effect return type. */ export type EffectSuspenseQueriesResults< - T extends ReadonlyArray<{ queryFn: (...args: any) => Effect.Effect }>, + T extends ReadonlyArray<{ + queryFn: (...args: any) => Effect.Effect; + }>, > = { -readonly [K in keyof T]: T[K] extends { queryFn: (...args: any) => Effect.Effect; select?: (data: any) => infer TSelected; } ? UseSuspenseQueryResult - : T[K] extends { queryFn: (...args: any) => Effect.Effect } + : T[K] extends { + queryFn: (...args: any) => Effect.Effect; + } ? UseSuspenseQueryResult : UseSuspenseQueryResult; }; diff --git a/src/useEffectMutation.ts b/src/useEffectMutation.ts index 49f8998..48a3c61 100644 --- a/src/useEffectMutation.ts +++ b/src/useEffectMutation.ts @@ -1,6 +1,5 @@ import { useMutation } from "@tanstack/react-query"; -import { Cause, Effect, Exit, ManagedRuntime, Runtime } from "effect"; -import { hasProperty } from "effect/Predicate"; +import { createEffectQueryFn } from "./internal/createEffectQueryFn"; import type { UseEffectMutationOptions, UseEffectMutationResult } from "./types"; /** @@ -9,7 +8,8 @@ import type { UseEffectMutationOptions, UseEffectMutationResult } from "./types" * @example * ```ts * import { useEffectMutation } from "@effect-react-query"; - * import { Match, Schema } from "effect"; + * import * as Match from "effect/Match"; + * import * as Schema from "effect/Schema"; * * // Define your errors with Schema.TaggedError * class NetworkError extends Schema.TaggedError()("NetworkError", { @@ -27,7 +27,7 @@ import type { UseEffectMutationOptions, UseEffectMutationResult } from "./types" * // Effect with requirements - runtime is required * const mutation = useEffectMutation({ * mutationFn: createUserWithService, // Effect - * runtime: myRuntime, // Runtime + * runtime: myRuntime, // Context or ManagedRuntime * onError: Match.valueTags({ * NetworkError: (e) => toast.error(e.message), * }), @@ -41,37 +41,7 @@ export function useEffectMutation({ ...restOptions, - mutationFn: async (variables: TVariables) => { - const effect = mutationFn(variables); - - // Determine how to run the effect based on runtime type - // Use unknown for error type since ManagedRuntime can add layer errors - let exit: Exit.Exit; - - if (runtime) { - if (hasProperty(runtime, ManagedRuntime.TypeId)) { - exit = await runtime.runPromiseExit(effect); - } else { - exit = await Runtime.runPromiseExit(runtime)(effect); - } - } else { - exit = await Effect.runPromiseExit(effect as Effect.Effect); - } - - if (Exit.isSuccess(exit)) return exit.value; - - const cause = exit.cause; - - // Check for interruption - don't call onError, just hang - // React Query will handle cleanup - if (Cause.isInterruptedOnly(cause)) { - return new Promise(() => { - // Never resolves - mutation is cancelled - }); - } - - throw Cause.squash(cause); - }, + mutationFn: createEffectQueryFn(mutationFn, runtime, () => undefined), }); return mutation; diff --git a/src/useEffectQueries.ts b/src/useEffectQueries.ts index e527617..3f41a20 100644 --- a/src/useEffectQueries.ts +++ b/src/useEffectQueries.ts @@ -1,6 +1,8 @@ import type { QueryKey } from "@tanstack/react-query"; import { useQueries } from "@tanstack/react-query"; -import type { Effect, ManagedRuntime, Runtime } from "effect"; +import type * as Context from "effect/Context"; +import type * as Effect from "effect/Effect"; +import type * as ManagedRuntime from "effect/ManagedRuntime"; import { createEffectQueryFn } from "./internal/createEffectQueryFn"; import type { EffectQueriesResults } from "./types"; @@ -12,7 +14,7 @@ import type { EffectQueriesResults } from "./types"; type EffectQueryOptionsBase = { queryKey: QueryKey; queryFn: (...args: any[]) => Effect.Effect; - runtime?: Runtime.Runtime | ManagedRuntime.ManagedRuntime | undefined; + runtime?: Context.Context | ManagedRuntime.ManagedRuntime | undefined; }; /** @@ -24,7 +26,7 @@ type EffectQueryOptionsBase = { * @example * ```ts * import { useEffectQueries } from "@effect-react-query"; - * import { Effect } from "effect"; + * import * as Effect from "effect/Effect"; * * // Multiple queries without requirements * const results = useEffectQueries({ diff --git a/src/useEffectQuery.ts b/src/useEffectQuery.ts index 8e34dd0..3935e7c 100644 --- a/src/useEffectQuery.ts +++ b/src/useEffectQuery.ts @@ -1,6 +1,8 @@ import type { QueryFunctionContext, QueryKey } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query"; -import type { Effect, ManagedRuntime, Runtime } from "effect"; +import type * as Context from "effect/Context"; +import type * as Effect from "effect/Effect"; +import type * as ManagedRuntime from "effect/ManagedRuntime"; import { createEffectQueryFn } from "./internal/createEffectQueryFn"; import type { DefinedInitialDataEffectQueryOptions, @@ -20,7 +22,9 @@ import type { * @example * ```ts * import { useEffectQuery } from "@effect-react-query"; - * import { Match, Schema, Effect } from "effect"; + * import * as Match from "effect/Match"; + * import * as Schema from "effect/Schema"; + * import * as Effect from "effect/Effect"; * * // Effect without requirements (R = never) * const query = useEffectQuery({ @@ -32,7 +36,7 @@ import type { * const query = useEffectQuery({ * queryKey: ["user", userId], * queryFn: () => fetchUserWithService(userId), // Effect - * runtime: myRuntime, // Runtime + * runtime: myRuntime, // Context or ManagedRuntime * }); * * // Handle errors with Match @@ -86,7 +90,7 @@ export function useEffectQuery< ): UseEffectQueryResult { const { queryFn, runtime, ...restOptions } = options as { queryFn: (context: QueryFunctionContext) => Effect.Effect; - runtime?: Runtime.Runtime | ManagedRuntime.ManagedRuntime; + runtime?: Context.Context | ManagedRuntime.ManagedRuntime; } & Omit, "queryFn" | "runtime">; return useQuery({ diff --git a/src/useEffectSuspenseQueries.ts b/src/useEffectSuspenseQueries.ts index a1a8dcc..0219365 100644 --- a/src/useEffectSuspenseQueries.ts +++ b/src/useEffectSuspenseQueries.ts @@ -1,6 +1,8 @@ import type { QueryKey } from "@tanstack/react-query"; import { useSuspenseQueries } from "@tanstack/react-query"; -import type { Effect, ManagedRuntime, Runtime } from "effect"; +import type * as Context from "effect/Context"; +import type * as Effect from "effect/Effect"; +import type * as ManagedRuntime from "effect/ManagedRuntime"; import { createEffectQueryFn } from "./internal/createEffectQueryFn"; import type { EffectSuspenseQueriesResults } from "./types"; @@ -12,7 +14,7 @@ import type { EffectSuspenseQueriesResults } from "./types"; type EffectSuspenseQueryOptionsBase = { queryKey: QueryKey; queryFn: (...args: any[]) => Effect.Effect; - runtime?: Runtime.Runtime | ManagedRuntime.ManagedRuntime; + runtime?: Context.Context | ManagedRuntime.ManagedRuntime; }; /** @@ -25,7 +27,7 @@ type EffectSuspenseQueryOptionsBase = { * @example * ```ts * import { useEffectSuspenseQueries } from "@effect-react-query"; - * import { Effect } from "effect"; + * import * as Effect from "effect/Effect"; * * // Multiple queries without requirements - data is always defined * const results = useEffectSuspenseQueries({ diff --git a/src/useEffectSuspenseQuery.ts b/src/useEffectSuspenseQuery.ts index d31a99e..a6d4090 100644 --- a/src/useEffectSuspenseQuery.ts +++ b/src/useEffectSuspenseQuery.ts @@ -1,6 +1,8 @@ import type { QueryFunctionContext, QueryKey } from "@tanstack/react-query"; import { useSuspenseQuery } from "@tanstack/react-query"; -import type { Effect, ManagedRuntime, Runtime } from "effect"; +import type * as Context from "effect/Context"; +import type * as Effect from "effect/Effect"; +import type * as ManagedRuntime from "effect/ManagedRuntime"; import { createEffectQueryFn } from "./internal/createEffectQueryFn"; import type { UseEffectSuspenseQueryOptions, UseEffectSuspenseQueryResult } from "./types"; @@ -13,7 +15,7 @@ import type { UseEffectSuspenseQueryOptions, UseEffectSuspenseQueryResult } from * @example * ```ts * import { useEffectSuspenseQuery } from "@effect-react-query"; - * import { Effect } from "effect"; + * import * as Effect from "effect/Effect"; * * // Effect without requirements (R = never) * const query = useEffectSuspenseQuery({ @@ -25,7 +27,7 @@ import type { UseEffectSuspenseQueryOptions, UseEffectSuspenseQueryResult } from * const query = useEffectSuspenseQuery({ * queryKey: ["user", userId], * queryFn: () => fetchUserWithService(userId), // Effect - * runtime: myRuntime, // Runtime + * runtime: myRuntime, // Context or ManagedRuntime * }); * ``` */ @@ -40,7 +42,7 @@ export function useEffectSuspenseQuery< ): UseEffectSuspenseQueryResult { const { queryFn, runtime, ...restOptions } = options as { queryFn: (context: QueryFunctionContext) => Effect.Effect; - runtime?: Runtime.Runtime | ManagedRuntime.ManagedRuntime; + runtime?: Context.Context | ManagedRuntime.ManagedRuntime; } & Omit< UseEffectSuspenseQueryOptions, "queryFn" | "runtime" diff --git a/src/useInfiniteEffectQuery.ts b/src/useInfiniteEffectQuery.ts index d459a0f..81d00e8 100644 --- a/src/useInfiniteEffectQuery.ts +++ b/src/useInfiniteEffectQuery.ts @@ -1,6 +1,8 @@ import type { InfiniteData, QueryFunctionContext, QueryKey } from "@tanstack/react-query"; import { useInfiniteQuery } from "@tanstack/react-query"; -import type { Effect, ManagedRuntime, Runtime } from "effect"; +import type * as Context from "effect/Context"; +import type * as Effect from "effect/Effect"; +import type * as ManagedRuntime from "effect/ManagedRuntime"; import { createEffectQueryFn } from "./internal/createEffectQueryFn"; import type { DefinedInitialDataInfiniteEffectQueryOptions, @@ -19,7 +21,7 @@ import type { * @example * ```ts * import { useInfiniteEffectQuery } from "@effect-react-query"; - * import { Effect } from "effect"; + * import * as Effect from "effect/Effect"; * * // Effect without requirements (R = never) * const query = useInfiniteEffectQuery({ @@ -108,7 +110,7 @@ export function useInfiniteEffectQuery< queryFn: ( context: QueryFunctionContext, ) => Effect.Effect; - runtime?: Runtime.Runtime | ManagedRuntime.ManagedRuntime; + runtime?: Context.Context | ManagedRuntime.ManagedRuntime; } & Omit< UseInfiniteEffectQueryOptions, "queryFn" | "runtime" diff --git a/src/useInfiniteEffectSuspenseQuery.ts b/src/useInfiniteEffectSuspenseQuery.ts index 2602101..b852e9c 100644 --- a/src/useInfiniteEffectSuspenseQuery.ts +++ b/src/useInfiniteEffectSuspenseQuery.ts @@ -1,6 +1,8 @@ import type { InfiniteData, QueryFunctionContext, QueryKey } from "@tanstack/react-query"; import { useSuspenseInfiniteQuery } from "@tanstack/react-query"; -import type { Effect, ManagedRuntime, Runtime } from "effect"; +import type * as Context from "effect/Context"; +import type * as Effect from "effect/Effect"; +import type * as ManagedRuntime from "effect/ManagedRuntime"; import { createEffectQueryFn } from "./internal/createEffectQueryFn"; import type { UseInfiniteEffectSuspenseQueryOptions, @@ -13,7 +15,7 @@ import type { * @example * ```ts * import { useInfiniteEffectSuspenseQuery } from "@effect-react-query"; - * import { Effect } from "effect"; + * import * as Effect from "effect/Effect"; * * // Effect without requirements (R = never) * const query = useInfiniteEffectSuspenseQuery({ @@ -61,7 +63,7 @@ export function useInfiniteEffectSuspenseQuery< queryFn: ( context: QueryFunctionContext, ) => Effect.Effect; - runtime?: Runtime.Runtime | ManagedRuntime.ManagedRuntime; + runtime?: Context.Context | ManagedRuntime.ManagedRuntime; } & Omit< UseInfiniteEffectSuspenseQueryOptions, "queryFn" | "runtime" diff --git a/test/effectQueryOptions.test.ts b/test/effectQueryOptions.test.ts index 237dd8e..9a9beed 100644 --- a/test/effectQueryOptions.test.ts +++ b/test/effectQueryOptions.test.ts @@ -1,4 +1,8 @@ -import { Context, Effect, Layer, ManagedRuntime, Schema } from "effect"; +import * as Context from "effect/Context"; +import * as Effect from "effect/Effect"; +import * as Layer from "effect/Layer"; +import * as ManagedRuntime from "effect/ManagedRuntime"; +import * as Schema from "effect/Schema"; import { describe, expect, it } from "vitest"; import type { DefinedInitialDataEffectQueryOptionsResult, @@ -12,10 +16,10 @@ class NetworkError extends Schema.TaggedError()("NetworkError", { }) {} // Define a service for testing runtime requirements -class UserService extends Context.Tag("UserService")< +class UserService extends Context.Service< UserService, { readonly getUser: (id: string) => Effect.Effect<{ id: string; name: string }, NetworkError> } ->() {} +>()("UserService") {} describe("effectQueryOptions", () => { it("should export effectQueryOptions", () => { diff --git a/test/infiniteEffectQueryOptions.test.ts b/test/infiniteEffectQueryOptions.test.ts index 8d666fa..0a2b3c7 100644 --- a/test/infiniteEffectQueryOptions.test.ts +++ b/test/infiniteEffectQueryOptions.test.ts @@ -1,4 +1,8 @@ -import { Context, Effect, Layer, ManagedRuntime, Schema } from "effect"; +import * as Context from "effect/Context"; +import * as Effect from "effect/Effect"; +import * as Layer from "effect/Layer"; +import * as ManagedRuntime from "effect/ManagedRuntime"; +import * as Schema from "effect/Schema"; import { describe, expect, it } from "vitest"; import { infiniteEffectQueryOptions } from "../src"; @@ -14,10 +18,10 @@ interface PostsPage { } // Define a service for testing runtime requirements -class PostService extends Context.Tag("PostService")< +class PostService extends Context.Service< PostService, { readonly getPosts: (cursor: number) => Effect.Effect } ->() {} +>()("PostService") {} describe("infiniteEffectQueryOptions", () => { it("should export infiniteEffectQueryOptions", () => { diff --git a/test/toQueryOptions.test.ts b/test/toQueryOptions.test.ts index a4db221..81d479a 100644 --- a/test/toQueryOptions.test.ts +++ b/test/toQueryOptions.test.ts @@ -1,5 +1,9 @@ import { QueryClient } from "@tanstack/react-query"; -import { Context, Effect, Layer, ManagedRuntime, Schema } from "effect"; +import * as Context from "effect/Context"; +import * as Effect from "effect/Effect"; +import * as Layer from "effect/Layer"; +import * as ManagedRuntime from "effect/ManagedRuntime"; +import * as Schema from "effect/Schema"; import { describe, expect, it } from "vitest"; import { effectQueryOptions, toQueryOptions } from "../src"; @@ -13,10 +17,10 @@ class NotFoundError extends Schema.TaggedError()("NotFoundError", }) {} // Define a service for testing runtime requirements -class UserService extends Context.Tag("UserService")< +class UserService extends Context.Service< UserService, { readonly getUser: (id: string) => Effect.Effect<{ id: string; name: string }, NetworkError> } ->() {} +>()("UserService") {} function createTestQueryClient(): QueryClient { return new QueryClient({ @@ -169,18 +173,16 @@ describe("toQueryOptions with runtime", () => { await runtime.dispose(); }); - it("should work with standard Runtime", async () => { + it("should work with a Context", async () => { const queryClient = createTestQueryClient(); - const UserServiceLive = Layer.succeed( + const runtime = Context.make( UserService, UserService.of({ getUser: (id) => Effect.succeed({ id, name: `Runtime User ${id}` }), }), ); - const runtime = await Effect.runPromise(Layer.toRuntime(UserServiceLive).pipe(Effect.scoped)); - const options = effectQueryOptions({ queryKey: ["user-standard-runtime", "789"] as const, queryFn: () => diff --git a/test/useEffectMutation.test.ts b/test/useEffectMutation.test.ts index 7ea15c9..ca35afe 100644 --- a/test/useEffectMutation.test.ts +++ b/test/useEffectMutation.test.ts @@ -1,5 +1,10 @@ import { act, renderHook, waitFor } from "@testing-library/react"; -import { Context, Effect, Layer, ManagedRuntime, Match, Schema } from "effect"; +import * as Context from "effect/Context"; +import * as Effect from "effect/Effect"; +import * as Layer from "effect/Layer"; +import * as ManagedRuntime from "effect/ManagedRuntime"; +import * as Match from "effect/Match"; +import * as Schema from "effect/Schema"; import { describe, expect, it, vi } from "vitest"; import type { UseEffectMutationOptions } from "../src"; import { useEffectMutation } from "../src"; @@ -11,18 +16,18 @@ class NetworkError extends Schema.TaggedError()("NetworkError", { }) {} class ValidationError extends Schema.TaggedError()("ValidationError", { - fields: Schema.Record({ key: Schema.String, value: Schema.String }), + fields: Schema.Record(Schema.String, Schema.String), }) {} // Define a service for testing runtime requirements -class UserService extends Context.Tag("UserService")< +class UserService extends Context.Service< UserService, { readonly createUser: ( name: string, ) => Effect.Effect<{ id: string; name: string }, NetworkError>; } ->() {} +>()("UserService") {} // ============================================================================ // Hook Behavior Tests diff --git a/test/useEffectQueries.test.ts b/test/useEffectQueries.test.ts index 5d91e2a..f1c4fbb 100644 --- a/test/useEffectQueries.test.ts +++ b/test/useEffectQueries.test.ts @@ -1,5 +1,10 @@ import { renderHook, waitFor } from "@testing-library/react"; -import { Context, Effect, Layer, ManagedRuntime, Match, Schema } from "effect"; +import * as Context from "effect/Context"; +import * as Effect from "effect/Effect"; +import * as Layer from "effect/Layer"; +import * as ManagedRuntime from "effect/ManagedRuntime"; +import * as Match from "effect/Match"; +import * as Schema from "effect/Schema"; import { describe, expect, it, vi } from "vitest"; import type { UseEffectQueryOptionsForUseQueries } from "../src"; import { useEffectQueries } from "../src"; @@ -15,10 +20,10 @@ class NotFoundError extends Schema.TaggedError()("NotFoundError", }) {} // Define a service for testing runtime requirements -class UserService extends Context.Tag("UserService")< +class UserService extends Context.Service< UserService, { readonly getUser: (id: string) => Effect.Effect<{ id: string; name: string }, NetworkError> } ->() {} +>()("UserService") {} // ============================================================================ // Hook Behavior Tests diff --git a/test/useEffectQuery.test.ts b/test/useEffectQuery.test.ts index ce97c72..7749e13 100644 --- a/test/useEffectQuery.test.ts +++ b/test/useEffectQuery.test.ts @@ -1,5 +1,10 @@ import { renderHook, waitFor } from "@testing-library/react"; -import { Context, Effect, Layer, ManagedRuntime, Match, Schema } from "effect"; +import * as Context from "effect/Context"; +import * as Effect from "effect/Effect"; +import * as Layer from "effect/Layer"; +import * as ManagedRuntime from "effect/ManagedRuntime"; +import * as Match from "effect/Match"; +import * as Schema from "effect/Schema"; import { describe, expect, it, vi } from "vitest"; import type { DefinedInitialDataEffectQueryOptions, @@ -21,10 +26,10 @@ class NotFoundError extends Schema.TaggedError()("NotFoundError", }) {} // Define a service for testing runtime requirements -class UserService extends Context.Tag("UserService")< +class UserService extends Context.Service< UserService, { readonly getUser: (id: string) => Effect.Effect<{ id: string; name: string }, NetworkError> } ->() {} +>()("UserService") {} // ============================================================================ // Hook Behavior Tests diff --git a/test/useEffectSuspenseQueries.test.ts b/test/useEffectSuspenseQueries.test.ts index fe5fe34..47afe8d 100644 --- a/test/useEffectSuspenseQueries.test.ts +++ b/test/useEffectSuspenseQueries.test.ts @@ -1,5 +1,9 @@ import { renderHook, waitFor } from "@testing-library/react"; -import { Context, Effect, Layer, ManagedRuntime, Schema } from "effect"; +import * as Context from "effect/Context"; +import * as Effect from "effect/Effect"; +import * as Layer from "effect/Layer"; +import * as ManagedRuntime from "effect/ManagedRuntime"; +import * as Schema from "effect/Schema"; import { describe, expect, it, vi } from "vitest"; import type { UseEffectSuspenseQueryOptionsForUseQueries } from "../src"; import { useEffectSuspenseQueries } from "../src"; @@ -11,10 +15,10 @@ class NetworkError extends Schema.TaggedError()("NetworkError", { }) {} // Define a service for testing runtime requirements -class UserService extends Context.Tag("UserService")< +class UserService extends Context.Service< UserService, { readonly getUser: (id: string) => Effect.Effect<{ id: string; name: string }, NetworkError> } ->() {} +>()("UserService") {} // ============================================================================ // Hook Behavior Tests diff --git a/test/useEffectSuspenseQuery.test.ts b/test/useEffectSuspenseQuery.test.ts index 3eadbc5..9fc96e8 100644 --- a/test/useEffectSuspenseQuery.test.ts +++ b/test/useEffectSuspenseQuery.test.ts @@ -1,5 +1,9 @@ import { renderHook, waitFor } from "@testing-library/react"; -import { Context, Effect, Layer, ManagedRuntime, Schema } from "effect"; +import * as Context from "effect/Context"; +import * as Effect from "effect/Effect"; +import * as Layer from "effect/Layer"; +import * as ManagedRuntime from "effect/ManagedRuntime"; +import * as Schema from "effect/Schema"; import { describe, expect, it, vi } from "vitest"; import type { UseEffectSuspenseQueryOptions, UseEffectSuspenseQueryResult } from "../src"; import { useEffectSuspenseQuery } from "../src"; @@ -15,10 +19,10 @@ class NotFoundError extends Schema.TaggedError()("NotFoundError", }) {} // Define a service for testing runtime requirements -class UserService extends Context.Tag("UserService")< +class UserService extends Context.Service< UserService, { readonly getUser: (id: string) => Effect.Effect<{ id: string; name: string }, NetworkError> } ->() {} +>()("UserService") {} // ============================================================================ // Hook Behavior Tests diff --git a/test/useInfiniteEffectQuery.test.ts b/test/useInfiniteEffectQuery.test.ts index c0c4a95..efe9c3b 100644 --- a/test/useInfiniteEffectQuery.test.ts +++ b/test/useInfiniteEffectQuery.test.ts @@ -1,6 +1,11 @@ import type { InfiniteData } from "@tanstack/react-query"; import { act, renderHook, waitFor } from "@testing-library/react"; -import { Context, Effect, Layer, ManagedRuntime, Match, Schema } from "effect"; +import * as Context from "effect/Context"; +import * as Effect from "effect/Effect"; +import * as Layer from "effect/Layer"; +import * as ManagedRuntime from "effect/ManagedRuntime"; +import * as Match from "effect/Match"; +import * as Schema from "effect/Schema"; import { describe, expect, it, vi } from "vitest"; import type { DefinedInitialDataInfiniteEffectQueryOptions, @@ -27,10 +32,10 @@ interface PostsPage { } // Define a service for testing runtime requirements -class PostService extends Context.Tag("PostService")< +class PostService extends Context.Service< PostService, { readonly getPosts: (cursor: number) => Effect.Effect } ->() {} +>()("PostService") {} // ============================================================================ // Hook Behavior Tests diff --git a/test/useInfiniteEffectSuspenseQuery.test.ts b/test/useInfiniteEffectSuspenseQuery.test.ts index 6400698..a209b86 100644 --- a/test/useInfiniteEffectSuspenseQuery.test.ts +++ b/test/useInfiniteEffectSuspenseQuery.test.ts @@ -1,6 +1,10 @@ import type { InfiniteData } from "@tanstack/react-query"; import { act, renderHook, waitFor } from "@testing-library/react"; -import { Context, Effect, Layer, ManagedRuntime, Schema } from "effect"; +import * as Context from "effect/Context"; +import * as Effect from "effect/Effect"; +import * as Layer from "effect/Layer"; +import * as ManagedRuntime from "effect/ManagedRuntime"; +import * as Schema from "effect/Schema"; import { describe, expect, it, vi } from "vitest"; import type { UseInfiniteEffectSuspenseQueryOptions, @@ -21,10 +25,10 @@ interface PostsPage { } // Define a service for testing runtime requirements -class PostService extends Context.Tag("PostService")< +class PostService extends Context.Service< PostService, { readonly getPosts: (cursor: number) => Effect.Effect } ->() {} +>()("PostService") {} // ============================================================================ // Hook Behavior Tests