@getstrata/core 0.5.79 → 0.5.80

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 (36) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/core/runtime/appKeyPrefix.d.ts +3 -1
  3. package/dist/entries/audit/exportAuditLogs.js +6 -0
  4. package/dist/entries/audit/siemFormatter.js +6 -0
  5. package/dist/entries/auth/oauth/providers.js +6 -0
  6. package/dist/entries/auth/oauth/samlProvider.js +6 -0
  7. package/dist/entries/auth/passwordConfirmCookie.js +58 -2
  8. package/dist/entries/auth/sessionCookie.js +58 -2
  9. package/dist/entries/auth/sessionGuard.js +58 -2
  10. package/dist/entries/auth/tokenHash.js +58 -2
  11. package/dist/entries/cache/createCacheStore.js +6 -0
  12. package/dist/entries/facades.js +6 -0
  13. package/dist/entries/http/csrfMiddleware.js +56 -2
  14. package/dist/entries/http/csrfToken.js +56 -2
  15. package/dist/entries/http/flashMiddleware.js +58 -2
  16. package/dist/entries/http/flashSession.js +58 -2
  17. package/dist/entries/http/loginThrottleMiddleware.js +6 -0
  18. package/dist/entries/http/memoryThrottleMiddleware.js +6 -0
  19. package/dist/entries/http/scimThrottleMiddleware.js +6 -0
  20. package/dist/entries/http/securityHeadersMiddleware.js +6 -0
  21. package/dist/entries/http/signedUrl.js +57 -1
  22. package/dist/entries/http/throttleMiddleware.js +6 -0
  23. package/dist/entries/jobs/exportAuditLogsJob.js +6 -0
  24. package/dist/entries/mail/mailer.js +6 -0
  25. package/dist/entries/openapi/generator.js +6 -0
  26. package/dist/entries/queue/createAppQueue.js +6 -0
  27. package/dist/entries/queue/publicQueue.js +6 -0
  28. package/dist/entries/queue/queueMetrics.js +6 -0
  29. package/dist/entries/queue/redisQueue.js +6 -0
  30. package/dist/entries/runtime/appKeyPrefix.js +8 -0
  31. package/dist/entries/security/oauthState.js +57 -1
  32. package/dist/entries/security/safeFetch.js +6 -0
  33. package/dist/entries/tracing/tracingMiddleware.js +6 -0
  34. package/dist/entries/view.js +58 -4
  35. package/dist/index.js +11 -7
  36. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # @getstrata/core changelog
2
2
 
3
+ ## 0.5.80
4
+
5
+ - `appCookieName()` / `appDevSecret()` on `@getstrata/core/runtime/appKeyPrefix`. HMAC session, CSRF, flash, password-confirm, signed-URL, OAuth-state, and token-pepper fallbacks follow `APP_KEY_PREFIX` (WorkHub defaults unchanged).
6
+
3
7
  ## 0.5.79
4
8
 
5
9
  - `readSession()` returns `{ userId, issuedAt }` from the HMAC session cookie. `isSessionInvalidated(issuedAt, session_valid_after)` lets `SessionGuard` reject cookies issued before `AuthUserRecord.session_valid_after` (Jetstream logout-other-devices / password change).
@@ -1,4 +1,6 @@
1
1
  declare function appKeyPrefix(): string;
2
+ declare function appCookieName(kind: string): string;
3
+ declare function appDevSecret(kind: string): string;
2
4
  declare function namespacedRedisKey(kind: string): string;
3
5
  declare function smtpEhloHost(): string;
4
6
  declare function siemEventType(): string;
@@ -10,4 +12,4 @@ declare function appEnv(): string;
10
12
  declare function appUrl(): string;
11
13
  declare function apiPrefix(): string;
12
14
  declare function sdkClientClassName(): string;
13
- export { apiPrefix, appDisplayName, appEnv, appKeyPrefix, appUrl, appUserAgent, namespacedRedisKey, otelServiceName, sdkClientClassName, siemEventType, smtpEhloHost, webhookSignatureHeader, };
15
+ export { apiPrefix, appCookieName, appDevSecret, appDisplayName, appEnv, appKeyPrefix, appUrl, appUserAgent, namespacedRedisKey, otelServiceName, sdkClientClassName, siemEventType, smtpEhloHost, webhookSignatureHeader, };
@@ -6,6 +6,12 @@ import { repositoryConnection as db2 } from "@getstrata/core/database/repository
6
6
  function appKeyPrefix() {
7
7
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
8
8
  }
9
+ function appCookieName(kind) {
10
+ return `${appKeyPrefix()}_${kind}`;
11
+ }
12
+ function appDevSecret(kind) {
13
+ return `${appKeyPrefix()}-dev-${kind}`;
14
+ }
9
15
  function namespacedRedisKey(kind) {
10
16
  return `${appKeyPrefix()}:${kind}`;
11
17
  }
@@ -3,6 +3,12 @@
3
3
  function appKeyPrefix() {
4
4
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
5
5
  }
6
+ function appCookieName(kind) {
7
+ return `${appKeyPrefix()}_${kind}`;
8
+ }
9
+ function appDevSecret(kind) {
10
+ return `${appKeyPrefix()}-dev-${kind}`;
11
+ }
6
12
  function namespacedRedisKey(kind) {
7
13
  return `${appKeyPrefix()}:${kind}`;
8
14
  }
@@ -3,6 +3,12 @@
3
3
  function appKeyPrefix() {
4
4
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
5
5
  }
6
+ function appCookieName(kind) {
7
+ return `${appKeyPrefix()}_${kind}`;
8
+ }
9
+ function appDevSecret(kind) {
10
+ return `${appKeyPrefix()}-dev-${kind}`;
11
+ }
6
12
  function namespacedRedisKey(kind) {
7
13
  return `${appKeyPrefix()}:${kind}`;
8
14
  }
@@ -3,6 +3,12 @@
3
3
  function appKeyPrefix() {
4
4
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
5
5
  }
6
+ function appCookieName(kind) {
7
+ return `${appKeyPrefix()}_${kind}`;
8
+ }
9
+ function appDevSecret(kind) {
10
+ return `${appKeyPrefix()}-dev-${kind}`;
11
+ }
6
12
  function namespacedRedisKey(kind) {
7
13
  return `${appKeyPrefix()}:${kind}`;
8
14
  }
@@ -1,17 +1,73 @@
1
1
  // @bun
2
2
  // ../../src/core/auth/passwordConfirmCookie.ts
3
3
  import { createHmac, timingSafeEqual } from "crypto";
