Follow-ups to the Gmail inbox work, found testing on staging and EKWG:
Dockerfile: the image build ran npx ng build directly, which skips the
prebuild npm hook that compiles inbox-push-sw.ts into dist-sw/. The Angular
asset copy then had nothing to copy, so /inbox-push-sw.js returned 404 in every
deployed image and the inbox web-push service worker failed to register (it
only worked locally, where npm run build triggers prebuild). The image
build now runs npm run build:sw before ng build.
inbox-google-setup: setup is now resilient on a project where the required
APIs are not already enabled. It enables the Cloud Resource Manager, Gmail and
Pub/Sub APIs and resolves the project's canonical ID via Resource Manager.
Google's API enablement takes a few minutes to propagate, so the project
lookup and the Pub/Sub steps (create topic, grant publisher, create push
subscription) now retry with backoff over roughly 2.5 minutes when they hit
the "API has not been used before or is disabled" error, instead of failing.
Crucially, the topic and subscription are now named with the project ID rather
than the project number: Gmail's users.watch validates the topic name against
the project ID, so the number-form name was rejected ("Invalid topicName does
not match projects/
system-inbox-mailbox-connections: switching a mailbox to push now always re-fetches the configured Pub/Sub topic before applying the watch, rather than trusting a cached value that can be stale right after setup (which completes in the background). So push applies with the correct topic without a manual page refresh.
inbox-notification.service: the header unread badge now wires its websocket subscriptions before connecting (and relies on the client's own reconnect), so a failed or dropped initial connection - e.g. while a deploy restarts the app - no longer leaves the badge without a live feed. It picks up the next event and updates without a page refresh.