A live map of police, fire, medical and traffic calls near you, from the 911 feeds cities publish, plus weather warnings, earthquakes and wildfires. Push alerts for the places you care about and the p
翻译准备中
生活方式TypeScript · JavaScriptGitHub @moshcoder在线运营者未确认
试用过了吗? 点一下就好,无需登录。
Live 911 incidents near you, push alerts for your places, police radio. Every feature free. PWA, API, CLI, TUI, MCP.
翻译准备中
正在加载完整 README。
查看完整 README ↗Live 911 incidents near you on a map, push alerts for the places you care about, and the police and fire radio for your county. No account, no ads.
Free: the live map and list (24 h), radio, every kind of call, push alerts
for 1 place within 3 miles. Premium, $4.99 once for life (CoinPay): up to 25
places, up to 50 miles each, 7 and 30 days of history. Premium is a key
(ra_…), made at checkout and valid once the payment settles; the browser keeps
it, and X-Premium-Key sends it to the API.
GET /api/v1/incidents?lat=&lon=&km=&hours=&kinds=&min_severity=, /api/v1/incidents/:id, /api/v1/radio?lat=&lon=, /api/v1/sourcesbunx @profullstack/residentalerts near 47.61 -122.33, … watch 47.61 -122.33claude mcp add residentalerts -- bunx @profullstack/residentalerts mcpEmail sign-in with a one-time link (no password): /signin -> link (hashed,
single use, 20 min, spent by a POST so mail scanners cannot) -> 180-day
session cookie (writes only count with Sec-Fetch-Site: same-origin). An
account holds Premium (bought while signed in, or a key attached on
/account), synced alert places and the community name. Buying Premium and
posting need an account; the map, radio and one alert place do not.
Sign in with CoinPay (OAuth 2.1 code + PKCE S256, client
cp_14548d98fe01a7ca13c42dd0, COINPAY_OAUTH_CLIENT_ID/SECRET): accounts link
by CoinPay sub, never by email (CoinPay emails are unverified). A new
CoinPay-only account keeps that email aside as unverified (not an admin, not on
the mailing list) until it is confirmed with a one-time link from /account;
confirming an email that already has an account merges the two. A signed-in
email account can connect CoinPay from /account.
ADMIN_EMAILS have Premium. Mail goes through Resend (RESEND_API_KEY,
MAIL_FROM); GET /api/v1/admin/emails (x-admin-key) exports the opt-in list
as CSV.
Credit codes (@profullstack/redeem-credits):
a code grants the unit premium; one with amount 1 is lifetime Premium, the
same thing $4.99 buys. A signed-in person redeems it under "Have a code?" on
/account (or POST /api/v1/redeem {"code"} with the session cookie). The
credit is applied the way a purchase is: a settled $0 row in payments
(chain credit-code) on the account, so Premium has one source of truth and
moves with the account on a merge. Someone who already has Premium is refused
before the code is spent. Mint one on the server (run the bin under bun; its
node shebang fails as root):
cd /opt/resident.alerts
bun $(readlink -f node_modules/.bin/redeem-credits) mint --db "$DATABASE_PATH" \
--unit premium --amount 1 --label "for Dan" [--max 10] [--expires 30d]
bun $(readlink -f node_modules/.bin/redeem-credits) list --db "$DATABASE_PATH"
bun $(readlink -f node_modules/.bin/redeem-credits) revoke <codeId> --db "$DATABASE_PATH"
A grant --unit premium --amount 1 --user <account id> works too: it switches
on the next time that person opens /account.
Invites (@profullstack/affiliates):
three single-use links per account at /invites (GET/POST /api/v1/invites).
A link lands on /invite/<code> (/i/ is an incident page), rides in a 7-day
cookie, and is spent when that browser makes a new account (email link or
CoinPay). Premium is lifetime-only and there is nothing smaller to give, so an
invite gives neither person anything beyond the invite: we only remember who
brought whom. Every account also has an affiliate link (/?ref=<code>),
remembered first-touch for 30 days and credited to new accounts.
Customer webhooks via @profullstack/webhooks:
an account adds endpoints on /account#webhooks, with residentalerts webhook add <url>,
MCP create_webhook, or POST /api/v1/webhooks. The API takes an account API key
(Authorization: Bearer rak_…, made on /account, stored hashed, one per account), a
Premium key that belongs to an account (X-Premium-Key), or the signed-in session from our
own pages; anything else is 401. Bodies are CloudEvents, signed per Standard Webhooks,
queued in the app's SQLite (webhook_endpoints, webhook_deliveries) and retried for about
three days; URLs must be https to public addresses.
| Event | When | Owner |
|---|---|---|
alert.issued | a new incident (or a fire that grew into it) in a place saved to the account | the account whose places it is in |
alert.updated / alert.ended | an incident the account was sent changed / stopped being listed | same |
premium.activated | the account's Premium switched on (payment settled, or a credit code) | the account |
Devices stay anonymous push subscriptions, so they own no webhooks. A payload carries the incident as the public map shows it plus which of the owner's places it concerns: never a resident's name, token or media, nor anyone else's places. Same 30-minute freshness rule as push, at most 200 events an account an hour; deleting an account deletes its webhooks, and merging accounts moves them.
Residents (rt_ token + name, tied to an account): comments on every
incident, an area chat per ~40 km geohash cell, residents' own reports
(unverified; push only after two other residents confirm), photos and videos.
Photos are re-encoded in the browser (EXIF/GPS gone), MP4/MOV udta/meta
boxes are blanked on the server, files are capped (10 MB photo, 25 MB video,
30/day, MEDIA_MAX_GB total, oldest first) and served sandboxed with ranges.
Three flags hide anything; ADMIN_KEY removes and bans (resident + network).
Public feeds agencies publish themselves, read every few minutes on the server
(see src/cities.ts and /coverage):
以上为 README 的开头部分。其余内容请阅读原文。 查看完整 README ↗