mirror of
https://github.com/kennethnym/aris.git
synced 2026-03-26 11:51:17 +00:00
feat(backend): add PUT /api/sources/:sourceId (#87)
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>
This commit is contained in:
@@ -136,6 +136,52 @@ export class UserSessionManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates, persists, and upserts a user's source config, then
|
||||
* refreshes the cached session. Unlike updateSourceConfig, this
|
||||
* inserts a new row if one doesn't exist and fully replaces config
|
||||
* (no merge).
|
||||
*
|
||||
* @throws {SourceNotFoundError} if the sourceId has no registered provider
|
||||
* @throws {InvalidSourceConfigError} if config fails schema validation
|
||||
*/
|
||||
async upsertSourceConfig(
|
||||
userId: string,
|
||||
sourceId: string,
|
||||
data: { enabled: boolean; config: unknown },
|
||||
): Promise<void> {
|
||||
const provider = this.providers.get(sourceId)
|
||||
if (!provider) {
|
||||
throw new SourceNotFoundError(sourceId, userId)
|
||||
}
|
||||
|
||||
if (provider.configSchema) {
|
||||
const validated = provider.configSchema(data.config)
|
||||
if (validated instanceof type.errors) {
|
||||
throw new InvalidSourceConfigError(sourceId, validated.summary)
|
||||
}
|
||||
}
|
||||
|
||||
await sources(this.db, userId).upsertConfig(sourceId, {
|
||||
enabled: data.enabled,
|
||||
config: data.config,
|
||||
})
|
||||
|
||||
const session = this.sessions.get(userId)
|
||||
if (session) {
|
||||
if (!data.enabled) {
|
||||
session.removeSource(sourceId)
|
||||
} else {
|
||||
const source = await provider.feedSourceForUser(userId, data.config)
|
||||
if (session.hasSource(sourceId)) {
|
||||
session.replaceSource(sourceId, source)
|
||||
} else {
|
||||
session.addSource(source)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces a provider and updates all active sessions.
|
||||
* The new provider must have the same sourceId as an existing one.
|
||||
|
||||
@@ -73,6 +73,32 @@ export class UserSession {
|
||||
return this.sources.has(sourceId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new source in the engine and invalidates all caches.
|
||||
* Stops and restarts the engine to establish reactive subscriptions.
|
||||
*/
|
||||
addSource(source: FeedSource): void {
|
||||
if (this.sources.has(source.id)) {
|
||||
throw new Error(`Cannot add source "${source.id}": already registered`)
|
||||
}
|
||||
|
||||
const wasStarted = this.engine.isStarted()
|
||||
|
||||
if (wasStarted) {
|
||||
this.engine.stop()
|
||||
}
|
||||
|
||||
this.engine.register(source)
|
||||
this.sources.set(source.id, source)
|
||||
|
||||
this.invalidateEnhancement()
|
||||
this.enhancingPromise = null
|
||||
|
||||
if (wasStarted) {
|
||||
this.engine.start()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces a source in the engine and invalidates all caches.
|
||||
* Stops and restarts the engine to re-establish reactive subscriptions.
|
||||
|
||||
Reference in New Issue
Block a user