@fayz-ai/core 0.19.1 → 0.22.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/dist/{chunk-H6XDQXN5.js → chunk-UZEVKHLS.js} +73 -6
- package/dist/chunk-UZEVKHLS.js.map +1 -0
- package/dist/{chunk-S3EEGDEK.js → chunk-XJGV7TWQ.js} +4 -3
- package/dist/chunk-XJGV7TWQ.js.map +1 -0
- package/dist/data/index.js +1 -1
- package/dist/data/resolve.d.ts.map +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/i18n/shell-translations.en.d.ts.map +1 -1
- package/dist/i18n/shell-translations.pt-br.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +43 -5
- package/dist/index.js.map +1 -1
- package/dist/lib/pending-command.d.ts +15 -0
- package/dist/lib/pending-command.d.ts.map +1 -0
- package/dist/printing/escpos.d.ts +42 -0
- package/dist/printing/escpos.d.ts.map +1 -0
- package/dist/printing/index.d.ts +6 -0
- package/dist/printing/index.d.ts.map +1 -0
- package/dist/printing/index.js +509 -0
- package/dist/printing/index.js.map +1 -0
- package/dist/printing/print-job.d.ts +129 -0
- package/dist/printing/print-job.d.ts.map +1 -0
- package/dist/printing/printer.d.ts +25 -0
- package/dist/printing/printer.d.ts.map +1 -0
- package/dist/{shell-translations.pt-br-GFBWBZZJ.js → shell-translations.pt-br-SZ4EIDJS.js} +70 -3
- package/dist/shell-translations.pt-br-SZ4EIDJS.js.map +1 -0
- package/dist/types/crud.d.ts +39 -0
- package/dist/types/crud.d.ts.map +1 -1
- package/dist/types/org.d.ts +5 -0
- package/dist/types/org.d.ts.map +1 -1
- package/dist/types/plugins.d.ts +11 -0
- package/dist/types/plugins.d.ts.map +1 -1
- package/dist/types/setup-guide.d.ts +23 -0
- package/dist/types/setup-guide.d.ts.map +1 -1
- package/package.json +5 -1
- package/dist/chunk-H6XDQXN5.js.map +0 -1
- package/dist/chunk-S3EEGDEK.js.map +0 -1
- package/dist/shell-translations.pt-br-GFBWBZZJ.js.map +0 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** An acknowledged SQL rejection is different from losing the response. */
|
|
2
|
+
export declare function isSqlRejection(error: unknown): boolean;
|
|
3
|
+
/**
|
|
4
|
+
* In-memory command attempt for a mounted editor. A retry sends an immutable
|
|
5
|
+
* snapshot with the same key; it cannot turn into a different payment/entry.
|
|
6
|
+
* This is not durable recovery after reload and must never be advertised as it.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createPendingCommand<Input extends {
|
|
9
|
+
idempotencyKey?: string;
|
|
10
|
+
}>(key: () => string, context?: (input: Input) => string): {
|
|
11
|
+
readonly pending: boolean;
|
|
12
|
+
readonly running: boolean;
|
|
13
|
+
run<Result>(input: Input, write: (snapshot: Input) => Promise<Result>): Promise<Result>;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=pending-command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pending-command.d.ts","sourceRoot":"","sources":["../../src/lib/pending-command.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAGtD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,SAAS;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,EAC5E,GAAG,EAAE,MAAM,MAAM,EACjB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM;;;QAQtB,MAAM,SAAS,KAAK,SAAS,CAAC,QAAQ,EAAE,KAAK,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;EAuBhG"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { PaperWidth, PrintJob } from './print-job';
|
|
2
|
+
/** `ESC t` index per code page. The pair (index, table) must always match. */
|
|
3
|
+
declare const CODEPAGES: {
|
|
4
|
+
readonly cp860: {
|
|
5
|
+
readonly index: 3;
|
|
6
|
+
readonly table: Record<string, number>;
|
|
7
|
+
};
|
|
8
|
+
readonly cp850: {
|
|
9
|
+
readonly index: 2;
|
|
10
|
+
readonly table: Record<string, number>;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
export type Codepage = keyof typeof CODEPAGES;
|
|
14
|
+
/**
|
|
15
|
+
* Encodes a QR payload into a module matrix (`true` = dark).
|
|
16
|
+
*
|
|
17
|
+
* Injected rather than bundled: core carries no QR library, and every surface
|
|
18
|
+
* that prints already has one — the browser can hand over a canvas-derived
|
|
19
|
+
* matrix, a worker can use whatever the app installed.
|
|
20
|
+
*/
|
|
21
|
+
export type QrEncoder = (payload: string) => boolean[][];
|
|
22
|
+
export interface EscPosOptions {
|
|
23
|
+
width?: PaperWidth;
|
|
24
|
+
/** Defaults to CP860 — the code page the Brazilian panels answer to. */
|
|
25
|
+
codepage?: Codepage;
|
|
26
|
+
/** Printable dots. Defaults to 12 per character column (48 chars = 576). */
|
|
27
|
+
dots?: number;
|
|
28
|
+
qr?: QrEncoder;
|
|
29
|
+
/** Dots per QR module. 7 is comfortably scannable; 5 halves the payload. */
|
|
30
|
+
qrModuleScale?: number;
|
|
31
|
+
/**
|
|
32
|
+
* This document emends onto one already on the paper, so it must not reset.
|
|
33
|
+
*
|
|
34
|
+
* Set it on every document of a strip except the first. The reset is not
|
|
35
|
+
* merely redundant there — `ESC @` immediately after a partial cut completes
|
|
36
|
+
* that cut, which is exactly what a strip is trying to avoid.
|
|
37
|
+
*/
|
|
38
|
+
continued?: boolean;
|
|
39
|
+
}
|
|
40
|
+
export declare function renderEscPos(job: PrintJob, options?: EscPosOptions): Uint8Array;
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=escpos.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escpos.d.ts","sourceRoot":"","sources":["../../src/printing/escpos.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAyD,UAAU,EAAE,QAAQ,EAAa,MAAM,aAAa,CAAA;AAwDzH,8EAA8E;AAC9E,QAAA,MAAM,SAAS;;;;;;;;;CAGL,CAAA;AAEV,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,SAAS,CAAA;AAwK7C;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,EAAE,EAAE,CAAA;AAExD,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,EAAE,CAAC,EAAE,SAAS,CAAA;IACd,4EAA4E;IAC5E,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,GAAE,aAAkB,GAAG,UAAU,CAkBnF"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { renderEscPos } from './escpos';
|
|
2
|
+
export type { EscPosOptions, Codepage, QrEncoder } from './escpos';
|
|
3
|
+
export { memoryPrinter } from './printer';
|
|
4
|
+
export type { PrinterPort, PrintResult } from './printer';
|
|
5
|
+
export type { PrintJob, PrintLine, PaperWidth, KitchenTicket, CustomerTicket, TicketPromo, BillJob, FiscalReceipt, } from './print-job';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/printing/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AACzC,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AACzD,YAAY,EACV,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,GACpG,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
// src/printing/escpos.ts
|
|
2
|
+
var formatCents = (cents) => new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL" }).format(cents / 100);
|
|
3
|
+
var ESC = 27;
|
|
4
|
+
var GS = 29;
|
|
5
|
+
var CP860 = {
|
|
6
|
+
"\xC7": 128,
|
|
7
|
+
"\xFC": 129,
|
|
8
|
+
"\xE9": 130,
|
|
9
|
+
"\xE2": 131,
|
|
10
|
+
"\xE3": 132,
|
|
11
|
+
"\xE0": 133,
|
|
12
|
+
"\xC1": 134,
|
|
13
|
+
"\xE7": 135,
|
|
14
|
+
"\xEA": 136,
|
|
15
|
+
"\xCA": 137,
|
|
16
|
+
"\xE8": 138,
|
|
17
|
+
"\xCD": 139,
|
|
18
|
+
"\xD4": 140,
|
|
19
|
+
"\xEC": 141,
|
|
20
|
+
"\xC3": 142,
|
|
21
|
+
"\xC2": 143,
|
|
22
|
+
"\xC9": 144,
|
|
23
|
+
"\xC0": 145,
|
|
24
|
+
"\xC8": 146,
|
|
25
|
+
"\xF4": 147,
|
|
26
|
+
"\xF5": 148,
|
|
27
|
+
"\xF2": 149,
|
|
28
|
+
"\xDA": 150,
|
|
29
|
+
"\xF9": 151,
|
|
30
|
+
"\xCC": 152,
|
|
31
|
+
"\xD5": 153,
|
|
32
|
+
"\xDC": 154,
|
|
33
|
+
"\xA2": 155,
|
|
34
|
+
"\xA3": 156,
|
|
35
|
+
"\xD9": 157,
|
|
36
|
+
"\u20A7": 158,
|
|
37
|
+
"\xD3": 159,
|
|
38
|
+
"\xE1": 160,
|
|
39
|
+
"\xED": 161,
|
|
40
|
+
"\xF3": 162,
|
|
41
|
+
"\xFA": 163,
|
|
42
|
+
"\xF1": 164,
|
|
43
|
+
"\xD1": 165,
|
|
44
|
+
"\xAA": 166,
|
|
45
|
+
"\xBA": 167,
|
|
46
|
+
"\xBF": 168,
|
|
47
|
+
"\xD2": 169,
|
|
48
|
+
"\xAC": 170,
|
|
49
|
+
"\xBD": 171,
|
|
50
|
+
"\xBC": 172,
|
|
51
|
+
"\xA1": 173,
|
|
52
|
+
"\xAB": 174,
|
|
53
|
+
"\xBB": 175,
|
|
54
|
+
"\u03B1": 224,
|
|
55
|
+
"\xDF": 225,
|
|
56
|
+
"\u0393": 226,
|
|
57
|
+
"\u03C0": 227,
|
|
58
|
+
"\u03A3": 228,
|
|
59
|
+
"\u03C3": 229,
|
|
60
|
+
"\xB5": 230,
|
|
61
|
+
"\u03C4": 231,
|
|
62
|
+
"\u03A6": 232,
|
|
63
|
+
"\u0398": 233,
|
|
64
|
+
"\u03A9": 234,
|
|
65
|
+
"\u03B4": 235,
|
|
66
|
+
"\u221E": 236,
|
|
67
|
+
"\u03C6": 237,
|
|
68
|
+
"\u03B5": 238,
|
|
69
|
+
"\u2229": 239,
|
|
70
|
+
"\u2261": 240,
|
|
71
|
+
"\xB1": 241,
|
|
72
|
+
"\u2265": 242,
|
|
73
|
+
"\u2264": 243,
|
|
74
|
+
"\u2320": 244,
|
|
75
|
+
"\u2321": 245,
|
|
76
|
+
"\xF7": 246,
|
|
77
|
+
"\u2248": 247,
|
|
78
|
+
"\xB0": 248,
|
|
79
|
+
"\u2219": 249,
|
|
80
|
+
"\xB7": 250,
|
|
81
|
+
"\u221A": 251,
|
|
82
|
+
"\u207F": 252,
|
|
83
|
+
"\xB2": 253,
|
|
84
|
+
"\u25A0": 254,
|
|
85
|
+
"\xA0": 255
|
|
86
|
+
};
|
|
87
|
+
var CP850 = {
|
|
88
|
+
"\xC7": 128,
|
|
89
|
+
"\xFC": 129,
|
|
90
|
+
"\xE9": 130,
|
|
91
|
+
"\xE2": 131,
|
|
92
|
+
"\xE4": 132,
|
|
93
|
+
"\xE0": 133,
|
|
94
|
+
"\xE5": 134,
|
|
95
|
+
"\xE7": 135,
|
|
96
|
+
"\xEA": 136,
|
|
97
|
+
"\xEB": 137,
|
|
98
|
+
"\xE8": 138,
|
|
99
|
+
"\xEF": 139,
|
|
100
|
+
"\xEE": 140,
|
|
101
|
+
"\xEC": 141,
|
|
102
|
+
"\xC4": 142,
|
|
103
|
+
"\xC5": 143,
|
|
104
|
+
"\xC9": 144,
|
|
105
|
+
"\xE6": 145,
|
|
106
|
+
"\xC6": 146,
|
|
107
|
+
"\xF4": 147,
|
|
108
|
+
"\xF6": 148,
|
|
109
|
+
"\xF2": 149,
|
|
110
|
+
"\xFB": 150,
|
|
111
|
+
"\xF9": 151,
|
|
112
|
+
"\xFF": 152,
|
|
113
|
+
"\xD6": 153,
|
|
114
|
+
"\xDC": 154,
|
|
115
|
+
"\xF8": 155,
|
|
116
|
+
"\xA3": 156,
|
|
117
|
+
"\xD8": 157,
|
|
118
|
+
"\xD7": 158,
|
|
119
|
+
"\u0192": 159,
|
|
120
|
+
"\xE1": 160,
|
|
121
|
+
"\xED": 161,
|
|
122
|
+
"\xF3": 162,
|
|
123
|
+
"\xFA": 163,
|
|
124
|
+
"\xF1": 164,
|
|
125
|
+
"\xD1": 165,
|
|
126
|
+
"\xAA": 166,
|
|
127
|
+
"\xBA": 167,
|
|
128
|
+
"\xBF": 168,
|
|
129
|
+
"\xAE": 169,
|
|
130
|
+
"\xAC": 170,
|
|
131
|
+
"\xBD": 171,
|
|
132
|
+
"\xBC": 172,
|
|
133
|
+
"\xA1": 173,
|
|
134
|
+
"\xAB": 174,
|
|
135
|
+
"\xBB": 175,
|
|
136
|
+
"\xC1": 181,
|
|
137
|
+
"\xC2": 182,
|
|
138
|
+
"\xC0": 183,
|
|
139
|
+
"\xA9": 184,
|
|
140
|
+
"\xA2": 189,
|
|
141
|
+
"\xA5": 190,
|
|
142
|
+
"\xE3": 198,
|
|
143
|
+
"\xC3": 199,
|
|
144
|
+
"\xA4": 207,
|
|
145
|
+
"\xF0": 208,
|
|
146
|
+
"\xD0": 209,
|
|
147
|
+
"\xCA": 210,
|
|
148
|
+
"\xCB": 211,
|
|
149
|
+
"\xC8": 212,
|
|
150
|
+
"\u0131": 213,
|
|
151
|
+
"\xCD": 214,
|
|
152
|
+
"\xCE": 215,
|
|
153
|
+
"\xCF": 216,
|
|
154
|
+
"\xA6": 221,
|
|
155
|
+
"\xCC": 222,
|
|
156
|
+
"\xD3": 224,
|
|
157
|
+
"\xDF": 225,
|
|
158
|
+
"\xD4": 226,
|
|
159
|
+
"\xD2": 227,
|
|
160
|
+
"\xF5": 228,
|
|
161
|
+
"\xD5": 229,
|
|
162
|
+
"\xB5": 230,
|
|
163
|
+
"\xFE": 231,
|
|
164
|
+
"\xDE": 232,
|
|
165
|
+
"\xDA": 233,
|
|
166
|
+
"\xDB": 234,
|
|
167
|
+
"\xD9": 235,
|
|
168
|
+
"\xFD": 236,
|
|
169
|
+
"\xDD": 237,
|
|
170
|
+
"\xAF": 238,
|
|
171
|
+
"\xB4": 239,
|
|
172
|
+
"\xAD": 240,
|
|
173
|
+
"\xB1": 241,
|
|
174
|
+
"\u2017": 242,
|
|
175
|
+
"\xBE": 243,
|
|
176
|
+
"\xB6": 244,
|
|
177
|
+
"\xA7": 245,
|
|
178
|
+
"\xF7": 246,
|
|
179
|
+
"\xB8": 247,
|
|
180
|
+
"\xB0": 248,
|
|
181
|
+
"\xA8": 249,
|
|
182
|
+
"\xB7": 250,
|
|
183
|
+
"\xB9": 251,
|
|
184
|
+
"\xB3": 252,
|
|
185
|
+
"\xB2": 253,
|
|
186
|
+
"\u25A0": 254,
|
|
187
|
+
"\xA0": 255
|
|
188
|
+
};
|
|
189
|
+
var FOLD = { "\u2013": "-", "\u2014": "-", "\u2018": "'", "\u2019": "'", "\u201C": '"', "\u201D": '"', "\u2026": "..." };
|
|
190
|
+
var CODEPAGES = {
|
|
191
|
+
cp860: { index: 3, table: CP860 },
|
|
192
|
+
cp850: { index: 2, table: CP850 }
|
|
193
|
+
};
|
|
194
|
+
function encode(text, table) {
|
|
195
|
+
const out = [];
|
|
196
|
+
for (const char of text) {
|
|
197
|
+
const mapped = table[char];
|
|
198
|
+
if (mapped !== void 0) {
|
|
199
|
+
out.push(mapped);
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
const folded = FOLD[char];
|
|
203
|
+
if (folded !== void 0) {
|
|
204
|
+
for (const c of folded) out.push(c.charCodeAt(0));
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
const code = char.charCodeAt(0);
|
|
208
|
+
out.push(code >= 32 && code <= 126 ? code : 63);
|
|
209
|
+
}
|
|
210
|
+
return out;
|
|
211
|
+
}
|
|
212
|
+
var Ribbon = class {
|
|
213
|
+
constructor(opts) {
|
|
214
|
+
this.opts = opts;
|
|
215
|
+
this.bytes = [];
|
|
216
|
+
this.width = opts.width;
|
|
217
|
+
}
|
|
218
|
+
raw(...bytes) {
|
|
219
|
+
this.bytes.push(...bytes);
|
|
220
|
+
return this;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Initialize, then select the code page. ESC @ resets it, so order matters.
|
|
224
|
+
*
|
|
225
|
+
* Skipped entirely for a continued document. `ESC @` arriving just after the
|
|
226
|
+
* previous document's partial cut makes the printer finish that cut, and the
|
|
227
|
+
* ticket meant to stay attached falls on the floor.
|
|
228
|
+
*/
|
|
229
|
+
init() {
|
|
230
|
+
if (this.opts.continued) return this;
|
|
231
|
+
return this.raw(ESC, 64).raw(ESC, 116, CODEPAGES[this.opts.codepage].index);
|
|
232
|
+
}
|
|
233
|
+
align(at) {
|
|
234
|
+
return this.raw(ESC, 97, at === "center" ? 1 : at === "right" ? 2 : 0);
|
|
235
|
+
}
|
|
236
|
+
bold(on) {
|
|
237
|
+
return this.raw(ESC, 69, on ? 1 : 0);
|
|
238
|
+
}
|
|
239
|
+
/** GS ! packs width and height into one byte as two 4-bit multipliers. */
|
|
240
|
+
size(w, h) {
|
|
241
|
+
return this.raw(GS, 33, w - 1 << 4 | h - 1);
|
|
242
|
+
}
|
|
243
|
+
text(value) {
|
|
244
|
+
this.bytes.push(...encode(value, CODEPAGES[this.opts.codepage].table));
|
|
245
|
+
return this;
|
|
246
|
+
}
|
|
247
|
+
line(value = "") {
|
|
248
|
+
return this.text(value).raw(10);
|
|
249
|
+
}
|
|
250
|
+
feed(lines) {
|
|
251
|
+
return this.raw(ESC, 100, lines);
|
|
252
|
+
}
|
|
253
|
+
rule(char = "-") {
|
|
254
|
+
return this.line(char.repeat(this.width));
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Name left, value right, on one line. Wraps the name rather than letting a
|
|
258
|
+
* long product push the price off the paper — a receipt whose total is not
|
|
259
|
+
* on it is not a receipt.
|
|
260
|
+
*/
|
|
261
|
+
columns(left, right, indent = 0) {
|
|
262
|
+
const room = this.width - right.length - indent - 1;
|
|
263
|
+
const pad = " ".repeat(indent);
|
|
264
|
+
if (room <= 0) return this.line(left).line(right.padStart(this.width));
|
|
265
|
+
const [head, ...rest] = wrap(left, room);
|
|
266
|
+
this.line(`${pad}${(head ?? "").padEnd(room)} ${right}`);
|
|
267
|
+
for (const extra of rest) this.line(`${pad}${extra}`);
|
|
268
|
+
return this;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* A 1-bit bitmap as `GS v 0`. Rows are packed MSB-first and every row is
|
|
272
|
+
* `dots / 8` bytes wide, padded — the printer reads a fixed stride and a
|
|
273
|
+
* short row shears the whole image diagonally.
|
|
274
|
+
*/
|
|
275
|
+
raster(rows, heightDots) {
|
|
276
|
+
const perRow = this.opts.dots >> 3;
|
|
277
|
+
return this.raw(
|
|
278
|
+
GS,
|
|
279
|
+
118,
|
|
280
|
+
48,
|
|
281
|
+
0,
|
|
282
|
+
perRow & 255,
|
|
283
|
+
perRow >> 8 & 255,
|
|
284
|
+
heightDots & 255,
|
|
285
|
+
heightDots >> 8 & 255
|
|
286
|
+
).raw(...rows);
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* QR as a raster bitmap, NOT as `GS ( k`.
|
|
290
|
+
*
|
|
291
|
+
* The panel's Masung answers `GS k` (1D barcode) and `GS v 0` (raster) but
|
|
292
|
+
* ignores every `GS ( k` variant — model 1 and 2, three module sizes, three
|
|
293
|
+
* error levels all printed nothing and reported no error. Cheap ESC/POS
|
|
294
|
+
* clones commonly skip the QR command set, so drawing the modules ourselves
|
|
295
|
+
* is the only version that is portable across the hardware a restaurant
|
|
296
|
+
* actually buys.
|
|
297
|
+
*/
|
|
298
|
+
/** Há codificador? Um QR prometido e não desenhado é pior que nenhum. */
|
|
299
|
+
canQr() {
|
|
300
|
+
return Boolean(this.opts.qr);
|
|
301
|
+
}
|
|
302
|
+
qr(payload) {
|
|
303
|
+
if (!this.opts.qr) throw new Error("renderEscPos: a QR encoder is required to print this job.");
|
|
304
|
+
const matrix = this.opts.qr(payload);
|
|
305
|
+
const modules = matrix.length;
|
|
306
|
+
if (!modules) throw new Error("renderEscPos: the QR encoder returned an empty matrix.");
|
|
307
|
+
const scale = this.opts.qrModuleScale;
|
|
308
|
+
const quiet = 2;
|
|
309
|
+
const side = (modules + quiet * 2) * scale;
|
|
310
|
+
const perRow = this.opts.dots >> 3;
|
|
311
|
+
const left = Math.max(0, this.opts.dots - side >> 1 & -8);
|
|
312
|
+
const rows = new Uint8Array(perRow * side);
|
|
313
|
+
for (let y = 0; y < side; y++) {
|
|
314
|
+
const my = Math.floor(y / scale) - quiet;
|
|
315
|
+
if (my < 0 || my >= modules) continue;
|
|
316
|
+
const row = matrix[my];
|
|
317
|
+
if (!row) continue;
|
|
318
|
+
for (let x = 0; x < side; x++) {
|
|
319
|
+
const mx = Math.floor(x / scale) - quiet;
|
|
320
|
+
if (mx < 0 || mx >= modules || !row[mx]) continue;
|
|
321
|
+
const px = left + x;
|
|
322
|
+
if (px >= this.opts.dots) continue;
|
|
323
|
+
rows[y * perRow + (px >> 3)] |= 128 >> (px & 7);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return this.raster(rows, side);
|
|
327
|
+
}
|
|
328
|
+
/** Pin 2, 50ms on / 250ms off — the timing every BR drawer ships wired for. */
|
|
329
|
+
drawer() {
|
|
330
|
+
return this.raw(ESC, 112, 0, 50, 250);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Partial cut, with the paper held by a tab.
|
|
334
|
+
*
|
|
335
|
+
* Three details, all of them measured on a Masung POS80 rather than chosen:
|
|
336
|
+
*
|
|
337
|
+
* GS V 1 Plain partial cut. `GS V 66 n` — "feed then partial" — is the
|
|
338
|
+
* tidier-looking command and this printer severs the paper
|
|
339
|
+
* completely when it is followed by more content.
|
|
340
|
+
* bare LFs `ESC d n` before the cut had the same effect. Line feeds do
|
|
341
|
+
* not.
|
|
342
|
+
* three Enough to clear the cutter, which sits a few millimetres above
|
|
343
|
+
* the head; fewer and the cut lands in the last line.
|
|
344
|
+
*
|
|
345
|
+
* A document that emends onto another must also skip `init()` — see
|
|
346
|
+
* `EscPosOptions.continued`. `ESC @` landing right after a partial cut
|
|
347
|
+
* finishes it.
|
|
348
|
+
*/
|
|
349
|
+
cut() {
|
|
350
|
+
return this.raw(10, 10, 10).raw(GS, 86, 1);
|
|
351
|
+
}
|
|
352
|
+
done() {
|
|
353
|
+
return Uint8Array.from(this.bytes);
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
function wrap(text, width) {
|
|
357
|
+
const out = [];
|
|
358
|
+
let current = "";
|
|
359
|
+
for (const word of text.split(/\s+/).filter(Boolean)) {
|
|
360
|
+
if (!current) {
|
|
361
|
+
current = word;
|
|
362
|
+
} else if (current.length + 1 + word.length <= width) {
|
|
363
|
+
current += ` ${word}`;
|
|
364
|
+
} else {
|
|
365
|
+
out.push(current);
|
|
366
|
+
current = word;
|
|
367
|
+
}
|
|
368
|
+
while (current.length > width) {
|
|
369
|
+
out.push(current.slice(0, width));
|
|
370
|
+
current = current.slice(width);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
if (current) out.push(current);
|
|
374
|
+
return out.length ? out : [""];
|
|
375
|
+
}
|
|
376
|
+
var time = (at) => new Intl.DateTimeFormat("pt-BR", { dateStyle: "short", timeStyle: "short", timeZone: "America/Sao_Paulo" }).format(at);
|
|
377
|
+
var groupKey = (key) => (key.match(/.{1,4}/g) ?? []).join(" ");
|
|
378
|
+
function renderEscPos(job, options = {}) {
|
|
379
|
+
const width = options.width ?? 48;
|
|
380
|
+
const resolved = {
|
|
381
|
+
width,
|
|
382
|
+
dots: options.dots ?? width * 12,
|
|
383
|
+
codepage: options.codepage ?? "cp860",
|
|
384
|
+
qrModuleScale: options.qrModuleScale ?? 7,
|
|
385
|
+
continued: options.continued ?? false,
|
|
386
|
+
...options.qr ? { qr: options.qr } : {}
|
|
387
|
+
};
|
|
388
|
+
const r = new Ribbon(resolved).init();
|
|
389
|
+
if (job.kind === "kitchen_ticket") kitchen(r, job);
|
|
390
|
+
else if (job.kind === "customer_ticket") customer(r, job);
|
|
391
|
+
else if (job.kind === "bill") bill(r, job);
|
|
392
|
+
else fiscal(r, job);
|
|
393
|
+
if (job.openDrawer) r.drawer();
|
|
394
|
+
if (job.cut !== false) r.cut();
|
|
395
|
+
return r.done();
|
|
396
|
+
}
|
|
397
|
+
function kitchen(r, job) {
|
|
398
|
+
r.align("center").size(3, 3).bold(true).line(job.ticket).bold(false).size(1, 1);
|
|
399
|
+
r.line(job.serviceMode.toUpperCase()).line(time(job.placedAt)).rule().align("left");
|
|
400
|
+
for (const line of job.lines) {
|
|
401
|
+
r.size(1, 2).bold(true).text(`${line.quantity}x `).bold(false);
|
|
402
|
+
for (const [i, part] of wrap(line.name, r.width - 4).entries()) r.line(i === 0 ? part : ` ${part}`);
|
|
403
|
+
r.size(1, 1);
|
|
404
|
+
if (line.note) for (const part of wrap(line.note, r.width - 4)) r.line(` ${part}`);
|
|
405
|
+
}
|
|
406
|
+
if (job.notes) {
|
|
407
|
+
r.rule().bold(true).line("OBS:").bold(false);
|
|
408
|
+
for (const p of wrap(job.notes, r.width)) r.line(p);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
function customer(r, job) {
|
|
412
|
+
r.align("center").bold(true).line(job.brandName).bold(false).feed(1);
|
|
413
|
+
r.size(4, 4).bold(true).line(job.ticket).bold(false).size(1, 1);
|
|
414
|
+
r.line(job.serviceMode.toUpperCase()).line(job.reference).feed(1);
|
|
415
|
+
r.size(1, 2).line(formatCents(job.totalCents)).size(1, 1);
|
|
416
|
+
if (!job.paid) r.feed(1).bold(true).line("PENDENTE").line("PASSE NO CAIXA").bold(false);
|
|
417
|
+
if (job.footer) {
|
|
418
|
+
r.feed(1);
|
|
419
|
+
for (const part of wrap(job.footer, r.width)) r.line(part);
|
|
420
|
+
}
|
|
421
|
+
promo(r, job);
|
|
422
|
+
}
|
|
423
|
+
function promo(r, job) {
|
|
424
|
+
const promo2 = job.promo;
|
|
425
|
+
if (!promo2 || !promo2.headline && !promo2.offer && !promo2.site && !promo2.qr) return;
|
|
426
|
+
r.feed(1).rule();
|
|
427
|
+
if (promo2.headline) {
|
|
428
|
+
r.bold(true);
|
|
429
|
+
for (const part of wrap(promo2.headline, r.width)) r.line(part);
|
|
430
|
+
r.bold(false);
|
|
431
|
+
}
|
|
432
|
+
if (promo2.offer) {
|
|
433
|
+
r.feed(1).bold(true).size(2, 2);
|
|
434
|
+
for (const part of wrap(promo2.offer, Math.floor(r.width / 2))) r.line(part);
|
|
435
|
+
r.size(1, 1).bold(false).feed(1);
|
|
436
|
+
}
|
|
437
|
+
if (promo2.site) r.line(promo2.site);
|
|
438
|
+
if (promo2.qr && r.canQr()) r.feed(1).qr(promo2.qr);
|
|
439
|
+
}
|
|
440
|
+
function bill(r, job) {
|
|
441
|
+
r.align("center").bold(true).line(job.brandName).bold(false).line(job.reference).rule().align("left");
|
|
442
|
+
for (const line of job.lines) priced(r, line);
|
|
443
|
+
r.rule();
|
|
444
|
+
r.columns("Subtotal", formatCents(job.subtotalCents));
|
|
445
|
+
if (job.serviceChargeCents) r.columns("Servi\xE7o", formatCents(job.serviceChargeCents));
|
|
446
|
+
r.bold(true).size(1, 2).columns("TOTAL", formatCents(job.totalCents)).size(1, 1).bold(false);
|
|
447
|
+
r.align("center").feed(1);
|
|
448
|
+
for (const part of wrap(job.footer ?? "Este documento n\xE3o \xE9 documento fiscal", r.width)) r.line(part);
|
|
449
|
+
}
|
|
450
|
+
function priced(r, line) {
|
|
451
|
+
const total = (line.unitPriceCents ?? 0) * line.quantity;
|
|
452
|
+
r.columns(`${line.quantity}x ${line.name}`, formatCents(total));
|
|
453
|
+
if (line.note) for (const part of wrap(line.note, r.width - 4)) r.line(` ${part}`);
|
|
454
|
+
}
|
|
455
|
+
function fiscal(r, job) {
|
|
456
|
+
r.align("center").bold(true).line(job.emitter.name).bold(false);
|
|
457
|
+
r.line(`CNPJ: ${job.emitter.cnpj}`);
|
|
458
|
+
for (const part of wrap(job.emitter.address, r.width)) r.line(part);
|
|
459
|
+
r.rule();
|
|
460
|
+
for (const part of wrap("DANFE NFC-e - Documento Auxiliar da Nota Fiscal de Consumidor Eletr\xF4nica", r.width)) r.line(part);
|
|
461
|
+
if (job.homologation) {
|
|
462
|
+
r.rule("=").bold(true);
|
|
463
|
+
for (const part of wrap("EMITIDA EM AMBIENTE DE HOMOLOGA\xC7\xC3O - SEM VALOR FISCAL", r.width)) r.line(part);
|
|
464
|
+
r.bold(false).rule("=");
|
|
465
|
+
}
|
|
466
|
+
r.align("left").rule();
|
|
467
|
+
r.line("COD DESCRICAO QTD UN VL UN VL TOT");
|
|
468
|
+
r.rule();
|
|
469
|
+
for (const line of job.lines) {
|
|
470
|
+
r.line(`${line.code} ${line.name}`.slice(0, r.width));
|
|
471
|
+
r.columns(` ${line.quantity} ${line.unit} x ${formatCents(line.unitPriceCents ?? 0)}`, formatCents(line.totalCents));
|
|
472
|
+
}
|
|
473
|
+
r.rule();
|
|
474
|
+
r.columns("Qtd. total de itens", String(job.lines.length));
|
|
475
|
+
r.bold(true).size(1, 2).columns("VALOR TOTAL R$", formatCents(job.totalCents)).size(1, 1).bold(false);
|
|
476
|
+
for (const payment of job.payments) r.columns(payment.label, formatCents(payment.amountCents));
|
|
477
|
+
if (job.changeCents) r.columns("Troco", formatCents(job.changeCents));
|
|
478
|
+
r.rule().align("center");
|
|
479
|
+
for (const part of wrap("Consulte pela Chave de Acesso em", r.width)) r.line(part);
|
|
480
|
+
r.line(job.lookupUrl);
|
|
481
|
+
r.feed(1).line(groupKey(job.accessKey)).feed(1);
|
|
482
|
+
r.line(job.consumer?.document ? `CONSUMIDOR: ${job.consumer.document}` : "CONSUMIDOR NAO IDENTIFICADO");
|
|
483
|
+
if (job.consumer?.name) r.line(job.consumer.name);
|
|
484
|
+
r.rule();
|
|
485
|
+
r.line(`NFC-e n. ${job.number} Serie ${job.series}`);
|
|
486
|
+
r.line(time(job.issuedAt));
|
|
487
|
+
for (const part of wrap(`Protocolo de Autorizacao: ${job.protocol}`, r.width)) r.line(part);
|
|
488
|
+
r.feed(1).qr(job.qrCode);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// src/printing/printer.ts
|
|
492
|
+
function memoryPrinter(options = {}) {
|
|
493
|
+
const jobs = [];
|
|
494
|
+
return {
|
|
495
|
+
id: "memory",
|
|
496
|
+
get jobs() {
|
|
497
|
+
return jobs;
|
|
498
|
+
},
|
|
499
|
+
async print(job) {
|
|
500
|
+
jobs.push(job);
|
|
501
|
+
renderEscPos(job, options);
|
|
502
|
+
return { ok: true };
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
export { memoryPrinter, renderEscPos };
|
|
508
|
+
//# sourceMappingURL=index.js.map
|
|
509
|
+
//# sourceMappingURL=index.js.map
|