Optimize JSON and QR codes

- Replaced original JSON with minimized binary format (gzip + base64).
- Adjusted rendering and QR code generation for compatibility.
- Reduced payload size for improved efficiency.
This commit is contained in:
lockbitchat
2025-10-05 06:21:14 -04:00
parent ec04bebf22
commit d2830b9c46
8 changed files with 824 additions and 212 deletions

File diff suppressed because one or more lines are too long

353
dist/app.js vendored
View File

@@ -489,7 +489,7 @@ var EnhancedConnectionSetup = ({
}, "Creating a secure channel")
]),
// Step 1
React.createElement("div", {
!showAnswerStep && React.createElement("div", {
key: "step1",
className: "card-minimal rounded-xl p-6"
}, [
@@ -510,16 +510,16 @@ var EnhancedConnectionSetup = ({
key: "description",
className: "text-secondary text-sm mb-4"
}, "Creating cryptographically strong keys and codes to protect against attacks"),
React.createElement("button", {
!showOfferStep && React.createElement("button", {
key: "create-btn",
onClick: onCreateOffer,
disabled: connectionStatus === "connecting" || showOfferStep,
disabled: connectionStatus === "connecting",
className: `w-full btn-primary text-white py-3 px-4 rounded-lg font-medium transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed`
}, [
React.createElement("i", {
className: "fas fa-shield-alt mr-2"
}),
showOfferStep ? "Keys created \u2713" : "Create secure keys"
"Create secure keys"
]),
showOfferStep && React.createElement("div", {
key: "offer-result",
@@ -542,46 +542,29 @@ var EnhancedConnectionSetup = ({
key: "offer-data",
className: "space-y-3"
}, [
React.createElement("textarea", {
key: "textarea",
value: typeof offerData === "object" ? JSON.stringify(offerData, null, 2) : offerData,
readOnly: true,
rows: 8,
className: "w-full p-3 bg-custom-bg border border-gray-500/20 rounded-lg font-mono text-xs text-secondary resize-none custom-scrollbar"
}),
// Raw JSON hidden intentionally; users copy compressed string or use QR
React.createElement("div", {
key: "buttons",
className: "flex gap-2"
}, [
React.createElement(EnhancedCopyButton, {
key: "copy",
text: typeof offerData === "object" ? JSON.stringify(offerData, null, 2) : offerData,
className: "flex-1 px-3 py-2 bg-orange-500/10 hover:bg-orange-500/20 text-orange-400 border border-orange-500/20 rounded text-sm font-medium"
}, "Copy invitation code"),
React.createElement("button", {
key: "qr-toggle",
onClick: async () => {
const next = !showQRCode;
setShowQRCode(next);
if (next) {
try {
const payload = typeof offerData === "object" ? JSON.stringify(offerData) : offerData;
if (payload && payload.length) {
await generateQRCode(payload);
}
} catch (e2) {
console.warn("QR regenerate on toggle failed:", e2);
text: (() => {
try {
const min = typeof offerData === "object" ? JSON.stringify(offerData) : offerData || "";
if (typeof window.encodeBinaryToPrefixed === "function") {
return window.encodeBinaryToPrefixed(min);
}
if (typeof window.compressToPrefixedGzip === "function") {
return window.compressToPrefixedGzip(min);
}
return min;
} catch {
return typeof offerData === "object" ? JSON.stringify(offerData) : offerData || "";
}
},
className: "px-3 py-2 bg-blue-500/10 hover:bg-blue-500/20 text-blue-400 border border-blue-500/20 rounded text-sm font-medium transition-all duration-200"
}, [
React.createElement("i", {
key: "icon",
className: showQRCode ? "fas fa-eye-slash mr-1" : "fas fa-qrcode mr-1"
}),
showQRCode ? "Hide QR" : "Show QR"
])
})(),
className: "flex-1 px-3 py-2 bg-orange-500/10 hover:bg-orange-500/20 text-orange-400 border border-orange-500/20 rounded text-sm font-medium"
}, "Copy invitation code")
]),
showQRCode && qrCodeUrl && React.createElement("div", {
key: "qr-container",
@@ -785,8 +768,7 @@ var EnhancedConnectionSetup = ({
className: "text-xl font-semibold text-primary mb-2"
}, "Joining the secure channel")
]),
// Step 1
React.createElement("div", {
showAnswerStep ? null : React.createElement("div", {
key: "step1",
className: "card-minimal rounded-xl p-6"
}, [
@@ -934,16 +916,23 @@ var EnhancedConnectionSetup = ({
key: "answer-data",
className: "space-y-3 mb-4"
}, [
React.createElement("textarea", {
key: "textarea",
value: typeof answerData === "object" ? JSON.stringify(answerData, null, 2) : answerData,
readOnly: true,
rows: 6,
className: "w-full p-3 bg-custom-bg border border-green-500/20 rounded-lg font-mono text-xs text-secondary resize-none custom-scrollbar"
}),
// Raw JSON hidden intentionally; users copy compressed string or use QR
React.createElement(EnhancedCopyButton, {
key: "copy",
text: typeof answerData === "object" ? JSON.stringify(answerData, null, 2) : answerData,
text: (() => {
try {
const min = typeof answerData === "object" ? JSON.stringify(answerData) : answerData || "";
if (typeof window.encodeBinaryToPrefixed === "function") {
return window.encodeBinaryToPrefixed(min);
}
if (typeof window.compressToPrefixedGzip === "function") {
return window.compressToPrefixedGzip(min);
}
return min;
} catch {
return typeof answerData === "object" ? JSON.stringify(answerData) : answerData || "";
}
})(),
className: "w-full px-3 py-2 bg-green-500/10 hover:bg-green-500/20 text-green-400 border border-green-500/20 rounded text-sm font-medium"
}, "Copy response code")
]),
@@ -1823,6 +1812,7 @@ var EnhancedSecureP2PChat = () => {
return templateOffer;
};
const MAX_QR_LEN = 800;
const BIN_MAX_QR_LEN = 400;
const [qrFramesTotal, setQrFramesTotal] = React.useState(0);
const [qrFrameIndex, setQrFrameIndex] = React.useState(0);
const [qrManualMode, setQrManualMode] = React.useState(false);
@@ -1839,6 +1829,29 @@ var EnhancedSecureP2PChat = () => {
setQrFramesTotal(0);
setQrManualMode(false);
};
const renderCurrent = async () => {
const { chunks, idx } = qrAnimationRef.current || {};
if (!chunks || !chunks.length) return;
const current = chunks[idx % chunks.length];
try {
const isDesktop = typeof window !== "undefined" && (window.innerWidth || 0) >= 1024;
const QR_SIZE = isDesktop ? 720 : 512;
const url = await (window.generateQRCode ? window.generateQRCode(current, { errorCorrectionLevel: "M", margin: 2, size: QR_SIZE }) : Promise.resolve(""));
if (url) setQrCodeUrl(url);
} catch (e2) {
console.warn("Animated QR render error (current):", e2);
}
setQrFrameIndex((qrAnimationRef.current?.idx || 0) % (qrAnimationRef.current?.chunks?.length || 1) + 1);
};
const renderAndAdvance = async () => {
await renderCurrent();
const len = qrAnimationRef.current?.chunks?.length || 0;
if (len > 0) {
const nextIdx = ((qrAnimationRef.current?.idx || 0) + 1) % len;
qrAnimationRef.current.idx = nextIdx;
setQrFrameIndex(nextIdx + 1);
}
};
const toggleQrManualMode = () => {
const newManualMode = !qrManualMode;
setQrManualMode(newManualMode);
@@ -1849,39 +1862,65 @@ var EnhancedSecureP2PChat = () => {
}
console.log("QR Manual mode enabled - auto-scroll stopped");
} else {
if (qrAnimationRef.current.chunks.length > 1 && qrAnimationRef.current.active) {
const intervalMs = 4e3;
qrAnimationRef.current.timer = setInterval(renderNext, intervalMs);
if (qrAnimationRef.current.chunks.length > 1) {
const intervalMs = 3e3;
qrAnimationRef.current.active = true;
clearInterval(qrAnimationRef.current.timer);
qrAnimationRef.current.timer = setInterval(renderAndAdvance, intervalMs);
}
console.log("QR Manual mode disabled - auto-scroll resumed");
}
};
const nextQrFrame = () => {
const nextQrFrame = async () => {
console.log("\u{1F3AE} nextQrFrame called, qrFramesTotal:", qrFramesTotal, "qrAnimationRef.current:", qrAnimationRef.current);
if (qrAnimationRef.current.chunks.length > 1) {
const nextIdx = (qrAnimationRef.current.idx + 1) % qrAnimationRef.current.chunks.length;
qrAnimationRef.current.idx = nextIdx;
setQrFrameIndex(nextIdx + 1);
console.log("\u{1F3AE} Next frame index:", nextIdx + 1);
renderNext();
try {
clearInterval(qrAnimationRef.current.timer);
} catch {
}
qrAnimationRef.current.timer = null;
await renderCurrent();
if (!qrManualMode && qrAnimationRef.current.chunks.length > 1) {
const intervalMs = 3e3;
qrAnimationRef.current.active = true;
qrAnimationRef.current.timer = setInterval(renderAndAdvance, intervalMs);
} else {
qrAnimationRef.current.active = false;
}
} else {
console.log("\u{1F3AE} No multiple frames to navigate");
}
};
const prevQrFrame = () => {
const prevQrFrame = async () => {
console.log("\u{1F3AE} prevQrFrame called, qrFramesTotal:", qrFramesTotal, "qrAnimationRef.current:", qrAnimationRef.current);
if (qrAnimationRef.current.chunks.length > 1) {
const prevIdx = (qrAnimationRef.current.idx - 1 + qrAnimationRef.current.chunks.length) % qrAnimationRef.current.chunks.length;
qrAnimationRef.current.idx = prevIdx;
setQrFrameIndex(prevIdx + 1);
console.log("\u{1F3AE} Previous frame index:", prevIdx + 1);
renderNext();
try {
clearInterval(qrAnimationRef.current.timer);
} catch {
}
qrAnimationRef.current.timer = null;
await renderCurrent();
if (!qrManualMode && qrAnimationRef.current.chunks.length > 1) {
const intervalMs = 3e3;
qrAnimationRef.current.active = true;
qrAnimationRef.current.timer = setInterval(renderAndAdvance, intervalMs);
} else {
qrAnimationRef.current.active = false;
}
} else {
console.log("\u{1F3AE} No multiple frames to navigate");
}
};
const qrChunksBufferRef = React.useRef({ id: null, total: 0, seen: /* @__PURE__ */ new Set(), items: [] });
const generateQRCode2 = async (data) => {
const generateQRCode = async (data) => {
try {
const originalSize = typeof data === "string" ? data.length : JSON.stringify(data).length;
const payload = typeof data === "string" ? data : JSON.stringify(data);
@@ -1889,14 +1928,32 @@ var EnhancedSecureP2PChat = () => {
const QR_SIZE = isDesktop ? 720 : 512;
if (payload.length <= MAX_QR_LEN) {
if (!window.generateQRCode) throw new Error("QR code generator unavailable");
stopQrAnimation();
try {
if (qrAnimationRef.current && qrAnimationRef.current.timer) {
clearInterval(qrAnimationRef.current.timer);
}
} catch {
}
qrAnimationRef.current = { timer: null, chunks: [], idx: 0, active: false };
setQrFrameIndex(0);
setQrFramesTotal(0);
setQrManualMode(false);
const qrDataUrl = await window.generateQRCode(payload, { errorCorrectionLevel: "M", size: QR_SIZE, margin: 2 });
setQrCodeUrl(qrDataUrl);
setQrFramesTotal(1);
setQrFrameIndex(1);
return;
}
stopQrAnimation();
try {
if (qrAnimationRef.current && qrAnimationRef.current.timer) {
clearInterval(qrAnimationRef.current.timer);
}
} catch {
}
qrAnimationRef.current = { timer: null, chunks: [], idx: 0, active: false };
setQrFrameIndex(0);
setQrFramesTotal(0);
setQrManualMode(false);
const id = `raw_${Date.now()}_${Math.random().toString(36).slice(2)}`;
const TARGET_CHUNKS = 10;
const FRAME_MAX = Math.max(200, Math.floor(payload.length / TARGET_CHUNKS));
@@ -1921,26 +1978,11 @@ var EnhancedSecureP2PChat = () => {
setQrFramesTotal(rawChunks.length);
setQrFrameIndex(1);
const EC_OPTS = { errorCorrectionLevel: "M", margin: 2, size: QR_SIZE };
const renderNext2 = async () => {
const { chunks, idx, active } = qrAnimationRef.current;
if (!active || !chunks.length) return;
const current = chunks[idx % chunks.length];
try {
const url = await window.generateQRCode(current, EC_OPTS);
setQrCodeUrl(url);
} catch (e2) {
console.warn("Animated QR render error (raw):", e2);
}
const nextIdx = (idx + 1) % chunks.length;
qrAnimationRef.current.idx = nextIdx;
setQrFrameIndex(nextIdx + 1);
};
await renderNext2();
await renderNext();
if (!qrManualMode) {
const ua = typeof navigator !== "undefined" && navigator.userAgent ? navigator.userAgent : "";
const isIOS = /iPhone|iPad|iPod/i.test(ua);
const intervalMs = 4e3;
qrAnimationRef.current.timer = setInterval(renderNext2, intervalMs);
qrAnimationRef.current.active = true;
qrAnimationRef.current.timer = setInterval(renderAndAdvance, intervalMs);
}
return;
} catch (error) {
@@ -2018,7 +2060,18 @@ var EnhancedSecureP2PChat = () => {
};
const handleQRScan = async (scannedData) => {
try {
const parsedData = JSON.parse(scannedData);
let parsedData;
if (typeof window.decodeAnyPayload === "function") {
const any = window.decodeAnyPayload(scannedData);
if (typeof any === "string") {
parsedData = JSON.parse(any);
} else {
parsedData = any;
}
} else {
const maybeDecompressed = typeof window.decompressIfNeeded === "function" ? window.decompressIfNeeded(scannedData) : scannedData;
parsedData = JSON.parse(maybeDecompressed);
}
if (parsedData.hdr && parsedData.body) {
const { hdr } = parsedData;
if (!qrChunksBufferRef.current.id || qrChunksBufferRef.current.id !== hdr.id) {
@@ -2064,6 +2117,34 @@ var EnhancedSecureP2PChat = () => {
console.warn("RAW multi-frame reconstruction failed:", e2);
return Promise.resolve(false);
}
} else if (hdr.rt === "bin") {
try {
const parts = qrChunksBufferRef.current.items.map((s) => JSON.parse(s)).sort((a, b) => (a.hdr.seq || 0) - (b.hdr.seq || 0)).map((p) => p.body || "");
const fullText = parts.join("");
let payloadObj;
if (typeof window.decodeAnyPayload === "function") {
const any = window.decodeAnyPayload(fullText);
payloadObj = typeof any === "string" ? JSON.parse(any) : any;
} else {
payloadObj = JSON.parse(fullText);
}
if (showOfferStep) {
setAnswerInput(JSON.stringify(payloadObj, null, 2));
} else {
setOfferInput(JSON.stringify(payloadObj, null, 2));
}
setMessages((prev) => [...prev, { message: "All frames captured. BIN payload reconstructed.", type: "success" }]);
try {
document.dispatchEvent(new CustomEvent("qr-scan-complete", { detail: { id: hdr.id } }));
} catch {
}
qrChunksBufferRef.current = { id: null, total: 0, seen: /* @__PURE__ */ new Set(), items: [] };
setShowQRScannerModal(false);
return Promise.resolve(true);
} catch (e2) {
console.warn("BIN multi-frame reconstruction failed:", e2);
return Promise.resolve(false);
}
} else if (window.receiveAndProcess) {
try {
const results = await window.receiveAndProcess(qrChunksBufferRef.current.items);
@@ -2130,9 +2211,9 @@ var EnhancedSecureP2PChat = () => {
return false;
}
} else {
if (!parsedData.sdp) {
if (!parsedData.sdp && parsedData.type === "enhanced_secure_offer") {
setMessages((prev) => [...prev, {
message: "QR code contains compressed data (SDP removed). Please use copy/paste for full data.",
message: "Compressed QR may omit SDP for brevity. Use copy/paste if connection fails.",
type: "warning"
}]);
}
@@ -2174,7 +2255,50 @@ var EnhancedSecureP2PChat = () => {
setOfferData(offer);
setShowOfferStep(true);
const offerString = typeof offer === "object" ? JSON.stringify(offer) : offer;
await generateQRCode2(offerString);
try {
if (typeof window.encodeBinaryToPrefixed === "function") {
const bin = window.encodeBinaryToPrefixed(offerString);
const id = `bin_${Date.now()}_${Math.random().toString(36).slice(2)}`;
const TARGET_CHUNKS = 10;
let FRAME_MAX = Math.max(200, Math.floor(bin.length / TARGET_CHUNKS));
if (FRAME_MAX <= 0) FRAME_MAX = 200;
let total = Math.ceil(bin.length / FRAME_MAX);
if (total < 2) {
total = 2;
FRAME_MAX = Math.ceil(bin.length / 2) || 1;
}
const chunks = [];
for (let i = 0; i < total; i++) {
const seq = i + 1;
const part = bin.slice(i * FRAME_MAX, (i + 1) * FRAME_MAX);
chunks.push(JSON.stringify({ hdr: { v: 1, id, seq, total, rt: "bin" }, body: part }));
}
const isDesktop = typeof window !== "undefined" && (window.innerWidth || 0) >= 1024;
const QR_SIZE = isDesktop ? 720 : 512;
if (window.generateQRCode && chunks.length > 0) {
const firstUrl = await window.generateQRCode(chunks[0], { errorCorrectionLevel: "M", size: QR_SIZE, margin: 2 });
if (firstUrl) setQrCodeUrl(firstUrl);
}
try {
if (qrAnimationRef.current && qrAnimationRef.current.timer) {
clearInterval(qrAnimationRef.current.timer);
}
} catch {
}
qrAnimationRef.current = { timer: null, chunks, idx: 0, active: true };
setQrFramesTotal(chunks.length);
setQrFrameIndex(1);
setQrManualMode(false);
const intervalMs = 3e3;
qrAnimationRef.current.timer = setInterval(renderAndAdvance, intervalMs);
try {
setShowQRCode(true);
} catch {
}
}
} catch (e2) {
console.warn("Offer QR precompute failed:", e2);
}
const existingMessages = messages.filter(
(m) => m.type === "system" && (m.message.includes("Secure invitation created") || m.message.includes("Send the encrypted code"))
);
@@ -2224,7 +2348,13 @@ var EnhancedSecureP2PChat = () => {
}]);
let offer;
try {
offer = JSON.parse(offerInput.trim());
if (typeof window.decodeAnyPayload === "function") {
const any = window.decodeAnyPayload(offerInput.trim());
offer = typeof any === "string" ? JSON.parse(any) : any;
} else {
const rawText = typeof window.decompressIfNeeded === "function" ? window.decompressIfNeeded(offerInput.trim()) : offerInput.trim();
offer = JSON.parse(rawText);
}
} catch (parseError) {
throw new Error(`Invalid invitation format: ${parseError.message}`);
}
@@ -2239,7 +2369,62 @@ var EnhancedSecureP2PChat = () => {
setAnswerData(answer);
setShowAnswerStep(true);
const answerString = typeof answer === "object" ? JSON.stringify(answer) : answer;
await generateQRCode2(answerString);
try {
if (typeof window.encodeBinaryToPrefixed === "function") {
const bin = window.encodeBinaryToPrefixed(answerString);
const id = `ans_${Date.now()}_${Math.random().toString(36).slice(2)}`;
const TARGET_CHUNKS = 10;
let FRAME_MAX = Math.max(200, Math.floor(bin.length / TARGET_CHUNKS));
if (FRAME_MAX <= 0) FRAME_MAX = 200;
let total = Math.ceil(bin.length / FRAME_MAX);
if (total < 2) {
total = 2;
FRAME_MAX = Math.ceil(bin.length / 2) || 1;
}
const chunks = [];
for (let i = 0; i < total; i++) {
const seq = i + 1;
const part = bin.slice(i * FRAME_MAX, (i + 1) * FRAME_MAX);
chunks.push(JSON.stringify({ hdr: { v: 1, id, seq, total, rt: "bin" }, body: part }));
}
const isDesktop = typeof window !== "undefined" && (window.innerWidth || 0) >= 1024;
const QR_SIZE = isDesktop ? 720 : 512;
if (window.generateQRCode && chunks.length > 0) {
const firstUrl = await window.generateQRCode(chunks[0], { errorCorrectionLevel: "M", size: QR_SIZE, margin: 2 });
if (firstUrl) setQrCodeUrl(firstUrl);
}
try {
if (qrAnimationRef.current && qrAnimationRef.current.timer) {
clearInterval(qrAnimationRef.current.timer);
}
} catch {
}
qrAnimationRef.current = { timer: null, chunks, idx: 0, active: true };
setQrFramesTotal(chunks.length);
setQrFrameIndex(1);
setQrManualMode(false);
const intervalMs = 3e3;
qrAnimationRef.current.timer = setInterval(renderAndAdvance, intervalMs);
try {
setShowQRCode(true);
} catch {
}
} else {
let url = "";
if (typeof window.generateCompressedQRCode === "function") {
url = await window.generateCompressedQRCode(answerString);
} else {
url = await generateQRCode(answerString);
}
if (url) setQrCodeUrl(url);
try {
setShowQRCode(true);
} catch {
}
}
} catch (e2) {
console.warn("Answer QR generation failed:", e2);
}
if (e.target.value.trim().length > 0) {
if (typeof markAnswerCreated === "function") {
markAnswerCreated();
@@ -2304,7 +2489,13 @@ var EnhancedSecureP2PChat = () => {
}]);
let answer;
try {
answer = JSON.parse(answerInput.trim());
if (typeof window.decodeAnyPayload === "function") {
const anyAnswer = window.decodeAnyPayload(answerInput.trim());
answer = typeof anyAnswer === "string" ? JSON.parse(anyAnswer) : anyAnswer;
} else {
const rawText = typeof window.decompressIfNeeded === "function" ? window.decompressIfNeeded(answerInput.trim()) : answerInput.trim();
answer = JSON.parse(rawText);
}
} catch (parseError) {
throw new Error(`Invalid response format: ${parseError.message}`);
}

6
dist/app.js.map vendored

File diff suppressed because one or more lines are too long

141
dist/qr-local.js vendored
View File

@@ -860,7 +860,7 @@ var require_reed_solomon_encoder = __commonJS({
this.degree = degree;
this.genPoly = Polynomial.generateECPolynomial(this.degree);
};
ReedSolomonEncoder.prototype.encode = function encode2(data) {
ReedSolomonEncoder.prototype.encode = function encode3(data) {
if (!this.genPoly) {
throw new Error("Encoder not initialized");
}
@@ -27551,7 +27551,7 @@ var require_cbor = __commonJS({
(function(global2, undefined2) {
"use strict";
var POW_2_24 = Math.pow(2, -24), POW_2_32 = Math.pow(2, 32), POW_2_53 = Math.pow(2, 53);
function encode2(value) {
function encode3(value) {
var data = new ArrayBuffer(256);
var dataView = new DataView(data);
var lastLength;
@@ -27694,7 +27694,7 @@ var require_cbor = __commonJS({
retView.setUint8(i, dataView.getUint8(i));
return ret;
}
function decode2(data, tagger, simpleValue) {
function decode3(data, tagger, simpleValue) {
var dataView = new DataView(data);
var offset = 0;
if (typeof tagger !== "function")
@@ -27890,7 +27890,7 @@ var require_cbor = __commonJS({
throw "Remaining bytes";
return ret;
}
var obj = { encode: encode2, decode: decode2 };
var obj = { encode: encode3, decode: decode3 };
if (typeof define === "function" && define.amd)
define("cbor/cbor", obj);
else if (typeof module !== "undefined" && module.exports)
@@ -31900,9 +31900,6 @@ var Html5QrcodeScanner = (function() {
return Html5QrcodeScanner2;
})();
// src/crypto/cose-qr.js
var cbor = __toESM(require_cbor());
// node_modules/pako/dist/pako.esm.mjs
var Z_FIXED$1 = 4;
var Z_BINARY = 0;
@@ -36076,9 +36073,15 @@ var inflate_1$1 = {
var { Deflate, deflate, deflateRaw, gzip } = deflate_1$1;
var { Inflate, inflate, inflateRaw, ungzip } = inflate_1$1;
var deflate_1 = deflate;
var gzip_1 = gzip;
var inflate_1 = inflate;
var ungzip_1 = ungzip;
// src/scripts/qr-local.js
var cbor2 = __toESM(require_cbor());
// src/crypto/cose-qr.js
var cbor = __toESM(require_cbor());
var base64 = __toESM(require_base64_js());
function toBase64Url(uint8) {
let b64 = base64.fromByteArray(uint8);
@@ -36421,12 +36424,83 @@ window.packSecurePayload = packSecurePayload;
window.receiveAndProcess = receiveAndProcess;
// src/scripts/qr-local.js
var COMPRESSION_PREFIX = "SB1:gz:";
var BINARY_PREFIX = "SB1:bin:";
function uint8ToBase64(bytes) {
let binary = "";
const chunkSize = 32768;
for (let i = 0; i < bytes.length; i += chunkSize) {
const chunk = bytes.subarray(i, i + chunkSize);
binary += String.fromCharCode.apply(null, chunk);
}
return btoa(binary);
}
function base64ToUint8(b64) {
const binary = atob(b64);
const len = binary.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) bytes[i] = binary.charCodeAt(i);
return bytes;
}
function compressStringToBase64Gzip(text) {
const utf8 = new TextEncoder().encode(text);
const gz = gzip_1(utf8);
return uint8ToBase64(gz);
}
function decompressBase64GzipToString(b64) {
const gz = base64ToUint8(b64);
const out = ungzip_1(gz);
return new TextDecoder().decode(out);
}
async function generateQRCode(text, opts = {}) {
const size = opts.size || 512;
const margin = opts.margin ?? 2;
const errorCorrectionLevel = opts.errorCorrectionLevel || "M";
return await QRCode.toDataURL(text, { width: size, margin, errorCorrectionLevel });
}
async function generateCompressedQRCode(text, opts = {}) {
try {
const compressedB64 = compressStringToBase64Gzip(text);
const payload = COMPRESSION_PREFIX + compressedB64;
return await generateQRCode(payload, opts);
} catch (e) {
console.warn("generateCompressedQRCode failed, falling back to plain:", e?.message || e);
return await generateQRCode(text, opts);
}
}
function base64ToBase64Url(b64) {
return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
}
function base64UrlToBase64(b64url) {
let b64 = b64url.replace(/-/g, "+").replace(/_/g, "/");
const pad = b64.length % 4;
if (pad) b64 += "=".repeat(4 - pad);
return b64;
}
function encodeObjectToBinaryBase64Url(obj) {
const cborBytes = cbor2.encode(obj);
const compressed = deflate_1(new Uint8Array(cborBytes));
const b64 = uint8ToBase64(compressed);
return base64ToBase64Url(b64);
}
function decodeBinaryBase64UrlToObject(b64url) {
const b64 = base64UrlToBase64(b64url);
const compressed = base64ToUint8(b64);
const decompressed = inflate_1(compressed);
const ab = decompressed.buffer.slice(decompressed.byteOffset, decompressed.byteOffset + decompressed.byteLength);
return cbor2.decode(ab);
}
async function generateBinaryQRCodeFromObject(obj, opts = {}) {
try {
const b64url = encodeObjectToBinaryBase64Url(obj);
const payload = BINARY_PREFIX + b64url;
return await generateQRCode(payload, opts);
} catch (e) {
console.warn("generateBinaryQRCodeFromObject failed, falling back to JSON compressed:", e?.message || e);
const text = JSON.stringify(obj);
return await generateCompressedQRCode(text, opts);
}
}
async function generateCOSEQRCode(data, senderKey = null, recipientKey = null) {
try {
console.log("\u{1F510} Generating COSE-based QR code...");
@@ -36443,11 +36517,62 @@ async function generateCOSEQRCode(data, senderKey = null, recipientKey = null) {
}
}
window.generateQRCode = generateQRCode;
window.generateCompressedQRCode = generateCompressedQRCode;
window.generateBinaryQRCodeFromObject = generateBinaryQRCodeFromObject;
window.generateCOSEQRCode = generateCOSEQRCode;
window.Html5Qrcode = Html5Qrcode;
window.packSecurePayload = packSecurePayload;
window.receiveAndProcess = receiveAndProcess;
console.log("QR libraries loaded: generateQRCode, generateCOSEQRCode, Html5Qrcode, COSE functions");
window.decompressIfNeeded = function(scannedText) {
try {
if (typeof scannedText === "string" && scannedText.startsWith(COMPRESSION_PREFIX)) {
const b64 = scannedText.slice(COMPRESSION_PREFIX.length);
return decompressBase64GzipToString(b64);
}
} catch (e) {
console.warn("decompressIfNeeded failed:", e?.message || e);
}
return scannedText;
};
window.compressToPrefixedGzip = function(text) {
try {
const payload = String(text || "");
const compressedB64 = compressStringToBase64Gzip(payload);
return COMPRESSION_PREFIX + compressedB64;
} catch (e) {
console.warn("compressToPrefixedGzip failed:", e?.message || e);
return String(text || "");
}
};
window.encodeBinaryToPrefixed = function(objOrJson) {
try {
const obj = typeof objOrJson === "string" ? JSON.parse(objOrJson) : objOrJson;
const b64url = encodeObjectToBinaryBase64Url(obj);
return BINARY_PREFIX + b64url;
} catch (e) {
console.warn("encodeBinaryToPrefixed failed:", e?.message || e);
return typeof objOrJson === "string" ? objOrJson : JSON.stringify(objOrJson);
}
};
window.decodeAnyPayload = function(scannedText) {
try {
if (typeof scannedText === "string") {
if (scannedText.startsWith(BINARY_PREFIX)) {
const b64url = scannedText.slice(BINARY_PREFIX.length);
return decodeBinaryBase64UrlToObject(b64url);
}
if (scannedText.startsWith(COMPRESSION_PREFIX)) {
const s = window.decompressIfNeeded(scannedText);
return s;
}
return scannedText;
}
} catch (e) {
console.warn("decodeAnyPayload failed:", e?.message || e);
}
return scannedText;
};
console.log("QR libraries loaded: generateQRCode, generateCompressedQRCode, generateBinaryQRCodeFromObject, Html5Qrcode, COSE functions");
/*! Bundled license information:
pako/dist/pako.esm.mjs:

File diff suppressed because one or more lines are too long