← Book map

Chapter 12 · Synthesis

Nine tabs, one recipe

Validate, build a details object, wrap, sign, encode. If you can say that sentence with the right details class and flags, you can add a tab.

The nine tabs at a glance Each tab is a details class plus a set of flags; the pipeline underneath is identical. Update Identity → IdentityUpdate Service Signer → IdentityUpdate Authentication → Auth Invoice → VerusPayInvoice App Encryption → Auth + AppEncryption Data Packet → DataPacket User Data → UserData Attestation → DataPacket + MMR TX Signing → GeneralType Nine tabs, five distinct request primitives, one pipeline.

FIGURE 12.1 · The whole app in one grid.

The mental model

Every tab does the same four things: validate input, build a details object, wrap it in a GenericRequest, sign and encode. What differs is only which details object and which flags — and, in two cases, that more than one detail is needed.

A working sketch for a new tab

// routes/requests/myThing.ts
import { MyThingRequestDetails, MyThingRequestOrdinalVDXFObject } from "verus-typescript-primitives";
import { buildGenericRequestFromDetails, signRequest, getRpcConfig,
         requireString, parseRedirectsField } from "../utils";

export async function generateMyThingQr(req, res) {
  try {
    const signingId = requireString(req.body.signingId, "signingId");
    const redirects = parseRedirectsField(req.body.redirects);
    const { rpcHost, rpcPort, rpcUser, rpcPassword, isTestnet } = getRpcConfig();

    const details = new MyThingRequestDetails({ /* form fields */ });

    const request = buildGenericRequestFromDetails({
      details: [new MyThingRequestOrdinalVDXFObject({ data: details })],
      signed: true, signingId, redirects
    }, isTestnet);

    await signRequest({ request, rpcHost, rpcPort, rpcUser, rpcPassword, signingId });

    const deeplink = request.toWalletDeeplinkUri();
    res.json({ deeplink, qrDataUrl: await QRCode.toDataURL(deeplink) });
  } catch (e) {
    res.status(e.name === "ValidationError" ? 400 : 500).json({ error: e.message });
  }
}

Then mount it in server.ts and add a form view. That is genuinely the whole recipe; the rest of each route file is validation and the odd workaround.

The five lessons worth carrying

If you can describe a tab as "a details class plus flags, fed through two shared functions", you can build it in an afternoon.

Where to go next

the primitives book   → for the byte-level meaning of each details class
src/routes/utils.ts   → the shared pipeline, read end to end
__tests__/            → concrete expected outputs per tab
docs/                 → per-tab manual test notes and design plans