@vielzeug/sigil 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +40 -0
  2. package/dist/_dev.cjs +2 -0
  3. package/dist/_dev.cjs.map +1 -0
  4. package/dist/_dev.d.ts +2 -0
  5. package/dist/_dev.d.ts.map +1 -0
  6. package/dist/_dev.js +6 -0
  7. package/dist/_dev.js.map +1 -0
  8. package/dist/_format.cjs +2 -0
  9. package/dist/_format.cjs.map +1 -0
  10. package/dist/_format.d.ts +11 -0
  11. package/dist/_format.d.ts.map +1 -0
  12. package/dist/_format.js +37 -0
  13. package/dist/_format.js.map +1 -0
  14. package/dist/_galois.cjs +2 -0
  15. package/dist/_galois.cjs.map +1 -0
  16. package/dist/_galois.d.ts +13 -0
  17. package/dist/_galois.d.ts.map +1 -0
  18. package/dist/_galois.js +22 -0
  19. package/dist/_galois.js.map +1 -0
  20. package/dist/_mask.cjs +2 -0
  21. package/dist/_mask.cjs.map +1 -0
  22. package/dist/_mask.d.ts +14 -0
  23. package/dist/_mask.d.ts.map +1 -0
  24. package/dist/_mask.js +81 -0
  25. package/dist/_mask.js.map +1 -0
  26. package/dist/_matrix.cjs +2 -0
  27. package/dist/_matrix.cjs.map +1 -0
  28. package/dist/_matrix.d.ts +18 -0
  29. package/dist/_matrix.d.ts.map +1 -0
  30. package/dist/_matrix.js +65 -0
  31. package/dist/_matrix.js.map +1 -0
  32. package/dist/_reed-solomon.cjs +2 -0
  33. package/dist/_reed-solomon.cjs.map +1 -0
  34. package/dist/_reed-solomon.d.ts +3 -0
  35. package/dist/_reed-solomon.d.ts.map +1 -0
  36. package/dist/_reed-solomon.js +22 -0
  37. package/dist/_reed-solomon.js.map +1 -0
  38. package/dist/_segments.cjs +2 -0
  39. package/dist/_segments.cjs.map +1 -0
  40. package/dist/_segments.d.ts +32 -0
  41. package/dist/_segments.d.ts.map +1 -0
  42. package/dist/_segments.js +70 -0
  43. package/dist/_segments.js.map +1 -0
  44. package/dist/_tables.cjs +2 -0
  45. package/dist/_tables.cjs.map +1 -0
  46. package/dist/_tables.d.ts +46 -0
  47. package/dist/_tables.d.ts.map +1 -0
  48. package/dist/_tables.js +409 -0
  49. package/dist/_tables.js.map +1 -0
  50. package/dist/canvas.cjs +2 -0
  51. package/dist/canvas.cjs.map +1 -0
  52. package/dist/canvas.d.ts +9 -0
  53. package/dist/canvas.d.ts.map +1 -0
  54. package/dist/canvas.js +14 -0
  55. package/dist/canvas.js.map +1 -0
  56. package/dist/encode.cjs +2 -0
  57. package/dist/encode.cjs.map +1 -0
  58. package/dist/encode.d.ts +9 -0
  59. package/dist/encode.d.ts.map +1 -0
  60. package/dist/encode.js +112 -0
  61. package/dist/encode.js.map +1 -0
  62. package/dist/errors.cjs +2 -0
  63. package/dist/errors.cjs.map +1 -0
  64. package/dist/errors.d.ts +30 -0
  65. package/dist/errors.d.ts.map +1 -0
  66. package/dist/errors.js +17 -0
  67. package/dist/errors.js.map +1 -0
  68. package/dist/index.cjs +1 -0
  69. package/dist/index.d.ts +7 -0
  70. package/dist/index.d.ts.map +1 -0
  71. package/dist/index.js +6 -0
  72. package/dist/scan.cjs +2 -0
  73. package/dist/scan.cjs.map +1 -0
  74. package/dist/scan.d.ts +12 -0
  75. package/dist/scan.d.ts.map +1 -0
  76. package/dist/scan.js +141 -0
  77. package/dist/scan.js.map +1 -0
  78. package/dist/sigil.cjs +2 -0
  79. package/dist/sigil.cjs.map +1 -0
  80. package/dist/sigil.iife.js +2 -0
  81. package/dist/sigil.iife.js.map +1 -0
  82. package/dist/sigil.js +2 -0
  83. package/dist/sigil.js.map +1 -0
  84. package/dist/svg.cjs +2 -0
  85. package/dist/svg.cjs.map +1 -0
  86. package/dist/svg.d.ts +3 -0
  87. package/dist/svg.d.ts.map +1 -0
  88. package/dist/svg.js +26 -0
  89. package/dist/svg.js.map +1 -0
  90. package/dist/types.d.ts +118 -0
  91. package/dist/types.d.ts.map +1 -0
  92. package/package.json +48 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encode.cjs","names":[],"sources":["../src/encode.ts"],"sourcesContent":["import { warn } from './_dev';\nimport { drawFormatInfo, drawVersionInfo } from './_format';\nimport { applyMask, penaltyScore } from './_mask';\nimport { createGrid, drawFunctionPatterns, placeData } from './_matrix';\nimport { ecCodewords } from './_reed-solomon';\nimport { buildDataCodewords, detectMode, segmentBits } from './_segments';\nimport {\n ALPHANUMERIC_CHARSET,\n CHAR_COUNT_BITS,\n dataCodewords,\n ecCodewordsPerBlock,\n matrixSize,\n numEcBlocks,\n totalCodewords,\n versionGroup,\n} from './_tables';\nimport { SigilCapacityError, SigilOptionError } from './errors';\nimport type { QrEncodeOptions, QrErrorCorrection, QrMatrix, QrMode } from './types';\n\nconst MAX_VERSION = 40;\n\nfunction checkOptions(options: QrEncodeOptions): void {\n const { version, minVersion, mask, errorCorrection } = options;\n const inRange = (v: number) => Number.isInteger(v) && v >= 1 && v <= MAX_VERSION;\n if (version !== undefined && !inRange(version))\n throw new SigilOptionError(`version must be an integer 1–${MAX_VERSION}, got ${version}`);\n if (minVersion !== undefined && !inRange(minVersion))\n throw new SigilOptionError(`minVersion must be an integer 1–${MAX_VERSION}, got ${minVersion}`);\n if (version !== undefined && minVersion !== undefined && minVersion > version)\n throw new SigilOptionError(`minVersion (${minVersion}) exceeds version (${version})`);\n if (mask !== undefined && (!Number.isInteger(mask) || mask < 0 || mask > 7))\n throw new SigilOptionError(`mask must be an integer 0–7, got ${mask}`);\n if (errorCorrection !== undefined && !'LMQH'.includes(errorCorrection))\n throw new SigilOptionError(`errorCorrection must be 'L', 'M', 'Q', or 'H'`);\n}\n\n/** Character capacity of (version, level, mode) — the `qrCapacity` core. */\nfunction capacityFor(version: number, level: QrErrorCorrection, mode: QrMode): number {\n const countBits = CHAR_COUNT_BITS[mode][versionGroup(version)];\n const usable = dataCodewords(version, level) * 8 - 4 - countBits;\n if (usable <= 0) return 0;\n switch (mode) {\n case 'numeric':\n return Math.floor(usable / 10) * 3 + (usable % 10 >= 7 ? 2 : usable % 10 >= 4 ? 1 : 0);\n case 'alphanumeric':\n return Math.floor(usable / 11) * 2 + (usable % 11 >= 6 ? 1 : 0);\n case 'byte':\n return Math.floor(usable / 8);\n }\n}\n\n/** Smallest version ≥ minVersion whose data area fits the segment. */\nfunction pickVersion(data: string, mode: QrMode, level: QrErrorCorrection, minVersion: number): number {\n for (let v = minVersion; v <= MAX_VERSION; v++)\n if (segmentBits(data, mode, v) <= dataCodewords(v, level) * 8) return v;\n // Nothing fits — the caller reports against v40.\n return -1;\n}\n\n/** Split data codewords into EC blocks and interleave data + EC (§7.6). */\nfunction interleaveBlocks(data: readonly number[], version: number, level: QrErrorCorrection): number[] {\n const numBlocks = numEcBlocks(version, level);\n const ecLen = ecCodewordsPerBlock(version, level);\n const rawLen = totalCodewords(version);\n const shortLen = Math.floor(rawLen / numBlocks) - ecLen; // data codewords in a short block\n const numLong = rawLen % numBlocks; // long blocks carry one extra data codeword\n\n const blocks: number[][] = [];\n let offset = 0;\n for (let b = 0; b < numBlocks; b++) {\n const isLong = b >= numBlocks - numLong;\n const dat = data.slice(offset, offset + shortLen + (isLong ? 1 : 0));\n offset += dat.length;\n const ecc = ecCodewords(dat, ecLen);\n // Short blocks get a pad slot so every block array shares one length;\n // the slot is skipped during interleave below.\n blocks.push(isLong ? [...dat, ...ecc] : [...dat, 0, ...ecc]);\n }\n\n const out: number[] = [];\n for (let i = 0; i < blocks[0].length; i++)\n for (let b = 0; b < numBlocks; b++) {\n // Skip the pad slot on short blocks (index = shortLen).\n if (i !== shortLen || b >= numBlocks - numLong) out.push(blocks[b][i]);\n }\n return out;\n}\n\nfunction freezeMatrix(grid: readonly (readonly boolean[])[], meta: Omit<QrMatrix, 'modules' | 'get'>): QrMatrix {\n const modules = grid.map((row) => Object.freeze([...row]));\n Object.freeze(modules);\n return Object.freeze({\n ...meta,\n get: (x: number, y: number) => (x >= 0 && y >= 0 && x < meta.size && y < meta.size ? modules[y][x] : false),\n modules,\n });\n}\n\n/**\n * Encode `data` into a QR Model 2 symbol. Pure and synchronous.\n * Byte mode is UTF-8 without an ECI header — the industry-standard assumption.\n */\nexport function encodeQr(data: string | Uint8Array, options: QrEncodeOptions = {}): QrMatrix {\n checkOptions(options);\n const text = typeof data === 'string' ? data : new TextDecoder().decode(data);\n if (text.length === 0) throw new SigilOptionError('Cannot encode an empty input');\n\n const level = options.errorCorrection ?? 'M';\n const mode = options.mode ?? detectMode(text);\n if (mode !== 'byte' && detectMode(text) !== mode && !isModeCompatible(text, mode))\n throw new SigilOptionError(`Input cannot be encoded in ${mode} mode`);\n\n const version = options.version ?? pickVersion(text, mode, level, options.minVersion ?? 1);\n if (version === -1 || segmentBits(text, mode, version) > dataCodewords(version, level) * 8) {\n const bytes = new TextEncoder().encode(text).length;\n const max = capacityFor(options.version ?? MAX_VERSION, level, mode);\n throw new SigilCapacityError(\n `Input of ${bytes} bytes exceeds QR capacity (${max} ${mode === 'byte' ? 'bytes' : 'chars'} ` +\n `at version ${options.version ?? MAX_VERSION}-${level})`,\n bytes,\n max,\n options.version ?? MAX_VERSION,\n );\n }\n\n const used = segmentBits(text, mode, version);\n const capacity = dataCodewords(version, level) * 8;\n if (used / capacity > 0.9 && options.version === undefined)\n warn(\n `Payload uses ${Math.round((used / capacity) * 100)}% of version ${version}-${level} ` +\n `capacity; a slightly longer input will bump the QR size`,\n );\n\n const codewords = interleaveBlocks(buildDataCodewords(text, mode, version, level), version, level);\n const grid = createGrid(matrixSize(version));\n drawFunctionPatterns(grid, version);\n placeData(grid, codewords);\n\n // Try every mask (or the forced one), keep the lowest penalty.\n const candidates = options.mask !== undefined ? [options.mask] : [0, 1, 2, 3, 4, 5, 6, 7];\n let bestMask = candidates[0];\n let bestScore = Number.POSITIVE_INFINITY;\n let bestModules: boolean[][] | null = null;\n for (const m of candidates) {\n applyMask(grid, m);\n drawFormatInfo(grid, level, m);\n const score = penaltyScore(grid);\n if (score < bestScore) {\n bestScore = score;\n bestMask = m;\n bestModules = grid.modules.map((row) => [...row]);\n }\n applyMask(grid, m); // undo\n // Clear format info for the next candidate (function flags stay set).\n if (m !== candidates[candidates.length - 1]) clearFormat(grid);\n }\n\n grid.modules = bestModules as boolean[][];\n drawVersionInfo(grid, version);\n\n return freezeMatrix(grid.modules, {\n errorCorrection: level,\n mask: bestMask,\n mode,\n size: grid.size,\n version,\n });\n}\n\n/** Whether `text` is representable in `mode` (used when the mode is forced). */\nfunction isModeCompatible(text: string, mode: QrMode): boolean {\n if (mode === 'numeric') return /^\\d+$/.test(text);\n if (mode === 'alphanumeric') return [...text].every((ch) => ALPHANUMERIC_CHARSET.includes(ch));\n return true;\n}\n\n/** Un-mark and un-draw format modules so the next mask candidate starts clean. */\nfunction clearFormat(grid: ReturnType<typeof createGrid>): void {\n const size = grid.size;\n const cells: Array<readonly [number, number]> = [];\n for (let i = 0; i <= 8; i++) {\n if (i !== 6) {\n cells.push([8, i], [i, 8]);\n }\n }\n for (let i = 0; i < 8; i++) cells.push([size - 1 - i, 8]);\n for (let i = 0; i < 7; i++) cells.push([8, size - 1 - i]);\n cells.push([8, size - 8]);\n for (const [x, y] of cells) grid.modules[y][x] = false;\n}\n\n/** Max characters/bytes encodable at (version, level, mode). */\nexport function qrCapacity(version: number, errorCorrection: QrErrorCorrection, mode: QrMode): number {\n if (!Number.isInteger(version) || version < 1 || version > MAX_VERSION)\n throw new SigilOptionError(`version must be an integer 1–${MAX_VERSION}, got ${version}`);\n return capacityFor(version, errorCorrection, mode);\n}\n"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { QrEncodeOptions, QrErrorCorrection, QrMatrix, QrMode } from './types';
2
+ /**
3
+ * Encode `data` into a QR Model 2 symbol. Pure and synchronous.
4
+ * Byte mode is UTF-8 without an ECI header — the industry-standard assumption.
5
+ */
6
+ export declare function encodeQr(data: string | Uint8Array, options?: QrEncodeOptions): QrMatrix;
7
+ /** Max characters/bytes encodable at (version, level, mode). */
8
+ export declare function qrCapacity(version: number, errorCorrection: QrErrorCorrection, mode: QrMode): number;
9
+ //# sourceMappingURL=encode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encode.d.ts","sourceRoot":"","sources":["../src/encode.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAiFpF;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,OAAO,GAAE,eAAoB,GAAG,QAAQ,CAiE3F;AAwBD,gEAAgE;AAChE,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAIpG"}
package/dist/encode.js ADDED
@@ -0,0 +1,112 @@
1
+ import "./_dev.js";
2
+ import { ALPHANUMERIC_CHARSET as e, CHAR_COUNT_BITS as t, dataCodewords as n, ecCodewordsPerBlock as r, matrixSize as i, numEcBlocks as a, totalCodewords as o, versionGroup as s } from "./_tables.js";
3
+ import { drawFormatInfo as c, drawVersionInfo as l } from "./_format.js";
4
+ import { applyMask as u, penaltyScore as d } from "./_mask.js";
5
+ import { createGrid as f, drawFunctionPatterns as p, placeData as m } from "./_matrix.js";
6
+ import { ecCodewords as h } from "./_reed-solomon.js";
7
+ import { buildDataCodewords as g, detectMode as _, segmentBits as v } from "./_segments.js";
8
+ import { SigilCapacityError as y, SigilOptionError as b } from "./errors.js";
9
+ //#region src/encode.ts
10
+ var x = 40;
11
+ function S(e) {
12
+ let { version: t, minVersion: n, mask: r, errorCorrection: i } = e, a = (e) => Number.isInteger(e) && e >= 1 && e <= x;
13
+ if (t !== void 0 && !a(t)) throw new b(`version must be an integer 1–${x}, got ${t}`);
14
+ if (n !== void 0 && !a(n)) throw new b(`minVersion must be an integer 1–${x}, got ${n}`);
15
+ if (t !== void 0 && n !== void 0 && n > t) throw new b(`minVersion (${n}) exceeds version (${t})`);
16
+ if (r !== void 0 && (!Number.isInteger(r) || r < 0 || r > 7)) throw new b(`mask must be an integer 0–7, got ${r}`);
17
+ if (i !== void 0 && !"LMQH".includes(i)) throw new b("errorCorrection must be 'L', 'M', 'Q', or 'H'");
18
+ }
19
+ function C(e, r, i) {
20
+ let a = t[i][s(e)], o = n(e, r) * 8 - 4 - a;
21
+ if (o <= 0) return 0;
22
+ switch (i) {
23
+ case "numeric": return Math.floor(o / 10) * 3 + (o % 10 >= 7 ? 2 : +(o % 10 >= 4));
24
+ case "alphanumeric": return Math.floor(o / 11) * 2 + +(o % 11 >= 6);
25
+ case "byte": return Math.floor(o / 8);
26
+ }
27
+ }
28
+ function w(e, t, r, i) {
29
+ for (let a = i; a <= x; a++) if (v(e, t, a) <= n(a, r) * 8) return a;
30
+ return -1;
31
+ }
32
+ function T(e, t, n) {
33
+ let i = a(t, n), s = r(t, n), c = o(t), l = Math.floor(c / i) - s, u = c % i, d = [], f = 0;
34
+ for (let t = 0; t < i; t++) {
35
+ let n = t >= i - u, r = e.slice(f, f + l + +!!n);
36
+ f += r.length;
37
+ let a = h(r, s);
38
+ d.push(n ? [...r, ...a] : [
39
+ ...r,
40
+ 0,
41
+ ...a
42
+ ]);
43
+ }
44
+ let p = [];
45
+ for (let e = 0; e < d[0].length; e++) for (let t = 0; t < i; t++) (e !== l || t >= i - u) && p.push(d[t][e]);
46
+ return p;
47
+ }
48
+ function E(e, t) {
49
+ let n = e.map((e) => Object.freeze([...e]));
50
+ return Object.freeze(n), Object.freeze({
51
+ ...t,
52
+ get: (e, r) => e >= 0 && r >= 0 && e < t.size && r < t.size && n[r][e],
53
+ modules: n
54
+ });
55
+ }
56
+ function D(e, t = {}) {
57
+ S(t);
58
+ let r = typeof e == "string" ? e : new TextDecoder().decode(e);
59
+ if (r.length === 0) throw new b("Cannot encode an empty input");
60
+ let a = t.errorCorrection ?? "M", o = t.mode ?? _(r);
61
+ if (o !== "byte" && _(r) !== o && !O(r, o)) throw new b(`Input cannot be encoded in ${o} mode`);
62
+ let s = t.version ?? w(r, o, a, t.minVersion ?? 1);
63
+ if (s === -1 || v(r, o, s) > n(s, a) * 8) {
64
+ let e = new TextEncoder().encode(r).length, n = C(t.version ?? x, a, o);
65
+ throw new y(`Input of ${e} bytes exceeds QR capacity (${n} ${o === "byte" ? "bytes" : "chars"} at version ${t.version ?? x}-${a})`, e, n, t.version ?? x);
66
+ }
67
+ let h = v(r, o, s), D = n(s, a) * 8;
68
+ h / D > .9 && t.version === void 0 && `${Math.round(h / D * 100)}${s}${a}`;
69
+ let A = T(g(r, o, s, a), s, a), j = f(i(s));
70
+ p(j, s), m(j, A);
71
+ let M = t.mask === void 0 ? [
72
+ 0,
73
+ 1,
74
+ 2,
75
+ 3,
76
+ 4,
77
+ 5,
78
+ 6,
79
+ 7
80
+ ] : [t.mask], N = M[0], P = Infinity, F = null;
81
+ for (let e of M) {
82
+ u(j, e), c(j, a, e);
83
+ let t = d(j);
84
+ t < P && (P = t, N = e, F = j.modules.map((e) => [...e])), u(j, e), e !== M[M.length - 1] && k(j);
85
+ }
86
+ return j.modules = F, l(j, s), E(j.modules, {
87
+ errorCorrection: a,
88
+ mask: N,
89
+ mode: o,
90
+ size: j.size,
91
+ version: s
92
+ });
93
+ }
94
+ function O(t, n) {
95
+ return n === "numeric" ? /^\d+$/.test(t) : n !== "alphanumeric" || [...t].every((t) => e.includes(t));
96
+ }
97
+ function k(e) {
98
+ let t = e.size, n = [];
99
+ for (let e = 0; e <= 8; e++) e !== 6 && n.push([8, e], [e, 8]);
100
+ for (let e = 0; e < 8; e++) n.push([t - 1 - e, 8]);
101
+ for (let e = 0; e < 7; e++) n.push([8, t - 1 - e]);
102
+ n.push([8, t - 8]);
103
+ for (let [t, r] of n) e.modules[r][t] = !1;
104
+ }
105
+ function A(e, t, n) {
106
+ if (!Number.isInteger(e) || e < 1 || e > x) throw new b(`version must be an integer 1–${x}, got ${e}`);
107
+ return C(e, t, n);
108
+ }
109
+ //#endregion
110
+ export { D as encodeQr, A as qrCapacity };
111
+
112
+ //# sourceMappingURL=encode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encode.js","names":[],"sources":["../src/encode.ts"],"sourcesContent":["import { warn } from './_dev';\nimport { drawFormatInfo, drawVersionInfo } from './_format';\nimport { applyMask, penaltyScore } from './_mask';\nimport { createGrid, drawFunctionPatterns, placeData } from './_matrix';\nimport { ecCodewords } from './_reed-solomon';\nimport { buildDataCodewords, detectMode, segmentBits } from './_segments';\nimport {\n ALPHANUMERIC_CHARSET,\n CHAR_COUNT_BITS,\n dataCodewords,\n ecCodewordsPerBlock,\n matrixSize,\n numEcBlocks,\n totalCodewords,\n versionGroup,\n} from './_tables';\nimport { SigilCapacityError, SigilOptionError } from './errors';\nimport type { QrEncodeOptions, QrErrorCorrection, QrMatrix, QrMode } from './types';\n\nconst MAX_VERSION = 40;\n\nfunction checkOptions(options: QrEncodeOptions): void {\n const { version, minVersion, mask, errorCorrection } = options;\n const inRange = (v: number) => Number.isInteger(v) && v >= 1 && v <= MAX_VERSION;\n if (version !== undefined && !inRange(version))\n throw new SigilOptionError(`version must be an integer 1–${MAX_VERSION}, got ${version}`);\n if (minVersion !== undefined && !inRange(minVersion))\n throw new SigilOptionError(`minVersion must be an integer 1–${MAX_VERSION}, got ${minVersion}`);\n if (version !== undefined && minVersion !== undefined && minVersion > version)\n throw new SigilOptionError(`minVersion (${minVersion}) exceeds version (${version})`);\n if (mask !== undefined && (!Number.isInteger(mask) || mask < 0 || mask > 7))\n throw new SigilOptionError(`mask must be an integer 0–7, got ${mask}`);\n if (errorCorrection !== undefined && !'LMQH'.includes(errorCorrection))\n throw new SigilOptionError(`errorCorrection must be 'L', 'M', 'Q', or 'H'`);\n}\n\n/** Character capacity of (version, level, mode) — the `qrCapacity` core. */\nfunction capacityFor(version: number, level: QrErrorCorrection, mode: QrMode): number {\n const countBits = CHAR_COUNT_BITS[mode][versionGroup(version)];\n const usable = dataCodewords(version, level) * 8 - 4 - countBits;\n if (usable <= 0) return 0;\n switch (mode) {\n case 'numeric':\n return Math.floor(usable / 10) * 3 + (usable % 10 >= 7 ? 2 : usable % 10 >= 4 ? 1 : 0);\n case 'alphanumeric':\n return Math.floor(usable / 11) * 2 + (usable % 11 >= 6 ? 1 : 0);\n case 'byte':\n return Math.floor(usable / 8);\n }\n}\n\n/** Smallest version ≥ minVersion whose data area fits the segment. */\nfunction pickVersion(data: string, mode: QrMode, level: QrErrorCorrection, minVersion: number): number {\n for (let v = minVersion; v <= MAX_VERSION; v++)\n if (segmentBits(data, mode, v) <= dataCodewords(v, level) * 8) return v;\n // Nothing fits — the caller reports against v40.\n return -1;\n}\n\n/** Split data codewords into EC blocks and interleave data + EC (§7.6). */\nfunction interleaveBlocks(data: readonly number[], version: number, level: QrErrorCorrection): number[] {\n const numBlocks = numEcBlocks(version, level);\n const ecLen = ecCodewordsPerBlock(version, level);\n const rawLen = totalCodewords(version);\n const shortLen = Math.floor(rawLen / numBlocks) - ecLen; // data codewords in a short block\n const numLong = rawLen % numBlocks; // long blocks carry one extra data codeword\n\n const blocks: number[][] = [];\n let offset = 0;\n for (let b = 0; b < numBlocks; b++) {\n const isLong = b >= numBlocks - numLong;\n const dat = data.slice(offset, offset + shortLen + (isLong ? 1 : 0));\n offset += dat.length;\n const ecc = ecCodewords(dat, ecLen);\n // Short blocks get a pad slot so every block array shares one length;\n // the slot is skipped during interleave below.\n blocks.push(isLong ? [...dat, ...ecc] : [...dat, 0, ...ecc]);\n }\n\n const out: number[] = [];\n for (let i = 0; i < blocks[0].length; i++)\n for (let b = 0; b < numBlocks; b++) {\n // Skip the pad slot on short blocks (index = shortLen).\n if (i !== shortLen || b >= numBlocks - numLong) out.push(blocks[b][i]);\n }\n return out;\n}\n\nfunction freezeMatrix(grid: readonly (readonly boolean[])[], meta: Omit<QrMatrix, 'modules' | 'get'>): QrMatrix {\n const modules = grid.map((row) => Object.freeze([...row]));\n Object.freeze(modules);\n return Object.freeze({\n ...meta,\n get: (x: number, y: number) => (x >= 0 && y >= 0 && x < meta.size && y < meta.size ? modules[y][x] : false),\n modules,\n });\n}\n\n/**\n * Encode `data` into a QR Model 2 symbol. Pure and synchronous.\n * Byte mode is UTF-8 without an ECI header — the industry-standard assumption.\n */\nexport function encodeQr(data: string | Uint8Array, options: QrEncodeOptions = {}): QrMatrix {\n checkOptions(options);\n const text = typeof data === 'string' ? data : new TextDecoder().decode(data);\n if (text.length === 0) throw new SigilOptionError('Cannot encode an empty input');\n\n const level = options.errorCorrection ?? 'M';\n const mode = options.mode ?? detectMode(text);\n if (mode !== 'byte' && detectMode(text) !== mode && !isModeCompatible(text, mode))\n throw new SigilOptionError(`Input cannot be encoded in ${mode} mode`);\n\n const version = options.version ?? pickVersion(text, mode, level, options.minVersion ?? 1);\n if (version === -1 || segmentBits(text, mode, version) > dataCodewords(version, level) * 8) {\n const bytes = new TextEncoder().encode(text).length;\n const max = capacityFor(options.version ?? MAX_VERSION, level, mode);\n throw new SigilCapacityError(\n `Input of ${bytes} bytes exceeds QR capacity (${max} ${mode === 'byte' ? 'bytes' : 'chars'} ` +\n `at version ${options.version ?? MAX_VERSION}-${level})`,\n bytes,\n max,\n options.version ?? MAX_VERSION,\n );\n }\n\n const used = segmentBits(text, mode, version);\n const capacity = dataCodewords(version, level) * 8;\n if (used / capacity > 0.9 && options.version === undefined)\n warn(\n `Payload uses ${Math.round((used / capacity) * 100)}% of version ${version}-${level} ` +\n `capacity; a slightly longer input will bump the QR size`,\n );\n\n const codewords = interleaveBlocks(buildDataCodewords(text, mode, version, level), version, level);\n const grid = createGrid(matrixSize(version));\n drawFunctionPatterns(grid, version);\n placeData(grid, codewords);\n\n // Try every mask (or the forced one), keep the lowest penalty.\n const candidates = options.mask !== undefined ? [options.mask] : [0, 1, 2, 3, 4, 5, 6, 7];\n let bestMask = candidates[0];\n let bestScore = Number.POSITIVE_INFINITY;\n let bestModules: boolean[][] | null = null;\n for (const m of candidates) {\n applyMask(grid, m);\n drawFormatInfo(grid, level, m);\n const score = penaltyScore(grid);\n if (score < bestScore) {\n bestScore = score;\n bestMask = m;\n bestModules = grid.modules.map((row) => [...row]);\n }\n applyMask(grid, m); // undo\n // Clear format info for the next candidate (function flags stay set).\n if (m !== candidates[candidates.length - 1]) clearFormat(grid);\n }\n\n grid.modules = bestModules as boolean[][];\n drawVersionInfo(grid, version);\n\n return freezeMatrix(grid.modules, {\n errorCorrection: level,\n mask: bestMask,\n mode,\n size: grid.size,\n version,\n });\n}\n\n/** Whether `text` is representable in `mode` (used when the mode is forced). */\nfunction isModeCompatible(text: string, mode: QrMode): boolean {\n if (mode === 'numeric') return /^\\d+$/.test(text);\n if (mode === 'alphanumeric') return [...text].every((ch) => ALPHANUMERIC_CHARSET.includes(ch));\n return true;\n}\n\n/** Un-mark and un-draw format modules so the next mask candidate starts clean. */\nfunction clearFormat(grid: ReturnType<typeof createGrid>): void {\n const size = grid.size;\n const cells: Array<readonly [number, number]> = [];\n for (let i = 0; i <= 8; i++) {\n if (i !== 6) {\n cells.push([8, i], [i, 8]);\n }\n }\n for (let i = 0; i < 8; i++) cells.push([size - 1 - i, 8]);\n for (let i = 0; i < 7; i++) cells.push([8, size - 1 - i]);\n cells.push([8, size - 8]);\n for (const [x, y] of cells) grid.modules[y][x] = false;\n}\n\n/** Max characters/bytes encodable at (version, level, mode). */\nexport function qrCapacity(version: number, errorCorrection: QrErrorCorrection, mode: QrMode): number {\n if (!Number.isInteger(version) || version < 1 || version > MAX_VERSION)\n throw new SigilOptionError(`version must be an integer 1–${MAX_VERSION}, got ${version}`);\n return capacityFor(version, errorCorrection, mode);\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ var e=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},t=class extends e{bytes;maxBytes;version;constructor(e,t,n,r,i){super(e,i),this.bytes=t,this.maxBytes=n,this.version=r}},n=class extends e{},r=class extends e{},i=class extends e{},a=class extends e{};exports.SigilCapacityError=t,exports.SigilDisposedError=a,exports.SigilError=e,exports.SigilOptionError=n,exports.SigilPermissionError=i,exports.SigilUnsupportedError=r;
2
+ //# sourceMappingURL=errors.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Base class for all sigil errors.\n * Use `instanceof SigilError` to catch any sigil-originated error in one branch.\n */\nexport class SigilError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when input data does not fit in the requested version/level. */\nexport class SigilCapacityError extends SigilError {\n readonly bytes: number;\n readonly maxBytes: number;\n readonly version: number;\n\n constructor(message: string, bytes: number, maxBytes: number, version: number, opts?: ErrorOptions) {\n super(message, opts);\n this.bytes = bytes;\n this.maxBytes = maxBytes;\n this.version = version;\n }\n}\n\n/** Thrown for an invalid option: version/minVersion out of range, mask outside 0–7. */\nexport class SigilOptionError extends SigilError {}\n\n/**\n * Thrown when the environment lacks `BarcodeDetector`, `getUserMedia`, or QR\n * format support. Feature-detect with `isQrScanSupported()`/`qrScanSupport()`.\n */\nexport class SigilUnsupportedError extends SigilError {}\n\n/** Thrown when camera access is denied (wraps `NotAllowedError`). */\nexport class SigilPermissionError extends SigilError {}\n\n/** Thrown when a disposed scanner is used. */\nexport class SigilDisposedError extends SigilError {}\n"],"mappings":"AAIA,IAAa,EAAb,cAAgC,KAAM,CACpC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,WAAW,KACvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CACF,EAGa,EAAb,cAAwC,CAAW,CACjD,MACA,SACA,QAEA,YAAY,EAAiB,EAAe,EAAkB,EAAiB,EAAqB,CAClG,MAAM,EAAS,CAAI,EACnB,KAAK,MAAQ,EACb,KAAK,SAAW,EAChB,KAAK,QAAU,CACjB,CACF,EAGa,EAAb,cAAsC,CAAW,CAAC,EAMrC,EAAb,cAA2C,CAAW,CAAC,EAG1C,EAAb,cAA0C,CAAW,CAAC,EAGzC,EAAb,cAAwC,CAAW,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Base class for all sigil errors.
3
+ * Use `instanceof SigilError` to catch any sigil-originated error in one branch.
4
+ */
5
+ export declare class SigilError extends Error {
6
+ constructor(message: string, opts?: ErrorOptions);
7
+ }
8
+ /** Thrown when input data does not fit in the requested version/level. */
9
+ export declare class SigilCapacityError extends SigilError {
10
+ readonly bytes: number;
11
+ readonly maxBytes: number;
12
+ readonly version: number;
13
+ constructor(message: string, bytes: number, maxBytes: number, version: number, opts?: ErrorOptions);
14
+ }
15
+ /** Thrown for an invalid option: version/minVersion out of range, mask outside 0–7. */
16
+ export declare class SigilOptionError extends SigilError {
17
+ }
18
+ /**
19
+ * Thrown when the environment lacks `BarcodeDetector`, `getUserMedia`, or QR
20
+ * format support. Feature-detect with `isQrScanSupported()`/`qrScanSupport()`.
21
+ */
22
+ export declare class SigilUnsupportedError extends SigilError {
23
+ }
24
+ /** Thrown when camera access is denied (wraps `NotAllowedError`). */
25
+ export declare class SigilPermissionError extends SigilError {
26
+ }
27
+ /** Thrown when a disposed scanner is used. */
28
+ export declare class SigilDisposedError extends SigilError {
29
+ }
30
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;CAKjD;AAED,0EAA0E;AAC1E,qBAAa,kBAAmB,SAAQ,UAAU;IAChD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAEb,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;CAMnG;AAED,uFAAuF;AACvF,qBAAa,gBAAiB,SAAQ,UAAU;CAAG;AAEnD;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,UAAU;CAAG;AAExD,qEAAqE;AACrE,qBAAa,oBAAqB,SAAQ,UAAU;CAAG;AAEvD,8CAA8C;AAC9C,qBAAa,kBAAmB,SAAQ,UAAU;CAAG"}
package/dist/errors.js ADDED
@@ -0,0 +1,17 @@
1
+ //#region src/errors.ts
2
+ var e = class extends Error {
3
+ constructor(e, t) {
4
+ super(e, t), this.name = new.target.name, Object.setPrototypeOf(this, new.target.prototype);
5
+ }
6
+ }, t = class extends e {
7
+ bytes;
8
+ maxBytes;
9
+ version;
10
+ constructor(e, t, n, r, i) {
11
+ super(e, i), this.bytes = t, this.maxBytes = n, this.version = r;
12
+ }
13
+ }, n = class extends e {}, r = class extends e {}, i = class extends e {}, a = class extends e {};
14
+ //#endregion
15
+ export { t as SigilCapacityError, a as SigilDisposedError, e as SigilError, n as SigilOptionError, i as SigilPermissionError, r as SigilUnsupportedError };
16
+
17
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Base class for all sigil errors.\n * Use `instanceof SigilError` to catch any sigil-originated error in one branch.\n */\nexport class SigilError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when input data does not fit in the requested version/level. */\nexport class SigilCapacityError extends SigilError {\n readonly bytes: number;\n readonly maxBytes: number;\n readonly version: number;\n\n constructor(message: string, bytes: number, maxBytes: number, version: number, opts?: ErrorOptions) {\n super(message, opts);\n this.bytes = bytes;\n this.maxBytes = maxBytes;\n this.version = version;\n }\n}\n\n/** Thrown for an invalid option: version/minVersion out of range, mask outside 0–7. */\nexport class SigilOptionError extends SigilError {}\n\n/**\n * Thrown when the environment lacks `BarcodeDetector`, `getUserMedia`, or QR\n * format support. Feature-detect with `isQrScanSupported()`/`qrScanSupport()`.\n */\nexport class SigilUnsupportedError extends SigilError {}\n\n/** Thrown when camera access is denied (wraps `NotAllowedError`). */\nexport class SigilPermissionError extends SigilError {}\n\n/** Thrown when a disposed scanner is used. */\nexport class SigilDisposedError extends SigilError {}\n"],"mappings":";AAIA,IAAa,IAAb,cAAgC,MAAM;CACpC,YAAY,GAAiB,GAAqB;EAGhD,AAFA,MAAM,GAAS,CAAI,GACnB,KAAK,OAAO,WAAW,MACvB,OAAO,eAAe,MAAM,WAAW,SAAS;CAClD;AACF,GAGa,IAAb,cAAwC,EAAW;CACjD;CACA;CACA;CAEA,YAAY,GAAiB,GAAe,GAAkB,GAAiB,GAAqB;EAIlG,AAHA,MAAM,GAAS,CAAI,GACnB,KAAK,QAAQ,GACb,KAAK,WAAW,GAChB,KAAK,UAAU;CACjB;AACF,GAGa,IAAb,cAAsC,EAAW,CAAC,GAMrC,IAAb,cAA2C,EAAW,CAAC,GAG1C,IAAb,cAA0C,EAAW,CAAC,GAGzC,IAAb,cAAwC,EAAW,CAAC"}
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./canvas.cjs"),t=require("./errors.cjs"),n=require("./encode.cjs"),r=require("./scan.cjs"),i=require("./svg.cjs");exports.SigilCapacityError=t.SigilCapacityError,exports.SigilDisposedError=t.SigilDisposedError,exports.SigilError=t.SigilError,exports.SigilOptionError=t.SigilOptionError,exports.SigilPermissionError=t.SigilPermissionError,exports.SigilUnsupportedError=t.SigilUnsupportedError,exports.createQrScanner=r.createQrScanner,exports.detectQr=r.detectQr,exports.drawToCanvas=e.drawToCanvas,exports.encodeQr=n.encodeQr,exports.isQrScanSupported=r.isQrScanSupported,exports.qrCapacity=n.qrCapacity,exports.qrScanSupport=r.qrScanSupport,exports.toSvg=i.toSvg;
@@ -0,0 +1,7 @@
1
+ export { drawToCanvas } from './canvas';
2
+ export { encodeQr, qrCapacity } from './encode';
3
+ export { SigilCapacityError, SigilDisposedError, SigilError, SigilOptionError, SigilPermissionError, SigilUnsupportedError, } from './errors';
4
+ export { createQrScanner, detectQr, isQrScanSupported, qrScanSupport } from './scan';
5
+ export { toSvg } from './svg';
6
+ export type { QrCanvasOptions, QrDetector, QrEncodeOptions, QrErrorCorrection, QrMatrix, QrMode, QrScanner, QrScannerOptions, QrScannerStatus, QrScanResult, QrSvgOptions, SigilEvent, } from './types';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,UAAU,EACV,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACrF,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAC9B,YAAY,EACV,eAAe,EACf,UAAU,EACV,eAAe,EACf,iBAAiB,EACjB,QAAQ,EACR,MAAM,EACN,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,UAAU,GACX,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ import { drawToCanvas as e } from "./canvas.js";
2
+ import { SigilCapacityError as t, SigilDisposedError as n, SigilError as r, SigilOptionError as i, SigilPermissionError as a, SigilUnsupportedError as o } from "./errors.js";
3
+ import { encodeQr as s, qrCapacity as c } from "./encode.js";
4
+ import { createQrScanner as l, detectQr as u, isQrScanSupported as d, qrScanSupport as f } from "./scan.js";
5
+ import { toSvg as p } from "./svg.js";
6
+ export { t as SigilCapacityError, n as SigilDisposedError, r as SigilError, i as SigilOptionError, a as SigilPermissionError, o as SigilUnsupportedError, l as createQrScanner, u as detectQr, e as drawToCanvas, s as encodeQr, d as isQrScanSupported, c as qrCapacity, f as qrScanSupport, p as toSvg };
package/dist/scan.cjs ADDED
@@ -0,0 +1,2 @@
1
+ const e=require("./errors.cjs");var t=globalThis,n=()=>t.BarcodeDetector;function r(){return typeof n()==`function`}async function i(){let e=n();if(typeof e!=`function`)return!1;if(typeof e.getSupportedFormats!=`function`)return!0;try{return(await e.getSupportedFormats()).includes(`qr_code`)}catch{return!1}}async function a(t,r={}){r.signal?.throwIfAborted();let i=n(),a=r.detector??(i?new i({formats:[`qr_code`]}):void 0);if(!a)throw new e.SigilUnsupportedError(`BarcodeDetector is not available in this environment`);let o=await a.detect(t);r.signal?.throwIfAborted();let s=o[0];return s?{cornerPoints:s.cornerPoints,value:s.rawValue}:null}function o(t){let r=t.mediaDevices??globalThis.navigator?.mediaDevices,i=t.once??!0,a=t.intervalMs??200,o=new AbortController,s=new Set,c=new Set,l=`idle`,u=null,d=null,f=!1,p=e=>{if(s.size!==0)for(let t of[...s])try{t(e)}catch{}},m=e=>{l!==e&&(l=e,p({status:e,type:`status-change`}))},h=()=>{if(d!==null&&(clearInterval(d),d=null),u){for(let e of u.getTracks())e.stop();u=null}t.video.srcObject=null},g=e=>{p({error:e,type:`error`}),h(),m(`stopped`)},_=async()=>{if(l!==`scanning`||u===null)return;let n=t.video;if(n.readyState<2){p({reason:`not-ready`,type:`frame-skipped`});return}if(f){p({reason:`busy`,type:`frame-skipped`});return}f=!0;let r=Date.now();try{let e=(await(await v).detect(n))[0];if(e){let t={cornerPoints:e.cornerPoints,value:e.rawValue};p({elapsedMs:Date.now()-r,type:`detect`,value:t.value});for(let e of[...c])e(t);i&&(h(),m(`stopped`))}}catch(t){g(t instanceof e.SigilError?t:new e.SigilError(`QR detection failed`,{cause:t}))}finally{f=!1}},v=Promise.resolve().then(()=>{if(t.detector)return t.detector;let r=n();if(typeof r!=`function`)throw new e.SigilUnsupportedError(`BarcodeDetector is not available in this environment`);return new r({formats:[`qr_code`]})}),y={get disposalSignal(){return o.signal},dispose(){l!==`disposed`&&(p({type:`dispose`}),h(),c.clear(),s.clear(),m(`disposed`),o.abort())},get disposed(){return l===`disposed`},onResult(e){return l===`disposed`?()=>{}:(c.add(e),()=>c.delete(e))},async start(){if(l===`disposed`)throw new e.SigilDisposedError(`Scanner is disposed`);if(l!==`starting`&&l!==`scanning`){if(!r||typeof r.getUserMedia!=`function`)throw new e.SigilUnsupportedError(`getUserMedia is not available in this environment`);await v,t.signal?.throwIfAborted(),m(`starting`);try{u=await r.getUserMedia({video:t.constraints??{facingMode:`environment`}})}catch(t){throw m(`idle`),t instanceof DOMException&&t.name===`NotAllowedError`?new e.SigilPermissionError(`Camera permission denied`,{cause:t}):t instanceof Error?t:new e.SigilError(`Camera request failed`,{cause:t})}t.signal?.throwIfAborted(),t.video.srcObject=u,await t.video.play().catch(()=>{}),m(`scanning`),d=setInterval(()=>void _(),a),_()}},get status(){return l},stop(){l!==`disposed`&&(h(),m(l===`idle`?`idle`:`stopped`))},tap(e,t){if(l===`disposed`)return()=>{};s.add(e);let n=()=>s.delete(e);return t?.signal?.addEventListener(`abort`,n,{once:!0}),n},[Symbol.dispose](){y.dispose()}};return t.signal?.addEventListener(`abort`,()=>y.stop(),{once:!0}),y}exports.createQrScanner=o,exports.detectQr=a,exports.isQrScanSupported=r,exports.qrScanSupport=i;
2
+ //# sourceMappingURL=scan.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.cjs","names":[],"sources":["../src/scan.ts"],"sourcesContent":["import { SigilDisposedError, SigilError, SigilPermissionError, SigilUnsupportedError } from './errors';\nimport type { QrDetector, QrScanner, QrScannerOptions, QrScannerStatus, QrScanResult, SigilEvent } from './types';\n\n/**\n * Scanning via the native `BarcodeDetector` API — a thin lifecycle wrapper.\n * Feature detection is lazy so importing the package is always safe (SSR).\n * No from-scratch image decoder: unsupported environments get\n * `SigilUnsupportedError` at `start()`/`detectQr()`, never at import.\n */\n\ninterface BarcodeDetectorLike {\n detect(\n source: ImageBitmapSource,\n ): Promise<ReadonlyArray<{ rawValue: string; cornerPoints?: ReadonlyArray<{ x: number; y: number }> }>>;\n}\n\ninterface BarcodeDetectorCtor {\n getSupportedFormats?(): Promise<readonly string[]>;\n new (options?: { formats?: string[] }): BarcodeDetectorLike;\n}\n\nconst globalScope = globalThis as { BarcodeDetector?: BarcodeDetectorCtor };\n\nconst barcodeDetector = (): BarcodeDetectorCtor | undefined => globalScope.BarcodeDetector;\n\n/** Sync check: `BarcodeDetector` exists. Format support needs the async variant. */\nexport function isQrScanSupported(): boolean {\n return typeof barcodeDetector() === 'function';\n}\n\n/** Full check: `BarcodeDetector` exists and reports `qr_code` support. */\nexport async function qrScanSupport(): Promise<boolean> {\n const ctor = barcodeDetector();\n if (typeof ctor !== 'function') return false;\n if (typeof ctor.getSupportedFormats !== 'function') return true;\n try {\n return (await ctor.getSupportedFormats()).includes('qr_code');\n } catch {\n return false;\n }\n}\n\n/** One-shot detection on an image source; `null` when no code is found. */\nexport async function detectQr(\n source: ImageBitmapSource,\n options: { signal?: AbortSignal; detector?: QrDetector } = {},\n): Promise<QrScanResult | null> {\n options.signal?.throwIfAborted();\n const ctor = barcodeDetector();\n const detector = options.detector ?? (ctor ? new ctor({ formats: ['qr_code'] }) : undefined);\n if (!detector) throw new SigilUnsupportedError('BarcodeDetector is not available in this environment');\n const results = await detector.detect(source);\n options.signal?.throwIfAborted();\n const first = results[0];\n return first ? { cornerPoints: first.cornerPoints, value: first.rawValue } : null;\n}\n\nexport function createQrScanner(options: QrScannerOptions): QrScanner {\n const media = options.mediaDevices ?? globalThis.navigator?.mediaDevices;\n const once = options.once ?? true;\n const intervalMs = options.intervalMs ?? 200;\n const disposal = new AbortController();\n const tappers = new Set<(event: SigilEvent) => void>();\n const handlers = new Set<(result: QrScanResult) => void>();\n\n let status: QrScannerStatus = 'idle';\n let stream: MediaStream | null = null;\n let timer: ReturnType<typeof setInterval> | null = null;\n let busy = false;\n\n const emit = (event: SigilEvent): void => {\n if (tappers.size === 0) return;\n for (const handler of [...tappers]) {\n try {\n handler(event);\n } catch {\n // Observability must never affect behavior.\n }\n }\n };\n\n const setStatus = (next: QrScannerStatus): void => {\n if (status === next) return;\n status = next;\n emit({ status: next, type: 'status-change' });\n };\n\n const stopTracks = (): void => {\n if (timer !== null) {\n clearInterval(timer);\n timer = null;\n }\n if (stream) {\n for (const track of stream.getTracks()) track.stop();\n stream = null;\n }\n options.video.srcObject = null;\n };\n\n const fail = (error: SigilError): void => {\n emit({ error, type: 'error' });\n stopTracks();\n setStatus('stopped');\n };\n\n const tick = async (): Promise<void> => {\n if (status !== 'scanning' || stream === null) return;\n const video = options.video;\n if (video.readyState < 2 /* HAVE_CURRENT_DATA */) {\n emit({ reason: 'not-ready', type: 'frame-skipped' });\n return;\n }\n if (busy) {\n emit({ reason: 'busy', type: 'frame-skipped' });\n return;\n }\n busy = true;\n const started = Date.now();\n try {\n const detector = await detectorPromise;\n const results = await detector.detect(video);\n const first = results[0];\n if (first) {\n const result: QrScanResult = { cornerPoints: first.cornerPoints, value: first.rawValue };\n emit({ elapsedMs: Date.now() - started, type: 'detect', value: result.value });\n for (const handler of [...handlers]) handler(result);\n if (once) {\n stopTracks();\n setStatus('stopped');\n }\n }\n } catch (error) {\n fail(error instanceof SigilError ? error : new SigilError('QR detection failed', { cause: error }));\n } finally {\n busy = false;\n }\n };\n\n const detectorPromise: Promise<QrDetector> = Promise.resolve().then(() => {\n if (options.detector) return options.detector;\n const ctor = barcodeDetector();\n if (typeof ctor !== 'function')\n throw new SigilUnsupportedError('BarcodeDetector is not available in this environment');\n return new ctor({ formats: ['qr_code'] });\n });\n\n const api: QrScanner = {\n get disposalSignal() {\n return disposal.signal;\n },\n dispose() {\n if (status === 'disposed') return;\n emit({ type: 'dispose' });\n stopTracks();\n handlers.clear();\n tappers.clear();\n setStatus('disposed');\n disposal.abort();\n },\n get disposed() {\n return status === 'disposed';\n },\n onResult(handler) {\n if (status === 'disposed') return () => {};\n handlers.add(handler);\n return () => handlers.delete(handler);\n },\n async start() {\n if (status === 'disposed') throw new SigilDisposedError('Scanner is disposed');\n if (status === 'starting' || status === 'scanning') return;\n if (!media || typeof media.getUserMedia !== 'function')\n throw new SigilUnsupportedError('getUserMedia is not available in this environment');\n // Surface a missing detector at start() (not construction) per contract.\n await detectorPromise;\n options.signal?.throwIfAborted();\n setStatus('starting');\n try {\n stream = await media.getUserMedia({ video: options.constraints ?? { facingMode: 'environment' } });\n } catch (error) {\n setStatus('idle');\n if (error instanceof DOMException && error.name === 'NotAllowedError')\n throw new SigilPermissionError('Camera permission denied', { cause: error });\n throw error instanceof Error ? error : new SigilError('Camera request failed', { cause: error });\n }\n options.signal?.throwIfAborted();\n options.video.srcObject = stream;\n await options.video.play().catch(() => {});\n setStatus('scanning');\n timer = setInterval(() => void tick(), intervalMs);\n void tick();\n },\n get status() {\n return status;\n },\n stop() {\n if (status === 'disposed') return;\n stopTracks();\n setStatus(status === 'idle' ? 'idle' : 'stopped');\n },\n tap(handler, tapOptions) {\n if (status === 'disposed') return () => {};\n tappers.add(handler);\n const off = () => tappers.delete(handler);\n tapOptions?.signal?.addEventListener('abort', off, { once: true });\n return off;\n },\n [Symbol.dispose]() {\n api.dispose();\n },\n };\n\n options.signal?.addEventListener('abort', () => api.stop(), { once: true });\n return api;\n}\n"],"mappings":"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"}
package/dist/scan.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import type { QrDetector, QrScanner, QrScannerOptions, QrScanResult } from './types';
2
+ /** Sync check: `BarcodeDetector` exists. Format support needs the async variant. */
3
+ export declare function isQrScanSupported(): boolean;
4
+ /** Full check: `BarcodeDetector` exists and reports `qr_code` support. */
5
+ export declare function qrScanSupport(): Promise<boolean>;
6
+ /** One-shot detection on an image source; `null` when no code is found. */
7
+ export declare function detectQr(source: ImageBitmapSource, options?: {
8
+ signal?: AbortSignal;
9
+ detector?: QrDetector;
10
+ }): Promise<QrScanResult | null>;
11
+ export declare function createQrScanner(options: QrScannerOptions): QrScanner;
12
+ //# sourceMappingURL=scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,gBAAgB,EAAmB,YAAY,EAAc,MAAM,SAAS,CAAC;AAwBlH,oFAAoF;AACpF,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,0EAA0E;AAC1E,wBAAsB,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CAStD;AAED,2EAA2E;AAC3E,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,iBAAiB,EACzB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,EAAE,UAAU,CAAA;CAAO,GAC5D,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAS9B;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CA4JpE"}
package/dist/scan.js ADDED
@@ -0,0 +1,141 @@
1
+ import { SigilDisposedError as e, SigilError as t, SigilPermissionError as n, SigilUnsupportedError as r } from "./errors.js";
2
+ //#region src/scan.ts
3
+ var i = globalThis, a = () => i.BarcodeDetector;
4
+ function o() {
5
+ return typeof a() == "function";
6
+ }
7
+ async function s() {
8
+ let e = a();
9
+ if (typeof e != "function") return !1;
10
+ if (typeof e.getSupportedFormats != "function") return !0;
11
+ try {
12
+ return (await e.getSupportedFormats()).includes("qr_code");
13
+ } catch {
14
+ return !1;
15
+ }
16
+ }
17
+ async function c(e, t = {}) {
18
+ t.signal?.throwIfAborted();
19
+ let n = a(), i = t.detector ?? (n ? new n({ formats: ["qr_code"] }) : void 0);
20
+ if (!i) throw new r("BarcodeDetector is not available in this environment");
21
+ let o = await i.detect(e);
22
+ t.signal?.throwIfAborted();
23
+ let s = o[0];
24
+ return s ? {
25
+ cornerPoints: s.cornerPoints,
26
+ value: s.rawValue
27
+ } : null;
28
+ }
29
+ function l(i) {
30
+ let o = i.mediaDevices ?? globalThis.navigator?.mediaDevices, s = i.once ?? !0, c = i.intervalMs ?? 200, l = new AbortController(), u = /* @__PURE__ */ new Set(), d = /* @__PURE__ */ new Set(), f = "idle", p = null, m = null, h = !1, g = (e) => {
31
+ if (u.size !== 0) for (let t of [...u]) try {
32
+ t(e);
33
+ } catch {}
34
+ }, _ = (e) => {
35
+ f !== e && (f = e, g({
36
+ status: e,
37
+ type: "status-change"
38
+ }));
39
+ }, v = () => {
40
+ if (m !== null && (clearInterval(m), m = null), p) {
41
+ for (let e of p.getTracks()) e.stop();
42
+ p = null;
43
+ }
44
+ i.video.srcObject = null;
45
+ }, y = (e) => {
46
+ g({
47
+ error: e,
48
+ type: "error"
49
+ }), v(), _("stopped");
50
+ }, b = async () => {
51
+ if (f !== "scanning" || p === null) return;
52
+ let e = i.video;
53
+ if (e.readyState < 2) {
54
+ g({
55
+ reason: "not-ready",
56
+ type: "frame-skipped"
57
+ });
58
+ return;
59
+ }
60
+ if (h) {
61
+ g({
62
+ reason: "busy",
63
+ type: "frame-skipped"
64
+ });
65
+ return;
66
+ }
67
+ h = !0;
68
+ let n = Date.now();
69
+ try {
70
+ let t = (await (await x).detect(e))[0];
71
+ if (t) {
72
+ let e = {
73
+ cornerPoints: t.cornerPoints,
74
+ value: t.rawValue
75
+ };
76
+ g({
77
+ elapsedMs: Date.now() - n,
78
+ type: "detect",
79
+ value: e.value
80
+ });
81
+ for (let t of [...d]) t(e);
82
+ s && (v(), _("stopped"));
83
+ }
84
+ } catch (e) {
85
+ y(e instanceof t ? e : new t("QR detection failed", { cause: e }));
86
+ } finally {
87
+ h = !1;
88
+ }
89
+ }, x = Promise.resolve().then(() => {
90
+ if (i.detector) return i.detector;
91
+ let e = a();
92
+ if (typeof e != "function") throw new r("BarcodeDetector is not available in this environment");
93
+ return new e({ formats: ["qr_code"] });
94
+ }), S = {
95
+ get disposalSignal() {
96
+ return l.signal;
97
+ },
98
+ dispose() {
99
+ f !== "disposed" && (g({ type: "dispose" }), v(), d.clear(), u.clear(), _("disposed"), l.abort());
100
+ },
101
+ get disposed() {
102
+ return f === "disposed";
103
+ },
104
+ onResult(e) {
105
+ return f === "disposed" ? () => {} : (d.add(e), () => d.delete(e));
106
+ },
107
+ async start() {
108
+ if (f === "disposed") throw new e("Scanner is disposed");
109
+ if (f !== "starting" && f !== "scanning") {
110
+ if (!o || typeof o.getUserMedia != "function") throw new r("getUserMedia is not available in this environment");
111
+ await x, i.signal?.throwIfAborted(), _("starting");
112
+ try {
113
+ p = await o.getUserMedia({ video: i.constraints ?? { facingMode: "environment" } });
114
+ } catch (e) {
115
+ throw _("idle"), e instanceof DOMException && e.name === "NotAllowedError" ? new n("Camera permission denied", { cause: e }) : e instanceof Error ? e : new t("Camera request failed", { cause: e });
116
+ }
117
+ i.signal?.throwIfAborted(), i.video.srcObject = p, await i.video.play().catch(() => {}), _("scanning"), m = setInterval(() => void b(), c), b();
118
+ }
119
+ },
120
+ get status() {
121
+ return f;
122
+ },
123
+ stop() {
124
+ f !== "disposed" && (v(), _(f === "idle" ? "idle" : "stopped"));
125
+ },
126
+ tap(e, t) {
127
+ if (f === "disposed") return () => {};
128
+ u.add(e);
129
+ let n = () => u.delete(e);
130
+ return t?.signal?.addEventListener("abort", n, { once: !0 }), n;
131
+ },
132
+ [Symbol.dispose]() {
133
+ S.dispose();
134
+ }
135
+ };
136
+ return i.signal?.addEventListener("abort", () => S.stop(), { once: !0 }), S;
137
+ }
138
+ //#endregion
139
+ export { l as createQrScanner, c as detectQr, o as isQrScanSupported, s as qrScanSupport };
140
+
141
+ //# sourceMappingURL=scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.js","names":[],"sources":["../src/scan.ts"],"sourcesContent":["import { SigilDisposedError, SigilError, SigilPermissionError, SigilUnsupportedError } from './errors';\nimport type { QrDetector, QrScanner, QrScannerOptions, QrScannerStatus, QrScanResult, SigilEvent } from './types';\n\n/**\n * Scanning via the native `BarcodeDetector` API — a thin lifecycle wrapper.\n * Feature detection is lazy so importing the package is always safe (SSR).\n * No from-scratch image decoder: unsupported environments get\n * `SigilUnsupportedError` at `start()`/`detectQr()`, never at import.\n */\n\ninterface BarcodeDetectorLike {\n detect(\n source: ImageBitmapSource,\n ): Promise<ReadonlyArray<{ rawValue: string; cornerPoints?: ReadonlyArray<{ x: number; y: number }> }>>;\n}\n\ninterface BarcodeDetectorCtor {\n getSupportedFormats?(): Promise<readonly string[]>;\n new (options?: { formats?: string[] }): BarcodeDetectorLike;\n}\n\nconst globalScope = globalThis as { BarcodeDetector?: BarcodeDetectorCtor };\n\nconst barcodeDetector = (): BarcodeDetectorCtor | undefined => globalScope.BarcodeDetector;\n\n/** Sync check: `BarcodeDetector` exists. Format support needs the async variant. */\nexport function isQrScanSupported(): boolean {\n return typeof barcodeDetector() === 'function';\n}\n\n/** Full check: `BarcodeDetector` exists and reports `qr_code` support. */\nexport async function qrScanSupport(): Promise<boolean> {\n const ctor = barcodeDetector();\n if (typeof ctor !== 'function') return false;\n if (typeof ctor.getSupportedFormats !== 'function') return true;\n try {\n return (await ctor.getSupportedFormats()).includes('qr_code');\n } catch {\n return false;\n }\n}\n\n/** One-shot detection on an image source; `null` when no code is found. */\nexport async function detectQr(\n source: ImageBitmapSource,\n options: { signal?: AbortSignal; detector?: QrDetector } = {},\n): Promise<QrScanResult | null> {\n options.signal?.throwIfAborted();\n const ctor = barcodeDetector();\n const detector = options.detector ?? (ctor ? new ctor({ formats: ['qr_code'] }) : undefined);\n if (!detector) throw new SigilUnsupportedError('BarcodeDetector is not available in this environment');\n const results = await detector.detect(source);\n options.signal?.throwIfAborted();\n const first = results[0];\n return first ? { cornerPoints: first.cornerPoints, value: first.rawValue } : null;\n}\n\nexport function createQrScanner(options: QrScannerOptions): QrScanner {\n const media = options.mediaDevices ?? globalThis.navigator?.mediaDevices;\n const once = options.once ?? true;\n const intervalMs = options.intervalMs ?? 200;\n const disposal = new AbortController();\n const tappers = new Set<(event: SigilEvent) => void>();\n const handlers = new Set<(result: QrScanResult) => void>();\n\n let status: QrScannerStatus = 'idle';\n let stream: MediaStream | null = null;\n let timer: ReturnType<typeof setInterval> | null = null;\n let busy = false;\n\n const emit = (event: SigilEvent): void => {\n if (tappers.size === 0) return;\n for (const handler of [...tappers]) {\n try {\n handler(event);\n } catch {\n // Observability must never affect behavior.\n }\n }\n };\n\n const setStatus = (next: QrScannerStatus): void => {\n if (status === next) return;\n status = next;\n emit({ status: next, type: 'status-change' });\n };\n\n const stopTracks = (): void => {\n if (timer !== null) {\n clearInterval(timer);\n timer = null;\n }\n if (stream) {\n for (const track of stream.getTracks()) track.stop();\n stream = null;\n }\n options.video.srcObject = null;\n };\n\n const fail = (error: SigilError): void => {\n emit({ error, type: 'error' });\n stopTracks();\n setStatus('stopped');\n };\n\n const tick = async (): Promise<void> => {\n if (status !== 'scanning' || stream === null) return;\n const video = options.video;\n if (video.readyState < 2 /* HAVE_CURRENT_DATA */) {\n emit({ reason: 'not-ready', type: 'frame-skipped' });\n return;\n }\n if (busy) {\n emit({ reason: 'busy', type: 'frame-skipped' });\n return;\n }\n busy = true;\n const started = Date.now();\n try {\n const detector = await detectorPromise;\n const results = await detector.detect(video);\n const first = results[0];\n if (first) {\n const result: QrScanResult = { cornerPoints: first.cornerPoints, value: first.rawValue };\n emit({ elapsedMs: Date.now() - started, type: 'detect', value: result.value });\n for (const handler of [...handlers]) handler(result);\n if (once) {\n stopTracks();\n setStatus('stopped');\n }\n }\n } catch (error) {\n fail(error instanceof SigilError ? error : new SigilError('QR detection failed', { cause: error }));\n } finally {\n busy = false;\n }\n };\n\n const detectorPromise: Promise<QrDetector> = Promise.resolve().then(() => {\n if (options.detector) return options.detector;\n const ctor = barcodeDetector();\n if (typeof ctor !== 'function')\n throw new SigilUnsupportedError('BarcodeDetector is not available in this environment');\n return new ctor({ formats: ['qr_code'] });\n });\n\n const api: QrScanner = {\n get disposalSignal() {\n return disposal.signal;\n },\n dispose() {\n if (status === 'disposed') return;\n emit({ type: 'dispose' });\n stopTracks();\n handlers.clear();\n tappers.clear();\n setStatus('disposed');\n disposal.abort();\n },\n get disposed() {\n return status === 'disposed';\n },\n onResult(handler) {\n if (status === 'disposed') return () => {};\n handlers.add(handler);\n return () => handlers.delete(handler);\n },\n async start() {\n if (status === 'disposed') throw new SigilDisposedError('Scanner is disposed');\n if (status === 'starting' || status === 'scanning') return;\n if (!media || typeof media.getUserMedia !== 'function')\n throw new SigilUnsupportedError('getUserMedia is not available in this environment');\n // Surface a missing detector at start() (not construction) per contract.\n await detectorPromise;\n options.signal?.throwIfAborted();\n setStatus('starting');\n try {\n stream = await media.getUserMedia({ video: options.constraints ?? { facingMode: 'environment' } });\n } catch (error) {\n setStatus('idle');\n if (error instanceof DOMException && error.name === 'NotAllowedError')\n throw new SigilPermissionError('Camera permission denied', { cause: error });\n throw error instanceof Error ? error : new SigilError('Camera request failed', { cause: error });\n }\n options.signal?.throwIfAborted();\n options.video.srcObject = stream;\n await options.video.play().catch(() => {});\n setStatus('scanning');\n timer = setInterval(() => void tick(), intervalMs);\n void tick();\n },\n get status() {\n return status;\n },\n stop() {\n if (status === 'disposed') return;\n stopTracks();\n setStatus(status === 'idle' ? 'idle' : 'stopped');\n },\n tap(handler, tapOptions) {\n if (status === 'disposed') return () => {};\n tappers.add(handler);\n const off = () => tappers.delete(handler);\n tapOptions?.signal?.addEventListener('abort', off, { once: true });\n return off;\n },\n [Symbol.dispose]() {\n api.dispose();\n },\n };\n\n options.signal?.addEventListener('abort', () => api.stop(), { once: true });\n return api;\n}\n"],"mappings":"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"}
package/dist/sigil.cjs ADDED
@@ -0,0 +1,2 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e,t,n={}){let r=n.margin??4,i=n.scale??1,a=n.dark??`#000000`,o=n.light??`#ffffff`,s=(e.size+r*2)*i,c=globalThis.devicePixelRatio||1;t.width=s*c,t.height=s*c,t.style.width=`${s}px`,t.style.height=`${s}px`;let l=t.getContext(`2d`);if(!l)throw Error(`Canvas 2D context unavailable`);l.scale(c,c),l.fillStyle=o,l.fillRect(0,0,s,s),l.fillStyle=a;for(let t=0;t<e.size;t++)for(let n=0;n<e.size;n++)e.get(n,t)&&l.fillRect((n+r)*i,(t+r)*i,i,i);return s}var t=[`L`,`M`,`Q`,`H`],n=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:`,r={alphanumeric:2,byte:4,numeric:1},i={alphanumeric:[9,11,13],byte:[8,16,16],numeric:[10,12,14]},a={H:2,L:1,M:0,Q:3},o=[[-1,7,10,15,20,26,18,20,24,30,18,20,24,26,30,22,24,28,30,28,28,28,28,30,30,26,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,10,16,26,18,24,16,18,22,22,26,30,22,22,24,24,28,28,26,26,26,26,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28],[-1,13,22,18,26,18,24,18,22,20,24,28,26,24,20,30,24,28,28,26,30,28,30,30,30,30,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,17,28,22,16,22,28,26,26,24,28,24,28,22,24,24,30,28,28,26,28,30,24,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30]],s=[[-1,1,1,1,1,1,2,2,2,2,4,4,4,4,4,6,6,6,6,7,8,8,9,9,10,12,12,12,13,14,15,16,17,18,19,19,20,21,22,24,25],[-1,1,1,1,2,2,4,4,4,5,5,5,8,9,9,10,10,11,13,14,16,17,17,18,20,21,23,25,26,28,29,31,33,35,37,38,40,43,45,47,49],[-1,1,1,2,2,4,4,6,6,8,8,8,10,12,16,12,17,16,18,21,20,23,23,25,27,29,34,34,35,38,40,43,45,48,51,53,56,59,62,65,68],[-1,1,1,2,4,4,4,5,6,8,8,11,11,16,16,18,16,19,21,25,25,25,34,30,32,35,37,40,42,45,48,51,56,59,62,65,68,71,74,77,81]],c=e=>t.indexOf(e),l=e=>e*4+17;function u(e){if(e===1)return[];let t=Math.floor(e/7)+2,n=e===32?26:Math.ceil((e*4+4)/(t*2-2))*2,r=[6];for(let i=e*4+10;r.length<t;i-=n)r.splice(1,0,i);return r}function d(e){let t=(16*e+128)*e+64;if(e>=2){let n=Math.floor(e/7)+2;t-=(25*n-10)*n-55,e>=7&&(t-=36)}return t}var f=e=>Math.floor(d(e)/8);function p(e,t){return o[c(t)][e]}function m(e,t){return s[c(t)][e]}function h(e,t){return f(e)-p(e,t)*m(e,t)}function g(e){return e<=9?0:e<=26?1:2}var _=1335,ee=21522,v=7973;function te(e,t){let n=a[e]<<3|t,r=n;for(let e=0;e<10;e++)r=r<<1^(r>>>9&1)*_;return(n<<10|r&1023)^ee}function ne(e){let t=e;for(let e=0;e<12;e++)t=t<<1^(t>>>11&1)*v;return e<<12|t&4095}var y=(e,t,n,r)=>{e.modules[n][t]=r,e.isFunction[n][t]=!0};function b(e,t,n){let r=e.size,i=te(t,n),a=e=>(i>>>e&1)==1;for(let t=0;t<=5;t++)y(e,8,t,a(t));y(e,8,7,a(6)),y(e,8,8,a(7)),y(e,7,8,a(8));for(let t=9;t<15;t++)y(e,14-t,8,a(t));for(let t=0;t<8;t++)y(e,r-1-t,8,a(t));for(let t=8;t<15;t++)y(e,8,r-15+t,a(t));y(e,8,r-8,!0)}function x(e,t){if(t<7)return;let n=e.size,r=ne(t);for(let t=0;t<18;t++){let i=(r>>>t&1)==1,a=n-11+t%3,o=Math.floor(t/3);y(e,a,o,i),y(e,o,a,i)}}var S=[(e,t)=>(e+t)%2==0,(e,t)=>t%2==0,e=>e%3==0,(e,t)=>(e+t)%3==0,(e,t)=>(Math.floor(e/3)+Math.floor(t/2))%2==0,(e,t)=>e*t%2+e*t%3==0,(e,t)=>(e*t%2+e*t%3)%2==0,(e,t)=>((e+t)%2+e*t%3)%2==0];function C(e,t){let n=S[t];for(let t=0;t<e.size;t++)for(let r=0;r<e.size;r++)!e.isFunction[t][r]&&n(r,t)&&(e.modules[t][r]=!e.modules[t][r])}var w=3,re=3,ie=40,ae=10;function oe(e){let t=0,n=(e,n)=>(!e&&n>=5&&(t+=w+n-5),e?n+1:1);for(let r=0;r<e.size;r++){let i=1,a=1;for(let t=1;t<e.size;t++)i=n(e.modules[r][t]===e.modules[r][t-1],i),a=n(e.modules[t][r]===e.modules[t-1][r],a);i>=5&&(t+=w+i-5),a>=5&&(t+=w+a-5)}return t}function se(e){let t=0;for(let n=0;n<e.size-1;n++)for(let r=0;r<e.size-1;r++){let i=e.modules[n][r];i===e.modules[n][r+1]&&i===e.modules[n+1][r]&&i===e.modules[n+1][r+1]&&(t+=re)}return t}function ce(e){let t=e.size,n=0,r=e=>{for(let r=0;r+11<=t;r++){let t=Array.from({length:11},(t,n)=>e(r+n)),i=[!1,!1,!1,!1,!0,!1,!0,!0,!0,!1,!0],a=[!0,!1,!0,!0,!0,!1,!0,!1,!1,!1,!1];(t.every((e,t)=>e===i[t])||t.every((e,t)=>e===a[t]))&&(n+=ie)}};for(let n=0;n<t;n++)r(t=>e.modules[n][t]);for(let n=0;n<t;n++)r(t=>e.modules[t][n]);return n}function le(e){let t=0;for(let n of e.modules)for(let e of n)e&&t++;let n=e.size*e.size;return Math.floor(Math.abs(t*20-n*10)/n)*ae}function ue(e){return oe(e)+se(e)+ce(e)+le(e)}function de(e){return{isFunction:Array.from({length:e},()=>Array(e).fill(!1)),modules:Array.from({length:e},()=>Array(e).fill(!1)),size:e}}var T=(e,t,n,r)=>{e.modules[n][t]=r,e.isFunction[n][t]=!0};function E(e,t,n){for(let r=-4;r<=4;r++)for(let i=-4;i<=4;i++){let a=t+3+i,o=n+3+r;if(a<0||o<0||a>=e.size||o>=e.size)continue;let s=Math.max(Math.abs(i),Math.abs(r));T(e,a,o,s!==2&&s!==4)}}function fe(e){for(let t=8;t<e.size-8;t++){let n=t%2==0;e.isFunction[6][t]||T(e,t,6,n),e.isFunction[t][6]||T(e,6,t,n)}}function pe(e,t,n){for(let r=-2;r<=2;r++)for(let i=-2;i<=2;i++)T(e,t+i,n+r,Math.max(Math.abs(i),Math.abs(r))!==1)}function me(e){let t=e.size;for(let t=0;t<=8;t++)t!==6&&(e.isFunction[8][t]=!0,e.isFunction[t][8]=!0);for(let n=0;n<7;n++)e.isFunction[t-1-n][8]=!0;for(let n=0;n<8;n++)e.isFunction[8][t-1-n]=!0;e.isFunction[t-8][8]=!0}function D(e,t){if(t<7)return;let n=e.size;for(let t=0;t<18;t++){let r=n-11+t%3,i=Math.floor(t/3);e.isFunction[i][r]=!0,e.isFunction[r][i]=!0}}function O(e,t){E(e,0,0),E(e,e.size-7,0),E(e,0,e.size-7),fe(e);let n=u(t);for(let t of n)for(let r of n)r===6&&t===6||r===6&&t===e.size-7||r===e.size-7&&t===6||pe(e,r,t);me(e),D(e,t)}function k(e,t){let n=e.size,r=t.length*8,i=0,a=!0;for(let o=n-1;o>=1;o-=2){o===6&&(o=5);for(let s=0;s<n;s++)for(let c=0;c<2;c++){let l=o-c,u=a?n-1-s:s;e.isFunction[u][l]||(e.modules[u][l]=i<r&&(t[i>>>3]>>>7-(i&7)&1)==1,i++)}a=!a}}var A=285,j=new Uint8Array(512),M=new Uint8Array(256);{let e=1;for(let t=0;t<255;t++)j[t]=e,M[e]=t,e<<=1,e&256&&(e^=A);for(let e=255;e<512;e++)j[e]=j[e-255]}function N(e,t){return e===0||t===0?0:j[M[e]+M[t]]}function P(e){return j[e%255]}function F(e,t){let n=Array(e.length+t.length-1).fill(0);for(let r=0;r<e.length;r++)for(let i=0;i<t.length;i++)n[r+i]^=N(e[r],t[i]);return n}var I=new Map;function L(e){let t=I.get(e);if(t)return t;let n=[1];for(let t=0;t<e;t++)n=F(n,[1,P(t)]);return I.set(e,n),n}function R(e,t){let n=L(t),r=Array(t).fill(0);for(let i of e){let e=i^r[0];if(r.copyWithin(0,1),r[t-1]=0,e!==0)for(let i=0;i<t;i++)r[i]^=N(n[i+1],e)}return r}var z=class{bits=[];get length(){return this.bits.length}append(e,t){for(let n=t-1;n>=0;n--)this.bits.push(e>>>n&1)}padToByte(){for(;this.bits.length%8!=0;)this.bits.push(0)}toBytes(){let e=[];for(let t=0;t<this.bits.length;t+=8){let n=0;for(let e=0;e<8;e++)n=n<<1|this.bits[t+e];e.push(n)}return e}};function B(e){if(/^\d+$/.test(e))return`numeric`;for(let t of e)if(!`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:`.includes(t))return`byte`;return`alphanumeric`}var V=new TextEncoder;function he(e,t){switch(t){case`numeric`:return Math.floor(e.length/3)*10+(e.length%3==1?4:e.length%3==2?7:0);case`alphanumeric`:return Math.floor(e.length/2)*11+e.length%2*6;case`byte`:return V.encode(e).length*8}}function ge(e,t,a,o){switch(e.append(r[a],4),e.append(_e(t,a),i[a][g(o)]),a){case`numeric`:for(let n=0;n<t.length;){let r=Math.min(3,t.length-n);e.append(Number.parseInt(t.slice(n,n+r),10),r===3?10:r===2?7:4),n+=r}break;case`alphanumeric`:for(let r=0;r<t.length;)r+1<t.length?(e.append(n.indexOf(t[r])*45+n.indexOf(t[r+1]),11),r+=2):(e.append(n.indexOf(t[r]),6),r+=1);break;case`byte`:for(let n of V.encode(t))e.append(n,8)}}function _e(e,t){return t===`byte`?V.encode(e).length:e.length}var ve=(e,t)=>h(e,t)*8;function H(e,t,n){return 4+i[t][g(n)]+he(e,t)}function ye(e,t,n,r){let i=new z;ge(i,e,t,n);let a=ve(n,r);i.append(0,Math.min(4,a-i.length)),i.padToByte();let o=i.toBytes(),s=[236,17];for(let e=0;o.length<h(n,r);e++)o.push(s[e%2]);return o}var U=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},W=class extends U{bytes;maxBytes;version;constructor(e,t,n,r,i){super(e,i),this.bytes=t,this.maxBytes=n,this.version=r}},G=class extends U{},K=class extends U{},q=class extends U{},J=class extends U{},Y=40;function be(e){let{version:t,minVersion:n,mask:r,errorCorrection:i}=e,a=e=>Number.isInteger(e)&&e>=1&&e<=Y;if(t!==void 0&&!a(t))throw new G(`version must be an integer 1–${Y}, got ${t}`);if(n!==void 0&&!a(n))throw new G(`minVersion must be an integer 1–${Y}, got ${n}`);if(t!==void 0&&n!==void 0&&n>t)throw new G(`minVersion (${n}) exceeds version (${t})`);if(r!==void 0&&(!Number.isInteger(r)||r<0||r>7))throw new G(`mask must be an integer 0–7, got ${r}`);if(i!==void 0&&!`LMQH`.includes(i))throw new G(`errorCorrection must be 'L', 'M', 'Q', or 'H'`)}function X(e,t,n){let r=i[n][g(e)],a=h(e,t)*8-4-r;if(a<=0)return 0;switch(n){case`numeric`:return Math.floor(a/10)*3+(a%10>=7?2:+(a%10>=4));case`alphanumeric`:return Math.floor(a/11)*2+ +(a%11>=6);case`byte`:return Math.floor(a/8)}}function xe(e,t,n,r){for(let i=r;i<=Y;i++)if(H(e,t,i)<=h(i,n)*8)return i;return-1}function Se(e,t,n){let r=m(t,n),i=p(t,n),a=f(t),o=Math.floor(a/r)-i,s=a%r,c=[],l=0;for(let t=0;t<r;t++){let n=t>=r-s,a=e.slice(l,l+o+ +!!n);l+=a.length;let u=R(a,i);c.push(n?[...a,...u]:[...a,0,...u])}let u=[];for(let e=0;e<c[0].length;e++)for(let t=0;t<r;t++)(e!==o||t>=r-s)&&u.push(c[t][e]);return u}function Z(e,t){let n=e.map(e=>Object.freeze([...e]));return Object.freeze(n),Object.freeze({...t,get:(e,r)=>e>=0&&r>=0&&e<t.size&&r<t.size&&n[r][e],modules:n})}function Ce(e,t={}){be(t);let n=typeof e==`string`?e:new TextDecoder().decode(e);if(n.length===0)throw new G(`Cannot encode an empty input`);let r=t.errorCorrection??`M`,i=t.mode??B(n);if(i!==`byte`&&B(n)!==i&&!we(n,i))throw new G(`Input cannot be encoded in ${i} mode`);let a=t.version??xe(n,i,r,t.minVersion??1);if(a===-1||H(n,i,a)>h(a,r)*8){let e=new TextEncoder().encode(n).length,a=X(t.version??Y,r,i);throw new W(`Input of ${e} bytes exceeds QR capacity (${a} ${i===`byte`?`bytes`:`chars`} at version ${t.version??Y}-${r})`,e,a,t.version??Y)}let o=H(n,i,a),s=h(a,r)*8;o/s>.9&&t.version===void 0&&`${Math.round(o/s*100)}${a}${r}`;let c=Se(ye(n,i,a,r),a,r),u=de(l(a));O(u,a),k(u,c);let d=t.mask===void 0?[0,1,2,3,4,5,6,7]:[t.mask],f=d[0],p=1/0,m=null;for(let e of d){C(u,e),b(u,r,e);let t=ue(u);t<p&&(p=t,f=e,m=u.modules.map(e=>[...e])),C(u,e),e!==d[d.length-1]&&Te(u)}return u.modules=m,x(u,a),Z(u.modules,{errorCorrection:r,mask:f,mode:i,size:u.size,version:a})}function we(e,t){return t===`numeric`?/^\d+$/.test(e):t!==`alphanumeric`||[...e].every(e=>n.includes(e))}function Te(e){let t=e.size,n=[];for(let e=0;e<=8;e++)e!==6&&n.push([8,e],[e,8]);for(let e=0;e<8;e++)n.push([t-1-e,8]);for(let e=0;e<7;e++)n.push([8,t-1-e]);n.push([8,t-8]);for(let[t,r]of n)e.modules[r][t]=!1}function Ee(e,t,n){if(!Number.isInteger(e)||e<1||e>Y)throw new G(`version must be an integer 1–${Y}, got ${e}`);return X(e,t,n)}var De=globalThis,Q=()=>De.BarcodeDetector;function Oe(){return typeof Q()==`function`}async function ke(){let e=Q();if(typeof e!=`function`)return!1;if(typeof e.getSupportedFormats!=`function`)return!0;try{return(await e.getSupportedFormats()).includes(`qr_code`)}catch{return!1}}async function Ae(e,t={}){t.signal?.throwIfAborted();let n=Q(),r=t.detector??(n?new n({formats:[`qr_code`]}):void 0);if(!r)throw new K(`BarcodeDetector is not available in this environment`);let i=await r.detect(e);t.signal?.throwIfAborted();let a=i[0];return a?{cornerPoints:a.cornerPoints,value:a.rawValue}:null}function je(e){let t=e.mediaDevices??globalThis.navigator?.mediaDevices,n=e.once??!0,r=e.intervalMs??200,i=new AbortController,a=new Set,o=new Set,s=`idle`,c=null,l=null,u=!1,d=e=>{if(a.size!==0)for(let t of[...a])try{t(e)}catch{}},f=e=>{s!==e&&(s=e,d({status:e,type:`status-change`}))},p=()=>{if(l!==null&&(clearInterval(l),l=null),c){for(let e of c.getTracks())e.stop();c=null}e.video.srcObject=null},m=e=>{d({error:e,type:`error`}),p(),f(`stopped`)},h=async()=>{if(s!==`scanning`||c===null)return;let t=e.video;if(t.readyState<2){d({reason:`not-ready`,type:`frame-skipped`});return}if(u){d({reason:`busy`,type:`frame-skipped`});return}u=!0;let r=Date.now();try{let e=(await(await g).detect(t))[0];if(e){let t={cornerPoints:e.cornerPoints,value:e.rawValue};d({elapsedMs:Date.now()-r,type:`detect`,value:t.value});for(let e of[...o])e(t);n&&(p(),f(`stopped`))}}catch(e){m(e instanceof U?e:new U(`QR detection failed`,{cause:e}))}finally{u=!1}},g=Promise.resolve().then(()=>{if(e.detector)return e.detector;let t=Q();if(typeof t!=`function`)throw new K(`BarcodeDetector is not available in this environment`);return new t({formats:[`qr_code`]})}),_={get disposalSignal(){return i.signal},dispose(){s!==`disposed`&&(d({type:`dispose`}),p(),o.clear(),a.clear(),f(`disposed`),i.abort())},get disposed(){return s===`disposed`},onResult(e){return s===`disposed`?()=>{}:(o.add(e),()=>o.delete(e))},async start(){if(s===`disposed`)throw new J(`Scanner is disposed`);if(s!==`starting`&&s!==`scanning`){if(!t||typeof t.getUserMedia!=`function`)throw new K(`getUserMedia is not available in this environment`);await g,e.signal?.throwIfAborted(),f(`starting`);try{c=await t.getUserMedia({video:e.constraints??{facingMode:`environment`}})}catch(e){throw f(`idle`),e instanceof DOMException&&e.name===`NotAllowedError`?new q(`Camera permission denied`,{cause:e}):e instanceof Error?e:new U(`Camera request failed`,{cause:e})}e.signal?.throwIfAborted(),e.video.srcObject=c,await e.video.play().catch(()=>{}),f(`scanning`),l=setInterval(()=>void h(),r),h()}},get status(){return s},stop(){s!==`disposed`&&(p(),f(s===`idle`?`idle`:`stopped`))},tap(e,t){if(s===`disposed`)return()=>{};a.add(e);let n=()=>a.delete(e);return t?.signal?.addEventListener(`abort`,n,{once:!0}),n},[Symbol.dispose](){_.dispose()}};return e.signal?.addEventListener(`abort`,()=>_.stop(),{once:!0}),_}var $=e=>e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`);function Me(e,t={}){let n=t.margin??4,r=t.scale??1,i=t.dark??`currentColor`,a=t.light??`transparent`,o=t.optimizePath??!0,s=(e.size+n*2)*r,c=[`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${s} ${s}" role="img"`];t.label!==void 0&&c.push(` aria-label="${$(t.label)}"`),c.push(` shape-rendering="crispEdges">`),t.label!==void 0&&c.push(`<title>${$(t.label)}</title>`),a!==`transparent`&&c.push(`<rect width="${s}" height="${s}" fill="${a}"/>`);let l=[];for(let t=0;t<e.size;t++){let i=0;for(;i<e.size;){if(!e.get(i,t)){i++;continue}if(o){let a=1;for(;i+a<e.size&&e.get(i+a,t);)a++;l.push(`M${(i+n)*r} ${(t+n)*r}h${a*r}v${r}h${-a*r}z`),i+=a}else l.push(`M${(i+n)*r} ${(t+n)*r}h${r}v${r}h${-r}z`),i++}}return c.push(`<path d="${l.join(``)}" fill="${i}"/>`),c.push(`</svg>`),c.join(``)}exports.SigilCapacityError=W,exports.SigilDisposedError=J,exports.SigilError=U,exports.SigilOptionError=G,exports.SigilPermissionError=q,exports.SigilUnsupportedError=K,exports.createQrScanner=je,exports.detectQr=Ae,exports.drawToCanvas=e,exports.encodeQr=Ce,exports.isQrScanSupported=Oe,exports.qrCapacity=Ee,exports.qrScanSupport=ke,exports.toSvg=Me;
2
+ //# sourceMappingURL=sigil.cjs.map