Compare commits

...

3 Commits

Author SHA1 Message Date
610c1bf759 Update dependency @effect/language-service to ^0.56.0
All checks were successful
Lint / lint (push) Successful in 39s
Test build / test-build (pull_request) Successful in 18s
2025-11-16 01:29:45 +01:00
Julien Valverdé
25d5defdca Add Query module
All checks were successful
Lint / lint (push) Successful in 12s
2025-11-15 05:04:34 +01:00
Julien Valverdé
f78b9f318a Add PubSub module
All checks were successful
Lint / lint (push) Successful in 40s
2025-11-15 01:19:14 +01:00
6 changed files with 50 additions and 27 deletions

View File

@@ -1,11 +1,12 @@
{ {
"lockfileVersion": 1, "lockfileVersion": 1,
"configVersion": 0,
"workspaces": { "workspaces": {
"": { "": {
"name": "@effect-fc/monorepo", "name": "@effect-fc/monorepo",
"devDependencies": { "devDependencies": {
"@biomejs/biome": "^2.3.4", "@biomejs/biome": "^2.3.4",
"@effect/language-service": "^0.55.3", "@effect/language-service": "^0.56.0",
"@types/bun": "^1.3.2", "@types/bun": "^1.3.2",
"npm-check-updates": "^19.1.2", "npm-check-updates": "^19.1.2",
"npm-sort": "^0.0.4", "npm-sort": "^0.0.4",
@@ -130,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.55.3", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-dteG8LvrQ5ClN76pFzqgEOuY5sXVqM0OrZLqFXrdtlpUF8/6/XZwk1mPdDnEVhvf5iQawVVvV+ybJoT6Hwy/DA=="], "@effect/language-service": ["@effect/language-service@0.56.0", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-gvJaHoeXMHAoA6+Xyj9Vdq52yDCs+ECLbKpHvxHtdJP/C0D9b3JFEfLjdVuw37zoWcYS856um4rgEYHlW2LSEQ=="],
"@effect/platform": ["@effect/platform@0.93.0", "", { "dependencies": { "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.4", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.19.0" } }, "sha512-VaIv0duA+Dk2h8XYDPxCLCXGbMyd6hwuHUQt9THL1ZEqv1C3Fypg/Gi2UkzRys6TQsSnC9fJbdpMb7haPURYkQ=="], "@effect/platform": ["@effect/platform@0.93.0", "", { "dependencies": { "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.4", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.19.0" } }, "sha512-VaIv0duA+Dk2h8XYDPxCLCXGbMyd6hwuHUQt9THL1ZEqv1C3Fypg/Gi2UkzRys6TQsSnC9fJbdpMb7haPURYkQ=="],

View File

@@ -16,7 +16,7 @@
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "^2.3.4", "@biomejs/biome": "^2.3.4",
"@effect/language-service": "^0.55.3", "@effect/language-service": "^0.56.0",
"@types/bun": "^1.3.2", "@types/bun": "^1.3.2",
"npm-check-updates": "^19.1.2", "npm-check-updates": "^19.1.2",
"npm-sort": "^0.0.4", "npm-sort": "^0.0.4",

View File

@@ -0,0 +1,14 @@
import { Effect, PubSub, type Scope } from "effect"
import type * as React from "react"
import * as Component from "./Component.js"
export const usePubSubFromReactiveValues = Effect.fnUntraced(function* <const A extends React.DependencyList>(
values: A
): Effect.fn.Return<PubSub.PubSub<A>, never, Scope.Scope> {
const pubsub = yield* Component.useOnMount(() => Effect.acquireRelease(PubSub.unbounded<A>(), PubSub.shutdown))
yield* Component.useReactEffect(() => Effect.unlessEffect(PubSub.publish(pubsub, values), PubSub.isShutdown(pubsub)), values)
return pubsub
})
export * from "effect/PubSub"

View File

@@ -0,0 +1,29 @@
import { type Effect, Pipeable, Predicate, type Stream } from "effect"
export const QueryTypeId: unique symbol = Symbol.for("@effect-fc/Query/Query")
export type QueryTypeId = typeof QueryTypeId
export interface Query<in out K extends readonly any[], in out A, in out E = never, out R = never, in out P = never>
extends Pipeable.Pipeable {
readonly [QueryTypeId]: QueryTypeId
readonly key: Stream.Stream<K>
readonly query: (key: K) => Effect.Effect<A, E, R>
readonly initialProgress: P
}
class QueryImpl<in out K extends readonly any[], in out A, in out E = never, out R = never, in out P = never>
extends Pipeable.Class() implements Query<K, A, E, R, P> {
readonly [QueryTypeId]: QueryTypeId = QueryTypeId
constructor(
readonly key: Stream.Stream<K>,
readonly query: (key: K) => Effect.Effect<A, E, R>,
readonly initialProgress: P,
) {
super()
}
}
export const isQuery = (u: unknown): u is Query<unknown[], unknown, unknown, unknown, unknown> => Predicate.hasProperty(u, QueryTypeId)

View File

@@ -1,4 +1,4 @@
import { Effect, Equivalence, Option, PubSub, Ref, type Scope, Stream } from "effect" import { Effect, Equivalence, Option, Stream } from "effect"
import * as React from "react" import * as React from "react"
import * as Component from "./Component.js" import * as Component from "./Component.js"
@@ -30,27 +30,4 @@ export const useStream: {
return reactStateValue as Option.Some<A> return reactStateValue as Option.Some<A>
}) })
export const useStreamFromReactiveValues = Effect.fnUntraced(function* <const A extends React.DependencyList>(
values: A
): Effect.fn.Return<Stream.Stream<A>, never, Scope.Scope> {
const { latest, pubsub, stream } = yield* Component.useOnMount(() => Effect.Do.pipe(
Effect.bind("latest", () => Ref.make(values)),
Effect.bind("pubsub", () => Effect.acquireRelease(PubSub.unbounded<A>(), PubSub.shutdown)),
Effect.let("stream", ({ latest, pubsub }) => latest.pipe(
Effect.flatMap(a => Effect.map(
Stream.fromPubSub(pubsub, { scoped: true }),
s => Stream.concat(Stream.make(a), s),
)),
Stream.unwrapScoped,
)),
))
yield* Component.useReactEffect(() => Ref.set(latest, values).pipe(
Effect.andThen(PubSub.publish(pubsub, values)),
Effect.unlessEffect(PubSub.isShutdown(pubsub)),
), values)
return stream
})
export * from "effect/Stream" export * from "effect/Stream"

View File

@@ -4,6 +4,8 @@ export * as ErrorObserver from "./ErrorObserver.js"
export * as Form from "./Form.js" export * as Form from "./Form.js"
export * as Memoized from "./Memoized.js" export * as Memoized from "./Memoized.js"
export * as PropertyPath from "./PropertyPath.js" export * as PropertyPath from "./PropertyPath.js"
export * as PubSub from "./PubSub.js"
export * as Query from "./Query.js"
export * as ReactRuntime from "./ReactRuntime.js" export * as ReactRuntime from "./ReactRuntime.js"
export * as Result from "./Result.js" export * as Result from "./Result.js"
export * as SetStateAction from "./SetStateAction.js" export * as SetStateAction from "./SetStateAction.js"