@getstrata/core 0.5.66 → 0.5.68

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 (43) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +1 -1
  3. package/dist/core/http/corsMiddleware.d.ts +8 -1
  4. package/dist/core/openapi/generator.d.ts +2 -2
  5. package/dist/{config/queue.d.ts → core/queue/queueConfig.d.ts} +2 -1
  6. package/dist/core/runtime/appKeyPrefix.d.ts +5 -1
  7. package/dist/entries/audit/exportAuditLogs.js +50 -39
  8. package/dist/entries/audit/siemFormatter.js +20 -0
  9. package/dist/entries/auth/oauth/providers.js +20 -0
  10. package/dist/entries/auth/oauth/samlProvider.js +20 -0
  11. package/dist/entries/cache/createCacheStore.js +20 -0
  12. package/dist/entries/facades.js +20 -0
  13. package/dist/entries/http/corsMiddleware.js +20 -18
  14. package/dist/entries/http/loginThrottleMiddleware.js +20 -0
  15. package/dist/entries/http/memoryThrottleMiddleware.js +20 -0
  16. package/dist/entries/http/parseMultipartUpload.js +1 -1
  17. package/dist/entries/http/requireAbilityMiddleware.js +4 -1
  18. package/dist/entries/http/response.js +4 -1
  19. package/dist/entries/http/scimThrottleMiddleware.js +20 -0
  20. package/dist/entries/http/securityHeadersMiddleware.js +48 -9
  21. package/dist/entries/http/throttleMiddleware.js +20 -0
  22. package/dist/entries/http/webErrorResponse.js +18 -15
  23. package/dist/entries/jobs/exportAuditLogsJob.js +50 -39
  24. package/dist/entries/mail/mailer.js +20 -0
  25. package/dist/entries/openapi/generator.js +58 -19
  26. package/dist/entries/queue/createAppQueue.js +40 -18
  27. package/dist/entries/queue/jobRunner.js +23 -21
  28. package/dist/entries/queue/publicQueue.js +40 -18
  29. package/dist/entries/queue/queueMetrics.js +43 -21
  30. package/dist/entries/queue/redisQueue.js +40 -18
  31. package/dist/entries/runtime/appKeyPrefix.js +24 -0
  32. package/dist/entries/runtime/frontendMode.js +23 -0
  33. package/dist/entries/security/publicReads.js +1 -22
  34. package/dist/entries/security/safeFetch.js +48 -9
  35. package/dist/entries/tracing/tracingMiddleware.js +20 -0
  36. package/dist/index.js +45 -57
  37. package/package.json +7 -2
  38. package/dist/bootstrap/config.d.ts +0 -15
  39. package/dist/config/app.d.ts +0 -10
  40. package/dist/config/cors.d.ts +0 -9
  41. package/dist/config/features.d.ts +0 -18
  42. /package/dist/{config → core/http}/uploads.d.ts +0 -0
  43. /package/dist/{config/frontend.d.ts → core/runtime/frontendMode.d.ts} +0 -0
@@ -2,21 +2,6 @@
2
2
  // ../../src/core/http/webErrorResponse.ts
3
3
  import { HttpError as HttpError2, UnauthorizedError, ValidationError } from "@getstrata/core/errors/http";
4
4
 
5
- // ../../src/config/frontend.ts
6
- function readFrontendMode() {
7
- const mode = (process.env.FRONTEND_MODE ?? "api").trim();
8
- if (mode === "server-htmx") {
9
- return "server-htmx";
10
- }
11
- if (mode === "spa-react") {
12
- return "spa-react";
13
- }
14
- return "api";
15
- }
16
- function isViewsEnabled() {
17
- return readFrontendMode() === "server-htmx";
18
- }
19
-
20
5
  // ../../src/core/database/errors.ts
21
6
  import {
22
7
  BadRequestError,
@@ -80,6 +65,24 @@ async function withDatabaseErrorHandling(operation) {
80
65
  }
81
66
  }
82
67
 
68
+ // ../../src/core/runtime/frontendMode.ts
69
+ function readFrontendMode() {
70
+ const mode = (process.env.FRONTEND_MODE ?? "api").trim();
71
+ if (mode === "server-htmx") {
72
+ return "server-htmx";
73
+ }
74
+ if (mode === "spa-react") {
75
+ return "spa-react";
76
+ }
77
+ return "api";
78
+ }
79
+ function isViewsEnabled() {
80
+ return readFrontendMode() === "server-htmx";
81
+ }
82
+ function isSpaEnabled() {
83
+ return readFrontendMode() === "spa-react";
84
+ }
85
+
83
86
  // ../../src/core/view/webErrorView.ts
84
87
  import { currentRequestMeta } from "@getstrata/core/http/requestMetaContext";
85
88
 
