@getstrata/core 0.2.0 → 0.3.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 (129) hide show
  1. package/README.md +6 -0
  2. package/dist/bootstrap/applicationRegistry.d.ts +16 -0
  3. package/dist/bootstrap/config.d.ts +19 -0
  4. package/dist/bootstrap/contracts.d.ts +63 -0
  5. package/dist/bootstrap/httpKernel.d.ts +26 -0
  6. package/dist/config/app.d.ts +10 -0
  7. package/dist/config/contentSecurityPolicy.d.ts +5 -0
  8. package/dist/config/cors.d.ts +9 -0
  9. package/dist/config/database.d.ts +10 -0
  10. package/dist/config/features.d.ts +18 -0
  11. package/dist/config/frontend.d.ts +6 -0
  12. package/dist/config/rateLimit.d.ts +9 -0
  13. package/dist/config/uploads.d.ts +5 -0
  14. package/dist/core/auth/accessControl.d.ts +8 -0
  15. package/dist/core/auth/authContext.d.ts +12 -0
  16. package/dist/core/auth/guard.d.ts +36 -0
  17. package/dist/core/auth/membershipContext.d.ts +16 -0
  18. package/dist/core/auth/membershipContextMiddleware.d.ts +3 -0
  19. package/dist/core/auth/membershipMiddleware.d.ts +2 -0
  20. package/dist/core/auth/oauth/oidcProvider.d.ts +18 -0
  21. package/dist/core/auth/oauth/providers.d.ts +22 -0
  22. package/dist/core/auth/oauth/samlProvider.d.ts +9 -0
  23. package/dist/core/auth/oauth/types.d.ts +11 -0
  24. package/dist/core/auth/password.d.ts +3 -0
  25. package/dist/core/auth/policy.d.ts +15 -0
  26. package/dist/core/auth/tokenHash.d.ts +3 -0
  27. package/dist/core/cache/repository.d.ts +17 -0
  28. package/dist/core/cache/store.d.ts +12 -0
  29. package/dist/core/cache/taggedCache.d.ts +9 -0
  30. package/dist/core/cache/tags.d.ts +11 -0
  31. package/dist/core/crypto/fieldEncryption.d.ts +13 -0
  32. package/dist/core/crypto/mfaSecret.d.ts +3 -0
  33. package/dist/core/database/baseRepository.d.ts +44 -0
  34. package/dist/core/database/connection.d.ts +7 -0
  35. package/dist/core/database/connectionContext.d.ts +7 -0
  36. package/dist/core/database/errors.d.ts +12 -0
  37. package/dist/core/database/index.d.ts +11 -0
  38. package/dist/core/database/query.d.ts +51 -0
  39. package/dist/core/database/relationships.d.ts +26 -0
  40. package/dist/core/database/table.d.ts +13 -0
  41. package/dist/core/database/transaction.d.ts +3 -0
  42. package/dist/core/database/types.d.ts +29 -0
  43. package/dist/core/errors/http.d.ts +33 -0
  44. package/dist/core/events/eventBus.d.ts +10 -0
  45. package/dist/core/events/index.d.ts +4 -0
  46. package/dist/core/facades/index.d.ts +10 -0
  47. package/dist/core/http/authMiddleware.d.ts +5 -0
  48. package/dist/core/http/authorizeMiddleware.d.ts +5 -0
  49. package/dist/core/http/bodySizeLimitMiddleware.d.ts +4 -0
  50. package/dist/core/http/conditionalResponse.d.ts +2 -0
  51. package/dist/core/http/contentNegotiation.d.ts +2 -0
  52. package/dist/core/http/corsMiddleware.d.ts +3 -0
  53. package/dist/core/http/csrfMiddleware.d.ts +3 -0
  54. package/dist/core/http/csrfToken.d.ts +14 -0
  55. package/dist/core/http/etag.d.ts +18 -0
  56. package/dist/core/http/flashMiddleware.d.ts +3 -0
  57. package/dist/core/http/flashSession.d.ts +12 -0
  58. package/dist/core/http/formRequest.d.ts +10 -0
  59. package/dist/core/http/index.d.ts +27 -0
  60. package/dist/core/http/loginThrottleMiddleware.d.ts +11 -0
  61. package/dist/core/http/memoryThrottleMiddleware.d.ts +9 -0
  62. package/dist/core/http/metricsMiddleware.d.ts +4 -0
  63. package/dist/core/http/middleware.d.ts +8 -0
  64. package/dist/core/http/pagination.d.ts +11 -0
  65. package/dist/core/http/parseFormBody.d.ts +6 -0
  66. package/dist/core/http/parseMultipartUpload.d.ts +10 -0
  67. package/dist/core/http/requestMetaContext.d.ts +16 -0
  68. package/dist/core/http/requireAbilityMiddleware.d.ts +4 -0
  69. package/dist/core/http/requireAuthMiddleware.d.ts +4 -0
  70. package/dist/core/http/requireGlobalAdminMiddleware.d.ts +3 -0
  71. package/dist/core/http/requireWebAuthMiddleware.d.ts +4 -0
  72. package/dist/core/http/resources.d.ts +7 -0
  73. package/dist/core/http/route.d.ts +6 -0
  74. package/dist/core/http/routeMiddleware.d.ts +3 -0
  75. package/dist/core/http/routeModelBinding.d.ts +3 -0
  76. package/dist/core/http/securedRouteModelBinding.d.ts +10 -0
  77. package/dist/core/http/securityHeadersMiddleware.d.ts +3 -0
  78. package/dist/core/http/throttleMiddleware.d.ts +11 -0
  79. package/dist/core/http/validation.d.ts +23 -0
  80. package/dist/core/http/webErrorResponse.d.ts +5 -0
  81. package/dist/core/http/webFormRequest.d.ts +6 -0
  82. package/dist/core/logging/logger.d.ts +17 -0
  83. package/dist/core/logging/requestLoggingMiddleware.d.ts +3 -0
  84. package/dist/core/mail/mailer.d.ts +36 -0
  85. package/dist/core/metrics/prometheus.d.ts +26 -0
  86. package/dist/core/pagination/index.d.ts +17 -0
  87. package/dist/core/queue/index.d.ts +19 -0
  88. package/dist/core/security/publicReads.d.ts +3 -0
  89. package/dist/core/security/securityEvents.d.ts +6 -0
  90. package/dist/core/security/tokenExpiry.d.ts +2 -0
  91. package/dist/core/security/totp.d.ts +3 -0
  92. package/dist/core/storage/storage.d.ts +41 -0
  93. package/dist/core/tenant/databaseTenantContext.d.ts +2 -0
  94. package/dist/core/tenant/resolveTenant.d.ts +3 -0
  95. package/dist/core/tenant/tenantContext.d.ts +14 -0
  96. package/dist/core/tenant/tenantDatabaseScope.d.ts +7 -0
  97. package/dist/core/tenant/tenantMiddleware.d.ts +6 -0
  98. package/dist/core/tracing/otel.d.ts +26 -0
  99. package/dist/core/tracing/traceContext.d.ts +10 -0
  100. package/dist/core/tracing/tracingMiddleware.d.ts +3 -0
  101. package/dist/core/view/etaViewEngine.d.ts +15 -0
  102. package/dist/core/view/htmlResponse.d.ts +6 -0
  103. package/dist/core/view/index.d.ts +5 -0
  104. package/dist/core/view/viewEngine.d.ts +6 -0
  105. package/dist/core/view/webLayoutData.d.ts +17 -0
  106. package/dist/db/connection/createConnection.d.ts +6 -0
  107. package/dist/db/connection/index.d.ts +11 -0
  108. package/dist/domain/abilities.d.ts +5 -0
  109. package/dist/domain/auth.d.ts +4 -0
  110. package/dist/framework/public-api.d.ts +30 -0
  111. package/dist/index.js +17 -2
  112. package/dist/modules/organization/memberRepository.d.ts +14 -0
  113. package/dist/modules/organization/memberTypes.d.ts +9 -0
  114. package/dist/modules/user/apiTokenRepository.d.ts +8 -0
  115. package/dist/modules/user/apiTokenTable.d.ts +3 -0
  116. package/dist/modules/user/authService.d.ts +23 -0
  117. package/dist/modules/user/notificationRepository.d.ts +6 -0
  118. package/dist/modules/user/notificationService.d.ts +25 -0
  119. package/dist/modules/user/notificationTable.d.ts +3 -0
  120. package/dist/modules/user/notificationTypes.d.ts +12 -0
  121. package/dist/modules/user/oauthIdentityRepository.d.ts +9 -0
  122. package/dist/modules/user/provider.d.ts +11 -0
  123. package/dist/modules/user/repository.d.ts +12 -0
  124. package/dist/modules/user/table.d.ts +3 -0
  125. package/dist/modules/user/tokenService.d.ts +29 -0
  126. package/dist/modules/user/types.d.ts +46 -0
  127. package/dist/types/services.d.ts +16 -0
  128. package/package.json +7 -6
  129. package/index.ts +0 -1
