Runtime Guides

Package-source copy · Generated into the site so runtime docs are searchable and linkable.

API Reference (TypeScript)

This reference is generated from declaration files emitted from ts/src. Do not hand-edit signatures here; run make generate-api-reference.

Drift check

make verify-api-reference

Public modules

errors

export type ErrorCode = 'ErrItemNotFound' | 'ErrConditionFailed' | 'ErrVersionConflict' | 'ErrLeaseHeld' | 'ErrLeaseNotOwned' | 'ErrInvalidModel' | 'ErrMissingPrimaryKey' | 'ErrInvalidOperator' | 'ErrTableNotFound' | 'ErrEncryptedFieldNotQueryable' | 'ErrEncryptionNotConfigured' | 'ErrInvalidEncryptedEnvelope' | 'ErrImmutableModelMutation' | 'ErrProtectedFieldMutation' | 'ErrRejectedDeployAuthorityEvidence';
export declare class TheorydbError extends Error {
    readonly code: ErrorCode;
    readonly codes: readonly ErrorCode[];
    constructor(code: ErrorCode, message: string, options?: {
        cause?: unknown;
        codes?: readonly ErrorCode[];
    });
}
export declare function isTheorydbError(value: unknown): value is TheorydbError;
export declare function theorydbErrorCodes(value: unknown): readonly ErrorCode[];
export declare function hasTheorydbErrorCode(value: unknown, code: ErrorCode): boolean;

client

import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { type BatchGetResult, type BatchWriteResult, type RetryOptions } from './batch.js';
import type { Model, ModelItem } from './model.js';
import type { SendOptions } from './send-options.js';
import { type NumberUnmarshalMode } from './marshal.js';
import { QueryBuilder, ScanBuilder } from './query.js';
import type { TransactAction, TransactGetAction } from './transaction.js';
import { UpdateBuilder } from './update-builder.js';
import { type EncryptionProvider } from './encryption.js';
import { type WritePolicyOptions } from './write-policy.js';
export interface TheorydbClientOptions {
    encryption?: EncryptionProvider;
    now?: () => string;
    sendOptions?: SendOptions;
    /**
     * Controls how DynamoDB N/NS values are unmarshaled.
     *
     * The default, 'string', returns canonical DynamoDB decimal strings so reads
     * are precision-safe for integers outside the safe range and high-precision
     * decimals. Use 'number' only when lossy JavaScript Number conversion is
     * acceptable for a specific client.
     */
    numberUnmarshalMode?: NumberUnmarshalMode;
}
type ModelKey<TItem extends Record<string, unknown>> = Partial<TItem>;
type ModelField<TItem extends Record<string, unknown>> = Extract<keyof TItem, string>;
export declare class ModelRepository<TItem extends Record<string, unknown> = Record<string, unknown>> {
    private readonly client;
    private readonly modelDef;
    constructor(client: TheorydbClient, modelDef: Model<TItem>);
    create(item: TItem, opts?: {
        ifNotExists?: boolean;
    }): Promise<void>;
    save(item: TItem): Promise<void>;
    get(key: ModelKey<TItem>): Promise<TItem>;
    getOrNull(key: ModelKey<TItem>): Promise<TItem | null>;
    update(item: TItem, fields: readonly ModelField<TItem>[], opts?: WritePolicyOptions): Promise<void>;
    delete(key: ModelKey<TItem>): Promise<void>;
    batchGet(keys: Array<ModelKey<TItem>>, opts?: RetryOptions & {
        consistentRead?: boolean;
    }): Promise<BatchGetResult<TItem>>;
    batchWrite(req: {
        puts?: TItem[];
        deletes?: Array<ModelKey<TItem>>;
    }, opts?: RetryOptions): Promise<BatchWriteResult>;
    query(): QueryBuilder<TItem>;
    scan(): ScanBuilder<TItem>;
    updateBuilder(key: ModelKey<TItem>): UpdateBuilder;
}
export declare class TheorydbClient {
    private readonly ddb;
    private readonly models;
    private encryption;
    private readonly now;
    private readonly sendOptions;
    private readonly unmarshalOptions;
    constructor(ddb: DynamoDBClient, opts?: TheorydbClientOptions);
    withEncryption(provider: EncryptionProvider): this;
    withSendOptions(sendOptions?: SendOptions): TheorydbClient;
    withDynamoDBClient(ddb: DynamoDBClient): TheorydbClient;
    register(...models: Model[]): this;
    model<M extends Model>(model: M): ModelRepository<ModelItem<M>>;
    model(modelName: string): ModelRepository<Record<string, unknown>>;
    private requireModel;
    private requireEncryption;
    create(modelName: string, item: Record<string, unknown>, opts?: {
        ifNotExists?: boolean;
    }): Promise<void>;
    save(modelName: string, item: Record<string, unknown>): Promise<void>;
    get(modelName: string, key: Record<string, unknown>): Promise<Record<string, unknown>>;
    getOrNull(modelName: string, key: Record<string, unknown>): Promise<Record<string, unknown> | null>;
    update(modelName: string, item: Record<string, unknown>, fields: string[], opts?: WritePolicyOptions): Promise<void>;
    delete(modelName: string, key: Record<string, unknown>): Promise<void>;
    batchGet(modelName: string, keys: Array<Record<string, unknown>>, opts?: RetryOptions & {
        consistentRead?: boolean;
    }): Promise<BatchGetResult>;
    batchWrite(modelName: string, req: {
        puts?: Array<Record<string, unknown>>;
        deletes?: Array<Record<string, unknown>>;
    }, opts?: RetryOptions): Promise<BatchWriteResult>;
    transactGet(actions: TransactGetAction[]): Promise<Array<Record<string, unknown> | undefined>>;
    transactWrite(actions: TransactAction[]): Promise<void>;
    query(modelName: string): QueryBuilder;
    scan(modelName: string): ScanBuilder;
    updateBuilder(modelName: string, key: Record<string, unknown>): UpdateBuilder;
}
export {};

