@getstrata/core 0.5.85 → 0.5.87

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @getstrata/core changelog
2
2
 
3
+ ## 0.5.87
4
+
5
+ - `AuthUserDirectory.hasActiveBrowserSession?(userId, issuedAt)` is optional. `SessionGuard` calls it after `session_valid_after` and rejects the HMAC cookie when it returns false so WorkHub can revoke a single browser session by deleting the `sessions` row.
6
+
7
+ ## 0.5.86
8
+
9
+ - `createSessionCookieDetails()` returns the HMAC session header plus `issuedAt` / `ttlSeconds` so apps can persist Jetstream browser-session rows without changing the cookie format.
10
+
3
11
  ## 0.5.85
4
12
 
5
13
  - `applicationRegistry` prefers the latest `Symbol.for("@getstrata/applicationContext")` on `globalThis` so a stale module-local context cannot hide the bootstrapped app after `build:framework`.
package/README.md CHANGED
@@ -82,7 +82,7 @@ import type { Migration } from "@getstrata/core/database/migrations/types";
82
82
  Package name: **`@getstrata/core`** (npm org [`@getstrata`](https://www.npmjs.com/org/getstrata)).
83
83
 
84
84
  1. Add `NPM_TOKEN` to GitHub repository secrets.
85
- 2. Tag a release: `git tag v0.5.85 && git push origin v0.5.85`
85
+ 2. Tag a release: `git tag v0.5.92 && git push origin v0.5.92`
86
86
  3. [Release workflow](../../.github/workflows/release.yml) builds and runs `npm publish --access public`.
87
87
 
88
88
  Previously published as `@eyk-workhub/framework@0.1.0`, deprecated in favor of this package.
@@ -14,7 +14,14 @@ declare function sessionRememberTtlSeconds(): number;
14
14
  declare function readSession(request: Request): SignedSession | null;
15
15
  declare function readSessionUserId(request: Request): number | null;
16
16
  declare function isSessionInvalidated(issuedAt: number, validAfter: Date | string | null | undefined): boolean;
17
+ interface SessionCookieDetails {
18
+ header: string;
19
+ userId: number;
20
+ issuedAt: number;
21
+ ttlSeconds: number;
22
+ }
23
+ declare function createSessionCookieDetails(userId: number, options?: CreateSessionCookieOptions): SessionCookieDetails;
17
24
  declare function createSessionCookie(userId: number, options?: CreateSessionCookieOptions): string;
18
25
  declare function clearSessionCookie(): string;
19
- export type { CreateSessionCookieOptions, SignedSession };
20
- export { clearSessionCookie, createSessionCookie, isSessionInvalidated, readSession, readSessionUserId, SESSION_COOKIE, SESSION_REMEMBER_TTL_SECONDS, SESSION_TTL_SECONDS, sessionCookieName, sessionRememberTtlSeconds, sessionTtlSeconds, };
26
+ export type { CreateSessionCookieOptions, SessionCookieDetails, SignedSession };
27
+ export { clearSessionCookie, createSessionCookie, createSessionCookieDetails, isSessionInvalidated, readSession, readSessionUserId, SESSION_COOKIE, SESSION_REMEMBER_TTL_SECONDS, SESSION_TTL_SECONDS, sessionCookieName, sessionRememberTtlSeconds, sessionTtlSeconds, };
@@ -9,5 +9,6 @@ interface AuthUserRecord {
9
9
  interface AuthUserDirectory {
10
10
  resolveUserFromToken(token: string): Promise<AuthUser | null>;
11
11
  findByIdOrThrow(id: number): Promise<AuthUserRecord>;
12
+ hasActiveBrowserSession?(userId: number, issuedAt: number): Promise<boolean>;
12
13
  }
13
14
  export type { AuthUserDirectory, AuthUserRecord };
@@ -149,12 +149,20 @@ function isSessionInvalidated(issuedAt, validAfter) {
149
149
  }
150
150
  return issuedAt < timestamp;
151
151
  }
152
- function createSessionCookie(userId, options = {}) {
152
+ function createSessionCookieDetails(userId, options = {}) {
153
153
  const issuedAt = Date.now();
154
154
  const ttlSeconds = options.remember ? sessionRememberTtlSeconds() : sessionTtlSeconds();
155
155
  const value = options.remember ? signSession(userId, issuedAt, ttlSeconds) : signSession(userId, issuedAt);
156
156
  const secure = process.env.APP_ENV === "production" ? "; Secure" : "";
157
- return `${sessionCookieName()}=${encodeURIComponent(value)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${ttlSeconds}${secure}`;
157
+ return {
158
+ header: `${sessionCookieName()}=${encodeURIComponent(value)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${ttlSeconds}${secure}`,
159
+ userId,
160
+ issuedAt,
161
+ ttlSeconds
162
+ };
163
+ }
164
+ function createSessionCookie(userId, options = {}) {
165
+ return createSessionCookieDetails(userId, options).header;
158
166
  }
159
167
  function clearSessionCookie() {
160
168
  const secure = process.env.APP_ENV === "production" ? "; Secure" : "";
@@ -166,6 +174,7 @@ export {
166
174
  SESSION_TTL_SECONDS,
167
175
  clearSessionCookie,
168
176
  createSessionCookie,
177
+ createSessionCookieDetails,
169
178
  isSessionInvalidated,
170
179
  readSession,
171
180
  readSessionUserId,
@@ -234,12 +234,20 @@ function isSessionInvalidated(issuedAt, validAfter) {
234
234
  }
235
235
  return issuedAt < timestamp;
236
236
  }
237
- function createSessionCookie(userId, options = {}) {
237
+ function createSessionCookieDetails(userId, options = {}) {
238
238
  const issuedAt = Date.now();
239
239
  const ttlSeconds = options.remember ? sessionRememberTtlSeconds() : sessionTtlSeconds();
240
240
  const value = options.remember ? signSession(userId, issuedAt, ttlSeconds) : signSession(userId, issuedAt);
241
241
  const secure = process.env.APP_ENV === "production" ? "; Secure" : "";
242
- return `${sessionCookieName()}=${encodeURIComponent(value)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${ttlSeconds}${secure}`;
242
+ return {
243
+ header: `${sessionCookieName()}=${encodeURIComponent(value)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${ttlSeconds}${secure}`,
244
+ userId,
245
+ issuedAt,
246
+ ttlSeconds
247
+ };
248
+ }
249
+ function createSessionCookie(userId, options = {}) {
250
+ return createSessionCookieDetails(userId, options).header;
243
251
  }
244
252
  function clearSessionCookie() {
245
253
  const secure = process.env.APP_ENV === "production" ? "; Secure" : "";
@@ -266,6 +274,12 @@ class SessionGuard {
266
274
  if (isSessionInvalidated(session.issuedAt, user.session_valid_after)) {
267
275
  return null;
268
276
  }
277
+ if (typeof tokenService.hasActiveBrowserSession === "function") {
278
+ const active = await tokenService.hasActiveBrowserSession(session.userId, session.issuedAt);
279
+ if (!active) {
280
+ return null;
281
+ }
282
+ }
269
283
  return {
270
284
  id: user.id,
271
285
  role: user.role,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getstrata/core",
3
- "version": "0.5.85",
3
+ "version": "0.5.87",
4
4
  "description": "Strata — Laravel-inspired Bun framework public API",
5
5
  "type": "module",
6
6
  "license": "MIT",