@happenv/print-agent-sdk 0.1.1 → 0.1.2
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 +23 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.js +23 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -59,7 +59,8 @@ var en = {
|
|
|
59
59
|
agentError: "agent error",
|
|
60
60
|
noWebSocket: "no WebSocket implementation (pass the WebSocket option)",
|
|
61
61
|
printNoPrinter: "print: printer name is required (printer)",
|
|
62
|
-
printSource: "print: provide exactly one source \u2014 url or base64"
|
|
62
|
+
printSource: "print: provide exactly one source \u2014 url or base64",
|
|
63
|
+
printNoUrls: "printBatch: at least one url is required (urls)"
|
|
63
64
|
};
|
|
64
65
|
|
|
65
66
|
// src/locales/pl.ts
|
|
@@ -72,7 +73,8 @@ var pl = {
|
|
|
72
73
|
agentError: "b\u0142\u0105d agenta",
|
|
73
74
|
noWebSocket: "brak implementacji WebSocket (przeka\u017C opcj\u0119 WebSocket)",
|
|
74
75
|
printNoPrinter: "print: wymagana nazwa drukarki (printer)",
|
|
75
|
-
printSource: "print: podaj dok\u0142adnie jedno \u017Ar\xF3d\u0142o \u2014 url albo base64"
|
|
76
|
+
printSource: "print: podaj dok\u0142adnie jedno \u017Ar\xF3d\u0142o \u2014 url albo base64",
|
|
77
|
+
printNoUrls: "printBatch: wymagany co najmniej jeden url (urls)"
|
|
76
78
|
};
|
|
77
79
|
|
|
78
80
|
// src/locales/index.ts
|
|
@@ -164,6 +166,25 @@ var PrintAgent = class {
|
|
|
164
166
|
copies: opts.copies
|
|
165
167
|
});
|
|
166
168
|
}
|
|
169
|
+
/** Sends a batch of label PDFs as a SINGLE merged print job.
|
|
170
|
+
* The agent fetches all URLs, merges them (each label repeated `copies`
|
|
171
|
+
* times) and sends one job to the spooler — avoiding the printer's pauses
|
|
172
|
+
* between separate jobs. Resolves once the agent has accepted the batch. */
|
|
173
|
+
async printBatch(opts) {
|
|
174
|
+
if (!opts || !opts.printer) {
|
|
175
|
+
throw new Error(this.t.printNoPrinter);
|
|
176
|
+
}
|
|
177
|
+
if (!Array.isArray(opts.urls) || opts.urls.length === 0) {
|
|
178
|
+
throw new Error(this.t.printNoUrls);
|
|
179
|
+
}
|
|
180
|
+
const pdfs = opts.urls.map((url) => ({ url }));
|
|
181
|
+
await this.request({
|
|
182
|
+
type: "printBatch",
|
|
183
|
+
printer: opts.printer,
|
|
184
|
+
pdfs,
|
|
185
|
+
copies: opts.copies
|
|
186
|
+
});
|
|
187
|
+
}
|
|
167
188
|
// --- internal ---
|
|
168
189
|
openSocket(onOpen, onFail) {
|
|
169
190
|
this.setStatus("connecting");
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/locales/en.ts","../src/locales/pl.ts","../src/locales/index.ts","../src/client.ts"],"sourcesContent":["export { PrintAgent } from \"./client\";\nexport {\n AgentError,\n NotConnectedError,\n TimeoutError,\n type AgentVersion,\n type ConnectionStatus,\n type Printer,\n type PrintAgentOptions,\n type PrintOptions,\n type WebSocketCtor,\n type WebSocketLike,\n} from \"./types\";\nexport { locales, getMessages, type Lang, type Messages } from \"./locales\";\n","import type { Lang } from \"./locales\";\n\n/** Connection status with the local agent. */\nexport type ConnectionStatus = \"connecting\" | \"open\" | \"closed\";\n\n/** A printer returned by the agent. */\nexport interface Printer {\n name: string;\n default: boolean;\n}\n\n/** Agent version. */\nexport interface AgentVersion {\n brand: string;\n version: string;\n}\n\n/** Print job parameters. Provide exactly one source: url or base64. */\nexport interface PrintOptions {\n printer: string;\n url?: string;\n base64?: string;\n copies?: number;\n}\n\n/** PrintAgent constructor options. */\nexport interface PrintAgentOptions {\n host?: string;\n port?: number;\n url?: string;\n autoReconnect?: boolean;\n requestTimeoutMs?: number;\n WebSocket?: WebSocketCtor;\n /** Language of SDK error messages; defaults to \"en\". */\n lang?: Lang;\n}\n\n/** Minimal WebSocket interface used by the SDK (compatible with the browser and the ws package). */\nexport interface WebSocketLike {\n send(data: string): void;\n close(): void;\n onopen: ((ev: unknown) => void) | null;\n onmessage: ((ev: { data: unknown }) => void) | null;\n onclose: ((ev: unknown) => void) | null;\n onerror: ((ev: unknown) => void) | null;\n}\n\nexport interface WebSocketCtor {\n new (url: string): WebSocketLike;\n}\n\n/** No active connection to the agent. (Message is localized by the client.) */\nexport class NotConnectedError extends Error {\n constructor(message = \"no connection to the agent\") {\n super(message);\n this.name = \"NotConnectedError\";\n }\n}\n\n/** Timed out waiting for the agent. (Message is localized by the client.) */\nexport class TimeoutError extends Error {\n constructor(message = \"timed out waiting for the agent\") {\n super(message);\n this.name = \"TimeoutError\";\n }\n}\n\n/** The agent responded with an error (ok:false). */\nexport class AgentError extends Error {\n constructor(message = \"agent error\") {\n super(message);\n this.name = \"AgentError\";\n }\n}\n","import type { Messages } from \"./types\";\n\n/** English message catalog (default). */\nexport const en: Messages = {\n notConnected: \"no connection to the agent\",\n connectionClosed: \"connection closed\",\n connectFailed: \"could not connect to the agent\",\n timeout: \"timed out waiting for the agent's response\",\n connectTimeout: \"timed out connecting to the agent\",\n agentError: \"agent error\",\n noWebSocket: \"no WebSocket implementation (pass the WebSocket option)\",\n printNoPrinter: \"print: printer name is required (printer)\",\n printSource: \"print: provide exactly one source — url or base64\",\n};\n","import type { Messages } from \"./types\";\n\n/** Polish message catalog. */\nexport const pl: Messages = {\n notConnected: \"brak połączenia z agentem\",\n connectionClosed: \"połączenie zamknięte\",\n connectFailed: \"nie udało się połączyć z agentem\",\n timeout: \"przekroczono czas oczekiwania na odpowiedź agenta\",\n connectTimeout: \"przekroczono czas łączenia z agentem\",\n agentError: \"błąd agenta\",\n noWebSocket: \"brak implementacji WebSocket (przekaż opcję WebSocket)\",\n printNoPrinter: \"print: wymagana nazwa drukarki (printer)\",\n printSource: \"print: podaj dokładnie jedno źródło — url albo base64\",\n};\n","import { en } from \"./en\";\nimport { pl } from \"./pl\";\nimport type { Lang, Messages } from \"./types\";\n\nexport type { Lang, Messages };\n\n/** All available message catalogs keyed by language. */\nexport const locales: Record<Lang, Messages> = { en, pl };\n\n/** Returns the message catalog for the given language (defaults to English). */\nexport function getMessages(lang: Lang = \"en\"): Messages {\n return locales[lang] ?? en;\n}\n","import {\n AgentError,\n NotConnectedError,\n TimeoutError,\n type AgentVersion,\n type ConnectionStatus,\n type PrintAgentOptions,\n type PrintOptions,\n type Printer,\n type WebSocketCtor,\n type WebSocketLike,\n} from \"./types\";\nimport { getMessages, type Messages } from \"./locales\";\n\ninterface AgentResponse {\n type: string;\n id?: string;\n ok: boolean;\n error?: string;\n printers?: Printer[];\n brand?: string;\n version?: string;\n}\n\ninterface Pending {\n resolve: (r: AgentResponse) => void;\n reject: (e: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\nconst RECONNECT_BACKOFF_MS = [1000, 2000, 5000, 10000];\n\n/** Client for the local print agent. */\nexport class PrintAgent {\n private readonly url: string;\n private readonly autoReconnect: boolean;\n private readonly requestTimeoutMs: number;\n private readonly WS: WebSocketCtor;\n private readonly t: Messages;\n\n private ws?: WebSocketLike;\n private _status: ConnectionStatus = \"closed\";\n private statusListeners = new Set<(s: ConnectionStatus) => void>();\n private pending = new Map<string, Pending>();\n private idCounter = 0;\n private wantConnected = false;\n private reconnectAttempt = 0;\n private reconnectTimer?: ReturnType<typeof setTimeout>;\n\n constructor(opts: PrintAgentOptions = {}) {\n this.t = getMessages(opts.lang);\n const host = opts.host ?? \"localhost\";\n const port = opts.port ?? 45123;\n this.url = opts.url ?? `wss://${host}:${port}/ws`;\n this.autoReconnect = opts.autoReconnect ?? true;\n this.requestTimeoutMs = opts.requestTimeoutMs ?? 10000;\n const ctor = opts.WebSocket ?? (globalThis as { WebSocket?: WebSocketCtor }).WebSocket;\n if (!ctor) {\n throw new Error(this.t.noWebSocket);\n }\n this.WS = ctor;\n }\n\n get status(): ConnectionStatus {\n return this._status;\n }\n\n isConnected(): boolean {\n return this._status === \"open\";\n }\n\n /** Registers a status-change listener; returns an unsubscribe function. */\n onStatusChange(cb: (s: ConnectionStatus) => void): () => void {\n this.statusListeners.add(cb);\n return () => this.statusListeners.delete(cb);\n }\n\n /** Connects to the agent; resolves on open, rejects on timeout/failure.\n * Idempotent when the connection is already open. */\n connect(): Promise<void> {\n this.wantConnected = true;\n if (this._status === \"open\") {\n return Promise.resolve();\n }\n return new Promise<void>((resolve, reject) => {\n this.openSocket(resolve, reject);\n });\n }\n\n /** Closes the connection and disables auto-reconnect. */\n disconnect(): void {\n this.wantConnected = false;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n if (this.ws) {\n this.ws.close();\n }\n }\n\n /** List of printers installed on the client's system. */\n async getPrinters(): Promise<Printer[]> {\n const r = await this.request({ type: \"listPrinters\" });\n return r.printers ?? [];\n }\n\n /** Agent brand and version. */\n async getVersion(): Promise<AgentVersion> {\n const r = await this.request({ type: \"version\" });\n return { brand: r.brand ?? \"\", version: r.version ?? \"\" };\n }\n\n /** Sends a PDF print job; resolves once the agent confirms. */\n async print(opts: PrintOptions): Promise<void> {\n if (!opts || !opts.printer) {\n throw new Error(this.t.printNoPrinter);\n }\n const hasUrl = typeof opts.url === \"string\" && opts.url.length > 0;\n const hasB64 = typeof opts.base64 === \"string\" && opts.base64.length > 0;\n if (hasUrl === hasB64) {\n throw new Error(this.t.printSource);\n }\n const pdf = hasUrl ? { url: opts.url } : { base64: opts.base64 };\n await this.request({\n type: \"printPDF\",\n printer: opts.printer,\n pdf,\n copies: opts.copies,\n });\n }\n\n // --- internal ---\n\n private openSocket(\n onOpen?: () => void,\n onFail?: (e: Error) => void\n ): void {\n this.setStatus(\"connecting\");\n let settled = false;\n const ws = new this.WS(this.url);\n this.ws = ws;\n\n const connectTimer = setTimeout(() => {\n if (!settled) {\n settled = true;\n try {\n ws.close();\n } catch {\n /* ignore */\n }\n onFail?.(new TimeoutError(this.t.connectTimeout));\n }\n }, this.requestTimeoutMs);\n\n ws.onopen = () => {\n settled = true;\n clearTimeout(connectTimer);\n this.reconnectAttempt = 0;\n this.setStatus(\"open\");\n onOpen?.();\n };\n ws.onmessage = (ev) => this.handleMessage(ev.data);\n ws.onerror = () => {\n /* onclose will follow the error */\n };\n ws.onclose = () => {\n clearTimeout(connectTimer);\n this.ws = undefined;\n this.setStatus(\"closed\");\n this.rejectAllPending(new NotConnectedError(this.t.connectionClosed));\n if (!settled) {\n settled = true;\n onFail?.(new NotConnectedError(this.t.connectFailed));\n }\n if (this.wantConnected && this.autoReconnect) {\n this.scheduleReconnect();\n }\n };\n }\n\n private scheduleReconnect(): void {\n const delay =\n RECONNECT_BACKOFF_MS[Math.min(this.reconnectAttempt, RECONNECT_BACKOFF_MS.length - 1)];\n this.reconnectAttempt++;\n this.reconnectTimer = setTimeout(() => {\n if (this.wantConnected) {\n this.openSocket();\n }\n }, delay);\n }\n\n private handleMessage(data: unknown): void {\n const text = typeof data === \"string\" ? data : String(data);\n let msg: AgentResponse;\n try {\n msg = JSON.parse(text);\n } catch {\n return;\n }\n const id = msg.id;\n if (!id) return;\n const p = this.pending.get(id);\n if (!p) return;\n clearTimeout(p.timer);\n this.pending.delete(id);\n if (msg.ok) {\n p.resolve(msg);\n } else {\n p.reject(new AgentError(msg.error || this.t.agentError));\n }\n }\n\n private request(payload: Record<string, unknown>): Promise<AgentResponse> {\n if (!this.isConnected() || !this.ws) {\n return Promise.reject(new NotConnectedError(this.t.notConnected));\n }\n const id = String(++this.idCounter);\n const ws = this.ws;\n return new Promise<AgentResponse>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new TimeoutError(this.t.timeout));\n }, this.requestTimeoutMs);\n this.pending.set(id, { resolve, reject, timer });\n try {\n ws.send(JSON.stringify({ ...payload, id }));\n } catch (e) {\n clearTimeout(timer);\n this.pending.delete(id);\n reject(e instanceof Error ? e : new Error(String(e)));\n }\n });\n }\n\n private rejectAllPending(err: Error): void {\n for (const [, p] of this.pending) {\n clearTimeout(p.timer);\n p.reject(err);\n }\n this.pending.clear();\n }\n\n private setStatus(s: ConnectionStatus): void {\n if (this._status === s) return;\n this._status = s;\n for (const cb of this.statusListeners) {\n cb(s);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/locales/en.ts","../src/locales/pl.ts","../src/locales/index.ts","../src/client.ts"],"sourcesContent":["export { PrintAgent } from \"./client\";\nexport {\n AgentError,\n NotConnectedError,\n TimeoutError,\n type AgentVersion,\n type ConnectionStatus,\n type Printer,\n type PrintAgentOptions,\n type PrintOptions,\n type PrintBatchOptions,\n type WebSocketCtor,\n type WebSocketLike,\n} from \"./types\";\nexport { locales, getMessages, type Lang, type Messages } from \"./locales\";\n","import type { Lang } from \"./locales\";\n\n/** Connection status with the local agent. */\nexport type ConnectionStatus = \"connecting\" | \"open\" | \"closed\";\n\n/** A printer returned by the agent. */\nexport interface Printer {\n name: string;\n default: boolean;\n}\n\n/** Agent version. */\nexport interface AgentVersion {\n brand: string;\n version: string;\n}\n\n/** Print job parameters. Provide exactly one source: url or base64. */\nexport interface PrintOptions {\n printer: string;\n url?: string;\n base64?: string;\n copies?: number;\n}\n\n/** Batch print parameters: many label PDFs merged into a single print job. */\nexport interface PrintBatchOptions {\n printer: string;\n /** PDF URLs, printed in this order as one merged job. */\n urls: string[];\n /** Copies of each label (each label is repeated this many times). */\n copies?: number;\n}\n\n/** PrintAgent constructor options. */\nexport interface PrintAgentOptions {\n host?: string;\n port?: number;\n url?: string;\n autoReconnect?: boolean;\n requestTimeoutMs?: number;\n WebSocket?: WebSocketCtor;\n /** Language of SDK error messages; defaults to \"en\". */\n lang?: Lang;\n}\n\n/** Minimal WebSocket interface used by the SDK (compatible with the browser and the ws package). */\nexport interface WebSocketLike {\n send(data: string): void;\n close(): void;\n onopen: ((ev: unknown) => void) | null;\n onmessage: ((ev: { data: unknown }) => void) | null;\n onclose: ((ev: unknown) => void) | null;\n onerror: ((ev: unknown) => void) | null;\n}\n\nexport interface WebSocketCtor {\n new (url: string): WebSocketLike;\n}\n\n/** No active connection to the agent. (Message is localized by the client.) */\nexport class NotConnectedError extends Error {\n constructor(message = \"no connection to the agent\") {\n super(message);\n this.name = \"NotConnectedError\";\n }\n}\n\n/** Timed out waiting for the agent. (Message is localized by the client.) */\nexport class TimeoutError extends Error {\n constructor(message = \"timed out waiting for the agent\") {\n super(message);\n this.name = \"TimeoutError\";\n }\n}\n\n/** The agent responded with an error (ok:false). */\nexport class AgentError extends Error {\n constructor(message = \"agent error\") {\n super(message);\n this.name = \"AgentError\";\n }\n}\n","import type { Messages } from \"./types\";\n\n/** English message catalog (default). */\nexport const en: Messages = {\n notConnected: \"no connection to the agent\",\n connectionClosed: \"connection closed\",\n connectFailed: \"could not connect to the agent\",\n timeout: \"timed out waiting for the agent's response\",\n connectTimeout: \"timed out connecting to the agent\",\n agentError: \"agent error\",\n noWebSocket: \"no WebSocket implementation (pass the WebSocket option)\",\n printNoPrinter: \"print: printer name is required (printer)\",\n printSource: \"print: provide exactly one source — url or base64\",\n printNoUrls: \"printBatch: at least one url is required (urls)\",\n};\n","import type { Messages } from \"./types\";\n\n/** Polish message catalog. */\nexport const pl: Messages = {\n notConnected: \"brak połączenia z agentem\",\n connectionClosed: \"połączenie zamknięte\",\n connectFailed: \"nie udało się połączyć z agentem\",\n timeout: \"przekroczono czas oczekiwania na odpowiedź agenta\",\n connectTimeout: \"przekroczono czas łączenia z agentem\",\n agentError: \"błąd agenta\",\n noWebSocket: \"brak implementacji WebSocket (przekaż opcję WebSocket)\",\n printNoPrinter: \"print: wymagana nazwa drukarki (printer)\",\n printSource: \"print: podaj dokładnie jedno źródło — url albo base64\",\n printNoUrls: \"printBatch: wymagany co najmniej jeden url (urls)\",\n};\n","import { en } from \"./en\";\nimport { pl } from \"./pl\";\nimport type { Lang, Messages } from \"./types\";\n\nexport type { Lang, Messages };\n\n/** All available message catalogs keyed by language. */\nexport const locales: Record<Lang, Messages> = { en, pl };\n\n/** Returns the message catalog for the given language (defaults to English). */\nexport function getMessages(lang: Lang = \"en\"): Messages {\n return locales[lang] ?? en;\n}\n","import {\n AgentError,\n NotConnectedError,\n TimeoutError,\n type AgentVersion,\n type ConnectionStatus,\n type PrintAgentOptions,\n type PrintBatchOptions,\n type PrintOptions,\n type Printer,\n type WebSocketCtor,\n type WebSocketLike,\n} from \"./types\";\nimport { getMessages, type Messages } from \"./locales\";\n\ninterface AgentResponse {\n type: string;\n id?: string;\n ok: boolean;\n error?: string;\n printers?: Printer[];\n brand?: string;\n version?: string;\n}\n\ninterface Pending {\n resolve: (r: AgentResponse) => void;\n reject: (e: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\nconst RECONNECT_BACKOFF_MS = [1000, 2000, 5000, 10000];\n\n/** Client for the local print agent. */\nexport class PrintAgent {\n private readonly url: string;\n private readonly autoReconnect: boolean;\n private readonly requestTimeoutMs: number;\n private readonly WS: WebSocketCtor;\n private readonly t: Messages;\n\n private ws?: WebSocketLike;\n private _status: ConnectionStatus = \"closed\";\n private statusListeners = new Set<(s: ConnectionStatus) => void>();\n private pending = new Map<string, Pending>();\n private idCounter = 0;\n private wantConnected = false;\n private reconnectAttempt = 0;\n private reconnectTimer?: ReturnType<typeof setTimeout>;\n\n constructor(opts: PrintAgentOptions = {}) {\n this.t = getMessages(opts.lang);\n const host = opts.host ?? \"localhost\";\n const port = opts.port ?? 45123;\n this.url = opts.url ?? `wss://${host}:${port}/ws`;\n this.autoReconnect = opts.autoReconnect ?? true;\n this.requestTimeoutMs = opts.requestTimeoutMs ?? 10000;\n const ctor = opts.WebSocket ?? (globalThis as { WebSocket?: WebSocketCtor }).WebSocket;\n if (!ctor) {\n throw new Error(this.t.noWebSocket);\n }\n this.WS = ctor;\n }\n\n get status(): ConnectionStatus {\n return this._status;\n }\n\n isConnected(): boolean {\n return this._status === \"open\";\n }\n\n /** Registers a status-change listener; returns an unsubscribe function. */\n onStatusChange(cb: (s: ConnectionStatus) => void): () => void {\n this.statusListeners.add(cb);\n return () => this.statusListeners.delete(cb);\n }\n\n /** Connects to the agent; resolves on open, rejects on timeout/failure.\n * Idempotent when the connection is already open. */\n connect(): Promise<void> {\n this.wantConnected = true;\n if (this._status === \"open\") {\n return Promise.resolve();\n }\n return new Promise<void>((resolve, reject) => {\n this.openSocket(resolve, reject);\n });\n }\n\n /** Closes the connection and disables auto-reconnect. */\n disconnect(): void {\n this.wantConnected = false;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n if (this.ws) {\n this.ws.close();\n }\n }\n\n /** List of printers installed on the client's system. */\n async getPrinters(): Promise<Printer[]> {\n const r = await this.request({ type: \"listPrinters\" });\n return r.printers ?? [];\n }\n\n /** Agent brand and version. */\n async getVersion(): Promise<AgentVersion> {\n const r = await this.request({ type: \"version\" });\n return { brand: r.brand ?? \"\", version: r.version ?? \"\" };\n }\n\n /** Sends a PDF print job; resolves once the agent confirms. */\n async print(opts: PrintOptions): Promise<void> {\n if (!opts || !opts.printer) {\n throw new Error(this.t.printNoPrinter);\n }\n const hasUrl = typeof opts.url === \"string\" && opts.url.length > 0;\n const hasB64 = typeof opts.base64 === \"string\" && opts.base64.length > 0;\n if (hasUrl === hasB64) {\n throw new Error(this.t.printSource);\n }\n const pdf = hasUrl ? { url: opts.url } : { base64: opts.base64 };\n await this.request({\n type: \"printPDF\",\n printer: opts.printer,\n pdf,\n copies: opts.copies,\n });\n }\n\n /** Sends a batch of label PDFs as a SINGLE merged print job.\n * The agent fetches all URLs, merges them (each label repeated `copies`\n * times) and sends one job to the spooler — avoiding the printer's pauses\n * between separate jobs. Resolves once the agent has accepted the batch. */\n async printBatch(opts: PrintBatchOptions): Promise<void> {\n if (!opts || !opts.printer) {\n throw new Error(this.t.printNoPrinter);\n }\n if (!Array.isArray(opts.urls) || opts.urls.length === 0) {\n throw new Error(this.t.printNoUrls);\n }\n const pdfs = opts.urls.map((url) => ({ url }));\n await this.request({\n type: \"printBatch\",\n printer: opts.printer,\n pdfs,\n copies: opts.copies,\n });\n }\n\n // --- internal ---\n\n private openSocket(\n onOpen?: () => void,\n onFail?: (e: Error) => void\n ): void {\n this.setStatus(\"connecting\");\n let settled = false;\n const ws = new this.WS(this.url);\n this.ws = ws;\n\n const connectTimer = setTimeout(() => {\n if (!settled) {\n settled = true;\n try {\n ws.close();\n } catch {\n /* ignore */\n }\n onFail?.(new TimeoutError(this.t.connectTimeout));\n }\n }, this.requestTimeoutMs);\n\n ws.onopen = () => {\n settled = true;\n clearTimeout(connectTimer);\n this.reconnectAttempt = 0;\n this.setStatus(\"open\");\n onOpen?.();\n };\n ws.onmessage = (ev) => this.handleMessage(ev.data);\n ws.onerror = () => {\n /* onclose will follow the error */\n };\n ws.onclose = () => {\n clearTimeout(connectTimer);\n this.ws = undefined;\n this.setStatus(\"closed\");\n this.rejectAllPending(new NotConnectedError(this.t.connectionClosed));\n if (!settled) {\n settled = true;\n onFail?.(new NotConnectedError(this.t.connectFailed));\n }\n if (this.wantConnected && this.autoReconnect) {\n this.scheduleReconnect();\n }\n };\n }\n\n private scheduleReconnect(): void {\n const delay =\n RECONNECT_BACKOFF_MS[Math.min(this.reconnectAttempt, RECONNECT_BACKOFF_MS.length - 1)];\n this.reconnectAttempt++;\n this.reconnectTimer = setTimeout(() => {\n if (this.wantConnected) {\n this.openSocket();\n }\n }, delay);\n }\n\n private handleMessage(data: unknown): void {\n const text = typeof data === \"string\" ? data : String(data);\n let msg: AgentResponse;\n try {\n msg = JSON.parse(text);\n } catch {\n return;\n }\n const id = msg.id;\n if (!id) return;\n const p = this.pending.get(id);\n if (!p) return;\n clearTimeout(p.timer);\n this.pending.delete(id);\n if (msg.ok) {\n p.resolve(msg);\n } else {\n p.reject(new AgentError(msg.error || this.t.agentError));\n }\n }\n\n private request(payload: Record<string, unknown>): Promise<AgentResponse> {\n if (!this.isConnected() || !this.ws) {\n return Promise.reject(new NotConnectedError(this.t.notConnected));\n }\n const id = String(++this.idCounter);\n const ws = this.ws;\n return new Promise<AgentResponse>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new TimeoutError(this.t.timeout));\n }, this.requestTimeoutMs);\n this.pending.set(id, { resolve, reject, timer });\n try {\n ws.send(JSON.stringify({ ...payload, id }));\n } catch (e) {\n clearTimeout(timer);\n this.pending.delete(id);\n reject(e instanceof Error ? e : new Error(String(e)));\n }\n });\n }\n\n private rejectAllPending(err: Error): void {\n for (const [, p] of this.pending) {\n clearTimeout(p.timer);\n p.reject(err);\n }\n this.pending.clear();\n }\n\n private setStatus(s: ConnectionStatus): void {\n if (this._status === s) return;\n this._status = s;\n for (const cb of this.statusListeners) {\n cb(s);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -20,6 +20,8 @@ interface Messages {
|
|
|
20
20
|
printNoPrinter: string;
|
|
21
21
|
/** print(): wrong number of PDF sources. */
|
|
22
22
|
printSource: string;
|
|
23
|
+
/** printBatch(): empty url list. */
|
|
24
|
+
printNoUrls: string;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
/** All available message catalogs keyed by language. */
|
|
@@ -46,6 +48,14 @@ interface PrintOptions {
|
|
|
46
48
|
base64?: string;
|
|
47
49
|
copies?: number;
|
|
48
50
|
}
|
|
51
|
+
/** Batch print parameters: many label PDFs merged into a single print job. */
|
|
52
|
+
interface PrintBatchOptions {
|
|
53
|
+
printer: string;
|
|
54
|
+
/** PDF URLs, printed in this order as one merged job. */
|
|
55
|
+
urls: string[];
|
|
56
|
+
/** Copies of each label (each label is repeated this many times). */
|
|
57
|
+
copies?: number;
|
|
58
|
+
}
|
|
49
59
|
/** PrintAgent constructor options. */
|
|
50
60
|
interface PrintAgentOptions {
|
|
51
61
|
host?: string;
|
|
@@ -115,6 +125,11 @@ declare class PrintAgent {
|
|
|
115
125
|
getVersion(): Promise<AgentVersion>;
|
|
116
126
|
/** Sends a PDF print job; resolves once the agent confirms. */
|
|
117
127
|
print(opts: PrintOptions): Promise<void>;
|
|
128
|
+
/** Sends a batch of label PDFs as a SINGLE merged print job.
|
|
129
|
+
* The agent fetches all URLs, merges them (each label repeated `copies`
|
|
130
|
+
* times) and sends one job to the spooler — avoiding the printer's pauses
|
|
131
|
+
* between separate jobs. Resolves once the agent has accepted the batch. */
|
|
132
|
+
printBatch(opts: PrintBatchOptions): Promise<void>;
|
|
118
133
|
private openSocket;
|
|
119
134
|
private scheduleReconnect;
|
|
120
135
|
private handleMessage;
|
|
@@ -123,4 +138,4 @@ declare class PrintAgent {
|
|
|
123
138
|
private setStatus;
|
|
124
139
|
}
|
|
125
140
|
|
|
126
|
-
export { AgentError, type AgentVersion, type ConnectionStatus, type Lang, type Messages, NotConnectedError, PrintAgent, type PrintAgentOptions, type PrintOptions, type Printer, TimeoutError, type WebSocketCtor, type WebSocketLike, getMessages, locales };
|
|
141
|
+
export { AgentError, type AgentVersion, type ConnectionStatus, type Lang, type Messages, NotConnectedError, PrintAgent, type PrintAgentOptions, type PrintBatchOptions, type PrintOptions, type Printer, TimeoutError, type WebSocketCtor, type WebSocketLike, getMessages, locales };
|
package/dist/index.d.ts
CHANGED
|
@@ -20,6 +20,8 @@ interface Messages {
|
|
|
20
20
|
printNoPrinter: string;
|
|
21
21
|
/** print(): wrong number of PDF sources. */
|
|
22
22
|
printSource: string;
|
|
23
|
+
/** printBatch(): empty url list. */
|
|
24
|
+
printNoUrls: string;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
/** All available message catalogs keyed by language. */
|
|
@@ -46,6 +48,14 @@ interface PrintOptions {
|
|
|
46
48
|
base64?: string;
|
|
47
49
|
copies?: number;
|
|
48
50
|
}
|
|
51
|
+
/** Batch print parameters: many label PDFs merged into a single print job. */
|
|
52
|
+
interface PrintBatchOptions {
|
|
53
|
+
printer: string;
|
|
54
|
+
/** PDF URLs, printed in this order as one merged job. */
|
|
55
|
+
urls: string[];
|
|
56
|
+
/** Copies of each label (each label is repeated this many times). */
|
|
57
|
+
copies?: number;
|
|
58
|
+
}
|
|
49
59
|
/** PrintAgent constructor options. */
|
|
50
60
|
interface PrintAgentOptions {
|
|
51
61
|
host?: string;
|
|
@@ -115,6 +125,11 @@ declare class PrintAgent {
|
|
|
115
125
|
getVersion(): Promise<AgentVersion>;
|
|
116
126
|
/** Sends a PDF print job; resolves once the agent confirms. */
|
|
117
127
|
print(opts: PrintOptions): Promise<void>;
|
|
128
|
+
/** Sends a batch of label PDFs as a SINGLE merged print job.
|
|
129
|
+
* The agent fetches all URLs, merges them (each label repeated `copies`
|
|
130
|
+
* times) and sends one job to the spooler — avoiding the printer's pauses
|
|
131
|
+
* between separate jobs. Resolves once the agent has accepted the batch. */
|
|
132
|
+
printBatch(opts: PrintBatchOptions): Promise<void>;
|
|
118
133
|
private openSocket;
|
|
119
134
|
private scheduleReconnect;
|
|
120
135
|
private handleMessage;
|
|
@@ -123,4 +138,4 @@ declare class PrintAgent {
|
|
|
123
138
|
private setStatus;
|
|
124
139
|
}
|
|
125
140
|
|
|
126
|
-
export { AgentError, type AgentVersion, type ConnectionStatus, type Lang, type Messages, NotConnectedError, PrintAgent, type PrintAgentOptions, type PrintOptions, type Printer, TimeoutError, type WebSocketCtor, type WebSocketLike, getMessages, locales };
|
|
141
|
+
export { AgentError, type AgentVersion, type ConnectionStatus, type Lang, type Messages, NotConnectedError, PrintAgent, type PrintAgentOptions, type PrintBatchOptions, type PrintOptions, type Printer, TimeoutError, type WebSocketCtor, type WebSocketLike, getMessages, locales };
|
package/dist/index.js
CHANGED
|
@@ -28,7 +28,8 @@ var en = {
|
|
|
28
28
|
agentError: "agent error",
|
|
29
29
|
noWebSocket: "no WebSocket implementation (pass the WebSocket option)",
|
|
30
30
|
printNoPrinter: "print: printer name is required (printer)",
|
|
31
|
-
printSource: "print: provide exactly one source \u2014 url or base64"
|
|
31
|
+
printSource: "print: provide exactly one source \u2014 url or base64",
|
|
32
|
+
printNoUrls: "printBatch: at least one url is required (urls)"
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
// src/locales/pl.ts
|
|
@@ -41,7 +42,8 @@ var pl = {
|
|
|
41
42
|
agentError: "b\u0142\u0105d agenta",
|
|
42
43
|
noWebSocket: "brak implementacji WebSocket (przeka\u017C opcj\u0119 WebSocket)",
|
|
43
44
|
printNoPrinter: "print: wymagana nazwa drukarki (printer)",
|
|
44
|
-
printSource: "print: podaj dok\u0142adnie jedno \u017Ar\xF3d\u0142o \u2014 url albo base64"
|
|
45
|
+
printSource: "print: podaj dok\u0142adnie jedno \u017Ar\xF3d\u0142o \u2014 url albo base64",
|
|
46
|
+
printNoUrls: "printBatch: wymagany co najmniej jeden url (urls)"
|
|
45
47
|
};
|
|
46
48
|
|
|
47
49
|
// src/locales/index.ts
|
|
@@ -133,6 +135,25 @@ var PrintAgent = class {
|
|
|
133
135
|
copies: opts.copies
|
|
134
136
|
});
|
|
135
137
|
}
|
|
138
|
+
/** Sends a batch of label PDFs as a SINGLE merged print job.
|
|
139
|
+
* The agent fetches all URLs, merges them (each label repeated `copies`
|
|
140
|
+
* times) and sends one job to the spooler — avoiding the printer's pauses
|
|
141
|
+
* between separate jobs. Resolves once the agent has accepted the batch. */
|
|
142
|
+
async printBatch(opts) {
|
|
143
|
+
if (!opts || !opts.printer) {
|
|
144
|
+
throw new Error(this.t.printNoPrinter);
|
|
145
|
+
}
|
|
146
|
+
if (!Array.isArray(opts.urls) || opts.urls.length === 0) {
|
|
147
|
+
throw new Error(this.t.printNoUrls);
|
|
148
|
+
}
|
|
149
|
+
const pdfs = opts.urls.map((url) => ({ url }));
|
|
150
|
+
await this.request({
|
|
151
|
+
type: "printBatch",
|
|
152
|
+
printer: opts.printer,
|
|
153
|
+
pdfs,
|
|
154
|
+
copies: opts.copies
|
|
155
|
+
});
|
|
156
|
+
}
|
|
136
157
|
// --- internal ---
|
|
137
158
|
openSocket(onOpen, onFail) {
|
|
138
159
|
this.setStatus("connecting");
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/locales/en.ts","../src/locales/pl.ts","../src/locales/index.ts","../src/client.ts"],"sourcesContent":["import type { Lang } from \"./locales\";\n\n/** Connection status with the local agent. */\nexport type ConnectionStatus = \"connecting\" | \"open\" | \"closed\";\n\n/** A printer returned by the agent. */\nexport interface Printer {\n name: string;\n default: boolean;\n}\n\n/** Agent version. */\nexport interface AgentVersion {\n brand: string;\n version: string;\n}\n\n/** Print job parameters. Provide exactly one source: url or base64. */\nexport interface PrintOptions {\n printer: string;\n url?: string;\n base64?: string;\n copies?: number;\n}\n\n/** PrintAgent constructor options. */\nexport interface PrintAgentOptions {\n host?: string;\n port?: number;\n url?: string;\n autoReconnect?: boolean;\n requestTimeoutMs?: number;\n WebSocket?: WebSocketCtor;\n /** Language of SDK error messages; defaults to \"en\". */\n lang?: Lang;\n}\n\n/** Minimal WebSocket interface used by the SDK (compatible with the browser and the ws package). */\nexport interface WebSocketLike {\n send(data: string): void;\n close(): void;\n onopen: ((ev: unknown) => void) | null;\n onmessage: ((ev: { data: unknown }) => void) | null;\n onclose: ((ev: unknown) => void) | null;\n onerror: ((ev: unknown) => void) | null;\n}\n\nexport interface WebSocketCtor {\n new (url: string): WebSocketLike;\n}\n\n/** No active connection to the agent. (Message is localized by the client.) */\nexport class NotConnectedError extends Error {\n constructor(message = \"no connection to the agent\") {\n super(message);\n this.name = \"NotConnectedError\";\n }\n}\n\n/** Timed out waiting for the agent. (Message is localized by the client.) */\nexport class TimeoutError extends Error {\n constructor(message = \"timed out waiting for the agent\") {\n super(message);\n this.name = \"TimeoutError\";\n }\n}\n\n/** The agent responded with an error (ok:false). */\nexport class AgentError extends Error {\n constructor(message = \"agent error\") {\n super(message);\n this.name = \"AgentError\";\n }\n}\n","import type { Messages } from \"./types\";\n\n/** English message catalog (default). */\nexport const en: Messages = {\n notConnected: \"no connection to the agent\",\n connectionClosed: \"connection closed\",\n connectFailed: \"could not connect to the agent\",\n timeout: \"timed out waiting for the agent's response\",\n connectTimeout: \"timed out connecting to the agent\",\n agentError: \"agent error\",\n noWebSocket: \"no WebSocket implementation (pass the WebSocket option)\",\n printNoPrinter: \"print: printer name is required (printer)\",\n printSource: \"print: provide exactly one source — url or base64\",\n};\n","import type { Messages } from \"./types\";\n\n/** Polish message catalog. */\nexport const pl: Messages = {\n notConnected: \"brak połączenia z agentem\",\n connectionClosed: \"połączenie zamknięte\",\n connectFailed: \"nie udało się połączyć z agentem\",\n timeout: \"przekroczono czas oczekiwania na odpowiedź agenta\",\n connectTimeout: \"przekroczono czas łączenia z agentem\",\n agentError: \"błąd agenta\",\n noWebSocket: \"brak implementacji WebSocket (przekaż opcję WebSocket)\",\n printNoPrinter: \"print: wymagana nazwa drukarki (printer)\",\n printSource: \"print: podaj dokładnie jedno źródło — url albo base64\",\n};\n","import { en } from \"./en\";\nimport { pl } from \"./pl\";\nimport type { Lang, Messages } from \"./types\";\n\nexport type { Lang, Messages };\n\n/** All available message catalogs keyed by language. */\nexport const locales: Record<Lang, Messages> = { en, pl };\n\n/** Returns the message catalog for the given language (defaults to English). */\nexport function getMessages(lang: Lang = \"en\"): Messages {\n return locales[lang] ?? en;\n}\n","import {\n AgentError,\n NotConnectedError,\n TimeoutError,\n type AgentVersion,\n type ConnectionStatus,\n type PrintAgentOptions,\n type PrintOptions,\n type Printer,\n type WebSocketCtor,\n type WebSocketLike,\n} from \"./types\";\nimport { getMessages, type Messages } from \"./locales\";\n\ninterface AgentResponse {\n type: string;\n id?: string;\n ok: boolean;\n error?: string;\n printers?: Printer[];\n brand?: string;\n version?: string;\n}\n\ninterface Pending {\n resolve: (r: AgentResponse) => void;\n reject: (e: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\nconst RECONNECT_BACKOFF_MS = [1000, 2000, 5000, 10000];\n\n/** Client for the local print agent. */\nexport class PrintAgent {\n private readonly url: string;\n private readonly autoReconnect: boolean;\n private readonly requestTimeoutMs: number;\n private readonly WS: WebSocketCtor;\n private readonly t: Messages;\n\n private ws?: WebSocketLike;\n private _status: ConnectionStatus = \"closed\";\n private statusListeners = new Set<(s: ConnectionStatus) => void>();\n private pending = new Map<string, Pending>();\n private idCounter = 0;\n private wantConnected = false;\n private reconnectAttempt = 0;\n private reconnectTimer?: ReturnType<typeof setTimeout>;\n\n constructor(opts: PrintAgentOptions = {}) {\n this.t = getMessages(opts.lang);\n const host = opts.host ?? \"localhost\";\n const port = opts.port ?? 45123;\n this.url = opts.url ?? `wss://${host}:${port}/ws`;\n this.autoReconnect = opts.autoReconnect ?? true;\n this.requestTimeoutMs = opts.requestTimeoutMs ?? 10000;\n const ctor = opts.WebSocket ?? (globalThis as { WebSocket?: WebSocketCtor }).WebSocket;\n if (!ctor) {\n throw new Error(this.t.noWebSocket);\n }\n this.WS = ctor;\n }\n\n get status(): ConnectionStatus {\n return this._status;\n }\n\n isConnected(): boolean {\n return this._status === \"open\";\n }\n\n /** Registers a status-change listener; returns an unsubscribe function. */\n onStatusChange(cb: (s: ConnectionStatus) => void): () => void {\n this.statusListeners.add(cb);\n return () => this.statusListeners.delete(cb);\n }\n\n /** Connects to the agent; resolves on open, rejects on timeout/failure.\n * Idempotent when the connection is already open. */\n connect(): Promise<void> {\n this.wantConnected = true;\n if (this._status === \"open\") {\n return Promise.resolve();\n }\n return new Promise<void>((resolve, reject) => {\n this.openSocket(resolve, reject);\n });\n }\n\n /** Closes the connection and disables auto-reconnect. */\n disconnect(): void {\n this.wantConnected = false;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n if (this.ws) {\n this.ws.close();\n }\n }\n\n /** List of printers installed on the client's system. */\n async getPrinters(): Promise<Printer[]> {\n const r = await this.request({ type: \"listPrinters\" });\n return r.printers ?? [];\n }\n\n /** Agent brand and version. */\n async getVersion(): Promise<AgentVersion> {\n const r = await this.request({ type: \"version\" });\n return { brand: r.brand ?? \"\", version: r.version ?? \"\" };\n }\n\n /** Sends a PDF print job; resolves once the agent confirms. */\n async print(opts: PrintOptions): Promise<void> {\n if (!opts || !opts.printer) {\n throw new Error(this.t.printNoPrinter);\n }\n const hasUrl = typeof opts.url === \"string\" && opts.url.length > 0;\n const hasB64 = typeof opts.base64 === \"string\" && opts.base64.length > 0;\n if (hasUrl === hasB64) {\n throw new Error(this.t.printSource);\n }\n const pdf = hasUrl ? { url: opts.url } : { base64: opts.base64 };\n await this.request({\n type: \"printPDF\",\n printer: opts.printer,\n pdf,\n copies: opts.copies,\n });\n }\n\n // --- internal ---\n\n private openSocket(\n onOpen?: () => void,\n onFail?: (e: Error) => void\n ): void {\n this.setStatus(\"connecting\");\n let settled = false;\n const ws = new this.WS(this.url);\n this.ws = ws;\n\n const connectTimer = setTimeout(() => {\n if (!settled) {\n settled = true;\n try {\n ws.close();\n } catch {\n /* ignore */\n }\n onFail?.(new TimeoutError(this.t.connectTimeout));\n }\n }, this.requestTimeoutMs);\n\n ws.onopen = () => {\n settled = true;\n clearTimeout(connectTimer);\n this.reconnectAttempt = 0;\n this.setStatus(\"open\");\n onOpen?.();\n };\n ws.onmessage = (ev) => this.handleMessage(ev.data);\n ws.onerror = () => {\n /* onclose will follow the error */\n };\n ws.onclose = () => {\n clearTimeout(connectTimer);\n this.ws = undefined;\n this.setStatus(\"closed\");\n this.rejectAllPending(new NotConnectedError(this.t.connectionClosed));\n if (!settled) {\n settled = true;\n onFail?.(new NotConnectedError(this.t.connectFailed));\n }\n if (this.wantConnected && this.autoReconnect) {\n this.scheduleReconnect();\n }\n };\n }\n\n private scheduleReconnect(): void {\n const delay =\n RECONNECT_BACKOFF_MS[Math.min(this.reconnectAttempt, RECONNECT_BACKOFF_MS.length - 1)];\n this.reconnectAttempt++;\n this.reconnectTimer = setTimeout(() => {\n if (this.wantConnected) {\n this.openSocket();\n }\n }, delay);\n }\n\n private handleMessage(data: unknown): void {\n const text = typeof data === \"string\" ? data : String(data);\n let msg: AgentResponse;\n try {\n msg = JSON.parse(text);\n } catch {\n return;\n }\n const id = msg.id;\n if (!id) return;\n const p = this.pending.get(id);\n if (!p) return;\n clearTimeout(p.timer);\n this.pending.delete(id);\n if (msg.ok) {\n p.resolve(msg);\n } else {\n p.reject(new AgentError(msg.error || this.t.agentError));\n }\n }\n\n private request(payload: Record<string, unknown>): Promise<AgentResponse> {\n if (!this.isConnected() || !this.ws) {\n return Promise.reject(new NotConnectedError(this.t.notConnected));\n }\n const id = String(++this.idCounter);\n const ws = this.ws;\n return new Promise<AgentResponse>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new TimeoutError(this.t.timeout));\n }, this.requestTimeoutMs);\n this.pending.set(id, { resolve, reject, timer });\n try {\n ws.send(JSON.stringify({ ...payload, id }));\n } catch (e) {\n clearTimeout(timer);\n this.pending.delete(id);\n reject(e instanceof Error ? e : new Error(String(e)));\n }\n });\n }\n\n private rejectAllPending(err: Error): void {\n for (const [, p] of this.pending) {\n clearTimeout(p.timer);\n p.reject(err);\n }\n this.pending.clear();\n }\n\n private setStatus(s: ConnectionStatus): void {\n if (this._status === s) return;\n this._status = s;\n for (const cb of this.statusListeners) {\n cb(s);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/locales/en.ts","../src/locales/pl.ts","../src/locales/index.ts","../src/client.ts"],"sourcesContent":["import type { Lang } from \"./locales\";\n\n/** Connection status with the local agent. */\nexport type ConnectionStatus = \"connecting\" | \"open\" | \"closed\";\n\n/** A printer returned by the agent. */\nexport interface Printer {\n name: string;\n default: boolean;\n}\n\n/** Agent version. */\nexport interface AgentVersion {\n brand: string;\n version: string;\n}\n\n/** Print job parameters. Provide exactly one source: url or base64. */\nexport interface PrintOptions {\n printer: string;\n url?: string;\n base64?: string;\n copies?: number;\n}\n\n/** Batch print parameters: many label PDFs merged into a single print job. */\nexport interface PrintBatchOptions {\n printer: string;\n /** PDF URLs, printed in this order as one merged job. */\n urls: string[];\n /** Copies of each label (each label is repeated this many times). */\n copies?: number;\n}\n\n/** PrintAgent constructor options. */\nexport interface PrintAgentOptions {\n host?: string;\n port?: number;\n url?: string;\n autoReconnect?: boolean;\n requestTimeoutMs?: number;\n WebSocket?: WebSocketCtor;\n /** Language of SDK error messages; defaults to \"en\". */\n lang?: Lang;\n}\n\n/** Minimal WebSocket interface used by the SDK (compatible with the browser and the ws package). */\nexport interface WebSocketLike {\n send(data: string): void;\n close(): void;\n onopen: ((ev: unknown) => void) | null;\n onmessage: ((ev: { data: unknown }) => void) | null;\n onclose: ((ev: unknown) => void) | null;\n onerror: ((ev: unknown) => void) | null;\n}\n\nexport interface WebSocketCtor {\n new (url: string): WebSocketLike;\n}\n\n/** No active connection to the agent. (Message is localized by the client.) */\nexport class NotConnectedError extends Error {\n constructor(message = \"no connection to the agent\") {\n super(message);\n this.name = \"NotConnectedError\";\n }\n}\n\n/** Timed out waiting for the agent. (Message is localized by the client.) */\nexport class TimeoutError extends Error {\n constructor(message = \"timed out waiting for the agent\") {\n super(message);\n this.name = \"TimeoutError\";\n }\n}\n\n/** The agent responded with an error (ok:false). */\nexport class AgentError extends Error {\n constructor(message = \"agent error\") {\n super(message);\n this.name = \"AgentError\";\n }\n}\n","import type { Messages } from \"./types\";\n\n/** English message catalog (default). */\nexport const en: Messages = {\n notConnected: \"no connection to the agent\",\n connectionClosed: \"connection closed\",\n connectFailed: \"could not connect to the agent\",\n timeout: \"timed out waiting for the agent's response\",\n connectTimeout: \"timed out connecting to the agent\",\n agentError: \"agent error\",\n noWebSocket: \"no WebSocket implementation (pass the WebSocket option)\",\n printNoPrinter: \"print: printer name is required (printer)\",\n printSource: \"print: provide exactly one source — url or base64\",\n printNoUrls: \"printBatch: at least one url is required (urls)\",\n};\n","import type { Messages } from \"./types\";\n\n/** Polish message catalog. */\nexport const pl: Messages = {\n notConnected: \"brak połączenia z agentem\",\n connectionClosed: \"połączenie zamknięte\",\n connectFailed: \"nie udało się połączyć z agentem\",\n timeout: \"przekroczono czas oczekiwania na odpowiedź agenta\",\n connectTimeout: \"przekroczono czas łączenia z agentem\",\n agentError: \"błąd agenta\",\n noWebSocket: \"brak implementacji WebSocket (przekaż opcję WebSocket)\",\n printNoPrinter: \"print: wymagana nazwa drukarki (printer)\",\n printSource: \"print: podaj dokładnie jedno źródło — url albo base64\",\n printNoUrls: \"printBatch: wymagany co najmniej jeden url (urls)\",\n};\n","import { en } from \"./en\";\nimport { pl } from \"./pl\";\nimport type { Lang, Messages } from \"./types\";\n\nexport type { Lang, Messages };\n\n/** All available message catalogs keyed by language. */\nexport const locales: Record<Lang, Messages> = { en, pl };\n\n/** Returns the message catalog for the given language (defaults to English). */\nexport function getMessages(lang: Lang = \"en\"): Messages {\n return locales[lang] ?? en;\n}\n","import {\n AgentError,\n NotConnectedError,\n TimeoutError,\n type AgentVersion,\n type ConnectionStatus,\n type PrintAgentOptions,\n type PrintBatchOptions,\n type PrintOptions,\n type Printer,\n type WebSocketCtor,\n type WebSocketLike,\n} from \"./types\";\nimport { getMessages, type Messages } from \"./locales\";\n\ninterface AgentResponse {\n type: string;\n id?: string;\n ok: boolean;\n error?: string;\n printers?: Printer[];\n brand?: string;\n version?: string;\n}\n\ninterface Pending {\n resolve: (r: AgentResponse) => void;\n reject: (e: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\nconst RECONNECT_BACKOFF_MS = [1000, 2000, 5000, 10000];\n\n/** Client for the local print agent. */\nexport class PrintAgent {\n private readonly url: string;\n private readonly autoReconnect: boolean;\n private readonly requestTimeoutMs: number;\n private readonly WS: WebSocketCtor;\n private readonly t: Messages;\n\n private ws?: WebSocketLike;\n private _status: ConnectionStatus = \"closed\";\n private statusListeners = new Set<(s: ConnectionStatus) => void>();\n private pending = new Map<string, Pending>();\n private idCounter = 0;\n private wantConnected = false;\n private reconnectAttempt = 0;\n private reconnectTimer?: ReturnType<typeof setTimeout>;\n\n constructor(opts: PrintAgentOptions = {}) {\n this.t = getMessages(opts.lang);\n const host = opts.host ?? \"localhost\";\n const port = opts.port ?? 45123;\n this.url = opts.url ?? `wss://${host}:${port}/ws`;\n this.autoReconnect = opts.autoReconnect ?? true;\n this.requestTimeoutMs = opts.requestTimeoutMs ?? 10000;\n const ctor = opts.WebSocket ?? (globalThis as { WebSocket?: WebSocketCtor }).WebSocket;\n if (!ctor) {\n throw new Error(this.t.noWebSocket);\n }\n this.WS = ctor;\n }\n\n get status(): ConnectionStatus {\n return this._status;\n }\n\n isConnected(): boolean {\n return this._status === \"open\";\n }\n\n /** Registers a status-change listener; returns an unsubscribe function. */\n onStatusChange(cb: (s: ConnectionStatus) => void): () => void {\n this.statusListeners.add(cb);\n return () => this.statusListeners.delete(cb);\n }\n\n /** Connects to the agent; resolves on open, rejects on timeout/failure.\n * Idempotent when the connection is already open. */\n connect(): Promise<void> {\n this.wantConnected = true;\n if (this._status === \"open\") {\n return Promise.resolve();\n }\n return new Promise<void>((resolve, reject) => {\n this.openSocket(resolve, reject);\n });\n }\n\n /** Closes the connection and disables auto-reconnect. */\n disconnect(): void {\n this.wantConnected = false;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n if (this.ws) {\n this.ws.close();\n }\n }\n\n /** List of printers installed on the client's system. */\n async getPrinters(): Promise<Printer[]> {\n const r = await this.request({ type: \"listPrinters\" });\n return r.printers ?? [];\n }\n\n /** Agent brand and version. */\n async getVersion(): Promise<AgentVersion> {\n const r = await this.request({ type: \"version\" });\n return { brand: r.brand ?? \"\", version: r.version ?? \"\" };\n }\n\n /** Sends a PDF print job; resolves once the agent confirms. */\n async print(opts: PrintOptions): Promise<void> {\n if (!opts || !opts.printer) {\n throw new Error(this.t.printNoPrinter);\n }\n const hasUrl = typeof opts.url === \"string\" && opts.url.length > 0;\n const hasB64 = typeof opts.base64 === \"string\" && opts.base64.length > 0;\n if (hasUrl === hasB64) {\n throw new Error(this.t.printSource);\n }\n const pdf = hasUrl ? { url: opts.url } : { base64: opts.base64 };\n await this.request({\n type: \"printPDF\",\n printer: opts.printer,\n pdf,\n copies: opts.copies,\n });\n }\n\n /** Sends a batch of label PDFs as a SINGLE merged print job.\n * The agent fetches all URLs, merges them (each label repeated `copies`\n * times) and sends one job to the spooler — avoiding the printer's pauses\n * between separate jobs. Resolves once the agent has accepted the batch. */\n async printBatch(opts: PrintBatchOptions): Promise<void> {\n if (!opts || !opts.printer) {\n throw new Error(this.t.printNoPrinter);\n }\n if (!Array.isArray(opts.urls) || opts.urls.length === 0) {\n throw new Error(this.t.printNoUrls);\n }\n const pdfs = opts.urls.map((url) => ({ url }));\n await this.request({\n type: \"printBatch\",\n printer: opts.printer,\n pdfs,\n copies: opts.copies,\n });\n }\n\n // --- internal ---\n\n private openSocket(\n onOpen?: () => void,\n onFail?: (e: Error) => void\n ): void {\n this.setStatus(\"connecting\");\n let settled = false;\n const ws = new this.WS(this.url);\n this.ws = ws;\n\n const connectTimer = setTimeout(() => {\n if (!settled) {\n settled = true;\n try {\n ws.close();\n } catch {\n /* ignore */\n }\n onFail?.(new TimeoutError(this.t.connectTimeout));\n }\n }, this.requestTimeoutMs);\n\n ws.onopen = () => {\n settled = true;\n clearTimeout(connectTimer);\n this.reconnectAttempt = 0;\n this.setStatus(\"open\");\n onOpen?.();\n };\n ws.onmessage = (ev) => this.handleMessage(ev.data);\n ws.onerror = () => {\n /* onclose will follow the error */\n };\n ws.onclose = () => {\n clearTimeout(connectTimer);\n this.ws = undefined;\n this.setStatus(\"closed\");\n this.rejectAllPending(new NotConnectedError(this.t.connectionClosed));\n if (!settled) {\n settled = true;\n onFail?.(new NotConnectedError(this.t.connectFailed));\n }\n if (this.wantConnected && this.autoReconnect) {\n this.scheduleReconnect();\n }\n };\n }\n\n private scheduleReconnect(): void {\n const delay =\n RECONNECT_BACKOFF_MS[Math.min(this.reconnectAttempt, RECONNECT_BACKOFF_MS.length - 1)];\n this.reconnectAttempt++;\n this.reconnectTimer = setTimeout(() => {\n if (this.wantConnected) {\n this.openSocket();\n }\n }, delay);\n }\n\n private handleMessage(data: unknown): void {\n const text = typeof data === \"string\" ? data : String(data);\n let msg: AgentResponse;\n try {\n msg = JSON.parse(text);\n } catch {\n return;\n }\n const id = msg.id;\n if (!id) return;\n const p = this.pending.get(id);\n if (!p) return;\n clearTimeout(p.timer);\n this.pending.delete(id);\n if (msg.ok) {\n p.resolve(msg);\n } else {\n p.reject(new AgentError(msg.error || this.t.agentError));\n }\n }\n\n private request(payload: Record<string, unknown>): Promise<AgentResponse> {\n if (!this.isConnected() || !this.ws) {\n return Promise.reject(new NotConnectedError(this.t.notConnected));\n }\n const id = String(++this.idCounter);\n const ws = this.ws;\n return new Promise<AgentResponse>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new TimeoutError(this.t.timeout));\n }, this.requestTimeoutMs);\n this.pending.set(id, { resolve, reject, timer });\n try {\n ws.send(JSON.stringify({ ...payload, id }));\n } catch (e) {\n clearTimeout(timer);\n this.pending.delete(id);\n reject(e instanceof Error ? e : new Error(String(e)));\n }\n });\n }\n\n private rejectAllPending(err: Error): void {\n for (const [, p] of this.pending) {\n clearTimeout(p.timer);\n p.reject(err);\n }\n this.pending.clear();\n }\n\n private setStatus(s: ConnectionStatus): void {\n if (this._status === s) return;\n this._status = s;\n for (const cb of this.statusListeners) {\n cb(s);\n }\n }\n}\n"],"mappings":"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","names":[]}
|