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' | 'ErrNumberPrecisionLoss' | 'ErrMigrationEncryptionRequired' | 'ErrImmutableModelMutation' | 'ErrProtectedFieldMutation' | 'ErrRejectedDeployAuthorityEvidence' | 'ErrTransactionFailed' | 'ErrTransactionConflict' | 'ErrThrottled';
/**
 * One entry of a DynamoDB transaction cancellation reason list, in its original
 * position. It carries only the classification code and the service message: the
 * DynamoDB item image is never copied here, so cancellation reasons are always
 * safe to log. Entries whose code is missing keep their position with an empty
 * `code`; DynamoDB's "None" placeholder is kept verbatim.
 */
export interface CancellationReason {
    readonly index: number;
    readonly code: string;
    readonly message: string;
}
export declare class TheorydbError extends Error {
    readonly code: ErrorCode;
    readonly codes: readonly ErrorCode[];
    readonly cancellationReasons: readonly CancellationReason[];
    constructor(code: ErrorCode, message: string, options?: {
        cause?: unknown;
        codes?: readonly ErrorCode[];
        cancellationReasons?: readonly CancellationReason[];
    });
}
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;
/**
 * The typed, item-free surface of a `TheorydbError`.
 */
export interface SafeErrorFields {
    readonly code: ErrorCode;
    readonly codes: readonly ErrorCode[];
    readonly message: string;
    readonly cancellationReasons: readonly CancellationReason[];
}
/**
 * Projects a `TheorydbError` onto its typed surface only.
 *
 * The result never contains `cause`, so it cannot carry the underlying SDK
 * exception — and therefore never carries `CancellationReasons[].Item`, an
 * `Item` payload, a key, or a request/response body. Returns `undefined` for a
 * value that is not a `TheorydbError`: there is no typed surface to project.
 *
 * A whole-error dump (`JSON.stringify(err)`, `console.log(err)`, `util.inspect`)
 * is not safe: `TheorydbError.cause` is an own enumerable property, so it walks
 * the raw SDK exception. Use this helper to log the typed surface, and the
 * client's `redactItemImages` option to strip item images from the retained
 * cause itself.
 */
export declare function safeErrorFields(err: unknown): SafeErrorFields | undefined;

client

import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { type BatchGetResult, type BatchWriteResult, type RetryOptions } from './batch.js';
import type { InferModelItemForMode, Model, ModelSchema, NumberUnmarshalMode } from './model.js';
import type { SendOptions } from './send-options.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;
    /**
     * When true, item images are stripped from the cause retained on a mapped
     * error: `CancellationReasons[].Item` and the `Item` a
     * `ConditionalCheckFailedException` carries. Off by default, so a client that
     * does not set it retains exactly what it does today. The error's own typed
     * surface (`code`, `codes`, `message`, `cancellationReasons`) never carries
     * item data either way; see `safeErrorFields` for the safe logging surface.
     */
    redactItemImages?: boolean;
    /**
     * 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<TNumberMode extends NumberUnmarshalMode = 'string'> {
    private readonly ddb;
    private readonly models;
    private encryption;
    private readonly now;
    private readonly sendOptions;
    private readonly unmarshalOptions;
    private readonly redactItemImages;
    constructor(ddb: DynamoDBClient, opts?: TheorydbClientOptions);
    /**
     * Maps an SDK error to the typed TableTheory error, applying this client's
     * configured cause redaction. Every client write/read path funnels through
     * here so the option is honored uniformly.
     */
    private mapError;
    withEncryption(provider: EncryptionProvider): this;
    withSendOptions(sendOptions?: SendOptions): TheorydbClient<TNumberMode>;
    withDynamoDBClient(ddb: DynamoDBClient): TheorydbClient<TNumberMode>;
    register(...models: Model[]): this;
    /**
     * Returns a new client with the same configuration as this one and its own
     * empty model registry.
     *
     * `register()` writes into a registry keyed by model name. A component that
     * registers fixed model names into a caller-owned client therefore rebinds
     * any earlier component that registered the same names against a different
     * table. `fork()` lets such a component hold a private binding while still
     * inheriting the caller's encryption provider, clock, send options, and
     * number-unmarshal mode instead of mutating the shared registry.
     */
    fork(): TheorydbClient<TNumberMode>;
    model<M extends Model>(model: M): ModelRepository<InferModelItemForMode<M, TNumberMode>>;
    model(modelName: string): ModelRepository<Record<string, unknown>>;
    /**
     * Returns the registered schema for a model name.
     *
     * Release-state transition helpers use this to bind an appended event to the
     * exact actual row it describes before any transaction is submitted.
     */
    modelSchema(modelName: string): Readonly<ModelSchema>;
    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';
/**
 * Controls how DynamoDB N/NS values are unmarshaled.
 *
 * 'string' (the client default) returns canonical DynamoDB decimal strings so
 * reads are precision-safe; 'number' returns JavaScript numbers.
 */