cursor

import type { AttributeValue } from '@aws-sdk/client-dynamodb';
export type CursorSort = 'ASC' | 'DESC';
export interface Cursor {
    lastKey: Record<string, AttributeValue>;
    index?: string;
    sort?: CursorSort;
}
export declare function encodeCursor(cursor: Cursor): string;
export declare function decodeCursor(encoded: string): Cursor;

dms

import { type Model, type ModelSchema } from './model.js';
export interface DmsDocument {
    dms_version: string;
    namespace?: string;
    models: ModelSchema[];
}
export interface DmsCompareOptions {
    ignoreTableName?: boolean;
}
export declare function parseDmsDocument(raw: string): DmsDocument;
export declare function getDmsModel(doc: DmsDocument, name: string): ModelSchema;
export declare function modelToDmsModel(model: Model | ModelSchema): Readonly<ModelSchema>;
export declare function assertModelsEquivalent(got: Model | ModelSchema, want: ModelSchema, options?: DmsCompareOptions): void;

model

export type ScalarType = 'S' | 'N' | 'B' | 'BOOL' | 'NULL' | 'M' | 'L' | 'SS' | 'NS' | 'BS';
export type KeyType = 'S' | 'N' | 'B';
export interface ValueConverter {
    toDynamoValue(value: unknown): unknown;
    fromDynamoValue(value: unknown): unknown;
}
export interface KeySchema {
    attribute: string;
    type: KeyType;
}
export interface AttributeSchema {
    attribute: string;
    type: ScalarType;
    required?: boolean;
    optional?: boolean;
    omit_empty?: boolean;
    json?: boolean;
    binary?: boolean;
    format?: string;
    roles?: readonly string[];
    encryption?: unknown;
    converter?: ValueConverter;
}
export interface IndexSchema {
    name: string;
    type: 'GSI' | 'LSI';
    partition: KeySchema;
    sort?: KeySchema;
    projection?: {
        type: 'ALL' | 'KEYS_ONLY' | 'INCLUDE';
        fields?: readonly string[];
    };
}
export interface WritePolicySchema {
    mode?: 'mutable' | 'write_once';
    protected_attributes?: readonly string[];
}
export interface WritePolicy {
    mode: 'mutable' | 'write_once';
    protectedAttributes: readonly string[];
}
export interface ModelSchema {
    name: string;
    table: {
        name: string;
    };
    naming?: {
        convention?: 'camelCase' | 'snake_case' | 'dynamorm';
    };
    keys: {
        partition: KeySchema;
        sort?: KeySchema;
    };
    write_policy?: WritePolicySchema;
    attributes: readonly AttributeSchema[];
    indexes?: readonly IndexSchema[];
}
export interface ModelRoles {
    pk: string;
    sk?: string;
    createdAt?: string;
    updatedAt?: string;
    version?: string;
    ttl?: string;
}
export interface Model<TItem extends Record<string, unknown> = Record<string, unknown>> {
    readonly name: string;
    readonly tableName: string;
    readonly schema: Readonly<ModelSchema>;
    readonly attributes: ReadonlyMap<string, Readonly<AttributeSchema>>;
    readonly indexes: ReadonlyMap<string, Readonly<IndexSchema>>;
    readonly roles: Readonly<ModelRoles>;
    readonly writePolicy: Readonly<WritePolicy>;
    readonly __itemType?: TItem;
}
type AttributeValueFor<A extends AttributeSchema> = A['type'] extends 'S' ? string : A['type'] extends 'N' ? number : A['type'] extends 'B' ? Uint8Array : A['type'] extends 'BOOL' ? boolean : A['type'] extends 'NULL' ? null : A['type'] extends 'SS' ? string[] : A['type'] extends 'NS' ? number[] : A['type'] extends 'BS' ? Uint8Array[] : A['type'] extends 'L' ? unknown[] : A['type'] extends 'M' ? Record<string, unknown> : unknown;
type AttributeHasRole<A extends AttributeSchema, R extends string> = A['roles'] extends readonly string[] ? R extends A['roles'][number] ? true : false : false;
type IsOptionalAttribute<A extends AttributeSchema> = A extends {
    optional: true;
} ? true : A extends {
    omit_empty: true;
} ? true : AttributeHasRole<A, 'created_at'> extends true ? true : AttributeHasRole<A, 'updated_at'> extends true ? true : AttributeHasRole<A, 'version'> extends true ? true : AttributeHasRole<A, 'ttl'> extends true ? true : false;
type AttributeName<A extends AttributeSchema> = A['attribute'] extends string ? A['attribute'] : never;
type RequiredAttributes<S extends ModelSchema> = {
    [A in S['attributes'][number] as IsOptionalAttribute<A> extends true ? never : AttributeName<A>]: AttributeValueFor<A>;
};
type OptionalAttributes<S extends ModelSchema> = {
    [A in S['attributes'][number] as IsOptionalAttribute<A> extends true ? AttributeName<A> : never]?: AttributeValueFor<A>;
};
export type InferModelItem<S extends ModelSchema> = RequiredAttributes<S> & OptionalAttributes<S>;
export type ModelItem<M extends Model> = M extends Model<infer TItem> ? TItem : Record<string, unknown>;
export declare function defineModel<const S extends ModelSchema>(schema: S): Model<InferModelItem<S>>;
export {};

query

