dikshiprintagent 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NPM-PACKAGE.md +48 -0
- package/README.md +98 -0
- package/npm/browser.js +7 -0
- package/npm/index.d.ts +52 -0
- package/npm/index.js +135 -0
- package/npm/test/sdk.test.mjs +29 -0
- package/package.json +41 -0
package/NPM-PACKAGE.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# dikshiprintagent npm package
|
|
2
|
+
|
|
3
|
+
Install after publishing (or install the generated `.tgz` file locally):
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install dikshiprintagent
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
The package uses ES modules and works in modern browser build tools and Node.js 18+.
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
import DikshiPrintAgent from 'dikshiprintagent';
|
|
13
|
+
|
|
14
|
+
const agent = new DikshiPrintAgent({
|
|
15
|
+
token: 'TOKEN_FROM_THE_WINDOWS_TRAY_APP'
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const { printers } = await agent.printers();
|
|
19
|
+
const job = await agent.printText(printers[0].name, 'Hello from npm');
|
|
20
|
+
await agent.wait(job.jobId);
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
ESC/POS receipt example:
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
const receipt = DikshiPrintAgent.receiptBuilder({ width: 42 })
|
|
27
|
+
.center().bold().text('DIKSHI STORE\n').bold(false)
|
|
28
|
+
.line()
|
|
29
|
+
.row('Total', 'Rs. 100.00')
|
|
30
|
+
.cut()
|
|
31
|
+
.build();
|
|
32
|
+
|
|
33
|
+
await agent.printEscPos('EPSON TM-T82', receipt);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Create the distributable package:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm test
|
|
40
|
+
npm pack
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Publish (requires npm account access and ownership of the package name):
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm login
|
|
47
|
+
npm publish
|
|
48
|
+
```
|
package/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Dikshi Print Agent V10
|
|
2
|
+
|
|
3
|
+
Windows local print bridge for websites. Designed around Windows printer queues, so newly installed printers are discovered automatically when Windows has a working driver.
|
|
4
|
+
|
|
5
|
+
Android/iOS remote printing through the optional secure relay is documented in [REMOTE-PRINTING.md](REMOTE-PRINTING.md).
|
|
6
|
+
|
|
7
|
+
## V10 features
|
|
8
|
+
- Windows tray application
|
|
9
|
+
- Loopback-only HTTP API on `127.0.0.1:8181`
|
|
10
|
+
- First-run 256-bit random API token
|
|
11
|
+
- Origin allow-list/CORS protection
|
|
12
|
+
- Dynamic installed-printer discovery and default-printer detection
|
|
13
|
+
- Queued print jobs + job status/history
|
|
14
|
+
- Text printing through Windows PrintDocument
|
|
15
|
+
- Image printing (base64 PNG/JPG/BMP etc.)
|
|
16
|
+
- RAW printing through Winspool (label languages / printer-native data)
|
|
17
|
+
- ESC/POS uses the RAW path
|
|
18
|
+
- PDF printing through Windows registered PDF `printto` handler
|
|
19
|
+
- Direct PDF URL printing: agent downloads the PDF from an API URL and sends it to the selected printer
|
|
20
|
+
- HTML printing through WebView2 with page size/orientation options
|
|
21
|
+
- Invoice/receipt template printing from plain JSON data
|
|
22
|
+
- QR and CODE128 barcode printing
|
|
23
|
+
- ESC/POS receipt builder in the browser SDK
|
|
24
|
+
- Persistent recent job history under `%APPDATA%\DikshiPrintAgent\job-history.json`
|
|
25
|
+
- Local dashboard with printer list, HTML/text test print, and job history
|
|
26
|
+
- Visual template designer at `/designer` with drag/drop fields and saved JSON layouts
|
|
27
|
+
- Designer validation, version backups, locked layouts, resize handles, undo/redo, zoom, logo upload, and custom table columns
|
|
28
|
+
- Dashboard/designer pages do not embed the API token; paste it from the tray menu before using protected actions
|
|
29
|
+
- Daily logs under `%APPDATA%\DikshiPrintAgent\logs`
|
|
30
|
+
- Start-with-Windows support
|
|
31
|
+
- Browser JavaScript SDK + test page
|
|
32
|
+
- Single-file self-contained `win-x64` publish
|
|
33
|
+
- Inno Setup script included
|
|
34
|
+
|
|
35
|
+
## Build
|
|
36
|
+
Install the Microsoft .NET 8 SDK on the Windows development PC, then run `build-exe.bat`.
|
|
37
|
+
Output: `DikshiPrintAgent-V10.exe` in the project root.
|
|
38
|
+
|
|
39
|
+
## First run
|
|
40
|
+
Run the EXE. It creates:
|
|
41
|
+
`%APPDATA%\DikshiPrintAgent\config.json`
|
|
42
|
+
|
|
43
|
+
Right-click the tray icon -> **Copy API Token**.
|
|
44
|
+
Edit `AllowedOrigins` in config.json to include your websites, then restart the agent.
|
|
45
|
+
Example:
|
|
46
|
+
```json
|
|
47
|
+
"AllowedOrigins": [
|
|
48
|
+
"https://erp.example.com",
|
|
49
|
+
"https://billing.example.com",
|
|
50
|
+
"http://localhost:*"
|
|
51
|
+
]
|
|
52
|
+
```
|
|
53
|
+
Do not set `AllowAllOrigins=true` on production PCs unless you fully understand the security risk.
|
|
54
|
+
|
|
55
|
+
## API
|
|
56
|
+
- `GET /api/v1/health` (no token; health only)
|
|
57
|
+
- `GET /api/v1/printers`
|
|
58
|
+
- `GET /api/v1/jobs`
|
|
59
|
+
- `GET /api/v1/jobs/{id}`
|
|
60
|
+
- `GET /api/v1/templates`
|
|
61
|
+
- `GET /api/v1/templates/{name}`
|
|
62
|
+
- `POST /api/v1/templates`
|
|
63
|
+
- `POST /api/v1/print/text`
|
|
64
|
+
- `POST /api/v1/print/image`
|
|
65
|
+
- `POST /api/v1/print/code`
|
|
66
|
+
- `POST /api/v1/print/raw`
|
|
67
|
+
- `POST /api/v1/print/escpos`
|
|
68
|
+
- `POST /api/v1/print/pdf`
|
|
69
|
+
- `POST /api/v1/print/pdf-url`
|
|
70
|
+
- `POST /api/v1/print/html`
|
|
71
|
+
- `POST /api/v1/print/template`
|
|
72
|
+
- `POST /api/v1/print/designed-template`
|
|
73
|
+
- WebSocket: `/ws?token=...`
|
|
74
|
+
|
|
75
|
+
Authenticated REST requests require `X-Dikshi-Token`.
|
|
76
|
+
|
|
77
|
+
### Print a PDF directly from an API URL
|
|
78
|
+
Use this when your server API returns `application/pdf` as a downloadable file. The agent downloads the PDF locally, validates it, queues it, and prints through the existing PDF print handler.
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
curl -X POST "http://127.0.0.1:8181/api/v1/print/pdf-url" \
|
|
82
|
+
-H "Content-Type: application/json" \
|
|
83
|
+
-H "X-Dikshi-Token: YOUR_AGENT_TOKEN" \
|
|
84
|
+
-d "{\"printer\":\"YOUR_WINDOWS_PRINTER_NAME\",\"url\":\"https://dikshitech.ddns.net/kingmotorsapi/api/BookingEntry/DownloadBookingPdf/001/B00009AA\",\"documentName\":\"Booking_B00009AA.pdf\"}"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Browser SDK:
|
|
88
|
+
```js
|
|
89
|
+
await agent.printPdfUrl(printerName, bookingPdfUrl, {
|
|
90
|
+
documentName: 'Booking_B00009AA.pdf'
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Important compatibility notes
|
|
95
|
+
1. Generic printing works with printers exposed as valid Windows printer queues. Future printer models normally need only their Windows driver.
|
|
96
|
+
2. RAW/ESC-POS requires the printer/driver to accept the command language being sent. There is no universal ESC/POS guarantee for every model.
|
|
97
|
+
3. PDF `printto` relies on a Windows PDF application that implements the `printto` shell verb. For maximum unattended PDF reliability, a dedicated PDF rendering/printing engine should be embedded in a future signed enterprise build.
|
|
98
|
+
4. An HTTPS website talking to a local agent can be affected by browser mixed-content/private-network policies. For strict enterprise/all-site deployment, use a trusted local TLS certificate or companion Chrome/Edge extension. This source keeps loopback HTTP intentionally simple and auditable.
|
package/npm/browser.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { DikshiPrintAgent, DikshiReceiptBuilder, default } from './index.js';
|
|
2
|
+
import { DikshiPrintAgent, DikshiReceiptBuilder } from './index.js';
|
|
3
|
+
|
|
4
|
+
if (typeof window !== 'undefined') {
|
|
5
|
+
window.DikshiPrintAgent = DikshiPrintAgent;
|
|
6
|
+
window.DikshiReceiptBuilder = DikshiReceiptBuilder;
|
|
7
|
+
}
|
package/npm/index.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export interface AgentOptions {
|
|
2
|
+
token: string;
|
|
3
|
+
host?: string;
|
|
4
|
+
port?: number;
|
|
5
|
+
protocol?: 'http' | 'https';
|
|
6
|
+
fetch?: typeof fetch;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type PrintOptions = Record<string, unknown>;
|
|
10
|
+
export interface PrintJob { jobId?: string; status?: string; error?: string; [key: string]: unknown; }
|
|
11
|
+
|
|
12
|
+
export class DikshiPrintAgent {
|
|
13
|
+
constructor(options: AgentOptions);
|
|
14
|
+
token: string;
|
|
15
|
+
base: string;
|
|
16
|
+
request(path: string, options?: RequestInit): Promise<any>;
|
|
17
|
+
health(): Promise<any>;
|
|
18
|
+
printers(): Promise<any>;
|
|
19
|
+
jobs(): Promise<any>;
|
|
20
|
+
job(id: string): Promise<PrintJob>;
|
|
21
|
+
templates(): Promise<any>;
|
|
22
|
+
template(name: string): Promise<any>;
|
|
23
|
+
saveTemplate(template: object): Promise<any>;
|
|
24
|
+
printText(printer: string, text: string, options?: PrintOptions): Promise<PrintJob>;
|
|
25
|
+
printRaw(printer: string, data: Uint8Array | string, options?: PrintOptions): Promise<PrintJob>;
|
|
26
|
+
printEscPos(printer: string, data: Uint8Array | string, options?: PrintOptions): Promise<PrintJob>;
|
|
27
|
+
printImage(printer: string, dataBase64: string, options?: PrintOptions): Promise<PrintJob>;
|
|
28
|
+
printCode(printer: string, value: string, options?: PrintOptions): Promise<PrintJob>;
|
|
29
|
+
printQr(printer: string, value: string, options?: PrintOptions): Promise<PrintJob>;
|
|
30
|
+
printBarcode(printer: string, value: string, options?: PrintOptions): Promise<PrintJob>;
|
|
31
|
+
printPdf(printer: string, dataBase64: string, options?: PrintOptions): Promise<PrintJob>;
|
|
32
|
+
printPdfUrl(printer: string, url: string, options?: PrintOptions): Promise<PrintJob>;
|
|
33
|
+
printHtml(printer: string, html: string, options?: PrintOptions): Promise<PrintJob>;
|
|
34
|
+
printTemplate(printer: string, templateData?: object): Promise<PrintJob>;
|
|
35
|
+
printDesignedTemplate(printer: string, templateName: string, data?: object, options?: PrintOptions): Promise<PrintJob>;
|
|
36
|
+
wait(jobId: string, timeoutMs?: number): Promise<PrintJob>;
|
|
37
|
+
static receiptBuilder(options?: ReceiptBuilderOptions): DikshiReceiptBuilder;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface ReceiptBuilderOptions { width?: number; encoding?: string; }
|
|
41
|
+
export class DikshiReceiptBuilder {
|
|
42
|
+
constructor(options?: ReceiptBuilderOptions);
|
|
43
|
+
init(): this; bytes(...values: number[]): this; text(value?: unknown): this; line(char?: string): this;
|
|
44
|
+
feed(lines?: number): this; bold(on?: boolean): this; underline(on?: boolean): this;
|
|
45
|
+
size(mode?: 'normal' | 'double' | 'wide' | 'tall'): this; align(value?: 'left' | 'center' | 'right'): this;
|
|
46
|
+
left(): this; center(): this; right(): this; row(left: unknown, right: unknown): this;
|
|
47
|
+
item(name: unknown, qty: number, rate: number, amount?: number): this; qr(value: unknown, size?: number): this;
|
|
48
|
+
barcode(value: unknown, height?: number): this; openCashDrawer(): this; cut(partial?: boolean): this;
|
|
49
|
+
raw(data: Uint8Array | number[]): this; build(): Uint8Array;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export default DikshiPrintAgent;
|
package/npm/index.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/** JavaScript client for the Dikshi Print Agent HTTP API. */
|
|
2
|
+
export class DikshiPrintAgent {
|
|
3
|
+
constructor({ token, host = '127.0.0.1', port = 8181, protocol = 'http', fetch: fetchImpl } = {}) {
|
|
4
|
+
if (!token) throw new Error('Dikshi Print Agent token is required');
|
|
5
|
+
this.token = token;
|
|
6
|
+
this.base = `${protocol}://${host}:${port}`;
|
|
7
|
+
this.fetch = fetchImpl || globalThis.fetch;
|
|
8
|
+
if (typeof this.fetch !== 'function') throw new Error('A fetch implementation is required');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async request(path, options = {}) {
|
|
12
|
+
const response = await this.fetch(this.base + path, {
|
|
13
|
+
...options,
|
|
14
|
+
headers: {
|
|
15
|
+
'Content-Type': 'application/json',
|
|
16
|
+
'X-Dikshi-Token': this.token,
|
|
17
|
+
...(options.headers || {})
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
const data = await response.json().catch(() => ({}));
|
|
21
|
+
if (!response.ok) throw new Error(data.error || `Print Agent HTTP ${response.status}`);
|
|
22
|
+
return data;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async health() {
|
|
26
|
+
const response = await this.fetch(this.base + '/api/v1/health');
|
|
27
|
+
const data = await response.json().catch(() => ({}));
|
|
28
|
+
if (!response.ok) throw new Error(data.error || `Print Agent HTTP ${response.status}`);
|
|
29
|
+
return data;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
printers() { return this.request('/api/v1/printers'); }
|
|
33
|
+
jobs() { return this.request('/api/v1/jobs'); }
|
|
34
|
+
job(id) { return this.request('/api/v1/jobs/' + encodeURIComponent(id)); }
|
|
35
|
+
templates() { return this.request('/api/v1/templates'); }
|
|
36
|
+
template(name) { return this.request('/api/v1/templates/' + encodeURIComponent(name)); }
|
|
37
|
+
saveTemplate(template) { return this.request('/api/v1/templates', this._post(template)); }
|
|
38
|
+
printText(printer, text, options = {}) { return this.request('/api/v1/print/text', this._post({ printer, text, ...options })); }
|
|
39
|
+
printImage(printer, dataBase64, options = {}) { return this.request('/api/v1/print/image', this._post({ printer, dataBase64, ...options })); }
|
|
40
|
+
printCode(printer, value, options = {}) { return this.request('/api/v1/print/code', this._post({ printer, value, ...options })); }
|
|
41
|
+
printQr(printer, value, options = {}) { return this.printCode(printer, value, { type: 'QR', ...options }); }
|
|
42
|
+
printBarcode(printer, value, options = {}) { return this.printCode(printer, value, { type: 'CODE128', ...options }); }
|
|
43
|
+
printPdf(printer, dataBase64, options = {}) { return this.request('/api/v1/print/pdf', this._post({ printer, dataBase64, ...options })); }
|
|
44
|
+
printPdfUrl(printer, url, options = {}) { return this.request('/api/v1/print/pdf-url', this._post({ printer, url, ...options })); }
|
|
45
|
+
printHtml(printer, html, options = {}) { return this.request('/api/v1/print/html', this._post({ printer, html, ...options })); }
|
|
46
|
+
printTemplate(printer, templateData = {}) { return this.request('/api/v1/print/template', this._post({ printer, ...templateData })); }
|
|
47
|
+
printDesignedTemplate(printer, templateName, data = {}, options = {}) {
|
|
48
|
+
return this.request('/api/v1/print/designed-template', this._post({ printer, templateName, data, ...options }));
|
|
49
|
+
}
|
|
50
|
+
printRaw(printer, bytesOrBase64, options = {}) { return this._binary('/api/v1/print/raw', printer, bytesOrBase64, options); }
|
|
51
|
+
printEscPos(printer, bytesOrBase64, options = {}) { return this._binary('/api/v1/print/escpos', printer, bytesOrBase64, options); }
|
|
52
|
+
|
|
53
|
+
async wait(jobId, timeoutMs = 20000) {
|
|
54
|
+
const start = Date.now();
|
|
55
|
+
while (Date.now() - start < timeoutMs) {
|
|
56
|
+
const job = await this.job(jobId);
|
|
57
|
+
if (job.status === 'completed') return job;
|
|
58
|
+
if (job.status === 'failed') throw new Error(job.error || 'Print failed');
|
|
59
|
+
await new Promise(resolve => setTimeout(resolve, 300));
|
|
60
|
+
}
|
|
61
|
+
throw new Error('Print job timeout');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
_post(value) { return { method: 'POST', body: JSON.stringify(value) }; }
|
|
65
|
+
_binary(path, printer, data, options) {
|
|
66
|
+
let dataBase64 = data;
|
|
67
|
+
if (data instanceof Uint8Array) dataBase64 = bytesToBase64(data);
|
|
68
|
+
return this.request(path, this._post({ printer, dataBase64, ...options }));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
static receiptBuilder(options = {}) { return new DikshiReceiptBuilder(options); }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export class DikshiReceiptBuilder {
|
|
75
|
+
constructor({ width = 42, encoding = 'utf-8' } = {}) {
|
|
76
|
+
this.width = width;
|
|
77
|
+
this.encoding = encoding;
|
|
78
|
+
this.parts = [];
|
|
79
|
+
this.init();
|
|
80
|
+
}
|
|
81
|
+
init() { return this.bytes(0x1b, 0x40); }
|
|
82
|
+
bytes(...values) { this.parts.push(Uint8Array.from(values)); return this; }
|
|
83
|
+
text(value = '') { this.parts.push(new TextEncoder(this.encoding).encode(String(value))); return this; }
|
|
84
|
+
line(char = '-') { return this.text(String(char).repeat(this.width) + '\n'); }
|
|
85
|
+
feed(lines = 1) { return this.text('\n'.repeat(Math.max(1, lines))); }
|
|
86
|
+
bold(on = true) { return this.bytes(0x1b, 0x45, on ? 1 : 0); }
|
|
87
|
+
underline(on = true) { return this.bytes(0x1b, 0x2d, on ? 1 : 0); }
|
|
88
|
+
size(mode = 'normal') { return this.bytes(0x1d, 0x21, mode === 'double' ? 0x11 : mode === 'wide' ? 0x10 : mode === 'tall' ? 0x01 : 0x00); }
|
|
89
|
+
align(value = 'left') { return this.bytes(0x1b, 0x61, value === 'center' ? 1 : value === 'right' ? 2 : 0); }
|
|
90
|
+
left() { return this.align('left'); }
|
|
91
|
+
center() { return this.align('center'); }
|
|
92
|
+
right() { return this.align('right'); }
|
|
93
|
+
row(left, right) {
|
|
94
|
+
const a = String(left ?? '');
|
|
95
|
+
const b = String(right ?? '');
|
|
96
|
+
return this.text(a + ' '.repeat(Math.max(1, this.width - a.length - b.length)) + b + '\n');
|
|
97
|
+
}
|
|
98
|
+
item(name, qty, rate, amount = Number(qty || 0) * Number(rate || 0)) {
|
|
99
|
+
this.text(String(name ?? '') + '\n');
|
|
100
|
+
return this.row(`${qty} x ${Number(rate || 0).toFixed(2)}`, Number(amount || 0).toFixed(2));
|
|
101
|
+
}
|
|
102
|
+
qr(value, size = 6) {
|
|
103
|
+
const data = new TextEncoder(this.encoding).encode(String(value ?? ''));
|
|
104
|
+
const length = data.length + 3;
|
|
105
|
+
return this.align('center')
|
|
106
|
+
.bytes(0x1d, 0x28, 0x6b, 0x04, 0x00, 0x31, 0x41, 0x32, 0x00)
|
|
107
|
+
.bytes(0x1d, 0x28, 0x6b, 0x03, 0x00, 0x31, 0x43, Math.max(1, Math.min(16, size)))
|
|
108
|
+
.bytes(0x1d, 0x28, 0x6b, 0x03, 0x00, 0x31, 0x45, 0x31)
|
|
109
|
+
.bytes(0x1d, 0x28, 0x6b, length & 0xff, (length >> 8) & 0xff, 0x31, 0x50, 0x30)
|
|
110
|
+
.raw(data).bytes(0x1d, 0x28, 0x6b, 0x03, 0x00, 0x31, 0x51, 0x30).align('left');
|
|
111
|
+
}
|
|
112
|
+
barcode(value, height = 70) {
|
|
113
|
+
const data = new TextEncoder(this.encoding).encode(String(value ?? ''));
|
|
114
|
+
return this.align('center').bytes(0x1d, 0x68, Math.max(1, Math.min(255, height)))
|
|
115
|
+
.bytes(0x1d, 0x48, 0x02).bytes(0x1d, 0x6b, 0x49, data.length).raw(data).feed().align('left');
|
|
116
|
+
}
|
|
117
|
+
openCashDrawer() { return this.bytes(0x1b, 0x70, 0x00, 0x19, 0xfa); }
|
|
118
|
+
cut(partial = false) { return this.feed(3).bytes(0x1d, 0x56, partial ? 0x01 : 0x00); }
|
|
119
|
+
raw(data) { this.parts.push(data instanceof Uint8Array ? data : Uint8Array.from(data || [])); return this; }
|
|
120
|
+
build() {
|
|
121
|
+
const output = new Uint8Array(this.parts.reduce((sum, part) => sum + part.length, 0));
|
|
122
|
+
let offset = 0;
|
|
123
|
+
for (const part of this.parts) { output.set(part, offset); offset += part.length; }
|
|
124
|
+
return output;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function bytesToBase64(bytes) {
|
|
129
|
+
if (typeof Buffer !== 'undefined') return Buffer.from(bytes).toString('base64');
|
|
130
|
+
let binary = '';
|
|
131
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
132
|
+
return btoa(binary);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export default DikshiPrintAgent;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import DikshiPrintAgent, { DikshiReceiptBuilder } from '../index.js';
|
|
4
|
+
|
|
5
|
+
test('requires a token', () => {
|
|
6
|
+
assert.throws(() => new DikshiPrintAgent(), /token is required/);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
test('sends authenticated print requests', async () => {
|
|
10
|
+
let request;
|
|
11
|
+
const agent = new DikshiPrintAgent({
|
|
12
|
+
token: 'secret',
|
|
13
|
+
fetch: async (url, options) => {
|
|
14
|
+
request = { url, options };
|
|
15
|
+
return { ok: true, json: async () => ({ jobId: '123' }) };
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
const result = await agent.printText('Printer 1', 'Hello');
|
|
19
|
+
assert.equal(result.jobId, '123');
|
|
20
|
+
assert.equal(request.url, 'http://127.0.0.1:8181/api/v1/print/text');
|
|
21
|
+
assert.equal(request.options.headers['X-Dikshi-Token'], 'secret');
|
|
22
|
+
assert.deepEqual(JSON.parse(request.options.body), { printer: 'Printer 1', text: 'Hello' });
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('builds ESC/POS bytes', () => {
|
|
26
|
+
const output = new DikshiReceiptBuilder({ width: 10 }).text('Hi').cut().build();
|
|
27
|
+
assert.ok(output instanceof Uint8Array);
|
|
28
|
+
assert.ok(output.length > 5);
|
|
29
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dikshiprintagent",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "JavaScript SDK for the Dikshi Print Agent local Windows printing service",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"printing",
|
|
7
|
+
"silent-print",
|
|
8
|
+
"escpos",
|
|
9
|
+
"windows-printer",
|
|
10
|
+
"dikshi"
|
|
11
|
+
],
|
|
12
|
+
"license": "UNLICENSED",
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "./npm/index.js",
|
|
15
|
+
"module": "./npm/index.js",
|
|
16
|
+
"types": "./npm/index.d.ts",
|
|
17
|
+
"browser": "./npm/browser.js",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./npm/index.d.ts",
|
|
21
|
+
"import": "./npm/index.js",
|
|
22
|
+
"default": "./npm/index.js"
|
|
23
|
+
},
|
|
24
|
+
"./browser": "./npm/browser.js"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"npm",
|
|
28
|
+
"README.md",
|
|
29
|
+
"NPM-PACKAGE.md"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"test": "node --test npm/test",
|
|
33
|
+
"prepack": "npm test"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
}
|
|
41
|
+
}
|