Native push notifications (Apple Push Notification service).
ONE job: when a turn finishes on this gateway, wake the phone that asked to be woken. Everything here is server-side; the app only ever hands us a device token.
Three moving parts:
Credentials. A token-based APNs auth key (.p8, ES256) plus its key
id, the Apple team id and the app's bundle id (the APNs topic).
Resolved from VIS_APNS_KEY_PATH / VIS_APNS_KEY_ID / VIS_APNS_TEAM_ID
/ VIS_APNS_TOPIC, else auto-discovered from ~/.vis/apns/AuthKey_<kid>.p8
(the key id is read off the filename) with the team/topic still from env
or ~/.vis/apns/apns.edn. No credentials = push silently OFF; the gateway
keeps working exactly as before.
A device registry at ~/.vis/devices.edn — device token -> platform,
APNs environment, client label/version, timestamps. Registration is
idempotent on the token. Tokens are SECRETS: nothing here logs more than
a masked prefix.
A sender — a signed ES256 JWT (cached, refreshed well inside Apple's
one-hour window) over HTTP/2 to api.push.apple.com. A device that
registered with the wrong environment is retried once against the other
host, and an APNs BadDeviceToken/Unregistered verdict evicts the
device so a stale token cannot accumulate.
The wire surface lives in gateway.server (/v1/devices); this namespace
knows nothing about Ring.
Native push notifications (Apple Push Notification service). ONE job: when a turn finishes on this gateway, wake the phone that asked to be woken. Everything here is server-side; the app only ever hands us a device token. Three moving parts: 1. **Credentials.** A token-based APNs auth key (`.p8`, ES256) plus its key id, the Apple team id and the app's bundle id (the APNs *topic*). Resolved from `VIS_APNS_KEY_PATH` / `VIS_APNS_KEY_ID` / `VIS_APNS_TEAM_ID` / `VIS_APNS_TOPIC`, else auto-discovered from `~/.vis/apns/AuthKey_<kid>.p8` (the key id is read off the filename) with the team/topic still from env or `~/.vis/apns/apns.edn`. No credentials = push silently OFF; the gateway keeps working exactly as before. 2. **A device registry** at `~/.vis/devices.edn` — device token -> platform, APNs environment, client label/version, timestamps. Registration is idempotent on the token. Tokens are SECRETS: nothing here logs more than a masked prefix. 3. **A sender** — a signed ES256 JWT (cached, refreshed well inside Apple's one-hour window) over HTTP/2 to `api.push.apple.com`. A device that registered with the wrong environment is retried once against the other host, and an APNs `BadDeviceToken`/`Unregistered` verdict evicts the device so a stale token cannot accumulate. The wire surface lives in `gateway.server` (`/v1/devices`); this namespace knows nothing about Ring.
(broadcast! notification)Send one notification to every registered device. Returns a per-device summary; never throws.
Send one notification to every registered device. Returns a per-device summary; never throws.
(config)Resolved APNs credentials, or a map with :is-configured false and the
list of what is still missing. Never throws and never returns key MATERIAL.
Resolved APNs credentials, or a map with `:is-configured false` and the list of what is still missing. Never throws and never returns key MATERIAL.
(configured?)True when this gateway can actually deliver a push.
True when this gateway can actually deliver a push.
(devices-file)Where the device registry is persisted.
Where the device registry is persisted.
(list-devices)Every registered device, tokens MASKED — safe for an HTTP response.
Every registered device, tokens MASKED — safe for an HTTP response.
(mask token)A device token is a secret. This is the ONLY form allowed into a log.
A device token is a secret. This is the ONLY form allowed into a log.
(on-event! sid event)Event tap: push exactly on a terminal turn event, and only when push is both configured and wanted by at least one device. Cheap and silent otherwise — this runs on EVERY gateway event.
Event tap: push exactly on a terminal turn event, and only when push is both configured and wanted by at least one device. Cheap and silent otherwise — this runs on EVERY gateway event.
(register-device! {:keys [token platform environment client client-version label
bundle-id]})Idempotently register (or refresh) one device token. Returns the stored device, or nil when the token is unusable.
Idempotently register (or refresh) one device token. Returns the stored device, or nil when the token is unusable.
(reload-devices!)Drop the in-memory cache and re-read the registry from disk.
Drop the in-memory cache and re-read the registry from disk.
(send-to-device! device notification)Deliver one alert to one registered device. Retries once against the other
APNs environment (a TestFlight build registered as sandbox, or the
reverse, is the single most common misconfiguration) and evicts the device
when Apple says the token is dead. Returns {:is-delivered bool :status :reason}.
Deliver one alert to one registered device. Retries once against the other
APNs environment (a TestFlight build registered as `sandbox`, or the
reverse, is the single most common misconfiguration) and evicts the device
when Apple says the token is dead. Returns `{:is-delivered bool :status
:reason}`.(set-session-describer! f)Install the fn that turns a session id into {:title …} for the alert.
Install the fn that turns a session id into `{:title …}` for the alert.
(status)Push capability for /v1/capabilities and /v1/admin/status.
Push capability for `/v1/capabilities` and `/v1/admin/status`.
(unregister-device! token)Drop one device token. Returns true when it was present.
Drop one device token. Returns true when it was present.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |