Changelog
The three packages (@dotworld/shadow-canary-core, …-templates, …-skill) version together via Changesets — bumping any of them bumps all three to the same version. Each entry below points at what changed at the user level; the per-package CHANGELOGs on GitHub have the granular per-package detail.
v0.7.0
New: Next.js 16 proxy.ts support via shadowCanaryProxy alias. Next.js 16 (Oct 2025) renamed the file convention from middleware.ts → proxy.ts and the exported function from middleware() → proxy(). The wire-level API (NextRequest, NextResponse, config.matcher) is unchanged in v16, so shadowCanaryMiddleware already worked — but importing a function named Middleware into a file named proxy.ts reads awkwardly.
Two ergonomic exports added, both in the main and edge entry points:
shadowCanaryProxy— strict alias ofshadowCanaryMiddleware(same function reference, no re-implementation).ShadowCanaryProxyOptions— alias ofShadowCanaryMiddlewareOptions.
// Next.js 16 proxy.ts (Node runtime)import { shadowCanaryProxy } from '@dotworld/shadow-canary-core';
export async function proxy(req: NextRequest) { const res = await shadowCanaryProxy(req); return res ?? NextResponse.next();}The middleware function is also now exported from the main entry point (it was previously only on /edge) so v16 proxy.ts files can import without the subpath. v15 setups and v16 Edge-runtime middleware.ts keep working unchanged — both names point at the same function.
Note: proxy.ts runs on Node.js runtime only. middleware.ts is the only path for Edge runtime on v16 (deprecated, no removal date announced). Vercel ships a codemod for the file convention migration: npx @next/codemod@canary middleware-to-proxy .
Full migration recipe: Manual migration — Next.js 16: proxy.ts.
v0.6.0
New: runtime info helper for Sentry / PostHog telemetry. Two exports — getBuildInfo() (sync, env vars only) and getRuntimeBucket() (async, queries Edge Config) — return which deploy slot the running code lives in plus commit / branch / region metadata. The bucket field disambiguates prod-current vs prod-previous so canary regressions can be filtered in Sentry / PostHog by the bucket actually serving the broken request, instead of seeing a blended “production” environment.
import { getBuildInfo, getRuntimeBucket } from '@dotworld/shadow-canary-core';
const info = getBuildInfo();// { slot: 'production-track', commitShaShort: 'abc1234', branch: 'production', ... }
const runtime = await getRuntimeBucket();// { bucket: 'prod-current', resolvedFromEdgeConfig: true, ... }Plus formatBuildInfoTag() for one-line log prefixes / debug headers ([prod-current @ production abc1234]). Exported from both Node and edge entry points.
Full integration recipes: Runtime info reference — covers Sentry.init config, posthog.register(), and three patterns (server prop / inline <script> / API route) for surfacing build info to client code.
Fix: admin dashboard React hydration mismatch (error #418) caused by server-rendered timestamps differing from client (Date.now() drift, locale-default timezone for toLocaleString). The dashboard now defers time-derived text to after mount; SSR shows '—' placeholders.
v0.5.0 → v0.5.1
Deeper shadow rollback (last 20 deploys). ShadowConfig gains shadowHistory?: string[] — a ring buffer of the 20 most recent shadow deploy URLs. deploy-shadow.yml prepends to it on every push to master. The admin gets a “Shadow deploys récents” section with per-entry rollback, mirroring the prod deploys list — operators can now go further back than one step when the most recent shadows are all known-bad.
/api/admin/rollback-shadow accepts {targetUrl?: string} (back-compat with empty body).
deploymentDomainShadowPrevious is now deprecated but still populated with shadowHistory[0] for v0.4.x admin UI compat. Will be removed in v0.7.
Configurable manual canary step. The MANUEL buttons on the admin take a step-size input (default 4, range 1–50). Buttons re-label dynamically (+ 7% (step forward)). Endpoints /api/admin/canary/step-forward and /step-back accept {step?: number}.
Patch (0.5.1): admin traffic-bar legend now shows the canary knob values the workflow actually mutates (new prod 9% du prod, previous prod 91% du prod, shadow 1% du total) instead of the effective traffic share — resolves the confusion where the SLO log said 5% → 9% but the legend said 8.9% (a 0.1pt gap from shadow eating 1% of total before the prod split). Bar widths stay proportional to actual share; a small secondary line surfaces the effective % when shadow is non-zero.
v0.4.0 → v0.4.1
Admin dashboard improvements. Four features land at once, no breaking changes for host projects that re-copy the template.
- Version / branch per bucket. Traffic-bar legend now displays the branch name and short commit SHA under each bucket URL (shadow, prod-new, prod-previous). New
getDeploymentByUrl()helper exported from core; new/api/admin/bucket-infoendpoint. - SLO check log.
canary-ramp.ymlwrites each check result to a ring buffer in Edge Config (sloChecks, last 10). Admin renders a timeline with pass/fail icon, timestamp, HTTP codes, pct transition, and body excerpt — empty list ⇒ cron isn’t running, ✗ ⇒ SLO failed → rollback. New exported typeSloCheck. - Shadow rollback v1.
deploy-shadow.ymlsaves the current shadow URL intodeploymentDomainShadowPreviousbefore overwriting on each push. Admin gets a “Rollback shadow” button that swaps the two URLs symmetrically. New/api/admin/rollback-shadowendpoint. (Superseded byshadowHistoryin 0.5.0.) - Bug fix. Removed the dead
/debuglink from the Bucket forcer.
Patch (0.4.1):
- Timer accuracy. “Prochain check dans …” is now computed from
lastSloCheck.ts + 15min(what actually happened) instead of the theoretical cron firing time. GH Actions cron has multi-minute latency, so the theoretical schedule drifts. Overdue label switches to “Check attendu il y a …” in amber. - Pct clarity. Legend shows the share of prod alongside the share of total on prod buckets (e.g. “7.9%” with “8% du prod” underneath) — resolves the 7.9% / 8% mismatch confusion.
- Expandable SLO body. Body truncation in
canary-ramp.ymlbumped 80 → 500 chars. Each SLO log row is clickable to expand the full payload — useful for reading the full JSON / error response that triggered a rollback.
v0.3.0
Breaking change — the Edge Config key is now derived deterministically from the repo slug as shadow-<repo-slug>-canary on both sides: runtime reads VERCEL_GIT_REPO_SLUG (auto-injected by Vercel), CI reads github.event.repository.name / $GITHUB_REPOSITORY.
- Removes the class of bugs where the deploy workflow and middleware read/write different keys on a shared store
SHADOW_CANARY_KEYenv var and GH Actions secret are no longer used (ignored if present)configKeyoption onshadowCanaryMiddleware+getShadowConfig/readShadowConfig/patchShadowConfighas been removedDEFAULT_CONFIG_KEYexport removed — seeresolveConfigKey()(now takes no arguments)- Pre-flight “Verify SHADOW_CANARY_KEY consistency” step removed from workflows — no longer possible to desync by construction
- Local dev must set
VERCEL_GIT_REPO_SLUGin.env.local(or runvercel env pull); middleware logs a one-time warn + passes through in non-production, throws in production patchShadowConfignow rejects writes > 8 KB to protect shared stores from one tenant blowing the 64 KB store cap- Workflows gain a shared
concurrency: shadow-canary-${{ github.repository }}group so deploy + ramp can’t race on the same key
Upgrading an existing project:
- Bump
@dotworld/shadow-canary-coreto^0.3.0. - Re-copy the workflows:
npx @dotworld/shadow-canary-templates@latest copy . --forceon the.github/workflows/dir. - Remove the
SHADOW_CANARY_KEYGitHub Actions secret and Vercel env var (both ignored now). - Copy your Edge Config value to the new key. In the Edge Config store’s Items tab, duplicate the value from
shadow-configuration(or your custom key) into a new item atshadow-<repo-slug>-canary. Without this step, the middleware readsnullon the first post-upgrade deploy — the nextdeploy-shadow.ymlrun will repopulatedeploymentDomainShadow,trafficShadowPercent,trafficProdCanaryPercent, but any customshadowForceIPsentries need to be carried manually. - For local dev: add
VERCEL_GIT_REPO_SLUG=<your-repo-slug>to.env.local(or runvercel env pull).
v0.2.x
Series of patch releases on the original 0.2.0 design (configurable Edge Config key via SHADOW_CANARY_KEY). Superseded by v0.3.0’s deterministic key — these versions are still on npm but no longer recommended for new installs.
- 0.2.4 — guardrails against the silent-shadow trap: runtime
console.warnwhen the Edge Config key returns no value, pre-flight verification in workflows that the GH Actions secret matches the Vercel project env var. - 0.2.3 — configurable production branch (
productionBranchoption,SHADOW_CANARY_PRODUCTION_BRANCHenv var). Default'production'; pass''to disable the branch filter. - 0.2.2 — auto-wire Vercel Deployment Protection bypass on rewrites (
x-vercel-protection-bypass+x-vercel-set-bypass-cookie: samesitenone, sourced fromVERCEL_AUTOMATION_BYPASS_SECRET). - 0.2.1 — workflows honor
SHADOW_CANARY_KEY(was hardcoded to'shadow-configuration', breaking shared Edge Config store setups).
Initial release
Baseline shadow-canary feature set:
- Shadow slot: permanent 1% of production traffic on
master, configurable viatrafficShadowPercent - Canary ramp: SLO-gated 0→100% ramp on
productionmerges, +4%/15min (Europe/Paris curve) - Three GitHub Actions workflows:
deploy-shadow.yml,deploy-prod.yml,canary-ramp.yml - Single Edge Config key as the source of truth for routing state
- Commit markers:
[skip-canary]for direct promotes,[keep-canary]for fix-in-place /debugpage with bucket display and force-override buttons/admindashboard with Pause, Resume, Cancel, and 1-click rollback/api/slostub (replace with real signal — see SLO integration)- Slack notifications on canary start, 100% completion, and rollback
- IP allowlist (
shadowForceIPs) for forcing specific IPs to shadow - Session sticky cookies (
shadow-bucket) with 24-hour TTL
For per-package detail and migration steps: @dotworld/shadow-canary-core CHANGELOG, …-templates CHANGELOG. For tagged release notes: GitHub releases.