nucleic-edge
Cloudflare Worker for Nucleic's cloud edge. See docs/CLOUD_INFRA.md for the full design.
- Phase A (now):
POST /v1/heartbeat— anonymous DAU heartbeat → Workers Analytics Engine (nucleic_dau).GET /healthfor a liveness check. - Phase B/C (later): WebSocket relay (Durable Object
Room) + APNS approval push. Bindings for those are stubbed as comments inwrangler.jsonc.
Develop
npm install
npm run typecheck # tsc --noEmit
npm test # vitest — unit tests for the payload validator
npm run check # wrangler deploy --dry-run (bundles, no upload, no auth)
npm run dev # local server at http://localhost:8787
POST smoke test against a local npm run dev:
curl -i -XPOST http://localhost:8787/v1/heartbeat \
-H 'content-type: application/json' \
-d '{"installId":"11111111-2222-3333-4444-555555555555","platform":"macos","osVersion":"26.0","channel":"beta","appVersion":"0.1.0","build":"42","arch":"arm64","locale":"en"}'
# → 204
(AE writes are accepted but not queryable from local dev; verify counts after deploy.)
Provision (one-time, Cloudflare dashboard / API)
-
Ensure the
blakeslee.xyzzone is on this account (theroutescustom domain needs it). -
Deploy:
npm run deploy— provisionsapi.nucleic.blakeslee.xyz+ cert and creates thenucleic_daudataset on first write. -
Query DAU (AE SQL API), e.g. last 30 days split by platform:
SELECT toStartOfDay(timestamp) AS d, blob1 AS platform, count(DISTINCT index1) AS dau FROM nucleic_dau WHERE timestamp > now() - INTERVAL '30' DAY GROUP BY d, platform ORDER BY d
Blob/index layout (keep in sync with the client + the SQL above)
| Field | Slot |
|---|---|
installId |
index1 |
platform |
blob1 |
osVersion |
blob2 |
channel |
blob3 |
appVersion |
blob4 |
build |
blob5 |
arch |
blob6 |
locale |
blob7 |
Relay + APNS (Phase B/C)
The relay is E2EE-opaque: binary WebSocket frames are forwarded byte-for-byte and never
inspected (Noise runs end-to-end through it). A separate text control plane carries non-secret
relay metadata. See docs/CLOUD_INFRA.md §2–§3 and §2.1 for the token lifecycle.
Endpoints
| Method & path | Auth | Purpose |
|---|---|---|
GET /relay?t=<connToken> (Upgrade) |
connection token | Join a room's WebSocket |
POST /v1/relay/token |
RELAY_ADMIN_SECRET |
Host mints a 90-day membership token for a paired device |
POST /v1/relay/connect |
membership token (Bearer) | Trade membership → a ~2-min connection token |
POST /v1/relay/revoke |
RELAY_ADMIN_SECRET |
Revoke a device on unpair ({deviceId}) |
POST /v1/push/notify |
RELAY_ADMIN_SECRET |
Out-of-band APNS wake for {deviceId} |
Control-plane frames (text JSON over the room socket):
- phone → relay:
{"t":"register","pushToken":"<hex>","env":"sandbox|production"} - host → relay:
{"t":"wake","deviceId":"<id>"}— pushes only if that device's socket is absent - relay → all:
{"t":"presence","peers":[{deviceId,role}]}
Provision (one-time)
- KV:
wrangler kv namespace create NUCLEIC_RELAY_TOKENSand... NUCLEIC_PUSH_TOKENS; paste the ids intowrangler.jsonc. - Relay secrets:
wrangler secret put RELAY_TOKEN_SECRET(random 32+ bytes),RELAY_ADMIN_SECRET. - APNS: create a
.p8auth key (Apple Developer → Keys, Push enabled), thenwrangler secret put APNS_KEY_P8(paste the PEM),APNS_KEY_ID,APNS_TEAM_ID(L7UDTQ6F5W),APNS_TOPIC(xyz.blakeslee.nucleic.remote),APNS_ENV(sandboxfor TestFlight/dev,productionfor App Store). - Enable Push Notifications on the
xyz.blakeslee.nucleic.remoteApp ID; ship the iOS app withaps-environment. npm run deploy(creates theRoomDO on first deploy).
Smoke test (after deploy)
M=$(curl -s -XPOST https://api.nucleic.blakeslee.xyz/v1/relay/token \
-H "authorization: Bearer $RELAY_ADMIN_SECRET" \
-d '{"roomId":"r1","deviceId":"host1","role":"host"}' | jq -r .token)
C=$(curl -s -XPOST https://api.nucleic.blakeslee.xyz/v1/relay/connect \
-H "authorization: Bearer $M" | jq -r .token)
websocat "wss://relay.nucleic.blakeslee.xyz/relay?t=$C" # then a second client in room r1
APNS delivery must be exercised from the deployed Worker — local
wrangler devcan't do HTTP/2 to Apple (workerd #4841).