1import { functionEnvironment, functionSlug } from "@/Neon/FunctionConfig";
2import { expect, test } from "alchemy-test";
3import * as Effect from "effect/Effect";
4import * as Redacted from "effect/Redacted";
5
6const props = {
7 branch: { projectId: "project", branchId: "branch" },
8 main: "index.ts",
9};
10for (const key of [
11 "NEON_API_KEY",
12 "DATABASE_URL",
13 "AWS_SECRET_ACCESS_KEY",
14 "NEON_AI_GATEWAY_TOKEN",
15 "NEON_DATA_API_URL",
16 "NEON_BRANCH",
17 "ALCHEMY_STAGE",
18]) {
19 test.effect(
20 `rejects overriding injected environment ${key}`,
21 () =>
22 Effect.gen(function* () {
23 const rejected = yield* functionEnvironment(
24 { ...props, env: { [key]: "must-not-deploy" } },
25 [],
26 ).pipe(
27 Effect.as(false),
28 Effect.catchTag("FunctionConfigurationError", () =>
29 Effect.succeed(true),
30 ),
31 );
32 expect(rejected).toBe(true);
33 }),
34 { tags: ["unit", "provider:neon", "provider:neon:function", "local"] },
35 );
36}
37test.effect(
38 "unwraps redacted application values only at deployment",
39 () =>
40 Effect.gen(function* () {
41 expect(
42 yield* functionEnvironment(
43 {
44 ...props,
45 env: { APP_TOKEN: Redacted.make("test-token"), OMITTED: undefined },
46 },
47 [],
48 ),
49 ).toEqual({ APP_TOKEN: "test-token" });
50 }),
51 { tags: ["unit", "provider:neon", "provider:neon:function", "local"] },
52);
53for (const slug of [
54 "contains-hyphen",
55 "Uppercase",
56 "morethan20characterslong",
57 "",
58]) {
59 test.effect(
60 `rejects invalid explicit slug ${JSON.stringify(slug)}`,
61 () =>
62 Effect.gen(function* () {
63 expect(
64 yield* functionSlug("Api", slug).pipe(
65 Effect.as(false),
66 Effect.catchTag("FunctionConfigurationError", () =>
67 Effect.succeed(true),
68 ),
69 ),
70 ).toBe(true);
71 }),
72 { tags: ["unit", "provider:neon", "provider:neon:function", "local"] },
73 );
74}