@getstrata/core 0.2.0 → 0.3.2
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.
- package/README.md +6 -0
- package/dist/bootstrap/applicationRegistry.d.ts +16 -0
- package/dist/bootstrap/config.d.ts +20 -0
- package/dist/bootstrap/contracts.d.ts +63 -0
- package/dist/bootstrap/httpKernel.d.ts +26 -0
- package/dist/config/app.d.ts +10 -0
- package/dist/config/contentSecurityPolicy.d.ts +5 -0
- package/dist/config/cors.d.ts +9 -0
- package/dist/config/database.d.ts +10 -0
- package/dist/config/features.d.ts +18 -0
- package/dist/config/frontend.d.ts +6 -0
- package/dist/config/rateLimit.d.ts +9 -0
- package/dist/config/uploads.d.ts +5 -0
- package/dist/core/auth/accessControl.d.ts +8 -0
- package/dist/core/auth/authContext.d.ts +12 -0
- package/dist/core/auth/guard.d.ts +36 -0
- package/dist/core/auth/membershipContext.d.ts +16 -0
- package/dist/core/auth/membershipContextMiddleware.d.ts +3 -0
- package/dist/core/auth/membershipMiddleware.d.ts +2 -0
- package/dist/core/auth/oauth/oidcProvider.d.ts +18 -0
- package/dist/core/auth/oauth/providers.d.ts +22 -0
- package/dist/core/auth/oauth/samlProvider.d.ts +9 -0
- package/dist/core/auth/oauth/types.d.ts +11 -0
- package/dist/core/auth/password.d.ts +3 -0
- package/dist/core/auth/policy.d.ts +15 -0
- package/dist/core/auth/tokenHash.d.ts +3 -0
- package/dist/core/cache/repository.d.ts +17 -0
- package/dist/core/cache/store.d.ts +12 -0
- package/dist/core/cache/taggedCache.d.ts +9 -0
- package/dist/core/cache/tags.d.ts +11 -0
- package/dist/core/crypto/fieldEncryption.d.ts +13 -0
- package/dist/core/crypto/mfaSecret.d.ts +3 -0
- package/dist/core/database/baseRepository.d.ts +47 -0
- package/dist/core/database/connection.d.ts +7 -0
- package/dist/core/database/connectionContext.d.ts +7 -0
- package/dist/core/database/errors.d.ts +12 -0
- package/dist/core/database/index.d.ts +12 -0
- package/dist/core/database/query.d.ts +51 -0
- package/dist/core/database/relationships.d.ts +26 -0
- package/dist/core/database/repositoryQuery.d.ts +20 -0
- package/dist/core/database/table.d.ts +13 -0
- package/dist/core/database/transaction.d.ts +3 -0
- package/dist/core/database/types.d.ts +29 -0
- package/dist/core/errors/http.d.ts +33 -0
- package/dist/core/events/eventBus.d.ts +10 -0
- package/dist/core/events/index.d.ts +4 -0
- package/dist/core/facades/index.d.ts +10 -0
- package/dist/core/http/authMiddleware.d.ts +5 -0
- package/dist/core/http/authorizeMiddleware.d.ts +5 -0
- package/dist/core/http/bodySizeLimitMiddleware.d.ts +4 -0
- package/dist/core/http/conditionalResponse.d.ts +2 -0
- package/dist/core/http/contentNegotiation.d.ts +2 -0
- package/dist/core/http/corsMiddleware.d.ts +3 -0
- package/dist/core/http/csrfMiddleware.d.ts +3 -0
- package/dist/core/http/csrfToken.d.ts +14 -0
- package/dist/core/http/etag.d.ts +18 -0
- package/dist/core/http/flashMiddleware.d.ts +3 -0
- package/dist/core/http/flashSession.d.ts +12 -0
- package/dist/core/http/formRequest.d.ts +10 -0
- package/dist/core/http/index.d.ts +27 -0
- package/dist/core/http/loginThrottleMiddleware.d.ts +11 -0
- package/dist/core/http/memoryThrottleMiddleware.d.ts +9 -0
- package/dist/core/http/metricsMiddleware.d.ts +4 -0
- package/dist/core/http/middleware.d.ts +8 -0
- package/dist/core/http/pagination.d.ts +11 -0
- package/dist/core/http/parseFormBody.d.ts +6 -0
- package/dist/core/http/parseMultipartUpload.d.ts +10 -0
- package/dist/core/http/requestMetaContext.d.ts +16 -0
- package/dist/core/http/requireAbilityMiddleware.d.ts +4 -0
- package/dist/core/http/requireAuthMiddleware.d.ts +4 -0
- package/dist/core/http/requireGlobalAdminMiddleware.d.ts +3 -0
- package/dist/core/http/requireWebAuthMiddleware.d.ts +4 -0
- package/dist/core/http/resources.d.ts +7 -0
- package/dist/core/http/route.d.ts +6 -0
- package/dist/core/http/routeMiddleware.d.ts +3 -0
- package/dist/core/http/routeModelBinding.d.ts +3 -0
- package/dist/core/http/securedRouteModelBinding.d.ts +10 -0
- package/dist/core/http/securityHeadersMiddleware.d.ts +3 -0
- package/dist/core/http/throttleMiddleware.d.ts +11 -0
- package/dist/core/http/validation.d.ts +23 -0
- package/dist/core/http/webErrorResponse.d.ts +5 -0
- package/dist/core/http/webFormRequest.d.ts +6 -0
- package/dist/core/logging/logger.d.ts +17 -0
- package/dist/core/logging/requestLoggingMiddleware.d.ts +3 -0
- package/dist/core/mail/mailer.d.ts +36 -0
- package/dist/core/metrics/prometheus.d.ts +26 -0
- package/dist/core/pagination/index.d.ts +17 -0
- package/dist/core/queue/index.d.ts +19 -0
- package/dist/core/security/publicReads.d.ts +3 -0
- package/dist/core/security/securityEvents.d.ts +6 -0
- package/dist/core/security/tokenExpiry.d.ts +2 -0
- package/dist/core/security/totp.d.ts +3 -0
- package/dist/core/storage/storage.d.ts +41 -0
- package/dist/core/tenant/databaseTenantContext.d.ts +2 -0
- package/dist/core/tenant/resolveTenant.d.ts +3 -0
- package/dist/core/tenant/tenantContext.d.ts +14 -0
- package/dist/core/tenant/tenantDatabaseScope.d.ts +7 -0
- package/dist/core/tenant/tenantMiddleware.d.ts +6 -0
- package/dist/core/tracing/otel.d.ts +26 -0
- package/dist/core/tracing/traceContext.d.ts +10 -0
- package/dist/core/tracing/tracingMiddleware.d.ts +3 -0
- package/dist/core/view/etaViewEngine.d.ts +15 -0
- package/dist/core/view/htmlResponse.d.ts +6 -0
- package/dist/core/view/index.d.ts +5 -0
- package/dist/core/view/viewEngine.d.ts +6 -0
- package/dist/core/view/webLayoutData.d.ts +17 -0
- package/dist/db/connection/createConnection.d.ts +6 -0
- package/dist/db/connection/index.d.ts +11 -0
- package/dist/domain/abilities.d.ts +5 -0
- package/dist/domain/auth.d.ts +4 -0
- package/dist/framework/public-api.d.ts +35 -0
- package/dist/index.js +120 -2
- package/dist/modules/organization/memberRepository.d.ts +14 -0
- package/dist/modules/organization/memberTypes.d.ts +9 -0
- package/dist/modules/user/apiTokenRepository.d.ts +8 -0
- package/dist/modules/user/apiTokenTable.d.ts +3 -0
- package/dist/modules/user/authService.d.ts +23 -0
- package/dist/modules/user/notificationRepository.d.ts +6 -0
- package/dist/modules/user/notificationService.d.ts +25 -0
- package/dist/modules/user/notificationTable.d.ts +3 -0
- package/dist/modules/user/notificationTypes.d.ts +12 -0
- package/dist/modules/user/oauthIdentityRepository.d.ts +9 -0
- package/dist/modules/user/provider.d.ts +11 -0
- package/dist/modules/user/repository.d.ts +12 -0
- package/dist/modules/user/table.d.ts +3 -0
- package/dist/modules/user/tokenService.d.ts +29 -0
- package/dist/modules/user/types.d.ts +46 -0
- package/dist/types/services.d.ts +16 -0
- package/package.json +7 -6
- 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,20 @@
|
|
|
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 CORE_TOKEN_SERVICE_TOKEN = "core.tokenService";
|
|
13
|
+
declare const AUTH_DEV_HEADERS_CONFIG_KEY = "auth.allowDevHeaders";
|
|
14
|
+
declare const DEFAULT_APP_PORT = 3000;
|
|
15
|
+
declare const DEFAULT_CACHE_TTL_MS = 3600000;
|
|
16
|
+
declare const DEFAULT_CACHE_MAX_ENTRIES = 100;
|
|
17
|
+
declare const DEFAULT_CACHE_DRIVER = "array";
|
|
18
|
+
declare const DEFAULT_API_TOKEN = "";
|
|
19
|
+
declare const DEFAULT_QUEUE_DRIVER = "sync";
|
|
20
|
+
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, CORE_TOKEN_SERVICE_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,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,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,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,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,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,47 @@
|
|
|
1
|
+
import { type PaginatedResult } from "../pagination/index.ts";
|
|
2
|
+
import { type BelongsToRelation, type HasManyRelation } from "./relationships.ts";
|
|
3
|
+
import { RepositoryQuery } from "./repositoryQuery.ts";
|
|
4
|
+
import type { TableDefinition } from "./table.ts";
|
|
5
|
+
import type { MutationValues, QueryOptions, QueryWhere, UpdateValues } from "./types.ts";
|
|
6
|
+
interface DatabaseConnection {
|
|
7
|
+
unsafe<T>(query: string, params?: readonly unknown[]): Promise<T[]>;
|
|
8
|
+
}
|
|
9
|
+
type ErrorFactory<TValue> = (value: TValue) => Error;
|
|
10
|
+
declare class BaseRepository<TEntity extends object, PrimaryKey extends keyof TEntity & string> {
|
|
11
|
+
protected readonly table: TableDefinition<TEntity, PrimaryKey>;
|
|
12
|
+
protected readonly connection: DatabaseConnection;
|
|
13
|
+
constructor(table: TableDefinition<TEntity, PrimaryKey>, connection?: DatabaseConnection);
|
|
14
|
+
findAll(options?: QueryOptions<TEntity>): Promise<TEntity[]>;
|
|
15
|
+
paginate(options: {
|
|
16
|
+
page: number;
|
|
17
|
+
perPage: number;
|
|
18
|
+
} & Omit<QueryOptions<TEntity>, "limit" | "offset">): Promise<PaginatedResult<TEntity>>;
|
|
19
|
+
findById(id: TEntity[PrimaryKey]): Promise<TEntity | null>;
|
|
20
|
+
findByIdOrThrow(id: TEntity[PrimaryKey], errorFactory?: ErrorFactory<TEntity[PrimaryKey]>): Promise<TEntity>;
|
|
21
|
+
findByIds(ids: readonly TEntity[PrimaryKey][]): Promise<TEntity[]>;
|
|
22
|
+
firstOrNull(where: QueryWhere<TEntity>, options?: Omit<QueryOptions<TEntity>, "where" | "limit">): Promise<TEntity | null>;
|
|
23
|
+
create(values: MutationValues<TEntity>): Promise<TEntity>;
|
|
24
|
+
updateById(id: TEntity[PrimaryKey], changes: UpdateValues<TEntity, PrimaryKey>): Promise<TEntity | null>;
|
|
25
|
+
updateByIdOrThrow(id: TEntity[PrimaryKey], changes: UpdateValues<TEntity, PrimaryKey>, errorFactory?: ErrorFactory<TEntity[PrimaryKey]>): Promise<TEntity>;
|
|
26
|
+
deleteById(id: TEntity[PrimaryKey]): Promise<boolean>;
|
|
27
|
+
softDeleteById(id: TEntity[PrimaryKey]): Promise<boolean>;
|
|
28
|
+
forceDeleteById(id: TEntity[PrimaryKey]): Promise<boolean>;
|
|
29
|
+
restoreById(id: TEntity[PrimaryKey]): Promise<TEntity | null>;
|
|
30
|
+
withConnection(connection: DatabaseConnection): this;
|
|
31
|
+
getConnection(): DatabaseConnection;
|
|
32
|
+
query(where?: QueryWhere<TEntity>): RepositoryQuery<TEntity, PrimaryKey>;
|
|
33
|
+
protected findWhere(where: QueryWhere<TEntity>, options?: Omit<QueryOptions<TEntity>, "where">): Promise<TEntity[]>;
|
|
34
|
+
protected countWhere(where?: QueryWhere<TEntity>, options?: Pick<QueryOptions<TEntity>, "withTrashed" | "onlyTrashed">): Promise<number>;
|
|
35
|
+
protected averageColumn(column: keyof TEntity & string, where?: QueryWhere<TEntity>): Promise<number>;
|
|
36
|
+
protected averageExpression(expression: string, alias: string, where?: QueryWhere<TEntity>): Promise<number>;
|
|
37
|
+
protected pluckNumberValues(expression: string, alias: string, options?: QueryOptions<TEntity>): Promise<number[]>;
|
|
38
|
+
protected countGroupedBy<K extends keyof TEntity & string>(column: K, where?: QueryWhere<TEntity>): Promise<Array<{
|
|
39
|
+
value: TEntity[K] | null;
|
|
40
|
+
count: number;
|
|
41
|
+
}>>;
|
|
42
|
+
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[]>;
|
|
43
|
+
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[]>>;
|
|
44
|
+
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>>;
|
|
45
|
+
}
|
|
46
|
+
export default BaseRepository;
|
|
47
|
+
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,12 @@
|
|
|
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 { RepositoryQuery } from "./repositoryQuery.ts";
|
|
9
|
+
export type { TableDefinition } from "./table.ts";
|
|
10
|
+
export { defineTable } from "./table.ts";
|
|
11
|
+
export { runInTransaction } from "./transaction.ts";
|
|
12
|
+
export type { DatabaseComparable, DatabaseScalar, MutationValues, QueryFilterValue, QueryOperator, QueryOptions, QueryOrder, QueryWhere, UpdateValues, } from "./types.ts";
|