@getstrata/bootstrap 0.2.49 → 0.2.50

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
@@ -20,6 +20,7 @@ import { applyMiddlewareToRoutes } from "@getstrata/core/http/middleware";
20
20
 
21
21
  // ../../src/bootstrap/httpKernel.ts
22
22
  import { createMembershipMiddleware } from "@getstrata/core/auth/membershipMiddleware";
23
+ import { resolveAbilityChecker } from "@getstrata/core/contracts/serviceTokens";
23
24
  import { createAuthMiddleware } from "@getstrata/core/http/authMiddleware";
24
25
  import { createAuthorizeMiddleware } from "@getstrata/core/http/authorizeMiddleware";
25
26
  import { createBodySizeLimitMiddleware } from "@getstrata/core/http/bodySizeLimitMiddleware";
@@ -77,24 +78,38 @@ function parsePositiveInt(value, fallback) {
77
78
  }
78
79
  return Math.trunc(parsed);
79
80
  }
81
+ function parseWindowSeconds(secondsValue, msValue, fallback) {
82
+ if (secondsValue !== undefined && secondsValue.trim() !== "") {
83
+ return parsePositiveInt(secondsValue, fallback);
84
+ }
85
+ if (msValue !== undefined && msValue.trim() !== "") {
86
+ const parsedMs = Number(msValue);
87
+ if (Number.isFinite(parsedMs) && parsedMs > 0) {
88
+ return Math.max(1, Math.trunc(parsedMs / 1000));
89
+ }
90
+ }
91
+ return fallback;
92
+ }
80
93
  function resolveLoginRateLimit() {
81
94
  const defaults = isLocalAppEnv() ? LOCAL_LOGIN_RATE_LIMIT : PRODUCTION_LOGIN_RATE_LIMIT;
82
95
  return {
83
96
  maxAttempts: parsePositiveInt(process.env.LOGIN_RATE_LIMIT_PER_WINDOW, defaults.maxAttempts),
84
- decaySeconds: parsePositiveInt(process.env.LOGIN_RATE_LIMIT_WINDOW_SECONDS, defaults.decaySeconds)
97
+ decaySeconds: parseWindowSeconds(process.env.LOGIN_RATE_LIMIT_WINDOW_SECONDS, process.env.LOGIN_RATE_LIMIT_WINDOW_MS, defaults.decaySeconds)
85
98
  };
86
99
  }
87
100
  function resolveRegisterRateLimit() {
88
101
  const defaults = isLocalAppEnv() ? { maxAttempts: 100, decaySeconds: 60 } : { maxAttempts: 10, decaySeconds: 60 };
89
102
  return {
90
103
  maxAttempts: parsePositiveInt(process.env.REGISTER_RATE_LIMIT_PER_WINDOW, defaults.maxAttempts),
91
- decaySeconds: parsePositiveInt(process.env.REGISTER_RATE_LIMIT_WINDOW_SECONDS ?? process.env.REGISTER_RATE_LIMIT_WINDOW_MS ? String(Number(process.env.REGISTER_RATE_LIMIT_WINDOW_MS) / 1000) : undefined, defaults.decaySeconds)
104
+ decaySeconds: parseWindowSeconds(process.env.REGISTER_RATE_LIMIT_WINDOW_SECONDS, process.env.REGISTER_RATE_LIMIT_WINDOW_MS, defaults.decaySeconds)
92
105
  };
93
106
  }
94
107
 
95
108
  // ../../src/bootstrap/config.ts
