@fuzdev/fuz_app 0.109.0 → 0.110.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/dist/auth/CLAUDE.md +6 -5
  2. package/dist/auth/account_action_specs.d.ts +18 -0
  3. package/dist/auth/account_action_specs.d.ts.map +1 -1
  4. package/dist/auth/account_action_specs.js +14 -1
  5. package/dist/auth/account_actions.d.ts.map +1 -1
  6. package/dist/auth/account_actions.js +6 -2
  7. package/dist/auth/bootstrap_account.d.ts +7 -2
  8. package/dist/auth/bootstrap_account.d.ts.map +1 -1
  9. package/dist/auth/bootstrap_account.js +9 -4
  10. package/dist/auth/bootstrap_routes.d.ts +12 -4
  11. package/dist/auth/bootstrap_routes.d.ts.map +1 -1
  12. package/dist/auth/bootstrap_routes.js +15 -6
  13. package/dist/auth/daemon_token_middleware.d.ts +7 -69
  14. package/dist/auth/daemon_token_middleware.d.ts.map +1 -1
  15. package/dist/auth/daemon_token_middleware.js +8 -104
  16. package/dist/auth/deps.d.ts +9 -5
  17. package/dist/auth/deps.d.ts.map +1 -1
  18. package/dist/auth/middleware.js +1 -1
  19. package/dist/auth/request_context.d.ts +1 -3
  20. package/dist/auth/request_context.d.ts.map +1 -1
  21. package/dist/auth/request_context.js +2 -5
  22. package/dist/auth/session_cookie.d.ts +18 -36
  23. package/dist/auth/session_cookie.d.ts.map +1 -1
  24. package/dist/auth/session_cookie.js +16 -26
  25. package/dist/auth/session_middleware.d.ts +1 -1
  26. package/dist/auth/session_middleware.d.ts.map +1 -1
  27. package/dist/auth/session_middleware.js +1 -4
  28. package/dist/auth/session_queries.d.ts +14 -30
  29. package/dist/auth/session_queries.d.ts.map +1 -1
  30. package/dist/auth/session_queries.js +15 -45
  31. package/dist/auth/token_lifetime.d.ts +51 -0
  32. package/dist/auth/token_lifetime.d.ts.map +1 -0
  33. package/dist/auth/token_lifetime.js +54 -0
  34. package/dist/dev/setup.d.ts +5 -9
  35. package/dist/dev/setup.d.ts.map +1 -1
  36. package/dist/dev/setup.js +18 -21
  37. package/dist/runtime/deno.d.ts.map +1 -1
  38. package/dist/runtime/deno.js +27 -1
  39. package/dist/runtime/deps.d.ts +38 -4
  40. package/dist/runtime/deps.d.ts.map +1 -1
  41. package/dist/runtime/fs.d.ts +24 -5
  42. package/dist/runtime/fs.d.ts.map +1 -1
  43. package/dist/runtime/fs.js +38 -7
  44. package/dist/runtime/mock.d.ts +7 -0
  45. package/dist/runtime/mock.d.ts.map +1 -1
  46. package/dist/runtime/mock.js +41 -1
  47. package/dist/runtime/node.d.ts.map +1 -1
  48. package/dist/runtime/node.js +7 -1
  49. package/dist/runtime/secure_file.d.ts +71 -0
  50. package/dist/runtime/secure_file.d.ts.map +1 -0
  51. package/dist/runtime/secure_file.js +125 -0
  52. package/dist/server/app_backend.d.ts +6 -5
  53. package/dist/server/app_backend.d.ts.map +1 -1
  54. package/dist/server/app_backend.js +2 -3
  55. package/dist/testing/CLAUDE.md +15 -1
  56. package/dist/testing/admin_integration.d.ts.map +1 -1
  57. package/dist/testing/admin_integration.js +57 -20
  58. package/dist/testing/app_server.d.ts.map +1 -1
  59. package/dist/testing/app_server.js +13 -8
  60. package/dist/testing/audit_completeness.d.ts.map +1 -1
  61. package/dist/testing/audit_completeness.js +5 -1
  62. package/dist/testing/cross_backend/cell_grant_role.d.ts.map +1 -1
  63. package/dist/testing/cross_backend/cell_grant_role.js +34 -1
  64. package/dist/testing/cross_backend/conformance_table.d.ts.map +1 -1
  65. package/dist/testing/cross_backend/conformance_table.js +2 -1
  66. package/dist/testing/cross_backend/setup.js +1 -1
  67. package/dist/testing/cross_backend/token_lifetime.d.ts +15 -0
  68. package/dist/testing/cross_backend/token_lifetime.d.ts.map +1 -0
  69. package/dist/testing/cross_backend/token_lifetime.js +99 -0
  70. package/dist/testing/cross_backend/token_scope_surface.js +1 -1
  71. package/dist/testing/daemon_token_rotation.d.ts +83 -0
  72. package/dist/testing/daemon_token_rotation.d.ts.map +1 -0
  73. package/dist/testing/daemon_token_rotation.js +99 -0
  74. package/dist/testing/integration.d.ts.map +1 -1
  75. package/dist/testing/integration.js +15 -3
  76. package/dist/testing/stubs.d.ts.map +1 -1
  77. package/dist/testing/stubs.js +4 -4
  78. package/dist/ui/AccountSessions.svelte +0 -5
  79. package/dist/ui/AccountSessions.svelte.d.ts.map +1 -1
  80. package/dist/ui/AdminOverview.svelte +7 -4
  81. package/dist/ui/AdminOverview.svelte.d.ts.map +1 -1
  82. package/dist/ui/AdminSessions.svelte +0 -5
  83. package/dist/ui/AdminSessions.svelte.d.ts.map +1 -1
  84. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"deps.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/deps.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAEhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,WAAW,OAAO;IACvB,+DAA+D;IAC/D,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACnD,2BAA2B;IAC3B,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,qBAAqB;IACrB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,0CAA0C;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,6EAA6E;IAC7E,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,yBAAyB;IACzB,EAAE,EAAE,EAAE,CAAC;IACP,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;OAMG;IACH,KAAK,EAAE,YAAY,CAAC;IACpB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;CACvB;AAED;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAEnD;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IACjC,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,4DAA4D;IAC5D,KAAK,EAAE,YAAY,CAAC;CACpB"}
