1import {
2 packEnvValue,
3 packEnvValueKeepRedacted,
4 unpackEnvValue,
5} from "@/RuntimeContext.ts";
6import { describe, expect, it } from "alchemy-test";
7import * as Redacted from "effect/Redacted";
8
9describe("packEnvValue / unpackEnvValue", { tags: ["unit", "local"] }, () => {
10 it("stores a plain string verbatim (no quote characters on the wire)", () => {
11 // #1243: a queue name must reach the env binding bare so raw readers
12 // (dashboard, MessageBatch.queue comparisons) see the real name.
13 expect(packEnvValue("my-queue")).toBe("my-queue");
14 expect(packEnvValue("https://example.com/a?b=c")).toBe(
15 "https://example.com/a?b=c",
16 );
17 });
18
19 it("keeps ambiguous strings packed so the read side can't reinterpret them", () => {
20 // These would JSON.parse into a different value if stored bare.
21 for (const s of [
22 "123",
23 "-4.5",
24 "null",
25 "true",
26 '"quoted"',
27 '{"a":1}',
28 "[1]",
29 ]) {
30 expect(packEnvValue(s)).toBe(JSON.stringify(s));
31 expect(unpackEnvValue(packEnvValue(s))).toBe(s);
32 }
33 });
34
35 it("round-trips every string exactly", () => {
36 for (const s of [
37 "my-queue",
38 "",
39 " ",
40 "123",
41 "null",
42 "Infinity",
43 '"unterminated',
44 "{not json",
45 "line\nbreak",
46 ]) {
47 expect(unpackEnvValue(packEnvValue(s))).toBe(s);
48 }
49 });
50
51 it("round-trips non-string JSON values", () => {
52 expect(unpackEnvValue(packEnvValue(8080))).toBe(8080);
53 expect(unpackEnvValue(packEnvValue(true))).toBe(true);
54 expect(unpackEnvValue(packEnvValue({ a: [1, "x"] }))).toEqual({
55 a: [1, "x"],
56 });
57 });
58
59 it("round-trips Redacted through the marker", () => {
60 const out = unpackEnvValue<Redacted.Redacted<string>>(
61 packEnvValue(Redacted.make("s3cret")),
62 );
63 expect(Redacted.isRedacted(out)).toBe(true);
64 expect(Redacted.value(out!)).toBe("s3cret");
65 });
66
67 it("packEnvValueKeepRedacted keeps the wrapper outside the packed string", () => {
68 const packed = packEnvValueKeepRedacted(Redacted.make("s3cret"));
69 expect(Redacted.isRedacted(packed)).toBe(true);
70 const inner = Redacted.value(packed as Redacted.Redacted<string>);
71 const out = unpackEnvValue<Redacted.Redacted<string>>(inner);
72 expect(Redacted.isRedacted(out)).toBe(true);
73 expect(Redacted.value(out!)).toBe("s3cret");
74 // Non-Redacted values stay plain strings.
75 expect(packEnvValueKeepRedacted("my-queue")).toBe("my-queue");
76 });
77
78 it("unpackEnvValue passes through raw env vars a user set directly", () => {
79 expect(unpackEnvValue("my-queue")).toBe("my-queue");
80 expect(unpackEnvValue(undefined)).toBeUndefined();
81 // A user-set raw numeric env var still parses — unchanged behavior.
82 expect(unpackEnvValue("123")).toBe(123);
83 });
84});