import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import type { AggregateResult } from './aggregates.js';
import { GroupByQuery } from './aggregates.js';
import { type CursorSort } from './cursor.js';
import { type EncryptionProvider } from './encryption.js';
import { type UnmarshalOptions } from './marshal.js';
import type { Model } from './model.js';
import type { BuilderShape } from './optimizer.js';
import type { SendOptions } from './send-options.js';
import type { Page, QueryOperator, QueryRetryOptions } from './query-types.js';
export { unsafeOperator } from './query-types.js';
export type { KnownOperator, OperatorEscape, Page, QueryOperator, QueryRetryOptions, } from './query-types.js';
export interface FilterGroupBuilder {
    filter(field: string, op: QueryOperator, ...values: unknown[]): this;
    orFilter(field: string, op: QueryOperator, ...values: unknown[]): this;
    filterGroup(fn: (b: FilterGroupBuilder) => void): this;
    orFilterGroup(fn: (b: FilterGroupBuilder) => void): this;
}
export declare class QueryBuilder<TItem extends Record<string, unknown> = Record<string, unknown>> {
    private readonly ddb;
    private readonly model;
    private readonly encryption?;
    private readonly sendOptions?;
    private readonly unmarshalOptions;
    private indexName?;
    private pkValue?;
    private skCondition?;
    private limitCount?;
    private projectionFields?;
    private consistentReadEnabled;
    private cursorToken;
    private sortDir;
    private readonly filters;
    constructor(ddb: DynamoDBClient, model: Model, encryption?: EncryptionProvider | undefined, sendOptions?: SendOptions | undefined, unmarshalOptions?: UnmarshalOptions);
    usingIndex(name: string): this;
    sort(direction: CursorSort): this;
    consistentRead(enabled?: boolean): this;
    limit(n: number): this;
    projection(fields: string[]): this;
    filter(field: string, op: QueryOperator, ...values: unknown[]): this;
    orFilter(field: string, op: QueryOperator, ...values: unknown[]): this;
    filterGroup(fn: (b: FilterGroupBuilder) => void): this;
    orFilterGroup(fn: (b: FilterGroupBuilder) => void): this;
    cursor(encoded: string): this;
    partitionKey(value: unknown): this;
    sortKey(op: '=' | '<' | '<=' | '>' | '>=' | 'between' | 'begins_with', ...values: unknown[]): this;
    page(): Promise<Page<TItem>>;
    count(): Promise<number>;
    private countPage;
    all(): Promise<TItem[]>;
    pages(): AsyncGenerator<Page<TItem>>;
    items(): AsyncGenerator<TItem>;
    /**
     * Client-side aggregation: calls `all()` and materializes every matching item before summing.
     * Use only for bounded result sets; use native `count()` for count-only reads.
     */
    sum(field: string): Promise<number>;
    /**
     * Client-side aggregation: calls `all()` and materializes every matching item before averaging.
     * Use only for bounded result sets; use native `count()` for count-only reads.
     */
    average(field: string): Promise<number>;
    /**
     * Client-side aggregation: calls `all()` and materializes every matching item before selecting the minimum.
     * Use only for bounded result sets; use native `count()` for count-only reads.
     */
    min(field: string): Promise<unknown>;
    /**
     * Client-side aggregation: calls `all()` and materializes every matching item before selecting the maximum.
     * Use only for bounded result sets; use native `count()` for count-only reads.
     */
    max(field: string): Promise<unknown>;
    /**
     * Client-side aggregation: calls `all()` and materializes every matching item before computing the aggregate.
     * Use only for bounded result sets; use native `count()` for count-only reads.
     */
    aggregate(...fields: string[]): Promise<AggregateResult>;
    /**
     * Client-side aggregation: calls `all()` and materializes every matching item before counting distinct values.
     * Use only for bounded result sets; use native `count()` for count-only reads.
     */
    countDistinct(field: string): Promise<number>;
    /**
     * Client-side aggregation: the returned group query calls `all()` during `execute()` and keeps groups in memory.
     * Use only for bounded result sets; use native `count()` for count-only reads.
     */
    groupBy(field: string): GroupByQuery<TItem>;
    describe(): BuilderShape;
    pageWithRetry(opts?: QueryRetryOptions<TItem>): Promise<Page<TItem>>;
    private resolveKeySchema;
}
export declare class ScanBuilder<TItem extends Record<string, unknown> = Record<string, unknown>> {
    private readonly ddb;
    private readonly model;
    private readonly encryption?;
    private readonly sendOptions?;
    private readonly unmarshalOptions;
    private indexName?;
    private limitCount?;
    private projectionFields?;
    private consistentReadEnabled;
    private cursorToken;
    private readonly filters;
    private segment?;
    private totalSegments?;
    constructor(ddb: DynamoDBClient, model: Model, encryption?: EncryptionProvider | undefined, sendOptions?: SendOptions | undefined, unmarshalOptions?: UnmarshalOptions);
    usingIndex(name: string): this;
    consistentRead(enabled?: boolean): this;
    limit(n: number): this;
    projection(fields: string[]): this;
    filter(field: string, op: QueryOperator, ...values: unknown[]): this;
    orFilter(field: string, op: QueryOperator, ...values: unknown[]): this;
    filterGroup(fn: (b: FilterGroupBuilder) => void): this;
    orFilterGroup(fn: (b: FilterGroupBuilder) => void): this;
    cursor(encoded: string): this;
    parallelScan(segment: number, totalSegments: number): this;
    scanAllSegments(totalSegments: number, opts?: {
        concurrency?: number;
    }): Promise<TItem[]>;
    count(): Promise<number>;
    private countPage;
    all(): Promise<TItem[]>;
    pages(): AsyncGenerator<Page<TItem>>;
    items(): AsyncGenerator<TItem>;
    /**
     * Client-side aggregation: calls `all()` and materializes every matching item before summing.
     * Use only for bounded result sets; use native `count()` for count-only reads.
     */
    sum(field: string): Promise<number>;
    /**
     * Client-side aggregation: calls `all()` and materializes every matching item before averaging.
     * Use only for bounded result sets; use native `count()` for count-only reads.
     */
    average(field: string): Promise<number>;
    /**
     * Client-side aggregation: calls `all()` and materializes every matching item before selecting the minimum.
     * Use only for bounded result sets; use native `count()` for count-only reads.
     */
    min(field: string): Promise<unknown>;
    /**
     * Client-side aggregation: calls `all()` and materializes every matching item before selecting the maximum.
     * Use only for bounded result sets; use native `count()` for count-only reads.
     */
    max(field: string): Promise<unknown>;
    /**
     * Client-side aggregation: calls `all()` and materializes every matching item before computing the aggregate.
     * Use only for bounded result sets; use native `count()` for count-only reads.
     */
    aggregate(...fields: string[]): Promise<AggregateResult>;
    /**
     * Client-side aggregation: calls `all()` and materializes every matching item before counting distinct values.
     * Use only for bounded result sets; use native `count()` for count-only reads.
     */
    countDistinct(field: string): Promise<number>;
    /**
     * Client-side aggregation: the returned group query calls `all()` during `execute()` and keeps groups in memory.
     * Use only for bounded result sets; use native `count()` for count-only reads.
     */
    groupBy(field: string): GroupByQuery<TItem>;
    describe(): BuilderShape;
    page(): Promise<Page<TItem>>;
    pageWithRetry(opts?: QueryRetryOptions<TItem>): Promise<Page<TItem>>;
}

