From 195cd9f54216aba77dcff7d646159e588ce9e142 Mon Sep 17 00:00:00 2001 From: Patrick Roza Date: Fri, 8 Aug 2025 14:41:48 +0200 Subject: [PATCH 1/6] play with effect-atom --- frontend/lib.ts | 11 +++++++++++ frontend/pages/index.vue | 13 +++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 frontend/lib.ts diff --git a/frontend/lib.ts b/frontend/lib.ts new file mode 100644 index 000000000..80b12178d --- /dev/null +++ b/frontend/lib.ts @@ -0,0 +1,11 @@ +import { FetchHttpClient } from "@effect/platform" +import { RpcClient, RpcSerialization } from "@effect/rpc" +import { Layer } from "effect-app" + +export const RpcClientProtocolLayers = (path: string) => + Layer.provideMerge( + RpcClient.layerProtocolHttp({ + url: "http://localhost:3610/rpc" + path, + }).pipe(Layer.provide(RpcSerialization.layerJson)), + FetchHttpClient.layer, + ) diff --git a/frontend/pages/index.vue b/frontend/pages/index.vue index f37215755..5c29f41a8 100644 --- a/frontend/pages/index.vue +++ b/frontend/pages/index.vue @@ -2,6 +2,9 @@ import { HelloWorldRsc } from "#resources" import { buildFormFromSchema } from "@effect-app/vue/form" import { S } from "effect-app" +import { Atom, AtomRpc, useAtomValue } from "@effect-atom/atom-vue" +import { makeRpcGroup } from "effect-app/client" +import { RpcClientProtocolLayers } from "~/lib" class Input extends S.Class("Input")({ title: S.NonEmptyString255, @@ -27,8 +30,14 @@ const makeReq = () => ({ const req = ref(makeReq()) -const helloWorldClient = clientFor(HelloWorldRsc) -const [result] = useSafeQuery(helloWorldClient.GetHelloWorld, req) +const helloWorldRpcs = makeRpcGroup(HelloWorldRsc) +const helloWorldAtom = AtomRpc.make(helloWorldRpcs, { + runtime: Atom.runtime(RpcClientProtocolLayers("/HelloWorld")), +}) + +const result = useAtomValue( + helloWorldAtom.query("HelloWorld.GetHelloWorld", req.value), +) // TODO: make reactive based on `req` // onMounted(() => { // setInterval(() => { From 84f92dea7738df4878c222cae7fe11c3da0630ad Mon Sep 17 00:00:00 2001 From: Patrick Roza Date: Sat, 9 Aug 2025 10:50:31 +0200 Subject: [PATCH 2/6] use new thunk atom --- frontend/pages/index.vue | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/pages/index.vue b/frontend/pages/index.vue index 5c29f41a8..fc8aebdb8 100644 --- a/frontend/pages/index.vue +++ b/frontend/pages/index.vue @@ -35,9 +35,10 @@ const helloWorldAtom = AtomRpc.make(helloWorldRpcs, { runtime: Atom.runtime(RpcClientProtocolLayers("/HelloWorld")), }) -const result = useAtomValue( - helloWorldAtom.query("HelloWorld.GetHelloWorld", req.value), -) // TODO: make reactive based on `req` +const result = useAtomValue(() => { + console.log("Querying HelloWorld.GetHelloWorld with:", req.value) + return helloWorldAtom.query("HelloWorld.GetHelloWorld", req.value) +}) // onMounted(() => { // setInterval(() => { From d769ae0cfda8d015621920b3f3d6e6f6f9fc72d2 Mon Sep 17 00:00:00 2001 From: Patrick Roza Date: Sat, 9 Aug 2025 13:50:36 +0200 Subject: [PATCH 3/6] add global layers to Atom runtime --- frontend/composables/runtime.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/composables/runtime.ts b/frontend/composables/runtime.ts index 9190dd14d..e5639053c 100644 --- a/frontend/composables/runtime.ts +++ b/frontend/composables/runtime.ts @@ -10,6 +10,7 @@ import { HttpClient } from "effect-app/http" import { FetchHttpClient } from "@effect/platform" import { ApiClientFactory } from "effect-app/client/apiClientFactory" import { type useRuntimeConfig } from "nuxt/app" +import { Atom } from "@effect-atom/atom-vue" export const versionMatch = ref(true) @@ -53,7 +54,7 @@ function makeRuntime(feVersion: string, disableTracing: boolean) { clean: () => void } = initializeSync(apiLayers.pipe(Layer.provideMerge(globalLayers))) - //Atom.runtime.addGlobalLayer(globalLayers) + Atom.runtime.addGlobalLayer(globalLayers) return { ...rt, From 2ecf7eda6b3832f8d7682331ef4fd29bafa41eca Mon Sep 17 00:00:00 2001 From: Patrick Roza Date: Sun, 10 Aug 2025 06:21:17 +0200 Subject: [PATCH 4/6] Use `refreshOnWindowFocus` --- frontend/pages/index.vue | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/frontend/pages/index.vue b/frontend/pages/index.vue index fc8aebdb8..cf2f2729b 100644 --- a/frontend/pages/index.vue +++ b/frontend/pages/index.vue @@ -36,8 +36,10 @@ const helloWorldAtom = AtomRpc.make(helloWorldRpcs, { }) const result = useAtomValue(() => { - console.log("Querying HelloWorld.GetHelloWorld with:", req.value) - return helloWorldAtom.query("HelloWorld.GetHelloWorld", req.value) + console.log("Recomputing HelloWorld.GetHelloWorld atom with:", req.value) + return Atom.refreshOnWindowFocus( + helloWorldAtom.query("HelloWorld.GetHelloWorld", req.value), + ) }) // onMounted(() => { @@ -51,7 +53,7 @@ const result = useAtomValue(() => { // }) onMounted(() => { - const t = setInterval(() => (req.value = makeReq()), 5000) + const t = setInterval(() => (req.value = makeReq()), 10_000) return () => clearInterval(t) }) From bf249b5b4c41a0dc5262a70b6aeb9473fa62ea81 Mon Sep 17 00:00:00 2001 From: Patrick Roza Date: Sun, 10 Aug 2025 06:50:49 +0200 Subject: [PATCH 5/6] meh tracing --- frontend/composables/runtime.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/composables/runtime.ts b/frontend/composables/runtime.ts index e5639053c..ac355d7af 100644 --- a/frontend/composables/runtime.ts +++ b/frontend/composables/runtime.ts @@ -81,7 +81,9 @@ const config = (globalThis as any).__NUXT__.config as ReturnType< typeof useRuntimeConfig > const isRemote = config.public.env !== "local-dev" -const disableTracing = !isRemote || !config.public.telemetry +const disableTracing = false // !isRemote || !config.public.telemetry + +console.log({ isRemote, disableTracing }) export const runtime = makeRuntime( config.public.feVersion, From b70f201fbec336aa8aba3a3e078f34061ea18778 Mon Sep 17 00:00:00 2001 From: Patrick Roza Date: Sun, 10 Aug 2025 06:51:04 +0200 Subject: [PATCH 6/6] play with reactivityKeys --- api/src/HelloWorld.controllers.ts | 3 +++ api/src/resources/HelloWorld.ts | 4 ++++ frontend/pages/index.vue | 16 ++++++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/api/src/HelloWorld.controllers.ts b/api/src/HelloWorld.controllers.ts index e3c3ef95e..aa0051cd7 100644 --- a/api/src/HelloWorld.controllers.ts +++ b/api/src/HelloWorld.controllers.ts @@ -30,6 +30,9 @@ export default Router(HelloWorldRsc)({ currentUser: user, randomUser: generate(S.A.make(User)).value }) + }, + *Set({ echo }) { + yield* Effect.logInfo("Bogus", { echo }) } }) } diff --git a/api/src/resources/HelloWorld.ts b/api/src/resources/HelloWorld.ts index b0d7e02ac..c214cdb23 100644 --- a/api/src/resources/HelloWorld.ts +++ b/api/src/resources/HelloWorld.ts @@ -14,6 +14,10 @@ export class GetHelloWorld extends S.Req()("GetHelloWorld", { echo: S.String }, { allowAnonymous: true, allowRoles: ["user"], success: Response }) {} +export class Set extends S.Req()("Set", { + echo: S.String +}, { allowAnonymous: true, allowRoles: ["user"] }) {} + // codegen:start {preset: meta, sourcePrefix: src/resources/} export const meta = { moduleName: "HelloWorld" } as const // codegen:end diff --git a/frontend/pages/index.vue b/frontend/pages/index.vue index cf2f2729b..603799048 100644 --- a/frontend/pages/index.vue +++ b/frontend/pages/index.vue @@ -2,7 +2,7 @@ import { HelloWorldRsc } from "#resources" import { buildFormFromSchema } from "@effect-app/vue/form" import { S } from "effect-app" -import { Atom, AtomRpc, useAtomValue } from "@effect-atom/atom-vue" +import { Atom, AtomRpc, useAtomSet, useAtomValue } from "@effect-atom/atom-vue" import { makeRpcGroup } from "effect-app/client" import { RpcClientProtocolLayers } from "~/lib" @@ -38,10 +38,21 @@ const helloWorldAtom = AtomRpc.make(helloWorldRpcs, { const result = useAtomValue(() => { console.log("Recomputing HelloWorld.GetHelloWorld atom with:", req.value) return Atom.refreshOnWindowFocus( - helloWorldAtom.query("HelloWorld.GetHelloWorld", req.value), + helloWorldAtom.query("HelloWorld.GetHelloWorld", req.value, { + reactivityKeys: ["echo"], + }), ) }) +const increment = useAtomSet(() => helloWorldAtom.mutation("HelloWorld.Set")) +const test = () => + increment({ payload: { echo: "test" }, reactivityKeys: { echo: ["echo"] } }) + +// const mutation = Effect.fn("MySpan")(function* () { +// yield* Effect.logInfo("doing something") +// increment({ payload: { echo: "test" }, reactivityKeys: { echo: ["echo"] } }) +// }) + // onMounted(() => { // setInterval(() => { // // Fallback to the default focus check @@ -61,6 +72,7 @@ onMounted(() => {