UNPKG

@getanthill/datastore

Version:

Event-Sourced Datastore

326 lines (325 loc) 9.85 kB
/// <reference types="node" /> import type { FindCursor, Db } from 'mongodb'; import type { NextFunction, Request, Response, Router } from 'express'; import type { EventEmitter } from 'events'; import type { Datastore } from '../sdk'; import type { MongoDbConnector } from '@getanthill/mongodb-connector'; import type Ajv from 'ajv'; import type { Models } from '../models'; import type MQTTClient from '../services/mqtt'; import type AMQPClient from '../services/amqp'; import type FullyHomomorphicEncryptionClient from '../services/fhe'; import type Authz from '../services/authz'; import type { envConfig } from '../config'; import * as metrics from '../constants/metrics'; import * as telemetry from '@getanthill/telemetry'; export * as authorizations from './authorizations'; export type Source = 'entities' | 'events'; export type AccessLevel = 'read' | 'decrypt' | 'write' | 'admin'; export interface Access { id: string; token: string; level: AccessLevel; } export interface Event { type: string; v?: string; [x: string]: any; } export interface ResponseError extends Error { name: string; status?: number; details?: object[]; } export type Telemetry = typeof telemetry; export type Reducer = (state: object, event: Event, validator?: Ajv) => object; export type DatastoreConfig = typeof envConfig; export type AnyObject = { [key: string]: any; }; export type Any = null | number | string | boolean | AnyObject | AnyObject[]; export interface Services { config: DatastoreConfig; telemetry: Telemetry; metrics: typeof metrics; signals: EventEmitter; api: (services: Services) => Promise<Router>; events: (services: Services) => Promise<void>; mongodb: MongoDbConnector; mqtt: MQTTClient; amqp: AMQPClient; fhe: FullyHomomorphicEncryptionClient; models: Models; authz: Authz; datastores: Map<string, Datastore>; } export interface ApiErrorsObject { message?: { [key: string]: number | ((err: Error, req: Request, res: Response, next: NextFunction) => Promise<number>); }; code?: { [key: string]: number | ((err: Error, req: Request, res: Response, next: NextFunction) => Promise<number>); }; } export type ProcessDestroySignal = 'SIGTERM' | 'SIGINT' | 'uncaughtException' | 'unhandledRejection'; export interface ModelSchema { model?: any; events?: any; } export interface ModelIndex { collection: string; fields: object | { [key: string]: string | number; }; opts: { name?: string; [key: string]: any; }; } export interface Processing { name: string; field: string; purpose: string; persons: string[]; recipients: string[]; duration_in_seconds: number; tokens?: string[]; security_policies?: string; owner?: { name: string; email?: string; phone?: string; url?: string; location?: { address?: string; post_code?: string; city?: string; country_code?: string; region?: string; }; }; } export interface ModelConfig { name: string; correlation_field: string; schema: ModelSchema; db?: string; is_enabled?: boolean; description?: string; retry_duration?: number; indexes?: ModelIndex[]; encrypted_fields?: string[]; links?: { [key: string]: string; }; with_default_events?: boolean; with_global_version?: boolean; with_fully_homomorphic_encryption?: boolean; fhe_public_key_field?: string; with_blockchain_hash?: boolean; current_hash_field?: string; previous_hash_field?: string; nonce_field?: string; blockchain_hash_difficulty?: number; blockchain_hash_genesis?: string; must_wait_state_persistence?: boolean; [key: string]: any; processings?: Processing[]; } export interface DatastoreImportLink { model: string; id?: string; is_idempotency_condition?: boolean; idempotency?: { [key: string]: any; }; map: string | { [key: string]: string; }; } export interface DatastoreImportFixture { model: string; id: string; idempotency: { [key: string]: any; }; omit_on_update?: string[]; links?: DatastoreImportLink[]; entity: any; } export interface HandlerFunc { (obj: any, metadata: { handlerId?: string; path?: string; datastore?: string; model?: string; source?: Source; raw?: boolean; }): Promise<any>; } export interface StartFunc { (): Promise<RunnerServices>; } export interface StopFunc { (): Promise<void>; } export interface RunnerServices { telemetry?: Telemetry; datastores: { [key: string]: Datastore; }; [key: string]: any; } export interface RunnerTrigger { datastore?: string; model?: string; source?: Source; raw?: boolean; query?: object; headers?: object; queryAsJSONSchema?: boolean; processing?: { correlation_field: string; field: string; states: [string, string, string?, string?]; }; } export interface HandlerConfig extends RunnerTrigger { triggers?: RunnerTrigger[]; start: StartFunc; stop: StopFunc; handler: HandlerFunc; } export interface HandlerBuilderFunc { (url?: URL): Promise<HandlerConfig>; } export type EntityState = any; export type ModelConstructor<T> = new (services: Services, correlationId?: string, retryDuration?: number) => T; export interface HandleOptions { mustEncrypt?: boolean; imperativeVersion?: number; isReadonly?: string; mustWaitStatePersistence?: boolean; retryDuration?: number; } export interface ModelInstance { state: EntityState; mongodb: MongoDbConnector; retryDuration: number; correlationId: string; latestHandledEvents: Event[]; handleWithRetry(handler: () => Event[], retryDuration: number, storeStateErrorHandler: (...args: any) => void, handleOptions?: HandleOptions): Promise<any>; apply(eventType: string, data: AnyObject, handleOptions?: HandleOptions, v?: string): Promise<ModelInstance>; getState(): Promise<EntityState>; patch(data: AnyObject, handleOptions?: HandleOptions): Promise<ModelInstance>; update(data: AnyObject, handleOptions?: HandleOptions): Promise<ModelInstance>; create(data: AnyObject, handleOptions?: HandleOptions): Promise<ModelInstance>; upsert(data: AnyObject, handleOptions?: HandleOptions): Promise<ModelInstance>; getEvents(version?: number): FindCursor<any>; restore(version: number): Promise<ModelInstance>; rollback(events: Event[], updatedState: EntityState): Promise<ModelInstance>; createSnapshot(): Promise<EntityState>; getStateAtVersion(version: number, mustThrow?: boolean): Promise<EntityState>; getNextVersion(): Promise<number>; archive(): Promise<ModelInstance>; unarchive(): Promise<ModelInstance>; delete(): Promise<void>; } export interface ModelStatic { IV_LENGTH: number; RETRY_ERRORS: string[]; encryptionKeys: any[] | null; hashedEncryptionKeys: any[] | null; getSchema(): ModelSchema; getModelConfig(): ModelConfig; getOriginalSchema(): any; getCorrelationField(): string; getCollectionName(): string; db(mongodb: MongoDbConnector, isRead?: boolean): Db; explain(cursor: any, query: any): void; count(mongodb: MongoDbConnector, query: any): Promise<number>; find(mongodb: MongoDbConnector, query: any, opts?: any): FindCursor<any>; isEncryptedField(field: string): boolean; getStatesCollection(db: any): any; getEventsCollection(db: any): any; getSnapshotsCollection(db: any): any; getEncryptionKeys(): string[]; getHashesEncryptionKeys(): string[]; getEligibleKeys(keys: string[]): string[]; getRequiredIndexes(): { [x: string]: (object | { version: number; name: string; unique?: boolean; })[][]; }; hashValue(data: any): string; encrypt(data: any, additionalEncryptedFields?: string[], keys?: string[], hashes?: string[], algorithm?: string): any; decrypt(data: any, additionalEncryptedFields?: string[], keys?: string[], hashedKeys?: string[]): any; getIsReadonlyProperty(modelConfig?: ModelConfig): any; getIsArchivedProperty(modelConfig?: ModelConfig): any; getIsDeletedProperty(modelConfig?: ModelConfig): any; } export type GenericType = ModelConstructor<ModelInstance> & ModelStatic; export interface Links { [key: string]: { path: string; model: GenericType; }; } export interface BuiltLinks { [key: string]: { operationId: string; parameters: { [key: string]: string; }; }; } export interface SpecFragment { openapi: string; servers: Array<{ description: 'API Server'; url: '/api'; [key: string]: any; }>; info: { title: string; description: string; version: string; license: { name: string; url: string; [key: string]: any; }; [key: string]: any; }; tags: Array<{ name: string; description: string; }>; components: any; paths: any; } export interface Ctx { telemetry: Telemetry; entities?: Map<string, any>; projections?: any[]; data?: { config: { datastores: { [key: string]: any; }; imports?: { date: any; }; runner_params: any; exit_timeout: any; }; events: any[]; imports: any; projections: any[]; assertions: any[]; }; instances?: any; [key: string]: any; }