@@ -2,14 +2,53 @@
2
2
  // ../../src/core/audit/exportAuditLogs.ts
3
3
  import { repositoryConnection as db2 } from "@getstrata/core/database/repositoryConnection";
4
4
 
5
- // ../../src/config/app.ts
6
- var appConfig = {
7
- name: process.env.APP_NAME?.trim() || "WorkHub",
8
- env: process.env.APP_ENV ?? "local",
9
- debug: (process.env.APP_DEBUG ?? "true") !== "false",
10
- url: process.env.APP_URL ?? "http://localhost:3000",
11
- apiPrefix: process.env.API_PREFIX ?? "/api/v1"
12
- };
5
+ // ../../src/core/runtime/appKeyPrefix.ts
6
+ function appKeyPrefix() {
7
+ return process.env.APP_KEY_PREFIX?.trim() || "workhub";
8
+ }
9
+ function namespacedRedisKey(kind) {
10
+ return `${appKeyPrefix()}:${kind}`;
11
+ }
12
+ function smtpEhloHost() {
13
+ const raw = process.env.MAIL_EHLO?.trim() || `${appKeyPrefix()}.local`;
14
+ const safe = raw.replace(/[^a-zA-Z0-9.-]/g, "");
15
+ return safe || "strata.local";
16
+ }
17
+ function siemEventType() {
18
+ return process.env.SIEM_EVENT_TYPE?.trim() || `${appKeyPrefix()}.audit`;
19
+ }
20
+ function appUserAgent() {
21
+ return process.env.APP_USER_AGENT?.trim() || appKeyPrefix();
22
+ }
23
+ function otelServiceName() {
24
+ return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
25
+ }
26
+ function webhookSignatureHeader() {
27
+ return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
28
+ }
29
+ function appDisplayName() {
30
+ return process.env.APP_NAME?.trim() || "WorkHub";
31
+ }
32
+ function appEnv() {
33
+ return process.env.APP_ENV?.trim() || "local";
34
+ }
35
+ function appUrl() {
36
+ return (process.env.APP_URL?.trim() || "http://localhost:3000").replace(/\/$/, "");
37
+ }
38
+ function apiPrefix() {
39
+ const raw = process.env.API_PREFIX?.trim() || "/api/v1";
40
+ const withSlash = raw.startsWith("/") ? raw : `/${raw}`;
41
+ const trimmed = withSlash.replace(/\/+$/, "");
42
+ return trimmed || "/api/v1";
43
+ }
44
+ function sdkClientClassName() {
45
+ const override = process.env.APP_SDK_CLASS?.trim();
46
+ if (override && /^[A-Za-z_][A-Za-z0-9_]*$/.test(override)) {
47
+ return override;
48
+ }
49
+ const fromName = appDisplayName().replace(/[^A-Za-z0-9]/g, "");
50
+ return fromName ? `${fromName}Client` : "AppClient";
51
+ }
13
52
 
14
53
  // ../../src/core/security/safeUrl.ts
15
54
  import { lookup as dnsLookupImpl } from "dns/promises";
@@ -113,7 +152,7 @@ var DEFAULT_FETCH_TIMEOUT_MS = 1e4;
113
152
  async function safeFetch(input, init = {}, options = {}) {
114
153
  const timeoutMs = options.timeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;
115
154
  const maxRedirects = options.maxRedirects ?? 0;
116
- const resolveDns = options.resolveDns ?? appConfig.env === "production";
155
+ const resolveDns = options.resolveDns ?? appEnv() === "production";
117
156
  const urlOptions = { allowHttp: options.allowHttp, resolveDns };
118
157
  const controller = new AbortController;
119
158
  const timeout = setTimeout(() => controller.abort(), timeoutMs);
@@ -153,34 +192,6 @@ async function runWithMigrationBypass(callback) {
153
192
  }
154
193
  }
155
194
 
156
- // ../../src/core/runtime/appKeyPrefix.ts
157
- function appKeyPrefix() {
158
- return process.env.APP_KEY_PREFIX?.trim() || "workhub";
159
- }
160
- function namespacedRedisKey(kind) {
161
- return `${appKeyPrefix()}:${kind}`;
162
- }
163
- function smtpEhloHost() {
164
- const raw = process.env.MAIL_EHLO?.trim() || `${appKeyPrefix()}.local`;
165
- const safe = raw.replace(/[^a-zA-Z0-9.-]/g, "");
166
- return safe || "strata.local";
167
- }
168
- function siemEventType() {
169
- return process.env.SIEM_EVENT_TYPE?.trim() || `${appKeyPrefix()}.audit`;
170
- }
171
- function appUserAgent() {
172
- return process.env.APP_USER_AGENT?.trim() || appKeyPrefix();
173
- }
174
- function otelServiceName() {
175
- return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
176
- }
177
- function webhookSignatureHeader() {
178
- return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
179
- }
180
- function appDisplayName() {
181
- return process.env.APP_NAME?.trim() || "WorkHub";
182
- }
183
-
184
195
  // ../../src/core/audit/siemFormatter.ts
