Add a PUT endpoint that inserts or fully replaces a user's source
config. Unlike PATCH (which deep-merges and requires an existing row),
PUT requires both `enabled` and `config`, performs an upsert via
INSERT ... ON CONFLICT DO UPDATE, and replaces config entirely.
- Add `upsertConfig` to user-sources data layer
- Add `upsertSourceConfig` to UserSessionManager
- Add `addSource` to UserSession for new source registration
- 12 new tests covering insert, replace, validation, and session refresh
Co-authored-by: Ona <no-reply@ona.com>
Add endpoint for users to update their source config
and enabled state. Config is deep-merged with existing
values via lodash.merge and validated against the
provider's schema before persisting.
Co-authored-by: Ona <no-reply@ona.com>
UserSessionManager now queries the user_sources table for enabled
sources before calling any provider. Providers receive the per-user
JSON config directly instead of querying the DB themselves, removing
their db dependency and eliminating redundant round-trips.
Co-authored-by: Ona <no-reply@ona.com>
* feat(session): add per-user source refresh
Add refreshSource(provider) to UserSession so per-user
config changes can re-resolve a source without replacing
the global provider.
- UserSession now carries userId
- Simplify UserSessionManager sessions map
- replaceProvider delegates to session.refreshSource
- Remove updateSessionSource from manager
Co-authored-by: Ona <no-reply@ona.com>
* docs: fix stale jsdoc on provider failure behavior
Co-authored-by: Ona <no-reply@ona.com>
---------
Co-authored-by: Ona <no-reply@ona.com>
* feat(backend): add admin API with provider config endpoint
Add /api/admin/* route group with admin role middleware and a
PUT /api/admin/:sourceId/config endpoint for updating feed source
provider config at runtime. Currently supports aelis.weather.
Co-authored-by: Ona <no-reply@ona.com>
* test: remove weak active session test
Co-authored-by: Ona <no-reply@ona.com>
---------
Co-authored-by: Ona <no-reply@ona.com>
Add ability to replace a FeedSourceProvider at runtime and propagate
the new source to all active (and pending) user sessions, invalidating
their feed caches.
Co-authored-by: Ona <no-reply@ona.com>
* feat(backend): make FeedSourceProvider async
Make feedSourceForUser and FeedSourceProviderFn return promises.
Use Promise.allSettled to tolerate partial provider failures.
Guard concurrent getOrCreate calls with in-flight promise dedup.
Return 503 from HTTP handlers when session creation fails.
Co-authored-by: Ona <no-reply@ona.com>
* fix(backend): handle remove() during in-flight session creation
Cancel pending getOrCreate when remove() is called mid-flight.
Destroy the resulting session to prevent it from leaking.
Co-authored-by: Ona <no-reply@ona.com>
---------
Co-authored-by: Ona <no-reply@ona.com>
Rename all references across the codebase: package names,
imports, source IDs, directory names, docs, and configs.
Co-authored-by: Ona <no-reply@ona.com>