1
+ {"version":3,"file":"deps.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/deps.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAEhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,WAAW,OAAO;IACvB;;;;;;;OAOG;IACH,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IACxD,qBAAqB;IACrB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,0CAA0C;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,6EAA6E;IAC7E,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,yBAAyB;IACzB,EAAE,EAAE,EAAE,CAAC;IACP,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;OAMG;IACH,KAAK,EAAE,YAAY,CAAC;IACpB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;CACvB;AAED;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAEnD;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IACjC,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,4DAA4D;IAC5D,KAAK,EAAE,YAAY,CAAC;CACpB"}
@@ -35,7 +35,7 @@ export const create_auth_middleware_specs = async (deps, options) => {
35
35
  import('./bearer_auth.js')
36
36
  ]);
37
37
  const session_middleware = create_session_middleware(keyring, session_options);
38
- const request_context_middleware = create_request_context_middleware(query_deps, deps.log);
38
+ const request_context_middleware = create_request_context_middleware(query_deps);
39
39
  const bearer_auth_middleware = create_bearer_auth_middleware(query_deps, deps.log);
40
40
  const specs = [
41
41
  {
@@ -35,7 +35,6 @@
35
35
  * @module
36
36
  */
37
37
  import type { Context, MiddlewareHandler } from 'hono';
38
- import type { Logger } from '@fuzdev/fuz_util/log.ts';
39
38
  import { type Account, type Actor, type RoleGrant } from './account_schema.js';
40
39
  import type { QueryDeps } from '../db/query_deps.js';
41
40
  import type { RouteSpec } from '../http/route_spec.js';
@@ -224,11 +223,10 @@ export declare const resolve_acting_actor: (deps: QueryDeps, account_id: string,
224
223
  * `require_auth` / `require_role` enforce.
225
224
  *
226
225
  * @param deps - query dependencies (pool-level db for middleware)
227
- * @param log - the logger instance
228
226
  * @param session_context_key - the Hono context key where session middleware stored the session token
229
227
  * @mutates Hono context - sets `ACCOUNT_ID_KEY`, `CREDENTIAL_TYPE_KEY`, `AUTH_SESSION_TOKEN_HASH_KEY`, and `AUTH_API_TOKEN_ID_KEY`
230
228
  */
231
- export declare const create_request_context_middleware: (deps: QueryDeps, log: Logger, session_context_key?: string) => MiddlewareHandler;
229
+ export declare const create_request_context_middleware: (deps: QueryDeps, session_context_key?: string) => MiddlewareHandler;
232
230
  /**
233
231
  * Refuse a non-RPC surface to a narrowed token — rule 3, for callers that are
234
232
  * not route specs. Under the Rust twin's name
@@ -1 +1 @@
1
- {"version":3,"file":"request_context.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/request_context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"request_context.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/request_context.ts"],"names":[],"mappings":"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"}
@@ -35,7 +35,7 @@
35
35
  * @module
36
36
  */
37
37
  import { is_role_grant_active } from './account_schema.js';
38
- import { hash_session_token, session_touch_fire_and_forget, query_session_get_valid } from './session_queries.js';
38
+ import { hash_session_token, query_session_get_valid } from './session_queries.js';
39
39
  import { query_account_by_id, query_actor_by_id, query_active_actors_by_account } from './account_queries.js';
40
40
  import { query_role_grant_find_active_for_actor } from './role_grant_queries.js';
41
41
  import { ACCOUNT_ID_KEY, AUTH_API_TOKEN_ID_KEY, CREDENTIAL_TYPE_KEY, TOKEN_SCOPE_KEY, TEST_CONTEXT_PRESET_KEY } from '../hono_context.js';
@@ -208,11 +208,10 @@ export const resolve_acting_actor = async (deps, account_id, acting_actor_id) =>
208
208
  * `require_auth` / `require_role` enforce.
209
209
  *
210
210
  * @param deps - query dependencies (pool-level db for middleware)
211
- * @param log - the logger instance
212
211
  * @param session_context_key - the Hono context key where session middleware stored the session token
213
212
  * @mutates Hono context - sets `ACCOUNT_ID_KEY`, `CREDENTIAL_TYPE_KEY`, `AUTH_SESSION_TOKEN_HASH_KEY`, and `AUTH_API_TOKEN_ID_KEY`
214
213
  */
215
- export const create_request_context_middleware = (deps, log, session_context_key = 'auth_session_id') => {
214
+ export const create_request_context_middleware = (deps, session_context_key = 'auth_session_id') => {
216
215
  return async (c, next) => {
217
216
  c.set(REQUEST_CONTEXT_KEY, null);
218
217
  c.set(ACCOUNT_ID_KEY, null);
@@ -235,8 +234,6 @@ export const create_request_context_middleware = (deps, log, session_context_key
235
234
  // A session is full account authority by construction.
236
235
  c.set(TOKEN_SCOPE_KEY, token_scope_full());
237
236
  c.set(AUTH_SESSION_TOKEN_HASH_KEY, token_hash);
238
- // Touch session (fire-and-forget, don't block the request)
239
- void session_touch_fire_and_forget(deps, token_hash, c.var.pending_effects, log);
240
237
  await next();
241
238
  };
242
239
  };
@@ -10,16 +10,15 @@
10
10
  * @module
11
11
  */
12
12
  import type { Keyring } from './keyring.js';
13
- /** Cookie max age in seconds (30 days — aligned with AUTH_SESSION_LIFETIME_MS). */
14
- export declare const SESSION_AGE_MAX: number;
15
13
  /**
16
- * Threshold (seconds) at which `process_session_cookie` re-signs a still-valid
17
- * cookie to extend its embedded expiration. Mirrors the DB-side
18
- * `AUTH_SESSION_EXTEND_THRESHOLD_MS` so a continuously-active user's cookie
19
- * stays in sync with their server-side session lifetime. Set
20
- * `SessionOptions.refresh_threshold_seconds = 0` to disable.
14
+ * Cookie max age in seconds (30 days — aligned with AUTH_SESSION_LIFETIME_MS).
15
+ *
16
+ * This is an **absolute** session lifetime: the cookie is signed once at
17
+ * mint (`expires_at = mint + max_age`) and never re-signed, matching the DB
18
+ * row's fixed `expires_at`. There is deliberately no sliding renewal on
19
+ * either leg — see `docs/security.md` §Session Security.
21
20
  */
22
- export declare const SESSION_REFRESH_THRESHOLD_S: number;
21
+ export declare const SESSION_AGE_MAX: number;
23
22
  /**
24
23
  * Cookie options for session cookies.
25
24
  */
@@ -91,14 +90,6 @@ export interface SessionOptions<TIdentity> {
91
90
  * cannot carry `maxAge` so the two values can't drift.
92
91
  */
93
92
  max_age?: number;
94
- /**
95
- * Threshold (seconds) for expiration-based cookie refresh. When a parsed
96
- * cookie's `expires_at - now <= refresh_threshold_seconds`,
97
- * `process_session_cookie` returns `action: 'refresh'` with a freshly-signed
98
- * value (extending the embedded expiration by `max_age`). Defaults to
99
- * `SESSION_REFRESH_THRESHOLD_S` (1 day). Set to `0` to disable.
100
- */
101
- refresh_threshold_seconds?: number;
102
93
  cookie_options?: Partial<Omit<SessionCookieOptions, 'maxAge'>>;
103
94
  /** Encode identity into the cookie payload (before the `:expires_at` suffix). */
104
95
  encode_identity: (identity: TIdentity) => string;
@@ -111,26 +102,14 @@ export interface SessionOptions<TIdentity> {
111
102
  export interface ParsedSession<TIdentity> {
112
103
  /** The decoded identity. */
113
104
  identity: TIdentity;
114
- /** True if verified with a non-primary key (needs re-signing). */
115
- should_refresh_signature: boolean;
116
- /**
117
- * True if the embedded `expires_at` is within
118
- * `options.refresh_threshold_seconds` of `now`. Signals that the cookie is
119
- * valid but should be re-signed to extend its lifetime — mirrors
120
- * `query_session_touch`'s DB-side extension so the cookie and server
121
- * session don't drift. Always false when the threshold is `0`.
122
- */
123
- should_refresh_expiration: boolean;
124
- /** Index of the key that verified the signature. */
105
+ /** Index of the key that verified the signature (0 = primary). */
125
106
  key_index: number;
126
107
  }
127
108
  /**
128
109
  * Parse a signed session cookie value.
129
110
  *
130
111
  * The signed value format is `${encode(identity)}:${expires_at}`.
131
- * Tries all keys in order to support key rotation. The result's
132
- * `should_refresh_expiration` flag fires when the cookie is within
133
- * `options.refresh_threshold_seconds` of `expires_at`.
112
+ * Tries all keys in order to support key rotation.
134
113
  *
135
114
  * @param signed_value - the raw cookie value (signed)
136
115
  * @param keyring - key ring for verification
@@ -159,9 +138,7 @@ export interface ProcessSessionResult<TIdentity> {
159
138
  /** Whether the session is valid. */
160
139
  valid: boolean;
161
140
  /** Action the adapter should take. */
162
- action: 'none' | 'clear' | 'refresh';
163
- /** New signed value when action is 'refresh'. */
164
- new_signed_value?: string;
141
+ action: 'none' | 'clear';
165
142
  /** The decoded identity if the cookie was valid. */
166
143
  identity?: TIdentity;
167
144
  }
@@ -181,9 +158,14 @@ export declare const fuz_session_config: SessionOptions<string>;
181
158
  /**
182
159
  * Process a session cookie and determine what action to take.
183
160
  *
184
- * `action: 'refresh'` fires on key rotation **or** impending expiration
185
- * (within `options.refresh_threshold_seconds`); both produce a freshly-signed
186
- * `new_signed_value`.
161
+ * There is deliberately no refresh action: any re-sign computes a fresh
162
+ * `now + max_age` expiry, extending the cookie past the DB row's fixed
163
+ * `expires_at` — the holder would go silently anonymous while carrying a
164
+ * self-perpetuating cookie. The absolute lifetime is one signing at mint,
165
+ * on both legs, matching the Rust spine. A cookie signed by a retired
166
+ * (non-primary) key keeps verifying until the key leaves the keyring;
167
+ * retired keys are safe to drop after `SESSION_AGE_MAX` (see
168
+ * `docs/security.md` §Cookie Key Rotation).
187
169
  *
188
170
  * @param signed_value - the raw cookie value (may be undefined)
189
171
  * @param keyring - key ring for verification and signing
@@ -1 +1 @@
1
- {"version":3,"file":"session_cookie.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/session_cookie.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session_cookie.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/session_cookie.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,QAAoB,CAAC;AAQjD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,oBAMpC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,WAAW,cAAc,CAAC,SAAS;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC/D,iFAAiF;IACjF,eAAe,EAAE,CAAC,QAAQ,EAAE,SAAS,KAAK,MAAM,CAAC;IACjD,mEAAmE;IACnE,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,SAAS,GAAG,IAAI,CAAC;CACvD;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,SAAS;IACvC,4BAA4B;IAC5B,QAAQ,EAAE,SAAS,CAAC;IACpB,kEAAkE;IAClE,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,GAAU,SAAS,EAC5C,cAAc,MAAM,GAAG,SAAS,EAChC,SAAS,OAAO,EAChB,SAAS,cAAc,CAAC,SAAS,CAAC,EAClC,cAAc,MAAM,KAClB,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,GAAG,IAAI,GAAG,SAAS,CA+BrD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,2BAA2B,GAAU,SAAS,EAC1D,SAAS,OAAO,EAChB,UAAU,SAAS,EACnB,SAAS,cAAc,CAAC,SAAS,CAAC,EAClC,cAAc,MAAM,KAClB,OAAO,CAAC,MAAM,CAMhB,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,oBAAoB,CAAC,SAAS;IAC9C,oCAAoC;IACpC,KAAK,EAAE,OAAO,CAAC;IACf,sCAAsC;IACtC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,GAAI,aAAa,MAAM,KAAG,cAAc,CAAC,MAAM,CAK/E,CAAC;AAEH,iDAAiD;AACjD,eAAO,MAAM,kBAAkB,EAAE,cAAc,CAAC,MAAM,CAAwC,CAAC;AAE/F;;;;;;;;;;;;;;;;;GAiBG;AAEH,eAAO,MAAM,sBAAsB,GAAU,SAAS,EACrD,cAAc,MAAM,GAAG,SAAS,EAChC,SAAS,OAAO,EAChB,SAAS,cAAc,CAAC,SAAS,CAAC,EAClC,cAAc,MAAM,KAClB,OAAO,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAgBzC,CAAC"}
@@ -9,16 +9,15 @@
9
9
  *
10
10
  * @module
11
11
  */
12
- /** Cookie max age in seconds (30 days — aligned with AUTH_SESSION_LIFETIME_MS). */
13
- export const SESSION_AGE_MAX = 60 * 60 * 24 * 30;
14
12
  /**
15
- * Threshold (seconds) at which `process_session_cookie` re-signs a still-valid
16
- * cookie to extend its embedded expiration. Mirrors the DB-side
17
- * `AUTH_SESSION_EXTEND_THRESHOLD_MS` so a continuously-active user's cookie
18
- * stays in sync with their server-side session lifetime. Set
19
- * `SessionOptions.refresh_threshold_seconds = 0` to disable.
13
+ * Cookie max age in seconds (30 days — aligned with AUTH_SESSION_LIFETIME_MS).
14
+ *
15
+ * This is an **absolute** session lifetime: the cookie is signed once at
16
+ * mint (`expires_at = mint + max_age`) and never re-signed, matching the DB
17
+ * row's fixed `expires_at`. There is deliberately no sliding renewal on
18
+ * either leg — see `docs/security.md` §Session Security.
20
19
  */
21
- export const SESSION_REFRESH_THRESHOLD_S = 60 * 60 * 24;
20
+ export const SESSION_AGE_MAX = 60 * 60 * 24 * 30;
22
21
  /** Separator between identity payload and expires_at in signed value. */
23
22
  const VALUE_SEPARATOR = ':';
24
23
  /** Strict integer matcher for the embedded `expires_at` field. */
@@ -42,9 +41,7 @@ export const session_cookie_options = {
42
41
  * Parse a signed session cookie value.
43
42
  *
44
43
  * The signed value format is `${encode(identity)}:${expires_at}`.
45
- * Tries all keys in order to support key rotation. The result's
46
- * `should_refresh_expiration` flag fires when the cookie is within
47
- * `options.refresh_threshold_seconds` of `expires_at`.
44
+ * Tries all keys in order to support key rotation.
48
45
  *
49
46
  * @param signed_value - the raw cookie value (signed)
50
47
  * @param keyring - key ring for verification
@@ -79,12 +76,8 @@ export const parse_session = async (signed_value, keyring, options, now_seconds)
79
76
  const now = now_seconds ?? Math.floor(Date.now() / 1000);
80
77
  if (expires_at <= now)
81
78
  return null;
82
- const refresh_threshold = options.refresh_threshold_seconds ?? SESSION_REFRESH_THRESHOLD_S;
83
- const should_refresh_expiration = refresh_threshold > 0 && expires_at - now <= refresh_threshold;
84
79
  return {
85
80
  identity,
86
- should_refresh_signature: result.key_index > 0,
87
- should_refresh_expiration,
88
81
  key_index: result.key_index
89
82
  };
90
83
  };
@@ -128,9 +121,14 @@ export const fuz_session_config = create_session_config('fuz_session');
128
121
  /**
129
122
  * Process a session cookie and determine what action to take.
130
123
  *
131
- * `action: 'refresh'` fires on key rotation **or** impending expiration
132
- * (within `options.refresh_threshold_seconds`); both produce a freshly-signed
133
- * `new_signed_value`.
124
+ * There is deliberately no refresh action: any re-sign computes a fresh
125
+ * `now + max_age` expiry, extending the cookie past the DB row's fixed
126
+ * `expires_at` — the holder would go silently anonymous while carrying a
127
+ * self-perpetuating cookie. The absolute lifetime is one signing at mint,
128
+ * on both legs, matching the Rust spine. A cookie signed by a retired
129
+ * (non-primary) key keeps verifying until the key leaves the keyring;
130
+ * retired keys are safe to drop after `SESSION_AGE_MAX` (see
131
+ * `docs/security.md` §Cookie Key Rotation).
134
132
  *
135
133
  * @param signed_value - the raw cookie value (may be undefined)
136
134
  * @param keyring - key ring for verification and signing
@@ -149,13 +147,5 @@ export const process_session_cookie = async (signed_value, keyring, options, now
149
147
  // Invalid cookie - should be cleared
150
148
  return { valid: false, action: 'clear' };
151
149
  }
152
- // Valid session — re-sign if the verifying key isn't primary OR if the
153
- // embedded expiration is approaching the threshold. The latter mirrors
154
- // `query_session_touch`'s DB-side extension so a continuously-active user's
155
- // cookie doesn't hard-expire while their server session is still alive.
156
- if (parsed.should_refresh_signature || parsed.should_refresh_expiration) {
157
- const new_signed_value = await create_session_cookie_value(keyring, parsed.identity, options, now);
158
- return { valid: true, action: 'refresh', new_signed_value, identity: parsed.identity };
159
- }
160
150
  return { valid: true, action: 'none', identity: parsed.identity };
161
151
  };
@@ -35,7 +35,7 @@ export declare const clear_session_cookie: <T>(c: Context, options: SessionOptio
35
35
  *
36
36
  * @param keyring - key ring for cookie verification
37
37
  * @param options - session configuration
38
- * @mutates Hono context - sets `options.context_key` and may refresh or clear the session cookie
38
+ * @mutates Hono context - sets `options.context_key` and may clear the session cookie
39
39
  */
40
40
  export declare const create_session_middleware: <TIdentity>(keyring: Keyring, options: SessionOptions<TIdentity>) => MiddlewareHandler;
41
41
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"session_middleware.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/session_middleware.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAGvD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EACN,KAAK,cAAc,EAKnB,MAAM,qBAAqB,CAAC;AAQ7B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAAI,CAAC,EACnC,GAAG,OAAO,EACV,SAAS,cAAc,CAAC,CAAC,CAAC,KACxB,MAAM,GAAG,SAEX,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,GAAI,CAAC,EACnC,GAAG,OAAO,EACV,OAAO,MAAM,EACb,SAAS,cAAc,CAAC,CAAC,CAAC,KACxB,IAOF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,GAAI,CAAC,EAAE,GAAG,OAAO,EAAE,SAAS,cAAc,CAAC,CAAC,CAAC,KAAG,IAMhF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB,GAAI,SAAS,EAClD,SAAS,OAAO,EAChB,SAAS,cAAc,CAAC,SAAS,CAAC,KAChC,iBAgBF,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,gCAAgC;IAChD,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,kDAAkD;IAClD,IAAI,EAAE,SAAS,CAAC;IAChB,2CAA2C;IAC3C,CAAC,EAAE,OAAO,CAAC;IACX,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,GACzC,SAAS,gCAAgC,KACvC,OAAO,CAAC,IAAI,CAad,CAAC"}
1
+ {"version":3,"file":"session_middleware.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/session_middleware.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAGvD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EACN,KAAK,cAAc,EAKnB,MAAM,qBAAqB,CAAC;AAQ7B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAAI,CAAC,EACnC,GAAG,OAAO,EACV,SAAS,cAAc,CAAC,CAAC,CAAC,KACxB,MAAM,GAAG,SAEX,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,GAAI,CAAC,EACnC,GAAG,OAAO,EACV,OAAO,MAAM,EACb,SAAS,cAAc,CAAC,CAAC,CAAC,KACxB,IAOF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,GAAI,CAAC,EAAE,GAAG,OAAO,EAAE,SAAS,cAAc,CAAC,CAAC,CAAC,KAAG,IAMhF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB,GAAI,SAAS,EAClD,SAAS,OAAO,EAChB,SAAS,cAAc,CAAC,SAAS,CAAC,KAChC,iBAcF,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,gCAAgC;IAChD,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,kDAAkD;IAClD,IAAI,EAAE,SAAS,CAAC;IAChB,2CAA2C;IAC3C,CAAC,EAAE,OAAO,CAAC;IACX,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,GACzC,SAAS,gCAAgC,KACvC,OAAO,CAAC,IAAI,CAad,CAAC"}
@@ -49,7 +49,7 @@ export const clear_session_cookie = (c, options) => {
49
49
  *
50
50
  * @param keyring - key ring for cookie verification
51
51
  * @param options - session configuration
52
- * @mutates Hono context - sets `options.context_key` and may refresh or clear the session cookie
52
+ * @mutates Hono context - sets `options.context_key` and may clear the session cookie
53
53
  */
54
54
  export const create_session_middleware = (keyring, options) => {
55
55
  return async (c, next) => {
@@ -60,9 +60,6 @@ export const create_session_middleware = (keyring, options) => {
60
60
  if (result.action === 'clear') {
61
61
  clear_session_cookie(c, options);
62
62
  }
63
- else if (result.action === 'refresh' && result.new_signed_value) {
64
- set_session_cookie(c, result.new_signed_value, options);
65
- }
66
63
  await next();
67
64
  };
68
65
  };
@@ -6,13 +6,17 @@
6
6
  *
7
7
  * @module
8
8
  */
9
- import type { Logger } from '@fuzdev/fuz_util/log.ts';
10
9
  import type { QueryDeps } from '../db/query_deps.js';
11
10
  import type { AuthSession, SessionId } from './account_schema.js';
12
- /** Session lifetime in milliseconds (30 days). */
11
+ /**
12
+ * Session lifetime in milliseconds (30 days).
13
+ *
14
+ * An **absolute** cap: `expires_at` is set once at mint and never extended —
15
+ * there is deliberately no touch/renewal query on either spine (a sliding
16
+ * window renews a leaked cookie forever; see `docs/security.md` §Session
17
+ * Security). The cookie's `SESSION_AGE_MAX` mirrors this value.
18
+ */
13
19
  export declare const AUTH_SESSION_LIFETIME_MS: number;
14
- /** Extend session when it has less than this remaining (1 day in ms). */
15
- export declare const AUTH_SESSION_EXTEND_THRESHOLD_MS: number;
16
20
  /**
17
21
  * Hash a session token to its storage key using blake3.
18
22
  *
@@ -46,16 +50,6 @@ export declare const query_create_session: (deps: QueryDeps, token_hash: string,
46
50
  * @param token_hash - blake3 hash of the session token
47
51
  */
48
52
  export declare const query_session_get_valid: (deps: QueryDeps, token_hash: string) => Promise<AuthSession | undefined>;
49
- /**
50
- * Update `last_seen_at` and optionally extend expiry for a session.
51
- *
52
- * Extends if less than `AUTH_SESSION_EXTEND_THRESHOLD_MS` remaining.
53
- *
54
- * @param deps - query dependencies
55
- * @param token_hash - blake3 hash of the session token
56
- * @mutates `auth_session` row - updates `last_seen_at` and conditionally `expires_at`
57
- */
58
- export declare const query_session_touch: (deps: QueryDeps, token_hash: string) => Promise<void>;
59
53
  /**
60
54
  * Revoke (delete) a session by its token hash, with no account scoping.
61
55
  *
@@ -137,9 +131,14 @@ export declare const query_session_enforce_limit: (deps: QueryDeps, account_id:
137
131
  /**
138
132
  * List all active sessions across all accounts with usernames.
139
133
  *
134
+ * Ordered by `created_at DESC` (newest session first), matching the
135
+ * per-account listing. `last_seen_at` is still selected for the wire shape
136
+ * but is decorative — nothing updates it post-mint (it always equals
137
+ * `created_at`); it is slated for removal on its own twin migration.
138
+ *
140
139
  * @param deps - query dependencies
141
140
  * @param limit - maximum entries to return
142
- * @returns active sessions joined with account usernames, newest activity first
141
+ * @returns active sessions joined with account usernames, newest first
143
142
  */
144
143
  export declare const query_session_list_all_active: (deps: QueryDeps, limit?: number) => Promise<Array<AuthSession & {
145
144
  username: string;
@@ -151,19 +150,4 @@ export declare const query_session_list_all_active: (deps: QueryDeps, limit?: nu
151
150
  * @mutates `auth_session` table - deletes every row past `expires_at`
152
151
  */
153
152
  export declare const query_session_cleanup_expired: (deps: QueryDeps) => Promise<number>;
154
- /**
155
- * Touch a session without blocking the caller.
156
- *
157
- * Errors are logged to console — session touching never breaks request flows.
158
- * Pass `pending_effects` (from `c.var.pending_effects`) to register
159
- * the promise for test flushing.
160
- *
161
- * @param deps - query dependencies
162
- * @param token_hash - blake3 hash of the session token
163
- * @param pending_effects - optional array to register the effect for later awaiting
164
- * @param log - the logger instance
165
- * @returns the settled promise (callers may ignore it — fire-and-forget semantics preserved)
166
- * @mutates `pending_effects` - pushes the in-flight settled promise when provided
167
- */
168
- export declare const session_touch_fire_and_forget: (deps: QueryDeps, token_hash: string, pending_effects: Array<Promise<void>> | undefined, log: Logger) => Promise<void>;
169
153
  //# sourceMappingURL=session_queries.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/session_queries.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAGtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAElE,kDAAkD;AAClD,eAAO,MAAM,wBAAwB,QAA2B,CAAC;AAEjE,yEAAyE;AACzE,eAAO,MAAM,gCAAgC,QAAsB,CAAC;AAEpE;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,KAAG,SAElD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,QAAO,MAEzC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,GAChC,MAAM,SAAS,EACf,YAAY,MAAM,EAClB,YAAY,MAAM,EAClB,YAAY,IAAI,KACd,OAAO,CAAC,IAAI,CAMd,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GACnC,MAAM,SAAS,EACf,YAAY,MAAM,KAChB,OAAO,CAAC,WAAW,GAAG,SAAS,CAKjC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,GAAU,MAAM,SAAS,EAAE,YAAY,MAAM,KAAG,OAAO,CAAC,IAAI,CAY3F,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qCAAqC,GACjD,MAAM,SAAS,EACf,YAAY,MAAM,KAChB,OAAO,CAAC,IAAI,CAEd,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gCAAgC,GAC5C,MAAM,SAAS,EACf,YAAY,MAAM,EAClB,YAAY,MAAM,KAChB,OAAO,CAAC,OAAO,CAMjB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oCAAoC,GAChD,MAAM,SAAS,EACf,YAAY,MAAM,KAChB,OAAO,CAAC,MAAM,CAMhB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,8BAA8B,GAC1C,MAAM,SAAS,EACf,YAAY,MAAM,EAClB,cAAU,KACR,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAK5B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,eAAO,MAAM,2BAA2B,GACvC,MAAM,SAAS,EACf,YAAY,MAAM,EAClB,cAAc,MAAM,KAClB,OAAO,CAAC,MAAM,CAYhB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,GACzC,MAAM,SAAS,EACf,cAAW,KACT,OAAO,CAAC,KAAK,CAAC,WAAW,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CASnD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,GAAU,MAAM,SAAS,KAAG,OAAO,CAAC,MAAM,CAKnF,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,6BAA6B,GACzC,MAAM,SAAS,EACf,YAAY,MAAM,EAClB,iBAAiB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,EACjD,KAAK,MAAM,KACT,OAAO,CAAC,IAAI,CAMd,CAAC"}
1
+ {"version":3,"file":"session_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/session_queries.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAElE;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,QAA2B,CAAC;AAEjE;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,KAAG,SAElD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,QAAO,MAEzC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,GAChC,MAAM,SAAS,EACf,YAAY,MAAM,EAClB,YAAY,MAAM,EAClB,YAAY,IAAI,KACd,OAAO,CAAC,IAAI,CAMd,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GACnC,MAAM,SAAS,EACf,YAAY,MAAM,KAChB,OAAO,CAAC,WAAW,GAAG,SAAS,CAKjC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qCAAqC,GACjD,MAAM,SAAS,EACf,YAAY,MAAM,KAChB,OAAO,CAAC,IAAI,CAEd,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gCAAgC,GAC5C,MAAM,SAAS,EACf,YAAY,MAAM,EAClB,YAAY,MAAM,KAChB,OAAO,CAAC,OAAO,CAMjB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oCAAoC,GAChD,MAAM,SAAS,EACf,YAAY,MAAM,KAChB,OAAO,CAAC,MAAM,CAMhB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,8BAA8B,GAC1C,MAAM,SAAS,EACf,YAAY,MAAM,EAClB,cAAU,KACR,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAK5B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,eAAO,MAAM,2BAA2B,GACvC,MAAM,SAAS,EACf,YAAY,MAAM,EAClB,cAAc,MAAM,KAClB,OAAO,CAAC,MAAM,CAYhB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,6BAA6B,GACzC,MAAM,SAAS,EACf,cAAW,KACT,OAAO,CAAC,KAAK,CAAC,WAAW,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CASnD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,GAAU,MAAM,SAAS,KAAG,OAAO,CAAC,MAAM,CAKnF,CAAC"}
@@ -8,10 +8,15 @@
8
8
  */
9
9
  import { hash_blake3 } from '@fuzdev/fuz_util/hash_blake3.ts';
10
10
  import { generate_random_base64url } from '../crypto.js';
11
- /** Session lifetime in milliseconds (30 days). */
11
+ /**
12
+ * Session lifetime in milliseconds (30 days).
13
+ *
14
+ * An **absolute** cap: `expires_at` is set once at mint and never extended —
15
+ * there is deliberately no touch/renewal query on either spine (a sliding
16
+ * window renews a leaked cookie forever; see `docs/security.md` §Session
17
+ * Security). The cookie's `SESSION_AGE_MAX` mirrors this value.
18
+ */
12
19
  export const AUTH_SESSION_LIFETIME_MS = 30 * 24 * 60 * 60 * 1000;
13
- /** Extend session when it has less than this remaining (1 day in ms). */
14
- export const AUTH_SESSION_EXTEND_THRESHOLD_MS = 24 * 60 * 60 * 1000;
15
20
  /**
16
21
  * Hash a session token to its storage key using blake3.
17
22
  *
@@ -57,25 +62,6 @@ export const query_create_session = async (deps, token_hash, account_id, expires
57
62
  export const query_session_get_valid = async (deps, token_hash) => {
58
63
  return deps.db.query_one(`SELECT * FROM auth_session WHERE id = $1 AND expires_at > NOW()`, [token_hash]);
59
64
  };
60
- /**
61
- * Update `last_seen_at` and optionally extend expiry for a session.
62
- *
63
- * Extends if less than `AUTH_SESSION_EXTEND_THRESHOLD_MS` remaining.
64
- *
65
- * @param deps - query dependencies
66
- * @param token_hash - blake3 hash of the session token
67
- * @mutates `auth_session` row - updates `last_seen_at` and conditionally `expires_at`
68
- */
69
- export const query_session_touch = async (deps, token_hash) => {
70
- const new_expires = new Date(Date.now() + AUTH_SESSION_LIFETIME_MS);
71
- await deps.db.query(`UPDATE auth_session
72
- SET last_seen_at = NOW(),
73
- expires_at = CASE
74
- WHEN expires_at - NOW() < INTERVAL '1 day' THEN $2::timestamptz
75
- ELSE expires_at
76
- END
77
- WHERE id = $1`, [token_hash, new_expires.toISOString()]);
78
- };
79
65
  /**
80
66
  * Revoke (delete) a session by its token hash, with no account scoping.
81
67
  *
@@ -176,16 +162,21 @@ export const query_session_enforce_limit = async (deps, account_id, max_sessions
176
162
  /**
177
163
  * List all active sessions across all accounts with usernames.
178
164
  *
165
+ * Ordered by `created_at DESC` (newest session first), matching the
166
+ * per-account listing. `last_seen_at` is still selected for the wire shape
167
+ * but is decorative — nothing updates it post-mint (it always equals
168
+ * `created_at`); it is slated for removal on its own twin migration.
169
+ *
179
170
  * @param deps - query dependencies
180
171
  * @param limit - maximum entries to return
181
- * @returns active sessions joined with account usernames, newest activity first
172
+ * @returns active sessions joined with account usernames, newest first
182
173
  */
183
174
  export const query_session_list_all_active = async (deps, limit = 200) => {
184
175
  return deps.db.query(`SELECT s.id, s.account_id, s.created_at, s.expires_at, s.last_seen_at, a.username
185
176
  FROM auth_session s
186
177
  JOIN account a ON a.id = s.account_id
187
178
  WHERE s.expires_at > NOW()
188
- ORDER BY s.last_seen_at DESC LIMIT $1`, [limit]);
179
+ ORDER BY s.created_at DESC, s.id DESC LIMIT $1`, [limit]);
189
180
  };
190
181
  /**
191
182
  * Delete expired sessions.
@@ -197,24 +188,3 @@ export const query_session_cleanup_expired = async (deps) => {
197
188
  const rows = await deps.db.query(`DELETE FROM auth_session WHERE expires_at <= NOW() RETURNING id`);
198
189
  return rows.length;
199
190
  };
200
- /**
201
- * Touch a session without blocking the caller.
202
- *
203
- * Errors are logged to console — session touching never breaks request flows.
204
- * Pass `pending_effects` (from `c.var.pending_effects`) to register
205
- * the promise for test flushing.
206
- *
207
- * @param deps - query dependencies
208
- * @param token_hash - blake3 hash of the session token
209
- * @param pending_effects - optional array to register the effect for later awaiting
210
- * @param log - the logger instance
211
- * @returns the settled promise (callers may ignore it — fire-and-forget semantics preserved)
212
- * @mutates `pending_effects` - pushes the in-flight settled promise when provided
213
- */
214
- export const session_touch_fire_and_forget = (deps, token_hash, pending_effects, log) => {
215
- const p = query_session_touch(deps, token_hash).catch((err) => {
216
- log.error('Session touch failed:', err);
217
- });
218
- pending_effects?.push(p);
219
- return p;
220
- };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * API token lifetime — the temporal axis of a minted credential.
3
+ *
4
+ * `lifetime` is **required** on `account_token_create`, mirroring `scope`:
5
+ * there is deliberately no default. A caller who wants a never-expiring token
6
+ * spells `{kind: 'eternal'}`, and the request records that they did — an
7
+ * omitted lifetime is a validation error upstream, not an eternal token.
8
+ * `expires_at IS NULL` therefore means "deliberately eternal", never "minted
9
+ * before the policy existed".
10
+ *
11
+ * Lifetime is deliberately **not** part of the scope document — `TokenScope`
12
+ * is strict on both spines and sits on the hot resolve path. The expiry lives
13
+ * in the indexed `api_token.expires_at` column where the SQL validation gate
14
+ * already enforces it (`expires_at IS NULL OR expires_at > NOW()`).
15
+ *
16
+ * A framework-level ceiling (`max_token_ttl_days`) is deferred until `fuzf`
17
+ * has an expiry story (an expiry-aware read + a 401 hint); see
18
+ * `docs/security.md` §API tokens.
19
+ *
20
+ * @module
21
+ */
22
+ import { z } from 'zod';
23
+ /**
24
+ * Upper bound on `ttl.days` — a sanity cap (100 years), not a policy ceiling.
25
+ * Shared with the Rust twin so out-of-range requests 400 identically on both
26
+ * spines.
27
+ */
28
+ export declare const TOKEN_TTL_DAYS_MAX = 36500;
29
+ /**
30
+ * Caller-provided lifetime for `account_token_create`.
31
+ *
32
+ * `eternal` mints a never-expiring token (`expires_at` NULL); `ttl` bounds it
33
+ * to `days` from mint time. `eternal` is deliberately the first variant so
34
+ * schema-driven test generators produce it by default.
35
+ */
36
+ export declare const TokenLifetimeInput: z.ZodDiscriminatedUnion<[z.ZodObject<{
37
+ kind: z.ZodLiteral<"eternal">;
38
+ }, z.core.$strict>, z.ZodObject<{
39
+ kind: z.ZodLiteral<"ttl">;
40
+ days: z.ZodNumber;
41
+ }, z.core.$strict>], "kind">;
42
+ export type TokenLifetimeInput = z.infer<typeof TokenLifetimeInput>;
43
+ /**
44
+ * Resolve a lifetime input to the `expires_at` value the mint query stores.
45
+ *
46
+ * @param lifetime - the validated lifetime input
47
+ * @param now - mint time (injectable for tests; defaults to the current time)
48
+ * @returns the expiry `Date`, or `null` for an eternal token
49
+ */
50
+ export declare const token_lifetime_to_expires_at: (lifetime: TokenLifetimeInput, now?: Date) => Date | null;
51
+ //# sourceMappingURL=token_lifetime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token_lifetime.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/token_lifetime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,QAAS,CAAC;AAEzC;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB;;;;;4BAM7B,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEpE;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,GACxC,UAAU,kBAAkB,EAC5B,MAAK,IAAiB,KACpB,IAAI,GAAG,IAGT,CAAC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * API token lifetime — the temporal axis of a minted credential.
3
+ *
4
+ * `lifetime` is **required** on `account_token_create`, mirroring `scope`:
5
+ * there is deliberately no default. A caller who wants a never-expiring token
6
+ * spells `{kind: 'eternal'}`, and the request records that they did — an
7
+ * omitted lifetime is a validation error upstream, not an eternal token.
8
+ * `expires_at IS NULL` therefore means "deliberately eternal", never "minted
9
+ * before the policy existed".
10
+ *
11
+ * Lifetime is deliberately **not** part of the scope document — `TokenScope`
12
+ * is strict on both spines and sits on the hot resolve path. The expiry lives
13
+ * in the indexed `api_token.expires_at` column where the SQL validation gate
14
+ * already enforces it (`expires_at IS NULL OR expires_at > NOW()`).
15
+ *
16
+ * A framework-level ceiling (`max_token_ttl_days`) is deferred until `fuzf`
17
+ * has an expiry story (an expiry-aware read + a 401 hint); see
18
+ * `docs/security.md` §API tokens.
19
+ *
20
+ * @module
21
+ */
22
+ import { z } from 'zod';
23
+ /**
24
+ * Upper bound on `ttl.days` — a sanity cap (100 years), not a policy ceiling.
25
+ * Shared with the Rust twin so out-of-range requests 400 identically on both
26
+ * spines.
27
+ */
28
+ export const TOKEN_TTL_DAYS_MAX = 36_500;
29
+ /**
30
+ * Caller-provided lifetime for `account_token_create`.
31
+ *
32
+ * `eternal` mints a never-expiring token (`expires_at` NULL); `ttl` bounds it
33
+ * to `days` from mint time. `eternal` is deliberately the first variant so
34
+ * schema-driven test generators produce it by default.
35
+ */
36
+ export const TokenLifetimeInput = z.discriminatedUnion('kind', [
37
+ z.strictObject({ kind: z.literal('eternal') }),
38
+ z.strictObject({
39
+ kind: z.literal('ttl'),
40
+ days: z.number().int().min(1).max(TOKEN_TTL_DAYS_MAX)
41
+ })
42
+ ]);
43
+ /**
44
+ * Resolve a lifetime input to the `expires_at` value the mint query stores.
45
+ *
46
+ * @param lifetime - the validated lifetime input
47
+ * @param now - mint time (injectable for tests; defaults to the current time)
48
+ * @returns the expiry `Date`, or `null` for an eternal token
49
+ */
50
+ export const token_lifetime_to_expires_at = (lifetime, now = new Date()) => {
51
+ if (lifetime.kind === 'eternal')
52
+ return null;
53
+ return new Date(now.getTime() + lifetime.days * 86_400_000);
54
+ };