One signing surface for both apps, and the white label finally paints

Featurekamo-signer-monorepo
Shipped
September 9, 2026 at 10:19 PM UTC
Author
Kamo
Commit
63f8e6c

The signing UI existed twice — here, and hand-copied into kamo-internal's legal execution wizard — and the two had drifted in both directions. `@kamo/esign-core`, `@kamo/esign-ui` and `@kamo/doc-render` are published packages now, built and pushed to the Forgejo registry by this repo's CI, and kamo-internal consumes them instead of its fork. The merge took the better half of each: kamo-internal's store (format validation, storage guarded on `localStorage` rather than on the DELEGATED and NOT_YET reasons). Components take their strings as PROPS — the two apps translate out of two different dictionaries, and a component that picks its own keys can only live in one. FOUR defects, and one of them caused two of the others: - **Every contained MUI button in this app was transparent.** `AppProviders` passed `enableCssLayer: true`, so all MUI CSS landed in `@layer mui` — and Tailwind's preflight, loaded unlayered by `@tailwind base`, beats layered CSS outright whatever the specificity. Measured: `.MuiButton-containedPrimary` computed `background-color: rgba(0,0,0,0)` with `color: rgba(0,0,0,0.87)`. So "Agree & continue" rendered as plain text, and "Cancel" and "Adopt & sign" sat next to each other as two runs of grey text reading as one sentence — which is exactly how it was reported. Preflight's `p { margin: 0 }` was beating the consent card's `mb` for the same reason, which is why everything on that page ran together. kamo-internal has always mounted its Emotion cache unlayered; matching it fixes all of it at once. - **The logo was a broken image.** `ThemeLogo` fell back to `/img/logo-full.svg`, which this app does not serve, and painted the browser's torn-page glyph in the sender's place. It now walks the extension list for BOTH variants (an org whose mark is a .png had `.svg` requested, 404ed, and stopped there — `sign-pink` is exactly that org), and when nothing resolves it draws the org's short name as a wordmark, or nothing at all before a token has named an organization. - **The favicon and the tab title were never set — nor was the org's brand CSS.** `DynamicMetaLoader` computed `const slug = orgSlug || getThemeSlug()` ONCE, in the effect body, before any token had been validated: `''`. The `KAMO_THEME_REAPPLY` listener, raised the moment the inviting org WAS known, re-ran a closure over that same `''` and returned at the guard. config.json was therefore never fetched on the signing route at all. Resolved per apply now, favicons REPLACE rather than append, and the title is "Sign - {Org Short Name}" as asked. Verified against a real tenant: `Sign - Sign Pink`, four org favicons, the .png mark, and `--color-primary: #452d4e` reaching the tabs, checkboxes and buttons — the MUI palette cannot hold a `var()`, so every brand-bearing component is pointed at it explicitly. - **The language picker was a globe over a list of endonyms**, so a signer who reads none of the Latin scripts had nothing to aim at. Flags and native names now, the same table and the same emoji font stack as kamo-internal's NavTop. It also appears on the welcome and consent screens: it used to arrive only with the TopBar, after the signer had already read an English disclosure. Downloads offer all three copies wherever one was offered: the executed document, the certificate of completion, or both zipped (`/api/sign/download?what=`). The certificate is the half of the record that attributes a signature to a person; handing over only the PDF hands over the half that proves nothing. The consent gate now carries the six clauses 15 U.S.C. § 7001(c) requires a consumer to be shown BEFORE consenting, and the locale it was rendered in rides out with the consent so the certificate can state which of the twenty-two translations was actually read.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing