@getstrata/core 0.5.58 → 0.5.60

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 ADDED
@@ -0,0 +1,21 @@
1
+ # @getstrata/core changelog
2
+
3
+ ## 0.5.60
4
+
5
+ - `@getstrata/core/database/boundConnection` publishes `getBoundDatabaseConnection` and `resetBoundDatabaseConnection` on the JS entry (not only the types file). Tests can reset the bound pool after `closeDatabase()` without a postinstall patch.
6
+ - `bindBunSql` / `createBunSqlPool` on `@getstrata/core/database/bunSql` create a Bun `SQL` pool and register it as the bound connection plus default pool.
7
+ - `xmlResponse` accepts `{ contentType }`. `rssResponse` sends `application/rss+xml`.
8
+ - Memory throttle buckets are per middleware instance. `resetMemoryThrottleForTests()` clears every instance map so nested HTTP tests do not leak.
9
+
10
+ ## 0.5.59
11
+
12
+ Sibling HTMX apps can consume published packages without WorkHub-only glue.
13
+
14
+ - Emit `@getstrata/core/facades` types at `dist/core/facades/index.d.ts` (CI checks every `exports.*.types` path after build).
15
+ - Session and CSRF cookie names are configurable (`SESSION_COOKIE_NAME`, `CSRF_COOKIE_NAME`). Defaults remain `workhub_session` and `workhub_csrf` for WorkHub.
16
+ - Split `CORE_ABILITY_CHECKER_TOKEN` and `CORE_AUTH_USER_DIRECTORY_TOKEN` from `CORE_TOKEN_SERVICE_TOKEN`. HttpKernel prefers the ability-checker token; HMAC `SessionGuard` / layout data prefer the user directory. A compatibility shim uses `CORE_TOKEN_SERVICE_TOKEN` only when the bound value matches the requested type.
17
+ - `configureWebLayoutData` lets apps choose `currentUser` vs `authUser`, a custom user loader, and extra template fields. WorkHub still gets `{ authUser, csrfToken, flash }`.
18
+ - `redirectResponse`, `notFoundHtmlResponse`, `textResponse`, and `xmlResponse` join `htmlResponse` / `isHtmxRequest` on `@getstrata/core/view`.
19
+ - `LOGIN_RATE_LIMIT_WINDOW_MS` is a deprecated alias for `LOGIN_RATE_LIMIT_WINDOW_SECONDS`.
20
+
21
+ HMAC `SessionGuard` is unchanged for WorkHub API/token apps. Sibling HTMX apps should use `@getstrata/bootstrap` `CookieSessionStore` + `createCookieSessionAuthManager`.
package/README.md CHANGED
@@ -5,7 +5,7 @@ Stable **Strata** framework surface for application modules.
5
5
  **Source:** `src/framework/public-api.ts` (monorepo)
