@getstrata/core 1.0.3 → 1.0.4

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/core/runtime/appEnv.d.ts +16 -2
  3. package/dist/core/runtime/appKeyPrefix.d.ts +8 -1
  4. package/dist/entries/audit/exportAuditLogs.js +83 -18
  5. package/dist/entries/audit/siemFormatter.js +32 -3
  6. package/dist/entries/auth/intendedUrlCookie.js +33 -4
  7. package/dist/entries/auth/jwt.js +36 -4
  8. package/dist/entries/auth/jwtGuard.js +36 -4
  9. package/dist/entries/auth/oauth/providers.js +32 -3
  10. package/dist/entries/auth/oauth/samlProvider.js +32 -3
  11. package/dist/entries/auth/passwordConfirmCookie.js +35 -6
  12. package/dist/entries/auth/sessionCookie.js +35 -6
  13. package/dist/entries/auth/sessionGuard.js +35 -6
  14. package/dist/entries/auth/tokenHash.js +33 -4
  15. package/dist/entries/cache/createCacheStore.js +32 -3
  16. package/dist/entries/facades.js +32 -3
  17. package/dist/entries/http/corsMiddleware.js +16 -1
  18. package/dist/entries/http/csrfMiddleware.js +34 -5
  19. package/dist/entries/http/csrfToken.js +34 -5
  20. package/dist/entries/http/flashMiddleware.js +33 -4
  21. package/dist/entries/http/flashSession.js +33 -4
  22. package/dist/entries/http/loginThrottleMiddleware.js +1 -373
  23. package/dist/entries/http/memoryThrottleMiddleware.js +32 -58
  24. package/dist/entries/http/response.js +16 -56
  25. package/dist/entries/http/scimThrottleMiddleware.js +32 -3
  26. package/dist/entries/http/securityHeadersMiddleware.js +32 -3
  27. package/dist/entries/http/signedUrl.js +33 -4
  28. package/dist/entries/http/throttleMiddleware.js +32 -58
  29. package/dist/entries/http/webErrorResponse.js +1 -401
  30. package/dist/entries/jobs/exportAuditLogsJob.js +83 -18
  31. package/dist/entries/lifecycle/gracefulShutdown.js +1 -50
  32. package/dist/entries/mail/mailer.js +32 -3
  33. package/dist/entries/openapi/generator.js +32 -3
  34. package/dist/entries/queue/createAppQueue.js +32 -3
  35. package/dist/entries/queue/publicQueue.js +32 -3
  36. package/dist/entries/queue/queueMetrics.js +32 -3
  37. package/dist/entries/queue/redisQueue.js +32 -3
  38. package/dist/entries/runtime/appEnv.js +18 -1
  39. package/dist/entries/runtime/appKeyPrefix.js +1 -70
  40. package/dist/entries/security/oauthState.js +33 -4
  41. package/dist/entries/security/safeFetch.js +32 -9
  42. package/dist/entries/security/safeUrl.js +1 -105
  43. package/dist/entries/security/totp.js +32 -3
  44. package/dist/entries/tenant/databaseTenantContext.js +48 -6
  45. package/dist/entries/tracing/tracingMiddleware.js +32 -3
  46. package/dist/entries/view.js +1 -778
  47. package/dist/framework/public-api.d.ts +27 -18
  48. package/dist/index.js +442 -53
  49. package/package.json +2 -2
@@ -1,6 +1,26 @@
1
1
  // @bun
2
2
  // ../../src/core/audit/exportAuditLogs.ts
3
- import { repositoryConnection as db2 } from "@getstrata/core/database/repositoryConnection";
3
+ import { repositoryConnection as db } from "@getstrata/core/database/repositoryConnection";
4
+
5
+ // ../../src/core/runtime/appEnv.ts
6
+ var NON_PRODUCTION_APP_ENVS = new Set(["local", "development", "dev", "test", "testing", "ci"]);
7
+ function normalizeEnvValue(value) {
8
+ return (value ?? "").trim().toLowerCase();
9
+ }
10
+ function isProductionEnv(env = process.env) {
11
+ const appEnv = normalizeEnvValue(env.APP_ENV);
12
+ const nodeEnv = normalizeEnvValue(env.NODE_ENV);
13
+ if (appEnv === "production" || nodeEnv === "production") {
14
+ return true;
15
+ }
16
+ if (appEnv === "") {
17
+ return false;
18
+ }
19
+ return !NON_PRODUCTION_APP_ENVS.has(appEnv);
20
+ }
21
+ function envFlagEnabled(value) {
22
+ return value === "true";
23
+ }
4
24
 
