dazzle-zpl 0.1.2 → 0.2.0-beta.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/index.cjs +127 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -5
- package/dist/index.d.ts +52 -5
- package/dist/index.js +127 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -24,18 +24,87 @@ __export(index_exports, {
|
|
|
24
24
|
DazzleError: () => DazzleError
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
function toBase64(bytes) {
|
|
28
|
+
let binary = "";
|
|
29
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
30
|
+
binary += String.fromCharCode(bytes[i]);
|
|
31
|
+
}
|
|
32
|
+
return btoa(binary);
|
|
33
|
+
}
|
|
27
34
|
var Dazzle = class {
|
|
28
35
|
constructor(options) {
|
|
36
|
+
this.watchers = /* @__PURE__ */ new Set();
|
|
37
|
+
this.pollTimer = null;
|
|
38
|
+
this.pollInterval = 0;
|
|
39
|
+
this.lastStatus = null;
|
|
29
40
|
const host = options?.host ?? "localhost";
|
|
30
41
|
const port = options?.port ?? 29100;
|
|
31
42
|
const protocol = options?.protocol ?? "http";
|
|
32
43
|
this.baseUrl = `${protocol}://${host}:${port}`;
|
|
33
44
|
}
|
|
34
|
-
/**
|
|
45
|
+
/**
|
|
46
|
+
* Watch for server status changes. The callback fires immediately with
|
|
47
|
+
* the current status, then again whenever the status changes.
|
|
48
|
+
*
|
|
49
|
+
* Returns an unwatch function. When all watchers unsubscribe, polling stops.
|
|
50
|
+
*
|
|
51
|
+
* ```ts
|
|
52
|
+
* const unwatch = dazzle.watch((running) => {
|
|
53
|
+
* banner.classList.toggle('d-none', running);
|
|
54
|
+
* });
|
|
55
|
+
* // later: unwatch();
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
watch(callback, options) {
|
|
59
|
+
const interval = options?.interval ?? 5e3;
|
|
60
|
+
this.watchers.add(callback);
|
|
61
|
+
this.isRunning().then((running) => {
|
|
62
|
+
if (this.watchers.has(callback)) {
|
|
63
|
+
callback(running);
|
|
64
|
+
this.lastStatus = running;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
if (this.pollTimer === null || interval < this.pollInterval) {
|
|
68
|
+
this.startPolling(interval);
|
|
69
|
+
}
|
|
70
|
+
return () => {
|
|
71
|
+
this.watchers.delete(callback);
|
|
72
|
+
if (this.watchers.size === 0) {
|
|
73
|
+
this.stopPolling();
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
startPolling(interval) {
|
|
78
|
+
this.stopPolling();
|
|
79
|
+
this.pollInterval = interval;
|
|
80
|
+
this.pollTimer = setInterval(async () => {
|
|
81
|
+
const running = await this.isRunning();
|
|
82
|
+
if (running !== this.lastStatus) {
|
|
83
|
+
this.lastStatus = running;
|
|
84
|
+
for (const cb of this.watchers) {
|
|
85
|
+
cb(running);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}, interval);
|
|
89
|
+
}
|
|
90
|
+
stopPolling() {
|
|
91
|
+
if (this.pollTimer !== null) {
|
|
92
|
+
clearInterval(this.pollTimer);
|
|
93
|
+
this.pollTimer = null;
|
|
94
|
+
this.pollInterval = 0;
|
|
95
|
+
this.lastStatus = null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Check if the Dazzle server is reachable.
|
|
100
|
+
*
|
|
101
|
+
* Uses `no-cors` mode to avoid noisy CORS console errors when
|
|
102
|
+
* the server is not running.
|
|
103
|
+
*/
|
|
35
104
|
async isRunning() {
|
|
36
105
|
try {
|
|
37
|
-
await this.status
|
|
38
|
-
return
|
|
106
|
+
const res = await fetch(`${this.baseUrl}/status`, { mode: "no-cors" });
|
|
107
|
+
return res.type === "opaque" || res.ok;
|
|
39
108
|
} catch {
|
|
40
109
|
return false;
|
|
41
110
|
}
|
|
@@ -55,21 +124,73 @@ var Dazzle = class {
|
|
|
55
124
|
/**
|
|
56
125
|
* Send ZPL to be printed.
|
|
57
126
|
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
127
|
+
* Accepts a `string` (ASCII ZPL), `Uint8Array`, or `ArrayBuffer`.
|
|
128
|
+
* Binary data is automatically base64-encoded for safe transmission.
|
|
129
|
+
* Strings are also base64-encoded by default to avoid any encoding issues.
|
|
60
130
|
*/
|
|
61
131
|
async print(zpl, options) {
|
|
62
132
|
const url = new URL(`${this.baseUrl}/print`);
|
|
133
|
+
url.searchParams.set("encoding", "base64");
|
|
63
134
|
if (options?.printer) {
|
|
64
135
|
url.searchParams.set("printer", options.printer);
|
|
65
136
|
}
|
|
66
|
-
|
|
137
|
+
let bytes;
|
|
138
|
+
if (typeof zpl === "string") {
|
|
139
|
+
bytes = new Uint8Array(zpl.length);
|
|
140
|
+
for (let i = 0; i < zpl.length; i++) {
|
|
141
|
+
bytes[i] = zpl.charCodeAt(i) & 255;
|
|
142
|
+
}
|
|
143
|
+
} else if (zpl instanceof ArrayBuffer) {
|
|
144
|
+
bytes = new Uint8Array(zpl);
|
|
145
|
+
} else {
|
|
146
|
+
bytes = zpl;
|
|
147
|
+
}
|
|
148
|
+
const res = await fetch(url, {
|
|
149
|
+
method: "POST",
|
|
150
|
+
body: toBase64(bytes)
|
|
151
|
+
});
|
|
67
152
|
if (!res.ok) {
|
|
68
153
|
const body = await res.text().catch(() => "");
|
|
69
154
|
throw new DazzleError(body || `Print failed: ${res.status}`, res.status);
|
|
70
155
|
}
|
|
71
156
|
return res.json();
|
|
72
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Fetch a ZPL file from a URL and print it.
|
|
160
|
+
*
|
|
161
|
+
* Fetches as binary (ArrayBuffer) to preserve image data,
|
|
162
|
+
* then base64-encodes and sends to the print server.
|
|
163
|
+
*/
|
|
164
|
+
async printURL(url, options) {
|
|
165
|
+
const response = await fetch(url);
|
|
166
|
+
if (!response.ok) {
|
|
167
|
+
throw new DazzleError(`Failed to fetch ZPL from ${url}: ${response.status}`, response.status);
|
|
168
|
+
}
|
|
169
|
+
const buffer = await response.arrayBuffer();
|
|
170
|
+
return this.print(buffer, options);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Print multiple ZPL payloads sequentially to preserve print order.
|
|
174
|
+
*
|
|
175
|
+
* Each item can be a `string`, `Uint8Array`, or `ArrayBuffer`.
|
|
176
|
+
*/
|
|
177
|
+
async printAll(items, options) {
|
|
178
|
+
const results = [];
|
|
179
|
+
for (const item of items) {
|
|
180
|
+
results.push(await this.print(item, options));
|
|
181
|
+
}
|
|
182
|
+
return results;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Fetch and print multiple ZPL files sequentially to preserve print order.
|
|
186
|
+
*/
|
|
187
|
+
async printURLs(urls, options) {
|
|
188
|
+
const results = [];
|
|
189
|
+
for (const url of urls) {
|
|
190
|
+
results.push(await this.printURL(url, options));
|
|
191
|
+
}
|
|
192
|
+
return results;
|
|
193
|
+
}
|
|
73
194
|
};
|
|
74
195
|
var DazzleError = class extends Error {
|
|
75
196
|
constructor(message, statusCode) {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export interface DazzleOptions {\n /** Hostname of the Dazzle server. @default \"localhost\" */\n host?: string;\n /** Port of the Dazzle server. @default 29100 */\n port?: number;\n /** Protocol to use. @default \"http\" */\n protocol?: 'http' | 'https';\n}\n\nexport interface Printer {\n name: string;\n is_default: boolean;\n}\n\nexport interface PrintResult {\n job_id: string;\n}\n\nexport interface ServerStatus {\n status: string;\n version: string;\n}\n\nexport interface PrintOptions {\n /** Override the default printer for this job. */\n printer?: string;\n}\n\nexport class Dazzle {\n private baseUrl: string;\n\n constructor(options?: DazzleOptions) {\n const host = options?.host ?? 'localhost';\n const port = options?.port ?? 29100;\n const protocol = options?.protocol ?? 'http';\n this.baseUrl = `${protocol}://${host}:${port}`;\n }\n\n /** Check if the Dazzle server is reachable. */\n async isRunning(): Promise<boolean> {\n try {\n await this.status();\n return true;\n } catch {\n return false;\n }\n }\n\n /** Get server status and version. */\n async status(): Promise<ServerStatus> {\n const res = await fetch(`${this.baseUrl}/status`);\n if (!res.ok) throw new DazzleError(`Server error: ${res.status}`, res.status);\n return res.json();\n }\n\n /** List available printers on the host machine. */\n async printers(): Promise<Printer[]> {\n const res = await fetch(`${this.baseUrl}/printers`);\n if (!res.ok) throw new DazzleError(`Server error: ${res.status}`, res.status);\n return res.json();\n }\n\n /**\n * Send ZPL to be printed.\n *\n * Uses the server's configured default printer unless\n * `options.printer` is specified.\n */\n async print(zpl: string, options?: PrintOptions): Promise<PrintResult> {\n const url = new URL(`${this.baseUrl}/print`);\n if (options?.printer) {\n url.searchParams.set('printer', options.printer);\n }\n\n const res = await fetch(url, { method: 'POST', body: zpl });\n\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n throw new DazzleError(body || `Print failed: ${res.status}`, res.status);\n }\n\n return res.json();\n }\n}\n\nexport class DazzleError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number\n ) {\n super(message);\n this.name = 'DazzleError';\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BO,IAAM,SAAN,MAAa;AAAA,EAGlB,YAAY,SAAyB;AACnC,UAAM,OAAO,SAAS,QAAQ;AAC9B,UAAM,OAAO,SAAS,QAAQ;AAC9B,UAAM,WAAW,SAAS,YAAY;AACtC,SAAK,UAAU,GAAG,QAAQ,MAAM,IAAI,IAAI,IAAI;AAAA,EAC9C;AAAA;AAAA,EAGA,MAAM,YAA8B;AAClC,QAAI;AACF,YAAM,KAAK,OAAO;AAClB,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,SAAgC;AACpC,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,OAAO,SAAS;AAChD,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,YAAY,iBAAiB,IAAI,MAAM,IAAI,IAAI,MAAM;AAC5E,WAAO,IAAI,KAAK;AAAA,EAClB;AAAA;AAAA,EAGA,MAAM,WAA+B;AACnC,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,OAAO,WAAW;AAClD,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,YAAY,iBAAiB,IAAI,MAAM,IAAI,IAAI,MAAM;AAC5E,WAAO,IAAI,KAAK;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,MAAM,KAAa,SAA8C;AACrE,UAAM,MAAM,IAAI,IAAI,GAAG,KAAK,OAAO,QAAQ;AAC3C,QAAI,SAAS,SAAS;AACpB,UAAI,aAAa,IAAI,WAAW,QAAQ,OAAO;AAAA,IACjD;AAEA,UAAM,MAAM,MAAM,MAAM,KAAK,EAAE,QAAQ,QAAQ,MAAM,IAAI,CAAC;AAE1D,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AAC5C,YAAM,IAAI,YAAY,QAAQ,iBAAiB,IAAI,MAAM,IAAI,IAAI,MAAM;AAAA,IACzE;AAEA,WAAO,IAAI,KAAK;AAAA,EAClB;AACF;AAEO,IAAM,cAAN,cAA0B,MAAM;AAAA,EACrC,YACE,SACgB,YAChB;AACA,UAAM,OAAO;AAFG;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export interface DazzleOptions {\n /** Hostname of the Dazzle server. @default \"localhost\" */\n host?: string;\n /** Port of the Dazzle server. @default 29100 */\n port?: number;\n /** Protocol to use. @default \"http\" */\n protocol?: 'http' | 'https';\n}\n\nexport interface Printer {\n name: string;\n is_default: boolean;\n}\n\nexport interface PrintResult {\n job_id: string;\n}\n\nexport interface ServerStatus {\n status: string;\n version: string;\n}\n\nexport interface PrintOptions {\n /** Override the default printer for this job. */\n printer?: string;\n}\n\nexport interface WatchOptions {\n /** Polling interval in milliseconds. @default 5000 */\n interval?: number;\n}\n\n/**\n * Base64-encode a Uint8Array for binary-safe transmission.\n * Uses btoa with a latin1 intermediate string.\n */\nfunction toBase64(bytes: Uint8Array): string {\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\nexport class Dazzle {\n private baseUrl: string;\n private watchers = new Set<(running: boolean) => void>();\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private pollInterval = 0;\n private lastStatus: boolean | null = null;\n\n constructor(options?: DazzleOptions) {\n const host = options?.host ?? 'localhost';\n const port = options?.port ?? 29100;\n const protocol = options?.protocol ?? 'http';\n this.baseUrl = `${protocol}://${host}:${port}`;\n }\n\n /**\n * Watch for server status changes. The callback fires immediately with\n * the current status, then again whenever the status changes.\n *\n * Returns an unwatch function. When all watchers unsubscribe, polling stops.\n *\n * ```ts\n * const unwatch = dazzle.watch((running) => {\n * banner.classList.toggle('d-none', running);\n * });\n * // later: unwatch();\n * ```\n */\n watch(callback: (running: boolean) => void, options?: WatchOptions): () => void {\n const interval = options?.interval ?? 5000;\n this.watchers.add(callback);\n\n // Fire immediately with current known status, then poll\n this.isRunning().then((running) => {\n if (this.watchers.has(callback)) {\n callback(running);\n this.lastStatus = running;\n }\n });\n\n // Start or restart polling at the shortest requested interval\n if (this.pollTimer === null || interval < this.pollInterval) {\n this.startPolling(interval);\n }\n\n return () => {\n this.watchers.delete(callback);\n if (this.watchers.size === 0) {\n this.stopPolling();\n }\n };\n }\n\n private startPolling(interval: number): void {\n this.stopPolling();\n this.pollInterval = interval;\n this.pollTimer = setInterval(async () => {\n const running = await this.isRunning();\n if (running !== this.lastStatus) {\n this.lastStatus = running;\n for (const cb of this.watchers) {\n cb(running);\n }\n }\n }, interval);\n }\n\n private stopPolling(): void {\n if (this.pollTimer !== null) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n this.pollInterval = 0;\n this.lastStatus = null;\n }\n }\n\n /**\n * Check if the Dazzle server is reachable.\n *\n * Uses `no-cors` mode to avoid noisy CORS console errors when\n * the server is not running.\n */\n async isRunning(): Promise<boolean> {\n try {\n // An opaque response (type \"opaque\") means the server responded.\n // A network error (TypeError) means it's unreachable.\n const res = await fetch(`${this.baseUrl}/status`, { mode: 'no-cors' });\n return res.type === 'opaque' || res.ok;\n } catch {\n return false;\n }\n }\n\n /** Get server status and version. */\n async status(): Promise<ServerStatus> {\n const res = await fetch(`${this.baseUrl}/status`);\n if (!res.ok) throw new DazzleError(`Server error: ${res.status}`, res.status);\n return res.json();\n }\n\n /** List available printers on the host machine. */\n async printers(): Promise<Printer[]> {\n const res = await fetch(`${this.baseUrl}/printers`);\n if (!res.ok) throw new DazzleError(`Server error: ${res.status}`, res.status);\n return res.json();\n }\n\n /**\n * Send ZPL to be printed.\n *\n * Accepts a `string` (ASCII ZPL), `Uint8Array`, or `ArrayBuffer`.\n * Binary data is automatically base64-encoded for safe transmission.\n * Strings are also base64-encoded by default to avoid any encoding issues.\n */\n async print(\n zpl: string | Uint8Array | ArrayBuffer,\n options?: PrintOptions\n ): Promise<PrintResult> {\n const url = new URL(`${this.baseUrl}/print`);\n url.searchParams.set('encoding', 'base64');\n if (options?.printer) {\n url.searchParams.set('printer', options.printer);\n }\n\n let bytes: Uint8Array;\n if (typeof zpl === 'string') {\n // Encode string as latin1 bytes to preserve ZPL binary data\n bytes = new Uint8Array(zpl.length);\n for (let i = 0; i < zpl.length; i++) {\n bytes[i] = zpl.charCodeAt(i) & 0xff;\n }\n } else if (zpl instanceof ArrayBuffer) {\n bytes = new Uint8Array(zpl);\n } else {\n bytes = zpl;\n }\n\n const res = await fetch(url, {\n method: 'POST',\n body: toBase64(bytes),\n });\n\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n throw new DazzleError(body || `Print failed: ${res.status}`, res.status);\n }\n\n return res.json();\n }\n\n /**\n * Fetch a ZPL file from a URL and print it.\n *\n * Fetches as binary (ArrayBuffer) to preserve image data,\n * then base64-encodes and sends to the print server.\n */\n async printURL(url: string, options?: PrintOptions): Promise<PrintResult> {\n const response = await fetch(url);\n if (!response.ok) {\n throw new DazzleError(`Failed to fetch ZPL from ${url}: ${response.status}`, response.status);\n }\n const buffer = await response.arrayBuffer();\n return this.print(buffer, options);\n }\n\n /**\n * Print multiple ZPL payloads sequentially to preserve print order.\n *\n * Each item can be a `string`, `Uint8Array`, or `ArrayBuffer`.\n */\n async printAll(\n items: (string | Uint8Array | ArrayBuffer)[],\n options?: PrintOptions\n ): Promise<PrintResult[]> {\n const results: PrintResult[] = [];\n for (const item of items) {\n results.push(await this.print(item, options));\n }\n return results;\n }\n\n /**\n * Fetch and print multiple ZPL files sequentially to preserve print order.\n */\n async printURLs(urls: string[], options?: PrintOptions): Promise<PrintResult[]> {\n const results: PrintResult[] = [];\n for (const url of urls) {\n results.push(await this.printURL(url, options));\n }\n return results;\n }\n}\n\nexport class DazzleError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number\n ) {\n super(message);\n this.name = 'DazzleError';\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -21,10 +21,39 @@ interface PrintOptions {
|
|
|
21
21
|
/** Override the default printer for this job. */
|
|
22
22
|
printer?: string;
|
|
23
23
|
}
|
|
24
|
+
interface WatchOptions {
|
|
25
|
+
/** Polling interval in milliseconds. @default 5000 */
|
|
26
|
+
interval?: number;
|
|
27
|
+
}
|
|
24
28
|
declare class Dazzle {
|
|
25
29
|
private baseUrl;
|
|
30
|
+
private watchers;
|
|
31
|
+
private pollTimer;
|
|
32
|
+
private pollInterval;
|
|
33
|
+
private lastStatus;
|
|
26
34
|
constructor(options?: DazzleOptions);
|
|
27
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* Watch for server status changes. The callback fires immediately with
|
|
37
|
+
* the current status, then again whenever the status changes.
|
|
38
|
+
*
|
|
39
|
+
* Returns an unwatch function. When all watchers unsubscribe, polling stops.
|
|
40
|
+
*
|
|
41
|
+
* ```ts
|
|
42
|
+
* const unwatch = dazzle.watch((running) => {
|
|
43
|
+
* banner.classList.toggle('d-none', running);
|
|
44
|
+
* });
|
|
45
|
+
* // later: unwatch();
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
watch(callback: (running: boolean) => void, options?: WatchOptions): () => void;
|
|
49
|
+
private startPolling;
|
|
50
|
+
private stopPolling;
|
|
51
|
+
/**
|
|
52
|
+
* Check if the Dazzle server is reachable.
|
|
53
|
+
*
|
|
54
|
+
* Uses `no-cors` mode to avoid noisy CORS console errors when
|
|
55
|
+
* the server is not running.
|
|
56
|
+
*/
|
|
28
57
|
isRunning(): Promise<boolean>;
|
|
29
58
|
/** Get server status and version. */
|
|
30
59
|
status(): Promise<ServerStatus>;
|
|
@@ -33,14 +62,32 @@ declare class Dazzle {
|
|
|
33
62
|
/**
|
|
34
63
|
* Send ZPL to be printed.
|
|
35
64
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
65
|
+
* Accepts a `string` (ASCII ZPL), `Uint8Array`, or `ArrayBuffer`.
|
|
66
|
+
* Binary data is automatically base64-encoded for safe transmission.
|
|
67
|
+
* Strings are also base64-encoded by default to avoid any encoding issues.
|
|
68
|
+
*/
|
|
69
|
+
print(zpl: string | Uint8Array | ArrayBuffer, options?: PrintOptions): Promise<PrintResult>;
|
|
70
|
+
/**
|
|
71
|
+
* Fetch a ZPL file from a URL and print it.
|
|
72
|
+
*
|
|
73
|
+
* Fetches as binary (ArrayBuffer) to preserve image data,
|
|
74
|
+
* then base64-encodes and sends to the print server.
|
|
75
|
+
*/
|
|
76
|
+
printURL(url: string, options?: PrintOptions): Promise<PrintResult>;
|
|
77
|
+
/**
|
|
78
|
+
* Print multiple ZPL payloads sequentially to preserve print order.
|
|
79
|
+
*
|
|
80
|
+
* Each item can be a `string`, `Uint8Array`, or `ArrayBuffer`.
|
|
81
|
+
*/
|
|
82
|
+
printAll(items: (string | Uint8Array | ArrayBuffer)[], options?: PrintOptions): Promise<PrintResult[]>;
|
|
83
|
+
/**
|
|
84
|
+
* Fetch and print multiple ZPL files sequentially to preserve print order.
|
|
38
85
|
*/
|
|
39
|
-
|
|
86
|
+
printURLs(urls: string[], options?: PrintOptions): Promise<PrintResult[]>;
|
|
40
87
|
}
|
|
41
88
|
declare class DazzleError extends Error {
|
|
42
89
|
readonly statusCode: number;
|
|
43
90
|
constructor(message: string, statusCode: number);
|
|
44
91
|
}
|
|
45
92
|
|
|
46
|
-
export { Dazzle, DazzleError, type DazzleOptions, type PrintOptions, type PrintResult, type Printer, type ServerStatus };
|
|
93
|
+
export { Dazzle, DazzleError, type DazzleOptions, type PrintOptions, type PrintResult, type Printer, type ServerStatus, type WatchOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -21,10 +21,39 @@ interface PrintOptions {
|
|
|
21
21
|
/** Override the default printer for this job. */
|
|
22
22
|
printer?: string;
|
|
23
23
|
}
|
|
24
|
+
interface WatchOptions {
|
|
25
|
+
/** Polling interval in milliseconds. @default 5000 */
|
|
26
|
+
interval?: number;
|
|
27
|
+
}
|
|
24
28
|
declare class Dazzle {
|
|
25
29
|
private baseUrl;
|
|
30
|
+
private watchers;
|
|
31
|
+
private pollTimer;
|
|
32
|
+
private pollInterval;
|
|
33
|
+
private lastStatus;
|
|
26
34
|
constructor(options?: DazzleOptions);
|
|
27
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* Watch for server status changes. The callback fires immediately with
|
|
37
|
+
* the current status, then again whenever the status changes.
|
|
38
|
+
*
|
|
39
|
+
* Returns an unwatch function. When all watchers unsubscribe, polling stops.
|
|
40
|
+
*
|
|
41
|
+
* ```ts
|
|
42
|
+
* const unwatch = dazzle.watch((running) => {
|
|
43
|
+
* banner.classList.toggle('d-none', running);
|
|
44
|
+
* });
|
|
45
|
+
* // later: unwatch();
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
watch(callback: (running: boolean) => void, options?: WatchOptions): () => void;
|
|
49
|
+
private startPolling;
|
|
50
|
+
private stopPolling;
|
|
51
|
+
/**
|
|
52
|
+
* Check if the Dazzle server is reachable.
|
|
53
|
+
*
|
|
54
|
+
* Uses `no-cors` mode to avoid noisy CORS console errors when
|
|
55
|
+
* the server is not running.
|
|
56
|
+
*/
|
|
28
57
|
isRunning(): Promise<boolean>;
|
|
29
58
|
/** Get server status and version. */
|
|
30
59
|
status(): Promise<ServerStatus>;
|
|
@@ -33,14 +62,32 @@ declare class Dazzle {
|
|
|
33
62
|
/**
|
|
34
63
|
* Send ZPL to be printed.
|
|
35
64
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
65
|
+
* Accepts a `string` (ASCII ZPL), `Uint8Array`, or `ArrayBuffer`.
|
|
66
|
+
* Binary data is automatically base64-encoded for safe transmission.
|
|
67
|
+
* Strings are also base64-encoded by default to avoid any encoding issues.
|
|
68
|
+
*/
|
|
69
|
+
print(zpl: string | Uint8Array | ArrayBuffer, options?: PrintOptions): Promise<PrintResult>;
|
|
70
|
+
/**
|
|
71
|
+
* Fetch a ZPL file from a URL and print it.
|
|
72
|
+
*
|
|
73
|
+
* Fetches as binary (ArrayBuffer) to preserve image data,
|
|
74
|
+
* then base64-encodes and sends to the print server.
|
|
75
|
+
*/
|
|
76
|
+
printURL(url: string, options?: PrintOptions): Promise<PrintResult>;
|
|
77
|
+
/**
|
|
78
|
+
* Print multiple ZPL payloads sequentially to preserve print order.
|
|
79
|
+
*
|
|
80
|
+
* Each item can be a `string`, `Uint8Array`, or `ArrayBuffer`.
|
|
81
|
+
*/
|
|
82
|
+
printAll(items: (string | Uint8Array | ArrayBuffer)[], options?: PrintOptions): Promise<PrintResult[]>;
|
|
83
|
+
/**
|
|
84
|
+
* Fetch and print multiple ZPL files sequentially to preserve print order.
|
|
38
85
|
*/
|
|
39
|
-
|
|
86
|
+
printURLs(urls: string[], options?: PrintOptions): Promise<PrintResult[]>;
|
|
40
87
|
}
|
|
41
88
|
declare class DazzleError extends Error {
|
|
42
89
|
readonly statusCode: number;
|
|
43
90
|
constructor(message: string, statusCode: number);
|
|
44
91
|
}
|
|
45
92
|
|
|
46
|
-
export { Dazzle, DazzleError, type DazzleOptions, type PrintOptions, type PrintResult, type Printer, type ServerStatus };
|
|
93
|
+
export { Dazzle, DazzleError, type DazzleOptions, type PrintOptions, type PrintResult, type Printer, type ServerStatus, type WatchOptions };
|
package/dist/index.js
CHANGED
|
@@ -1,16 +1,85 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
+
function toBase64(bytes) {
|
|
3
|
+
let binary = "";
|
|
4
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
5
|
+
binary += String.fromCharCode(bytes[i]);
|
|
6
|
+
}
|
|
7
|
+
return btoa(binary);
|
|
8
|
+
}
|
|
2
9
|
var Dazzle = class {
|
|
3
10
|
constructor(options) {
|
|
11
|
+
this.watchers = /* @__PURE__ */ new Set();
|
|
12
|
+
this.pollTimer = null;
|
|
13
|
+
this.pollInterval = 0;
|
|
14
|
+
this.lastStatus = null;
|
|
4
15
|
const host = options?.host ?? "localhost";
|
|
5
16
|
const port = options?.port ?? 29100;
|
|
6
17
|
const protocol = options?.protocol ?? "http";
|
|
7
18
|
this.baseUrl = `${protocol}://${host}:${port}`;
|
|
8
19
|
}
|
|
9
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* Watch for server status changes. The callback fires immediately with
|
|
22
|
+
* the current status, then again whenever the status changes.
|
|
23
|
+
*
|
|
24
|
+
* Returns an unwatch function. When all watchers unsubscribe, polling stops.
|
|
25
|
+
*
|
|
26
|
+
* ```ts
|
|
27
|
+
* const unwatch = dazzle.watch((running) => {
|
|
28
|
+
* banner.classList.toggle('d-none', running);
|
|
29
|
+
* });
|
|
30
|
+
* // later: unwatch();
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
watch(callback, options) {
|
|
34
|
+
const interval = options?.interval ?? 5e3;
|
|
35
|
+
this.watchers.add(callback);
|
|
36
|
+
this.isRunning().then((running) => {
|
|
37
|
+
if (this.watchers.has(callback)) {
|
|
38
|
+
callback(running);
|
|
39
|
+
this.lastStatus = running;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
if (this.pollTimer === null || interval < this.pollInterval) {
|
|
43
|
+
this.startPolling(interval);
|
|
44
|
+
}
|
|
45
|
+
return () => {
|
|
46
|
+
this.watchers.delete(callback);
|
|
47
|
+
if (this.watchers.size === 0) {
|
|
48
|
+
this.stopPolling();
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
startPolling(interval) {
|
|
53
|
+
this.stopPolling();
|
|
54
|
+
this.pollInterval = interval;
|
|
55
|
+
this.pollTimer = setInterval(async () => {
|
|
56
|
+
const running = await this.isRunning();
|
|
57
|
+
if (running !== this.lastStatus) {
|
|
58
|
+
this.lastStatus = running;
|
|
59
|
+
for (const cb of this.watchers) {
|
|
60
|
+
cb(running);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}, interval);
|
|
64
|
+
}
|
|
65
|
+
stopPolling() {
|
|
66
|
+
if (this.pollTimer !== null) {
|
|
67
|
+
clearInterval(this.pollTimer);
|
|
68
|
+
this.pollTimer = null;
|
|
69
|
+
this.pollInterval = 0;
|
|
70
|
+
this.lastStatus = null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Check if the Dazzle server is reachable.
|
|
75
|
+
*
|
|
76
|
+
* Uses `no-cors` mode to avoid noisy CORS console errors when
|
|
77
|
+
* the server is not running.
|
|
78
|
+
*/
|
|
10
79
|
async isRunning() {
|
|
11
80
|
try {
|
|
12
|
-
await this.status
|
|
13
|
-
return
|
|
81
|
+
const res = await fetch(`${this.baseUrl}/status`, { mode: "no-cors" });
|
|
82
|
+
return res.type === "opaque" || res.ok;
|
|
14
83
|
} catch {
|
|
15
84
|
return false;
|
|
16
85
|
}
|
|
@@ -30,21 +99,73 @@ var Dazzle = class {
|
|
|
30
99
|
/**
|
|
31
100
|
* Send ZPL to be printed.
|
|
32
101
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
102
|
+
* Accepts a `string` (ASCII ZPL), `Uint8Array`, or `ArrayBuffer`.
|
|
103
|
+
* Binary data is automatically base64-encoded for safe transmission.
|
|
104
|
+
* Strings are also base64-encoded by default to avoid any encoding issues.
|
|
35
105
|
*/
|
|
36
106
|
async print(zpl, options) {
|
|
37
107
|
const url = new URL(`${this.baseUrl}/print`);
|
|
108
|
+
url.searchParams.set("encoding", "base64");
|
|
38
109
|
if (options?.printer) {
|
|
39
110
|
url.searchParams.set("printer", options.printer);
|
|
40
111
|
}
|
|
41
|
-
|
|
112
|
+
let bytes;
|
|
113
|
+
if (typeof zpl === "string") {
|
|
114
|
+
bytes = new Uint8Array(zpl.length);
|
|
115
|
+
for (let i = 0; i < zpl.length; i++) {
|
|
116
|
+
bytes[i] = zpl.charCodeAt(i) & 255;
|
|
117
|
+
}
|
|
118
|
+
} else if (zpl instanceof ArrayBuffer) {
|
|
119
|
+
bytes = new Uint8Array(zpl);
|
|
120
|
+
} else {
|
|
121
|
+
bytes = zpl;
|
|
122
|
+
}
|
|
123
|
+
const res = await fetch(url, {
|
|
124
|
+
method: "POST",
|
|
125
|
+
body: toBase64(bytes)
|
|
126
|
+
});
|
|
42
127
|
if (!res.ok) {
|
|
43
128
|
const body = await res.text().catch(() => "");
|
|
44
129
|
throw new DazzleError(body || `Print failed: ${res.status}`, res.status);
|
|
45
130
|
}
|
|
46
131
|
return res.json();
|
|
47
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Fetch a ZPL file from a URL and print it.
|
|
135
|
+
*
|
|
136
|
+
* Fetches as binary (ArrayBuffer) to preserve image data,
|
|
137
|
+
* then base64-encodes and sends to the print server.
|
|
138
|
+
*/
|
|
139
|
+
async printURL(url, options) {
|
|
140
|
+
const response = await fetch(url);
|
|
141
|
+
if (!response.ok) {
|
|
142
|
+
throw new DazzleError(`Failed to fetch ZPL from ${url}: ${response.status}`, response.status);
|
|
143
|
+
}
|
|
144
|
+
const buffer = await response.arrayBuffer();
|
|
145
|
+
return this.print(buffer, options);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Print multiple ZPL payloads sequentially to preserve print order.
|
|
149
|
+
*
|
|
150
|
+
* Each item can be a `string`, `Uint8Array`, or `ArrayBuffer`.
|
|
151
|
+
*/
|
|
152
|
+
async printAll(items, options) {
|
|
153
|
+
const results = [];
|
|
154
|
+
for (const item of items) {
|
|
155
|
+
results.push(await this.print(item, options));
|
|
156
|
+
}
|
|
157
|
+
return results;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Fetch and print multiple ZPL files sequentially to preserve print order.
|
|
161
|
+
*/
|
|
162
|
+
async printURLs(urls, options) {
|
|
163
|
+
const results = [];
|
|
164
|
+
for (const url of urls) {
|
|
165
|
+
results.push(await this.printURL(url, options));
|
|
166
|
+
}
|
|
167
|
+
return results;
|
|
168
|
+
}
|
|
48
169
|
};
|
|
49
170
|
var DazzleError = class extends Error {
|
|
50
171
|
constructor(message, statusCode) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export interface DazzleOptions {\n /** Hostname of the Dazzle server. @default \"localhost\" */\n host?: string;\n /** Port of the Dazzle server. @default 29100 */\n port?: number;\n /** Protocol to use. @default \"http\" */\n protocol?: 'http' | 'https';\n}\n\nexport interface Printer {\n name: string;\n is_default: boolean;\n}\n\nexport interface PrintResult {\n job_id: string;\n}\n\nexport interface ServerStatus {\n status: string;\n version: string;\n}\n\nexport interface PrintOptions {\n /** Override the default printer for this job. */\n printer?: string;\n}\n\nexport class Dazzle {\n private baseUrl: string;\n\n constructor(options?: DazzleOptions) {\n const host = options?.host ?? 'localhost';\n const port = options?.port ?? 29100;\n const protocol = options?.protocol ?? 'http';\n this.baseUrl = `${protocol}://${host}:${port}`;\n }\n\n /** Check if the Dazzle server is reachable. */\n async isRunning(): Promise<boolean> {\n try {\n await this.status();\n return true;\n } catch {\n return false;\n }\n }\n\n /** Get server status and version. */\n async status(): Promise<ServerStatus> {\n const res = await fetch(`${this.baseUrl}/status`);\n if (!res.ok) throw new DazzleError(`Server error: ${res.status}`, res.status);\n return res.json();\n }\n\n /** List available printers on the host machine. */\n async printers(): Promise<Printer[]> {\n const res = await fetch(`${this.baseUrl}/printers`);\n if (!res.ok) throw new DazzleError(`Server error: ${res.status}`, res.status);\n return res.json();\n }\n\n /**\n * Send ZPL to be printed.\n *\n * Uses the server's configured default printer unless\n * `options.printer` is specified.\n */\n async print(zpl: string, options?: PrintOptions): Promise<PrintResult> {\n const url = new URL(`${this.baseUrl}/print`);\n if (options?.printer) {\n url.searchParams.set('printer', options.printer);\n }\n\n const res = await fetch(url, { method: 'POST', body: zpl });\n\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n throw new DazzleError(body || `Print failed: ${res.status}`, res.status);\n }\n\n return res.json();\n }\n}\n\nexport class DazzleError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number\n ) {\n super(message);\n this.name = 'DazzleError';\n }\n}\n"],"mappings":";AA4BO,IAAM,SAAN,MAAa;AAAA,EAGlB,YAAY,SAAyB;AACnC,UAAM,OAAO,SAAS,QAAQ;AAC9B,UAAM,OAAO,SAAS,QAAQ;AAC9B,UAAM,WAAW,SAAS,YAAY;AACtC,SAAK,UAAU,GAAG,QAAQ,MAAM,IAAI,IAAI,IAAI;AAAA,EAC9C;AAAA;AAAA,EAGA,MAAM,YAA8B;AAClC,QAAI;AACF,YAAM,KAAK,OAAO;AAClB,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,SAAgC;AACpC,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,OAAO,SAAS;AAChD,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,YAAY,iBAAiB,IAAI,MAAM,IAAI,IAAI,MAAM;AAC5E,WAAO,IAAI,KAAK;AAAA,EAClB;AAAA;AAAA,EAGA,MAAM,WAA+B;AACnC,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,OAAO,WAAW;AAClD,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,YAAY,iBAAiB,IAAI,MAAM,IAAI,IAAI,MAAM;AAC5E,WAAO,IAAI,KAAK;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,MAAM,KAAa,SAA8C;AACrE,UAAM,MAAM,IAAI,IAAI,GAAG,KAAK,OAAO,QAAQ;AAC3C,QAAI,SAAS,SAAS;AACpB,UAAI,aAAa,IAAI,WAAW,QAAQ,OAAO;AAAA,IACjD;AAEA,UAAM,MAAM,MAAM,MAAM,KAAK,EAAE,QAAQ,QAAQ,MAAM,IAAI,CAAC;AAE1D,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AAC5C,YAAM,IAAI,YAAY,QAAQ,iBAAiB,IAAI,MAAM,IAAI,IAAI,MAAM;AAAA,IACzE;AAEA,WAAO,IAAI,KAAK;AAAA,EAClB;AACF;AAEO,IAAM,cAAN,cAA0B,MAAM;AAAA,EACrC,YACE,SACgB,YAChB;AACA,UAAM,OAAO;AAFG;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export interface DazzleOptions {\n /** Hostname of the Dazzle server. @default \"localhost\" */\n host?: string;\n /** Port of the Dazzle server. @default 29100 */\n port?: number;\n /** Protocol to use. @default \"http\" */\n protocol?: 'http' | 'https';\n}\n\nexport interface Printer {\n name: string;\n is_default: boolean;\n}\n\nexport interface PrintResult {\n job_id: string;\n}\n\nexport interface ServerStatus {\n status: string;\n version: string;\n}\n\nexport interface PrintOptions {\n /** Override the default printer for this job. */\n printer?: string;\n}\n\nexport interface WatchOptions {\n /** Polling interval in milliseconds. @default 5000 */\n interval?: number;\n}\n\n/**\n * Base64-encode a Uint8Array for binary-safe transmission.\n * Uses btoa with a latin1 intermediate string.\n */\nfunction toBase64(bytes: Uint8Array): string {\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\nexport class Dazzle {\n private baseUrl: string;\n private watchers = new Set<(running: boolean) => void>();\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private pollInterval = 0;\n private lastStatus: boolean | null = null;\n\n constructor(options?: DazzleOptions) {\n const host = options?.host ?? 'localhost';\n const port = options?.port ?? 29100;\n const protocol = options?.protocol ?? 'http';\n this.baseUrl = `${protocol}://${host}:${port}`;\n }\n\n /**\n * Watch for server status changes. The callback fires immediately with\n * the current status, then again whenever the status changes.\n *\n * Returns an unwatch function. When all watchers unsubscribe, polling stops.\n *\n * ```ts\n * const unwatch = dazzle.watch((running) => {\n * banner.classList.toggle('d-none', running);\n * });\n * // later: unwatch();\n * ```\n */\n watch(callback: (running: boolean) => void, options?: WatchOptions): () => void {\n const interval = options?.interval ?? 5000;\n this.watchers.add(callback);\n\n // Fire immediately with current known status, then poll\n this.isRunning().then((running) => {\n if (this.watchers.has(callback)) {\n callback(running);\n this.lastStatus = running;\n }\n });\n\n // Start or restart polling at the shortest requested interval\n if (this.pollTimer === null || interval < this.pollInterval) {\n this.startPolling(interval);\n }\n\n return () => {\n this.watchers.delete(callback);\n if (this.watchers.size === 0) {\n this.stopPolling();\n }\n };\n }\n\n private startPolling(interval: number): void {\n this.stopPolling();\n this.pollInterval = interval;\n this.pollTimer = setInterval(async () => {\n const running = await this.isRunning();\n if (running !== this.lastStatus) {\n this.lastStatus = running;\n for (const cb of this.watchers) {\n cb(running);\n }\n }\n }, interval);\n }\n\n private stopPolling(): void {\n if (this.pollTimer !== null) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n this.pollInterval = 0;\n this.lastStatus = null;\n }\n }\n\n /**\n * Check if the Dazzle server is reachable.\n *\n * Uses `no-cors` mode to avoid noisy CORS console errors when\n * the server is not running.\n */\n async isRunning(): Promise<boolean> {\n try {\n // An opaque response (type \"opaque\") means the server responded.\n // A network error (TypeError) means it's unreachable.\n const res = await fetch(`${this.baseUrl}/status`, { mode: 'no-cors' });\n return res.type === 'opaque' || res.ok;\n } catch {\n return false;\n }\n }\n\n /** Get server status and version. */\n async status(): Promise<ServerStatus> {\n const res = await fetch(`${this.baseUrl}/status`);\n if (!res.ok) throw new DazzleError(`Server error: ${res.status}`, res.status);\n return res.json();\n }\n\n /** List available printers on the host machine. */\n async printers(): Promise<Printer[]> {\n const res = await fetch(`${this.baseUrl}/printers`);\n if (!res.ok) throw new DazzleError(`Server error: ${res.status}`, res.status);\n return res.json();\n }\n\n /**\n * Send ZPL to be printed.\n *\n * Accepts a `string` (ASCII ZPL), `Uint8Array`, or `ArrayBuffer`.\n * Binary data is automatically base64-encoded for safe transmission.\n * Strings are also base64-encoded by default to avoid any encoding issues.\n */\n async print(\n zpl: string | Uint8Array | ArrayBuffer,\n options?: PrintOptions\n ): Promise<PrintResult> {\n const url = new URL(`${this.baseUrl}/print`);\n url.searchParams.set('encoding', 'base64');\n if (options?.printer) {\n url.searchParams.set('printer', options.printer);\n }\n\n let bytes: Uint8Array;\n if (typeof zpl === 'string') {\n // Encode string as latin1 bytes to preserve ZPL binary data\n bytes = new Uint8Array(zpl.length);\n for (let i = 0; i < zpl.length; i++) {\n bytes[i] = zpl.charCodeAt(i) & 0xff;\n }\n } else if (zpl instanceof ArrayBuffer) {\n bytes = new Uint8Array(zpl);\n } else {\n bytes = zpl;\n }\n\n const res = await fetch(url, {\n method: 'POST',\n body: toBase64(bytes),\n });\n\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n throw new DazzleError(body || `Print failed: ${res.status}`, res.status);\n }\n\n return res.json();\n }\n\n /**\n * Fetch a ZPL file from a URL and print it.\n *\n * Fetches as binary (ArrayBuffer) to preserve image data,\n * then base64-encodes and sends to the print server.\n */\n async printURL(url: string, options?: PrintOptions): Promise<PrintResult> {\n const response = await fetch(url);\n if (!response.ok) {\n throw new DazzleError(`Failed to fetch ZPL from ${url}: ${response.status}`, response.status);\n }\n const buffer = await response.arrayBuffer();\n return this.print(buffer, options);\n }\n\n /**\n * Print multiple ZPL payloads sequentially to preserve print order.\n *\n * Each item can be a `string`, `Uint8Array`, or `ArrayBuffer`.\n */\n async printAll(\n items: (string | Uint8Array | ArrayBuffer)[],\n options?: PrintOptions\n ): Promise<PrintResult[]> {\n const results: PrintResult[] = [];\n for (const item of items) {\n results.push(await this.print(item, options));\n }\n return results;\n }\n\n /**\n * Fetch and print multiple ZPL files sequentially to preserve print order.\n */\n async printURLs(urls: string[], options?: PrintOptions): Promise<PrintResult[]> {\n const results: PrintResult[] = [];\n for (const url of urls) {\n results.push(await this.printURL(url, options));\n }\n return results;\n }\n}\n\nexport class DazzleError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number\n ) {\n super(message);\n this.name = 'DazzleError';\n }\n}\n"],"mappings":"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","names":[]}
|