feat: notifications in PlatformClient - #40
Closed
ABujalance wants to merge 9 commits into
Closed
Conversation
Apps can already call the notification API — the iframe hands them the signed-in user's JWT — so this is client methods over endpoints that are already live, not new surface. Adds getNotifications, getUnreadNotificationCount, markNotificationsRead, markAllNotificationsRead, getNotificationSubscriptions and unsubscribeFromAutomation. The types come from the backend repo through a submodule rather than being copied into src/types like every other type here. Those copies are why base.ts has to alias ObjectId to string and hope it stays true; the backend's src/common/dto describes what the API actually sends and imports nothing from mongodb, so it compiles in a browser build unchanged. The submodule is sparse-checked-out to that one directory, so 37 files land on disk instead of the whole backend repo. Sparse config lives in the submodule's .git and does not survive a clone, which is why CI runs types:init after checkout. Moving the pin is `yarn types:update`, a command rather than a postinstall hook: an install that silently moved it would break builds with no commit explaining why. vite-plugin-dts and tsconfig both needed the vendored path adding. Without it the published .d.ts re-exports from ../../vendor/... and that resolves to nothing once installed — the build succeeds and consumers get broken types. Pinned to the backend's feature/notification-dtos branch until that merges.
backend-api#321 is merged, so the DTOs no longer live on a feature branch. Tracking dev rather than main because that is where they are: main gets them with the next release, and repointing is a one-line change here plus yarn types:update. Pin includes the review fixes on that PR — the base.dto helpers are gone and the type union guard is bidirectional.
The backend repo is private, so the default GITHUB_TOKEN cannot clone it and checkout with submodules: true fails outright with "Repository not found". Credential is scoped to the fetch step via url.insteadOf and unset immediately after, rather than handed to actions/checkout. Passing it to checkout would make it the identity for everything else in the job, including the release workflow's version-bump push. Needs a BACKEND_TYPES_TOKEN secret on this repo with read access to contents on platform_backend-api.
The failure was a bare "Repository not found" from git, which says nothing about the cause or the fix. CI now fails with an annotation, a job summary and step-by-step setup instructions. Also accepts a deploy key as an alternative to the token. A read-only deploy key on the backend repo never expires and belongs to the repo rather than to whoever created it, so the yearly token rotation goes away. Both work by rewriting the https URL rather than editing .gitmodules, so cloning over https locally is unaffected. The credential handling moved out of the workflows and into the script, so the two workflows cannot drift and the guidance sits next to the failure.
Replaces the standing token with an App-derived one, scoped to platform_backend-api and valid for an hour, so the only long-lived secret is an App key that grants nothing by itself. A plain token or a deploy key still work if those secrets are set instead. Failure instructions now lead with the App setup.
Three methods the client was missing. subscribeToAutomation and updateAutomationSubscription cover the project routes that have been live since task 04. Without them an app could list and cancel subscriptions but never create one, which is a daft half of the feature. onNotification opens the /notifications socket namespace added in backend-api#325. It is deliberately unlike onExecutionProgress: that one follows a single execution and closes when it ends, while a bell stays connected for the session, so this returns a disconnect function instead of managing its own lifecycle. Events carry ids rather than notifications, so a burst stays cheap and the socket is never the source of a stale render. The token is resolved per connection so a provider-backed client opens with a current one.
This repo is public and the backend is private, so vendoring its DTOs made a clean clone unbuildable and left fork PRs, which get no secrets, with no way to run CI. Reaching outside src also moved tsc's root: the published layout became dist/src/... plus dist/vendor/... with index.d.ts as a stub, so every deep import broke. Both are Sergio's findings and both are hard blockers rather than preferences. The types are declared in src/types/notifications.ts instead, the same as every other type in this package, with a note on why and what sharing them properly would take. Sharing needs the backend's wire DTOs published as their own package so they arrive through node_modules rather than through the source tree. The client methods are unaffected and stay. Also removes the App-token CI step, which had no fallback path anyway: without continue-on-error the job died before the || could be evaluated.
The API returns `outcome`, `groupKey` and `groupLabel` on every automation notification and this mirror did not have them, so an app building against the package was told they do not exist. `outcome` matters most. Without it the only way to know whether a run failed is to match on `title`, and `title` is built from the user's own automation name — an automation called "Failover sync" reports every successful run as a failure to anything reading the copy. That is not a hypothetical; it shipped in our own client and had to be fixed there. `groupKey` and `groupLabel` are what a client needs to collapse a busy automation's runs into one row instead of fifty.
Three changesets on one unreleased feature meant three changelog entries for what a reader experiences as a single addition, split by the order the branch happened to be built in rather than by anything meaningful to a consumer.
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Apps can read and manage the signed-in user's notifications, subscribe to
automations, and listen for new ones live. Nothing here existed before — the
package had no notification surface at all.
Changes
PlatformClientgainsgetNotifications,getUnreadNotificationCount,markNotificationsRead,markAllNotificationsRead,getNotificationSubscriptions,subscribeToAutomation,updateAutomationSubscriptionandunsubscribeFromAutomation. All scoped tothe signed-in user through the bearer token an app already holds.
onNotification, a live socket subscription. UnlikeonExecutionProgressitstays connected for the session rather than closing on a terminal event, and
returns a function that disconnects.
src/types/notifications.tsmirrors the backend's wire DTOs by hand, thesame as every other type here, including
outcome,groupKeyandgroupLabel.outcomeis worth calling out: it is how an automation run ended, and it isthe field to read rather than matching on the copy.
titleis built from theuser's own automation name, so an automation called "Failover sync" makes every
successful run look failed to anything parsing the text. That one shipped in
our own client before it was caught.
Related
Consumes the notifications API from platform_backend-api. The CI commits here
authenticate the cross-repo submodule fetch with a GitHub App credential rather
than a PAT.