@getstrata/bootstrap 1.0.3 → 1.0.5

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,14 @@
1
1
  # @getstrata/bootstrap changelog
2
2
 
3
+ ## 1.0.5
4
+
5
+ - Lockstep with `create-strata` 1.0.5. No runtime changes.
6
+
7
+ ## 1.0.4
8
+
9
+ - `assertProductionSecrets()` uses `isProductionEnv()`, so `NODE_ENV=production`, `APP_ENV=Production`, and `APP_ENV=staging` cannot skip the guard.
10
+ - Feature flags parse with `envFlagEnabled()` (`=== "true"` only).
11
+
3
12
  ## 1.0.3
4
13
 
5
14
  - Lockstep with `create-strata` 1.0.3. No runtime changes.
package/README.md CHANGED
@@ -20,7 +20,7 @@ bun add @getstrata/bootstrap @getstrata/core
20
20
  import { coreProviders, createAppContext, createHttpKernel } from "@getstrata/bootstrap";
21
21
  ```
22
22
 
23
- `createAppContext()` does not call `assertProductionSecrets`. Call that yourself when `APP_ENV=production`; it is feature-gated, so an HTML app with API tokens off is not asked for token secrets. It rejects empty secrets, short `SESSION_SECRET` values, wildcard `CORS_ALLOWED_ORIGINS`, `AUTH_DEV_HEADERS=true`, `FEATURE_PUBLIC_READS=true`, and any secret still holding a generated `change-me` placeholder.
23
+ `createAppContext()` does not call `assertProductionSecrets`. Call that yourself when `isProductionEnv()` is true (`APP_ENV` or `NODE_ENV` production, `APP_ENV=staging`, or an unrecognized `APP_ENV`); it is feature-gated, so an HTML app with API tokens off is not asked for token secrets. It rejects empty secrets, short `SESSION_SECRET` values, wildcard `CORS_ALLOWED_ORIGINS`, `AUTH_DEV_HEADERS` other than `false`, `FEATURE_PUBLIC_READS=true`, and any secret still holding a generated `change-me` placeholder.
24
24
 
25
25
  Build routes with `buildWebModuleRoutes` and `buildModuleRoutes`.
26
26
 
@@ -105,8 +105,9 @@ import { JwtGuard } from "@getstrata/core/auth/jwtGuard";
105
105
  import { SessionGuard } from "@getstrata/core/auth/sessionGuard";
106
106
 
107
107
  // ../../src/config/auth.ts
108
+ import { envFlagEnabled } from "@getstrata/core/runtime/appEnv";
108
109
  var authConfig = {
109
- allowDevHeaders: process.env.AUTH_DEV_HEADERS === "true",
110
+ allowDevHeaders: envFlagEnabled(process.env.AUTH_DEV_HEADERS),
110
111
  tokenDefaultAbilities: ["*"]
111
112
  };
112
113
 
@@ -105,8 +105,9 @@ import { JwtGuard } from "@getstrata/core/auth/jwtGuard";
105
105
  import { SessionGuard } from "@getstrata/core/auth/sessionGuard";
106
106
 
107
107
  // ../../src/config/auth.ts
108
+ import { envFlagEnabled } from "@getstrata/core/runtime/appEnv";
108
109
  var authConfig = {
109
- allowDevHeaders: process.env.AUTH_DEV_HEADERS === "true",
110
+ allowDevHeaders: envFlagEnabled(process.env.AUTH_DEV_HEADERS),
110
111
  tokenDefaultAbilities: ["*"]
111
112
  };
112
113
 
@@ -11,8 +11,9 @@ import { JwtGuard } from "@getstrata/core/auth/jwtGuard";
11
11
  import { SessionGuard } from "@getstrata/core/auth/sessionGuard";
12
12
 
13
13
  // ../../src/config/auth.ts
14
+ import { envFlagEnabled } from "@getstrata/core/runtime/appEnv";
14
15
  var authConfig = {
15
- allowDevHeaders: process.env.AUTH_DEV_HEADERS === "true",
16
+ allowDevHeaders: envFlagEnabled(process.env.AUTH_DEV_HEADERS),
16
17
  tokenDefaultAbilities: ["*"]
17
18
  };
18
19
 
@@ -1,5 +1,6 @@
1
1
  // @bun
2
2
  // ../../src/bootstrap/secretsGuard.ts
3
+ import { envFlagEnabled, isProductionEnv } from "@getstrata/core/runtime/appEnv";
3
4
  import { isViewsMode, parseFrontendMode } from "@getstrata/core/runtime/frontendMode";
4
5
  var PUBLISHED_TEST_ADMIN_API_TOKEN = "strata-admin-test-token";
5
6
  var PUBLISHED_TEST_MEMBER_API_TOKEN = "strata-member-test-token";
@@ -29,23 +30,17 @@ function assertNoPlaceholderSecrets(env) {
29
30
  throw new Error(`Production startup blocked: replace the generated placeholder values for ${unrotated.join(", ")}.`);
30
31
  }
31
32
  }
32
- function isEnabled(value, defaultEnabled) {
33
- if (value === undefined) {
34
- return defaultEnabled;
35
- }
36
- return defaultEnabled ? value !== "false" : value === "true";
37
- }
38
33
  function isTokenAuthEnabled(env) {
39
- return Boolean(env.ADMIN_API_TOKEN?.trim()) || Boolean(env.MEMBER_API_TOKEN?.trim()) || env.FEATURE_API_TOKENS === "true";
34
+ return Boolean(env.ADMIN_API_TOKEN?.trim()) || Boolean(env.MEMBER_API_TOKEN?.trim()) || envFlagEnabled(env.FEATURE_API_TOKENS);
40
35
  }
41
36
  function isOAuthEnabled(env) {
42
- 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());
37
+ return envFlagEnabled(env.FEATURE_OAUTH) || envFlagEnabled(env.FEATURE_SAML) || Boolean(env.GITHUB_CLIENT_ID?.trim()) || Boolean(env.OIDC_ISSUER?.trim()) || Boolean(env.SAML_LOGIN_URL?.trim());
43
38
  }
44
39
  function isCorsConfigured(env) {
45
40
  return env.CORS_ALLOWED_ORIGINS !== undefined;
46
41
  }
47
42
  function assertAuthDevHeadersDisabled(env) {
48
- if (isEnabled(env.AUTH_DEV_HEADERS, true)) {
43
+ if (env.AUTH_DEV_HEADERS !== "false") {
49
44
  throw new Error("Production startup blocked: set AUTH_DEV_HEADERS=false to disable development auth headers.");
50
45
  }
51
46
  }
@@ -76,16 +71,16 @@ function assertTokenAuthProductionSecrets(env) {
76
71
  }
77
72
  }
78
73
  function assertFeatureProductionSecrets(env) {
79
- if (isEnabled(env.FEATURE_SCIM, false)) {
74
+ if (envFlagEnabled(env.FEATURE_SCIM)) {
80
75
  const scimToken = env.SCIM_BEARER_TOKEN ?? PUBLISHED_TEST_SCIM_BEARER_TOKEN;
81
76
  if (PUBLISHED_TEST_SCIM_TOKENS.has(scimToken) || !env.SCIM_BEARER_TOKEN?.trim()) {
82
77
  throw new Error("Production startup blocked: rotate SCIM_BEARER_TOKEN away from published test defaults.");
83
78
  }
84
79
  }
85
- if (isEnabled(env.FEATURE_FIELD_ENCRYPTION, false) && !env.KMS_ENCRYPTION_KEY?.trim()) {
80
+ if (envFlagEnabled(env.FEATURE_FIELD_ENCRYPTION) && !env.KMS_ENCRYPTION_KEY?.trim()) {
86
81
  throw new Error("Production startup blocked: set KMS_ENCRYPTION_KEY when field encryption is enabled.");
87
82
  }
88
- if (isEnabled(env.FEATURE_BILLING, false) && !env.STRIPE_WEBHOOK_SECRET?.trim()) {
83
+ if (envFlagEnabled(env.FEATURE_BILLING) && !env.STRIPE_WEBHOOK_SECRET?.trim()) {
89
84
  throw new Error("Production startup blocked: set STRIPE_WEBHOOK_SECRET when billing webhooks are enabled.");
90
85
  }
91
86
  if (isOAuthEnabled(env) && !env.OAUTH_STATE_SECRET?.trim()) {
@@ -97,10 +92,10 @@ function assertFeatureProductionSecrets(env) {
97
92
  throw new Error("Production startup blocked: set explicit CORS_ALLOWED_ORIGINS instead of wildcard.");
98
93
  }
99
94
  }
100
- if (isEnabled(env.FEATURE_PUBLIC_READS, false)) {
95
+ if (envFlagEnabled(env.FEATURE_PUBLIC_READS)) {
101
96
  throw new Error("Production startup blocked: set FEATURE_PUBLIC_READS=false for authenticated-only reads.");
102
97
  }
103
- if (!env.SIEM_EXPORT_URL?.trim() && isEnabled(env.FEATURE_SIEM_EXPORT, false)) {
98
+ if (!env.SIEM_EXPORT_URL?.trim() && envFlagEnabled(env.FEATURE_SIEM_EXPORT)) {
104
99
  console.warn("[secrets] SIEM_EXPORT_URL is not configured; audit logs remain database-only.");
105
100
  }
106
101
  }
@@ -121,8 +116,7 @@ function assertPublicAppUrl(env) {
121
116
  }
122
117
  }
123
118
  function assertProductionSecrets(env = process.env) {
124
- const appEnv = env.APP_ENV ?? "local";
125
- if (appEnv !== "production") {
119
+ if (!isProductionEnv(env)) {
126
120
  return;
127
121
  }
128
122
  assertNoPlaceholderSecrets(env);
package/dist/index.js CHANGED
@@ -538,8 +538,9 @@ import { JwtGuard } from "@getstrata/core/auth/jwtGuard";
538
538
  import { SessionGuard } from "@getstrata/core/auth/sessionGuard";
539
539
 
540
540
  // ../../src/config/auth.ts
541
+ import { envFlagEnabled } from "@getstrata/core/runtime/appEnv";
541
542
  var authConfig = {
542
- allowDevHeaders: process.env.AUTH_DEV_HEADERS === "true",
543
+ allowDevHeaders: envFlagEnabled(process.env.AUTH_DEV_HEADERS),
543
544
  tokenDefaultAbilities: ["*"]
544
545
  };
545
546
 
@@ -1139,6 +1140,7 @@ import {
1139
1140
  // ../../src/bootstrap/membershipService.ts
1140
1141
  import { resolveMembershipService } from "@getstrata/core/auth/membershipService";
1141
1142
  // ../../src/bootstrap/secretsGuard.ts
1143
+ import { envFlagEnabled as envFlagEnabled2, isProductionEnv } from "@getstrata/core/runtime/appEnv";
1142
1144
  import { isViewsMode, parseFrontendMode } from "@getstrata/core/runtime/frontendMode";
1143
1145
  var PUBLISHED_TEST_ADMIN_API_TOKEN = "strata-admin-test-token";
1144
1146
  var PUBLISHED_TEST_MEMBER_API_TOKEN = "strata-member-test-token";
@@ -1168,23 +1170,17 @@ function assertNoPlaceholderSecrets(env) {
1168
1170
  throw new Error(`Production startup blocked: replace the generated placeholder values for ${unrotated.join(", ")}.`);
1169
1171
  }
1170
1172
  }
1171
- function isEnabled(value, defaultEnabled) {
1172
- if (value === undefined) {
1173
- return defaultEnabled;
1174
- }
1175
- return defaultEnabled ? value !== "false" : value === "true";
1176
- }
1177
1173
  function isTokenAuthEnabled(env) {
1178
- return Boolean(env.ADMIN_API_TOKEN?.trim()) || Boolean(env.MEMBER_API_TOKEN?.trim()) || env.FEATURE_API_TOKENS === "true";
1174
+ return Boolean(env.ADMIN_API_TOKEN?.trim()) || Boolean(env.MEMBER_API_TOKEN?.trim()) || envFlagEnabled2(env.FEATURE_API_TOKENS);
1179
1175
  }
1180
1176
  function isOAuthEnabled(env) {
1181
- 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());
1177
+ return envFlagEnabled2(env.FEATURE_OAUTH) || envFlagEnabled2(env.FEATURE_SAML) || Boolean(env.GITHUB_CLIENT_ID?.trim()) || Boolean(env.OIDC_ISSUER?.trim()) || Boolean(env.SAML_LOGIN_URL?.trim());
1182
1178
  }
1183
1179
  function isCorsConfigured(env) {
1184
1180
  return env.CORS_ALLOWED_ORIGINS !== undefined;
1185
1181
  }
1186
1182
  function assertAuthDevHeadersDisabled(env) {
1187
- if (isEnabled(env.AUTH_DEV_HEADERS, true)) {
1183
+ if (env.AUTH_DEV_HEADERS !== "false") {
1188
1184
  throw new Error("Production startup blocked: set AUTH_DEV_HEADERS=false to disable development auth headers.");
1189
1185
  }
1190
1186
  }
@@ -1215,16 +1211,16 @@ function assertTokenAuthProductionSecrets(env) {
1215
1211
  }
1216
1212
  }
1217
1213
  function assertFeatureProductionSecrets(env) {
1218
- if (isEnabled(env.FEATURE_SCIM, false)) {
1214
+ if (envFlagEnabled2(env.FEATURE_SCIM)) {
1219
1215
  const scimToken = env.SCIM_BEARER_TOKEN ?? PUBLISHED_TEST_SCIM_BEARER_TOKEN;
1220
1216
  if (PUBLISHED_TEST_SCIM_TOKENS.has(scimToken) || !env.SCIM_BEARER_TOKEN?.trim()) {
1221
1217
  throw new Error("Production startup blocked: rotate SCIM_BEARER_TOKEN away from published test defaults.");
1222
1218
  }
1223
1219
  }
1224
- if (isEnabled(env.FEATURE_FIELD_ENCRYPTION, false) && !env.KMS_ENCRYPTION_KEY?.trim()) {
1220
+ if (envFlagEnabled2(env.FEATURE_FIELD_ENCRYPTION) && !env.KMS_ENCRYPTION_KEY?.trim()) {
1225
1221
  throw new Error("Production startup blocked: set KMS_ENCRYPTION_KEY when field encryption is enabled.");
1226
1222
  }
1227
- if (isEnabled(env.FEATURE_BILLING, false) && !env.STRIPE_WEBHOOK_SECRET?.trim()) {
1223
+ if (envFlagEnabled2(env.FEATURE_BILLING) && !env.STRIPE_WEBHOOK_SECRET?.trim()) {
1228
1224
  throw new Error("Production startup blocked: set STRIPE_WEBHOOK_SECRET when billing webhooks are enabled.");
1229
1225
  }
1230
1226
  if (isOAuthEnabled(env) && !env.OAUTH_STATE_SECRET?.trim()) {
@@ -1236,10 +1232,10 @@ function assertFeatureProductionSecrets(env) {
1236
1232
  throw new Error("Production startup blocked: set explicit CORS_ALLOWED_ORIGINS instead of wildcard.");
1237
1233
  }
1238
1234
  }
1239
- if (isEnabled(env.FEATURE_PUBLIC_READS, false)) {
1235
+ if (envFlagEnabled2(env.FEATURE_PUBLIC_READS)) {
1240
1236
  throw new Error("Production startup blocked: set FEATURE_PUBLIC_READS=false for authenticated-only reads.");
1241
1237
  }
1242
- if (!env.SIEM_EXPORT_URL?.trim() && isEnabled(env.FEATURE_SIEM_EXPORT, false)) {
1238
+ if (!env.SIEM_EXPORT_URL?.trim() && envFlagEnabled2(env.FEATURE_SIEM_EXPORT)) {
1243
1239
  console.warn("[secrets] SIEM_EXPORT_URL is not configured; audit logs remain database-only.");
1244
1240
  }
1245
1241
  }
@@ -1260,8 +1256,7 @@ function assertPublicAppUrl(env) {
1260
1256
  }
1261
1257
  }
1262
1258
  function assertProductionSecrets(env = process.env) {
1263
- const appEnv = env.APP_ENV ?? "local";
1264
- if (appEnv !== "production") {
1259
+ if (!isProductionEnv(env)) {
1265
1260
  return;
1266
1261
  }
1267
1262
  assertNoPlaceholderSecrets(env);
@@ -1436,7 +1431,7 @@ import { getDefaultDatabasePool as getDefaultDatabasePool2 } from "@getstrata/co
1436
1431
  import { currentSqlDialect, sqlTimestamp } from "@getstrata/core/database/dialect";
1437
1432
  import { readRequestCookie } from "@getstrata/core/http/cookies";
1438
1433
  import { currentRequestMeta as currentRequestMeta3 } from "@getstrata/core/http/requestMetaContext";
1439
- import { isProductionEnv } from "@getstrata/core/runtime/appEnv";
1434
+ import { isProductionEnv as isProductionEnv2 } from "@getstrata/core/runtime/appEnv";
1440
1435
  import { timingSafeCompareString } from "@getstrata/core/security/timingSafeCompare";
1441
1436
  function sqlPlaceholder(index) {
1442
1437
  return currentSqlDialect().placeholder(index);
@@ -1539,7 +1534,7 @@ class CookieSessionStore {
1539
1534
  return sessionId;
1540
1535
  }
1541
1536
  withSecureFlag(header) {
1542
- if (!isProductionEnv()) {
1537
+ if (!isProductionEnv2()) {
1543
1538
  return header;
1544
1539
  }
1545
1540
  return header.includes("Secure") ? header : `${header}; Secure`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getstrata/bootstrap",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "Strata application bootstrap: HttpKernel, DI, web session helpers",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -175,7 +175,7 @@
175
175
  "access": "public"
176
176
  },
177
177
  "peerDependencies": {
178
- "@getstrata/core": "^1.0.3",
178
+ "@getstrata/core": "^1.0.5",
179
179
  "typescript": "^5.9.0"
180
180
  },
181
181
  "engines": {