@happenv/print-agent-sdk 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,7 +14,7 @@ npm install @happenv/print-agent-sdk
14
14
  ```ts
15
15
  import { PrintAgent } from "@happenv/print-agent-sdk";
16
16
 
17
- const agent = new PrintAgent({ port: 45123 }); // wss://localhost:45123/ws
17
+ const agent = new PrintAgent({ port: 45123, lang: "en" }); // wss://localhost:45123/ws
18
18
 
19
19
  agent.onStatusChange((s) => console.log("status:", s));
20
20
 
@@ -34,7 +34,8 @@ agent.disconnect();
34
34
 
35
35
  ## API
36
36
 
37
- - `new PrintAgent(options)` — `{ host?, port?, url?, autoReconnect?, requestTimeoutMs?, WebSocket? }`
37
+ - `new PrintAgent(options)` — `{ host?, port?, url?, autoReconnect?, requestTimeoutMs?, WebSocket?, lang? }`
38
+ - `lang` — language of SDK error messages: `"en"` (default) or `"pl"`.
38
39
  - `connect()` / `disconnect()`
39
40
  - `status` / `isConnected()` / `onStatusChange(cb)` — status: `connecting | open | closed`
40
41
  - `getPrinters()` → `{ name, default }[]`
@@ -44,6 +45,20 @@ agent.disconnect();
44
45
 
45
46
  Errors: `NotConnectedError`, `TimeoutError`, `AgentError`.
46
47
 
48
+ ### Localization
49
+
50
+ SDK-generated error messages are localized. Pass `lang` to pick the catalog
51
+ (default `"en"`):
52
+
53
+ ```ts
54
+ const agent = new PrintAgent({ port: 45123, lang: "pl" });
55
+ ```
56
+
57
+ Catalogs live in `src/locales/` (`en.ts`, `pl.ts`) and are exported for
58
+ inspection or reuse: `import { locales, getMessages, type Lang, type Messages } from "@happenv/print-agent-sdk"`.
59
+ Note: error text returned by the agent itself (`AgentError`) is passed through
60
+ as-is and is not translated by the SDK.
61
+
47
62
  ## Notes
48
63
 
49
64
  - The SDK connects over `wss` using a certificate signed by the product's local
package/dist/index.cjs CHANGED
@@ -23,30 +23,64 @@ __export(index_exports, {
23
23
  AgentError: () => AgentError,
24
24
  NotConnectedError: () => NotConnectedError,
25
25
  PrintAgent: () => PrintAgent,
26
- TimeoutError: () => TimeoutError
26
+ TimeoutError: () => TimeoutError,
27
+ getMessages: () => getMessages,
28
+ locales: () => locales
27
29
  });
28
30
  module.exports = __toCommonJS(index_exports);
29
31
 
30
32
  // src/types.ts
31
33
  var NotConnectedError = class extends Error {
32
- constructor(message = "brak po\u0142\u0105czenia z agentem") {
34
+ constructor(message = "no connection to the agent") {
33
35
  super(message);
34
36
  this.name = "NotConnectedError";
35
37
  }
36
38
  };
37
39
  var TimeoutError = class extends Error {
38
- constructor(message = "przekroczono czas oczekiwania na odpowied\u017A agenta") {
40
+ constructor(message = "timed out waiting for the agent") {
39
41
  super(message);
40
42
  this.name = "TimeoutError";
41
43
  }
42
44
  };
43
45
  var AgentError = class extends Error {
44
- constructor(message = "b\u0142\u0105d agenta") {
46
+ constructor(message = "agent error") {
45
47
  super(message);
46
48
  this.name = "AgentError";
47
49
  }
48
50
  };
49
51
 
52
+ // src/locales/en.ts
53
+ var en = {
54
+ notConnected: "no connection to the agent",
55
+ connectionClosed: "connection closed",
56
+ connectFailed: "could not connect to the agent",
57
+ timeout: "timed out waiting for the agent's response",
58
+ connectTimeout: "timed out connecting to the agent",
59
+ agentError: "agent error",
60
+ noWebSocket: "no WebSocket implementation (pass the WebSocket option)",
61
+ printNoPrinter: "print: printer name is required (printer)",
62
+ printSource: "print: provide exactly one source \u2014 url or base64"
63
+ };
64
+
65
+ // src/locales/pl.ts
66
+ var pl = {
67
+ notConnected: "brak po\u0142\u0105czenia z agentem",
68
+ connectionClosed: "po\u0142\u0105czenie zamkni\u0119te",
69
+ connectFailed: "nie uda\u0142o si\u0119 po\u0142\u0105czy\u0107 z agentem",
70
+ timeout: "przekroczono czas oczekiwania na odpowied\u017A agenta",
71
+ connectTimeout: "przekroczono czas \u0142\u0105czenia z agentem",
72
+ agentError: "b\u0142\u0105d agenta",
73
+ noWebSocket: "brak implementacji WebSocket (przeka\u017C opcj\u0119 WebSocket)",
74
+ printNoPrinter: "print: wymagana nazwa drukarki (printer)",
75
+ printSource: "print: podaj dok\u0142adnie jedno \u017Ar\xF3d\u0142o \u2014 url albo base64"
76
+ };
77
+
78
+ // src/locales/index.ts
79
+ var locales = { en, pl };
80
+ function getMessages(lang = "en") {
81
+ return locales[lang] ?? en;
82
+ }
83
+
50
84
  // src/client.ts
51
85
  var RECONNECT_BACKOFF_MS = [1e3, 2e3, 5e3, 1e4];
52
86
  var PrintAgent = class {
@@ -57,6 +91,7 @@ var PrintAgent = class {
57
91
  this.idCounter = 0;
58
92
  this.wantConnected = false;
59
93
  this.reconnectAttempt = 0;
94
+ this.t = getMessages(opts.lang);
60
95
  const host = opts.host ?? "localhost";
61
96
  const port = opts.port ?? 45123;
62
97
  this.url = opts.url ?? `wss://${host}:${port}/ws`;
@@ -64,7 +99,7 @@ var PrintAgent = class {
64
99
  this.requestTimeoutMs = opts.requestTimeoutMs ?? 1e4;
65
100
  const ctor = opts.WebSocket ?? globalThis.WebSocket;
66
101
  if (!ctor) {
67
- throw new Error("brak implementacji WebSocket (przeka\u017C opcj\u0119 WebSocket)");
102
+ throw new Error(this.t.noWebSocket);
68
103
  }
69
104
  this.WS = ctor;
70
105
  }
