import { type SharedRuntimePublishPlan } from './unrealCandidate'; export type SharedRuntimeUploadTicket = { role: string; path: string; url: string; contentType: string; cacheControl: string; contentLength: number; expiresAt: string; }; export type SharedRuntimeCreateResponse = { buildId: string; buildNumber: number; status: string; uploads: SharedRuntimeUploadTicket[]; }; export type SharedRuntimeBuildReceipt = { buildId: string; buildNumber: number; status: string; manifestDigest: string; manifestSignature: string; manifestSigningKeyId: string; bundleSizeBytes: number; promotedAt?: string; }; /** The slice of HelixApi this needs — the seam the specs fake. */ export type UnrealPublishApi = { request(method: string, path: string, body?: unknown): Promise; requestItem(method: string, path: string, body?: unknown): Promise; }; export type UnrealPublishProgress = (message: string) => void; export type UnrealPublishOptions = { /** World slug or UUID. A slug is resolved against the caller's own worlds. */ world: string; activityId?: string; maxPlayers: number; idempotencyKey?: string; /** Promote the validated build to the world's active release. Default true. */ promote?: boolean; visibility?: 'private' | 'unlisted' | 'public'; /** Pin the Unreal version a candidate must declare. */ engineVersion?: string; /** Re-fetch client delivery after promoting and check it against the plan. */ verifyDelivery?: boolean; }; export type UnrealPublishResult = { worldId: string; buildId: string; buildNumber: number; status: string; networkMode: string; artifactCount: number; bundleSizeBytes: number; manifestDigest: string; manifestSigningKeyId: string; uploadedCount: number; /** True when the create call replayed an existing build (nothing re-uploaded). */ replayed: boolean; promoted: boolean; deliveryVerified: boolean; }; /** * Resolves a world slug to its id. A UUID is passed straight through — the * backend routes on id, and requiring a lookup would make publishing to a * world you own but did not name locally impossible. */ export declare function resolveWorldId(api: UnrealPublishApi, world: string): Promise; /** * Checks that the server's presign response binds EVERY artifact we declared, * with the exact content-type, length, and cache-control it signed. A ticket * that disagrees would produce an opaque R2 403 at PUT time; catching it here * says which artifact and why. */ export declare function assertCreateResponseMatchesPlan(plan: SharedRuntimePublishPlan, response: SharedRuntimeCreateResponse): void; /** Fail-closed check of a finalize/promote receipt. */ export declare function assertReceipt(receipt: SharedRuntimeBuildReceipt): void; /** * PUTs one artifact to its presigned ticket, streaming from disk. * * Content-Type, Cache-Control and Content-Length are all folded into the R2 * signature by the backend, so every one of them must be echoed EXACTLY or the * upload comes back as an opaque 403 AccessDenied. Content-Length in * particular has to be set by hand: a streamed body has no length undici can * infer, and without the header the request is chunked and the signature fails. */ export declare function uploadArtifact(absolutePath: string, ticket: SharedRuntimeUploadTicket, attempts?: number): Promise; /** * Verify a cooked candidate, register the Build, upload every artifact, * finalize, and (by default) promote it to the world's active release. */ export declare function publishUnrealBuild(candidateDir: string, api: UnrealPublishApi, options: UnrealPublishOptions, onProgress?: UnrealPublishProgress): Promise; /** * Confirms the build a CLIENT would download is the build we uploaded: same * signed digest, and every client-role artifact present with the digest and * size we declared. This is the only check that looks at the delivery path * rather than the publish path. */ export declare function assertClientDeliveryMatchesPlan(plan: SharedRuntimePublishPlan, receipt: SharedRuntimeBuildReceipt, delivery: { buildId: string; manifestDigest: string; manifestSignature: string; artifacts: Array<{ role: string; path: string; digest: string; sizeBytes: number; }>; }): void; /** Renders an already-thrown publish failure for a terminal. */ export declare function renderPublishFailure(error: unknown): string;