Skip to content

feat: Edge Runtime compatibility — drop axios and all node: imports#8

Open
cport1 wants to merge 1 commit into
mainfrom
feat/281-edge-runtime-compat
Open

feat: Edge Runtime compatibility — drop axios and all node: imports#8
cport1 wants to merge 1 commit into
mainfrom
feat/281-edge-runtime-compat

Conversation

@cport1

@cport1 cport1 commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Closes the SDK half of WebDecoy/app#281 (Vercel Marketplace milestone, Phase 0).

Why

@webdecoy/nextjs middleware could not run in Vercel Edge Middleware: tsup bundles the whole package into one file, so the axios/https/node:crypto/net imports poisoned the bundle and failed Next.js Edge builds. Middleware is where a security SDK gets installed — this blocked the entire Vercel story (and Cloudflare Workers/Deno/Bun along the way).

What changed

Area Before After
HTTP client axios + https.Agent Web-standard fetch + AbortController timeout (same error messages)
Captcha token/PoW/service sync node:crypto async Web Crypto (crypto.subtle) — breaking, 0.5.0
Fingerprint correlation key sha256 (sync, node:crypto) FNV-1a 64 — non-crypto is fine for a correlation key (adversary controls their own signals); keeps DetectionEngine.score sync
isIPv4 node:net strict local check (matches net.isIPv4 semantics)
Honeytoken randomness randomBytes crypto.getRandomValues
New src/webcrypto.ts (sha256/hmac/randomHex/timing-safe/base64url, Web-standard only)

tlsRejectUnauthorized is kept for API compatibility but ignored by the fetch transport; docs point to NODE_EXTRA_CA_CERTS for local self-signed certs. Framework adapters (Express/Fastify/Next.js) already awaited the async handle(), so they need no changes; the examples/captcha-express login route gained one await.

Verification (both wired into CI alongside build + test)

  1. scripts/check-edge.mjs — bundles each entry with esbuild platform: browser, where Node built-ins don't resolve; any node: import anywhere in the graph fails. Runs for @webdecoy/node and @webdecoy/nextjs.
  2. edge-runtime.test.ts — executes the bundled SDK inside @edge-runtime/vm (Vercel's actual Edge Runtime): keyless rate limiting (3rd request over max: 2 denied), honeytoken tripwire fires, async token issue → verify → replay-rejection all pass in the VM.

turbo build test: 12/12 tasks, 110 tests passing. Pre-existing note: adapter packages had jest exiting 1 on "No tests found", making turbo test unusable as a gate — added --passWithNoTests.

Breaking (0.5.0)

Captcha.issueChallenge/verify/score/verifyToken, PoWManager.generate/verify, TokenManager.issue/verify now return Promises. Anyone using the HTTP handler or framework adapters is unaffected.

…ebDecoy/app#281)

Make @webdecoy/node and @webdecoy/nextjs run in Vercel Edge Middleware
(and other WinterCG runtimes) by removing every Node-only API from the
bundled module graph:

- client: axios + https.Agent -> Web-standard fetch with AbortController
  timeout; identical error messages preserved. tlsRejectUnauthorized is
  kept for API compatibility but ignored (use NODE_EXTRA_CA_CERTS).
- captcha (token/pow/service/http): node:crypto -> Web Crypto
  (crypto.subtle); issue/verify/generate/score are now async. BREAKING —
  version bumped to 0.5.0. Framework adapters already awaited the async
  handle() so they are unaffected.
- fingerprint detector: sha256 -> FNV-1a 64 (correlation key only; keeps
  DetectionEngine.score sync)
- ip: net.isIPv4 -> strict local check; honeytoken: randomBytes ->
  crypto.getRandomValues
- new src/webcrypto.ts: sha256/hmac/randomHex/timing-safe-compare/
  base64url helpers, Web-standard only

Verification, wired into CI (build + test + check:edge):
- scripts/check-edge.mjs: esbuild browser-platform bundle gate — any
  node: import anywhere in the graph fails the build
- edge-runtime.test.ts: executes the bundled SDK inside @edge-runtime/vm
  (Vercel's Edge Runtime): keyless rate limiting, tripwire/honeytoken,
  and async token issue/verify all pass in the VM

Also: jest --passWithNoTests for adapter packages (pre-existing 'No
tests found' failure made turbo test unusable as a gate).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant