
Security News
Happy Birthday, Shai-Hulud
It has been one year since Shai-Hulud made its first appearance on npm.
@device-router/middleware-hono
Advanced tools
Hono middleware for DeviceRouter — device classification and rendering hints, edge-compatible
Hono middleware for DeviceRouter. Adds device classification and rendering hints to every request. Edge-compatible.
pnpm add @device-router/middleware-hono @device-router/storage
For automatic probe injection:
pnpm add @device-router/probe
import { Hono } from 'hono';
import { createDeviceRouter } from '@device-router/middleware-hono';
import { MemoryStorageAdapter } from '@device-router/storage';
const app = new Hono();
const { middleware, probeEndpoint } = createDeviceRouter({
storage: new MemoryStorageAdapter(),
});
app.use('*', middleware);
app.post('/device-router/probe', probeEndpoint);
app.get('/', (c) => {
const profile = c.get('deviceProfile');
if (profile?.hints.preferServerRendering) {
return c.html(renderSSR());
}
if (profile?.hints.deferHeavyComponents) {
return c.html(renderLite());
}
return c.html(renderFull());
});
export default app;
c.set('deviceProfile', profile)c.get('deviceProfile') to access tiers and hintsAutomatically inject the probe <script> into HTML responses:
const { middleware, probeEndpoint, injectionMiddleware } = createDeviceRouter({
storage: new MemoryStorageAdapter(),
injectProbe: true,
probeNonce: 'my-csp-nonce', // optional
});
app.use('*', injectionMiddleware);
Streaming responses: Injection reads the entire response body as text. If your handler returns a
ReadableStream, the response is buffered into memory before injection. For streaming HTML, add the probe<script>tag to your HTML shell manually instead.
const { middleware, probeEndpoint } = createDeviceRouter({
storage,
thresholds: {
cpu: { lowUpperBound: 4, midUpperBound: 8 },
memory: { midUpperBound: 8 },
},
});
| Option | Type | Default | Description |
|---|---|---|---|
storage | StorageAdapter | (required) | Storage backend for profiles |
cookieName | string | 'device-router-session' | Session cookie name |
cookiePath | string | '/' | Cookie path |
cookieSecure | boolean | false | Set Secure flag on the session cookie |
ttl | number | 86400 (24h) | Profile TTL in seconds |
rejectBots | boolean | true | Reject bot/crawler probe submissions |
thresholds | TierThresholds | Built-in defaults | Custom tier thresholds (validated at startup) |
injectProbe | boolean | false | Auto-inject probe into HTML |
probePath | string | — | Custom probe endpoint path |
probeNonce | string | ((c: Context) => string) | — | CSP nonce for injected script |
fallbackProfile | FallbackProfile | — | Fallback profile for first requests |
classifyFromHeaders | boolean | false | Classify from UA/Client Hints |
onEvent | OnEventCallback | — | Observability callback for logging/metrics |
Pass an onEvent callback to receive events for classification, storage, bot rejection, and errors:
const { middleware, probeEndpoint } = createDeviceRouter({
storage,
onEvent: (event) => {
console.log(`[device-router] ${event.type}`, event);
},
});
See the Observability guide for details.
Use the DeviceRouterEnv type for full type safety:
import type { DeviceRouterEnv } from '@device-router/middleware-hono';
const app = new Hono<DeviceRouterEnv>();
// c.get('deviceProfile') is now typed
Use the individual pieces when you need fine-grained control over each component:
import {
createMiddleware,
createProbeEndpoint,
createInjectionMiddleware,
loadProbeScript,
} from '@device-router/middleware-hono';
// Use only what you need
const middleware = createMiddleware({ storage, thresholds });
const endpoint = createProbeEndpoint({ storage, ttl: 3600 });
const injection = createInjectionMiddleware({
probeScript: loadProbeScript(),
});
app.use('*', injection);
app.use('*', middleware);
app.post('/device-router/probe', endpoint);
loadProbeScript() reads the @device-router/probe bundle and optionally rewrites the endpoint URL via { probePath }. Thresholds passed to createMiddleware() are validated at creation time.
createDeviceRouter(options) — All-in-one setup returning { middleware, probeEndpoint, injectionMiddleware? }createMiddleware(options) — Standalone middleware (validates thresholds)createProbeEndpoint(options) — Standalone probe endpoint handlercreateInjectionMiddleware(options) — Standalone injection middlewareloadProbeScript(options?) — Load the minified probe script for use with createInjectionMiddleware()DeviceRouterEnv — Hono env type for typed context accessMIT
FAQs
Hono middleware for DeviceRouter — device classification and rendering hints, edge-compatible
We found that @device-router/middleware-hono demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
It has been one year since Shai-Hulud made its first appearance on npm.

Research
/Security News
Operators behind PolinRider used a compromised GitHub account to plant malware in four development versions of a Packagist package with 700,000+ downloads.

Security News
GitHub Actions now supports cache-mode, a least-privilege control on the Actions cache aimed at the cache poisoning technique behind recent compromises.