/** * All NOYDB error classes — a single import surface for `catch` blocks and * `instanceof` checks. * * ## Class hierarchy * * ``` * Error * └─ NoydbError (code: string) * ├─ Crypto errors * │ ├─ DecryptionError — AES-GCM tag failure * │ ├─ TamperedError — ciphertext modified after write * │ └─ InvalidKeyError — wrong passphrase / corrupt keyring * ├─ Access errors * │ ├─ NoAccessError — no DEK for this collection * │ ├─ ReadOnlyError — ro permission, write attempted * │ ├─ PermissionDeniedError — role too low for operation * │ ├─ PrivilegeEscalationError — grant wider than grantor holds * │ └─ StoreCapabilityError — optional store method missing * ├─ Sync errors * │ ├─ ConflictError — optimistic-lock version mismatch * │ ├─ PodVersionConflictError — bundle push rejected by remote * │ └─ NetworkError — push/pull network failure * ├─ Data errors * │ ├─ NotFoundError — get(id) on missing record * │ ├─ ValidationError — application-level guard failed * │ └─ SchemaValidationError — Standard Schema v1 rejection * ├─ Query errors * │ ├─ JoinTooLargeError — join row ceiling exceeded * │ ├─ CrossJoinTooLargeError — cross-join row ceiling exceeded * │ ├─ CrossJoinSourceUnknownError — target collection not in vault * │ ├─ DanglingReferenceError — strict ref() points at nothing * │ ├─ GroupCardinalityError — groupBy bucket cap exceeded * │ ├─ IndexRequiredError — lazy-mode query touches unindexed field * │ ├─ IndexWriteFailureError — index side-car put/delete failed post-main * │ ├─ UniqueConstraintError — duplicate value on unique index * │ ├─ UnsupportedIndexOptionError — unique+lazy or unique+crdt at registration * │ └─ FieldNotQueryableError — field's Via posture is queryable: 'none' * ├─ i18n / Dictionary errors * │ ├─ ReservedCollectionNameError * │ ├─ DictKeyMissingError * │ ├─ DictKeyInUseError * │ ├─ RestrictRefUnresolvableError — restrict edge's compare-key unresolvable (#654) * │ ├─ MissingTranslationError * │ ├─ LocaleNotSpecifiedError * │ ├─ ScriptViolationError * │ ├─ StaticDictReadonlyError * │ ├─ UnknownDictCodeError * │ ├─ UnknownLookupKeyError * │ └─ TranslatorNotConfiguredError * ├─ Backup errors * │ ├─ BackupLedgerError — hash-chain verification failed * │ └─ BackupCorruptedError — envelope hash mismatch in dump * ├─ Bundle errors * │ └─ BundleIntegrityError — .noydb body sha256 mismatch * ├─ Session errors * │ ├─ SessionExpiredError * │ ├─ SessionNotFoundError * │ └─ SessionPolicyError * ├─ Snapshot errors * │ └─ SnapshotNotFoundError — snapshot key absent from snapshot store * └─ Computed field errors * └─ ComputedFieldError — computed function threw during a write * └─ Erasure errors * └─ ForgetStrategyNotConfiguredError — vault.forget() with no withForgetCascade * ├─ Sealed-record errors (record-scoped CEK sealing) * │ ├─ SealedRecordExpiredError — sealed CEK binding past expiresAt * │ ├─ SealedRecordMismatchError — CEK sealed for record A used on record B * │ └─ RecordCekNotFoundError — record missing or no per-record `_cek` * └─ Embedding errors * ├─ EmbeddingDimMismatchError — stored vector dim ≠ descriptor dim * └─ EmbeddingModelMismatchError — stored vector model tag ≠ descriptor model * ``` * * ## Catching all NOYDB errors * * ```ts * import { NoydbError, InvalidKeyError, ConflictError } from '@noy-db/hub' * * try { * await vault.unlock(passphrase) * } catch (e) { * if (e instanceof InvalidKeyError) { showBadPassphraseUI(); return } * if (e instanceof NoydbError) { logToSentry(e.code, e); return } * throw e // unexpected — re-throw * } * ``` * * @module */ import type { GateName, GatePolicy } from './types.js'; /** * Base class for all NOYDB errors. * * Every error thrown by `@noy-db/hub` extends this class, so consumers can * catch all NOYDB errors in a single `catch (e) { if (e instanceof NoydbError) ... }` * block. The `code` field is a machine-readable string (e.g. `'DECRYPTION_FAILED'`) * suitable for `switch` statements and logging pipelines. */ export declare class NoydbError extends Error { /** Machine-readable error code. Stable across library versions. */ readonly code: string; constructor(code: string, message: string); } /** * Thrown at construction when `debugPlaintext: true` is combined with * encryption (`encrypt` not `false`). Debug-plaintext writes records in * cleartext laid out for native store inspection; it is meaningless and * unsafe under encryption, so the coupling is rejected loudly rather than * silently ignored. */ export declare class DebugPlaintextError extends NoydbError { constructor(message?: string); } /** * Thrown when a record written under `debugPlaintext` carries a top-level * field whose name starts with `_`. Debug mode inlines record fields beside * the reserved `_`-prefixed envelope metadata, so a `_`-prefixed record field * would collide with metadata. The `_` namespace is reserved by NOYDB * regardless; rename the field. */ export declare class DebugReservedFieldError extends NoydbError { constructor(collection: string, field: string); } /** * Thrown when AES-GCM decryption fails. * * The most common cause is a wrong passphrase or a corrupted ciphertext. * A `DecryptionError` at the wrong passphrase level is caught internally * and re-thrown as `InvalidKeyError` — so in practice this surfaces for * per-record corruption rather than authentication failures. */ export declare class DecryptionError extends NoydbError { constructor(message?: string); } /** * Thrown when GCM tag verification fails, indicating the ciphertext was * modified after encryption. * * AES-256-GCM is authenticated encryption — the tag over the ciphertext * is checked on every decrypt. If any byte was flipped (accidental * corruption or deliberate tampering), decryption throws this error. * Treat it as a security alert: the stored bytes are not what NOYDB wrote. */ export declare class TamperedError extends NoydbError { constructor(message?: string); } /** * Thrown when key unwrapping fails, typically because the passphrase is wrong * or the keyring file is corrupted. * * NOYDB uses AES-KW (RFC 3394) to wrap DEKs with the KEK. If AES-KW * unwrapping fails, it means either the KEK was derived from the wrong * passphrase (PBKDF2 with 600K iterations) or the keyring bytes are * corrupted. This is the error shown to the user on a failed unlock attempt. */ export declare class InvalidKeyError extends NoydbError { constructor(message?: string); } /** * Thrown when a keyring's wrapped-DEK set unwraps partially — at least * one DEK succeeds (proving the KEK is correct) but at least one fails. * The passphrase is right; the failed entries are corrupted. * * This is distinct from {@link InvalidKeyError} so that * `NoydbOptions.onInvalidKey: 'reset'` does NOT fire — resetting on * partial corruption would destroy the still-valid DEKs and the data * they protect, which is silent data loss in response to a feature * designed for stale-credential recovery. */ export declare class KeyringCorruptError extends NoydbError { readonly failedCollections: readonly string[]; readonly intactCount: number; constructor(opts: { failedCollections: readonly string[]; intactCount: number; message?: string; }); } /** * Thrown when the authenticated user does not have a DEK for the requested * collection — i.e. the collection is not in their keyring at all. * * This is the "no key for this door" error. It is different from * `ReadOnlyError` (user has a key but it only grants ro) and from * `PermissionDeniedError` (user's role doesn't allow the operation). */ export declare class NoAccessError extends NoydbError { constructor(message?: string); } /** * Thrown when a user with read-only (`ro`) permission attempts a write * operation (`put` or `delete`) on a collection. * * The user has a DEK for the collection (they can decrypt and read), but * their keyring grants only `ro`. To fix: re-grant the user with `rw` * permission, or do not attempt writes as a viewer/client role. */ export declare class ReadOnlyError extends NoydbError { constructor(message?: string); } /** * Thrown when a write is attempted against a historical view produced * by `vault.at(timestamp)`. Time-machine views are read-only by * contract — mutating the past would require either the shadow-vault * mechanism or a ledger-history rewrite (which breaks * the tamper-evidence guarantee). * * Distinct from {@link ReadOnlyError} (keyring-level) and * {@link PermissionDeniedError} (role-level): this error is about the * *view* being historical, independent of the caller's permissions. */ export declare class ReadOnlyAtInstantError extends NoydbError { constructor(operation: string, timestamp: string); } /** * Thrown when a write is attempted against a shadow-vault frame * produced by `vault.frame()`. Frames are read-only by contract — * the use case is screen-sharing / demos / compliance review where * the operator wants to prevent accidental edits. * * Behavioural enforcement only — the underlying keyring still holds * write-capable DEKs. See {@link VaultFrame} for the full caveat. */ export declare class ReadOnlyFrameError extends NoydbError { constructor(operation: string); } /** * Thrown when the authenticated user's role does not permit the requested * operation — e.g. a `viewer` calling `grantAccess()`, or an `operator` * calling `rotateKeys()`. * * This is a role-level check (what the user's role allows), distinct from * `NoAccessError` (collection not in keyring) and `ReadOnlyError` (in * keyring, but write not allowed). */ export declare class PermissionDeniedError extends NoydbError { constructor(message?: string); } /** * Thrown when an `@noy-db/as-*` export is attempted without the * required capability bit on the invoking keyring. * * Two sub-cases discriminated by the `tier` field: * * - `tier: 'plaintext'` — a plaintext-tier export (`as-xlsx`, * `as-csv`, `as-blob`, `as-zip`, …) was attempted but the * keyring's `exportCapability.plaintext` does not include the * requested `format` (nor the `'*'` wildcard). Default for every * role is `plaintext: []` — the owner must positively grant. * - `tier: 'bundle'` — an encrypted `as-noydb` bundle export was * attempted but the keyring's `exportCapability.bundle` is * `false`. Default for `owner`/`admin` is `true`; for * `operator`/`viewer`/`client` it is `false`. * * Distinct from `PermissionDeniedError` (role-level check) and * `NoAccessError` (collection not readable). Surfaces separately so * UI layers can show a "request the export capability from your * admin" flow rather than a generic permission error. */ export declare class ExportCapabilityError extends NoydbError { readonly tier: 'plaintext' | 'bundle'; readonly format?: string; readonly userId: string; constructor(opts: { tier: 'plaintext' | 'bundle'; userId: string; format?: string; message?: string; }); } /** * Thrown when a keyring file's `expires_at` cutoff has passed. * Surfaced by `loadKeyring` before any DEK unwrap is attempted — * past the cutoff the slot refuses to open even with the right * passphrase. Distinct from PBKDF2 / unwrap errors so consumer code * can show a precise "this bundle slot has expired" message instead * of the generic decryption-failure UX. * * Used predominantly on `BundleRecipient` slots produced by * `writePod({ recipients: [...] })` to time-box audit access. */ export declare class KeyringExpiredError extends NoydbError { readonly userId: string; readonly expiresAt: string; constructor(opts: { userId: string; expiresAt: string; }); } /** * Thrown when an `@noy-db/as-*` import is attempted but the invoking * keyring lacks the required import-capability bit. * * - `tier: 'plaintext'` — a plaintext-tier import (`as-csv`, `as-json`, * `as-ndjson`, `as-zip`, …) was attempted but the keyring's * `importCapability.plaintext` does not include the requested * `format` (nor the `'*'` wildcard). * - `tier: 'bundle'` — a `.noydb` bundle import was attempted but the * keyring's `importCapability.bundle` is not `true`. * * Default for every role on every dimension is closed — owners and * admins must positively grant the capability. Distinct from * `PermissionDeniedError` and `NoAccessError` so UI layers can show a * specific "request the import capability" flow. */ export declare class ImportCapabilityError extends NoydbError { readonly tier: 'plaintext' | 'bundle'; readonly format?: string; readonly userId: string; constructor(opts: { tier: 'plaintext' | 'bundle'; userId: string; format?: string; message?: string; }); } /** * Thrown when a grant would give the grantee a permission the grantor * does not themselves hold — the "admin cannot grant what admin cannot * do" rule from the admin-delegation work. * * Distinct from `PermissionDeniedError` so callers can tell the two * cases apart in logs and tests: * * - `PermissionDeniedError` — "you are not allowed to perform this * operation at all" (wrong role). * - `PrivilegeEscalationError` — "you are allowed to grant, but not * with these specific permissions" (widening attempt). * * Under the admin model the grantee of an admin-grants-admin call * inherits the caller's entire DEK set by construction, so this error * is structurally unreachable in typical flows. The check and error * class exist so that future per-collection admin scoping cannot * accidentally bypass the subset rule — the guard is already wired in. * * `offendingCollection` carries the first collection name that failed * the subset check, to make the violation actionable in error output. */ /** * Thrown when a caller invokes an API that requires an optional * store capability the active store does not implement. * * Today the only call site is `Noydb.listAccessibleVaults()`, * which depends on the optional `NoydbStore.listVaults()` * method. The error message names the missing method and the calling * API so consumers know exactly which combination is unsupported, * and the `capability` field is machine-readable so library code can * pattern-match in catch blocks (e.g. fall back to a candidate-list * shape). * * The class lives in `errors.ts` rather than as a generic * `ValidationError` because the diagnostic shape is different: a * `ValidationError` says "the inputs you passed are wrong"; this * error says "the inputs are fine, but the store you wired up * doesn't support what you're asking for." Different fix, different * documentation. */ export declare class StoreCapabilityError extends NoydbError { /** The store method/capability that was missing. */ readonly capability: string; constructor(capability: string, callerApi: string, storeName?: string); } export declare class PrivilegeEscalationError extends NoydbError { readonly offendingCollection: string; constructor(offendingCollection: string, message?: string); } /** * Thrown when a reserved internal vault name (e.g. `__noydb_state__`) is used * as a group name or partition key. * * Internal vault names are prefixed or surrounded with double-underscores to * avoid collisions with user-defined vault names. Attempting to use one as a * group name or partition key bypasses the naming policy and is rejected * eagerly so the mis-configuration is surfaced immediately. */ export declare class ReservedVaultNameError extends NoydbError { /** The rejected vault name. */ readonly vaultName: string; constructor(vaultName: string); } /** * Thrown by `Collection.put` / `.delete` when the target record's * envelope `_ts` falls within a closed accounting period. * * Distinct from `ReadOnlyError` (keyring-level), `ReadOnlyAtInstantError` * (historical view), and `ReadOnlyFrameError` (shadow vault): this * error is about the STORED RECORD being sealed by an operator call * to `vault.closePeriod()`, independent of caller permissions or * view type. The `periodName` and `endDate` fields name the sealing * period so audit UIs can surface a "this record is locked in * FY2026-Q1 (closed 2026-03-31)" message without parsing the error * string. * * To apply a correction after close, book a compensating entry in a * new period rather than unlocking the old one. Re-opening a closed * period is deliberately unsupported. */ export declare class PeriodClosedError extends NoydbError { readonly periodName: string; readonly endDate: string; readonly recordTs: string; constructor(periodName: string, endDate: string, recordTs: string); } /** * Thrown when a `put()` or `delete()` is rejected by a guard's `check` * function. The `reason` is the message the guard supplied — typically a * short business description (e.g. "invoice is issued"). The full * collection + id are surfaced so audit UIs can link back to the record. */ export declare class RecordLockedError extends NoydbError { readonly collection: string; readonly id: string; readonly reason: string; constructor(collection: string, id: string, reason: string); } /** * Thrown when a `put()` changes one or more fields that are frozen by a * `frozenFields` guard. The `fields` list contains the specific paths * that were detected as changed. */ export declare class FieldFrozenError extends NoydbError { readonly collection: string; readonly id: string; readonly fields: readonly string[]; constructor(collection: string, id: string, fields: readonly string[]); } /** * Thrown by a `transitionGuard` when a write moves a state field along an * arc that the declared transition graph does not allow — either an * update `from → to` that is not a listed edge, or an insert whose * initial state is not in the allowed `initial` set (reported with * `from: '(none)'`). Override via an amendment transaction by an * authorized role, like any guard. */ export declare class IllegalTransitionError extends NoydbError { readonly collection: string; readonly id: string; readonly from: string; readonly to: string; constructor(collection: string, id: string, from: string, to: string); } /** * Thrown by an amendment invariant when the proposed change-set violates * the declared business rule (e.g. disbursement total not preserved). * Triggers a full transaction rollback via the existing revert pass. */ export declare class InvariantError extends NoydbError { constructor(message: string); } /** * Thrown at `withTransactions({ amendment: true })` open if the caller's * role is not in the guard's allowed amendment roles. Fail-fast: thrown * before any writes are attempted. */ export declare class AmendmentForbiddenError extends NoydbError { readonly userId: string; readonly role: string; constructor(userId: string, role: string); } /** * Thrown by `listUsersWithEnvelopes` when the vault's user directory * has been disabled (via `db.setDirectoryEnabled(vault, false)`) and * the caller's role is neither `owner` nor `admin`. Owner/admin can * still enumerate users — the toggle is a UX privacy switch, not a * security boundary. * * Honest caveat: this is a UX flag, not a privacy guarantee. The * envelope ciphertext is still in the store, the keyring file is * still listed at `_keyring/*`, and anyone with direct store read * access can count keyrings without going through the hub. See * `https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/user-envelope.md` → "Directory visibility". */ export declare class DirectoryDisabledError extends NoydbError { readonly vault: string; constructor(vault: string); } /** * Thrown when a user tries to act at a tier they are not cleared for. * * This is the umbrella error for tier write refusals: * - `put({ tier: N })` when the user's keyring lacks tier-N DEK. * - `elevate(id, N)` when the caller cannot reach tier N. * * Distinct from `TierAccessDeniedError` which covers *read* refusals on * the invisibility/ghost path. */ export declare class TierNotGrantedError extends NoydbError { readonly tier: number; readonly collection: string; constructor(collection: string, tier: number); } /** * Thrown when a tier-0 `put()` or `delete()` targets a record whose LIVE * envelope is elevated (`_tier > 0`) — regardless of whether the caller * holds the tier's DEK. `put()`/`delete()` are the tier-0 write APIs; * the sanctioned way to write an elevated record is `putAtTier()`, * `elevate()`, or `demote()`. * * Distinct from `TierNotGrantedError`, which means "no DEK for tier N" * and refuses only non-holders. This error refuses HOLDERS too — the * problem isn't clearance, it's that `put()`/`delete()` are the wrong * API for an already-elevated record (a tier-0 `put()` over one would * otherwise silently demote it; a tier-0 `delete()` would write a * marker with no `_tier`, erasing the elevation signal). It is also * distinct from the read-path invisibility gate (`liveRecordIsElevated` * in `tier-visibility.ts`), which throws nothing — elevated records * simply read as absent there. This is a write-path refusal, not a * read-path ghost. * * #708: also raised by the coordinated-cutover pre-check * (`assertCutoverTierSafe`) — a bulk-rewrite is a third tier-0 write path, * so it gets the same refusal with a `detail` override naming the record. */ export declare class TierWriteRefusedError extends NoydbError { readonly tier: number; readonly collection: string; constructor(collection: string, tier: number, detail?: string); } /** * Thrown at `vault.collection()` registration when `tiers` is declared * together with a derived-artifact feature whose crypto has not yet been * made tier-aware (elevate()/demote() do not re-key it), so an elevated * record's data would stay readable at tier 0. Mirrors * `UnsupportedIndexOptionError` — the refusal happens loudly at * registration instead of leaking silently at rest. * * `feature` names the incompatible feature (e.g. `'blobs'`) so catch * blocks can pattern-match without inspecting the error message. */ export declare class UnsupportedTierCompositionError extends NoydbError { readonly feature: string; constructor(feature: string, message: string); } /** * Thrown by `createIntent` (blob durability journal, #753 spec §7 C8) when a * `_blob_intent` marker already exists for `{collection}::{recordId}` — the * CAS create-if-absent (`expectedVersion: 0`) lost to a present row. A * present marker means a shred or rehome is already in flight for this * record and MUST be resumed before any new intent is minted (overwriting it * would orphan the prior op's op-stamps — spec C8). Callers catch this and * resume the pending marker first, then retry. */ export declare class BlobIntentPendingError extends NoydbError { readonly collection: string; readonly recordId: string; constructor(collection: string, recordId: string); } /** * Thrown when an elevated-handle operation runs after the elevation's * TTL expired. Reads continue at the original tier; only writes * through the scoped handle flip to throwing once expired. */ export declare class ElevationExpiredError extends NoydbError { readonly tier: number; readonly expiresAt: number; constructor(opts: { tier: number; expiresAt: number; }); } /** * Thrown by `vault.elevate(...)` when an elevation is already active * on the vault. Adopters must `release()` the existing handle before * starting a new elevation. */ export declare class AlreadyElevatedError extends NoydbError { readonly activeTier: number; constructor(activeTier: number); } /** * Thrown when `demote()` is called by someone who is not the original * elevator and not an owner. */ export declare class TierDemoteDeniedError extends NoydbError { constructor(id: string, tier: number); } /** * Thrown when `db.delegate()` is called against a user that has no * keyring in the target vault — the delegation token cannot be * constructed without the target user's KEK wrap. */ export declare class DelegationTargetMissingError extends NoydbError { readonly toUser: string; constructor(toUser: string); } /** * Thrown when a `put()` detects an optimistic concurrency conflict. * * NOYDB uses version numbers (`_v`) for optimistic locking. If a `put()` * is called with `expectedVersion: N` but the stored record is at version * `M ≠ N`, the write is rejected and the caller must re-read, re-apply their * change, and retry. The `version` field carries the actual stored version * so callers can decide whether to retry or surface the conflict to the user. */ export declare class ConflictError extends NoydbError { /** The actual stored version at the time of conflict. */ readonly version: number; constructor(version: number, message?: string); } /** * Thrown by `LedgerStore.append()` after exhausting its CAS retry * budget under multi-writer contention. Two browser tabs, a * web app + an offline mobile peer, or a server worker pool all * producing ledger entries against the same vault can race on the * "read head, write head+1" cycle; the optimistic-CAS retry loop * resolves the race for `casAtomic: true` stores, but pathological * contention (or a buggy peer) can still exhaust the budget. When * that happens, the chain is intact — the failed writer simply * couldn't claim a slot. Caller's choice whether to retry, queue, * or surface the failure to the user. */ export declare class LedgerContentionError extends NoydbError { readonly attempts: number; constructor(attempts: number); } /** * Thrown by `vault.sequence(name).next()` after exhausting its CAS retry * budget under contention. The counter is intact; the caller may retry. */ export declare class SequenceContentionError extends NoydbError { readonly sequence: string; readonly attempts: number; constructor(sequence: string, attempts: number); } /** * Thrown by `vault.sequence(name).next()` when the backing store is not * CAS-capable (`capabilities.casAtomic !== true`). Gap-free numbering * requires single-authority serialization, which an offline / non-CAS * store cannot provide — this is a deliberate online-only wall. */ export declare class SequenceOfflineError extends NoydbError { constructor(); } /** * Thrown by `vault.sequence()` when the atomic-sequence capability was not * opted into (the default `NO_SEQUENCE` stub). Sequence is an opt-in, * tree-shakeable capability: enable it with `sequenceStrategy: withSequence()` * from "@noy-db/hub" in createNoydb(). Deferred-numbering series * (`withDeferredNumbering`) are a separate capability and are unaffected. */ export declare class SequenceNotEnabledError extends NoydbError { constructor(message?: string); } /** Thrown by a deferred-numbering pass when the store clock is unavailable or its uncertainty cannot be resolved. */ export declare class NumberingUncertaintyError extends NoydbError { readonly series: string; constructor(series: string); } /** * Thrown when a bundle push is rejected because the remote has been updated * since the local bundle was last pulled. * * Unlike `ConflictError` (per-record), this is a whole-bundle conflict — * the remote's bundle handle has changed. The caller must pull the new * bundle, merge, and re-push. `remoteVersion` is the handle of the newer * remote bundle for use in diagnostics. */ export declare class PodVersionConflictError extends NoydbError { /** The bundle handle of the newer remote version that rejected the push. */ readonly remoteVersion: string; constructor(remoteVersion: string, message?: string); } /** @deprecated Use `PodVersionConflictError`. */ export declare const BundleVersionConflictError: typeof PodVersionConflictError; /** @deprecated Use `PodVersionConflictError`. */ export type BundleVersionConflictError = PodVersionConflictError; /** * Thrown when a sync operation (push or pull) fails due to a network error. * * NOYDB's offline-first design means network errors are expected during sync. * Callers should catch `NetworkError`, surface connectivity status in the UI, * and rely on the `SyncScheduler` to retry when connectivity is restored. */ export declare class NetworkError extends NoydbError { constructor(message?: string); } /** * Thrown when `collection.get(id)` is called with an ID that does not exist. * * NOYDB collections are memory-first, so this error is synchronous and cheap — * it does not make a network round-trip. Callers that expect the record to be * absent should use `collection.getOrNull(id)` instead. */ export declare class NotFoundError extends NoydbError { constructor(message?: string); } /** * Thrown when application-level validation fails before encryption. * * Distinct from `SchemaValidationError` (Standard Schema v1 validator) * and `MissingTranslationError` (i18nText). `ValidationError` is the * general-purpose validation base — use it for custom guards in `put()` * hooks or store middleware. */ export declare class ValidationError extends NoydbError { constructor(message?: string); } /** * Thrown when a Standard Schema v1 validator rejects a record on * `put()` (input validation) or on read (output validation). Carries * the raw issue list so callers can render field-level errors. * * `direction` distinguishes the two cases: * - `'input'`: the user passed bad data into `put()`. This is a * normal error case that application code should handle — typically * by showing validation messages in the UI. * - `'output'`: stored data does not match the current schema. This * indicates a schema drift (the schema was changed without * migrating the existing records) and should be treated as a bug * — the application should not swallow it silently. * * The `issues` type is deliberately `readonly unknown[]` on this class * so that `errors.ts` doesn't need to import from `schema.ts` (and * create a dependency cycle). Callers who know they're holding a * `SchemaValidationError` can cast to the more precise * `readonly StandardSchemaV1Issue[]` from `schema.ts`. */ export declare class SchemaValidationError extends NoydbError { readonly issues: readonly unknown[]; readonly direction: 'input' | 'output'; constructor(message: string, issues: readonly unknown[], direction: 'input' | 'output'); } /** Base for schema-evolution strategy rejections. */ export declare class SchemaUpdateError extends NoydbError { constructor(code: string, message: string); } /** A non-additive schema change was rejected by the `additiveOnly()` strategy. */ export declare class NonAdditiveSchemaChangeError extends SchemaUpdateError { constructor(message: string); } /** A schema change was rejected by the `lockSchema()` strategy. */ export declare class SchemaLockedError extends SchemaUpdateError { constructor(message: string); } /** Write attempted while a schema cutover fence is up (draining/migrating, or this collection has a pending cutover). */ export declare class SchemaFenceError extends SchemaUpdateError { constructor(message: string); } /** Write attempted by a client whose generation snapshot is behind the live fence — reload required. */ export declare class MigrationRequiredError extends SchemaUpdateError { constructor(message: string); } /** A coordinated cutover timed out waiting for active clients to quiesce. */ export declare class QuiesceTimeoutError extends SchemaUpdateError { constructor(message: string); } /** * Thrown when `.groupBy().aggregate()` produces more than the hard * cardinality cap (default 100_000 groups).. * * The cap exists because `.groupBy()` materializes one bucket per * distinct key value in memory, and runaway cardinality — a groupBy * on a high-uniqueness field like `id` or `createdAt` — is almost * always a query mistake rather than legitimate use. A hard error is * better than silent OOM: the consumer sees an actionable message * naming the field and the observed cardinality, with guidance to * either narrow the query with `.where()` or accept the ceiling * override. * * A separate one-shot warning fires at 10% of the cap (10_000 * groups) so consumers get a heads-up before the hard error — same * pattern as `JoinTooLargeError` and the `.join()` row ceiling. * * **Not overridable in.** The 100k cap is a fixed constant so * the failure mode is consistent across the codebase; a * `{ maxGroups }` override can be added later without a break if a * real consumer asks. */ export declare class GroupCardinalityError extends NoydbError { /** The field being grouped on. */ readonly field: string; /** Observed number of distinct groups at the moment the cap tripped. */ readonly cardinality: number; /** The cap that was exceeded. */ readonly maxGroups: number; constructor(field: string, cardinality: number, maxGroups: number); } /** * Thrown in lazy mode when a `.query()` / `.where()` / `.orderBy()` clause * references a field that does not have a declared index. * * Lazy-mode queries only work when every touched field is indexed. * This is deliberate — silent scan-fallback would hide the performance * cliff that lazy-mode indexes exist to prevent. * * Payload: * - `collection` — name of the collection queried * - `touchedFields` — every field referenced by the query (filter + order) * - `missingFields` — subset of `touchedFields` that have no declared index */ export declare class IndexRequiredError extends NoydbError { readonly collection: string; readonly touchedFields: readonly string[]; readonly missingFields: readonly string[]; constructor(args: { collection: string; touchedFields: readonly string[]; missingFields: readonly string[]; }); } /** * Thrown by `Collection.put()` when writing a record would violate a * unique-index constraint — the same field value (or composite field * tuple) is already held by a *different* record id in the collection. * * Properties: * - `collection` — name of the collection the write was targeting * - `recordId` — the id of the record being written (the would-be violator) * - `fields` — the constrained field(s), e.g. `['taxId']` or `['workerId','employerEntityId']` * - `conflictingId` — the id of the record already holding the value * * Null-distinct semantics: if any constrained field is `null`/`undefined`, * the row is exempt (the constraint does not fire). This matches standard * SQL NULL-distinct behavior. */ export declare class UniqueConstraintError extends NoydbError { readonly collection: string; readonly recordId: string; readonly fields: readonly string[]; readonly conflictingId: string; constructor(collection: string, recordId: string, fields: readonly string[], conflictingId: string); } /** * Thrown at collection registration when an index option is declared that * is incompatible with the collection's operating mode. * * Currently covers two cases: * - `unique: true` on a lazy-mode (`prefetch: false`) collection — lazy mode * does not pre-load all records, so an in-memory uniqueness map cannot be * maintained reliably. * - `unique: true` on a CRDT collection (`crdt: 'lww-map' | 'rga' | 'yjs'`) — * CRDT put() short-circuits the unique-constraint check, so enforcement would * silently not fire. * * Both cases are caught eagerly at `vault.collection()` time so the developer * sees the incompatibility immediately rather than shipping silently-ignored * constraints. * * The `option` field names the incompatible option (`'unique'`) so catch blocks * can pattern-match without inspecting the error message. */ export declare class UnsupportedIndexOptionError extends NoydbError { readonly option: string; constructor(option: string, message: string); } /** * Thrown (or surfaced via the `index:write-partial` event) when one or more * per-indexed-field side-car writes fail after the main record write has * already succeeded. * * Not thrown out of `.put()` / `.delete()` directly — those succeed when the * main record succeeds. Instead, `IndexWriteFailureError` instances are collected * into the session-scoped reconcile queue and emitted on the Collection * emitter as `index:write-partial`. * * Payload: * - `recordId` — the id of the main record whose side-car writes failed * - `field` — the indexed field whose side-car write failed * - `op` — `'put'` or `'delete'`, indicating which mutation was in flight * - `cause` — the underlying error from the store */ export declare class IndexWriteFailureError extends NoydbError { readonly recordId: string; readonly field: string; readonly op: 'put' | 'delete'; readonly cause: unknown; constructor(args: { recordId: string; field: string; op: 'put' | 'delete'; cause: unknown; }); } /** * Thrown when `PersistedIndexStore`'s compensating `remove()` — the undo of a * stale debounced `_ftindex` save that raced a purge (#725) — itself fails. * That failure is sticky (`pendingCompensation`) and retried-first by every * subsequent store entrypoint (`ensureBuilt`/`rebuildAndPersist`/ * `removePersisted`) rather than silently dropped, but was previously * rethrown as the RAW adapter error indefinitely — indistinguishable from * any other adapter failure, so a caller could not catch it deliberately the * way `forget()` catches `_purgeSearchIndex` into `indexResidue` (#764). * * `cause` is the underlying adapter error. Callers that want stuck- * compensation resilience instead of an abort (e.g. `elevate()`/`demote()`, * #764) catch this type specifically and surface it as residue. */ export declare class PersistedIndexCompensationError extends NoydbError { readonly cause: unknown; constructor(cause: unknown); } /** * Thrown by `.where()` / `.orderBy()` / `.aggregate()` (via the Via * pipeline's `postureFor`/`wrapReducers`) when the field is covered by a Via * feature whose declared posture is `queryable: 'none'` — e.g. a `blobFields` * slot (blob content is out-of-band; it never reaches the decrypted record, * so nothing indexes or compares it). #629 Task 8 — the first posture * consumer. * * Payload: * - `field` — the refused field name */ export declare class FieldNotQueryableError extends NoydbError { readonly field: string; constructor(field: string); } /** * Thrown by `readPod()` when the body bytes don't match * the integrity hash declared in the bundle header — i.e. someone * modified the bytes between write and read. * * Distinct from a generic `Error` (which would be thrown for * format violations like a missing magic prefix or malformed * header JSON) so consumers can pattern-match the corruption case * and handle it differently from a producer bug. A * `BundleIntegrityError` indicates "the bytes you got are not * what was written"; a plain `Error` from `parsePrefixAndHeader` * indicates "what was written wasn't a valid bundle in the first * place." * * Also thrown when decompression fails after the integrity hash * passed — that's a producer bug (the wrong algorithm byte was * written) but it surfaces with the same error class because the * end result is "the body cannot be turned back into a dump." */ export declare class BundleIntegrityError extends NoydbError { constructor(message: string); } /** * Thrown by `readPod` when the bundle carries * sealed per-user passphrases but no supplied `SealingKeyProvider` * has a `.id` (= `pid`) matching the sealed entry's `pid`. * * Carries the failing pid + the user id so the recipient can * surface an actionable prompt: * * ``` * BundleSealMismatchError: bundle carries sealed passphrase for user "alice" * under provider "macos-keychain:com.acme.app/alice@acme.example", * but no registered provider matches that pid. * ``` * * Three resolution paths the message names (per foundation §11.9.4): * * 1. Configure a provider matching the pid and retry import. * 2. Pass `attemptUnsealAcrossProviders: true` to try each * registered provider regardless of pid. * 3. Inspect without unsealing — pass no `sealingProviders` to * receive the sealed entries unmodified for offline analysis. */ export declare class BundleSealMismatchError extends NoydbError { readonly userId: string; readonly pid: string; constructor(userId: string, pid: string); } /** * Thrown when `vault.collection()` is called with a name that is * reserved for NOYDB internal use (any name starting with `_dict_`). * * Dictionary collections are accessed exclusively via * `vault.dictionary(name)` — attempting to open one as a regular * collection would bypass the dictionary invariants (ACL, rename * tracking, reserved-name policy). */ export declare class ReservedCollectionNameError extends NoydbError { /** The rejected collection name. */ readonly collectionName: string; constructor(collectionName: string); } /** * Thrown by `DictionaryHandle.get()` and `DictionaryHandle.delete()` when * the requested key does not exist in the dictionary. * * Distinct from `NotFoundError` (which is for data records) so callers * can distinguish "data record missing" from "dictionary key missing" * without inspecting error messages. */ export declare class DictKeyMissingError extends NoydbError { /** The dictionary name. */ readonly dictionaryName: string; /** The key that was not found. */ readonly key: string; constructor(dictionaryName: string, key: string); } /** * Thrown by `DictionaryHandle.delete()` in strict mode when the key to * be deleted is still referenced by one or more records. * * The caller must either rename the key first (the only sanctioned * mass-mutation path) or pass `{ mode: 'warn' }` to skip the check * (development only). */ export declare class DictKeyInUseError extends NoydbError { /** The dictionary name. */ readonly dictionaryName: string; /** The key that is still referenced. */ readonly key: string; /** Name of the first collection found to reference this key. */ readonly usedBy: string; /** Number of records in `usedBy` that reference this key. */ readonly count: number; constructor(dictionaryName: string, key: string, usedBy: string, count: number); } /** * Thrown by `VaultLinks.checkLookupRefsRestrict()` (#654) when a `restrict`-mode lookup-ref * edge's compare-key cannot be resolved from the backing row — a matrix dimension with a * non-default `key` whose row is missing that field or holds a non-string/non-number value * (corruption-class rarity). Whether the referencer still points at this row can't be proven * either way, so the delete/forget is refused rather than silently allowed through — the * fail-closed twin of `DictKeyInUseError` ("cannot prove no references ⇒ do not delete"). */ export declare class RestrictRefUnresolvableError extends NoydbError { /** The dimension (backing collection/dictionary) whose row's compare-key was unresolvable. */ readonly dimension: string; /** The backing row's key (its PUT-id) that was being deleted/forgotten. */ readonly key: string; /** The unresolvable restrict edge, formatted `"collection.field"`. */ readonly referencing: string; constructor(dimension: string, key: string, referencing: string); } /** * Thrown by `Collection.put()` when an `i18nText` field is missing one * or more required translations. * * The `missing` array names each locale code that was absent from the * field value. The `field` property names the field so callers can * render a field-level error message without parsing the string. */ export declare class MissingTranslationError extends NoydbError { /** The field name whose translation(s) are missing. */ readonly field: string; /** Locale codes that were required but absent. */ readonly missing: readonly string[]; constructor(field: string, missing: readonly string[], message?: string); } /** * Thrown when reading an `i18nText` field without specifying a locale — * either at the call site (`get(id, { locale })`) or on the vault * (`openVault(name, { locale })`). * * Also thrown when `resolveI18nText()` exhausts the fallback chain and * no translation is available for the requested locale. * * The `field` property names the field that triggered the error so the * caller can surface it in the UI. */ export declare class LocaleNotSpecifiedError extends NoydbError { /** The field name that required a locale. */ readonly field: string; constructor(field: string, message?: string); } /** * Thrown at write time when an `i18nText` slot's value contains * characters outside the script set allowed for that locale, and the * field's `onScriptViolation` policy is `'reject'` (the default). * * Distinct from {@link MissingTranslationError} (write-shape) and * {@link LocaleNotSpecifiedError} (read-hole) so callers can tell a * wrong-script value from a missing one. */ export declare class ScriptViolationError extends NoydbError { /** The field whose value violated its script constraint. */ readonly field: string; /** The locale slot (e.g. `'en'`) that was checked. */ readonly locale: string; /** The Unicode scripts allowed for this slot. */ readonly expected: readonly string[]; /** A short sample of the offending characters, for diagnostics. */ readonly sample: string; constructor(field: string, locale: string, expected: readonly string[], sample: string, message?: string); } /** * Thrown when a mutation (`put`/`putAll`/`rename`/`delete`) is attempted * against a dictionary name that is backed by a `staticDict()` descriptor. * * A static dict's labels are code constants with no per-vault storage and no * mutation surface — a label change is a code deploy, not a runtime write. * Distinct from the other dictionary errors so callers can tell a * "this dict is read-only by construction" refusal from a missing-key or * key-in-use failure. */ export declare class StaticDictReadonlyError extends NoydbError { /** The static dictionary name that was the target of the mutation. */ readonly dictionaryName: string; constructor(dictionaryName: string); } /** * Thrown at put-time when a record stores a code for a `staticDict()` field * that is not in the descriptor's declared `keys` (a typo or a stale code). * * Codes are closed by construction, so an unknown code is treated as a bug by * default. Opt out per descriptor with `{ validateCodes: false }`. * * Distinct from {@link LocaleNotSpecifiedError} (a read-hole) — this is a * write-shape error. */ export declare class UnknownDictCodeError extends NoydbError { /** The static dictionary name. */ readonly dictionaryName: string; /** The field that carried the unknown code. */ readonly field: string; /** The offending code value. */ readonly code: string; constructor(dictionaryName: string, field: string, code: string); } /** * Thrown at put-time when a `vocabulary: 'closed'` lookup field (#650 Task * 3 — `lookup()`/`enumOf()`/`dict()`, the via-lookup binding) carries a key * that is not a member of its dimension — the enum tier's declared key set, * the dict tier's declared keys / live reserved-collection entries, or the * matrix tier's backing collection. * * Distinct from {@link UnknownDictCodeError} (the `staticDict()` alias's own * error, unchanged by this task) — this is the native `lookup`/`dict`/`enum` * descriptors' equivalent. `'open'` vocabulary (the default) never throws * this; declare `{ vocabulary: 'closed' }` to opt in. */ export declare class UnknownLookupKeyError extends NoydbError { /** The dimension (dictionary/target collection) name. */ readonly dimension: string; /** The field that carried the unknown key. */ readonly field: string; /** The offending key value. */ readonly key: string; constructor(dimension: string, field: string, key: string); } /** * Thrown when a collection has an `i18nText` field with * `autoTranslate: true` but no `plaintextTranslator` was configured * on `createNoydb()`. * * The error is raised at `put()` time (not at schema construction) so * the mis-configuration is surfaced by the first write rather than * silently at startup. */ export declare class TranslatorNotConfiguredError extends NoydbError { /** The field that requested auto-translation. */ readonly field: string; /** The collection the put was targeting. */ readonly collection: string; constructor(field: string, collection: string); } /** * Thrown when `Vault.load()` finds that a backup's hash chain * doesn't verify, or that its embedded `ledgerHead.hash` doesn't * match the chain head reconstructed from the loaded entries. * * Distinct from `BackupCorruptedError` so callers can choose to * recover from one but not the other (e.g., a corrupted JSON file is * unrecoverable; a chain mismatch might mean the backup is from an * incompatible noy-db version). */ export declare class BackupLedgerError extends NoydbError { /** First-broken-entry index, if known. */ readonly divergedAt?: number; constructor(message: string, divergedAt?: number); } /** * Thrown when `Vault.load()` finds that the backup's data * collection content doesn't match the ledger's recorded * `payloadHash`es. This is the "envelope was tampered with after * dump" detection — the chain itself can be intact, but if any * encrypted record bytes were swapped, this check catches it. */ export declare class BackupCorruptedError extends NoydbError { /** The (collection, id) pair whose envelope failed the hash check. */ readonly collection: string; readonly id: string; constructor(collection: string, id: string, message: string); } /** * Thrown by partition-extraction primitives when the * transitive-closure walk fails — e.g. the FK graph is deeper than * `maxDepth`, signalling a runaway or unexpectedly cyclic graph. */ export declare class PartitionExtractionError extends NoydbError { constructor(message: string); } /** * Thrown by `adoptPartition` when the transfer seal can't be * opened — a wrong/short transfer key (AES-GCM auth-tag failure) or a * malformed sealed payload. */ export declare class TransferSealError extends NoydbError { constructor(message: string); } /** * Thrown when an adoption-lifecycle precondition fails — re-adopting a * partition already consumed in this store, or owner-creation on a * vault that isn't in the adopted-unowned state. */ export declare class AdoptionStateError extends NoydbError { constructor(message: string); } /** Document-attestation failures: undeclared field-schema, non-owner issue, missing field, signer failure. */ export declare class AttestationError extends NoydbError { constructor(message: string); } /** * Thrown when an attestation capability method (`issueAttestation`, * `getDocumentSigningPublicKey`, `revokeAttestation`, `unrevokeAttestation`, * `getRevokedDocIds`, `publishRevocationList`) is called without opting into * the attestation capability (the default `NO_ATTESTATION` stub). Attestation * is an opt-in, tree-shakeable capability: enable it with * `attestationStrategy: withAttestation()` from "@noy-db/hub/attestation" in * createNoydb(). */ export declare class AttestationNotEnabledError extends NoydbError { constructor(message?: string); } /** * Thrown when `collection.reveal()` is called without opting into the * classified capability (the default `NO_CLASSIFIED` stub). Classified reveal * is an opt-in, tree-shakeable capability: enable it with * `classifiedStrategy: withClassified()` from "@noy-db/hub/classified" in * createNoydb(). */ export declare class ClassifiedNotEnabledError extends NoydbError { constructor(message?: string); } /** * Thrown when a hierarchical-tiers capability method (`putAtTier`, `getAtTier`, * `listAtTier`, `elevate`, `demote`) is called without opting into the tiers * capability (the default `NO_TIERS` stub). Tiers is an opt-in, tree-shakeable * capability: enable it with `tiersStrategy: withTiers()` from * "@noy-db/hub/tiers" in createNoydb(). */ export declare class TiersNotEnabledError extends NoydbError { constructor(message?: string); } /** * Thrown when a sealed-record grantor method (`sealRecordToHost`, * `revokeSealedRecord`, `rotateRecordCek`) is called without opting into the * sealed-record capability (the default `NO_SEALED_RECORD` stub). Sealed-record * is an opt-in, tree-shakeable capability: enable it with * `sealedRecordStrategy: withSealedRecord()` from "@noy-db/hub/sealed-record" in * createNoydb(). (The host-side `openSealedRecord` opener is ungated.) */ export declare class SealedRecordNotEnabledError extends NoydbError { constructor(message?: string); } /** * Thrown when a portability capability method (`exportMyAccessibleData`, * `unilateralWithdrawal`, `requestWithdrawal`, `listWithdrawalRequests`, * `approveWithdrawal`, `rejectWithdrawal`) is called without opting into the * portability capability (the default `NO_PORTABILITY` stub). Portability is an * opt-in, tree-shakeable capability: enable it with * `portabilityStrategy: withPortability()` from "@noy-db/hub/portability" in * createNoydb(). */ export declare class PortabilityNotEnabledError extends NoydbError { constructor(message?: string); } /** * Thrown when a sovereign-custody (FR-6) operation — `db.grantCustodian`, * `db.revokeCustodian`, or `vault.custody.liberate()` (and the `vault.custody.*` * facade that composes them) — is called without opting into the custody * capability (the default `NO_CUSTODY` stub). Custody is an opt-in, * tree-shakeable capability: enable it with `custodyStrategy: withCustody()` * from "@noy-db/hub" in createNoydb(). (The lower-level `liberateVault` free * function stays ungated.) */ export declare class CustodyNotEnabledError extends NoydbError { constructor(message?: string); } /** * Thrown when a multi-user team operation — `db.grant`, `db.revoke`, or * `db.rotate` — is called without opting into the team capability (the * default `NO_TEAM` stub). The always-on floor is single-user by design * (#267 keyring-grant → team split): enable multi-user grant/revoke/rotate * with `teamStrategy: withTeam()` from "@noy-db/hub/team" in createNoydb(). * Single-user primitives (owner keyring, unlock, `listUsers`, `updateUser`, * passphrase rotate/recover) stay ungated. */ export declare class TeamNotEnabledError extends NoydbError { constructor(message?: string); } /** * Thrown when a search / retrieval capability method — `collection.search`, * `collection.retrieve`, `collection.similarTo`, `collection.warmIndex`, * `collection.flushIndex`, or the put()-time embedding-vector compute for a * collection declaring `embeddings` — is called without opting into the search * capability (the default `NO_SEARCH` stub). Search is an opt-in, * tree-shakeable capability: enable it with `searchStrategy: withSearch()` from * "@noy-db/hub" in createNoydb(). Opting in also enables embedding compute (a * vector no gated retrieval could read would be dead weight). */ export declare class SearchNotEnabledError extends NoydbError { constructor(message?: string); } /** * Thrown when the source-side cargo operation — `extractPartition(vault, …)` — * is called without opting into the cargo capability (the default `NO_CARGO` * stub). Cargo is an opt-in, tree-shakeable capability: enable it with * `cargoStrategy: withCargo()` from "@noy-db/hub/cargo" in createNoydb(). The * recipient-side `adoptPartition` / `decryptExtractedPartition` free functions — * and `diffVault` (shared import/merge infra) — operate without a gated source * instance and stay ungated. */ export declare class CargoNotEnabledError extends NoydbError { constructor(message?: string); } /** * Thrown when `vault.broker()` is called without opting into the broker * capability (the default `NO_BROKER` stub). Opt in with * `brokerStrategy: withBroker(config)` from "@noy-db/hub/broker" in * createNoydb(). */ export declare class BrokerNotEnabledError extends NoydbError { constructor(message?: string); } /** * Thrown when the `_broker` seed cannot be enrolled with the broker host: * `enroll()`/`rotate()` called on a DEK-only keyring (KEK required to * provision the `_broker` DEK on first use — R-B8/I3), a `/enroll` POST * refused for lacking a valid dev-backend attestation (R-B3), or * `credentialSource()` called on a seed whose `/enroll` never completed * successfully (`registered !== true` — a partial enrol, I9). */ export declare class BrokerEnrolmentError extends NoydbError { constructor(message?: string); } /** * Thrown when the broker host rejects a submitted challenge proof (MAC * mismatch, expired `expiresAt`, or a reused/burned challenge — R-B5). */ export declare class BrokerProofError extends NoydbError { constructor(message?: string); } /** * Thrown by `resolveSession()` when the session token's `expiresAt` * timestamp is in the past. The session key is also removed from the * in-memory store when this is thrown, so retrying with the same sessionId * will produce `SessionNotFoundError`. * * Separate from `SessionNotFoundError` so callers can distinguish between * "session is gone" (key store cleared, tab reloaded) and "session is * still in the store but has exceeded its lifetime" (idle timeout, absolute * timeout, policy-driven expiry). The remediation differs: expired sessions * should prompt a fresh unlock; not-found sessions may indicate a bug or a * cross-tab scenario where the session was never established. */ export declare class SessionExpiredError extends NoydbError { readonly sessionId: string; constructor(sessionId: string); } /** * Thrown by `resolveSession()` when the session key cannot be found in * the module-level store. This happens when: * - The session was explicitly revoked via `revokeSession()`. * - The JS context was reloaded (tab navigation, page refresh, worker restart). * - `Noydb.close()` was called (which calls `revokeAllSessions()`). * - The sessionId is wrong or was generated by a different JS context. * * The session token (if the caller holds it) is permanently useless after * this error — the key is gone and cannot be recovered. */ export declare class SessionNotFoundError extends NoydbError { readonly sessionId: string; constructor(sessionId: string); } /** * Thrown when a session policy blocks an operation — for example, * `requireReAuthFor: ['export']` is set and the caller attempts to * call `exportStream()` without re-authenticating for this session. * * The `operation` field names the specific operation that was blocked * (e.g. `'export'`, `'grant'`, `'rotate'`) so the caller can surface * a targeted prompt ("Please re-enter your passphrase to export data"). */ export declare class SessionPolicyError extends NoydbError { readonly operation: string; constructor(operation: string, message?: string); } /** * Thrown when a `.join()` would exceed its configured row ceiling on * either side. The ceiling defaults to 50,000 per side and can be * overridden via the `{ maxRows }` option on `.join()`. * * Carries both row counts so the error message can show which side * tripped the limit (e.g. "left had 60,000 rows, right had 1,200, * max was 50,000"). The `side` field is machine-readable so test * code and devtools can match on it without regex-parsing the * message. * * The row ceiling exists because joins are bounded in-memory * operations over materialized record sets. Consumers whose * collections genuinely exceed the ceiling should track * (streaming joins over `scan()`) or filter the left side further * with `where()` / `limit()` before joining. */ export declare class JoinTooLargeError extends NoydbError { readonly leftRows: number; readonly rightRows: number; readonly maxRows: number; readonly side: 'left' | 'right'; constructor(opts: { leftRows: number; rightRows: number; maxRows: number; side: 'left' | 'right'; message: string; }); } /** * Thrown by `.crossJoin()` when the cumulative cartesian product (or lateral * filtered count) exceeds the configured ceiling. Check before allocating. * Mirrors the pattern of `JoinTooLargeError` and the `.join()` row ceiling. * * @see CrossJoinClause.maxRows — per-clause override * @see DEFAULT_CROSS_JOIN_MAX_ROWS — package default (50_000) */ export declare class CrossJoinTooLargeError extends NoydbError { readonly target: string; readonly expected: number; readonly limit: number; constructor(opts: { target: string; expected: number; limit: number; }); } /** * Thrown at cross-join execution time when the target collection is not * reachable from the current vault. The left collection is included in the * message for context. */ export declare class CrossJoinSourceUnknownError extends NoydbError { readonly target: string; readonly leftCollection: string; constructor(target: string, leftCollection: string); } /** * Thrown by `.join()` in strict `ref()` mode when a left-side record * points at a right-side id that does not exist in the target * collection. * * Distinct from `RefIntegrityError` so test code can pattern-match * on the *read-time* dangling case without catching *write-time* * integrity violations. Both indicate "ref points at nothing" but * happen at different lifecycle phases and deserve different * remediation in documentation: a RefIntegrityError on `put()` * means the input is invalid; a DanglingReferenceError on `.join()` * means stored data has drifted and `vault.checkIntegrity()` * is the right tool to find the full set of orphans. */ export declare class DanglingReferenceError extends NoydbError { readonly field: string; readonly target: string; readonly refId: string; constructor(opts: { field: string; target: string; refId: string; message: string; }); } /** * Thrown by {@link sanitizeFilename} when an input filename cannot be * made safe — NUL byte, empty after normalization, missing * `opaqueId` for the opaque profile, `..` segment, or a `maxBytes` * cap too small to hold a single code point. */ export declare class FilenameSanitizationError extends NoydbError { constructor(message: string); } /** * Thrown when a write target resolves OUTSIDE the requested * directory after sanitization — the canonical Zip-Slip class. The * sanitizer's job is to strip path-traversal segments; this error * is the defense-in-depth fallback at the FS write site. */ export declare class PathEscapeError extends NoydbError { readonly attempted: string; readonly targetDir: string; constructor(opts: { attempted: string; targetDir: string; }); } /** * Thrown at vault open if the derivation graph contains a cycle. * `path` is the offending chain (e.g. `['a', 'b', 'c', 'a']`). */ export declare class DerivationCycleError extends NoydbError { readonly path: readonly string[]; constructor(path: readonly string[]); } /** * Thrown when a cascade of source → output → source → … exceeds the * configured `maxDepth` (default 5). */ export declare class DerivationDepthError extends NoydbError { readonly limit: number; readonly attempted: number; constructor(limit: number, attempted: number); } /** * Thrown at registration if a `withDerivation` strategy references an * output `collection` that isn't otherwise declared (no schema, no use * elsewhere). Surfacing this early catches typos in collection names. */ export declare class DerivationOutputUnknownError extends NoydbError { readonly collection: string; constructor(collection: string); } /** * Thrown when the user's `derive` function returns a value that doesn't * match the declared output spec (e.g. wrong shape, wrong key set). */ export declare class DerivationOutputShapeError extends NoydbError { readonly outputKey: string; constructor(outputKey: string, detail: string); } /** * Thrown by array-shape derivations when the `derive` function * returns more rows than the output's `maxFanout` cap. The cap exists * to keep dispatch cost bounded — without it a single source-row * update could fan out to thousands of derived rows, dominating the * write path. * * Defaults to `maxFanout: 64`. Raise on the output spec for * carry-forward expansion cases (e.g. monthly rows across multi-year * contracts). */ export declare class DerivationCapExceededError extends NoydbError { readonly outputKey: string; readonly returned: number; readonly maxFanout: number; constructor(outputKey: string, returned: number, maxFanout: number); } /** * Thrown at vault open if the materialized-view graph contains a * cycle. `path` is the offending chain (e.g. `['a-mv', 'b-mv', 'a-mv']`). * Detected by the same shared DFS that catches `DerivationCycleError`; * surfaces with a distinct error type so consumers can disambiguate. */ export declare class MaterializedViewCycleError extends NoydbError { readonly path: readonly string[]; constructor(path: readonly string[]); } /** * Thrown at MV registration if the query references a source * collection that isn't declared on the vault. Surfacing this early * catches typos in collection names. */ export declare class MaterializedViewSourceUnknownError extends NoydbError { readonly mvName: string; readonly collection: string; constructor(mvName: string, collection: string); } /** * Thrown by the MV executor when a refresh produces more rows than * the configured ceiling. Default ceiling is 100k rows; override * per-MV via `maxRows`. Mirrors `JoinTooLargeError` / * `GroupCardinalityError` from the query DSL — the explosion is * detected BEFORE writes hit the store, so the source-write * transaction can roll back cleanly via strict-mode. */ export declare class MaterializedViewTooLargeError extends NoydbError { readonly mvName: string; readonly expected: number; readonly limit: number; constructor(mvName: string, expected: number, limit: number); } /** * Thrown by `withMaterializedView()` at registration time when the * strategy is structurally malformed. Distinct from * `MaterializedViewSourceUnknownError` (the source list is well-formed * but names a collection the vault doesn't know) and * `MaterializedViewCycleError` (the source graph has a cycle): this * error fires before either check, at the moment the spec is being * normalized. * * Today the trigger cases are all about the `query` / `unionSources` * dichotomy: * - both `query` and `unionSources` were set (mutually exclusive), * - neither `query` nor `unionSources` was set, * - `unionSources` has fewer than 2 arms, * - two arms in `unionSources` reference the same `collection`. * * The error message is prefixed with `[noy-db] withMaterializedView:` * so it's grep-friendly in logs and looks consistent with the existing * `ValidationError` messages from the same factory. */ export declare class MaterializedViewConfigError extends NoydbError { constructor(message: string); } /** * Thrown at vault open when a `withOverlayedView` declaration uses * another virtual-overlay name as its `base`. Multi-overlay stacking * is a v2 non-goal — the shallow expansion in * `QueryDependencyAnalyzer` would truncate at the inner overlay * name, leaving downstream MVs silently stale. */ export declare class OverlayBaseIsVirtualError extends NoydbError { readonly overlayName: string; readonly base: string; constructor(overlayName: string, base: string); } /** * Thrown at vault open when a `withOverlayedView`'s `overlay` * references an unknown collection or an MV-owned collection. The * overlay collection is user-writable; MV-owned collections aren't. */ export declare class OverlayCollectionUnavailableError extends NoydbError { readonly overlayName: string; readonly overlay: string; constructor(overlayName: string, overlay: string); } /** * Thrown at vault open when a `withOverlayedView`'s virtual `name` * collides with an MV output or a concrete source collection. */ export declare class OverlayNameCollisionError extends NoydbError { readonly overlayName: string; constructor(overlayName: string); } /** * Thrown by the virtual overlay's `put(id, record)` when the * consumer-supplied `id` doesn't match `rowKey(record)`. Catches * fat-finger separator typos that would otherwise silently produce * orphaned overlay rows. Direct writes to the underlying overlay * collection (bypass the virtual layer) skip this validation. */ export declare class OverlayIdMismatchError extends NoydbError { readonly actual: string; readonly expected: string; constructor(actual: string, expected: string); } /** * Thrown when a requested snapshot version does not exist in the * snapshot store — either it was never created, was pruned by the * retention policy, or was deleted manually. * * The `version` field carries the key that was looked up so callers * can surface an actionable "snapshot X not found" message without * parsing the error string. */ export declare class SnapshotNotFoundError extends NoydbError { readonly version: string; constructor(version: string); } /** * Thrown when a write targets a partition key that has no shard and * `sharding.autoCreate` is disabled. */ export declare class UnknownShardError extends NoydbError { readonly partitionKey: string; constructor(partitionKey: string, groupName: string); } /** * Thrown by `createShard` when the registry has a row for a partition * but the corresponding vault is not provisioned in the store — * a registry/store divergence. Refusing to recreate avoids masking * data loss. */ export declare class ShardProvisioningError extends NoydbError { readonly vaultId: string; constructor(vaultId: string, partitionKey: string); } /** * Thrown by `VaultGroup.createShard` when `sharding.regionOf` resolves a * required region that doesn't match the placement backend's * `capabilities.region` — the shard would land on a non-compliant backend * (a data-residency violation). Raised BEFORE provisioning, so no * vault is created. */ export declare class DataResidencyError extends NoydbError { readonly vaultId: string; readonly requiredRegion: string; readonly backendRegion: string | undefined; constructor(vaultId: string, requiredRegion: string, backendRegion: string | undefined); } /** * Thrown by `ShardedQuery.crossShardJoin` / `broadcastJoin` for * deterministic, query-shaping errors: an undeclared join ref (which * would fail identically on every shard), or calling a deferred * reactive/aggregate surface on a query that already carries join legs. */ export declare class CrossShardJoinError extends NoydbError { constructor(message: string); } /** Thrown when a VaultGroup references a template name that was never registered. */ export declare class VaultTemplateNotFoundError extends NoydbError { readonly templateName: string; constructor(templateName: string); } /** * Thrown when `vault.forget(subjectId)` is called on a vault whose * `createNoydb({ forgetStrategy })` declared no subject fields (the * default `NO_FORGET`). GDPR crypto-shred needs a declared subject → * record index to know which records belong to a data subject; without * one there is nothing to erase and a silent no-op would be a dangerous * false "erased" signal. Configure with * `forgetStrategy: withForgetCascade({ subjects: { invoices: 'buyerId' } })`. */ export declare class ForgetStrategyNotConfiguredError extends NoydbError { constructor(message?: string); } /** * Thrown by `openSealedRecord()` when the sealed CEK's binding has passed its * `expiresAt`. Surfaced on two checks: a cheap fast-path check on the delivery * envelope's clear-text `expiresAt`, and the AUTHORITATIVE check on the * `expiresAt` inside the sealed binding (the latter cannot be forged by editing * the delivery envelope). Distinct from {@link KeyringExpiredError} (bundle-slot * expiry) so a host can tell "this single-record grant lapsed" from a keyring- * level expiry. */ export declare class SealedRecordExpiredError extends NoydbError { readonly expiresAt: string; constructor(expiresAt: string); } /** * Thrown by `openSealedRecord()` when the sealed binding's * `{collection, id}` does not match the record envelope the host is trying to * decrypt. This is the host-denial boundary: a CEK sealed for record A cannot * be replayed against record B's envelope. (A CEK sealed for a PRE-rotation * version of a record, applied to the POST-rotation live envelope, is a * different failure — the binding still matches `{collection, id}` so it gets * past this check, and the AES-GCM auth-tag failure surfaces as * {@link TamperedError} instead.) */ export declare class SealedRecordMismatchError extends NoydbError { readonly expected: { collection: string; id: string; }; readonly actual: { collection: string; id: string; }; constructor(expected: { collection: string; id: string; }, actual: { collection: string; id: string; }); } /** * Thrown by `vault.sealRecordToHost()` / `vault.rotateRecordCek()` when the * target record has no live envelope, or its live envelope carries no `_cek` * (a legacy / non-`perRecordKeys` collection has nothing record-scoped to * seal — its body is keyed off the shared collection DEK, which sealing * deliberately never exposes). */ export declare class RecordCekNotFoundError extends NoydbError { readonly collection: string; readonly id: string; constructor(collection: string, id: string); } /** * Thrown when a stored vector's dimension does not match the dimension declared * by the active `EmbeddingDescriptor`. The `field`, `expected`, and `actual` * properties are machine-readable for switch blocks and logging. */ export declare class EmbeddingDimMismatchError extends NoydbError { readonly field: string; readonly expected: number; readonly actual: number; constructor(field: string, expected: number, actual: number); } /** * Thrown when the model tag on a stored vector does not match the `model` * declared by the active `EmbeddingDescriptor`. Signals that the encoder was * swapped without re-indexing; call `vault.embeddings.reindex()` to rebuild. */ export declare class EmbeddingModelMismatchError extends NoydbError { readonly expected: string; readonly found: string; constructor(expected: string, found: string); } /** * Thrown when a user-envelope payload exceeds {@link USER_ENVELOPE_MAX_BYTES} * after JSON-serialization. The error carries the actual size so callers * can decide whether to trim or split. */ export declare class UserEnvelopeOversizedError extends NoydbError { readonly bytes: number; readonly limit: number; constructor(bytes: number, limit?: number); } /** * Why a gate denied a request. Stable across hub versions so consumers * can switch on the value in error UIs. */ export type PolicyDenyReason = 'insufficient-tier' | 'missing-factor' | 'stale-proof' | 'disabled' | 'shared-device-blocked'; /** * Thrown by {@link checkGate} when the active session does not meet * the gate's requirements. Carries the gate name, the reason, and the * full required {@link GatePolicy} so error UIs can prompt the user * for the missing factor without re-reading the policy document. */ export declare class PolicyDeniedError extends NoydbError { readonly gate: GateName; readonly reason: PolicyDenyReason; readonly required: GatePolicy; constructor(gate: GateName, reason: PolicyDenyReason, required: GatePolicy, message?: string); } /** * Raised by `createNoydb({ ... })` when the developer omits a recovery * profile and `recover-passphrase` is not explicitly disabled. Vaults * MUST have at least one recovery path enrolled before being * production-ready (paper, shamir, multi-channel, or admin-mediated). * * The error message carries a pointer to the recovery design docs. */ export declare class RecoveryNotEnrolledError extends NoydbError { constructor(message?: string); } /** * Raised by `openVault` when a managed-passphrase-mode vault has no * STRONG recovery profile enrolled. * * Managed mode means the user never types a passphrase — the unlock * material lives in a `SealingKeyProvider` (`at-*` package). If that * provider's key is lost AND no strong recovery is enrolled, the * vault is irrecoverable. To prevent that footgun, managed-mode vaults * require at least one strong recovery profile (Shamir today; * multi-channel / admin-mediated when those ship). * * Paper recovery alone is NOT strong under managed mode: the user has * no memorized passphrase to fall back on, so losing the paper sheet = * losing every record permanently. * * Bootstrap with `db.openVaultAndEnrollRecovery(vault, { recovery: [{ profile: "shamir", k, n }] })` * to atomically create-and-enroll, or call `db.enrollRecovery(vault, { profile: "shamir", ... })` * separately before re-attempting `openVault`. */ export declare class ManagedRecoveryNotEnrolledError extends NoydbError { readonly vault: string; constructor(vault: string); } /** * Raised by `db.recoverPassphrase` / `db.enrollRecovery` / * `db.rotateRecovery` when the developer requests a recovery profile * not yet wired in this hub release. * * Implemented: `paper` and `shamir`. * Pending: `multi-channel` and `admin-mediated` (follow-up slices). * * The carried `profile` and `tracking` fields let consumers steer the * UI ("multi-channel recovery is not yet wired up — open issue #N to follow"). */ export declare class RecoveryProfileNotImplementedError extends NoydbError { readonly profile: string; readonly tracking: string; constructor(profile: string, tracking: string); } /** * Thrown by a `kernel/enclave` fork's **optional groups** — sealing, * deterministic, per-record-key lifecycle — when that fork's crypto * engine does not implement the requested behavior. * * The enclave barrel is a frozen fork-swap contract: every symbol must * exist, but the optional groups may refuse to work rather than * implement the full reference semantics. The unconditional core * (crypto ops, `RecordCodec`, tombstone) must never throw this — those * groups are load-bearing for every consumer regardless of which * enclave is wired in. noy-db's own reference enclave supports every * group, so this error is never thrown by `@noy-db/hub` itself; it * exists for fork authors to signal "my enclave doesn't do X" with a * stable, catchable code instead of an ad hoc throw. */ export declare class EnclaveNotSupportedError extends NoydbError { /** The optional group that is not supported by this enclave. */ readonly group: 'sealing' | 'deterministic' | 'per-record-keys'; constructor(group: 'sealing' | 'deterministic' | 'per-record-keys', detail?: string); } /** * Raised when a collection's `classifiedFields` configuration is invalid * (e.g. a claimed field name collides with a rider companion or another * classified field). Homed in `kernel/errors.ts` (rather than the classified * feature module) so `kernel/enclave/classify/*` can throw it without * importing with-*; the classified feature module re-exports it under the * same name for backward-compatible import paths. */ export declare class ClassifiedConfigError extends Error { readonly collection: string; constructor(collection: string, message: string); } /** * Raised by `collection.reveal()` when a field cannot be revealed — unknown * field, `storage:'never'`, or missing record. See {@link ClassifiedConfigError} * for why this lives in `kernel/errors.ts`. */ export declare class ClassifiedRevealError extends Error { readonly collection: string; readonly field: string; constructor(collection: string, field: string, detail: string); } /** * Raised by the classified verify path (`storage:'digest-only'`, stage 2) * when a field cannot be verified — unknown field, not digest-only, or no * digest stored yet. */ export declare class ClassifiedVerifyError extends Error { readonly collection: string; readonly field: string; constructor(collection: string, field: string, detail: string); } /** * Raised by the classified rotation path (stage 2) when a new value is * refused — e.g. reuse of one of the last N values (`notLastN`). */ export declare class ClassifiedRotationError extends Error { readonly collection: string; readonly field: string; constructor(collection: string, field: string, detail: string); } /** * A satellite-collection declaration or operation violated the refusal * matrix (R-S1…R-S10) of the satellite-collections design. The message * always names the R-S id. */ export declare class SatelliteConfigError extends NoydbError { constructor(message: string, options?: { readonly cause?: unknown; }); }