ninepm 0.81.0 → 0.85.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.
- package/README.md +31 -3
- package/dist/index.d.ts +62 -2
- package/dist/index.js +477 -14
- package/dist/qr-code.d.ts +48 -0
- package/dist/qr-code.js +85 -0
- package/dist/vendor/qrcodegen.d.ts +93 -0
- package/dist/vendor/qrcodegen.js +879 -0
- package/package.json +1 -1
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** White border on every side, in modules: the QR standard's required quiet zone. */
|
|
2
|
+
export declare const QR_QUIET_ZONE_MODULES = 4;
|
|
3
|
+
/** Smallest printed width we promise scans, border included (spec: release-gated by print tests). */
|
|
4
|
+
export declare const QR_MIN_WIDTH_MM = 25;
|
|
5
|
+
/**
|
|
6
|
+
* Our chosen product floor for one module, in millimetres - not a universal scanning
|
|
7
|
+
* threshold. The printed scan fixtures are what justify it; re-measure before changing it.
|
|
8
|
+
*/
|
|
9
|
+
export declare const QR_MIN_MODULE_MM = 0.5;
|
|
10
|
+
export interface QrMatrix {
|
|
11
|
+
/** Modules per side INCLUDING the quiet zone. */
|
|
12
|
+
size: number;
|
|
13
|
+
/** Modules per side of the symbol alone. */
|
|
14
|
+
symbolSize: number;
|
|
15
|
+
/** `modules[y][x]`, true = dark, quiet zone included. */
|
|
16
|
+
modules: boolean[][];
|
|
17
|
+
}
|
|
18
|
+
export type ProjectQrUnavailableReason = "not_published" | "disabled" | "service_access";
|
|
19
|
+
export interface ProjectQrAddress {
|
|
20
|
+
url: string;
|
|
21
|
+
hostname: string;
|
|
22
|
+
kind: "custom_domain" | "platform";
|
|
23
|
+
isDefault: boolean;
|
|
24
|
+
}
|
|
25
|
+
export type ProjectQrResponse = {
|
|
26
|
+
available: true;
|
|
27
|
+
accessMode: string;
|
|
28
|
+
addresses: ProjectQrAddress[];
|
|
29
|
+
} | {
|
|
30
|
+
available: false;
|
|
31
|
+
accessMode: string;
|
|
32
|
+
reason: ProjectQrUnavailableReason;
|
|
33
|
+
};
|
|
34
|
+
export declare function qrMatrix(url: string): QrMatrix;
|
|
35
|
+
/** max(25 mm, 0.5 mm × (symbol modules per side + 8)): the 8 is the two four-module borders. */
|
|
36
|
+
export declare function qrMinimumWidthMm(url: string): number;
|
|
37
|
+
/**
|
|
38
|
+
* Black on white, sized only by its viewBox (one unit per module), so it prints at
|
|
39
|
+
* whatever physical width the owner chooses without resampling.
|
|
40
|
+
*/
|
|
41
|
+
export declare function qrSvg(url: string): string;
|
|
42
|
+
/**
|
|
43
|
+
* Two module rows per text line using half blocks. LIGHT modules are drawn and dark ones
|
|
44
|
+
* left blank, so on the usual dark-background terminal the code reads dark-on-light, the
|
|
45
|
+
* polarity phone cameras expect. The size is always odd, so the last line's lower half lies
|
|
46
|
+
* past the matrix and is drawn light: a little more quiet zone, never a missing module.
|
|
47
|
+
*/
|
|
48
|
+
export declare function qrTerminal(url: string): string[];
|
package/dist/qr-code.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// AUTO-GENERATED by scripts/generate-cli-package.mjs from the in-repo CLI source -- do not edit.
|
|
2
|
+
// Edit src/cli or src/shared instead; this is regenerated on typecheck/test/build/pack.
|
|
3
|
+
// App QR codes (_specs/app-qr-codes.md): the encoder settings every surface shares.
|
|
4
|
+
//
|
|
5
|
+
// The server decides WHICH address a code may encode (GET /v1/sites/:id/qr); each client
|
|
6
|
+
// draws it with these functions, so the dashboard, the CLI and any test produce the same
|
|
7
|
+
// symbol for the same URL. Pure: no DOM, no node: imports, no packages.
|
|
8
|
+
import { qrcodegen } from "./vendor/qrcodegen.js";
|
|
9
|
+
/** White border on every side, in modules: the QR standard's required quiet zone. */
|
|
10
|
+
export const QR_QUIET_ZONE_MODULES = 4;
|
|
11
|
+
/** Smallest printed width we promise scans, border included (spec: release-gated by print tests). */
|
|
12
|
+
export const QR_MIN_WIDTH_MM = 25;
|
|
13
|
+
/**
|
|
14
|
+
* Our chosen product floor for one module, in millimetres - not a universal scanning
|
|
15
|
+
* threshold. The printed scan fixtures are what justify it; re-measure before changing it.
|
|
16
|
+
*/
|
|
17
|
+
export const QR_MIN_MODULE_MM = 0.5;
|
|
18
|
+
function encode(url) {
|
|
19
|
+
const { QrCode, QrSegment } = qrcodegen;
|
|
20
|
+
// boostEcl=false: upstream otherwise raises Q to H whenever the data still fits the same
|
|
21
|
+
// version. The size would not change, but the fixed-Q contract would.
|
|
22
|
+
const code = QrCode.encodeSegments(QrSegment.makeSegments(url), QrCode.Ecc.QUARTILE, QrCode.MIN_VERSION, QrCode.MAX_VERSION, -1, false);
|
|
23
|
+
if (code.errorCorrectionLevel !== QrCode.Ecc.QUARTILE) {
|
|
24
|
+
throw new Error("QR encoder did not keep error correction at Q");
|
|
25
|
+
}
|
|
26
|
+
return code;
|
|
27
|
+
}
|
|
28
|
+
export function qrMatrix(url) {
|
|
29
|
+
const code = encode(url);
|
|
30
|
+
const border = QR_QUIET_ZONE_MODULES;
|
|
31
|
+
const size = code.size + border * 2;
|
|
32
|
+
const modules = [];
|
|
33
|
+
for (let y = 0; y < size; y++) {
|
|
34
|
+
const row = [];
|
|
35
|
+
for (let x = 0; x < size; x++)
|
|
36
|
+
row.push(code.getModule(x - border, y - border));
|
|
37
|
+
modules.push(row);
|
|
38
|
+
}
|
|
39
|
+
return { size, symbolSize: code.size, modules };
|
|
40
|
+
}
|
|
41
|
+
/** max(25 mm, 0.5 mm × (symbol modules per side + 8)): the 8 is the two four-module borders. */
|
|
42
|
+
export function qrMinimumWidthMm(url) {
|
|
43
|
+
const { size } = qrMatrix(url);
|
|
44
|
+
return Math.max(QR_MIN_WIDTH_MM, QR_MIN_MODULE_MM * size);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Black on white, sized only by its viewBox (one unit per module), so it prints at
|
|
48
|
+
* whatever physical width the owner chooses without resampling.
|
|
49
|
+
*/
|
|
50
|
+
export function qrSvg(url) {
|
|
51
|
+
const { size, modules } = qrMatrix(url);
|
|
52
|
+
const parts = [];
|
|
53
|
+
modules.forEach((row, y) => {
|
|
54
|
+
row.forEach((dark, x) => {
|
|
55
|
+
if (dark)
|
|
56
|
+
parts.push(`M${x},${y}h1v1h-1z`);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
return [
|
|
60
|
+
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${size} ${size}" shape-rendering="crispEdges">`,
|
|
61
|
+
`<rect width="${size}" height="${size}" fill="#ffffff"/>`,
|
|
62
|
+
`<path d="${parts.join("")}" fill="#000000"/>`,
|
|
63
|
+
`</svg>`,
|
|
64
|
+
].join("");
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Two module rows per text line using half blocks. LIGHT modules are drawn and dark ones
|
|
68
|
+
* left blank, so on the usual dark-background terminal the code reads dark-on-light, the
|
|
69
|
+
* polarity phone cameras expect. The size is always odd, so the last line's lower half lies
|
|
70
|
+
* past the matrix and is drawn light: a little more quiet zone, never a missing module.
|
|
71
|
+
*/
|
|
72
|
+
export function qrTerminal(url) {
|
|
73
|
+
const { size, modules } = qrMatrix(url);
|
|
74
|
+
const lines = [];
|
|
75
|
+
for (let y = 0; y < size; y += 2) {
|
|
76
|
+
let line = "";
|
|
77
|
+
for (let x = 0; x < size; x++) {
|
|
78
|
+
const top = !(modules[y]?.[x] ?? false);
|
|
79
|
+
const bottom = !(modules[y + 1]?.[x] ?? false);
|
|
80
|
+
line += top && bottom ? "█" : top ? "▀" : bottom ? "▄" : " ";
|
|
81
|
+
}
|
|
82
|
+
lines.push(line);
|
|
83
|
+
}
|
|
84
|
+
return lines;
|
|
85
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
export declare namespace qrcodegen {
|
|
2
|
+
type bit = number;
|
|
3
|
+
type byte = number;
|
|
4
|
+
type int = number;
|
|
5
|
+
export class QrCode {
|
|
6
|
+
readonly version: int;
|
|
7
|
+
readonly errorCorrectionLevel: QrCode.Ecc;
|
|
8
|
+
static encodeText(text: string, ecl: QrCode.Ecc): QrCode;
|
|
9
|
+
static encodeBinary(data: Readonly<Array<byte>>, ecl: QrCode.Ecc): QrCode;
|
|
10
|
+
static encodeSegments(segs: Readonly<Array<QrSegment>>, ecl: QrCode.Ecc, minVersion?: int, maxVersion?: int, mask?: int, boostEcl?: boolean): QrCode;
|
|
11
|
+
readonly size: int;
|
|
12
|
+
readonly mask: int;
|
|
13
|
+
private readonly modules;
|
|
14
|
+
private readonly isFunction;
|
|
15
|
+
constructor(version: int, errorCorrectionLevel: QrCode.Ecc, dataCodewords: Readonly<Array<byte>>, msk: int);
|
|
16
|
+
getModule(x: int, y: int): boolean;
|
|
17
|
+
private drawFunctionPatterns;
|
|
18
|
+
private drawFormatBits;
|
|
19
|
+
private drawVersion;
|
|
20
|
+
private drawFinderPattern;
|
|
21
|
+
private drawAlignmentPattern;
|
|
22
|
+
private setFunctionModule;
|
|
23
|
+
private addEccAndInterleave;
|
|
24
|
+
private drawCodewords;
|
|
25
|
+
private applyMask;
|
|
26
|
+
private getPenaltyScore;
|
|
27
|
+
private getAlignmentPatternPositions;
|
|
28
|
+
private static getNumRawDataModules;
|
|
29
|
+
private static getNumDataCodewords;
|
|
30
|
+
private static reedSolomonComputeDivisor;
|
|
31
|
+
private static reedSolomonComputeRemainder;
|
|
32
|
+
private static reedSolomonMultiply;
|
|
33
|
+
private finderPenaltyCountPatterns;
|
|
34
|
+
private finderPenaltyTerminateAndCount;
|
|
35
|
+
private finderPenaltyAddHistory;
|
|
36
|
+
static readonly MIN_VERSION: int;
|
|
37
|
+
static readonly MAX_VERSION: int;
|
|
38
|
+
private static readonly PENALTY_N1;
|
|
39
|
+
private static readonly PENALTY_N2;
|
|
40
|
+
private static readonly PENALTY_N3;
|
|
41
|
+
private static readonly PENALTY_N4;
|
|
42
|
+
private static readonly ECC_CODEWORDS_PER_BLOCK;
|
|
43
|
+
private static readonly NUM_ERROR_CORRECTION_BLOCKS;
|
|
44
|
+
}
|
|
45
|
+
export class QrSegment {
|
|
46
|
+
readonly mode: QrSegment.Mode;
|
|
47
|
+
readonly numChars: int;
|
|
48
|
+
private readonly bitData;
|
|
49
|
+
static makeBytes(data: Readonly<Array<byte>>): QrSegment;
|
|
50
|
+
static makeNumeric(digits: string): QrSegment;
|
|
51
|
+
static makeAlphanumeric(text: string): QrSegment;
|
|
52
|
+
static makeSegments(text: string): Array<QrSegment>;
|
|
53
|
+
static makeEci(assignVal: int): QrSegment;
|
|
54
|
+
static isNumeric(text: string): boolean;
|
|
55
|
+
static isAlphanumeric(text: string): boolean;
|
|
56
|
+
constructor(mode: QrSegment.Mode, numChars: int, bitData: Array<bit>);
|
|
57
|
+
getData(): Array<bit>;
|
|
58
|
+
static getTotalBits(segs: Readonly<Array<QrSegment>>, version: int): number;
|
|
59
|
+
private static toUtf8ByteArray;
|
|
60
|
+
private static readonly NUMERIC_REGEX;
|
|
61
|
+
private static readonly ALPHANUMERIC_REGEX;
|
|
62
|
+
private static readonly ALPHANUMERIC_CHARSET;
|
|
63
|
+
}
|
|
64
|
+
export {};
|
|
65
|
+
}
|
|
66
|
+
export declare namespace qrcodegen.QrCode {
|
|
67
|
+
type int = number;
|
|
68
|
+
export class Ecc {
|
|
69
|
+
readonly ordinal: int;
|
|
70
|
+
readonly formatBits: int;
|
|
71
|
+
static readonly LOW: Ecc;
|
|
72
|
+
static readonly MEDIUM: Ecc;
|
|
73
|
+
static readonly QUARTILE: Ecc;
|
|
74
|
+
static readonly HIGH: Ecc;
|
|
75
|
+
private constructor();
|
|
76
|
+
}
|
|
77
|
+
export {};
|
|
78
|
+
}
|
|
79
|
+
export declare namespace qrcodegen.QrSegment {
|
|
80
|
+
type int = number;
|
|
81
|
+
export class Mode {
|
|
82
|
+
readonly modeBits: int;
|
|
83
|
+
private readonly numBitsCharCount;
|
|
84
|
+
static readonly NUMERIC: Mode;
|
|
85
|
+
static readonly ALPHANUMERIC: Mode;
|
|
86
|
+
static readonly BYTE: Mode;
|
|
87
|
+
static readonly KANJI: Mode;
|
|
88
|
+
static readonly ECI: Mode;
|
|
89
|
+
private constructor();
|
|
90
|
+
numCharCountBits(ver: int): int;
|
|
91
|
+
}
|
|
92
|
+
export {};
|
|
93
|
+
}
|