From 192d451f5e7512d20098373a963fbdd899150ca1 Mon Sep 17 00:00:00 2001 From: "shoney.arickathil" Date: Sat, 29 Aug 2026 21:03:23 +0200 Subject: [PATCH] feat(porch-store): store tables for rate limit + idempotency (Phase A) (cherry picked from commit 519d4117fd0d6d0bd7d51f80bcb20de4d6294503) --- docs/examples/porch/middleware/store.wo | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 docs/examples/porch/middleware/store.wo diff --git a/docs/examples/porch/middleware/store.wo b/docs/examples/porch/middleware/store.wo new file mode 100644 index 0000000..79ca842 --- /dev/null +++ b/docs/examples/porch/middleware/store.wo @@ -0,0 +1,24 @@ +-- porch/middleware/store.wo — store-backed middleware tables. +-- Two purpose-shaped @table classes for rate limiting and idempotency. +-- Iteration 1 of the porch track. + +-- Rate limiter: fixed-window counter. +-- Key format: "ip:192.168.1.1" or "principal:alice" +-- Window = start of current window in time.ticks (µs monotonic) +@table(name: "rate_limit_counters", index: [key]) +class RateLimitCounter { + key: Text @unique + count: Int + window: Int +} + +-- Idempotency: stored response for replay. +-- Key format: "idem:keyheader" or "idem:keyheader:sha256(method|path|body)" +-- Response = JSON-encoded Resp {status, headers, body} (allowlist: status, body, content-type) +-- created_at = time.ticks when stored (µs monotonic) for lazy expiry +@table(name: "idempotency_keys", index: [key]) +class IdempotencyKey { + key: Text @unique + response: Text + created_at: Int +} \ No newline at end of file