1import * as Cloudflare from "@alchemy.run/cloudflare";
2import { expect } from "@alchemy.run/test";
3import * as Test from "@alchemy.run/test/Alchemy";
4import * as Alchemy from "alchemy";
5import * as Effect from "effect/Effect";
6import * as HttpClient from "effect/http/HttpClient";
7import ZlibProbeWorker from "./fixtures/zlib-probe-worker.ts";
8
9const state = Alchemy.inMemoryState();
10
11const { test, beforeAll, afterAll, deploy, destroy } = Test.make({
12 providers: Cloudflare.providers(),
13 state,
14 dev: true,
15});
16
17const Stack = Alchemy.Stack(
18 "ZlibProbeStack",
19 { providers: Cloudflare.providers(), state },
20 Effect.gen(function* () {
21 const worker = yield* ZlibProbeWorker;
22 return { url: worker.url.as<string>() };
23 }),
24);
25
26const stack = beforeAll(deploy(Stack));
27afterAll(destroy(Stack));
28
29test(
30 "workerd node:zlib keeps the synchronous exact-span inflate the pack parser relies on",
31 Effect.gen(function* () {
32 const { url } = yield* stack;
33 const client = yield* HttpClient.HttpClient;
34 const res = yield* client.get(`${url}/?path=probe`);
35 for (const path of [
36 "processChunk",
37 "processChunkReuse",
38 "info",
39 "plain",
40 "stream",
41 "sha1",
42 "copy",
43 "jsloop",
44 "effect",
45 "deflate6",
46 "deflate1",
47 ]) {
48 const n = path.startsWith("deflate") ? 200 : 2000;
49 yield* client.get(`${url}/?path=${path}&n=50`).pipe(Effect.flatMap((r) => r.json));
50 const t0 = performance.now();
51 const r = (yield* client
52 .get(`${url}/?path=${path}&n=${n}`)
53 .pipe(Effect.flatMap((r) => r.json))) as { ok: number; error?: string };
54 const ms = performance.now() - t0;
55 console.log(
56 `[zlib-local] ${path.padEnd(12)} ok ${r.ok}/${n} in ${ms.toFixed(0)}ms → ${(ms / n).toFixed(3)} ms/entry${r.error ? ` error: ${r.error}` : ""}`,
57 );
58 }
59 const body = (yield* res.json) as {
60 hasProcessChunk: boolean;
61 info?: { outLen: number; bytesWritten: number; expectedConsumed: number };
62 contentLen: number;
63 };
64 console.log("[zlib-probe]", JSON.stringify(body));
65 expect(res.status).toBe(200);
66 // PackParser's per-entry inflate takes the synchronous `_processChunk`
67 // fast path (Zlib.ts); a workerd without it falls back to a streaming
68 // inflater measured ~50x slower per object. Pin it.
69 expect(body.hasProcessChunk).toBe(true);
70 expect(body.info?.outLen).toBe(body.contentLen);
71 expect(body.info?.bytesWritten).toBe(body.info?.expectedConsumed);
72 }),
73 {
74 tags: ["provider:cloudflare", "provider:cloudflare:worker", "local"],
75 timeout: 60_000,
76 },
77);