@getstrata/core 0.5.12 → 0.5.14

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/dist/index.js CHANGED
@@ -149,6 +149,62 @@ function resolveApplicationLogger() {
149
149
  function resolveApplicationDependencies() {
150
150
  return requireActiveApplicationContext().dependencies;
151
151
  }
152
+ // ../../src/core/admin/formatValue.ts
153
+ function formatAdminValue(value, type = "text") {
154
+ if (value === null || value === undefined) {
155
+ return "";
156
+ }
157
+ if (type === "boolean") {
158
+ return value ? "yes" : "no";
159
+ }
160
+ if (type === "number") {
161
+ return String(value);
162
+ }
163
+ if (type === "datetime") {
164
+ if (value instanceof Date) {
165
+ return value.toISOString();
166
+ }
167
+ return String(value);
168
+ }
169
+ if (type === "code") {
170
+ if (typeof value === "string") {
171
+ return value;
172
+ }
173
+ return JSON.stringify(value, null, 2);
174
+ }
175
+ if (typeof value === "object") {
176
+ return JSON.stringify(value);
177
+ }
178
+ return String(value);
179
+ }
180
+ // ../../src/core/admin/registry.ts
181
+ class AdminResourceRegistry {
182
+ resources = new Map;
183
+ constructor() {}
184
+ register(resource) {
185
+ if (this.resources.has(resource.name)) {
186
+ throw new Error(`Admin resource "${resource.name}" is already registered.`);
187
+ }
188
+ this.resources.set(resource.name, resource);
189
+ }
190
+ get(name) {
191
+ return this.resources.get(name);
192
+ }
193
+ list() {
194
+ const definitions = [];
195
+ for (const resource of this.resources.values()) {
196
+ const { handlers: _handlers, ...definition } = resource;
197
+ definitions.push(definition);
198
+ }
199
+ return definitions;
200
+ }
201
+ all() {
202
+ return [...this.resources.values()];
203
+ }
204
+ clear() {
205
+ this.resources.clear();
206
+ }
207
+ }
152
208
  // ../../src/core/auth/authContext.ts
153
209
  import { AsyncLocalStorage } from "async_hooks";
154
210
  var authContext = new AsyncLocalStorage;
@@ -158,6 +214,130 @@ function runWithAuthUser(user, callback) {
158
214
  function currentAuthUser() {
159
215
  return authContext.getStore() ?? null;
160
216
  }
217
+ // ../../src/core/auth/membershipContext.ts
218
+ import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
219
+
220
+ // ../../src/config/database.ts
221
+ function readInteger(name, fallback) {
222
+ const parsed = Number.parseInt(process.env[name] ?? String(fallback), 10);
223
+ return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback;
224
+ }
225
+ var databaseConfig = {
226
+ url: process.env.DATABASE_URL ?? "",
227
+ poolMax: readInteger("DB_POOL_MAX", 10),
228
+ idleTimeoutSeconds: readInteger("DB_POOL_IDLE_TIMEOUT", 30),
229
+ maxLifetimeSeconds: readInteger("DB_POOL_MAX_LIFETIME", 3600),
230
+ connectionTimeoutSeconds: readInteger("DB_CONNECTION_TIMEOUT", 10)
231
+ };
232
+
233
+ // ../../src/core/database/connectionContext.ts
234
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
235
+ var activeConnection = new AsyncLocalStorage2;
236
+ function runWithDatabaseConnection(connection, callback) {
237
+ return activeConnection.run(connection, callback);
238
+ }
239
+ function getActiveDatabaseConnection(fallback) {
240
+ return activeConnection.getStore() ?? fallback;
241
+ }
242
+
243
+ // ../../src/db/connection/createConnection.ts
244
+ var {SQL } = globalThis.Bun;
245
+ function createDatabaseConnection(config) {
246
+ if (!config.url) {
247
+ throw new Error("DATABASE_URL is not configured. Set DATABASE_URL before starting the app or running integration tests.");
248
+ }
249
+ return new SQL({
250
+ url: config.url,
251
+ max: config.poolMax,
252
+ idleTimeout: config.idleTimeoutSeconds,
253
+ maxLifetime: config.maxLifetimeSeconds,
254
+ connectionTimeout: config.connectionTimeoutSeconds
255
+ });
256
+ }
257
+
258
+ // ../../src/db/connection/index.ts
259
+ var connectionHolder = {
260
+ connection: null
261
+ };
262
+ function getDatabase() {
263
+ if (!connectionHolder.connection) {
264
+ connectionHolder.connection = createDatabaseConnection(databaseConfig);
265
+ }
266
+ return connectionHolder.connection;
267
+ }
268
+ var POOL_CONNECTION_METHODS = new Set(["begin", "close", "connect"]);
269
+ function resolveDatabase() {
270
+ return getActiveDatabaseConnection(getDatabase());
271
+ }
272
+ function resolveDatabaseForProperty(property) {
273
+ if (typeof property === "string" && POOL_CONNECTION_METHODS.has(property)) {
274
+ return getDatabase();
275
+ }
276
+ return resolveDatabase();
277
+ }
278
+ var db = new Proxy(function database() {}, {
279
+ apply(_target, _thisArg, args) {
280
+ return resolveDatabase()(...args);
281
+ },
282
+ get(_target, property) {
283
+ const connection = resolveDatabaseForProperty(property);
284
+ const value = connection[property];
285
+ return typeof value === "function" ? value.bind(connection) : value;
286
+ }
287
+ });
288
+ var connection_default = db;
289
+
290
+ // ../../src/modules/organization/memberRepository.ts
291
+ class OrganizationMemberRepository {
292
+ constructor() {}
293
+ async findMembership(userId, organizationId) {
294
+ const rows = await connection_default`
295
+ SELECT id, organization_id, user_id, role, created_at
296
+ FROM organization_member
297
+ WHERE user_id = ${userId} AND organization_id = ${organizationId}
298
+ LIMIT 1
299
+ `;
300
+ return rows[0] ?? null;
301
+ }
302
+ async listForUser(userId) {
303
+ return await connection_default`
304
+ SELECT id, organization_id, user_id, role, created_at
305
+ FROM organization_member
306
+ WHERE user_id = ${userId}
307
+ ORDER BY organization_id
308
+ `;
309
+ }
310
+ async listForOrganization(organizationId) {
311
+ return await connection_default`
312
+ SELECT id, organization_id, user_id, role, created_at
313
+ FROM organization_member
314
+ WHERE organization_id = ${organizationId}
315
+ ORDER BY id
316
+ `;
317
+ }
318
+ async addMember(input) {
319
+ const rows = await connection_default`
320
+ INSERT INTO organization_member (organization_id, user_id, role)
321
+ VALUES (${input.organizationId}, ${input.userId}, ${input.role ?? "member"})
322
+ RETURNING id, organization_id, user_id, role, created_at
323
+ `;
324
+ const row = rows[0];
325
+ if (!row) {
326
+ throw new Error("Organization member insert did not return a row.");
327
+ }
328
+ return row;
329
+ }
330
+ async removeMember(organizationId, userId) {
331
+ const rows = await connection_default`
332
+ DELETE FROM organization_member
333
+ WHERE organization_id = ${organizationId} AND user_id = ${userId}
334
+ RETURNING id
335
+ `;
336
+ return rows.length > 0;
337
+ }
338
+ }
339
+ var memberRepository_default = OrganizationMemberRepository;
340
+
161
341
  // ../../src/core/errors/http.ts
162
342
  class HttpError extends Error {
163
343
  status;
@@ -224,6 +404,84 @@ class PreconditionFailedError extends HttpError {
224
404
  }
225
405
  }
226
406
 
407
+ // ../../src/core/auth/accessControl.ts
408
+ var ROLE_RANK = {
409
+ member: 1,
410
+ admin: 2,
411
+ owner: 3
412
+ };
413
+ function isGlobalAdmin(user) {
414
+ return user?.role === "admin";
415
+ }
416
+ function hasMinimumOrgRole(role, minimum) {
417
+ if (!role) {
418
+ return false;
419
+ }
420
+ return ROLE_RANK[role] >= ROLE_RANK[minimum];
421
+ }
422
+ function requireAuthenticatedUser() {
423
+ const user = currentAuthUser();
424
+ if (!user) {
425
+ throw new ForbiddenError("Authentication required.");
426
+ }
427
+ return user;
428
+ }
429
+ function resolveUserId(user) {
430
+ const userId = typeof user.id === "number" ? user.id : Number(user.id);
431
+ if (!Number.isInteger(userId) || userId <= 0) {
432
+ throw new ForbiddenError("Invalid authenticated user.");
433
+ }
434
+ return userId;
435
+ }
436
+
437
+ // ../../src/core/auth/membershipContext.ts
438
+ var membershipContext = new AsyncLocalStorage3;
439
+ var membershipRepository = new memberRepository_default;
440
+ async function runWithMembershipContext(callback) {
441
+ const user = currentAuthUser();
442
+ if (!user || isGlobalAdmin(user)) {
443
+ return await callback();
444
+ }
445
+ const memberships = await membershipRepository.listForUser(resolveUserId(user));
446
+ const context = {
447
+ organizationIds: memberships.map((membership) => membership.organization_id),
448
+ rolesByOrganizationId: new Map(memberships.map((membership) => [membership.organization_id, membership.role]))
449
+ };
450
+ return await membershipContext.run(context, callback);
451
+ }
452
+ function currentOrgRole(organizationId) {
453
+ return membershipContext.getStore()?.rolesByOrganizationId.get(organizationId) ?? null;
454
+ }
455
+ function hasOrgMembership(organizationId) {
456
+ return currentOrgRole(organizationId) !== null;
457
+ }
458
+ function currentOrganizationIds() {
459
+ return membershipContext.getStore()?.organizationIds ?? [];
460
+ }
461
+ function hasMinimumOrgRole2(organizationId, minimum) {
462
+ const role = currentOrgRole(organizationId);
463
+ if (!role) {
464
+ return false;
465
+ }
466
+ const ranks = {
467
+ member: 1,
468
+ admin: 2,
469
+ owner: 3
470
+ };
471
+ return ranks[role] >= ranks[minimum];
472
+ }
473
+
474
+ // ../../src/core/auth/membershipContextMiddleware.ts
475
+ function createMembershipContextMiddleware() {
476
+ return async (_request, next) => {
477
+ return await runWithMembershipContext(async () => await next());
478
+ };
479
+ }
480
+
481
+ // ../../src/core/auth/membershipMiddleware.ts
482
+ function createMembershipMiddleware() {
483
+ return createMembershipContextMiddleware();
484
+ }
227
485
  // ../../src/core/auth/policy.ts
228
486
  class Policy {
229
487
  constructor() {}
@@ -1003,76 +1261,6 @@ function indexMorphToRelation(children, parentsByType, relation) {
1003
1261
  return result;
1004
1262
  }
1005
1263
 
1006
- // ../../src/config/database.ts
1007
- function readInteger(name, fallback) {
1008
- const parsed = Number.parseInt(process.env[name] ?? String(fallback), 10);
1009
- return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback;
1010
- }
1011
- var databaseConfig = {
1012
- url: process.env.DATABASE_URL ?? "",
1013
- poolMax: readInteger("DB_POOL_MAX", 10),
1014
- idleTimeoutSeconds: readInteger("DB_POOL_IDLE_TIMEOUT", 30),
1015
- maxLifetimeSeconds: readInteger("DB_POOL_MAX_LIFETIME", 3600),
1016
- connectionTimeoutSeconds: readInteger("DB_CONNECTION_TIMEOUT", 10)
1017
- };
1018
-
1019
- // ../../src/core/database/connectionContext.ts
1020
- import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
1021
- var activeConnection = new AsyncLocalStorage2;
1022
- function runWithDatabaseConnection(connection, callback) {
1023
- return activeConnection.run(connection, callback);
1024
- }
1025
- function getActiveDatabaseConnection(fallback) {
1026
- return activeConnection.getStore() ?? fallback;
1027
- }
1028
-
1029
- // ../../src/db/connection/createConnection.ts
1030
- var {SQL } = globalThis.Bun;
1031
- function createDatabaseConnection(config) {
1032
- if (!config.url) {
1033
- throw new Error("DATABASE_URL is not configured. Set DATABASE_URL before starting the app or running integration tests.");
1034
- }
1035
- return new SQL({
1036
- url: config.url,
1037
- max: config.poolMax,
1038
- idleTimeout: config.idleTimeoutSeconds,
1039
- maxLifetime: config.maxLifetimeSeconds,
1040
- connectionTimeout: config.connectionTimeoutSeconds
1041
- });
1042
- }
1043
-
1044
- // ../../src/db/connection/index.ts
1045
- var connectionHolder = {
1046
- connection: null
1047
- };
1048
- function getDatabase() {
1049
- if (!connectionHolder.connection) {
1050
- connectionHolder.connection = createDatabaseConnection(databaseConfig);
1051
- }
1052
- return connectionHolder.connection;
1053
- }
1054
- var POOL_CONNECTION_METHODS = new Set(["begin", "close", "connect"]);
1055
- function resolveDatabase() {
1056
- return getActiveDatabaseConnection(getDatabase());
1057
- }
1058
- function resolveDatabaseForProperty(property) {
1059
- if (typeof property === "string" && POOL_CONNECTION_METHODS.has(property)) {
1060
- return getDatabase();
1061
- }
1062
- return resolveDatabase();
1063
- }
1064
- var db = new Proxy(function database() {}, {
1065
- apply(_target, _thisArg, args) {
1066
- return resolveDatabase()(...args);
1067
- },
1068
- get(_target, property) {
1069
- const connection = resolveDatabaseForProperty(property);
1070
- const value = connection[property];
1071
- return typeof value === "function" ? value.bind(connection) : value;
1072
- }
1073
- });
1074
- var connection_default = db;
1075
-
1076
1264
  // ../../src/core/database/boundConnection.ts
1077
1265
  var boundConnectionHolder = {
1078
1266
  connection: null
@@ -2877,7 +3065,12 @@ async function defaultSmtpTransport(config, message) {
2877
3065
  }
2878
3066
  }
2879
3067
  function buildSmtpPayload(from, message) {
2880
- const headers = [`From: ${from}`, `To: ${message.to}`, `Subject: ${message.subject}`, "MIME-Version: 1.0"];
3068
+ const headers = [
3069
+ `From: ${from}`,
3070
+ `To: ${message.to}`,
3071
+ `Subject: ${message.subject}`,
3072
+ "MIME-Version: 1.0"
3073
+ ];
2881
3074
  if (message.html) {
2882
3075
  const boundary = `strata-${Date.now().toString(36)}`;
2883
3076
  headers.push(`Content-Type: multipart/alternative; boundary="${boundary}"`);
@@ -2957,8 +3150,11 @@ class LocalStorageDriver {
2957
3150
  constructor(rootDirectory) {
2958
3151
  this.rootDirectory = rootDirectory;
2959
3152
  }
3153
+ resolveRootDirectory() {
3154
+ return this.rootDirectory ?? process.env.STORAGE_PATH ?? "storage";
3155
+ }
2960
3156
  resolvePath(path) {
2961
- return join3(this.rootDirectory, path.replace(/^\/+/, ""));
3157
+ return join3(this.resolveRootDirectory(), path.replace(/^\/+/, ""));
2962
3158
  }
2963
3159
  async put(path, contents) {
2964
3160
  const absolutePath = this.resolvePath(path);
@@ -3054,11 +3250,17 @@ function createStorageDriver() {
3054
3250
  if (driver === "s3") {
3055
3251
  return new S3StorageDriver(createS3Client());
3056
3252
  }
3057
- return new LocalStorageDriver(process.env.STORAGE_PATH ?? "storage");
3253
+ return new LocalStorageDriver;
3058
3254
  }
3059
- var defaultStorage = new StorageManager(createStorageDriver());
3255
+ var defaultStorage = { current: null };
3060
3256
  function storage() {
3061
- return defaultStorage;
3257
+ if (!defaultStorage.current) {
3258
+ defaultStorage.current = new StorageManager(createStorageDriver());
3259
+ }
3260
+ return defaultStorage.current;
3261
+ }
3262
+ function resetDefaultStorage() {
3263
+ defaultStorage.current = null;
3062
3264
  }
3063
3265
 
3064
3266
  // ../../src/core/facades/index.ts
@@ -3142,12 +3344,62 @@ function readRequestCookie(request, name) {
3142
3344
  function readBunRequestCookie(request, name) {
3143
3345
  return request.cookies.get(name) ?? readRequestCookie(request, name);
3144
3346
  }
3347
+ // ../../src/config/cors.ts
3348
+ var corsConfig = {
3349
+ allowedOrigins: (process.env.CORS_ALLOWED_ORIGINS ?? "*").split(",").map((origin) => origin.trim()).filter(Boolean),
3350
+ allowedMethods: ["GET", "POST", "PATCH", "PUT", "DELETE", "OPTIONS"],
3351
+ allowedHeaders: [
3352
+ "Authorization",
3353
+ "Content-Type",
3354
+ "X-Request-Id",
3355
+ "X-Tenant-Id",
3356
+ "X-Authenticated-User-Id",
3357
+ "X-Authenticated-User-Role",
3358
+ "If-Match",
3359
+ "If-None-Match"
3360
+ ],
3361
+ maxAgeSeconds: 86400
3362
+ };
3363
+
3364
+ // ../../src/core/http/corsMiddleware.ts
3365
+ function createCorsMiddleware() {
3366
+ return async (request, next) => {
3367
+ if (request.method === "OPTIONS") {
3368
+ return new Response(null, {
3369
+ status: 204,
3370
+ headers: buildCorsHeaders(request)
3371
+ });
3372
+ }
3373
+ const response = await next();
3374
+ const headers = new Headers(response.headers);
3375
+ for (const [key, value] of buildCorsHeaders(request)) {
3376
+ headers.set(key, value);
3377
+ }
3378
+ return new Response(response.body, {
3379
+ status: response.status,
3380
+ statusText: response.statusText,
3381
+ headers
3382
+ });
3383
+ };
3384
+ }
3385
+ function buildCorsHeaders(request) {
3386
+ const headers = new Headers;
3387
+ const origin = request.headers.get("origin");
3388
+ const allowedOrigins = corsConfig.allowedOrigins;
3389
+ const allowOrigin = allowedOrigins.includes("*") || origin && allowedOrigins.includes(origin) ? origin ?? "*" : allowedOrigins[0] ?? "*";
3390
+ headers.set("Access-Control-Allow-Origin", allowOrigin);
3391
+ headers.set("Access-Control-Allow-Methods", corsConfig.allowedMethods.join(", "));
3392
+ headers.set("Access-Control-Allow-Headers", corsConfig.allowedHeaders.join(", "));
3393
+ headers.set("Access-Control-Max-Age", String(corsConfig.maxAgeSeconds));
3394
+ headers.set("Vary", "Origin");
3395
+ return headers;
3396
+ }
3145
3397
  // ../../src/core/http/csrfToken.ts
3146
3398
  import { timingSafeEqual } from "crypto";
3147
3399
 
3148
3400
  // ../../src/core/http/requestMetaContext.ts
3149
- import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
3150
- var requestMetaContext = new AsyncLocalStorage3;
3401
+ import { AsyncLocalStorage as AsyncLocalStorage4 } from "async_hooks";
3402
+ var requestMetaContext = new AsyncLocalStorage4;
3151
3403
  function runWithRequestMeta(meta, callback) {
3152
3404
  return requestMetaContext.run(meta, callback);
3153
3405
  }
@@ -3379,29 +3631,142 @@ function applyConditionalGet(request, response, etag) {
3379
3631
  headers
3380
3632
  });
3381
3633
  }
3382
- // ../../src/core/tenant/tenantContext.ts
3383
- import { AsyncLocalStorage as AsyncLocalStorage4 } from "async_hooks";
3384
- var tenantContext = new AsyncLocalStorage4;
3385
- function runWithTenant(tenant, callback) {
3386
- return tenantContext.run(tenant, callback);
3387
- }
3388
- function currentTenant() {
3389
- return tenantContext.getStore() ?? null;
3634
+ // ../../src/core/http/flashSession.ts
3635
+ import { createHmac, timingSafeEqual as timingSafeEqual2 } from "crypto";
3636
+ var FLASH_COOKIE = "workhub_flash";
3637
+ var FLASH_TTL_MS = 60 * 1000;
3638
+ function resolveFlashSecret() {
3639
+ return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || "workhub-dev-flash-secret";
3390
3640
  }
3391
- function currentTenantId() {
3392
- return currentTenant()?.id ?? 1;
3641
+ function signFlashPayload(payload, issuedAt) {
3642
+ const signature = createHmac("sha256", resolveFlashSecret()).update(`${payload}.${issuedAt}`).digest("hex");
3643
+ return `${payload}.${issuedAt}.${signature}`;
3393
3644
  }
3394
- function rateLimitMultiplierForPlan(plan) {
3395
- switch (plan) {
3396
- case "enterprise":
3397
- return 4;
3398
- case "pro":
3399
- return 2;
3400
- default:
3401
- return 1;
3645
+ function readFlashCookie(request) {
3646
+ const cookieHeader = request.headers.get("cookie");
3647
+ if (!cookieHeader) {
3648
+ return null;
3402
3649
  }
3650
+ for (const part of cookieHeader.split(";")) {
3651
+ const [name, ...rest] = part.trim().split("=");
3652
+ if (name === FLASH_COOKIE) {
3653
+ return decodeURIComponent(rest.join("="));
3654
+ }
3655
+ }
3656
+ return null;
3403
3657
  }
3404
-
3658
+ function parseFlashCookie(cookieValue) {
3659
+ const parts = cookieValue.split(".");
3660
+ if (parts.length < 3) {
3661
+ return null;
3662
+ }
3663
+ const signature = parts.pop();
3664
+ const issuedAtRaw = parts.pop();
3665
+ const payload = parts.join(".");
3666
+ if (!signature || !issuedAtRaw || !payload) {
3667
+ return null;
3668
+ }
3669
+ const issuedAt = Number.parseInt(issuedAtRaw, 10);
3670
+ if (!Number.isFinite(issuedAt) || Date.now() - issuedAt > FLASH_TTL_MS) {
3671
+ return null;
3672
+ }
3673
+ const expectedSignature = signFlashPayload(payload, issuedAt).split(".").pop();
3674
+ if (!expectedSignature) {
3675
+ return null;
3676
+ }
3677
+ const expectedBuffer = Buffer.from(expectedSignature);
3678
+ const actualBuffer = Buffer.from(signature);
3679
+ if (expectedBuffer.length !== actualBuffer.length) {
3680
+ return null;
3681
+ }
3682
+ if (!timingSafeEqual2(expectedBuffer, actualBuffer)) {
3683
+ return null;
3684
+ }
3685
+ try {
3686
+ const parsed = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
3687
+ if (!parsed?.message || typeof parsed.message !== "string") {
3688
+ return null;
3689
+ }
3690
+ if (parsed.level !== "success" && parsed.level !== "error" && parsed.level !== "info") {
3691
+ return null;
3692
+ }
3693
+ return parsed;
3694
+ } catch {
3695
+ return null;
3696
+ }
3697
+ }
3698
+ function createFlashCookie(message) {
3699
+ const payload = Buffer.from(JSON.stringify(message), "utf8").toString("base64url");
3700
+ const issuedAt = Date.now();
3701
+ const value = signFlashPayload(payload, issuedAt);
3702
+ return `${FLASH_COOKIE}=${encodeURIComponent(value)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=60`;
3703
+ }
3704
+ function clearFlashCookie() {
3705
+ return `${FLASH_COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`;
3706
+ }
3707
+ function pullFlash(request) {
3708
+ const cookieValue = readFlashCookie(request);
3709
+ if (!cookieValue) {
3710
+ return null;
3711
+ }
3712
+ return parseFlashCookie(cookieValue);
3713
+ }
3714
+ function flashResponse(response, message) {
3715
+ const headers = new Headers(response.headers);
3716
+ headers.append("set-cookie", createFlashCookie(message));
3717
+ return new Response(response.body, {
3718
+ status: response.status,
3719
+ statusText: response.statusText,
3720
+ headers
3721
+ });
3722
+ }
3723
+ function withFlashClear(response) {
3724
+ const headers = new Headers(response.headers);
3725
+ headers.append("set-cookie", clearFlashCookie());
3726
+ return new Response(response.body, {
3727
+ status: response.status,
3728
+ statusText: response.statusText,
3729
+ headers
3730
+ });
3731
+ }
3732
+
3733
+ // ../../src/core/http/flashMiddleware.ts
3734
+ function createFlashMiddleware() {
3735
+ return async (request, next) => {
3736
+ const flash = pullFlash(request);
3737
+ const meta = currentRequestMeta();
3738
+ return await runWithRequestMeta({ ...meta, request, flash }, async () => {
3739
+ const response = await next();
3740
+ if (flash) {
3741
+ return withFlashClear(response);
3742
+ }
3743
+ return response;
3744
+ });
3745
+ };
3746
+ }
3747
+ // ../../src/core/tenant/tenantContext.ts
3748
+ import { AsyncLocalStorage as AsyncLocalStorage5 } from "async_hooks";
3749
+ var tenantContext = new AsyncLocalStorage5;
3750
+ function runWithTenant(tenant, callback) {
3751
+ return tenantContext.run(tenant, callback);
3752
+ }
3753
+ function currentTenant() {
3754
+ return tenantContext.getStore() ?? null;
3755
+ }
3756
+ function currentTenantId() {
3757
+ return currentTenant()?.id ?? 1;
3758
+ }
3759
+ function rateLimitMultiplierForPlan(plan) {
3760
+ switch (plan) {
3761
+ case "enterprise":
3762
+ return 4;
3763
+ case "pro":
3764
+ return 2;
3765
+ default:
3766
+ return 1;
3767
+ }
3768
+ }
3769
+
3405
3770
  // ../../src/core/http/validation.ts
3406
3771
  function buildRequestCacheKey(fallbackPath, request) {
3407
3772
  if (!request) {
@@ -3791,7 +4156,7 @@ async function verifyPassword(password, passwordHash) {
3791
4156
  }
3792
4157
 
3793
4158
  // ../../src/core/crypto/fieldEncryption.ts
3794
- import { createCipheriv, createDecipheriv, createHmac, randomBytes } from "crypto";
4159
+ import { createCipheriv, createDecipheriv, createHmac as createHmac2, randomBytes } from "crypto";
3795
4160
  var ENCRYPTION_PREFIX = "enc:v1:";
3796
4161
  var IV_LENGTH = 12;
3797
4162
  var TAG_LENGTH = 16;
@@ -3840,7 +4205,7 @@ function decryptField(value, key) {
3840
4205
  return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
3841
4206
  }
3842
4207
  function hashLookupValue(normalizedValue, key) {
3843
- return createHmac("sha256", key).update(normalizedValue).digest("hex");
4208
+ return createHmac2("sha256", key).update(normalizedValue).digest("hex");
3844
4209
  }
3845
4210
  function normalizeEmail(email) {
3846
4211
  return email.trim().toLowerCase();
@@ -3920,7 +4285,7 @@ function resolveDefaultTokenExpiryDays() {
3920
4285
  }
3921
4286
 
3922
4287
  // ../../src/core/security/totp.ts
3923
- import { createHmac as createHmac2 } from "crypto";
4288
+ import { createHmac as createHmac3 } from "crypto";
3924
4289
  function decodeBase32(input) {
3925
4290
  const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
3926
4291
  const normalized = input.replace(/=+$/u, "").toUpperCase();
@@ -3942,7 +4307,7 @@ function generateTotp(secret, counter, digits = 6) {
3942
4307
  const key = decodeBase32(secret);
3943
4308
  const buffer = Buffer.alloc(8);
3944
4309
  buffer.writeBigUInt64BE(BigInt(counter));
3945
- const digest = createHmac2("sha1", key).update(buffer).digest();
4310
+ const digest = createHmac3("sha1", key).update(buffer).digest();
3946
4311
  const lastByte = digest[digest.length - 1] ?? 0;
3947
4312
  const offset = lastByte & 15;
3948
4313
  const b0 = digest[offset] ?? 0;
@@ -4134,14 +4499,14 @@ var userTable = defineTable({
4134
4499
  });
4135
4500
 
4136
4501
  // ../../src/core/auth/tokenHash.ts
4137
- import { createHash, createHmac as createHmac3 } from "crypto";
4502
+ import { createHash, createHmac as createHmac4 } from "crypto";
4138
4503
  function resolveTokenPepper() {
4139
4504
  return process.env.TOKEN_HASH_PEPPER?.trim() ?? "workhub-dev-token-pepper";
4140
4505
  }
4141
4506
  function hashApiToken(token) {
4142
4507
  const pepper = resolveTokenPepper();
4143
4508
  if (pepper && pepper !== "workhub-dev-token-pepper") {
4144
- return createHmac3("sha256", pepper).update(token).digest("hex");
4509
+ return createHmac4("sha256", pepper).update(token).digest("hex");
4145
4510
  }
4146
4511
  return createHash("sha256").update(token).digest("hex");
4147
4512
  }
@@ -4149,105 +4514,6 @@ function hashApiToken(token) {
4149
4514
  // ../../src/modules/user/provider.ts
4150
4515
  var tokenServiceToken = CORE_TOKEN_SERVICE_TOKEN;
4151
4516
 
4152
- // ../../src/core/http/flashSession.ts
4153
- import { createHmac as createHmac4, timingSafeEqual as timingSafeEqual2 } from "crypto";
4154
- var FLASH_COOKIE = "workhub_flash";
4155
- var FLASH_TTL_MS = 60 * 1000;
4156
- function resolveFlashSecret() {
4157
- return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || "workhub-dev-flash-secret";
4158
- }
4159
- function signFlashPayload(payload, issuedAt) {
4160
- const signature = createHmac4("sha256", resolveFlashSecret()).update(`${payload}.${issuedAt}`).digest("hex");
4161
- return `${payload}.${issuedAt}.${signature}`;
4162
- }
4163
- function readFlashCookie(request) {
4164
- const cookieHeader = request.headers.get("cookie");
4165
- if (!cookieHeader) {
4166
- return null;
4167
- }
4168
- for (const part of cookieHeader.split(";")) {
4169
- const [name, ...rest] = part.trim().split("=");
4170
- if (name === FLASH_COOKIE) {
4171
- return decodeURIComponent(rest.join("="));
4172
- }
4173
- }
4174
- return null;
4175
- }
4176
- function parseFlashCookie(cookieValue) {
4177
- const parts = cookieValue.split(".");
4178
- if (parts.length < 3) {
4179
- return null;
4180
- }
4181
- const signature = parts.pop();
4182
- const issuedAtRaw = parts.pop();
4183
- const payload = parts.join(".");
4184
- if (!signature || !issuedAtRaw || !payload) {
4185
- return null;
4186
- }
4187
- const issuedAt = Number.parseInt(issuedAtRaw, 10);
4188
- if (!Number.isFinite(issuedAt) || Date.now() - issuedAt > FLASH_TTL_MS) {
4189
- return null;
4190
- }
4191
- const expectedSignature = signFlashPayload(payload, issuedAt).split(".").pop();
4192
- if (!expectedSignature) {
4193
- return null;
4194
- }
4195
- const expectedBuffer = Buffer.from(expectedSignature);
4196
- const actualBuffer = Buffer.from(signature);
4197
- if (expectedBuffer.length !== actualBuffer.length) {
4198
- return null;
4199
- }
4200
- if (!timingSafeEqual2(expectedBuffer, actualBuffer)) {
4201
- return null;
4202
- }
4203
- try {
4204
- const parsed = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
4205
- if (!parsed?.message || typeof parsed.message !== "string") {
4206
- return null;
4207
- }
4208
- if (parsed.level !== "success" && parsed.level !== "error" && parsed.level !== "info") {
4209
- return null;
4210
- }
4211
- return parsed;
4212
- } catch {
4213
- return null;
4214
- }
4215
- }
4216
- function createFlashCookie(message) {
4217
- const payload = Buffer.from(JSON.stringify(message), "utf8").toString("base64url");
4218
- const issuedAt = Date.now();
4219
- const value = signFlashPayload(payload, issuedAt);
4220
- return `${FLASH_COOKIE}=${encodeURIComponent(value)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=60`;
4221
- }
4222
- function clearFlashCookie() {
4223
- return `${FLASH_COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`;
4224
- }
4225
- function pullFlash(request) {
4226
- const cookieValue = readFlashCookie(request);
4227
- if (!cookieValue) {
4228
- return null;
4229
- }
4230
- return parseFlashCookie(cookieValue);
4231
- }
4232
- function flashResponse(response, message) {
4233
- const headers = new Headers(response.headers);
4234
- headers.append("set-cookie", createFlashCookie(message));
4235
- return new Response(response.body, {
4236
- status: response.status,
4237
- statusText: response.statusText,
4238
- headers
4239
- });
4240
- }
4241
- function withFlashClear(response) {
4242
- const headers = new Headers(response.headers);
4243
- headers.append("set-cookie", clearFlashCookie());
4244
- return new Response(response.body, {
4245
- status: response.status,
4246
- statusText: response.statusText,
4247
- headers
4248
- });
4249
- }
4250
-
4251
4517
  // ../../src/core/view/webLayoutData.ts
4252
4518
  async function resolveWebLayoutData(container, request) {
4253
4519
  const csrfToken = request ? resolveCsrfTokenForRequest(request) : "";
@@ -4843,6 +5109,38 @@ function createMetricsMiddleware() {
4843
5109
  return response;
4844
5110
  };
4845
5111
  }
5112
+ // ../../src/core/http/requireAbilityMiddleware.ts
5113
+ function createRequireAbilityMiddleware(abilityChecker) {
5114
+ return (ability) => {
5115
+ return async (_request, next) => {
5116
+ const user = currentAuthUser();
5117
+ try {
5118
+ abilityChecker.requireAbility(user, ability);
5119
+ } catch (error) {
5120
+ if (error instanceof ForbiddenError) {
5121
+ return Response.json({ error: error.message }, { status: error.status });
5122
+ }
5123
+ throw error;
5124
+ }
5125
+ return await next();
5126
+ };
5127
+ };
5128
+ }
5129
+ // ../../src/core/http/requireGlobalAdminMiddleware.ts
5130
+ function createRequireGlobalAdminMiddleware() {
5131
+ return async (_request, next) => {
5132
+ const user = currentAuthUser();
5133
+ if (!isGlobalAdmin(user)) {
5134
+ logSecurityEvent("privilege_escalation_blocked", {
5135
+ required_role: "platform_admin",
5136
+ path: new URL(_request.url).pathname
5137
+ });
5138
+ const error = new ForbiddenError("Platform admin access required.");
5139
+ return Response.json({ error: error.message }, { status: error.status });
5140
+ }
5141
+ return await next();
5142
+ };
5143
+ }
4846
5144
  // ../../src/core/http/requireWebAuthMiddleware.ts
4847
5145
  function createRequireWebAuthMiddleware(auth2) {
4848
5146
  return async (request, next) => {
@@ -5049,6 +5347,29 @@ function resetGracefulShutdownForTests() {
5049
5347
  shutdownInstalled = false;
5050
5348
  shuttingDown = false;
5051
5349
  }
5350
+ // ../../src/core/logging/requestLoggingMiddleware.ts
5351
+ function createRequestLoggingMiddleware() {
5352
+ return async (request, next) => {
5353
+ return await runWithRequestMeta({
5354
+ ipAddress: request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? request.headers.get("x-real-ip"),
5355
+ userAgent: request.headers.get("user-agent"),
5356
+ request
5357
+ }, async () => {
5358
+ const startedAt = performance.now();
5359
+ const requestId = request.headers.get("x-request-id") ?? crypto.randomUUID();
5360
+ const response = await next();
5361
+ const durationMs = Math.round(performance.now() - startedAt);
5362
+ appLogger.info("HTTP request completed", {
5363
+ requestId,
5364
+ method: request.method,
5365
+ path: new URL(request.url).pathname,
5366
+ status: response.status,
5367
+ durationMs
5368
+ });
5369
+ return response;
5370
+ });
5371
+ };
5372
+ }
5052
5373
  // ../../src/core/mail/markdownMail.ts
5053
5374
  function escapeHtml(value) {
5054
5375
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
@@ -5183,6 +5504,9 @@ function createNotificationDispatcher(mailer2, databaseStore) {
5183
5504
  }
5184
5505
  // ../../src/core/notifications/notification.ts
5185
5506
  class Notification {
5507
+ via(_notifiable) {
5508
+ throw new Error("Notification subclasses must implement via().");
5509
+ }
5186
5510
  toMail(_notifiable) {
5187
5511
  return null;
5188
5512
  }
@@ -5256,6 +5580,12 @@ class FailedJobService {
5256
5580
  await this.repository.deleteById(id);
5257
5581
  return failedJob;
5258
5582
  }
5583
+ async delete(id) {
5584
+ const deleted = await this.repository.deleteById(id);
5585
+ if (!deleted) {
5586
+ throw new Error(`Failed job ${id} not found.`);
5587
+ }
5588
+ }
5259
5589
  async flush() {
5260
5590
  const jobs = await this.repository.findAll();
5261
5591
  let deleted = 0;
@@ -5297,9 +5627,6 @@ class JobRegistry {
5297
5627
  }
5298
5628
  var jobRegistry = new JobRegistry;
5299
5629
 
5300
- // ../../src/core/queue/redisQueue.ts
5301
- var {RedisClient: RedisClient3 } = globalThis.Bun;
5302
-
5303
5630
  // ../../src/config/queue.ts
5304
5631
  var queueConfig = {
5305
5632
  driver: process.env.QUEUE_DRIVER === "redis" || process.env.QUEUE_DRIVER === "async" || process.env.QUEUE_DRIVER === "sync" ? process.env.QUEUE_DRIVER : DEFAULT_QUEUE_DRIVER,
@@ -5338,6 +5665,7 @@ async function runQueueJob(envelope, failedJobs) {
5338
5665
  }
5339
5666
 
5340
5667
  // ../../src/core/queue/redisQueue.ts
5668
+ var {RedisClient: RedisClient3 } = globalThis.Bun;
5341
5669
  var QUEUE_LIST_KEY = "workhub:queue:default";
5342
5670
  var QUEUE_HIGH_KEY = "workhub:queue:high";
5343
5671
  var QUEUE_LOW_KEY = "workhub:queue:low";
@@ -5542,6 +5870,208 @@ async function runDueScheduledTasks(schedule = appSchedule, now = new Date) {
5542
5870
  }
5543
5871
  return due.length;
5544
5872
  }
5873
+ // ../../src/core/security/publicReads.ts
5874
+ function isPublicReadsEnabled() {
5875
+ return isFeatureEnabled("publicReads");
5876
+ }
5877
+ function guestCanViewResource() {
5878
+ return isPublicReadsEnabled();
5879
+ }
5880
+ // ../../src/core/tenant/tenantMiddleware.ts
5881
+ import { createHash as createHash2 } from "crypto";
5882
+
5883
+ // ../../src/core/tenant/databaseTenantContext.ts
5884
+ async function runWithMigrationBypass(callback) {
5885
+ await connection_default`SELECT set_config('app.bypass_rls', 'true', false)`;
5886
+ try {
5887
+ return await callback();
5888
+ } finally {
5889
+ await connection_default`SELECT set_config('app.bypass_rls', 'false', false)`;
5890
+ }
5891
+ }
5892
+
5893
+ // ../../src/core/tenant/resolveTenant.ts
5894
+ async function resolveTenant(tenantId) {
5895
+ const rows = await connection_default`
5896
+ SELECT id, slug, plan, region
5897
+ FROM tenant
5898
+ WHERE id = ${tenantId}
5899
+ LIMIT 1
5900
+ `;
5901
+ const row = rows[0];
5902
+ return row ? { id: row.id, slug: row.slug, plan: row.plan, region: row.region ?? "eu" } : null;
5903
+ }
5904
+
5905
+ // ../../src/core/tenant/tenantDatabaseScope.ts
5906
+ async function applyTenantContextToTransaction(transaction, tenantId) {
5907
+ await transaction.unsafe(`SELECT set_config('app.tenant_id', $1, true)`, [String(tenantId)]);
5908
+ await transaction.unsafe(`SELECT set_config('app.bypass_rls', $1, true)`, ["false"]);
5909
+ }
5910
+ async function runWithTenantDatabase(tenant, callback) {
5911
+ return await getDatabase().begin(async (transaction) => {
5912
+ await applyTenantContextToTransaction(transaction, tenant.id);
5913
+ return await runWithDatabaseConnection(transaction, async () => {
5914
+ return await runWithTenant(tenant, callback);
5915
+ });
5916
+ });
5917
+ }
5918
+
5919
+ // ../../src/core/tenant/tenantMiddleware.ts
5920
+ var DEFAULT_TENANT = {
5921
+ id: 1,
5922
+ slug: "default",
5923
+ plan: "enterprise",
5924
+ region: "eu"
5925
+ };
5926
+ async function resolveUserTenantId(userId) {
5927
+ return await runWithMigrationBypass(async () => {
5928
+ const rows = await connection_default`
5929
+ SELECT tenant_id
5930
+ FROM users
5931
+ WHERE id = ${userId}
5932
+ LIMIT 1
5933
+ `;
5934
+ return rows[0]?.tenant_id ?? DEFAULT_TENANT.id;
5935
+ });
5936
+ }
5937
+ function auditChecksum(payload) {
5938
+ return createHash2("sha256").update(JSON.stringify(payload)).digest("hex");
5939
+ }
5940
+ async function resolveTenantForRequest(request) {
5941
+ const user = currentAuthUser();
5942
+ const headerValue = request.headers.get("x-tenant-id")?.trim();
5943
+ const parsedHeader = headerValue !== undefined && headerValue.length > 0 ? Number.parseInt(headerValue, 10) : Number.NaN;
5944
+ if (user) {
5945
+ const userId = typeof user.id === "number" ? user.id : Number.parseInt(String(user.id), 10);
5946
+ if (Number.isInteger(userId) && userId > 0) {
5947
+ const userTenantId = await resolveUserTenantId(userId);
5948
+ if (!isGlobalAdmin(user)) {
5949
+ if (Number.isInteger(parsedHeader) && parsedHeader > 0 && parsedHeader !== userTenantId) {
5950
+ throw new ForbiddenError("Tenant header does not match your account.");
5951
+ }
5952
+ return await resolveTenant(userTenantId) ?? DEFAULT_TENANT;
5953
+ }
5954
+ if (Number.isInteger(parsedHeader) && parsedHeader > 0) {
5955
+ return await resolveTenant(parsedHeader) ?? DEFAULT_TENANT;
5956
+ }
5957
+ return await resolveTenant(userTenantId) ?? DEFAULT_TENANT;
5958
+ }
5959
+ }
5960
+ const tenantId = Number.isInteger(parsedHeader) && parsedHeader > 0 ? parsedHeader : DEFAULT_TENANT.id;
5961
+ return await resolveTenant(tenantId) ?? DEFAULT_TENANT;
5962
+ }
5963
+ function createTenantMiddleware() {
5964
+ return async (request, next) => {
5965
+ try {
5966
+ const tenant = await resolveTenantForRequest(request);
5967
+ return await runWithTenantDatabase(tenant, async () => {
5968
+ const response = await next();
5969
+ const headers = new Headers(response.headers);
5970
+ headers.set("x-tenant-id", String(tenant.id));
5971
+ headers.set("x-tenant-region", tenant.region);
5972
+ return new Response(response.body, {
5973
+ status: response.status,
5974
+ statusText: response.statusText,
5975
+ headers
5976
+ });
5977
+ });
5978
+ } catch (error) {
5979
+ if (error instanceof HttpError) {
5980
+ return Response.json({ error: error.message }, { status: error.status });
5981
+ }
5982
+ throw error;
5983
+ }
5984
+ };
5985
+ }
5986
+ // ../../src/core/tracing/otel.ts
5987
+ import { randomBytes as randomBytes2 } from "crypto";
5988
+ function randomHex(bytes) {
5989
+ return randomBytes2(bytes).toString("hex");
5990
+ }
5991
+ function createSpan(input) {
5992
+ const spanId = randomHex(8);
5993
+ return {
5994
+ traceId: input.traceId,
5995
+ spanId,
5996
+ name: input.name,
5997
+ startTimeUnixNano: String(Math.floor(input.startedAt * 1e6)),
5998
+ endTimeUnixNano: String(Math.floor(input.endedAt * 1e6)),
5999
+ attributes: Object.entries(input.attributes ?? {}).map(([key, value]) => ({
6000
+ key,
6001
+ value: { stringValue: value }
6002
+ })),
6003
+ status: { code: 1 }
6004
+ };
6005
+ }
6006
+ async function exportOtelSpan(span) {
6007
+ const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT?.trim();
6008
+ if (!endpoint) {
6009
+ return;
6010
+ }
6011
+ const serviceName = process.env.OTEL_SERVICE_NAME?.trim() ?? "workhub-api";
6012
+ const url = endpoint.endsWith("/v1/traces") ? endpoint : `${endpoint.replace(/\/$/, "")}/v1/traces`;
6013
+ await fetch(url, {
6014
+ method: "POST",
6015
+ headers: { "content-type": "application/json" },
6016
+ body: JSON.stringify({
6017
+ resourceSpans: [
6018
+ {
6019
+ resource: {
6020
+ attributes: [{ key: "service.name", value: { stringValue: serviceName } }]
6021
+ },
6022
+ scopeSpans: [{ spans: [span] }]
6023
+ }
6024
+ ]
6025
+ })
6026
+ });
6027
+ }
6028
+
6029
+ // ../../src/core/tracing/traceContext.ts
6030
+ import { AsyncLocalStorage as AsyncLocalStorage6 } from "async_hooks";
6031
+ var traceContextStorage = new AsyncLocalStorage6;
6032
+ function runWithTraceContext(context, callback) {
6033
+ return traceContextStorage.run(context, callback);
6034
+ }
6035
+ function currentTraceId() {
6036
+ return traceContextStorage.getStore()?.traceId ?? null;
6037
+ }
6038
+
6039
+ // ../../src/core/tracing/tracingMiddleware.ts
6040
+ function createTracingMiddleware() {
6041
+ return async (request, next) => {
6042
+ const traceId = (request.headers.get("x-trace-id") ?? crypto.randomUUID()).replace(/-/g, "");
6043
+ const spanId = crypto.randomUUID().replace(/-/g, "").slice(0, 16);
6044
+ const startedAt = performance.now();
6045
+ const path = new URL(request.url).pathname;
6046
+ return await runWithTraceContext({ traceId, spanId }, async () => {
6047
+ const response = await next();
6048
+ const endedAt = performance.now();
6049
+ const headers = new Headers(response.headers);
6050
+ headers.set("x-trace-id", traceId);
6051
+ headers.set("x-span-id", spanId);
6052
+ headers.set("traceparent", `00-${traceId}-${spanId}-01`);
6053
+ headers.set("server-timing", `app;dur=${(endedAt - startedAt).toFixed(2)}`);
6054
+ exportOtelSpan(createSpan({
6055
+ traceId,
6056
+ name: `${request.method} ${path}`,
6057
+ startedAt,
6058
+ endedAt,
6059
+ attributes: {
6060
+ "http.method": request.method,
6061
+ "http.route": path,
6062
+ "http.status_code": String(response.status)
6063
+ }
6064
+ })).catch(() => {
6065
+ return;
6066
+ });
6067
+ return new Response(response.body, {
6068
+ status: response.status,
6069
+ statusText: response.statusText,
6070
+ headers
6071
+ });
6072
+ });
6073
+ };
6074
+ }
5545
6075
  // ../../src/core/validation/rules.ts
5546
6076
  function required() {
5547
6077
  return (field, value) => {
@@ -5712,6 +6242,7 @@ export {
5712
6242
  runWithDatabaseConnection,
5713
6243
  runWithAuthUser,
5714
6244
  runSeedersFromDirectory,
6245
+ runQueueJob,
5715
6246
  runInTransaction,
5716
6247
  runGracefulShutdown,
5717
6248
  runDueScheduledTasks,
@@ -5728,7 +6259,9 @@ export {
5728
6259
  resolveApplicationConfig,
5729
6260
  resolveApplicationCache,
5730
6261
  resolveApplicationAuth,
6262
+ resetDefaultStorage,
5731
6263
  required,
6264
+ requestIdMiddleware,
5732
6265
  renderMarkdownMail,
5733
6266
  registerShutdownHandler,
5734
6267
  registerModelRepository,
@@ -5757,6 +6290,7 @@ export {
5757
6290
  loadMigrationsFromDirectory,
5758
6291
  jsonResponse2 as jsonResponse,
5759
6292
  jobRegistry,
6293
+ isPublicReadsEnabled,
5760
6294
  isHtmxRequest,
5761
6295
  isEtagEnabled,
5762
6296
  installGracefulShutdownSignals,
@@ -5776,6 +6310,7 @@ export {
5776
6310
  getMigrationStatus,
5777
6311
  getActiveDatabaseConnection,
5778
6312
  freshDatabase,
6313
+ formatAdminValue,
5779
6314
  filterMassAssignable,
5780
6315
  events,
5781
6316
  etagFromResource,
@@ -5785,23 +6320,31 @@ export {
5785
6320
  currentAuthUser,
5786
6321
  createdResponse,
5787
6322
  createTrackedJob,
6323
+ createTracingMiddleware,
5788
6324
  createThrottleMiddleware,
6325
+ createTenantMiddleware,
5789
6326
  createSecurityHeadersMiddleware,
5790
6327
  createSchemaBuilder,
5791
6328
  createRequireWebAuthMiddleware,
6329
+ createRequireGlobalAdminMiddleware,
5792
6330
  createRequireAuthMiddleware,
6331
+ createRequireAbilityMiddleware,
6332
+ createRequestLoggingMiddleware,
5793
6333
  createQueueWorker,
5794
6334
  createQueue,
5795
6335
  createProductionQueue,
5796
6336
  createNotificationDispatcher,
5797
6337
  createMetricsMiddleware,
5798
6338
  createMemoryThrottleMiddleware,
6339
+ createMembershipMiddleware,
5799
6340
  createLoginThrottleMiddleware,
6341
+ createFlashMiddleware,
5800
6342
  createFailedJobService,
5801
6343
  createDatabaseConnection2 as createDatabaseConnection,
5802
6344
  createCsrfTokenCookie,
5803
6345
  createCsrfProtection,
5804
6346
  createCsrfMiddleware,
6347
+ createCorsMiddleware,
5805
6348
  createBodySizeLimitMiddleware,
5806
6349
  createAuthorizeMiddleware,
5807
6350
  createAuthMiddleware,
@@ -5865,5 +6408,6 @@ export {
5865
6408
  Blueprint,
5866
6409
  baseRepository_default as BaseRepository,
5867
6410
  BadRequestError,
5868
- AsyncQueue
6411
+ AsyncQueue,
6412
+ AdminResourceRegistry
5869
6413
  };