export type NumberUnmarshalMode = 'number' | 'string';
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>, TSchema extends ModelSchema = ModelSchema, TNumberMode extends NumberUnmarshalMode = 'string'> {
    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;
    readonly __schemaType?: TSchema;
    readonly __numberMode?: TNumberMode;
}
type AttributeValueFor<A extends AttributeSchema, N extends NumberUnmarshalMode> = A['type'] extends 'S' ? string : A['type'] extends 'N' ? N extends 'number' ? number : string : A['type'] extends 'B' ? Uint8Array : A['type'] extends 'BOOL' ? boolean : A['type'] extends 'NULL' ? null : A['type'] extends 'SS' ? string[] : A['type'] extends 'NS' ? N extends 'number' ? number[] : string[] : 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, N extends NumberUnmarshalMode> = {
    [A in S['attributes'][number] as IsOptionalAttribute<A> extends true ? never : AttributeName<A>]: AttributeValueFor<A, N>;
};
type OptionalAttributes<S extends ModelSchema, N extends NumberUnmarshalMode> = {
    [A in S['attributes'][number] as IsOptionalAttribute<A> extends true ? AttributeName<A> : never]?: AttributeValueFor<A, N>;
};
export type InferModelItem<S extends ModelSchema, N extends NumberUnmarshalMode = 'string'> = RequiredAttributes<S, N> & OptionalAttributes<S, N>;
export type ModelItem<M extends Model> = M extends Model<infer TItem, ModelSchema, NumberUnmarshalMode> ? TItem : Record<string, unknown>;
/**
 * The item type a model produces for a given number-unmarshal mode. Used by the
 * typed repository so reads are declared with the representation the client is
 * actually configured to return.
 */
export type InferModelItemForMode<M extends Model, N extends NumberUnmarshalMode> = M extends Model<Record<string, unknown>, infer S, NumberUnmarshalMode> ? InferModelItem<S, N> : never;
export declare function defineModel<const S extends ModelSchema>(schema: S): Model<InferModelItem<S, 'string'>, S, 'string'>;
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` or `TransactModelUpdate`.
 */
type TransactUpdateRaw = {
    kind: 'update';
    model: string;
    key: Record<string, unknown>;
    updateExpression: string;
    conditionExpression?: string;
    expressionAttributeNames?: Record<string, string>;
    expressionAttributeValues?: Record<string, AttributeValue>;
    updateFn?: never;
    item?: never;
    fields?: 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;
    item?: never;
    fields?: never;
};
/**
 * A model-based transactional update with an explicit field selection.
 *
 * Selected empty `omit_empty` attributes are removed according to DMS v0.2;
 * every other selected attribute is set from `item`. Fields not listed in
 * `fields` are not mutated, except that the runtime advances `updatedAt` when
 * the model declares that lifecycle role. `createdAt` and version cannot be
 * selected because those attributes are library-owned.
 */
export type TransactModelUpdate = {
    kind: 'update';
    model: string;
    item: Record<string, unknown>;
    fields: readonly string[];
    conditionExpression?: string;
    expressionAttributeNames?: Record<string, string>;
    expressionAttributeValues?: Record<string, AttributeValue>;
    key?: never;
    updateExpression?: never;
    updateFn?: never;
};
export type TransactAction = {
    kind: 'put';
    model: string;
    item: Record<string, unknown>;
    ifNotExists?: boolean;
} | TransactUpdateRaw | TransactUpdateWithBuilder | TransactModelUpdate | {
    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 { EncryptionProvider } from './encryption.js';
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;
    /** Provider used to encrypt plaintext attributes the target declares encrypted. */
    encryption?: EncryptionProvider;
}
/**
 * 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>;
    /**
     * Optional immutable write-once outbox row created in the same transaction as
     * the actual-state update and event append. Provide `outboxModel` and
     * `outboxItem` together.
     */
    outboxModel?: string;
    outboxItem?: 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;

preflight

import type { AttributeValue } from '@aws-sdk/client-dynamodb';
import type { Model } from './model.js';
/**
 * ItemWriterPath names a TableTheory writer path whose stored DynamoDB
 * representation an item preflight must reproduce.
 *
 * Unlike Go, the TypeScript runtime serializes every whole item through one
 * function (`marshalPutItem`): `create`, `save`, `batchWrite` puts and
 * `transactWrite` puts all call it, so both paths return the same
 * representation. That representation is a fixed compatibility contract, frozen
 * by the operator's policy that TableTheory supports its consumers rather than
 * changing stored data. The two members exist so cross-runtime preflight code and
 * the shared nil/empty conformance table name writer paths identically on every
 * runtime.
 */
export type ItemWriterPath = 'put' | 'transact_write';
/**
 * Returns the DynamoDB item that the named writer path stores for `item`.
 *
 * The returned item is byte-equal to the payload the real writer sends: for
 * `create`, `save`, `batchWrite` and `transactWrite` puts that is
 * `marshalPutItem`, which this function calls directly. Both writer paths are
 * pinned by regression tests that capture live payloads through the stateful
 * fake client, so neither answer can drift from its writer without failing the
 * build.
 *
 * `item` is the same plain object `create`/`save` would receive, and `opts.now`
 * overrides the lifecycle timestamp exactly as it does for the writers.
 *
 * Scope:
 *
 *   - Models that declare encrypted attributes are refused. An encrypted
 *     attribute is stored as a KMS-wrapped envelope that only the asynchronous
 *     writer path can produce, so a synchronous preflight cannot predict its
 *     bytes.
 *   - For a model that declares `createdAt` or `updatedAt`, both writer paths
 *     stamp it from the client's clock: `create`, `save` and `batchWrite` pass
 *     it to `marshalPutItem`, and `transactWrite` puts do the same. Pass
 *     `opts.now` to reproduce a specific client clock; with no clock injected
 *     both paths use `nowRfc3339Nano`, matching the writers.
 *
 * An unrecognized path is refused. The preflight has no side effects and never
 * contacts DynamoDB.
 */
export declare function marshalItemForWriterPath(model: Model, item: Record<string, unknown>, path: ItemWriterPath, opts?: {
    now?: string;
}): Record<string, AttributeValue>;

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;