Compare commits
6 Commits
16f6ca0f29
...
b2c9c2c451
| Author | SHA1 | Date | |
|---|---|---|---|
| b2c9c2c451 | |||
|
|
cfd3028218 | ||
|
|
f09c6e3a1c | ||
|
|
edf06b5f99 | ||
|
|
cb5e3a84ae | ||
|
|
94ba0b0c5e |
4
bun.lock
4
bun.lock
@@ -6,7 +6,7 @@
|
|||||||
"name": "@effect-fc/monorepo",
|
"name": "@effect-fc/monorepo",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "^2.3.8",
|
"@biomejs/biome": "^2.3.8",
|
||||||
"@effect/language-service": "^0.60.0",
|
"@effect/language-service": "^0.62.0",
|
||||||
"@types/bun": "^1.3.3",
|
"@types/bun": "^1.3.3",
|
||||||
"npm-check-updates": "^19.1.2",
|
"npm-check-updates": "^19.1.2",
|
||||||
"npm-sort": "^0.0.4",
|
"npm-sort": "^0.0.4",
|
||||||
@@ -131,7 +131,7 @@
|
|||||||
|
|
||||||
"@effect-fc/example": ["@effect-fc/example@workspace:packages/example"],
|
"@effect-fc/example": ["@effect-fc/example@workspace:packages/example"],
|
||||||
|
|
||||||
"@effect/language-service": ["@effect/language-service@0.60.0", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-elJDWHG5Naq3OkilPt9ZRn56JfSA3MhXUIlDx9RWJeScHm96kZ+HkZ3eFBxqROzXwD6Q2DTtFctFwOM0+QLZEA=="],
|
"@effect/language-service": ["@effect/language-service@0.62.4", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-IPe/oGOILtzUIUdhhaz6e2JcnGymPADnjI03f1xOe+LaPLDg/AsRmkY87jhbtb/6qg8NVzlU+ZK4s0JoIMW/yQ=="],
|
||||||
|
|
||||||
"@effect/platform": ["@effect/platform@0.93.6", "", { "dependencies": { "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.4", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.19.8" } }, "sha512-I5lBGQWzWXP4zlIdPs7z7WHmEFVBQhn+74emr/h16GZX96EEJ6I1rjGaKyZF7mtukbMuo9wEckDPssM8vskZ/w=="],
|
"@effect/platform": ["@effect/platform@0.93.6", "", { "dependencies": { "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.4", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.19.8" } }, "sha512-I5lBGQWzWXP4zlIdPs7z7WHmEFVBQhn+74emr/h16GZX96EEJ6I1rjGaKyZF7mtukbMuo9wEckDPssM8vskZ/w=="],
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "^2.3.8",
|
"@biomejs/biome": "^2.3.8",
|
||||||
"@effect/language-service": "^0.60.0",
|
"@effect/language-service": "^0.62.0",
|
||||||
"@types/bun": "^1.3.3",
|
"@types/bun": "^1.3.3",
|
||||||
"npm-check-updates": "^19.1.2",
|
"npm-check-updates": "^19.1.2",
|
||||||
"npm-sort": "^0.0.4",
|
"npm-sort": "^0.0.4",
|
||||||
|
|||||||
@@ -76,13 +76,14 @@ extends Pipeable.Class() implements Form<A, I, R, MA, ME, MR, MP> {
|
|||||||
field<const P extends PropertyPath.Paths<I>>(
|
field<const P extends PropertyPath.Paths<I>>(
|
||||||
path: P
|
path: P
|
||||||
): Effect.Effect<FormField<PropertyPath.ValueFromPath<A, P>, PropertyPath.ValueFromPath<I, P>>> {
|
): Effect.Effect<FormField<PropertyPath.ValueFromPath<A, P>, PropertyPath.ValueFromPath<I, P>>> {
|
||||||
|
const key = new FormFieldKey(path)
|
||||||
return this.fieldCache.pipe(
|
return this.fieldCache.pipe(
|
||||||
Effect.map(HashMap.get(new FormFieldKey(path))),
|
Effect.map(HashMap.get(key)),
|
||||||
Effect.flatMap(Option.match({
|
Effect.flatMap(Option.match({
|
||||||
onSome: v => Effect.succeed(v as FormField<PropertyPath.ValueFromPath<A, P>, PropertyPath.ValueFromPath<I, P>>),
|
onSome: v => Effect.succeed(v as FormField<PropertyPath.ValueFromPath<A, P>, PropertyPath.ValueFromPath<I, P>>),
|
||||||
onNone: () => Effect.tap(
|
onNone: () => Effect.tap(
|
||||||
Effect.succeed(makeFormField(this as Form<A, I, R, MA, ME, MR, MP>, path)),
|
Effect.succeed(makeFormField(this as Form<A, I, R, MA, ME, MR, MP>, path)),
|
||||||
v => Ref.update(this.fieldCache, HashMap.set(new FormFieldKey(path), v as FormField<unknown, unknown>)),
|
v => Ref.update(this.fieldCache, HashMap.set(key, v as FormField<unknown, unknown>)),
|
||||||
),
|
),
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
@@ -120,7 +121,7 @@ extends Pipeable.Class() implements Form<A, I, R, MA, ME, MR, MP> {
|
|||||||
|
|
||||||
export const isForm = (u: unknown): u is Form<unknown, unknown, unknown, unknown, unknown, unknown> => Predicate.hasProperty(u, FormTypeId)
|
export const isForm = (u: unknown): u is Form<unknown, unknown, unknown, unknown, unknown, unknown> => Predicate.hasProperty(u, FormTypeId)
|
||||||
|
|
||||||
export namespace make {
|
export declare namespace make {
|
||||||
export interface Options<in out A, in out I = A, in out R = never, in out MA = void, in out ME = never, in out MR = never, in out MP = never>
|
export interface Options<in out A, in out I = A, in out R = never, in out MA = void, in out ME = never, in out MR = never, in out MP = never>
|
||||||
extends Mutation.make.Options<
|
extends Mutation.make.Options<
|
||||||
readonly [value: NoInfer<A>, form: Form<NoInfer<A>, NoInfer<I>, NoInfer<R>, unknown, unknown, unknown>],
|
readonly [value: NoInfer<A>, form: Form<NoInfer<A>, NoInfer<I>, NoInfer<R>, unknown, unknown, unknown>],
|
||||||
@@ -202,7 +203,7 @@ export const run = <A, I, R, MA, ME, MR, MP>(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace service {
|
export declare namespace service {
|
||||||
export interface Options<in out A, in out I = A, in out R = never, in out MA = void, in out ME = never, in out MR = never, in out MP = never>
|
export interface Options<in out A, in out I = A, in out R = never, in out MA = void, in out ME = never, in out MR = never, in out MP = never>
|
||||||
extends make.Options<A, I, R, MA, ME, MR, MP> {}
|
extends make.Options<A, I, R, MA, ME, MR, MP> {}
|
||||||
}
|
}
|
||||||
@@ -259,7 +260,7 @@ class FormFieldKey implements Equal.Equal {
|
|||||||
return isFormFieldKey(that) && PropertyPath.equivalence(this.path, that.path)
|
return isFormFieldKey(that) && PropertyPath.equivalence(this.path, that.path)
|
||||||
}
|
}
|
||||||
[Hash.symbol]() {
|
[Hash.symbol]() {
|
||||||
return 0
|
return Hash.array(this.path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { type Cause, type Context, Effect, Fiber, identity, Option, Pipeable, Predicate, type Scope, Stream, type Subscribable, SubscriptionRef } from "effect"
|
import { type Cause, type Context, type Duration, Effect, Fiber, identity, Option, Pipeable, Predicate, type Scope, Stream, type Subscribable, SubscriptionRef } from "effect"
|
||||||
|
import * as QueryClient from "./QueryClient.js"
|
||||||
import * as Result from "./Result.js"
|
import * as Result from "./Result.js"
|
||||||
|
|
||||||
|
|
||||||
@@ -9,11 +10,13 @@ export interface Query<in out K extends Query.AnyKey, in out A, in out E = never
|
|||||||
extends Pipeable.Pipeable {
|
extends Pipeable.Pipeable {
|
||||||
readonly [QueryTypeId]: QueryTypeId
|
readonly [QueryTypeId]: QueryTypeId
|
||||||
|
|
||||||
readonly context: Context.Context<Scope.Scope | R>
|
readonly context: Context.Context<Scope.Scope | QueryClient.QueryClient | R>
|
||||||
readonly key: Stream.Stream<K>
|
readonly key: Stream.Stream<K>
|
||||||
readonly f: (key: K) => Effect.Effect<A, E, R>
|
readonly f: (key: K) => Effect.Effect<A, E, R>
|
||||||
readonly initialProgress: P
|
readonly initialProgress: P
|
||||||
|
|
||||||
|
readonly staleTime: Duration.DurationInput
|
||||||
|
|
||||||
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>>>
|
||||||
readonly result: Subscribable.Subscribable<Result.Result<A, E, P>>
|
readonly result: Subscribable.Subscribable<Result.Result<A, E, P>>
|
||||||
@@ -35,11 +38,13 @@ extends Pipeable.Class() implements Query<K, A, E, R, P> {
|
|||||||
readonly [QueryTypeId]: QueryTypeId = QueryTypeId
|
readonly [QueryTypeId]: QueryTypeId = QueryTypeId
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly context: Context.Context<Scope.Scope | NoInfer<R>>,
|
readonly context: Context.Context<Scope.Scope | QueryClient.QueryClient | R>,
|
||||||
readonly key: Stream.Stream<K>,
|
readonly key: Stream.Stream<K>,
|
||||||
readonly f: (key: K) => Effect.Effect<A, E, R>,
|
readonly f: (key: K) => Effect.Effect<A, E, R>,
|
||||||
readonly initialProgress: P,
|
readonly initialProgress: P,
|
||||||
|
|
||||||
|
readonly staleTime: Duration.DurationInput,
|
||||||
|
|
||||||
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>>>,
|
||||||
readonly result: SubscriptionRef.SubscriptionRef<Result.Result<A, E, P>>,
|
readonly result: SubscriptionRef.SubscriptionRef<Result.Result<A, E, P>>,
|
||||||
@@ -147,6 +152,7 @@ export declare namespace make {
|
|||||||
readonly key: Stream.Stream<K>
|
readonly key: Stream.Stream<K>
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,14 +161,18 @@ export const make = Effect.fnUntraced(function* <K extends Query.AnyKey, A, E =
|
|||||||
): Effect.fn.Return<
|
): Effect.fn.Return<
|
||||||
Query<K, A, E, Result.forkEffect.OutputContext<A, E, R, P>, P>,
|
Query<K, A, E, Result.forkEffect.OutputContext<A, E, R, P>, P>,
|
||||||
never,
|
never,
|
||||||
Scope.Scope | Result.forkEffect.OutputContext<A, E, R, P>
|
Scope.Scope | QueryClient.QueryClient | Result.forkEffect.OutputContext<A, E, R, P>
|
||||||
> {
|
> {
|
||||||
|
const client = yield* QueryClient.QueryClient
|
||||||
|
|
||||||
return new QueryImpl(
|
return new QueryImpl(
|
||||||
yield* Effect.context<Scope.Scope | Result.forkEffect.OutputContext<A, E, R, P>>(),
|
yield* Effect.context<Scope.Scope | QueryClient.QueryClient | Result.forkEffect.OutputContext<A, E, R, P>>(),
|
||||||
options.key,
|
options.key,
|
||||||
options.f as any,
|
options.f as any,
|
||||||
options.initialProgress as P,
|
options.initialProgress as P,
|
||||||
|
|
||||||
|
options.staleTime ?? client.defaultStaleTime,
|
||||||
|
|
||||||
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>>()),
|
||||||
yield* SubscriptionRef.make(Result.initial<A, E, P>()),
|
yield* SubscriptionRef.make(Result.initial<A, E, P>()),
|
||||||
@@ -176,7 +186,7 @@ export const service = <K extends Query.AnyKey, A, E = never, R = never, P = nev
|
|||||||
): Effect.Effect<
|
): Effect.Effect<
|
||||||
Query<K, A, E, Result.forkEffect.OutputContext<A, E, R, P>, P>,
|
Query<K, A, E, Result.forkEffect.OutputContext<A, E, R, P>, P>,
|
||||||
never,
|
never,
|
||||||
Scope.Scope | Result.forkEffect.OutputContext<A, E, R, P>
|
Scope.Scope | QueryClient.QueryClient | Result.forkEffect.OutputContext<A, E, R, P>
|
||||||
> => Effect.tap(
|
> => Effect.tap(
|
||||||
make(options),
|
make(options),
|
||||||
query => Effect.forkScoped(run(query)),
|
query => Effect.forkScoped(run(query)),
|
||||||
|
|||||||
@@ -1,43 +1,107 @@
|
|||||||
import { Equal, Equivalence, Hash, type HashMap, Pipeable, Predicate, type Ref } from "effect"
|
import { type DateTime, type Duration, Effect, Equal, Equivalence, Hash, HashMap, Pipeable, Predicate, type Scope, SubscriptionRef } from "effect"
|
||||||
import type * as Query from "./Query.js"
|
import type * as Query from "./Query.js"
|
||||||
import type * as Result from "./Result.js"
|
import type * as Result from "./Result.js"
|
||||||
|
|
||||||
|
|
||||||
export const QueryClientTypeId: unique symbol = Symbol.for("@effect-fc/QueryClient/QueryClient")
|
export const QueryClientServiceTypeId: unique symbol = Symbol.for("@effect-fc/QueryClient/QueryClientServiceTypeId")
|
||||||
export type QueryClientTypeId = typeof QueryClientTypeId
|
export type QueryClientServiceTypeId = typeof QueryClientServiceTypeId
|
||||||
|
|
||||||
export interface QueryClient extends Pipeable.Pipeable {
|
export interface QueryClientService extends Pipeable.Pipeable {
|
||||||
readonly [QueryClientTypeId]: QueryClientTypeId
|
readonly [QueryClientServiceTypeId]: QueryClientServiceTypeId
|
||||||
|
readonly cache: SubscriptionRef.SubscriptionRef<HashMap.HashMap<QueryClientCacheKey, QueryClientCacheEntry>>
|
||||||
readonly cache: Ref.Ref<HashMap.HashMap<Query.Query.AnyKey, Result.Final<unknown, unknown, unknown>>>
|
readonly gcTime: Duration.DurationInput
|
||||||
|
readonly defaultStaleTime: Duration.DurationInput
|
||||||
}
|
}
|
||||||
|
|
||||||
export class QueryClientImpl extends Pipeable.Class() implements QueryClient {
|
export class QueryClient extends Effect.Service<QueryClient>()("@effect-fc/QueryClient/QueryClient", {
|
||||||
readonly [QueryClientTypeId]: QueryClientTypeId = QueryClientTypeId
|
scoped: Effect.suspend(() => service())
|
||||||
|
}) {}
|
||||||
|
|
||||||
|
export class QueryClientServiceImpl
|
||||||
|
extends Pipeable.Class()
|
||||||
|
implements QueryClientService {
|
||||||
|
readonly [QueryClientServiceTypeId]: QueryClientServiceTypeId = QueryClientServiceTypeId
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly cache: Ref.Ref<HashMap.HashMap<Query.Query.AnyKey, Result.Final<unknown, unknown, unknown>>>
|
readonly cache: SubscriptionRef.SubscriptionRef<HashMap.HashMap<QueryClientCacheKey, QueryClientCacheEntry>>,
|
||||||
|
readonly gcTime: Duration.DurationInput,
|
||||||
|
readonly defaultStaleTime: Duration.DurationInput,
|
||||||
|
readonly runSemaphore: Effect.Semaphore,
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isQueryClient = (u: unknown): u is QueryClient => Predicate.hasProperty(u, QueryClientTypeId)
|
export const isQueryClientService = (u: unknown): u is QueryClientService => Predicate.hasProperty(u, QueryClientServiceTypeId)
|
||||||
|
|
||||||
|
export declare namespace make {
|
||||||
const QueryClientCacheKeyTypeId: unique symbol = Symbol.for("@effect-fc/QueryClient/QueryClientCacheKey")
|
export interface Options {
|
||||||
type QueryClientCacheKeyTypeId = typeof QueryClientCacheKeyTypeId
|
readonly gcTime?: Duration.DurationInput
|
||||||
|
readonly defaultStaleTime?: Duration.DurationInput
|
||||||
class QueryClientCacheKey implements Equal.Equal {
|
|
||||||
readonly [QueryClientCacheKeyTypeId]: QueryClientCacheKeyTypeId = QueryClientCacheKeyTypeId
|
|
||||||
constructor(readonly key: Query.Query.AnyKey) {}
|
|
||||||
|
|
||||||
[Equal.symbol](that: Equal.Equal) {
|
|
||||||
return isQueryClientKey(that) && Equivalence.array(Equal.equivalence())(this.key, that.key)
|
|
||||||
}
|
|
||||||
[Hash.symbol]() {
|
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isQueryClientKey = (u: unknown): u is QueryClientCacheKey => Predicate.hasProperty(u, QueryClientCacheKeyTypeId)
|
export const make = Effect.fnUntraced(function* (options: make.Options = {}): Effect.fn.Return<QueryClientService> {
|
||||||
|
return new QueryClientServiceImpl(
|
||||||
|
yield* SubscriptionRef.make(HashMap.empty<QueryClientCacheKey, QueryClientCacheEntry>()),
|
||||||
|
options.gcTime ?? "5 minutes",
|
||||||
|
options.defaultStaleTime ?? "0 minutes",
|
||||||
|
yield* Effect.makeSemaphore(1),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export const run = (_self: QueryClientService): Effect.Effect<void> => Effect.void
|
||||||
|
|
||||||
|
export declare namespace service {
|
||||||
|
export interface Options extends make.Options {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const service = (options?: service.Options): Effect.Effect<QueryClientService, never, Scope.Scope> => Effect.tap(
|
||||||
|
make(options),
|
||||||
|
client => Effect.forkScoped(run(client)),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
export const QueryClientCacheKeyTypeId: unique symbol = Symbol.for("@effect-fc/QueryClient/QueryClientCacheKey")
|
||||||
|
export type QueryClientCacheKeyTypeId = typeof QueryClientCacheKeyTypeId
|
||||||
|
|
||||||
|
export class QueryClientCacheKey
|
||||||
|
extends Pipeable.Class()
|
||||||
|
implements Pipeable.Pipeable, Equal.Equal {
|
||||||
|
readonly [QueryClientCacheKeyTypeId]: QueryClientCacheKeyTypeId = QueryClientCacheKeyTypeId
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
readonly key: Query.Query.AnyKey,
|
||||||
|
readonly f: (key: Query.Query.AnyKey) => Effect.Effect<unknown, unknown, unknown>,
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
[Equal.symbol](that: Equal.Equal) {
|
||||||
|
return isQueryClientCacheKey(that) && Equivalence.array(Equal.equivalence())(this.key, that.key) && Equivalence.strict()(this.f, that.f)
|
||||||
|
}
|
||||||
|
[Hash.symbol]() {
|
||||||
|
return Hash.combine(Hash.hash(this.f))(Hash.array(this.key))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isQueryClientCacheKey = (u: unknown): u is QueryClientCacheKey => Predicate.hasProperty(u, QueryClientCacheKeyTypeId)
|
||||||
|
|
||||||
|
|
||||||
|
export const QueryClientCacheEntryTypeId: unique symbol = Symbol.for("@effect-fc/QueryClient/QueryClientCacheEntry")
|
||||||
|
export type QueryClientCacheEntryTypeId = typeof QueryClientCacheEntryTypeId
|
||||||
|
|
||||||
|
export class QueryClientCacheEntry
|
||||||
|
extends Pipeable.Class()
|
||||||
|
implements Pipeable.Pipeable {
|
||||||
|
readonly [QueryClientCacheEntryTypeId]: QueryClientCacheEntryTypeId = QueryClientCacheEntryTypeId
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
readonly result: Result.Final<unknown, unknown, unknown>,
|
||||||
|
readonly createdAt: DateTime.DateTime,
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isQueryClientCacheEntry = (u: unknown): u is QueryClientCacheEntry => Predicate.hasProperty(u, QueryClientCacheEntryTypeId)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Effect, Layer, ManagedRuntime, Predicate, Runtime, Scope } from "effect
|
|||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import * as Component from "./Component.js"
|
import * as Component from "./Component.js"
|
||||||
import * as ErrorObserver from "./ErrorObserver.js"
|
import * as ErrorObserver from "./ErrorObserver.js"
|
||||||
|
import * as QueryClient from "./QueryClient.js"
|
||||||
|
|
||||||
|
|
||||||
export const TypeId: unique symbol = Symbol.for("@effect-fc/ReactRuntime/ReactRuntime")
|
export const TypeId: unique symbol = Symbol.for("@effect-fc/ReactRuntime/ReactRuntime")
|
||||||
@@ -17,9 +18,14 @@ export interface ReactRuntime<R, ER> {
|
|||||||
|
|
||||||
const ReactRuntimeProto = Object.freeze({ [TypeId]: TypeId } as const)
|
const ReactRuntimeProto = Object.freeze({ [TypeId]: TypeId } as const)
|
||||||
|
|
||||||
export const Prelude: Layer.Layer<Component.ScopeMap | ErrorObserver.ErrorObserver> = Layer.mergeAll(
|
export const Prelude: Layer.Layer<
|
||||||
|
| Component.ScopeMap
|
||||||
|
| ErrorObserver.ErrorObserver
|
||||||
|
| QueryClient.QueryClient
|
||||||
|
> = Layer.mergeAll(
|
||||||
Component.ScopeMap.Default,
|
Component.ScopeMap.Default,
|
||||||
ErrorObserver.layer,
|
ErrorObserver.layer,
|
||||||
|
QueryClient.QueryClient.Default,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,18 +4,19 @@ import { Cause, Context, Data, Effect, Equal, Exit, type Fiber, Hash, Layer, Mat
|
|||||||
export const ResultTypeId: unique symbol = Symbol.for("@effect-fc/Result/Result")
|
export const ResultTypeId: unique symbol = Symbol.for("@effect-fc/Result/Result")
|
||||||
export type ResultTypeId = typeof ResultTypeId
|
export type ResultTypeId = typeof ResultTypeId
|
||||||
|
|
||||||
export type Result<A, E = never, P = never> = (
|
export type Result<A, E = never, P = never> = ResultState<A, E, P> & (ResultState<A, E, P> | Optimistic)
|
||||||
|
type ResultState<A, E = never, P = never> = (
|
||||||
| Initial
|
| Initial
|
||||||
| Running<P>
|
| Running<P>
|
||||||
| Final<A, E, P>
|
| Final<A, E, P>
|
||||||
)
|
)
|
||||||
|
|
||||||
export type Final<A, E = never, P = never> = (
|
export type Final<A, E = never, P = never> = (
|
||||||
| Success<A>
|
& FinalState<A, E>
|
||||||
| (Success<A> & Refreshing<P>)
|
& (FinalState<A, E> | Refreshing<P>)
|
||||||
| Failure<A, E>
|
& (FinalState<A, E> | Optimistic)
|
||||||
| (Failure<A, E> & Refreshing<P>)
|
|
||||||
)
|
)
|
||||||
|
type FinalState<A, E = never> = Success<A> | Failure<A, E>
|
||||||
|
|
||||||
export namespace Result {
|
export namespace Result {
|
||||||
export interface Prototype extends Pipeable.Pipeable, Equal.Equal {
|
export interface Prototype extends Pipeable.Pipeable, Equal.Equal {
|
||||||
@@ -52,6 +53,10 @@ export interface Refreshing<P = never> {
|
|||||||
readonly progress: P
|
readonly progress: P
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Optimistic {
|
||||||
|
readonly optimistic: true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const ResultPrototype = Object.freeze({
|
const ResultPrototype = Object.freeze({
|
||||||
...Pipeable.Prototype,
|
...Pipeable.Prototype,
|
||||||
@@ -106,6 +111,7 @@ export const isRunning = (u: unknown): u is Running<unknown> => isResult(u) && u
|
|||||||
export const isSuccess = (u: unknown): u is Success<unknown> => isResult(u) && u._tag === "Success"
|
export const isSuccess = (u: unknown): u is Success<unknown> => isResult(u) && u._tag === "Success"
|
||||||
export const isFailure = (u: unknown): u is Failure<unknown, unknown> => isResult(u) && u._tag === "Failure"
|
export const isFailure = (u: unknown): u is Failure<unknown, unknown> => isResult(u) && u._tag === "Failure"
|
||||||
export const isRefreshing = (u: unknown): u is Refreshing<unknown> => isResult(u) && Predicate.hasProperty(u, "refreshing") && u.refreshing
|
export const isRefreshing = (u: unknown): u is Refreshing<unknown> => isResult(u) && Predicate.hasProperty(u, "refreshing") && u.refreshing
|
||||||
|
export const isOptimistic = (u: unknown): u is Optimistic => isResult(u) && Predicate.hasProperty(u, "optimistic") && u.optimistic
|
||||||
|
|
||||||
export const initial: {
|
export const initial: {
|
||||||
(): Initial
|
(): Initial
|
||||||
@@ -131,6 +137,13 @@ export const refreshing = <R extends Success<any> | Failure<any, any>, P = never
|
|||||||
Object.getPrototypeOf(result),
|
Object.getPrototypeOf(result),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export const optimistic = <R extends Success<any> | Failure<any, any>>(
|
||||||
|
result: R
|
||||||
|
): Omit<R, keyof Optimistic> & Optimistic => Object.setPrototypeOf(
|
||||||
|
Object.assign({}, result, { optimistic: true }),
|
||||||
|
Object.getPrototypeOf(result),
|
||||||
|
)
|
||||||
|
|
||||||
export const fromExit = <A, E>(
|
export const fromExit = <A, E>(
|
||||||
exit: Exit.Exit<A, E>,
|
exit: Exit.Exit<A, E>,
|
||||||
previousSuccess?: Success<NoInfer<A>>,
|
previousSuccess?: Success<NoInfer<A>>,
|
||||||
|
|||||||
@@ -26,8 +26,8 @@
|
|||||||
"vite": "^7.2.6"
|
"vite": "^7.2.6"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@effect/platform": "^0.93.6",
|
"@effect/platform": "^0.94.0",
|
||||||
"@effect/platform-browser": "^0.73.0",
|
"@effect/platform-browser": "^0.74.0",
|
||||||
"@radix-ui/themes": "^3.2.1",
|
"@radix-ui/themes": "^3.2.1",
|
||||||
"@typed/id": "^0.17.2",
|
"@typed/id": "^0.17.2",
|
||||||
"effect": "^3.19.8",
|
"effect": "^3.19.8",
|
||||||
|
|||||||
Reference in New Issue
Block a user