@getstrata/bootstrap 2.0.9 → 2.2.0

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 (40) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +1 -1
  3. package/dist/bootstrap/app.d.ts +7 -1
  4. package/dist/bootstrap/config.d.ts +1 -1
  5. package/dist/bootstrap/context.d.ts +8 -2
  6. package/dist/bootstrap/contracts.d.ts +1 -1
  7. package/dist/bootstrap/dependencies.d.ts +1 -1
  8. package/dist/bootstrap/discoverJobs.d.ts +11 -3
  9. package/dist/bootstrap/discoverListeners.d.ts +7 -3
  10. package/dist/bootstrap/discoverModels.d.ts +8 -0
  11. package/dist/bootstrap/discoverModules.d.ts +4 -1
  12. package/dist/bootstrap/httpKernel.d.ts +25 -20
  13. package/dist/bootstrap/inProcessCron.d.ts +2 -1
  14. package/dist/bootstrap/infrastructureDiscovery.d.ts +9 -0
  15. package/dist/bootstrap/modules.d.ts +1 -1
  16. package/dist/bootstrap/providers/tracing.d.ts +3 -0
  17. package/dist/bootstrap/public-api.d.ts +9 -4
  18. package/dist/bootstrap/web/index.d.ts +1 -1
  19. package/dist/bootstrap/web/routing.d.ts +2 -2
  20. package/dist/bootstrap/web/server.d.ts +15 -7
  21. package/dist/entries/buildModuleRoutes.js +212 -67
  22. package/dist/entries/buildWebModuleRoutes.js +212 -67
  23. package/dist/entries/cache/modelCacheTags.js +157 -51
  24. package/dist/entries/config.js +6 -0
  25. package/dist/entries/context.js +427 -188
  26. package/dist/entries/contracts.js +2 -0
  27. package/dist/entries/createWebRoutes.js +214 -69
  28. package/dist/entries/dependencies.js +429 -190
  29. package/dist/entries/discoverJobs.js +132 -50
  30. package/dist/entries/discoverListeners.js +85 -37
  31. package/dist/entries/discoverModels.js +39 -0
  32. package/dist/entries/discoverModules.js +158 -51
  33. package/dist/entries/health.js +3 -0
  34. package/dist/entries/httpKernel.js +52 -13
  35. package/dist/entries/listeners/invalidateCacheOnModelWrite.js +157 -51
  36. package/dist/entries/providers.js +307 -164
  37. package/dist/entries/web/routing.js +52 -13
  38. package/dist/entries/web/server.js +69 -14
  39. package/dist/index.js +591 -216
  40. package/package.json +8 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # @getstrata/bootstrap changelog
2
2
 
3
+ ## 2.2.0
4
+
5
+ Consistent model scopes.
6
+ Changed-field model writes.
7
+ Awaited provider startup.
8
+ Shared cache correctness.
9
+ Native HTTP controls and body limits.
10
+ Graceful lifecycle.
11
+ Validated async discovery.
12
+ Stronger model input types.
13
+ OpenTelemetry tracing.
14
+ Distributed scheduler ownership.
15
+ App-owned quota policy.
16
+ Bounded memory throttling.
17
+
18
+ ## Unreleased
19
+
20
+ - Provide shared tracing provider ownership and phased OpenTelemetry flush/shutdown without replacing application global tracer providers.
21
+
22
+ - Breaking source contract: `discoverJobs()` and `discoverListeners()` now return promises. Await ESM discovery before queue construction or listener boot; malformed exports and duplicate discovered identities fail visibly. Add explicit job/listener/module manifests for bundles, preserve custom job factories, evict failed discovery loads and protect publication after reset. See `docs/DISCOVERY.md` before release/adoption.
23
+
24
+ - Make provider startup awaited, register all providers before boot, and expose idempotent context disposal with failure cleanup. Direct startup helper callers must now await; appContext getters require completed startup.
25
+
26
+ - Add awaited model discovery with nested exports, two-phase naming/boot, duplicate-name detection and startup error propagation.
27
+
28
+ ## 2.1.0
29
+
30
+ - refactor(starter): reuse shared config and base repositories - fix(database): await password casts before model writes - fix(database): preserve concrete model types in query results
31
+
3
32
  ## 2.0.9
