@getstrata/core 0.5.5 → 0.5.7
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 +3 -0
- package/dist/bootstrap/discoverModules.d.ts +4 -0
- package/dist/bootstrap/modules.d.ts +1 -0
- package/dist/bootstrap/routeRegistry.d.ts +14 -0
- package/dist/core/audit/exportAuditLogs.d.ts +8 -0
- package/dist/core/audit/siemFormatter.d.ts +30 -0
- package/dist/core/auth/membershipScope.d.ts +16 -0
- package/dist/core/auth/membershipService.d.ts +20 -0
- package/dist/core/auth/scimAuthMiddleware.d.ts +3 -0
- package/dist/core/auth/sessionCookie.d.ts +6 -0
- package/dist/core/auth/sessionGuard.d.ts +9 -0
- package/dist/core/cache/createCacheStore.d.ts +11 -0
- package/dist/core/cache/keys.d.ts +2 -0
- package/dist/core/cache/modelCacheTags.d.ts +3 -0
- package/dist/core/cache/redisCacheStore.d.ts +23 -0
- package/dist/core/cache/simpleCache.d.ts +23 -0
- package/dist/core/cache/simpleCacheStore.d.ts +16 -0
- package/dist/core/config/envSchema.d.ts +12 -0
- package/dist/core/crypto/nonCryptographicHash.d.ts +2 -0
- package/dist/core/database/factory.d.ts +6 -0
- package/dist/core/http/cookies.d.ts +4 -0
- package/dist/core/http/csrfProtection.d.ts +12 -0
- package/dist/core/http/scimThrottleMiddleware.d.ts +9 -0
- package/dist/core/jobs/dispatchWebhookJob.d.ts +14 -0
- package/dist/core/jobs/invalidateCacheTagsJob.d.ts +12 -0
- package/dist/core/openapi/generator.d.ts +22 -0
- package/dist/core/openapi/validate.d.ts +3 -0
- package/dist/core/queue/createAppQueue.d.ts +6 -0
- package/dist/core/queue/queueMetrics.d.ts +15 -0
- package/dist/core/security/oauthState.d.ts +8 -0
- package/dist/core/security/safeFetch.d.ts +8 -0
- package/dist/core/security/safeUrl.d.ts +5 -0
- package/dist/core/security/scimTenantTokens.d.ts +3 -0
- package/dist/core/security/stripeWebhook.d.ts +2 -0
- package/dist/core/security/timingSafeCompare.d.ts +2 -0
- package/dist/domain/scim.d.ts +9 -0
- package/dist/entries/auth/guard.js +20 -20
- package/dist/entries/database.js +20 -20
- package/dist/entries/http/csrfToken.js +49 -65
- package/dist/entries/http/etag.js +6 -4
- package/dist/entries/http/webErrorResponse.js +73 -87
- package/dist/entries/http.js +80 -90
- package/dist/entries/queue/createAppQueue.js +20 -20
- package/dist/entries/queue/publicQueue.js +20 -20
- package/dist/entries/queue/queueMetrics.js +20 -20
- package/dist/entries/view.js +73 -87
- package/dist/framework/public-api.d.ts +4 -0
- package/dist/index.js +121 -107
- package/package.json +61 -58
package/README.md
CHANGED
|
@@ -16,6 +16,7 @@ process.env.DATABASE_URL ??= "postgresql://postgres:postgres@localhost:5432/myap
|
|
|
16
16
|
|
|
17
17
|
import {
|
|
18
18
|
BaseRepository,
|
|
19
|
+
EtaViewEngine,
|
|
19
20
|
FormRequest,
|
|
20
21
|
Policy,
|
|
21
22
|
mailer,
|
|
@@ -24,6 +25,8 @@ import {
|
|
|
24
25
|
} from "@getstrata/core";
|
|
25
26
|
```
|
|
26
27
|
|
|
28
|
+
**Dependency:** `eta` is bundled as a direct dependency of `@getstrata/core` — apps do not need to list it separately. The database driver is your app's choice — WorkHub and getstrata use **Bun's built-in `Bun.sql`** client; bind it with `bindDatabaseConnection()`.
|
|
29
|
+
|
|
27
30
|
`orderBy` accepts explicit `{ column, direction }` objects or Laravel-style shorthand `{ published_at: "desc" }`.
|
|
28
31
|
|
|
29
32
|
## Build & verify (monorepo root)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { appModules, discoverModules } from "./discoverModules";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface RegisteredRoute {
|
|
2
|
+
method: string;
|
|
3
|
+
path: string;
|
|
4
|
+
middleware: string[];
|
|
5
|
+
}
|
|
6
|
+
declare class RouteRegistry {
|
|
7
|
+
private readonly routes;
|
|
8
|
+
register(route: RegisteredRoute): void;
|
|
9
|
+
clear(): void;
|
|
10
|
+
list(): RegisteredRoute[];
|
|
11
|
+
}
|
|
12
|
+
declare const routeRegistry: RouteRegistry;
|
|
13
|
+
export type { RegisteredRoute };
|
|
14
|
+
export { RouteRegistry, routeRegistry };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface AuditExportConfig {
|
|
2
|
+
endpoint: string;
|
|
3
|
+
format: "json" | "cef";
|
|
4
|
+
batchSize: number;
|
|
5
|
+
}
|
|
6
|
+
declare function resolveAuditExportConfig(): AuditExportConfig | null;
|
|
7
|
+
declare function exportPendingAuditLogs(): Promise<number>;
|
|
8
|
+
export { exportPendingAuditLogs, resolveAuditExportConfig };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
interface SiemAuditEvent {
|
|
2
|
+
timestamp: string;
|
|
3
|
+
event_type: string;
|
|
4
|
+
actor_user_id: number | null;
|
|
5
|
+
tenant_id: number | null;
|
|
6
|
+
trace_id: string | null;
|
|
7
|
+
action: string;
|
|
8
|
+
subject_type: string;
|
|
9
|
+
subject_id: number | null;
|
|
10
|
+
ip_address: string | null;
|
|
11
|
+
user_agent: string | null;
|
|
12
|
+
checksum: string | null;
|
|
13
|
+
payload: Record<string, unknown>;
|
|
14
|
+
}
|
|
15
|
+
declare function formatSiemAuditEvent(input: {
|
|
16
|
+
action: string;
|
|
17
|
+
subject_type: string;
|
|
18
|
+
subject_id: number | null;
|
|
19
|
+
user_id: number | null;
|
|
20
|
+
tenant_id?: number | null;
|
|
21
|
+
trace_id?: string | null;
|
|
22
|
+
ip_address?: string | null;
|
|
23
|
+
user_agent?: string | null;
|
|
24
|
+
checksum?: string | null;
|
|
25
|
+
payload?: Record<string, unknown>;
|
|
26
|
+
created_at: Date;
|
|
27
|
+
}): SiemAuditEvent;
|
|
28
|
+
declare function formatCefLine(event: SiemAuditEvent): string;
|
|
29
|
+
export type { SiemAuditEvent };
|
|
30
|
+
export { formatCefLine, formatSiemAuditEvent };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
declare function resolveOrganizationScope(): number[] | null;
|
|
2
|
+
declare function scopedOrganizationIds(requestedOrganizationId?: number): number[] | null;
|
|
3
|
+
declare function appendOrganizationScope<T extends object>(where: T, requestedOrganizationId?: number): T;
|
|
4
|
+
declare function appendProjectScope<T extends object>(where: T, accessibleProjectIds: number[] | null, requestedProjectId?: number): T;
|
|
5
|
+
declare function emptyPaginateResult<T>(page: number, perPage: number): {
|
|
6
|
+
data: T[];
|
|
7
|
+
meta: {
|
|
8
|
+
page: number;
|
|
9
|
+
per_page: number;
|
|
10
|
+
total: number;
|
|
11
|
+
last_page: number;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
declare function assertResourceInCurrentTenant(resourceTenantId: number, resourceLabel: string, resourceId: number): void;
|
|
15
|
+
declare function assertOrganizationReadable(organizationId: number): void;
|
|
16
|
+
export { appendOrganizationScope, appendProjectScope, assertOrganizationReadable, assertResourceInCurrentTenant, emptyPaginateResult, resolveOrganizationScope, scopedOrganizationIds, };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { OrganizationMemberRole } from "../../modules/organization/memberTypes";
|
|
2
|
+
import { type AuthUser } from "./authContext";
|
|
3
|
+
declare class MembershipService {
|
|
4
|
+
constructor();
|
|
5
|
+
listOrganizationIdsForUser(userId: number): Promise<number[]>;
|
|
6
|
+
getOrgRole(userId: number, organizationId: number): Promise<OrganizationMemberRole | null>;
|
|
7
|
+
requireOrgAccess(organizationId: number, minimumRole?: OrganizationMemberRole, user?: AuthUser | null): Promise<OrganizationMemberRole>;
|
|
8
|
+
filterAccessibleOrganizationIds(organizationIds: number[], user?: AuthUser | null): Promise<number[]>;
|
|
9
|
+
addOwnerOnOrganizationCreate(organizationId: number, userId: number): Promise<void>;
|
|
10
|
+
listMembersForOrganization(organizationId: number): Promise<import("../../modules/organization/memberTypes").OrganizationMemberRecord[]>;
|
|
11
|
+
addMember(input: {
|
|
12
|
+
organizationId: number;
|
|
13
|
+
userId: number;
|
|
14
|
+
role?: OrganizationMemberRole;
|
|
15
|
+
}): Promise<import("../../modules/organization/memberTypes").OrganizationMemberRecord>;
|
|
16
|
+
removeMember(organizationId: number, userId: number): Promise<boolean>;
|
|
17
|
+
}
|
|
18
|
+
declare function resolveMembershipService(): MembershipService;
|
|
19
|
+
export default MembershipService;
|
|
20
|
+
export { resolveMembershipService };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
declare const SESSION_COOKIE = "workhub_session";
|
|
2
|
+
declare const SESSION_TTL_SECONDS: number;
|
|
3
|
+
declare function readSessionUserId(request: Request): number | null;
|
|
4
|
+
declare function createSessionCookie(userId: number): string;
|
|
5
|
+
declare function clearSessionCookie(): string;
|
|
6
|
+
export { clearSessionCookie, createSessionCookie, readSessionUserId, SESSION_COOKIE, SESSION_TTL_SECONDS, };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ServiceContainer } from "../../bootstrap/contracts";
|
|
2
|
+
import type { AuthUser } from "./authContext";
|
|
3
|
+
import type { AuthGuard } from "./guard";
|
|
4
|
+
declare class SessionGuard implements AuthGuard {
|
|
5
|
+
private readonly container;
|
|
6
|
+
constructor(container: ServiceContainer);
|
|
7
|
+
resolve(request: Request): Promise<AuthUser | null>;
|
|
8
|
+
}
|
|
9
|
+
export { SessionGuard };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CacheStore } from "./store";
|
|
2
|
+
type CacheDriver = "array" | "redis";
|
|
3
|
+
interface CreateCacheStoreOptions {
|
|
4
|
+
driver: CacheDriver;
|
|
5
|
+
ttlMs: number;
|
|
6
|
+
maxEntries: number;
|
|
7
|
+
redisUrl?: string;
|
|
8
|
+
}
|
|
9
|
+
declare function createCacheStore(options: CreateCacheStoreOptions): CacheStore;
|
|
10
|
+
export type { CacheDriver, CreateCacheStoreOptions };
|
|
11
|
+
export { createCacheStore };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { CacheStore } from "./store";
|
|
2
|
+
declare class RedisCacheStore implements CacheStore {
|
|
3
|
+
private readonly ttlMs;
|
|
4
|
+
private readonly maxEntries;
|
|
5
|
+
private readonly client;
|
|
6
|
+
private readonly inflight;
|
|
7
|
+
private readonly keyTags;
|
|
8
|
+
constructor(redisUrl: string, ttlMs: number, maxEntries: number);
|
|
9
|
+
get<T>(key: string): Promise<T | undefined>;
|
|
10
|
+
set<T>(key: string, value: T, ttlMs?: number): Promise<void>;
|
|
11
|
+
getOrSet<T>(key: string, loader: () => Promise<T>, ttlMs?: number): Promise<T>;
|
|
12
|
+
attachTags(key: string, tags: string[]): Promise<void>;
|
|
13
|
+
flushTags(tags: string[]): Promise<number>;
|
|
14
|
+
invalidate(key: string): Promise<boolean>;
|
|
15
|
+
invalidateByPrefix(prefix: string): Promise<number>;
|
|
16
|
+
clear(): Promise<void>;
|
|
17
|
+
size(): Promise<number>;
|
|
18
|
+
private storageKey;
|
|
19
|
+
private tagKey;
|
|
20
|
+
private detachKeyFromTags;
|
|
21
|
+
private enforceMaxEntries;
|
|
22
|
+
}
|
|
23
|
+
export default RedisCacheStore;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
declare class SimpleCache {
|
|
2
|
+
private readonly ttlMs;
|
|
3
|
+
private readonly maxEntries;
|
|
4
|
+
private readonly cache;
|
|
5
|
+
private readonly inflight;
|
|
6
|
+
private readonly tagIndex;
|
|
7
|
+
private readonly keyTags;
|
|
8
|
+
constructor(ttlMs?: number, maxEntries?: number);
|
|
9
|
+
get<T>(key: string): T | undefined;
|
|
10
|
+
set<T>(key: string, value: T, ttlMs?: number): void;
|
|
11
|
+
getOrSet<T>(key: string, loader: () => Promise<T>, ttlMs?: number): Promise<T>;
|
|
12
|
+
attachTags(key: string, tags: string[]): void;
|
|
13
|
+
flushTags(tags: string[]): number;
|
|
14
|
+
invalidate(key: string): boolean;
|
|
15
|
+
invalidateByPrefix(prefix: string): number;
|
|
16
|
+
clear(): void;
|
|
17
|
+
size(): number;
|
|
18
|
+
private detachKeyFromTags;
|
|
19
|
+
private getFreshEntry;
|
|
20
|
+
private pruneExpired;
|
|
21
|
+
private evictOverflow;
|
|
22
|
+
}
|
|
23
|
+
export default SimpleCache;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type SimpleCache from "./simpleCache";
|
|
2
|
+
import type { CacheStore } from "./store";
|
|
3
|
+
declare class SimpleCacheStore implements CacheStore {
|
|
4
|
+
private readonly cache;
|
|
5
|
+
constructor(cache: SimpleCache);
|
|
6
|
+
get<T>(key: string): Promise<T | undefined>;
|
|
7
|
+
set<T>(key: string, value: T, ttlMs?: number): Promise<void>;
|
|
8
|
+
getOrSet<T>(key: string, loader: () => Promise<T>, ttlMs?: number): Promise<T>;
|
|
9
|
+
attachTags(key: string, tags: string[]): Promise<void>;
|
|
10
|
+
flushTags(tags: string[]): Promise<number>;
|
|
11
|
+
invalidate(key: string): Promise<boolean>;
|
|
12
|
+
invalidateByPrefix(prefix: string): Promise<number>;
|
|
13
|
+
clear(): Promise<void>;
|
|
14
|
+
size(): Promise<number>;
|
|
15
|
+
}
|
|
16
|
+
export default SimpleCacheStore;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface EnvRule {
|
|
2
|
+
required?: boolean;
|
|
3
|
+
integer?: boolean;
|
|
4
|
+
minimum?: number;
|
|
5
|
+
default?: string;
|
|
6
|
+
pattern?: RegExp;
|
|
7
|
+
}
|
|
8
|
+
type EnvSchema = Record<string, EnvRule>;
|
|
9
|
+
declare function defineEnvSchema(schema: EnvSchema): EnvSchema;
|
|
10
|
+
declare function validateEnv(schema: EnvSchema, env?: Record<string, string | undefined>): Record<string, string>;
|
|
11
|
+
export type { EnvRule, EnvSchema };
|
|
12
|
+
export { defineEnvSchema, validateEnv };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare const DEFAULT_CSRF_TTL_MS: number;
|
|
2
|
+
interface CsrfProtectionOptions {
|
|
3
|
+
expiresIn?: number;
|
|
4
|
+
maxAge?: number;
|
|
5
|
+
}
|
|
6
|
+
declare function createCsrfProtection(secret: string, options?: CsrfProtectionOptions): {
|
|
7
|
+
generate(_sessionKey?: string): string;
|
|
8
|
+
verify(token: string | undefined, _sessionKey?: string): boolean;
|
|
9
|
+
secret: string;
|
|
10
|
+
};
|
|
11
|
+
export type { CsrfProtectionOptions };
|
|
12
|
+
export { createCsrfProtection, DEFAULT_CSRF_TTL_MS };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Middleware } from "./middleware";
|
|
2
|
+
interface ScimThrottleOptions {
|
|
3
|
+
redisUrl?: string;
|
|
4
|
+
maxAttempts: number;
|
|
5
|
+
decaySeconds: number;
|
|
6
|
+
}
|
|
7
|
+
declare function createScimThrottleMiddleware(options: ScimThrottleOptions): Middleware;
|
|
8
|
+
export type { ScimThrottleOptions };
|
|
9
|
+
export { createScimThrottleMiddleware };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Job } from "../queue";
|
|
2
|
+
interface DispatchWebhookPayload {
|
|
3
|
+
webhookId: number;
|
|
4
|
+
event: string;
|
|
5
|
+
payload: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
declare class DispatchWebhookJob extends Job<DispatchWebhookPayload> {
|
|
8
|
+
constructor();
|
|
9
|
+
readonly maxAttempts = 3;
|
|
10
|
+
readonly backoffMs = 2000;
|
|
11
|
+
handle(payload: DispatchWebhookPayload): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export default DispatchWebhookJob;
|
|
14
|
+
export type { DispatchWebhookPayload };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CacheLike } from "../../types/services";
|
|
2
|
+
import { Job } from "../queue";
|
|
3
|
+
interface InvalidateCacheTagsPayload {
|
|
4
|
+
tags: string[];
|
|
5
|
+
}
|
|
6
|
+
declare class InvalidateCacheTagsJob extends Job<InvalidateCacheTagsPayload> {
|
|
7
|
+
private readonly cache;
|
|
8
|
+
constructor(cache: CacheLike);
|
|
9
|
+
handle(payload: InvalidateCacheTagsPayload): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
export default InvalidateCacheTagsJob;
|
|
12
|
+
export type { InvalidateCacheTagsPayload };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { RegisteredRoute } from "../../bootstrap/routeRegistry";
|
|
2
|
+
interface OpenApiSpec {
|
|
3
|
+
openapi: string;
|
|
4
|
+
info: {
|
|
5
|
+
title: string;
|
|
6
|
+
version: string;
|
|
7
|
+
};
|
|
8
|
+
servers: Array<{
|
|
9
|
+
url: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
}>;
|
|
12
|
+
paths: Record<string, Record<string, unknown>>;
|
|
13
|
+
components: {
|
|
14
|
+
securitySchemes: Record<string, unknown>;
|
|
15
|
+
schemas?: Record<string, unknown>;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
declare function generateOpenApiSpec(routes: RegisteredRoute[]): OpenApiSpec;
|
|
19
|
+
declare function renderOpenApiDocument(spec: OpenApiSpec): string;
|
|
20
|
+
declare function renderTypeScriptSdk(spec: OpenApiSpec, apiPrefix?: string): string;
|
|
21
|
+
export type { OpenApiSpec };
|
|
22
|
+
export { generateOpenApiSpec, renderOpenApiDocument, renderTypeScriptSdk };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Queue } from "./index";
|
|
2
|
+
import { createFailedJobService, createQueueWorker, createTrackedJob, type FailedJobService } from "./publicQueue";
|
|
3
|
+
declare const FAILED_JOB_SERVICE_TOKEN = "core.failedJobs";
|
|
4
|
+
declare function registerDefaultJobs(): void;
|
|
5
|
+
declare function createAppQueue(driver: "sync" | "async" | "redis", redisUrl?: string, failedJobs?: FailedJobService): Queue;
|
|
6
|
+
export { createAppQueue, createFailedJobService, createQueueWorker, createTrackedJob, FAILED_JOB_SERVICE_TOKEN, registerDefaultJobs, };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
interface QueueDepthMetrics {
|
|
2
|
+
high: number;
|
|
3
|
+
default: number;
|
|
4
|
+
low: number;
|
|
5
|
+
total: number;
|
|
6
|
+
}
|
|
7
|
+
interface QueueMetricsSnapshot {
|
|
8
|
+
driver: string;
|
|
9
|
+
pending: QueueDepthMetrics;
|
|
10
|
+
failedCount: number;
|
|
11
|
+
}
|
|
12
|
+
declare function readRedisQueueDepth(redisUrl: string): Promise<QueueDepthMetrics>;
|
|
13
|
+
declare function collectQueueMetrics(): Promise<QueueMetricsSnapshot>;
|
|
14
|
+
export type { QueueDepthMetrics, QueueMetricsSnapshot };
|
|
15
|
+
export { collectQueueMetrics, readRedisQueueDepth };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
declare const OAUTH_STATE_COOKIE = "oauth_state";
|
|
2
|
+
declare function createOAuthStateCookie(): {
|
|
3
|
+
state: string;
|
|
4
|
+
cookie: string;
|
|
5
|
+
};
|
|
6
|
+
declare function verifyOAuthState(request: Request, returnedState: string | null): boolean;
|
|
7
|
+
declare function clearOAuthStateCookie(): string;
|
|
8
|
+
export { clearOAuthStateCookie, createOAuthStateCookie, OAUTH_STATE_COOKIE, verifyOAuthState };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
declare const DEFAULT_FETCH_TIMEOUT_MS = 10000;
|
|
2
|
+
interface SafeFetchOptions {
|
|
3
|
+
timeoutMs?: number;
|
|
4
|
+
maxRedirects?: number;
|
|
5
|
+
}
|
|
6
|
+
declare function safeFetch(input: string, init?: RequestInit, options?: SafeFetchOptions): Promise<Response>;
|
|
7
|
+
export type { SafeFetchOptions };
|
|
8
|
+
export { DEFAULT_FETCH_TIMEOUT_MS, safeFetch };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const TEST_SCIM_BEARER_TOKEN = "workhub-scim-test-token";
|
|
2
|
+
export declare const DEFAULT_SCIM_BEARER_TOKEN = "workhub-scim-test-token";
|
|
3
|
+
export declare const SCIM_SCHEMAS: {
|
|
4
|
+
readonly user: "urn:ietf:params:scim:schemas:core:2.0:User";
|
|
5
|
+
readonly group: "urn:ietf:params:scim:schemas:core:2.0:Group";
|
|
6
|
+
readonly listResponse: "urn:ietf:params:scim:api:messages:2.0:ListResponse";
|
|
7
|
+
readonly patchOp: "urn:ietf:params:scim:api:messages:2.0:PatchOp";
|
|
8
|
+
readonly serviceProviderConfig: "urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig";
|
|
9
|
+
};
|
|
@@ -1555,26 +1555,26 @@ class Model {
|
|
|
1555
1555
|
throw new Error(`${this.constructor.name}.primaryKey() is not implemented.`);
|
|
1556
1556
|
}
|
|
1557
1557
|
static primaryKeyField() {
|
|
1558
|
-
return resolveModelRepository(
|
|
1558
|
+
return resolveModelRepository(Model).getTable().primaryKey;
|
|
1559
1559
|
}
|
|
1560
1560
|
static hydrateAttributes(attributes) {
|
|
1561
|
-
const casts = modelStatics(
|
|
1561
|
+
const casts = modelStatics(Model).$casts ?? {};
|
|
1562
1562
|
return applyCasts(attributes, casts, "hydrate");
|
|
1563
1563
|
}
|
|
1564
1564
|
static dehydrateAttributes(attributes) {
|
|
1565
|
-
const casts = modelStatics(
|
|
1565
|
+
const casts = modelStatics(Model).$casts ?? {};
|
|
1566
1566
|
return applyCasts(attributes, casts, "dehydrate");
|
|
1567
1567
|
}
|
|
1568
1568
|
static fromRecord(record, repository, exists = true) {
|
|
1569
|
-
const statics = modelStatics(
|
|
1569
|
+
const statics = modelStatics(Model);
|
|
1570
1570
|
const hydrated = statics.hydrateAttributes(record);
|
|
1571
1571
|
return new statics(hydrated, repository, exists);
|
|
1572
1572
|
}
|
|
1573
1573
|
static boot() {}
|
|
1574
1574
|
static addGlobalScope(_name, scope) {
|
|
1575
|
-
ensureBooted(
|
|
1576
|
-
const existing = modelGlobalScopes.get(
|
|
1577
|
-
modelGlobalScopes.set(
|
|
1575
|
+
ensureBooted(Model);
|
|
1576
|
+
const existing = modelGlobalScopes.get(Model) ?? [];
|
|
1577
|
+
modelGlobalScopes.set(Model, [
|
|
1578
1578
|
...existing,
|
|
1579
1579
|
scope
|
|
1580
1580
|
]);
|
|
@@ -1584,17 +1584,17 @@ class Model {
|
|
|
1584
1584
|
}
|
|
1585
1585
|
static query() {
|
|
1586
1586
|
ensureBooted(this);
|
|
1587
|
-
const repository = resolveModelRepository(
|
|
1587
|
+
const repository = resolveModelRepository(Model);
|
|
1588
1588
|
let query = repository.query();
|
|
1589
|
-
for (const scope of getGlobalScopes(
|
|
1589
|
+
for (const scope of getGlobalScopes(Model)) {
|
|
1590
1590
|
query = scope(query);
|
|
1591
1591
|
}
|
|
1592
1592
|
return query;
|
|
1593
1593
|
}
|
|
1594
1594
|
static async create(attributes) {
|
|
1595
1595
|
const statics = modelStatics(this);
|
|
1596
|
-
ensureBooted(
|
|
1597
|
-
const repository = resolveModelRepository(
|
|
1596
|
+
ensureBooted(Model);
|
|
1597
|
+
const repository = resolveModelRepository(Model);
|
|
1598
1598
|
const table = repository.getTable();
|
|
1599
1599
|
const timestamps = statics.$timestamps ?? true;
|
|
1600
1600
|
const assignable = filterMassAssignable(statics.$fillable, statics.$guarded, attributes);
|
|
@@ -1604,23 +1604,23 @@ class Model {
|
|
|
1604
1604
|
return statics.fromRecord(record, repository, true);
|
|
1605
1605
|
}
|
|
1606
1606
|
static async find(id) {
|
|
1607
|
-
const statics = modelStatics(
|
|
1608
|
-
const repository = resolveModelRepository(
|
|
1607
|
+
const statics = modelStatics(Model);
|
|
1608
|
+
const repository = resolveModelRepository(Model);
|
|
1609
1609
|
const primaryKey = repository.getTable().primaryKey;
|
|
1610
|
-
const record = await Model.query.call(
|
|
1610
|
+
const record = await Model.query.call(Model).where({ [primaryKey]: id }).first();
|
|
1611
1611
|
return record ? statics.fromRecord(record, repository, true) : null;
|
|
1612
1612
|
}
|
|
1613
1613
|
static async findOrFail(id, errorFactory) {
|
|
1614
|
-
const model = await Model.find.call(
|
|
1614
|
+
const model = await Model.find.call(Model, id);
|
|
1615
1615
|
if (model) {
|
|
1616
1616
|
return model;
|
|
1617
1617
|
}
|
|
1618
|
-
throw errorFactory?.(id) ?? new NotFoundError(`${
|
|
1618
|
+
throw errorFactory?.(id) ?? new NotFoundError(`${Model.name} ${String(id)} not found.`);
|
|
1619
1619
|
}
|
|
1620
1620
|
static async all(options = {}) {
|
|
1621
1621
|
const statics = modelStatics(this);
|
|
1622
|
-
const repository = resolveModelRepository(
|
|
1623
|
-
let query = Model.query.call(
|
|
1622
|
+
const repository = resolveModelRepository(Model);
|
|
1623
|
+
let query = Model.query.call(Model);
|
|
1624
1624
|
if (options.orderBy) {
|
|
1625
1625
|
query = query.orderBy(options.orderBy);
|
|
1626
1626
|
}
|
|
@@ -1632,8 +1632,8 @@ class Model {
|
|
|
1632
1632
|
}
|
|
1633
1633
|
static async firstWhere(where, options = {}) {
|
|
1634
1634
|
const statics = modelStatics(this);
|
|
1635
|
-
const repository = resolveModelRepository(
|
|
1636
|
-
let query = Model.query.call(
|
|
1635
|
+
const repository = resolveModelRepository(Model);
|
|
1636
|
+
let query = Model.query.call(Model).where(where);
|
|
1637
1637
|
if (options.orderBy) {
|
|
1638
1638
|
query = query.orderBy(options.orderBy);
|
|
1639
1639
|
}
|
package/dist/entries/database.js
CHANGED
|
@@ -1353,26 +1353,26 @@ class Model {
|
|
|
1353
1353
|
throw new Error(`${this.constructor.name}.primaryKey() is not implemented.`);
|
|
1354
1354
|
}
|
|
1355
1355
|
static primaryKeyField() {
|
|
1356
|
-
return resolveModelRepository(
|
|
1356
|
+
return resolveModelRepository(Model).getTable().primaryKey;
|
|
1357
1357
|
}
|
|
1358
1358
|
static hydrateAttributes(attributes) {
|
|
1359
|
-
const casts = modelStatics(
|
|
1359
|
+
const casts = modelStatics(Model).$casts ?? {};
|
|
1360
1360
|
return applyCasts(attributes, casts, "hydrate");
|
|
1361
1361
|
}
|
|
1362
1362
|
static dehydrateAttributes(attributes) {
|
|
1363
|
-
const casts = modelStatics(
|
|
1363
|
+
const casts = modelStatics(Model).$casts ?? {};
|
|
1364
1364
|
return applyCasts(attributes, casts, "dehydrate");
|
|
1365
1365
|
}
|
|
1366
1366
|
static fromRecord(record, repository, exists = true) {
|
|
1367
|
-
const statics = modelStatics(
|
|
1367
|
+
const statics = modelStatics(Model);
|
|
1368
1368
|
const hydrated = statics.hydrateAttributes(record);
|
|
1369
1369
|
return new statics(hydrated, repository, exists);
|
|
1370
1370
|
}
|
|
1371
1371
|
static boot() {}
|
|
1372
1372
|
static addGlobalScope(_name, scope) {
|
|
1373
|
-
ensureBooted(
|
|
1374
|
-
const existing = modelGlobalScopes.get(
|
|
1375
|
-
modelGlobalScopes.set(
|
|
1373
|
+
ensureBooted(Model);
|
|
1374
|
+
const existing = modelGlobalScopes.get(Model) ?? [];
|
|
1375
|
+
modelGlobalScopes.set(Model, [
|
|
1376
1376
|
...existing,
|
|
1377
1377
|
scope
|
|
1378
1378
|
]);
|
|
@@ -1382,17 +1382,17 @@ class Model {
|
|
|
1382
1382
|
}
|
|
1383
1383
|
static query() {
|
|
1384
1384
|
ensureBooted(this);
|
|
1385
|
-
const repository = resolveModelRepository(
|
|
1385
|
+
const repository = resolveModelRepository(Model);
|
|
1386
1386
|
let query = repository.query();
|
|
1387
|
-
for (const scope of getGlobalScopes(
|
|
1387
|
+
for (const scope of getGlobalScopes(Model)) {
|
|
1388
1388
|
query = scope(query);
|
|
1389
1389
|
}
|
|
1390
1390
|
return query;
|
|
1391
1391
|
}
|
|
1392
1392
|
static async create(attributes) {
|
|
1393
1393
|
const statics = modelStatics(this);
|
|
1394
|
-
ensureBooted(
|
|
1395
|
-
const repository = resolveModelRepository(
|
|
1394
|
+
ensureBooted(Model);
|
|
1395
|
+
const repository = resolveModelRepository(Model);
|
|
1396
1396
|
const table = repository.getTable();
|
|
1397
1397
|
const timestamps = statics.$timestamps ?? true;
|
|
1398
1398
|
const assignable = filterMassAssignable(statics.$fillable, statics.$guarded, attributes);
|
|
@@ -1402,23 +1402,23 @@ class Model {
|
|
|
1402
1402
|
return statics.fromRecord(record, repository, true);
|
|
1403
1403
|
}
|
|
1404
1404
|
static async find(id) {
|
|
1405
|
-
const statics = modelStatics(
|
|
1406
|
-
const repository = resolveModelRepository(
|
|
1405
|
+
const statics = modelStatics(Model);
|
|
1406
|
+
const repository = resolveModelRepository(Model);
|
|
1407
1407
|
const primaryKey = repository.getTable().primaryKey;
|
|
1408
|
-
const record = await Model.query.call(
|
|
1408
|
+
const record = await Model.query.call(Model).where({ [primaryKey]: id }).first();
|
|
1409
1409
|
return record ? statics.fromRecord(record, repository, true) : null;
|
|
1410
1410
|
}
|
|
1411
1411
|
static async findOrFail(id, errorFactory) {
|
|
1412
|
-
const model = await Model.find.call(
|
|
1412
|
+
const model = await Model.find.call(Model, id);
|
|
1413
1413
|
if (model) {
|
|
1414
1414
|
return model;
|
|
1415
1415
|
}
|
|
1416
|
-
throw errorFactory?.(id) ?? new NotFoundError(`${
|
|
1416
|
+
throw errorFactory?.(id) ?? new NotFoundError(`${Model.name} ${String(id)} not found.`);
|
|
1417
1417
|
}
|
|
1418
1418
|
static async all(options = {}) {
|
|
1419
1419
|
const statics = modelStatics(this);
|
|
1420
|
-
const repository = resolveModelRepository(
|
|
1421
|
-
let query = Model.query.call(
|
|
1420
|
+
const repository = resolveModelRepository(Model);
|
|
1421
|
+
let query = Model.query.call(Model);
|
|
1422
1422
|
if (options.orderBy) {
|
|
1423
1423
|
query = query.orderBy(options.orderBy);
|
|
1424
1424
|
}
|
|
@@ -1430,8 +1430,8 @@ class Model {
|
|
|
1430
1430
|
}
|
|
1431
1431
|
static async firstWhere(where, options = {}) {
|
|
1432
1432
|
const statics = modelStatics(this);
|
|
1433
|
-
const repository = resolveModelRepository(
|
|
1434
|
-
let query = Model.query.call(
|
|
1433
|
+
const repository = resolveModelRepository(Model);
|
|
1434
|
+
let query = Model.query.call(Model).where(where);
|
|
1435
1435
|
if (options.orderBy) {
|
|
1436
1436
|
query = query.orderBy(options.orderBy);
|
|
1437
1437
|
}
|