/** * Locate the `craft` binary. * * Craft owns this contract. An explicit path or `CRAFT_BIN` wins, then the * pantry-installed `craft` on PATH. Keeping this as a direct delegation avoids * Stacks drifting back into checkout and node_modules probing. */ export declare function resolveCraftBinary(explicit?: string | undefined): string; export declare function resolveCraftExecutable(explicit?: string | undefined, findOnPath?: CraftBinaryLocator): string; /** * Whether this application supplies its own desktop launcher. * * The framework launcher opens a Craft window on a URL from `desktop.json`, * which is right for a hosted Stacks app and wrong for a local-first one — a * disk cleaner, a log viewer, anything whose data is the machine it runs on. * Those need to start something locally and open a window on that, and until * an app could replace the launcher its only option was to reimplement * `build:desktop` and `build:dmg` outside the framework. */ export declare function hasUserlandDesktopLauncher(projectRoot?: string): boolean; /** * The launcher entrypoint `buddy build:desktop` compiles into the native * bundle. * * `app/Desktop/launcher.ts` wins when present, the same way anything else * under `app/` overrides its framework default. Otherwise: inside this monorepo * the TypeScript source is right there, while a consumer app only has the * published package, which ships `dist/launcher.js` — so resolve whichever * exists rather than assuming the monorepo layout, which is what previously * made desktop builds impossible outside this repo. */ export declare function resolveDesktopLauncher(projectRoot?: string): string; export declare function xmlEscape(value: string): string; /** * Serialise a JSON value as a plist fragment. * * Applications declare extra `Info.plist` entries as JSON rather than XML so a * typo cannot produce a bundle macOS silently refuses to launch. The keys that * matter most are the `NS*UsageDescription` strings: they are the sentences a * person reads in a permission prompt, and without them macOS shows a generic * prompt or refuses the request outright. */ export declare function plistValue(value: unknown, indent?: string): string; /** * Render an application's declared `Info.plist` entries, dropping any key the * bundle must own. Returns the ignored keys so the caller can say so. */ export declare function renderUserlandPlistEntries(declared: Record): { xml: string, ignored: string[] }; export declare function resolveDevWindowUrl(port: number, options?: OpenDevWindowOptions): string; export declare function craftDevCommand(port: number, options?: OpenDevWindowOptions): string[]; export declare function createUpdateManifestUrl(baseUrl: string, channel?: string): string; export declare function openDevWindow(port: number, options?: OpenDevWindowOptions, launcher?: CraftLauncher): Promise; /** * Whether a file is a Bun standalone executable. * * Size first because it is a `stat`, then the marker, so the expensive check * only runs on the handful of files large enough to be a runtime at all. */ export declare function looksLikeBunExecutable(path: string, read?: (path: string) => { size: number, tail: string } | null): boolean; /** * What a bundle is paying to ship more than one Bun-compiled executable. * * Every one of them embeds a complete copy of the Bun runtime. An app that * splits its launcher, its server and a worker into three binaries ships three * copies — about 180 MB — and nothing says so: the bundle is simply large, and * a large desktop app looks normal. * * Returns null when there is at most one, which is the case worth saying * nothing about. */ export declare function describeRuntimeDuplication(runtimes: BundledRuntime[]): string | null; /** Where an application puts a launcher of its own. */ export declare const USERLAND_LAUNCHER: 'app/Desktop/launcher.ts'; /** * Keys the bundle itself must control. * * Letting an app rewrite its own identifier or executable from `Info.plist.json` * produces a bundle that does not match what was signed — which fails at * launch, long after the build said it succeeded. */ export declare const RESERVED_PLIST_KEYS: ReadonlySet; /** * The trailer `bun build --compile` writes into every standalone executable. * * Present in a Bun single-file binary and absent from a native one, which is * what makes it usable to tell the two apart inside a finished bundle. */ export declare const BUN_EXECUTABLE_MARKER: '---- Bun!'; export declare interface Desktop { app: unknown core: unknown dpi: unknown event: unknown image: unknown menu: unknown mocks: unknown path: unknown tray: unknown webview: unknown webviewWindow: unknown window: unknown } // let _desktop: Desktop | undefined // export async function getDesktop(): Promise { // if (_desktop) return _desktop // const tauri = await import('@tauri-apps/api') // _desktop = { // app: tauri.app, // core: tauri.core, // dpi: tauri.dpi, // event: tauri.event, // image: tauri.image, // menu: tauri.menu, // mocks: tauri.mocks, // path: tauri.path, // tray: tauri.tray, // webview: tauri.webview, // webviewWindow: tauri.webviewWindow, // window: tauri.window, // } // return _desktop // } export declare interface OpenDevWindowOptions { url?: string title?: string width?: number height?: number darkMode?: boolean hotReload?: boolean nativeSidebar?: boolean sidebarWidth?: number sidebarConfig?: unknown devTools?: boolean craftBin?: string systemTray?: boolean hideDockIcon?: boolean menubarOnly?: boolean } /** One Bun-compiled executable found in a bundle. */ export declare interface BundledRuntime { name: string bytes: number } export type CraftLauncher = (command: string[]) => void | Promise; export type CraftBinaryLocator = (binary: string) => string | null; export * from './invites'; export * from './updater'; export * from './support';