import type { AssetStat, AssetStore } from '../images/asset-support.js'; import type { EvaluationScore } from '../types/evaluate.js'; import type { Store } from '../types/store.js'; /** What kind of medium an asset is, from its MIME type. */ export type CatalogMediaKind = 'image' | 'audio' | 'video' | 'document' | 'other'; /** The latest score of one key an asset was given. */ export interface CatalogScore { /** The score. */ score: number; /** Whether it passed, when the evaluator judged rather than measured. */ passed?: boolean; /** The evaluator's explanation. */ comment?: string; /** Who gave it, such as an online evaluation's source. */ source?: string; /** ISO-8601 time it was given. */ at: string; } /** One stored asset, as the catalog records it. */ export interface MediaCatalogEntry { /** The asset's id in its store. */ assetId: string; /** The tenant that owns it. */ tenantId: string; /** Its kind, from its MIME type. */ kind: CatalogMediaKind; /** Its MIME type. */ mimeType: string; /** The store's URI for it. */ uri: string; /** The asset store's name, when the catalog covers several. */ store?: string; /** Its size in bytes, when known. */ bytes?: number; /** Width in pixels, when known. */ width?: number; /** Height in pixels, when known. */ height?: number; /** Its file name, when it has one. */ filename?: string; /** Its SHA-256 digest, hex-encoded, when known. */ sha256?: string; /** The provider that made it, or `upload`'s provider for one brought in. */ provider: string; /** The model that made it. */ model?: string; /** Whether it was generated, edited, or uploaded. */ operation: string; /** The request that made it. */ requestId: string; /** The assets it was derived from, for an edit. */ parentAssetIds?: string[]; /** The run that made it, from its provenance's `runId`, when recorded. */ runId?: string; /** The trace that made it, from its provenance's `traceId`, when recorded. */ traceId?: string; /** Labels to find it by. */ tags: string[]; /** Application data. */ metadata?: Record; /** The latest score per key, from evaluations of it. */ scores: Record; /** ISO-8601 time it was stored. */ createdAt: string; /** ISO-8601 time it expires, when it does; the entry is never read after it. */ expiresAt?: string; /** Goes up on every change, so concurrent changes are never lost. */ version: number; /** Each tag as a field, so a store filters by it. */ tagged: Record; } /** What `MediaCatalog.list()` looks for. Every field narrows the match. */ export interface MediaCatalogQuery { /** One tenant's assets. Defaults to every tenant's. */ tenantId?: string; /** Assets of this kind. */ kind?: CatalogMediaKind; /** Assets of this MIME type. */ mimeType?: string; /** Assets this provider made. */ provider?: string; /** Assets this model made. */ model?: string; /** Assets generated, edited, or uploaded. */ operation?: string; /** Assets one run made. */ runId?: string; /** Assets in one asset store. */ store?: string; /** Assets with this tag. */ tag?: string; /** Assets stored at or after this ISO-8601 time. */ since?: string; /** Assets stored at or before this ISO-8601 time. */ until?: string; /** Assets whose latest score for `key` is below `below`. */ scoreBelow?: { key: string; below: number; }; /** Assets whose latest score for `key` is at least `atLeast`. */ scoreAtLeast?: { key: string; atLeast: number; }; /** Assets with no score for this key yet. */ unscored?: string; /** Most entries returned. Defaults to 50. */ limit?: number; /** Where the page before ended, from its `next`. */ cursor?: string; /** Most entries read to fill a page, when filters the store cannot apply skip many. Defaults to 10,000. */ scanLimit?: number; } /** A page of entries, newest first. */ export interface MediaCatalogPage { /** The entries. */ entries: MediaCatalogEntry[]; /** Passed as `cursor`, the next page; absent after the last. */ next?: string; } /** How much is catalogued, by kind. */ export interface MediaCatalogStats { /** Assets. */ assets: number; /** Their bytes, of those whose size is known. */ bytes: number; /** The same, per kind. */ byKind: Partial>; /** True when it stopped at its limit before the end. */ truncated: boolean; } /** What `record()` adds to what the asset store says. */ export interface MediaCatalogRecordOptions { /** Labels to find it by. */ tags?: string[]; /** Application data. */ metadata?: Record; /** The asset store's name, when the catalog covers several. */ store?: string; /** The run that made it, when its provenance does not say. */ runId?: string; /** The trace that made it, when its provenance does not say. */ traceId?: string; } /** Options for `mediaCatalog()`. */ export interface MediaCatalogOptions { /** Where entries are kept: any long-term store, such as the Postgres, SQLite, Redis, or memory one. */ store: Store; /** The namespace entries live under, beside each tenant's id. Defaults to `['nexus', 'media']`. */ namespace?: readonly string[]; /** Replaces the system clock, for tests. */ now?: () => Date; } /** One record of every stored asset. */ export interface MediaCatalog { /** Records an asset an asset store has stored, from its `AssetStat`, replacing any earlier entry. */ record(stat: AssetStat, options?: MediaCatalogRecordOptions): Promise; /** Removes an asset's entry. */ forget(assetId: string, tenantId: string): Promise; /** One asset's entry. */ get(assetId: string, tenantId: string): Promise; /** Entries that match, newest first, a page at a time. */ list(query?: MediaCatalogQuery): Promise; /** Records an asset's score, keeping the latest per key. Resolves to the entry, or `undefined` when there is none. */ score(assetId: string, tenantId: string, score: EvaluationScore & { source?: string; }): Promise; /** Adds and removes an asset's tags. */ tag(assetId: string, tenantId: string, change: { add?: string[]; remove?: string[]; }): Promise; /** * Records scores on every stored asset a value refers to, such as the images in a run's output, * and resolves to how many assets were scored: what an online evaluation's `onScored` calls. */ attach(value: unknown, scores: readonly EvaluationScore[], options: { tenantId: string; source?: string; }): Promise; /** Counts what is catalogued, reading at most `limit` entries (100,000). */ stats(options?: { tenantId?: string; limit?: number; }): Promise; /** * Removes the entries of assets that expired. An expired entry is never read, so this only frees * the space; an asset store wrapped by `catalogedAssetStore()` calls it from `purgeExpired()`. * Resolves to how many went. */ purgeExpired(options?: { tenantId?: string; }): Promise; /** * Removes entries whose asset is gone from its store, as when it was deleted around the catalog. * Reads at most `limit` entries (10,000). */ reconcile(assets: Pick, options?: { tenantId?: string; store?: string; limit?: number; }): Promise<{ checked: number; removed: number; }>; } /** * A media catalog in any long-term store. Give the asset stores to `catalogedAssetStore()`, and * every asset stored through them is recorded, its entry gone when it is deleted or expires. * * ```ts * const catalog = mediaCatalog({ store: new PostgresStore(pool) }); * const assets = catalogedAssetStore(new S3AssetStore({ ... }), catalog, { name: 's3' }); * const blurry = await catalog.list({ tenantId: 'acme', scoreBelow: { key: 'sharpness', below: 0.5 } }); * ``` */ export declare function mediaCatalog(options: MediaCatalogOptions): MediaCatalog; /** Options for `catalogedAssetStore()`. */ export interface CatalogedAssetStoreOptions { /** The store's name, recorded on each entry, when the catalog covers several stores. */ name?: string; /** Tags each asset is recorded with, from what was stored. */ tags?: (stat: AssetStat) => string[] | undefined; /** * Hears a failure to record an asset, which then stays stored, uncatalogued. Without it, the asset * is deleted again and the store's `put()` rejects, so the catalog and the store always agree. */ onError?: (error: unknown, stat: AssetStat) => void; } /** * Wraps an asset store so the catalog records every asset stored through it, and forgets every asset * deleted through it. An entry expires with its asset, and `purgeExpired()` removes both. Everything * else about the store is its own. */ export declare function catalogedAssetStore(assets: AssetStore, catalog: MediaCatalog, options?: CatalogedAssetStoreOptions): AssetStore;