poka.sh

Docs

poka-web HTTP API

reference

poka-web is the local web server in web/ (cd web && cargo run). It is a small standard-library HTTP/1.1 server that serves the web app and the same preview engine the desktop host uses. The deployed site at poka.sh is a static Cloudflare Worker with no server compute, so only the local server has POST /api/preview.

The server listens on 127.0.0.1:21220 unless POKA_WEB_ADDR says otherwise (see Environment variables and file locations). On start it prints the bound address and how many extensions it loaded.

Limits

Limit Value
Upload body (POST /api/preview) 256 MB; larger returns 413
Request line or one header 16 KiB; larger returns 431
Number of headers 100; more returns 431
Idle read or write on a connection 60 seconds
Result cache the last 64 results, in memory, keyed by file name and content hash

An unknown path returns 404 with the body not found.

Preview and catalogue

Method Path Returns
POST /api/preview?name=<filename> The preview of the bytes in the request body, as a PreviewResult (JSON). The main endpoint
POST /api/preview?src=<path> The preview of a file under the examples directory, in place. Local server only
GET /api/formats Every routed extension and file name, with its viewer and module id
GET /api/formats.json The full route table the engine uses: hashes, sizes and limits
GET /wasm/{id} The module's .wasm (application/wasm)
GET /wasm/{id}/{file} A named file from that module's directory: its .wasm or its plugin.json
GET /examples/{name} A file from the examples directory, for "try a sample" links

POST /api/preview

The body is the raw file bytes. The name query parameter (percent-encoded, default file.bin) decides which parser the file routes to, so it must include the extension. Identical name and bytes return the cached result without running a module.

src=<path> previews a file where it lies instead of from a temporary copy, so the module's /input directory is that file's real folder. Formats whose scene sits beside the file (a project file with an asset/ folder) need this. The path must stay inside the examples directory; every refusal gives the same message so a probe cannot tell "outside" from "missing". Results from src= are not cached.

The response is always 200 with JSON. Its type field is the variant of PreviewResult, one of:

type Meaning
Image Decoded raster bytes, with format, width and height
Svg Inline SVG markup in content
Pdf PDF bytes, drawn by the frontend
Html Viewer HTML in content, with optional facts and integrity notes
Text Plain text in content
Model A mesh to load: path, format, optional mtl
Dwg Structured CAD entities with bounds
Scene3D Meshes, materials, textures, cameras and lights with bounds
MultiView Several tabs, each a titled PreviewResult
NoExtension No module handles the file: file_ext, extension_id, size_mb, supported
AudioTranscode, VideoTranscode A transcoded temporary file to play, with a hint
NoAudioPlayback, NoVideoPlayback The media cannot be played, with a hint
ExtensionError The module failed: code, message, recoverable. A recoverable error is the parser's own warning rather than a verdict on the file: both frontends render it as a warning card (file-warning), not a failure
ServerError The host failed: message and kind

The type is defined once in core/poka-core/src/preview_types.rs, the shared engine crate both the desktop app and the local server use, so a field cannot be added to one host only.

In the browser engine a ServerError also says why. Its kind is load (a module would not download or is not a valid module), run (it ran and failed), output (it answered with something unreadable), timeout, too-large, routes (the format list would not load) or engine. Where they apply it adds stage (parser or viewer), extension (the module id), status (the HTTP status), offline, damaged, sizeMB and capMB, and limitMs. The server path sends only message.

GET /api/formats

A JSON array, sorted with extension rows first and then file-name rows:

[{"ext": "dwg", "viewer": "", "id": "poka-dwg"}, {"filename": "makefile", "viewer": "poka-code-viewer", "id": "poka-code"}]
  • ext is the extension without the dot; filename is an exact file name (a row has one or the other)
  • viewer is the composed viewer id, empty for a monolithic module
  • id is the module id; use it with /wasm/{id}

GET /api/formats.json

The route table both hosts install from. Each element describes one route:

Field Meaning
id The parser's module id
ext or filename What the route matches: an extension, or an exact lowercased file name
wasm, manifest Paths of the parser's .wasm and plugin.json under /wasm/
sha256, bytes Hash and size of the parser wasm, checked before it runs or is installed
memory_mb, max_time_ms The parser's declared limits
viewer The composed viewer id, empty for a monolithic module
viewer_wasm, viewer_manifest, viewer_sha256, viewer_bytes The same facts for the viewer; present only when there is one

A route's wasm may point into another module's directory when several routes share one binary. Every route is listed in the generated route table reference.

GET /wasm/{id} and GET /wasm/{id}/{file}

Serve a module binary or manifest. {file} is one path segment. A shared binary is found in the directory of the module that owns it, so /wasm/poka-m3u8/poka-code.wasm is served from poka-code/. A manifest is served only from its own module's directory. Unknown ids, unsafe names (anything with .. or a separator) and unregistered files return 404.

Pages and assets

The server also serves the web app itself, so cargo run matches the deployed site:

Path Content
/ The app
/app.js, /home.js, /version.js The page scripts
/version.json Which build is running
/preview-frame The sandboxed document that hosts viewer HTML
/embed The app with only the viewer, which the format pages under /docs frame (#503). The one page another page may frame, and only one of this origin. A built bundle has it; the local server does not
/docs, /50-50, /50-50.js, /50-50.json The help page and the 50+50 formats page
/engine.js, /engine-worker.js, /engine-core.js, /proto.js, /wasi.js, /routing.js, /content-sniff.js, /content-signatures.json The client-side preview engine
/js/* The desktop frontend scripts, served in place from desktop/src/js/
/favicon.ico The favicon

/50-50.json has a second reader: the start screen's surprise me button (web/src/home.js) fetches it when the button is reached, keeps only the samples marked cleared and opens one of them through /examples/<file> like a pasted link. It adds no route and nothing to the bundle.

The account page and its API passthrough exist on the local server too; they are not part of the preview API and are not described here.

The browser engine

The browser does not need POST /api/preview. It fetches the route table, downloads the parser and viewer wasm by id (with the first 16 hex digits of the route's SHA-256 in the URL as a cache key) and runs them in a Web Worker. The file never leaves the device. Appending ?server=1 to the app address uses POST /api/preview instead, so the two engines can be compared; node scripts/test-parity.mjs automates that comparison over the whole corpus.

URL preview

Pasting a public file URL into the app, or opening https://poka.sh/?url=<address>, fetches the file in the browser, so the server never fetches it. An address opened as ?url= in the page address is sent to the server with the page request. The address must end in a recognisable extension, the site must allow cross-origin requests, the file is capped at 256 MB, and only public addresses work. If the site blocks cross-origin requests, download the file and drop it on the page.