labelinn 1.1.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/CHANGELOG.md +36 -0
- package/LICENSE +21 -0
- package/README.md +458 -0
- package/bin/cli.js +793 -0
- package/lib/index.d.ts +327 -0
- package/lib/index.js +556 -0
- package/package.json +61 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LabelInn Node.js SDK
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* const LabelInn = require('labelinn');
|
|
6
|
+
* const client = new LabelInn('sk_live_xxxxx');
|
|
7
|
+
*
|
|
8
|
+
* // Print a label from a template
|
|
9
|
+
* const job = await client.print.create({
|
|
10
|
+
* printer_id: 'abc123',
|
|
11
|
+
* payload_type: 'template',
|
|
12
|
+
* design_id: 'tmpl_shipping',
|
|
13
|
+
* data: { barcode: 'TR123', name: 'Ali' },
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* // Check job status
|
|
17
|
+
* const status = await client.print.get(job.id);
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
'use strict';
|
|
21
|
+
|
|
22
|
+
const BASE_URL = 'https://labelinn.com/v1';
|
|
23
|
+
|
|
24
|
+
class LabelInnError extends Error {
|
|
25
|
+
constructor(status, code, message, raw) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.name = 'LabelInnError';
|
|
28
|
+
this.status = status;
|
|
29
|
+
this.code = code;
|
|
30
|
+
this.raw = raw;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
class LabelInnRateLimitError extends LabelInnError {
|
|
35
|
+
constructor(status, code, message, retryAfter, raw) {
|
|
36
|
+
super(status, code, message, raw);
|
|
37
|
+
this.name = 'LabelInnRateLimitError';
|
|
38
|
+
this.retryAfter = retryAfter;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ─── HTTP Client ─────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
class HttpClient {
|
|
45
|
+
constructor(apiKey, opts = {}) {
|
|
46
|
+
this.apiKey = apiKey;
|
|
47
|
+
this.baseUrl = opts.baseUrl || BASE_URL;
|
|
48
|
+
this.timeout = opts.timeout || 30000;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async request(method, path, body, opts = {}) {
|
|
52
|
+
const url = `${this.baseUrl}${path}`;
|
|
53
|
+
const headers = {
|
|
54
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
55
|
+
'Content-Type': 'application/json',
|
|
56
|
+
'User-Agent': 'labelinn-node/1.0.0',
|
|
57
|
+
};
|
|
58
|
+
if (opts.idempotencyKey) {
|
|
59
|
+
headers['X-Idempotency-Key'] = opts.idempotencyKey;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const fetchOpts = {
|
|
63
|
+
method,
|
|
64
|
+
headers,
|
|
65
|
+
signal: AbortSignal.timeout(this.timeout),
|
|
66
|
+
};
|
|
67
|
+
if (body && method !== 'GET') {
|
|
68
|
+
fetchOpts.body = JSON.stringify(body);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const response = await fetch(url, fetchOpts);
|
|
72
|
+
|
|
73
|
+
// Parse rate limit headers
|
|
74
|
+
const rateLimit = {
|
|
75
|
+
limit: parseInt(response.headers.get('x-ratelimit-limit') || '0', 10),
|
|
76
|
+
remaining: parseInt(response.headers.get('x-ratelimit-remaining') || '0', 10),
|
|
77
|
+
reset: parseInt(response.headers.get('x-ratelimit-reset') || '0', 10),
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
let data;
|
|
81
|
+
try {
|
|
82
|
+
data = await response.json();
|
|
83
|
+
} catch {
|
|
84
|
+
data = null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (!response.ok) {
|
|
88
|
+
const err = data?.error || {};
|
|
89
|
+
if (response.status === 429) {
|
|
90
|
+
throw new LabelInnRateLimitError(
|
|
91
|
+
429, err.code || 'RATE_LIMIT_EXCEEDED',
|
|
92
|
+
err.message || 'Rate limit exceeded',
|
|
93
|
+
err.retry_after_seconds || rateLimit.reset,
|
|
94
|
+
data
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
throw new LabelInnError(
|
|
98
|
+
response.status,
|
|
99
|
+
err.code || 'API_ERROR',
|
|
100
|
+
err.message || `HTTP ${response.status}`,
|
|
101
|
+
data
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const result = data?.data || data;
|
|
106
|
+
result._rateLimit = rateLimit;
|
|
107
|
+
if (data?._idempotent) result._idempotent = true;
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
get(path) { return this.request('GET', path); }
|
|
112
|
+
post(path, body, opts) { return this.request('POST', path, body, opts); }
|
|
113
|
+
put(path, body) { return this.request('PUT', path, body); }
|
|
114
|
+
patch(path, body) { return this.request('PATCH', path, body); }
|
|
115
|
+
del(path) { return this.request('DELETE', path); }
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ─── Resource: Print Jobs ────────────────────────────────────
|
|
119
|
+
|
|
120
|
+
class PrintResource {
|
|
121
|
+
constructor(http) { this._http = http; }
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Submit a print job.
|
|
125
|
+
*
|
|
126
|
+
* @param {object} params
|
|
127
|
+
* @param {string} params.printer_id - Target printer ID
|
|
128
|
+
* @param {string} params.payload_type - "zpl" | "image" | "template"
|
|
129
|
+
* @param {string} [params.payload_data] - ZPL string or base64 image
|
|
130
|
+
* @param {string} [params.image_url] - HTTPS URL to image (for payload_type:"image")
|
|
131
|
+
* @param {string} [params.design_id] - Template ID (for payload_type:"template")
|
|
132
|
+
* @param {object|object[]} [params.data] - Variable values for template
|
|
133
|
+
* @param {string} [params.job_name] - Human-readable job name
|
|
134
|
+
* @param {number} [params.copies] - Number of copies (1-1000)
|
|
135
|
+
* @param {number} [params.media_width_mm] - Label width in mm
|
|
136
|
+
* @param {number} [params.media_height_mm] - Label height in mm
|
|
137
|
+
* @param {string} [opts.idempotencyKey] - Prevents duplicate prints
|
|
138
|
+
* @returns {Promise<object>} Created job
|
|
139
|
+
*/
|
|
140
|
+
create(params, opts = {}) {
|
|
141
|
+
return this._http.post('/print/jobs', params, opts);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* List print jobs.
|
|
146
|
+
* @param {object} [query] - { status, printer_id, limit, page_token }
|
|
147
|
+
*/
|
|
148
|
+
list(query = {}) {
|
|
149
|
+
const qs = new URLSearchParams();
|
|
150
|
+
for (const [k, v] of Object.entries(query)) {
|
|
151
|
+
if (v !== undefined && v !== null) qs.set(k, String(v));
|
|
152
|
+
}
|
|
153
|
+
const qstr = qs.toString();
|
|
154
|
+
return this._http.get(`/print/jobs${qstr ? '?' + qstr : ''}`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Get a single print job by ID.
|
|
159
|
+
* @param {string} jobId
|
|
160
|
+
*/
|
|
161
|
+
get(jobId) {
|
|
162
|
+
return this._http.get(`/print/jobs/${jobId}`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Cancel a queued print job.
|
|
167
|
+
* @param {string} jobId
|
|
168
|
+
*/
|
|
169
|
+
cancel(jobId) {
|
|
170
|
+
return this._http.del(`/print/jobs/${jobId}`);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Reprint a previous job.
|
|
175
|
+
* @param {string} jobId
|
|
176
|
+
* @param {object} [overrides] - { printer_id, copies, data }
|
|
177
|
+
*/
|
|
178
|
+
reprint(jobId, overrides = {}) {
|
|
179
|
+
return this._http.post(`/print/jobs/${jobId}/reprint`, overrides);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Retry a failed job (creates new job from original).
|
|
184
|
+
* @param {string} jobId
|
|
185
|
+
* @param {object} [params] - { printer_id } optional override
|
|
186
|
+
*/
|
|
187
|
+
retry(jobId, params = {}) {
|
|
188
|
+
return this._http.post(`/print/jobs/${jobId}/retry`, params);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Submit up to 100 print jobs in a single request.
|
|
193
|
+
* @param {object[]} jobs - Array of job objects
|
|
194
|
+
*/
|
|
195
|
+
batch(jobs) {
|
|
196
|
+
return this._http.post('/print/batch', { jobs });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ─── Resource: Fleet (Printers) ──────────────────────────────
|
|
201
|
+
|
|
202
|
+
class FleetResource {
|
|
203
|
+
constructor(http) {
|
|
204
|
+
this._http = http;
|
|
205
|
+
this.groups = new FleetGroupsResource(http);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* List all printers.
|
|
210
|
+
* @param {object} [query] - { status, type, connection }
|
|
211
|
+
*/
|
|
212
|
+
list(query = {}) {
|
|
213
|
+
const qs = new URLSearchParams();
|
|
214
|
+
for (const [k, v] of Object.entries(query)) {
|
|
215
|
+
if (v !== undefined && v !== null) qs.set(k, String(v));
|
|
216
|
+
}
|
|
217
|
+
const qstr = qs.toString();
|
|
218
|
+
return this._http.get(`/fleet/printers${qstr ? '?' + qstr : ''}`);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Get printer details + telemetry.
|
|
223
|
+
* @param {string} printerId
|
|
224
|
+
*/
|
|
225
|
+
get(printerId) {
|
|
226
|
+
return this._http.get(`/fleet/printers/${printerId}`);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Get live printer status (lightweight).
|
|
231
|
+
* @param {string} printerId
|
|
232
|
+
*/
|
|
233
|
+
status(printerId) {
|
|
234
|
+
return this._http.get(`/fleet/printers/${printerId}/status`);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Update printer metadata.
|
|
239
|
+
* @param {string} printerId
|
|
240
|
+
* @param {object} params - { name, metadata }
|
|
241
|
+
*/
|
|
242
|
+
update(printerId, params) {
|
|
243
|
+
return this._http.put(`/fleet/printers/${printerId}`, params);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Flash/beep a printer to identify it.
|
|
248
|
+
* @param {string} printerId
|
|
249
|
+
*/
|
|
250
|
+
identify(printerId) {
|
|
251
|
+
return this._http.post(`/fleet/printers/${printerId}/identify`);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Set media definition on a printer.
|
|
256
|
+
* @param {string} printerId
|
|
257
|
+
* @param {object} params - { width_mm, height_mm, media_type, gap_mm, ... }
|
|
258
|
+
*/
|
|
259
|
+
setMedia(printerId, params) {
|
|
260
|
+
return this._http.put(`/fleet/printers/${printerId}/media`, params);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
class FleetGroupsResource {
|
|
265
|
+
constructor(http) { this._http = http; }
|
|
266
|
+
|
|
267
|
+
create(params) { return this._http.post('/fleet/groups', params); }
|
|
268
|
+
list(query = {}) {
|
|
269
|
+
const qs = new URLSearchParams();
|
|
270
|
+
for (const [k, v] of Object.entries(query)) {
|
|
271
|
+
if (v !== undefined && v !== null) qs.set(k, String(v));
|
|
272
|
+
}
|
|
273
|
+
const qstr = qs.toString();
|
|
274
|
+
return this._http.get(`/fleet/groups${qstr ? '?' + qstr : ''}`);
|
|
275
|
+
}
|
|
276
|
+
get(groupId) { return this._http.get(`/fleet/groups/${groupId}`); }
|
|
277
|
+
update(groupId, params) { return this._http.put(`/fleet/groups/${groupId}`, params); }
|
|
278
|
+
delete(groupId) { return this._http.del(`/fleet/groups/${groupId}`); }
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// ─── Resource: Designs (Templates) ───────────────────────────
|
|
282
|
+
|
|
283
|
+
class DesignsResource {
|
|
284
|
+
constructor(http) { this._http = http; }
|
|
285
|
+
|
|
286
|
+
list(query = {}) {
|
|
287
|
+
const qs = new URLSearchParams();
|
|
288
|
+
for (const [k, v] of Object.entries(query)) {
|
|
289
|
+
if (v !== undefined && v !== null) qs.set(k, String(v));
|
|
290
|
+
}
|
|
291
|
+
const qstr = qs.toString();
|
|
292
|
+
return this._http.get(`/designs${qstr ? '?' + qstr : ''}`);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
get(designId) {
|
|
296
|
+
return this._http.get(`/designs/${designId}`);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
create(params) {
|
|
300
|
+
return this._http.post('/designs', params);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
update(designId, params) {
|
|
304
|
+
return this._http.put(`/designs/${designId}`, params);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
delete(designId) {
|
|
308
|
+
return this._http.del(`/designs/${designId}`);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// ── Elements ──
|
|
312
|
+
|
|
313
|
+
listElements(designId) {
|
|
314
|
+
return this._http.get(`/designs/${designId}/elements`);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
addElement(designId, params) {
|
|
318
|
+
return this._http.post(`/designs/${designId}/elements`, params);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
updateElement(designId, elementId, params) {
|
|
322
|
+
return this._http.patch(`/designs/${designId}/elements/${elementId}`, params);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
deleteElement(designId, elementId) {
|
|
326
|
+
return this._http.del(`/designs/${designId}/elements/${elementId}`);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// ── Variables & Actions ──
|
|
330
|
+
|
|
331
|
+
listVariables(designId) {
|
|
332
|
+
return this._http.get(`/designs/${designId}/variables`);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
clone(designId) {
|
|
336
|
+
return this._http.post(`/designs/${designId}/clone`);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
render(designId, params = {}) {
|
|
340
|
+
return this._http.post(`/designs/${designId}/render`, params);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Print a design directly with data.
|
|
345
|
+
* @param {string} designId
|
|
346
|
+
* @param {object} params - { printer_id, data, copies }
|
|
347
|
+
*/
|
|
348
|
+
print(designId, params) {
|
|
349
|
+
return this._http.post(`/designs/${designId}/print`, params);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* List revision history for a design.
|
|
354
|
+
* @param {string} designId
|
|
355
|
+
* @param {object} [query] - { limit }
|
|
356
|
+
*/
|
|
357
|
+
revisions(designId, query = {}) {
|
|
358
|
+
const qs = new URLSearchParams();
|
|
359
|
+
for (const [k, v] of Object.entries(query)) {
|
|
360
|
+
if (v !== undefined && v !== null) qs.set(k, String(v));
|
|
361
|
+
}
|
|
362
|
+
const qstr = qs.toString();
|
|
363
|
+
return this._http.get(`/designs/${designId}/revisions${qstr ? '?' + qstr : ''}`);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// ─── Resource: Webhooks ──────────────────────────────────────
|
|
368
|
+
|
|
369
|
+
class WebhooksResource {
|
|
370
|
+
constructor(http) { this._http = http; }
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Subscribe to events.
|
|
374
|
+
* @param {object} params - { url, events, description }
|
|
375
|
+
*/
|
|
376
|
+
create(params) {
|
|
377
|
+
return this._http.post('/webhooks', params);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
list() {
|
|
381
|
+
return this._http.get('/webhooks');
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
delete(webhookId) {
|
|
385
|
+
return this._http.del(`/webhooks/${webhookId}`);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Send a test ping to a webhook endpoint.
|
|
390
|
+
* @param {string} webhookId
|
|
391
|
+
*/
|
|
392
|
+
test(webhookId) {
|
|
393
|
+
return this._http.post(`/webhooks/${webhookId}/test`);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Update a webhook subscription.
|
|
398
|
+
* @param {string} webhookId
|
|
399
|
+
* @param {object} params - { url, events, description, enabled }
|
|
400
|
+
*/
|
|
401
|
+
update(webhookId, params) {
|
|
402
|
+
return this._http.put(`/webhooks/${webhookId}`, params);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* List recent delivery attempts for a webhook.
|
|
407
|
+
* @param {string} webhookId
|
|
408
|
+
* @param {object} [query] - { limit }
|
|
409
|
+
*/
|
|
410
|
+
deliveries(webhookId, query = {}) {
|
|
411
|
+
const qs = new URLSearchParams();
|
|
412
|
+
for (const [k, v] of Object.entries(query)) {
|
|
413
|
+
if (v !== undefined && v !== null) qs.set(k, String(v));
|
|
414
|
+
}
|
|
415
|
+
const qstr = qs.toString();
|
|
416
|
+
return this._http.get(`/webhooks/${webhookId}/deliveries${qstr ? '?' + qstr : ''}`);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// ─── Main Client ─────────────────────────────────────────────
|
|
421
|
+
|
|
422
|
+
class ConnectResource {
|
|
423
|
+
constructor(http) { this._http = http; }
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Push data in any format (XML, CSV, JSON).
|
|
427
|
+
* @param {object} params - { payload, source_id?, format?, name?, config? }
|
|
428
|
+
*/
|
|
429
|
+
ingest(params) {
|
|
430
|
+
return this._http.post('/connect/ingest', params);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Parse data without storing (dry run).
|
|
435
|
+
* @param {object} params - { payload, format?, config? }
|
|
436
|
+
*/
|
|
437
|
+
testParse(params) {
|
|
438
|
+
return this._http.post('/connect/test-parse', params);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Create a connector source.
|
|
443
|
+
* @param {object} params - { name, description?, format?, config? }
|
|
444
|
+
*/
|
|
445
|
+
createSource(params) {
|
|
446
|
+
return this._http.post('/connect/sources', params);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/** List all connector sources. */
|
|
450
|
+
listSources(query = {}) {
|
|
451
|
+
const qs = new URLSearchParams();
|
|
452
|
+
for (const [k, v] of Object.entries(query)) {
|
|
453
|
+
if (v !== undefined && v !== null) qs.set(k, String(v));
|
|
454
|
+
}
|
|
455
|
+
const qstr = qs.toString();
|
|
456
|
+
return this._http.get(`/connect/sources${qstr ? '?' + qstr : ''}`);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/** Get a connector source by ID. */
|
|
460
|
+
getSource(sourceId) {
|
|
461
|
+
return this._http.get(`/connect/sources/${sourceId}`);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/** Update a connector source. */
|
|
465
|
+
updateSource(sourceId, params) {
|
|
466
|
+
return this._http.put(`/connect/sources/${sourceId}`, params);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/** Delete (deactivate) a connector source. */
|
|
470
|
+
deleteSource(sourceId) {
|
|
471
|
+
return this._http.del(`/connect/sources/${sourceId}`);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/** Get records from a connector source. */
|
|
475
|
+
listRecords(sourceId, query = {}) {
|
|
476
|
+
const qs = new URLSearchParams();
|
|
477
|
+
for (const [k, v] of Object.entries(query)) {
|
|
478
|
+
if (v !== undefined && v !== null) qs.set(k, String(v));
|
|
479
|
+
}
|
|
480
|
+
const qstr = qs.toString();
|
|
481
|
+
return this._http.get(`/connect/sources/${sourceId}/records${qstr ? '?' + qstr : ''}`);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/** Get discovered schema for a connector source. */
|
|
485
|
+
getSchema(sourceId) {
|
|
486
|
+
return this._http.get(`/connect/sources/${sourceId}/schema`);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/** Get field mappings for a connector source. */
|
|
490
|
+
getMappings(sourceId) {
|
|
491
|
+
return this._http.get(`/connect/sources/${sourceId}/mappings`);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/** Set field→label mappings. */
|
|
495
|
+
updateMappings(sourceId, mappings) {
|
|
496
|
+
return this._http.put(`/connect/sources/${sourceId}/mappings`, { mappings });
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Print labels from connector data.
|
|
501
|
+
* @param {string} sourceId
|
|
502
|
+
* @param {object} params - { printer_id, design_id, record_ids?, ingest_id?, copies?, field_mappings? }
|
|
503
|
+
*/
|
|
504
|
+
print(sourceId, params) {
|
|
505
|
+
return this._http.post(`/connect/sources/${sourceId}/print`, params);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
class LabelInn {
|
|
510
|
+
/**
|
|
511
|
+
* Create a LabelInn API client.
|
|
512
|
+
*
|
|
513
|
+
* @param {string} apiKey - Your API key (sk_live_xxx or sk_test_xxx)
|
|
514
|
+
* @param {object} [opts]
|
|
515
|
+
* @param {string} [opts.baseUrl] - Override API base URL
|
|
516
|
+
* @param {number} [opts.timeout] - Request timeout in ms (default: 30000)
|
|
517
|
+
*/
|
|
518
|
+
constructor(apiKey, opts = {}) {
|
|
519
|
+
if (!apiKey || typeof apiKey !== 'string') {
|
|
520
|
+
throw new Error('LabelInn: apiKey is required. Get one at https://labelinn.com → Settings → API Keys');
|
|
521
|
+
}
|
|
522
|
+
if (!apiKey.startsWith('sk_live_') && !apiKey.startsWith('sk_test_')) {
|
|
523
|
+
throw new Error('LabelInn: apiKey must start with sk_live_ or sk_test_');
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
this._http = new HttpClient(apiKey, opts);
|
|
527
|
+
|
|
528
|
+
/** @type {PrintResource} Print job operations */
|
|
529
|
+
this.print = new PrintResource(this._http);
|
|
530
|
+
|
|
531
|
+
/** @type {FleetResource} Printer fleet management */
|
|
532
|
+
this.fleet = new FleetResource(this._http);
|
|
533
|
+
|
|
534
|
+
/** @type {DesignsResource} Design/template management */
|
|
535
|
+
this.designs = new DesignsResource(this._http);
|
|
536
|
+
|
|
537
|
+
/** @type {WebhooksResource} Webhook subscriptions */
|
|
538
|
+
this.webhooks = new WebhooksResource(this._http);
|
|
539
|
+
|
|
540
|
+
/** @type {ConnectResource} Data Connect — enterprise data ingestion */
|
|
541
|
+
this.connect = new ConnectResource(this._http);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/** Returns true if using a test key */
|
|
545
|
+
get isTestMode() {
|
|
546
|
+
return this._http.apiKey.startsWith('sk_test_');
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// ─── Exports ─────────────────────────────────────────────────
|
|
551
|
+
|
|
552
|
+
module.exports = LabelInn;
|
|
553
|
+
module.exports.LabelInn = LabelInn;
|
|
554
|
+
module.exports.LabelInnError = LabelInnError;
|
|
555
|
+
module.exports.LabelInnRateLimitError = LabelInnRateLimitError;
|
|
556
|
+
module.exports.default = LabelInn;
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "labelinn",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Official Node.js SDK for the LabelInn Cloud Print API. Send labels to Zebra, TSC, and Honeywell thermal printers from any system.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"labelinn",
|
|
7
|
+
"label",
|
|
8
|
+
"printer",
|
|
9
|
+
"zebra",
|
|
10
|
+
"tsc",
|
|
11
|
+
"honeywell",
|
|
12
|
+
"zpl",
|
|
13
|
+
"barcode",
|
|
14
|
+
"shipping",
|
|
15
|
+
"thermal",
|
|
16
|
+
"thermal-printer",
|
|
17
|
+
"cloud-print",
|
|
18
|
+
"print-api",
|
|
19
|
+
"warehouse",
|
|
20
|
+
"logistics",
|
|
21
|
+
"ecommerce"
|
|
22
|
+
],
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"author": "LabelInn <support@labelinn.com> (https://labelinn.com)",
|
|
25
|
+
"homepage": "https://labelinn.com/developers",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/labelcraft31/labelinn-node.git"
|
|
29
|
+
},
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/labelcraft31/labelinn-node/issues"
|
|
32
|
+
},
|
|
33
|
+
"funding": {
|
|
34
|
+
"url": "https://labelinn.com"
|
|
35
|
+
},
|
|
36
|
+
"main": "lib/index.js",
|
|
37
|
+
"types": "lib/index.d.ts",
|
|
38
|
+
"exports": {
|
|
39
|
+
".": {
|
|
40
|
+
"require": "./lib/index.js",
|
|
41
|
+
"types": "./lib/index.d.ts"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"bin": {
|
|
45
|
+
"labelinn": "bin/cli.js"
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"lib/",
|
|
49
|
+
"bin/",
|
|
50
|
+
"LICENSE",
|
|
51
|
+
"README.md",
|
|
52
|
+
"CHANGELOG.md"
|
|
53
|
+
],
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=18.0.0"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"test": "node test/basic.js",
|
|
59
|
+
"prepublishOnly": "node -e \"require('./lib/index.js')\""
|
|
60
|
+
}
|
|
61
|
+
}
|