import { Buffer } from 'buffer'; import type { VerifyResult } from '../verify/classify.js'; import { type BuildManifest } from '../publish/bundle.js'; /** * `'public' | 'private'`, or `undefined` when the flag was not passed. * * Undefined is NOT "private": it means "say nothing about visibility", and the server keeps * whatever the game already is. Defaulting to private here meant every bare `bitmagic publish` * re-asserted it, so shipping a routine update to a public game silently unlisted it and took * its `/play/` page out of service. A game's first publish is still private — `createGame` * inserts it that way; nobody has to assert it on every publish thereafter. * * A typo is still rejected rather than silently coerced, matching the server's own asymmetric * contract (see cli-publish.ts). */ export declare function resolveVisibility(raw: string | undefined): 'public' | 'private' | undefined; export interface PublishRunDeps { fetch: typeof globalThis.fetch; sleep: (ms: number) => Promise; /** Test-only override; production omits it and loadProjectContext walks up from process.cwd(). */ startDir?: string; /** Test-only override; production omits it and the credential helpers read ~/.bitmagic. */ baseDir?: string; /** * Test-only override. Production omits it: prose goes through the Output seam, which routes to * stderr under `--json` so it cannot land beside the result document on stdout. */ log?: (message: string) => void; /** Injectable so a test can assert reuse-vs-rebuild without a real tsc/vite toolchain. */ runBuild: (root: string, engineVersion: string, options: { singleFile: boolean; }) => BuildManifest; readBuildManifest: (root: string) => BuildManifest | null; /** Injectable so a test can assert the smoke check's wiring without launching a browser. */ runSmokeCheck: (options: { publishedUrl: string; artifactDir: string; root: string; log: (message: string) => void; }) => Promise; /** * Shows the published URL as a scannable code — drawn in the terminal, or written as a PNG when * it cannot be. Returns the image path when a file was written, else null. * * Additional output, exactly like `bitmagic cover`'s inline image — never a failure, and never a * replacement for the plain `Published …` line above it. */ emitQr: (url: string, options: { root: string; json: boolean; disabled: boolean; }) => string | null; } export interface PublishArgs { visibility?: string; name?: string; description?: string; force?: boolean; /** Hyphenated to match the flag citty parses; there is no camelCase alias. */ 'skip-smoke'?: boolean; 'version-url'?: boolean; 'no-qr'?: boolean; 'single-file'?: boolean; json?: boolean; } /** One candidate for this publish's thumbnail, already read off disk. */ interface ThumbnailSource { bytes: Buffer; filename: string; contentType: string; /** Named in the output, so the creator can see which of the two they got. */ label: string; /** Whether this is `bitmagic cover`'s artwork. False means the fallback, which earns a nudge. */ generated: boolean; } /** * What this publish should use as its thumbnail, in preference order. * * The generated cover wins when there is one: it was drawn from the game's design, whereas the * verify screenshot is whatever the camera happened to be pointing at one second after load. The * screenshot remains the fallback rather than being retired, because `bitmagic cover` costs sparks * and is optional — a creator who never runs it must still be able to publish. * * Between the two screenshots, the one matching the game's OWN platform wins: `bitmagic verify` * boots a mobile-primary game as a phone by default and then writes only `screenshot.mobile.png`, * so preferring the desktop file would both pick a picture the game is not about and, on a * mobile-only project, find nothing at all. * * Returns null when none of the three exists, which the caller turns into exit 3. */ export declare function resolveThumbnailSource(root: string, readFile?: (file: string) => Buffer): ThumbnailSource | null; /** * The whole command. See the file header for why the order below cannot be reshuffled. */ export declare function runPublish(args: PublishArgs, deps?: PublishRunDeps): Promise; export declare const publishCommand: import("citty").CommandDef<{ readonly 'original-prompt': { readonly type: "string"; readonly description: string; }; readonly visibility: { readonly type: "string"; readonly description: string; }; readonly name: { readonly type: "string"; readonly description: "Override the published name for this publish only — never written to game.json."; }; readonly description: { readonly type: "string"; readonly description: "Override the published description for this publish only — never written to game.json."; }; readonly force: { readonly type: "boolean"; readonly description: "Publish despite a stale or failed verify. Does NOT bypass a missing verify record."; }; readonly 'skip-smoke': { readonly type: "boolean"; readonly description: "Skip the post-publish render check. The game still publishes; it is simply not confirmed to render."; }; readonly 'version-url': { readonly type: "boolean"; readonly description: string; }; readonly 'no-qr': { readonly type: "boolean"; readonly description: "Do not draw the published URL as a QR code. `BITMAGIC_NO_QR` does the same for every run."; }; readonly 'single-file': { readonly type: "boolean"; readonly description: string; }; readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; }>; export {};