4
+
5
+ // ../../src/core/runtime/appKeyPrefix.ts
6
+ function appKeyPrefix() {
7
+ return process.env.APP_KEY_PREFIX?.trim() || "workhub";
8
+ }
9
+ function appCookieName(kind) {
10
+ return `${appKeyPrefix()}_${kind}`;
11
+ }
12
+ function appDevSecret(kind) {
13
+ return `${appKeyPrefix()}-dev-${kind}`;
14
+ }
15
+ function namespacedRedisKey(kind) {
16
+ return `${appKeyPrefix()}:${kind}`;
17
+ }
18
+ function smtpEhloHost() {
19
+ const raw = process.env.MAIL_EHLO?.trim() || `${appKeyPrefix()}.local`;
20
+ const safe = raw.replace(/[^a-zA-Z0-9.-]/g, "");
21
+ return safe || "strata.local";
22
+ }
23
+ function siemEventType() {
24
+ return process.env.SIEM_EVENT_TYPE?.trim() || `${appKeyPrefix()}.audit`;
25
+ }
26
+ function appUserAgent() {
27
+ return process.env.APP_USER_AGENT?.trim() || appKeyPrefix();
28
+ }
29
+ function otelServiceName() {
30
+ return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
31
+ }
32
+ function webhookSignatureHeader() {
33
+ return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
34
+ }
35
+ function appDisplayName() {
36
+ return process.env.APP_NAME?.trim() || "WorkHub";
37
+ }
38
+ function appEnv() {
39
+ return process.env.APP_ENV?.trim() || "local";
40
+ }
41
+ function appUrl() {
42
+ return (process.env.APP_URL?.trim() || "http://localhost:3000").replace(/\/$/, "");
43
+ }
44
+ function apiPrefix() {
45
+ const raw = process.env.API_PREFIX?.trim() || "/api/v1";
46
+ const withSlash = raw.startsWith("/") ? raw : `/${raw}`;
47
+ const trimmed = withSlash.replace(/\/+$/, "");
48
+ return trimmed || "/api/v1";
49
+ }
50
+ function sdkClientClassName() {
51
+ const override = process.env.APP_SDK_CLASS?.trim();
52
+ if (override && /^[A-Za-z_][A-Za-z0-9_]*$/.test(override)) {
53
+ return override;
54
+ }
55
+ const fromName = appDisplayName().replace(/[^A-Za-z0-9]/g, "");
56
+ return fromName ? `${fromName}Client` : "AppClient";
57
+ }
58
+
59
+ // ../../src/core/auth/passwordConfirmCookie.ts
4
60
  var PASSWORD_CONFIRM_COOKIE = "workhub_password_confirmed";
5
61
  var DEFAULT_PASSWORD_CONFIRM_TTL_SECONDS = 3 * 60 * 60;
6
62
  function passwordConfirmCookieName() {
7
- return process.env.PASSWORD_CONFIRM_COOKIE_NAME?.trim() || PASSWORD_CONFIRM_COOKIE;
63
+ return process.env.PASSWORD_CONFIRM_COOKIE_NAME?.trim() || appCookieName("password_confirmed");
8
64
  }
9
65
  function passwordConfirmTtlSeconds() {
10
66
  const parsed = Number.parseInt(process.env.PASSWORD_CONFIRM_TIMEOUT ?? "", 10);
11
67
  return Number.isInteger(parsed) && parsed > 0 ? parsed : DEFAULT_PASSWORD_CONFIRM_TTL_SECONDS;
12
68
  }
13
69
  function resolvePasswordConfirmSecret() {
14
- return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || "workhub-dev-session-secret";
70
+ return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || appDevSecret("session-secret");
15
71
  }
