From fa2d34b50f2fe1a18750bdc85412218d37842cb9 Mon Sep 17 00:00:00 2001 From: George Moon Date: Sun, 1 Nov 2026 11:00:45 -0500 Subject: [PATCH 1/2] docs(examples): add fetchWebKey /download/:id route to hono-basic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Demonstrates the key-addressed seam: an alias map (standing in for a DB / token resolver / tenant prefix) decouples the public id from the storage key, so a key full of reserved characters is served verbatim — the case the URL-addressed fetchWeb path can't carry. Verified e2e against s3proxy-public: /download/home -> index.html (200), /download/special -> the specialCharacters!... object (200, 46B), /download/bogus -> 404. Co-Authored-By: Claude Opus 4.8 --- examples/hono-basic.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/examples/hono-basic.ts b/examples/hono-basic.ts index 2654250..0c7e40a 100644 --- a/examples/hono-basic.ts +++ b/examples/hono-basic.ts @@ -30,6 +30,22 @@ app.get('/health', async (c) => { app.get('/', (c) => c.redirect('/index.html')); +// fetchWebKey() names the S3 key explicitly — the URL does NOT select the key. +// This alias map stands in for a real lookup (a DB row, a signed-token resolver, +// a per-tenant prefix): the public id is decoupled from the storage key, and the +// key is served verbatim, so keys with reserved characters (%, spaces, +, ...) +// need no URL-encoding contortions — the exact failure fetchWeb's URL path can't +// avoid. `special` points at an object whose key is a pile of reserved chars. +const KEY_ALIASES: Record = { + home: 'index.html', + special: 'specialCharacters!-_.*\'()&$@=;:+ ,?\\{^}%`]">[~<#|.', +}; +app.get('/download/:id', (c) => { + const key = KEY_ALIASES[c.req.param('id')]; + if (key === undefined) return new Response('unknown id', { status: 404 }); + return proxy.fetchWebKey(key, c.req.raw); +}); + // fetchWeb adapts the Web `Request` -> `Response` in one line, so nothing here // re-encodes the library's HttpRequest shape or the stream conversion. It throws // the typed S3ProxyError on 404/403/416, which the app's onError below renders. From e5e4b9256cb90245143bb071b3aa79aabf3086b1 Mon Sep 17 00:00:00 2001 From: George Moon Date: Sun, 1 Nov 2026 11:09:55 -0500 Subject: [PATCH 2/2] test(conformance): cover fetchWebKey via the key-addressed kit scenario MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps @forkzero/s3-website-test-kit ^0.4.0 -> ^0.5.0 (adds scenarios/s3proxy/key-addressed.yml) and extends `make conformance-local` to run it against examples/hono-basic.ts on :8083 — so the CI conformance gate exercises the new fetchWebKey /download/:id route end-to-end (/download/home + /download/special -> 200, /download/bogus -> 404). Verified green against real S3 (make conformance-local exit 0). Co-Authored-By: Claude Opus 4.8 --- Makefile | 3 +++ package-lock.json | 8 ++++---- package.json | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index a80d1f9..eaa242a 100644 --- a/Makefile +++ b/Makefile @@ -89,6 +89,9 @@ conformance-local: @$(RUN_LOCAL) examples/fastify-basic.ts 8081 \ sh -c 'npx artillery run --target http://localhost:8081 --config $(TEST_KIT)/configs/conformance.yml $(TEST_KIT)/scenarios/core/conformance.yml && \ npx artillery run --target http://localhost:8081 --config $(TEST_KIT)/configs/conformance.yml $(TEST_KIT)/scenarios/s3proxy/error-contract.yml' + @echo "Running key-addressed (fetchWebKey) conformance against examples/hono-basic.ts on :8083..." + @$(RUN_LOCAL) examples/hono-basic.ts 8083 \ + npx artillery run --target http://localhost:8083 --config $(TEST_KIT)/configs/conformance.yml $(TEST_KIT)/scenarios/s3proxy/key-addressed.yml .PHONY: validation-local validation-local: diff --git a/package-lock.json b/package-lock.json index a69f4e2..746a55e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "devDependencies": { "@aws-sdk/client-s3": "^3.832.0", "@biomejs/biome": "^2.0.4", - "@forkzero/s3-website-test-kit": "^0.4.0", + "@forkzero/s3-website-test-kit": "^0.5.0", "@hono/node-server": "^2.0.0", "@types/debug": "^4.1.12", "@types/express": "^5.0.3", @@ -2021,9 +2021,9 @@ } }, "node_modules/@forkzero/s3-website-test-kit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@forkzero/s3-website-test-kit/-/s3-website-test-kit-0.4.0.tgz", - "integrity": "sha512-UziHuWnDFfniSl7+TFz6XxLG78TEma39kT3KLhs6BnOx47LC6Vy+O5HvrOkhvf9aRtFMkpqaNKRE6kkjNE5ulg==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@forkzero/s3-website-test-kit/-/s3-website-test-kit-0.5.0.tgz", + "integrity": "sha512-/XKwCG/E9kFfpKJ1VDpPSK8rl3dchyj3F50J+VMRxFZa6E56ggNiLkYBb+42rScZghUTUYOdi91hi3JhRonVUQ==", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/package.json b/package.json index 181cac1..cc25703 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "devDependencies": { "@aws-sdk/client-s3": "^3.832.0", "@biomejs/biome": "^2.0.4", - "@forkzero/s3-website-test-kit": "^0.4.0", + "@forkzero/s3-website-test-kit": "^0.5.0", "@hono/node-server": "^2.0.0", "@types/debug": "^4.1.12", "@types/express": "^5.0.3",