import { type HelixSceneV2, type SceneResource } from '@hypersoniclabs/helix-manifest'; import type { VaultAssetKind } from '../assets'; import { type VaultAssetLicense } from '../vaultPublish'; export declare const VAULT_PIN_RECEIPT_FILENAME = "vault-pins.json"; export declare const VAULT_PIN_RECEIPT_SCHEMA = "helix.scene-v2-vault-pins/1"; /** * Which Vault kinds may back which Scene resource kind. * * This MIRRORS `SCENE_VAULT_RESOURCE_KINDS` in the backend's * universal-items service, which is the authority: it re-resolves every pin at * publication and refuses one whose asset kind is not in this table. The copy * exists so a pack is refused on this machine, naming the offending resource, * BEFORE a single byte is uploaded — discovering it after 1,900 uploads is the * failure mode this table is here to prevent. Keep the two in step. */ export declare const SCENE_VAULT_RESOURCE_KINDS: Readonly>; /** One confirmed Vault version holding exactly the bytes it is keyed by. */ export type VaultPin = { assetId: string; revision: number; checksumSha256: string; sizeBytes: number; mimeType: string; kind: VaultAssetKind; visibility: string; /** The bundle path whose bytes these are — provenance for a human reader. */ sourcePath: string; confirmedAt: string; }; /** * The resumability record. Keyed by CONTENT hash, not by path: the compiler * already dedups identical meshes, a proxy GLB backs both a `model` and a * `collider` resource, and re-compiling the same pack into a fresh directory * produces the same bytes under new names. One pin per distinct byte string. */ export type VaultPinReceipt = { schemaVersion: typeof VAULT_PIN_RECEIPT_SCHEMA; /** Pins are backend-specific; a receipt from another API must never be reused. */ apiUrl: string; pins: Record; }; /** One unique compiled file the Scene document declares as a bundle resource. */ export type VaultPinTarget = { contentSha256: string; /** Canonical bundle URI, e.g. `assets/mesh-abc.detail.glb`. */ path: string; mimeType: string; /** Every Scene resource kind that reads these bytes. */ resourceKinds: SceneResource['kind'][]; resourceIds: string[]; declaredBytes?: number; }; export declare function vaultPinReceiptPath(packageDir: string): string; /** * Every DISTINCT byte string the Scene declares as a bundle resource, with the * full set of resource kinds that read it. * * Two resources may legitimately share one file (the proxy GLB is both the * rendered LOD 1 and the triangle-mesh collider); they must therefore share one * Vault asset, and the asset's kind has to satisfy BOTH. Conflicting * declarations for one URI are a corrupt package, not something to average out. */ export declare function collectVaultPinTargets(scene: HelixSceneV2): VaultPinTarget[]; /** * Everything that can be known to be wrong BEFORE the network is touched. * * The backend re-resolves every pin at publication and refuses a mismatch, but * it does so after the whole pack has been uploaded. Each of these is a * constraint that is already knowable from the compiled package plus the Vault * kind about to be used, so it is checked here, once, with the offending * resource named. */ export declare function assertVaultPinnable(target: VaultPinTarget, kind: VaultAssetKind): void; /** Parse a receipt, refusing a malformed one rather than treating it as empty. */ export declare function parseVaultPinReceipt(value: unknown, label: string): VaultPinReceipt; export declare function readVaultPinReceipt(path: string): Promise; /** * Write the receipt atomically. It is flushed after EVERY confirmed upload, so * a torn write here would be the one thing that loses the record of assets that * are already in the Vault — the exact cost this file exists to avoid. */ export declare function writeVaultPinReceipt(path: string, receipt: VaultPinReceipt): Promise; /** * Rewrite a sealed Scene document's bundle resources as Vault pins. * * Pure, and total: a bundle resource with no confirmed pin throws rather than * being left behind or silently dropped, because a half-pinned Scene would * publish as a world with holes in it. The document is re-sealed exactly the * way the compiler seals one — revision derived from the integrity of the * zeroed document, then integrity over that — and re-validated, so a rewrite * that produced an invalid Scene never reaches disk. */ export declare function applyVaultPinsToScene(scene: HelixSceneV2, pins: ReadonlyMap, /** * Content hashes the caller has decided to LEAVE in the bundle because the * Vault refused them. Only hashes named here may stay bundle-sourced; an * unpinned resource that is not on this list is still a hard error, so a * forgotten upload can never quietly downgrade to a bundle file. */ skipped?: ReadonlySet): HelixSceneV2; /** The transport slice pinning needs. `HelixApi` satisfies it; tests inject a fake. */ export type VaultPinApi = { postMultipart(path: string, form: FormData): Promise; request(method: string, path: string, body?: unknown): Promise; }; /** * The texture files a mesh REFERENCES rather than embeds. * * Reads the GLB's JSON chunk directly instead of parsing the document, because * a GLB whose images carry a uri instead of a bufferView is exactly what a glTF * library refuses to open -- the format is the thing being inspected, so it has * to be read as bytes. * * Returns [] for an ordinary self-contained mesh, so nothing changes for any * asset that does not use shared textures. */ export declare function companionTexturesFor(packageDir: string, resourcePath: string, bytes: Buffer): Promise>; /** * Upload one file and CONFIRM what the Vault actually stored. * * The publish response is the server's account of its own write; it is not * proof. Both immutable facts the publication path will later compare — the * asset's kind and visibility, and the version's checksum, size and MIME — are * re-read from the Vault before the pin is recorded, so a receipt entry means * "this asset is in the Vault, public, and holds exactly these bytes" and not * "an upload call returned 201". */ export declare function uploadAndConfirmVaultPin(input: { api: VaultPinApi; bytes: Buffer; path: string; kind: VaultAssetKind; mimeType: string; title: string; license: VaultAssetLicense; description?: string; tags?: string[]; companionTextures?: Array<{ filename: string; bytes: Buffer; }>; }): Promise; /** Guesses the Vault license from the import receipt's own rights slug. */ export declare function vaultLicenseForRightsClass(licenseClass: string): VaultAssetLicense; export type VaultPinRunResult = { schemaVersion: 'helix.scene-v2-vault-pin-run/1'; packageDir: string; receiptPath: string; apiUrl: string; /** Distinct byte strings the Scene declares as bundle resources. */ uniqueFiles: number; uploaded: number; /** Already confirmed by an earlier run; no bytes re-sent. */ reused: number; /** Scene resources rewritten from a bundle URI to a Vault pin. */ pinnedResources: number; streamedBytes: number; sceneBytesBefore: number; sceneBytesAfter: number; sceneId: string; sceneRevision: string; sceneIntegritySha256: string; /** Files the Vault refused, left as bundle resources. Empty on a clean run. */ skippedUnpinnable: Array<{ path: string; contentSha256: string; message: string; attempts: number; }>; dryRun: boolean; }; /** * Publish a compiled package's resources to the Vault and rewrite its Scene * document to pin them. Idempotent, resumable, and refuses to leave the Scene * half-rewritten: nothing touches `scene.helix-scene.json` until every distinct * file the document names has a confirmed pin. */ export declare function pinScenePackageToVault(input: { packageDir: string; api: VaultPinApi; apiUrl: string; kind?: VaultAssetKind; license?: VaultAssetLicense; titlePrefix?: string; concurrency?: number; /** Upload attempts per file before it counts as failed (default 3). */ attempts?: number; /** * Leave files the Vault refuses as bundle resources instead of failing the * run. Off by default: a hole in the world should take a decision, not a * default. */ skipUnpinnable?: boolean; dryRun?: boolean; onProgress?: (message: string) => void; }): Promise;