@reffuse/extension-query 0.1.5 (#16)
Co-authored-by: Julien Valverdé <julien.valverde@mailo.com> Reviewed-on: https://gitea:3000/Thilawyn/reffuse/pulls/16
This commit was merged in pull request #16.
This commit is contained in:
@@ -1,16 +1,16 @@
|
||||
import { AlertDialog, Button, Flex, Text } from "@radix-ui/themes"
|
||||
import { Cause, Console, Effect, Either, flow, Match, Option, Stream } from "effect"
|
||||
import { useState } from "react"
|
||||
import { AppQueryClient } from "./query"
|
||||
import { R } from "./reffuse"
|
||||
import { AppQueryErrorHandler } from "./services"
|
||||
|
||||
|
||||
export function VQueryErrorHandler() {
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const error = R.useSubscribeStream(
|
||||
R.useMemo(() => AppQueryClient.pipe(
|
||||
Effect.map(client => client.errorHandler.errors.pipe(
|
||||
R.useMemo(() => AppQueryErrorHandler.AppQueryErrorHandler.pipe(
|
||||
Effect.map(handler => handler.errors.pipe(
|
||||
Stream.changes,
|
||||
Stream.tap(Console.error),
|
||||
Stream.tap(() => Effect.sync(() => setOpen(true))),
|
||||
|
||||
@@ -5,14 +5,14 @@ import { Layer } from "effect"
|
||||
import { StrictMode } from "react"
|
||||
import { createRoot } from "react-dom/client"
|
||||
import { ReffuseRuntime } from "reffuse"
|
||||
import { AppQueryClient, AppQueryErrorHandler } from "./query"
|
||||
import { RootContext } from "./reffuse"
|
||||
import { routeTree } from "./routeTree.gen"
|
||||
import { AppQueryClient, AppQueryErrorHandler } from "./services"
|
||||
|
||||
|
||||
const layer = Layer.empty.pipe(
|
||||
Layer.provideMerge(AppQueryClient.Default),
|
||||
Layer.provideMerge(AppQueryErrorHandler.Default),
|
||||
Layer.provideMerge(AppQueryClient.AppQueryClient.Default),
|
||||
Layer.provideMerge(AppQueryErrorHandler.AppQueryErrorHandler.Default),
|
||||
Layer.provideMerge(Clipboard.layer),
|
||||
Layer.provideMerge(Geolocation.layer),
|
||||
Layer.provideMerge(Permissions.layer),
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import { HttpClientError } from "@effect/platform"
|
||||
import { QueryClient, QueryErrorHandler } from "@reffuse/extension-query"
|
||||
import { Effect } from "effect"
|
||||
|
||||
|
||||
export class AppQueryErrorHandler extends QueryErrorHandler.Service<AppQueryErrorHandler,
|
||||
HttpClientError.HttpClientError
|
||||
>()(
|
||||
"AppQueryErrorHandler",
|
||||
|
||||
(self, failure, defect) => self.pipe(
|
||||
Effect.catchTag("RequestError", "ResponseError", failure),
|
||||
Effect.catchAllDefect(defect),
|
||||
),
|
||||
) {}
|
||||
|
||||
export class AppQueryClient extends QueryClient.Service<AppQueryClient>()({ ErrorHandler: AppQueryErrorHandler }) {}
|
||||
@@ -3,11 +3,12 @@ import { Clipboard, Geolocation, Permissions } from "@effect/platform-browser"
|
||||
import { LazyRefExtension } from "@reffuse/extension-lazyref"
|
||||
import { QueryExtension } from "@reffuse/extension-query"
|
||||
import { Reffuse, ReffuseContext } from "reffuse"
|
||||
import { AppQueryClient } from "./query"
|
||||
import { AppQueryClient, AppQueryErrorHandler } from "./services"
|
||||
|
||||
|
||||
export const RootContext = ReffuseContext.make<
|
||||
| AppQueryClient
|
||||
| AppQueryClient.AppQueryClient
|
||||
| AppQueryErrorHandler.AppQueryErrorHandler
|
||||
| Clipboard.Clipboard
|
||||
| Geolocation.Geolocation
|
||||
| Permissions.Permissions
|
||||
|
||||
7
packages/example/src/services/AppQueryClient.ts
Normal file
7
packages/example/src/services/AppQueryClient.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { QueryClient } from "@reffuse/extension-query"
|
||||
import * as AppQueryErrorHandler from "./AppQueryErrorHandler"
|
||||
|
||||
|
||||
export class AppQueryClient extends QueryClient.Service<AppQueryClient>()({
|
||||
errorHandler: AppQueryErrorHandler.AppQueryErrorHandler
|
||||
}) {}
|
||||
13
packages/example/src/services/AppQueryErrorHandler.ts
Normal file
13
packages/example/src/services/AppQueryErrorHandler.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { HttpClientError } from "@effect/platform"
|
||||
import { QueryErrorHandler } from "@reffuse/extension-query"
|
||||
import { Effect } from "effect"
|
||||
|
||||
|
||||
export class AppQueryErrorHandler extends Effect.Service<AppQueryErrorHandler>()("AppQueryErrorHandler", {
|
||||
effect: QueryErrorHandler.make<HttpClientError.HttpClientError>()(
|
||||
(self, failure, defect) => self.pipe(
|
||||
Effect.catchTag("RequestError", "ResponseError", failure),
|
||||
Effect.catchAllDefect(defect),
|
||||
)
|
||||
)
|
||||
}) {}
|
||||
@@ -1 +1,2 @@
|
||||
export {}
|
||||
export * as AppQueryClient from "./AppQueryClient"
|
||||
export * as AppQueryErrorHandler from "./AppQueryErrorHandler"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@reffuse/extension-query",
|
||||
"version": "0.1.4",
|
||||
"version": "0.1.5",
|
||||
"type": "module",
|
||||
"files": [
|
||||
"./README.md",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Context, Effect, Layer } from "effect"
|
||||
import { Context, Effect, identity, Layer } from "effect"
|
||||
import type { Mutable } from "effect/Types"
|
||||
import * as QueryErrorHandler from "./QueryErrorHandler.js"
|
||||
|
||||
@@ -8,6 +8,17 @@ export interface QueryClient<FallbackA, HandledE> {
|
||||
}
|
||||
|
||||
|
||||
export interface MakeProps<FallbackA, HandledE> {
|
||||
readonly errorHandler: QueryErrorHandler.QueryErrorHandler<FallbackA, HandledE>
|
||||
}
|
||||
|
||||
export const make = <FallbackA, HandledE>(
|
||||
{ errorHandler }: MakeProps<FallbackA, HandledE>
|
||||
): Effect.Effect<QueryClient<FallbackA, HandledE>> => Effect.Do.pipe(
|
||||
Effect.let("errorHandler", () => errorHandler)
|
||||
)
|
||||
|
||||
|
||||
const id = "@reffuse/extension-query/QueryClient"
|
||||
|
||||
export type TagClassShape<FallbackA, HandledE> = Context.TagClassShape<typeof id, QueryClient<FallbackA, HandledE>>
|
||||
@@ -19,46 +30,28 @@ export type GenericTagClass<FallbackA, HandledE> = Context.TagClass<
|
||||
export const makeGenericTagClass = <FallbackA = never, HandledE = never>(): GenericTagClass<FallbackA, HandledE> => Context.Tag(id)()
|
||||
|
||||
|
||||
export interface ServiceProps<EH, FallbackA, HandledE> {
|
||||
readonly ErrorHandler?: Context.Tag<EH, QueryErrorHandler.QueryErrorHandler<FallbackA, HandledE>>
|
||||
export interface ServiceProps<FallbackA = never, HandledE = never, E = never, R = never> {
|
||||
readonly errorHandler?: Effect.Effect<QueryErrorHandler.QueryErrorHandler<FallbackA, HandledE>, E, R>
|
||||
}
|
||||
|
||||
export interface ServiceResult<Self, EH, FallbackA, HandledE> extends Context.TagClass<
|
||||
export interface ServiceResult<Self, FallbackA, HandledE, E, R> extends Context.TagClass<
|
||||
Self,
|
||||
typeof id,
|
||||
QueryClient<FallbackA, HandledE>
|
||||
> {
|
||||
readonly Default: Layer.Layer<
|
||||
Self | (EH extends QueryErrorHandler.DefaultQueryErrorHandler ? EH : never),
|
||||
never,
|
||||
EH extends QueryErrorHandler.DefaultQueryErrorHandler ? never : EH
|
||||
>
|
||||
readonly Default: Layer.Layer<Self, E, R>
|
||||
}
|
||||
|
||||
export const Service = <Self>() => (
|
||||
<
|
||||
EH = QueryErrorHandler.DefaultQueryErrorHandler,
|
||||
FallbackA = QueryErrorHandler.Fallback<Context.Tag.Service<QueryErrorHandler.DefaultQueryErrorHandler>>,
|
||||
HandledE = QueryErrorHandler.Error<Context.Tag.Service<QueryErrorHandler.DefaultQueryErrorHandler>>,
|
||||
>(
|
||||
props?: ServiceProps<EH, FallbackA, HandledE>
|
||||
): ServiceResult<Self, EH, FallbackA, HandledE> => {
|
||||
const TagClass = Context.Tag(id)() as ServiceResult<Self, EH, FallbackA, HandledE>
|
||||
<FallbackA = never, HandledE = never, E = never, R = never>(
|
||||
props?: ServiceProps<FallbackA, HandledE, E, R>
|
||||
): ServiceResult<Self, FallbackA, HandledE, E, R> => {
|
||||
const TagClass = Context.Tag(id)() as ServiceResult<Self, FallbackA, HandledE, E, R>
|
||||
|
||||
(TagClass as Mutable<typeof TagClass>).Default = Layer.effect(TagClass, Effect.Do.pipe(
|
||||
Effect.bind("errorHandler", () =>
|
||||
(props?.ErrorHandler ?? QueryErrorHandler.DefaultQueryErrorHandler) as Effect.Effect<
|
||||
QueryErrorHandler.QueryErrorHandler<FallbackA, HandledE>,
|
||||
never,
|
||||
EH extends QueryErrorHandler.DefaultQueryErrorHandler ? never : EH
|
||||
>
|
||||
)
|
||||
)).pipe(
|
||||
Layer.provideMerge((props?.ErrorHandler
|
||||
? Layer.empty
|
||||
: QueryErrorHandler.DefaultQueryErrorHandler.Default
|
||||
) as Layer.Layer<EH>)
|
||||
)
|
||||
(TagClass as Mutable<typeof TagClass>).Default = Layer.effect(TagClass, Effect.flatMap(
|
||||
props?.errorHandler ?? QueryErrorHandler.make<never>()(identity),
|
||||
errorHandler => make({ errorHandler }),
|
||||
))
|
||||
|
||||
return TagClass
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Cause, Context, Effect, identity, Layer, PubSub, Stream } from "effect"
|
||||
import type { Mutable } from "effect/Types"
|
||||
import { Cause, Effect, PubSub, Stream } from "effect"
|
||||
|
||||
|
||||
export interface QueryErrorHandler<FallbackA, HandledE> {
|
||||
@@ -11,55 +10,31 @@ export type Fallback<T> = T extends QueryErrorHandler<infer A, any> ? A : never
|
||||
export type Error<T> = T extends QueryErrorHandler<any, infer E> ? E : never
|
||||
|
||||
|
||||
export interface ServiceResult<
|
||||
Self,
|
||||
Id extends string,
|
||||
FallbackA,
|
||||
HandledE,
|
||||
> extends Context.TagClass<
|
||||
Self,
|
||||
Id,
|
||||
QueryErrorHandler<FallbackA, HandledE>
|
||||
> {
|
||||
readonly Default: Layer.Layer<Self>
|
||||
}
|
||||
|
||||
export const Service = <Self, HandledE = never>() => (
|
||||
<const Id extends string, FallbackA>(
|
||||
id: Id,
|
||||
export const make = <HandledE = never>() => (
|
||||
<FallbackA>(
|
||||
f: (
|
||||
self: Effect.Effect<never, HandledE>,
|
||||
failure: (failure: HandledE) => Effect.Effect<never>,
|
||||
defect: (defect: unknown) => Effect.Effect<never>,
|
||||
) => Effect.Effect<FallbackA>,
|
||||
): ServiceResult<Self, Id, FallbackA, HandledE> => {
|
||||
const TagClass = Context.Tag(id)() as ServiceResult<Self, Id, FallbackA, HandledE>
|
||||
) => Effect.Effect<FallbackA>
|
||||
): Effect.Effect<QueryErrorHandler<FallbackA, HandledE>> => Effect.gen(function*() {
|
||||
const pubsub = yield* PubSub.unbounded<Cause.Cause<HandledE>>()
|
||||
const errors = Stream.fromPubSub(pubsub)
|
||||
|
||||
(TagClass as Mutable<typeof TagClass>).Default = Layer.effect(TagClass, Effect.gen(function*() {
|
||||
const pubsub = yield* PubSub.unbounded<Cause.Cause<HandledE>>()
|
||||
const errors = Stream.fromPubSub(pubsub)
|
||||
const handle = <A, E, R>(
|
||||
self: Effect.Effect<A, E, R>
|
||||
): Effect.Effect<A | FallbackA, Exclude<E, HandledE>, R> => f(
|
||||
self as unknown as Effect.Effect<never, HandledE, never>,
|
||||
(failure: HandledE) => Effect.andThen(
|
||||
PubSub.publish(pubsub, Cause.fail(failure)),
|
||||
Effect.failCause(Cause.empty),
|
||||
),
|
||||
(defect: unknown) => Effect.andThen(
|
||||
PubSub.publish(pubsub, Cause.die(defect)),
|
||||
Effect.failCause(Cause.empty),
|
||||
),
|
||||
)
|
||||
|
||||
const handle = <A, E, R>(
|
||||
self: Effect.Effect<A, E, R>
|
||||
): Effect.Effect<A | FallbackA, Exclude<E, HandledE>, R> => f(
|
||||
self as unknown as Effect.Effect<never, HandledE, never>,
|
||||
(failure: HandledE) => PubSub.publish(pubsub, Cause.fail(failure)).pipe(
|
||||
Effect.andThen(Effect.failCause(Cause.empty))
|
||||
),
|
||||
(defect: unknown) => PubSub.publish(pubsub, Cause.die(defect)).pipe(
|
||||
Effect.andThen(Effect.failCause(Cause.empty))
|
||||
),
|
||||
)
|
||||
|
||||
return { errors, handle }
|
||||
}))
|
||||
|
||||
return TagClass
|
||||
}
|
||||
return { errors, handle }
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
export class DefaultQueryErrorHandler extends Service<DefaultQueryErrorHandler>()(
|
||||
"@reffuse/extension-query/DefaultQueryErrorHandler",
|
||||
identity,
|
||||
) {}
|
||||
|
||||
Reference in New Issue
Block a user