@@ -74,13 +109,13 @@ var PrintAgent = class {
74
109
  isConnected() {
75
110
  return this._status === "open";
76
111
  }
77
- /** Rejestruje nasłuch zmian statusu; zwraca funkcję wyrejestrowującą. */
112
+ /** Registers a status-change listener; returns an unsubscribe function. */
78
113
  onStatusChange(cb) {
79
114
  this.statusListeners.add(cb);
80
115
  return () => this.statusListeners.delete(cb);
81
116
  }
82
- /** Łączy z agentem; resolve po otwarciu, reject przy timeoucie/zerwaniu.
83
- * Idempotentne, gdy połączenie jest już otwarte. */
117
+ /** Connects to the agent; resolves on open, rejects on timeout/failure.
118
+ * Idempotent when the connection is already open. */
84
119
  connect() {
85
120
  this.wantConnected = true;
86
121
  if (this._status === "open") {
@@ -90,7 +125,7 @@ var PrintAgent = class {
90
125
  this.openSocket(resolve, reject);
91
126
  });
92
127
  }
93
- /** Zamyka połączenie i wyłącza auto-reconnect. */
128
+ /** Closes the connection and disables auto-reconnect. */
94
129
  disconnect() {
95
130
  this.wantConnected = false;
96
131
  if (this.reconnectTimer) {
@@ -101,25 +136,25 @@ var PrintAgent = class {
101
136
  this.ws.close();
102
137
  }
103
138
  }
104
- /** Lista drukarek zainstalowanych w systemie klienta. */
139
+ /** List of printers installed on the client's system. */
105
140
  async getPrinters() {
106
141
  const r = await this.request({ type: "listPrinters" });
107
142
  return r.printers ?? [];
108
143
  }
109
- /** Wersja i brand agenta. */
144
+ /** Agent brand and version. */
110
145
  async getVersion() {
111
146
  const r = await this.request({ type: "version" });
112
147
  return { brand: r.brand ?? "", version: r.version ?? "" };
113
148
  }
114
- /** Wysyła zadanie druku PDF; resolve po potwierdzeniu agenta. */
149
+ /** Sends a PDF print job; resolves once the agent confirms. */
115
150
  async print(opts) {
116
151
  if (!opts || !opts.printer) {
117
- throw new Error("print: wymagana nazwa drukarki (printer)");
152
+ throw new Error(this.t.printNoPrinter);
118
153
  }
119
154
  const hasUrl = typeof opts.url === "string" && opts.url.length > 0;
120
155
  const hasB64 = typeof opts.base64 === "string" && opts.base64.length > 0;
121
156
  if (hasUrl === hasB64) {
122
- throw new Error("print: podaj dok\u0142adnie jedno \u017Ar\xF3d\u0142o \u2014 url albo base64");
157
+ throw new Error(this.t.printSource);
123
158
  }
124
159
  const pdf = hasUrl ? { url: opts.url } : { base64: opts.base64 };
125
160
  await this.request({
@@ -129,7 +164,7 @@ var PrintAgent = class {
129
164
  copies: opts.copies
130
165
  });
131
166
  }
132
- // --- wewnętrzne ---
167
+ // --- internal ---
133
168
  openSocket(onOpen, onFail) {
134
169
  this.setStatus("connecting");
135
170
  let settled = false;
@@ -142,7 +177,7 @@ var PrintAgent = class {
142
177
  ws.close();
143
178
  } catch {
144
179
  }
145
- onFail?.(new TimeoutError("przekroczono czas \u0142\u0105czenia z agentem"));
180
+ onFail?.(new TimeoutError(this.t.connectTimeout));
146
181
  }
147
182
  }, this.requestTimeoutMs);
148
183
  ws.onopen = () => {
@@ -159,10 +194,10 @@ var PrintAgent = class {
159
194
  clearTimeout(connectTimer);
160
195
  this.ws = void 0;
161
196
  this.setStatus("closed");
162
- this.rejectAllPending(new NotConnectedError("po\u0142\u0105czenie zamkni\u0119te"));
197
+ this.rejectAllPending(new NotConnectedError(this.t.connectionClosed));
163
198
  if (!settled) {
164
199
  settled = true;
165
- onFail?.(new NotConnectedError("nie uda\u0142o si\u0119 po\u0142\u0105czy\u0107 z agentem"));
200
+ onFail?.(new NotConnectedError(this.t.connectFailed));
166
201
  }
167
202
  if (this.wantConnected && this.autoReconnect) {
168
203
  this.scheduleReconnect();
@@ -195,19 +230,19 @@ var PrintAgent = class {
195
230
  if (msg.ok) {
196
231
  p.resolve(msg);
197
232
  } else {
198
- p.reject(new AgentError(msg.error || "b\u0142\u0105d agenta"));
233
+ p.reject(new AgentError(msg.error || this.t.agentError));
199
234
  }
200
235
  }
201
236
  request(payload) {
202
237
  if (!this.isConnected() || !this.ws) {
203
- return Promise.reject(new NotConnectedError());
238
+ return Promise.reject(new NotConnectedError(this.t.notConnected));
204
239
  }
205
240
  const id = String(++this.idCounter);
206
241
  const ws = this.ws;
207
242
  return new Promise((resolve, reject) => {
208
243
  const timer = setTimeout(() => {
209
244
  this.pending.delete(id);
210
- reject(new TimeoutError());
245
+ reject(new TimeoutError(this.t.timeout));
211
246
  }, this.requestTimeoutMs);
212
247
  this.pending.set(id, { resolve, reject, timer });
213
248
  try {
@@ -239,6 +274,8 @@ var PrintAgent = class {
239
274
  AgentError,
240
275
  NotConnectedError,
241
276
  PrintAgent,
242
- TimeoutError
277
+ TimeoutError,
278
+ getMessages,
279
+ locales
243
280
  });
244
281
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/types.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\";\n","/** Status połączenia z lokalnym agentem. */\nexport type ConnectionStatus = \"connecting\" | \"open\" | \"closed\";\n\n/** Drukarka zwrócona przez agenta. */\nexport interface Printer {\n name: string;\n default: boolean;\n}\n\n/** Wersja agenta. */\nexport interface AgentVersion {\n brand: string;\n version: string;\n}\n\n/** Parametry zadania druku. Dokładnie jedno ze źródeł: url albo base64. */\nexport interface PrintOptions {\n printer: string;\n url?: string;\n base64?: string;\n copies?: number;\n}\n\n/** Opcje konstruktora PrintAgent. */\nexport interface PrintAgentOptions {\n host?: string;\n port?: number;\n url?: string;\n autoReconnect?: boolean;\n requestTimeoutMs?: number;\n WebSocket?: WebSocketCtor;\n}\n\n/** Minimalny interfejs WebSocket używany przez SDK (zgodny z przeglądarką i pakietem ws). */\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/** Brak aktywnego połączenia z agentem. */\nexport class NotConnectedError extends Error {\n constructor(message = \"brak połączenia z agentem\") {\n super(message);\n this.name = \"NotConnectedError\";\n }\n}\n\n/** Przekroczono czas oczekiwania na odpowiedź agenta. */\nexport class TimeoutError extends Error {\n constructor(message = \"przekroczono czas oczekiwania na odpowiedź agenta\") {\n super(message);\n this.name = \"TimeoutError\";\n }\n}\n\n/** Agent odpowiedział błędem (ok:false). */\nexport class AgentError extends Error {\n constructor(message = \"błąd agenta\") {\n super(message);\n this.name = \"AgentError\";\n }\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\";\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/** Klient lokalnego agenta druku. */\nexport class PrintAgent {\n private readonly url: string;\n private readonly autoReconnect: boolean;\n private readonly requestTimeoutMs: number;\n private readonly WS: WebSocketCtor;\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 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(\"brak implementacji WebSocket (przekaż opcję WebSocket)\");\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 /** Rejestruje nasłuch zmian statusu; zwraca funkcję wyrejestrowującą. */\n onStatusChange(cb: (s: ConnectionStatus) => void): () => void {\n this.statusListeners.add(cb);\n return () => this.statusListeners.delete(cb);\n }\n\n /** Łączy z agentem; resolve po otwarciu, reject przy timeoucie/zerwaniu.\n * Idempotentne, gdy połączenie jest już otwarte. */\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 /** Zamyka połączenie i wyłącza 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 /** Lista drukarek zainstalowanych w systemie klienta. */\n async getPrinters(): Promise<Printer[]> {\n const r = await this.request({ type: \"listPrinters\" });\n return r.printers ?? [];\n }\n\n /** Wersja i brand agenta. */\n async getVersion(): Promise<AgentVersion> {\n const r = await this.request({ type: \"version\" });\n return { brand: r.brand ?? \"\", version: r.version ?? \"\" };\n }\n\n /** Wysyła zadanie druku PDF; resolve po potwierdzeniu agenta. */\n async print(opts: PrintOptions): Promise<void> {\n if (!opts || !opts.printer) {\n throw new Error(\"print: wymagana nazwa drukarki (printer)\");\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(\"print: podaj dokładnie jedno źródło — url albo base64\");\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 // --- wewnętrzne ---\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(\"przekroczono czas łączenia z agentem\"));\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 /* po błędzie nastąpi onclose */\n };\n ws.onclose = () => {\n clearTimeout(connectTimer);\n this.ws = undefined;\n this.setStatus(\"closed\");\n this.rejectAllPending(new NotConnectedError(\"połączenie zamknięte\"));\n if (!settled) {\n settled = true;\n onFail?.(new NotConnectedError(\"nie udało się połączyć z agentem\"));\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 || \"błąd agenta\"));\n }\n }\n\n private request(payload: Record<string, unknown>): Promise<AgentResponse> {\n if (!this.isConnected() || !this.ws) {\n return Promise.reject(new NotConnectedError());\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());\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 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":[]}
package/dist/index.d.cts CHANGED
@@ -1,23 +1,52 @@
1
- /** Status połączenia z lokalnym agentem. */
1
+ /** Supported SDK languages for user-facing messages. */
2
+ type Lang = "en" | "pl";
3
+ /** Message catalog used for SDK-generated error messages. */
4
+ interface Messages {
5
+ /** No active connection to the agent. */
6
+ notConnected: string;
7
+ /** The connection was closed. */
8
+ connectionClosed: string;
9
+ /** Initial connection attempt failed. */
10
+ connectFailed: string;
11
+ /** Request timed out waiting for a response. */
12
+ timeout: string;
13
+ /** Connection attempt timed out. */
14
+ connectTimeout: string;
15
+ /** Fallback when the agent returns an error without text. */
16
+ agentError: string;
17
+ /** No WebSocket implementation available. */
18
+ noWebSocket: string;
19
+ /** print(): printer name missing. */
20
+ printNoPrinter: string;
21
+ /** print(): wrong number of PDF sources. */
22
+ printSource: string;
23
+ }
24
+
25
+ /** All available message catalogs keyed by language. */
26
+ declare const locales: Record<Lang, Messages>;
27
+ /** Returns the message catalog for the given language (defaults to English). */
28
+ declare function getMessages(lang?: Lang): Messages;
29
+
30
+ /** Connection status with the local agent. */
2
31
  type ConnectionStatus = "connecting" | "open" | "closed";
3
- /** Drukarka zwrócona przez agenta. */
32
+ /** A printer returned by the agent. */
4
33
  interface Printer {
5
34
  name: string;
6
35
  default: boolean;
7
36
  }
8
- /** Wersja agenta. */
37
+ /** Agent version. */
9
38
  interface AgentVersion {
10
39
  brand: string;
11
40
  version: string;
12
41
  }
13
- /** Parametry zadania druku. Dokładnie jedno ze źródeł: url albo base64. */
42
+ /** Print job parameters. Provide exactly one source: url or base64. */
14
43
  interface PrintOptions {
15
44
  printer: string;
16
45
  url?: string;
17
46
  base64?: string;
18
47
  copies?: number;
19
48
  }
20
- /** Opcje konstruktora PrintAgent. */
49
+ /** PrintAgent constructor options. */
21
50
  interface PrintAgentOptions {
22
51
  host?: string;
23
52
  port?: number;
@@ -25,8 +54,10 @@ interface PrintAgentOptions {
25
54
  autoReconnect?: boolean;
26
55
  requestTimeoutMs?: number;
27
56
  WebSocket?: WebSocketCtor;
57
+ /** Language of SDK error messages; defaults to "en". */
58
+ lang?: Lang;
28
59
  }
29
- /** Minimalny interfejs WebSocket używany przez SDK (zgodny z przeglądarką i pakietem ws). */
60
+ /** Minimal WebSocket interface used by the SDK (compatible with the browser and the ws package). */
30
61
  interface WebSocketLike {
31
62
  send(data: string): void;
32
63
  close(): void;
@@ -40,25 +71,26 @@ interface WebSocketLike {
40
71
  interface WebSocketCtor {
41
72
  new (url: string): WebSocketLike;
42
73
  }
43
- /** Brak aktywnego połączenia z agentem. */
74
+ /** No active connection to the agent. (Message is localized by the client.) */
44
75
  declare class NotConnectedError extends Error {
45
76
  constructor(message?: string);
46
77
  }
47
- /** Przekroczono czas oczekiwania na odpowiedź agenta. */
78
+ /** Timed out waiting for the agent. (Message is localized by the client.) */
48
79
  declare class TimeoutError extends Error {
49
80
  constructor(message?: string);
50
81
  }
51
- /** Agent odpowiedział błędem (ok:false). */
82
+ /** The agent responded with an error (ok:false). */
52
83
  declare class AgentError extends Error {
53
84
  constructor(message?: string);
54
85
  }
55
86
 
56
- /** Klient lokalnego agenta druku. */
87
+ /** Client for the local print agent. */
57
88
  declare class PrintAgent {
58
89
  private readonly url;
59
90
  private readonly autoReconnect;
60
91
  private readonly requestTimeoutMs;
61
92
  private readonly WS;
93
+ private readonly t;
62
94
  private ws?;
63
95
  private _status;
64
96
  private statusListeners;
@@ -70,18 +102,18 @@ declare class PrintAgent {
70
102
  constructor(opts?: PrintAgentOptions);
71
103
  get status(): ConnectionStatus;
72
104
  isConnected(): boolean;
73
- /** Rejestruje nasłuch zmian statusu; zwraca funkcję wyrejestrowującą. */
105
+ /** Registers a status-change listener; returns an unsubscribe function. */
74
106
  onStatusChange(cb: (s: ConnectionStatus) => void): () => void;
75
- /** Łączy z agentem; resolve po otwarciu, reject przy timeoucie/zerwaniu.
76
- * Idempotentne, gdy połączenie jest już otwarte. */
107
+ /** Connects to the agent; resolves on open, rejects on timeout/failure.
108
+ * Idempotent when the connection is already open. */
77
109
  connect(): Promise<void>;
78
- /** Zamyka połączenie i wyłącza auto-reconnect. */
110
+ /** Closes the connection and disables auto-reconnect. */
79
111
  disconnect(): void;
80
- /** Lista drukarek zainstalowanych w systemie klienta. */
112
+ /** List of printers installed on the client's system. */
81
113
  getPrinters(): Promise<Printer[]>;
82
- /** Wersja i brand agenta. */
114
+ /** Agent brand and version. */
83
115
  getVersion(): Promise<AgentVersion>;
84
- /** Wysyła zadanie druku PDF; resolve po potwierdzeniu agenta. */
116
+ /** Sends a PDF print job; resolves once the agent confirms. */
85
117
  print(opts: PrintOptions): Promise<void>;
86
118
  private openSocket;
87
119
  private scheduleReconnect;
@@ -91,4 +123,4 @@ declare class PrintAgent {
91
123
  private setStatus;
92
124
  }
93
125
 
94
- export { AgentError, type AgentVersion, type ConnectionStatus, NotConnectedError, PrintAgent, type PrintAgentOptions, type PrintOptions, type Printer, TimeoutError, type WebSocketCtor, type WebSocketLike };
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 };
package/dist/index.d.ts CHANGED
@@ -1,23 +1,52 @@
1
- /** Status połączenia z lokalnym agentem. */
1
+ /** Supported SDK languages for user-facing messages. */
2
+ type Lang = "en" | "pl";
3
+ /** Message catalog used for SDK-generated error messages. */
4
+ interface Messages {
5
+ /** No active connection to the agent. */
6
+ notConnected: string;
7
+ /** The connection was closed. */
8
+ connectionClosed: string;
9
+ /** Initial connection attempt failed. */
10
+ connectFailed: string;
11
+ /** Request timed out waiting for a response. */
12
+ timeout: string;
13
+ /** Connection attempt timed out. */
14
+ connectTimeout: string;
15
+ /** Fallback when the agent returns an error without text. */
16
+ agentError: string;
17
+ /** No WebSocket implementation available. */
18
+ noWebSocket: string;
19
+ /** print(): printer name missing. */
20
+ printNoPrinter: string;
21
+ /** print(): wrong number of PDF sources. */
22
+ printSource: string;
23
+ }
24
+
25
+ /** All available message catalogs keyed by language. */
26
+ declare const locales: Record<Lang, Messages>;
27
+ /** Returns the message catalog for the given language (defaults to English). */
28
+ declare function getMessages(lang?: Lang): Messages;
29
+
30
+ /** Connection status with the local agent. */
2
31
  type ConnectionStatus = "connecting" | "open" | "closed";
3
- /** Drukarka zwrócona przez agenta. */
32
+ /** A printer returned by the agent. */
4
33
  interface Printer {
5
34
  name: string;
6
35
  default: boolean;
7
36
  }
8
- /** Wersja agenta. */
37
+ /** Agent version. */
9
38
  interface AgentVersion {
10
39
  brand: string;
11
40
  version: string;
12
41
  }
13
- /** Parametry zadania druku. Dokładnie jedno ze źródeł: url albo base64. */
42
+ /** Print job parameters. Provide exactly one source: url or base64. */
14
43
  interface PrintOptions {
15
44
  printer: string;
16
45
  url?: string;
17
46
  base64?: string;
18
47
  copies?: number;
19
48
  }
20
- /** Opcje konstruktora PrintAgent. */
49
+ /** PrintAgent constructor options. */
21
50
  interface PrintAgentOptions {
22
51
  host?: string;
23
52
  port?: number;
@@ -25,8 +54,10 @@ interface PrintAgentOptions {
25
54
  autoReconnect?: boolean;
26
55
  requestTimeoutMs?: number;
27
56
  WebSocket?: WebSocketCtor;
57
+ /** Language of SDK error messages; defaults to "en". */
58
+ lang?: Lang;
28
59
  }
29
- /** Minimalny interfejs WebSocket używany przez SDK (zgodny z przeglądarką i pakietem ws). */
60
+ /** Minimal WebSocket interface used by the SDK (compatible with the browser and the ws package). */
30
61
  interface WebSocketLike {
31
62
  send(data: string): void;
32
63
  close(): void;
@@ -40,25 +71,26 @@ interface WebSocketLike {
40
71
  interface WebSocketCtor {
41
72
  new (url: string): WebSocketLike;
42
73
  }
43
- /** Brak aktywnego połączenia z agentem. */
74
+ /** No active connection to the agent. (Message is localized by the client.) */
44
75
  declare class NotConnectedError extends Error {
45
76
  constructor(message?: string);
46
77
  }
47
- /** Przekroczono czas oczekiwania na odpowiedź agenta. */
78
+ /** Timed out waiting for the agent. (Message is localized by the client.) */
48
79
  declare class TimeoutError extends Error {
49
80
  constructor(message?: string);
50
81
  }
51
- /** Agent odpowiedział błędem (ok:false). */
82
+ /** The agent responded with an error (ok:false). */
52
83
  declare class AgentError extends Error {
53
84
  constructor(message?: string);
54
85
  }
55
86
 
56
- /** Klient lokalnego agenta druku. */
87
+ /** Client for the local print agent. */
57
88
  declare class PrintAgent {
58
89
  private readonly url;
59
90
  private readonly autoReconnect;
60
91
  private readonly requestTimeoutMs;
61
92
  private readonly WS;
93
+ private readonly t;
62
94
  private ws?;
63
95
  private _status;
64
96
  private statusListeners;
@@ -70,18 +102,18 @@ declare class PrintAgent {
70
102
  constructor(opts?: PrintAgentOptions);
71
103
  get status(): ConnectionStatus;
72
104
  isConnected(): boolean;
73
- /** Rejestruje nasłuch zmian statusu; zwraca funkcję wyrejestrowującą. */
105
+ /** Registers a status-change listener; returns an unsubscribe function. */
74
106
  onStatusChange(cb: (s: ConnectionStatus) => void): () => void;
75
- /** Łączy z agentem; resolve po otwarciu, reject przy timeoucie/zerwaniu.
76
- * Idempotentne, gdy połączenie jest już otwarte. */
107
+ /** Connects to the agent; resolves on open, rejects on timeout/failure.
108
+ * Idempotent when the connection is already open. */
77
109
  connect(): Promise<void>;
78
- /** Zamyka połączenie i wyłącza auto-reconnect. */
110
+ /** Closes the connection and disables auto-reconnect. */
79
111
  disconnect(): void;
80
- /** Lista drukarek zainstalowanych w systemie klienta. */
112
+ /** List of printers installed on the client's system. */
81
113
  getPrinters(): Promise<Printer[]>;
82
- /** Wersja i brand agenta. */
114
+ /** Agent brand and version. */
83
115
  getVersion(): Promise<AgentVersion>;
84
- /** Wysyła zadanie druku PDF; resolve po potwierdzeniu agenta. */
116
+ /** Sends a PDF print job; resolves once the agent confirms. */
85
117
  print(opts: PrintOptions): Promise<void>;
86
118
  private openSocket;
87
119
  private scheduleReconnect;
@@ -91,4 +123,4 @@ declare class PrintAgent {
91
123
  private setStatus;
92
124
  }
93
125
 
94
- export { AgentError, type AgentVersion, type ConnectionStatus, NotConnectedError, PrintAgent, type PrintAgentOptions, type PrintOptions, type Printer, TimeoutError, type WebSocketCtor, type WebSocketLike };
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 };
package/dist/index.js CHANGED
@@ -1,23 +1,55 @@
1
1
  // src/types.ts
2
2
  var NotConnectedError = class extends Error {
3
- constructor(message = "brak po\u0142\u0105czenia z agentem") {
3
+ constructor(message = "no connection to the agent") {
4
4
  super(message);
5
5
  this.name = "NotConnectedError";
6
6
  }
7
7
  };
8
8
  var TimeoutError = class extends Error {
9
- constructor(message = "przekroczono czas oczekiwania na odpowied\u017A agenta") {
9
+ constructor(message = "timed out waiting for the agent") {
10
10
  super(message);
11
11
  this.name = "TimeoutError";
12
12
  }
13
13
  };
14
14
  var AgentError = class extends Error {
15
- constructor(message = "b\u0142\u0105d agenta") {
15
+ constructor(message = "agent error") {
16
16
  super(message);
17
17
  this.name = "AgentError";
18
18
  }
19
19
  };
20
20
 
21
+ // src/locales/en.ts
22
+ var en = {
23
+ notConnected: "no connection to the agent",
24
+ connectionClosed: "connection closed",
25
+ connectFailed: "could not connect to the agent",
26
+ timeout: "timed out waiting for the agent's response",
27
+ connectTimeout: "timed out connecting to the agent",
28
+ agentError: "agent error",
29
+ noWebSocket: "no WebSocket implementation (pass the WebSocket option)",
30
+ printNoPrinter: "print: printer name is required (printer)",
31
+ printSource: "print: provide exactly one source \u2014 url or base64"
32
+ };
33
+
34
+ // src/locales/pl.ts
35
+ var pl = {
36
+ notConnected: "brak po\u0142\u0105czenia z agentem",
37
+ connectionClosed: "po\u0142\u0105czenie zamkni\u0119te",
38
+ connectFailed: "nie uda\u0142o si\u0119 po\u0142\u0105czy\u0107 z agentem",
39
+ timeout: "przekroczono czas oczekiwania na odpowied\u017A agenta",
40
+ connectTimeout: "przekroczono czas \u0142\u0105czenia z agentem",
41
+ agentError: "b\u0142\u0105d agenta",
42
+ noWebSocket: "brak implementacji WebSocket (przeka\u017C opcj\u0119 WebSocket)",
43
+ printNoPrinter: "print: wymagana nazwa drukarki (printer)",
44
+ printSource: "print: podaj dok\u0142adnie jedno \u017Ar\xF3d\u0142o \u2014 url albo base64"
45
+ };
46
+
47
+ // src/locales/index.ts
48
+ var locales = { en, pl };
49
+ function getMessages(lang = "en") {
50
+ return locales[lang] ?? en;
51
+ }
52
+
21
53
  // src/client.ts
22
54
  var RECONNECT_BACKOFF_MS = [1e3, 2e3, 5e3, 1e4];
23
55
  var PrintAgent = class {
@@ -28,6 +60,7 @@ var PrintAgent = class {
28
60
  this.idCounter = 0;
29
61
  this.wantConnected = false;
30
62
  this.reconnectAttempt = 0;
63
+ this.t = getMessages(opts.lang);
31
64
  const host = opts.host ?? "localhost";
32
65
  const port = opts.port ?? 45123;
33
66
  this.url = opts.url ?? `wss://${host}:${port}/ws`;
@@ -35,7 +68,7 @@ var PrintAgent = class {
35
68
  this.requestTimeoutMs = opts.requestTimeoutMs ?? 1e4;
36
69
  const ctor = opts.WebSocket ?? globalThis.WebSocket;
37
70
  if (!ctor) {
38
- throw new Error("brak implementacji WebSocket (przeka\u017C opcj\u0119 WebSocket)");
71
+ throw new Error(this.t.noWebSocket);
39
72
  }
40
73
  this.WS = ctor;
41
74
  }
@@ -45,13 +78,13 @@ var PrintAgent = class {
45
78
  isConnected() {
46
79
  return this._status === "open";
47
80
  }
48
- /** Rejestruje nasłuch zmian statusu; zwraca funkcję wyrejestrowującą. */
81
+ /** Registers a status-change listener; returns an unsubscribe function. */
49
82
  onStatusChange(cb) {
50
83
  this.statusListeners.add(cb);
51
84
  return () => this.statusListeners.delete(cb);
52
85
  }
53
- /** Łączy z agentem; resolve po otwarciu, reject przy timeoucie/zerwaniu.
54
- * Idempotentne, gdy połączenie jest już otwarte. */
86
+ /** Connects to the agent; resolves on open, rejects on timeout/failure.
87
+ * Idempotent when the connection is already open. */
55
88
  connect() {
56
89
  this.wantConnected = true;
57
90
  if (this._status === "open") {
@@ -61,7 +94,7 @@ var PrintAgent = class {
61
94
  this.openSocket(resolve, reject);
62
95
  });
63
96
  }
64
- /** Zamyka połączenie i wyłącza auto-reconnect. */
97
+ /** Closes the connection and disables auto-reconnect. */
65
98
  disconnect() {
66
99
  this.wantConnected = false;
67
100
  if (this.reconnectTimer) {
@@ -72,25 +105,25 @@ var PrintAgent = class {
72
105
  this.ws.close();
73
106
  }
74
107
  }
75
- /** Lista drukarek zainstalowanych w systemie klienta. */
108
+ /** List of printers installed on the client's system. */
76
109
  async getPrinters() {
77
110
  const r = await this.request({ type: "listPrinters" });
78
111
  return r.printers ?? [];
79
112
  }
80
- /** Wersja i brand agenta. */
113
+ /** Agent brand and version. */
81
114
  async getVersion() {
82
115
  const r = await this.request({ type: "version" });
83
116
  return { brand: r.brand ?? "", version: r.version ?? "" };
84
117
  }
85
- /** Wysyła zadanie druku PDF; resolve po potwierdzeniu agenta. */
118
+ /** Sends a PDF print job; resolves once the agent confirms. */
86
119
  async print(opts) {
87
120
  if (!opts || !opts.printer) {
88
- throw new Error("print: wymagana nazwa drukarki (printer)");
121
+ throw new Error(this.t.printNoPrinter);
89
122
  }
90
123
  const hasUrl = typeof opts.url === "string" && opts.url.length > 0;
91
124
  const hasB64 = typeof opts.base64 === "string" && opts.base64.length > 0;
92
125
  if (hasUrl === hasB64) {
93
- throw new Error("print: podaj dok\u0142adnie jedno \u017Ar\xF3d\u0142o \u2014 url albo base64");
126
+ throw new Error(this.t.printSource);
94
127
  }
95
128
  const pdf = hasUrl ? { url: opts.url } : { base64: opts.base64 };
96
129
  await this.request({
@@ -100,7 +133,7 @@ var PrintAgent = class {
100
133
  copies: opts.copies
101
134
  });
102
135
  }
103
- // --- wewnętrzne ---
136
+ // --- internal ---
104
137
  openSocket(onOpen, onFail) {
105
138
  this.setStatus("connecting");
106
139
  let settled = false;
@@ -113,7 +146,7 @@ var PrintAgent = class {
113
146
  ws.close();
114
147
  } catch {
115
148
  }
116
- onFail?.(new TimeoutError("przekroczono czas \u0142\u0105czenia z agentem"));
149
+ onFail?.(new TimeoutError(this.t.connectTimeout));
117
150
  }
118
151
  }, this.requestTimeoutMs);
119
152
  ws.onopen = () => {
@@ -130,10 +163,10 @@ var PrintAgent = class {
130
163
  clearTimeout(connectTimer);
131
164
  this.ws = void 0;
132
165
  this.setStatus("closed");
133
- this.rejectAllPending(new NotConnectedError("po\u0142\u0105czenie zamkni\u0119te"));
166
+ this.rejectAllPending(new NotConnectedError(this.t.connectionClosed));
134
167
  if (!settled) {
135
168
  settled = true;
136
- onFail?.(new NotConnectedError("nie uda\u0142o si\u0119 po\u0142\u0105czy\u0107 z agentem"));
169
+ onFail?.(new NotConnectedError(this.t.connectFailed));
137
170
  }
138
171
  if (this.wantConnected && this.autoReconnect) {
139
172
  this.scheduleReconnect();
@@ -166,19 +199,19 @@ var PrintAgent = class {
166
199
  if (msg.ok) {
167
200
  p.resolve(msg);
168
201
  } else {
169
- p.reject(new AgentError(msg.error || "b\u0142\u0105d agenta"));
202
+ p.reject(new AgentError(msg.error || this.t.agentError));
170
203
  }
171
204
  }
172
205
  request(payload) {
173
206
  if (!this.isConnected() || !this.ws) {
174
- return Promise.reject(new NotConnectedError());
207
+ return Promise.reject(new NotConnectedError(this.t.notConnected));
175
208
  }
176
209
  const id = String(++this.idCounter);
177
210
  const ws = this.ws;
178
211
  return new Promise((resolve, reject) => {
179
212
  const timer = setTimeout(() => {
180
213
  this.pending.delete(id);
181
- reject(new TimeoutError());
214
+ reject(new TimeoutError(this.t.timeout));
182
215
  }, this.requestTimeoutMs);
183
216
  this.pending.set(id, { resolve, reject, timer });
184
217
  try {
@@ -209,6 +242,8 @@ export {
209
242
  AgentError,
210
243
  NotConnectedError,
211
244
  PrintAgent,
212
- TimeoutError
245
+ TimeoutError,
246
+ getMessages,
247
+ locales
213
248
  };
214
249
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/client.ts"],"sourcesContent":["/** Status połączenia z lokalnym agentem. */\nexport type ConnectionStatus = \"connecting\" | \"open\" | \"closed\";\n\n/** Drukarka zwrócona przez agenta. */\nexport interface Printer {\n name: string;\n default: boolean;\n}\n\n/** Wersja agenta. */\nexport interface AgentVersion {\n brand: string;\n version: string;\n}\n\n/** Parametry zadania druku. Dokładnie jedno ze źródeł: url albo base64. */\nexport interface PrintOptions {\n printer: string;\n url?: string;\n base64?: string;\n copies?: number;\n}\n\n/** Opcje konstruktora PrintAgent. */\nexport interface PrintAgentOptions {\n host?: string;\n port?: number;\n url?: string;\n autoReconnect?: boolean;\n requestTimeoutMs?: number;\n WebSocket?: WebSocketCtor;\n}\n\n/** Minimalny interfejs WebSocket używany przez SDK (zgodny z przeglądarką i pakietem ws). */\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/** Brak aktywnego połączenia z agentem. */\nexport class NotConnectedError extends Error {\n constructor(message = \"brak połączenia z agentem\") {\n super(message);\n this.name = \"NotConnectedError\";\n }\n}\n\n/** Przekroczono czas oczekiwania na odpowiedź agenta. */\nexport class TimeoutError extends Error {\n constructor(message = \"przekroczono czas oczekiwania na odpowiedź agenta\") {\n super(message);\n this.name = \"TimeoutError\";\n }\n}\n\n/** Agent odpowiedział błędem (ok:false). */\nexport class AgentError extends Error {\n constructor(message = \"błąd agenta\") {\n super(message);\n this.name = \"AgentError\";\n }\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\";\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/** Klient lokalnego agenta druku. */\nexport class PrintAgent {\n private readonly url: string;\n private readonly autoReconnect: boolean;\n private readonly requestTimeoutMs: number;\n private readonly WS: WebSocketCtor;\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 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(\"brak implementacji WebSocket (przekaż opcję WebSocket)\");\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 /** Rejestruje nasłuch zmian statusu; zwraca funkcję wyrejestrowującą. */\n onStatusChange(cb: (s: ConnectionStatus) => void): () => void {\n this.statusListeners.add(cb);\n return () => this.statusListeners.delete(cb);\n }\n\n /** Łączy z agentem; resolve po otwarciu, reject przy timeoucie/zerwaniu.\n * Idempotentne, gdy połączenie jest już otwarte. */\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 /** Zamyka połączenie i wyłącza 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 /** Lista drukarek zainstalowanych w systemie klienta. */\n async getPrinters(): Promise<Printer[]> {\n const r = await this.request({ type: \"listPrinters\" });\n return r.printers ?? [];\n }\n\n /** Wersja i brand agenta. */\n async getVersion(): Promise<AgentVersion> {\n const r = await this.request({ type: \"version\" });\n return { brand: r.brand ?? \"\", version: r.version ?? \"\" };\n }\n\n /** Wysyła zadanie druku PDF; resolve po potwierdzeniu agenta. */\n async print(opts: PrintOptions): Promise<void> {\n if (!opts || !opts.printer) {\n throw new Error(\"print: wymagana nazwa drukarki (printer)\");\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(\"print: podaj dokładnie jedno źródło — url albo base64\");\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 // --- wewnętrzne ---\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(\"przekroczono czas łączenia z agentem\"));\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 /* po błędzie nastąpi onclose */\n };\n ws.onclose = () => {\n clearTimeout(connectTimer);\n this.ws = undefined;\n this.setStatus(\"closed\");\n this.rejectAllPending(new NotConnectedError(\"połączenie zamknięte\"));\n if (!settled) {\n settled = true;\n onFail?.(new NotConnectedError(\"nie udało się połączyć z agentem\"));\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 || \"błąd agenta\"));\n }\n }\n\n private request(payload: Record<string, unknown>): Promise<AgentResponse> {\n if (!this.isConnected() || !this.ws) {\n return Promise.reject(new NotConnectedError());\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());\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/** 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":";AAoDO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAC3C,YAAY,UAAU,8BAA8B;AAClD,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,eAAN,cAA2B,MAAM;AAAA,EACtC,YAAY,UAAU,mCAAmC;AACvD,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,aAAN,cAAyB,MAAM;AAAA,EACpC,YAAY,UAAU,eAAe;AACnC,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;;;ACtEO,IAAM,KAAe;AAAA,EAC1B,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,SAAS;AAAA,EACT,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,aAAa;AACf;;;ACVO,IAAM,KAAe;AAAA,EAC1B,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,SAAS;AAAA,EACT,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,aAAa;AACf;;;ACNO,IAAM,UAAkC,EAAE,IAAI,GAAG;AAGjD,SAAS,YAAY,OAAa,MAAgB;AACvD,SAAO,QAAQ,IAAI,KAAK;AAC1B;;;ACkBA,IAAM,uBAAuB,CAAC,KAAM,KAAM,KAAM,GAAK;AAG9C,IAAM,aAAN,MAAiB;AAAA,EAgBtB,YAAY,OAA0B,CAAC,GAAG;AAR1C,SAAQ,UAA4B;AACpC,SAAQ,kBAAkB,oBAAI,IAAmC;AACjE,SAAQ,UAAU,oBAAI,IAAqB;AAC3C,SAAQ,YAAY;AACpB,SAAQ,gBAAgB;AACxB,SAAQ,mBAAmB;AAIzB,SAAK,IAAI,YAAY,KAAK,IAAI;AAC9B,UAAM,OAAO,KAAK,QAAQ;AAC1B,UAAM,OAAO,KAAK,QAAQ;AAC1B,SAAK,MAAM,KAAK,OAAO,SAAS,IAAI,IAAI,IAAI;AAC5C,SAAK,gBAAgB,KAAK,iBAAiB;AAC3C,SAAK,mBAAmB,KAAK,oBAAoB;AACjD,UAAM,OAAO,KAAK,aAAc,WAA6C;AAC7E,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,KAAK,EAAE,WAAW;AAAA,IACpC;AACA,SAAK,KAAK;AAAA,EACZ;AAAA,EAEA,IAAI,SAA2B;AAC7B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,cAAuB;AACrB,WAAO,KAAK,YAAY;AAAA,EAC1B;AAAA;AAAA,EAGA,eAAe,IAA+C;AAC5D,SAAK,gBAAgB,IAAI,EAAE;AAC3B,WAAO,MAAM,KAAK,gBAAgB,OAAO,EAAE;AAAA,EAC7C;AAAA;AAAA;AAAA,EAIA,UAAyB;AACvB,SAAK,gBAAgB;AACrB,QAAI,KAAK,YAAY,QAAQ;AAC3B,aAAO,QAAQ,QAAQ;AAAA,IACzB;AACA,WAAO,IAAI,QAAc,CAAC,SAAS,WAAW;AAC5C,WAAK,WAAW,SAAS,MAAM;AAAA,IACjC,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,aAAmB;AACjB,SAAK,gBAAgB;AACrB,QAAI,KAAK,gBAAgB;AACvB,mBAAa,KAAK,cAAc;AAChC,WAAK,iBAAiB;AAAA,IACxB;AACA,QAAI,KAAK,IAAI;AACX,WAAK,GAAG,MAAM;AAAA,IAChB;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,cAAkC;AACtC,UAAM,IAAI,MAAM,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AACrD,WAAO,EAAE,YAAY,CAAC;AAAA,EACxB;AAAA;AAAA,EAGA,MAAM,aAAoC;AACxC,UAAM,IAAI,MAAM,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAChD,WAAO,EAAE,OAAO,EAAE,SAAS,IAAI,SAAS,EAAE,WAAW,GAAG;AAAA,EAC1D;AAAA;AAAA,EAGA,MAAM,MAAM,MAAmC;AAC7C,QAAI,CAAC,QAAQ,CAAC,KAAK,SAAS;AAC1B,YAAM,IAAI,MAAM,KAAK,EAAE,cAAc;AAAA,IACvC;AACA,UAAM,SAAS,OAAO,KAAK,QAAQ,YAAY,KAAK,IAAI,SAAS;AACjE,UAAM,SAAS,OAAO,KAAK,WAAW,YAAY,KAAK,OAAO,SAAS;AACvE,QAAI,WAAW,QAAQ;AACrB,YAAM,IAAI,MAAM,KAAK,EAAE,WAAW;AAAA,IACpC;AACA,UAAM,MAAM,SAAS,EAAE,KAAK,KAAK,IAAI,IAAI,EAAE,QAAQ,KAAK,OAAO;AAC/D,UAAM,KAAK,QAAQ;AAAA,MACjB,MAAM;AAAA,MACN,SAAS,KAAK;AAAA,MACd;AAAA,MACA,QAAQ,KAAK;AAAA,IACf,CAAC;AAAA,EACH;AAAA;AAAA,EAIQ,WACN,QACA,QACM;AACN,SAAK,UAAU,YAAY;AAC3B,QAAI,UAAU;AACd,UAAM,KAAK,IAAI,KAAK,GAAG,KAAK,GAAG;AAC/B,SAAK,KAAK;AAEV,UAAM,eAAe,WAAW,MAAM;AACpC,UAAI,CAAC,SAAS;AACZ,kBAAU;AACV,YAAI;AACF,aAAG,MAAM;AAAA,QACX,QAAQ;AAAA,QAER;AACA,iBAAS,IAAI,aAAa,KAAK,EAAE,cAAc,CAAC;AAAA,MAClD;AAAA,IACF,GAAG,KAAK,gBAAgB;AAExB,OAAG,SAAS,MAAM;AAChB,gBAAU;AACV,mBAAa,YAAY;AACzB,WAAK,mBAAmB;AACxB,WAAK,UAAU,MAAM;AACrB,eAAS;AAAA,IACX;AACA,OAAG,YAAY,CAAC,OAAO,KAAK,cAAc,GAAG,IAAI;AACjD,OAAG,UAAU,MAAM;AAAA,IAEnB;AACA,OAAG,UAAU,MAAM;AACjB,mBAAa,YAAY;AACzB,WAAK,KAAK;AACV,WAAK,UAAU,QAAQ;AACvB,WAAK,iBAAiB,IAAI,kBAAkB,KAAK,EAAE,gBAAgB,CAAC;AACpE,UAAI,CAAC,SAAS;AACZ,kBAAU;AACV,iBAAS,IAAI,kBAAkB,KAAK,EAAE,aAAa,CAAC;AAAA,MACtD;AACA,UAAI,KAAK,iBAAiB,KAAK,eAAe;AAC5C,aAAK,kBAAkB;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,oBAA0B;AAChC,UAAM,QACJ,qBAAqB,KAAK,IAAI,KAAK,kBAAkB,qBAAqB,SAAS,CAAC,CAAC;AACvF,SAAK;AACL,SAAK,iBAAiB,WAAW,MAAM;AACrC,UAAI,KAAK,eAAe;AACtB,aAAK,WAAW;AAAA,MAClB;AAAA,IACF,GAAG,KAAK;AAAA,EACV;AAAA,EAEQ,cAAc,MAAqB;AACzC,UAAM,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO,IAAI;AAC1D,QAAI;AACJ,QAAI;AACF,YAAM,KAAK,MAAM,IAAI;AAAA,IACvB,QAAQ;AACN;AAAA,IACF;AACA,UAAM,KAAK,IAAI;AACf,QAAI,CAAC,GAAI;AACT,UAAM,IAAI,KAAK,QAAQ,IAAI,EAAE;AAC7B,QAAI,CAAC,EAAG;AACR,iBAAa,EAAE,KAAK;AACpB,SAAK,QAAQ,OAAO,EAAE;AACtB,QAAI,IAAI,IAAI;AACV,QAAE,QAAQ,GAAG;AAAA,IACf,OAAO;AACL,QAAE,OAAO,IAAI,WAAW,IAAI,SAAS,KAAK,EAAE,UAAU,CAAC;AAAA,IACzD;AAAA,EACF;AAAA,EAEQ,QAAQ,SAA0D;AACxE,QAAI,CAAC,KAAK,YAAY,KAAK,CAAC,KAAK,IAAI;AACnC,aAAO,QAAQ,OAAO,IAAI,kBAAkB,KAAK,EAAE,YAAY,CAAC;AAAA,IAClE;AACA,UAAM,KAAK,OAAO,EAAE,KAAK,SAAS;AAClC,UAAM,KAAK,KAAK;AAChB,WAAO,IAAI,QAAuB,CAAC,SAAS,WAAW;AACrD,YAAM,QAAQ,WAAW,MAAM;AAC7B,aAAK,QAAQ,OAAO,EAAE;AACtB,eAAO,IAAI,aAAa,KAAK,EAAE,OAAO,CAAC;AAAA,MACzC,GAAG,KAAK,gBAAgB;AACxB,WAAK,QAAQ,IAAI,IAAI,EAAE,SAAS,QAAQ,MAAM,CAAC;AAC/C,UAAI;AACF,WAAG,KAAK,KAAK,UAAU,EAAE,GAAG,SAAS,GAAG,CAAC,CAAC;AAAA,MAC5C,SAAS,GAAG;AACV,qBAAa,KAAK;AAClB,aAAK,QAAQ,OAAO,EAAE;AACtB,eAAO,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC;AAAA,MACtD;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,iBAAiB,KAAkB;AACzC,eAAW,CAAC,EAAE,CAAC,KAAK,KAAK,SAAS;AAChC,mBAAa,EAAE,KAAK;AACpB,QAAE,OAAO,GAAG;AAAA,IACd;AACA,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA,EAEQ,UAAU,GAA2B;AAC3C,QAAI,KAAK,YAAY,EAAG;AACxB,SAAK,UAAU;AACf,eAAW,MAAM,KAAK,iBAAiB;AACrC,SAAG,CAAC;AAAA,IACN;AAAA,EACF;AACF;","names":[]}
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@happenv/print-agent-sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "description": "Prosty SDK do lokalnego agenta druku (WebSocket): drukarki, druk PDF, status.",
7
+ "description": "Simple SDK for the local print agent (WebSocket): printers, PDF printing, status.",
8
8
  "type": "module",
9
9
  "main": "./dist/index.cjs",
10
10
  "module": "./dist/index.js",
@@ -21,14 +21,22 @@
21
21
  }
22
22
  }
23
23
  },
24
- "files": ["dist"],
24
+ "files": [
25
+ "dist"
26
+ ],
25
27
  "sideEffects": false,
26
28
  "scripts": {
27
29
  "build": "tsup",
28
30
  "test": "vitest run",
29
- "prepublishOnly": "npm run build"
31
+ "prepublishOnly": "npm run build",
32
+ "release": "npm version patch && npm publish"
30
33
  },
31
- "keywords": ["printing", "websocket", "pdf", "print-agent"],
34
+ "keywords": [
35
+ "printing",
36
+ "websocket",
37
+ "pdf",
38
+ "print-agent"
39
+ ],
32
40
  "license": "MIT",
33
41
  "devDependencies": {
34
42
  "@types/ws": "^8.5.10",