Skip to content

feat: P2 push client — register device + route approval notifications - #7

Merged
saucam merged 1 commit into
mainfrom
feat/p2-push-client
Jul 26, 2026
Merged

feat: P2 push client — register device + route approval notifications#7
saucam merged 1 commit into
mainfrom
feat/p2-push-client

Conversation

@saucam

@saucam saucam commented Jul 26, 2026

Copy link
Copy Markdown
Collaborator

What

Push notifications — the mobile client (P2 push, slice 2 of 3). codeoid-mobile now registers for and routes the daemon's content-blind approval pushes. Pairs with the daemon backbone (codeoid #249, merged).

Flow

  1. On connect, the client declares the push capability. If the daemon advertises it back on auth.ok (i.e. a push transport is configured), the client requests notification permission, fetches this device's Expo push token, and sends push.register { token, platform }. Fire-and-forget — a registration failure never fails the connection. Sign-out sends push.unregister.
  2. The daemon sends a content-blind wake-up (opaque session id only) when one of this user's sessions blocks on approval.
  3. Tapping it opens that session, where the P2 approval bar (already shipped) shows what's pending. Warm taps navigate immediately; a cold-launch tap is stashed and opened once the sessions screen is connected. Foreground pushes still show a banner (approvals are time-sensitive).

Release coupling (why the shim)

The daemon's push.* is merged but not yet in a published @codeoid/protocol release, and this app pins the registry version — so src/lib/push-protocol.ts locally mirrors push.register / push.unregister + the "push" capability, cast at one send boundary. The daemon already validates these exact shapes. Once the release ships, delete that file and import from @codeoid/protocol — the shapes are identical by construction. (This app's @codeoid/protocol pin also needs bumping to the release then; it's currently stale.)

Deps + build

  • Expo SDK 57 bundled versions: expo-notifications@~57.0.3, expo-device@~57.0.0.
  • app.json gains the expo-notifications plugin; new eas.json (development / preview / production).
  • Remote push tokens require a dev/standalone buildgetExpoPushTokenAsync throws in Expo Go for a custom bundle id — so push lights up under eas build --profile development, not Expo Go. The client degrades gracefully (logs + skips) elsewhere and no-ops on web.

Verification

  • tsc + eslint clean; expo export --platform web bundles 1018 modules (notification deps import cleanly).
  • Device e2e (real push delivery + tap → approval) needs the EAS dev build plus a daemon with push.transport: expo configured — the one step that can't run headlessly.

Follow-ups

  • Slice 3: self-hosted content-blind relay + iOS Notification Service Extension + daemon reverse channel for background Approve/Deny (without opening the app).
  • Post-release: drop the protocol shim, bump @codeoid/protocol.

🤖 Generated with Claude Code

Slice 2 of push: codeoid-mobile now registers for and routes the daemon's
content-blind approval pushes. Pairs with the daemon backbone (codeoid
#249, merged); consumes push.* via a local wire shim until that ships in a
published @codeoid/protocol release.

- Declares the `push` capability; on a connect where the daemon advertises
  it (i.e. a push transport is configured), requests notification
  permission, fetches this device's Expo push token, and sends
  push.register { token, platform }. Fire-and-forget — a registration
  failure never fails the connection. Unregisters on sign-out.
- Tapping a push opens its session (the P2 approval bar shows what's
  pending): warm taps navigate immediately; a cold-launch tap is stashed
  and opened once the sessions screen is connected. Foreground pushes still
  show a banner (approvals are time-sensitive).
- src/lib/push-protocol.ts: local mirror of push.register / push.unregister
  + the "push" capability, cast at one send boundary. Delete and import
  from @codeoid/protocol once the release ships — the shapes are identical
  by construction and the daemon already validates them.
- Deps (Expo SDK 57 bundled): expo-notifications@~57.0.3,
  expo-device@~57.0.0. app.json gains the expo-notifications plugin; new
  eas.json (development / preview / production profiles).

Note: remote push tokens require a dev/standalone build — getExpoPushToken
throws in Expo Go for a custom bundle id — so push lights up under
`eas build --profile development`, not Expo Go. The client degrades
gracefully (logs + skips) everywhere else, and no-ops on web.

Verified: tsc + eslint clean; expo export (web) bundles 1018 modules
(expo-notifications / expo-device import cleanly). Device e2e (real push
delivery + tap) needs the dev build plus a daemon with push configured.

Signed-off-by: Yash Datta <saucam@gmail.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatedexpo-constants@​57.0.3 ⏵ 57.0.77610079100 +1100
Addedexpo-notifications@​57.0.77810084100100
Addedexpo-device@​57.0.110010081100100

View full report

@saucam
saucam merged commit 867697f into main Jul 26, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants