@jazzdev/dpd-local-sdk 1.0.11 → 1.0.12
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 +74 -5
- package/dist/index.js +9 -39
- package/dist/index.mjs +9 -39
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -201,6 +201,9 @@ const result = await createCompleteShipment(
|
|
|
201
201
|
|
|
202
202
|
if (result.success) {
|
|
203
203
|
console.log('Shipment created!');
|
|
204
|
+
console.log('Shipment ID:', result.shipmentId); // Save this for label regeneration
|
|
205
|
+
console.log('Consignment Number:', result.consignmentNumber); // 10-digit reference
|
|
206
|
+
console.log('Parcel Number:', result.parcelNumber); // 14-digit tracking number
|
|
204
207
|
console.log('Tracking URL:', result.trackingUrl);
|
|
205
208
|
console.log('Label URL:', result.labelUrl);
|
|
206
209
|
} else {
|
|
@@ -208,6 +211,71 @@ if (result.success) {
|
|
|
208
211
|
}
|
|
209
212
|
```
|
|
210
213
|
|
|
214
|
+
## Understanding DPD Identifiers
|
|
215
|
+
|
|
216
|
+
When you create a shipment with DPD, you receive three different identifiers:
|
|
217
|
+
|
|
218
|
+
1. **shipmentId** - DPD's internal shipment identifier (numeric)
|
|
219
|
+
- Required for label regeneration
|
|
220
|
+
- Save this in your database!
|
|
221
|
+
|
|
222
|
+
2. **consignmentNumber** - 10-digit reference number (e.g., `6504286395`)
|
|
223
|
+
- Used for internal tracking
|
|
224
|
+
|
|
225
|
+
3. **parcelNumber** - 14-digit tracking number (e.g., `15976504286395`)
|
|
226
|
+
- What customers use to track their delivery
|
|
227
|
+
- Used in the tracking URL
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
// When creating a shipment, save ALL identifiers:
|
|
231
|
+
const result = await createCompleteShipment(...);
|
|
232
|
+
|
|
233
|
+
if (result.success) {
|
|
234
|
+
await saveToDatabase({
|
|
235
|
+
shipmentId: result.shipmentId, // Save for label regeneration
|
|
236
|
+
consignmentNumber: result.consignmentNumber,
|
|
237
|
+
parcelNumber: result.parcelNumber, // Give to customer for tracking
|
|
238
|
+
trackingUrl: result.trackingUrl,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Regenerating Labels
|
|
244
|
+
|
|
245
|
+
If you need to regenerate a label (e.g., printer jam), use the `shipmentId`:
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
import { generateLabel } from '@jazzdev/dpd-local-sdk';
|
|
249
|
+
|
|
250
|
+
const result = await generateLabel(credentials, {
|
|
251
|
+
shipmentId: '12345678', // Use the shipmentId, not consignment/parcel number
|
|
252
|
+
labelFormat: 'zpl' // or 'clp', 'html'
|
|
253
|
+
});
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Testing Label Generation
|
|
257
|
+
|
|
258
|
+
A test script is included to verify label generation:
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
# Using npm script
|
|
262
|
+
npm run test:label <shipmentId> [format]
|
|
263
|
+
|
|
264
|
+
# Or directly with tsx
|
|
265
|
+
npx tsx test-label-generation.ts <shipmentId> [format]
|
|
266
|
+
|
|
267
|
+
# Examples
|
|
268
|
+
npm run test:label 12345678
|
|
269
|
+
npm run test:label 12345678 html
|
|
270
|
+
npm run test:label 12345678 zpl
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
The script will:
|
|
274
|
+
- Validate your DPD credentials
|
|
275
|
+
- Generate the label in the specified format
|
|
276
|
+
- Save it to a file (`label-<shipmentId>.<format>`)
|
|
277
|
+
- Display a preview of the label content
|
|
278
|
+
|
|
211
279
|
## API Reference
|
|
212
280
|
|
|
213
281
|
### Configuration
|
|
@@ -379,11 +447,12 @@ console.log('DPD_ENCRYPTION_KEY=' + key);
|
|
|
379
447
|
|
|
380
448
|
Complete adapter examples are available in the `examples/` directory:
|
|
381
449
|
|
|
382
|
-
- `examples/
|
|
383
|
-
- `examples/
|
|
384
|
-
- `examples/
|
|
385
|
-
- `examples/firebase-storage-adapter.ts` - Firebase Storage
|
|
386
|
-
|
|
450
|
+
- `examples/basic-usage.ts` - Complete workflow example
|
|
451
|
+
- `examples/regenerate-label.ts` - Label regeneration example
|
|
452
|
+
- `examples/firestore-adapter.ts` - Firestore database adapter
|
|
453
|
+
- `examples/firebase-storage-adapter.ts` - Firebase Storage adapter
|
|
454
|
+
|
|
455
|
+
For other databases (MongoDB, PostgreSQL, etc.), implement the `DatabaseAdapter` interface following the Firestore example as a reference. The adapter pattern is database-agnostic by design.
|
|
387
456
|
|
|
388
457
|
## Error Handling
|
|
389
458
|
|
package/dist/index.js
CHANGED
|
@@ -324,10 +324,6 @@ async function authenticatedRequest(credentials, options) {
|
|
|
324
324
|
const isLabelRequest = acceptHeader === "text/vnd.zebra-zpl" || acceptHeader === "text/vnd.citizen-clp" || acceptHeader === "text/vnd.eltron-epl" || acceptHeader === "text/html";
|
|
325
325
|
let data = null;
|
|
326
326
|
if (isLabelRequest) {
|
|
327
|
-
console.log("\u{1F3F7}\uFE0F [SDK auth] Label request detected");
|
|
328
|
-
console.log(` HTTP Status: ${response.status} ${response.statusText}`);
|
|
329
|
-
console.log(` Response length: ${raw.length} chars`);
|
|
330
|
-
console.log(` Response preview (first 300 chars): ${raw.substring(0, 300)}`);
|
|
331
327
|
if (!response.ok) {
|
|
332
328
|
throw new Error(
|
|
333
329
|
`Label request failed: ${response.status} ${response.statusText}`
|
|
@@ -335,20 +331,18 @@ async function authenticatedRequest(credentials, options) {
|
|
|
335
331
|
}
|
|
336
332
|
try {
|
|
337
333
|
const parsed = JSON.parse(raw);
|
|
338
|
-
console.log("\u{1F50D} [SDK auth] Label request - parsed JSON response:", parsed);
|
|
339
334
|
if (parsed?.error || parsed?.data === null) {
|
|
340
|
-
console.log("\u26A0\uFE0F [SDK auth] Detected error response:", {
|
|
341
|
-
hasError: !!parsed?.error,
|
|
342
|
-
dataIsNull: parsed?.data === null,
|
|
343
|
-
errorObj: parsed?.error
|
|
344
|
-
});
|
|
345
335
|
const errorObj = parsed?.error;
|
|
346
336
|
let errorMessage = "Label generation failed";
|
|
347
337
|
let errorCode = "UNKNOWN";
|
|
348
338
|
if (errorObj) {
|
|
349
|
-
if (errorObj
|
|
339
|
+
if (Array.isArray(errorObj)) {
|
|
340
|
+
const firstError = errorObj[0];
|
|
341
|
+
errorMessage = firstError?.errorMessage || errorMessage;
|
|
342
|
+
errorCode = firstError?.errorCode || errorCode;
|
|
343
|
+
} else if (errorObj.errorMessage) {
|
|
350
344
|
errorMessage = errorObj.errorMessage;
|
|
351
|
-
errorCode = errorObj.errorCode || errorObj.name ||
|
|
345
|
+
errorCode = errorObj.errorCode || errorObj.name || errorCode;
|
|
352
346
|
} else if (errorObj.name) {
|
|
353
347
|
errorMessage = errorObj.name;
|
|
354
348
|
errorCode = errorObj.name;
|
|
@@ -359,7 +353,6 @@ async function authenticatedRequest(credentials, options) {
|
|
|
359
353
|
}
|
|
360
354
|
}
|
|
361
355
|
}
|
|
362
|
-
console.error(`\u274C [SDK auth] Throwing error - Code: ${errorCode}, Message: ${errorMessage}`);
|
|
363
356
|
throw new Error(`DPD API Error ${errorCode}: ${errorMessage}`);
|
|
364
357
|
}
|
|
365
358
|
if (parsed?.data) {
|
|
@@ -574,12 +567,7 @@ async function createShipment(credentials, params, businessConfig) {
|
|
|
574
567
|
async function generateLabel(credentials, params) {
|
|
575
568
|
try {
|
|
576
569
|
const { shipmentId, labelFormat } = params;
|
|
577
|
-
console.log("\n\u{1F3F7}\uFE0F [SDK generateLabel] Starting label generation");
|
|
578
|
-
console.log(` Shipment ID: ${shipmentId} (type: ${typeof shipmentId})`);
|
|
579
|
-
console.log(` Format: ${labelFormat}`);
|
|
580
|
-
console.log(` Accept Header: ${getAcceptHeader(labelFormat)}`);
|
|
581
570
|
const endpoint = `${DPD_API.ENDPOINTS.LABEL}/${shipmentId}/label/`;
|
|
582
|
-
console.log(` Endpoint: ${endpoint}`);
|
|
583
571
|
const response = await authenticatedRequest(credentials, {
|
|
584
572
|
method: "GET",
|
|
585
573
|
endpoint,
|
|
@@ -587,35 +575,17 @@ async function generateLabel(credentials, params) {
|
|
|
587
575
|
Accept: getAcceptHeader(labelFormat)
|
|
588
576
|
}
|
|
589
577
|
});
|
|
590
|
-
|
|
591
|
-
console.log(
|
|
592
|
-
"\u{1F4E6} [SDK generateLabel] Raw response:",
|
|
593
|
-
typeof response === "string" ? `String (${response.length} chars): ${response.substring(0, 200)}...` : response
|
|
594
|
-
);
|
|
595
|
-
if (typeof response === "object" && response.error) {
|
|
596
|
-
const errorObj = response.error;
|
|
597
|
-
console.error("\u274C [SDK generateLabel] DPD returned error object:", errorObj);
|
|
598
|
-
const errorMessage = errorObj.errorMessage || errorObj.name || JSON.stringify(errorObj);
|
|
599
|
-
return {
|
|
600
|
-
success: false,
|
|
601
|
-
error: `DPD API error: ${errorMessage}`
|
|
602
|
-
};
|
|
603
|
-
}
|
|
604
|
-
if (!response || typeof response === "object" && !response.data) {
|
|
605
|
-
console.error("\u274C [SDK generateLabel] No label data in response");
|
|
578
|
+
if (!response || typeof response !== "string") {
|
|
606
579
|
return {
|
|
607
580
|
success: false,
|
|
608
581
|
error: "No label data received from DPD"
|
|
609
582
|
};
|
|
610
583
|
}
|
|
611
|
-
const labelData = typeof response === "string" ? response : response.data;
|
|
612
|
-
console.log(`\u2705 [SDK generateLabel] Success! Label data length: ${labelData.length} chars`);
|
|
613
584
|
return {
|
|
614
585
|
success: true,
|
|
615
|
-
labelData
|
|
586
|
+
labelData: response
|
|
616
587
|
};
|
|
617
588
|
} catch (error) {
|
|
618
|
-
console.error("\u{1F4A5} [SDK generateLabel] Exception:", error);
|
|
619
589
|
return {
|
|
620
590
|
success: false,
|
|
621
591
|
error: error instanceof Error ? error.message : "Unknown error"
|
|
@@ -760,7 +730,7 @@ async function createCompleteShipment(orderId, params, config2, dbAdapter, stora
|
|
|
760
730
|
}
|
|
761
731
|
const labelResult = await generateAndUploadLabel(
|
|
762
732
|
shipmentResult.shipmentId,
|
|
763
|
-
|
|
733
|
+
config2.labels.format,
|
|
764
734
|
config2.credentials,
|
|
765
735
|
storageAdapter
|
|
766
736
|
);
|
package/dist/index.mjs
CHANGED
|
@@ -236,10 +236,6 @@ async function authenticatedRequest(credentials, options) {
|
|
|
236
236
|
const isLabelRequest = acceptHeader === "text/vnd.zebra-zpl" || acceptHeader === "text/vnd.citizen-clp" || acceptHeader === "text/vnd.eltron-epl" || acceptHeader === "text/html";
|
|
237
237
|
let data = null;
|
|
238
238
|
if (isLabelRequest) {
|
|
239
|
-
console.log("\u{1F3F7}\uFE0F [SDK auth] Label request detected");
|
|
240
|
-
console.log(` HTTP Status: ${response.status} ${response.statusText}`);
|
|
241
|
-
console.log(` Response length: ${raw.length} chars`);
|
|
242
|
-
console.log(` Response preview (first 300 chars): ${raw.substring(0, 300)}`);
|
|
243
239
|
if (!response.ok) {
|
|
244
240
|
throw new Error(
|
|
245
241
|
`Label request failed: ${response.status} ${response.statusText}`
|
|
@@ -247,20 +243,18 @@ async function authenticatedRequest(credentials, options) {
|
|
|
247
243
|
}
|
|
248
244
|
try {
|
|
249
245
|
const parsed = JSON.parse(raw);
|
|
250
|
-
console.log("\u{1F50D} [SDK auth] Label request - parsed JSON response:", parsed);
|
|
251
246
|
if (parsed?.error || parsed?.data === null) {
|
|
252
|
-
console.log("\u26A0\uFE0F [SDK auth] Detected error response:", {
|
|
253
|
-
hasError: !!parsed?.error,
|
|
254
|
-
dataIsNull: parsed?.data === null,
|
|
255
|
-
errorObj: parsed?.error
|
|
256
|
-
});
|
|
257
247
|
const errorObj = parsed?.error;
|
|
258
248
|
let errorMessage = "Label generation failed";
|
|
259
249
|
let errorCode = "UNKNOWN";
|
|
260
250
|
if (errorObj) {
|
|
261
|
-
if (errorObj
|
|
251
|
+
if (Array.isArray(errorObj)) {
|
|
252
|
+
const firstError = errorObj[0];
|
|
253
|
+
errorMessage = firstError?.errorMessage || errorMessage;
|
|
254
|
+
errorCode = firstError?.errorCode || errorCode;
|
|
255
|
+
} else if (errorObj.errorMessage) {
|
|
262
256
|
errorMessage = errorObj.errorMessage;
|
|
263
|
-
errorCode = errorObj.errorCode || errorObj.name ||
|
|
257
|
+
errorCode = errorObj.errorCode || errorObj.name || errorCode;
|
|
264
258
|
} else if (errorObj.name) {
|
|
265
259
|
errorMessage = errorObj.name;
|
|
266
260
|
errorCode = errorObj.name;
|
|
@@ -271,7 +265,6 @@ async function authenticatedRequest(credentials, options) {
|
|
|
271
265
|
}
|
|
272
266
|
}
|
|
273
267
|
}
|
|
274
|
-
console.error(`\u274C [SDK auth] Throwing error - Code: ${errorCode}, Message: ${errorMessage}`);
|
|
275
268
|
throw new Error(`DPD API Error ${errorCode}: ${errorMessage}`);
|
|
276
269
|
}
|
|
277
270
|
if (parsed?.data) {
|
|
@@ -486,12 +479,7 @@ async function createShipment(credentials, params, businessConfig) {
|
|
|
486
479
|
async function generateLabel(credentials, params) {
|
|
487
480
|
try {
|
|
488
481
|
const { shipmentId, labelFormat } = params;
|
|
489
|
-
console.log("\n\u{1F3F7}\uFE0F [SDK generateLabel] Starting label generation");
|
|
490
|
-
console.log(` Shipment ID: ${shipmentId} (type: ${typeof shipmentId})`);
|
|
491
|
-
console.log(` Format: ${labelFormat}`);
|
|
492
|
-
console.log(` Accept Header: ${getAcceptHeader(labelFormat)}`);
|
|
493
482
|
const endpoint = `${DPD_API.ENDPOINTS.LABEL}/${shipmentId}/label/`;
|
|
494
|
-
console.log(` Endpoint: ${endpoint}`);
|
|
495
483
|
const response = await authenticatedRequest(credentials, {
|
|
496
484
|
method: "GET",
|
|
497
485
|
endpoint,
|
|
@@ -499,35 +487,17 @@ async function generateLabel(credentials, params) {
|
|
|
499
487
|
Accept: getAcceptHeader(labelFormat)
|
|
500
488
|
}
|
|
501
489
|
});
|
|
502
|
-
|
|
503
|
-
console.log(
|
|
504
|
-
"\u{1F4E6} [SDK generateLabel] Raw response:",
|
|
505
|
-
typeof response === "string" ? `String (${response.length} chars): ${response.substring(0, 200)}...` : response
|
|
506
|
-
);
|
|
507
|
-
if (typeof response === "object" && response.error) {
|
|
508
|
-
const errorObj = response.error;
|
|
509
|
-
console.error("\u274C [SDK generateLabel] DPD returned error object:", errorObj);
|
|
510
|
-
const errorMessage = errorObj.errorMessage || errorObj.name || JSON.stringify(errorObj);
|
|
511
|
-
return {
|
|
512
|
-
success: false,
|
|
513
|
-
error: `DPD API error: ${errorMessage}`
|
|
514
|
-
};
|
|
515
|
-
}
|
|
516
|
-
if (!response || typeof response === "object" && !response.data) {
|
|
517
|
-
console.error("\u274C [SDK generateLabel] No label data in response");
|
|
490
|
+
if (!response || typeof response !== "string") {
|
|
518
491
|
return {
|
|
519
492
|
success: false,
|
|
520
493
|
error: "No label data received from DPD"
|
|
521
494
|
};
|
|
522
495
|
}
|
|
523
|
-
const labelData = typeof response === "string" ? response : response.data;
|
|
524
|
-
console.log(`\u2705 [SDK generateLabel] Success! Label data length: ${labelData.length} chars`);
|
|
525
496
|
return {
|
|
526
497
|
success: true,
|
|
527
|
-
labelData
|
|
498
|
+
labelData: response
|
|
528
499
|
};
|
|
529
500
|
} catch (error) {
|
|
530
|
-
console.error("\u{1F4A5} [SDK generateLabel] Exception:", error);
|
|
531
501
|
return {
|
|
532
502
|
success: false,
|
|
533
503
|
error: error instanceof Error ? error.message : "Unknown error"
|
|
@@ -672,7 +642,7 @@ async function createCompleteShipment(orderId, params, config2, dbAdapter, stora
|
|
|
672
642
|
}
|
|
673
643
|
const labelResult = await generateAndUploadLabel(
|
|
674
644
|
shipmentResult.shipmentId,
|
|
675
|
-
|
|
645
|
+
config2.labels.format,
|
|
676
646
|
config2.credentials,
|
|
677
647
|
storageAdapter
|
|
678
648
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jazzdev/dpd-local-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.12",
|
|
4
4
|
"description": "TypeScript SDK for DPD Local shipping API integration - database-agnostic and framework-independent",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
23
23
|
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
24
24
|
"typecheck": "tsc --noEmit",
|
|
25
|
-
"prepublishOnly": "npm run build"
|
|
25
|
+
"prepublishOnly": "npm run build",
|
|
26
|
+
"test:label": "tsx test-label-generation.ts"
|
|
26
27
|
},
|
|
27
28
|
"keywords": [
|
|
28
29
|
"dpd",
|