7 Commits

Author SHA1 Message Date
Julien Valverdé
e9e17ac211 Fix
All checks were successful
Lint / lint (push) Successful in 12s
2025-03-16 04:11:25 +01:00
Julien Valverdé
1f0ff725ff Fix
All checks were successful
Lint / lint (push) Successful in 13s
2025-03-16 04:05:39 +01:00
Julien Valverdé
447d89982c Fix
All checks were successful
Lint / lint (push) Successful in 13s
2025-03-16 03:34:54 +01:00
Julien Valverdé
778ee27795 ErrorHandler refactoring
All checks were successful
Lint / lint (push) Successful in 16s
2025-03-16 03:33:01 +01:00
Julien Valverdé
077816efb6 Fix
All checks were successful
Lint / lint (push) Successful in 13s
2025-03-16 03:23:12 +01:00
Julien Valverdé
e4bacd1ca7 Working QueryClient refactoring
All checks were successful
Lint / lint (push) Successful in 13s
2025-03-16 03:19:12 +01:00
Julien Valverdé
0e2c0db28f QueryClient refactoring
All checks were successful
Lint / lint (push) Successful in 13s
2025-03-16 02:52:49 +01:00
7 changed files with 57 additions and 63 deletions

View File

@@ -5,7 +5,7 @@ import { Layer } from "effect"
import { StrictMode } from "react" import { StrictMode } from "react"
import { createRoot } from "react-dom/client" import { createRoot } from "react-dom/client"
import { ReffuseRuntime } from "reffuse" import { ReffuseRuntime } from "reffuse"
import { AppQueryClientLive, AppQueryErrorHandlerLive } from "./query" import { AppQueryClient, AppQueryErrorHandler } from "./query"
import { GlobalContext } from "./reffuse" import { GlobalContext } from "./reffuse"
import { routeTree } from "./routeTree.gen" import { routeTree } from "./routeTree.gen"
@@ -15,8 +15,8 @@ const layer = Layer.empty.pipe(
Layer.provideMerge(Geolocation.layer), Layer.provideMerge(Geolocation.layer),
Layer.provideMerge(Permissions.layer), Layer.provideMerge(Permissions.layer),
Layer.provideMerge(FetchHttpClient.layer), Layer.provideMerge(FetchHttpClient.layer),
Layer.provideMerge(AppQueryClientLive), Layer.provideMerge(AppQueryClient.Live),
Layer.provideMerge(AppQueryErrorHandlerLive), Layer.provideMerge(AppQueryErrorHandler.Live),
) )
const router = createRouter({ routeTree }) const router = createRouter({ routeTree })

View File

@@ -2,9 +2,8 @@ import { HttpClientError } from "@effect/platform"
import { ErrorHandler, QueryClient } from "@reffuse/extension-query" import { ErrorHandler, QueryClient } from "@reffuse/extension-query"
export class AppQueryErrorHandler extends ErrorHandler.Tag("AppQueryErrorHandler")<AppQueryErrorHandler, export class AppQueryErrorHandler extends ErrorHandler.Service("AppQueryErrorHandler")<AppQueryErrorHandler,
HttpClientError.HttpClientError HttpClientError.HttpClientError
>() {} >() {}
export const AppQueryErrorHandlerLive = ErrorHandler.layer(AppQueryErrorHandler)
export const [AppQueryClient, AppQueryClientLive] = QueryClient.make({ ErrorHandler: AppQueryErrorHandler }) export class AppQueryClient extends QueryClient.Service({ ErrorHandler: AppQueryErrorHandler })<AppQueryClient>() {}

View File

@@ -2,7 +2,6 @@ import { HttpClient } from "@effect/platform"
import { Clipboard, Geolocation, Permissions } from "@effect/platform-browser" import { Clipboard, Geolocation, Permissions } from "@effect/platform-browser"
import { LazyRefExtension } from "@reffuse/extension-lazyref" import { LazyRefExtension } from "@reffuse/extension-lazyref"
import { QueryExtension } from "@reffuse/extension-query" import { QueryExtension } from "@reffuse/extension-query"
import { Context } from "effect"
import { Reffuse, ReffuseContext } from "reffuse" import { Reffuse, ReffuseContext } from "reffuse"
import { AppQueryClient, AppQueryErrorHandler } from "./query" import { AppQueryClient, AppQueryErrorHandler } from "./query"
@@ -12,7 +11,7 @@ export const GlobalContext = ReffuseContext.make<
| Geolocation.Geolocation | Geolocation.Geolocation
| Permissions.Permissions | Permissions.Permissions
| HttpClient.HttpClient | HttpClient.HttpClient
| Context.Tag.Service<typeof AppQueryClient> | AppQueryClient
| AppQueryErrorHandler | AppQueryErrorHandler
>() >()

