When updateSourceCredentials was called for a source not yet in the
active session (e.g. because credentials were missing at config time),
the source was never instantiated despite being enabled in the DB.
Now, if the source row is enabled but absent from the session, the
source is added instead of skipped.
Co-authored-by: Ona <no-reply@ona.com>
Wire CalDavSourceProvider into the backend to support CalDAV
calendar sources (e.g. iCloud) with basic auth. Config accepts
serverUrl, username, lookAheadDays, and timeZone. Credentials
(app-specific password) are stored encrypted via the existing
credential storage infrastructure.
Co-authored-by: Ona <no-reply@ona.com>
Add credentials parameter to FeedSourceProvider.feedSourceForUser so
providers can receive decrypted per-user credentials (OAuth tokens,
passwords) from the user_sources table.
Wire CredentialEncryptor into UserSessionManager to handle
encrypt/decrypt. Providers receive plaintext and handle validation
internally. Existing providers ignore the new parameter.
Co-authored-by: Ona <no-reply@ona.com>
strict: true requires all property names to be known upfront,
which is incompatible with the dynamic-key maps in slotFills.
Also replace type array with anyOf for nullable slot values.
* fix(backend): add CORS middleware and disable CSRF in dev
- Add CORS middleware for /api/auth/* and global routes
- Disable better-auth CSRF origin check when NODE_ENV != production
Co-authored-by: Ona <no-reply@ona.com>
* fix: gate permissive CORS to dev only
In production, only origins listed in CORS_ORIGINS env
var are allowed. In dev, any origin is reflected back.
Co-authored-by: Ona <no-reply@ona.com>
---------
Co-authored-by: Ona <no-reply@ona.com>
Set reasoning effort to none in the LLM client to reduce latency
and token usage. Fall back to the reasoning field when content is
absent in the response.
Co-authored-by: Ona <no-reply@ona.com>
Add "+": "reject" to all arktype schemas so undeclared
keys return 400. Sources without a configSchema now
reject the config field entirely at the HTTP layer.
Co-authored-by: Ona <no-reply@ona.com>
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): add admin plugin and create-admin script
Add Better Auth admin plugin for role-based user management.
Includes a CLI script to create admin accounts.
Co-authored-by: Ona <no-reply@ona.com>
* fix(backend): guard against missing BETTER_AUTH_SECRET
Co-authored-by: Ona <no-reply@ona.com>
---------
Co-authored-by: Ona <no-reply@ona.com>
* feat(backend): add DB persistence layer
Replace raw pg Pool with Drizzle ORM backed by Bun.sql.
Add per-user source configuration table (user_sources).
Migrate Better Auth to drizzle-adapter.
Add AES-256-GCM credential encryption.
Co-authored-by: Ona <no-reply@ona.com>
* fix(backend): set updatedAt explicitly in all mutations
onConflictDoUpdate bypasses Drizzle's $onUpdate hook.
Set updatedAt explicitly in all mutation methods.
Co-authored-by: Ona <no-reply@ona.com>
* fix(backend): add composite index on user_sources
Add (user_id, enabled) index for the enabled() query path.
Co-authored-by: Ona <no-reply@ona.com>
---------
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>
Each FeedSource implementation now sets sourceId on items
it produces, allowing consumers to trace items back to
their originating source.
Co-authored-by: Ona <no-reply@ona.com>
* feat(backend): add GET /api/context endpoint
Query context values by key with exact/prefix match
support. Default mode tries exact first, falls back
to prefix.
Co-authored-by: Ona <no-reply@ona.com>
* fix(backend): validate context key element types
Reject booleans, nulls, and nested arrays in the key
param. Only string, number, and plain objects with
primitive values are accepted.
Co-authored-by: Ona <no-reply@ona.com>
---------
Co-authored-by: Ona <no-reply@ona.com>
Use mockAuthSessionMiddleware with a fully populated dev
user when NODE_ENV is not production. Auth handlers are
only registered in production.
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>