@getstrata/core 2.1.0 → 2.2.1
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/CHANGELOG.md +40 -0
- package/dist/core/cache/createCacheStore.d.ts +3 -1
- package/dist/core/cache/redisCacheStore.d.ts +21 -8
- package/dist/core/cache/repository.d.ts +3 -2
- package/dist/core/cache/store.d.ts +4 -1
- package/dist/core/cache/taggedCache.d.ts +1 -1
- package/dist/core/contracts/di.d.ts +4 -2
- package/dist/core/contracts/serviceTokens.d.ts +7 -1
- package/dist/core/database/baseRepository.d.ts +0 -1
- package/dist/core/database/index.d.ts +1 -1
- package/dist/core/database/model.d.ts +51 -22
- package/dist/core/database/repositoryQuery.d.ts +16 -1
- package/dist/core/database/types.d.ts +25 -2
- package/dist/core/database/whereBuilder.d.ts +5 -5
- package/dist/core/events/deferredModelEvents.d.ts +2 -1
- package/dist/core/http/loginThrottleMiddleware.d.ts +6 -5
- package/dist/core/http/memoryThrottleMiddleware.d.ts +11 -3
- package/dist/core/http/requestMetaContext.d.ts +2 -0
- package/dist/core/http/scimThrottleMiddleware.d.ts +12 -3
- package/dist/core/http/throttleMiddleware.d.ts +24 -6
- package/dist/core/lifecycle/gracefulShutdown.d.ts +33 -5
- package/dist/core/queue/createAppQueue.d.ts +2 -1
- package/dist/core/queue/failedJobService.d.ts +3 -1
- package/dist/core/queue/index.d.ts +17 -2
- package/dist/core/queue/jobRunner.d.ts +7 -1
- package/dist/core/queue/publicQueue.d.ts +2 -1
- package/dist/core/queue/queueConfig.d.ts +3 -0
- package/dist/core/queue/redisQueue.d.ts +6 -7
- package/dist/core/queue/redisQueueKeys.d.ts +8 -0
- package/dist/core/queue/redisStreams.d.ts +73 -0
- package/dist/core/queue/resilientQueue.d.ts +2 -2
- package/dist/core/queue/types.d.ts +1 -0
- package/dist/core/runtime/applicationRegistry.d.ts +2 -1
- package/dist/core/runtime/boundedThrottleStore.d.ts +29 -0
- package/dist/core/scheduler/leases.d.ts +40 -0
- package/dist/core/scheduler/schedule.d.ts +29 -5
- package/dist/core/tenant/publicTenantHost.d.ts +11 -0
- package/dist/core/tenant/tenantContext.d.ts +5 -4
- package/dist/core/tenant/tenantMiddleware.d.ts +11 -1
- package/dist/core/tracing/otel.d.ts +28 -26
- package/dist/core/tracing/tracingMiddleware.d.ts +4 -1
- package/dist/entries/audit/exportAuditLogs.js +14 -2
- package/dist/entries/auth/basicAuthGuard.js +81 -0
- package/dist/entries/auth/jwtGuard.js +81 -0
- package/dist/entries/auth/scimAuthMiddleware.js +17 -7
- package/dist/entries/auth/sessionGuard.js +81 -0
- package/dist/entries/cache/createCacheStore.js +365 -119
- package/dist/entries/cache/repository.js +5 -0
- package/dist/entries/contracts/serviceTokens.js +85 -0
- package/dist/entries/database/factory.js +0 -3
- package/dist/entries/database/model.js +1 -2486
- package/dist/entries/database/repositoryQuery.js +67 -9
- package/dist/entries/http/bodySizeLimitMiddleware.js +76 -10
- package/dist/entries/http/memoryThrottleMiddleware.js +276 -21
- package/dist/entries/http/scimThrottleMiddleware.js +576 -54
- package/dist/entries/http/throttleMiddleware.js +65 -16
- package/dist/entries/jobs/exportAuditLogsJob.js +44 -7
- package/dist/entries/jobs/invalidateCacheTagsJob.js +30 -5
- package/dist/entries/queue/createAppQueue.js +748 -72
- package/dist/entries/queue/failedJobRepository.js +1 -1
- package/dist/entries/queue/failedJobService.js +5 -1
- package/dist/entries/queue/jobRunner.js +67 -2
- package/dist/entries/queue/publicQueue.js +746 -71
- package/dist/entries/queue/queueMetrics.js +761 -78
- package/dist/entries/queue/redisQueue.js +768 -148
- package/dist/entries/queue.js +30 -5
- package/dist/entries/scheduler/schedule.js +1 -72
- package/dist/entries/tenant/databaseTenantContext.js +14 -2
- package/dist/entries/tenant/tenantDatabaseScope.js +14 -2
- package/dist/entries/tracing/tracingMiddleware.js +186 -454
- package/dist/framework/public-api.d.ts +14 -10
- package/dist/index.js +2444 -688
- package/dist/types/services.d.ts +3 -3
- package/package.json +17 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
# @getstrata/core changelog
|
|
2
2
|
|
|
3
|
+
## 2.2.1
|
|
4
|
+
|
|
5
|
+
F02 — complete queue durability. Queues have leased reservations, recovery and fenced acknowledgement, but still use Redis lists. Persisted retry schedules, execution deadlines, cancellation and the planned Streams migration remain unfinished. Retries currently wait inside the running worker.
|
|
6
|
+
F10 — production public-route tenancy. Separate anonymous access from development tenant headers, support a trusted-host resolver, reject unknown hosts, and accept forwarded hosts only through configured trusted proxies. The shop still lacks the approved-domain mapping.
|
|
7
|
+
F12 — initial administrator provisioning and migration guidance. Automatic demo seeding is fixed. Secure initial-admin provisioning and a consolidated upgrade/operations guide remain.
|
|
8
|
+
Distributed qualification. Cache generations/fill leases, scheduler ownership, OpenTelemetry, body limits and lifecycle controls now exist. Their implementation should no longer be described as entirely pending, but broader failure and capacity qualification is still required.
|
|
9
|
+
|
|
10
|
+
## 2.2.0
|
|
11
|
+
|
|
12
|
+
Consistent model scopes.
|
|
13
|
+
Changed-field model writes.
|
|
14
|
+
Awaited provider startup.
|
|
15
|
+
Shared cache correctness.
|
|
16
|
+
Native HTTP controls and body limits.
|
|
17
|
+
Graceful lifecycle.
|
|
18
|
+
Validated async discovery.
|
|
19
|
+
Stronger model input types.
|
|
20
|
+
OpenTelemetry tracing.
|
|
21
|
+
Distributed scheduler ownership.
|
|
22
|
+
App-owned quota policy.
|
|
23
|
+
Bounded memory throttling.
|
|
24
|
+
|
|
25
|
+
## Unreleased
|
|
26
|
+
|
|
27
|
+
- Coordinate scheduled minute occurrences with renewable Redis ownership, overlap exclusion, completion retention and lease-loss cancellation. Production defaults to Redis without local fallback; direct task callbacks now accept ownership context. Share appSchedule across root/subpath imports. See SCHEDULER.md for explicit local mode and replay limits.
|
|
28
|
+
|
|
29
|
+
- Use maintained OpenTelemetry tracing with W3C propagation, consistent identities/epoch timestamps, bounded batching, sampling, error status and lifecycle-owned flush/shutdown. Raw URL/exception secrets are omitted; debug x-trace-id no longer overrides identity.
|
|
30
|
+
|
|
31
|
+
- Strengthen declared model write/filter/identifier contracts and add typed plain-record projections with model casts and existing scope/RLS semantics. Source compatibility: use `query().select(...)` instead of partial selects on model-returning helpers, `whereDynamic` for qualified/dynamic predicates, and `newFromTrustedRecord` for deliberate partial driver hydration. Database defaults and mass-assignment rules remain runtime concerns.
|
|
32
|
+
|
|
33
|
+
- Accept awaited provider hooks and explicit cleanup registration; expose optional closure of owned Redis cache/queue clients.
|
|
34
|
+
|
|
35
|
+
- Persist only changed attributes on existing model saves, skip no-op updates and unchanged write casts, and restore retryable snapshots after transaction/savepoint rollback.
|
|
36
|
+
|
|
37
|
+
- Apply related target model scopes and composed filters to lazy/eager/existence/count reads; retain batched connection reuse, isolate morph targets by type and ID, and use dialect-aware through/pivot read parameters.
|
|
38
|
+
|
|
39
|
+
- Compose repeated query predicates and protect global model scopes from caller OR branches; preserve scopes in chunks/cursor pages and intersect cursor bounds with existing filters.
|
|
40
|
+
|
|
41
|
+
- Add typed `defineModel(table)` bases and two-phase model startup; preserve explicit repository overrides and share model identity across package import paths.
|
|
42
|
+
|
|
3
43
|
## 2.1.0
|
|
4
44
|
|
|
5
45
|
- refactor(starter): reuse shared config and base repositories - fix(database): await password casts before model writes - fix(database): preserve concrete model types in query results
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type RedisCacheOptions } from "./redisCacheStore";
|
|
1
2
|
import type { CacheStore } from "./store";
|
|
2
3
|
type CacheDriver = "array" | "redis";
|
|
3
4
|
interface CreateCacheStoreOptions {
|
|
@@ -5,7 +6,8 @@ interface CreateCacheStoreOptions {
|
|
|
5
6
|
ttlMs: number;
|
|
6
7
|
maxEntries: number;
|
|
7
8
|
redisUrl?: string;
|
|
9
|
+
redis?: RedisCacheOptions;
|
|
8
10
|
}
|
|
9
11
|
declare function createCacheStore(options: CreateCacheStoreOptions): CacheStore;
|
|
10
|
-
export type { CacheDriver, CreateCacheStoreOptions };
|
|
12
|
+
export type { CacheDriver, CreateCacheStoreOptions, RedisCacheOptions };
|
|
11
13
|
export { createCacheStore };
|
|
@@ -1,23 +1,36 @@
|
|
|
1
1
|
import type { CacheStore } from "./store";
|
|
2
|
+
type RedisCacheOptions = {
|
|
3
|
+
commandTimeoutMs?: number;
|
|
4
|
+
leaseMs?: number;
|
|
5
|
+
fillTimeoutMs?: number;
|
|
6
|
+
waitTimeoutMs?: number;
|
|
7
|
+
pollMs?: number;
|
|
8
|
+
metadataTtlMs?: number;
|
|
9
|
+
metadataLimit?: number;
|
|
10
|
+
};
|
|
2
11
|
declare class RedisCacheStore implements CacheStore {
|
|
3
12
|
private readonly ttlMs;
|
|
4
13
|
private readonly maxEntries;
|
|
5
14
|
private readonly client;
|
|
6
|
-
private readonly
|
|
7
|
-
private readonly
|
|
8
|
-
|
|
15
|
+
private readonly keys;
|
|
16
|
+
private readonly options;
|
|
17
|
+
private readonly fills;
|
|
18
|
+
private closed;
|
|
19
|
+
constructor(redisUrl: string, ttlMs: number, maxEntries: number, options?: RedisCacheOptions);
|
|
20
|
+
close(): void;
|
|
9
21
|
get<T>(key: string): Promise<T | undefined>;
|
|
10
22
|
set<T>(key: string, value: T, ttlMs?: number): Promise<void>;
|
|
11
|
-
getOrSet<T>(key: string, loader: () => Promise<T>, ttlMs?: number): Promise<T>;
|
|
23
|
+
getOrSet<T>(key: string, loader: (signal?: AbortSignal) => Promise<T>, ttlMs?: number): Promise<T>;
|
|
24
|
+
getOrSetTagged<T>(key: string, loader: (signal?: AbortSignal) => Promise<T>, tags: string[], ttlMs?: number): Promise<T>;
|
|
12
25
|
attachTags(key: string, tags: string[]): Promise<void>;
|
|
13
26
|
flushTags(tags: string[]): Promise<number>;
|
|
14
27
|
invalidate(key: string): Promise<boolean>;
|
|
15
28
|
invalidateByPrefix(prefix: string): Promise<number>;
|
|
16
29
|
clear(): Promise<void>;
|
|
17
30
|
size(): Promise<number>;
|
|
18
|
-
private
|
|
19
|
-
private
|
|
20
|
-
private
|
|
21
|
-
private enforceMaxEntries;
|
|
31
|
+
private fill;
|
|
32
|
+
private serialize;
|
|
33
|
+
private execute;
|
|
22
34
|
}
|
|
35
|
+
export type { RedisCacheOptions };
|
|
23
36
|
export default RedisCacheStore;
|
|
@@ -3,12 +3,13 @@ import TaggedCache from "./taggedCache";
|
|
|
3
3
|
declare class CacheRepository {
|
|
4
4
|
private readonly store;
|
|
5
5
|
constructor(store: CacheStore);
|
|
6
|
+
close(): Promise<void>;
|
|
6
7
|
get<T>(key: string): Promise<T | undefined>;
|
|
7
|
-
remember<T>(key: string, callback: () => Promise<T>, ttlMs?: number): Promise<T>;
|
|
8
|
+
remember<T>(key: string, callback: (signal?: AbortSignal) => Promise<T>, ttlMs?: number): Promise<T>;
|
|
8
9
|
forget(key: string): Promise<boolean>;
|
|
9
10
|
flush(): Promise<void>;
|
|
10
11
|
tags(...names: string[]): TaggedCache;
|
|
11
|
-
getOrSet<T>(key: string, loader: () => Promise<T>, ttlMs?: number): Promise<T>;
|
|
12
|
+
getOrSet<T>(key: string, loader: (signal?: AbortSignal) => Promise<T>, ttlMs?: number): Promise<T>;
|
|
12
13
|
invalidate(key: string): Promise<boolean>;
|
|
13
14
|
invalidateByPrefix(prefix: string): Promise<number>;
|
|
14
15
|
clear(): Promise<void>;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
interface CacheStore {
|
|
2
|
+
close?(): void | Promise<void>;
|
|
2
3
|
get<T>(key: string): Promise<T | undefined>;
|
|
3
4
|
set<T>(key: string, value: T, ttlMs?: number): Promise<void>;
|
|
4
|
-
getOrSet<T>(key: string, loader: () => Promise<T>, ttlMs?: number): Promise<T>;
|
|
5
|
+
getOrSet<T>(key: string, loader: (signal?: AbortSignal) => Promise<T>, ttlMs?: number): Promise<T>;
|
|
6
|
+
/** Shared stores can bind tags before starting a fill. */
|
|
7
|
+
getOrSetTagged?<T>(key: string, loader: (signal?: AbortSignal) => Promise<T>, tags: string[], ttlMs?: number): Promise<T>;
|
|
5
8
|
attachTags(key: string, tags: string[]): Promise<void>;
|
|
6
9
|
flushTags(tags: string[]): Promise<number>;
|
|
7
10
|
invalidate(key: string): Promise<boolean>;
|
|
@@ -3,7 +3,7 @@ declare class TaggedCache {
|
|
|
3
3
|
private readonly store;
|
|
4
4
|
private readonly tags;
|
|
5
5
|
constructor(store: CacheStore, tags: string[]);
|
|
6
|
-
remember<T>(key: string, callback: () => Promise<T>, ttlMs?: number): Promise<T>;
|
|
6
|
+
remember<T>(key: string, callback: (signal?: AbortSignal) => Promise<T>, ttlMs?: number): Promise<T>;
|
|
7
7
|
flush(): Promise<number>;
|
|
8
8
|
}
|
|
9
9
|
export default TaggedCache;
|
|
@@ -13,11 +13,13 @@ interface ProviderContext {
|
|
|
13
13
|
container: ServiceContainer;
|
|
14
14
|
config: ConfigStore;
|
|
15
15
|
dependencies: MutableAppDependencies;
|
|
16
|
+
/** Register owned resources immediately; flush precedes close, each in reverse order. */
|
|
17
|
+
onCleanup(handler: () => void | Promise<void>, phase?: "drain" | "flush" | "close"): void;
|
|
16
18
|
}
|
|
17
19
|
interface ServiceProvider {
|
|
18
20
|
name: string;
|
|
19
|
-
register?(context: ProviderContext): void
|
|
20
|
-
boot?(context: ProviderContext): void
|
|
21
|
+
register?(context: ProviderContext): void | Promise<void>;
|
|
22
|
+
boot?(context: ProviderContext): void | Promise<void>;
|
|
21
23
|
}
|
|
22
24
|
interface AppContext {
|
|
23
25
|
container: ServiceContainer;
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import type { AbilityChecker } from "../auth/abilityChecker";
|
|
2
|
+
import type { ThrottleQuotaPolicy } from "../http/throttleMiddleware";
|
|
3
|
+
import type { PublicTenancyOptions, TenantResolver } from "../tenant/tenantMiddleware";
|
|
2
4
|
import type { AuthUserDirectory } from "./authUserDirectory";
|
|
3
5
|
import type { ServiceContainerLike } from "./container";
|
|
6
|
+
declare const CORE_THROTTLE_QUOTA_POLICY_TOKEN: import("./container").ServiceToken<ThrottleQuotaPolicy>;
|
|
7
|
+
declare const CORE_PUBLIC_TENANCY_TOKEN: import("./container").ServiceToken<PublicTenancyOptions>;
|
|
8
|
+
declare const CORE_TENANT_RESOLVER_TOKEN: import("./container").ServiceToken<TenantResolver>;
|
|
9
|
+
declare const CORE_HTTP_CLEANUP_TOKEN: import("./container").ServiceToken<(cleanup: () => void) => void>;
|
|
4
10
|
declare const CORE_CONFIG_TOKEN = "core.config";
|
|
5
11
|
declare const CORE_CACHE_TOKEN = "core.cache";
|
|
6
12
|
declare const CORE_QUEUE_TOKEN = "core.queue";
|
|
@@ -14,4 +20,4 @@ declare function isAbilityChecker(value: unknown): value is AbilityChecker;
|
|
|
14
20
|
declare function isAuthUserDirectory(value: unknown): value is AuthUserDirectory;
|
|
15
21
|
declare function resolveAbilityChecker(container: ServiceContainerLike): AbilityChecker;
|
|
16
22
|
declare function resolveAuthUserDirectory(container: ServiceContainerLike): AuthUserDirectory | null;
|
|
17
|
-
export { CORE_ABILITY_CHECKER_TOKEN, CORE_AUTH_TOKEN, CORE_AUTH_USER_DIRECTORY_TOKEN, CORE_CACHE_TOKEN, CORE_CONFIG_TOKEN, CORE_EVENT_BUS_TOKEN, CORE_POLICY_GATE_TOKEN, CORE_QUEUE_TOKEN, CORE_TOKEN_SERVICE_TOKEN, isAbilityChecker, isAuthUserDirectory, resolveAbilityChecker, resolveAuthUserDirectory, };
|
|
23
|
+
export { CORE_ABILITY_CHECKER_TOKEN, CORE_AUTH_TOKEN, CORE_AUTH_USER_DIRECTORY_TOKEN, CORE_CACHE_TOKEN, CORE_CONFIG_TOKEN, CORE_EVENT_BUS_TOKEN, CORE_HTTP_CLEANUP_TOKEN, CORE_POLICY_GATE_TOKEN, CORE_PUBLIC_TENANCY_TOKEN, CORE_QUEUE_TOKEN, CORE_TENANT_RESOLVER_TOKEN, CORE_THROTTLE_QUOTA_POLICY_TOKEN, CORE_TOKEN_SERVICE_TOKEN, isAbilityChecker, isAuthUserDirectory, resolveAbilityChecker, resolveAuthUserDirectory, };
|
|
@@ -73,7 +73,6 @@ declare class BaseRepository<TEntity extends object, PrimaryKey extends keyof TE
|
|
|
73
73
|
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[]>>;
|
|
74
74
|
findHasManyThrough<TParent extends object, LocalKey extends keyof TParent & string, FirstKey extends string, SecondLocalKey extends string, SecondKey extends keyof TEntity & string>(parentId: unknown, relation: HasManyThroughRelation<TParent, TEntity, LocalKey, FirstKey, SecondLocalKey, SecondKey>, options?: QueryOptions<TEntity>): Promise<TEntity[]>;
|
|
75
75
|
loadHasManyThroughForParents<TParent extends object, LocalKey extends keyof TParent & string, FirstKey extends string, SecondLocalKey extends string, SecondKey extends keyof TEntity & string>(parents: readonly TParent[], relation: HasManyThroughRelation<TParent, TEntity, LocalKey, FirstKey, SecondLocalKey, SecondKey>, options?: QueryOptions<TEntity>): Promise<Map<TParent[LocalKey], TEntity[]>>;
|
|
76
|
-
private throughSoftDeleteClause;
|
|
77
76
|
private buildThroughWhere;
|
|
78
77
|
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>>;
|
|
79
78
|
loadMorphManyForParents<TParent extends object, LocalKey extends keyof TParent & string, MorphTypeKey extends keyof TEntity & string, MorphIdKey extends keyof TEntity & string>(parents: readonly TParent[], relation: MorphManyRelation<TParent, TEntity, LocalKey, MorphTypeKey, MorphIdKey>, options?: Omit<QueryOptions<TEntity>, "where">): Promise<Map<TParent[LocalKey], TEntity[]>>;
|
|
@@ -9,7 +9,7 @@ export { mapDatabaseError, withDatabaseErrorHandling } from "./errors.ts";
|
|
|
9
9
|
export { Factory } from "./factory.ts";
|
|
10
10
|
export { foreignKeyFromTable, pivotTableName, singularize } from "./inflection.ts";
|
|
11
11
|
export type { CastType, GlobalScopeFn, ModelConstructor } from "./model.ts";
|
|
12
|
-
export { applyCasts, BelongsToManyRelationQuery, BelongsToRelationQuery, dehydrateValue, filterMassAssignable, HasManyRelationQuery, HasManyThroughRelationQuery, HasOneRelationQuery, hydrateValue, Model, ModelQuery, MorphManyRelationQuery, MorphOneRelationQuery, MorphToRelationQuery, registerModelClass, registerModelRepository, } from "./model.ts";
|
|
12
|
+
export { applyCasts, BelongsToManyRelationQuery, BelongsToRelationQuery, bootModels, defineModel, dehydrateValue, filterMassAssignable, HasManyRelationQuery, HasManyThroughRelationQuery, HasOneRelationQuery, hydrateValue, Model, ModelQuery, MorphManyRelationQuery, MorphOneRelationQuery, MorphToRelationQuery, registerModelClass, registerModelRepository, } from "./model.ts";
|
|
13
13
|
export type { MysqlConnection, MysqlExecutable, MysqlPool } from "./mysqlConnection.ts";
|
|
14
14
|
export { createMysqlConnection, createMysqlConnectionFromPool, createMysqlPool, } from "./mysqlConnection.ts";
|
|
15
15
|
export type { NamedConnectionEntry } from "./namedConnections.ts";
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import BaseRepository from "./baseRepository.ts";
|
|
2
2
|
import type { AnyRelationQuery, RelatedModelClass } from "./relationQuery.ts";
|
|
3
3
|
import { BelongsToManyRelationQuery, BelongsToRelationQuery, HasManyRelationQuery, HasManyThroughRelationQuery, HasOneRelationQuery, MorphManyRelationQuery, MorphOneRelationQuery, MorphToRelationQuery } from "./relationQuery.ts";
|
|
4
4
|
import type { BelongsToManyRelation, BelongsToRelation, HasManyRelation, HasOneRelation } from "./relationships.ts";
|
|
5
5
|
import type { RepositoryQuery } from "./repositoryQuery.ts";
|
|
6
|
-
import type {
|
|
6
|
+
import type { TableDefinition } from "./table.ts";
|
|
7
|
+
import type { ModelWhere, ModelWriteValues, QueryOptions, QueryWhere } from "./types.ts";
|
|
7
8
|
type CastType = "date" | "datetime" | "json" | "bool" | "boolean" | "integer" | "int" | "hashed";
|
|
8
9
|
type LoadedAttributes = Record<string, unknown>;
|
|
9
10
|
type ModelCasts = Partial<Record<string, CastType>>;
|
|
@@ -16,6 +17,9 @@ type AnyModel = Model<Record<string, unknown>, "id">;
|
|
|
16
17
|
type ModelAttributes<TModel> = TModel extends {
|
|
17
18
|
toObject(): infer TRecord extends object;
|
|
18
19
|
} ? TRecord : Record<string, unknown>;
|
|
20
|
+
type ModelIdentifier<TModel> = TModel extends {
|
|
21
|
+
readonly id: infer TKey;
|
|
22
|
+
} ? TKey : unknown;
|
|
19
23
|
type WithModelCount<TModel, TCount extends string> = {
|
|
20
24
|
toObject(): Omit<ModelAttributes<TModel>, TCount> & Record<TCount, unknown>;
|
|
21
25
|
get<K extends keyof (Omit<ModelAttributes<TModel>, TCount> & Record<TCount, unknown>)>(key: K): (Omit<ModelAttributes<TModel>, TCount> & Record<TCount, unknown>)[K];
|
|
@@ -34,6 +38,10 @@ type ModelObserver = {
|
|
|
34
38
|
deleting?: (model: AnyModel) => unknown;
|
|
35
39
|
deleted?: (model: AnyModel) => unknown;
|
|
36
40
|
};
|
|
41
|
+
/** Typed model base with a lazily created framework repository and active connection. */
|
|
42
|
+
declare function defineModel<TEntity extends object, PrimaryKey extends keyof TEntity & string>(table: TableDefinition<TEntity, PrimaryKey>): typeof Model<TEntity, PrimaryKey>;
|
|
43
|
+
/** Register all relationship names before initializing any model's boot hooks. */
|
|
44
|
+
declare function bootModels(models: readonly object[]): void;
|
|
37
45
|
/** Alias for `hasMany("Name")` when `Name` is not `constructor.name` or `$morphClass`. */
|
|
38
46
|
declare function registerModelClass(name: string, model: object): void;
|
|
39
47
|
declare function hydrateValue(value: unknown, cast: CastType): unknown;
|
|
@@ -44,21 +52,31 @@ declare function filterMassAssignable(fillable: readonly string[] | undefined, g
|
|
|
44
52
|
declare function applyCasts(values: LoadedAttributes, casts: ModelCasts, direction: "hydrate"): LoadedAttributes;
|
|
45
53
|
declare function applyCasts(values: LoadedAttributes, casts: ModelCasts, direction: "dehydrate"): Promise<LoadedAttributes>;
|
|
46
54
|
declare function applyCasts(values: LoadedAttributes, casts: ModelCasts, direction: "hydrate" | "dehydrate"): LoadedAttributes | Promise<LoadedAttributes>;
|
|
55
|
+
/** Read-only plain records; partial selection never acquires model mutation methods. */
|
|
56
|
+
declare class ModelProjection<TEntity extends object, K extends keyof TEntity & string> {
|
|
57
|
+
private readonly load;
|
|
58
|
+
constructor(load: (limit?: number) => Promise<Array<Pick<TEntity, K>>>);
|
|
59
|
+
get(): Promise<Array<Pick<TEntity, K>>>;
|
|
60
|
+
first(): Promise<Pick<TEntity, K> | null>;
|
|
61
|
+
}
|
|
47
62
|
declare class ModelQuery<TModel extends object = AnyModel, TCounts extends string = never> {
|
|
48
63
|
private readonly modelClass;
|
|
49
64
|
readonly query: RepositoryQuery<Record<string, unknown>, "id">;
|
|
50
65
|
private readonly eager;
|
|
51
66
|
constructor(modelClass: object, query: RepositoryQuery<Record<string, unknown>, "id">);
|
|
52
67
|
with(...relations: RelationNameInput[]): this;
|
|
53
|
-
where(input:
|
|
54
|
-
orWhere(input:
|
|
55
|
-
|
|
68
|
+
where(input: ModelWhere<ModelAttributes<TModel>> | ((builder: import("./whereBuilder.ts").WhereBuilder<ModelAttributes<TModel>, ModelWhere<ModelAttributes<TModel>>>) => void)): this;
|
|
69
|
+
orWhere(input: ModelWhere<ModelAttributes<TModel>> | ((builder: import("./whereBuilder.ts").WhereBuilder<ModelAttributes<TModel>, ModelWhere<ModelAttributes<TModel>>>) => void)): this;
|
|
70
|
+
/** Qualified/dynamic filters retain existing SQL semantics through an explicit escape hatch. */
|
|
71
|
+
whereDynamic(input: QueryWhere<object>): this;
|
|
72
|
+
select<K extends keyof ModelAttributes<TModel> & string>(...columns: readonly K[]): ModelProjection<ModelAttributes<TModel>, K>;
|
|
73
|
+
orderBy(orderBy: QueryOptions<ModelAttributes<TModel>>["orderBy"]): this;
|
|
56
74
|
limit(limit: number): this;
|
|
57
75
|
offset(offset: number): this;
|
|
58
|
-
whereNull(column: string): this;
|
|
59
|
-
whereNotNull(column: string): this;
|
|
60
|
-
whereIn(column:
|
|
61
|
-
whereNotIn(column:
|
|
76
|
+
whereNull(column: keyof ModelAttributes<TModel> & string): this;
|
|
77
|
+
whereNotNull(column: keyof ModelAttributes<TModel> & string): this;
|
|
78
|
+
whereIn<K extends keyof ModelAttributes<TModel> & string>(column: K, values: readonly ModelAttributes<TModel>[K][]): this;
|
|
79
|
+
whereNotIn<K extends keyof ModelAttributes<TModel> & string>(column: K, values: readonly ModelAttributes<TModel>[K][]): this;
|
|
62
80
|
groupBy(groupBy: QueryOptions<object>["groupBy"]): this;
|
|
63
81
|
having(having: QueryWhere<object>): this;
|
|
64
82
|
join(left: `${string}.${string}`, right: `${string}.${string}`): this;
|
|
@@ -92,8 +110,8 @@ declare class ModelQuery<TModel extends object = AnyModel, TCounts extends strin
|
|
|
92
110
|
pluck(column: string): Promise<unknown[]>;
|
|
93
111
|
pluck(column: string, keyBy: string): Promise<Map<unknown, unknown>>;
|
|
94
112
|
value(column: string): Promise<unknown>;
|
|
95
|
-
find(id:
|
|
96
|
-
findOrFail(id:
|
|
113
|
+
find(id: ModelIdentifier<TModel>): Promise<ModelQueryResult<TModel, TCounts> | null>;
|
|
114
|
+
findOrFail(id: ModelIdentifier<TModel>, errorFactory?: (id: unknown) => Error): Promise<ModelQueryResult<TModel, TCounts>>;
|
|
97
115
|
then(onfulfilled?: ((value: ModelQueryResult<TModel, TCounts>[]) => unknown) | null, onrejected?: ((reason: unknown) => unknown) | null): Promise<unknown>;
|
|
98
116
|
withCount<TName extends string, TAlias extends string = `${TName}_count`>(name: TName, alias?: TAlias): ModelQuery<TModel, TCounts | TAlias>;
|
|
99
117
|
private constrainExists;
|
|
@@ -110,11 +128,13 @@ declare class Model<TEntity extends object, PrimaryKey extends keyof TEntity & s
|
|
|
110
128
|
static $appends?: readonly string[];
|
|
111
129
|
static $morphClass?: string;
|
|
112
130
|
private _exists;
|
|
131
|
+
private originalAttributes;
|
|
113
132
|
private readonly loadedRelations;
|
|
114
133
|
private hiddenOverrides;
|
|
115
134
|
private visibleOverrides;
|
|
116
135
|
private appended;
|
|
117
136
|
constructor(attributes: TEntity, repository: BaseRepository<TEntity, PrimaryKey>, exists?: boolean);
|
|
137
|
+
private acceptPersistedAttributes;
|
|
118
138
|
getRepository(): BaseRepository<TEntity, PrimaryKey>;
|
|
119
139
|
get $exists(): boolean;
|
|
120
140
|
get<K extends keyof TEntity>(key: K): TEntity[K];
|
|
@@ -134,15 +154,24 @@ declare class Model<TEntity extends object, PrimaryKey extends keyof TEntity & s
|
|
|
134
154
|
static observe(this: object, observer: ModelObserver): void;
|
|
135
155
|
static addGlobalScope<TEntity extends object, PrimaryKey extends keyof TEntity & string>(this: object, _name: string, scope: GlobalScopeFn<TEntity, PrimaryKey>): void;
|
|
136
156
|
static repository<TEntity extends object, PrimaryKey extends keyof TEntity & string>(this: object): BaseRepository<TEntity, PrimaryKey>;
|
|
157
|
+
/** Apply this model's global filters to a query with an explicitly selected connection. */
|
|
158
|
+
static scopeQuery<TEntity extends object, PrimaryKey extends keyof TEntity & string>(this: object, query: RepositoryQuery<TEntity, PrimaryKey>): RepositoryQuery<TEntity, PrimaryKey>;
|
|
137
159
|
static query<TModel extends object>(this: {
|
|
138
160
|
prototype: TModel;
|
|
139
161
|
}): ModelQuery<TModel>;
|
|
140
162
|
static newFromRecord<TModel extends object>(this: {
|
|
141
163
|
prototype: TModel;
|
|
164
|
+
}, record: NoInfer<ModelWriteValues<ModelAttributes<TModel>>>, exists: false): TModel;
|
|
165
|
+
static newFromRecord<TModel extends object>(this: {
|
|
166
|
+
prototype: TModel;
|
|
167
|
+
}, record: NoInfer<ModelAttributes<TModel>>, exists?: boolean): TModel;
|
|
168
|
+
/** Trusted SQL/driver/partial-record hydration. Callers own shape and completeness. */
|
|
169
|
+
static newFromTrustedRecord<TModel extends object>(this: {
|
|
170
|
+
prototype: TModel;
|
|
142
171
|
}, record: object, exists?: boolean): TModel;
|
|
143
172
|
static create<TModel extends object>(this: {
|
|
144
173
|
prototype: TModel;
|
|
145
|
-
}, attributes:
|
|
174
|
+
}, attributes: NoInfer<ModelWriteValues<ModelAttributes<TModel>>>, forced?: NoInfer<ModelWriteValues<ModelAttributes<TModel>>>): Promise<TModel>;
|
|
146
175
|
static with<TModel extends object>(this: {
|
|
147
176
|
prototype: TModel;
|
|
148
177
|
}, ...relations: RelationNameInput[]): ModelQuery<TModel>;
|
|
@@ -183,32 +212,32 @@ declare class Model<TEntity extends object, PrimaryKey extends keyof TEntity & s
|
|
|
183
212
|
}, name: string, constrain?: (query: AnyRelationQuery) => void): ModelQuery<TModel>;
|
|
184
213
|
static find<TModel extends object>(this: {
|
|
185
214
|
prototype: TModel;
|
|
186
|
-
}, id:
|
|
215
|
+
}, id: NoInfer<ModelIdentifier<TModel>>): Promise<TModel | null>;
|
|
187
216
|
static findOrFail<TModel extends object>(this: {
|
|
188
217
|
prototype: TModel;
|
|
189
|
-
}, id:
|
|
218
|
+
}, id: NoInfer<ModelIdentifier<TModel>>, errorFactory?: (id: unknown) => Error): Promise<TModel>;
|
|
190
219
|
static all<TModel extends object>(this: {
|
|
191
220
|
prototype: TModel;
|
|
192
|
-
}, options?: Omit<QueryOptions<
|
|
221
|
+
}, options?: Omit<QueryOptions<ModelAttributes<TModel>>, "where" | "select">): Promise<TModel[]>;
|
|
193
222
|
static where<TModel extends object>(this: {
|
|
194
223
|
prototype: TModel;
|
|
195
|
-
}, where:
|
|
224
|
+
}, where: NoInfer<ModelWhere<ModelAttributes<TModel>>>): ModelQuery<TModel>;
|
|
196
225
|
static count(this: object): Promise<number>;
|
|
197
226
|
static pluck(this: object, column: string): Promise<unknown[]>;
|
|
198
227
|
static pluck(this: object, column: string, keyBy: string): Promise<Map<unknown, unknown>>;
|
|
199
228
|
static value(this: object, column: string): Promise<unknown>;
|
|
200
229
|
static firstWhere<TModel extends object>(this: {
|
|
201
230
|
prototype: TModel;
|
|
202
|
-
}, where:
|
|
231
|
+
}, where: NoInfer<ModelWhere<ModelAttributes<TModel>>>, options?: Omit<QueryOptions<ModelAttributes<TModel>>, "where" | "select">): Promise<TModel | null>;
|
|
203
232
|
static firstOrNew<TModel extends object>(this: {
|
|
204
233
|
prototype: TModel;
|
|
205
|
-
}, where:
|
|
234
|
+
}, where: NoInfer<ModelWhere<ModelAttributes<TModel>>>, values?: NoInfer<ModelWriteValues<ModelAttributes<TModel>>>): Promise<TModel>;
|
|
206
235
|
static firstOrCreate<TModel extends object>(this: {
|
|
207
236
|
prototype: TModel;
|
|
208
|
-
}, where:
|
|
237
|
+
}, where: NoInfer<ModelWhere<ModelAttributes<TModel>>>, values?: NoInfer<ModelWriteValues<ModelAttributes<TModel>>>): Promise<TModel>;
|
|
209
238
|
static updateOrCreate<TModel extends object>(this: {
|
|
210
239
|
prototype: TModel;
|
|
211
|
-
}, where:
|
|
240
|
+
}, where: NoInfer<ModelWhere<ModelAttributes<TModel>>>, values?: NoInfer<ModelWriteValues<ModelAttributes<TModel>>>): Promise<TModel>;
|
|
212
241
|
save(): Promise<this>;
|
|
213
242
|
update(changes: Partial<TEntity>): Promise<this>;
|
|
214
243
|
delete(): Promise<boolean>;
|
|
@@ -234,5 +263,5 @@ declare class Model<TEntity extends object, PrimaryKey extends keyof TEntity & s
|
|
|
234
263
|
/** Binds a Model class to its table/connection and names it for `hasMany("User")`. */
|
|
235
264
|
declare function registerModelRepository<TModelClass>(model: TModelClass, repository: object): TModelClass;
|
|
236
265
|
export { BelongsToManyRelationQuery, BelongsToRelationQuery, HasManyRelationQuery, HasManyThroughRelationQuery, HasOneRelationQuery, MorphManyRelationQuery, MorphOneRelationQuery, MorphToRelationQuery, } from "./relationQuery.ts";
|
|
237
|
-
export type { CastType, GlobalScopeFn, ModelClassType, ModelConstructor };
|
|
238
|
-
export { applyCasts, dehydrateValue, filterMassAssignable, hydrateValue, Model, ModelQuery, registerModelClass, registerModelRepository, };
|
|
266
|
+
export type { CastType, GlobalScopeFn, ModelAttributes, ModelClassType, ModelConstructor, ModelProjection, };
|
|
267
|
+
export { applyCasts, bootModels, defineModel, dehydrateValue, filterMassAssignable, hydrateValue, Model, ModelQuery, registerModelClass, registerModelRepository, };
|
|
@@ -10,8 +10,11 @@ declare class RepositoryQuery<TEntity extends object, PrimaryKey extends keyof T
|
|
|
10
10
|
private queryOptions;
|
|
11
11
|
private readonly eagerLoads;
|
|
12
12
|
private readonly whereNodes;
|
|
13
|
+
private readonly protectedWhere;
|
|
13
14
|
constructor(repository: BaseRepository<TEntity, PrimaryKey>, whereClause?: QueryWhere<TEntity>, queryOptions?: Omit<QueryOptions<TEntity>, "where">);
|
|
14
15
|
where(input: QueryWhere<TEntity> | ((builder: WhereBuilder<TEntity>) => void)): this;
|
|
16
|
+
/** Preserve completed scope predicates separately from subsequent caller OR conditions. */
|
|
17
|
+
protectWhere(): this;
|
|
15
18
|
orWhere(input: QueryWhere<TEntity> | ((builder: WhereBuilder<TEntity>) => void)): this;
|
|
16
19
|
orderBy(orderBy: QueryOptions<TEntity>["orderBy"]): this;
|
|
17
20
|
limit(limit: number): this;
|
|
@@ -31,7 +34,7 @@ declare class RepositoryQuery<TEntity extends object, PrimaryKey extends keyof T
|
|
|
31
34
|
withBelongsTo<TParent extends object, ForeignKey extends keyof TEntity & string, OwnerKey extends keyof TParent & string, Alias extends string>(as: Alias, relation: BelongsToRelation<TEntity, TParent, ForeignKey, OwnerKey>, parentRepository: BaseRepository<TParent, OwnerKey>, options?: Omit<QueryOptions<TParent>, "where">): this;
|
|
32
35
|
withMorphMany<TChild extends object, LocalKey extends keyof TEntity & string, MorphTypeKey extends keyof TChild & string, MorphIdKey extends keyof TChild & string, Alias extends string>(as: Alias, relation: MorphManyRelation<TEntity, TChild, LocalKey, MorphTypeKey, MorphIdKey>, childRepository: BaseRepository<TChild, keyof TChild & string>, options?: Omit<QueryOptions<TChild>, "where">): this;
|
|
33
36
|
withMorphOne<TChild extends object, LocalKey extends keyof TEntity & string, MorphTypeKey extends keyof TChild & string, MorphIdKey extends keyof TChild & string, Alias extends string>(as: Alias, relation: MorphOneRelation<TEntity, TChild, LocalKey, MorphTypeKey, MorphIdKey>, childRepository: BaseRepository<TChild, keyof TChild & string>, options?: Omit<QueryOptions<TChild>, "where">): this;
|
|
34
|
-
withMorphTo<TParent extends object, MorphTypeKey extends keyof TEntity & string, MorphIdKey extends keyof TEntity & string, Alias extends string>(as: Alias, relation: MorphToRelation<TEntity, MorphTypeKey, MorphIdKey>, repositoriesByType: ReadonlyMap<string, BaseRepository<TParent, keyof TParent & string>>, options?: Omit<QueryOptions<TParent>, "where"
|
|
37
|
+
withMorphTo<TParent extends object, MorphTypeKey extends keyof TEntity & string, MorphIdKey extends keyof TEntity & string, Alias extends string>(as: Alias, relation: MorphToRelation<TEntity, MorphTypeKey, MorphIdKey>, repositoriesByType: ReadonlyMap<string, BaseRepository<TParent, keyof TParent & string>>, options?: Omit<QueryOptions<TParent>, "where">, optionsByType?: ReadonlyMap<string, QueryOptions<TParent>>): this;
|
|
35
38
|
withBelongsToMany<TRelated extends object, Pivot extends object, ParentKey extends keyof TEntity & string, RelatedKey extends keyof TRelated & string, ForeignPivotKey extends keyof Pivot & string, RelatedPivotKey extends keyof Pivot & string, Alias extends string>(as: Alias, relation: BelongsToManyRelation<TEntity, TRelated, Pivot, ParentKey, RelatedKey, ForeignPivotKey, RelatedPivotKey>, relatedRepository: BaseRepository<TRelated, RelatedKey>, options?: Omit<QueryOptions<TRelated>, "where">): this;
|
|
36
39
|
withHasManyThrough<TFar extends object, LocalKey extends keyof TEntity & string, SecondKey extends keyof TFar & string, Alias extends string>(as: Alias, relation: HasManyThroughRelation<TEntity, TFar, LocalKey, string, string, SecondKey>, farRepository: BaseRepository<TFar, keyof TFar & string>, options?: Omit<QueryOptions<TFar>, "where">): this;
|
|
37
40
|
withTrashed(): this;
|
|
@@ -42,11 +45,23 @@ declare class RepositoryQuery<TEntity extends object, PrimaryKey extends keyof T
|
|
|
42
45
|
pluck<K extends keyof TEntity & string>(column: K): Promise<Array<TEntity[K]>>;
|
|
43
46
|
pluck<K extends keyof TEntity & string, KK extends keyof TEntity & string>(column: K, keyBy: KK): Promise<Map<TEntity[KK], TEntity[K]>>;
|
|
44
47
|
value<K extends keyof TEntity & string>(column: K): Promise<TEntity[K] | null>;
|
|
48
|
+
/** Plain selected records, never complete entities or hydrated models. */
|
|
49
|
+
project<K extends keyof TEntity & string>(columns: readonly K[], limit?: number): Promise<Array<Pick<TEntity, K>>>;
|
|
45
50
|
attachToRows(rows: readonly TEntity[]): Promise<Array<TEntity & LoadedRow>>;
|
|
46
51
|
paginate(options: {
|
|
47
52
|
page: number;
|
|
48
53
|
perPage: number;
|
|
49
54
|
}): Promise<PaginatedResult<TEntity>>;
|
|
55
|
+
chunk(count: number, callback: (rows: Array<TEntity & LoadedRow>) => Promise<boolean | void>): Promise<void>;
|
|
56
|
+
cursorPaginate(options: {
|
|
57
|
+
perPage: number;
|
|
58
|
+
cursor?: TEntity[PrimaryKey];
|
|
59
|
+
}): Promise<{
|
|
60
|
+
meta: import("../pagination/index.ts").CursorPaginationMeta<TEntity[PrimaryKey]>;
|
|
61
|
+
data: (TEntity & LoadedRow)[];
|
|
62
|
+
}>;
|
|
63
|
+
/** Compiled query filters for batched relationship loaders. */
|
|
64
|
+
getOptions(): QueryOptions<TEntity>;
|
|
50
65
|
private buildOptions;
|
|
51
66
|
private addJoin;
|
|
52
67
|
private attach;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { WhereNode } from "./whereBuilder.ts";
|
|
1
2
|
type DatabaseComparable = string | number | Date;
|
|
2
3
|
type DatabaseScalar = DatabaseComparable | boolean | null;
|
|
3
4
|
type QueryOperator = {
|
|
@@ -15,6 +16,27 @@ type QueryOperator = {
|
|
|
15
16
|
};
|
|
16
17
|
type QueryFilterValue = DatabaseScalar | readonly DatabaseScalar[] | QueryOperator;
|
|
17
18
|
type QueryWhere<TEntity> = Partial<Record<keyof TEntity & string, QueryFilterValue>> & Partial<Record<string, QueryFilterValue>>;
|
|
19
|
+
/** Ordinary model filters constrain keys and operators to their declared scalar values. */
|
|
20
|
+
type ModelFilterScalar<T> = unknown extends T ? DatabaseScalar : Extract<T, DatabaseScalar>;
|
|
21
|
+
type ModelFilterOperator<T> = {
|
|
22
|
+
eq?: ModelFilterScalar<T>;
|
|
23
|
+
ne?: ModelFilterScalar<T>;
|
|
24
|
+
in?: readonly ModelFilterScalar<T>[];
|
|
25
|
+
notIn?: readonly ModelFilterScalar<T>[];
|
|
26
|
+
gt?: Extract<ModelFilterScalar<T>, DatabaseComparable>;
|
|
27
|
+
gte?: Extract<ModelFilterScalar<T>, DatabaseComparable>;
|
|
28
|
+
lt?: Extract<ModelFilterScalar<T>, DatabaseComparable>;
|
|
29
|
+
lte?: Extract<ModelFilterScalar<T>, DatabaseComparable>;
|
|
30
|
+
isNull?: boolean;
|
|
31
|
+
} & (Extract<T, string> extends never ? unknown : {
|
|
32
|
+
ilike?: string;
|
|
33
|
+
tsMatch?: string;
|
|
34
|
+
});
|
|
35
|
+
type ModelWhere<TEntity> = string extends keyof TEntity ? QueryWhere<TEntity> : {
|
|
36
|
+
[K in keyof TEntity & string]?: ModelFilterScalar<TEntity[K]> | readonly ModelFilterScalar<TEntity[K]>[] | ModelFilterOperator<TEntity[K]>;
|
|
37
|
+
};
|
|
38
|
+
/** Omission stays legal: DB defaults, generated columns and fillable/timestamp policy are runtime concerns. */
|
|
39
|
+
type ModelWriteValues<TEntity> = Partial<TEntity>;
|
|
18
40
|
type QueryOrder<TEntity> = {
|
|
19
41
|
column: keyof TEntity & string;
|
|
20
42
|
direction?: "ASC" | "DESC" | "asc" | "desc";
|
|
@@ -56,7 +78,8 @@ type QuerySelectItem = {
|
|
|
56
78
|
query: string;
|
|
57
79
|
as: string;
|
|
58
80
|
};
|
|
59
|
-
interface QueryOptions<TEntity> {
|
|
81
|
+
interface QueryOptions<TEntity extends object> {
|
|
82
|
+
whereNodes?: WhereNode<TEntity>[];
|
|
60
83
|
where?: QueryWhere<TEntity>;
|
|
61
84
|
orderBy?: QueryOrder<TEntity> | QueryOrder<TEntity>[] | QueryOrderShorthand<TEntity>;
|
|
62
85
|
limit?: number;
|
|
@@ -70,4 +93,4 @@ interface QueryOptions<TEntity> {
|
|
|
70
93
|
}
|
|
71
94
|
type MutationValues<TEntity> = Partial<TEntity>;
|
|
72
95
|
type UpdateValues<TEntity, PrimaryKey extends keyof TEntity & string = keyof TEntity & string> = Partial<Omit<TEntity, PrimaryKey>>;
|
|
73
|
-
export type { DatabaseComparable, DatabaseScalar, MutationValues, QueryFilterValue, QueryJoin, QueryJoinOn, QueryOperator, QueryOptions, QueryOrder, QuerySelectItem, QueryWhere, UpdateValues, };
|
|
96
|
+
export type { DatabaseComparable, DatabaseScalar, ModelWhere, ModelWriteValues, MutationValues, QueryFilterValue, QueryJoin, QueryJoinOn, QueryOperator, QueryOptions, QueryOrder, QuerySelectItem, QueryWhere, UpdateValues, };
|
|
@@ -14,12 +14,12 @@ type WhereNode<TEntity extends object> = {
|
|
|
14
14
|
kind: "and" | "or";
|
|
15
15
|
exists: ExistsClause;
|
|
16
16
|
};
|
|
17
|
-
declare class WhereBuilder<TEntity extends object
|
|
17
|
+
declare class WhereBuilder<TEntity extends object, TWhere extends object = QueryWhere<TEntity>> {
|
|
18
18
|
readonly nodes: WhereNode<TEntity>[];
|
|
19
|
-
where(where:
|
|
20
|
-
orWhere(where:
|
|
21
|
-
whereGroup(fn: (builder: WhereBuilder<TEntity>) => void): this;
|
|
22
|
-
orWhereGroup(fn: (builder: WhereBuilder<TEntity>) => void): this;
|
|
19
|
+
where(where: TWhere): this;
|
|
20
|
+
orWhere(where: TWhere): this;
|
|
21
|
+
whereGroup(fn: (builder: WhereBuilder<TEntity, TWhere>) => void): this;
|
|
22
|
+
orWhereGroup(fn: (builder: WhereBuilder<TEntity, TWhere>) => void): this;
|
|
23
23
|
}
|
|
24
24
|
export type { ExistsClause, WhereNode };
|
|
25
25
|
export { WhereBuilder };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
declare function dispatchModelEvent(event: string, payload: unknown): Promise<void>;
|
|
2
2
|
declare function runWithDeferredModelEvents<T>(callback: () => T | Promise<T>): Promise<T>;
|
|
3
|
-
|
|
3
|
+
declare function onDeferredModelRollback(callback: () => void): void;
|
|
4
|
+
export { dispatchModelEvent, onDeferredModelRollback, runWithDeferredModelEvents };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { type MemoryThrottleStorageOptions } from "../runtime/boundedThrottleStore";
|
|
2
|
+
import type { DisposableMemoryThrottle } from "./memoryThrottleMiddleware";
|
|
3
|
+
import { type DisposableThrottle, type RedisThrottleClient } from "./throttleMiddleware";
|
|
4
|
+
interface LoginThrottleOptions extends MemoryThrottleStorageOptions {
|
|
4
5
|
redisUrl?: string;
|
|
5
6
|
maxAttempts: number;
|
|
6
7
|
decaySeconds: number;
|
|
@@ -10,8 +11,8 @@ interface LoginThrottleOptions {
|
|
|
10
11
|
}
|
|
11
12
|
declare function resolveLoginIdentity(request: Request): string;
|
|
12
13
|
declare function resolveLoginEmail(request: Request): Promise<string>;
|
|
13
|
-
declare function createMemoryLoginThrottleMiddleware(options: LoginThrottleOptions):
|
|
14
|
-
declare function createLoginThrottleMiddleware(options: LoginThrottleOptions):
|
|
14
|
+
declare function createMemoryLoginThrottleMiddleware(options: LoginThrottleOptions): DisposableMemoryThrottle;
|
|
15
|
+
declare function createLoginThrottleMiddleware(options: LoginThrottleOptions): DisposableThrottle;
|
|
15
16
|
declare function resetMemoryLoginThrottleForTests(): void;
|
|
16
17
|
export type { LoginThrottleOptions };
|
|
17
18
|
export { createLoginThrottleMiddleware, createMemoryLoginThrottleMiddleware, resetMemoryLoginThrottleForTests, resolveLoginEmail, resolveLoginIdentity, };
|
|
@@ -1,10 +1,18 @@
|
|
|
1
|
+
import { type MemoryThrottleStats, type MemoryThrottleStorageOptions } from "../runtime/boundedThrottleStore";
|
|
1
2
|
import type { Middleware } from "./middleware";
|
|
2
|
-
|
|
3
|
+
import { type ThrottleQuotaPolicy } from "./throttleMiddleware";
|
|
4
|
+
interface MemoryThrottleOptions extends MemoryThrottleStorageOptions {
|
|
3
5
|
maxAttempts: number;
|
|
4
6
|
decaySeconds: number;
|
|
5
7
|
keyPrefix?: string;
|
|
8
|
+
quotaPolicy?: ThrottleQuotaPolicy;
|
|
6
9
|
}
|
|
7
|
-
|
|
10
|
+
type DisposableMemoryThrottle = Middleware & {
|
|
11
|
+
dispose(): void;
|
|
12
|
+
stats(): MemoryThrottleStats;
|
|
13
|
+
};
|
|
14
|
+
declare function createMemoryThrottleMiddleware(options: MemoryThrottleOptions): DisposableMemoryThrottle;
|
|
15
|
+
/** Lazy generation reset avoids retaining middleware instances in a global test registry. */
|
|
8
16
|
declare function resetMemoryThrottleForTests(): void;
|
|
9
|
-
export type { MemoryThrottleOptions };
|
|
17
|
+
export type { DisposableMemoryThrottle, MemoryThrottleOptions, MemoryThrottleStats, MemoryThrottleStorageOptions, };
|
|
10
18
|
export { createMemoryThrottleMiddleware, resetMemoryThrottleForTests };
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
type RequestMeta = {
|
|
2
2
|
ipAddress: string | null;
|
|
3
|
+
/** Immediate socket peer recorded by the transport; never a forwarded client header. */
|
|
4
|
+
peerAddress?: string | null;
|
|
3
5
|
userAgent: string | null;
|
|
4
6
|
request?: Request;
|
|
5
7
|
/** Registered route template; never a URL supplied by the client. */
|
|
@@ -1,9 +1,18 @@
|
|
|
1
|
+
import { type MemoryThrottleStorageOptions } from "../runtime/boundedThrottleStore";
|
|
1
2
|
import type { Middleware } from "./middleware";
|
|
2
|
-
|
|
3
|
+
import { type RedisThrottleClient } from "./throttleMiddleware";
|
|
4
|
+
interface ScimThrottleOptions extends MemoryThrottleStorageOptions {
|
|
3
5
|
redisUrl?: string;
|
|
4
6
|
maxAttempts: number;
|
|
5
7
|
decaySeconds: number;
|
|
8
|
+
commandTimeoutMs?: number;
|
|
9
|
+
redisClient?: RedisThrottleClient;
|
|
10
|
+
keyPrefix?: string;
|
|
6
11
|
}
|
|
7
|
-
declare function
|
|
12
|
+
declare function resolveScimIdentity(request: Request): string;
|
|
13
|
+
declare function createScimThrottleMiddleware(options: ScimThrottleOptions): Middleware & {
|
|
14
|
+
dispose: () => void;
|
|
15
|
+
stats: () => import("./memoryThrottleMiddleware").MemoryThrottleStats | undefined;
|
|
16
|
+
};
|
|
8
17
|
export type { ScimThrottleOptions };
|
|
9
|
-
export { createScimThrottleMiddleware };
|
|
18
|
+
export { createScimThrottleMiddleware, resolveScimIdentity };
|