1import * as Cloudflare from "@/Cloudflare/index.ts";
2import * as Effect from "effect/Effect";
3import * as Layer from "effect/Layer";
4import { HttpServerRequest } from "effect/http/HttpServerRequest";
5import * as HttpServerResponse from "effect/http/HttpServerResponse";
6
7/**
8 * Effect-native Worker fixture exercising the Effect-first AI Search bindings:
9 * - `Cloudflare.AI.Search.Search(search)` attaches the single-instance
10 * `ai_search` binding and returns an Effect-native `InstanceClient`. The
11 * `search` is the `AiSearch` construct's result — proving it's usable
12 * anywhere an `AiSearchInstance` is, here passed straight to `Search(...)`.
13 * - `Cloudflare.AI.SearchNamespace(namespace)` attaches the
14 * `ai_search_namespace` binding; `.get(name)` scopes to an instance.
15 *
16 * The `/bindings` route resolves each client's `raw` runtime handle (an
17 * `AiSearchInstance` / `AiSearchNamespace`) and reports its runtime shape —
18 * proving the Effect clients wire through to the live runtime bindings (it
19 * does not query, which needs indexed data).
20 */
21export default class AiSearchEffectBindingsWorker extends Cloudflare.Worker<AiSearchEffectBindingsWorker>()(
22 "AiSearchEffectBindingsWorker",
23 {
24 main: import.meta.url,
25 },
26 Effect.gen(function* () {
27 const bucket = yield* Cloudflare.R2.Bucket("AiSearchEffectBindingBucket", {
28 forceDestroy: true,
29 });
30 const namespace = yield* Cloudflare.AI.SearchNamespace(
31 "AiSearchEffectBindingNs",
32 );
33 const aiSearch = yield* Cloudflare.AI.Search(
34 "AiSearchEffectBindingInstance",
35 { source: bucket },
36 );
37 const search = yield* Cloudflare.AI.QuerySearch(aiSearch);
38 const ns = yield* Cloudflare.AI.QuerySearchNamespace(namespace);
39
40 return {
41 fetch: Effect.gen(function* () {
42 const request = yield* HttpServerRequest;
43 if (request.url.includes("/bindings")) {
44 const raw = yield* search.raw;
45 const nsRaw = yield* ns.raw;
46 return yield* HttpServerResponse.json({
47 mode: "effect",
48 searchRaw: typeof raw,
49 searchChatCompletions: typeof raw.chatCompletions,
50 searchSearch: typeof raw.search,
51 nsRaw: typeof nsRaw,
52 nsChatCompletions: typeof nsRaw.get("docs-search").chatCompletions,
53 });
54 }
55 return HttpServerResponse.text("ok");
56 }),
57 };
58 }).pipe(
59 Effect.provide(
60 Layer.mergeAll(
61 Cloudflare.AI.QuerySearchBinding,
62 Cloudflare.AI.QuerySearchNamespaceBinding,
63 ),
64 ),
65 ),
66) {}