@getstrata/bootstrap 0.2.22 → 0.2.25

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 (239) hide show
  1. package/dist/bootstrap/applicationRegistry.d.ts +1 -1
  2. package/dist/bootstrap/buildModuleRoutes.d.ts +10 -0
  3. package/dist/bootstrap/buildWebModuleRoutes.d.ts +9 -0
  4. package/dist/bootstrap/config.d.ts +1 -1
  5. package/dist/bootstrap/contracts.d.ts +4 -4
  6. package/dist/bootstrap/env.d.ts +1 -1
  7. package/dist/bootstrap/membershipService.d.ts +1 -1
  8. package/dist/bootstrap/public-api.d.ts +6 -2
  9. package/dist/bootstrap/routeRegistry.d.ts +1 -1
  10. package/dist/entries/applicationRegistry.js +12 -115
  11. package/dist/entries/buildModuleRoutes.js +411 -0
  12. package/dist/entries/buildWebModuleRoutes.js +435 -0
  13. package/dist/entries/config.js +9 -9
  14. package/dist/entries/context.js +112 -192
  15. package/dist/entries/contracts.js +10 -85
  16. package/dist/entries/createWebRoutes.js +100 -682
  17. package/dist/entries/dependencies.js +112 -192
  18. package/dist/entries/http/securedRouteModelBinding.js +0 -37
  19. package/dist/entries/httpKernel.js +9 -9
  20. package/dist/entries/membershipService.js +2 -426
  21. package/dist/entries/providers/view.js +9 -20
  22. package/dist/entries/providers.js +102 -129
  23. package/dist/entries/queue/defaultJobs.js +0 -37
  24. package/dist/entries/web/routing.js +16 -44
  25. package/dist/index.js +507 -730
  26. package/package.json +14 -4
  27. package/dist/cli/commands/scheduleRun.d.ts +0 -3
  28. package/dist/config/app.d.ts +0 -10
  29. package/dist/config/auth.d.ts +0 -7
  30. package/dist/config/contentSecurityPolicy.d.ts +0 -5
  31. package/dist/config/cors.d.ts +0 -9
  32. package/dist/config/database.d.ts +0 -10
  33. package/dist/config/features.d.ts +0 -18
  34. package/dist/config/frontend.d.ts +0 -6
  35. package/dist/config/queue.d.ts +0 -8
  36. package/dist/config/rateLimit.d.ts +0 -10
  37. package/dist/config/uploads.d.ts +0 -5
  38. package/dist/core/admin/formatValue.d.ts +0 -3
  39. package/dist/core/admin/index.d.ts +0 -3
  40. package/dist/core/admin/registry.d.ts +0 -11
  41. package/dist/core/admin/types.d.ts +0 -24
  42. package/dist/core/audit/exportAuditLogs.d.ts +0 -8
  43. package/dist/core/audit/siemFormatter.d.ts +0 -30
  44. package/dist/core/auth/abilityChecker.d.ts +0 -6
  45. package/dist/core/auth/accessControl.d.ts +0 -8
  46. package/dist/core/auth/authContext.d.ts +0 -11
  47. package/dist/core/auth/guard.d.ts +0 -36
  48. package/dist/core/auth/membershipContext.d.ts +0 -15
  49. package/dist/core/auth/membershipContextMiddleware.d.ts +0 -3
  50. package/dist/core/auth/membershipMiddleware.d.ts +0 -2
  51. package/dist/core/auth/membershipScope.d.ts +0 -16
  52. package/dist/core/auth/membershipService.d.ts +0 -23
  53. package/dist/core/auth/oauth/oidcProvider.d.ts +0 -18
  54. package/dist/core/auth/oauth/providers.d.ts +0 -22
  55. package/dist/core/auth/oauth/samlProvider.d.ts +0 -9
  56. package/dist/core/auth/oauth/types.d.ts +0 -11
  57. package/dist/core/auth/password.d.ts +0 -3
  58. package/dist/core/auth/policy.d.ts +0 -15
  59. package/dist/core/auth/resolveMembershipService.d.ts +0 -3
  60. package/dist/core/auth/scimAuthMiddleware.d.ts +0 -3
  61. package/dist/core/auth/sessionCookie.d.ts +0 -6
  62. package/dist/core/auth/sessionGuard.d.ts +0 -9
  63. package/dist/core/auth/tokenHash.d.ts +0 -3
  64. package/dist/core/cache/createCacheStore.d.ts +0 -11
  65. package/dist/core/cache/redisCacheStore.d.ts +0 -23
  66. package/dist/core/cache/repository.d.ts +0 -17
  67. package/dist/core/cache/simpleCache.d.ts +0 -23
  68. package/dist/core/cache/simpleCacheStore.d.ts +0 -16
  69. package/dist/core/cache/store.d.ts +0 -12
  70. package/dist/core/cache/taggedCache.d.ts +0 -9
  71. package/dist/core/cache/tags.d.ts +0 -11
  72. package/dist/core/config/envSchema.d.ts +0 -12
  73. package/dist/core/contracts/container.d.ts +0 -30
  74. package/dist/core/contracts/di.d.ts +0 -31
  75. package/dist/core/contracts/serviceContainer.d.ts +0 -1
  76. package/dist/core/contracts/serviceTokens.d.ts +0 -8
  77. package/dist/core/crypto/fieldEncryption.d.ts +0 -13
  78. package/dist/core/crypto/mfaSecret.d.ts +0 -3
  79. package/dist/core/crypto/nonCryptographicHash.d.ts +0 -2
  80. package/dist/core/database/baseRepository.d.ts +0 -67
  81. package/dist/core/database/bindConnection.d.ts +0 -3
  82. package/dist/core/database/boundConnection.d.ts +0 -5
  83. package/dist/core/database/connection.d.ts +0 -7
  84. package/dist/core/database/connectionContext.d.ts +0 -8
  85. package/dist/core/database/defaultConnection.d.ts +0 -6
  86. package/dist/core/database/errors.d.ts +0 -12
  87. package/dist/core/database/index.d.ts +0 -18
  88. package/dist/core/database/migrations/advisoryLock.d.ts +0 -6
  89. package/dist/core/database/migrations/runner.d.ts +0 -25
  90. package/dist/core/database/migrations/types.d.ts +0 -15
  91. package/dist/core/database/model.d.ts +0 -57
  92. package/dist/core/database/query.d.ts +0 -63
  93. package/dist/core/database/queryProxy.d.ts +0 -3
  94. package/dist/core/database/relationships.d.ts +0 -100
  95. package/dist/core/database/repositoryConnection.d.ts +0 -4
  96. package/dist/core/database/repositoryQuery.d.ts +0 -38
  97. package/dist/core/database/schema/blueprint.d.ts +0 -47
  98. package/dist/core/database/schema/columnDefinition.d.ts +0 -36
  99. package/dist/core/database/schema/driver.d.ts +0 -8
  100. package/dist/core/database/schema/errors.d.ts +0 -4
  101. package/dist/core/database/schema/grammars/compileStatements.d.ts +0 -8
  102. package/dist/core/database/schema/grammars/createGrammar.d.ts +0 -4
  103. package/dist/core/database/schema/grammars/grammar.d.ts +0 -10
  104. package/dist/core/database/schema/grammars/index.d.ts +0 -7
  105. package/dist/core/database/schema/grammars/mysqlGrammar.d.ts +0 -2
  106. package/dist/core/database/schema/grammars/postgresGrammar.d.ts +0 -2
  107. package/dist/core/database/schema/grammars/sqliteGrammar.d.ts +0 -2
  108. package/dist/core/database/schema/index.d.ts +0 -12
  109. package/dist/core/database/schema/schema.d.ts +0 -21
  110. package/dist/core/database/seeders/runner.d.ts +0 -6
  111. package/dist/core/database/seeders/types.d.ts +0 -8
  112. package/dist/core/database/table.d.ts +0 -13
  113. package/dist/core/database/transaction.d.ts +0 -3
  114. package/dist/core/database/types.d.ts +0 -66
  115. package/dist/core/database/whereBuilder.d.ts +0 -17
  116. package/dist/core/errors/http.d.ts +0 -33
  117. package/dist/core/events/eventBus.d.ts +0 -10
  118. package/dist/core/events/index.d.ts +0 -4
  119. package/dist/core/facades/index.d.ts +0 -10
  120. package/dist/core/http/authMiddleware.d.ts +0 -5
  121. package/dist/core/http/authorizeMiddleware.d.ts +0 -5
  122. package/dist/core/http/bodySizeLimitMiddleware.d.ts +0 -4
  123. package/dist/core/http/conditionalResponse.d.ts +0 -2
  124. package/dist/core/http/contentNegotiation.d.ts +0 -2
  125. package/dist/core/http/cookies.d.ts +0 -4
  126. package/dist/core/http/corsMiddleware.d.ts +0 -3
  127. package/dist/core/http/csrfMiddleware.d.ts +0 -3
  128. package/dist/core/http/csrfProtection.d.ts +0 -12
  129. package/dist/core/http/csrfToken.d.ts +0 -14
  130. package/dist/core/http/etag.d.ts +0 -18
  131. package/dist/core/http/flashMiddleware.d.ts +0 -3
  132. package/dist/core/http/flashSession.d.ts +0 -12
  133. package/dist/core/http/formRequest.d.ts +0 -10
  134. package/dist/core/http/index.d.ts +0 -27
  135. package/dist/core/http/loginThrottleMiddleware.d.ts +0 -11
  136. package/dist/core/http/memoryThrottleMiddleware.d.ts +0 -9
  137. package/dist/core/http/metricsMiddleware.d.ts +0 -4
  138. package/dist/core/http/middleware.d.ts +0 -8
  139. package/dist/core/http/pagination.d.ts +0 -11
  140. package/dist/core/http/parseFormBody.d.ts +0 -6
  141. package/dist/core/http/parseMultipartUpload.d.ts +0 -10
  142. package/dist/core/http/requestMetaContext.d.ts +0 -15
  143. package/dist/core/http/requireAbilityMiddleware.d.ts +0 -4
  144. package/dist/core/http/requireAuthMiddleware.d.ts +0 -4
  145. package/dist/core/http/requireGlobalAdminMiddleware.d.ts +0 -3
  146. package/dist/core/http/requireWebAuthMiddleware.d.ts +0 -4
  147. package/dist/core/http/resources.d.ts +0 -7
  148. package/dist/core/http/route.d.ts +0 -6
  149. package/dist/core/http/routeMiddleware.d.ts +0 -3
  150. package/dist/core/http/routeModelBinding.d.ts +0 -3
  151. package/dist/core/http/scimThrottleMiddleware.d.ts +0 -9
  152. package/dist/core/http/securedRouteModelBinding.d.ts +0 -11
  153. package/dist/core/http/securityHeadersMiddleware.d.ts +0 -3
  154. package/dist/core/http/throttleMiddleware.d.ts +0 -11
  155. package/dist/core/http/validation.d.ts +0 -23
  156. package/dist/core/http/webErrorResponse.d.ts +0 -5
  157. package/dist/core/http/webFormRequest.d.ts +0 -7
  158. package/dist/core/jobs/dispatchWebhookJob.d.ts +0 -13
  159. package/dist/core/jobs/invalidateCacheTagsJob.d.ts +0 -12
  160. package/dist/core/lifecycle/gracefulShutdown.d.ts +0 -6
  161. package/dist/core/logging/logger.d.ts +0 -17
  162. package/dist/core/logging/requestLoggingMiddleware.d.ts +0 -3
  163. package/dist/core/mail/mailer.d.ts +0 -38
  164. package/dist/core/mail/markdownMail.d.ts +0 -15
  165. package/dist/core/mail/markdownMailable.d.ts +0 -12
  166. package/dist/core/metrics/prometheus.d.ts +0 -26
  167. package/dist/core/notifications/dispatcher.d.ts +0 -13
  168. package/dist/core/notifications/index.d.ts +0 -3
  169. package/dist/core/notifications/notification.d.ts +0 -7
  170. package/dist/core/notifications/types.d.ts +0 -25
  171. package/dist/core/openapi/registeredRoute.d.ts +0 -6
  172. package/dist/core/pagination/index.d.ts +0 -27
  173. package/dist/core/queue/createAppQueue.d.ts +0 -5
  174. package/dist/core/queue/failedJobRepository.d.ts +0 -6
  175. package/dist/core/queue/failedJobService.d.ts +0 -16
  176. package/dist/core/queue/failedJobTable.d.ts +0 -3
  177. package/dist/core/queue/index.d.ts +0 -19
  178. package/dist/core/queue/jobRegistry.d.ts +0 -13
  179. package/dist/core/queue/jobRunner.d.ts +0 -9
  180. package/dist/core/queue/publicQueue.d.ts +0 -16
  181. package/dist/core/queue/queueMetrics.d.ts +0 -15
  182. package/dist/core/queue/redisQueue.d.ts +0 -29
  183. package/dist/core/queue/resilientQueue.d.ts +0 -9
  184. package/dist/core/queue/types.d.ts +0 -8
  185. package/dist/core/runtime/applicationRegistry.d.ts +0 -17
  186. package/dist/core/runtime/asyncContextStore.d.ts +0 -3
  187. package/dist/core/scheduler/schedule.d.ts +0 -15
  188. package/dist/core/security/publicReads.d.ts +0 -3
  189. package/dist/core/security/safeFetch.d.ts +0 -10
  190. package/dist/core/security/safeUrl.d.ts +0 -20
  191. package/dist/core/security/scimTenantTokens.d.ts +0 -3
  192. package/dist/core/security/securityEvents.d.ts +0 -6
  193. package/dist/core/security/timingSafeCompare.d.ts +0 -2
  194. package/dist/core/security/tokenExpiry.d.ts +0 -2
  195. package/dist/core/security/totp.d.ts +0 -3
  196. package/dist/core/storage/storage.d.ts +0 -44
  197. package/dist/core/tenant/databaseTenantContext.d.ts +0 -2
  198. package/dist/core/tenant/resolveTenant.d.ts +0 -3
  199. package/dist/core/tenant/tenantContext.d.ts +0 -13
  200. package/dist/core/tenant/tenantDatabaseScope.d.ts +0 -8
  201. package/dist/core/tenant/tenantMiddleware.d.ts +0 -6
  202. package/dist/core/tracing/otel.d.ts +0 -26
  203. package/dist/core/tracing/traceContext.d.ts +0 -9
  204. package/dist/core/tracing/tracingMiddleware.d.ts +0 -3
  205. package/dist/core/validation/rules.d.ts +0 -17
  206. package/dist/core/view/etaViewEngine.d.ts +0 -15
  207. package/dist/core/view/htmlResponse.d.ts +0 -6
  208. package/dist/core/view/index.d.ts +0 -5
  209. package/dist/core/view/viewEngine.d.ts +0 -6
  210. package/dist/core/view/webLayoutData.d.ts +0 -17
  211. package/dist/db/connection/createConnection.d.ts +0 -6
  212. package/dist/db/connection/index.d.ts +0 -11
  213. package/dist/domain/abilities.d.ts +0 -5
  214. package/dist/domain/auth.d.ts +0 -4
  215. package/dist/domain/scim.d.ts +0 -9
  216. package/dist/domain/workhub.d.ts +0 -35
  217. package/dist/framework/public-api.d.ts +0 -116
  218. package/dist/modules/organization/memberRepository.d.ts +0 -14
  219. package/dist/modules/organization/memberTypes.d.ts +0 -9
  220. package/dist/modules/organization/repository.d.ts +0 -14
  221. package/dist/modules/organization/table.d.ts +0 -3
  222. package/dist/modules/organization/types.d.ts +0 -10
  223. package/dist/modules/scim/controller.d.ts +0 -16
  224. package/dist/modules/scim/scimResponse.d.ts +0 -10
  225. package/dist/modules/scim/service.d.ts +0 -214
  226. package/dist/modules/user/apiTokenRepository.d.ts +0 -8
  227. package/dist/modules/user/apiTokenTable.d.ts +0 -3
  228. package/dist/modules/user/authService.d.ts +0 -23
  229. package/dist/modules/user/notificationRepository.d.ts +0 -6
  230. package/dist/modules/user/notificationService.d.ts +0 -25
  231. package/dist/modules/user/notificationTable.d.ts +0 -3
  232. package/dist/modules/user/notificationTypes.d.ts +0 -12
  233. package/dist/modules/user/oauthIdentityRepository.d.ts +0 -9
  234. package/dist/modules/user/provider.d.ts +0 -11
  235. package/dist/modules/user/repository.d.ts +0 -13
  236. package/dist/modules/user/table.d.ts +0 -3
  237. package/dist/modules/user/tokenService.d.ts +0 -29
  238. package/dist/modules/user/types.d.ts +0 -46
  239. package/dist/types/services.d.ts +0 -16
