{
  "schema": "leumas.docs.page/1",
  "id": "pkg:@leumas/adapter-qr",
  "slug": "adapters/adapter-qr",
  "kind": "capabilities",
  "bucket": "package",
  "title": "qr (adapter system)",
  "name": "qr",
  "eyebrow": "adapter system",
  "chip": null,
  "summary": "QR adapter — payload building and styled vector rendering over @leumas/qr. Loaded by the adapter registry (POST /api/adapters/qr/<fn>), and doubles as a chatbot functioncall + MCP tool. Pure and...",
  "keywords": [
    "qr-code",
    "qrcode",
    "dynamic qr",
    "qr styling",
    "wifi",
    "vcard",
    "leumas qr"
  ],
  "audience": "both",
  "funnel": {
    "product": null,
    "cta": null
  },
  "body": "# qr (adapter system)\n\nQR codes end to end: build the payload string, then render it as a **styled vector code** with a\nreadability check that says when it will not scan.\n\nThin over **`@leumas/qr`**. The payload builders used to live in this file — ported from\n`leumas-middleware/lib/a.qr`, whose server, `public/` dashboard, `qrcodes.json` DB and redirect-app\ncoupling were all stripped. They moved into the package because the generator page, the HTTP export\nroute and this adapter all need them and a browser cannot import an adapter. This file imports the\nsame functions the SPA does, so there is exactly one definition of what a WIFI payload looks like.\n\n## Tools (`adapters`)\n\n| tool | args | result |\n|------|------|--------|\n| `types` | — | `{ types: [...] }` — twelve, from the engine, not a list written here |\n| `payload` | `{ type, ...fields }` | `{ type, payload }` — the string only, no image |\n| `styles` | — | `{ styles, vocabulary }` — the presets, each already checked, plus the closed sets a style may draw from |\n| `render` | `{ type, ...fields, qrOptions? }` | `{ type, payload, dataUrl, rendered, createdAt }` — **the unchanged legacy raster lane**; `dataUrl` is a PNG |\n| `renderStyled` | `{ type, ...fields } \\| { text }`, `style?`, `size?` | `{ payload, svg, dataUrl, style, warnings, scannable, matrix }` — `dataUrl` is an **SVG** URI |\n| `batch` | `{ items, style?, size?, limit? }` | `{ results, rendered, failed, unscannable }` |\n\n**`render` is deliberately unchanged.** The seeded chatbot functioncall `generate_qr` calls\n`qr.render` with `qrOptions` and expects a raster data-URL, so its contract is load-bearing. It still\ngoes through `qrcode.toDataURL` and still draws plain black squares. Everything about module shapes,\ngradients, styled eyes and logos is in `renderStyled`.\n\n`types` and `payload` now answer for twelve types instead of seven — additive, so no caller breaks.\n\n## The two fields worth reading\n\n- **`scannable`** — false when the style carries an error (too little contrast, an oversized logo).\n  `renderStyled` still returns the SVG, because blocking a preview somebody is mid-way through\n  choosing is worse than showing them what is wrong. **A save lane must check this.**\n- **`style`** — the *resolved* style, including repairs the engine made (a logo raises error\n  correction to `H`). Store this, not the input, or a re-render will not match what was printed.\n\n`batch` never fails wholesale: a thousand-row import with one malformed phone number returns 999\ncodes and one named failure. `unscannable` is counted separately from `failed`, because those rows\n*did* produce an image and a caller printing a sheet needs to know part of it will not read.\n\n## No sharp here\n\nPNG and PDF export live in the HTTP route (`/api/qr/export`), not in this adapter. The registry loads\nevery adapter at boot, so a native libvips binding imported here would be paid by every install\nincluding the ones that never render an image — and sharp has to be imported before `createApp()` to\nwork at all, which is a guarantee a route can make and an adapter cannot.\n",
  "source": {
    "path": "shared/engines/adapters/domain/qr/README.md",
    "blobSha": "",
    "commit": "",
    "committedAt": "",
    "provenance": "no-git",
    "bytes": 3244,
    "hash": "e389633783a57b464860ac751ccea97938a0f178"
  },
  "urls": {
    "html": "/p/adapters/adapter-qr",
    "json": "/docs/adapters/adapter-qr.json",
    "md": "/docs/adapters/adapter-qr.md"
  },
  "links": {
    "composes": [
      "pkg:@leumas/qr"
    ],
    "usedBy": [],
    "product": [],
    "howTo": [],
    "skills": []
  },
  "exports": null
}
