0.2.2 #31

Merged
Thilawyn merged 184 commits from next into master 2026-01-16 17:05:31 +01:00
4 changed files with 31 additions and 10 deletions
Showing only changes of commit 93f65c5016 - Show all commits

View File

@@ -17,6 +17,9 @@
"packages/effect-fc": { "packages/effect-fc": {
"name": "effect-fc", "name": "effect-fc",
"version": "0.2.1", "version": "0.2.1",
"devDependencies": {
"@effect/platform-browser": "^0.74.0",
},
"peerDependencies": { "peerDependencies": {
"@types/react": "^19.2.0", "@types/react": "^19.2.0",
"effect": "^3.19.0", "effect": "^3.19.0",
@@ -655,6 +658,8 @@
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"effect-fc/@effect/platform-browser": ["@effect/platform-browser@0.74.0", "", { "dependencies": { "multipasta": "^0.2.7" }, "peerDependencies": { "@effect/platform": "^0.94.0", "effect": "^3.19.13" } }, "sha512-PAgkg5L5cASQpScA0SZTSy543MVA4A9kmpVCjo2fCINLRpTeuCFAOQHgPmw8dKHnYS0yGs2TYn7AlrhhqQ5o3g=="],
"readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"recast/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "recast/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],

View File

@@ -37,6 +37,9 @@
"clean:dist": "rm -rf dist", "clean:dist": "rm -rf dist",
"clean:modules": "rm -rf node_modules" "clean:modules": "rm -rf node_modules"
}, },
"devDependencies": {
"@effect/platform-browser": "^0.74.0"
},
"peerDependencies": { "peerDependencies": {
"@types/react": "^19.2.0", "@types/react": "^19.2.0",
"effect": "^3.19.0", "effect": "^3.19.0",

View File

@@ -16,6 +16,7 @@ extends Pipeable.Pipeable {
readonly initialProgress: P readonly initialProgress: P
readonly staleTime: Duration.DurationInput readonly staleTime: Duration.DurationInput
readonly refreshOnWindowFocus: boolean
readonly latestKey: Subscribable.Subscribable<Option.Option<K>> readonly latestKey: Subscribable.Subscribable<Option.Option<K>>
readonly fiber: Subscribable.Subscribable<Option.Option<Fiber.Fiber<A, E>>> readonly fiber: Subscribable.Subscribable<Option.Option<Fiber.Fiber<A, E>>>
@@ -47,6 +48,7 @@ extends Pipeable.Class() implements Query<K, A, E, R, P> {
readonly initialProgress: P, readonly initialProgress: P,
readonly staleTime: Duration.DurationInput, readonly staleTime: Duration.DurationInput,
readonly refreshOnWindowFocus: boolean,
readonly latestKey: SubscriptionRef.SubscriptionRef<Option.Option<K>>, readonly latestKey: SubscriptionRef.SubscriptionRef<Option.Option<K>>,
readonly fiber: SubscriptionRef.SubscriptionRef<Option.Option<Fiber.Fiber<A, E>>>, readonly fiber: SubscriptionRef.SubscriptionRef<Option.Option<Fiber.Fiber<A, E>>>,
@@ -59,17 +61,22 @@ extends Pipeable.Class() implements Query<K, A, E, R, P> {
} }
get run(): Effect.Effect<void> { get run(): Effect.Effect<void> {
return Stream.runForEach(this.key, key => this.interrupt.pipe( return Effect.all([
Effect.andThen(SubscriptionRef.set(this.latestKey, Option.some(key))), Stream.runForEach(this.key, key => this.fetchSubscribable(key)),
Effect.andThen(this.latestFinalResult),
Effect.andThen(previous => this.startCached(key, Option.isSome(previous) Effect.promise(() => import("@effect/platform-browser")).pipe(
? Result.willFetch(previous.value) as Result.Final<A, E, P> Effect.andThen(({ BrowserStream }) => this.refreshOnWindowFocus
: Result.initial() ? Stream.runForEach(
)), BrowserStream.fromEventListenerWindow("focus"),
Effect.andThen(sub => Effect.forkScoped(this.watch(key, sub))), () => this.refreshSubscribable,
)).pipe( )
: Effect.void
),
Effect.catchAllDefect(() => Effect.void),
),
], { concurrency: "unbounded" }).pipe(
Effect.ignore,
this.runSemaphore.withPermits(1), this.runSemaphore.withPermits(1),
Effect.provide(this.context),
) )
} }
@@ -269,6 +276,7 @@ export declare namespace make {
readonly f: (key: NoInfer<K>) => Effect.Effect<A, E, Result.forkEffect.InputContext<R, NoInfer<P>>> readonly f: (key: NoInfer<K>) => Effect.Effect<A, E, Result.forkEffect.InputContext<R, NoInfer<P>>>
readonly initialProgress?: P readonly initialProgress?: P
readonly staleTime?: Duration.DurationInput readonly staleTime?: Duration.DurationInput
readonly refreshOnWindowFocus?: boolean
} }
} }
@@ -288,6 +296,7 @@ export const make = Effect.fnUntraced(function* <K extends Query.AnyKey, A, E =
options.initialProgress as P, options.initialProgress as P,
options.staleTime ?? client.defaultStaleTime, options.staleTime ?? client.defaultStaleTime,
options.refreshOnWindowFocus ?? client.defaultRefreshOnWindowFocus,
yield* SubscriptionRef.make(Option.none<K>()), yield* SubscriptionRef.make(Option.none<K>()),
yield* SubscriptionRef.make(Option.none<Fiber.Fiber<A, E>>()), yield* SubscriptionRef.make(Option.none<Fiber.Fiber<A, E>>()),

View File

@@ -11,6 +11,7 @@ export interface QueryClientService extends Pipeable.Pipeable {
readonly cache: SubscriptionRef.SubscriptionRef<HashMap.HashMap<QueryClientCacheKey, QueryClientCacheEntry>> readonly cache: SubscriptionRef.SubscriptionRef<HashMap.HashMap<QueryClientCacheKey, QueryClientCacheEntry>>
readonly gcTime: Duration.DurationInput readonly gcTime: Duration.DurationInput
readonly defaultStaleTime: Duration.DurationInput readonly defaultStaleTime: Duration.DurationInput
readonly defaultRefreshOnWindowFocus: boolean
} }
export class QueryClient extends Effect.Service<QueryClient>()("@effect-fc/QueryClient/QueryClient", { export class QueryClient extends Effect.Service<QueryClient>()("@effect-fc/QueryClient/QueryClient", {
@@ -26,6 +27,7 @@ implements QueryClientService {
readonly cache: SubscriptionRef.SubscriptionRef<HashMap.HashMap<QueryClientCacheKey, QueryClientCacheEntry>>, readonly cache: SubscriptionRef.SubscriptionRef<HashMap.HashMap<QueryClientCacheKey, QueryClientCacheEntry>>,
readonly gcTime: Duration.DurationInput, readonly gcTime: Duration.DurationInput,
readonly defaultStaleTime: Duration.DurationInput, readonly defaultStaleTime: Duration.DurationInput,
readonly defaultRefreshOnWindowFocus: boolean,
readonly runSemaphore: Effect.Semaphore, readonly runSemaphore: Effect.Semaphore,
) { ) {
super() super()
@@ -38,6 +40,7 @@ export declare namespace make {
export interface Options { export interface Options {
readonly gcTime?: Duration.DurationInput readonly gcTime?: Duration.DurationInput
readonly defaultStaleTime?: Duration.DurationInput readonly defaultStaleTime?: Duration.DurationInput
readonly defaultRefreshOnWindowFocus?: boolean
} }
} }
@@ -46,6 +49,7 @@ export const make = Effect.fnUntraced(function* (options: make.Options = {}): Ef
yield* SubscriptionRef.make(HashMap.empty<QueryClientCacheKey, QueryClientCacheEntry>()), yield* SubscriptionRef.make(HashMap.empty<QueryClientCacheKey, QueryClientCacheEntry>()),
options.gcTime ?? "5 minutes", options.gcTime ?? "5 minutes",
options.defaultStaleTime ?? "0 minutes", options.defaultStaleTime ?? "0 minutes",
options.defaultRefreshOnWindowFocus ?? true,
yield* Effect.makeSemaphore(1), yield* Effect.makeSemaphore(1),
) )
}) })