batch

import type { AttributeValue, WriteRequest } from '@aws-sdk/client-dynamodb';
export interface RetryOptions {
    maxAttempts?: number;
    baseDelayMs?: number;
}
export interface BatchGetResult<T = Record<string, unknown>> {
    items: T[];
    unprocessedKeys: Array<Record<string, AttributeValue>>;
}
export interface BatchWriteResult {
    unprocessed: WriteRequest[];
}
export declare function chunk<T>(items: T[], size: number): T[][];
export declare function sleep(ms: number): Promise<void>;

transaction

import type { AttributeValue } from '@aws-sdk/client-dynamodb';
import type { UpdateBuilder } from './update-builder.js';
/**
 * Raw transaction updates bypass UpdateBuilder encryption/validation and are
 * therefore only valid for models without encrypted attributes. Encrypted
 * models must use `updateFn`.
 */
type TransactUpdateRaw = {
    kind: 'update';
    model: string;
    key: Record<string, unknown>;
    updateExpression: string;
    conditionExpression?: string;
    expressionAttributeNames?: Record<string, string>;
    expressionAttributeValues?: Record<string, AttributeValue>;
    updateFn?: never;
};
type TransactUpdateWithBuilder = {
    kind: 'update';
    model: string;
    key: Record<string, unknown>;
    updateFn: (builder: UpdateBuilder) => void | Promise<void>;
    updateExpression?: never;
    conditionExpression?: never;
    expressionAttributeNames?: never;
    expressionAttributeValues?: never;
};
export type TransactAction = {
    kind: 'put';
    model: string;
    item: Record<string, unknown>;
    ifNotExists?: boolean;
} | TransactUpdateRaw | TransactUpdateWithBuilder | {
    kind: 'delete';
    model: string;
    key: Record<string, unknown>;
    conditionExpression?: string;
    expressionAttributeNames?: Record<string, string>;
    expressionAttributeValues?: Record<string, AttributeValue>;
} | {
    kind: 'condition';
    model: string;
    key: Record<string, unknown>;
    conditionExpression: string;
    expressionAttributeNames?: Record<string, string>;
    expressionAttributeValues?: Record<string, AttributeValue>;
};
export type TransactGetAction = {
    model: string;
    key: Record<string, unknown>;
    projection?: string[];
};
export {};

streams

import type { Model } from './model.js';
export interface StreamRecord {
    dynamodb?: {
        Keys?: Record<string, unknown>;
        NewImage?: Record<string, unknown>;
        OldImage?: Record<string, unknown>;
    };
}
export declare function unmarshalStreamImage(model: Model, image: Record<string, unknown>): Record<string, unknown>;
export declare function unmarshalStreamRecord(model: Model, record: StreamRecord): {
    keys?: Record<string, unknown>;
    newImage?: Record<string, unknown>;
    oldImage?: Record<string, unknown>;
};

aggregates

/** Result of an in-memory client-side aggregation over an already materialized item array. */
export interface AggregateResult {
    min?: unknown;
    max?: unknown;
    count: number;
    sum: number;
    average: number;
}
/** Group produced by `GroupByQuery.execute()` after all source items have been materialized in memory. */
export interface GroupedResult<T = Record<string, unknown>> {
    key: unknown;
    count: number;
    items: T[];
    aggregates: Record<string, AggregateResult>;
}
/**
 * Client-side group-by helper. `execute()` loads the full source item set into memory,
 * then keeps grouped items and aggregates in memory; use only for bounded result sets.
 */
export declare class GroupByQuery<T extends Record<string, unknown>> {
    private readonly items;
    private readonly groupByField;
    private readonly aggregates;
    private readonly havingClauses;
    constructor(items: () => Promise<T[]>, groupByField: string);
    /** Adds a count aggregate computed in memory after the full source set is materialized. */
    count(alias: string): this;
    /** Adds a sum aggregate computed in memory after the full source set is materialized. */
    sum(field: string, alias: string): this;
    /** Adds an average aggregate computed in memory after the full source set is materialized. */
    avg(field: string, alias: string): this;
    /** Adds a minimum aggregate computed in memory after the full source set is materialized. */
    min(field: string, alias: string): this;
    /** Adds a maximum aggregate computed in memory after the full source set is materialized. */
    max(field: string, alias: string): this;
    /** Adds an in-memory having filter evaluated after groups and aggregates are materialized. */
    having(aggregate: string, operator: string, value: unknown): this;
    /** Materializes the full source set, groups it in memory, computes aggregates, and returns all groups. */
    execute(): Promise<Array<GroupedResult<T>>>;
}
/** Client-side sum over an already materialized item array; use only for bounded result sets. */
export declare function sumField<T extends Record<string, unknown>>(items: T[], field: string): number;
/** Client-side average over an already materialized item array; use only for bounded result sets. */
export declare function averageField<T extends Record<string, unknown>>(items: T[], field: string): number;
/** Client-side minimum over an already materialized item array; use only for bounded result sets. */
export declare function minField<T extends Record<string, unknown>>(items: T[], field: string): unknown;
/** Client-side maximum over an already materialized item array; use only for bounded result sets. */
export declare function maxField<T extends Record<string, unknown>>(items: T[], field: string): unknown;
/** Client-side aggregate over an already materialized item array; use only for bounded result sets. */
export declare function aggregateField<T extends Record<string, unknown>>(items: T[], field?: string): AggregateResult;
/** Client-side distinct count over an already materialized item array; use only for bounded result sets. */
export declare function countDistinct<T extends Record<string, unknown>>(items: T[], field: string): number;

optimizer

export type QueryOperation = 'Query' | 'Scan';
export interface QueryPlan {
    id: string;
    operation: QueryOperation;
    indexName?: string;
    projections?: string[];
    parallelSegments?: number;
    optimizationHints: string[];
}
export interface OptimizationOptions {
    enableParallel?: boolean;
    maxParallelism?: number;
}
export interface OptimizerCondition {
    field: string;
    operator: string;
}
export interface OptimizerIndexShape {
    name?: string;
    type: 'PRIMARY' | 'GSI' | 'LSI';
    partition: string;
    sort?: string;
    projectionType?: 'ALL' | 'KEYS_ONLY' | 'INCLUDE';
}
export type BuilderShape = {
    kind: 'query';
    modelName: string;
    tableName: string;
    indexName?: string;
    indexType?: 'GSI' | 'LSI';
    hasPartitionKey: boolean;
    hasSortKey: boolean;
    hasSortKeyCondition: boolean;
    hasFilters: boolean;
    projections?: string[];
    consistentRead: boolean;
    sort: 'ASC' | 'DESC';
    indexes?: OptimizerIndexShape[];
    conditions?: OptimizerCondition[];
} | {
    kind: 'scan';
    modelName: string;
    tableName: string;
    indexName?: string;
    indexType?: 'GSI' | 'LSI';
    hasFilters: boolean;
    projections?: string[];
    consistentRead: boolean;
    parallelScanConfigured: boolean;
    totalSegments?: number;
    indexes?: OptimizerIndexShape[];
    conditions?: OptimizerCondition[];
};
export interface RequiredKeys {
    partitionKey: string;
    sortKey: string;
    sortKeyOp: string;
}
export declare class QueryOptimizer {
    private readonly enableParallel;
    private readonly maxParallelism;
    constructor(opts?: OptimizationOptions);
    explain(shape: BuilderShape): QueryPlan;
}
export declare function analyzeConditions(conditions: readonly OptimizerCondition[]): RequiredKeys;
export declare function selectOptimalIndex(required: RequiredKeys, indexes: readonly OptimizerIndexShape[]): OptimizerIndexShape | undefined;

encryption

import type { AttributeValue } from '@aws-sdk/client-dynamodb';
import type { AttributeSchema, Model } from './model.js';
export interface EncryptionContext {
    model: string;
    attribute: string;
}
export interface EncryptedEnvelope {
    v: 1;
    edk: Uint8Array;
    nonce: Uint8Array;
    ct: Uint8Array;
}
export interface EncryptionProvider {
    encrypt(plaintext: Uint8Array, ctx: EncryptionContext): Promise<EncryptedEnvelope>;
    decrypt(envelope: EncryptedEnvelope, ctx: EncryptionContext): Promise<Uint8Array>;
}
export declare function modelHasEncryptedAttributes(model: Model): boolean;
export declare function marshalPutItemEncrypted(model: Model, item: Record<string, unknown>, provider: EncryptionProvider, opts?: {
    now?: string;
}): Promise<Record<string, AttributeValue>>;
export declare function decryptItemAttributes(model: Model, item: Record<string, AttributeValue>, provider: EncryptionProvider): Promise<Record<string, AttributeValue>>;
export declare function encryptAttributeValue(schema: Readonly<AttributeSchema>, value: unknown, provider: EncryptionProvider, ctx: EncryptionContext): Promise<AttributeValue>;

encryption-kms

import { type KMSClient } from '@aws-sdk/client-kms';
import type { EncryptedEnvelope, EncryptionContext, EncryptionProvider } from './encryption.js';
export interface AwsKmsEncryptionProviderOptions {
    keyArn: string;
    randomBytes?: (size: number) => Uint8Array;
}
export declare class AwsKmsEncryptionProvider implements EncryptionProvider {
    private readonly kms;
    private readonly keyArn;
    private readonly randomBytes;
    constructor(kms: Pick<KMSClient, 'send'>, opts: AwsKmsEncryptionProviderOptions);
    encrypt(plaintext: Uint8Array, ctx: EncryptionContext): Promise<EncryptedEnvelope>;
    decrypt(envelope: EncryptedEnvelope, ctx: EncryptionContext): Promise<Uint8Array>;
}

schema

import { type DynamoDBClient, type TableDescription } from '@aws-sdk/client-dynamodb';
import type { Model } from './model.js';
export type BillingMode = 'PAY_PER_REQUEST' | 'PROVISIONED';
export interface ProvisionedThroughput {
    readCapacityUnits: number;
    writeCapacityUnits: number;
}
export interface CreateTableOptions {
    tableName?: string;
    billingMode?: BillingMode;
    provisionedThroughput?: ProvisionedThroughput;
    waitForActive?: boolean;
    waitTimeoutSeconds?: number;
    pollIntervalMs?: number;
}
export interface DeleteTableOptions {
    tableName?: string;
    waitForDelete?: boolean;
    waitTimeoutSeconds?: number;
    pollIntervalMs?: number;
    ignoreMissing?: boolean;
}
export interface DescribeTableOptions {
    tableName?: string;
}
export interface UpdateTimeToLiveOptions {
    tableName?: string;
    attributeName?: string;
    enabled?: boolean;
}
export declare function createTable(ddb: DynamoDBClient, model: Model, opts?: CreateTableOptions): Promise<void>;
export declare function ensureTable(ddb: DynamoDBClient, model: Model, opts?: CreateTableOptions): Promise<void>;
export declare function deleteTable(ddb: DynamoDBClient, model: Model, opts?: DeleteTableOptions): Promise<void>;
export declare function describeTable(ddb: DynamoDBClient, model: Model, opts?: DescribeTableOptions): Promise<TableDescription>;
export declare function resolveTimeToLiveAttribute(model: Model): string | undefined;
export declare function updateTimeToLive(ddb: DynamoDBClient, model: Model, opts?: UpdateTimeToLiveOptions): Promise<void>;

