Configurable sliding session lifetime + flattened, on-by-default entitlement freshness (v0.5.0)#111
Merged
Merged
Conversation
…ult (v0.4.6)
Decouple login lifetime (authentication) from entitlement freshness
(authorization), which were previously conflated by a hardcoded 24h
session that forced a daily re-login.
Sessions:
- Session TTL is now configurable via `session: { ttl: { ms } }` in the
factory config, defaulting to a rolling 30 days.
- Sliding renewal: validateSession extends expires_at once less than half
the window remains (one DB write per ~half-TTL of activity), so active
users effectively never re-login while idle sessions still expire.
- `session_id` is now a persistent (Max-Age) cookie so it survives browser
restarts; the renewed Max-Age is re-issued on the proxy hot path.
Entitlements:
- Patreon's entitlement ttl default (when enabled without an explicit ms)
is now 1 day instead of the generic 15 min, as a backstop for missed
webhooks now that sessions are long-lived. Still overridable via ttl.ms.
Centralizes the session cookie string in a sessionSetCookie helper.
Adds tests for custom/sliding session TTL, persistent + renewal cookies,
factory config resolution, and the Patreon 1-day TTL default. All 137 pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
startup-api | a1cc4d7 | Jul 03 2026, 07:06 PM |
…ation type (v0.5.0)
Refines the config API surface from the initial pass on this branch:
- Flatten `freshness: { ttl, cron, webhook }` into descriptive per-provider
keys: `entitlementTtl` / `entitlementCron` / `entitlementWebhook`
(camelCase, matching existing keys). BREAKING vs 0.4.5.
- `entitlementTtl` is now ON by default for entitlement providers (1 day for
Patreon, 15 min otherwise) instead of opt-in, so every deployment gets a
freshness backstop now that sessions are long-lived. `false` disables it.
- Durations are expressed as a named-unit object ({ days: 30 }, { minutes: 15 };
units summed) or a plain number of ms, via a shared Duration type +
durationToMs(). Applied to both `session.ttl` and `entitlementTtl` — the ttl
value is a time, no longer a boolean.
Updates README (breaking-change note, new examples), the Draw Leather config,
and tests. Adds durationToMs unit tests and named-unit session coverage.
Bumps to 0.5.0 (breaking config rename). All 139 tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Patreon-logged-in users were forced to re-authenticate roughly daily — a hardcoded 24h session with no renewal. Fixing it surfaced that login lifetime (authentication) and entitlement freshness (authorization) were conflated; this PR separates them and cleans up the freshness config API.
What changed
Sessions
session: { ttl }, default 30 days. Sliding renewal invalidateSessionpushesexpires_atforward once less than half the window remains (≈one write per ½·TTL of activity). Active users effectively never re-login; idle sessions still expire.session_idis now a persistent (Max-Age) cookie and the refreshedMax-Ageis re-issued on the proxy hot path. Cookie string centralized insessionSetCookie.Entitlement freshness — flatter, on-by-default, time-valued
freshness: { ttl, cron, webhook }→ per-providerentitlementTtl/entitlementCron/entitlementWebhook.entitlementTtlis ON by default for entitlement providers (1 day for Patreon, 15 min otherwise) — every deployment gets a freshness backstop now that sessions are long-lived.entitlementTtl: falsedisables it (webhook-only).{ days: 30 },{ minutes: 15 }— summed) or a plain number of ms, via a sharedDuration+durationToMs(). Applied to bothsession.ttlandentitlementTtl.Behavior / breaking changes (for release notes)
freshness.*config removed →entitlementTtl/entitlementCron/entitlementWebhook.entitlementTtldefault: off → on (1 day Patreon / 15 min other).session_id→ persistent cookie.Tests
139 pass + eslint clean. Coverage added for: custom/sliding/no-renew session TTL (
userdo), persistent + renewalSet-Cookieon the proxy path (headers), factory config resolution, 30-day default, named-unit durations,durationToMs(factory), and the on-by-default Patreon 1-day entitlement TTL (entitlement_integration).Versioning
Bumped
0.4.5 → **0.5.0**— thefreshnessrename is a breaking config change, so a minor bump (pre-1.0) rather than a patch. Say the word if you'd rather keepfreshnessas a deprecated alias to avoid the break.🤖 Generated with Claude Code