package/README.md CHANGED
@@ -9,7 +9,11 @@ WorkHub is the reference application built on Strata; import the framework from
9
9
 
10
10
  ## Usage
11
11
 
12
+ Set `DATABASE_URL` before importing (connection is created lazily on first query):
13
+
12
14
  ```typescript
15
+ process.env.DATABASE_URL ??= "postgresql://postgres:postgres@localhost:5432/myapp";
16
+
13
17
  import {
14
18
  BaseRepository,
15
19
  FormRequest,
@@ -20,6 +24,8 @@ import {
20
24
  } from "@getstrata/core";
21
25
  ```
22
26
 
27
+ `orderBy` accepts explicit `{ column, direction }` objects or Laravel-style shorthand `{ published_at: "desc" }`.
28
+
23
29
  ## Build & verify (monorepo root)
24
30
 
25
31
  ```bash
@@ -0,0 +1,16 @@
1
+ import type { AuthManager } from "../core/auth/guard";
2
+ import type { PolicyGate } from "../core/auth/policy";
3
+ import { type Logger } from "../core/logging/logger";
4
+ import type { Queue } from "../core/queue";
5
+ import type { CacheLike } from "../types/services";
6
+ import type { AppContext } from "./contracts";
7
+ import { type ConfigStore } from "./contracts";
8
+ declare function setActiveApplicationContext(context: AppContext): void;
9
+ declare function resolveApplicationCache(): CacheLike;
10
+ declare function resolveApplicationQueue(): Queue;
11
+ declare function resolveApplicationAuth(): AuthManager;
12
+ declare function resolveApplicationPolicyGate(): PolicyGate;
13
+ declare function resolveApplicationConfig(): ConfigStore;
14
+ declare function resolveApplicationLogger(): Logger;
15
+ declare function resolveApplicationDependencies(): import("./contracts").AppDependencies;
16
+ export { resolveApplicationAuth, resolveApplicationCache, resolveApplicationConfig, resolveApplicationDependencies, resolveApplicationLogger, resolveApplicationPolicyGate, resolveApplicationQueue, setActiveApplicationContext, };
@@ -0,0 +1,19 @@
1
+ declare const APP_PORT_CONFIG_KEY = "app.port";
2
+ declare const CACHE_TTL_MS_CONFIG_KEY = "cache.ttlMs";
3
+ declare const CACHE_MAX_ENTRIES_CONFIG_KEY = "cache.maxEntries";
4
+ declare const CACHE_DRIVER_CONFIG_KEY = "cache.driver";
5
+ declare const REDIS_URL_CONFIG_KEY = "cache.redisUrl";
6
+ declare const DATABASE_URL_CONFIG_KEY = "database.url";
7
+ declare const CORE_CONFIG_TOKEN = "core.config";
8
+ declare const CORE_CACHE_TOKEN = "core.cache";
9
+ declare const CORE_QUEUE_TOKEN = "core.queue";
10
+ declare const CORE_POLICY_GATE_TOKEN = "core.policyGate";
11
+ declare const CORE_AUTH_TOKEN = "core.auth";
12
+ declare const AUTH_DEV_HEADERS_CONFIG_KEY = "auth.allowDevHeaders";
13
+ declare const DEFAULT_APP_PORT = 3000;
14
+ declare const DEFAULT_CACHE_TTL_MS = 3600000;
15
+ declare const DEFAULT_CACHE_MAX_ENTRIES = 100;
16
+ declare const DEFAULT_CACHE_DRIVER = "array";
17
+ declare const DEFAULT_API_TOKEN = "";
18
+ declare const DEFAULT_QUEUE_DRIVER = "sync";
19
+ export { APP_PORT_CONFIG_KEY, AUTH_DEV_HEADERS_CONFIG_KEY, CACHE_DRIVER_CONFIG_KEY, CACHE_MAX_ENTRIES_CONFIG_KEY, CACHE_TTL_MS_CONFIG_KEY, CORE_AUTH_TOKEN, CORE_CACHE_TOKEN, CORE_CONFIG_TOKEN, CORE_POLICY_GATE_TOKEN, CORE_QUEUE_TOKEN, DATABASE_URL_CONFIG_KEY, DEFAULT_API_TOKEN, DEFAULT_APP_PORT, DEFAULT_CACHE_DRIVER, DEFAULT_CACHE_MAX_ENTRIES, DEFAULT_CACHE_TTL_MS, DEFAULT_QUEUE_DRIVER, REDIS_URL_CONFIG_KEY, };
@@ -0,0 +1,63 @@
1
+ import type { CacheLike } from "../types/services";
2
+ type CachedJson = <T>(cacheKey: string, loader: () => Promise<T>, tags?: string[], request?: Request) => Promise<Response>;
3
+ type AppRouteMap = Record<string, any>;
4
+ type ServiceFactory<T> = (container: ServiceContainer) => T;
5
+ declare class ServiceContainer {
6
+ private readonly services;
7
+ private readonly singletonFactories;
8
+ private readonly bindings;
9
+ set<T>(key: string, value: T): T;
10
+ singleton<T>(key: string, factory: ServiceFactory<T>): void;
11
+ bind<T>(key: string, factory: ServiceFactory<T>): void;
12
+ get<T>(key: string): T;
13
+ resolve<T>(key: string): T;
14
+ has(key: string): boolean;
15
+ }
16
+ declare class ConfigStore {
17
+ private readonly values;
18
+ set<T>(key: string, value: T): T;
19
+ get<T>(key: string): T | undefined;
20
+ require<T>(key: string): T;
21
+ has(key: string): boolean;
22
+ }
23
+ interface AppDependencies {
24
+ container: ServiceContainer;
25
+ cache: CacheLike;
26
+ }
27
+ type MutableAppDependencies = Partial<Omit<AppDependencies, "container">> & Pick<AppDependencies, "container">;
28
+ interface ProviderContext {
29
+ container: ServiceContainer;
30
+ config: ConfigStore;
31
+ dependencies: MutableAppDependencies;
32
+ }
33
+ import type { HttpKernel } from "./httpKernel";
34
+ interface ModuleRouteContext {
35
+ dependencies: AppDependencies;
36
+ cachedJson: CachedJson;
37
+ kernel: HttpKernel;
38
+ }
39
+ interface ServiceProvider {
40
+ name: string;
41
+ register?(context: ProviderContext): void;
42
+ boot?(context: ProviderContext): void;
43
+ }
44
+ interface AppModule {
45
+ name: string;
46
+ order?: number;
47
+ tableName?: string;
48
+ cacheTags?: readonly string[];
49
+ cacheDeleteExtraTags?: readonly string[];
50
+ providers?: ServiceProvider[];
51
+ routes?(context: ModuleRouteContext): AppRouteMap;
52
+ webRoutes?(context: ModuleRouteContext): AppRouteMap;
53
+ }
54
+ interface AppContext {
55
+ container: ServiceContainer;
56
+ config: ConfigStore;
57
+ dependencies: AppDependencies;
58
+ }
59
+ declare function getRequiredDependency<K extends keyof AppDependencies>(dependencies: Partial<AppDependencies>, key: K): AppDependencies[K];
60
+ declare function assertAppDependenciesComplete(dependencies: MutableAppDependencies): asserts dependencies is AppDependencies;
61
+ declare function resolveService<T>(dependencies: AppDependencies, token: string): T;
62
+ export type { AppContext, AppDependencies, AppModule, AppRouteMap, CachedJson, ModuleRouteContext, MutableAppDependencies, ProviderContext, ServiceFactory, ServiceProvider, };
63
+ export { assertAppDependenciesComplete, ConfigStore, getRequiredDependency, resolveService, ServiceContainer, };
@@ -0,0 +1,26 @@
1
+ import type { Policy } from "../core/auth/policy";
2
+ import { type Middleware, type RouteHandler } from "../core/http/middleware";
3
+ import type { AppDependencies } from "./contracts";
4
+ type MiddlewareGroupName = "api" | "authenticated" | "web";
5
+ declare class HttpKernel {
6
+ private readonly dependencies;
7
+ constructor(dependencies: AppDependencies);
8
+ globalMiddleware(): Middleware[];
9
+ group(name: MiddlewareGroupName): Middleware[];
10
+ wrap(groups: MiddlewareGroupName | MiddlewareGroupName[], handler: RouteHandler): RouteHandler;
11
+ wrapApi(handler: RouteHandler): RouteHandler;
12
+ wrapWeb(handler: RouteHandler): RouteHandler;
13
+ wrapWebPublicRead(handler: RouteHandler): RouteHandler;
14
+ wrapWebAuthenticated(handler: RouteHandler): RouteHandler;
15
+ wrapWebAbility(ability: string, handler: RouteHandler): RouteHandler;
16
+ wrapWebGlobalAdmin(handler: RouteHandler): RouteHandler;
17
+ wrapAuthenticated(handler: RouteHandler): RouteHandler;
18
+ wrapPublicRead(handler: RouteHandler): RouteHandler;
19
+ wrapGlobalAdmin(handler: RouteHandler): RouteHandler;
20
+ wrapAbility(ability: string, handler: RouteHandler): RouteHandler;
21
+ wrapPolicy(resource: string, action: keyof Policy, handler: RouteHandler): RouteHandler;
22
+ wrapLogin(handler: RouteHandler): RouteHandler;
23
+ }
24
+ declare function createHttpKernel(dependencies: AppDependencies): HttpKernel;
25
+ export type { MiddlewareGroupName };
26
+ export { createHttpKernel, HttpKernel };
@@ -0,0 +1,10 @@
1
+ interface AppConfig {
2
+ name: string;
3
+ env: string;
4
+ debug: boolean;
5
+ url: string;
6
+ apiPrefix: string;
7
+ }
8
+ declare const appConfig: AppConfig;
9
+ export type { AppConfig };
10
+ export { appConfig };
@@ -0,0 +1,5 @@
1
+ declare function strictApiContentSecurityPolicy(): string;
2
+ declare function serverHtmxContentSecurityPolicy(): string;
3
+ declare function spaContentSecurityPolicy(): string;
4
+ declare function resolveContentSecurityPolicy(response: Response): string;
5
+ export { resolveContentSecurityPolicy, serverHtmxContentSecurityPolicy, spaContentSecurityPolicy, strictApiContentSecurityPolicy, };
@@ -0,0 +1,9 @@
1
+ interface CorsConfig {
2
+ allowedOrigins: string[];
3
+ allowedMethods: string[];
4
+ allowedHeaders: string[];
5
+ maxAgeSeconds: number;
6
+ }
7
+ declare const corsConfig: CorsConfig;
8
+ export type { CorsConfig };
9
+ export { corsConfig };
@@ -0,0 +1,10 @@
1
+ interface DatabaseConfig {
2
+ url: string;
3
+ poolMax: number;
4
+ idleTimeoutSeconds: number;
5
+ maxLifetimeSeconds: number;
6
+ connectionTimeoutSeconds: number;
7
+ }
8
+ declare const databaseConfig: DatabaseConfig;
9
+ export type { DatabaseConfig };
10
+ export { databaseConfig };
@@ -0,0 +1,18 @@
1
+ interface FeatureFlags {
2
+ webhooks: boolean;
3
+ fullTextSearch: boolean;
4
+ auditLog: boolean;
5
+ oauthLogin: boolean;
6
+ samlLogin: boolean;
7
+ scim: boolean;
8
+ billing: boolean;
9
+ siemExport: boolean;
10
+ publicReads: boolean;
11
+ emailVerification: boolean;
12
+ mfa: boolean;
13
+ }
14
+ declare function readFeatureFlags(): FeatureFlags;
15
+ declare const featureFlags: FeatureFlags;
16
+ declare function isFeatureEnabled(feature: keyof FeatureFlags): boolean;
17
+ export type { FeatureFlags };
18
+ export { featureFlags, isFeatureEnabled, readFeatureFlags };
@@ -0,0 +1,6 @@
1
+ type FrontendMode = "api" | "server-htmx" | "spa-react";
2
+ declare function readFrontendMode(): FrontendMode;
3
+ declare function isViewsEnabled(): boolean;
4
+ declare function isSpaEnabled(): boolean;
5
+ export type { FrontendMode };
6
+ export { isSpaEnabled, isViewsEnabled, readFrontendMode };
@@ -0,0 +1,9 @@
1
+ interface LoginRateLimitConfig {
2
+ maxAttempts: number;
3
+ decaySeconds: number;
4
+ }
5
+ declare const LOCAL_LOGIN_RATE_LIMIT: LoginRateLimitConfig;
6
+ declare const PRODUCTION_LOGIN_RATE_LIMIT: LoginRateLimitConfig;
7
+ declare function resolveLoginRateLimit(): LoginRateLimitConfig;
8
+ export type { LoginRateLimitConfig };
9
+ export { LOCAL_LOGIN_RATE_LIMIT, PRODUCTION_LOGIN_RATE_LIMIT, resolveLoginRateLimit };
@@ -0,0 +1,5 @@
1
+ declare const DEFAULT_MAX_UPLOAD_BYTES: number;
2
+ declare const ALLOWED_UPLOAD_MIME_TYPES: Set<string>;
3
+ declare function resolveMaxUploadBytes(): number;
4
+ declare function isAllowedMimeType(mimeType: string): boolean;
5
+ export { ALLOWED_UPLOAD_MIME_TYPES, DEFAULT_MAX_UPLOAD_BYTES, isAllowedMimeType, resolveMaxUploadBytes, };
@@ -0,0 +1,8 @@
1
+ import type { OrganizationMemberRole } from "../../modules/organization/memberTypes";
2
+ import { type AuthUser } from "./authContext";
3
+ declare const ROLE_RANK: Record<OrganizationMemberRole, number>;
4
+ declare function isGlobalAdmin(user: AuthUser | null): boolean;
5
+ declare function hasMinimumOrgRole(role: OrganizationMemberRole | null | undefined, minimum: OrganizationMemberRole): boolean;
6
+ declare function requireAuthenticatedUser(): AuthUser;
7
+ declare function resolveUserId(user: AuthUser): number;
8
+ export { hasMinimumOrgRole, isGlobalAdmin, ROLE_RANK, requireAuthenticatedUser, resolveUserId };
@@ -0,0 +1,12 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ type AuthUser = {
3
+ id: number | string;
4
+ role?: string;
5
+ abilities?: string[];
6
+ tokenId?: number;
7
+ };
8
+ declare const authContext: AsyncLocalStorage<AuthUser | null>;
9
+ declare function runWithAuthUser<T>(user: AuthUser | null, callback: () => T | Promise<T>): T | Promise<T>;
10
+ declare function currentAuthUser(): AuthUser | null;
11
+ export type { AuthUser };
12
+ export { authContext, currentAuthUser, runWithAuthUser };
@@ -0,0 +1,36 @@
1
+ import type { ServiceContainer } from "../../bootstrap/contracts";
2
+ import type { AuthUser } from "./authContext";
3
+ interface AuthGuard {
4
+ resolve(request: Request): AuthUser | null | Promise<AuthUser | null>;
5
+ }
6
+ declare class GuestGuard implements AuthGuard {
7
+ resolve(request: Request): AuthUser | null;
8
+ }
9
+ declare class ApiTokenGuard implements AuthGuard {
10
+ private readonly options;
11
+ constructor(options: {
12
+ token: string;
13
+ user: AuthUser;
14
+ });
15
+ resolve(request: Request): AuthUser | null;
16
+ }
17
+ declare class DatabaseTokenGuard implements AuthGuard {
18
+ private readonly container;
19
+ constructor(container: ServiceContainer);
20
+ resolve(request: Request): Promise<AuthUser | null>;
21
+ }
22
+ declare class CompositeGuard implements AuthGuard {
23
+ private readonly guards;
24
+ constructor(guards: AuthGuard[]);
25
+ resolve(request: Request): Promise<AuthUser | null>;
26
+ }
27
+ declare class AuthManager {
28
+ private readonly guard;
29
+ constructor(guard: AuthGuard);
30
+ resolve(request?: Request): Promise<AuthUser | null>;
31
+ user(request?: Request): Promise<AuthUser | null>;
32
+ check(request?: Request): Promise<boolean>;
33
+ requireUser(request?: Request): Promise<AuthUser>;
34
+ }
35
+ export type { AuthGuard, AuthUser };
36
+ export { ApiTokenGuard, AuthManager, CompositeGuard, DatabaseTokenGuard, GuestGuard };
@@ -0,0 +1,16 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ import OrganizationMemberRepository from "../../modules/organization/memberRepository";
3
+ import type { OrganizationMemberRole } from "../../modules/organization/memberTypes";
4
+ type MembershipContext = {
5
+ organizationIds: number[];
6
+ rolesByOrganizationId: Map<number, OrganizationMemberRole>;
7
+ };
8
+ declare const membershipContext: AsyncLocalStorage<MembershipContext>;
9
+ declare const membershipRepository: OrganizationMemberRepository;
10
+ declare function runWithMembershipContext<T>(callback: () => T | Promise<T>): Promise<T | Promise<T>>;
11
+ declare function currentOrgRole(organizationId: number): OrganizationMemberRole | null;
12
+ declare function hasOrgMembership(organizationId: number): boolean;
13
+ declare function currentOrganizationIds(): number[];
14
+ declare function hasMinimumOrgRole(organizationId: number, minimum: OrganizationMemberRole): boolean;
15
+ export type { MembershipContext };
16
+ export { currentOrganizationIds, currentOrgRole, hasMinimumOrgRole, hasOrgMembership, membershipContext, membershipRepository, runWithMembershipContext, };
@@ -0,0 +1,3 @@
1
+ import type { Middleware } from "../http/middleware";
2
+ declare function createMembershipContextMiddleware(): Middleware;
3
+ export { createMembershipContextMiddleware };
@@ -0,0 +1,2 @@
1
+ declare function createMembershipMiddleware(): import("../http").Middleware;
2
+ export { createMembershipMiddleware };
@@ -0,0 +1,18 @@
1
+ import type { OAuthProfile, OAuthProvider } from "./types";
2
+ interface OidcProviderOptions {
3
+ name: string;
4
+ issuer: string;
5
+ clientId: string;
6
+ clientSecret: string;
7
+ redirectUri: string;
8
+ scopes?: string[];
9
+ }
10
+ declare class OidcProvider implements OAuthProvider {
11
+ private readonly options;
12
+ readonly name: string;
13
+ constructor(options: OidcProviderOptions);
14
+ getAuthorizationUrl(state: string): string;
15
+ exchangeCode(code: string): Promise<OAuthProfile>;
16
+ }
17
+ export type { OidcProviderOptions };
18
+ export { OidcProvider };
@@ -0,0 +1,22 @@
1
+ import type { OAuthProfile, OAuthProvider } from "./types";
2
+ interface GitHubOAuthOptions {
3
+ clientId: string;
4
+ clientSecret: string;
5
+ redirectUri: string;
6
+ }
7
+ declare class GitHubOAuthProvider implements OAuthProvider {
8
+ private readonly options;
9
+ readonly name = "github";
10
+ constructor(options: GitHubOAuthOptions);
11
+ getAuthorizationUrl(state: string): string;
12
+ exchangeCode(code: string): Promise<OAuthProfile>;
13
+ }
14
+ declare class MockOAuthProvider implements OAuthProvider {
15
+ private readonly profile;
16
+ readonly name = "mock";
17
+ constructor(profile: OAuthProfile);
18
+ getAuthorizationUrl(state: string): string;
19
+ exchangeCode(code: string): Promise<OAuthProfile>;
20
+ }
21
+ export type { GitHubOAuthOptions };
22
+ export { GitHubOAuthProvider, MockOAuthProvider };
@@ -0,0 +1,9 @@
1
+ import type { OAuthProfile, OAuthProvider } from "./types";
2
+ declare class SamlProvider implements OAuthProvider {
3
+ private readonly loginUrl;
4
+ readonly name = "saml";
5
+ constructor(loginUrl: string);
6
+ getAuthorizationUrl(state: string): string;
7
+ exchangeCode(code: string): Promise<OAuthProfile>;
8
+ }
9
+ export { SamlProvider };
@@ -0,0 +1,11 @@
1
+ interface OAuthProfile {
2
+ providerUserId: string;
3
+ email: string;
4
+ name: string;
5
+ }
6
+ interface OAuthProvider {
7
+ readonly name: string;
8
+ getAuthorizationUrl(state: string): string;
9
+ exchangeCode(code: string): Promise<OAuthProfile>;
10
+ }
11
+ export type { OAuthProfile, OAuthProvider };
@@ -0,0 +1,3 @@
1
+ declare function hashPassword(password: string): Promise<string>;
2
+ declare function verifyPassword(password: string, passwordHash: string): Promise<boolean>;
3
+ export { hashPassword, verifyPassword };
@@ -0,0 +1,15 @@
1
+ declare abstract class Policy {
2
+ constructor();
3
+ view(_user?: unknown, _resource?: unknown): boolean;
4
+ create(_user?: unknown): boolean;
5
+ update(_user?: unknown, _resource?: unknown): boolean;
6
+ delete(_user?: unknown, _resource?: unknown): boolean;
7
+ }
8
+ declare class PolicyGate {
9
+ constructor();
10
+ private readonly policies;
11
+ register(resource: string, policy: Policy): void;
12
+ allows(resource: string, action: keyof Policy, user?: unknown, model?: unknown): boolean;
13
+ authorize(resource: string, action: keyof Policy, user?: unknown, model?: unknown): void;
14
+ }
15
+ export { Policy, PolicyGate };
@@ -0,0 +1,3 @@
1
+ declare function resolveTokenPepper(): string;
2
+ declare function hashApiToken(token: string): string;
3
+ export { hashApiToken, resolveTokenPepper };
@@ -0,0 +1,17 @@
1
+ import type { CacheStore } from "./store";
2
+ import TaggedCache from "./taggedCache";
3
+ declare class CacheRepository {
4
+ private readonly store;
5
+ constructor(store: CacheStore);
6
+ get<T>(key: string): Promise<T | undefined>;
7
+ remember<T>(key: string, callback: () => Promise<T>, ttlMs?: number): Promise<T>;
8
+ forget(key: string): Promise<boolean>;
9
+ flush(): Promise<void>;
10
+ tags(...names: string[]): TaggedCache;
11
+ getOrSet<T>(key: string, loader: () => Promise<T>, ttlMs?: number): Promise<T>;
12
+ invalidate(key: string): Promise<boolean>;
13
+ invalidateByPrefix(prefix: string): Promise<number>;
14
+ clear(): Promise<void>;
15
+ size(): Promise<number>;
16
+ }
17
+ export default CacheRepository;
@@ -0,0 +1,12 @@
1
+ interface CacheStore {
2
+ get<T>(key: string): Promise<T | undefined>;
3
+ set<T>(key: string, value: T, ttlMs?: number): Promise<void>;
4
+ getOrSet<T>(key: string, loader: () => Promise<T>, ttlMs?: number): Promise<T>;
5
+ attachTags(key: string, tags: string[]): Promise<void>;
6
+ flushTags(tags: string[]): Promise<number>;
7
+ invalidate(key: string): Promise<boolean>;
8
+ invalidateByPrefix(prefix: string): Promise<number>;
9
+ clear(): Promise<void>;
10
+ size(): Promise<number>;
11
+ }
12
+ export type { CacheStore };
@@ -0,0 +1,9 @@
1
+ import type { CacheStore } from "./store";
2
+ declare class TaggedCache {
3
+ private readonly store;
4
+ private readonly tags;
5
+ constructor(store: CacheStore, tags: string[]);
6
+ remember<T>(key: string, callback: () => Promise<T>, ttlMs?: number): Promise<T>;
7
+ flush(): Promise<number>;
8
+ }
9
+ export default TaggedCache;
@@ -0,0 +1,11 @@
1
+ declare const CACHE_TAGS: {
2
+ readonly organizations: "organizations";
3
+ readonly projects: "projects";
4
+ readonly tasks: "tasks";
5
+ readonly comments: "comments";
6
+ readonly attachments: "attachments";
7
+ readonly reports: "reports";
8
+ };
9
+ type CacheTag = (typeof CACHE_TAGS)[keyof typeof CACHE_TAGS];
10
+ export type { CacheTag };
11
+ export { CACHE_TAGS };
@@ -0,0 +1,13 @@
1
+ declare function resolveEncryptionKey(): Buffer | null;
2
+ declare function isFieldEncryptionEnabled(): boolean;
3
+ declare function encryptField(plaintext: string, key: Buffer): string;
4
+ declare function decryptField(value: string, key: Buffer): string;
5
+ declare function hashLookupValue(normalizedValue: string, key: Buffer): string;
6
+ declare function normalizeEmail(email: string): string;
7
+ declare function protectEmail(email: string): {
8
+ storedEmail: string;
9
+ emailLookup: string;
10
+ };
11
+ declare function revealEmail(storedEmail: string): string;
12
+ declare function emailLookupForQuery(email: string): string;
13
+ export { decryptField, emailLookupForQuery, encryptField, hashLookupValue, isFieldEncryptionEnabled, normalizeEmail, protectEmail, resolveEncryptionKey, revealEmail, };
@@ -0,0 +1,3 @@
1
+ declare function protectMfaSecret(secret: string): string;
2
+ declare function revealMfaSecret(stored: string | null | undefined): string | null;
3
+ export { protectMfaSecret, revealMfaSecret };
@@ -0,0 +1,44 @@
1
+ import { type PaginatedResult } from "../pagination/index.ts";
2
+ import { type BelongsToRelation, type HasManyRelation } from "./relationships.ts";
3
+ import type { TableDefinition } from "./table.ts";
4
+ import type { MutationValues, QueryOptions, QueryWhere, UpdateValues } from "./types.ts";
5
+ interface DatabaseConnection {
6
+ unsafe<T>(query: string, params?: readonly unknown[]): Promise<T[]>;
7
+ }
8
+ type ErrorFactory<TValue> = (value: TValue) => Error;
9
+ declare class BaseRepository<TEntity extends object, PrimaryKey extends keyof TEntity & string> {
10
+ protected readonly table: TableDefinition<TEntity, PrimaryKey>;
11
+ protected readonly connection: DatabaseConnection;
12
+ constructor(table: TableDefinition<TEntity, PrimaryKey>, connection?: DatabaseConnection);
13
+ findAll(options?: QueryOptions<TEntity>): Promise<TEntity[]>;
14
+ paginate(options: {
15
+ page: number;
16
+ perPage: number;
17
+ } & Omit<QueryOptions<TEntity>, "limit" | "offset">): Promise<PaginatedResult<TEntity>>;
18
+ findById(id: TEntity[PrimaryKey]): Promise<TEntity | null>;
19
+ findByIdOrThrow(id: TEntity[PrimaryKey], errorFactory?: ErrorFactory<TEntity[PrimaryKey]>): Promise<TEntity>;
20
+ findByIds(ids: readonly TEntity[PrimaryKey][]): Promise<TEntity[]>;
21
+ firstOrNull(where: QueryWhere<TEntity>, options?: Omit<QueryOptions<TEntity>, "where" | "limit">): Promise<TEntity | null>;
22
+ create(values: MutationValues<TEntity>): Promise<TEntity>;
23
+ updateById(id: TEntity[PrimaryKey], changes: UpdateValues<TEntity, PrimaryKey>): Promise<TEntity | null>;
24
+ updateByIdOrThrow(id: TEntity[PrimaryKey], changes: UpdateValues<TEntity, PrimaryKey>, errorFactory?: ErrorFactory<TEntity[PrimaryKey]>): Promise<TEntity>;
25
+ deleteById(id: TEntity[PrimaryKey]): Promise<boolean>;
26
+ softDeleteById(id: TEntity[PrimaryKey]): Promise<boolean>;
27
+ forceDeleteById(id: TEntity[PrimaryKey]): Promise<boolean>;
28
+ restoreById(id: TEntity[PrimaryKey]): Promise<TEntity | null>;
29
+ withConnection(connection: DatabaseConnection): this;
30
+ protected findWhere(where: QueryWhere<TEntity>, options?: Omit<QueryOptions<TEntity>, "where">): Promise<TEntity[]>;
31
+ protected countWhere(where?: QueryWhere<TEntity>, options?: Pick<QueryOptions<TEntity>, "withTrashed" | "onlyTrashed">): Promise<number>;
32
+ protected averageColumn(column: keyof TEntity & string, where?: QueryWhere<TEntity>): Promise<number>;
33
+ protected averageExpression(expression: string, alias: string, where?: QueryWhere<TEntity>): Promise<number>;
34
+ protected pluckNumberValues(expression: string, alias: string, options?: QueryOptions<TEntity>): Promise<number[]>;
35
+ protected countGroupedBy<K extends keyof TEntity & string>(column: K, where?: QueryWhere<TEntity>): Promise<Array<{
36
+ value: TEntity[K] | null;
37
+ count: number;
38
+ }>>;
39
+ protected findByHasManyRelation<TParent extends object, LocalKey extends keyof TParent & string, ForeignKey extends keyof TEntity & string>(relation: HasManyRelation<TParent, TEntity, LocalKey, ForeignKey>, parentId: TParent[LocalKey], options?: Omit<QueryOptions<TEntity>, "where">): Promise<TEntity[]>;
40
+ protected loadHasManyForParents<TParent extends object, LocalKey extends keyof TParent & string, ForeignKey extends keyof TEntity & string>(parents: readonly TParent[], relation: HasManyRelation<TParent, TEntity, LocalKey, ForeignKey>, options?: Omit<QueryOptions<TEntity>, "where">): Promise<Map<TParent[LocalKey], TEntity[]>>;
41
+ protected loadBelongsToForParents<TChild extends object, TParent extends object, ForeignKey extends keyof TChild & string, OwnerKey extends keyof TParent & string>(children: readonly TChild[], relation: BelongsToRelation<TChild, TParent, ForeignKey, OwnerKey>, parentRepository: BaseRepository<TParent, OwnerKey>, options?: Omit<QueryOptions<TParent>, "where">): Promise<Map<TChild[ForeignKey], TParent>>;
42
+ }
43
+ export default BaseRepository;
44
+ export type { DatabaseConnection };
@@ -0,0 +1,7 @@
1
+ import type { DatabaseConnection } from "./baseRepository.ts";
2
+ type UnsafeQueryable = {
3
+ unsafe<T>(query: string, params?: readonly unknown[]): Promise<T[]>;
4
+ };
5
+ declare function createDatabaseConnection(source: UnsafeQueryable): DatabaseConnection;
6
+ export type { UnsafeQueryable };
7
+ export { createDatabaseConnection };
@@ -0,0 +1,7 @@
1
+ type ActiveDatabaseHandle = {
2
+ unsafe<T>(query: string, params?: readonly unknown[]): Promise<T[]>;
3
+ };
4
+ declare function runWithDatabaseConnection<T>(connection: ActiveDatabaseHandle, callback: () => T | Promise<T>): T | Promise<T>;
5
+ declare function getActiveDatabaseConnection<T extends ActiveDatabaseHandle>(fallback: T): T;
6
+ export type { ActiveDatabaseHandle };
7
+ export { getActiveDatabaseConnection, runWithDatabaseConnection };
@@ -0,0 +1,12 @@
1
+ import { HttpError } from "../errors/http";
2
+ interface PostgresErrorLike {
3
+ code?: string;
4
+ errno?: string | number;
5
+ constraint?: string;
6
+ detail?: string;
7
+ message?: string;
8
+ }
9
+ declare function isPostgresError(error: unknown): error is PostgresErrorLike;
10
+ declare function mapDatabaseError(error: unknown): HttpError;
11
+ declare function withDatabaseErrorHandling<TValue>(operation: () => Promise<TValue>): Promise<TValue>;
12
+ export { isPostgresError, mapDatabaseError, withDatabaseErrorHandling };
@@ -0,0 +1,11 @@
1
+ export type { DatabaseConnection } from "./baseRepository.ts";
2
+ export { default as BaseRepository } from "./baseRepository.ts";
3
+ export { createDatabaseConnection } from "./connection.ts";
4
+ export { mapDatabaseError, withDatabaseErrorHandling } from "./errors.ts";
5
+ export { buildCountQuery, buildDeleteByIdQuery, buildGroupedCountQuery, buildInsertQuery, buildOrderByClause, buildProjectionQuery, buildQueryWhereClause, buildRestoreByIdQuery, buildSelectQuery, buildSoftDeleteByIdQuery, buildUpdateQuery, buildWhereClause, qualifyColumn, quoteIdentifier, resolveSoftDeleteColumn, } from "./query.ts";
6
+ export type { BelongsToRelation, HasManyRelation } from "./relationships.ts";
7
+ export { belongsTo, hasMany, indexBelongsToRelation, indexHasManyRelation, } from "./relationships.ts";
8
+ export type { TableDefinition } from "./table.ts";
9
+ export { defineTable } from "./table.ts";
10
+ export { runInTransaction } from "./transaction.ts";
11
+ export type { DatabaseComparable, DatabaseScalar, MutationValues, QueryFilterValue, QueryOperator, QueryOptions, QueryOrder, QueryWhere, UpdateValues, } from "./types.ts";
@@ -0,0 +1,51 @@
1
+ import type { TableDefinition } from "./table.ts";
2
+ import type { MutationValues, QueryOptions, QueryWhere, UpdateValues } from "./types.ts";
3
+ declare function quoteIdentifier(identifier: string): string;
4
+ declare function qualifyColumn(tableName: string, column: string): string;
5
+ declare function buildWhereClause<TEntity>(tableName: string, where?: QueryWhere<TEntity>): {
6
+ clause: string;
7
+ params: unknown[];
8
+ };
9
+ declare function resolveSoftDeleteColumn<TEntity>(table: TableDefinition<TEntity>): string | null;
10
+ declare function buildQueryWhereClause<TEntity>(table: TableDefinition<TEntity>, options?: Pick<QueryOptions<TEntity>, "where" | "withTrashed" | "onlyTrashed">): {
11
+ clause: string;
12
+ params: unknown[];
13
+ };
14
+ declare function buildOrderByClause<TEntity>(tableName: string, orderBy?: QueryOptions<TEntity>["orderBy"]): string;
15
+ declare function buildSelectQuery<TEntity>(table: TableDefinition<TEntity>, options?: QueryOptions<TEntity>): {
16
+ text: string;
17
+ params: unknown[];
18
+ };
19
+ declare function buildCountQuery<TEntity>(table: TableDefinition<TEntity>, where?: QueryWhere<TEntity>, options?: Pick<QueryOptions<TEntity>, "withTrashed" | "onlyTrashed">): {
20
+ text: string;
21
+ params: unknown[];
22
+ };
23
+ declare function buildProjectionQuery<TEntity>(table: TableDefinition<TEntity>, expression: string, alias: string, options?: QueryOptions<TEntity>): {
24
+ text: string;
25
+ params: unknown[];
26
+ };
27
+ declare function buildGroupedCountQuery<TEntity, K extends keyof TEntity & string>(table: TableDefinition<TEntity>, column: K, where?: QueryWhere<TEntity>, options?: Pick<QueryOptions<TEntity>, "withTrashed" | "onlyTrashed">): {
28
+ text: string;
29
+ params: unknown[];
30
+ };
31
+ declare function buildInsertQuery<TEntity, PrimaryKey extends keyof TEntity & string>(table: TableDefinition<TEntity, PrimaryKey>, values: MutationValues<TEntity>): {
32
+ text: string;
33
+ params: unknown[];
34
+ };
35
+ declare function buildUpdateQuery<TEntity, PrimaryKey extends keyof TEntity & string>(table: TableDefinition<TEntity, PrimaryKey>, id: TEntity[PrimaryKey], changes: UpdateValues<TEntity, PrimaryKey>): {
36
+ text: string;
37
+ params: unknown[];
38
+ };
39
+ declare function buildSoftDeleteByIdQuery<TEntity, PrimaryKey extends keyof TEntity & string>(table: TableDefinition<TEntity, PrimaryKey>, id: TEntity[PrimaryKey], deletedAt: Date): {
40
+ text: string;
41
+ params: unknown[];
42
+ };
43
+ declare function buildRestoreByIdQuery<TEntity, PrimaryKey extends keyof TEntity & string>(table: TableDefinition<TEntity, PrimaryKey>, id: TEntity[PrimaryKey]): {
44
+ text: string;
45
+ params: unknown[];
46
+ };
47
+ declare function buildDeleteByIdQuery<TEntity, PrimaryKey extends keyof TEntity & string>(table: TableDefinition<TEntity, PrimaryKey>, id: TEntity[PrimaryKey]): {
48
+ text: string;
49
+ params: unknown[];
50
+ };
51
+ export { buildCountQuery, buildDeleteByIdQuery, buildGroupedCountQuery, buildInsertQuery, buildOrderByClause, buildProjectionQuery, buildQueryWhereClause, buildRestoreByIdQuery, buildSelectQuery, buildSoftDeleteByIdQuery, buildUpdateQuery, buildWhereClause, qualifyColumn, quoteIdentifier, resolveSoftDeleteColumn, };