@reffuse/extension-query 0.1.5 #16
@@ -1,16 +1,16 @@
|
|||||||
import { AlertDialog, Button, Flex, Text } from "@radix-ui/themes"
|
import { AlertDialog, Button, Flex, Text } from "@radix-ui/themes"
|
||||||
import { Cause, Console, Effect, Either, flow, Match, Option, Stream } from "effect"
|
import { Cause, Console, Effect, Either, flow, Match, Option, Stream } from "effect"
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
import { AppQueryClient } from "./query"
|
|
||||||
import { R } from "./reffuse"
|
import { R } from "./reffuse"
|
||||||
|
import { AppQueryErrorHandler } from "./services"
|
||||||
|
|
||||||
|
|
||||||
export function VQueryErrorHandler() {
|
export function VQueryErrorHandler() {
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
const error = R.useSubscribeStream(
|
const error = R.useSubscribeStream(
|
||||||
R.useMemo(() => AppQueryClient.pipe(
|
R.useMemo(() => AppQueryErrorHandler.AppQueryErrorHandler.pipe(
|
||||||
Effect.map(client => client.errorHandler.errors.pipe(
|
Effect.map(handler => handler.errors.pipe(
|
||||||
Stream.changes,
|
Stream.changes,
|
||||||
Stream.tap(Console.error),
|
Stream.tap(Console.error),
|
||||||
Stream.tap(() => Effect.sync(() => setOpen(true))),
|
Stream.tap(() => Effect.sync(() => setOpen(true))),
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ 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 { AppQueryClient, AppQueryErrorHandler } from "./query"
|
|
||||||
import { RootContext } from "./reffuse"
|
import { RootContext } from "./reffuse"
|
||||||
import { routeTree } from "./routeTree.gen"
|
import { routeTree } from "./routeTree.gen"
|
||||||
|
import { AppQueryClient, AppQueryErrorHandler } from "./services"
|
||||||
|
|
||||||
|
|
||||||
const layer = Layer.empty.pipe(
|
const layer = Layer.empty.pipe(
|
||||||
Layer.provideMerge(AppQueryClient.Default),
|
Layer.provideMerge(AppQueryClient.AppQueryClient.Default),
|
||||||
Layer.provideMerge(AppQueryErrorHandler.Default),
|
Layer.provideMerge(AppQueryErrorHandler.AppQueryErrorHandler.Default),
|
||||||
Layer.provideMerge(Clipboard.layer),
|
Layer.provideMerge(Clipboard.layer),
|
||||||
Layer.provideMerge(Geolocation.layer),
|
Layer.provideMerge(Geolocation.layer),
|
||||||
Layer.provideMerge(Permissions.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 { LazyRefExtension } from "@reffuse/extension-lazyref"
|
||||||
import { QueryExtension } from "@reffuse/extension-query"
|
import { QueryExtension } from "@reffuse/extension-query"
|
||||||
import { Reffuse, ReffuseContext } from "reffuse"
|
import { Reffuse, ReffuseContext } from "reffuse"
|
||||||
import { AppQueryClient } from "./query"
|
import { AppQueryClient, AppQueryErrorHandler } from "./services"
|
||||||
|
|
||||||
|
|
||||||
export const RootContext = ReffuseContext.make<
|
export const RootContext = ReffuseContext.make<
|
||||||
| AppQueryClient
|
| AppQueryClient.AppQueryClient
|
||||||
|
| AppQueryErrorHandler.AppQueryErrorHandler
|
||||||
| Clipboard.Clipboard
|
| Clipboard.Clipboard
|
||||||
| Geolocation.Geolocation
|
| Geolocation.Geolocation
|
||||||
| Permissions.Permissions
|
| 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",
|
"name": "@reffuse/extension-query",
|
||||||
"version": "0.1.4",
|
"version": "0.1.5",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"files": [
|
"files": [
|
||||||
"./README.md",
|
"./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 type { Mutable } from "effect/Types"
|
||||||
import * as QueryErrorHandler from "./QueryErrorHandler.js"
|
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"
|
const id = "@reffuse/extension-query/QueryClient"
|
||||||
|
|
||||||
export type TagClassShape<FallbackA, HandledE> = Context.TagClassShape<typeof id, QueryClient<FallbackA, HandledE>>
|
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 const makeGenericTagClass = <FallbackA = never, HandledE = never>(): GenericTagClass<FallbackA, HandledE> => Context.Tag(id)()
|
||||||
|
|
||||||
|
|
||||||
export interface ServiceProps<EH, FallbackA, HandledE> {
|
export interface ServiceProps<FallbackA = never, HandledE = never, E = never, R = never> {
|
||||||
readonly ErrorHandler?: Context.Tag<EH, QueryErrorHandler.QueryErrorHandler<FallbackA, HandledE>>
|
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,
|
Self,
|
||||||
typeof id,
|
typeof id,
|
||||||
QueryClient<FallbackA, HandledE>
|
QueryClient<FallbackA, HandledE>
|
||||||
> {
|
> {
|
||||||
readonly Default: Layer.Layer<
|
readonly Default: Layer.Layer<Self, E, R>
|
||||||
Self | (EH extends QueryErrorHandler.DefaultQueryErrorHandler ? EH : never),
|
|
||||||
never,
|
|
||||||
EH extends QueryErrorHandler.DefaultQueryErrorHandler ? never : EH
|
|
||||||
>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Service = <Self>() => (
|
export const Service = <Self>() => (
|
||||||
<
|
<FallbackA = never, HandledE = never, E = never, R = never>(
|
||||||
EH = QueryErrorHandler.DefaultQueryErrorHandler,
|
props?: ServiceProps<FallbackA, HandledE, E, R>
|
||||||
FallbackA = QueryErrorHandler.Fallback<Context.Tag.Service<QueryErrorHandler.DefaultQueryErrorHandler>>,
|
): ServiceResult<Self, FallbackA, HandledE, E, R> => {
|
||||||
HandledE = QueryErrorHandler.Error<Context.Tag.Service<QueryErrorHandler.DefaultQueryErrorHandler>>,
|
const TagClass = Context.Tag(id)() as ServiceResult<Self, FallbackA, HandledE, E, R>
|
||||||
>(
|
|
||||||
props?: ServiceProps<EH, FallbackA, HandledE>
|
|
||||||
): ServiceResult<Self, EH, FallbackA, HandledE> => {
|
|
||||||
const TagClass = Context.Tag(id)() as ServiceResult<Self, EH, FallbackA, HandledE>
|
|
||||||
|
|
||||||
(TagClass as Mutable<typeof TagClass>).Default = Layer.effect(TagClass, Effect.Do.pipe(
|
(TagClass as Mutable<typeof TagClass>).Default = Layer.effect(TagClass, Effect.flatMap(
|
||||||
Effect.bind("errorHandler", () =>
|
props?.errorHandler ?? QueryErrorHandler.make<never>()(identity),
|
||||||
(props?.ErrorHandler ?? QueryErrorHandler.DefaultQueryErrorHandler) as Effect.Effect<
|
errorHandler => make({ errorHandler }),
|
||||||
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>)
|
|
||||||
)
|
|
||||||
|
|
||||||
return TagClass
|
return TagClass
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Cause, Context, Effect, identity, Layer, PubSub, Stream } from "effect"
|
import { Cause, Effect, PubSub, Stream } from "effect"
|
||||||
import type { Mutable } from "effect/Types"
|
|
||||||
|
|
||||||
|
|
||||||
export interface QueryErrorHandler<FallbackA, HandledE> {
|
export interface QueryErrorHandler<FallbackA, HandledE> {
|
||||||
@@ -11,31 +10,14 @@ 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 type Error<T> = T extends QueryErrorHandler<any, infer E> ? E : never
|
||||||
|
|
||||||
|
|
||||||
export interface ServiceResult<
|
export const make = <HandledE = never>() => (
|
||||||
Self,
|
<FallbackA>(
|
||||||
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,
|
|
||||||
f: (
|
f: (
|
||||||
self: Effect.Effect<never, HandledE>,
|
self: Effect.Effect<never, HandledE>,
|
||||||
failure: (failure: HandledE) => Effect.Effect<never>,
|
failure: (failure: HandledE) => Effect.Effect<never>,
|
||||||
defect: (defect: unknown) => Effect.Effect<never>,
|
defect: (defect: unknown) => Effect.Effect<never>,
|
||||||
) => Effect.Effect<FallbackA>,
|
) => Effect.Effect<FallbackA>
|
||||||
): ServiceResult<Self, Id, FallbackA, HandledE> => {
|
): Effect.Effect<QueryErrorHandler<FallbackA, HandledE>> => Effect.gen(function*() {
|
||||||
const TagClass = Context.Tag(id)() as ServiceResult<Self, Id, FallbackA, HandledE>
|
|
||||||
|
|
||||||
(TagClass as Mutable<typeof TagClass>).Default = Layer.effect(TagClass, Effect.gen(function*() {
|
|
||||||
const pubsub = yield* PubSub.unbounded<Cause.Cause<HandledE>>()
|
const pubsub = yield* PubSub.unbounded<Cause.Cause<HandledE>>()
|
||||||
const errors = Stream.fromPubSub(pubsub)
|
const errors = Stream.fromPubSub(pubsub)
|
||||||
|
|
||||||
@@ -43,23 +25,16 @@ export const Service = <Self, HandledE = never>() => (
|
|||||||
self: Effect.Effect<A, E, R>
|
self: Effect.Effect<A, E, R>
|
||||||
): Effect.Effect<A | FallbackA, Exclude<E, HandledE>, R> => f(
|
): Effect.Effect<A | FallbackA, Exclude<E, HandledE>, R> => f(
|
||||||
self as unknown as Effect.Effect<never, HandledE, never>,
|
self as unknown as Effect.Effect<never, HandledE, never>,
|
||||||
(failure: HandledE) => PubSub.publish(pubsub, Cause.fail(failure)).pipe(
|
(failure: HandledE) => Effect.andThen(
|
||||||
Effect.andThen(Effect.failCause(Cause.empty))
|
PubSub.publish(pubsub, Cause.fail(failure)),
|
||||||
|
Effect.failCause(Cause.empty),
|
||||||
),
|
),
|
||||||
(defect: unknown) => PubSub.publish(pubsub, Cause.die(defect)).pipe(
|
(defect: unknown) => Effect.andThen(
|
||||||
Effect.andThen(Effect.failCause(Cause.empty))
|
PubSub.publish(pubsub, Cause.die(defect)),
|
||||||
|
Effect.failCause(Cause.empty),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return { errors, handle }
|
return { errors, handle }
|
||||||
}))
|
})
|
||||||
|
|
||||||
return TagClass
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
export class DefaultQueryErrorHandler extends Service<DefaultQueryErrorHandler>()(
|
|
||||||
"@reffuse/extension-query/DefaultQueryErrorHandler",
|
|
||||||
identity,
|
|
||||||
) {}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user