6
6
  **Repository:** [EyK-26/strata](https://github.com/EyK-26/strata), directory `packages/strata-core`
7
7
 
8
- WorkHub is the reference application built on Strata; import the framework from this package in your own modules.
8
+ WorkHub is the reference application built on Strata; import the framework from this package in your own modules. Sibling HTMX apps (Eta, cookie sessions, no API tokens) should follow [docs/SIBLING-HTMX.md](../../docs/SIBLING-HTMX.md).
9
9
 
10
10
  ## Usage
11
11
 
@@ -28,7 +28,7 @@ import { EtaViewEngine } from "@getstrata/core/view";
28
28
 
29
29
  `.eta` files are **HTML + Eta tags** (`<% %>`, `<%= %>`, `<%~ include() %>`), not Pug. Class/attribute shorthand such as `section.section` or `a href=` fails at render time with the template name.
30
30
 
31
- **Dependency:** `eta` is bundled as a direct dependency of `@getstrata/core`. Apps do not need to list it separately. The database driver is your app's choice. WorkHub and getstrata use **Bun's built-in `Bun.sql`** client; bind it with `bindDatabaseConnection()`.
31
+ **Dependency:** `eta` is bundled as a direct dependency of `@getstrata/core`. Apps do not need to list it separately. The database driver is your app's choice. WorkHub and getstrata use **Bun's built-in `Bun.sql`** client; create and bind it with `createBunSqlPool()` / `bindBunSql()`, or call `bindDatabaseConnection()` yourself.
32
32
 
33
33
  `orderBy` accepts explicit `{ column, direction }` objects or column shorthand such as `{ published_at: "desc" }`.
34
34
 
@@ -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.58 && git push origin v0.5.58`
85
+ 2. Tag a release: `git tag v0.5.60 && git push origin v0.5.60`
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.
@@ -4,7 +4,7 @@ declare const CACHE_MAX_ENTRIES_CONFIG_KEY = "cache.maxEntries";
4
4
  declare const CACHE_DRIVER_CONFIG_KEY = "cache.driver";
5
5
  declare const REDIS_URL_CONFIG_KEY = "cache.redisUrl";
6
6
  declare const DATABASE_URL_CONFIG_KEY = "database.url";
7
- export { CORE_AUTH_TOKEN, CORE_CACHE_TOKEN, CORE_CONFIG_TOKEN, CORE_EVENT_BUS_TOKEN, CORE_POLICY_GATE_TOKEN, CORE_QUEUE_TOKEN, CORE_TOKEN_SERVICE_TOKEN, } from "@getstrata/core/contracts/serviceTokens";
7
+ export { CORE_ABILITY_CHECKER_TOKEN, CORE_AUTH_TOKEN, CORE_AUTH_USER_DIRECTORY_TOKEN, CORE_CACHE_TOKEN, CORE_CONFIG_TOKEN, CORE_EVENT_BUS_TOKEN, CORE_POLICY_GATE_TOKEN, CORE_QUEUE_TOKEN, CORE_TOKEN_SERVICE_TOKEN, } from "@getstrata/core/contracts/serviceTokens";
8
8
  declare const AUTH_DEV_HEADERS_CONFIG_KEY = "auth.allowDevHeaders";
9
9
  declare const DEFAULT_APP_PORT = 3000;
10
10
  declare const DEFAULT_CACHE_TTL_MS = 3600000;
@@ -1,6 +1,7 @@
1
1
  declare const SESSION_COOKIE = "workhub_session";
2
2
  declare const SESSION_TTL_SECONDS: number;
3
+ declare function sessionCookieName(): string;
3
4
  declare function readSessionUserId(request: Request): number | null;
4
5
  declare function createSessionCookie(userId: number): string;
5
6
  declare function clearSessionCookie(): string;
6
- export { clearSessionCookie, createSessionCookie, readSessionUserId, SESSION_COOKIE, SESSION_TTL_SECONDS, };
7
+ export { clearSessionCookie, createSessionCookie, readSessionUserId, SESSION_COOKIE, SESSION_TTL_SECONDS, sessionCookieName, };
@@ -1,3 +1,6 @@
1
+ import type { AbilityChecker } from "../auth/abilityChecker";
2
+ import type { AuthUserDirectory } from "./authUserDirectory";
3
+ import type { ServiceContainerLike } from "./container";
1
4
  declare const CORE_CONFIG_TOKEN = "core.config";
2
5
  declare const CORE_CACHE_TOKEN = "core.cache";
3
6
  declare const CORE_QUEUE_TOKEN = "core.queue";
@@ -5,4 +8,10 @@ declare const CORE_EVENT_BUS_TOKEN = "core.eventBus";
5
8
  declare const CORE_POLICY_GATE_TOKEN = "core.policyGate";
6
9
  declare const CORE_AUTH_TOKEN = "core.auth";
7
10
  declare const CORE_TOKEN_SERVICE_TOKEN = "core.tokenService";
8
- export { CORE_AUTH_TOKEN, CORE_CACHE_TOKEN, CORE_CONFIG_TOKEN, CORE_EVENT_BUS_TOKEN, CORE_POLICY_GATE_TOKEN, CORE_QUEUE_TOKEN, CORE_TOKEN_SERVICE_TOKEN, };
11
+ declare const CORE_ABILITY_CHECKER_TOKEN = "core.abilityChecker";
12
+ declare const CORE_AUTH_USER_DIRECTORY_TOKEN = "core.authUserDirectory";
13
+ declare function isAbilityChecker(value: unknown): value is AbilityChecker;
14
+ declare function isAuthUserDirectory(value: unknown): value is AuthUserDirectory;
15
+ declare function resolveAbilityChecker(container: ServiceContainerLike): AbilityChecker;
16
+ declare function resolveAuthUserDirectory(container: ServiceContainerLike): AuthUserDirectory | null;
17
+ export { CORE_ABILITY_CHECKER_TOKEN, CORE_AUTH_TOKEN, CORE_AUTH_USER_DIRECTORY_TOKEN, CORE_CACHE_TOKEN, CORE_CONFIG_TOKEN, CORE_EVENT_BUS_TOKEN, CORE_POLICY_GATE_TOKEN, CORE_QUEUE_TOKEN, CORE_TOKEN_SERVICE_TOKEN, isAbilityChecker, isAuthUserDirectory, resolveAbilityChecker, resolveAuthUserDirectory, };
@@ -1,3 +1 @@
1
- import type { DatabaseConnection } from "./baseRepository";
2
- declare function bindDatabaseConnection(connection: DatabaseConnection): void;
3
- export { bindDatabaseConnection };
1
+ export { bindDatabaseConnection, getBoundDatabaseConnection, resetBoundDatabaseConnection, } from "./boundConnection";
@@ -0,0 +1,13 @@
1
+ import { SQL } from "bun";
2
+ import type { DatabaseConnection } from "./baseRepository";
3
+ interface CreateBunSqlPoolOptions {
4
+ url: string;
5
+ max?: number;
6
+ idleTimeout?: number;
7
+ maxLifetime?: number;
8
+ connectionTimeout?: number;
9
+ }
10
+ declare function createBunSqlPool(options: CreateBunSqlPoolOptions): InstanceType<typeof SQL>;
11
+ declare function bindBunSql(sql: DatabaseConnection): DatabaseConnection;
12
+ export type { CreateBunSqlPoolOptions };
13
+ export { bindBunSql, createBunSqlPool };
@@ -1,4 +1,5 @@
1
1
  declare const CSRF_COOKIE = "workhub_csrf";
2
+ declare function csrfCookieName(): string;
2
3
  declare function createCsrfTokenCookie(): {
3
4
  token: string;
4
5
  cookie: string;
@@ -11,4 +12,4 @@ declare function readSubmittedCsrfToken(request: Request): string | null;
11
12
  declare function readSubmittedCsrfTokenFromBody(request: Request): Promise<string | null>;
12
13
  declare function verifyCsrfToken(request: Request, submittedToken: string | null): boolean;
13
14
  declare function resolveCsrfTokenForRequest(request: Request): string;
14
- export { CSRF_COOKIE, createCsrfTokenCookie, readSubmittedCsrfToken, readSubmittedCsrfTokenFromBody, resolveCsrfToken, resolveCsrfTokenForRequest, verifyCsrfToken, };
15
+ export { CSRF_COOKIE, createCsrfTokenCookie, csrfCookieName, readSubmittedCsrfToken, readSubmittedCsrfTokenFromBody, resolveCsrfToken, resolveCsrfTokenForRequest, verifyCsrfToken, };
@@ -5,5 +5,6 @@ interface MemoryThrottleOptions {
5
5
  keyPrefix?: string;
6
6
  }
7
7
  declare function createMemoryThrottleMiddleware(options: MemoryThrottleOptions): Middleware;
8
+ declare function resetMemoryThrottleForTests(): void;
8
9
  export type { MemoryThrottleOptions };
9
- export { createMemoryThrottleMiddleware };
10
+ export { createMemoryThrottleMiddleware, resetMemoryThrottleForTests };
@@ -3,4 +3,16 @@ declare function htmlResponse(html: string, init?: {
3
3
  statusText?: string;
4
4
  }): Response;
5
5
  declare function isHtmxRequest(request: Request): boolean;
6
- export { htmlResponse, isHtmxRequest };
6
+ declare function redirectResponse(location: string, status?: number): Response;
7
+ declare function notFoundHtmlResponse(body?: string): Response;
8
+ declare function textResponse(body: string, init?: {
9
+ status?: number;
10
+ }): Response;
11
+ declare function xmlResponse(body: string, init?: {
12
+ status?: number;
13
+ contentType?: string;
14
+ }): Response;
15
+ declare function rssResponse(body: string, init?: {
16
+ status?: number;
17
+ }): Response;
18
+ export { htmlResponse, isHtmxRequest, notFoundHtmlResponse, redirectResponse, rssResponse, textResponse, xmlResponse, };
@@ -1,5 +1,5 @@
1
1
  export { DEFAULT_VIEWS_DIRECTORY, EtaViewEngine } from "./etaViewEngine";
2
- export { htmlResponse, isHtmxRequest } from "./htmlResponse";
2
+ export { htmlResponse, isHtmxRequest, notFoundHtmlResponse, redirectResponse, rssResponse, textResponse, xmlResponse, } from "./htmlResponse";
3
3
  export type { ViewEngine } from "./viewEngine";
4
- export type { WebLayoutAuthUser, WebLayoutData } from "./webLayoutData";
5
- export { resolveWebLayoutData } from "./webLayoutData";
4
+ export type { WebLayoutAuthUser, WebLayoutData, WebLayoutDataOptions, WebLayoutUserKey, } from "./webLayoutData";
5
+ export { configureWebLayoutData, resolveWebLayoutData } from "./webLayoutData";
@@ -3,15 +3,26 @@ interface WebLayoutAuthUser {
3
3
  id: number;
4
4
  email: string;
5
5
  role: string;
6
+ [key: string]: unknown;
6
7
  }
7
8
  interface WebLayoutData {
8
- authUser: WebLayoutAuthUser | null;
9
+ authUser?: WebLayoutAuthUser | null;
10
+ currentUser?: WebLayoutAuthUser | null;
9
11
  csrfToken: string;
10
12
  flash: {
11
13
  level: string;
12
14
  message: string;
13
15
  } | null;
16
+ [key: string]: unknown;
14
17
  }
15
- declare function resolveWebLayoutData(container: ServiceContainerLike, request?: Request): Promise<Record<string, unknown>>;
16
- export type { WebLayoutAuthUser, WebLayoutData };
17
- export { resolveWebLayoutData };
18
+ type WebLayoutUserKey = "authUser" | "currentUser";
19
+ interface WebLayoutDataOptions {
20
+ userKey?: WebLayoutUserKey;
21
+ loadUser?: (container: ServiceContainerLike, request: Request | undefined) => Promise<Record<string, unknown> | null>;
22
+ extra?: Record<string, unknown> | ((user: Record<string, unknown> | null) => Record<string, unknown> | Promise<Record<string, unknown>>);
23
+ }
24
+ declare function configureWebLayoutData(options: WebLayoutDataOptions): void;
25
+ declare function resetWebLayoutDataConfigForTests(): void;
26
+ declare function resolveWebLayoutData(container: ServiceContainerLike, request?: Request, options?: WebLayoutDataOptions): Promise<Record<string, unknown>>;
27
+ export type { WebLayoutAuthUser, WebLayoutData, WebLayoutDataOptions, WebLayoutUserKey };
28
+ export { configureWebLayoutData, resetWebLayoutDataConfigForTests, resolveWebLayoutData };
@@ -3,6 +3,9 @@
3
3
  import { createHmac, timingSafeEqual } from "crypto";
4
4
  var SESSION_COOKIE = "workhub_session";
5
5
  var SESSION_TTL_SECONDS = 60 * 60 * 24 * 7;
6
+ function sessionCookieName() {
7
+ return process.env.SESSION_COOKIE_NAME?.trim() || SESSION_COOKIE;
8
+ }
6
9
  function resolveSessionSecret() {
7
10
  return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || process.env.ADMIN_API_TOKEN?.trim() || "workhub-dev-session-secret";
8
11
  }
@@ -25,7 +28,7 @@ function readCookieValue(request, cookieName) {
25
28
  return null;
26
29
  }
27
30
  function readSessionUserId(request) {
28
- const cookieValue = readCookieValue(request, SESSION_COOKIE);
31
+ const cookieValue = readCookieValue(request, sessionCookieName());
29
32
  if (!cookieValue) {
30
33
  return null;
31
34
  }
@@ -60,16 +63,17 @@ function createSessionCookie(userId) {
60
63
  const issuedAt = Date.now();
61
64
  const value = signSession(userId, issuedAt);
62
65
  const secure = process.env.APP_ENV === "production" ? "; Secure" : "";
63
- return `${SESSION_COOKIE}=${encodeURIComponent(value)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${SESSION_TTL_SECONDS}${secure}`;
66
+ return `${sessionCookieName()}=${encodeURIComponent(value)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${SESSION_TTL_SECONDS}${secure}`;
64
67
  }
65
68
  function clearSessionCookie() {
66
69
  const secure = process.env.APP_ENV === "production" ? "; Secure" : "";
67
- return `${SESSION_COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0${secure}`;
70
+ return `${sessionCookieName()}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0${secure}`;
68
71
  }
69
72
  export {
70
73
  SESSION_COOKIE,
71
74
  SESSION_TTL_SECONDS,
72
75
  clearSessionCookie,
73
76
  createSessionCookie,
74
- readSessionUserId
77
+ readSessionUserId,
78
+ sessionCookieName
75
79
  };
@@ -7,6 +7,42 @@ var CORE_EVENT_BUS_TOKEN = "core.eventBus";
7
7
  var CORE_POLICY_GATE_TOKEN = "core.policyGate";
8
8
  var CORE_AUTH_TOKEN = "core.auth";
9
9
  var CORE_TOKEN_SERVICE_TOKEN = "core.tokenService";
10
+ var CORE_ABILITY_CHECKER_TOKEN = "core.abilityChecker";
11
+ var CORE_AUTH_USER_DIRECTORY_TOKEN = "core.authUserDirectory";
12
+ function isAbilityChecker(value) {
13
+ if (!value || typeof value !== "object") {
14
+ return false;
15
+ }
16
+ const candidate = value;
17
+ return typeof candidate.tokenCan === "function" && typeof candidate.requireAbility === "function";
18
+ }
19
+ function isAuthUserDirectory(value) {
20
+ if (!value || typeof value !== "object") {
21
+ return false;
22
+ }
23
+ return typeof value.findByIdOrThrow === "function";
24
+ }
25
+ function resolveAbilityChecker(container) {
26
+ if (container.has(CORE_ABILITY_CHECKER_TOKEN)) {
27
+ return container.resolve(CORE_ABILITY_CHECKER_TOKEN);
28
+ }
29
+ return container.resolve(CORE_TOKEN_SERVICE_TOKEN);
30
+ }
31
+ function resolveAuthUserDirectory(container) {
32
+ if (container.has(CORE_AUTH_USER_DIRECTORY_TOKEN)) {
33
+ const directory = container.resolve(CORE_AUTH_USER_DIRECTORY_TOKEN);
34
+ if (isAuthUserDirectory(directory)) {
35
+ return directory;
36
+ }
37
+ }
38
+ if (container.has(CORE_TOKEN_SERVICE_TOKEN)) {
39
+ const tokenService = container.resolve(CORE_TOKEN_SERVICE_TOKEN);
40
+ if (isAuthUserDirectory(tokenService)) {
41
+ return tokenService;
42
+ }
43
+ }
44
+ return null;
45
+ }
10
46
 
11
47
  // ../../src/core/auth/abilityCatalog.ts
12
48
  var MEMBER_ABILITIES = [
@@ -50,6 +86,9 @@ function resolveAbilitiesForRole(role) {
50
86
  import { createHmac, timingSafeEqual } from "crypto";
51
87
  var SESSION_COOKIE = "workhub_session";
52
88
  var SESSION_TTL_SECONDS = 60 * 60 * 24 * 7;
89
+ function sessionCookieName() {
90
+ return process.env.SESSION_COOKIE_NAME?.trim() || SESSION_COOKIE;
91
+ }
53
92
  function resolveSessionSecret() {
54
93
  return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || process.env.ADMIN_API_TOKEN?.trim() || "workhub-dev-session-secret";
55
94
  }
@@ -72,7 +111,7 @@ function readCookieValue(request, cookieName) {
72
111
  return null;
73
112
  }
74
113
  function readSessionUserId(request) {
75
- const cookieValue = readCookieValue(request, SESSION_COOKIE);
114
+ const cookieValue = readCookieValue(request, sessionCookieName());
76
115
  if (!cookieValue) {
77
116
  return null;
78
117
  }
@@ -107,11 +146,11 @@ function createSessionCookie(userId) {
107
146
  const issuedAt = Date.now();
108
147
  const value = signSession(userId, issuedAt);
109
148
  const secure = process.env.APP_ENV === "production" ? "; Secure" : "";
110
- return `${SESSION_COOKIE}=${encodeURIComponent(value)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${SESSION_TTL_SECONDS}${secure}`;
149
+ return `${sessionCookieName()}=${encodeURIComponent(value)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${SESSION_TTL_SECONDS}${secure}`;
111
150
  }
112
151
  function clearSessionCookie() {
113
152
  const secure = process.env.APP_ENV === "production" ? "; Secure" : "";
114
- return `${SESSION_COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0${secure}`;
153
+ return `${sessionCookieName()}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0${secure}`;
115
154
  }
116
155
 
117
156
  // ../../src/core/auth/sessionGuard.ts
@@ -125,10 +164,10 @@ class SessionGuard {
125
164
  if (!userId) {
126
165
  return null;
127
166
  }
128
- if (!this.container.has(CORE_TOKEN_SERVICE_TOKEN)) {
167
+ const tokenService = resolveAuthUserDirectory(this.container);
168
+ if (!tokenService) {
129
169
  return null;
130
170
  }
131
- const tokenService = this.container.resolve(CORE_TOKEN_SERVICE_TOKEN);
132
171
  try {
133
172
  const user = await tokenService.findByIdOrThrow(userId);
134
173
  return {
@@ -7,12 +7,54 @@ var CORE_EVENT_BUS_TOKEN = "core.eventBus";
7
7
  var CORE_POLICY_GATE_TOKEN = "core.policyGate";
8
8
  var CORE_AUTH_TOKEN = "core.auth";
9
9
  var CORE_TOKEN_SERVICE_TOKEN = "core.tokenService";
10
+ var CORE_ABILITY_CHECKER_TOKEN = "core.abilityChecker";
11
+ var CORE_AUTH_USER_DIRECTORY_TOKEN = "core.authUserDirectory";
12
+ function isAbilityChecker(value) {
13
+ if (!value || typeof value !== "object") {
14
+ return false;
15
+ }
16
+ const candidate = value;
17
+ return typeof candidate.tokenCan === "function" && typeof candidate.requireAbility === "function";
18
+ }
19
+ function isAuthUserDirectory(value) {
20
+ if (!value || typeof value !== "object") {
21
+ return false;
22
+ }
23
+ return typeof value.findByIdOrThrow === "function";
24
+ }
25
+ function resolveAbilityChecker(container) {
26
+ if (container.has(CORE_ABILITY_CHECKER_TOKEN)) {
27
+ return container.resolve(CORE_ABILITY_CHECKER_TOKEN);
28
+ }
29
+ return container.resolve(CORE_TOKEN_SERVICE_TOKEN);
30
+ }
31
+ function resolveAuthUserDirectory(container) {
32
+ if (container.has(CORE_AUTH_USER_DIRECTORY_TOKEN)) {
33
+ const directory = container.resolve(CORE_AUTH_USER_DIRECTORY_TOKEN);
34
+ if (isAuthUserDirectory(directory)) {
35
+ return directory;
36
+ }
37
+ }
38
+ if (container.has(CORE_TOKEN_SERVICE_TOKEN)) {
39
+ const tokenService = container.resolve(CORE_TOKEN_SERVICE_TOKEN);
40
+ if (isAuthUserDirectory(tokenService)) {
41
+ return tokenService;
42
+ }
43
+ }
44
+ return null;
45
+ }
10
46
  export {
47
+ CORE_ABILITY_CHECKER_TOKEN,
11
48
  CORE_AUTH_TOKEN,
49
+ CORE_AUTH_USER_DIRECTORY_TOKEN,
12
50
  CORE_CACHE_TOKEN,
13
51
  CORE_CONFIG_TOKEN,
14
52
  CORE_EVENT_BUS_TOKEN,
15
53
  CORE_POLICY_GATE_TOKEN,
16
54
  CORE_QUEUE_TOKEN,
17
- CORE_TOKEN_SERVICE_TOKEN
55
+ CORE_TOKEN_SERVICE_TOKEN,
56
+ isAbilityChecker,
57
+ isAuthUserDirectory,
58
+ resolveAbilityChecker,
59
+ resolveAuthUserDirectory
18
60
  };
@@ -0,0 +1 @@
1
+ export * from "../../index.js";
@@ -62,6 +62,9 @@ function currentRequestMeta() {
62
62
  // ../../src/core/http/csrfToken.ts
63
63
  var CSRF_COOKIE = "workhub_csrf";
64
64
  var CSRF_TTL_MS = 60 * 60 * 1000;
65
+ function csrfCookieName() {
66
+ return process.env.CSRF_COOKIE_NAME?.trim() || CSRF_COOKIE;
67
+ }
65
68
  function resolveCsrfSecret() {
66
69
  return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || process.env.ADMIN_API_TOKEN?.trim() || "workhub-dev-csrf-secret";
67
70
  }
@@ -81,11 +84,11 @@ function createCsrfTokenCookie() {
81
84
  const secure = process.env.APP_ENV === "production" ? "; Secure" : "";
82
85
  return {
83
86
  token,
84
- cookie: `${CSRF_COOKIE}=${encodeURIComponent(token)}; Path=/; SameSite=Lax; Max-Age=${Math.floor(CSRF_TTL_MS / 1000)}${secure}`
87
+ cookie: `${csrfCookieName()}=${encodeURIComponent(token)}; Path=/; SameSite=Lax; Max-Age=${Math.floor(CSRF_TTL_MS / 1000)}${secure}`
85
88
  };
86
89
  }
87
90
  function resolveCsrfToken(request) {
88
- const cookieValue = readRequestCookie(request, CSRF_COOKIE);
91
+ const cookieValue = readRequestCookie(request, csrfCookieName());
89
92
  if (cookieValue && Bun.CSRF.verify(cookieValue, csrfVerifyOptions())) {
90
93
  return { token: cookieValue };
91
94
  }
@@ -121,7 +124,7 @@ function verifyCsrfToken(request, submittedToken) {
121
124
  if (!submittedToken) {
122
125
  return false;
123
126
  }
124
- const cookieValue = readRequestCookie(request, CSRF_COOKIE);
127
+ const cookieValue = readRequestCookie(request, csrfCookieName());
125
128
  if (!cookieValue) {
126
129
  return false;
127
130
  }
@@ -59,6 +59,9 @@ function currentRequestMeta() {
59
59
  // ../../src/core/http/csrfToken.ts
60
60
  var CSRF_COOKIE = "workhub_csrf";
61
61
  var CSRF_TTL_MS = 60 * 60 * 1000;
62
+ function csrfCookieName() {
63
+ return process.env.CSRF_COOKIE_NAME?.trim() || CSRF_COOKIE;
64
+ }
62
65
  function resolveCsrfSecret() {
63
66
  return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || process.env.ADMIN_API_TOKEN?.trim() || "workhub-dev-csrf-secret";
64
67
  }
@@ -78,11 +81,11 @@ function createCsrfTokenCookie() {
78
81
  const secure = process.env.APP_ENV === "production" ? "; Secure" : "";
79
82
  return {
80
83
  token,
81
- cookie: `${CSRF_COOKIE}=${encodeURIComponent(token)}; Path=/; SameSite=Lax; Max-Age=${Math.floor(CSRF_TTL_MS / 1000)}${secure}`
84
+ cookie: `${csrfCookieName()}=${encodeURIComponent(token)}; Path=/; SameSite=Lax; Max-Age=${Math.floor(CSRF_TTL_MS / 1000)}${secure}`
82
85
  };
83
86
  }
84
87
  function resolveCsrfToken(request) {
85
- const cookieValue = readRequestCookie(request, CSRF_COOKIE);
88
+ const cookieValue = readRequestCookie(request, csrfCookieName());
86
89
  if (cookieValue && Bun.CSRF.verify(cookieValue, csrfVerifyOptions())) {
87
90
  return { token: cookieValue };
88
91
  }
@@ -118,7 +121,7 @@ function verifyCsrfToken(request, submittedToken) {
118
121
  if (!submittedToken) {
119
122
  return false;
120
123
  }
121
- const cookieValue = readRequestCookie(request, CSRF_COOKIE);
124
+ const cookieValue = readRequestCookie(request, csrfCookieName());
122
125
  if (!cookieValue) {
123
126
  return false;
124
127
  }
@@ -137,6 +140,7 @@ function resolveCsrfTokenForRequest(request) {
137
140
  export {
138
141
  CSRF_COOKIE,
139
142
  createCsrfTokenCookie,
143
+ csrfCookieName,
140
144
  readSubmittedCsrfToken,
141
145
  readSubmittedCsrfTokenFromBody,
142
146
  resolveCsrfToken,
@@ -15,9 +15,11 @@ function readClientIp(request, env = process.env) {
15
15
  }
16
16
 
17
17
  // ../../src/core/http/memoryThrottleMiddleware.ts
18
- var buckets = new Map;
18
+ var throttleBucketRegistries = new Set;
19
19
  function createMemoryThrottleMiddleware(options) {
20
20
  const prefix = options.keyPrefix ?? "workhub:memory-throttle:";
21
+ const buckets = new Map;
22
+ throttleBucketRegistries.add(buckets);
21
23
  return async (request, next) => {
22
24
  const path = new URL(request.url).pathname;
23
25
  const identity = readClientIp(request) ?? request.headers.get("authorization")?.slice(0, 32) ?? "unknown";
@@ -40,6 +42,12 @@ function createMemoryThrottleMiddleware(options) {
40
42
  return await next();
41
43
  };
42
44
  }
45
+ function resetMemoryThrottleForTests() {
46
+ for (const buckets of throttleBucketRegistries) {
47
+ buckets.clear();
48
+ }
49
+ }
43
50
  export {
44
- createMemoryThrottleMiddleware
51
+ createMemoryThrottleMiddleware,
52
+ resetMemoryThrottleForTests
45
53
  };