1import * as GCP from "@/GCP";
2import * as Effect from "effect/Effect";
3import { serveProbes } from "../../bindingHost.ts";
4
5/**
6 * Retail only serves projects that accepted the Retail data use terms (a
7 * one-time console step); until then every call fails with
8 * `RetailDataUseTermsNotAccepted`. `GCP_TEST_RETAIL_TERMS=1` opts in once
9 * accepted; the gate is forwarded to the host's environment so the deployed
10 * runtime binds the same set.
11 */
12export const retailEnabled = !!process.env.GCP_TEST_RETAIL_TERMS;
13
14/** Product the search should find; declared only when enabled. */
15export const Shirt = GCP.Retail.CatalogsBranchesProduct("Shirt", {
16 title: "Cotton tee",
17 categories: ["Apparel > T-Shirts"],
18});
19
20/** Serving config the bindings bind; declared only when enabled. */
21export const Serving = GCP.Retail.CatalogsServingConfig("Search", {
22 displayName: "search",
23});
24
25const servingProbes = Effect.gen(function* () {
26 const search = yield* GCP.Retail.Search(Serving);
27 const predict = yield* GCP.Retail.Predict(Serving);
28 return {
29 search: search({
30 body: { visitorId: "alchemy-visitor", query: "tee", pageSize: 5 },
31 }),
32 predict: predict({
33 body: {
34 validateOnly: true,
35 userEvent: { eventType: "detail-page-view", visitorId: "visitor-1" },
36 },
37 }),
38 };
39});
40
41/**
42 * Effect-native Cloud Run service exercising every Retail binding as its own
43 * runtime service account. Deployed from {@link ../Bindings.test.ts}.
44 */
45export default class RetailBindingsHost extends GCP.Function<RetailBindingsHost>()(
46 "RetailBindingsHost",
47 {
48 main: import.meta.url,
49 invokerIamDisabled: true,
50 env: { GCP_TEST_RETAIL_TERMS: retailEnabled ? "1" : "" },
51 },
52 Effect.gen(function* () {
53 const serving = retailEnabled ? yield* servingProbes : {};
54 return { fetch: serveProbes({ ...serving }) };
55 }).pipe(
56 Effect.provide(GCP.Retail.SearchHttp),
57 Effect.provide(GCP.Retail.PredictHttp),
58 ),
59) {}