185
196
  function formatSiemAuditEvent(input) {
186
197
  return {
@@ -220,7 +231,7 @@ function resolveAuditExportConfig() {
220
231
  if (!endpoint) {
221
232
  return null;
222
233
  }
223
- assertSafeOutboundUrl(endpoint, { allowHttp: appConfig.env !== "production" });
234
+ assertSafeOutboundUrl(endpoint, { allowHttp: appEnv() !== "production" });
224
235
  const batchSize = Number(process.env.SIEM_EXPORT_BATCH_SIZE ?? "100");
225
236
  return {
226
237
  endpoint,
@@ -278,7 +289,7 @@ async function exportPendingAuditLogs() {
278
289
  ...process.env.SIEM_EXPORT_TOKEN ? { authorization: `Bearer ${process.env.SIEM_EXPORT_TOKEN}` } : {}
279
290
  },
280
291
  body
281
- }, { allowHttp: appConfig.env !== "production" });
292
+ }, { allowHttp: appEnv() !== "production" });
282
293
  if (!response.ok) {
283
294
  throw new Error(`SIEM export failed with status ${response.status}.`);
284
295
  }
@@ -26,6 +26,26 @@ function webhookSignatureHeader() {
26
26
  function appDisplayName() {
27
27
  return process.env.APP_NAME?.trim() || "WorkHub";
28
28
  }
29
+ function appEnv() {
30
+ return process.env.APP_ENV?.trim() || "local";
31
+ }
32
+ function appUrl() {
33
+ return (process.env.APP_URL?.trim() || "http://localhost:3000").replace(/\/$/, "");
34
+ }
35
+ function apiPrefix() {
36
+ const raw = process.env.API_PREFIX?.trim() || "/api/v1";
37
+ const withSlash = raw.startsWith("/") ? raw : `/${raw}`;
38
+ const trimmed = withSlash.replace(/\/+$/, "");
39
+ return trimmed || "/api/v1";
40
+ }
41
+ function sdkClientClassName() {
42
+ const override = process.env.APP_SDK_CLASS?.trim();
43
+ if (override && /^[A-Za-z_][A-Za-z0-9_]*$/.test(override)) {
44
+ return override;
45
+ }
46
+ const fromName = appDisplayName().replace(/[^A-Za-z0-9]/g, "");
47
+ return fromName ? `${fromName}Client` : "AppClient";
48
+ }
29
49
 
30
50
  // ../../src/core/mail/mailer.ts
31
51
  function resolveSmtpConfig() {
@@ -1,12 +1,51 @@
1
1
  // @bun
2
- // ../../src/config/app.ts
3
- var appConfig = {
4
- name: process.env.APP_NAME?.trim() || "WorkHub",
5
- env: process.env.APP_ENV ?? "local",
6
- debug: (process.env.APP_DEBUG ?? "true") !== "false",
7
- url: process.env.APP_URL ?? "http://localhost:3000",
8
- apiPrefix: process.env.API_PREFIX ?? "/api/v1"
9
- };
2
+ // ../../src/core/runtime/appKeyPrefix.ts
3
+ function appKeyPrefix() {
4
+ return process.env.APP_KEY_PREFIX?.trim() || "workhub";
5
+ }
6
+ function namespacedRedisKey(kind) {
7
+ return `${appKeyPrefix()}:${kind}`;
8
+ }
9
+ function smtpEhloHost() {
10
+ const raw = process.env.MAIL_EHLO?.trim() || `${appKeyPrefix()}.local`;
11
+ const safe = raw.replace(/[^a-zA-Z0-9.-]/g, "");
12
+ return safe || "strata.local";
13
+ }
14
+ function siemEventType() {
15
+ return process.env.SIEM_EVENT_TYPE?.trim() || `${appKeyPrefix()}.audit`;
16
+ }
17
+ function appUserAgent() {
18
+ return process.env.APP_USER_AGENT?.trim() || appKeyPrefix();
19
+ }
20
+ function otelServiceName() {
21
+ return process.env.OTEL_SERVICE_NAME?.trim() || `${appKeyPrefix()}-api`;
22
+ }
23
+ function webhookSignatureHeader() {
24
+ return process.env.WEBHOOK_SIGNATURE_HEADER?.trim() || `x-${appKeyPrefix()}-signature`;
25
+ }
26
+ function appDisplayName() {
27
+ return process.env.APP_NAME?.trim() || "WorkHub";
28
+ }
29
+ function appEnv() {
30
+ return process.env.APP_ENV?.trim() || "local";
31
+ }
32
+ function appUrl() {
33
+ return (process.env.APP_URL?.trim() || "http://localhost:3000").replace(/\/$/, "");
34
+ }
35
+ function apiPrefix() {
36
+ const raw = process.env.API_PREFIX?.trim() || "/api/v1";
37
+ const withSlash = raw.startsWith("/") ? raw : `/${raw}`;
38
+ const trimmed = withSlash.replace(/\/+$/, "");
39
+ return trimmed || "/api/v1";
40
+ }
41
+ function sdkClientClassName() {
42
+ const override = process.env.APP_SDK_CLASS?.trim();
43
+ if (override && /^[A-Za-z_][A-Za-z0-9_]*$/.test(override)) {
44
+ return override;
45
+ }
46
+ const fromName = appDisplayName().replace(/[^A-Za-z0-9]/g, "");
47
+ return fromName ? `${fromName}Client` : "AppClient";
48
+ }
10
49
 
11
50
  // ../../src/core/openapi/generator.ts
12
51
  var PUBLIC_ROUTE_DESCRIPTIONS = {
@@ -84,12 +123,12 @@ function generateOpenApiSpec(routes) {
84
123
  return {
85
124
  openapi: "3.1.0",
86
125
  info: {
87
- title: "WorkHub API",
126
+ title: `${appDisplayName()} API`,
88
127
  version: "1.0.0"
89
128
  },
90
129
  servers: [
91
- { url: `${appConfig.url}${appConfig.apiPrefix}`, description: "WorkHub API" },
92
- { url: appConfig.url, description: "Root (health, metrics, SCIM)" }
130
+ { url: `${appUrl()}${apiPrefix()}`, description: `${appDisplayName()} API` },
131
+ { url: appUrl(), description: "Root (health, metrics, SCIM)" }
93
132
  ],
94
133
  paths,
95
134
  components: {
@@ -142,17 +181,17 @@ function renderOpenApiDocument(spec) {
142
181
  return `${JSON.stringify(spec, null, 2)}
143
182
  `;
144
183
  }
145
- function toMethodName(method, path, apiPrefix) {
146
- const relativePath = path.startsWith(apiPrefix) ? path.slice(apiPrefix.length) || "/" : path;
184
+ function toMethodName(method, path, apiPrefix2) {
185
+ const relativePath = path.startsWith(apiPrefix2) ? path.slice(apiPrefix2.length) || "/" : path;
147
186
  const segments = relativePath.replace(/\{|\}/g, "").split("/").filter(Boolean).flatMap((segment) => segment.split("-")).map((segment) => segment.replace(/[^a-zA-Z0-9]/g, "")).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1));
148
187
  return `${method.toLowerCase()}${segments.join("")}`;
149
188
  }
150
- function toRequestPath(path, apiPrefix) {
151
- return path.startsWith(apiPrefix) ? path.slice(apiPrefix.length) || "/" : path;
189
+ function toRequestPath(path, apiPrefix2) {
190
+ return path.startsWith(apiPrefix2) ? path.slice(apiPrefix2.length) || "/" : path;
152
191
  }
153
- function renderTypeScriptSdk(spec, apiPrefix = "/api/v1") {
192
+ function renderTypeScriptSdk(spec, prefix = apiPrefix()) {
154
193
  const lines = [
155
- "export class WorkHubClient {",
194
+ `export class ${sdkClientClassName()} {`,
156
195
  ` constructor(private readonly baseUrl = "${spec.servers[0]?.url ?? ""}") {}`,
157
196
  "",
158
197
  " private async request(path: string, init: RequestInit = {}): Promise<Response> {",
@@ -161,9 +200,9 @@ function renderTypeScriptSdk(spec, apiPrefix = "/api/v1") {
161
200
  ""
162
201
  ];
163
202
  for (const [path, methods] of Object.entries(spec.paths)) {
164
- const requestPath = toRequestPath(path, apiPrefix);
203
+ const requestPath = toRequestPath(path, prefix);
165
204
  for (const method of Object.keys(methods)) {
166
- const functionName = toMethodName(method, path, apiPrefix);
205
+ const functionName = toMethodName(method, path, prefix);
167
206
  lines.push(` async ${functionName}(init: RequestInit = {}): Promise<Response> {`, ` return await this.request("${requestPath}", { ...init, method: "${method.toUpperCase()}" });`, " }", "");
168
207
  }
169
208
  }
@@ -100,25 +100,27 @@ function readSharedJobRegistry() {
100
100
  }
101
101
  var jobRegistry = readSharedJobRegistry();
102
102
 
103
- // ../../src/bootstrap/config.ts
104
- import {
105
- CORE_ABILITY_CHECKER_TOKEN,
106
- CORE_AUTH_TOKEN,
107
- CORE_AUTH_USER_DIRECTORY_TOKEN,
108
- CORE_CACHE_TOKEN,
109
- CORE_CONFIG_TOKEN,
110
- CORE_EVENT_BUS_TOKEN,
111
- CORE_POLICY_GATE_TOKEN,
112
- CORE_QUEUE_TOKEN,
113
- CORE_TOKEN_SERVICE_TOKEN
114
- } from "@getstrata/core/contracts/serviceTokens";
115
- var DEFAULT_QUEUE_DRIVER = "sync";
116
-
117
- // ../../src/config/queue.ts
103
+ // ../../src/core/queue/queueConfig.ts
104
+ function resolveQueueConfig() {
105
+ const driver = process.env.QUEUE_DRIVER;
106
+ const maxAttempts = Number(process.env.QUEUE_MAX_ATTEMPTS ?? "3");
107
+ const backoffMs = Number(process.env.QUEUE_BACKOFF_MS ?? "1000");
108
+ return {
109
+ driver: driver === "redis" || driver === "async" || driver === "sync" ? driver : "sync",
110
+ maxAttempts: Number.isFinite(maxAttempts) && maxAttempts > 0 ? maxAttempts : 3,
111
+ backoffMs: Number.isFinite(backoffMs) && backoffMs >= 0 ? backoffMs : 1000
112
+ };
113
+ }
118
114
  var queueConfig = {
119
- driver: process.env.QUEUE_DRIVER === "redis" || process.env.QUEUE_DRIVER === "async" || process.env.QUEUE_DRIVER === "sync" ? process.env.QUEUE_DRIVER : DEFAULT_QUEUE_DRIVER,
120
- maxAttempts: Number(process.env.QUEUE_MAX_ATTEMPTS ?? "3"),
121
- backoffMs: Number(process.env.QUEUE_BACKOFF_MS ?? "1000")
115
+ get driver() {
116
+ return resolveQueueConfig().driver;
117
+ },
118
+ get maxAttempts() {
119
+ return resolveQueueConfig().maxAttempts;
120
+ },
121
+ get backoffMs() {
122
+ return resolveQueueConfig().backoffMs;
123
+ }
122
124
  };
123
125
 
124
126
  // ../../src/core/queue/jobRunner.ts
@@ -181,6 +183,26 @@ function webhookSignatureHeader() {
181
183
  function appDisplayName() {
182
184
  return process.env.APP_NAME?.trim() || "WorkHub";
183
185
  }
186
+ function appEnv() {
187
+ return process.env.APP_ENV?.trim() || "local";
188
+ }
189
+ function appUrl() {
190
+ return (process.env.APP_URL?.trim() || "http://localhost:3000").replace(/\/$/, "");
191
+ }
192
+ function apiPrefix() {
193
+ const raw = process.env.API_PREFIX?.trim() || "/api/v1";
194
+ const withSlash = raw.startsWith("/") ? raw : `/${raw}`;
195
+ const trimmed = withSlash.replace(/\/+$/, "");
196
+ return trimmed || "/api/v1";
197
+ }
198
+ function sdkClientClassName() {
199
+ const override = process.env.APP_SDK_CLASS?.trim();
200
+ if (override && /^[A-Za-z_][A-Za-z0-9_]*$/.test(override)) {
201
+ return override;
202
+ }
203
+ const fromName = appDisplayName().replace(/[^A-Za-z0-9]/g, "");
204
+ return fromName ? `${fromName}Client` : "AppClient";
205
+ }
184
206
 
185
207
  // ../../src/core/queue/redisQueue.ts
186
208
  function queueListKey() {
@@ -1,25 +1,4 @@
1
1
  // @bun
2
- // ../../src/bootstrap/config.ts
3
- import {
4
- CORE_ABILITY_CHECKER_TOKEN,
5
- CORE_AUTH_TOKEN,
6
- CORE_AUTH_USER_DIRECTORY_TOKEN,
7
- CORE_CACHE_TOKEN,
8
- CORE_CONFIG_TOKEN,
9
- CORE_EVENT_BUS_TOKEN,
10
- CORE_POLICY_GATE_TOKEN,
11
- CORE_QUEUE_TOKEN,
12
- CORE_TOKEN_SERVICE_TOKEN
13
- } from "@getstrata/core/contracts/serviceTokens";
14
- var DEFAULT_QUEUE_DRIVER = "sync";
15
-
16
- // ../../src/config/queue.ts
17
- var queueConfig = {
18
- driver: process.env.QUEUE_DRIVER === "redis" || process.env.QUEUE_DRIVER === "async" || process.env.QUEUE_DRIVER === "sync" ? process.env.QUEUE_DRIVER : DEFAULT_QUEUE_DRIVER,
19
- maxAttempts: Number(process.env.QUEUE_MAX_ATTEMPTS ?? "3"),
20
- backoffMs: Number(process.env.QUEUE_BACKOFF_MS ?? "1000")
21
- };
22
-
23
2
  // ../../src/core/queue/jobRegistry.ts
24
3
  class JobRegistry {
25
4
  factories = new Map;
@@ -57,6 +36,29 @@ function readSharedJobRegistry() {
57
36
  }
58
37
  var jobRegistry = readSharedJobRegistry();
59
38
 
39
+ // ../../src/core/queue/queueConfig.ts
40
+ function resolveQueueConfig() {
41
+ const driver = process.env.QUEUE_DRIVER;
42
+ const maxAttempts = Number(process.env.QUEUE_MAX_ATTEMPTS ?? "3");
43
+ const backoffMs = Number(process.env.QUEUE_BACKOFF_MS ?? "1000");
44
+ return {
45
+ driver: driver === "redis" || driver === "async" || driver === "sync" ? driver : "sync",
46
+ maxAttempts: Number.isFinite(maxAttempts) && maxAttempts > 0 ? maxAttempts : 3,
47
+ backoffMs: Number.isFinite(backoffMs) && backoffMs >= 0 ? backoffMs : 1000
48
+ };
49
+ }
50
+ var queueConfig = {
51
+ get driver() {
52
+ return resolveQueueConfig().driver;
53
+ },
54
+ get maxAttempts() {
55
+ return resolveQueueConfig().maxAttempts;
56
+ },
57
+ get backoffMs() {
58
+ return resolveQueueConfig().backoffMs;
59
+ }
60
+ };
61
+
60
62
  // ../../src/core/queue/jobRunner.ts
61
63
  async function runQueueJob(envelope, failedJobs) {
62
64
  const job = jobRegistry.create(envelope.name);
@@ -100,25 +100,27 @@ function readSharedJobRegistry() {
100
100
  }
101
101
  var jobRegistry = readSharedJobRegistry();
102
102
 
103
- // ../../src/bootstrap/config.ts
104
- import {
105
- CORE_ABILITY_CHECKER_TOKEN,
106
- CORE_AUTH_TOKEN,
107
- CORE_AUTH_USER_DIRECTORY_TOKEN,
108
- CORE_CACHE_TOKEN,
109
- CORE_CONFIG_TOKEN,
110
- CORE_EVENT_BUS_TOKEN,
111
- CORE_POLICY_GATE_TOKEN,
112
- CORE_QUEUE_TOKEN,
113
- CORE_TOKEN_SERVICE_TOKEN
114
- } from "@getstrata/core/contracts/serviceTokens";
115
- var DEFAULT_QUEUE_DRIVER = "sync";
116
-
117
- // ../../src/config/queue.ts
103
+ // ../../src/core/queue/queueConfig.ts
104
+ function resolveQueueConfig() {
105
+ const driver = process.env.QUEUE_DRIVER;
106
+ const maxAttempts = Number(process.env.QUEUE_MAX_ATTEMPTS ?? "3");
107
+ const backoffMs = Number(process.env.QUEUE_BACKOFF_MS ?? "1000");
108
+ return {
109
+ driver: driver === "redis" || driver === "async" || driver === "sync" ? driver : "sync",
110
+ maxAttempts: Number.isFinite(maxAttempts) && maxAttempts > 0 ? maxAttempts : 3,
111
+ backoffMs: Number.isFinite(backoffMs) && backoffMs >= 0 ? backoffMs : 1000
112
+ };
113
+ }
118
114
  var queueConfig = {
119
- driver: process.env.QUEUE_DRIVER === "redis" || process.env.QUEUE_DRIVER === "async" || process.env.QUEUE_DRIVER === "sync" ? process.env.QUEUE_DRIVER : DEFAULT_QUEUE_DRIVER,
120
- maxAttempts: Number(process.env.QUEUE_MAX_ATTEMPTS ?? "3"),
121
- backoffMs: Number(process.env.QUEUE_BACKOFF_MS ?? "1000")
115
+ get driver() {
116
+ return resolveQueueConfig().driver;
117
+ },
118
+ get maxAttempts() {
119
+ return resolveQueueConfig().maxAttempts;
120
+ },
121
+ get backoffMs() {
122
+ return resolveQueueConfig().backoffMs;
123
+ }
122
124
  };
123
125
 
124
126
  // ../../src/core/queue/jobRunner.ts
@@ -181,6 +183,26 @@ function webhookSignatureHeader() {
181
183
  function appDisplayName() {
182
184
  return process.env.APP_NAME?.trim() || "WorkHub";
183
185
  }
186
+ function appEnv() {
187
+ return process.env.APP_ENV?.trim() || "local";
188
+ }
189
+ function appUrl() {
190
+ return (process.env.APP_URL?.trim() || "http://localhost:3000").replace(/\/$/, "");
191
+ }
192
+ function apiPrefix() {
193
+ const raw = process.env.API_PREFIX?.trim() || "/api/v1";
194
+ const withSlash = raw.startsWith("/") ? raw : `/${raw}`;
195
+ const trimmed = withSlash.replace(/\/+$/, "");
196
+ return trimmed || "/api/v1";
197
+ }
198
+ function sdkClientClassName() {
199
+ const override = process.env.APP_SDK_CLASS?.trim();
200
+ if (override && /^[A-Za-z_][A-Za-z0-9_]*$/.test(override)) {
201
+ return override;
202
+ }
203
+ const fromName = appDisplayName().replace(/[^A-Za-z0-9]/g, "");
204
+ return fromName ? `${fromName}Client` : "AppClient";
205
+ }
184
206
 
185
207
  // ../../src/core/queue/redisQueue.ts
186
208
  function queueListKey() {
@@ -2,27 +2,6 @@
2
2
  // ../../src/core/queue/queueMetrics.ts
3
3
  var {RedisClient: RedisClient2 } = globalThis.Bun;
4
4
 
5
- // ../../src/bootstrap/config.ts
6
- import {
7
- CORE_ABILITY_CHECKER_TOKEN,
8
- CORE_AUTH_TOKEN,
9
- CORE_AUTH_USER_DIRECTORY_TOKEN,
10
- CORE_CACHE_TOKEN,
11
- CORE_CONFIG_TOKEN,
12
- CORE_EVENT_BUS_TOKEN,
13
- CORE_POLICY_GATE_TOKEN,
14
- CORE_QUEUE_TOKEN,
15
- CORE_TOKEN_SERVICE_TOKEN
16
- } from "@getstrata/core/contracts/serviceTokens";
17
- var DEFAULT_QUEUE_DRIVER = "sync";
18
-
19
- // ../../src/config/queue.ts
20
- var queueConfig = {
21
- driver: process.env.QUEUE_DRIVER === "redis" || process.env.QUEUE_DRIVER === "async" || process.env.QUEUE_DRIVER === "sync" ? process.env.QUEUE_DRIVER : DEFAULT_QUEUE_DRIVER,
22
- maxAttempts: Number(process.env.QUEUE_MAX_ATTEMPTS ?? "3"),
23
- backoffMs: Number(process.env.QUEUE_BACKOFF_MS ?? "1000")
24
- };
25
-
26
5
  // ../../src/core/queue/failedJobRepository.ts
27
6
  import { BaseRepository } from "@getstrata/core/database/baseRepository";
28
7
 
@@ -124,6 +103,29 @@ function readSharedJobRegistry() {
124
103
  }
125
104
  var jobRegistry = readSharedJobRegistry();
126
105
 
106
+ // ../../src/core/queue/queueConfig.ts
107
+ function resolveQueueConfig() {
108
+ const driver = process.env.QUEUE_DRIVER;
109
+ const maxAttempts = Number(process.env.QUEUE_MAX_ATTEMPTS ?? "3");
110
+ const backoffMs = Number(process.env.QUEUE_BACKOFF_MS ?? "1000");
111
+ return {
112
+ driver: driver === "redis" || driver === "async" || driver === "sync" ? driver : "sync",
113
+ maxAttempts: Number.isFinite(maxAttempts) && maxAttempts > 0 ? maxAttempts : 3,
114
+ backoffMs: Number.isFinite(backoffMs) && backoffMs >= 0 ? backoffMs : 1000
115
+ };
116
+ }
117
+ var queueConfig = {
118
+ get driver() {
119
+ return resolveQueueConfig().driver;
120
+ },
121
+ get maxAttempts() {
122
+ return resolveQueueConfig().maxAttempts;
123
+ },
124
+ get backoffMs() {
125
+ return resolveQueueConfig().backoffMs;
126
+ }
127
+ };
128
+
127
129
  // ../../src/core/queue/jobRunner.ts
128
130
  async function runQueueJob(envelope, failedJobs) {
129
131
  const job = jobRegistry.create(envelope.name);
@@ -184,6 +186,26 @@ function webhookSignatureHeader() {
184
186
  function appDisplayName() {
185
187
  return process.env.APP_NAME?.trim() || "WorkHub";
186
188
  }
189
+ function appEnv() {
190
+ return process.env.APP_ENV?.trim() || "local";
191
+ }
192
+ function appUrl() {
193
+ return (process.env.APP_URL?.trim() || "http://localhost:3000").replace(/\/$/, "");
194
+ }
195
+ function apiPrefix() {
196
+ const raw = process.env.API_PREFIX?.trim() || "/api/v1";
197
+ const withSlash = raw.startsWith("/") ? raw : `/${raw}`;
198
+ const trimmed = withSlash.replace(/\/+$/, "");
199
+ return trimmed || "/api/v1";
200
+ }
201
+ function sdkClientClassName() {
202
+ const override = process.env.APP_SDK_CLASS?.trim();
203
+ if (override && /^[A-Za-z_][A-Za-z0-9_]*$/.test(override)) {
204
+ return override;
205
+ }
206
+ const fromName = appDisplayName().replace(/[^A-Za-z0-9]/g, "");
207
+ return fromName ? `${fromName}Client` : "AppClient";
208
+ }
187
209
 
188
210
  // ../../src/core/queue/redisQueue.ts
189
211
  function queueListKey() {
@@ -29,6 +29,26 @@ function webhookSignatureHeader() {
29
29
  function appDisplayName() {
30
30
  return process.env.APP_NAME?.trim() || "WorkHub";
31
31
  }
32
+ function appEnv() {
33
+ return process.env.APP_ENV?.trim() || "local";
34
+ }
35
+ function appUrl() {
36
+ return (process.env.APP_URL?.trim() || "http://localhost:3000").replace(/\/$/, "");
37
+ }
38
+ function apiPrefix() {
39
+ const raw = process.env.API_PREFIX?.trim() || "/api/v1";
40
+ const withSlash = raw.startsWith("/") ? raw : `/${raw}`;
41
+ const trimmed = withSlash.replace(/\/+$/, "");
42
+ return trimmed || "/api/v1";
43
+ }
44
+ function sdkClientClassName() {
45
+ const override = process.env.APP_SDK_CLASS?.trim();
46
+ if (override && /^[A-Za-z_][A-Za-z0-9_]*$/.test(override)) {
47
+ return override;
48
+ }
49
+ const fromName = appDisplayName().replace(/[^A-Za-z0-9]/g, "");
50
+ return fromName ? `${fromName}Client` : "AppClient";
51
+ }
32
52
 
33
53
  // ../../src/core/queue/jobRegistry.ts
34
54
  class JobRegistry {
@@ -67,25 +87,27 @@ function readSharedJobRegistry() {
67
87
  }
68
88
  var jobRegistry = readSharedJobRegistry();
69
89
 
70
- // ../../src/bootstrap/config.ts
71
- import {
72
- CORE_ABILITY_CHECKER_TOKEN,
73
- CORE_AUTH_TOKEN,
74
- CORE_AUTH_USER_DIRECTORY_TOKEN,
75
- CORE_CACHE_TOKEN,
76
- CORE_CONFIG_TOKEN,
77
- CORE_EVENT_BUS_TOKEN,
78
- CORE_POLICY_GATE_TOKEN,
79
- CORE_QUEUE_TOKEN,
80
- CORE_TOKEN_SERVICE_TOKEN
81
- } from "@getstrata/core/contracts/serviceTokens";
82
- var DEFAULT_QUEUE_DRIVER = "sync";
83
-
84
- // ../../src/config/queue.ts
90
+ // ../../src/core/queue/queueConfig.ts
91
+ function resolveQueueConfig() {
92
+ const driver = process.env.QUEUE_DRIVER;
93
+ const maxAttempts = Number(process.env.QUEUE_MAX_ATTEMPTS ?? "3");
94
+ const backoffMs = Number(process.env.QUEUE_BACKOFF_MS ?? "1000");
95
+ return {
96
+ driver: driver === "redis" || driver === "async" || driver === "sync" ? driver : "sync",
97
+ maxAttempts: Number.isFinite(maxAttempts) && maxAttempts > 0 ? maxAttempts : 3,
98
+ backoffMs: Number.isFinite(backoffMs) && backoffMs >= 0 ? backoffMs : 1000
99
+ };
100
+ }
85
101
  var queueConfig = {
86
- driver: process.env.QUEUE_DRIVER === "redis" || process.env.QUEUE_DRIVER === "async" || process.env.QUEUE_DRIVER === "sync" ? process.env.QUEUE_DRIVER : DEFAULT_QUEUE_DRIVER,
87
- maxAttempts: Number(process.env.QUEUE_MAX_ATTEMPTS ?? "3"),
88
- backoffMs: Number(process.env.QUEUE_BACKOFF_MS ?? "1000")
102
+ get driver() {
103
+ return resolveQueueConfig().driver;
104
+ },
105
+ get maxAttempts() {
106
+ return resolveQueueConfig().maxAttempts;
107
+ },
108
+ get backoffMs() {
109
+ return resolveQueueConfig().backoffMs;
110
+ }
89
111
  };
90
112
 
91
113
  // ../../src/core/queue/jobRunner.ts