@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
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
interface MetricLabels {
|
|
2
|
+
method: string;
|
|
3
|
+
path: string;
|
|
4
|
+
status: string;
|
|
5
|
+
}
|
|
6
|
+
declare class PrometheusRegistry {
|
|
7
|
+
private readonly httpRequestsTotal;
|
|
8
|
+
private readonly httpRequestDurationMs;
|
|
9
|
+
incrementHttpRequest(labels: MetricLabels): void;
|
|
10
|
+
observeHttpDuration(labels: MetricLabels, durationMs: number): void;
|
|
11
|
+
renderMetrics(): string;
|
|
12
|
+
resetForTests(): void;
|
|
13
|
+
getHttpRequestSummary(): {
|
|
14
|
+
totalRequests: number;
|
|
15
|
+
byStatus: Record<string, number>;
|
|
16
|
+
topPaths: Array<{
|
|
17
|
+
method: string;
|
|
18
|
+
path: string;
|
|
19
|
+
count: number;
|
|
20
|
+
}>;
|
|
21
|
+
};
|
|
22
|
+
private metricKey;
|
|
23
|
+
}
|
|
24
|
+
declare const prometheusRegistry: PrometheusRegistry;
|
|
25
|
+
export type { MetricLabels };
|
|
26
|
+
export { PrometheusRegistry, prometheusRegistry };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface PaginationMeta {
|
|
2
|
+
page: number;
|
|
3
|
+
per_page: number;
|
|
4
|
+
total: number;
|
|
5
|
+
last_page: number;
|
|
6
|
+
}
|
|
7
|
+
interface PaginatedResult<T> {
|
|
8
|
+
data: T[];
|
|
9
|
+
meta: PaginationMeta;
|
|
10
|
+
}
|
|
11
|
+
declare function buildPaginationMeta(input: {
|
|
12
|
+
page: number;
|
|
13
|
+
perPage: number;
|
|
14
|
+
total: number;
|
|
15
|
+
}): PaginationMeta;
|
|
16
|
+
export type { PaginatedResult, PaginationMeta };
|
|
17
|
+
export { buildPaginationMeta };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
type QueuePriority = "high" | "default" | "low";
|
|
2
|
+
declare abstract class Job<TPayload extends object = object> {
|
|
3
|
+
readonly maxAttempts?: number;
|
|
4
|
+
readonly backoffMs?: number;
|
|
5
|
+
readonly priority?: QueuePriority;
|
|
6
|
+
abstract handle(payload: TPayload): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
interface Queue {
|
|
9
|
+
dispatch<TPayload extends object>(job: Job<TPayload>, payload: TPayload): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
declare class SyncQueue implements Queue {
|
|
12
|
+
dispatch<TPayload extends object>(job: Job<TPayload>, payload: TPayload): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
declare class AsyncQueue implements Queue {
|
|
15
|
+
dispatch<TPayload extends object>(job: Job<TPayload>, payload: TPayload): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
declare function createQueue(driver: "sync" | "async"): Queue;
|
|
18
|
+
export type { Queue, QueuePriority };
|
|
19
|
+
export { AsyncQueue, createQueue, Job, SyncQueue };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { S3Client } from "bun";
|
|
2
|
+
interface StorageDriver {
|
|
3
|
+
put(path: string, contents: string | Uint8Array): Promise<string>;
|
|
4
|
+
get(path: string): Promise<Uint8Array | null>;
|
|
5
|
+
delete(path: string): Promise<boolean>;
|
|
6
|
+
}
|
|
7
|
+
interface S3StorageConfig {
|
|
8
|
+
accessKeyId: string;
|
|
9
|
+
secretAccessKey: string;
|
|
10
|
+
bucket: string;
|
|
11
|
+
region?: string;
|
|
12
|
+
endpoint?: string;
|
|
13
|
+
}
|
|
14
|
+
declare class LocalStorageDriver implements StorageDriver {
|
|
15
|
+
private readonly rootDirectory;
|
|
16
|
+
constructor(rootDirectory: string);
|
|
17
|
+
private resolvePath;
|
|
18
|
+
put(path: string, contents: string | Uint8Array): Promise<string>;
|
|
19
|
+
get(path: string): Promise<Uint8Array | null>;
|
|
20
|
+
delete(path: string): Promise<boolean>;
|
|
21
|
+
}
|
|
22
|
+
declare class S3StorageDriver implements StorageDriver {
|
|
23
|
+
private readonly client;
|
|
24
|
+
constructor(client: S3Client);
|
|
25
|
+
put(path: string, contents: string | Uint8Array): Promise<string>;
|
|
26
|
+
get(path: string): Promise<Uint8Array | null>;
|
|
27
|
+
delete(path: string): Promise<boolean>;
|
|
28
|
+
}
|
|
29
|
+
declare class StorageManager {
|
|
30
|
+
private readonly driver;
|
|
31
|
+
constructor(driver: StorageDriver);
|
|
32
|
+
put(path: string, contents: string | Uint8Array): Promise<string>;
|
|
33
|
+
get(path: string): Promise<Uint8Array | null>;
|
|
34
|
+
delete(path: string): Promise<boolean>;
|
|
35
|
+
}
|
|
36
|
+
declare function resolveS3Config(): S3StorageConfig;
|
|
37
|
+
declare function createS3Client(config?: S3StorageConfig): S3Client;
|
|
38
|
+
declare function createStorageDriver(): StorageDriver;
|
|
39
|
+
declare function storage(): StorageManager;
|
|
40
|
+
export type { S3StorageConfig, StorageDriver };
|
|
41
|
+
export { createS3Client, createStorageDriver, LocalStorageDriver, resolveS3Config, S3StorageDriver, StorageManager, storage, };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
type TenantContext = {
|
|
3
|
+
id: number;
|
|
4
|
+
slug: string;
|
|
5
|
+
plan: "free" | "pro" | "enterprise";
|
|
6
|
+
region: "eu" | "us" | "apac";
|
|
7
|
+
};
|
|
8
|
+
declare const tenantContext: AsyncLocalStorage<TenantContext>;
|
|
9
|
+
declare function runWithTenant<T>(tenant: TenantContext, callback: () => T | Promise<T>): T | Promise<T>;
|
|
10
|
+
declare function currentTenant(): TenantContext | null;
|
|
11
|
+
declare function currentTenantId(): number;
|
|
12
|
+
declare function rateLimitMultiplierForPlan(plan: TenantContext["plan"]): number;
|
|
13
|
+
export type { TenantContext };
|
|
14
|
+
export { currentTenant, currentTenantId, rateLimitMultiplierForPlan, runWithTenant, tenantContext };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type TenantContext } from "./tenantContext";
|
|
2
|
+
type TransactionHandle = {
|
|
3
|
+
unsafe(query: string, params?: readonly unknown[]): Promise<unknown[]>;
|
|
4
|
+
};
|
|
5
|
+
declare function applyTenantContextToTransaction(transaction: TransactionHandle, tenantId: number): Promise<void>;
|
|
6
|
+
declare function runWithTenantDatabase<T>(tenant: TenantContext, callback: () => T | Promise<T>): Promise<T>;
|
|
7
|
+
export { applyTenantContextToTransaction, runWithTenantDatabase };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { TenantContext } from "./tenantContext";
|
|
2
|
+
declare const DEFAULT_TENANT: TenantContext;
|
|
3
|
+
declare function resolveUserTenantId(userId: number): Promise<number>;
|
|
4
|
+
declare function auditChecksum(payload: Record<string, unknown>): string;
|
|
5
|
+
declare function createTenantMiddleware(): (request: Request, next: () => Promise<Response>) => Promise<Response>;
|
|
6
|
+
export { auditChecksum, createTenantMiddleware, DEFAULT_TENANT, resolveUserTenantId };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
interface OtelSpan {
|
|
2
|
+
traceId: string;
|
|
3
|
+
spanId: string;
|
|
4
|
+
name: string;
|
|
5
|
+
startTimeUnixNano: string;
|
|
6
|
+
endTimeUnixNano: string;
|
|
7
|
+
attributes: Array<{
|
|
8
|
+
key: string;
|
|
9
|
+
value: {
|
|
10
|
+
stringValue: string;
|
|
11
|
+
};
|
|
12
|
+
}>;
|
|
13
|
+
status: {
|
|
14
|
+
code: number;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
declare function createSpan(input: {
|
|
18
|
+
traceId: string;
|
|
19
|
+
name: string;
|
|
20
|
+
startedAt: number;
|
|
21
|
+
endedAt: number;
|
|
22
|
+
attributes?: Record<string, string>;
|
|
23
|
+
}): OtelSpan;
|
|
24
|
+
declare function exportOtelSpan(span: OtelSpan): Promise<void>;
|
|
25
|
+
export type { OtelSpan };
|
|
26
|
+
export { createSpan, exportOtelSpan };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
type TraceContext = {
|
|
3
|
+
traceId: string;
|
|
4
|
+
spanId: string;
|
|
5
|
+
};
|
|
6
|
+
declare const traceContextStorage: AsyncLocalStorage<TraceContext>;
|
|
7
|
+
declare function runWithTraceContext<T>(context: TraceContext, callback: () => T | Promise<T>): T | Promise<T>;
|
|
8
|
+
declare function currentTraceId(): string | null;
|
|
9
|
+
export type { TraceContext };
|
|
10
|
+
export { currentTraceId, runWithTraceContext, traceContextStorage };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ViewEngine } from "./viewEngine";
|
|
2
|
+
declare const DEFAULT_VIEWS_DIRECTORY: string;
|
|
3
|
+
declare const DEFAULT_LAYOUT = "layouts/app.eta";
|
|
4
|
+
interface RenderOptions {
|
|
5
|
+
layout?: string | false;
|
|
6
|
+
}
|
|
7
|
+
type LayoutDataResolver = () => Promise<Record<string, unknown>>;
|
|
8
|
+
declare class EtaViewEngine implements ViewEngine {
|
|
9
|
+
private readonly eta;
|
|
10
|
+
private readonly resolveLayoutData?;
|
|
11
|
+
constructor(viewsDirectory?: string, resolveLayoutData?: LayoutDataResolver);
|
|
12
|
+
render(name: string, data?: Record<string, unknown>, options?: RenderOptions): Promise<string>;
|
|
13
|
+
}
|
|
14
|
+
export type { RenderOptions };
|
|
15
|
+
export { DEFAULT_LAYOUT, DEFAULT_VIEWS_DIRECTORY, EtaViewEngine };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { DEFAULT_VIEWS_DIRECTORY, EtaViewEngine } from "./etaViewEngine";
|
|
2
|
+
export { htmlResponse, isHtmxRequest } from "./htmlResponse";
|
|
3
|
+
export type { ViewEngine } from "./viewEngine";
|
|
4
|
+
export type { WebLayoutAuthUser, WebLayoutData } from "./webLayoutData";
|
|
5
|
+
export { resolveWebLayoutData } from "./webLayoutData";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ServiceContainer } from "../../bootstrap/contracts";
|
|
2
|
+
interface WebLayoutAuthUser {
|
|
3
|
+
id: number;
|
|
4
|
+
email: string;
|
|
5
|
+
role: string;
|
|
6
|
+
}
|
|
7
|
+
interface WebLayoutData {
|
|
8
|
+
authUser: WebLayoutAuthUser | null;
|
|
9
|
+
csrfToken: string;
|
|
10
|
+
flash: {
|
|
11
|
+
level: string;
|
|
12
|
+
message: string;
|
|
13
|
+
} | null;
|
|
14
|
+
}
|
|
15
|
+
declare function resolveWebLayoutData(container: ServiceContainer, request?: Request): Promise<Record<string, unknown>>;
|
|
16
|
+
export type { WebLayoutAuthUser, WebLayoutData };
|
|
17
|
+
export { resolveWebLayoutData };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { SQL } from "bun";
|
|
2
|
+
import type { DatabaseConfig } from "../../config/database";
|
|
3
|
+
type DatabaseConnection = InstanceType<typeof SQL>;
|
|
4
|
+
declare function createDatabaseConnection(config: DatabaseConfig): DatabaseConnection;
|
|
5
|
+
export type { DatabaseConnection };
|
|
6
|
+
export { createDatabaseConnection };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type DatabaseConnection } from "./createConnection";
|
|
2
|
+
declare function getDatabase(): DatabaseConnection;
|
|
3
|
+
declare function pingDatabase(connection?: DatabaseConnection): Promise<boolean>;
|
|
4
|
+
declare function ensureDatabaseConnection(): Promise<DatabaseConnection>;
|
|
5
|
+
declare function closeDatabase(): Promise<void>;
|
|
6
|
+
declare function replaceDatabaseConnectionForTests(connection?: DatabaseConnection): Promise<void>;
|
|
7
|
+
declare function resetDatabaseConnectionForTests(connection: DatabaseConnection): void;
|
|
8
|
+
declare const db: Bun.SQL;
|
|
9
|
+
export default db;
|
|
10
|
+
export type { DatabaseConnection };
|
|
11
|
+
export { closeDatabase, ensureDatabaseConnection, getDatabase, pingDatabase, replaceDatabaseConnectionForTests, resetDatabaseConnectionForTests, };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
declare const MEMBER_ABILITIES: readonly ["organizations:read", "projects:read", "projects:create", "tasks:read", "tasks:create", "comments:read", "comments:create", "attachments:read", "attachments:create", "auth:tokens:read", "auth:tokens:write"];
|
|
2
|
+
declare const ADMIN_ABILITIES: readonly ["organizations:read", "projects:read", "projects:create", "tasks:read", "tasks:create", "comments:read", "comments:create", "attachments:read", "attachments:create", "auth:tokens:read", "auth:tokens:write", "organizations:create", "organizations:update", "organizations:delete", "projects:update", "projects:delete", "tasks:update", "tasks:delete", "comments:update", "comments:delete", "attachments:delete", "webhooks:read", "webhooks:write", "audit:read"];
|
|
3
|
+
declare const PLATFORM_ADMIN_ABILITIES: readonly ["*"];
|
|
4
|
+
declare function resolveAbilitiesForRole(role: string | null | undefined): string[];
|
|
5
|
+
export { ADMIN_ABILITIES, MEMBER_ABILITIES, PLATFORM_ADMIN_ABILITIES, resolveAbilitiesForRole };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable framework surface for application modules and future package extraction.
|
|
3
|
+
* Import from `@getstrata/core` (workspace) or `src/framework/public-api`.
|
|
4
|
+
*/
|
|
5
|
+
export type { ServiceProvider } from "../bootstrap/contracts";
|
|
6
|
+
export { ConfigStore, resolveService, ServiceContainer, } from "../bootstrap/contracts";
|
|
7
|
+
export type { AuthUser } from "../core/auth/authContext";
|
|
8
|
+
export { currentAuthUser, runWithAuthUser } from "../core/auth/authContext";
|
|
9
|
+
export { Policy } from "../core/auth/policy";
|
|
10
|
+
export { default as CacheRepository } from "../core/cache/repository";
|
|
11
|
+
export { CACHE_TAGS } from "../core/cache/tags";
|
|
12
|
+
export type { DatabaseConnection } from "../core/database/baseRepository";
|
|
13
|
+
export { default as BaseRepository } from "../core/database/baseRepository";
|
|
14
|
+
export type { BelongsToRelation, HasManyRelation } from "../core/database/relationships";
|
|
15
|
+
export { belongsTo, hasMany, indexBelongsToRelation, indexHasManyRelation, } from "../core/database/relationships";
|
|
16
|
+
export { RepositoryQuery } from "../core/database/repositoryQuery";
|
|
17
|
+
export { defineTable } from "../core/database/table";
|
|
18
|
+
export type { QueryOptions, QueryOrder, QueryWhere, } from "../core/database/types";
|
|
19
|
+
export { BadRequestError, ConflictError, ForbiddenError, NotFoundError, PreconditionFailedError, UnauthorizedError, UnprocessableEntityError, ValidationError, } from "../core/errors/http";
|
|
20
|
+
export { EventBus } from "../core/events/eventBus";
|
|
21
|
+
export { auth, cache, config, events, log, mail, policyGate, queue, storage, } from "../core/facades";
|
|
22
|
+
export { createdResponse, jsonResponse, noContentResponse, paginatedResponse, parsePaginationQuery, securedBindRouteModel, withErrorHandling, } from "../core/http";
|
|
23
|
+
export { assertIfMatch, etagFromResource, isEtagEnabled, } from "../core/http/etag";
|
|
24
|
+
export { FormRequest } from "../core/http/formRequest";
|
|
25
|
+
export { createMetricsMiddleware, normalizeMetricPath } from "../core/http/metricsMiddleware";
|
|
26
|
+
export type { Middleware, RouteHandler } from "../core/http/middleware";
|
|
27
|
+
export { WebFormRequest } from "../core/http/webFormRequest";
|
|
28
|
+
export type { MailDriver, MailMessage } from "../core/mail/mailer";
|
|
29
|
+
export { LogMailDriver, Mailer, mailer } from "../core/mail/mailer";
|
|
30
|
+
export type { MetricLabels } from "../core/metrics/prometheus";
|
|
31
|
+
export { PrometheusRegistry, prometheusRegistry } from "../core/metrics/prometheus";
|
|
32
|
+
export type { Queue, QueuePriority } from "../core/queue";
|
|
33
|
+
export { AsyncQueue, createQueue, Job, SyncQueue } from "../core/queue";
|
|
34
|
+
export type { StorageDriver } from "../core/storage/storage";
|
|
35
|
+
export { LocalStorageDriver, StorageManager } from "../core/storage/storage";
|
package/dist/index.js
CHANGED
|
@@ -285,9 +285,12 @@ function createDatabaseConnection(config) {
|
|
|
285
285
|
|
|
286
286
|
// ../../src/db/connection/index.ts
|
|
287
287
|
var connectionHolder = {
|
|
288
|
-
connection:
|
|
288
|
+
connection: null
|
|
289
289
|
};
|
|
290
290
|
function getDatabase() {
|
|
291
|
+
if (!connectionHolder.connection) {
|
|
292
|
+
connectionHolder.connection = createDatabaseConnection(databaseConfig);
|
|
293
|
+
}
|
|
291
294
|
return connectionHolder.connection;
|
|
292
295
|
}
|
|
293
296
|
var POOL_CONNECTION_METHODS = new Set(["begin", "close", "connect"]);
|
|
@@ -530,11 +533,23 @@ function buildQueryWhereClause(table, options = {}) {
|
|
|
530
533
|
params
|
|
531
534
|
};
|
|
532
535
|
}
|
|
536
|
+
function isQueryOrder(value) {
|
|
537
|
+
return "column" in value;
|
|
538
|
+
}
|
|
533
539
|
function normalizeOrderBy(orderBy) {
|
|
534
540
|
if (!orderBy) {
|
|
535
541
|
return [];
|
|
536
542
|
}
|
|
537
|
-
|
|
543
|
+
if (Array.isArray(orderBy)) {
|
|
544
|
+
return orderBy;
|
|
545
|
+
}
|
|
546
|
+
if (isQueryOrder(orderBy)) {
|
|
547
|
+
return [orderBy];
|
|
548
|
+
}
|
|
549
|
+
return Object.entries(orderBy).map(([column, direction]) => ({
|
|
550
|
+
column,
|
|
551
|
+
direction
|
|
552
|
+
}));
|
|
538
553
|
}
|
|
539
554
|
function buildOrderByClause(tableName, orderBy) {
|
|
540
555
|
const parts = normalizeOrderBy(orderBy).map(({ column, direction }) => {
|
|
@@ -684,6 +699,18 @@ function buildDeleteByIdQuery(table, id) {
|
|
|
684
699
|
}
|
|
685
700
|
|
|
686
701
|
// ../../src/core/database/relationships.ts
|
|
702
|
+
function hasMany(definition) {
|
|
703
|
+
return {
|
|
704
|
+
type: "hasMany",
|
|
705
|
+
...definition
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
function belongsTo(definition) {
|
|
709
|
+
return {
|
|
710
|
+
type: "belongsTo",
|
|
711
|
+
...definition
|
|
712
|
+
};
|
|
713
|
+
}
|
|
687
714
|
function indexHasManyRelation(parents, children, relation) {
|
|
688
715
|
const groups = new Map;
|
|
689
716
|
for (const parent of parents) {
|
|
@@ -715,6 +742,86 @@ function indexBelongsToRelation(children, parents, relation) {
|
|
|
715
742
|
return result;
|
|
716
743
|
}
|
|
717
744
|
|
|
745
|
+
// ../../src/core/database/repositoryQuery.ts
|
|
746
|
+
class RepositoryQuery {
|
|
747
|
+
repository;
|
|
748
|
+
whereClause;
|
|
749
|
+
queryOptions;
|
|
750
|
+
eagerLoads = [];
|
|
751
|
+
constructor(repository, whereClause = {}, queryOptions = {}) {
|
|
752
|
+
this.repository = repository;
|
|
753
|
+
this.whereClause = whereClause;
|
|
754
|
+
this.queryOptions = queryOptions;
|
|
755
|
+
}
|
|
756
|
+
where(where) {
|
|
757
|
+
this.whereClause = { ...this.whereClause, ...where };
|
|
758
|
+
return this;
|
|
759
|
+
}
|
|
760
|
+
orderBy(orderBy) {
|
|
761
|
+
this.queryOptions = { ...this.queryOptions, orderBy };
|
|
762
|
+
return this;
|
|
763
|
+
}
|
|
764
|
+
limit(limit) {
|
|
765
|
+
this.queryOptions = { ...this.queryOptions, limit };
|
|
766
|
+
return this;
|
|
767
|
+
}
|
|
768
|
+
withHasMany(as, relation, childRepository, options = {}) {
|
|
769
|
+
this.eagerLoads.push({
|
|
770
|
+
kind: "hasMany",
|
|
771
|
+
as,
|
|
772
|
+
relation,
|
|
773
|
+
repository: childRepository,
|
|
774
|
+
options
|
|
775
|
+
});
|
|
776
|
+
return this;
|
|
777
|
+
}
|
|
778
|
+
withBelongsTo(as, relation, parentRepository, options = {}) {
|
|
779
|
+
this.eagerLoads.push({
|
|
780
|
+
kind: "belongsTo",
|
|
781
|
+
as,
|
|
782
|
+
relation,
|
|
783
|
+
repository: parentRepository,
|
|
784
|
+
options
|
|
785
|
+
});
|
|
786
|
+
return this;
|
|
787
|
+
}
|
|
788
|
+
async get() {
|
|
789
|
+
const rows = await this.repository.findAll({
|
|
790
|
+
...this.queryOptions,
|
|
791
|
+
where: this.whereClause
|
|
792
|
+
});
|
|
793
|
+
return await this.attach(rows);
|
|
794
|
+
}
|
|
795
|
+
async first() {
|
|
796
|
+
const rows = await this.get();
|
|
797
|
+
return rows[0] ?? null;
|
|
798
|
+
}
|
|
799
|
+
async attach(rows) {
|
|
800
|
+
if (rows.length === 0 || this.eagerLoads.length === 0) {
|
|
801
|
+
return rows.map((row) => ({ ...row }));
|
|
802
|
+
}
|
|
803
|
+
let result = rows.map((row) => ({ ...row }));
|
|
804
|
+
for (const load of this.eagerLoads) {
|
|
805
|
+
if (load.kind === "hasMany") {
|
|
806
|
+
const relation2 = load.relation;
|
|
807
|
+
const grouped2 = await load.repository.withConnection(this.repository.getConnection()).loadHasManyForParents(rows, relation2, load.options);
|
|
808
|
+
result = result.map((row) => ({
|
|
809
|
+
...row,
|
|
810
|
+
[load.as]: grouped2.get(row[relation2.localKey]) ?? []
|
|
811
|
+
}));
|
|
812
|
+
continue;
|
|
813
|
+
}
|
|
814
|
+
const relation = load.relation;
|
|
815
|
+
const grouped = await this.repository.loadBelongsToForParents(rows, relation, load.repository, load.options);
|
|
816
|
+
result = result.map((row) => ({
|
|
817
|
+
...row,
|
|
818
|
+
[load.as]: grouped.get(row[relation.foreignKey])
|
|
819
|
+
}));
|
|
820
|
+
}
|
|
821
|
+
return result;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
|
|
718
825
|
// ../../src/core/database/baseRepository.ts
|
|
719
826
|
class BaseRepository {
|
|
720
827
|
table;
|
|
@@ -851,6 +958,12 @@ class BaseRepository {
|
|
|
851
958
|
clone.connection = connection;
|
|
852
959
|
return clone;
|
|
853
960
|
}
|
|
961
|
+
getConnection() {
|
|
962
|
+
return this.connection;
|
|
963
|
+
}
|
|
964
|
+
query(where = {}) {
|
|
965
|
+
return new RepositoryQuery(this, where);
|
|
966
|
+
}
|
|
854
967
|
async findWhere(where, options = {}) {
|
|
855
968
|
return await this.findAll({ ...options, where });
|
|
856
969
|
}
|
|
@@ -2148,6 +2261,9 @@ export {
|
|
|
2148
2261
|
log,
|
|
2149
2262
|
jsonResponse,
|
|
2150
2263
|
isEtagEnabled,
|
|
2264
|
+
indexHasManyRelation,
|
|
2265
|
+
indexBelongsToRelation,
|
|
2266
|
+
hasMany,
|
|
2151
2267
|
events,
|
|
2152
2268
|
etagFromResource,
|
|
2153
2269
|
defineTable,
|
|
@@ -2157,6 +2273,7 @@ export {
|
|
|
2157
2273
|
createMetricsMiddleware,
|
|
2158
2274
|
config,
|
|
2159
2275
|
cache,
|
|
2276
|
+
belongsTo,
|
|
2160
2277
|
auth,
|
|
2161
2278
|
assertIfMatch,
|
|
2162
2279
|
WebFormRequest,
|
|
@@ -2166,6 +2283,7 @@ export {
|
|
|
2166
2283
|
SyncQueue,
|
|
2167
2284
|
StorageManager,
|
|
2168
2285
|
ServiceContainer,
|
|
2286
|
+
RepositoryQuery,
|
|
2169
2287
|
PrometheusRegistry,
|
|
2170
2288
|
PreconditionFailedError,
|
|
2171
2289
|
Policy,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { OrganizationMemberRecord, OrganizationMemberRole } from "./memberTypes";
|
|
2
|
+
declare class OrganizationMemberRepository {
|
|
3
|
+
constructor();
|
|
4
|
+
findMembership(userId: number, organizationId: number): Promise<OrganizationMemberRecord | null>;
|
|
5
|
+
listForUser(userId: number): Promise<OrganizationMemberRecord[]>;
|
|
6
|
+
listForOrganization(organizationId: number): Promise<OrganizationMemberRecord[]>;
|
|
7
|
+
addMember(input: {
|
|
8
|
+
organizationId: number;
|
|
9
|
+
userId: number;
|
|
10
|
+
role?: OrganizationMemberRole;
|
|
11
|
+
}): Promise<OrganizationMemberRecord>;
|
|
12
|
+
removeMember(organizationId: number, userId: number): Promise<boolean>;
|
|
13
|
+
}
|
|
14
|
+
export default OrganizationMemberRepository;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type OrganizationMemberRole = "owner" | "admin" | "member";
|
|
2
|
+
type OrganizationMemberRecord = {
|
|
3
|
+
id: number;
|
|
4
|
+
organization_id: number;
|
|
5
|
+
user_id: number;
|
|
6
|
+
role: OrganizationMemberRole;
|
|
7
|
+
created_at: Date;
|
|
8
|
+
};
|
|
9
|
+
export type { OrganizationMemberRecord, OrganizationMemberRole };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { BaseRepository } from "../../core/database";
|
|
2
|
+
import type { ApiTokenRecord } from "./types";
|
|
3
|
+
declare class ApiTokenRepository extends BaseRepository<ApiTokenRecord, "id"> {
|
|
4
|
+
constructor();
|
|
5
|
+
findByTokenHash(tokenHash: string): Promise<ApiTokenRecord | null>;
|
|
6
|
+
touchLastUsedAt(id: number): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
export default ApiTokenRepository;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { OAuthProvider } from "../../core/auth/oauth/types";
|
|
2
|
+
import type OAuthIdentityRepository from "./oauthIdentityRepository";
|
|
3
|
+
import type UserRepository from "./repository";
|
|
4
|
+
import type TokenService from "./tokenService";
|
|
5
|
+
import type { CreatedApiToken } from "./types";
|
|
6
|
+
interface LoginOptions {
|
|
7
|
+
mfaCode?: string;
|
|
8
|
+
}
|
|
9
|
+
declare class AuthService {
|
|
10
|
+
private readonly users;
|
|
11
|
+
private readonly tokens;
|
|
12
|
+
private readonly oauthIdentities;
|
|
13
|
+
private readonly oauthProviders;
|
|
14
|
+
constructor(users: UserRepository, tokens: TokenService, oauthIdentities: OAuthIdentityRepository);
|
|
15
|
+
registerOAuthProvider(provider: OAuthProvider): void;
|
|
16
|
+
getOAuthProvider(name: string): OAuthProvider | undefined;
|
|
17
|
+
loginWithPassword(email: string, password: string, options?: LoginOptions): Promise<CreatedApiToken>;
|
|
18
|
+
loginWithOAuth(providerName: string, code: string): Promise<CreatedApiToken>;
|
|
19
|
+
buildOAuthAuthorizationUrl(providerName: string, state: string): string;
|
|
20
|
+
private findOrCreateOAuthUser;
|
|
21
|
+
}
|
|
22
|
+
export default AuthService;
|
|
23
|
+
export type { LoginOptions };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { BaseRepository } from "../../core/database";
|
|
2
|
+
import type { NotificationRecord } from "./notificationTypes";
|
|
3
|
+
declare class NotificationRepository extends BaseRepository<NotificationRecord, "id"> {
|
|
4
|
+
constructor();
|
|
5
|
+
}
|
|
6
|
+
export default NotificationRepository;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { PaginatedResult } from "../../core/pagination";
|
|
2
|
+
import type NotificationRepository from "./notificationRepository";
|
|
3
|
+
import type { NotificationRecord } from "./notificationTypes";
|
|
4
|
+
interface CreateNotificationInput {
|
|
5
|
+
userId: number;
|
|
6
|
+
tenantId: number;
|
|
7
|
+
type: string;
|
|
8
|
+
title: string;
|
|
9
|
+
body: string;
|
|
10
|
+
data?: Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
declare class NotificationService {
|
|
13
|
+
private readonly repository;
|
|
14
|
+
constructor(repository: NotificationRepository);
|
|
15
|
+
listForUser(userId: number, options: {
|
|
16
|
+
page: number;
|
|
17
|
+
perPage: number;
|
|
18
|
+
unreadOnly?: boolean;
|
|
19
|
+
}): Promise<PaginatedResult<NotificationRecord>>;
|
|
20
|
+
markRead(userId: number, notificationId: number): Promise<NotificationRecord>;
|
|
21
|
+
markAllRead(userId: number): Promise<number>;
|
|
22
|
+
create(input: CreateNotificationInput): Promise<NotificationRecord>;
|
|
23
|
+
}
|
|
24
|
+
export default NotificationService;
|
|
25
|
+
export type { CreateNotificationInput };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseRepository } from "../../core/database";
|
|
2
|
+
import type { OAuthIdentityRecord } from "./types";
|
|
3
|
+
declare const oauthIdentityTable: import("../../core/database").TableDefinition<OAuthIdentityRecord, "id">;
|
|
4
|
+
declare class OAuthIdentityRepository extends BaseRepository<OAuthIdentityRecord, "id"> {
|
|
5
|
+
constructor();
|
|
6
|
+
findByProviderUser(provider: string, providerUserId: string): Promise<OAuthIdentityRecord | null>;
|
|
7
|
+
}
|
|
8
|
+
export default OAuthIdentityRepository;
|
|
9
|
+
export { oauthIdentityTable };
|