Flatten the instance `runtime` object into two fields: `runtime` (the JS engine,
node | workerd) and `platform` (the deployment host). The About page shows each
as its own row with friendly labels (e.g. "workerd" + "Cloudflare Workers",
"Node.js" + "Docker").
- Detect the platform from the entry file (entry === target): each serverless
entry declares it; entry-node sniffs Cloud Run (K_SERVICE) / Docker
(ZPAN_RUNTIME, set in the Dockerfile) / bare node. Cloudflare is detected from
the D1 binding.
- Decouple the cloud payload: zpan-cloud-sdk fixes runtime { provider, target },
so CloudInstanceInfo keeps that shape and buildCloudInstanceInfo maps to it;
buildInstanceInfo serves the richer flat shape to the About API.
- Migrate PostHog instance telemetry to the runtime/platform shape and merge the
duplicate runtimeInfo in licensing-admin into the shared one.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: v2.5.0 T4 — Netlify deployment target
- server/entry-netlify.ts: Netlify Functions v2 (ESM) handler using hono/netlify
adapter; connects to Turso via @libsql/client; skips in-process migrations
(workflow applies them before deploy via drizzle-kit)
- deploy/netlify/netlify.toml: build command, functions directory, SPA fallback redirect
- .github/workflows/deploy-netlify.yml: 8-step workflow — secret guard, tag resolve,
Turso migrations, build, netlify deploy --prod, BETTER_AUTH_SECRET first-deploy, summary
- package.json: add build:netlify script (tsup ESM → netlify/functions)
- docs/deploy/netlify.md: 5-section setup guide covering Turso, site creation,
secrets, deploy trigger, first-boot storage setup, and cost breakdown
Agent-Profile: https://agent-kanban.dev/agents/a6bb038c4226a87f
* fix: address Netlify deploy review blockers
BLOCKER 1 — move BETTER_AUTH_SECRET step before Deploy in workflow so
the function always has the secret set before its first cold start.
BLOCKER 2 — replace inline platform construction in entry-netlify.ts
with createLibsqlPlatform(); removes duplicated db/schema wiring and
re-unifies with the shared factory. migrate() runs at cold start and
is idempotent (~50–100ms) per the workflow's prior drizzle-kit migrate.
BLOCKER 3 — add --external @libsql/client to build:netlify so tsup
leaves the native-binding package for Netlify to resolve; switch
netlify.toml to node_bundler=esbuild so Netlify bundles @libsql/client
from node_modules. Add included_files=["migrations/**"] so the
migrations folder is available in the function zip for migrate().
Minor — replace 2>/dev/null with 2>&1 in deploy step so netlify-cli
errors surface in CI logs instead of being silently swallowed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Bob <aibob@mails.agent-kanban.dev>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>