roc-lang / roc-lang/basic-webserver
Add SQLite-backed server-side sessions with explicit lifecycle and bounds
Nobody has claimed this yet.
- Dominant language
- HTML
- Stars
- 107
- Forks
- 20
- Avg merge
- 1d 17h
- Merged PRs (30d)
- 11
Description
Summary
Add a Session module implemented over the existing bounded SQLite pool. The browser receives only an opaque bearer identifier; application session data remains in SQLite.
Illustrative API:
store = Session.init!({
db,
max_payload_bytes: 16 * 1024,
idle_timeout_seconds: 30 * 60,
absolute_timeout_seconds: 24 * 60 * 60,
})?
created = Session.create!({ store, now, payload })?
loaded = Session.load!({ store, now, id })?
rotated = Session.rotate!({ store, now, id })?
Session.invalidate!({ store, id })?
Session.prune!({ store, now, max_rows: 500 })?
Dependencies
- #198 for OS-backed cryptographic random bytes
- #199 for typed request cookies and secure
Set-Cookierendering
Why this belongs in the platform
Server-side sessions are a conventional web framework facility and fit the platform's explicit preference for durable domain state in SQLite rather than arbitrary mutable process-local state.
The existing Sqlite.Db already provides bounded pooling, timeouts, typed errors, and transactions. The session facility can therefore be a Roc module over SQLite rather than a new host subsystem.
Required contract
- Depend on
Random.bytes!and the typed cookie module. - Generate identifiers from at least 32 OS-random bytes.
- Encode them as a fixed, validated cookie-safe representation.
- Make the identifier opaque and redact it from normal inspection.
- Store only a one-way digest of the bearer identifier in SQLite.
- Store application data as a bounded
List(U8)payload; serialization is application policy. - Use a fixed, namespaced, versioned table schema.
- Schema creation or migration occurs only through an explicit
Session.init!call. - Enforce idle and absolute expiry server-side.
- Atomically rotate the identifier and invalidate the old identifier to prevent session fixation.
- Support explicit invalidation/logout.
- Provide bounded pruning rather than a detached cleanup worker.
- Use SQLite transactions for each lifecycle operation.
- Document that session operations are not automatically atomic with arbitrary application-table updates in the first version.
- Return typed missing, expired, malformed, saturated, timeout, and SQLite failures.
- Never use an in-memory session cache as the source of truth.
The cookie helper should be used to emit an explicitly configured Secure, HttpOnly, SameSite cookie. The session module should not guess whether the public deployment uses HTTPS.
Tests
- Create, load, update, rotate, invalidate, and expire.
- Idle versus absolute expiry.
- Concurrent loads, rotations, and invalidations.
- Old identifier unusable immediately after rotation.
- Payload exact-limit and over-limit behavior.
- Bounded prune batches.
- SQLite busy, timeout, and rollback paths.
- Restart and multi-process behavior against the same database.
- No identifier values in diagnostics.
Non-goals
- Users, authentication, roles, or authorization
- In-memory sessions
- A generic key/value map with hidden serialization
- Client-side encrypted session cookies
- Background cleanup jobs
- Automatic session creation on every request
- Flash messages or login redirects
Acceptance criteria
- Session state is durable SQLite state, not process-local mutable state.
- Identifiers are cryptographically random, opaque, rotated, and explicitly invalidated.
- Idle and absolute timeouts are enforced by the server-side store.
- Payload, queries, and cleanup work are bounded.
- Cookie policy remains explicit at the application boundary.
- Concurrency and restart behavior are covered by real SQLite tests.
References
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading the existing bounded Sqlite.Db pool, transaction, timeout, and typed-error APIs, along with Random.bytes! and the typed cookie module from dependencies #198 and #199. Define the Session lifecycle around the listed create, load, rotate, invalidate, and prune operations, then cover the required SQLite concurrency, expiry, bounds, restart, rollback, and diagnostic tests. Done means durable bounded sessions with explicit cookie policy and all acceptance criteria satisfied.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- sqlite
- Domain
- backend, database, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100