schema-migration

import { type AttributeValue, type DynamoDBClient } from '@aws-sdk/client-dynamodb';
import type { Model } from './model.js';
/** A raw DynamoDB item (attribute-name to AttributeValue). */
export type MigrationItem = Record<string, AttributeValue>;
/**
 * A transform applied to each item during a data-copying migration. It mirrors
 * the Go `schema.TransformFunc` AttributeValue-level transforms.
 */
export type MigrationTransform = (item: MigrationItem) => MigrationItem;
export interface AutoMigrateOptions {
    /** Migrate into a different model/table than the source. Defaults to the source. */
    targetModel?: Model;
    /** Applied to each item when copying data. */
    transform?: MigrationTransform;
    /** When set, copy the source table into this backup table before migrating. */
    backupTable?: string;
    /** Scan/batch page size. Defaults to 25 (the DynamoDB BatchWriteItem limit). */
    batchSize?: number;
    /** Copy data from the source table into the target table. */
    dataCopy?: boolean;
}
/**
 * autoMigrate ensures the target table exists and, when requested, copies data
 * from the source table into it (optionally through a transform), mirroring the
 * Go `Manager.AutoMigrateWithOptions` story.
 */
export declare function autoMigrate(ddb: DynamoDBClient, sourceModel: Model, opts?: AutoMigrateOptions): Promise<void>;
/** copyAllFields returns a transform that passes every attribute through unchanged. */
export declare function copyAllFields(): MigrationTransform;
/** renameField returns a transform that renames one attribute. */
export declare function renameField(oldName: string, newName: string): MigrationTransform;
/** addField returns a transform that adds an attribute (overwriting if present). */
export declare function addField(name: string, value: AttributeValue): MigrationTransform;
/** removeField returns a transform that drops an attribute. */
export declare function removeField(name: string): MigrationTransform;
/** chainTransforms composes transforms left to right. */
export declare function chainTransforms(...transforms: MigrationTransform[]): MigrationTransform;

update-builder

