diff --git a/CHANGELOG.md b/CHANGELOG.md index 6065673..eb964a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,16 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -### Added - -- **OpenTelemetry spans** around `protect()` and rule evaluation. Pass a tracer: `new WebDecoy({ tracer: trace.getTracer('webdecoy') })`. Injected rather than imported, so the package stays dependency-free and edge-safe — the `Tracer` type is a structural subset of OpenTelemetry's, so `trace.getTracer()` works with no adapter, and omitting it means no spans, no dependency and no behaviour change. Attributes cover the decision id (which joins a span to its dashboard row), the conclusion, the deciding rule, and whether the request cost a round trip to ingest. A tracer that throws cannot fail a request. +## [0.15.1] - 2026-09-16 ### Changed - **`ClearanceOptions.scope` is documented as reserved.** It was described as a route-group scope that limits where a token is valid. No validator enforces that: a clearance token is bound to the organization, and each protected path's verification level is the way to require stronger proof. Passing `scope` (or `data-scope` on the script tag) still works and still has no effect. +## [0.15.0] - 2026-08-28 + +### Fixed + +- **A datacenter or VPN IP alone no longer forwards a request for server verification.** Local analysis scored a datacenter/VPN address high enough on its own to forward the request, so a real visitor on a VPN, with a normal browser and full headers, was sent for server-side scoring exactly like a bot. The SDK now forwards on a genuine local bot signal (a bot or automation user agent, or missing headers every real browser sends) or when TLS details are available to fingerprint. A datacenter IP and an absent `Sec-CH-UA` no longer force a forward, alone or together; both still travel with a request that is forwarded for another reason. Trade-off: a bot that perfectly imitates a browser from a datacenter IP, with no TLS details, is no longer forwarded on the IP alone. + +## [0.14.0] - 2026-08-28 + +### Changed + +- **Breaking: server-to-server traffic defaults to `https://in.webdecoy.com`.** The default `apiUrl` moved from `https://ingest.webdecoy.com`. Server-to-server calls carry no browser fingerprint, so the fronted hostname costs nothing and adds DDoS absorption and rate limiting in front of ingest. If you set `apiUrl` explicitly, nothing changes. `@webdecoy/client` keeps the direct hostname, because a browser's own TLS handshake is part of what it reports. + - **One adapter core.** Express, Fastify, Next.js (middleware and Pages wrapper) and the fetch guard each carried their own copy of skip-path matching, the 429 and 403 payloads, and honeytoken arming — five copies of one set of decisions, and five places the next correction can fail to land. They now share `adapter-core.ts`; the framework-specific response mechanics are untouched, and every honeytoken-injection test passes unchanged. Fastify keeps its awaited arming, which has no window where early requests are served without the link. +### Added + +- **OpenTelemetry spans** around `protect()` and rule evaluation. Pass a tracer: `new WebDecoy({ tracer: trace.getTracer('webdecoy') })`. Injected rather than imported, so the package stays dependency-free and edge-safe — the `Tracer` type is a structural subset of OpenTelemetry's, so `trace.getTracer()` works with no adapter, and omitting it means no spans, no dependency and no behaviour change. Attributes cover the decision id (which joins a span to its dashboard row), the conclusion, the deciding rule, and whether the request cost a round trip to ingest. A tracer that throws cannot fail a request. + +- **Six more crawlers are recognised:** DuckAssistBot, SofyaBot, Reflectionbot, xAI-SearchBot, LinkupBot, and IbouBot (classified as a search crawler). + ## [0.13.0] - 2026-08-22 ### Added diff --git a/package-lock.json b/package-lock.json index 3c5d474..eb83784 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10407,7 +10407,7 @@ }, "packages/client": { "name": "@webdecoy/client", - "version": "0.15.0", + "version": "0.15.1", "license": "MIT", "devDependencies": { "@types/jest": "^29.5.11", @@ -10424,10 +10424,10 @@ }, "packages/express": { "name": "@webdecoy/express", - "version": "0.15.0", + "version": "0.15.1", "license": "MIT", "dependencies": { - "@webdecoy/node": "^0.15.0" + "@webdecoy/node": "^0.15.1" }, "devDependencies": { "@types/express": "^4.17.21", @@ -10448,10 +10448,10 @@ }, "packages/fastify": { "name": "@webdecoy/fastify", - "version": "0.15.0", + "version": "0.15.1", "license": "MIT", "dependencies": { - "@webdecoy/node": "^0.15.0", + "@webdecoy/node": "^0.15.1", "fastify-plugin": "^4.5.1" }, "devDependencies": { @@ -10472,10 +10472,10 @@ }, "packages/hono": { "name": "@webdecoy/hono", - "version": "0.15.0", + "version": "0.15.1", "license": "MIT", "dependencies": { - "@webdecoy/node": "^0.15.0" + "@webdecoy/node": "^0.15.1" }, "devDependencies": { "@types/jest": "^29.5.11", @@ -10495,10 +10495,10 @@ }, "packages/nextjs": { "name": "@webdecoy/nextjs", - "version": "0.15.0", + "version": "0.15.1", "license": "MIT", "dependencies": { - "@webdecoy/node": "^0.15.0" + "@webdecoy/node": "^0.15.1" }, "devDependencies": { "@types/jest": "^29.5.11", @@ -10518,7 +10518,7 @@ }, "packages/webdecoy": { "name": "@webdecoy/node", - "version": "0.15.0", + "version": "0.15.1", "license": "MIT", "devDependencies": { "@types/jest": "^29.5.11", diff --git a/packages/client/package.json b/packages/client/package.json index 1fa580f..9d4d562 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@webdecoy/client", - "version": "0.15.0", + "version": "0.15.1", "description": "Web Decoy browser widget - signal collection, proof-of-work, and captcha UI", "main": "./dist/index.js", "module": "./dist/index.mjs", diff --git a/packages/client/src/clearance.ts b/packages/client/src/clearance.ts index a45298c..e43667b 100644 --- a/packages/client/src/clearance.ts +++ b/packages/client/src/clearance.ts @@ -1,8 +1,8 @@ /** - * wd_clearance minting (WAF Enforcement PRD FR6 / closes the #124 loop). + * wd_clearance minting. * * Real browsers earn a signed clearance token from WebDecoy's ingest service and - * carry it in a first-party cookie. The edge validator (FR7) lets tokened + * carry it in a first-party cookie. The edge validator lets tokened * sessions through; a decoy hit denies the token's fp (deny-at-mint + live-token * revocation). This is the *allow-and-observe* path — it mints silently during * normal browsing so the loop covers monitor mode, not just the enforce-mode diff --git a/packages/express/package.json b/packages/express/package.json index fb71404..54b8997 100644 --- a/packages/express/package.json +++ b/packages/express/package.json @@ -1,6 +1,6 @@ { "name": "@webdecoy/express", - "version": "0.15.0", + "version": "0.15.1", "description": "Web Decoy middleware for Express.js", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -40,7 +40,7 @@ "url": "https://github.com/WebDecoy/node/issues" }, "dependencies": { - "@webdecoy/node": "^0.15.0" + "@webdecoy/node": "^0.15.1" }, "peerDependencies": { "express": "^4.18.0 || ^5.0.0" diff --git a/packages/fastify/package.json b/packages/fastify/package.json index cc76aad..4ce9549 100644 --- a/packages/fastify/package.json +++ b/packages/fastify/package.json @@ -1,6 +1,6 @@ { "name": "@webdecoy/fastify", - "version": "0.15.0", + "version": "0.15.1", "description": "Web Decoy plugin for Fastify", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -40,7 +40,7 @@ "url": "https://github.com/WebDecoy/node/issues" }, "dependencies": { - "@webdecoy/node": "^0.15.0", + "@webdecoy/node": "^0.15.1", "fastify-plugin": "^4.5.1" }, "peerDependencies": { diff --git a/packages/hono/package.json b/packages/hono/package.json index 866f7fb..e2ee201 100644 --- a/packages/hono/package.json +++ b/packages/hono/package.json @@ -1,6 +1,6 @@ { "name": "@webdecoy/hono", - "version": "0.15.0", + "version": "0.15.1", "description": "Web Decoy middleware for Hono — Cloudflare Workers, Bun, Deno, Node", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -44,7 +44,7 @@ "url": "https://github.com/WebDecoy/node/issues" }, "dependencies": { - "@webdecoy/node": "^0.15.0" + "@webdecoy/node": "^0.15.1" }, "peerDependencies": { "hono": "^4.0.0" diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 2488057..119c1ad 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -1,6 +1,6 @@ { "name": "@webdecoy/nextjs", - "version": "0.15.0", + "version": "0.15.1", "description": "Web Decoy middleware for Next.js", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -42,7 +42,7 @@ "url": "https://github.com/WebDecoy/node/issues" }, "dependencies": { - "@webdecoy/node": "^0.15.0" + "@webdecoy/node": "^0.15.1" }, "peerDependencies": { "next": ">=13.0.0" diff --git a/packages/webdecoy/package.json b/packages/webdecoy/package.json index 2e98b95..43bf8b2 100644 --- a/packages/webdecoy/package.json +++ b/packages/webdecoy/package.json @@ -1,6 +1,6 @@ { "name": "@webdecoy/node", - "version": "0.15.0", + "version": "0.15.1", "description": "Web Decoy SDK for Node.js - Bot detection with TLS fingerprinting", "main": "./dist/index.js", "types": "./dist/index.d.ts",