package/dist/index.js CHANGED
@@ -1,4 +1,7 @@
1
1
  // @bun
2
+ // ../../src/bootstrap/public-api.ts
3
+ import { appSchedule as appSchedule2, runDueScheduledTasks as runDueScheduledTasks2, Schedule as Schedule2 } from "@getstrata/core/scheduler/schedule";
4
+
2
5
  // ../../src/core/scheduler/schedule.ts
3
6
  class Schedule {
4
7
  tasks = [];
@@ -503,157 +506,107 @@ async function scheduleRunCommand() {
503
506
  }
504
507
  await runDueScheduledTasks(appSchedule);
505
508
  }
506
- // ../../src/core/contracts/di.ts
507
- var requiredDependencyKeys = [
508
- "container",
509
- "cache",
510
- "storage"
511
- ];
512
- function getRequiredDependency(dependencies, key) {
513
- const dependency = dependencies[key];
514
- if (dependency === undefined) {
515
- throw new Error(`Required dependency "${key}" is not registered.`);
516
- }
517
- return dependency;
518
- }
519
- function assertAppDependenciesComplete(dependencies) {
520
- for (const key of requiredDependencyKeys) {
521
- getRequiredDependency(dependencies, key);
522
- }
523
- }
524
- function resolveService(dependencies, token) {
525
- return dependencies.container.resolve(token);
526
- }
509
+ // ../../src/bootstrap/applicationRegistry.ts
510
+ import {
511
+ resolveApplicationAuth,
512
+ resolveApplicationCache,
513
+ resolveApplicationConfig,
514
+ resolveApplicationDependencies,
515
+ resolveApplicationEventBus,
516
+ resolveApplicationLogger,
517
+ resolveApplicationPolicyGate,
518
+ resolveApplicationQueue,
519
+ setActiveApplicationContext
520
+ } from "@getstrata/core/runtime/applicationRegistry.ts";
521
+ // ../../src/bootstrap/buildModuleRoutes.ts
522
+ import { conditionalJsonResponse } from "@getstrata/core/http";
523
+ import { applyMiddlewareToRoutes } from "@getstrata/core/http/middleware";
527
524
 
528
- // ../../src/core/contracts/serviceTokens.ts
529
- var CORE_CONFIG_TOKEN = "core.config";
530
- var CORE_CACHE_TOKEN = "core.cache";
531
- var CORE_QUEUE_TOKEN = "core.queue";
532
- var CORE_EVENT_BUS_TOKEN = "core.eventBus";
533
- var CORE_POLICY_GATE_TOKEN = "core.policyGate";
534
- var CORE_AUTH_TOKEN = "core.auth";
535
- var CORE_TOKEN_SERVICE_TOKEN = "core.tokenService";
525
+ // ../../src/bootstrap/httpKernel.ts
526
+ import {
527
+ createAuthMiddleware,
528
+ createAuthorizeMiddleware,
529
+ createBodySizeLimitMiddleware,
530
+ createCorsMiddleware,
531
+ createCsrfMiddleware,
532
+ createFlashMiddleware,
533
+ createLoginThrottleMiddleware,
534
+ createMembershipMiddleware,
535
+ createMemoryThrottleMiddleware,
536
+ createMetricsMiddleware,
537
+ createRequestLoggingMiddleware,
538
+ createRequireAbilityMiddleware,
539
+ createRequireAuthMiddleware,
540
+ createRequireGlobalAdminMiddleware,
541
+ createRequireWebAuthMiddleware,
542
+ createSecurityHeadersMiddleware,
543
+ createTenantMiddleware,
544
+ createThrottleMiddleware,
545
+ createTracingMiddleware,
546
+ isPublicReadsEnabled,
547
+ requestIdMiddleware,
548
+ withMiddleware
549
+ } from "@getstrata/core";
536
550
 
