1import * as Cloudflare from "@/Cloudflare";
2import * as Effect from "effect/Effect";
3import * as Schedule from "effect/Schedule";
4import * as Stream from "effect/Stream";
5
6const KV = Cloudflare.KV.Namespace("DurableObjectWorkerEnvironmentKV", {
7 title: "durable-object-worker-environment-kv",
8});
9
10export class WorkerEnvironmentKVObject extends Cloudflare.DurableObject<WorkerEnvironmentKVObject>()(
11 "WorkerEnvironmentKVObject",
12 Effect.gen(function* () {
13 const kv = yield* Cloudflare.KV.ReadWriteNamespace(KV);
14
15 return Effect.gen(function* () {
16 const state = yield* Cloudflare.DurableObjectState;
17 return {
18 identity: () => Effect.sync(() => state.id.toString()),
19 put: (key: string, value: string) => kv.put(key, value),
20 get: (key: string) => kv.get(key),
21 // Egress colo is diagnostic, not a placement guarantee.
22 colo: () =>
23 Effect.promise(async () => {
24 const response = await fetch(
25 "https://cloudflare.com/cdn-cgi/trace",
26 );
27 const trace = await response.text();
28 return trace.match(/^colo=(.*)$/m)?.[1] ?? "unknown";
29 }),
30 // Mirrors the `tick` example from the tutorial:
31 // https://alchemy.run/cloudflare/compute/durable-objects
32 // An RPC method that returns a Stream of sequential numbers.
33 tick: (n: number) =>
34 Stream.iterate(0, (i) => i + 1).pipe(
35 Stream.take(n),
36 Stream.schedule(Schedule.spaced("100 millis")),
37 ),
38 };
39 });
40 }).pipe(Effect.provide(Cloudflare.KV.ReadWriteNamespaceBinding)),
41) {}