@getstrata/core 0.3.0 → 0.3.8
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/dist/bootstrap/config.d.ts +2 -1
- package/dist/core/auth/abilityChecker.d.ts +6 -0
- package/dist/core/database/baseRepository.d.ts +6 -3
- package/dist/core/database/index.d.ts +1 -0
- package/dist/core/database/migrations/runner.d.ts +19 -0
- package/dist/core/database/migrations/types.d.ts +14 -0
- package/dist/core/database/model.d.ts +28 -0
- package/dist/core/database/repositoryQuery.d.ts +20 -0
- package/dist/core/http/requireAbilityMiddleware.d.ts +2 -2
- package/dist/core/http/webFormRequest.d.ts +1 -0
- package/dist/core/validation/rules.d.ts +17 -0
- package/dist/framework/public-api.d.ts +12 -1
- package/dist/index.js +362 -5
- package/dist/modules/user/provider.d.ts +1 -1
- package/package.json +1 -1
|
@@ -9,6 +9,7 @@ declare const CORE_CACHE_TOKEN = "core.cache";
|
|
|
9
9
|
declare const CORE_QUEUE_TOKEN = "core.queue";
|
|
10
10
|
declare const CORE_POLICY_GATE_TOKEN = "core.policyGate";
|
|
11
11
|
declare const CORE_AUTH_TOKEN = "core.auth";
|
|
12
|
+
declare const CORE_TOKEN_SERVICE_TOKEN = "core.tokenService";
|
|
12
13
|
declare const AUTH_DEV_HEADERS_CONFIG_KEY = "auth.allowDevHeaders";
|
|
13
14
|
declare const DEFAULT_APP_PORT = 3000;
|
|
14
15
|
declare const DEFAULT_CACHE_TTL_MS = 3600000;
|
|
@@ -16,4 +17,4 @@ declare const DEFAULT_CACHE_MAX_ENTRIES = 100;
|
|
|
16
17
|
declare const DEFAULT_CACHE_DRIVER = "array";
|
|
17
18
|
declare const DEFAULT_API_TOKEN = "";
|
|
18
19
|
declare const DEFAULT_QUEUE_DRIVER = "sync";
|
|
19
|
-
export { APP_PORT_CONFIG_KEY, AUTH_DEV_HEADERS_CONFIG_KEY, CACHE_DRIVER_CONFIG_KEY, CACHE_MAX_ENTRIES_CONFIG_KEY, CACHE_TTL_MS_CONFIG_KEY, CORE_AUTH_TOKEN, CORE_CACHE_TOKEN, CORE_CONFIG_TOKEN, CORE_POLICY_GATE_TOKEN, CORE_QUEUE_TOKEN, DATABASE_URL_CONFIG_KEY, DEFAULT_API_TOKEN, DEFAULT_APP_PORT, DEFAULT_CACHE_DRIVER, DEFAULT_CACHE_MAX_ENTRIES, DEFAULT_CACHE_TTL_MS, DEFAULT_QUEUE_DRIVER, REDIS_URL_CONFIG_KEY, };
|
|
20
|
+
export { APP_PORT_CONFIG_KEY, AUTH_DEV_HEADERS_CONFIG_KEY, CACHE_DRIVER_CONFIG_KEY, CACHE_MAX_ENTRIES_CONFIG_KEY, CACHE_TTL_MS_CONFIG_KEY, CORE_AUTH_TOKEN, CORE_CACHE_TOKEN, CORE_CONFIG_TOKEN, CORE_POLICY_GATE_TOKEN, CORE_QUEUE_TOKEN, CORE_TOKEN_SERVICE_TOKEN, DATABASE_URL_CONFIG_KEY, DEFAULT_API_TOKEN, DEFAULT_APP_PORT, DEFAULT_CACHE_DRIVER, DEFAULT_CACHE_MAX_ENTRIES, DEFAULT_CACHE_TTL_MS, DEFAULT_QUEUE_DRIVER, REDIS_URL_CONFIG_KEY, };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type PaginatedResult } from "../pagination/index.ts";
|
|
2
2
|
import { type BelongsToRelation, type HasManyRelation } from "./relationships.ts";
|
|
3
|
+
import { RepositoryQuery } from "./repositoryQuery.ts";
|
|
3
4
|
import type { TableDefinition } from "./table.ts";
|
|
4
5
|
import type { MutationValues, QueryOptions, QueryWhere, UpdateValues } from "./types.ts";
|
|
5
6
|
interface DatabaseConnection {
|
|
@@ -27,6 +28,8 @@ declare class BaseRepository<TEntity extends object, PrimaryKey extends keyof TE
|
|
|
27
28
|
forceDeleteById(id: TEntity[PrimaryKey]): Promise<boolean>;
|
|
28
29
|
restoreById(id: TEntity[PrimaryKey]): Promise<TEntity | null>;
|
|
29
30
|
withConnection(connection: DatabaseConnection): this;
|
|
31
|
+
getConnection(): DatabaseConnection;
|
|
32
|
+
query(where?: QueryWhere<TEntity>): RepositoryQuery<TEntity, PrimaryKey>;
|
|
30
33
|
protected findWhere(where: QueryWhere<TEntity>, options?: Omit<QueryOptions<TEntity>, "where">): Promise<TEntity[]>;
|
|
31
34
|
protected countWhere(where?: QueryWhere<TEntity>, options?: Pick<QueryOptions<TEntity>, "withTrashed" | "onlyTrashed">): Promise<number>;
|
|
32
35
|
protected averageColumn(column: keyof TEntity & string, where?: QueryWhere<TEntity>): Promise<number>;
|
|
@@ -36,9 +39,9 @@ declare class BaseRepository<TEntity extends object, PrimaryKey extends keyof TE
|
|
|
36
39
|
value: TEntity[K] | null;
|
|
37
40
|
count: number;
|
|
38
41
|
}>>;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
findByHasManyRelation<TParent extends object, LocalKey extends keyof TParent & string, ForeignKey extends keyof TEntity & string>(relation: HasManyRelation<TParent, TEntity, LocalKey, ForeignKey>, parentId: TParent[LocalKey], options?: Omit<QueryOptions<TEntity>, "where">): Promise<TEntity[]>;
|
|
43
|
+
loadHasManyForParents<TParent extends object, LocalKey extends keyof TParent & string, ForeignKey extends keyof TEntity & string>(parents: readonly TParent[], relation: HasManyRelation<TParent, TEntity, LocalKey, ForeignKey>, options?: Omit<QueryOptions<TEntity>, "where">): Promise<Map<TParent[LocalKey], TEntity[]>>;
|
|
44
|
+
loadBelongsToForParents<TChild extends object, TParent extends object, ForeignKey extends keyof TChild & string, OwnerKey extends keyof TParent & string>(children: readonly TChild[], relation: BelongsToRelation<TChild, TParent, ForeignKey, OwnerKey>, parentRepository: BaseRepository<TParent, OwnerKey>, options?: Omit<QueryOptions<TParent>, "where">): Promise<Map<TChild[ForeignKey], TParent>>;
|
|
42
45
|
}
|
|
43
46
|
export default BaseRepository;
|
|
44
47
|
export type { DatabaseConnection };
|
|
@@ -5,6 +5,7 @@ export { mapDatabaseError, withDatabaseErrorHandling } from "./errors.ts";
|
|
|
5
5
|
export { buildCountQuery, buildDeleteByIdQuery, buildGroupedCountQuery, buildInsertQuery, buildOrderByClause, buildProjectionQuery, buildQueryWhereClause, buildRestoreByIdQuery, buildSelectQuery, buildSoftDeleteByIdQuery, buildUpdateQuery, buildWhereClause, qualifyColumn, quoteIdentifier, resolveSoftDeleteColumn, } from "./query.ts";
|
|
6
6
|
export type { BelongsToRelation, HasManyRelation } from "./relationships.ts";
|
|
7
7
|
export { belongsTo, hasMany, indexBelongsToRelation, indexHasManyRelation, } from "./relationships.ts";
|
|
8
|
+
export { RepositoryQuery } from "./repositoryQuery.ts";
|
|
8
9
|
export type { TableDefinition } from "./table.ts";
|
|
9
10
|
export { defineTable } from "./table.ts";
|
|
10
11
|
export { runInTransaction } from "./transaction.ts";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Migration, MigrationDatabase, MigrationStatus } from "./types";
|
|
2
|
+
type AppliedMigrationRow = {
|
|
3
|
+
name: string;
|
|
4
|
+
batch: number | string;
|
|
5
|
+
};
|
|
6
|
+
declare function ensureMigrationsTable(db: MigrationDatabase): Promise<void>;
|
|
7
|
+
declare function getAppliedMigrations(db: MigrationDatabase): Promise<AppliedMigrationRow[]>;
|
|
8
|
+
declare function loadMigrationsFromDirectory(directory: string): Promise<Migration[]>;
|
|
9
|
+
declare function getMigrationStatus(db: MigrationDatabase, migrations: Migration[]): Promise<MigrationStatus[]>;
|
|
10
|
+
declare function migrateDatabase(db: MigrationDatabase, migrations: Migration[], options?: {
|
|
11
|
+
onMigration?: (name: string) => void;
|
|
12
|
+
}): Promise<number>;
|
|
13
|
+
declare function rollbackDatabase(db: MigrationDatabase, migrations: Migration[], options?: {
|
|
14
|
+
onMigration?: (name: string) => void;
|
|
15
|
+
}): Promise<number>;
|
|
16
|
+
declare function freshDatabase(db: MigrationDatabase, migrations: Migration[], options?: {
|
|
17
|
+
onMigration?: (name: string) => void;
|
|
18
|
+
}): Promise<void>;
|
|
19
|
+
export { ensureMigrationsTable, freshDatabase, getAppliedMigrations, getMigrationStatus, loadMigrationsFromDirectory, migrateDatabase, rollbackDatabase, };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface MigrationDatabase {
|
|
2
|
+
unsafe<T = unknown>(query: string, params?: readonly unknown[]): Promise<T[]>;
|
|
3
|
+
}
|
|
4
|
+
interface Migration {
|
|
5
|
+
name: string;
|
|
6
|
+
up(db: MigrationDatabase): Promise<void>;
|
|
7
|
+
down(db: MigrationDatabase): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
type MigrationStatus = {
|
|
10
|
+
name: string;
|
|
11
|
+
status: "up" | "pending";
|
|
12
|
+
batch: number | null;
|
|
13
|
+
};
|
|
14
|
+
export type { Migration, MigrationDatabase, MigrationStatus };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type BaseRepository from "./baseRepository";
|
|
2
|
+
import type { BelongsToRelation, HasManyRelation } from "./relationships";
|
|
3
|
+
import type { RepositoryQuery } from "./repositoryQuery";
|
|
4
|
+
import type { QueryOptions, QueryWhere } from "./types";
|
|
5
|
+
interface ModelConstructor<TEntity extends object, PrimaryKey extends keyof TEntity & string, TModel extends Model<TEntity, PrimaryKey>> {
|
|
6
|
+
new (attributes: TEntity, repository: BaseRepository<TEntity, PrimaryKey>): TModel;
|
|
7
|
+
}
|
|
8
|
+
declare class Model<TEntity extends object, PrimaryKey extends keyof TEntity & string> {
|
|
9
|
+
protected readonly attributes: TEntity;
|
|
10
|
+
protected readonly repository: BaseRepository<TEntity, PrimaryKey>;
|
|
11
|
+
constructor(attributes: TEntity, repository: BaseRepository<TEntity, PrimaryKey>);
|
|
12
|
+
get<K extends keyof TEntity>(key: K): TEntity[K];
|
|
13
|
+
get id(): TEntity[PrimaryKey];
|
|
14
|
+
toObject(): TEntity;
|
|
15
|
+
protected primaryKey(): PrimaryKey;
|
|
16
|
+
static repository<TEntity extends object, PrimaryKey extends keyof TEntity & string, TModel extends Model<TEntity, PrimaryKey>>(this: ModelConstructor<TEntity, PrimaryKey, TModel>): BaseRepository<TEntity, PrimaryKey>;
|
|
17
|
+
static query<TEntity extends object, PrimaryKey extends keyof TEntity & string, TModel extends Model<TEntity, PrimaryKey>>(this: ModelConstructor<TEntity, PrimaryKey, TModel>): RepositoryQuery<TEntity, PrimaryKey>;
|
|
18
|
+
static find<TEntity extends object, PrimaryKey extends keyof TEntity & string, TModel extends Model<TEntity, PrimaryKey>>(this: ModelConstructor<TEntity, PrimaryKey, TModel>, id: TEntity[PrimaryKey]): Promise<TModel | null>;
|
|
19
|
+
static findOrFail<TEntity extends object, PrimaryKey extends keyof TEntity & string, TModel extends Model<TEntity, PrimaryKey>>(this: ModelConstructor<TEntity, PrimaryKey, TModel>, id: TEntity[PrimaryKey], errorFactory?: (id: TEntity[PrimaryKey]) => Error): Promise<TModel>;
|
|
20
|
+
static all<TEntity extends object, PrimaryKey extends keyof TEntity & string, TModel extends Model<TEntity, PrimaryKey>>(this: ModelConstructor<TEntity, PrimaryKey, TModel>, options?: QueryOptions<TEntity>): Promise<TModel[]>;
|
|
21
|
+
static firstWhere<TEntity extends object, PrimaryKey extends keyof TEntity & string, TModel extends Model<TEntity, PrimaryKey>>(this: ModelConstructor<TEntity, PrimaryKey, TModel>, where: QueryWhere<TEntity>, options?: Omit<QueryOptions<TEntity>, "where">): Promise<TModel | null>;
|
|
22
|
+
loadHasMany<TChild extends object, LocalKey extends keyof TEntity & string, ForeignKey extends keyof TChild & string, Alias extends string>(as: Alias, relation: HasManyRelation<TEntity, TChild, LocalKey, ForeignKey>, childRepository: BaseRepository<TChild, keyof TChild & string>, options?: Omit<QueryOptions<TChild>, "where">): Promise<this & Record<Alias, TChild[]>>;
|
|
23
|
+
loadBelongsTo<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">): Promise<this & Record<Alias, TParent | undefined>>;
|
|
24
|
+
mergeAttributes(patch: Partial<TEntity>): this;
|
|
25
|
+
}
|
|
26
|
+
declare function registerModelRepository<TEntity extends object, PrimaryKey extends keyof TEntity & string, TModel extends Model<TEntity, PrimaryKey>>(model: ModelConstructor<TEntity, PrimaryKey, TModel>, repository: BaseRepository<TEntity, PrimaryKey>): ModelConstructor<TEntity, PrimaryKey, TModel> & typeof Model;
|
|
27
|
+
export type { ModelConstructor };
|
|
28
|
+
export { Model, registerModelRepository };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type BaseRepository from "./baseRepository.ts";
|
|
2
|
+
import type { BelongsToRelation, HasManyRelation } from "./relationships.ts";
|
|
3
|
+
import type { QueryOptions, QueryWhere } from "./types.ts";
|
|
4
|
+
type LoadedRow = Record<string, unknown>;
|
|
5
|
+
declare class RepositoryQuery<TEntity extends object, PrimaryKey extends keyof TEntity & string> {
|
|
6
|
+
private readonly repository;
|
|
7
|
+
private whereClause;
|
|
8
|
+
private queryOptions;
|
|
9
|
+
private readonly eagerLoads;
|
|
10
|
+
constructor(repository: BaseRepository<TEntity, PrimaryKey>, whereClause?: QueryWhere<TEntity>, queryOptions?: Omit<QueryOptions<TEntity>, "where">);
|
|
11
|
+
where(where: QueryWhere<TEntity>): this;
|
|
12
|
+
orderBy(orderBy: QueryOptions<TEntity>["orderBy"]): this;
|
|
13
|
+
limit(limit: number): this;
|
|
14
|
+
withHasMany<TChild extends object, LocalKey extends keyof TEntity & string, ForeignKey extends keyof TChild & string, Alias extends string>(as: Alias, relation: HasManyRelation<TEntity, TChild, LocalKey, ForeignKey>, childRepository: BaseRepository<TChild, keyof TChild & string>, options?: Omit<QueryOptions<TChild>, "where">): this;
|
|
15
|
+
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;
|
|
16
|
+
get(): Promise<Array<TEntity & LoadedRow>>;
|
|
17
|
+
first(): Promise<(TEntity & LoadedRow) | null>;
|
|
18
|
+
private attach;
|
|
19
|
+
}
|
|
20
|
+
export { RepositoryQuery };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type { AbilityChecker } from "../auth/abilityChecker";
|
|
2
2
|
import type { Middleware } from "./middleware";
|
|
3
|
-
declare function createRequireAbilityMiddleware(
|
|
3
|
+
declare function createRequireAbilityMiddleware(abilityChecker: AbilityChecker): (ability: string) => Middleware;
|
|
4
4
|
export { createRequireAbilityMiddleware };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
declare abstract class WebFormRequest<TOutput> {
|
|
2
2
|
authorize(_request: Request): boolean | Promise<boolean>;
|
|
3
3
|
protected abstract parse(payload: unknown): TOutput;
|
|
4
|
+
validatePayload(payload: unknown): TOutput;
|
|
4
5
|
validate(request: Request): Promise<TOutput>;
|
|
5
6
|
}
|
|
6
7
|
export { WebFormRequest };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type ValidationRule = (field: string, value: unknown, payload: Record<string, unknown>) => string | undefined;
|
|
2
|
+
type ValidationSchema = Record<string, ValidationRule[]>;
|
|
3
|
+
declare function required(): ValidationRule;
|
|
4
|
+
declare function stringRule(): ValidationRule;
|
|
5
|
+
declare function minLength(minimum: number): ValidationRule;
|
|
6
|
+
declare function maxLength(maximum: number): ValidationRule;
|
|
7
|
+
declare function pattern(expression: RegExp): ValidationRule;
|
|
8
|
+
declare function enumRule<TValue extends string>(allowedValues: readonly TValue[]): ValidationRule;
|
|
9
|
+
declare function optional(): ValidationRule;
|
|
10
|
+
declare function integerRule(): ValidationRule;
|
|
11
|
+
declare function emailRule(): ValidationRule;
|
|
12
|
+
declare function confirmed(fieldName: string): ValidationRule;
|
|
13
|
+
declare function positiveIntegerRule(): ValidationRule;
|
|
14
|
+
declare function integerRange(minimum: number, maximum: number): ValidationRule;
|
|
15
|
+
declare function validateObject(payload: unknown, schema: ValidationSchema): Record<string, unknown>;
|
|
16
|
+
export type { ValidationRule, ValidationSchema };
|
|
17
|
+
export { confirmed, emailRule, enumRule, integerRange, integerRule, maxLength, minLength, optional, pattern, positiveIntegerRule, required, stringRule, validateObject, };
|
|
@@ -4,13 +4,22 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export type { ServiceProvider } from "../bootstrap/contracts";
|
|
6
6
|
export { ConfigStore, resolveService, ServiceContainer, } from "../bootstrap/contracts";
|
|
7
|
+
export type { AbilityChecker } from "../core/auth/abilityChecker";
|
|
7
8
|
export type { AuthUser } from "../core/auth/authContext";
|
|
8
9
|
export { currentAuthUser, runWithAuthUser } from "../core/auth/authContext";
|
|
9
|
-
export { Policy } from "../core/auth/policy";
|
|
10
|
+
export { Policy, PolicyGate } from "../core/auth/policy";
|
|
10
11
|
export { default as CacheRepository } from "../core/cache/repository";
|
|
11
12
|
export { CACHE_TAGS } from "../core/cache/tags";
|
|
13
|
+
export type { DatabaseConnection } from "../core/database/baseRepository";
|
|
12
14
|
export { default as BaseRepository } from "../core/database/baseRepository";
|
|
15
|
+
export { freshDatabase, getMigrationStatus, loadMigrationsFromDirectory, migrateDatabase, rollbackDatabase, } from "../core/database/migrations/runner";
|
|
16
|
+
export type { Migration, MigrationDatabase, MigrationStatus, } from "../core/database/migrations/types";
|
|
17
|
+
export { Model, registerModelRepository } from "../core/database/model";
|
|
18
|
+
export type { BelongsToRelation, HasManyRelation } from "../core/database/relationships";
|
|
19
|
+
export { belongsTo, hasMany, indexBelongsToRelation, indexHasManyRelation, } from "../core/database/relationships";
|
|
20
|
+
export { RepositoryQuery } from "../core/database/repositoryQuery";
|
|
13
21
|
export { defineTable } from "../core/database/table";
|
|
22
|
+
export type { QueryOptions, QueryOrder, QueryWhere, } from "../core/database/types";
|
|
14
23
|
export { BadRequestError, ConflictError, ForbiddenError, NotFoundError, PreconditionFailedError, UnauthorizedError, UnprocessableEntityError, ValidationError, } from "../core/errors/http";
|
|
15
24
|
export { EventBus } from "../core/events/eventBus";
|
|
16
25
|
export { auth, cache, config, events, log, mail, policyGate, queue, storage, } from "../core/facades";
|
|
@@ -28,3 +37,5 @@ export type { Queue, QueuePriority } from "../core/queue";
|
|
|
28
37
|
export { AsyncQueue, createQueue, Job, SyncQueue } from "../core/queue";
|
|
29
38
|
export type { StorageDriver } from "../core/storage/storage";
|
|
30
39
|
export { LocalStorageDriver, StorageManager } from "../core/storage/storage";
|
|
40
|
+
export type { ValidationRule, ValidationSchema } from "../core/validation/rules";
|
|
41
|
+
export { emailRule, maxLength, minLength, required, stringRule, validateObject, } from "../core/validation/rules";
|
package/dist/index.js
CHANGED
|
@@ -699,6 +699,18 @@ function buildDeleteByIdQuery(table, id) {
|
|
|
699
699
|
}
|
|
700
700
|
|
|
701
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
|
+
}
|
|
702
714
|
function indexHasManyRelation(parents, children, relation) {
|
|
703
715
|
const groups = new Map;
|
|
704
716
|
for (const parent of parents) {
|
|
@@ -730,6 +742,86 @@ function indexBelongsToRelation(children, parents, relation) {
|
|
|
730
742
|
return result;
|
|
731
743
|
}
|
|
732
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
|
+
|
|
733
825
|
// ../../src/core/database/baseRepository.ts
|
|
734
826
|
class BaseRepository {
|
|
735
827
|
table;
|
|
@@ -866,6 +958,12 @@ class BaseRepository {
|
|
|
866
958
|
clone.connection = connection;
|
|
867
959
|
return clone;
|
|
868
960
|
}
|
|
961
|
+
getConnection() {
|
|
962
|
+
return this.connection;
|
|
963
|
+
}
|
|
964
|
+
query(where = {}) {
|
|
965
|
+
return new RepositoryQuery(this, where);
|
|
966
|
+
}
|
|
869
967
|
async findWhere(where, options = {}) {
|
|
870
968
|
return await this.findAll({ ...options, where });
|
|
871
969
|
}
|
|
@@ -926,6 +1024,166 @@ class BaseRepository {
|
|
|
926
1024
|
}
|
|
927
1025
|
}
|
|
928
1026
|
var baseRepository_default = BaseRepository;
|
|
1027
|
+
// ../../src/core/database/migrations/runner.ts
|
|
1028
|
+
import { readdir } from "fs/promises";
|
|
1029
|
+
import { join } from "path";
|
|
1030
|
+
import { pathToFileURL } from "url";
|
|
1031
|
+
var MIGRATIONS_TABLE = "framework_migrations";
|
|
1032
|
+
async function ensureMigrationsTable(db2) {
|
|
1033
|
+
await db2.unsafe(`
|
|
1034
|
+
CREATE TABLE IF NOT EXISTS ${MIGRATIONS_TABLE} (
|
|
1035
|
+
name TEXT PRIMARY KEY,
|
|
1036
|
+
batch INTEGER NOT NULL,
|
|
1037
|
+
run_on TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
1038
|
+
)
|
|
1039
|
+
`);
|
|
1040
|
+
}
|
|
1041
|
+
async function getAppliedMigrations(db2) {
|
|
1042
|
+
await ensureMigrationsTable(db2);
|
|
1043
|
+
return await db2.unsafe(`
|
|
1044
|
+
SELECT name, batch
|
|
1045
|
+
FROM ${MIGRATIONS_TABLE}
|
|
1046
|
+
ORDER BY batch ASC, name ASC
|
|
1047
|
+
`);
|
|
1048
|
+
}
|
|
1049
|
+
async function loadMigrationsFromDirectory(directory) {
|
|
1050
|
+
const entries = await readdir(directory);
|
|
1051
|
+
const migrationFiles = entries.filter((entry) => entry.endsWith(".ts") && entry !== "types.ts" && entry !== "index.ts" && entry !== "runner.ts").sort();
|
|
1052
|
+
const loadedMigrations = await Promise.all(migrationFiles.map(async (fileName) => {
|
|
1053
|
+
const moduleUrl = pathToFileURL(join(directory, fileName)).href;
|
|
1054
|
+
const module = await import(moduleUrl);
|
|
1055
|
+
return module.default;
|
|
1056
|
+
}));
|
|
1057
|
+
return loadedMigrations.filter((migration) => migration?.name !== undefined);
|
|
1058
|
+
}
|
|
1059
|
+
async function getMigrationStatus(db2, migrations) {
|
|
1060
|
+
const applied = await getAppliedMigrations(db2);
|
|
1061
|
+
const appliedByName = new Map(applied.map(({ name, batch }) => [name, Number(batch)]));
|
|
1062
|
+
return migrations.map(({ name }) => ({
|
|
1063
|
+
name,
|
|
1064
|
+
status: appliedByName.has(name) ? "up" : "pending",
|
|
1065
|
+
batch: appliedByName.get(name) ?? null
|
|
1066
|
+
}));
|
|
1067
|
+
}
|
|
1068
|
+
async function migrateDatabase(db2, migrations, options = {}) {
|
|
1069
|
+
const applied = await getAppliedMigrations(db2);
|
|
1070
|
+
const appliedNames = new Set(applied.map(({ name }) => name));
|
|
1071
|
+
const nextBatch = applied.reduce((currentMax, { batch }) => Math.max(currentMax, Number(batch)), 0) + 1;
|
|
1072
|
+
const pendingMigrations = migrations.filter(({ name }) => !appliedNames.has(name));
|
|
1073
|
+
for (const migration of pendingMigrations) {
|
|
1074
|
+
options.onMigration?.(migration.name);
|
|
1075
|
+
await migration.up(db2);
|
|
1076
|
+
await db2.unsafe(`INSERT INTO ${MIGRATIONS_TABLE} (name, batch) VALUES ($1, $2) ON CONFLICT (name) DO NOTHING`, [migration.name, nextBatch]);
|
|
1077
|
+
}
|
|
1078
|
+
return pendingMigrations.length;
|
|
1079
|
+
}
|
|
1080
|
+
async function rollbackDatabase(db2, migrations, options = {}) {
|
|
1081
|
+
const applied = await getAppliedMigrations(db2);
|
|
1082
|
+
if (applied.length === 0) {
|
|
1083
|
+
return 0;
|
|
1084
|
+
}
|
|
1085
|
+
const lastBatch = applied.reduce((currentMax, { batch }) => Math.max(currentMax, Number(batch)), 0);
|
|
1086
|
+
const migrationsToRollback = new Set(applied.filter(({ batch }) => Number(batch) === lastBatch).map(({ name }) => name));
|
|
1087
|
+
let rolledBack = 0;
|
|
1088
|
+
for (const migration of [...migrations].reverse()) {
|
|
1089
|
+
if (!migrationsToRollback.has(migration.name)) {
|
|
1090
|
+
continue;
|
|
1091
|
+
}
|
|
1092
|
+
options.onMigration?.(migration.name);
|
|
1093
|
+
await migration.down(db2);
|
|
1094
|
+
await db2.unsafe(`DELETE FROM ${MIGRATIONS_TABLE} WHERE name = $1`, [migration.name]);
|
|
1095
|
+
rolledBack += 1;
|
|
1096
|
+
}
|
|
1097
|
+
return rolledBack;
|
|
1098
|
+
}
|
|
1099
|
+
async function freshDatabase(db2, migrations, options = {}) {
|
|
1100
|
+
const applied = await getAppliedMigrations(db2);
|
|
1101
|
+
const appliedNames = new Set(applied.map(({ name }) => name));
|
|
1102
|
+
const appliedMigrations = migrations.filter(({ name }) => appliedNames.has(name));
|
|
1103
|
+
for (const migration of [...appliedMigrations].reverse()) {
|
|
1104
|
+
options.onMigration?.(migration.name);
|
|
1105
|
+
await migration.down(db2);
|
|
1106
|
+
}
|
|
1107
|
+
if (appliedMigrations.length > 0) {
|
|
1108
|
+
await db2.unsafe(`DELETE FROM ${MIGRATIONS_TABLE}`);
|
|
1109
|
+
}
|
|
1110
|
+
await migrateDatabase(db2, migrations, options);
|
|
1111
|
+
}
|
|
1112
|
+
// ../../src/core/database/model.ts
|
|
1113
|
+
var modelRepositories = new WeakMap;
|
|
1114
|
+
function resolveModelRepository(model) {
|
|
1115
|
+
const repository = modelRepositories.get(model);
|
|
1116
|
+
if (!repository) {
|
|
1117
|
+
throw new Error(`${model.name}.repository() is not implemented.`);
|
|
1118
|
+
}
|
|
1119
|
+
return repository;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
class Model {
|
|
1123
|
+
attributes;
|
|
1124
|
+
repository;
|
|
1125
|
+
constructor(attributes, repository) {
|
|
1126
|
+
this.attributes = attributes;
|
|
1127
|
+
this.repository = repository;
|
|
1128
|
+
}
|
|
1129
|
+
get(key) {
|
|
1130
|
+
return this.attributes[key];
|
|
1131
|
+
}
|
|
1132
|
+
get id() {
|
|
1133
|
+
return this.attributes[this.primaryKey()];
|
|
1134
|
+
}
|
|
1135
|
+
toObject() {
|
|
1136
|
+
return { ...this.attributes };
|
|
1137
|
+
}
|
|
1138
|
+
primaryKey() {
|
|
1139
|
+
throw new Error(`${this.constructor.name}.primaryKey() is not implemented.`);
|
|
1140
|
+
}
|
|
1141
|
+
static repository() {
|
|
1142
|
+
return resolveModelRepository(this);
|
|
1143
|
+
}
|
|
1144
|
+
static query() {
|
|
1145
|
+
return resolveModelRepository(this).query();
|
|
1146
|
+
}
|
|
1147
|
+
static async find(id) {
|
|
1148
|
+
const repository = resolveModelRepository(this);
|
|
1149
|
+
const record = await repository.findById(id);
|
|
1150
|
+
return record ? new this(record, repository) : null;
|
|
1151
|
+
}
|
|
1152
|
+
static async findOrFail(id, errorFactory) {
|
|
1153
|
+
const repository = resolveModelRepository(this);
|
|
1154
|
+
const record = await repository.findByIdOrThrow(id, errorFactory ?? ((value) => new Error(`Record ${String(value)} not found.`)));
|
|
1155
|
+
return new this(record, repository);
|
|
1156
|
+
}
|
|
1157
|
+
static async all(options = {}) {
|
|
1158
|
+
const repository = resolveModelRepository(this);
|
|
1159
|
+
const rows = await repository.findAll(options);
|
|
1160
|
+
return rows.map((row) => new this(row, repository));
|
|
1161
|
+
}
|
|
1162
|
+
static async firstWhere(where, options = {}) {
|
|
1163
|
+
const repository = resolveModelRepository(this);
|
|
1164
|
+
const rows = await repository.findAll({ ...options, where, limit: 1 });
|
|
1165
|
+
const record = rows[0];
|
|
1166
|
+
return record ? new this(record, repository) : null;
|
|
1167
|
+
}
|
|
1168
|
+
async loadHasMany(as, relation, childRepository, options = {}) {
|
|
1169
|
+
const grouped = await childRepository.withConnection(this.repository.getConnection()).loadHasManyForParents([this.attributes], relation, options);
|
|
1170
|
+
const loaded = grouped.get(this.attributes[relation.localKey]) ?? [];
|
|
1171
|
+
return Object.assign(this, { [as]: loaded });
|
|
1172
|
+
}
|
|
1173
|
+
async loadBelongsTo(as, relation, parentRepository, options = {}) {
|
|
1174
|
+
const grouped = await this.repository.loadBelongsToForParents([this.attributes], relation, parentRepository, options);
|
|
1175
|
+
const loaded = grouped.get(this.attributes[relation.foreignKey]);
|
|
1176
|
+
return Object.assign(this, { [as]: loaded });
|
|
1177
|
+
}
|
|
1178
|
+
mergeAttributes(patch) {
|
|
1179
|
+
Object.assign(this.attributes, patch);
|
|
1180
|
+
return this;
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
function registerModelRepository(model, repository) {
|
|
1184
|
+
modelRepositories.set(model, repository);
|
|
1185
|
+
return model;
|
|
1186
|
+
}
|
|
929
1187
|
// ../../src/core/database/table.ts
|
|
930
1188
|
function defineTable(definition) {
|
|
931
1189
|
return definition;
|
|
@@ -1181,7 +1439,7 @@ function mailer() {
|
|
|
1181
1439
|
// ../../src/core/storage/storage.ts
|
|
1182
1440
|
var {S3Client } = globalThis.Bun;
|
|
1183
1441
|
import { mkdir, readFile, unlink, writeFile } from "fs/promises";
|
|
1184
|
-
import { dirname, join } from "path";
|
|
1442
|
+
import { dirname, join as join2 } from "path";
|
|
1185
1443
|
|
|
1186
1444
|
class LocalStorageDriver {
|
|
1187
1445
|
rootDirectory;
|
|
@@ -1189,7 +1447,7 @@ class LocalStorageDriver {
|
|
|
1189
1447
|
this.rootDirectory = rootDirectory;
|
|
1190
1448
|
}
|
|
1191
1449
|
resolvePath(path) {
|
|
1192
|
-
return
|
|
1450
|
+
return join2(this.rootDirectory, path.replace(/^\/+/, ""));
|
|
1193
1451
|
}
|
|
1194
1452
|
async put(path, contents) {
|
|
1195
1453
|
const absolutePath = this.resolvePath(path);
|
|
@@ -1336,9 +1594,9 @@ function isViewsEnabled() {
|
|
|
1336
1594
|
}
|
|
1337
1595
|
|
|
1338
1596
|
// ../../src/core/view/etaViewEngine.ts
|
|
1339
|
-
import { join as
|
|
1597
|
+
import { join as join3 } from "path";
|
|
1340
1598
|
import { Eta } from "eta";
|
|
1341
|
-
var DEFAULT_VIEWS_DIRECTORY =
|
|
1599
|
+
var DEFAULT_VIEWS_DIRECTORY = join3(process.cwd(), "resources/views");
|
|
1342
1600
|
// ../../src/core/view/htmlResponse.ts
|
|
1343
1601
|
function htmlResponse(html, init = {}) {
|
|
1344
1602
|
return new Response(html, {
|
|
@@ -2105,13 +2363,16 @@ class WebFormRequest {
|
|
|
2105
2363
|
authorize(_request) {
|
|
2106
2364
|
return true;
|
|
2107
2365
|
}
|
|
2366
|
+
validatePayload(payload) {
|
|
2367
|
+
return this.parse(payload);
|
|
2368
|
+
}
|
|
2108
2369
|
async validate(request) {
|
|
2109
2370
|
if (!await this.authorize(request)) {
|
|
2110
2371
|
throw new ForbiddenError;
|
|
2111
2372
|
}
|
|
2112
2373
|
const payload = requestPrefersJson(request) ? await parseJsonBody(request, (body) => body) : await parseFormBody(request);
|
|
2113
2374
|
try {
|
|
2114
|
-
return this.
|
|
2375
|
+
return this.validatePayload(payload);
|
|
2115
2376
|
} catch (error) {
|
|
2116
2377
|
if (error instanceof ValidationError) {
|
|
2117
2378
|
throw error;
|
|
@@ -2145,12 +2406,94 @@ class AsyncQueue {
|
|
|
2145
2406
|
function createQueue(driver) {
|
|
2146
2407
|
return driver === "async" ? new AsyncQueue : new SyncQueue;
|
|
2147
2408
|
}
|
|
2409
|
+
// ../../src/core/validation/rules.ts
|
|
2410
|
+
function required() {
|
|
2411
|
+
return (field, value) => {
|
|
2412
|
+
if (value === undefined || value === null || typeof value === "string" && value.trim() === "") {
|
|
2413
|
+
return `"${field}" is required.`;
|
|
2414
|
+
}
|
|
2415
|
+
return;
|
|
2416
|
+
};
|
|
2417
|
+
}
|
|
2418
|
+
function stringRule() {
|
|
2419
|
+
return (field, value) => {
|
|
2420
|
+
if (value === undefined || value === null) {
|
|
2421
|
+
return;
|
|
2422
|
+
}
|
|
2423
|
+
if (typeof value !== "string") {
|
|
2424
|
+
return `"${field}" must be a string.`;
|
|
2425
|
+
}
|
|
2426
|
+
return;
|
|
2427
|
+
};
|
|
2428
|
+
}
|
|
2429
|
+
function minLength(minimum) {
|
|
2430
|
+
return (field, value) => {
|
|
2431
|
+
if (typeof value !== "string") {
|
|
2432
|
+
return;
|
|
2433
|
+
}
|
|
2434
|
+
if (value.trim().length < minimum) {
|
|
2435
|
+
return `"${field}" must be at least ${minimum} characters.`;
|
|
2436
|
+
}
|
|
2437
|
+
return;
|
|
2438
|
+
};
|
|
2439
|
+
}
|
|
2440
|
+
function maxLength(maximum) {
|
|
2441
|
+
return (field, value) => {
|
|
2442
|
+
if (typeof value !== "string") {
|
|
2443
|
+
return;
|
|
2444
|
+
}
|
|
2445
|
+
if (value.trim().length > maximum) {
|
|
2446
|
+
return `"${field}" must be at most ${maximum} characters.`;
|
|
2447
|
+
}
|
|
2448
|
+
return;
|
|
2449
|
+
};
|
|
2450
|
+
}
|
|
2451
|
+
function emailRule() {
|
|
2452
|
+
return (field, value) => {
|
|
2453
|
+
if (typeof value !== "string") {
|
|
2454
|
+
return;
|
|
2455
|
+
}
|
|
2456
|
+
const normalized = value.trim();
|
|
2457
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(normalized)) {
|
|
2458
|
+
return `"${field}" must be a valid email address.`;
|
|
2459
|
+
}
|
|
2460
|
+
return;
|
|
2461
|
+
};
|
|
2462
|
+
}
|
|
2463
|
+
function validateObject(payload, schema) {
|
|
2464
|
+
if (payload === null || typeof payload !== "object" || Array.isArray(payload)) {
|
|
2465
|
+
throw new ValidationError("Request body must be a JSON object.");
|
|
2466
|
+
}
|
|
2467
|
+
const body = payload;
|
|
2468
|
+
const errors = {};
|
|
2469
|
+
const output = {};
|
|
2470
|
+
for (const [field, rules] of Object.entries(schema)) {
|
|
2471
|
+
const messages = rules.map((rule) => rule(field, body[field], body)).filter((message) => message !== undefined);
|
|
2472
|
+
if (messages.length > 0) {
|
|
2473
|
+
errors[field] = messages;
|
|
2474
|
+
continue;
|
|
2475
|
+
}
|
|
2476
|
+
if (field in body && body[field] !== undefined) {
|
|
2477
|
+
const rawValue = body[field];
|
|
2478
|
+
output[field] = typeof rawValue === "string" ? rawValue.trim() : rawValue;
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
if (Object.keys(errors).length > 0) {
|
|
2482
|
+
throw new ValidationError("The given data was invalid.", errors);
|
|
2483
|
+
}
|
|
2484
|
+
return output;
|
|
2485
|
+
}
|
|
2148
2486
|
export {
|
|
2149
2487
|
withErrorHandling,
|
|
2488
|
+
validateObject,
|
|
2489
|
+
stringRule,
|
|
2150
2490
|
storageFacade as storage,
|
|
2151
2491
|
securedBindRouteModel,
|
|
2152
2492
|
runWithAuthUser,
|
|
2493
|
+
rollbackDatabase,
|
|
2153
2494
|
resolveService,
|
|
2495
|
+
required,
|
|
2496
|
+
registerModelRepository,
|
|
2154
2497
|
queue,
|
|
2155
2498
|
prometheusRegistry,
|
|
2156
2499
|
policyGate,
|
|
@@ -2158,13 +2501,23 @@ export {
|
|
|
2158
2501
|
paginatedResponse,
|
|
2159
2502
|
normalizeMetricPath,
|
|
2160
2503
|
noContentResponse,
|
|
2504
|
+
minLength,
|
|
2505
|
+
migrateDatabase,
|
|
2506
|
+
maxLength,
|
|
2161
2507
|
mailer,
|
|
2162
2508
|
mail,
|
|
2163
2509
|
log,
|
|
2510
|
+
loadMigrationsFromDirectory,
|
|
2164
2511
|
jsonResponse,
|
|
2165
2512
|
isEtagEnabled,
|
|
2513
|
+
indexHasManyRelation,
|
|
2514
|
+
indexBelongsToRelation,
|
|
2515
|
+
hasMany,
|
|
2516
|
+
getMigrationStatus,
|
|
2517
|
+
freshDatabase,
|
|
2166
2518
|
events,
|
|
2167
2519
|
etagFromResource,
|
|
2520
|
+
emailRule,
|
|
2168
2521
|
defineTable,
|
|
2169
2522
|
currentAuthUser,
|
|
2170
2523
|
createdResponse,
|
|
@@ -2172,6 +2525,7 @@ export {
|
|
|
2172
2525
|
createMetricsMiddleware,
|
|
2173
2526
|
config,
|
|
2174
2527
|
cache,
|
|
2528
|
+
belongsTo,
|
|
2175
2529
|
auth,
|
|
2176
2530
|
assertIfMatch,
|
|
2177
2531
|
WebFormRequest,
|
|
@@ -2181,10 +2535,13 @@ export {
|
|
|
2181
2535
|
SyncQueue,
|
|
2182
2536
|
StorageManager,
|
|
2183
2537
|
ServiceContainer,
|
|
2538
|
+
RepositoryQuery,
|
|
2184
2539
|
PrometheusRegistry,
|
|
2185
2540
|
PreconditionFailedError,
|
|
2541
|
+
PolicyGate,
|
|
2186
2542
|
Policy,
|
|
2187
2543
|
NotFoundError,
|
|
2544
|
+
Model,
|
|
2188
2545
|
Mailer,
|
|
2189
2546
|
LogMailDriver,
|
|
2190
2547
|
LocalStorageDriver,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ServiceProvider } from "../../bootstrap/contracts";
|
|
2
2
|
declare const userRepositoryToken = "user.repository";
|
|
3
3
|
declare const apiTokenRepositoryToken = "user.apiTokenRepository";
|
|
4
|
-
declare const tokenServiceToken = "
|
|
4
|
+
declare const tokenServiceToken = "core.tokenService";
|
|
5
5
|
declare const authServiceToken = "user.authService";
|
|
6
6
|
declare const oauthIdentityRepositoryToken = "user.oauthIdentityRepository";
|
|
7
7
|
declare const notificationRepositoryToken = "user.notificationRepository";
|