537
- // ../../src/core/runtime/applicationRegistry.ts
538
- var APPLICATION_CONTEXT_KEY = Symbol.for("@getstrata/applicationContext");
539
- var activeContext;
540
- function readStoredApplicationContext() {
541
- if (activeContext) {
542
- return activeContext;
543
- }
544
- const globalContext = globalThis[APPLICATION_CONTEXT_KEY];
545
- if (globalContext) {
546
- activeContext = globalContext;
547
- }
548
- return activeContext;
549
- }
550
- function setActiveApplicationContext(context) {
551
- activeContext = context;
552
- globalThis[APPLICATION_CONTEXT_KEY] = context;
553
- }
554
- function requireActiveApplicationContext() {
555
- const context = readStoredApplicationContext();
556
- if (!context) {
557
- throw new Error("The application context has not been bootstrapped.");
551
+ // ../../src/config/frontend.ts
552
+ function readFrontendMode() {
553
+ const mode = (process.env.FRONTEND_MODE ?? "api").trim();
554
+ if (mode === "server-htmx") {
555
+ return "server-htmx";
558
556
  }
559
- return context;
560
- }
561
- function resolveApplicationCache() {
562
- return getRequiredDependency(requireActiveApplicationContext().dependencies, "cache");
563
- }
564
- function resolveApplicationQueue() {
565
- return requireActiveApplicationContext().container.resolve(CORE_QUEUE_TOKEN);
566
- }
567
- function resolveApplicationEventBus() {
568
- return requireActiveApplicationContext().container.resolve(CORE_EVENT_BUS_TOKEN);
569
- }
570
- function resolveApplicationAuth() {
571
- return requireActiveApplicationContext().container.resolve(CORE_AUTH_TOKEN);
572
- }
573
- function resolveApplicationPolicyGate() {
574
- return requireActiveApplicationContext().container.resolve(CORE_POLICY_GATE_TOKEN);
575
- }
576
- function resolveApplicationConfig() {
577
- return requireActiveApplicationContext().config;
578
- }
579
- function resolveApplicationLogger() {
580
- return appLogger;
581
- }
582
- function resolveApplicationDependencies() {
583
- return requireActiveApplicationContext().dependencies;
584
- }
585
- // ../../src/bootstrap/discoverModules.ts
586
- import { readdirSync } from "fs";
587
- import { join } from "path";
588
- import { pathToFileURL } from "url";
589
- var DISCOVER_MODULES_STATE_KEY = Symbol.for("@getstrata/discoverModulesState");
590
- function readDiscoverModulesState() {
591
- const existing = globalThis[DISCOVER_MODULES_STATE_KEY];
592
- if (existing) {
593
- return existing;
557
+ if (mode === "spa-react") {
558
+ return "spa-react";
594
559
  }
595
- const state = { appModules: [] };
596
- globalThis[DISCOVER_MODULES_STATE_KEY] = state;
597
- return state;
560
+ return "api";
598
561
  }
599
- function configureModulesDirectory(modulesDir) {
600
- readDiscoverModulesState().configuredModulesDir = modulesDir;
562
+ function isViewsEnabled() {
563
+ return readFrontendMode() === "server-htmx";
601
564
  }
602
- function resolveModulesDirectory(options) {
603
- const state = readDiscoverModulesState();
604
- if (options?.modulesDir) {
605
- return options.modulesDir;
606
- }
607
- if (state.configuredModulesDir) {
608
- return state.configuredModulesDir;
609
- }
610
- return join(import.meta.dir, "../modules");
565
+
566
+ // ../../src/config/rateLimit.ts
567
+ var LOCAL_LOGIN_RATE_LIMIT = {
568
+ maxAttempts: 100,
569
+ decaySeconds: 60
570
+ };
571
+ var PRODUCTION_LOGIN_RATE_LIMIT = {
572
+ maxAttempts: 5,
573
+ decaySeconds: 900
574
+ };
575
+ function isLocalAppEnv() {
576
+ return (process.env.APP_ENV ?? "local") === "local";
611
577
  }
612
- async function loadDiscoveredModules(options) {
613
- const modulesDirectory = resolveModulesDirectory(options);
614
- let moduleNames;
615
- try {
616
- moduleNames = readdirSync(modulesDirectory, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
617
- } catch (error) {
618
- if (error.code === "ENOENT") {
619
- return [];
620
- }
621
- throw error;
578
+ function parsePositiveInt(value, fallback) {
579
+ const parsed = Number(value);
580
+ if (!Number.isFinite(parsed) || parsed <= 0) {
581
+ return fallback;
622
582
  }
623
- const modules = await Promise.all(moduleNames.map(async (moduleName) => {
624
- const moduleUrl = pathToFileURL(join(modulesDirectory, moduleName, "index.ts")).href;
625
- const loaded = await import(moduleUrl);
626
- return loaded.default;
627
- }));
628
- return modules.filter((module) => module?.name !== undefined).sort((left, right) => (left.order ?? 100) - (right.order ?? 100));
583
+ return Math.trunc(parsed);
629
584
  }
630
- async function ensureModulesLoaded(options) {
631
- const state = readDiscoverModulesState();
632
- if (state.appModules.length > 0) {
633
- return state.appModules;
634
- }
635
- state.modulesReady ??= loadDiscoveredModules(options).then((modules) => {
636
- state.appModules.splice(0, state.appModules.length, ...modules);
637
- return state.appModules;
638
- });
639
- return state.modulesReady;
585
+ function resolveLoginRateLimit() {
586
+ const defaults = isLocalAppEnv() ? LOCAL_LOGIN_RATE_LIMIT : PRODUCTION_LOGIN_RATE_LIMIT;
587
+ return {
588
+ maxAttempts: parsePositiveInt(process.env.LOGIN_RATE_LIMIT_PER_WINDOW, defaults.maxAttempts),
589
+ decaySeconds: parsePositiveInt(process.env.LOGIN_RATE_LIMIT_WINDOW_SECONDS, defaults.decaySeconds)
590
+ };
640
591
  }
641
- function discoverModules() {
642
- return readDiscoverModulesState().appModules;
592
+ function resolveRegisterRateLimit() {
593
+ const defaults = isLocalAppEnv() ? { maxAttempts: 100, decaySeconds: 60 } : { maxAttempts: 10, decaySeconds: 60 };
594
+ return {
595
+ maxAttempts: parsePositiveInt(process.env.REGISTER_RATE_LIMIT_PER_WINDOW, defaults.maxAttempts),
596
+ decaySeconds: parsePositiveInt(process.env.REGISTER_RATE_LIMIT_WINDOW_SECONDS ?? process.env.REGISTER_RATE_LIMIT_WINDOW_MS ? String(Number(process.env.REGISTER_RATE_LIMIT_WINDOW_MS) / 1000) : undefined, defaults.decaySeconds)
597
+ };
643
598
  }
644
599
 
645
- // ../../src/bootstrap/cache/modelCacheTags.ts
646
- function cacheTagsForModelWrite(tableName, action) {
647
- const module = discoverModules().find((entry) => entry.tableName === tableName);
648
- const baseTags = module?.cacheTags ?? [`${tableName}s`];
649
- const isDelete = action === "deleted" || action === "force-deleted";
650
- const extraTags = isDelete ? module?.cacheDeleteExtraTags ?? [] : [];
651
- return [...new Set([...baseTags, ...extraTags])];
652
- }
653
- function discoverModelTableNames() {
654
- return discoverModules().map((module) => module.tableName).filter((tableName) => tableName !== undefined);
655
- }
656
600
  // ../../src/bootstrap/config.ts
601
+ import {
602
+ CORE_AUTH_TOKEN,
603
+ CORE_CACHE_TOKEN,
604
+ CORE_CONFIG_TOKEN,
605
+ CORE_EVENT_BUS_TOKEN,
606
+ CORE_POLICY_GATE_TOKEN,
607
+ CORE_QUEUE_TOKEN,
608
+ CORE_TOKEN_SERVICE_TOKEN
609
+ } from "@getstrata/core/contracts/serviceTokens.ts";
657
610
  var APP_PORT_CONFIG_KEY = "app.port";
658
611
  var CACHE_TTL_MS_CONFIG_KEY = "cache.ttlMs";
659
612
  var CACHE_MAX_ENTRIES_CONFIG_KEY = "cache.maxEntries";
@@ -666,70 +619,354 @@ var DEFAULT_CACHE_MAX_ENTRIES = 100;
666
619
  var DEFAULT_CACHE_DRIVER = "array";
667
620
  var DEFAULT_API_TOKEN = "";
668
621
  var DEFAULT_QUEUE_DRIVER = "sync";
669
- // ../../src/core/contracts/container.ts
670
- class ServiceContainer {
671
- services = new Map;
672
- singletonFactories = new Map;
673
- bindings = new Map;
674
- set(key, value) {
675
- this.singletonFactories.delete(key);
676
- this.bindings.delete(key);
677
- this.services.set(key, value);
678
- return value;
679
- }
680
- singleton(key, factory) {
681
- this.bindings.delete(key);
682
- this.services.delete(key);
683
- this.singletonFactories.set(key, factory);
622
+
623
+ // ../../src/bootstrap/httpKernel.ts
624
+ class HttpKernel {
625
+ dependencies;
626
+ constructor(dependencies) {
627
+ this.dependencies = dependencies;
684
628
  }
685
- bind(key, factory) {
686
- this.singletonFactories.delete(key);
687
- this.services.delete(key);
688
- this.bindings.set(key, factory);
629
+ globalMiddleware() {
630
+ const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
631
+ return [
632
+ createCorsMiddleware(),
633
+ createSecurityHeadersMiddleware(),
634
+ createBodySizeLimitMiddleware(),
635
+ createTracingMiddleware(),
636
+ createMetricsMiddleware(),
637
+ createRequestLoggingMiddleware(),
638
+ requestIdMiddleware,
639
+ createAuthMiddleware(auth),
640
+ createMembershipMiddleware(),
641
+ createTenantMiddleware()
642
+ ];
689
643
  }
690
- get(key) {
691
- if (this.services.has(key)) {
692
- return this.services.get(key);
693
- }
694
- const singletonFactory = this.singletonFactories.get(key);
695
- if (singletonFactory) {
696
- const value = singletonFactory(this);
697
- this.services.set(key, value);
698
- return value;
699
- }
700
- const binding = this.bindings.get(key);
701
- if (binding) {
702
- return binding(this);
644
+ group(name) {
645
+ const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
646
+ switch (name) {
647
+ case "authenticated":
648
+ return [createRequireAuthMiddleware(auth)];
649
+ case "web":
650
+ return isViewsEnabled() ? [createFlashMiddleware(), createCsrfMiddleware()] : [];
651
+ case "api": {
652
+ if (!this.dependencies.container.has(CORE_CONFIG_TOKEN)) {
653
+ return [];
654
+ }
655
+ const config = this.dependencies.container.resolve(CORE_CONFIG_TOKEN);
656
+ const redisUrl = config.get(REDIS_URL_CONFIG_KEY)?.trim() ?? "";
657
+ if (!redisUrl) {
658
+ const maxAttempts2 = Number(process.env.RATE_LIMIT_PER_MINUTE ?? "120");
659
+ return [
660
+ createMemoryThrottleMiddleware({
661
+ maxAttempts: Number.isFinite(maxAttempts2) ? maxAttempts2 : 120,
662
+ decaySeconds: 60
663
+ })
664
+ ];
665
+ }
666
+ const maxAttempts = Number(process.env.RATE_LIMIT_PER_MINUTE ?? "120");
667
+ return [
668
+ createThrottleMiddleware({
669
+ redisUrl,
670
+ maxAttempts: Number.isFinite(maxAttempts) ? maxAttempts : 120,
671
+ decaySeconds: 60
672
+ })
673
+ ];
674
+ }
675
+ default:
676
+ throw new Error(`Unknown middleware group "${name}".`);
703
677
  }
704
- throw new Error(`Service "${key}" is not registered.`);
705
678
  }
706
- resolve(key) {
707
- return this.get(key);
679
+ wrap(groups, handler) {
680
+ const names = Array.isArray(groups) ? groups : [groups];
681
+ const middleware = names.flatMap((name) => this.group(name));
682
+ if (middleware.length === 0) {
683
+ return handler;
684
+ }
685
+ return withMiddleware(...middleware)(handler);
708
686
  }
709
- has(key) {
710
- return this.services.has(key) || this.singletonFactories.has(key) || this.bindings.has(key);
687
+ wrapApi(handler) {
688
+ return this.wrap(["api", "authenticated"], handler);
711
689
  }
712
- }
713
-
714
- class ConfigStore {
715
- values = new Map;
716
- set(key, value) {
717
- this.values.set(key, value);
718
- return value;
690
+ wrapWeb(handler) {
691
+ return handler;
719
692
  }
720
- get(key) {
721
- return this.values.get(key);
693
+ wrapWebPublicRead(handler) {
694
+ if (isPublicReadsEnabled()) {
695
+ return this.wrapWeb(handler);
696
+ }
697
+ return this.wrapWebAuthenticated(handler);
698
+ }
699
+ wrapWebAuthenticated(handler) {
700
+ const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
701
+ return withMiddleware(createRequireWebAuthMiddleware(auth))(handler);
702
+ }
703
+ wrapWebAbility(ability, handler) {
704
+ const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
705
+ const abilityChecker = this.dependencies.container.resolve(CORE_TOKEN_SERVICE_TOKEN);
706
+ const requireAbility = createRequireAbilityMiddleware(abilityChecker);
707
+ const middleware = [createRequireWebAuthMiddleware(auth), requireAbility(ability)];
708
+ return withMiddleware(...middleware)(handler);
709
+ }
710
+ wrapWebGlobalAdmin(handler) {
711
+ const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
712
+ const middleware = [createRequireWebAuthMiddleware(auth), createRequireGlobalAdminMiddleware()];
713
+ return withMiddleware(...middleware)(handler);
714
+ }
715
+ wrapAuthenticated(handler) {
716
+ return this.wrap("authenticated", handler);
717
+ }
718
+ wrapPublicRead(handler) {
719
+ if (isPublicReadsEnabled()) {
720
+ return handler;
721
+ }
722
+ return this.wrapAuthenticated(handler);
723
+ }
724
+ wrapGlobalAdmin(handler) {
725
+ const middleware = [...this.group("authenticated"), createRequireGlobalAdminMiddleware()];
726
+ return withMiddleware(...middleware)(handler);
727
+ }
728
+ wrapAbility(ability, handler) {
729
+ const abilityChecker = this.dependencies.container.resolve(CORE_TOKEN_SERVICE_TOKEN);
730
+ const requireAbility = createRequireAbilityMiddleware(abilityChecker);
731
+ const middleware = [...this.group("authenticated"), requireAbility(ability)];
732
+ return withMiddleware(...middleware)(handler);
733
+ }
734
+ wrapPolicy(resource, action, handler) {
735
+ const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
736
+ const gate = this.dependencies.container.resolve(CORE_POLICY_GATE_TOKEN);
737
+ return withMiddleware(createAuthorizeMiddleware(gate, auth, resource, action))(handler);
738
+ }
739
+ wrapLogin(handler) {
740
+ return this.wrapThrottle("login", resolveLoginRateLimit(), handler);
741
+ }
742
+ wrapRegister(handler) {
743
+ return this.wrapThrottle("register", resolveRegisterRateLimit(), handler);
744
+ }
745
+ wrapThrottle(scope, rateLimit, handler) {
746
+ const middleware = [];
747
+ const memoryKeyPrefix = scope === "login" ? "login-throttle:" : "register-throttle:";
748
+ if (this.dependencies.container.has(CORE_CONFIG_TOKEN)) {
749
+ const config = this.dependencies.container.resolve(CORE_CONFIG_TOKEN);
750
+ const redisUrl = config.get(REDIS_URL_CONFIG_KEY)?.trim() ?? "";
751
+ if (redisUrl) {
752
+ const throttle = scope === "login" ? createLoginThrottleMiddleware({
753
+ redisUrl,
754
+ maxAttempts: rateLimit.maxAttempts,
755
+ decaySeconds: rateLimit.decaySeconds
756
+ }) : createThrottleMiddleware({
757
+ redisUrl,
758
+ maxAttempts: rateLimit.maxAttempts,
759
+ decaySeconds: rateLimit.decaySeconds,
760
+ keyPrefix: memoryKeyPrefix
761
+ });
762
+ middleware.push(throttle);
763
+ } else {
764
+ middleware.push(createMemoryThrottleMiddleware({
765
+ maxAttempts: rateLimit.maxAttempts,
766
+ decaySeconds: rateLimit.decaySeconds,
767
+ keyPrefix: memoryKeyPrefix
768
+ }));
769
+ }
770
+ } else {
771
+ middleware.push(createMemoryThrottleMiddleware({
772
+ maxAttempts: rateLimit.maxAttempts,
773
+ decaySeconds: rateLimit.decaySeconds,
774
+ keyPrefix: memoryKeyPrefix
775
+ }));
776
+ }
777
+ if (middleware.length === 0) {
778
+ return handler;
779
+ }
780
+ return withMiddleware(...middleware)(handler);
781
+ }
782
+ }
783
+ function createHttpKernel(dependencies) {
784
+ return new HttpKernel(dependencies);
785
+ }
786
+
787
+ // ../../src/bootstrap/discoverModules.ts
788
+ import { readdirSync } from "fs";
789
+ import { join } from "path";
790
+ import { pathToFileURL } from "url";
791
+ var DISCOVER_MODULES_STATE_KEY = Symbol.for("@getstrata/discoverModulesState");
792
+ function readDiscoverModulesState() {
793
+ const existing = globalThis[DISCOVER_MODULES_STATE_KEY];
794
+ if (existing) {
795
+ return existing;
796
+ }
797
+ const state = { appModules: [] };
798
+ globalThis[DISCOVER_MODULES_STATE_KEY] = state;
799
+ return state;
800
+ }
801
+ function configureModulesDirectory(modulesDir) {
802
+ readDiscoverModulesState().configuredModulesDir = modulesDir;
803
+ }
804
+ function resolveModulesDirectory(options) {
805
+ const state = readDiscoverModulesState();
806
+ if (options?.modulesDir) {
807
+ return options.modulesDir;
808
+ }
809
+ if (state.configuredModulesDir) {
810
+ return state.configuredModulesDir;
811
+ }
812
+ return join(import.meta.dir, "../modules");
813
+ }
814
+ async function loadDiscoveredModules(options) {
815
+ const modulesDirectory = resolveModulesDirectory(options);
816
+ let moduleNames;
817
+ try {
818
+ moduleNames = readdirSync(modulesDirectory, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
819
+ } catch (error) {
820
+ if (error.code === "ENOENT") {
821
+ return [];
822
+ }
823
+ throw error;
824
+ }
825
+ const modules = await Promise.all(moduleNames.map(async (moduleName) => {
826
+ const moduleUrl = pathToFileURL(join(modulesDirectory, moduleName, "index.ts")).href;
827
+ const loaded = await import(moduleUrl);
828
+ return loaded.default;
829
+ }));
830
+ return modules.filter((module) => module?.name !== undefined).sort((left, right) => (left.order ?? 100) - (right.order ?? 100));
831
+ }
832
+ async function ensureModulesLoaded(options) {
833
+ const state = readDiscoverModulesState();
834
+ if (state.appModules.length > 0) {
835
+ return state.appModules;
836
+ }
837
+ state.modulesReady ??= loadDiscoveredModules(options).then((modules) => {
838
+ state.appModules.splice(0, state.appModules.length, ...modules);
839
+ return state.appModules;
840
+ });
841
+ return state.modulesReady;
842
+ }
843
+ function discoverModules() {
844
+ return readDiscoverModulesState().appModules;
845
+ }
846
+ // ../../src/bootstrap/prefixRouteMap.ts
847
+ function prefixRouteMap(prefix, routes) {
848
+ const normalizedPrefix = prefix.replace(/\/$/, "");
849
+ const prefixed = {};
850
+ for (const [path, handler] of Object.entries(routes)) {
851
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
852
+ prefixed[`${normalizedPrefix}${normalizedPath}`] = handler;
853
+ }
854
+ return prefixed;
855
+ }
856
+
857
+ // ../../src/bootstrap/routeRegistry.ts
858
+ class RouteRegistry {
859
+ routes = [];
860
+ register(route) {
861
+ this.routes.push(route);
862
+ }
863
+ clear() {
864
+ this.routes.length = 0;
865
+ }
866
+ list() {
867
+ return [...this.routes].sort((left, right) => left.path.localeCompare(right.path));
868
+ }
869
+ }
870
+ var ROUTE_REGISTRY_KEY = Symbol.for("@getstrata/routeRegistry");
871
+ function readSharedRouteRegistry() {
872
+ const globalRegistry = globalThis[ROUTE_REGISTRY_KEY];
873
+ if (globalRegistry) {
874
+ return globalRegistry;
875
+ }
876
+ const registry = new RouteRegistry;
877
+ globalThis[ROUTE_REGISTRY_KEY] = registry;
878
+ return registry;
879
+ }
880
+ var routeRegistry = readSharedRouteRegistry();
881
+
882
+ // ../../src/bootstrap/buildModuleRoutes.ts
883
+ function registerOpenApiRoute(method, path, middleware) {
884
+ routeRegistry.register({ method, path, middleware });
885
+ }
886
+ function registerOpenApiRouteMap(routes, middleware) {
887
+ const registered = {};
888
+ for (const [path, handler] of Object.entries(routes)) {
889
+ if (handler && typeof handler === "object" && !Array.isArray(handler)) {
890
+ const methodMap = handler;
891
+ registered[path] = methodMap;
892
+ for (const method of Object.keys(methodMap)) {
893
+ registerOpenApiRoute(method.toUpperCase(), path, middleware);
894
+ }
895
+ continue;
896
+ }
897
+ registered[path] = handler;
898
+ registerOpenApiRoute("GET", path, middleware);
899
+ }
900
+ return registered;
901
+ }
902
+ function createCachedJson(dependencies) {
903
+ return async (cacheKey, loader, tags = [], request) => {
904
+ const data = tags.length > 0 ? await dependencies.cache.tags(...tags).remember(cacheKey, loader) : await dependencies.cache.remember(cacheKey, loader);
905
+ return conditionalJsonResponse(request, data);
906
+ };
907
+ }
908
+ function buildModuleRoutes(dependencies, options = {}) {
909
+ const { apiPrefix = "", modules = discoverModules(), clearRegistry = true } = options;
910
+ if (clearRegistry) {
911
+ routeRegistry.clear();
722
912
  }
723
- require(key) {
724
- if (!this.values.has(key)) {
725
- throw new Error(`Config key "${key}" is not defined.`);
913
+ const kernel = createHttpKernel(dependencies);
914
+ const middleware = [...kernel.globalMiddleware(), ...kernel.group("api")];
915
+ const cachedJson = createCachedJson(dependencies);
916
+ const moduleRoutes = {};
917
+ for (const module of modules) {
918
+ if (!module.routes) {
919
+ continue;
726
920
  }
727
- return this.values.get(key);
921
+ Object.assign(moduleRoutes, module.routes({ dependencies, cachedJson, kernel }));
922
+ }
923
+ const prefixedModuleRoutes = prefixRouteMap(apiPrefix, moduleRoutes);
924
+ return applyMiddlewareToRoutes(registerOpenApiRouteMap(prefixedModuleRoutes, ["global", "api"]), middleware);
925
+ }
926
+ // ../../src/bootstrap/buildWebModuleRoutes.ts
927
+ import { applyMiddlewareToRoutes as applyMiddlewareToRoutes2 } from "@getstrata/core/http/middleware";
928
+ function buildWebModuleRoutes(dependencies, options = {}) {
929
+ const { modules = discoverModules(), clearRegistry = true, seedRoutes = {} } = options;
930
+ if (clearRegistry) {
931
+ routeRegistry.clear();
728
932
  }
729
- has(key) {
730
- return this.values.has(key);
933
+ const kernel = createHttpKernel(dependencies);
934
+ const middleware = [...kernel.globalMiddleware(), ...kernel.group("web")];
935
+ const moduleRoutes = { ...seedRoutes };
936
+ for (const module of modules) {
937
+ if (!module.webRoutes) {
938
+ continue;
939
+ }
940
+ Object.assign(moduleRoutes, module.webRoutes({
941
+ dependencies,
942
+ cachedJson: async () => new Response(""),
943
+ kernel
944
+ }));
731
945
  }
946
+ return applyMiddlewareToRoutes2(registerOpenApiRouteMap(moduleRoutes, ["global", "web"]), middleware);
947
+ }
948
+ // ../../src/bootstrap/cache/modelCacheTags.ts
949
+ function cacheTagsForModelWrite(tableName, action) {
950
+ const module = discoverModules().find((entry) => entry.tableName === tableName);
951
+ const baseTags = module?.cacheTags ?? [`${tableName}s`];
952
+ const isDelete = action === "deleted" || action === "force-deleted";
953
+ const extraTags = isDelete ? module?.cacheDeleteExtraTags ?? [] : [];
954
+ return [...new Set([...baseTags, ...extraTags])];
732
955
  }
956
+ function discoverModelTableNames() {
957
+ return discoverModules().map((module) => module.tableName).filter((tableName) => tableName !== undefined);
958
+ }
959
+ // ../../src/bootstrap/contracts.ts
960
+ import {
961
+ ConfigStore,
962
+ ServiceContainer
963
+ } from "@getstrata/core/contracts/container";
964
+ import {
965
+ assertAppDependenciesComplete,
966
+ getRequiredDependency,
967
+ resolveService
968
+ } from "@getstrata/core/contracts/di";
969
+
733
970
  // ../../src/config/auth.ts
734
971
  var authConfig = {
735
972
  allowDevHeaders: (process.env.AUTH_DEV_HEADERS ?? "true") !== "false",
@@ -835,7 +1072,6 @@ var db = new Proxy(function database() {}, {
835
1072
  return typeof value === "function" ? value.bind(connection) : value;
836
1073
  }
837
1074
  });
838
- var connection_default = db;
839
1075
 
840
1076
  // ../../src/modules/user/apiTokenTable.ts
841
1077
  import { defineTable } from "@getstrata/core/database";
@@ -1667,9 +1903,6 @@ var queueConfig = {
1667
1903
  };
1668
1904
 
1669
1905
  // ../../src/core/config/envSchema.ts
1670
- function defineEnvSchema(schema) {
1671
- return schema;
1672
- }
1673
1906
  function validateEnv(schema, env = process.env) {
1674
1907
  const resolved = {};
1675
1908
  for (const [name, rule] of Object.entries(schema)) {
@@ -1698,6 +1931,7 @@ function validateEnv(schema, env = process.env) {
1698
1931
  }
1699
1932
 
1700
1933
  // ../../src/bootstrap/env.ts
1934
+ import { defineEnvSchema } from "@getstrata/core/config/envSchema";
1701
1935
  var appEnvSchema = defineEnvSchema({
1702
1936
  DATABASE_URL: { required: true, pattern: /^postgres(ql)?:\/\// },
1703
1937
  PORT: {
@@ -3947,22 +4181,65 @@ class DispatchWebhookJob extends Job {
3947
4181
  }
3948
4182
  var dispatchWebhookJob_default = DispatchWebhookJob;
3949
4183
 
3950
- // ../../src/bootstrap/queue/defaultJobs.ts
3951
- function registerDefaultJobs() {
3952
- jobRegistry.register("cache.invalidate-tags", () => {
3953
- return new invalidateCacheTagsJob_default(resolveApplicationCache());
3954
- });
3955
- jobRegistry.register("webhook.dispatch", () => new dispatchWebhookJob_default);
4184
+ // ../../src/core/contracts/di.ts
4185
+ function getRequiredDependency2(dependencies, key) {
4186
+ const dependency = dependencies[key];
4187
+ if (dependency === undefined) {
4188
+ throw new Error(`Required dependency "${key}" is not registered.`);
4189
+ }
4190
+ return dependency;
3956
4191
  }
3957
4192
 
3958
- // ../../src/bootstrap/providers/queue.ts
3959
- var queueProvider = {
3960
- name: "core.queue",
3961
- register({ container, config }) {
3962
- const configuredDriver = process.env.QUEUE_DRIVER ?? DEFAULT_QUEUE_DRIVER;
3963
- const driver = configuredDriver === "async" || configuredDriver === "redis" || configuredDriver === "sync" ? configuredDriver : DEFAULT_QUEUE_DRIVER;
3964
- config.set("queue.driver", driver);
3965
- const failedJobs = createFailedJobService();
4193
+ // ../../src/core/contracts/serviceTokens.ts
4194
+ var CORE_POLICY_GATE_TOKEN2 = "core.policyGate";
4195
+ var CORE_AUTH_TOKEN2 = "core.auth";
4196
+
4197
+ // ../../src/core/runtime/applicationRegistry.ts
4198
+ var APPLICATION_CONTEXT_KEY = Symbol.for("@getstrata/applicationContext");
4199
+ var activeContext;
4200
+ function readStoredApplicationContext() {
4201
+ if (activeContext) {
4202
+ return activeContext;
4203
+ }
4204
+ const globalContext = globalThis[APPLICATION_CONTEXT_KEY];
4205
+ if (globalContext) {
4206
+ activeContext = globalContext;
4207
+ }
4208
+ return activeContext;
4209
+ }
4210
+ function requireActiveApplicationContext() {
4211
+ const context = readStoredApplicationContext();
4212
+ if (!context) {
4213
+ throw new Error("The application context has not been bootstrapped.");
4214
+ }
4215
+ return context;
4216
+ }
4217
+ function resolveApplicationCache2() {
4218
+ return getRequiredDependency2(requireActiveApplicationContext().dependencies, "cache");
4219
+ }
4220
+ function resolveApplicationAuth2() {
4221
+ return requireActiveApplicationContext().container.resolve(CORE_AUTH_TOKEN2);
4222
+ }
4223
+ function resolveApplicationPolicyGate2() {
4224
+ return requireActiveApplicationContext().container.resolve(CORE_POLICY_GATE_TOKEN2);
4225
+ }
4226
+
4227
+ // ../../src/bootstrap/queue/defaultJobs.ts
4228
+ function registerDefaultJobs() {
4229
+ jobRegistry.register("cache.invalidate-tags", () => {
4230
+ return new invalidateCacheTagsJob_default(resolveApplicationCache2());
4231
+ });
4232
+ jobRegistry.register("webhook.dispatch", () => new dispatchWebhookJob_default);
4233
+ }
4234
+
4235
+ // ../../src/bootstrap/providers/queue.ts
4236
+ var queueProvider = {
4237
+ name: "core.queue",
4238
+ register({ container, config }) {
4239
+ const configuredDriver = process.env.QUEUE_DRIVER ?? DEFAULT_QUEUE_DRIVER;
4240
+ const driver = configuredDriver === "async" || configuredDriver === "redis" || configuredDriver === "sync" ? configuredDriver : DEFAULT_QUEUE_DRIVER;
4241
+ config.set("queue.driver", driver);
4242
+ const failedJobs = createFailedJobService();
3966
4243
  container.set(FAILED_JOB_SERVICE_TOKEN, failedJobs);
3967
4244
  container.set(CORE_QUEUE_TOKEN, createAppQueue(driver, config.get(REDIS_URL_CONFIG_KEY) ?? process.env.REDIS_URL, failedJobs, registerDefaultJobs));
3968
4245
  }
@@ -4091,21 +4368,6 @@ var storageProvider = {
4091
4368
  };
4092
4369
  var storage_default = storageProvider;
4093
4370
 
4094
- // ../../src/config/frontend.ts
4095
- function readFrontendMode() {
4096
- const mode = (process.env.FRONTEND_MODE ?? "api").trim();
4097
- if (mode === "server-htmx") {
4098
- return "server-htmx";
4099
- }
4100
- if (mode === "spa-react") {
4101
- return "spa-react";
4102
- }
4103
- return "api";
4104
- }
4105
- function isViewsEnabled() {
4106
- return readFrontendMode() === "server-htmx";
4107
- }
4108
-
4109
4371
  // ../../src/core/http/requestMetaContext.ts
4110
4372
  var requestMetaContext = createAsyncContextStore("@getstrata/requestMetaContext");
4111
4373
  function currentRequestMeta() {
@@ -4147,16 +4409,6 @@ class EtaViewEngine {
4147
4409
  });
4148
4410
  }
4149
4411
  }
4150
- // ../../src/core/view/htmlResponse.ts
4151
- function htmlResponse(html, init = {}) {
4152
- return new Response(html, {
4153
- status: init.status ?? 200,
4154
- statusText: init.statusText,
4155
- headers: {
4156
- "Content-Type": "text/html; charset=utf-8"
4157
- }
4158
- });
4159
- }
4160
4412
  // ../../src/core/http/cookies.ts
4161
4413
  function readRequestCookie(request, name) {
4162
4414
  const cookies = request.cookies;
@@ -4445,352 +4697,25 @@ function createAppContext() {
4445
4697
  }
4446
4698
  // ../../src/bootstrap/createWebRoutes.ts
4447
4699
  import { join as join5 } from "path";
4448
-
4449
- // ../../src/core/http/middleware.ts
4450
- function isRouteHandler(value) {
4451
- return typeof value === "function";
4452
- }
4453
- function isMethodRouteMap(value) {
4454
- if (value === null || typeof value !== "object" || Array.isArray(value)) {
4455
- return false;
4456
- }
4457
- const entries = Object.entries(value);
4458
- return entries.length > 0 && entries.every(([, handler]) => isRouteHandler(handler));
4459
- }
4460
- function composeMiddleware(...middleware) {
4461
- return (handler) => {
4462
- return async (request) => {
4463
- let index = 0;
4464
- const dispatch = async () => {
4465
- if (index >= middleware.length) {
4466
- return await handler(request);
4467
- }
4468
- const current = middleware[index];
4469
- index += 1;
4470
- if (!current) {
4471
- return await handler(request);
4472
- }
4473
- return await current(request, dispatch);
4474
- };
4475
- return await dispatch();
4476
- };
4477
- };
4478
- }
4479
- function wrapRouteHandler(handler, middleware) {
4480
- if (isMethodRouteMap(handler)) {
4481
- const wrapped = {};
4482
- for (const [method, routeHandler] of Object.entries(handler)) {
4483
- wrapped[method] = composeMiddleware(...middleware)(routeHandler);
4484
- }
4485
- return wrapped;
4486
- }
4487
- if (isRouteHandler(handler)) {
4488
- return composeMiddleware(...middleware)(handler);
4489
- }
4490
- return handler;
4491
- }
4492
- function applyMiddlewareToRoutes(routes, middleware) {
4493
- const wrapped = {};
4494
- for (const [path, routeHandler] of Object.entries(routes)) {
4495
- wrapped[path] = wrapRouteHandler(routeHandler, middleware);
4496
- }
4497
- return wrapped;
4498
- }
4499
-
4500
- // ../../src/bootstrap/httpKernel.ts
4501
- import {
4502
- createAuthMiddleware,
4503
- createAuthorizeMiddleware,
4504
- createBodySizeLimitMiddleware,
4505
- createCorsMiddleware,
4506
- createCsrfMiddleware,
4507
- createFlashMiddleware,
4508
- createLoginThrottleMiddleware,
4509
- createMembershipMiddleware,
4510
- createMemoryThrottleMiddleware,
4511
- createMetricsMiddleware,
4512
- createRequestLoggingMiddleware,
4513
- createRequireAbilityMiddleware,
4514
- createRequireAuthMiddleware,
4515
- createRequireGlobalAdminMiddleware,
4516
- createRequireWebAuthMiddleware,
4517
- createSecurityHeadersMiddleware,
4518
- createTenantMiddleware,
4519
- createThrottleMiddleware,
4520
- createTracingMiddleware,
4521
- isPublicReadsEnabled,
4522
- requestIdMiddleware,
4523
- withMiddleware
4524
- } from "@getstrata/core";
4525
-
4526
- // ../../src/config/rateLimit.ts
4527
- var LOCAL_LOGIN_RATE_LIMIT = {
4528
- maxAttempts: 100,
4529
- decaySeconds: 60
4530
- };
4531
- var PRODUCTION_LOGIN_RATE_LIMIT = {
4532
- maxAttempts: 5,
4533
- decaySeconds: 900
4534
- };
4535
- function isLocalAppEnv() {
4536
- return (process.env.APP_ENV ?? "local") === "local";
4537
- }
4538
- function parsePositiveInt(value, fallback) {
4539
- const parsed = Number(value);
4540
- if (!Number.isFinite(parsed) || parsed <= 0) {
4541
- return fallback;
4542
- }
4543
- return Math.trunc(parsed);
4544
- }
4545
- function resolveLoginRateLimit() {
4546
- const defaults = isLocalAppEnv() ? LOCAL_LOGIN_RATE_LIMIT : PRODUCTION_LOGIN_RATE_LIMIT;
4547
- return {
4548
- maxAttempts: parsePositiveInt(process.env.LOGIN_RATE_LIMIT_PER_WINDOW, defaults.maxAttempts),
4549
- decaySeconds: parsePositiveInt(process.env.LOGIN_RATE_LIMIT_WINDOW_SECONDS, defaults.decaySeconds)
4550
- };
4551
- }
4552
- function resolveRegisterRateLimit() {
4553
- const defaults = isLocalAppEnv() ? { maxAttempts: 100, decaySeconds: 60 } : { maxAttempts: 10, decaySeconds: 60 };
4554
- return {
4555
- maxAttempts: parsePositiveInt(process.env.REGISTER_RATE_LIMIT_PER_WINDOW, defaults.maxAttempts),
4556
- decaySeconds: parsePositiveInt(process.env.REGISTER_RATE_LIMIT_WINDOW_SECONDS ?? process.env.REGISTER_RATE_LIMIT_WINDOW_MS ? String(Number(process.env.REGISTER_RATE_LIMIT_WINDOW_MS) / 1000) : undefined, defaults.decaySeconds)
4557
- };
4558
- }
4559
-
4560
- // ../../src/bootstrap/httpKernel.ts
4561
- class HttpKernel {
4562
- dependencies;
4563
- constructor(dependencies) {
4564
- this.dependencies = dependencies;
4565
- }
4566
- globalMiddleware() {
4567
- const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
4568
- return [
4569
- createCorsMiddleware(),
4570
- createSecurityHeadersMiddleware(),
4571
- createBodySizeLimitMiddleware(),
4572
- createTracingMiddleware(),
4573
- createMetricsMiddleware(),
4574
- createRequestLoggingMiddleware(),
4575
- requestIdMiddleware,
4576
- createAuthMiddleware(auth),
4577
- createMembershipMiddleware(),
4578
- createTenantMiddleware()
4579
- ];
4580
- }
4581
- group(name) {
4582
- const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
4583
- switch (name) {
4584
- case "authenticated":
4585
- return [createRequireAuthMiddleware(auth)];
4586
- case "web":
4587
- return isViewsEnabled() ? [createFlashMiddleware(), createCsrfMiddleware()] : [];
4588
- case "api": {
4589
- if (!this.dependencies.container.has(CORE_CONFIG_TOKEN)) {
4590
- return [];
4591
- }
4592
- const config = this.dependencies.container.resolve(CORE_CONFIG_TOKEN);
4593
- const redisUrl = config.get(REDIS_URL_CONFIG_KEY)?.trim() ?? "";
4594
- if (!redisUrl) {
4595
- const maxAttempts2 = Number(process.env.RATE_LIMIT_PER_MINUTE ?? "120");
4596
- return [
4597
- createMemoryThrottleMiddleware({
4598
- maxAttempts: Number.isFinite(maxAttempts2) ? maxAttempts2 : 120,
4599
- decaySeconds: 60
4600
- })
4601
- ];
4602
- }
4603
- const maxAttempts = Number(process.env.RATE_LIMIT_PER_MINUTE ?? "120");
4604
- return [
4605
- createThrottleMiddleware({
4606
- redisUrl,
4607
- maxAttempts: Number.isFinite(maxAttempts) ? maxAttempts : 120,
4608
- decaySeconds: 60
4609
- })
4610
- ];
4611
- }
4612
- default:
4613
- throw new Error(`Unknown middleware group "${name}".`);
4614
- }
4615
- }
4616
- wrap(groups, handler) {
4617
- const names = Array.isArray(groups) ? groups : [groups];
4618
- const middleware = names.flatMap((name) => this.group(name));
4619
- if (middleware.length === 0) {
4620
- return handler;
4621
- }
4622
- return withMiddleware(...middleware)(handler);
4623
- }
4624
- wrapApi(handler) {
4625
- return this.wrap(["api", "authenticated"], handler);
4626
- }
4627
- wrapWeb(handler) {
4628
- return handler;
4629
- }
4630
- wrapWebPublicRead(handler) {
4631
- if (isPublicReadsEnabled()) {
4632
- return this.wrapWeb(handler);
4633
- }
4634
- return this.wrapWebAuthenticated(handler);
4635
- }
4636
- wrapWebAuthenticated(handler) {
4637
- const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
4638
- return withMiddleware(createRequireWebAuthMiddleware(auth))(handler);
4639
- }
4640
- wrapWebAbility(ability, handler) {
4641
- const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
4642
- const abilityChecker = this.dependencies.container.resolve(CORE_TOKEN_SERVICE_TOKEN);
4643
- const requireAbility = createRequireAbilityMiddleware(abilityChecker);
4644
- const middleware = [createRequireWebAuthMiddleware(auth), requireAbility(ability)];
4645
- return withMiddleware(...middleware)(handler);
4646
- }
4647
- wrapWebGlobalAdmin(handler) {
4648
- const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
4649
- const middleware = [createRequireWebAuthMiddleware(auth), createRequireGlobalAdminMiddleware()];
4650
- return withMiddleware(...middleware)(handler);
4651
- }
4652
- wrapAuthenticated(handler) {
4653
- return this.wrap("authenticated", handler);
4654
- }
4655
- wrapPublicRead(handler) {
4656
- if (isPublicReadsEnabled()) {
4657
- return handler;
4658
- }
4659
- return this.wrapAuthenticated(handler);
4660
- }
4661
- wrapGlobalAdmin(handler) {
4662
- const middleware = [...this.group("authenticated"), createRequireGlobalAdminMiddleware()];
4663
- return withMiddleware(...middleware)(handler);
4664
- }
4665
- wrapAbility(ability, handler) {
4666
- const abilityChecker = this.dependencies.container.resolve(CORE_TOKEN_SERVICE_TOKEN);
4667
- const requireAbility = createRequireAbilityMiddleware(abilityChecker);
4668
- const middleware = [...this.group("authenticated"), requireAbility(ability)];
4669
- return withMiddleware(...middleware)(handler);
4670
- }
4671
- wrapPolicy(resource, action, handler) {
4672
- const auth = this.dependencies.container.resolve(CORE_AUTH_TOKEN);
4673
- const gate = this.dependencies.container.resolve(CORE_POLICY_GATE_TOKEN);
4674
- return withMiddleware(createAuthorizeMiddleware(gate, auth, resource, action))(handler);
4675
- }
4676
- wrapLogin(handler) {
4677
- return this.wrapThrottle("login", resolveLoginRateLimit(), handler);
4678
- }
4679
- wrapRegister(handler) {
4680
- return this.wrapThrottle("register", resolveRegisterRateLimit(), handler);
4681
- }
4682
- wrapThrottle(scope, rateLimit, handler) {
4683
- const middleware = [];
4684
- const memoryKeyPrefix = scope === "login" ? "login-throttle:" : "register-throttle:";
4685
- if (this.dependencies.container.has(CORE_CONFIG_TOKEN)) {
4686
- const config = this.dependencies.container.resolve(CORE_CONFIG_TOKEN);
4687
- const redisUrl = config.get(REDIS_URL_CONFIG_KEY)?.trim() ?? "";
4688
- if (redisUrl) {
4689
- const throttle = scope === "login" ? createLoginThrottleMiddleware({
4690
- redisUrl,
4691
- maxAttempts: rateLimit.maxAttempts,
4692
- decaySeconds: rateLimit.decaySeconds
4693
- }) : createThrottleMiddleware({
4694
- redisUrl,
4695
- maxAttempts: rateLimit.maxAttempts,
4696
- decaySeconds: rateLimit.decaySeconds,
4697
- keyPrefix: memoryKeyPrefix
4698
- });
4699
- middleware.push(throttle);
4700
- } else {
4701
- middleware.push(createMemoryThrottleMiddleware({
4702
- maxAttempts: rateLimit.maxAttempts,
4703
- decaySeconds: rateLimit.decaySeconds,
4704
- keyPrefix: memoryKeyPrefix
4705
- }));
4706
- }
4707
- } else {
4708
- middleware.push(createMemoryThrottleMiddleware({
4709
- maxAttempts: rateLimit.maxAttempts,
4710
- decaySeconds: rateLimit.decaySeconds,
4711
- keyPrefix: memoryKeyPrefix
4712
- }));
4713
- }
4714
- if (middleware.length === 0) {
4715
- return handler;
4716
- }
4717
- return withMiddleware(...middleware)(handler);
4718
- }
4719
- }
4720
- function createHttpKernel(dependencies) {
4721
- return new HttpKernel(dependencies);
4722
- }
4723
-
4724
- // ../../src/bootstrap/routeRegistry.ts
4725
- class RouteRegistry {
4726
- routes = [];
4727
- register(route) {
4728
- this.routes.push(route);
4729
- }
4730
- clear() {
4731
- this.routes.length = 0;
4732
- }
4733
- list() {
4734
- return [...this.routes].sort((left, right) => left.path.localeCompare(right.path));
4735
- }
4736
- }
4737
- var ROUTE_REGISTRY_KEY = Symbol.for("@getstrata/routeRegistry");
4738
- function readSharedRouteRegistry() {
4739
- const globalRegistry = globalThis[ROUTE_REGISTRY_KEY];
4740
- if (globalRegistry) {
4741
- return globalRegistry;
4742
- }
4743
- const registry = new RouteRegistry;
4744
- globalThis[ROUTE_REGISTRY_KEY] = registry;
4745
- return registry;
4746
- }
4747
- var routeRegistry = readSharedRouteRegistry();
4748
-
4749
- // ../../src/bootstrap/createWebRoutes.ts
4700
+ import { htmlResponse as htmlResponse2 } from "@getstrata/core/view";
4750
4701
  function registerRoute(method, path, middleware) {
4751
4702
  routeRegistry.register({ method, path, middleware });
4752
4703
  }
4753
- function registerRouteMap(routes, middleware) {
4754
- const registered = {};
4755
- for (const [path, handler] of Object.entries(routes)) {
4756
- if (handler && typeof handler === "object" && !Array.isArray(handler)) {
4757
- const methodMap = handler;
4758
- registered[path] = methodMap;
4759
- for (const method of Object.keys(methodMap)) {
4760
- registerRoute(method.toUpperCase(), path, middleware);
4761
- }
4762
- continue;
4763
- }
4764
- registered[path] = handler;
4765
- registerRoute("GET", path, middleware);
4766
- }
4767
- return registered;
4768
- }
4769
4704
  function createWebRoutes(dependencies) {
4770
- const kernel = createHttpKernel(dependencies);
4771
- const middleware = [...kernel.globalMiddleware(), ...kernel.group("web")];
4772
- const moduleRoutes = {
4773
- "/": () => Response.redirect("/organizations", 302)
4774
- };
4775
- registerRoute("GET", "/", ["global", "web"]);
4776
- for (const module of discoverModules()) {
4777
- if (!module.webRoutes) {
4778
- continue;
4705
+ const wrappedRoutes = buildWebModuleRoutes(dependencies, {
4706
+ clearRegistry: false,
4707
+ seedRoutes: {
4708
+ "/": () => Response.redirect("/organizations", 302)
4779
4709
  }
4780
- Object.assign(moduleRoutes, module.webRoutes({
4781
- dependencies,
4782
- cachedJson: async () => htmlResponse(""),
4783
- kernel
4784
- }));
4785
- }
4786
- const wrappedRoutes = applyMiddlewareToRoutes(registerRouteMap(moduleRoutes, ["global", "web"]), middleware);
4710
+ });
4711
+ registerRoute("GET", "/", ["global", "web"]);
4787
4712
  wrappedRoutes["/assets/*"] = async (request) => {
4788
4713
  registerRoute("GET", "/assets/*", ["global", "web"]);
4789
4714
  const pathname = new URL(request.url).pathname;
4790
4715
  const relativePath = pathname.replace(/^\//, "");
4791
4716
  const file = Bun.file(join5(process.cwd(), "public", relativePath));
4792
4717
  if (!await file.exists()) {
4793
- return htmlResponse("Not Found", { status: 404 });
4718
+ return htmlResponse2("Not Found", { status: 404 });
4794
4719
  }
4795
4720
  return new Response(file);
4796
4721
  };
@@ -4921,8 +4846,8 @@ function securedBindRouteModel(param, resolver, authorization, handler) {
4921
4846
  return async (request) => {
4922
4847
  const id = parsePositiveIntParam(String(request.params[param]), String(param));
4923
4848
  const model = await resolver(id, request);
4924
- const gate = resolveApplicationPolicyGate();
4925
- const auth = resolveApplicationAuth();
4849
+ const gate = resolveApplicationPolicyGate2();
4850
+ const auth = resolveApplicationAuth2();
4926
4851
  const user = currentAuthUser() ?? await auth.resolve(request);
4927
4852
  gate.authorize(authorization.resource, authorization.action, user, model);
4928
4853
  if (isEtagEnabled() && isMutatingPolicyAction(authorization.action)) {
@@ -4944,8 +4869,8 @@ function securedBindRouteModelByKey(param, resolver, authorization, handler) {
4944
4869
  throw new BadRequestError(`Missing route parameter "${String(param)}".`);
4945
4870
  }
4946
4871
  const model = await resolver(key, request);
4947
- const gate = resolveApplicationPolicyGate();
4948
- const auth = resolveApplicationAuth();
4872
+ const gate = resolveApplicationPolicyGate2();
4873
+ const auth = resolveApplicationAuth2();
4949
4874
  const user = currentAuthUser() ?? await auth.resolve(request);
4950
4875
  gate.authorize(authorization.resource, authorization.action, user, model);
4951
4876
  if (isEtagEnabled() && isMutatingPolicyAction(authorization.action)) {
@@ -4960,158 +4885,8 @@ function securedBindRouteModelByKey(param, resolver, authorization, handler) {
4960
4885
  return response;
4961
4886
  };
4962
4887
  }
4963
- // ../../src/core/auth/accessControl.ts
4964
- var ROLE_RANK = {
4965
- member: 1,
4966
- admin: 2,
4967
- owner: 3
4968
- };
4969
- function isGlobalAdmin(user) {
4970
- return user?.role === "admin";
4971
- }
4972
- function hasMinimumOrgRole(role, minimum) {
4973
- if (!role) {
4974
- return false;
4975
- }
4976
- return ROLE_RANK[role] >= ROLE_RANK[minimum];
4977
- }
4978
- function resolveUserId(user) {
4979
- const userId = typeof user.id === "number" ? user.id : Number(user.id);
4980
- if (!Number.isInteger(userId) || userId <= 0) {
4981
- throw new ForbiddenError("Invalid authenticated user.");
4982
- }
4983
- return userId;
4984
- }
4985
-
4986
- // ../../src/modules/organization/memberRepository.ts
4987
- class OrganizationMemberRepository {
4988
- constructor() {}
4989
- async findMembership(userId, organizationId) {
4990
- const rows = await connection_default`
4991
- SELECT id, organization_id, user_id, role, created_at
4992
- FROM organization_member
4993
- WHERE user_id = ${userId} AND organization_id = ${organizationId}
4994
- LIMIT 1
4995
- `;
4996
- return rows[0] ?? null;
4997
- }
4998
- async listForUser(userId) {
4999
- return await connection_default`
5000
- SELECT id, organization_id, user_id, role, created_at
5001
- FROM organization_member
5002
- WHERE user_id = ${userId}
5003
- ORDER BY organization_id
5004
- `;
5005
- }
5006
- async listForOrganization(organizationId) {
5007
- return await connection_default`
5008
- SELECT id, organization_id, user_id, role, created_at
5009
- FROM organization_member
5010
- WHERE organization_id = ${organizationId}
5011
- ORDER BY id
5012
- `;
5013
- }
5014
- async addMember(input) {
5015
- const rows = await connection_default`
5016
- INSERT INTO organization_member (organization_id, user_id, role)
5017
- VALUES (${input.organizationId}, ${input.userId}, ${input.role ?? "member"})
5018
- RETURNING id, organization_id, user_id, role, created_at
5019
- `;
5020
- const row = rows[0];
5021
- if (!row) {
5022
- throw new Error("Organization member insert did not return a row.");
5023
- }
5024
- return row;
5025
- }
5026
- async removeMember(organizationId, userId) {
5027
- const rows = await connection_default`
5028
- DELETE FROM organization_member
5029
- WHERE organization_id = ${organizationId} AND user_id = ${userId}
5030
- RETURNING id
5031
- `;
5032
- return rows.length > 0;
5033
- }
5034
- }
5035
- var memberRepository_default = OrganizationMemberRepository;
5036
-
5037
- // ../../src/core/auth/membershipContext.ts
5038
- var membershipContext = createAsyncContextStore("@getstrata/membershipContext");
5039
- var membershipRepository = new memberRepository_default;
5040
-
5041
- // ../../src/core/auth/membershipService.ts
5042
- class MembershipService {
5043
- members;
5044
- constructor(members = membershipRepository) {
5045
- this.members = members;
5046
- }
5047
- async listOrganizationIdsForUser(userId) {
5048
- const memberships = await this.members.listForUser(userId);
5049
- return memberships.map((membership) => membership.organization_id);
5050
- }
5051
- async getOrgRole(userId, organizationId) {
5052
- const membership = await this.members.findMembership(userId, organizationId);
5053
- return membership?.role ?? null;
5054
- }
5055
- async requireOrgAccess(organizationId, minimumRole = "member", user = currentAuthUser()) {
5056
- if (!user) {
5057
- throw new ForbiddenError("Authentication required.");
5058
- }
5059
- if (isGlobalAdmin(user)) {
5060
- return "owner";
5061
- }
5062
- const role = await this.getOrgRole(resolveUserId(user), organizationId);
5063
- if (!role || !hasMinimumOrgRole(role, minimumRole)) {
5064
- throw new ForbiddenError("Organization membership required.");
5065
- }
5066
- return role;
5067
- }
5068
- async filterAccessibleOrganizationIds(organizationIds, user = currentAuthUser()) {
5069
- if (!user) {
5070
- return [];
5071
- }
5072
- if (isGlobalAdmin(user)) {
5073
- return organizationIds;
5074
- }
5075
- const allowed = new Set(await this.listOrganizationIdsForUser(resolveUserId(user)));
5076
- return organizationIds.filter((organizationId) => allowed.has(organizationId));
5077
- }
5078
- async addOwnerOnOrganizationCreate(organizationId, userId) {
5079
- await this.members.addMember({
5080
- organizationId,
5081
- userId,
5082
- role: "owner"
5083
- });
5084
- }
5085
- listMembersForOrganization(organizationId) {
5086
- return this.members.listForOrganization(organizationId);
5087
- }
5088
- addMember(input) {
5089
- return this.members.addMember(input);
5090
- }
5091
- removeMember(organizationId, userId) {
5092
- return this.members.removeMember(organizationId, userId);
5093
- }
5094
- }
5095
- var membershipService_default = MembershipService;
5096
-
5097
- // ../../src/core/auth/resolveMembershipService.ts
5098
- function resolveMembershipService() {
5099
- const dependencies = resolveApplicationDependencies();
5100
- if (dependencies.container.has("core.membership")) {
5101
- return dependencies.container.resolve("core.membership");
5102
- }
5103
- return new membershipService_default;
5104
- }
5105
- // ../../src/bootstrap/prefixRouteMap.ts
5106
- function prefixRouteMap(prefix, routes) {
5107
- const normalizedPrefix = prefix.replace(/\/$/, "");
5108
- const prefixed = {};
5109
- for (const [path, handler] of Object.entries(routes)) {
5110
- const normalizedPath = path.startsWith("/") ? path : `/${path}`;
5111
- prefixed[`${normalizedPrefix}${normalizedPath}`] = handler;
5112
- }
5113
- return prefixed;
5114
- }
4888
+ // ../../src/bootstrap/membershipService.ts
4889
+ import { resolveMembershipService } from "@getstrata/core/auth/membershipService";
5115
4890
  // ../../src/core/http/csrfProtection.ts
5116
4891
  var DEFAULT_CSRF_TTL_MS = 60 * 60 * 1000;
5117
4892
  function createCsrfProtection(secret, options = {}) {
@@ -5206,7 +4981,7 @@ function createRouteKernel(dependencies) {
5206
4981
  return createHttpKernel(dependencies);
5207
4982
  }
5208
4983
  // ../../src/bootstrap/web/server.ts
5209
- function wrapRouteHandler2(handler) {
4984
+ function wrapRouteHandler(handler) {
5210
4985
  return async (request) => {
5211
4986
  const response = await handler(request);
5212
4987
  return response ?? new Response("Not Found", { status: 404 });
@@ -5216,7 +4991,7 @@ function convertAppRoutesToBunRoutes(routes) {
5216
4991
  const bunRoutes = {};
5217
4992
  for (const [path, handler] of Object.entries(routes)) {
5218
4993
  if (typeof handler === "function") {
5219
- bunRoutes[path] = { GET: wrapRouteHandler2(handler) };
4994
+ bunRoutes[path] = { GET: wrapRouteHandler(handler) };
5220
4995
  continue;
5221
4996
  }
5222
4997
  if (handler && typeof handler === "object" && !Array.isArray(handler)) {
@@ -5225,7 +5000,7 @@ function convertAppRoutesToBunRoutes(routes) {
5225
5000
  if (typeof methodHandler !== "function") {
5226
5001
  continue;
5227
5002
  }
5228
- methods[method.toUpperCase()] = wrapRouteHandler2(methodHandler);
5003
+ methods[method.toUpperCase()] = wrapRouteHandler(methodHandler);
5229
5004
  }
5230
5005
  if (Object.keys(methods).length > 0) {
5231
5006
  bunRoutes[path] = methods;
@@ -5340,7 +5115,7 @@ export {
5340
5115
  securedBindRouteModel,
5341
5116
  scheduleRunCommand,
5342
5117
  runProviderPhase,
5343
- runDueScheduledTasks,
5118
+ runDueScheduledTasks2 as runDueScheduledTasks,
5344
5119
  routeRegistry,
5345
5120
  routeParams,
5346
5121
  resolveService,
@@ -5372,11 +5147,13 @@ export {
5372
5147
  configureModulesDirectory,
5373
5148
  collectProviders,
5374
5149
  cacheTagsForModelWrite,
5150
+ buildWebModuleRoutes,
5151
+ buildModuleRoutes,
5375
5152
  assertProductionSecrets,
5376
5153
  assertAppDependenciesComplete,
5377
- appSchedule,
5154
+ appSchedule2 as appSchedule,
5378
5155
  ServiceContainer,
5379
- Schedule,
5156
+ Schedule2 as Schedule,
5380
5157
  RouteRegistry,
5381
5158
  REDIS_URL_CONFIG_KEY,
5382
5159
  DEFAULT_APP_PORT,