Open-Source Cold Email & Warmup Platform
Warmbly is the open-source platform for cold email: warm your mailboxes, send campaigns, and triage every reply. Run it on our cloud or self-host the whole thing.
Single-operator outbound publishing service for the WitUS ecosystem.
MarketingTypeScript · JavaScriptGitHub @dapperAuteurOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Single-operator outbound publishing service for the WitUS ecosystem. Sibling to witus-inbox; routes signed-webhook publish requests to Ocoya.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Single-operator outbound publishing service for the WitUS ecosystem. Sibling to witus-inbox.Read the full README ↗Single-operator outbound publishing service for the WitUS ecosystem. Sibling to witus-inbox.
POST /api/ingest from any registered ecosystem product.scripts/import-radaar-csv.ts (the consultant calendar at gemini/witus/plans/social-media/consultant-response/she_clocked_in_radaar_import.csv).PublisherAdapter interface in lib/publishers/. Switching backends = add an adapter file, flip one env var./api/admin/tick; outbox dispatches to the active adapter.error at publish time./outbox for manual retry / reschedule / cancel / reconcile-now.DB columns are publisher-agnostic (publisher_backend, publisher_post_id, publisher_profile_id). Apps Script holds zero publisher credentials. Social-account changes need no code change — the next tick refreshes the cache from whichever adapter is active.
ADMIN_EMAIL)@sentry/nextjs SDK pointed at Better StackPoint uptime monitors at GET /api/health, not at /. The homepage can return a cached 200
while Postgres is down, so a green check there means nothing. /api/health is public,
unauthenticated, never cached (force-dynamic + Cache-Control: no-store) and runs one real
select 1 against Neon on every request:
| Condition | Status | Body |
|---|---|---|
| Database answers | 200 | {"ok":true,"checkedAt":"<ISO 8601>"} |
| Database unreachable, erroring, or slower than 4s | 503 | {"ok":false,"error":"database_unreachable"} |
The failure body is that fixed token and nothing else. Neon connection errors routinely embed the
connection string including the password, so the raw error never crosses the response boundary;
only the content-free error class name and SQLSTATE (via lib/db-safe.ts) go to the server log.
It checks the database and nothing else. It deliberately does not call Ocoya, SocialChamp, Mailgun or Mobile Text Alerts, and reports nothing about which publisher backend is configured or whether its token is valid: a vendor outage is not an outbox outage and must not turn the monitor red, provider error bodies echo bearer tokens, and this endpoint is open to the internet.
Not to be confused with GET /api/admin/health, which is bearer-authed and answers a different
question: "did the Apps Script reconciler tick recently, and what last broke?"
The reconciler itself is watched by a Better Stack heartbeat: /api/admin/tick pings
BETTERSTACK_HEARTBEAT_URL only at the end of a successful tick. A missed heartbeat IS the
signal — it means Apps Script stopped calling or the tick started failing — so failure paths
deliberately do not ping. Inert until the env var is set; the ping is awaited with a short timeout
and can never fail the tick itself.
Server, edge and browser errors report through the @sentry/nextjs SDK to a Better Stack source. The
SDK is guarded on the DSN: with SENTRY_DSN / NEXT_PUBLIC_SENTRY_DSN unset, init() never runs
and the whole layer is inert (__tests__/sentry-inert.test.ts guards that). Set the vars listed in
.env.example to turn it on; plans/user-tasks/16-error-monitoring-dsn.md has the operator steps.
Because outbox holds the ecosystem's publishing credentials, lib/sentry-scrub.ts runs a strict
beforeSend pass on every runtime: request bodies are dropped outright, cookies and credentialed
headers are deleted, captured local variables are dropped, and publisher API keys, ingest HMAC
secrets, social-platform OAuth tokens, JWTs, connection-string passwords and email addresses are
redacted out of messages, exception values, breadcrumbs, tags and extras. lib/sentry-scrub.test.ts
asserts the serialized event contains none of them.
app/global-error.tsx is the last-resort boundary for a crash in the root layout itself, which
error.tsx cannot catch because the layout is the thing that broke. It renders its own
<html>/<body> with inline styles and imports nothing but the Sentry SDK, so a broken component or
an unloaded stylesheet cannot take the error page down with it.
There is no Content-Security-Policy in this repo (no headers() in next.config.ts, no CSP in
proxy.ts, no <meta http-equiv>), so no connect-src has to name the ingest origin. If a CSP is
ever added it must list the DSN's origin, or the browser silently drops every client-side report and
the dashboard just looks quiet.
Traces go to Honeycomb over OTLP via @vercel/otel (otel.config.ts, registered from
instrumentation.ts before the Sentry configs load — whoever registers the global tracer
provider first wins, and Sentry is told to stand down via skipOpenTelemetrySetup in
sentry.server.config.ts). Service name is witus-outbox.
HONEYCOMB_INGEST_API_KEY_SECRET (fallback HONEYCOMB_API_KEY).
Same inert-until-provisioned pattern as the Sentry DSN — with neither var set, registration is
skipped entirely./api/health spans are dropped at the sampler — Better Stack probes it around the clock, and
those requests must not spend Honeycomb's free-tier event budget. Everything else is recorded
unsampled.@vercel/otel honors incoming W3C traceparent headers, so a publish request signed by a
sending ecosystem app continues here as the same distributed trace.Anonymous page-view analytics go to the ecosystem's shared PostHog project (US region), wired
exactly per witus-online's lib/analytics/INTEGRATE.md:
lib/analytics/posthog-provider.tsx and lib/analytics/capture.ts are byte-for-byte copies of
witus-online's files — don't edit them here; the init options are the ecosystem privacy posture.
lib/analytics/events.ts is this app's own taxonomy (ANALYTICS_APP = "outbox", the identity slug
from witus-online lib/identity/clients.ts).autocapture: false, session replay disabled, persistence: "memory" (no cookie,
no localStorage — so no consent banner), no identify(). Every event carries app: "outbox".
Because identity lives for one page session, treat "users" as "sessions"./ingest (rewrite in next.config.ts → https://us.i.posthog.com), so
ad blockers don't drop events. skipTrailingSlashRedirect: true is required for that. proxy.ts
uses explicit-path matchers, so it never touches /ingest. No app route may start with /ingest.NEXT_PUBLIC_POSTHOG_KEY (and NEXT_PUBLIC_POSTHOG_HOST, set
explicitly to https://us.i.posthog.com). Redeploy after setting — NEXT_PUBLIC_* is build-time.capture() from lib/analytics/capture.ts with a name from EVENTS.node scripts/check-posthog-conformance.mjs /path/to/witus-outbox.Playwright specs live in e2e/; the gate runs in .github/workflows/e2e.yml on
deployment_status — it tests the real Vercel deployment URL (preview → full suite,
production → @smoke only), so CI needs no secrets, database, or env. The suite runs desktop plus
a 360px mobile project, and every covered page must pass an axe check with zero serious or
critical WCAG A/AA violations — the gate is strict on purpose; fix the page, not the gate.
PLAYWRIGHT_BASE_URL=<url> npx playwright test (drives installed Chrome via
channel: "chrome"; Playwright's bundled chromium doesn't support macOS 13).VERCEL_AUTOMATION_BYPASS_SECRET Actions secret; public previews need
nothing.x-witus-origin-test: playwright-synthetic, which the OTel layer surfaces as the
witus.origin_test span attribute — Honeycomb queries (and logs/analytics) can include or
exclude test traffic. Absent header = attribute absent = real user.Optional. Set WITUS_OIDC_CLIENT_ID (witus-outbox) and WITUS_OIDC_CLIENT_SECRET (equal to
WITUS_OIDC_SECRET__OUTBOX on the witus.online IdP) and /auth/sign-in offers "Sign in with WitUS"
alongside the email magic link. Both are read at request time on the server, so setting them and
redeploying is enough; there is no separate client-side flag (the old NEXT_PUBLIC_WITUS_SSO is no
longer read). The client is registered in the witus repo's lib/identity/clients.ts (slug outbox)
with the redirect URI https://outbox.witus.online/api/auth/callback/witus.
ADMIN_EMAIL gate as the magic link
(lib/auth-gate.ts), and additionally need the IdP's email_verified claim to be true.email_verified check, which NextAuth runs before it links.id_token_signed_response_alg: "EdDSA" (openid-client defaults to RS256 and would fail at the
callback)./auth/sign-in?error=<code> with a notice
(lib/auth-error.ts) instead of NextAuth's bare error page.Two more behaviours ride on that config, and both stay completely dark without it:
<idp-origin>/api/ecosystem/session (derived from WITUS_OIDC_DISCOVERY_URL, never hardcoded a
second time) whether this browser already has a WitUS session. If it does, the button relabels to
"Continue as <name>". A blocked, failed or timed-out probe is invisible — no error, no
spinner, no layout shift — which is the common case on Safari and Firefox, where the IdP cookie is
a partitioned third-party cookie. The name is display copy only: clicking still runs the real OIDC
code flow, which is the only thing that establishes identity. A one-shot marker
(sessionStorage["witus.sso.attempted"], plus a ?sso=tried query param) is written before
the redirect so a stale IdP session cannot produce a sign-in loop./auth/sign-in; your WitUS session
and every other WitUS app stay signed in. With SSO configured, a second, secondary control,
Sign out of WitUS everywhere, also ends the shared session at accounts.witus.online; its help
text says other WitUS apps stay signed in until you sign out of them. That control destroys the
local NextAuth session first, then hands the browser to the IdP's end_session_endpoint, so an
unreachable or refusing IdP still leaves you signed out here. Without SSO configured only
Sign out shows.Design and reasoning: lib/silent-sso.ts. Tests: lib/silent-sso.test.ts.
Phase 1 in progress. Repo bootstrap. See plans/01-witus-outbox-bootstrap.md (local-only) for the full approved plan.
External steps that block Phase 1 smoke testing live in plans/user-tasks/.
Inbox is receive-only; outbox is send-only. Mixing the two in one app would couple unrelated lifecycles, secrets, and rate-limit budgets. Separation lets each service own one job — matching the WitUS ecosystem's "every platform has one job" rule.
See LICENSE when added.