# App file downloads — SDK 1.8.0 The browser player keeps app frames sandboxed. Apps offer exports through the trusted player; files remain in the browser and are not uploaded to Hackemist. A person must click **Download file** in the player dialog before a browser download is requested. ```js const bytes = await buildMyPDF(); // App-owned PDF generation const result = await Hackemist.downloadFile({ filename: 'document.pdf', mediaType: 'application/pdf', data: new Blob([bytes], {type: 'application/pdf'}) }); showStatus(result.status === 'requested' ? 'Download requested. Check your browser’s downloads.' : 'Download cancelled or expired. Your document is still open.'); ``` Pass one options object, containing `filename`, `mediaType`, and exactly one of: - `text`: UTF-8 text, at most **8 MiB**. Supported for JSON (valid JSON required), plain text, CSV, Markdown and RTF. - `data`: a **Blob, ArrayBuffer or Uint8Array**, at most **64 MiB**. The binary bytes are preserved exactly. | Extension | `mediaType` | | --- | --- | | pdf | application/pdf | | docx | application/vnd.openxmlformats-officedocument.wordprocessingml.document | | xlsx | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet | | pptx | application/vnd.openxmlformats-officedocument.presentationml.presentation | | odt, ods, odp | application/vnd.oasis.opendocument.text, application/vnd.oasis.opendocument.spreadsheet, application/vnd.oasis.opendocument.presentation (respectively) | | doc, xls, ppt | application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint (respectively) | | json, txt, csv, md | application/json, text/plain, text/csv, text/markdown (respectively) | | rtf | application/rtf or text/rtf | | zip | application/zip | | png, jpg/jpeg, webp | image/png, image/jpeg, image/webp (respectively) | | mp4, webm, mp3, wav | video/mp4, video/webm, audio/mpeg, audio/wav (respectively) | | ogg, m4a, flac | audio/ogg, audio/mp4, audio/flac (respectively) | | glb, gltf, obj, stl | model/gltf-binary, model/gltf+json, model/obj, model/stl (respectively) | Use a matching lowercase extension. Filenames are limited to 96 ASCII characters, start with a letter/digit, and contain letters, digits, dots, underscores, spaces or hyphens. Paths, remote URLs, HTML, SVG, executables and unknown media types are rejected. The suite handles transport; the app must generate valid document/media contents. Binary JSON exports do not run the text JSON validator. The existing text form is unchanged: ```js await Hackemist.downloadFile({ filename: 'workspace.json', mediaType: 'application/json', text: JSON.stringify(workspace) }); ``` Success is `{status:'requested', filename, mediaType, bytes}`. Other choices return `{status:'cancelled'}` or `{status:'expired'}`. Invalid requests reject the Promise. `requested` means the browser was asked to download; Hackemist cannot prove that a file was kept. Do not report a backup as saved, clear work or reload on that status alone. In particular, the SDK does **not** return `ready`, `size`, or support `downloadFile(blob, {filename, mimeType})`. Only one export can await a player decision per running app, with six attempts per minute. The choice expires after 110 seconds, with a 120-second SDK timeout. Closing the player cancels pending choices without changing app content or account saves. Browser cancellation after requesting a download is outside the SDK's observation. ## Existing Blob download buttons For browser apps using common `` exports, the injected SDK tracks bounded app-created Blob object URLs and routes their download clicks through the same player dialog. This covers attached links, detached `anchor.click()` and detached anchor click-event dispatch. The filename extension selects the supported MIME type when a library supplies `application/octet-stream`. There is no remote URL fetching or new iframe download permission. Blob URLs stay app-owned; revoke them after use. The app can observe `hackemist:download-result` events with `event.detail.status` (`requested`, `cancelled`, `expired`, `error`). This compatibility path does not change an app's own success messages. Explicit SDK integration is recommended because the returned Promise tracks the player choice. Data URL links, `window.open`, `window.print`, direct navigation, native file picker APIs, foreign URLs, object URLs created before SDK injection, URLs already revoked before activation and unsupported MIME types are outside this compatibility path. Standalone previews, publishing-check frames and native clients without a file-download bridge must expose a useful fallback; do not claim that local file export was verified there. The main browser player supports guests, signed-in sessions and interactive Studio previews, in opaque and isolated sandboxes.