1import * as AWS from "@/AWS";
2import * as Neon from "@/Neon";
3import * as Test from "@/Test/Alchemy";
4import * as SDK from "@distilled.cloud/neon";
5import { expect } from "alchemy-test";
6import * as Effect from "effect/Effect";
7import * as Layer from "effect/Layer";
8import * as Schedule from "effect/Schedule";
9import * as HttpClient from "effect/http/HttpClient";
10import BackendHttpLambda from "./fixtures/backend-http-lambda.ts";
11import { backendBranch } from "./fixtures/backend-resources.ts";
12
13const { test } = Test.make({
14 providers: Layer.mergeAll(Neon.providers(), AWS.providers()),
15});
16
17test.provider(
18 "Lambda HTTP bindings expose only public URLs and a scoped gateway token",
19 (stack) =>
20 Effect.gen(function* () {
21 yield* stack.destroy();
22 const deployed = yield* stack.deploy(
23 Effect.gen(function* () {
24 const branch = yield* backendBranch;
25 const api = yield* BackendHttpLambda;
26 return { branch, url: api.functionUrl };
27 }),
28 );
29 const http = yield* HttpClient.HttpClient;
30 const response = yield* http.get(deployed.url!).pipe(
31 Effect.retry({
32 schedule: Schedule.exponential("200 millis"),
33 times: 7,
34 }),
35 );
36 expect(response.status).toBe(200);
37 expect(yield* response.json).toMatchObject({ hasToken: true });
38 const request = {
39 project_id: deployed.branch.projectId,
40 branch_id: deployed.branch.branchId,
41 };
42 const credentials = (yield* SDK.listCredentials(
43 request,
44 )).credentials.filter(
45 (item) =>
46 item.principal_type === "user" &&
47 item.branch_id === deployed.branch.branchId &&
48 !item.revoked_at,
49 );
50 expect(credentials).toHaveLength(1);
51 expect(credentials[0].scopes).toContain("ai_gateway:invoke");
52 yield* stack.destroy();
53 expect(
54 yield* SDK.getProjectBranch(request).pipe(
55 Effect.as(false),
56 Effect.catchTag("NotFound", () => Effect.succeed(true)),
57 ),
58 ).toBe(true);
59 yield* stack.destroy();
60 }),
61 {
62 tags: [
63 "provider:aws",
64 "provider:aws:lambda",
65 "provider:neon",
66 "provider:neon:aigateway",
67 "provider:neon:auth",
68 "provider:neon:branch",
69 "provider:neon:dataapi",
70 "provider:neon:project",
71 "live",
72 ],
73 timeout: 240_000,
74 },
75);