UNPKG

@x5e/gink

Version:

an eventually consistent database

250 lines (224 loc) 6.18 kB
import { Behavior, BundleBuilder, ChangeBuilder } from "./builders"; import { DBSchema } from "idb"; export const PROTOCOL = "gink"; export type Bytes = Uint8Array; export type BundleBytes = Bytes; export type Medallion = number; export type Timestamp = number; export type ChainStart = Timestamp; export type SeenThrough = Timestamp; export type PriorTime = Timestamp; export type Offset = number; export type DirPath = string; export type FilePath = string; export type NumberStr = string; export type ScalarKey = number | string | Bytes; export type Value = | number | string | boolean | null | Bytes | Map<ScalarKey, Value> | Array<Value> | Date | BigInt; export type BundleInfoTuple = [ Timestamp, Medallion, ChainStart, PriorTime, string, ]; export type ChangeSetOffset = number; export type AsOf = Timestamp | Date | ChangeSetOffset; export type MuidTuple = [Timestamp, Medallion, Offset]; export type Cookies = Map<string, string>; export type Indexable = MuidTuple; export type ActorId = number; // process ID on the server side, something more complex in the browser export type StorageKey = ScalarKey | MuidTuple | [MuidTuple, MuidTuple] | []; export type Placement = { container: MuidTuple; key: StorageKey; placement: MuidTuple; }; export interface BundleListener { (bundle: BundleView): Promise<void>; } export interface ClaimedChain { medallion: Medallion; chainStart: ChainStart; actorId: ActorId; claimTime: Timestamp; } export interface CallBack { (...args: any[]): void; } export interface Indexer { (value: Muid): Indexable; } export interface AuthFunction { (token: string): boolean; } export interface BroadcastFunc { (bundle: BundleView): Promise<void>; } export interface Muid { medallion: Medallion; timestamp: Timestamp; offset: number; } export interface BundleInfo { timestamp: Timestamp; medallion: Medallion; chainStart: ChainStart; priorTime?: PriorTime; hashCode?: Bytes; comment?: string; } export interface BundleView { bytes: BundleBytes; info: BundleInfo; builder: BundleBuilder; } // data structure to represent an Entry; some fields are tuples of 0 or 1 entries because // the indexeddb system can't handle null or undefined in keys (but can handle tuples). export interface Entry { behavior: Behavior; containerId: MuidTuple; /** * storageKey is a KeyType if the entry is for a Directory, a Timestamp if it's for a sequence, * MuidTuple if it's for a property, and empty list for a box. */ storageKey: StorageKey; entryId: MuidTuple; pointeeList: Indexable[]; // use an empty list to denote no pointees value?: Value; expiry?: Timestamp; deletion?: boolean; placementId: MuidTuple; sourceList: Indexable[]; // used for edges targetList: Indexable[]; // used for edges purging?: boolean; } export interface Removal { removing: MuidTuple; // describes the placementId of the thing to be removed removalId: MuidTuple; // the ID of the movement or entry doing the removing containerId: MuidTuple; dest: number; entryId: MuidTuple; } export interface Movement { entryId: MuidTuple; movementId: MuidTuple; containerId: MuidTuple; dest: number; purge: boolean; } export interface Clearance { containerId: MuidTuple; clearanceId: MuidTuple; purging: boolean; } export interface EdgeData { source: Muid; target: Muid; etype?: Muid; value?: Value; effective?: number; } export interface KeyPair { publicKey: Bytes; secretKey: Bytes; } export interface Meta { bundler?: Bundler; comment?: string; identity?: string; } export interface Bundler { addChange(changeBuilder: ChangeBuilder): Muid; commit(comment?: string): Promise<BundleInfo>; medallion: number; } export interface Connection { subscribe(callback: () => void): () => void; get hasSentUnackedData(): boolean; get hasSentInitialSync(): boolean; get hasRecvInitialSync(): boolean; get hasSentGreeting(): boolean; get isReadOnly(): boolean; get synced(): boolean; get ready(): Promise<void>; close(): void; } export interface Sealer { (changes: ChangeBuilder[], meta?: Meta): Promise<BundleInfo>; } export interface IndexedDbStoreSchema extends DBSchema { accumulatorTotals: { key: MuidTuple; value: bigint; }; trxns: { key: BundleInfoTuple; value: BundleBytes; }; chainInfos: { value: BundleInfo; key: [number, number]; }; activeChains: { value: ClaimedChain; key: [number]; // claimTime }; containers: { key: MuidTuple; value: Bytes; }; removals: { value: Removal; key: MuidTuple; // movementId indexes: { "by-container-movement": [MuidTuple, MuidTuple]; // containerId, movementId "by-removing": [MuidTuple, MuidTuple]; // removing, removalId }; }; clearances: { value: Clearance; key: [MuidTuple, MuidTuple]; // ["containerId", "clearanceId"] }; entries: { value: Entry; key: MuidTuple; indexes: { "by-container-key-placement": [ MuidTuple, ScalarKey | Timestamp | MuidTuple | [], MuidTuple, ]; "by-container-name": [MuidTuple, string]; // for use with global property and container names "by-key-placement": [StorageKey, MuidTuple]; // for use with properties and the containers they describe pointees: Indexable; locations: [MuidTuple, MuidTuple]; sources: Indexable; targets: Indexable; }; }; identities: { value: string; key: [Medallion, ChainStart]; }; verifyKeys: { value: Bytes; key: [Medallion, ChainStart]; }; secretKeys: { value: Bytes; key: Bytes; }; symmetricKeys: { value: Bytes; key: number; }; }