notification catalogue: GET /api/notify/mapping
the piece that makes a new notification kind a server change rather than an app store release. a push carries a code and integers; this is what the code means, synced to the device instead of compiled into it. deliberately the same shape as affordances rather than a second mechanism: a `notifications/` directory of yaml in the plugin repository, copied to capabilities/notifications/<publisher>/<appName>/ on install, removed on uninstall. publish.ts mirrors affordances/publish.ts closely enough to diff. the namespace is DERIVED from where the file lands, never from what it declares — same rule as mountPrefix. a plugin writing `officer/core:test` as a key gets `<publisher>/<plugin>:officer/core:test` and the real core entry is untouched. that is the security property of the whole scheme and it is pinned by test. version is a content hash, not a counter. a counter needs somewhere to live and is then wrong after a restore, a rollback, or two servers built from the same install; a hash needs no storage and is right in all three. so the client compares mv !== version, and both docs now say so — i had written "higher". core entries ship in code rather than on disk, because capabilities/ is installed rather than committed and `test` has to exist on a machine that has installed nothing — it is what first light is proved with. read from disk per request, not memoised: installing a plugin has to change the answer without a restart, or it presents as "the new plugin's notifications don't work", which is the hardest kind of bug to place. verified live: 401 through the platform, plugin catalogue appearing and disappearing with no restart, version returning to its prior value when the plugin is removed. 10 catalogue tests, 100% coverage of catalogue.ts.
This commit is contained in:
@@ -119,6 +119,37 @@ normalised into one. A plugin ships an
|
||||
`affordances/` directory in its repository; installing copies it in, uninstalling removes it — the same
|
||||
shape as `assets/` and `publishAssets`.
|
||||
|
||||
## Notifications — the same shape, for push
|
||||
|
||||
A plugin can also declare what its push notifications MEAN. Same mechanism, different store:
|
||||
|
||||
```
|
||||
capabilities/notifications/
|
||||
officerdev/music/
|
||||
catalogue.yaml
|
||||
```
|
||||
|
||||
```yaml
|
||||
nowPlaying:
|
||||
title: 'Now playing'
|
||||
route: 'officer://music/{id}'
|
||||
```
|
||||
|
||||
That becomes the code `officerdev/music:nowPlaying`. A push carries the code and integers — never content —
|
||||
and the device renders the title and follows the route. The point is that **adding a notification is a
|
||||
server change and never an app build**, because the mapping is synced to the device rather than compiled
|
||||
into it.
|
||||
|
||||
**The namespace comes from where the file lands, not from what it says.** Writing `officer/core:test` as a
|
||||
key in your own catalogue produces `<you>/<yourplugin>:officer/core:test`, not the core code — the same
|
||||
rule as `mountPrefix`, and pinned by test in `src/servers/notifications/catalogue.test.ts`.
|
||||
|
||||
An entry needs a `title`; `body`, `target`, `route` and `thread` are optional, `thread` defaults to your
|
||||
namespace, and unknown keys are dropped rather than forwarded to the device. Broken YAML in one plugin's
|
||||
catalogue is skipped without affecting anyone else's.
|
||||
|
||||
See `docs/push-notifications.md`.
|
||||
|
||||
### A plugin-contributed one, for reference
|
||||
|
||||
This is the gitea plugin's, and it shows what these are for: the agent cannot discover from the
|
||||
|
||||
Reference in New Issue
Block a user