96
109
  import {
110
+ CORE_ABILITY_CHECKER_TOKEN,
97
111
  CORE_AUTH_TOKEN,
112
+ CORE_AUTH_USER_DIRECTORY_TOKEN,
98
113
  CORE_CACHE_TOKEN,
99
114
  CORE_CONFIG_TOKEN,
100
115
  CORE_EVENT_BUS_TOKEN,
@@ -197,7 +212,7 @@ class HttpKernel {
197
212
  }
198
213
  wrapWebAbility(ability, handler) {
199
214
  const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
200
- const abilityChecker = this.dependencies.container.resolve(CORE_TOKEN_SERVICE_TOKEN);
215
+ const abilityChecker = resolveAbilityChecker(this.dependencies.container);
201
216
  const requireAbility = createRequireAbilityMiddleware(abilityChecker);
202
217
  const middleware = [createRequireWebAuthMiddleware(auth), requireAbility(ability)];
203
218
  return this.wrapWeb(withMiddleware(...middleware)(handler));
@@ -221,7 +236,7 @@ class HttpKernel {
221
236
  return withMiddleware(...middleware)(handler);
222
237
  }
223
238
  wrapAbility(ability, handler) {
224
- const abilityChecker = this.dependencies.container.resolve(CORE_TOKEN_SERVICE_TOKEN);
239
+ const abilityChecker = resolveAbilityChecker(this.dependencies.container);
225
240
  const requireAbility = createRequireAbilityMiddleware(abilityChecker);
226
241
  const middleware = [...this.group("authenticated"), requireAbility(ability)];
227
242
  return withMiddleware(...middleware)(handler);
@@ -891,6 +906,101 @@ function mergeWebRoutes(dependencies, routes) {
891
906
  function createAppDependencies() {
892
907
  return createAppContext().dependencies;
893
908
  }
909
+ // ../../src/bootstrap/health.ts
910
+ import { getBoundDatabaseConnection } from "@getstrata/core/database/boundConnection";
911
+ import { getDefaultDatabasePool } from "@getstrata/core/database/defaultConnection";
912
+ import { jsonResponse } from "@getstrata/core/http/response";
913
+ var {RedisClient } = globalThis.Bun;
914
+ function resolveRedisUrl(dependencies) {
915
+ if (!dependencies.container.has(CORE_CONFIG_TOKEN)) {
916
+ return process.env.REDIS_URL?.trim() || undefined;
917
+ }
918
+ const config = dependencies.container.resolve(CORE_CONFIG_TOKEN);
919
+ const redisUrl = config.get(REDIS_URL_CONFIG_KEY)?.trim();
920
+ return redisUrl || undefined;
921
+ }
922
+ function resolveHealthDatabase() {
923
+ const bound = getBoundDatabaseConnection();
924
+ if (bound) {
925
+ return bound;
926
+ }
927
+ try {
928
+ return getDefaultDatabasePool();
929
+ } catch {
930
+ return null;
931
+ }
932
+ }
933
+ async function pingDatabaseClient(connection) {
934
+ try {
935
+ await connection.unsafe("SELECT 1");
936
+ return true;
937
+ } catch {
938
+ return false;
939
+ }
940
+ }
941
+ async function checkDatabase() {
942
+ const connection = resolveHealthDatabase();
943
+ if (!connection) {
944
+ return false;
945
+ }
946
+ return await pingDatabaseClient(connection);
947
+ }
948
+ async function pingDatabase() {
949
+ return await checkDatabase();
950
+ }
951
+ async function checkRedis(redisUrl) {
952
+ try {
953
+ const client = new RedisClient(redisUrl);
954
+ const response = await client.ping();
955
+ return response === "PONG";
956
+ } catch {
957
+ return false;
958
+ }
959
+ }
960
+ async function resolveExtraFields(extra) {
961
+ if (!extra) {
962
+ return {};
963
+ }
964
+ return typeof extra === "function" ? await extra() : extra;
965
+ }
966
+ async function collectDependencyChecks(dependencies) {
967
+ const checks = {
968
+ database: await checkDatabase() ? "ok" : "error"
969
+ };
970
+ const redisUrl = resolveRedisUrl(dependencies);
971
+ if (redisUrl) {
972
+ checks.redis = await checkRedis(redisUrl) ? "ok" : "error";
973
+ } else {
974
+ checks.redis = "skipped";
975
+ }
976
+ const ready = checks.database === "ok" && (checks.redis === "ok" || checks.redis === "skipped");
977
+ return { checks, ready };
978
+ }
979
+ function createHealthRoutes(dependencies, options = {}) {
980
+ return {
981
+ "/health": async () => {
982
+ const extra = await resolveExtraFields(options.extra);
983
+ if (!options.pingOnHealth) {
984
+ return jsonResponse({ status: "ok", ...extra });
985
+ }
986
+ const { checks, ready } = await collectDependencyChecks(dependencies);
987
+ return jsonResponse({
988
+ status: ready ? "ok" : "error",
989
+ checks,
990
+ ...extra
991
+ }, { status: ready ? 200 : 503 });
992
+ },
993
+ "/ready": async () => {
994
+ const extra = await resolveExtraFields(options.extra);
995
+ const { checks, ready } = await collectDependencyChecks(dependencies);
996
+ return jsonResponse({
997
+ status: ready ? "ready" : "not_ready",
998
+ checks,
999
+ ...extra
1000
+ }, { status: ready ? 200 : 503 });
1001
+ }
1002
+ };
1003
+ }
894
1004
  // ../../src/bootstrap/http/securedRouteModelBinding.ts
895
1005
  import {
896
1006
  securedBindRouteModel,
@@ -902,6 +1012,7 @@ import { resolveMembershipService } from "@getstrata/core/auth/membershipService
902
1012
  var DEFAULT_ADMIN_API_TOKEN = "workhub-admin-test-token";
903
1013
  var DEFAULT_MEMBER_API_TOKEN = "workhub-member-test-token";
904
1014
  var DEFAULT_SCIM_BEARER_TOKEN = "workhub-scim-test-token";
1015
+ var MIN_SESSION_SECRET_LENGTH = 32;
905
1016
  var DEFAULT_TOKENS = new Set([DEFAULT_ADMIN_API_TOKEN, DEFAULT_MEMBER_API_TOKEN]);
906
1017
  var DEFAULT_SCIM_TOKENS = new Set([DEFAULT_SCIM_BEARER_TOKEN]);
907
1018
  function isEnabled(value, defaultEnabled) {
@@ -910,19 +1021,31 @@ function isEnabled(value, defaultEnabled) {
910
1021
  }
911
1022
  return defaultEnabled ? value !== "false" : value === "true";
912
1023
  }
913
- function assertProductionSecrets(env = process.env) {
914
- const appEnv = env.APP_ENV ?? "local";
915
- if (appEnv !== "production") {
916
- return;
1024
+ function isTokenAuthEnabled(env) {
1025
+ return Boolean(env.ADMIN_API_TOKEN?.trim()) || Boolean(env.MEMBER_API_TOKEN?.trim()) || env.FEATURE_API_TOKENS === "true";
1026
+ }
1027
+ function isOAuthEnabled(env) {
1028
+ return isEnabled(env.FEATURE_OAUTH, false) || isEnabled(env.FEATURE_SAML, false) || Boolean(env.GITHUB_CLIENT_ID?.trim()) || Boolean(env.OIDC_ISSUER?.trim()) || Boolean(env.SAML_LOGIN_URL?.trim());
1029
+ }
1030
+ function isCorsConfigured(env) {
1031
+ return env.CORS_ALLOWED_ORIGINS !== undefined;
1032
+ }
1033
+ function assertAuthDevHeadersDisabled(env) {
1034
+ if (isEnabled(env.AUTH_DEV_HEADERS, true)) {
1035
+ throw new Error("Production startup blocked: set AUTH_DEV_HEADERS=false to disable development auth headers.");
917
1036
  }
1037
+ }
1038
+ function assertSessionSecret(env) {
1039
+ const secret = env.SESSION_SECRET?.trim() ?? "";
1040
+ if (secret.length < MIN_SESSION_SECRET_LENGTH) {
1041
+ throw new Error("Production startup blocked: set SESSION_SECRET when FRONTEND_MODE=server-htmx (32+ characters).");
1042
+ }
1043
+ }
1044
+ function assertWorkHubProductionSecrets(env) {
918
1045
  const adminToken = env.ADMIN_API_TOKEN ?? DEFAULT_ADMIN_API_TOKEN;
919
1046
  const memberToken = env.MEMBER_API_TOKEN ?? DEFAULT_MEMBER_API_TOKEN;
920
1047
  const scimToken = env.SCIM_BEARER_TOKEN ?? DEFAULT_SCIM_BEARER_TOKEN;
921
1048
  const encryptionEnabled = isEnabled(env.FEATURE_FIELD_ENCRYPTION, true);
922
- const devHeadersEnabled = isEnabled(env.AUTH_DEV_HEADERS, true);
923
- if (devHeadersEnabled) {
924
- throw new Error("Production startup blocked: set AUTH_DEV_HEADERS=false to disable development auth headers.");
925
- }
926
1049
  if (DEFAULT_TOKENS.has(adminToken) || DEFAULT_TOKENS.has(memberToken)) {
927
1050
  throw new Error("Production startup blocked: rotate ADMIN_API_TOKEN and MEMBER_API_TOKEN away from default WorkHub test values.");
928
1051
  }
@@ -954,9 +1077,50 @@ function assertProductionSecrets(env = process.env) {
954
1077
  if (!env.API_TOKEN_DEFAULT_EXPIRY_DAYS?.trim()) {
955
1078
  throw new Error("Production startup blocked: set API_TOKEN_DEFAULT_EXPIRY_DAYS to enforce token rotation.");
956
1079
  }
1080
+ }
1081
+ function assertSiblingProductionSecrets(env) {
1082
+ if (isEnabled(env.FEATURE_SCIM, false)) {
1083
+ const scimToken = env.SCIM_BEARER_TOKEN ?? DEFAULT_SCIM_BEARER_TOKEN;
1084
+ if (DEFAULT_SCIM_TOKENS.has(scimToken) || !env.SCIM_BEARER_TOKEN?.trim()) {
1085
+ throw new Error("Production startup blocked: rotate SCIM_BEARER_TOKEN away from default WorkHub test values.");
1086
+ }
1087
+ }
1088
+ if (isEnabled(env.FEATURE_FIELD_ENCRYPTION, false) && !env.KMS_ENCRYPTION_KEY?.trim()) {
1089
+ throw new Error("Production startup blocked: set KMS_ENCRYPTION_KEY when field encryption is enabled.");
1090
+ }
1091
+ if (isEnabled(env.FEATURE_BILLING, false) && !env.STRIPE_WEBHOOK_SECRET?.trim()) {
1092
+ throw new Error("Production startup blocked: set STRIPE_WEBHOOK_SECRET when billing webhooks are enabled.");
1093
+ }
1094
+ if (isOAuthEnabled(env) && !env.OAUTH_STATE_SECRET?.trim()) {
1095
+ throw new Error("Production startup blocked: set OAUTH_STATE_SECRET for OAuth CSRF protection.");
1096
+ }
1097
+ if (isCorsConfigured(env)) {
1098
+ const corsOrigins = (env.CORS_ALLOWED_ORIGINS ?? "*").split(",").map((origin) => origin.trim());
1099
+ if (corsOrigins.includes("*")) {
1100
+ throw new Error("Production startup blocked: set explicit CORS_ALLOWED_ORIGINS instead of wildcard.");
1101
+ }
1102
+ }
1103
+ if (isEnabled(env.FEATURE_PUBLIC_READS, false)) {
1104
+ throw new Error("Production startup blocked: set FEATURE_PUBLIC_READS=false for authenticated-only reads.");
1105
+ }
1106
+ if (!env.SIEM_EXPORT_URL?.trim() && isEnabled(env.FEATURE_SIEM_EXPORT, false)) {
1107
+ console.warn("[secrets] SIEM_EXPORT_URL is not configured; audit logs remain database-only.");
1108
+ }
1109
+ }
1110
+ function assertProductionSecrets(env = process.env) {
1111
+ const appEnv = env.APP_ENV ?? "local";
1112
+ if (appEnv !== "production") {
1113
+ return;
1114
+ }
1115
+ assertAuthDevHeadersDisabled(env);
1116
+ if (isTokenAuthEnabled(env)) {
1117
+ assertWorkHubProductionSecrets(env);
1118
+ } else {
1119
+ assertSiblingProductionSecrets(env);
1120
+ }
957
1121
  const frontendMode = (env.FRONTEND_MODE ?? "api").trim();
958
- if (frontendMode === "server-htmx" && !env.SESSION_SECRET?.trim()) {
959
- throw new Error("Production startup blocked: set SESSION_SECRET when FRONTEND_MODE=server-htmx.");
1122
+ if (frontendMode === "server-htmx") {
1123
+ assertSessionSecret(env);
960
1124
  }
961
1125
  }
962
1126
  // ../../src/bootstrap/web/forms.ts
@@ -1090,15 +1254,40 @@ function createWebServer(options) {
1090
1254
  }
1091
1255
  // ../../src/bootstrap/web/session.ts
1092
1256
  import { createHash, randomBytes } from "crypto";
1257
+ import { AuthManager as AuthManager2 } from "@getstrata/core/auth/guard";
1258
+ import { getBoundDatabaseConnection as getBoundDatabaseConnection2 } from "@getstrata/core/database/boundConnection";
1259
+ import { getDefaultDatabasePool as getDefaultDatabasePool2 } from "@getstrata/core/database/defaultConnection";
1093
1260
  import { readRequestCookie } from "@getstrata/core/http/cookies";
1261
+ function isSqlClient(value) {
1262
+ return typeof value.unsafe === "function";
1263
+ }
1264
+ function resolveSql(source) {
1265
+ if (isSqlClient(source)) {
1266
+ return source;
1267
+ }
1268
+ return source();
1269
+ }
1270
+ function defaultSessionSql() {
1271
+ const bound = getBoundDatabaseConnection2();
1272
+ if (bound) {
1273
+ return bound;
1274
+ }
1275
+ return getDefaultDatabasePool2();
1276
+ }
1277
+ function defaultMapSessionUser(user) {
1278
+ return {
1279
+ id: user.id,
1280
+ role: user.is_admin ? "admin" : "member"
1281
+ };
1282
+ }
1094
1283
 
1095
1284
  class CookieSessionStore {
1096
- sql;
1285
+ sqlSource;
1097
1286
  secret;
1098
1287
  cookieName;
1099
1288
  maxAgeSeconds;
1100
- constructor(sql, secret, cookieName = "strata_session", maxAgeSeconds = 60 * 60 * 24 * 14) {
1101
- this.sql = sql;
1289
+ constructor(sqlSource, secret, cookieName = "strata_session", maxAgeSeconds = 60 * 60 * 24 * 14) {
1290
+ this.sqlSource = sqlSource;
1102
1291
  this.secret = secret;
1103
1292
  this.cookieName = cookieName;
1104
1293
  this.maxAgeSeconds = maxAgeSeconds;
@@ -1116,10 +1305,13 @@ class CookieSessionStore {
1116
1305
  }
1117
1306
  return header.includes("Secure") ? header : `${header}; Secure`;
1118
1307
  }
1308
+ sql() {
1309
+ return resolveSql(this.sqlSource);
1310
+ }
1119
1311
  async create(user) {
1120
1312
  const id = randomBytes(32).toString("hex");
1121
1313
  const expires = new Date(Date.now() + this.maxAgeSeconds * 1000);
1122
- await this.sql.unsafe(`INSERT INTO sessions (id, user_id, expires_at) VALUES ($1, $2, $3)`, [
1314
+ await this.sql().unsafe(`INSERT INTO sessions (id, user_id, expires_at) VALUES ($1, $2, $3)`, [
1123
1315
  id,
1124
1316
  user.id,
1125
1317
  expires
@@ -1127,7 +1319,7 @@ class CookieSessionStore {
1127
1319
  return id;
1128
1320
  }
1129
1321
  async destroy(sessionId) {
1130
- await this.sql.unsafe(`DELETE FROM sessions WHERE id = $1`, [sessionId]);
1322
+ await this.sql().unsafe(`DELETE FROM sessions WHERE id = $1`, [sessionId]);
1131
1323
  }
1132
1324
  async read(request) {
1133
1325
  const cookie = readRequestCookie(request, this.cookieName);
@@ -1138,7 +1330,7 @@ class CookieSessionStore {
1138
1330
  if (!sessionId || !signature || signature !== this.sign(sessionId)) {
1139
1331
  return null;
1140
1332
  }
1141
- const rows = await this.sql.unsafe(`SELECT s.id, s.user_id, s.expires_at, u.name, u.email, u.learn_subscriber,
1333
+ const rows = await this.sql().unsafe(`SELECT s.id, s.user_id, s.expires_at, u.name, u.email, u.learn_subscriber,
1142
1334
  COALESCE(u.is_admin, false) AS is_admin
1143
1335
  FROM sessions s
1144
1336
  INNER JOIN users u ON u.id = s.user_id
@@ -1158,19 +1350,42 @@ class CookieSessionStore {
1158
1350
  return createHash("sha256").update(`${value}.${this.secret}`).digest("hex").slice(0, 32);
1159
1351
  }
1160
1352
  }
1353
+
1354
+ class CookieSessionGuard {
1355
+ store;
1356
+ mapUser;
1357
+ constructor(store, mapUser = defaultMapSessionUser) {
1358
+ this.store = store;
1359
+ this.mapUser = mapUser;
1360
+ }
1361
+ async resolve(request) {
1362
+ const user = await this.store.read(request);
1363
+ if (!user) {
1364
+ return null;
1365
+ }
1366
+ return this.mapUser(user);
1367
+ }
1368
+ }
1369
+ function createCookieSessionAuthManager(options = {}) {
1370
+ const store = options.store ?? new CookieSessionStore(options.sql ?? defaultSessionSql, options.secret ?? process.env.SESSION_SECRET?.trim() ?? "", options.cookieName, options.maxAgeSeconds);
1371
+ return new AuthManager2(new CookieSessionGuard(store, options.mapUser ?? defaultMapSessionUser));
1372
+ }
1161
1373
  // ../../src/bootstrap/web/slug.ts
1162
1374
  function slugify(value) {
1163
1375
  return value.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
1164
1376
  }
1165
1377
  export {
1166
1378
  APP_PORT_CONFIG_KEY,
1379
+ CORE_ABILITY_CHECKER_TOKEN,
1167
1380
  CORE_AUTH_TOKEN,
1381
+ CORE_AUTH_USER_DIRECTORY_TOKEN,
1168
1382
  CORE_CACHE_TOKEN,
1169
1383
  CORE_CONFIG_TOKEN,
1170
1384
  CORE_EVENT_BUS_TOKEN,
1171
1385
  CORE_POLICY_GATE_TOKEN,
1172
1386
  CORE_QUEUE_TOKEN,
1173
1387
  CORE_TOKEN_SERVICE_TOKEN,
1388
+ CookieSessionGuard,
1174
1389
  CookieSessionStore,
1175
1390
  DATABASE_URL_CONFIG_KEY,
1176
1391
  DEFAULT_APP_PORT,
@@ -1184,12 +1399,16 @@ export {
1184
1399
  buildModuleRoutes,
1185
1400
  buildWebModuleRoutes,
1186
1401
  cacheTagsForModelWrite,
1402
+ checkDatabase,
1403
+ checkRedis,
1187
1404
  collectProviders,
1188
1405
  configureModulesDirectory,
1189
1406
  coreProviders,
1190
1407
  createAppContext,
1191
1408
  createAppDependencies,
1409
+ createCookieSessionAuthManager,
1192
1410
  createCsrfProtection,
1411
+ createHealthRoutes,
1193
1412
  createHttpKernel,
1194
1413
  createRouteKernel,
1195
1414
  createWebRoutes,
@@ -1200,6 +1419,7 @@ export {
1200
1419
  getRequiredDependency,
1201
1420
  mergeWebRoutes,
1202
1421
  parseFormBody,
1422
+ pingDatabase,
1203
1423
  prefixRouteMap,
1204
1424
  registerDefaultJobs,
1205
1425
  resolveApplicationAuth,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getstrata/bootstrap",
3
- "version": "0.2.49",
3
+ "version": "0.2.50",
4
4
  "description": "Strata application bootstrap — HttpKernel, DI, web session helpers",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -116,7 +116,7 @@
116
116
  "default": "./dist/entries/providers.js"
117
117
  },
118
118
  "./providers/view": {
119
- "types": "./dist/bootstrap/providers/view/index.d.ts",
119
+ "types": "./dist/bootstrap/providers/view.d.ts",
120
120
  "import": "./dist/entries/providers/view.js",
121
121
  "default": "./dist/entries/providers/view.js"
122
122
  },
@@ -165,7 +165,8 @@
165
165
  "types": "./dist/bootstrap/public-api.d.ts",
166
166
  "files": [
167
167
  "dist",
168
- "README.md"
168
+ "README.md",
169
+ "CHANGELOG.md"
169
170
  ],
170
171
  "scripts": {
171
172
  "build": "bun run build:bundle && bun run build:shims && bun run build:subpaths && bun run build:types",
@@ -179,7 +180,7 @@
179
180
  "access": "public"
180
181
  },
181
182
  "peerDependencies": {
182
- "@getstrata/core": "^0.5.58",
183
+ "@getstrata/core": "^0.5.59",
183
184
  "typescript": "^5.9.0"
184
185
  }
185
186
  }