16
72
  function signPasswordConfirm(userId, confirmedAt) {
17
73
  const payload = `${userId}.${confirmedAt}`;
@@ -1,11 +1,67 @@
1
1
  // @bun
2
2
  // ../../src/core/auth/sessionCookie.ts
3
3
  import { createHmac, timingSafeEqual } from "crypto";
4
+
5
+ // ../../src/core/runtime/appKeyPrefix.ts
6
+ function appKeyPrefix() {
7
+ return process.env.APP_KEY_PREFIX?.trim() || "workhub";
8
+ }
9
+ function appCookieName(kind) {
10
+ return `${appKeyPrefix()}_${kind}`;
11
+ }
12
+ function appDevSecret(kind) {
13
+ return `${appKeyPrefix()}-dev-${kind}`;
14
+ }
15
+ function namespacedRedisKey(kind) {
16
+ return `${appKeyPrefix()}:${kind}`;
17
+ }
18
+ function smtpEhloHost() {
19
+ const raw = process.env.MAIL_EHLO?.trim() || `${appKeyPrefix()}.local`;
20
+ const safe = raw.replace(/[^a-zA-Z0-9.-]/g, "");
21
+ return safe || "strata.local";
22
+ }
23
+ function siemEventType() {
24
+ return process.env.SIEM_EVENT_TYPE?.trim() || `${appKeyPrefix()}.audit`;
25
+ }
26
+ function appUserAgent() {
27
+ return process.env.APP_USER_AGENT?.trim() || appKeyPrefix();
28
+ }
29
+ function otelServiceName() {
30
+ return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
31
+ }
32
+ function webhookSignatureHeader() {
33
+ return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
34
+ }
35
+ function appDisplayName() {
36
+ return process.env.APP_NAME?.trim() || "WorkHub";
37
+ }
38
+ function appEnv() {
39
+ return process.env.APP_ENV?.trim() || "local";
40
+ }
41
+ function appUrl() {
42
+ return (process.env.APP_URL?.trim() || "http://localhost:3000").replace(/\/$/, "");
43
+ }
44
+ function apiPrefix() {
45
+ const raw = process.env.API_PREFIX?.trim() || "/api/v1";
46
+ const withSlash = raw.startsWith("/") ? raw : `/${raw}`;
47
+ const trimmed = withSlash.replace(/\/+$/, "");
48
+ return trimmed || "/api/v1";
49
+ }
50
+ function sdkClientClassName() {
51
+ const override = process.env.APP_SDK_CLASS?.trim();
52
+ if (override && /^[A-Za-z_][A-Za-z0-9_]*$/.test(override)) {
53
+ return override;
54
+ }
55
+ const fromName = appDisplayName().replace(/[^A-Za-z0-9]/g, "");
56
+ return fromName ? `${fromName}Client` : "AppClient";
57
+ }
58
+
59
+ // ../../src/core/auth/sessionCookie.ts
4
60
  var SESSION_COOKIE = "workhub_session";
5
61
  var SESSION_TTL_SECONDS = 60 * 60 * 24 * 7;
6
62
  var SESSION_REMEMBER_TTL_SECONDS = 60 * 60 * 24 * 30;
7
63
  function sessionCookieName() {
8
- return process.env.SESSION_COOKIE_NAME?.trim() || SESSION_COOKIE;
64
+ return process.env.SESSION_COOKIE_NAME?.trim() || appCookieName("session");
9
65
  }
10
66
  function parsePositiveSeconds(raw, fallback) {
11
67
  const parsed = Number.parseInt(raw ?? "", 10);
@@ -18,7 +74,7 @@ function sessionRememberTtlSeconds() {
18
74
  return parsePositiveSeconds(process.env.SESSION_REMEMBER_TTL_SECONDS, SESSION_REMEMBER_TTL_SECONDS);
19
75
  }
20
76
  function resolveSessionSecret() {
21
- return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || process.env.ADMIN_API_TOKEN?.trim() || "workhub-dev-session-secret";
77
+ return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || process.env.ADMIN_API_TOKEN?.trim() || appDevSecret("session-secret");
22
78
  }
23
79
  function signSession(userId, issuedAt, ttlSeconds) {
24
80
  const payload = ttlSeconds === undefined ? `${userId}.${issuedAt}` : `${userId}.${issuedAt}.${ttlSeconds}`;
@@ -84,11 +84,67 @@ function resolveAbilitiesForRole(role) {
84
84
 
85
85
  // ../../src/core/auth/sessionCookie.ts
86
86
  import { createHmac, timingSafeEqual } from "crypto";
87
+
88
+ // ../../src/core/runtime/appKeyPrefix.ts
89
+ function appKeyPrefix() {
90
+ return process.env.APP_KEY_PREFIX?.trim() || "workhub";
91
+ }
92
+ function appCookieName(kind) {
93
+ return `${appKeyPrefix()}_${kind}`;
94
+ }
95
+ function appDevSecret(kind) {
96
+ return `${appKeyPrefix()}-dev-${kind}`;
97
+ }
98
+ function namespacedRedisKey(kind) {
99
+ return `${appKeyPrefix()}:${kind}`;
100
+ }
101
+ function smtpEhloHost() {
102
+ const raw = process.env.MAIL_EHLO?.trim() || `${appKeyPrefix()}.local`;
103
+ const safe = raw.replace(/[^a-zA-Z0-9.-]/g, "");
104
+ return safe || "strata.local";
105
+ }
106
+ function siemEventType() {
107
+ return process.env.SIEM_EVENT_TYPE?.trim() || `${appKeyPrefix()}.audit`;
108
+ }
109
+ function appUserAgent() {
110
+ return process.env.APP_USER_AGENT?.trim() || appKeyPrefix();
111
+ }
112
+ function otelServiceName() {
113
+ return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
114
+ }
115
+ function webhookSignatureHeader() {
116
+ return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
117
+ }
118
+ function appDisplayName() {
119
+ return process.env.APP_NAME?.trim() || "WorkHub";
120
+ }
121
+ function appEnv() {
122
+ return process.env.APP_ENV?.trim() || "local";
123
+ }
124
+ function appUrl() {
125
+ return (process.env.APP_URL?.trim() || "http://localhost:3000").replace(/\/$/, "");
126
+ }
127
+ function apiPrefix() {
128
+ const raw = process.env.API_PREFIX?.trim() || "/api/v1";
129
+ const withSlash = raw.startsWith("/") ? raw : `/${raw}`;
130
+ const trimmed = withSlash.replace(/\/+$/, "");
131
+ return trimmed || "/api/v1";
132
+ }
133
+ function sdkClientClassName() {
134
+ const override = process.env.APP_SDK_CLASS?.trim();
135
+ if (override && /^[A-Za-z_][A-Za-z0-9_]*$/.test(override)) {
136
+ return override;
137
+ }
138
+ const fromName = appDisplayName().replace(/[^A-Za-z0-9]/g, "");
139
+ return fromName ? `${fromName}Client` : "AppClient";
140
+ }
141
+
142
+ // ../../src/core/auth/sessionCookie.ts
87
143
  var SESSION_COOKIE = "workhub_session";
88
144
  var SESSION_TTL_SECONDS = 60 * 60 * 24 * 7;
89
145
  var SESSION_REMEMBER_TTL_SECONDS = 60 * 60 * 24 * 30;
90
146
  function sessionCookieName() {
91
- return process.env.SESSION_COOKIE_NAME?.trim() || SESSION_COOKIE;
147
+ return process.env.SESSION_COOKIE_NAME?.trim() || appCookieName("session");
92
148
  }
93
149
  function parsePositiveSeconds(raw, fallback) {
94
150
  const parsed = Number.parseInt(raw ?? "", 10);
@@ -101,7 +157,7 @@ function sessionRememberTtlSeconds() {
101
157
  return parsePositiveSeconds(process.env.SESSION_REMEMBER_TTL_SECONDS, SESSION_REMEMBER_TTL_SECONDS);
102
158
  }
103
159
  function resolveSessionSecret() {
104
- return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || process.env.ADMIN_API_TOKEN?.trim() || "workhub-dev-session-secret";
160
+ return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || process.env.ADMIN_API_TOKEN?.trim() || appDevSecret("session-secret");
105
161
  }
106
162
  function signSession(userId, issuedAt, ttlSeconds) {
107
163
  const payload = ttlSeconds === undefined ? `${userId}.${issuedAt}` : `${userId}.${issuedAt}.${ttlSeconds}`;
@@ -1,12 +1,68 @@
1
1
  // @bun
2
2
  // ../../src/core/auth/tokenHash.ts
3
3
  import { createHash, createHmac } from "crypto";
4
+
5
+ // ../../src/core/runtime/appKeyPrefix.ts
6
+ function appKeyPrefix() {
7
+ return process.env.APP_KEY_PREFIX?.trim() || "workhub";
8
+ }
9
+ function appCookieName(kind) {
10
+ return `${appKeyPrefix()}_${kind}`;
11
+ }
12
+ function appDevSecret(kind) {
13
+ return `${appKeyPrefix()}-dev-${kind}`;
14
+ }
15
+ function namespacedRedisKey(kind) {
16
+ return `${appKeyPrefix()}:${kind}`;
17
+ }
18
+ function smtpEhloHost() {
19
+ const raw = process.env.MAIL_EHLO?.trim() || `${appKeyPrefix()}.local`;
20
+ const safe = raw.replace(/[^a-zA-Z0-9.-]/g, "");
21
+ return safe || "strata.local";
22
+ }
23
+ function siemEventType() {
24
+ return process.env.SIEM_EVENT_TYPE?.trim() || `${appKeyPrefix()}.audit`;
25
+ }
26
+ function appUserAgent() {
27
+ return process.env.APP_USER_AGENT?.trim() || appKeyPrefix();
28
+ }
29
+ function otelServiceName() {
30
+ return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
31
+ }
32
+ function webhookSignatureHeader() {
33
+ return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
34
+ }
35
+ function appDisplayName() {
36
+ return process.env.APP_NAME?.trim() || "WorkHub";
37
+ }
38
+ function appEnv() {
39
+ return process.env.APP_ENV?.trim() || "local";
40
+ }
41
+ function appUrl() {
42
+ return (process.env.APP_URL?.trim() || "http://localhost:3000").replace(/\/$/, "");
43
+ }
44
+ function apiPrefix() {
45
+ const raw = process.env.API_PREFIX?.trim() || "/api/v1";
46
+ const withSlash = raw.startsWith("/") ? raw : `/${raw}`;
47
+ const trimmed = withSlash.replace(/\/+$/, "");
48
+ return trimmed || "/api/v1";
49
+ }
50
+ function sdkClientClassName() {
51
+ const override = process.env.APP_SDK_CLASS?.trim();
52
+ if (override && /^[A-Za-z_][A-Za-z0-9_]*$/.test(override)) {
53
+ return override;
54
+ }
55
+ const fromName = appDisplayName().replace(/[^A-Za-z0-9]/g, "");
56
+ return fromName ? `${fromName}Client` : "AppClient";
57
+ }
58
+
59
+ // ../../src/core/auth/tokenHash.ts
4
60
  function resolveTokenPepper() {
5
- return process.env.TOKEN_HASH_PEPPER?.trim() ?? "workhub-dev-token-pepper";
61
+ return process.env.TOKEN_HASH_PEPPER?.trim() ?? appDevSecret("token-pepper");
6
62
  }
7
63
  function hashApiToken(token) {
8
64
  const pepper = resolveTokenPepper();
9
- if (pepper && pepper !== "workhub-dev-token-pepper") {
65
+ if (pepper && pepper !== appDevSecret("token-pepper")) {
10
66
  return createHmac("sha256", pepper).update(token).digest("hex");
11
67
  }
12
68
  return createHash("sha256").update(token).digest("hex");
@@ -6,6 +6,12 @@ var {RedisClient } = globalThis.Bun;
6
6
  function appKeyPrefix() {
7
7
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
8
8
  }
9
+ function appCookieName(kind) {
10
+ return `${appKeyPrefix()}_${kind}`;
11
+ }
12
+ function appDevSecret(kind) {
13
+ return `${appKeyPrefix()}-dev-${kind}`;
14
+ }
9
15
  function namespacedRedisKey(kind) {
10
16
  return `${appKeyPrefix()}:${kind}`;
11
17
  }
@@ -15,6 +15,12 @@ import {
15
15
  function appKeyPrefix() {
16
16
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
17
17
  }
18
+ function appCookieName(kind) {
19
+ return `${appKeyPrefix()}_${kind}`;
20
+ }
21
+ function appDevSecret(kind) {
22
+ return `${appKeyPrefix()}-dev-${kind}`;
23
+ }
18
24
  function namespacedRedisKey(kind) {
19
25
  return `${appKeyPrefix()}:${kind}`;
20
26
  }
@@ -5,6 +5,60 @@ import { ForbiddenError } from "@getstrata/core/errors/http";
5
5
  // ../../src/core/http/csrfToken.ts
6
6
  import { timingSafeEqual } from "crypto";
7
7
 
8
+ // ../../src/core/runtime/appKeyPrefix.ts
9
+ function appKeyPrefix() {
10
+ return process.env.APP_KEY_PREFIX?.trim() || "workhub";
11
+ }
12
+ function appCookieName(kind) {
13
+ return `${appKeyPrefix()}_${kind}`;
14
+ }
15
+ function appDevSecret(kind) {
16
+ return `${appKeyPrefix()}-dev-${kind}`;
17
+ }
18
+ function namespacedRedisKey(kind) {
19
+ return `${appKeyPrefix()}:${kind}`;
20
+ }
21
+ function smtpEhloHost() {
22
+ const raw = process.env.MAIL_EHLO?.trim() || `${appKeyPrefix()}.local`;
23
+ const safe = raw.replace(/[^a-zA-Z0-9.-]/g, "");
24
+ return safe || "strata.local";
25
+ }
26
+ function siemEventType() {
27
+ return process.env.SIEM_EVENT_TYPE?.trim() || `${appKeyPrefix()}.audit`;
28
+ }
29
+ function appUserAgent() {
30
+ return process.env.APP_USER_AGENT?.trim() || appKeyPrefix();
31
+ }
32
+ function otelServiceName() {
33
+ return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
34
+ }
35
+ function webhookSignatureHeader() {
36
+ return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
37
+ }
38
+ function appDisplayName() {
39
+ return process.env.APP_NAME?.trim() || "WorkHub";
40
+ }
41
+ function appEnv() {
42
+ return process.env.APP_ENV?.trim() || "local";
43
+ }
44
+ function appUrl() {
45
+ return (process.env.APP_URL?.trim() || "http://localhost:3000").replace(/\/$/, "");
46
+ }
47
+ function apiPrefix() {
48
+ const raw = process.env.API_PREFIX?.trim() || "/api/v1";
49
+ const withSlash = raw.startsWith("/") ? raw : `/${raw}`;
50
+ const trimmed = withSlash.replace(/\/+$/, "");
51
+ return trimmed || "/api/v1";
52
+ }
53
+ function sdkClientClassName() {
54
+ const override = process.env.APP_SDK_CLASS?.trim();
55
+ if (override && /^[A-Za-z_][A-Za-z0-9_]*$/.test(override)) {
56
+ return override;
57
+ }
58
+ const fromName = appDisplayName().replace(/[^A-Za-z0-9]/g, "");
59
+ return fromName ? `${fromName}Client` : "AppClient";
60
+ }
61
+
8
62
  // ../../src/core/http/cookies.ts
9
63
  function readRequestCookie(request, name) {
10
64
  const cookies = request.cookies;
@@ -63,10 +117,10 @@ function currentRequestMeta() {
63
117
  var CSRF_COOKIE = "workhub_csrf";
64
118
  var CSRF_TTL_MS = 60 * 60 * 1000;
65
119
  function csrfCookieName() {
66
- return process.env.CSRF_COOKIE_NAME?.trim() || CSRF_COOKIE;
120
+ return process.env.CSRF_COOKIE_NAME?.trim() || appCookieName("csrf");
67
121
  }
68
122
  function resolveCsrfSecret() {
69
- return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || process.env.ADMIN_API_TOKEN?.trim() || "workhub-dev-csrf-secret";
123
+ return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || process.env.ADMIN_API_TOKEN?.trim() || appDevSecret("csrf-secret");
70
124
  }
71
125
  function csrfVerifyOptions() {
72
126
  return { secret: resolveCsrfSecret(), maxAge: CSRF_TTL_MS };
@@ -2,6 +2,60 @@
2
2
  // ../../src/core/http/csrfToken.ts
3
3
  import { timingSafeEqual } from "crypto";
4
4
 
5
+ // ../../src/core/runtime/appKeyPrefix.ts
6
+ function appKeyPrefix() {
7
+ return process.env.APP_KEY_PREFIX?.trim() || "workhub";
8
+ }
9
+ function appCookieName(kind) {
10
+ return `${appKeyPrefix()}_${kind}`;
11
+ }
12
+ function appDevSecret(kind) {
13
+ return `${appKeyPrefix()}-dev-${kind}`;
14
+ }
15
+ function namespacedRedisKey(kind) {
16
+ return `${appKeyPrefix()}:${kind}`;
17
+ }
18
+ function smtpEhloHost() {
19
+ const raw = process.env.MAIL_EHLO?.trim() || `${appKeyPrefix()}.local`;
20
+ const safe = raw.replace(/[^a-zA-Z0-9.-]/g, "");
21
+ return safe || "strata.local";
22
+ }
23
+ function siemEventType() {
24
+ return process.env.SIEM_EVENT_TYPE?.trim() || `${appKeyPrefix()}.audit`;
25
+ }
26
+ function appUserAgent() {
27
+ return process.env.APP_USER_AGENT?.trim() || appKeyPrefix();
28
+ }
29
+ function otelServiceName() {
30
+ return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
31
+ }
32
+ function webhookSignatureHeader() {
33
+ return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
34
+ }
35
+ function appDisplayName() {
36
+ return process.env.APP_NAME?.trim() || "WorkHub";
37
+ }
38
+ function appEnv() {
39
+ return process.env.APP_ENV?.trim() || "local";
40
+ }
41
+ function appUrl() {
42
+ return (process.env.APP_URL?.trim() || "http://localhost:3000").replace(/\/$/, "");
43
+ }
44
+ function apiPrefix() {
45
+ const raw = process.env.API_PREFIX?.trim() || "/api/v1";
46
+ const withSlash = raw.startsWith("/") ? raw : `/${raw}`;
47
+ const trimmed = withSlash.replace(/\/+$/, "");
48
+ return trimmed || "/api/v1";
49
+ }
50
+ function sdkClientClassName() {
51
+ const override = process.env.APP_SDK_CLASS?.trim();
52
+ if (override && /^[A-Za-z_][A-Za-z0-9_]*$/.test(override)) {
53
+ return override;
54
+ }
55
+ const fromName = appDisplayName().replace(/[^A-Za-z0-9]/g, "");
56
+ return fromName ? `${fromName}Client` : "AppClient";
57
+ }
58
+
5
59
  // ../../src/core/http/cookies.ts
6
60
  function readRequestCookie(request, name) {
7
61
  const cookies = request.cookies;
@@ -60,10 +114,10 @@ function currentRequestMeta() {
60
114
  var CSRF_COOKIE = "workhub_csrf";
61
115
  var CSRF_TTL_MS = 60 * 60 * 1000;
62
116
  function csrfCookieName() {
63
- return process.env.CSRF_COOKIE_NAME?.trim() || CSRF_COOKIE;
117
+ return process.env.CSRF_COOKIE_NAME?.trim() || appCookieName("csrf");
64
118
  }
65
119
  function resolveCsrfSecret() {
66
- return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || process.env.ADMIN_API_TOKEN?.trim() || "workhub-dev-csrf-secret";
120
+ return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || process.env.ADMIN_API_TOKEN?.trim() || appDevSecret("csrf-secret");
67
121
  }
68
122
  function csrfVerifyOptions() {
69
123
  return { secret: resolveCsrfSecret(), maxAge: CSRF_TTL_MS };
@@ -1,13 +1,69 @@
1
1
  // @bun
2
2
  // ../../src/core/http/flashSession.ts
3
3
  import { createHmac, timingSafeEqual } from "crypto";
4
+
5
+ // ../../src/core/runtime/appKeyPrefix.ts
6
+ function appKeyPrefix() {
7
+ return process.env.APP_KEY_PREFIX?.trim() || "workhub";
8
+ }
9
+ function appCookieName(kind) {
10
+ return `${appKeyPrefix()}_${kind}`;
11
+ }
12
+ function appDevSecret(kind) {
13
+ return `${appKeyPrefix()}-dev-${kind}`;
14
+ }
15
+ function namespacedRedisKey(kind) {
16
+ return `${appKeyPrefix()}:${kind}`;
17
+ }
18
+ function smtpEhloHost() {
19
+ const raw = process.env.MAIL_EHLO?.trim() || `${appKeyPrefix()}.local`;
20
+ const safe = raw.replace(/[^a-zA-Z0-9.-]/g, "");
21
+ return safe || "strata.local";
22
+ }
23
+ function siemEventType() {
24
+ return process.env.SIEM_EVENT_TYPE?.trim() || `${appKeyPrefix()}.audit`;
25
+ }
26
+ function appUserAgent() {
27
+ return process.env.APP_USER_AGENT?.trim() || appKeyPrefix();
28
+ }
29
+ function otelServiceName() {
30
+ return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
31
+ }
32
+ function webhookSignatureHeader() {
33
+ return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
34
+ }
35
+ function appDisplayName() {
36
+ return process.env.APP_NAME?.trim() || "WorkHub";
37
+ }
38
+ function appEnv() {
39
+ return process.env.APP_ENV?.trim() || "local";
40
+ }
41
+ function appUrl() {
42
+ return (process.env.APP_URL?.trim() || "http://localhost:3000").replace(/\/$/, "");
43
+ }
44
+ function apiPrefix() {
45
+ const raw = process.env.API_PREFIX?.trim() || "/api/v1";
46
+ const withSlash = raw.startsWith("/") ? raw : `/${raw}`;
47
+ const trimmed = withSlash.replace(/\/+$/, "");
48
+ return trimmed || "/api/v1";
49
+ }
50
+ function sdkClientClassName() {
51
+ const override = process.env.APP_SDK_CLASS?.trim();
52
+ if (override && /^[A-Za-z_][A-Za-z0-9_]*$/.test(override)) {
53
+ return override;
54
+ }
55
+ const fromName = appDisplayName().replace(/[^A-Za-z0-9]/g, "");
56
+ return fromName ? `${fromName}Client` : "AppClient";
57
+ }
58
+
59
+ // ../../src/core/http/flashSession.ts
4
60
  var FLASH_COOKIE = "workhub_flash";
5
61
  var FLASH_TTL_MS = 60 * 1000;
6
62
  function flashCookieName() {
7
- return process.env.FLASH_COOKIE_NAME?.trim() || FLASH_COOKIE;
63
+ return process.env.FLASH_COOKIE_NAME?.trim() || appCookieName("flash");
8
64
  }
9
65
  function resolveFlashSecret() {
10
- return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || "workhub-dev-flash-secret";
66
+ return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || appDevSecret("flash-secret");
11
67
  }
12
68
  function signFlashPayload(payload, issuedAt) {
13
69
  const signature = createHmac("sha256", resolveFlashSecret()).update(`${payload}.${issuedAt}`).digest("hex");
@@ -1,13 +1,69 @@
1
1
  // @bun
2
2
  // ../../src/core/http/flashSession.ts
3
3
  import { createHmac, timingSafeEqual } from "crypto";
4
+
5
+ // ../../src/core/runtime/appKeyPrefix.ts
6
+ function appKeyPrefix() {
7
+ return process.env.APP_KEY_PREFIX?.trim() || "workhub";
8
+ }
9
+ function appCookieName(kind) {
10
+ return `${appKeyPrefix()}_${kind}`;
11
+ }
12
+ function appDevSecret(kind) {
13
+ return `${appKeyPrefix()}-dev-${kind}`;
14
+ }
15
+ function namespacedRedisKey(kind) {
16
+ return `${appKeyPrefix()}:${kind}`;
17
+ }
18
+ function smtpEhloHost() {
19
+ const raw = process.env.MAIL_EHLO?.trim() || `${appKeyPrefix()}.local`;
20
+ const safe = raw.replace(/[^a-zA-Z0-9.-]/g, "");
21
+ return safe || "strata.local";
22
+ }
23
+ function siemEventType() {
24
+ return process.env.SIEM_EVENT_TYPE?.trim() || `${appKeyPrefix()}.audit`;
25
+ }
26
+ function appUserAgent() {
27
+ return process.env.APP_USER_AGENT?.trim() || appKeyPrefix();
28
+ }
29
+ function otelServiceName() {
30
+ return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
31
+ }
32
+ function webhookSignatureHeader() {
33
+ return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
34
+ }
35
+ function appDisplayName() {
36
+ return process.env.APP_NAME?.trim() || "WorkHub";
37
+ }
38
+ function appEnv() {
39
+ return process.env.APP_ENV?.trim() || "local";
40
+ }
41
+ function appUrl() {
42
+ return (process.env.APP_URL?.trim() || "http://localhost:3000").replace(/\/$/, "");
43
+ }
44
+ function apiPrefix() {
45
+ const raw = process.env.API_PREFIX?.trim() || "/api/v1";
46
+ const withSlash = raw.startsWith("/") ? raw : `/${raw}`;
47
+ const trimmed = withSlash.replace(/\/+$/, "");
48
+ return trimmed || "/api/v1";
49
+ }
50
+ function sdkClientClassName() {
51
+ const override = process.env.APP_SDK_CLASS?.trim();
52
+ if (override && /^[A-Za-z_][A-Za-z0-9_]*$/.test(override)) {
53
+ return override;
54
+ }
55
+ const fromName = appDisplayName().replace(/[^A-Za-z0-9]/g, "");
56
+ return fromName ? `${fromName}Client` : "AppClient";
57
+ }
58
+
59
+ // ../../src/core/http/flashSession.ts
4
60
  var FLASH_COOKIE = "workhub_flash";
5
61
  var FLASH_TTL_MS = 60 * 1000;
6
62
  function flashCookieName() {
7
- return process.env.FLASH_COOKIE_NAME?.trim() || FLASH_COOKIE;
63
+ return process.env.FLASH_COOKIE_NAME?.trim() || appCookieName("flash");
8
64
  }
9
65
  function resolveFlashSecret() {
10
- return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || "workhub-dev-flash-secret";
66
+ return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || appDevSecret("flash-secret");
11
67
  }
12
68
  function signFlashPayload(payload, issuedAt) {
13
69
  const signature = createHmac("sha256", resolveFlashSecret()).update(`${payload}.${issuedAt}`).digest("hex");
@@ -6,6 +6,12 @@ var {RedisClient } = globalThis.Bun;
6
6
  function appKeyPrefix() {
7
7
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
8
8
  }
9
+ function appCookieName(kind) {
10
+ return `${appKeyPrefix()}_${kind}`;
11
+ }
12
+ function appDevSecret(kind) {
13
+ return `${appKeyPrefix()}-dev-${kind}`;
14
+ }
9
15
  function namespacedRedisKey(kind) {
10
16
  return `${appKeyPrefix()}:${kind}`;
11
17
  }
@@ -3,6 +3,12 @@
3
3
  function appKeyPrefix() {
4
4
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
5
5
  }
6
+ function appCookieName(kind) {
7
+ return `${appKeyPrefix()}_${kind}`;
8
+ }
9
+ function appDevSecret(kind) {
10
+ return `${appKeyPrefix()}-dev-${kind}`;
11
+ }
6
12
  function namespacedRedisKey(kind) {
7
13
  return `${appKeyPrefix()}:${kind}`;
8
14
  }
@@ -6,6 +6,12 @@ var {RedisClient } = globalThis.Bun;
6
6
  function appKeyPrefix() {
7
7
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
8
8
  }
9
+ function appCookieName(kind) {
10
+ return `${appKeyPrefix()}_${kind}`;
11
+ }
12
+ function appDevSecret(kind) {
13
+ return `${appKeyPrefix()}-dev-${kind}`;
14
+ }
9
15
  function namespacedRedisKey(kind) {
10
16
  return `${appKeyPrefix()}:${kind}`;
11
17
  }
@@ -11,6 +11,12 @@ import { currentRequestMeta, runWithRequestMeta } from "@getstrata/core/http/req
11
11
  function appKeyPrefix() {
12
12
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
13
13
  }
14
+ function appCookieName(kind) {
15
+ return `${appKeyPrefix()}_${kind}`;
16
+ }
17
+ function appDevSecret(kind) {
18
+ return `${appKeyPrefix()}-dev-${kind}`;
19
+ }
14
20
  function namespacedRedisKey(kind) {
15
21
  return `${appKeyPrefix()}:${kind}`;
16
22
  }
@@ -3,8 +3,64 @@
3
3
  import { createHmac } from "crypto";
4
4
  import { ForbiddenError } from "@getstrata/core/errors/http";
5
5
  import { timingSafeCompareString } from "@getstrata/core/security/timingSafeCompare";
6
+
7
+ // ../../src/core/runtime/appKeyPrefix.ts
8
+ function appKeyPrefix() {
9
+ return process.env.APP_KEY_PREFIX?.trim() || "workhub";
10
+ }
11
+ function appCookieName(kind) {
12
+ return `${appKeyPrefix()}_${kind}`;
13
+ }
14
+ function appDevSecret(kind) {
15
+ return `${appKeyPrefix()}-dev-${kind}`;
16
+ }
17
+ function namespacedRedisKey(kind) {
18
+ return `${appKeyPrefix()}:${kind}`;
19
+ }
20
+ function smtpEhloHost() {
21
+ const raw = process.env.MAIL_EHLO?.trim() || `${appKeyPrefix()}.local`;
22
+ const safe = raw.replace(/[^a-zA-Z0-9.-]/g, "");
23
+ return safe || "strata.local";
24
+ }
25
+ function siemEventType() {
26
+ return process.env.SIEM_EVENT_TYPE?.trim() || `${appKeyPrefix()}.audit`;
27
+ }
28
+ function appUserAgent() {
29
+ return process.env.APP_USER_AGENT?.trim() || appKeyPrefix();
30
+ }
31
+ function otelServiceName() {
32
+ return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
33
+ }
34
+ function webhookSignatureHeader() {
35
+ return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
36
+ }
37
+ function appDisplayName() {
38
+ return process.env.APP_NAME?.trim() || "WorkHub";
39
+ }
40
+ function appEnv() {
41
+ return process.env.APP_ENV?.trim() || "local";
42
+ }
43
+ function appUrl() {
44
+ return (process.env.APP_URL?.trim() || "http://localhost:3000").replace(/\/$/, "");
45
+ }
46
+ function apiPrefix() {
47
+ const raw = process.env.API_PREFIX?.trim() || "/api/v1";
48
+ const withSlash = raw.startsWith("/") ? raw : `/${raw}`;
49
+ const trimmed = withSlash.replace(/\/+$/, "");
50
+ return trimmed || "/api/v1";
51
+ }
52
+ function sdkClientClassName() {
53
+ const override = process.env.APP_SDK_CLASS?.trim();
54
+ if (override && /^[A-Za-z_][A-Za-z0-9_]*$/.test(override)) {
55
+ return override;
56
+ }
57
+ const fromName = appDisplayName().replace(/[^A-Za-z0-9]/g, "");
58
+ return fromName ? `${fromName}Client` : "AppClient";
59
+ }
60
+
61
+ // ../../src/core/http/signedUrl.ts
6
62
  function resolveSignedUrlSecret() {
7
- return process.env.SIGNED_URL_SECRET?.trim() || process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || "workhub-dev-signed-url-secret";
63
+ return process.env.SIGNED_URL_SECRET?.trim() || process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || appDevSecret("signed-url-secret");
8
64
  }
9
65
  function resolveSignedUrlOrigin() {
10
66
  return (process.env.APP_URL ?? "http://localhost:3000").replace(/\/$/, "");
@@ -8,6 +8,12 @@ var {RedisClient } = globalThis.Bun;
8
8
  function appKeyPrefix() {
9
9
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
10
10
  }
11
+ function appCookieName(kind) {
12
+ return `${appKeyPrefix()}_${kind}`;
13
+ }
14
+ function appDevSecret(kind) {
15
+ return `${appKeyPrefix()}-dev-${kind}`;
16
+ }
11
17
  function namespacedRedisKey(kind) {
12
18
  return `${appKeyPrefix()}:${kind}`;
13
19
  }
@@ -6,6 +6,12 @@ import { repositoryConnection as db2 } from "@getstrata/core/database/repository
6
6
  function appKeyPrefix() {
7
7
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
8
8
  }
9
+ function appCookieName(kind) {
10
+ return `${appKeyPrefix()}_${kind}`;
11
+ }
12
+ function appDevSecret(kind) {
13
+ return `${appKeyPrefix()}-dev-${kind}`;
14
+ }
9
15
  function namespacedRedisKey(kind) {
10
16
  return `${appKeyPrefix()}:${kind}`;
11
17
  }
@@ -3,6 +3,12 @@
3
3
  function appKeyPrefix() {
4
4
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
5
5
  }
6
+ function appCookieName(kind) {
7
+ return `${appKeyPrefix()}_${kind}`;
8
+ }
9
+ function appDevSecret(kind) {
10
+ return `${appKeyPrefix()}-dev-${kind}`;
11
+ }
6
12
  function namespacedRedisKey(kind) {
7
13
  return `${appKeyPrefix()}:${kind}`;
8
14
  }
@@ -3,6 +3,12 @@
3
3
  function appKeyPrefix() {
4
4
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
5
5
  }
6
+ function appCookieName(kind) {
7
+ return `${appKeyPrefix()}_${kind}`;
8
+ }
9
+ function appDevSecret(kind) {
10
+ return `${appKeyPrefix()}-dev-${kind}`;
11
+ }
6
12
  function namespacedRedisKey(kind) {
7
13
  return `${appKeyPrefix()}:${kind}`;
8
14
  }
@@ -160,6 +160,12 @@ var {RedisClient } = globalThis.Bun;
160
160
  function appKeyPrefix() {
161
161
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
162
162
  }
163
+ function appCookieName(kind) {
164
+ return `${appKeyPrefix()}_${kind}`;
165
+ }
166
+ function appDevSecret(kind) {
167
+ return `${appKeyPrefix()}-dev-${kind}`;
168
+ }
163
169
  function namespacedRedisKey(kind) {
164
170
  return `${appKeyPrefix()}:${kind}`;
165
171
  }
@@ -160,6 +160,12 @@ var {RedisClient } = globalThis.Bun;
160
160
  function appKeyPrefix() {
161
161
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
162
162
  }
163
+ function appCookieName(kind) {
164
+ return `${appKeyPrefix()}_${kind}`;
165
+ }
166
+ function appDevSecret(kind) {
167
+ return `${appKeyPrefix()}-dev-${kind}`;
168
+ }
163
169
  function namespacedRedisKey(kind) {
164
170
  return `${appKeyPrefix()}:${kind}`;
165
171
  }
@@ -163,6 +163,12 @@ var {RedisClient } = globalThis.Bun;
163
163
  function appKeyPrefix() {
164
164
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
165
165
  }
166
+ function appCookieName(kind) {
167
+ return `${appKeyPrefix()}_${kind}`;
168
+ }
169
+ function appDevSecret(kind) {
170
+ return `${appKeyPrefix()}-dev-${kind}`;
171
+ }
166
172
  function namespacedRedisKey(kind) {
167
173
  return `${appKeyPrefix()}:${kind}`;
168
174
  }
@@ -6,6 +6,12 @@ var {RedisClient } = globalThis.Bun;
6
6
  function appKeyPrefix() {
7
7
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
8
8
  }
9
+ function appCookieName(kind) {
10
+ return `${appKeyPrefix()}_${kind}`;
11
+ }
12
+ function appDevSecret(kind) {
13
+ return `${appKeyPrefix()}-dev-${kind}`;
14
+ }
9
15
  function namespacedRedisKey(kind) {
10
16
  return `${appKeyPrefix()}:${kind}`;
11
17
  }
@@ -3,6 +3,12 @@
3
3
  function appKeyPrefix() {
4
4
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
5
5
  }
6
+ function appCookieName(kind) {
7
+ return `${appKeyPrefix()}_${kind}`;
8
+ }
9
+ function appDevSecret(kind) {
10
+ return `${appKeyPrefix()}-dev-${kind}`;
11
+ }
6
12
  function namespacedRedisKey(kind) {
7
13
  return `${appKeyPrefix()}:${kind}`;
8
14
  }
@@ -48,6 +54,8 @@ function sdkClientClassName() {
48
54
  }
49
55
  export {
50
56
  apiPrefix,
57
+ appCookieName,
58
+ appDevSecret,
51
59
  appDisplayName,
52
60
  appEnv,
53
61
  appKeyPrefix,
@@ -1,10 +1,66 @@
1
1
  // @bun
2
2
  // ../../src/core/security/oauthState.ts
3
3
  import { createHmac, randomBytes, timingSafeEqual } from "crypto";
4
+
5
+ // ../../src/core/runtime/appKeyPrefix.ts
6
+ function appKeyPrefix() {
7
+ return process.env.APP_KEY_PREFIX?.trim() || "workhub";
8
+ }
9
+ function appCookieName(kind) {
10
+ return `${appKeyPrefix()}_${kind}`;
11
+ }
12
+ function appDevSecret(kind) {
13
+ return `${appKeyPrefix()}-dev-${kind}`;
14
+ }
15
+ function namespacedRedisKey(kind) {
16
+ return `${appKeyPrefix()}:${kind}`;
17
+ }
18
+ function smtpEhloHost() {
19
+ const raw = process.env.MAIL_EHLO?.trim() || `${appKeyPrefix()}.local`;
20
+ const safe = raw.replace(/[^a-zA-Z0-9.-]/g, "");
21
+ return safe || "strata.local";
22
+ }
23
+ function siemEventType() {
24
+ return process.env.SIEM_EVENT_TYPE?.trim() || `${appKeyPrefix()}.audit`;
25
+ }
26
+ function appUserAgent() {
27
+ return process.env.APP_USER_AGENT?.trim() || appKeyPrefix();
28
+ }
29
+ function otelServiceName() {
30
+ return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
31
+ }
32
+ function webhookSignatureHeader() {
33
+ return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
34
+ }
35
+ function appDisplayName() {
36
+ return process.env.APP_NAME?.trim() || "WorkHub";
37
+ }
38
+ function appEnv() {
39
+ return process.env.APP_ENV?.trim() || "local";
40
+ }
41
+ function appUrl() {
42
+ return (process.env.APP_URL?.trim() || "http://localhost:3000").replace(/\/$/, "");
43
+ }
44
+ function apiPrefix() {
45
+ const raw = process.env.API_PREFIX?.trim() || "/api/v1";
46
+ const withSlash = raw.startsWith("/") ? raw : `/${raw}`;
47
+ const trimmed = withSlash.replace(/\/+$/, "");
48
+ return trimmed || "/api/v1";
49
+ }
50
+ function sdkClientClassName() {
51
+ const override = process.env.APP_SDK_CLASS?.trim();
52
+ if (override && /^[A-Za-z_][A-Za-z0-9_]*$/.test(override)) {
53
+ return override;
54
+ }
55
+ const fromName = appDisplayName().replace(/[^A-Za-z0-9]/g, "");
56
+ return fromName ? `${fromName}Client` : "AppClient";
57
+ }
58
+
59
+ // ../../src/core/security/oauthState.ts
4
60
  var OAUTH_STATE_COOKIE = "oauth_state";
5
61
  var OAUTH_STATE_TTL_MS = 10 * 60 * 1000;
6
62
  function resolveOAuthStateSecret() {
7
- return process.env.OAUTH_STATE_SECRET?.trim() || process.env.ADMIN_API_TOKEN?.trim() || "workhub-dev-oauth-state-secret";
63
+ return process.env.OAUTH_STATE_SECRET?.trim() || process.env.ADMIN_API_TOKEN?.trim() || appDevSecret("oauth-state-secret");
8
64
  }
9
65
  function signOAuthState(state, issuedAt) {
10
66
  const payload = `${state}.${issuedAt}`;
@@ -3,6 +3,12 @@
3
3
  function appKeyPrefix() {
4
4
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
5
5
  }
6
+ function appCookieName(kind) {
7
+ return `${appKeyPrefix()}_${kind}`;
8
+ }
9
+ function appDevSecret(kind) {
10
+ return `${appKeyPrefix()}-dev-${kind}`;
11
+ }
6
12
  function namespacedRedisKey(kind) {
7
13
  return `${appKeyPrefix()}:${kind}`;
8
14
  }
@@ -6,6 +6,12 @@ import { randomBytes } from "crypto";
6
6
  function appKeyPrefix() {
7
7
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
8
8
  }
9
+ function appCookieName(kind) {
10
+ return `${appKeyPrefix()}_${kind}`;
11
+ }
12
+ function appDevSecret(kind) {
13
+ return `${appKeyPrefix()}-dev-${kind}`;
14
+ }
9
15
  function namespacedRedisKey(kind) {
10
16
  return `${appKeyPrefix()}:${kind}`;
11
17
  }
@@ -384,6 +384,60 @@ function resolveAuthUserDirectory(container) {
384
384
  // ../../src/core/http/csrfToken.ts
385
385
  import { timingSafeEqual } from "crypto";
386
386
 
387
+ // ../../src/core/runtime/appKeyPrefix.ts
388
+ function appKeyPrefix() {
389
+ return process.env.APP_KEY_PREFIX?.trim() || "workhub";
390
+ }
391
+ function appCookieName(kind) {
392
+ return `${appKeyPrefix()}_${kind}`;
393
+ }
394
+ function appDevSecret(kind) {
395
+ return `${appKeyPrefix()}-dev-${kind}`;
396
+ }
397
+ function namespacedRedisKey(kind) {
398
+ return `${appKeyPrefix()}:${kind}`;
399
+ }
400
+ function smtpEhloHost() {
401
+ const raw = process.env.MAIL_EHLO?.trim() || `${appKeyPrefix()}.local`;
402
+ const safe = raw.replace(/[^a-zA-Z0-9.-]/g, "");
403
+ return safe || "strata.local";
404
+ }
405
+ function siemEventType() {
406
+ return process.env.SIEM_EVENT_TYPE?.trim() || `${appKeyPrefix()}.audit`;
407
+ }
408
+ function appUserAgent() {
409
+ return process.env.APP_USER_AGENT?.trim() || appKeyPrefix();
410
+ }
411
+ function otelServiceName() {
412
+ return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
413
+ }
414
+ function webhookSignatureHeader() {
415
+ return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
416
+ }
417
+ function appDisplayName() {
418
+ return process.env.APP_NAME?.trim() || "WorkHub";
419
+ }
420
+ function appEnv() {
421
+ return process.env.APP_ENV?.trim() || "local";
422
+ }
423
+ function appUrl() {
424
+ return (process.env.APP_URL?.trim() || "http://localhost:3000").replace(/\/$/, "");
425
+ }
426
+ function apiPrefix() {
427
+ const raw = process.env.API_PREFIX?.trim() || "/api/v1";
428
+ const withSlash = raw.startsWith("/") ? raw : `/${raw}`;
429
+ const trimmed = withSlash.replace(/\/+$/, "");
430
+ return trimmed || "/api/v1";
431
+ }
432
+ function sdkClientClassName() {
433
+ const override = process.env.APP_SDK_CLASS?.trim();
434
+ if (override && /^[A-Za-z_][A-Za-z0-9_]*$/.test(override)) {
435
+ return override;
436
+ }
437
+ const fromName = appDisplayName().replace(/[^A-Za-z0-9]/g, "");
438
+ return fromName ? `${fromName}Client` : "AppClient";
439
+ }
440
+
387
441
  // ../../src/core/http/cookies.ts
388
442
  function readRequestCookie(request, name) {
389
443
  const cookies = request.cookies;
@@ -442,10 +496,10 @@ function currentRequestMeta3() {
442
496
  var CSRF_COOKIE = "workhub_csrf";
443
497
  var CSRF_TTL_MS = 60 * 60 * 1000;
444
498
  function csrfCookieName() {
445
- return process.env.CSRF_COOKIE_NAME?.trim() || CSRF_COOKIE;
499
+ return process.env.CSRF_COOKIE_NAME?.trim() || appCookieName("csrf");
446
500
  }
447
501
  function resolveCsrfSecret() {
448
- return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || process.env.ADMIN_API_TOKEN?.trim() || "workhub-dev-csrf-secret";
502
+ return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || process.env.ADMIN_API_TOKEN?.trim() || appDevSecret("csrf-secret");
449
503
  }
450
504
  function csrfVerifyOptions() {
451
505
  return { secret: resolveCsrfSecret(), maxAge: CSRF_TTL_MS };
@@ -525,10 +579,10 @@ import { createHmac, timingSafeEqual as timingSafeEqual2 } from "crypto";
525
579
  var FLASH_COOKIE = "workhub_flash";
526
580
  var FLASH_TTL_MS = 60 * 1000;
527
581
  function flashCookieName() {
528
- return process.env.FLASH_COOKIE_NAME?.trim() || FLASH_COOKIE;
582
+ return process.env.FLASH_COOKIE_NAME?.trim() || appCookieName("flash");
529
583
  }
530
584
  function resolveFlashSecret() {
531
- return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || "workhub-dev-flash-secret";
585
+ return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || appDevSecret("flash-secret");
532
586
  }
533
587
  function signFlashPayload(payload, issuedAt) {
534
588
  const signature = createHmac("sha256", resolveFlashSecret()).update(`${payload}.${issuedAt}`).digest("hex");
package/dist/index.js CHANGED
@@ -979,6 +979,12 @@ var {RedisClient } = globalThis.Bun;
979
979
  function appKeyPrefix() {
980
980
  return process.env.APP_KEY_PREFIX?.trim() || "workhub";
981
981
  }
982
+ function appCookieName(kind) {
983
+ return `${appKeyPrefix()}_${kind}`;
984
+ }
985
+ function appDevSecret(kind) {
986
+ return `${appKeyPrefix()}-dev-${kind}`;
987
+ }
982
988
  function namespacedRedisKey(kind) {
983
989
  return `${appKeyPrefix()}:${kind}`;
984
990
  }
@@ -4560,13 +4566,12 @@ function currentRequestMeta() {
4560
4566
  }
4561
4567
 
4562
4568
  // ../../src/core/http/csrfToken.ts
4563
- var CSRF_COOKIE = "workhub_csrf";
4564
4569
  var CSRF_TTL_MS = 60 * 60 * 1000;
4565
4570
  function csrfCookieName() {
4566
- return process.env.CSRF_COOKIE_NAME?.trim() || CSRF_COOKIE;
4571
+ return process.env.CSRF_COOKIE_NAME?.trim() || appCookieName("csrf");
4567
4572
  }
4568
4573
  function resolveCsrfSecret() {
4569
- return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || process.env.ADMIN_API_TOKEN?.trim() || "workhub-dev-csrf-secret";
4574
+ return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || process.env.ADMIN_API_TOKEN?.trim() || appDevSecret("csrf-secret");
4570
4575
  }
4571
4576
  function csrfVerifyOptions() {
4572
4577
  return { secret: resolveCsrfSecret(), maxAge: CSRF_TTL_MS };
@@ -4692,13 +4697,12 @@ function createCsrfProtection(secret, options = {}) {
4692
4697
  }
4693
4698
  // ../../src/core/http/flashSession.ts
4694
4699
  import { createHmac, timingSafeEqual as timingSafeEqual3 } from "crypto";
4695
- var FLASH_COOKIE = "workhub_flash";
4696
4700
  var FLASH_TTL_MS = 60 * 1000;
4697
4701
  function flashCookieName() {
4698
- return process.env.FLASH_COOKIE_NAME?.trim() || FLASH_COOKIE;
4702
+ return process.env.FLASH_COOKIE_NAME?.trim() || appCookieName("flash");
4699
4703
  }
4700
4704
  function resolveFlashSecret() {
4701
- return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || "workhub-dev-flash-secret";
4705
+ return process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || appDevSecret("flash-secret");
4702
4706
  }
4703
4707
  function signFlashPayload(payload, issuedAt) {
4704
4708
  const signature = createHmac("sha256", resolveFlashSecret()).update(`${payload}.${issuedAt}`).digest("hex");
@@ -5709,7 +5713,7 @@ function createSecurityHeadersMiddleware(options = {}) {
5709
5713
  // ../../src/core/http/signedUrl.ts
5710
5714
  import { createHmac as createHmac2 } from "crypto";
5711
5715
  function resolveSignedUrlSecret() {
5712
- return process.env.SIGNED_URL_SECRET?.trim() || process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || "workhub-dev-signed-url-secret";
5716
+ return process.env.SIGNED_URL_SECRET?.trim() || process.env.SESSION_SECRET?.trim() || process.env.OAUTH_STATE_SECRET?.trim() || appDevSecret("signed-url-secret");
5713
5717
  }
5714
5718
  function resolveSignedUrlOrigin() {
5715
5719
  return (process.env.APP_URL ?? "http://localhost:3000").replace(/\/$/, "");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getstrata/core",
3
- "version": "0.5.79",
3
+ "version": "0.5.80",
4
4
  "description": "Strata — Laravel-inspired Bun framework public API",
5
5
  "type": "module",
6
6
  "license": "MIT",