export { LexiconDoc } from '@atcute/lexicon-doc'; import { E as ExistingRecordInfo, S as ServiceAuthGate } from './contrail-D42UaND_.js'; export { A as AppOptions, C as Contrail, a as ContrailOptions, b as CreateAppOptions, F as FeedSweepResult, J as JetstreamLiveEvent, c as JetstreamLiveHistoryExpiredError, M as MAX_NOTIFY_URIS, N as NotifyResult, P as PersistentIngestOptions, d as PersistentJetstreamSubscription, e as PersistentLabelsOptions, Q as QueryOptions, f as ServingSourcePosition, g as SortOption, h as assertServingSourceCompatibility, i as createApp, j as getFeedPruneCursor, k as getLastCursor, l as getServingSourcePosition, m as lookupExistingRecords, o as orderedSourcePosition, p as parseAtUri, n as processNotifyUris, q as pruneActorFeed, r as pruneFeedItems, s as queryRecords, t as registerNotifyRoute, u as runLabelIngestCycle, v as runPersistent, w as runPersistentLabels, x as saveCursor, y as saveCursorStatement, z as saveFeedPruneCursor, B as saveOrderedSourcePositionStatement, D as saveServingSourcePositionStatement, G as sweepFeedItems } from './contrail-D42UaND_.js'; export { A as ActivationDelivery, c as ChangeClaim, d as ChangeClaimOptions, e as ChangeClaimTooLargeError, f as ChangeConsumerNotFoundError, g as ChangeConsumerStatus, b as ChangeConsumers, h as ChangeFailure, i as ChangeGenerationMismatchError, j as ChangeHistoryGapError, k as ChangeLeaseLostError, l as ChangeLogCostPlan, m as ChangeLogState, n as ChangeLogStatus, o as CurrentActivationClaim, p as CurrentBootstrapClaimOptions, q as CurrentBootstrapRuntimeHandler, C as CurrentBootstrapRuntimeHandlers, r as CurrentBootstrapStatus, s as CurrentRecord, t as CurrentSnapshotClaim, u as DEFAULT_SCHEDULED_INGEST_BUDGET, v as DeliveryBatch, w as DeliveryContext, x as DeliveryHandler, D as DeliveryHandlers, a as DeliveryRuntimeOptions, y as DeliverySliceResult, F as FEED_PRUNE_RECOVERY_INTERVAL_MS, z as FEED_PRUNE_SWEEP_ACTORS, I as IngestState, L as LexiconDocument, M as MAX_CHANGE_BATCH_BYTES, B as MAX_CHANGE_BATCH_CHANGES, O as OPTIMIZE_LAST_MS_KEY, E as PruneChangesOptions, G as PruneChangesResult, H as PublicServiceAuthContract, J as PublicServiceCollection, K as PublicServiceDescription, N as PublicServiceManifest, P as PublicServiceOptions, Q as PublicServiceProtectedMethod, R as RecordChange, T as RequiredChangeConsumerReadiness, U as SCHEDULED_INGEST_METADATA_BYTES, V as ScheduledIngestBudget, W as ScheduledIngestCollectionStats, S as ScheduledIngestOptions, X as ScheduledIngestStopReason, Y as SkipChangeConsumerOptions, Z as SnapshotDeliveryPage, _ as acknowledgeChanges, $ as acknowledgeCurrentSnapshotPage, a0 as assertRequiredChangeConsumersReady, a1 as canonicalJson, a2 as claimChanges, a3 as claimCurrentActivation, a4 as claimCurrentBootstrapChanges, a5 as claimCurrentSnapshotPage, a6 as completeCurrentActivation, a7 as createIngestState, a8 as describePublicService, a9 as digestLexiconDocuments, aa as failChanges, ab as failCurrentActivation, ac as failCurrentSnapshotPage, ad as getChangeLogCostPlan, ae as getChangeLogState, af as getChangesStatus, ag as getCurrentBootstrapStatus, ah as getRequiredChangeConsumerReadiness, ai as hostsServiceDidDocument, aj as hydrateChanges, ak as ingestEvents, al as isPublicServiceAuthContract, am as isPublicServiceManifest, an as maybeOptimize, ao as normalizeLexiconDocuments, ap as normalizePublicServiceEndpoint, aq as pruneChanges, ar as registerChangeConsumer, as as renewChangeClaim, at as renewCurrentBootstrapClaim, au as resolveScheduledIngestBudget, av as retryChangeConsumer, aw as runChangeDeliverySlice, ax as runFeedPruneSlice, ay as runGatedFeedPrune, az as runIngestCycle, aA as runPersistentChangeDeliveries, aB as sha256, aC as skipChangeConsumer, aD as validateDeliveryHandlers, aE as validatePublicServiceAuthEndpoint, aF as validatePublicServiceLexicons, aG as validateServiceManifest } from './public-service-DlLFyNXn.js'; import { D as Database, S as Statement, C as ContrailConfig, P as ProjectionPhase, I as IngestEvent, M as MutationSource, c as CollectionConfig, d as SqlDialect, a as RecordRow, R as RecordSource, e as RelationConfig, f as ReferenceConfig, g as LabelsConfig } from './types-CmjW-xL4.js'; export { h as AtprotoServiceAuthConfig, A as AtprotoServiceAuthMethod, i as ChangeConsumerConfig, j as ChangeConsumerInitialMode, k as ChangeLogConfig, l as CollectionMethod, m as ConstellationConfig, n as CustomQueryHandler, o as DEFAULT_ANALYSIS_LIMIT, p as DEFAULT_COLLECTION_METHODS, q as DEFAULT_CONSTELLATION_URL, r as DEFAULT_FEED_MAX_ITEMS, s as DEFAULT_FOLLOW_NSID, t as DEFAULT_FOLLOW_SHORT, u as DEFAULT_JETSTREAMS, v as DEFAULT_LABELS_MAX_PER_REQUEST, w as DEFAULT_OPTIMIZE_INTERVAL_MS, x as DEFAULT_PROFILES, y as DEFAULT_RELAYS, F as FeedConfig, z as FeedTargetConfig, B as IngestValidationConfig, E as LabelRow, G as LabelerCursorRow, H as LabelerSource, L as Logger, J as MaintenanceConfig, K as MaintenanceOptimizeConfig, O as OrderedSourceConfig, N as PipelineQueryHandler, Q as ProfileConfig, T as QueryableField, b as ResolvedContrailConfig, U as ResolvedMaps, V as ResolvedRelation, W as buildFeedTargetCaps, X as buildFtsSchema, Y as canonicalChangeDefinitions, Z as changeConsumerPhases, _ as changeLogCoverage, $ as changesEnabled, a0 as countColumnName, a1 as deriveShortName, a2 as feedTargetMaxItems, a3 as ftsQueryClause, a4 as getCollectionMethods, a5 as getCollectionNames, a6 as getCollectionNsids, a7 as getCollectionShortNames, a8 as getDependentCollections, a9 as getDependentNsids, aa as getDependentShortNames, ab as getDialect, ac as getDiscoverableCollections, ad as getDiscoverableNsids, ae as getDiscoverableShortNames, af as getFeedFollowCollections, ag as getFeedFollowShortNames, ah as getFeedMutatingNsids, ai as getNestedValue, aj as getRelationField, ak as groupedCountColumnName, al as jetstreamService, am as jetstreamUrlOption, an as normalizeFeedTarget, ao as normalizeJetstreamService, ap as normalizeProfileConfig, aq as nsidForShortName, ar as optimizeAnalysisLimit, as as optimizeEnabled, at as optimizeIntervalMs, au as postgresDialect, av as recordsTableName, aw as resolveCollectionKey, ax as resolveConfig, ay as shortNameForNsid, az as sqliteDialect, aA as sqliteFtsContentExpression, aB as validateConfig, aC as validateFieldName } from './types-CmjW-xL4.js'; import { Did } from '@atcute/lexicons'; import { Client } from '@atcute/client'; import { c as IngestDiagnosticCounts } from './backfill-Bmp9TtLS.js'; export { a as BackfillAllOptions, d as BackfillCollectionMetrics, e as BackfillOptions, f as BackfillProgress, B as BackfillRetryOptions, b as BackfillRetryResult, g as BackfillRunMetrics, D as DiscoverAndBackfillResult, h as DiscoverDIDsOptions, i as INGEST_DIAGNOSTIC_CATEGORIES, I as IngestDiagnostic, j as IngestDiagnosticCategory, k as addIngestDiagnosticCounts, l as backfillPending, m as backfillUser, n as discoverAndBackfill, o as discoverDIDs, p as getIngestDiagnostics, q as ingestDiagnosticsStatement, r as retryPendingBackfills } from './backfill-Bmp9TtLS.js'; import { B as BootstrapFailureCategory, e as BootstrapTarget, S as SourcePosition, f as BootstrapRunState, P as PreparedSnapshot, c as SnapshotBatch, M as MutationBatch, a as SnapshotSource, b as SnapshotProgress } from './sources-DKyp_dDd.js'; export { g as BootstrapPhase, h as BootstrapResult, C as ChangeSource, i as CollectionCoverage, j as SnapshotRecord, k as SourceMutation, d as SourceSemantics, l as bootstrapFreshProjection } from './sources-DKyp_dDd.js'; export { a as JetstreamChangeSource, J as JetstreamChangeSourceOptions, S as SourceCatchupIncompleteError, b as SourceHistoryExpiredError } from './jetstream-source-a396D7Z4.js'; import { B as BackfillStatus } from './status-BRg9Abty.js'; export { a as BackfillAccountCounts, b as BackfillCollectionStatus, c as BackfillRetryStatus, f as finishBackfillRun, g as getBackfillStatus, h as heartbeatBackfillRun, t as tryStartBackfillRun } from './status-BRg9Abty.js'; import { RecordValidator } from '@atcute/lexicon-doc/validations'; import { Hono } from 'hono'; import { DidDocumentResolver } from '@atcute/identity-resolver'; import '@atcute/lexicons/syntax'; import '@atcute/xrpc-server/auth'; import './service-auth-contract-CER8k0ek.js'; import '@atcute/jetstream'; interface Identity { did: string; handle: string | null; pds: string | null; resolved_at: number; } declare function resolveIdentity(db: Database, did: Did, config?: ContrailConfig): Promise; declare function resolveIdentities(db: Database, dids: string[], config?: ContrailConfig): Promise>; declare function resolveActor(db: Database, actor: string, config?: ContrailConfig): Promise; /** * Apply a handle change from a Jetstream `#identity` event. * * UPDATE-only — does not create a row for unknown DIDs (we'd lack PDS, and * partial rows confuse the rest of the pipeline). PDS column is left * untouched; it gets refreshed lazily via `getPDS` / next slingshot resolve. */ declare function applyIdentityEventStatement(db: Database, did: string, handle: string, updatedAt?: number): Statement; declare function applyIdentityEvent(db: Database, did: string, handle: string): Promise; declare function refreshStaleIdentities(db: Database, dids: string[], config?: ContrailConfig): Promise; interface ResolvedIdentity { did: string; handle: string | null; pds: string | null; } /** Reject external URLs (PDS, labeler, …) that point to private/internal * addresses or non-HTTPS. The single SSRF guard shared across packages — * callers MUST route every externally-resolved endpoint through this so the * allowlist rules live in exactly one place. * * Hostnames in `additionalAllowedHosts` skip both checks. Match is exact, * case-insensitive (allowlist entries are lowercased on compare; `URL.hostname` * is already lowercased), and port-agnostic. * * Scope: best-effort guard against the obvious internal-address classes * (private/link-local IPv4 literals, localhost, non-HTTPS). It does NOT * resolve DNS, so a public hostname that resolves to a private address is not * caught here, and IPv6 / non-canonical IP encodings are only partially * covered. Defense-in-depth (egress network policy) is expected when resolver * inputs are fully untrusted. */ declare function validateExternalUrl(url: string, additionalAllowedHosts?: string[]): boolean; /** * Resolve identity info (did, handle, pds) for a DID or handle. * Uses slingshot first, falls back to DID doc for PDS. * * `config?.networkOverrides` (optional): customize the slingshot endpoint, * the PLC URL used during DID-doc fallback, and/or which hostnames bypass * the default SSRF guard. Omitting `config` preserves all defaults. */ declare function resolvePDS(identifier: string, config?: ContrailConfig, signal?: AbortSignal): Promise; declare function getPDS(did: Did, db?: Database, config?: ContrailConfig, signal?: AbortSignal): Promise; declare function getClient(did: Did, db?: Database, config?: ContrailConfig, signal?: AbortSignal): Promise; interface RecordEventInput { uri?: string; did: string; collection: string; rkey: string; operation: "create" | "update" | "delete"; cid?: string | null; value?: unknown; /** Record/application time used by query and feed ordering. */ timeUs: number; indexedAt?: number; /** Source ordering metadata. Defaults to a local observation. */ source?: Partial & Pick; } /** Normalize a source record into Contrail's canonical mutation shape. */ declare function createIngestEvent(input: RecordEventInput): IngestEvent; /** * Parse a record's configured application time independently of source order. * Missing, invalid, and future values fall back to the source observation time. */ declare function recordTimeUs(record: unknown, collection: string, config: ContrailConfig, fallbackUs: number): number; interface IngestWarningSamples { /** Fixed maximum number of warning strings retained by the caller. */ maxSamples: number; samples: string[]; omitted: number; } interface IngestRecordsOptions { skipReplayDetection?: boolean; skipFeedFanout?: boolean; /** Skip FTS and relation-count maintenance for a bulk load that will rebuild * both projections once canonical records are durable. */ skipDerivedProjections?: boolean; /** Pre-fetched rows, used by immediate synchronization. */ existing?: Map; /** Known actors used to filter dependent records without another DB read. */ knownDids?: ReadonlySet; /** Statements committed after projection in the same database batch. */ trailingStatements?: Statement[]; /** The source response is a current authoritative snapshot, so it supersedes * durable observations without a redundant version lookup. */ authoritativeSourceObservation?: boolean; /** Acquisition phase for optional durable consumers. Defaults to live for * backwards-compatible direct ingestRecords() calls. */ phase?: ProjectionPhase; /** @internal Aggregate private diagnostics for one bulk run. The caller * flushes this bounded object once after concurrent page processing. */ aggregateDiagnostics?: IngestDiagnosticCounts; /** Collect bounded warning details instead of logging per-record lines. */ warningSamples?: IngestWarningSamples; } interface IngestDropCounts { unknownCollection: number; invalidRecord: number; lexiconValidation: number; cidMismatch: number; cidEncoding: number; missingCid: number; recordFilter: number; unknownActor: number; unknownSubject: number; /** Duplicate or stale mutations rejected by durable source ordering. */ superseded: number; } interface IngestRecordsResult { accepted: IngestEvent[]; dropped: IngestDropCounts; /** Discoverable actors admitted by this batch but absent from knownDids. */ discoveredDids: string[]; } /** * The single admission and projection path for records from every source. * * Jetstream, persistent subscriptions, PDS backfill, and immediate * synchronization all produce the same IngestEvent shape and enter here. * Source connection and checkpoint handling remain outside this function. */ declare function ingestRecords(db: Database, events: IngestEvent[], config: ContrailConfig, options?: IngestRecordsOptions): Promise; interface BootstrapFailureReport { category: BootstrapFailureCategory; failedAt: number; attempts: number; } interface DatabaseBootstrapTargetOptions { /** Skip FTS/count maintenance while loading and rebuild it before complete. */ deferDerivedProjections?: boolean; /** Additional actors already known to be in acquisition scope. */ knownDids?: ReadonlySet; /** Map an opaque bootstrap checkpoint to the numeric cursor consumed by the * legacy cron Jetstream loop. The cursor commits atomically with each source * batch so ordinary scheduled ingestion can resume after bootstrap. */ liveCursor?: (position: SourcePosition) => number; } declare function getBootstrapFailure(db: Database): Promise; /** Database-backed projection target for one unpublished fresh generation. */ declare class DatabaseBootstrapTarget implements BootstrapTarget { private readonly db; private readonly config; private readonly options; private knownDids; private knownDidsLoaded; constructor(db: Database, config: ContrailConfig, options?: DatabaseBootstrapTargetOptions); load(): Promise; beginCapture(captureFrom: SourcePosition): Promise; setSnapshot(snapshot: PreparedSnapshot, captureFrom: SourcePosition): Promise; applySnapshotBatch(snapshot: PreparedSnapshot, batch: SnapshotBatch): Promise; beginCatchup(through: SourcePosition): Promise; applyMutationBatch(batch: MutationBatch): Promise; complete(): Promise; recordFailure(category: BootstrapFailureCategory): Promise; private apply; private getKnownDids; } declare const BOOTSTRAP_VERIFICATION_META_KEY = "bootstrap_verification"; interface BootstrapVerificationCheck { name: string; ok: boolean; failures: number; } interface BootstrapVerificationReport { ok: boolean; verifiedAt: number; checks: BootstrapVerificationCheck[]; } declare class BootstrapVerificationError extends Error { readonly report: BootstrapVerificationReport; constructor(report: BootstrapVerificationReport); } /** Aggregate-only integrity checks for an unpublished candidate database. */ declare function verifyBootstrapCandidate(db: Database, config: ContrailConfig): Promise; declare function getBootstrapVerification(db: Database): Promise; interface GenerationTuple { /** Stable immutable deployment generation ID. */ id: string; /** Digest or immutable version for the executable artifact. */ codeDigest: string; /** Digest of the projection/lexicon definition. */ definitionDigest: string; /** Platform-owned locator for this generation's dedicated database. */ databaseLocator: string; schemaVersion: number; } interface GenerationReadiness { through: SourcePosition; verification: BootstrapVerificationReport; } type GenerationLifecycleState = "candidate" | "ready" | "active" | "retained" | "retired"; interface GenerationRecord { tuple: GenerationTuple; readiness: GenerationReadiness | null; state: GenerationLifecycleState; createdAt: number; readyAt: number | null; lastActivatedAt: number | null; retiredAt: number | null; } interface GenerationActivation { previous: GenerationRecord | null; active: GenerationRecord; } /** Initialize a small control-plane registry. This database is separate from * candidate projection databases and stores no record bodies or source errors. */ declare function initGenerationRegistry(db: Database): Promise; /** Durable compare-and-swap registry for complete deployment tuples. * * Request routing must resolve this one active pointer; this API deliberately * exposes no percentage split between independent generation databases. */ declare class DatabaseGenerationRegistry { private readonly db; constructor(db: Database); registerCandidate(tuple: GenerationTuple): Promise; markReady(id: string, readiness: GenerationReadiness): Promise; get(id: string): Promise; active(): Promise; /** Atomically switch the complete tuple if the caller still sees the expected * active generation. The old tuple remains ready for explicit rollback. */ activate(candidateId: string, expectedActiveId: string | null): Promise; retire(id: string): Promise; list(): Promise; } interface PdsSnapshotSourceOptions { /** Concurrent DID-to-PDS resolutions. Default: 100. */ concurrency?: number; /** PDS hosts allowed to fetch concurrently. Default: 20. */ pdsConcurrency?: number; /** Repositories allowed to fetch concurrently from one PDS. Default: 3. */ didsPerPds?: number; requestTimeoutMs?: number; maxRetries?: number; } /** A PDS snapshot stays resumable but not ready while any partition fails. */ declare class PdsSnapshotIncompleteError extends Error { constructor(message: string, options?: ErrorOptions); } /** Current-state snapshot provider backed by relay discovery and PDS listRecords. */ declare class PdsSnapshotSource implements SnapshotSource { private readonly db; private readonly config; private readonly options; readonly id = "pds"; constructor(db: Database, config: ContrailConfig, options?: PdsSnapshotSourceOptions); prepare(options: { collections: string[]; signal?: AbortSignal; }): Promise; read(options: { snapshot: PreparedSnapshot; progress?: SnapshotProgress[]; signal?: AbortSignal; }): AsyncIterable; private partitions; } type RecordValidationFailure = "lexicon_validation" | "cid_mismatch" | "cid_encoding" | "missing_cid"; interface ValidationContext { validators: Map; strict: boolean; verifyCid: boolean; allowCidlessSources: ReadonlySet; } /** Bind the exact build/runtime Lexicon bundle used by collection-level * validation without making policy configuration import generated files. */ declare function bindRecordValidationLexicons(config: ContrailConfig, lexicons: readonly object[]): void; /** Build and cache one Atcute RecordValidator for each collection that * explicitly opts in with `validate: true`. */ declare function prepareRecordValidation(config: ContrailConfig): ValidationContext | null; /** Validate one parsed create/update before filters or projection. */ declare function validateCanonicalRecord(config: ContrailConfig, event: IngestEvent, record: Record): Promise; /** ECMAScript whitespace and line-terminator code points trimmed from the * combined FTS document. SQLite receives this same explicit set via char(). */ declare const FTS_TRIM_CODE_POINTS: readonly [9, 10, 11, 12, 13, 32, 160, 5760, 8192, 8193, 8194, 8195, 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8232, 8233, 8239, 8287, 12288, 65279]; declare function trimFtsWhitespace(value: string): string; /** * Resolve which fields are searchable for a collection. * Returns null if search is disabled or no fields found. */ declare function getSearchableFields(collection: string, colConfig: CollectionConfig): string[] | null; /** Sanitized FTS virtual-table name for a collection. */ declare function ftsTableName(collection: string): string; /** Ordinary unique URI-to-FTS-rowid mapping table for a collection. */ declare function ftsRowTableName(collection: string): string; /** Extract searchable field values from a record and join them into a single string. */ declare function buildFtsContent(record: unknown, fields: string[]): string | null; /** For a newly-known subject DID, find existing followers via Constellation * and ingest synthesized follow records into the configured follow table. * Best-effort: failures are logged but not retried (caller can re-trigger). */ declare function backfillFollowersFromConstellation(db: Database, config: ContrailConfig, subjectDid: string): Promise; declare const CONTRAIL_SCHEMA_VERSION = 14; declare function buildCollectionTables(config: ContrailConfig, dialect: SqlDialect): string[]; declare function buildDynamicIndexes(config: ContrailConfig, dialect: SqlDialect): string[]; declare function buildCountColumns(config: ContrailConfig): string[]; declare function addColumnIfNotExists(db: Database, table: string, column: string, columnDef: string): Promise; declare function applyCountColumns(db: Database, config: ContrailConfig): Promise; declare function buildFtsTables(config: ContrailConfig, dialect: SqlDialect): string[]; /** Pluggable schema extension retained for applications with their own tables. */ type SchemaModule = (db: Database) => Promise; interface InitSchemaOptions { extraSchemas?: SchemaModule[]; } declare function initSchema(db: Database, config: ContrailConfig, options?: InitSchemaOptions): Promise; /** * Generic single-row-per-key store backed by `_contrail_meta(key, value)`. * Backs the schema-fingerprint gate (schema.ts) and the optimize cadence * timestamp (the ingest tick). * * Reads are tolerant: if the table doesn't exist yet — the first `initSchema` * before any DDL has run — the read resolves to null rather than throwing, so a * caller treats "no table" the same as "no value". Any transient read error * degrades the same way (callers fall back to doing the work), which is safe * because the only callers gate idempotent work on the result. */ declare function getMeta(db: Database, key: string): Promise; declare function setMeta(db: Database, key: string, value: string): Promise; declare function getMetaNumber(db: Database, key: string): Promise; /** * Refresh the query planner's statistics so multi-predicate queries pick the * selective index rather than the planner's default heuristic. * * SQLite/D1 only. Runs a CPU-bounded `PRAGMA optimize`: `analysis_limit` caps * the rows sampled per run so it can't exceed D1's per-query CPU budget and * reset the shared Durable Object — the same guardrail the feed prune needs (a * raw unbounded `ANALYZE` on a large table is exactly that failure mode). * `PRAGMA optimize` only reanalyzes tables whose stats are stale, so it's a * near-no-op once warmed; the first call on a never-analyzed DB does the bulk * of the work, which `analysis_limit` bounds. * * No-op on Postgres, where autovacuum/autoanalyze maintains planner stats. * * Surfaces errors to the caller (e.g. an environment that rejects the pragmas); * the auto-run in the ingest tick wraps this so maintenance can't break ingest. */ declare function optimizeDatabase(db: Database, analysisLimit?: number): Promise; interface ProfileEntry { did: string; handle: string | null; uri?: string; cid?: string | null; value?: unknown; collection?: string; rkey?: string; /** Hydrated by the labels module when the caller has accepted-labelers * active and there are matching labels on this DID. */ labels?: unknown; } declare function collectDids(records: RecordRow[], hydrates: Record>>): string[]; declare function resolveProfiles(db: Database, config: ContrailConfig, dids: string[]): Promise>; declare function registerFeedRoutes(app: Hono, db: Database, config: ContrailConfig, serviceAuth?: ServiceAuthGate | null): void; interface CursorStatus { cursor: number | null; date: string | null; seconds_ago: number | null; } interface CollectionOverview { collection: string; records: number; unique_users: number; } declare function getCursorStatus(db: Database): Promise; declare function getStatusOverview(db: Database, config: ContrailConfig): Promise<{ status: "ok"; total_records: number; collections: CollectionOverview[]; ingestion: CursorStatus; backfill: BackfillStatus; delivery: { required: "ready" | "catching_up"; pending: number; through: string; }; }>; declare function registerCursorRoute(app: Hono, db: Database, config: ContrailConfig): void; interface FormattedRecord { uri: string; cid: string | null; value: unknown; did: string; collection: string; rkey: string; time_us: number; [key: string]: unknown; } declare function formatRecord(row: RecordRow): FormattedRecord; declare function parseIntParam(value: string | null | undefined, defaultValue?: number): number | undefined; declare function fieldToParam(field: string): string; declare function batchedInQuery(db: Database, sql: string, prefixBindings: (string | number)[], inValues: string[]): Promise; declare function runPipeline(db: Database, config: ContrailConfig, collection: string, params: URLSearchParams, source?: RecordSource, headers?: Headers): Promise<{ records: FormattedRecord[]; cursor?: string; profiles?: any[]; labelersApplied?: string[]; }>; declare function registerCollectionRoutes(app: Hono, db: Database, config: ContrailConfig): void; declare function parseHydrateParams(params: URLSearchParams, relations: Record, references: Record): { relations: Record; references: Set; }; type HydrateResult = Record>>; declare function resolveHydrates(db: Database, relations: Record, requested: Record, records: RecordRow[], config?: ContrailConfig): Promise; type ReferenceResult = Record>; declare function resolveReferences(db: Database, references: Record, requested: Set, records: RecordRow[], config?: ContrailConfig): Promise; /** Wire-shape for a hydrated label — matches `com.atproto.label.defs#label` * field-for-field so consumers can pass it straight through to atproto SDKs. */ interface HydratedLabel { src: string; uri: string; val: string; cid?: string; /** Only present when true. */ neg?: true; /** ISO-8601, omitted when no expiry is set. */ exp?: string; /** ISO-8601 creation timestamp. */ cts: string; } /** Fetch labels for a set of subjects, filter to caller's accepted labelers, * collapse `(src, uri, val)` tuples by latest `cts`, and drop tuples whose * latest is a `neg=true` retraction. Returns a per-subject map. * * Subjects can be at-URIs or bare DIDs — the same table holds both. */ declare function hydrateLabels(db: Database, subjects: string[], accepted: string[], recordCidByUri?: Map): Promise>; /** Pick which labelers to honor for this request. * * Order of precedence: * 1. `atproto-accept-labelers` header (atproto spec) * 2. `?labelers=` query param (fallback for SSE/WS where headers are awkward) * 3. `config.defaults` (operator policy) * 4. every entry in `config.sources` * * Each candidate DID is checked against `config.sources`. Unknowns are * dropped — we only have rows for labelers we've subscribed to. * * Header values can carry `;param` modifiers (e.g. `did:plc:...;redact`); * v1 strips and ignores those — only the bare DID is honored. */ interface SelectedLabelers { /** DIDs to use for hydration this request. */ accepted: string[]; } declare function selectAcceptedLabelers(headerValue: string | null | undefined, paramValue: string | null | undefined, cfg: LabelsConfig): SelectedLabelers; /** Wire shape of a single `com.atproto.label.defs#label` entry. Field names * match the spec exactly. We accept the spec's ISO-8601 strings and * convert to unix seconds at the storage boundary. */ interface IncomingLabel { src: string; uri: string; val: string; cid?: string; neg?: boolean; exp?: string; cts: string; sig?: Uint8Array; } /** Upsert a batch of labels. Idempotent on `(src, uri, val, cts)`. Bad rows * (missing required fields, unparseable timestamps) are dropped silently; * we don't want one malformed label to abort an entire labeler frame. */ declare function applyLabels(db: Database, labels: IncomingLabel[]): Promise; /** Optional network-override knobs accepted by labeler-endpoint resolution. * Mirrors the `ContrailConfig.networkOverrides` shape — kept narrow here so * callers can pass `config.networkOverrides` directly without re-shaping. * Omitting the object preserves the previous public-internet behavior. */ interface LabelerResolveOverrides { /** DID document resolver used when looking up the labeler service entry. * When unset, falls back to a default composite (PLC + Web) pointing at the * upstream PLC directory. Trusted; not SSRF-checked. * Mirrors the resolver-injection pattern in `core/client.ts`. */ resolver?: DidDocumentResolver; /** Hostnames (DNS names or IP literals) to allow past the default SSRF * guard when validating a resolved labeler endpoint. Match is exact, * case-insensitive, port-agnostic. */ additionalAllowedHosts?: string[]; } /** Reject endpoint URLs that point to private/internal addresses or non-HTTPS. * Thin alias for the single shared SSRF guard {@link validateExternalUrl} in * `contrail-base` — labeler endpoints are validated by the exact same rules as * PDS endpoints, so the allowlist logic must live in one place. Kept exported * under this name for existing callers/tests. */ declare const validateEndpointUrl: typeof validateExternalUrl; /** Look up the labeler service endpoint from a DID. * Reads the DID doc's `service[id="#atproto_labeler"].serviceEndpoint`. * * `networkOverrides` (optional): customize the DID resolver used during the * lookup, and/or which hostnames bypass the default SSRF guard. Omitting it * preserves the original public-internet behavior. */ declare function resolveLabelerEndpoint(did: string, networkOverrides?: LabelerResolveOverrides): Promise; /** State row for a labeler — the per-DID equivalent of the singleton * jetstream `cursor` table, with cached endpoint to avoid repeated DID-doc * fetches. */ interface LabelerState { did: string; cursor: number; endpoint: string | null; resolved_at: number | null; } /** Get cached `(endpoint, cursor)` for a labeler. Resolves endpoint on * cache miss or staleness; persists endpoint + resolved_at back to the DB * so subsequent ingest cycles avoid the network round-trip. * * `networkOverrides` (optional): forwarded to `resolveLabelerEndpoint` for * the cache-miss/stale path. Has no effect when `endpointOverride` is set * or when a fresh cached endpoint is used. */ declare function getLabelerState(db: Database, did: string, endpointOverride: string | undefined, networkOverrides?: LabelerResolveOverrides): Promise; /** Persist the highest seen seq number for a labeler. Idempotent; * the next ingest cycle resumes from `cursor + 1` via the `?cursor=` param. */ declare function saveLabelerCursor(db: Database, did: string, cursor: number): Promise; /** Reset cursor to 0 — used in response to `#info { name: "OutdatedCursor" }` * frames, which signal that the labeler's seq history was rewound. */ declare function resetLabelerCursor(db: Database, did: string): Promise; /** DDL for the labels module. Single `labels` table covers record-level * (uri starts with `at://`) and account-level (uri is a bare DID) entries — * the spec collapses both into the same row shape. `labeler_cursors` * mirrors the role of the singleton `cursor` table for jetstream, but * per-labeler. */ declare function buildLabelsSchema(dialect: SqlDialect): string[]; export { BOOTSTRAP_VERIFICATION_META_KEY, BackfillStatus, BootstrapFailureCategory, type BootstrapFailureReport, BootstrapRunState, BootstrapTarget, type BootstrapVerificationCheck, BootstrapVerificationError, type BootstrapVerificationReport, CONTRAIL_SCHEMA_VERSION, CollectionConfig, type CollectionOverview, ContrailConfig, type CursorStatus, Database, DatabaseBootstrapTarget, type DatabaseBootstrapTargetOptions, DatabaseGenerationRegistry, ExistingRecordInfo, FTS_TRIM_CODE_POINTS, type FormattedRecord, type GenerationActivation, type GenerationLifecycleState, type GenerationReadiness, type GenerationRecord, type GenerationTuple, type HydrateResult, type HydratedLabel, type Identity, type IncomingLabel, IngestDiagnosticCounts, type IngestDropCounts, IngestEvent, type IngestRecordsOptions, type IngestRecordsResult, type IngestWarningSamples, type InitSchemaOptions, type LabelerResolveOverrides, type LabelerState, LabelsConfig, MutationBatch, MutationSource, PdsSnapshotIncompleteError, PdsSnapshotSource, type PdsSnapshotSourceOptions, PreparedSnapshot, type ProfileEntry, ProjectionPhase, type RecordEventInput, RecordRow, RecordSource, type RecordValidationFailure, ReferenceConfig, type ReferenceResult, RelationConfig, type ResolvedIdentity, type SchemaModule, type SelectedLabelers, SnapshotBatch, SnapshotProgress, SnapshotSource, SourcePosition, SqlDialect, Statement, addColumnIfNotExists, applyCountColumns, applyIdentityEvent, applyIdentityEventStatement, applyLabels, backfillFollowersFromConstellation, batchedInQuery, bindRecordValidationLexicons, buildCollectionTables, buildCountColumns, buildDynamicIndexes, buildFtsContent, buildFtsTables, buildLabelsSchema, collectDids, createIngestEvent, fieldToParam, formatRecord, ftsRowTableName, ftsTableName, getBootstrapFailure, getBootstrapVerification, getClient, getCursorStatus, getLabelerState, getMeta, getMetaNumber, getPDS, getSearchableFields, getStatusOverview, hydrateLabels, ingestRecords, initGenerationRegistry, initSchema, optimizeDatabase, parseHydrateParams, parseIntParam, prepareRecordValidation, recordTimeUs, refreshStaleIdentities, registerCollectionRoutes, registerCursorRoute, registerFeedRoutes, resetLabelerCursor, resolveActor, resolveHydrates, resolveIdentities, resolveIdentity, resolveLabelerEndpoint, resolvePDS, resolveProfiles, resolveReferences, runPipeline, saveLabelerCursor, selectAcceptedLabelers, setMeta, trimFtsWhitespace, validateCanonicalRecord, validateEndpointUrl, validateExternalUrl, verifyBootstrapCandidate };