import type { IncomingMessage, ServerResponse } from 'node:http'; import type { ResolvedUpdater } from '../config.js'; export interface UpdateState { status: 'idle' | 'checking' | 'available' | 'not-available' | 'downloading' | 'ready' | 'error'; /** Running app version. */ current: string; latest?: string; notes?: string; mandatory?: boolean; /** 0..1, only meaningful while `status === 'downloading'`. */ progress?: number; error?: string; /** * Set alongside `status: 'not-available'` when the reason isn't "already * on the latest version" but a structural one the UI may want to word * differently — currently only `'system-package-manager'` (Linux, non- * AppImage packaging — see `runCheck()`'s Linux short-circuit below). This * is deliberately NOT `status: 'error'`: nothing is wrong, self-update * just isn't this package's story to tell. */ reason?: 'system-package-manager'; } export interface UpdaterEngineOptions { /** `null` means the app has no `updater` configured — check()/download()/install() all report a clean "not configured" error rather than crashing. */ resolvedUpdater: ResolvedUpdater | null; /** The running app's own version — NOT `@murasakijs/native`'s `version()` (that's the native crate's version, a different number). Read from `murasaki-meta.json` in prod, from `murasaki.config.ts`'s `version` in dev. */ currentVersion: string; /** `'dev'` fails `download()`/`install()` fast (§6) — there's no bundled app/launcher to apply an update to. `check()` still works in both modes. */ mode: 'dev' | 'prod'; /** Prod only: the packaged resources dir (`Contents/Resources` on macOS, `resources/` on Windows — Node's own `cwd`, per §7). Required for `install()`, which writes `.murasaki-apply.json` here; the launcher (not Node) derives the launcher/exe/target/relaunch paths from this same directory. */ resourcesDir?: string; /** Where downloaded payloads are staged before install. Defaults to a directory under `os.tmpdir()`. */ stagingDir?: string; /** Writable, persistent per-app directory for rollout identity. Packaged apps use Main's OS-standard data directory. */ stateDir?: string; /** Network timeout for each manifest/signature request. Primarily exposed so embedders can tune unusually slow self-hosted endpoints. */ requestTimeoutMs?: number; /** End-to-end timeout for an update payload download. */ downloadTimeoutMs?: number; /** Maximum accepted raw manifest size. */ maxManifestBytes?: number; /** Maximum accepted detached signature response size. */ maxSignatureBytes?: number; /** Maximum accepted update payload size. Enforced even without `content-length`. */ maxPayloadBytes?: number; } export interface UpdaterEngine { getState(): UpdateState; /** Registers a listener fired with the full new state on every transition. Returns an unsubscribe function. */ onChange(listener: (state: UpdateState) => void): () => void; check(): Promise; /** Starts (but does not await to completion by the caller — the HTTP layer calls this without awaiting) the download. Progress/completion are observable via `onChange`/`getState`. */ download(): Promise; install(): Promise<{ ok: true; } | { ok: false; error: string; }>; /** Stops the `checkInterval` timer, if one was started. Idempotent. Does not affect an in-flight check. */ dispose(): void; } export declare function createUpdaterEngine(opts: UpdaterEngineOptions): UpdaterEngine; /** * Dispatches the four `/__murasaki/update/*` routes against `engine`. * Returns `true` if the request matched (and was fully handled — including * unmatched methods/sub-paths under the prefix, which get a 404/405) so the * caller (a Connect middleware in dev) knows whether to fall through to * `next()`. */ export declare function createUpdateRequestHandler(engine: UpdaterEngine): (req: IncomingMessage, res: ServerResponse) => Promise; //# sourceMappingURL=updater.d.ts.map