@tillstack/shield-core
v0.3.1
Published
TillShield inline edge-decisioning engine — request matching, rate limiting, config sync and decision reporting. Runtime-agnostic core shared by @tillstack/shield-node and @tillstack/shield-cloudflare.
Maintainers
Readme
@tillstack/shield-core
The runtime-agnostic engine behind TillShield's inline WAF. It fetches the compiled ruleset from TillDev, evaluates a request locally (CIDR/path/method/country/UA matching, rate limiting, sha256 threat-intel deny list), and reports decisions back asynchronously.
Most people should use a framework adapter instead of this package directly:
@tillstack/shield-node— Express / Connect / Fastify / rawhttp@tillstack/shield-cloudflare— Cloudflare Workers
Using the engine directly
Any runtime with global fetch + WebCrypto (or injected implementations) works.
import { ShieldClient } from '@tillstack/shield-core'
const shield = new ShieldClient({ edgeKey: process.env.SHIELD_EDGE_KEY! })
const result = await shield.check({
ip: '203.0.113.9',
method: 'GET',
path: '/admin',
country: 'US',
userAgent: 'curl/8',
})
// result.decision: 'allow' | 'block' | 'challenge' | 'log'
if (result.decision === 'block') {
// serve result.status (default 403) + result.body
}
await shield.flush() // send queued decision reportsInjecting fetch / hashing / a rate limiter
new ShieldClient({
edgeKey,
fetchImpl: myFetch, // Node < 18, custom pools, tests
hashImpl: mySha256Hex, // Node < 20 without WebCrypto
rateLimiter: myDistributedLimiter, // implements RateLimiter
failMode: 'closed', // block if config can't be fetched
})Exports
ShieldClient, ConfigStore, Reporter, evaluate, MemoryRateLimiter,
sha256Hex, normalizeIp, CIDR/glob matchers (ipInCidr, pathMatchesAny, …),
and all types (ShieldConfig, EdgeRule, RequestInfo, EvalResult, …).
Fail-open by design: ShieldClient.check() never throws — on any internal error
it returns { decision: 'allow' }.
