-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture and Privacy
The collector reads top-level .notice, .updated, and .error elements under #wpbody-content and its immediate .wrap. A debounced MutationObserver handles late insertion, text changes, and severity changes. Nested editor feedback, Relay itself, #message, forms, and input controls are excluded.
The collector removes scripts/styles/dismiss controls from its text copy and sends at most 40 records per request. Original plugin output and actions remain unmodified except for provenance attributes and eligible informational-notice visibility. Custom buttons, warnings, errors, successes, and forms remain visible. Saving must succeed before an informational notice is hidden. If a hidden notice changes into a warning it is revealed.
Server-side wrappers retain the original notice callback's hook id, priority, arguments, return value, and output. Reflection attributes the emitting PHP file to its plugin; a shared renderer can therefore be labeled as the renderer rather than an upstream caller. JavaScript-only or unrecognized emitters stay unknown. Sender/kind attributes carry a WordPress nonce scoped to user, site, sender, and kind. This is provenance within a trusted WordPress installation, not a security boundary against other installed PHP plugins or same-origin scripts.
An explicit publisher API can register a sender and label a notice as a promotion. Relay does not guess promotional intent from text. Rules only affect information from an identified sender and never pins, warnings, or errors. Saving a rule is prospective: it takes effect on subsequent collection. Reset does not restore history.
One schema-3 document lives in user metadata at station_inbox_<blog_id>, containing records, settings/rules, a bounded Undo entry, and a monotonic revision. Legacy maps migrate on the next mutation. API routes always use the acting user; callers cannot choose a target user.
Record identity hashes verified sender (if any), severity, and normalized text. An exact legacy unknown record can be upgraded to a verified identity while preserving its choices. Records hold text, sender label/kind, sanitized source URL, first/last encounter, archive state, snooze deadline, read state, and pin state. Changed text is a new record.
Limits are 50, 150, or 300 records with at most 25 pins. Pins are retained first. Eviction forgets the record's archive decision, so it can appear as new later. Custom snooze dates use an IANA timezone and reject nonexistent spring-forward times; repeated fall-back times use PHP's deterministic offset choice. Both views display the resulting return time. Timers update open contexts at the next snooze expiry; suspended browsers catch up on focus or reload.
Source URLs are reconstructed beneath the site's admin URL, keeping an allowed PHP path and plugin-page parameter. Nonces, mutation parameters, original HTML, and executable action buttons are not persisted. Data is stored in the WordPress database without separate encryption. Site owners, trusted PHP plugins, backups, and database administrators can access it. Private inboxes describe application-level separation between users.
An atomic INSERT IGNORE into a unique non-autoloaded option name provides a short write lease per user/site. A conflict returns HTTP 409; it never silently overwrites another successful save. The lease expires after 60 seconds and is released conditionally by its owner in finally. User metadata is reread after acquiring it.
Bulk archive validates the entire selection before writing. Undo stores prior archive/snooze fields with a five-minute token. It restores only rows still bearing that archive token, preserving later read/pin choices and later restore/snooze decisions. Saving a retention limit or deleting history clears Undo.
The AJAX transport serializes local requests and rejects stale revisions. BroadcastChannel, or a localStorage fallback, carries only a revision in a channel named by an HMAC of the current user/site. Other contexts refetch through authenticated endpoints. No notice text is broadcast or placed in localStorage. OpenStation content-change watches refresh the native app; unchanged revisions do not rebroadcast. Native actions use framework effects to avoid their own echo.
Personal-history deletion explicitly confirms removal of records and Undo, including pins; settings/rules remain. Deactivation preserves data. Uninstall removes Relay inbox documents for all users/sites. Test fixtures and dependencies are excluded from the install ZIP.
There is no background crawl, email, external account, analytics, or automatic promotional-text classifier. Network-admin screens are not collected. The UI is currently English-only.