5
25
  // ../../src/core/runtime/appKeyPrefix.ts
6
26
  function appKeyPrefix() {
@@ -12,6 +32,18 @@ function appCookieName(kind) {
12
32
  function appDevSecret(kind) {
13
33
  return `${appKeyPrefix()}-dev-${kind}`;
14
34
  }
35
+ function requireConfiguredSecret(names, devKind, env = process.env) {
36
+ for (const name of names) {
37
+ const value = env[name]?.trim();
38
+ if (value) {
39
+ return value;
40
+ }
41
+ }
42
+ if (isProductionEnv(env)) {
43
+ throw new Error(`${names[0]} must be set outside development. Do not derive secrets from the app name.`);
44
+ }
45
+ return appDevSecret(devKind);
46
+ }
15
47
  function namespacedRedisKey(kind) {
16
48
  return `${appKeyPrefix()}:${kind}`;
17
49
  }
@@ -29,9 +61,6 @@ function appUserAgent() {
29
61
  function otelServiceName() {
30
62
  return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
31
63
  }
32
- function webhookSignatureHeader() {
33
- return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
34
- }
35
64
  function appDisplayName() {
36
65
  return process.env.APP_NAME?.trim() || "Strata";
37
66
  }
@@ -146,12 +175,6 @@ async function assertSafeOutboundUrlResolved(rawUrl, options = {}) {
146
175
  }
147
176
  return parsed;
148
177
  }
149
- function setDnsLookupForTests(lookupFn) {
150
- dnsLookup = lookupFn;
151
- }
152
- function resetDnsLookupForTests() {
153
- dnsLookup = dnsLookupImpl;
154
- }
155
178
 
156
179
  // ../../src/core/security/safeFetch.ts
157
180
  var DEFAULT_FETCH_TIMEOUT_MS = 1e4;
@@ -188,7 +211,33 @@ async function safeFetch(input, init = {}, options = {}) {
188
211
  }
189
212
 
190
213
  // ../../src/core/tenant/databaseTenantContext.ts
191
- import { repositoryConnection as db } from "@getstrata/core/database/repositoryConnection";
214
+ import { getDefaultDatabasePool } from "@getstrata/core/database/defaultConnection";
215
+
216
+ // ../../src/core/runtime/asyncContextStore.ts
217
+ import { AsyncLocalStorage } from "async_hooks";
218
+ function createAsyncContextStore(key) {
219
+ const symbol = Symbol.for(key);
220
+ const globalRecord = globalThis;
221
+ const existing = globalRecord[symbol];
222
+ if (existing) {
223
+ return existing;
224
+ }
225
+ const store = new AsyncLocalStorage;
226
+ globalRecord[symbol] = store;
227
+ return store;
228
+ }
229
+
230
+ // ../../src/core/database/connectionContext.ts
231
+ var activeConnection = createAsyncContextStore("@getstrata/databaseConnectionContext");
232
+ function runWithDatabaseConnection(connection, callback) {
233
+ return activeConnection.run(connection, callback);
234
+ }
235
+ function getActiveDatabaseConnection(fallback) {
236
+ return activeConnection.getStore() ?? fallback;
237
+ }
238
+ function hasActiveDatabaseConnection() {
239
+ return activeConnection.getStore() !== undefined;
240
+ }
192
241
 
193
242
  // ../../src/core/tenant/tenancyConfig.ts
194
243
  var TENANCY_DRIVERS = ["rls", "column", "none"];
@@ -210,16 +259,32 @@ function isRlsTenancy(env = process.env) {
210
259
  }
211
260
 
212
261
  // ../../src/core/tenant/databaseTenantContext.ts
262
+ async function applyBypassToTransaction(transaction, bypass) {
263
+ await transaction.unsafe(`SELECT set_config('app.bypass_rls', $1, true)`, [
264
+ bypass ? "true" : "false"
265
+ ]);
266
+ }
213
267
  async function runWithMigrationBypass(callback) {
214
268
  if (!isRlsTenancy()) {
215
269
  return await callback();
216
270
  }
217
- await db`SELECT set_config('app.bypass_rls', 'true', false)`;
218
- try {
219
- return await callback();
220
- } finally {
221
- await db`SELECT set_config('app.bypass_rls', 'false', false)`;
271
+ if (hasActiveDatabaseConnection()) {
272
+ const activeConnection = getActiveDatabaseConnection(getDefaultDatabasePool());
273
+ await applyBypassToTransaction(activeConnection, true);
274
+ try {
275
+ return await callback();
276
+ } finally {
277
+ await applyBypassToTransaction(activeConnection, false);
278
+ }
279
+ }
280
+ const pool = getDefaultDatabasePool();
281
+ if (typeof pool.begin !== "function") {
282
+ throw new Error("RLS migration bypass requires a pool that supports begin(). Session-scoped set_config is not used on pooled connections.");
222
283
  }
284
+ return await pool.begin(async (transaction) => {
285
+ await applyBypassToTransaction(transaction, true);
286
+ return await runWithDatabaseConnection(transaction, callback);
287
+ });
223
288
  }
224
289
 
225
290
  // ../../src/core/audit/siemFormatter.ts
@@ -275,7 +340,7 @@ async function exportPendingAuditLogs() {
275
340
  return 0;
276
341
  }
277
342
  return await runWithMigrationBypass(async () => {
278
- const rows = await db2`
343
+ const rows = await db`
279
344
  SELECT
280
345
  id,
281
346
  user_id,
@@ -325,7 +390,7 @@ async function exportPendingAuditLogs() {
325
390
  }
326
391
  const ids = rows.map((row) => row.id);
327
392
  for (const id of ids) {
328
- await db2`UPDATE audit_log SET exported_at = NOW() WHERE id = ${id}`;
393
+ await db`UPDATE audit_log SET exported_at = NOW() WHERE id = ${id}`;
329
394
  }
330
395
  return rows.length;
331
396
  });
@@ -1,50 +1 @@
1
- // @bun
2
- // ../../src/core/lifecycle/gracefulShutdown.ts
3
- var shutdownHandlers = new Map;
4
- var shutdownInstalled = false;
5
- var shuttingDown = false;
6
- function registerShutdownHandler(name, handler) {
7
- shutdownHandlers.set(name, handler);
8
- return () => {
9
- shutdownHandlers.delete(name);
10
- };
11
- }
12
- async function runGracefulShutdown(signal) {
13
- if (shuttingDown) {
14
- return;
15
- }
16
- shuttingDown = true;
17
- console.log(`[shutdown] Received ${signal}, draining ${shutdownHandlers.size} handler(s)...`);
18
- for (const [name, handler] of shutdownHandlers) {
19
- try {
20
- await handler();
21
- console.log(`[shutdown] Completed ${name}`);
22
- } catch (error) {
23
- console.error(`[shutdown] Failed ${name}:`, error);
24
- }
25
- }
26
- }
27
- function installGracefulShutdownSignals(signals = ["SIGINT", "SIGTERM"]) {
28
- if (shutdownInstalled) {
29
- return;
30
- }
31
- shutdownInstalled = true;
32
- for (const signal of signals) {
33
- process.on(signal, () => {
34
- runGracefulShutdown(signal).finally(() => {
35
- process.exit(0);
36
- });
37
- });
38
- }
39
- }
40
- function resetGracefulShutdownForTests() {
41
- shutdownHandlers.clear();
42
- shutdownInstalled = false;
43
- shuttingDown = false;
44
- }
45
- export {
46
- installGracefulShutdownSignals,
47
- registerShutdownHandler,
48
- resetGracefulShutdownForTests,
49
- runGracefulShutdown
50
- };
1
+ export * from "../../index.js";
@@ -1,4 +1,24 @@
1
1
  // @bun
2
+ // ../../src/core/runtime/appEnv.ts
3
+ var NON_PRODUCTION_APP_ENVS = new Set(["local", "development", "dev", "test", "testing", "ci"]);
4
+ function normalizeEnvValue(value) {
5
+ return (value ?? "").trim().toLowerCase();
6
+ }
7
+ function isProductionEnv(env = process.env) {
8
+ const appEnv = normalizeEnvValue(env.APP_ENV);
9
+ const nodeEnv = normalizeEnvValue(env.NODE_ENV);
10
+ if (appEnv === "production" || nodeEnv === "production") {
11
+ return true;
12
+ }
13
+ if (appEnv === "") {
14
+ return false;
15
+ }
16
+ return !NON_PRODUCTION_APP_ENVS.has(appEnv);
17
+ }
18
+ function envFlagEnabled(value) {
19
+ return value === "true";
20
+ }
21
+
2
22
  // ../../src/core/runtime/appKeyPrefix.ts
3
23
  function appKeyPrefix() {
4
24
  return process.env.APP_KEY_PREFIX?.trim() || "strata";
@@ -9,6 +29,18 @@ function appCookieName(kind) {
9
29
  function appDevSecret(kind) {
10
30
  return `${appKeyPrefix()}-dev-${kind}`;
11
31
  }
32
+ function requireConfiguredSecret(names, devKind, env = process.env) {
33
+ for (const name of names) {
34
+ const value = env[name]?.trim();
35
+ if (value) {
36
+ return value;
37
+ }
38
+ }
39
+ if (isProductionEnv(env)) {
40
+ throw new Error(`${names[0]} must be set outside development. Do not derive secrets from the app name.`);
41
+ }
42
+ return appDevSecret(devKind);
43
+ }
12
44
  function namespacedRedisKey(kind) {
13
45
  return `${appKeyPrefix()}:${kind}`;
14
46
  }
@@ -26,9 +58,6 @@ function appUserAgent() {
26
58
  function otelServiceName() {
27
59
  return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
28
60
  }
29
- function webhookSignatureHeader() {
30
- return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
31
- }
32
61
  function appDisplayName() {
33
62
  return process.env.APP_NAME?.trim() || "Strata";
34
63
  }
@@ -1,4 +1,24 @@
1
1
  // @bun
2
+ // ../../src/core/runtime/appEnv.ts
3
+ var NON_PRODUCTION_APP_ENVS = new Set(["local", "development", "dev", "test", "testing", "ci"]);
4
+ function normalizeEnvValue(value) {
5
+ return (value ?? "").trim().toLowerCase();
6
+ }
7
+ function isProductionEnv(env = process.env) {
8
+ const appEnv = normalizeEnvValue(env.APP_ENV);
9
+ const nodeEnv = normalizeEnvValue(env.NODE_ENV);
10
+ if (appEnv === "production" || nodeEnv === "production") {
11
+ return true;
12
+ }
13
+ if (appEnv === "") {
14
+ return false;
15
+ }
16
+ return !NON_PRODUCTION_APP_ENVS.has(appEnv);
17
+ }
18
+ function envFlagEnabled(value) {
19
+ return value === "true";
20
+ }
21
+
2
22
  // ../../src/core/runtime/appKeyPrefix.ts
3
23
  function appKeyPrefix() {
4
24
  return process.env.APP_KEY_PREFIX?.trim() || "strata";
@@ -9,6 +29,18 @@ function appCookieName(kind) {
9
29
  function appDevSecret(kind) {
10
30
  return `${appKeyPrefix()}-dev-${kind}`;
11
31
  }
32
+ function requireConfiguredSecret(names, devKind, env = process.env) {
33
+ for (const name of names) {
34
+ const value = env[name]?.trim();
35
+ if (value) {
36
+ return value;
37
+ }
38
+ }
39
+ if (isProductionEnv(env)) {
40
+ throw new Error(`${names[0]} must be set outside development. Do not derive secrets from the app name.`);
41
+ }
42
+ return appDevSecret(devKind);
43
+ }
12
44
  function namespacedRedisKey(kind) {
13
45
  return `${appKeyPrefix()}:${kind}`;
14
46
  }
@@ -26,9 +58,6 @@ function appUserAgent() {
26
58
  function otelServiceName() {
27
59
  return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
28
60
  }
29
- function webhookSignatureHeader() {
30
- return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
31
- }
32
61
  function appDisplayName() {
33
62
  return process.env.APP_NAME?.trim() || "Strata";
34
63
  }
@@ -156,6 +156,26 @@ async function runQueueJob(envelope, failedJobs) {
156
156
  // ../../src/core/queue/redisQueue.ts
157
157
  var {RedisClient } = globalThis.Bun;
158
158
 
159
+ // ../../src/core/runtime/appEnv.ts
160
+ var NON_PRODUCTION_APP_ENVS = new Set(["local", "development", "dev", "test", "testing", "ci"]);
161
+ function normalizeEnvValue(value) {
162
+ return (value ?? "").trim().toLowerCase();
163
+ }
164
+ function isProductionEnv(env = process.env) {
165
+ const appEnv = normalizeEnvValue(env.APP_ENV);
166
+ const nodeEnv = normalizeEnvValue(env.NODE_ENV);
167
+ if (appEnv === "production" || nodeEnv === "production") {
168
+ return true;
169
+ }
170
+ if (appEnv === "") {
171
+ return false;
172
+ }
173
+ return !NON_PRODUCTION_APP_ENVS.has(appEnv);
174
+ }
175
+ function envFlagEnabled(value) {
176
+ return value === "true";
177
+ }
178
+
159
179
  // ../../src/core/runtime/appKeyPrefix.ts
160
180
  function appKeyPrefix() {
161
181
  return process.env.APP_KEY_PREFIX?.trim() || "strata";
@@ -166,6 +186,18 @@ function appCookieName(kind) {
166
186
  function appDevSecret(kind) {
167
187
  return `${appKeyPrefix()}-dev-${kind}`;
168
188
  }
189
+ function requireConfiguredSecret(names, devKind, env = process.env) {
190
+ for (const name of names) {
191
+ const value = env[name]?.trim();
192
+ if (value) {
193
+ return value;
194
+ }
195
+ }
196
+ if (isProductionEnv(env)) {
197
+ throw new Error(`${names[0]} must be set outside development. Do not derive secrets from the app name.`);
198
+ }
199
+ return appDevSecret(devKind);
200
+ }
169
201
  function namespacedRedisKey(kind) {
170
202
  return `${appKeyPrefix()}:${kind}`;
171
203
  }
@@ -183,9 +215,6 @@ function appUserAgent() {
183
215
  function otelServiceName() {
184
216
  return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
185
217
  }
186
- function webhookSignatureHeader() {
187
- return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
188
- }
189
218
  function appDisplayName() {
190
219
  return process.env.APP_NAME?.trim() || "Strata";
191
220
  }
@@ -156,6 +156,26 @@ async function runQueueJob(envelope, failedJobs) {
156
156
  // ../../src/core/queue/redisQueue.ts
157
157
  var {RedisClient } = globalThis.Bun;
158
158
 
159
+ // ../../src/core/runtime/appEnv.ts
160
+ var NON_PRODUCTION_APP_ENVS = new Set(["local", "development", "dev", "test", "testing", "ci"]);
161
+ function normalizeEnvValue(value) {
162
+ return (value ?? "").trim().toLowerCase();
163
+ }
164
+ function isProductionEnv(env = process.env) {
165
+ const appEnv = normalizeEnvValue(env.APP_ENV);
166
+ const nodeEnv = normalizeEnvValue(env.NODE_ENV);
167
+ if (appEnv === "production" || nodeEnv === "production") {
168
+ return true;
169
+ }
170
+ if (appEnv === "") {
171
+ return false;
172
+ }
173
+ return !NON_PRODUCTION_APP_ENVS.has(appEnv);
174
+ }
175
+ function envFlagEnabled(value) {
176
+ return value === "true";
177
+ }
178
+
159
179
  // ../../src/core/runtime/appKeyPrefix.ts
160
180
  function appKeyPrefix() {
161
181
  return process.env.APP_KEY_PREFIX?.trim() || "strata";
@@ -166,6 +186,18 @@ function appCookieName(kind) {
166
186
  function appDevSecret(kind) {
167
187
  return `${appKeyPrefix()}-dev-${kind}`;
168
188
  }
189
+ function requireConfiguredSecret(names, devKind, env = process.env) {
190
+ for (const name of names) {
191
+ const value = env[name]?.trim();
192
+ if (value) {
193
+ return value;
194
+ }
195
+ }
196
+ if (isProductionEnv(env)) {
197
+ throw new Error(`${names[0]} must be set outside development. Do not derive secrets from the app name.`);
198
+ }
199
+ return appDevSecret(devKind);
200
+ }
169
201
  function namespacedRedisKey(kind) {
170
202
  return `${appKeyPrefix()}:${kind}`;
171
203
  }
@@ -183,9 +215,6 @@ function appUserAgent() {
183
215
  function otelServiceName() {
184
216
  return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
185
217
  }
186
- function webhookSignatureHeader() {
187
- return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
188
- }
189
218
  function appDisplayName() {
190
219
  return process.env.APP_NAME?.trim() || "Strata";
191
220
  }
@@ -159,6 +159,26 @@ async function runQueueJob(envelope, failedJobs) {
159
159
  // ../../src/core/queue/redisQueue.ts
160
160
  var {RedisClient } = globalThis.Bun;
161
161
 
162
+ // ../../src/core/runtime/appEnv.ts
163
+ var NON_PRODUCTION_APP_ENVS = new Set(["local", "development", "dev", "test", "testing", "ci"]);
164
+ function normalizeEnvValue(value) {
165
+ return (value ?? "").trim().toLowerCase();
166
+ }
167
+ function isProductionEnv(env = process.env) {
168
+ const appEnv = normalizeEnvValue(env.APP_ENV);
169
+ const nodeEnv = normalizeEnvValue(env.NODE_ENV);
170
+ if (appEnv === "production" || nodeEnv === "production") {
171
+ return true;
172
+ }
173
+ if (appEnv === "") {
174
+ return false;
175
+ }
176
+ return !NON_PRODUCTION_APP_ENVS.has(appEnv);
177
+ }
178
+ function envFlagEnabled(value) {
179
+ return value === "true";
180
+ }
181
+
162
182
  // ../../src/core/runtime/appKeyPrefix.ts
163
183
  function appKeyPrefix() {
164
184
  return process.env.APP_KEY_PREFIX?.trim() || "strata";
@@ -169,6 +189,18 @@ function appCookieName(kind) {
169
189
  function appDevSecret(kind) {
170
190
  return `${appKeyPrefix()}-dev-${kind}`;
171
191
  }
192
+ function requireConfiguredSecret(names, devKind, env = process.env) {
193
+ for (const name of names) {
194
+ const value = env[name]?.trim();
195
+ if (value) {
196
+ return value;
197
+ }
198
+ }
199
+ if (isProductionEnv(env)) {
200
+ throw new Error(`${names[0]} must be set outside development. Do not derive secrets from the app name.`);
201
+ }
202
+ return appDevSecret(devKind);
203
+ }
172
204
  function namespacedRedisKey(kind) {
173
205
  return `${appKeyPrefix()}:${kind}`;
174
206
  }
@@ -186,9 +218,6 @@ function appUserAgent() {
186
218
  function otelServiceName() {
187
219
  return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
188
220
  }
189
- function webhookSignatureHeader() {
190
- return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
191
- }
192
221
  function appDisplayName() {
193
222
  return process.env.APP_NAME?.trim() || "Strata";
194
223
  }
@@ -2,6 +2,26 @@
2
2
  // ../../src/core/queue/redisQueue.ts
3
3
  var {RedisClient } = globalThis.Bun;
4
4
 
5
+ // ../../src/core/runtime/appEnv.ts
6
+ var NON_PRODUCTION_APP_ENVS = new Set(["local", "development", "dev", "test", "testing", "ci"]);
7
+ function normalizeEnvValue(value) {
8
+ return (value ?? "").trim().toLowerCase();
9
+ }
10
+ function isProductionEnv(env = process.env) {
11
+ const appEnv = normalizeEnvValue(env.APP_ENV);
12
+ const nodeEnv = normalizeEnvValue(env.NODE_ENV);
13
+ if (appEnv === "production" || nodeEnv === "production") {
14
+ return true;
15
+ }
16
+ if (appEnv === "") {
17
+ return false;
18
+ }
19
+ return !NON_PRODUCTION_APP_ENVS.has(appEnv);
20
+ }
21
+ function envFlagEnabled(value) {
22
+ return value === "true";
23
+ }
24
+
5
25
  // ../../src/core/runtime/appKeyPrefix.ts
6
26
  function appKeyPrefix() {
7
27
  return process.env.APP_KEY_PREFIX?.trim() || "strata";
@@ -12,6 +32,18 @@ function appCookieName(kind) {
12
32
  function appDevSecret(kind) {
13
33
  return `${appKeyPrefix()}-dev-${kind}`;
14
34
  }
35
+ function requireConfiguredSecret(names, devKind, env = process.env) {
36
+ for (const name of names) {
37
+ const value = env[name]?.trim();
38
+ if (value) {
39
+ return value;
40
+ }
41
+ }
42
+ if (isProductionEnv(env)) {
43
+ throw new Error(`${names[0]} must be set outside development. Do not derive secrets from the app name.`);
44
+ }
45
+ return appDevSecret(devKind);
46
+ }
15
47
  function namespacedRedisKey(kind) {
16
48
  return `${appKeyPrefix()}:${kind}`;
17
49
  }
@@ -29,9 +61,6 @@ function appUserAgent() {
29
61
  function otelServiceName() {
30
62
  return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
31
63
  }
32
- function webhookSignatureHeader() {
33
- return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
34
- }
35
64
  function appDisplayName() {
36
65
  return process.env.APP_NAME?.trim() || "Strata";
37
66
  }
@@ -1,8 +1,25 @@
1
1
  // @bun
2
2
  // ../../src/core/runtime/appEnv.ts
3
+ var NON_PRODUCTION_APP_ENVS = new Set(["local", "development", "dev", "test", "testing", "ci"]);
4
+ function normalizeEnvValue(value) {
5
+ return (value ?? "").trim().toLowerCase();
6
+ }
3
7
  function isProductionEnv(env = process.env) {
4
- return env.APP_ENV === "production" || env.NODE_ENV === "production";
8
+ const appEnv = normalizeEnvValue(env.APP_ENV);
9
+ const nodeEnv = normalizeEnvValue(env.NODE_ENV);
10
+ if (appEnv === "production" || nodeEnv === "production") {
11
+ return true;
12
+ }
13
+ if (appEnv === "") {
14
+ return false;
15
+ }
16
+ return !NON_PRODUCTION_APP_ENVS.has(appEnv);
17
+ }
18
+ function envFlagEnabled(value) {
19
+ return value === "true";
5
20
  }
6
21
  export {
22
+ NON_PRODUCTION_APP_ENVS,
23
+ envFlagEnabled,
7
24
  isProductionEnv
8
25
  };
@@ -1,70 +1 @@
1
- // @bun
2
- // ../../src/core/runtime/appKeyPrefix.ts
3
- function appKeyPrefix() {
4
- return process.env.APP_KEY_PREFIX?.trim() || "strata";
5
- }
6
- function appCookieName(kind) {
7
- return `${appKeyPrefix()}_${kind}`;
8
- }
9
- function appDevSecret(kind) {
10
- return `${appKeyPrefix()}-dev-${kind}`;
11
- }
12
- function namespacedRedisKey(kind) {
13
- return `${appKeyPrefix()}:${kind}`;
14
- }
15
- function smtpEhloHost() {
16
- const raw = process.env.MAIL_EHLO?.trim() || `${appKeyPrefix()}.local`;
17
- const safe = raw.replace(/[^a-zA-Z0-9.-]/g, "");
18
- return safe || "strata.local";
19
- }
20
- function siemEventType() {
21
- return process.env.SIEM_EVENT_TYPE?.trim() || `${appKeyPrefix()}.audit`;
22
- }
23
- function appUserAgent() {
24
- return process.env.APP_USER_AGENT?.trim() || appKeyPrefix();
25
- }
26
- function otelServiceName() {
27
- return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
28
- }
29
- function webhookSignatureHeader() {
30
- return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
31
- }
32
- function appDisplayName() {
33
- return process.env.APP_NAME?.trim() || "Strata";
34
- }
35
- function appEnv() {
36
- return process.env.APP_ENV?.trim() || "local";
37
- }
38
- function appUrl() {
39
- return (process.env.APP_URL?.trim() || "http://localhost:3000").replace(/\/$/, "");
40
- }
41
- function apiPrefix() {
42
- const raw = process.env.API_PREFIX?.trim() || "/api/v1";
43
- const withSlash = raw.startsWith("/") ? raw : `/${raw}`;
44
- const trimmed = withSlash.replace(/\/+$/, "");
45
- return trimmed || "/api/v1";
46
- }
47
- function sdkClientClassName() {
48
- const override = process.env.APP_SDK_CLASS?.trim();
49
- if (override && /^[A-Za-z_][A-Za-z0-9_]*$/.test(override)) {
50
- return override;
51
- }
52
- const fromName = appDisplayName().replace(/[^A-Za-z0-9]/g, "");
53
- return fromName ? `${fromName}Client` : "AppClient";
54
- }
55
- export {
56
- apiPrefix,
57
- appCookieName,
58
- appDevSecret,
59
- appDisplayName,
60
- appEnv,
61
- appKeyPrefix,
62
- appUrl,
63
- appUserAgent,
64
- namespacedRedisKey,
65
- otelServiceName,
66
- sdkClientClassName,
67
- siemEventType,
68
- smtpEhloHost,
69
- webhookSignatureHeader
70
- };
1
+ export * from "../../index.js";