4
33
 
5
34
  - fix(starter): remove demo credentials from public login defaults
package/README.md CHANGED
@@ -48,7 +48,7 @@ HTML apps should bind `createCookieSessionAuthManager` from `@getstrata/bootstra
48
48
 
49
49
  ## Queue
50
50
 
51
- `registerDefaultJobs()` registers `cache.invalidate-tags` and `audit.export` only. Outbound model webhooks are not a core job. Put a class with `static jobName` in `src/jobs/` (generated `--webhooks` uses `webhook.dispatch`) and call `discoverJobs()` on boot. `queue:work` already does that. There is no `registerWebhookJobs()` export.
51
+ `registerDefaultJobs()` registers `cache.invalidate-tags` and `audit.export` only. Outbound model webhooks are not a core job. Put a class with `static jobName` in `src/jobs/` (generated `--webhooks` uses `webhook.dispatch`) and call `await discoverJobs()` on boot. `queue:work` already does that. There is no `registerWebhookJobs()` export.
52
52
 
53
53
  ## Not a starter API
54
54
 
@@ -1,6 +1,12 @@
1
+ import { type ShutdownResult } from "@getstrata/core/lifecycle/gracefulShutdown";
1
2
  declare class App {
2
3
  private server?;
3
- serve(): void;
4
+ private startup?;
5
+ private lifecycle?;
6
+ private uninstallSignals?;
7
+ serve(): Promise<void>;
8
+ private start;
9
+ shutdown(reason?: string): Promise<ShutdownResult>;
4
10
  stop(force?: boolean): void;
5
11
  private resolvePort;
6
12
  }
@@ -4,7 +4,7 @@ declare const CACHE_MAX_ENTRIES_CONFIG_KEY = "cache.maxEntries";
4
4
  declare const CACHE_DRIVER_CONFIG_KEY = "cache.driver";
5
5
  declare const REDIS_URL_CONFIG_KEY = "cache.redisUrl";
6
6
  declare const DATABASE_URL_CONFIG_KEY = "database.url";
7
- export { CORE_ABILITY_CHECKER_TOKEN, CORE_AUTH_TOKEN, CORE_AUTH_USER_DIRECTORY_TOKEN, CORE_CACHE_TOKEN, CORE_CONFIG_TOKEN, CORE_EVENT_BUS_TOKEN, CORE_POLICY_GATE_TOKEN, CORE_QUEUE_TOKEN, CORE_TOKEN_SERVICE_TOKEN, } from "@getstrata/core/contracts/serviceTokens";
7
+ export { CORE_ABILITY_CHECKER_TOKEN, CORE_AUTH_TOKEN, CORE_AUTH_USER_DIRECTORY_TOKEN, CORE_CACHE_TOKEN, CORE_CONFIG_TOKEN, CORE_EVENT_BUS_TOKEN, CORE_HTTP_CLEANUP_TOKEN, CORE_POLICY_GATE_TOKEN, CORE_QUEUE_TOKEN, CORE_TENANT_RESOLVER_TOKEN, CORE_THROTTLE_QUOTA_POLICY_TOKEN, CORE_TOKEN_SERVICE_TOKEN, } from "@getstrata/core/contracts/serviceTokens";
8
8
  declare const AUTH_DEV_HEADERS_CONFIG_KEY = "auth.allowDevHeaders";
9
9
  declare const DEFAULT_APP_PORT = 3000;
10
10
  declare const DEFAULT_CACHE_TTL_MS = 3600000;
@@ -1,6 +1,12 @@
1
1
  import { type AppContext, type AppModule, type ProviderContext, type ServiceProvider } from "./contracts";
2
+ type InitializedAppContext = AppContext & {
3
+ drain(): Promise<void>;
4
+ flush(): Promise<void>;
5
+ dispose(): Promise<void>;
6
+ };
2
7
  declare function collectProviders(modules?: AppModule[]): ServiceProvider[];
3
- declare function runProviderPhase(providers: ServiceProvider[], phase: "register" | "boot", context: ProviderContext): void;
4
- declare function createAppContext(): AppContext;
8
+ declare function runProviderPhase(providers: readonly ServiceProvider[], phase: "register" | "boot", context: ProviderContext): Promise<void>;
9
+ declare function createAppContext(providers?: readonly ServiceProvider[]): Promise<InitializedAppContext>;
5
10
  declare const appContext: AppContext;
11
+ export type { InitializedAppContext };
6
12
  export { appContext, collectProviders, createAppContext, runProviderPhase };
@@ -1,4 +1,4 @@
1
- export { ConfigStore, type ConfigStoreLike, ServiceContainer, type ServiceContainerLike, } from "@getstrata/core/contracts/container";
1
+ export { ConfigStore, type ConfigStoreLike, createServiceToken, ServiceContainer, type ServiceContainerLike, type ServiceToken, } from "@getstrata/core/contracts/container";
2
2
  export type { AppContext, AppDependencies, AppRouteMap, CachedJson, MutableAppDependencies, ProviderContext, ServiceFactory, ServiceProvider, } from "@getstrata/core/contracts/di";
3
3
  export { assertAppDependenciesComplete, getRequiredDependency, resolveService, } from "@getstrata/core/contracts/di";
4
4
  import type { AppDependencies, AppRouteMap, CachedJson, ServiceProvider } from "@getstrata/core/contracts/di";
@@ -1,4 +1,4 @@
1
1
  import { createAppContext } from "./context";
2
- declare function createAppDependencies(): import("./contracts").AppDependencies;
2
+ declare function createAppDependencies(): Promise<import("./contracts").AppDependencies>;
3
3
  export type { AppContext, AppDependencies } from "./contracts";
4
4
  export { createAppContext, createAppDependencies };
@@ -1,8 +1,16 @@
1
- import type { Job } from "@getstrata/core/queue";
1
+ import { Job } from "@getstrata/core/queue";
2
+ import { type InfrastructureDiscoveryOptions } from "./infrastructureDiscovery";
2
3
  type DiscoveredJobClass = (new () => Job) & {
3
4
  jobName: string;
4
5
  };
5
- declare function discoverJobs(): string[];
6
+ type JobManifestEntry = DiscoveredJobClass | {
7
+ name: string;
8
+ create: () => Job;
9
+ };
10
+ interface DiscoverJobsOptions extends InfrastructureDiscoveryOptions {
11
+ manifest?: readonly JobManifestEntry[];
12
+ }
13
+ declare function discoverJobs(options?: DiscoverJobsOptions): Promise<string[]>;
6
14
  declare function resetDiscoverJobsForTests(): void;
7
- export type { DiscoveredJobClass };
15
+ export type { DiscoveredJobClass, DiscoverJobsOptions, JobManifestEntry };
8
16
  export { discoverJobs, resetDiscoverJobsForTests };
@@ -1,5 +1,9 @@
1
- type ListenerRegistrar = () => void;
2
- declare function discoverListeners(): ListenerRegistrar[];
1
+ import { type InfrastructureDiscoveryOptions } from "./infrastructureDiscovery";
2
+ type ListenerRegistrar = () => void | Promise<void>;
3
+ interface DiscoverListenersOptions extends InfrastructureDiscoveryOptions {
4
+ manifest?: readonly ListenerRegistrar[];
5
+ }
6
+ declare function discoverListeners(options?: DiscoverListenersOptions): Promise<ListenerRegistrar[]>;
3
7
  declare function resetDiscoverListenersForTests(): void;
4
- export type { ListenerRegistrar };
8
+ export type { DiscoverListenersOptions, ListenerRegistrar };
5
9
  export { discoverListeners, resetDiscoverListenersForTests };
@@ -0,0 +1,8 @@
1
+ /** Import trusted application model modules, then bind and boot their exported classes. */
2
+ interface DiscoverModelsOptions {
3
+ /** Startup orchestration files are not model modules; avoids importing the awaiting caller. */
4
+ exclude?: readonly string[];
5
+ }
6
+ declare function discoverModels(directory?: string, options?: DiscoverModelsOptions): Promise<object[]>;
7
+ export type { DiscoverModelsOptions };
8
+ export { discoverModels };
@@ -1,10 +1,13 @@
1
1
  import type { AppModule } from "./contracts";
2
2
  interface DiscoverModulesOptions {
3
3
  modulesDir?: string;
4
+ exclude?: readonly string[];
5
+ manifest?: readonly AppModule[];
4
6
  }
5
7
  declare function configureModulesDirectory(modulesDir: string): void;
8
+ declare function configureModulesManifest(manifest: readonly AppModule[]): void;
6
9
  declare function ensureModulesLoaded(options?: DiscoverModulesOptions): Promise<AppModule[]>;
7
10
  declare function discoverModules(): AppModule[];
8
11
  declare function resetDiscoverModulesForTests(): void;
9
12
  export type { DiscoverModulesOptions };
10
- export { configureModulesDirectory, discoverModules, ensureModulesLoaded, resetDiscoverModulesForTests, };
13
+ export { configureModulesDirectory, configureModulesManifest, discoverModules, ensureModulesLoaded, resetDiscoverModulesForTests, };
@@ -6,33 +6,38 @@ type MiddlewareGroupName = "api" | "authenticated" | "web";
6
6
  type WebGuestHome = string | ((user: AuthUser) => string | Promise<string>);
7
7
  declare class HttpKernel {
8
8
  private readonly dependencies;
9
+ private readonly ownedThrottles;
10
+ private disposed;
9
11
  constructor(dependencies: AppDependencies);
12
+ dispose(): void;
13
+ /** Own custom disposable throttle middleware until this application closes. */
14
+ ownThrottle<T extends Middleware>(throttle: T): T;
10
15
  globalMiddleware(errorFormat?: "json" | "web"): Middleware[];
11
16
  group(name: MiddlewareGroupName): Middleware[];
12
- wrap(groups: MiddlewareGroupName | MiddlewareGroupName[], handler: RouteHandler): RouteHandler;
13
- wrapApi(handler: RouteHandler): RouteHandler;
14
- wrapWeb(handler: RouteHandler): RouteHandler;
17
+ wrap<TRequest extends Request = Request>(groups: MiddlewareGroupName | MiddlewareGroupName[], handler: RouteHandler<TRequest>): RouteHandler<TRequest>;
18
+ wrapApi<TRequest extends Request = Request>(handler: RouteHandler<TRequest>): RouteHandler<TRequest>;
19
+ wrapWeb<TRequest extends Request = Request>(handler: RouteHandler<TRequest>): RouteHandler<TRequest>;
15
20
  /** Signed-in HTML users redirect to `home` instead of seeing guest pages. */
16
- wrapWebGuest(handler: RouteHandler, home?: WebGuestHome): RouteHandler;
17
- wrapWebPublicRead(handler: RouteHandler): RouteHandler;
18
- wrapWebAuthenticated(handler: RouteHandler): RouteHandler;
21
+ wrapWebGuest<TRequest extends Request = Request>(handler: RouteHandler<TRequest>, home?: WebGuestHome): RouteHandler<TRequest>;
22
+ wrapWebPublicRead<TRequest extends Request = Request>(handler: RouteHandler<TRequest>): RouteHandler<TRequest>;
23
+ wrapWebAuthenticated<TRequest extends Request = Request>(handler: RouteHandler<TRequest>): RouteHandler<TRequest>;
19
24
  /** Signed-in HTML without the email-verified gate (logout, verification notice). */
20
- wrapWebAuthenticatedAllowUnverified(handler: RouteHandler): RouteHandler;
21
- wrapWebVerified(handler: RouteHandler): RouteHandler;
25
+ wrapWebAuthenticatedAllowUnverified<TRequest extends Request = Request>(handler: RouteHandler<TRequest>): RouteHandler<TRequest>;
26
+ wrapWebVerified<TRequest extends Request = Request>(handler: RouteHandler<TRequest>): RouteHandler<TRequest>;
22
27
  /** Requires a fresh signed password-confirmation cookie. */
23
- wrapWebPasswordConfirm(handler: RouteHandler): RouteHandler;
24
- wrapWebAbility(ability: string, handler: RouteHandler): RouteHandler;
25
- wrapWebGlobalAdmin(handler: RouteHandler): RouteHandler;
26
- wrapAuthenticated(handler: RouteHandler): RouteHandler;
28
+ wrapWebPasswordConfirm<TRequest extends Request = Request>(handler: RouteHandler<TRequest>): RouteHandler<TRequest>;
29
+ wrapWebAbility<TRequest extends Request = Request>(ability: string, handler: RouteHandler<TRequest>): RouteHandler<TRequest>;
30
+ wrapWebGlobalAdmin<TRequest extends Request = Request>(handler: RouteHandler<TRequest>): RouteHandler<TRequest>;
31
+ wrapAuthenticated<TRequest extends Request = Request>(handler: RouteHandler<TRequest>): RouteHandler<TRequest>;
27
32
  /** JSON routes that require a verified email. No-op when `FEATURE_EMAIL_VERIFICATION` is off. */
28
- wrapVerified(handler: RouteHandler): RouteHandler;
29
- wrapPublicRead(handler: RouteHandler): RouteHandler;
30
- wrapGlobalAdmin(handler: RouteHandler): RouteHandler;
31
- wrapAbility(ability: string, handler: RouteHandler): RouteHandler;
32
- wrapPolicy(resource: string, action: keyof Policy, handler: RouteHandler): RouteHandler;
33
- wrapLogin(handler: RouteHandler): RouteHandler;
34
- wrapSigned(handler: RouteHandler): RouteHandler;
35
- wrapRegister(handler: RouteHandler): RouteHandler;
33
+ wrapVerified<TRequest extends Request = Request>(handler: RouteHandler<TRequest>): RouteHandler<TRequest>;
34
+ wrapPublicRead<TRequest extends Request = Request>(handler: RouteHandler<TRequest>): RouteHandler<TRequest>;
35
+ wrapGlobalAdmin<TRequest extends Request = Request>(handler: RouteHandler<TRequest>): RouteHandler<TRequest>;
36
+ wrapAbility<TRequest extends Request = Request>(ability: string, handler: RouteHandler<TRequest>): RouteHandler<TRequest>;
37
+ wrapPolicy<TRequest extends Request = Request>(resource: string, action: keyof Policy, handler: RouteHandler<TRequest>): RouteHandler<TRequest>;
38
+ wrapLogin<TRequest extends Request = Request>(handler: RouteHandler<TRequest>): RouteHandler<TRequest>;
39
+ wrapSigned<TRequest extends Request = Request>(handler: RouteHandler<TRequest>): RouteHandler<TRequest>;
40
+ wrapRegister<TRequest extends Request = Request>(handler: RouteHandler<TRequest>): RouteHandler<TRequest>;
36
41
  private wrapWebAuth;
37
42
  private verifiedMiddleware;
38
43
  private wrapThrottle;
@@ -1,4 +1,5 @@
1
1
  import "./schedule";
2
2
  declare function startInProcessCronIfEnabled(): void;
3
3
  declare function stopInProcessCron(): void;
4
- export { startInProcessCronIfEnabled, stopInProcessCron };
4
+ declare function drainInProcessCron(): Promise<void>;
5
+ export { drainInProcessCron, startInProcessCronIfEnabled, stopInProcessCron };
@@ -0,0 +1,9 @@
1
+ interface InfrastructureDiscoveryOptions {
2
+ directory?: string;
3
+ /** Relative paths or basenames; exclusions apply before importing. */
4
+ exclude?: readonly string[];
5
+ }
6
+ declare function infrastructureFiles(directory: string, exclude?: readonly string[]): Promise<string[]>;
7
+ declare function importInfrastructure(file: string): Promise<Record<string, unknown>>;
8
+ export type { InfrastructureDiscoveryOptions };
9
+ export { importInfrastructure, infrastructureFiles };
@@ -1 +1 @@
1
- export { configureModulesDirectory, discoverModules, ensureModulesLoaded, } from "./discoverModules";
1
+ export { configureModulesDirectory, configureModulesManifest, discoverModules, ensureModulesLoaded, } from "./discoverModules";
@@ -0,0 +1,3 @@
1
+ import type { ServiceProvider } from "../contracts";
2
+ declare const tracingProvider: ServiceProvider;
3
+ export default tracingProvider;
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * @getstrata/bootstrap: application shell for Strata apps.
3
3
  */
4
- export type { ScheduledTask } from "@getstrata/core/scheduler/schedule";
5
- export { appSchedule, runDueScheduledTasks, Schedule } from "@getstrata/core/scheduler/schedule";
4
+ export type { ScheduledTask, ScheduledTaskContext, SchedulerLease, SchedulerLeaseStore, SchedulerRunOptions, } from "@getstrata/core/scheduler/schedule";
5
+ export { appSchedule, RedisSchedulerLeaseStore, runDueScheduledTasks, Schedule, SchedulerLeaseLostError, } from "@getstrata/core/scheduler/schedule";
6
6
  export { resolveApplicationAuth, resolveApplicationCache, resolveApplicationConfig, resolveApplicationDependencies, resolveApplicationEventBus, resolveApplicationLogger, resolveApplicationPolicyGate, resolveApplicationQueue, setActiveApplicationContext, } from "./applicationRegistry.ts";
7
7
  export type { BuildModuleRoutesOptions } from "./buildModuleRoutes.ts";
8
8
  export { buildModuleRoutes } from "./buildModuleRoutes.ts";
@@ -10,15 +10,19 @@ export type { BuildWebModuleRoutesOptions } from "./buildWebModuleRoutes.ts";
10
10
  export { buildWebModuleRoutes } from "./buildWebModuleRoutes.ts";
11
11
  export { cacheTagsForModelWrite, discoverModelTableNames } from "./cache/modelCacheTags.ts";
12
12
  export { APP_PORT_CONFIG_KEY, CORE_ABILITY_CHECKER_TOKEN, CORE_AUTH_TOKEN, CORE_AUTH_USER_DIRECTORY_TOKEN, CORE_CACHE_TOKEN, CORE_CONFIG_TOKEN, CORE_EVENT_BUS_TOKEN, CORE_POLICY_GATE_TOKEN, CORE_QUEUE_TOKEN, CORE_TOKEN_SERVICE_TOKEN, DATABASE_URL_CONFIG_KEY, DEFAULT_APP_PORT, REDIS_URL_CONFIG_KEY, } from "./config.ts";
13
+ export type { InitializedAppContext } from "./context.ts";
13
14
  export { collectProviders, createAppContext, runProviderPhase } from "./context.ts";
14
15
  export type { AppContext, AppDependencies, AppModule, AppRouteMap, CachedJson, ConfigStore, ModuleRouteContext, MutableAppDependencies, ProviderContext, ServiceFactory, ServiceProvider, } from "./contracts.ts";
15
16
  export { assertAppDependenciesComplete, getRequiredDependency, resolveService, ServiceContainer, } from "./contracts.ts";
16
17
  export type { CreateWebRoutesOptions } from "./createWebRoutes.ts";
17
18
  export { createWebRoutes, mergeWebRoutes } from "./createWebRoutes.ts";
18
19
  export { createAppDependencies } from "./dependencies.ts";
20
+ export type { DiscoveredJobClass, DiscoverJobsOptions, JobManifestEntry } from "./discoverJobs.ts";
19
21
  export { discoverJobs, resetDiscoverJobsForTests } from "./discoverJobs.ts";
22
+ export type { DiscoverModelsOptions } from "./discoverModels.ts";
23
+ export { discoverModels } from "./discoverModels.ts";
20
24
  export type { DiscoverModulesOptions } from "./discoverModules.ts";
21
- export { configureModulesDirectory, discoverModules, ensureModulesLoaded, } from "./discoverModules.ts";
25
+ export { configureModulesDirectory, configureModulesManifest, discoverModules, ensureModulesLoaded, } from "./discoverModules.ts";
22
26
  export type { CreateHealthRoutesOptions } from "./health.ts";
23
27
  export { checkDatabase, checkRedis, createHealthRoutes, pingDatabase } from "./health.ts";
24
28
  export { type RouteModelAuthorization, securedBindRouteModel, securedBindRouteModelByKey, } from "./http/securedRouteModelBinding.ts";
@@ -26,7 +30,8 @@ export { createHttpKernel, type HttpKernel, type MiddlewareGroupName } from "./h
26
30
  export { resolveMembershipService } from "./membershipService.ts";
27
31
  export { prefixRouteMap } from "./prefixRouteMap.ts";
28
32
  export { coreProviders } from "./providers/index.ts";
33
+ export { default as tracingProvider } from "./providers/tracing.ts";
29
34
  export { registerDefaultJobs } from "./queue/defaultJobs.ts";
30
35
  export { RouteRegistry, routeRegistry } from "./routeRegistry.ts";
31
36
  export { assertProductionSecrets } from "./secretsGuard.ts";
32
- export { CookieSessionAuthManager, CookieSessionGuard, CookieSessionStore, createCookieSessionAuthManager, createCsrfProtection, createRouteKernel, createWebServer, type LoadSessionUser, type MapSessionUser, type ParsedForm, parseFormBody, routeParams, type SessionUser, slugify, toRouteRequest, type WebServerOptions, wrapSecuredRouteModelByKey, wrapWebLogin, wrapWebRegister, } from "./web/index.ts";
37
+ export { CookieSessionAuthManager, CookieSessionGuard, CookieSessionStore, createCookieSessionAuthManager, createCsrfProtection, createRouteKernel, createWebServer, type LoadSessionUser, type MapSessionUser, type NativeServerOptions, type ParsedForm, parseFormBody, routeParams, type SessionUser, slugify, toRouteRequest, type WebServerOptions, wrapSecuredRouteModelByKey, wrapWebLogin, wrapWebRegister, } from "./web/index.ts";
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export { createCsrfProtection, type ParsedForm, parseFormBody } from "./forms.ts";
5
5
  export { createRouteKernel, routeParams, toRouteRequest, wrapSecuredRouteModelByKey, wrapWebLogin, wrapWebRegister, } from "./routing.ts";
6
- export { convertAppRoutesToBunRoutes, createWebServer, type WebServerOptions } from "./server.ts";
6
+ export { convertAppRoutesToBunRoutes, createWebServer, type NativeServerOptions, type WebServerOptions, } from "./server.ts";
7
7
  export { CookieSessionAuthManager, CookieSessionGuard, CookieSessionStore, createCookieSessionAuthManager, type LoadSessionUser, type MapSessionUser, type SessionUser, } from "./session.ts";
8
8
  export { slugify } from "./slug.ts";
@@ -21,8 +21,8 @@ export declare function wrapSecuredRouteModelByKey<TParams extends Record<string
21
21
  etag?: boolean;
22
22
  }, handler: (request: RouteRequest<TParams>, model: TModel) => Response | Promise<Response>): RouteHandler;
23
23
  /** Web group (CSRF + flash + HTML errors) plus login throttle. Do not wrap with wrapWeb again. */
24
- export declare function wrapWebLogin(kernel: HttpKernel, handler: RouteHandler, onThrottled: (request: Request) => Response | Promise<Response>): RouteHandler;
24
+ export declare function wrapWebLogin<TRequest extends Request = Request>(kernel: HttpKernel, handler: RouteHandler<TRequest>, onThrottled: (request: TRequest) => Response | Promise<Response>): RouteHandler<TRequest>;
25
25
  /** Web group (CSRF + flash + HTML errors) plus register throttle. Do not wrap with wrapWeb again. */
26
- export declare function wrapWebRegister(kernel: HttpKernel, handler: RouteHandler, onThrottled: (request: Request) => Response | Promise<Response>): RouteHandler;
26
+ export declare function wrapWebRegister<TRequest extends Request = Request>(kernel: HttpKernel, handler: RouteHandler<TRequest>, onThrottled: (request: TRequest) => Response | Promise<Response>): RouteHandler<TRequest>;
27
27
  /** Convenience alias for `createHttpKernel`. */
28
28
  export declare function createRouteKernel(dependencies: AppDependencies): HttpKernel;
@@ -1,16 +1,24 @@
1
1
  import { type CorsOptions } from "@getstrata/core/http/corsMiddleware";
2
- import type { BunRequest, Server } from "bun";
2
+ import type { LifecycleCoordinator } from "@getstrata/core/lifecycle/gracefulShutdown";
3
+ import type { BunRequest, Serve, Server } from "bun";
3
4
  import type { AppRouteMap } from "../contracts.ts";
4
- export interface WebServerOptions {
5
+ export type NativeServerOptions<T = unknown> = Omit<Serve.HostnamePortServeOptions<T>, "port"> & {
6
+ websocket?: Bun.WebSocketHandler<T>;
7
+ };
8
+ export interface WebServerOptions<T = unknown> {
5
9
  port: number;
6
- handle?: (request: Request) => Promise<Response | null> | Response | null;
10
+ handle?: (request: Request, server: Server<T>) => Promise<Response | null | undefined> | Response | null | undefined;
11
+ /** Bun transport options. Framework dispatch and route composition remain owned here. */
12
+ native?: NativeServerOptions<T>;
13
+ lifecycle?: LifecycleCoordinator;
7
14
  routes?: AppRouteMap;
8
15
  publicDir?: string;
9
16
  /** Additional approved headers for synthesized route preflights; origins still use framework policy. */
10
17
  cors?: CorsOptions;
11
- onRequest?: (request: Request) => Promise<void> | void;
18
+ onRequest?: (request: Request, server: Server<T>) => Promise<void | Response> | void | Response;
12
19
  }
13
- type BunRouteHandler = (request: BunRequest, server: Server<unknown>) => Response | Promise<Response>;
14
- declare function convertAppRoutesToBunRoutes(routes: AppRouteMap, cors?: CorsOptions): Record<string, Record<string, BunRouteHandler>>;
15
- export declare function createWebServer(options: WebServerOptions): Server<undefined>;
20
+ type TrackRequest = <T>(work: () => Promise<T>) => Promise<T>;
21
+ type BunRouteHandler<T = unknown> = (request: BunRequest, server: Server<T>) => Response | Promise<Response>;
22
+ declare function convertAppRoutesToBunRoutes<T = unknown>(routes: AppRouteMap, cors?: CorsOptions, onRequest?: WebServerOptions<T>["onRequest"], track?: TrackRequest): Record<string, Record<string, BunRouteHandler<T>>>;
23
+ export declare function createWebServer<T = unknown>(options: WebServerOptions<T>): Server<T>;
16
24
  export { convertAppRoutesToBunRoutes };