@leumas/converter-web
The public converter microservice at converter.leumas.tech — every pure, offline Leumas adapter as a tool anyone can run without an account. The tool list, every form on it and the sitemap are all...
@leumas/converter-web — the converter at converter.leumas.tech
Every pure, offline Leumas adapter as a tool anyone can run — no account, nothing uploaded, nothing stored. Base64 and hashes, case conversion and slugs, JSON reshaping, markdown and CSV, image resizing, unit conversion, and one date rendered in twenty-five calendars.
The one thing to know
There is no tool list in this product. The page fetches GET /api/convert and builds the whole directory — and every form on it — from what comes back. A pack added to shared/engines/adapters/ that declares safe: true appears here on the next page load, with no change to this product and no redeploy of it.
That is only possible because a tool's schema is now its own. Until recently the adapter registry published the pack-level input list for every function of a system, so all eighty of a-text's verbs described themselves as taking {text} and nothing else. A catalogue built from that would have rendered eighty identical one-box forms, and Truncate would have had nowhere to put its length. See @leumas/schemas/adapter-spec for the tier order that fixed it.
Why a public lane exists at all
/api/adapters is behind requireAuth and PassNode metering. That is right for a surface that can shell out to ffmpeg and read files off the server — and it is why a public converter could not exist: every tool on it, including uppercase, needed an account.
/api/convert (shared/engines/middleware/src/adapters/convertRouter.js) is a second, narrower door onto the same registry. /api/adapters is untouched; nothing about this lane weakens it.
Three things make it safe, and each is load-bearing:
| An allowlist that defaults to closed | spec.safe is false unless a pack positively said otherwise, so every pack nobody has reviewed is absent by construction rather than by anyone remembering to exclude it. A denylist would have been wrong the first time somebody added a pack. |
untrusted: true on the call | The allowlist alone would not have made image safe: its image argument accepts a filesystem path, which is a convenience for an authenticated operator and an arbitrary-file-read for a visitor. normalizeInput refuses paths when this flag is set. |
| A body cap | These tools take their payload inline — an image arrives as base64 — so without a cap the cheapest denial of service is one request. |
A tool that is well described is not a tool that is safe: a-audio has a per-function metadata.json for all thirty-two of its tools and is the best-documented pack in the tree, and it is not on this lane. Conflating the two is how an allowlist built from "has a schema" would have opened ffmpeg to the internet.
Running it
pnpm --filter @leumas/converter-web dev # :5044, proxying /api to the API on :3000
pnpm --filter @leumas/converter-web build # -> dist/, which the site row serves
pnpm smoke:converter-site # the row AND the lane, offline
Never set VITE_API_BASE. Most of this site is anonymous, so the damage is subtler than on a signed-in surface: the converter would keep working while the signed-in half silently stopped. An absolute API origin makes every call cross-origin, which drops the httpOnly leumas_session cookie.
How the subdomain answers
A platform-owned Imperium site row — shared/services/index/src/converterSite.js — provisioned on every API boot. Read platformSite.js's header before changing it: the hosted-not-first-party lane, the deliberately empty ownerUserId, the non-pruning upsert and the static target are each a trap that has been hit once already, and none of them is visible from the file itself.
The edge needs nothing. IIS binds *.leumas.tech to the Imperium worker, converter is not in RESERVED_SUBDOMAINS, and createApiProxy already forwards /api — which /api/convert is inside — to leumas-api on every hosted host. Do not add /convert to PROXIED_PREFIXES to shorten the URL: that list applies to every host the worker serves, so claiming it globally would take the path away from every customer site on the platform.
Root-level filenames are shadowed
imperium-server mounts express.static over the apex leumas-web build before the target dispatcher, on every host. So favicon.ico, favicon-32.png, favicon-192.png, apple-touch-icon.png and logo.svg at this site's root are served from leumas.tech's copy instead. Nothing errors; the wrong logo simply appears in the tab. Every root-level file this product adds is namespaced converter-. Hashed /assets/* are safe.