feat: QR code scanning for gateway onboarding

iOS:
- QR scanner view using DataScannerViewController
- Photo library QR detection via CIDetector for saved QR images
- Deep link parser for openclaw://gateway URLs and base64url setup codes
- Onboarding wizard: full-screen welcome with "Scan QR Code" button,
  auto-connect on scan, back navigation, step indicators for manual flow

Backend:
- Add /pair qr action to device-pair extension for QR code generation
- TUI/WebUI differentiation: ASCII QR for TUI, markdown image for WebUI
- Telegram: send QR as media attachment via sendMessageTelegram
- Add data URI support to loadWebMedia for generic base64 media handling
- Export renderQrPngBase64 from plugin SDK for extension use

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
(cherry picked from commit d79ed65be0)
This commit is contained in:
Hongwei Ma
2026-02-14 21:47:33 +08:00
committed by Mariano Belinky
parent df6d0ee92b
commit 06adadc759
6 changed files with 238 additions and 1 deletions

View File

@@ -451,3 +451,6 @@ export type { ProcessedLineMessage } from "../line/markdown-to-line.js";
// Media utilities
export { loadWebMedia, type WebMediaResult } from "../web/media.js";
// QR code utilities
export { renderQrPngBase64 } from "../web/qr-image.js";

View File

@@ -273,6 +273,19 @@ async function loadWebMediaInternal(
};
};
// Handle data: URLs (base64-encoded inline data)
if (mediaUrl.startsWith("data:")) {
const match = mediaUrl.match(/^data:([^;,]+)?(?:;base64)?,(.*)$/);
if (!match) {
throw new Error("Invalid data: URL format");
}
const contentType = match[1] || "application/octet-stream";
const base64Data = match[2];
const buffer = Buffer.from(base64Data, "base64");
const kind = mediaKindFromMime(contentType);
return await clampAndFinalize({ buffer, contentType, kind });
}
if (/^https?:\/\//i.test(mediaUrl)) {
// Enforce a download cap during fetch to avoid unbounded memory usage.
// For optimized images, allow fetching larger payloads before compression.