View File

@@ -1,4 +1,5 @@
import { type Cause, type Context, Effect, Layer, Queue, Stream } from "effect" import { type Cause, Context, Effect, Layer, Queue, Stream } from "effect"
import type { Mutable } from "effect/Types"
export interface ErrorHandler<E> { export interface ErrorHandler<E> {
@@ -9,13 +10,14 @@ export interface ErrorHandler<E> {
export type Error<T> = T extends ErrorHandler<infer E> ? E : never export type Error<T> = T extends ErrorHandler<infer E> ? E : never
export const Tag = <const Id extends string>(id: Id) => < export interface ServiceResult<Self, Id extends string, E> extends Context.TagClass<Self, Id, ErrorHandler<E>> {
Self, E = never, readonly Live: Layer.Layer<Self>
>() => Effect.Tag(id)<Self, ErrorHandler<E>>() }
export const layer = <Self, Id extends string, E>( export const Service = <const Id extends string>(id: Id) => (
tag: Context.TagClass<Self, Id, ErrorHandler<E>> <Self, E = never>(): ServiceResult<Self, Id, E> => {
): Layer.Layer<Self> => Layer.effect(tag, Effect.gen(function*() { const TagClass = Context.Tag(id)() as ServiceResult<Self, Id, E>
(TagClass as Mutable<typeof TagClass>).Live = Layer.effect(TagClass, Effect.gen(function*() {
const queue = yield* Queue.unbounded<Cause.Cause<E>>() const queue = yield* Queue.unbounded<Cause.Cause<E>>()
const errors = Stream.fromQueue(queue) const errors = Stream.fromQueue(queue)
@@ -26,8 +28,10 @@ export const layer = <Self, Id extends string, E>(
) as Effect.Effect<A, Exclude<SelfE, E>, R> ) as Effect.Effect<A, Exclude<SelfE, E>, R>
return { errors, handle } return { errors, handle }
})) }))
return TagClass
}
)
export class DefaultErrorHandler extends Tag("@reffuse/extension-query/DefaultErrorHandler")<DefaultErrorHandler>() {} export class DefaultErrorHandler extends Service("@reffuse/extension-query/DefaultErrorHandler")<DefaultErrorHandler>() {}
export const DefaultErrorHandlerLive = layer(DefaultErrorHandler)

View File

@@ -1,4 +1,5 @@
import { Context, Effect, Layer } from "effect" import { Context, Layer } from "effect"
import type { Mutable } from "effect/Types"
import * as ErrorHandler from "./ErrorHandler.js" import * as ErrorHandler from "./ErrorHandler.js"
@@ -6,42 +7,33 @@ export interface QueryClient<EH, HandledE> {
readonly ErrorHandler: Context.Tag<EH, ErrorHandler.ErrorHandler<HandledE>> readonly ErrorHandler: Context.Tag<EH, ErrorHandler.ErrorHandler<HandledE>>
} }
export type Tag<EH, HandledE> = Context.Tag<QueryClient<EH, HandledE>, QueryClient<EH, HandledE>>
export const makeTag = <EH = never, HandledE = never>(): Tag<EH, HandledE> => Context.GenericTag("@reffuse/extension-query/QueryClient") const id = "@reffuse/extension-query/QueryClient"
export type TagClassShape<EH, HandledE> = Context.TagClassShape<typeof id, QueryClient<EH, HandledE>>
export type GenericTagClass<EH, HandledE> = Context.TagClass<TagClassShape<EH, HandledE>, typeof id, QueryClient<EH, HandledE>>
export const makeGenericTagClass = <EH = never, HandledE = never>(): GenericTagClass<EH, HandledE> => Context.Tag(id)()
export interface MakeProps<EH, HandledE> { export interface ServiceProps<EH, HandledE> {
readonly ErrorHandler?: Context.Tag<EH, ErrorHandler.ErrorHandler<HandledE>> readonly ErrorHandler?: Context.Tag<EH, ErrorHandler.ErrorHandler<HandledE>>
} }
export type MakeResult<EH, HandledE> = [ export interface ServiceResult<Self, EH, HandledE> extends Context.TagClass<Self, typeof id, QueryClient<EH, HandledE>> {
tag: Tag<EH, HandledE>, readonly Live: Layer.Layer<Self>
layer: Layer.Layer< }
| QueryClient<EH, HandledE>
| (EH extends ErrorHandler.DefaultErrorHandler
? ErrorHandler.DefaultErrorHandler
: never)
>,
]
export const make = < export const Service = <
EH = ErrorHandler.DefaultErrorHandler, EH = ErrorHandler.DefaultErrorHandler,
HandledE = never, HandledE = ErrorHandler.Error<Context.Tag.Service<ErrorHandler.DefaultErrorHandler>>,
>( >(
props?: MakeProps<EH, HandledE> props?: ServiceProps<EH, HandledE>
): MakeResult<EH, HandledE> => [ ) => (
makeTag(), <Self>(): ServiceResult<Self, EH, HandledE> => {
const TagClass = Context.Tag(id)() as ServiceResult<Self, EH, HandledE>
Layer.empty.pipe( (TagClass as Mutable<typeof TagClass>).Live = Layer.succeed(TagClass, {
Layer.provideMerge(
Layer.effect(makeTag<EH, HandledE>(), Effect.succeed({
ErrorHandler: (props?.ErrorHandler ?? ErrorHandler.DefaultErrorHandler) as Context.Tag<EH, ErrorHandler.ErrorHandler<HandledE>> ErrorHandler: (props?.ErrorHandler ?? ErrorHandler.DefaultErrorHandler) as Context.Tag<EH, ErrorHandler.ErrorHandler<HandledE>>
})) })
), return TagClass
}
Layer.provideMerge((props?.ErrorHandler )
? Layer.empty
: ErrorHandler.DefaultErrorHandlerLive
) as Layer.Layer<ErrorHandler.DefaultErrorHandler>),
),
]

View File

@@ -34,11 +34,11 @@ export const QueryExtension = ReffuseExtension.make(() => ({
QR extends R, QR extends R,
R, R,
>( >(
this: ReffuseHelpers.ReffuseHelpers<R | QueryClient.QueryClient<EH, HandledE> | EH>, this: ReffuseHelpers.ReffuseHelpers<R | QueryClient.TagClassShape<EH, HandledE> | EH>,
props: UseQueryProps<QK, QA, QE, QR>, props: UseQueryProps<QK, QA, QE, QR>,
): UseQueryResult<QK, QA, Exclude<QE, HandledE>> { ): UseQueryResult<QK, QA, Exclude<QE, HandledE>> {
const runner = this.useMemo(() => QueryRunner.make({ const runner = this.useMemo(() => QueryRunner.make({
QueryClient: QueryClient.makeTag<EH, HandledE>(), QueryClient: QueryClient.makeGenericTagClass<EH, HandledE>(),
key: props.key, key: props.key,
query: props.query, query: props.query,
}), [props.key]) }), [props.key])

View File

@@ -21,7 +21,7 @@ export interface QueryRunner<K extends readonly unknown[], A, E, R> {
export interface MakeProps<EH, K extends readonly unknown[], A, E, HandledE, R> { export interface MakeProps<EH, K extends readonly unknown[], A, E, HandledE, R> {
readonly QueryClient: QueryClient.Tag<EH, HandledE> readonly QueryClient: QueryClient.GenericTagClass<EH, HandledE>
readonly key: Stream.Stream<K> readonly key: Stream.Stream<K>
readonly query: (key: K) => Effect.Effect<A, E, R> readonly query: (key: K) => Effect.Effect<A, E, R>
} }
@@ -35,9 +35,9 @@ export const make = <EH, K extends readonly unknown[], A, E, HandledE, R>(
): Effect.Effect< ): Effect.Effect<
QueryRunner<K, A, Exclude<E, HandledE>, R>, QueryRunner<K, A, Exclude<E, HandledE>, R>,
never, never,
R | QueryClient.QueryClient<EH, HandledE> | EH R | QueryClient.TagClassShape<EH, HandledE> | EH
> => Effect.gen(function*() { > => Effect.gen(function*() {
const context = yield* Effect.context<R | QueryClient.QueryClient<EH, HandledE> | EH>() const context = yield* Effect.context<R | QueryClient.TagClassShape<EH, HandledE> | EH>()
const latestKeyRef = yield* SubscriptionRef.make(Option.none<K>()) const latestKeyRef = yield* SubscriptionRef.make(Option.none<K>())
const stateRef = yield* SubscriptionRef.make(AsyncData.noData<A, Exclude<E, HandledE>>()) const stateRef = yield* SubscriptionRef.make(AsyncData.noData<A, Exclude<E, HandledE>>())