import { type AttributeValue, type DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { type EncryptionProvider } from './encryption.js';
import { type UnmarshalOptions } from './marshal.js';
import type { Model } from './model.js';
import type { SendOptions } from './send-options.js';
import type { QueryOperator } from './query-types.js';
export type ReturnValuesOption = 'NONE' | 'ALL_OLD' | 'UPDATED_OLD' | 'ALL_NEW' | 'UPDATED_NEW';
export declare class UpdateBuilder {
    private readonly ddb;
    private readonly model;
    private readonly key;
    private readonly encryption?;
    private readonly sendOptions?;
    private readonly unmarshalOptions;
    private readonly updateOps;
    private readonly conditionOps;
    private returnValuesOpt;
    private hasVersionCondition;
    constructor(ddb: DynamoDBClient, model: Model, key: Record<string, unknown>, encryption?: EncryptionProvider | undefined, sendOptions?: SendOptions | undefined, unmarshalOptions?: UnmarshalOptions);
    set(field: string, value: unknown): this;
    setIfNotExists(field: string, _value: unknown, defaultValue: unknown): this;
    add(field: string, value: unknown): this;
    increment(field: string): this;
    decrement(field: string): this;
    remove(field: string): this;
    delete(field: string, value: unknown): this;
    appendToList(field: string, values: unknown[]): this;
    prependToList(field: string, values: unknown[]): this;
    removeFromListAt(field: string, index: number): this;
    setListElement(field: string, index: number, value: unknown): this;
    condition(field: string, operator: QueryOperator, value?: unknown): this;
    orCondition(field: string, operator: QueryOperator, value?: unknown): this;
    conditionExists(field: string): this;
    conditionNotExists(field: string): this;
    conditionVersion(currentVersion: number): this;
    returnValues(option: ReturnValuesOption): this;
    build(): Promise<{
        updateExpression: string;
        conditionExpression?: string;
        expressionAttributeNames?: Record<string, string>;
        expressionAttributeValues?: Record<string, AttributeValue>;
    }>;
    execute(): Promise<Record<string, unknown> | undefined>;
    private buildConditionExpression;
    private buildUpdateExpression;
    private assertUpdatableField;
}

lambda

import { DynamoDBClient, type DynamoDBClientConfig } from '@aws-sdk/client-dynamodb';
import { TheorydbClient } from './client.js';
export type LambdaContextLike = {
    getRemainingTimeInMillis(): number;
};
export type LambdaMetric = {
    service: 'dynamodb';
    command: string;
    ms: number;
    ok: boolean;
};
export type LambdaTimeoutOptions = {
    bufferMs?: number;
};
export declare const DEFAULT_LAMBDA_TIMEOUT_BUFFER_MS = 1000;
export declare function isLambdaEnvironment(env?: NodeJS.ProcessEnv): boolean;
export declare function createLambdaTimeoutSignal(ctx: LambdaContextLike, opts?: LambdaTimeoutOptions): {
    signal: AbortSignal;
    cleanup: () => void;
};
export declare function withLambdaTimeout(client: TheorydbClient, ctx: LambdaContextLike, opts?: LambdaTimeoutOptions): {
    client: TheorydbClient;
    cleanup: () => void;
};
export declare function createLambdaDynamoDBClient(opts?: DynamoDBClientConfig & {
    connectionTimeoutMs?: number;
    socketTimeoutMs?: number;
    metrics?: (m: LambdaMetric) => void;
}): DynamoDBClient;
export declare function getLambdaDynamoDBClient(opts?: Parameters<typeof createLambdaDynamoDBClient>[0]): DynamoDBClient;

multiaccount

import { DynamoDBClient, type DynamoDBClientConfig } from '@aws-sdk/client-dynamodb';
import { AssumeRoleCommand, type AssumeRoleCommandOutput } from '@aws-sdk/client-sts';
import type { AwsCredentialIdentityProvider } from '@aws-sdk/types';
export type StsClientLike = {
    send(cmd: AssumeRoleCommand): Promise<AssumeRoleCommandOutput>;
};
export type AssumeRoleCredentialsProviderOptions = {
    roleArn: string;
    externalId?: string;
    region?: string;
    durationSeconds?: number;
    sessionName?: string;
    refreshBeforeMs?: number;
    now?: () => number;
    sts?: StsClientLike;
};
export declare function createAssumeRoleCredentialsProvider(opts: AssumeRoleCredentialsProviderOptions): AwsCredentialIdentityProvider;
export type AssumeRoleDynamoDBClientOptions = {
    roleArn: string;
    externalId?: string;
    region: string;
    durationSeconds?: number;
    sessionName?: string;
    refreshBeforeMs?: number;
    now?: () => number;
    sts?: StsClientLike;
    dynamo?: Omit<DynamoDBClientConfig, 'credentials' | 'region'>;
};
export declare function createAssumeRoleDynamoDBClient(opts: AssumeRoleDynamoDBClientOptions): DynamoDBClient;
export type AccountConfig = {
    roleArn: string;
    externalId?: string;
    region: string;
    durationSeconds?: number;
};
export declare class MultiAccountDynamoDBClients {
    private readonly opts;
    private readonly accounts;
    private readonly clients;
    constructor(accounts: Record<string, AccountConfig>, opts?: Omit<AssumeRoleDynamoDBClientOptions, 'roleArn' | 'externalId' | 'region'> & {
        dynamo?: Omit<DynamoDBClientConfig, 'credentials' | 'region'>;
    });
    client(partnerId: string): DynamoDBClient;
}

send-options

export type SendOptions = {
    abortSignal?: AbortSignal;
};

validation

declare const MaxFieldNameLength = 255;
declare const MaxOperatorLength = 20;
declare const MaxValueStringLength = 400000;
declare const MaxNestedDepth = 32;
declare const MaxExpressionLength = 4096;
type SecurityValidationErrorType = 'InjectionAttempt' | 'InvalidField' | 'InvalidOperator' | 'InvalidValue' | 'InvalidExpression' | 'InvalidTableName' | 'InvalidIndexName';
export declare class SecurityValidationError extends Error {
    readonly type: SecurityValidationErrorType;
    readonly detail: string;
    constructor(type: SecurityValidationErrorType, detail: string);
}
export declare function isSecurityValidationError(value: unknown): value is SecurityValidationError;
export { MaxExpressionLength, MaxFieldNameLength, MaxNestedDepth, MaxOperatorLength, MaxValueStringLength, };
export declare function validateFieldName(field: string): void;
export declare function validateOperator(op: string): void;
export declare function validateValue(value: unknown): void;
export declare function validateExpression(expression: string): void;
export declare function validateTableName(name: string): void;
export declare function validateIndexName(name: string): void;

protection

export declare class SimpleLimiter {
    private lastRefillMs;
    private tokens;
    private readonly maxTokens;
    private readonly refillIntervalMs;
    private readonly now;
    constructor(rps: number, burst: number, opts?: {
        now?: () => number;
    });
    allow(): boolean;
}
export declare class Semaphore {
    private readonly capacity;
    private inUse;
    private readonly waiters;
    constructor(capacity: number);
    tryAcquire(): (() => void) | null;
    acquire(opts?: {
        signal?: AbortSignal;
    }): Promise<() => void>;
    private release;
}

write-policy

import type { Model } from './model.js';
export interface WritePolicyOptions {
    protectedAttributes?: readonly string[];
}
export declare function isWriteOnceModel(model: Model): boolean;
export declare function assertMutableWritePolicy(model: Model, operation: string): void;
export declare function assertProtectedFieldsCanMutate(model: Model, fields: readonly string[], extraProtected?: readonly string[]): void;
export declare function assertRawUpdateExpressionAllowed(model: Model, updateExpression: string, expressionAttributeNames?: Record<string, string>): void;

release-state

import type { TheorydbClient } from './client.js';
/**
 * Input for a release-state registry transition. The actual-state update and
 * event-history append are committed through one DynamoDB transaction by the
 * supplied TableTheory client.
 *
 * External side effects such as Lambda alias flips or CodePipeline executions
 * are intentionally outside this helper's atomicity boundary. Callers should
 * pair those side effects with explicit retry/reconciliation/outbox behavior.
 */
export interface ReleaseStateTransitionInput {
    actualModel: string;
    actualKey: Record<string, unknown>;
    set: Record<string, unknown>;
    eventModel: string;
    eventItem: Record<string, unknown>;
    expectedVersion?: number;
    versionAttribute?: string;
}
/**
 * Transactionally update the release-state actual row and append one immutable
 * event-history row.
 */
export declare function transitionReleaseState(client: TheorydbClient, input: ReleaseStateTransitionInput): Promise<void>;
/**
 * Validate deterministic provenance/confidence metadata for a
 * deploy-authoritative release-state actual row.
 *
 * Ambiguous/conflicting or low-confidence evidence is rejected so it cannot be
 * persisted as deploy authority. Preserve that evidence as separate immutable
 * visibility/event records instead.
 */
export declare function validateDeployAuthorityMetadata(item: Record<string, unknown>): void;

lease

import { type DynamoDBClient } from '@aws-sdk/client-dynamodb';
import type { SendOptions } from './send-options.js';
export type LeaseKey = {
    pk: string;
    sk: string;
};
export type Lease = {
    key: LeaseKey;
    token: string;
    expiresAt: number;
};
export declare class LeaseManager {
    private readonly ddb;
    private readonly tableName;
    private readonly now;
    private readonly token;
    private readonly pkAttr;
    private readonly skAttr;
    private readonly tokenAttr;
    private readonly expiresAtAttr;
    private readonly ttlAttr;
    private readonly ttlBufferSeconds;
    private readonly sendOptions;
    constructor(ddb: DynamoDBClient, tableName: string, opts?: {
        now?: () => number;
        token?: () => string;
        pkAttr?: string;
        skAttr?: string;
        tokenAttr?: string;
        expiresAtAttr?: string;
        ttlAttr?: string;
        ttlBufferSeconds?: number;
        sendOptions?: SendOptions;
    });
    lockKey(pk: string, sk?: string): LeaseKey;
    acquire(key: LeaseKey, opts: {
        leaseSeconds: number;
    }): Promise<Lease>;
    refresh(lease: Lease, opts: {
        leaseSeconds: number;
    }): Promise<Lease>;
    release(lease: Lease): Promise<void>;
}

facetheory-isr

import type { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { TheorydbClient } from './client.js';
import { type Model } from './model.js';
export type FaceTheoryIsrMeta = {
    htmlPointer: string;
    generatedAtMs: number;
    revalidateSeconds: number;
    etag?: string;
};
export type FaceTheoryIsrLease = {
    leaseToken: string;
    leaseExpiresAtMs: number;
};
export type FaceTheoryIsrMetaStoreGetArgs = {
    cacheKey: string;
};
export type FaceTheoryIsrMetaStoreTryAcquireLeaseArgs = {
    cacheKey: string;
    leaseOwner?: string;
    nowMs?: number;
    leaseDurationMs: number;
};
export type FaceTheoryIsrMetaStoreCommitGenerationArgs = {
    cacheKey: string;
    leaseOwner?: string;
    leaseToken: string;
    nowMs?: number;
    htmlPointer: string;
    generatedAtMs: number;
    revalidateSeconds: number;
    etag?: string;
    ttlUnixSeconds?: number;
};
export type FaceTheoryIsrMetaStoreReleaseLeaseArgs = {
    cacheKey: string;
    leaseOwner?: string;
    leaseToken: string;
};
export type FaceTheoryIsrMetaStoreConfig = {
    ddb: DynamoDBClient;
    tableName: string;
    client?: TheorydbClient;
    pkFromCacheKey?: (cacheKey: string) => string;
    pkPrefix?: string;
    leaseTtlBufferSeconds?: number;
    leaseToken?: () => string;
    metaTtlSeconds?: number;
};
export declare function defineFaceTheoryCacheMetadataModel(tableName: string): Model;
export declare function defineFaceTheoryCacheLeaseModel(tableName: string): Model;
export declare class FaceTheoryIsrMetaStore {
    private readonly ddb;
    private readonly tableName;
    private readonly client;
    private readonly pkFromCacheKey;
    private readonly leaseTtlBufferSeconds;
    private readonly leaseToken;
    private readonly metaTtlSeconds;
    constructor(cfg: FaceTheoryIsrMetaStoreConfig);
    get(args: FaceTheoryIsrMetaStoreGetArgs): Promise<FaceTheoryIsrMeta | null>;
    tryAcquireLease(args: FaceTheoryIsrMetaStoreTryAcquireLeaseArgs): Promise<FaceTheoryIsrLease | null>;
    commitGeneration(args: FaceTheoryIsrMetaStoreCommitGenerationArgs): Promise<void>;
    releaseLease(args: FaceTheoryIsrMetaStoreReleaseLeaseArgs): Promise<void>;
}
export declare function createFaceTheoryIsrMetaStore(cfg: FaceTheoryIsrMetaStoreConfig): FaceTheoryIsrMetaStore;

key-contract

export type KeyContractInputValue = string | number | boolean;
export type KeyContractTransform = 'trim' | 'wildcard_empty' | 'lowercase' | 'url_encode';
export interface DerivedKeyContract {
    tabletheory_model_contract_version: '0.1' | '0.2';
    namespace?: string;
    dms_version?: string;
    models?: DerivedKeyModelContract[];
    derived_keys: DerivedKeyDefinition[];
}
export interface DerivedKeyModelContract {
    name: string;
    dms_model?: string;
    table?: string;
    derived_keys?: string[];
}
export interface DerivedKeyDefinition {
    name: string;
    helper?: string;
    description?: string;
    join: string;
    inputs?: DerivedKeyInput[];
    segments: DerivedKeySegment[];
    fixtures?: DerivedKeyFixture[];
}
export interface DerivedKeyInput {
    name: string;
    ts_name?: string;
    type?: 'string' | 'number' | 'boolean' | 'scalar';
    optional?: boolean;
}
export interface DerivedKeySegment {
    name?: string;
    prefix?: string;
    suffix?: string;
    literal?: string;
    value?: DerivedKeyValueSource;
    transforms?: KeyContractTransform[];
    default?: string;
    optional?: boolean;
    omit_when?: DerivedKeyOmitWhen;
}
export interface DerivedKeyValueSource {
    input?: string;
    literal?: string;
}
export interface DerivedKeyOmitWhen {
    empty?: boolean;
    default?: boolean;
    values?: string[];
}
export interface DerivedKeyFixture {
    name: string;
    description?: string;
    input: Record<string, KeyContractInputValue>;
    expect: string;
}
export declare function parseDerivedKeyContract(raw: string): DerivedKeyContract;
export declare function evaluateDerivedKey(contract: DerivedKeyContract, name: string, input?: Record<string, KeyContractInputValue>): string;
export declare function evaluateDerivedKeyDefinition(key: DerivedKeyDefinition, input?: Record<string, KeyContractInputValue>): string;
export declare function verifyDerivedKeyFixtures(contract: DerivedKeyContract): void;
export declare function validateDerivedKeyContract(value: unknown): asserts value is DerivedKeyContract;
export declare function validateDerivedKeyDefinition(value: unknown): asserts value is DerivedKeyDefinition;