@jazzdev/dpd-local-sdk 1.0.12 → 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/README.md +18 -23
- package/dist/index.d.mts +36 -25
- package/dist/index.d.ts +36 -25
- package/dist/index.js +188 -119
- package/dist/index.mjs +185 -101
- package/package.json +5 -6
- package/CHANGELOG.md +0 -38
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> TypeScript SDK for integrating DPD Local shipping services into your application. Database-agnostic, framework-independent, and production-ready.
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/@jazzdev/dpd-local-sdk)
|
|
6
6
|
[](https://www.typescriptlang.org/)
|
|
7
7
|
[](https://opensource.org/licenses/MIT)
|
|
8
8
|
|
|
@@ -419,30 +419,25 @@ app.post('/api/shipping/create', async (req, res) => {
|
|
|
419
419
|
});
|
|
420
420
|
```
|
|
421
421
|
|
|
422
|
-
##
|
|
422
|
+
## Configuration
|
|
423
423
|
|
|
424
|
-
|
|
425
|
-
# DPD Credentials (Required)
|
|
426
|
-
DPD_ACCOUNT_NUMBER=your_account_number
|
|
427
|
-
DPD_USERNAME=your_username
|
|
428
|
-
DPD_PASSWORD=your_password
|
|
429
|
-
|
|
430
|
-
# Encryption (Required in production)
|
|
431
|
-
DPD_ENCRYPTION_KEY=your_32_byte_hex_key
|
|
432
|
-
|
|
433
|
-
# Optional
|
|
434
|
-
NODE_ENV=production
|
|
435
|
-
```
|
|
436
|
-
|
|
437
|
-
### Generating Encryption Key
|
|
424
|
+
The SDK requires DPD credentials which you pass directly to the configuration:
|
|
438
425
|
|
|
439
426
|
```typescript
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
427
|
+
const config = createDPDConfig({
|
|
428
|
+
credentials: {
|
|
429
|
+
accountNumber: 'YOUR_ACCOUNT_NUMBER',
|
|
430
|
+
username: 'YOUR_USERNAME',
|
|
431
|
+
password: 'YOUR_PASSWORD',
|
|
432
|
+
},
|
|
433
|
+
business: {
|
|
434
|
+
// Your business details
|
|
435
|
+
}
|
|
436
|
+
});
|
|
444
437
|
```
|
|
445
438
|
|
|
439
|
+
**Important**: Credentials are passed programmatically - the SDK itself doesn't read from environment variables. How you store and retrieve credentials in your application is up to you.
|
|
440
|
+
|
|
446
441
|
## Adapter Examples
|
|
447
442
|
|
|
448
443
|
Complete adapter examples are available in the `examples/` directory:
|
|
@@ -498,7 +493,7 @@ import type {
|
|
|
498
493
|
|
|
499
494
|
## Contributing
|
|
500
495
|
|
|
501
|
-
Contributions are welcome! Please
|
|
496
|
+
Contributions are welcome! Please open an issue or submit a pull request on [GitHub](https://github.com/TheJazzDev/dpd-local-sdk).
|
|
502
497
|
|
|
503
498
|
## License
|
|
504
499
|
|
|
@@ -507,8 +502,8 @@ MIT © [Taiow Babarinde](https://github.com/TheJazzDev)
|
|
|
507
502
|
## Support
|
|
508
503
|
|
|
509
504
|
- 📧 Email: babsman4all@gmail.com
|
|
510
|
-
- 🐛 Issues: [GitHub Issues](https://github.com/TheJazzDev/dpd-local-sdk
|
|
505
|
+
- 🐛 Issues: [GitHub Issues](https://github.com/TheJazzDev/dpd-local-sdk/issues)
|
|
511
506
|
|
|
512
507
|
## Changelog
|
|
513
508
|
|
|
514
|
-
See [CHANGELOG.md](CHANGELOG.md) for release history.
|
|
509
|
+
See [CHANGELOG.md](https://github.com/TheJazzDev/dpd-local-sdk/blob/main/CHANGELOG.md) for release history.
|
package/dist/index.d.mts
CHANGED
|
@@ -316,6 +316,24 @@ interface LogFilters {
|
|
|
316
316
|
endDate?: Date;
|
|
317
317
|
limit?: number;
|
|
318
318
|
}
|
|
319
|
+
interface GeoSessionStorage {
|
|
320
|
+
get(): Promise<{
|
|
321
|
+
geoSession: string;
|
|
322
|
+
expiry: Date;
|
|
323
|
+
} | null>;
|
|
324
|
+
set(geoSession: string, expiry: Date): Promise<void>;
|
|
325
|
+
clear(): Promise<void>;
|
|
326
|
+
}
|
|
327
|
+
declare class InMemoryGeoSessionStorage implements GeoSessionStorage {
|
|
328
|
+
private geoSession;
|
|
329
|
+
private expiry;
|
|
330
|
+
get(): Promise<{
|
|
331
|
+
geoSession: string;
|
|
332
|
+
expiry: Date;
|
|
333
|
+
} | null>;
|
|
334
|
+
set(geoSession: string, expiry: Date): Promise<void>;
|
|
335
|
+
clear(): Promise<void>;
|
|
336
|
+
}
|
|
319
337
|
|
|
320
338
|
declare const DPD_API: {
|
|
321
339
|
readonly BASE_URL: "https://api.dpdlocal.co.uk";
|
|
@@ -408,6 +426,23 @@ declare function testConnection(credentials: DPDCredentials): Promise<{
|
|
|
408
426
|
success: boolean;
|
|
409
427
|
message: string;
|
|
410
428
|
}>;
|
|
429
|
+
declare class GeoSessionManager {
|
|
430
|
+
private credentials;
|
|
431
|
+
private storage;
|
|
432
|
+
private maxRetries;
|
|
433
|
+
private baseRetryDelay;
|
|
434
|
+
constructor(credentials: DPDCredentials, storage?: GeoSessionStorage, options?: {
|
|
435
|
+
maxRetries?: number;
|
|
436
|
+
baseRetryDelay?: number;
|
|
437
|
+
});
|
|
438
|
+
getValidGeoSession(): Promise<string>;
|
|
439
|
+
refreshGeoSession(): Promise<string>;
|
|
440
|
+
clearGeoSession(): Promise<void>;
|
|
441
|
+
private isSessionValid;
|
|
442
|
+
private authenticateWithRetry;
|
|
443
|
+
private authenticate;
|
|
444
|
+
private delay;
|
|
445
|
+
}
|
|
411
446
|
|
|
412
447
|
declare function createShipment(credentials: DPDCredentials, params: CreateShipmentParams, businessConfig: any): Promise<CreateShipmentResult>;
|
|
413
448
|
declare function generateLabel(credentials: DPDCredentials, params: GenerateLabelParams): Promise<GenerateLabelResult>;
|
|
@@ -452,30 +487,6 @@ declare const _default: {
|
|
|
452
487
|
getAuthStatus: typeof getAuthStatus;
|
|
453
488
|
};
|
|
454
489
|
|
|
455
|
-
declare function generateEncryptionKey(): string;
|
|
456
|
-
declare function encrypt(text: string): string;
|
|
457
|
-
declare function decrypt(encryptedHex: string): string;
|
|
458
|
-
declare function encryptCredentials(credentials: {
|
|
459
|
-
accountNumber: string;
|
|
460
|
-
username: string;
|
|
461
|
-
password: string;
|
|
462
|
-
}): {
|
|
463
|
-
accountNumber: string;
|
|
464
|
-
username: string;
|
|
465
|
-
passwordHash: string;
|
|
466
|
-
};
|
|
467
|
-
declare function decryptCredentials(encryptedCredentials: {
|
|
468
|
-
accountNumber: string;
|
|
469
|
-
username: string;
|
|
470
|
-
passwordHash: string;
|
|
471
|
-
}): {
|
|
472
|
-
accountNumber: string;
|
|
473
|
-
username: string;
|
|
474
|
-
password: string;
|
|
475
|
-
};
|
|
476
|
-
declare function hash(data: string): string;
|
|
477
|
-
declare function verifyHash(data: string, hashToVerify: string): boolean;
|
|
478
|
-
|
|
479
490
|
interface LoggerConfig {
|
|
480
491
|
enabled: boolean;
|
|
481
492
|
logToConsole: boolean;
|
|
@@ -522,4 +533,4 @@ declare function loggedOperation<T>(params: {
|
|
|
522
533
|
headers?: Record<string, string>;
|
|
523
534
|
}>): Promise<T>;
|
|
524
535
|
|
|
525
|
-
export { type BusinessConfig, type CreateShipmentParams, type CreateShipmentResult, type DPDAddress, type DPDAuthResponse, type DPDConsignment, type DPDContact, type DPDCredentials, type DPDError, type DPDLabelRequest, type DPDLabelResponse, type DPDLogDocument, type DPDModuleConfig, type DPDParcel, _default as DPDService, type DPDServiceCode, type DPDShipmentRequest, type DPDShipmentResponse, DPD_API, type DatabaseAdapter, type GenerateLabelParams, type GenerateLabelResult, type LabelConfig, type LogFilters, type NotificationConfig, type PricingConfig, SERVICE_DESCRIPTIONS, SERVICE_NAMES, type SavedAddress, type ServiceConfig, type ShipmentStatus, type ShipmentStatusUpdate, type ShippingData, type StorageAdapter, type TimestampType, type TrackShipmentParams, type TrackShipmentResult, type ValidateAddressParams, type ValidateAddressResult, authenticate, authenticatedRequest, calculateDPDCost, calculateDeliveryFee, calculateParcels, clearGeoSession, configureLogger, createCompleteShipment, createDPDConfig, createShipment,
|
|
536
|
+
export { type BusinessConfig, type CreateShipmentParams, type CreateShipmentResult, type DPDAddress, type DPDAuthResponse, type DPDConsignment, type DPDContact, type DPDCredentials, type DPDError, type DPDLabelRequest, type DPDLabelResponse, type DPDLogDocument, type DPDModuleConfig, type DPDParcel, _default as DPDService, type DPDServiceCode, type DPDShipmentRequest, type DPDShipmentResponse, DPD_API, type DatabaseAdapter, type GenerateLabelParams, type GenerateLabelResult, GeoSessionManager, type GeoSessionStorage, InMemoryGeoSessionStorage, type LabelConfig, type LogFilters, type NotificationConfig, type PricingConfig, SERVICE_DESCRIPTIONS, SERVICE_NAMES, type SavedAddress, type ServiceConfig, type ShipmentStatus, type ShipmentStatusUpdate, type ShippingData, type StorageAdapter, type TimestampType, type TrackShipmentParams, type TrackShipmentResult, type ValidateAddressParams, type ValidateAddressResult, authenticate, authenticatedRequest, calculateDPDCost, calculateDeliveryFee, calculateParcels, clearGeoSession, configureLogger, createCompleteShipment, createDPDConfig, createShipment, deleteSavedAddress, generateAndUploadLabel, generateConsignmentRef, generateLabel, getAuthStatus, getEstimatedDeliveryDate, getGeoSession, getLabelUrl, getNextCollectionDate, getSavedAddress, getSavedAddresses, getServiceDescription, getServiceName, getTokenExpiry, getTrackingUrl, hasValidToken, isValidServiceCode, logOperation, loggedOperation, meetsMinimumOrderValue, qualifiesForFreeDelivery, regenerateLabel, saveAddress, setLoggerAdapter, startTimer, testConnection, testDPDConnection, trackShipment, updateSavedAddress, validateAddress, validateDeliveryAddress, validateServiceCode };
|
package/dist/index.d.ts
CHANGED
|
@@ -316,6 +316,24 @@ interface LogFilters {
|
|
|
316
316
|
endDate?: Date;
|
|
317
317
|
limit?: number;
|
|
318
318
|
}
|
|
319
|
+
interface GeoSessionStorage {
|
|
320
|
+
get(): Promise<{
|
|
321
|
+
geoSession: string;
|
|
322
|
+
expiry: Date;
|
|
323
|
+
} | null>;
|
|
324
|
+
set(geoSession: string, expiry: Date): Promise<void>;
|
|
325
|
+
clear(): Promise<void>;
|
|
326
|
+
}
|
|
327
|
+
declare class InMemoryGeoSessionStorage implements GeoSessionStorage {
|
|
328
|
+
private geoSession;
|
|
329
|
+
private expiry;
|
|
330
|
+
get(): Promise<{
|
|
331
|
+
geoSession: string;
|
|
332
|
+
expiry: Date;
|
|
333
|
+
} | null>;
|
|
334
|
+
set(geoSession: string, expiry: Date): Promise<void>;
|
|
335
|
+
clear(): Promise<void>;
|
|
336
|
+
}
|
|
319
337
|
|
|
320
338
|
declare const DPD_API: {
|
|
321
339
|
readonly BASE_URL: "https://api.dpdlocal.co.uk";
|
|
@@ -408,6 +426,23 @@ declare function testConnection(credentials: DPDCredentials): Promise<{
|
|
|
408
426
|
success: boolean;
|
|
409
427
|
message: string;
|
|
410
428
|
}>;
|
|
429
|
+
declare class GeoSessionManager {
|
|
430
|
+
private credentials;
|
|
431
|
+
private storage;
|
|
432
|
+
private maxRetries;
|
|
433
|
+
private baseRetryDelay;
|
|
434
|
+
constructor(credentials: DPDCredentials, storage?: GeoSessionStorage, options?: {
|
|
435
|
+
maxRetries?: number;
|
|
436
|
+
baseRetryDelay?: number;
|
|
437
|
+
});
|
|
438
|
+
getValidGeoSession(): Promise<string>;
|
|
439
|
+
refreshGeoSession(): Promise<string>;
|
|
440
|
+
clearGeoSession(): Promise<void>;
|
|
441
|
+
private isSessionValid;
|
|
442
|
+
private authenticateWithRetry;
|
|
443
|
+
private authenticate;
|
|
444
|
+
private delay;
|
|
445
|
+
}
|
|
411
446
|
|
|
412
447
|
declare function createShipment(credentials: DPDCredentials, params: CreateShipmentParams, businessConfig: any): Promise<CreateShipmentResult>;
|
|
413
448
|
declare function generateLabel(credentials: DPDCredentials, params: GenerateLabelParams): Promise<GenerateLabelResult>;
|
|
@@ -452,30 +487,6 @@ declare const _default: {
|
|
|
452
487
|
getAuthStatus: typeof getAuthStatus;
|
|
453
488
|
};
|
|
454
489
|
|
|
455
|
-
declare function generateEncryptionKey(): string;
|
|
456
|
-
declare function encrypt(text: string): string;
|
|
457
|
-
declare function decrypt(encryptedHex: string): string;
|
|
458
|
-
declare function encryptCredentials(credentials: {
|
|
459
|
-
accountNumber: string;
|
|
460
|
-
username: string;
|
|
461
|
-
password: string;
|
|
462
|
-
}): {
|
|
463
|
-
accountNumber: string;
|
|
464
|
-
username: string;
|
|
465
|
-
passwordHash: string;
|
|
466
|
-
};
|
|
467
|
-
declare function decryptCredentials(encryptedCredentials: {
|
|
468
|
-
accountNumber: string;
|
|
469
|
-
username: string;
|
|
470
|
-
passwordHash: string;
|
|
471
|
-
}): {
|
|
472
|
-
accountNumber: string;
|
|
473
|
-
username: string;
|
|
474
|
-
password: string;
|
|
475
|
-
};
|
|
476
|
-
declare function hash(data: string): string;
|
|
477
|
-
declare function verifyHash(data: string, hashToVerify: string): boolean;
|
|
478
|
-
|
|
479
490
|
interface LoggerConfig {
|
|
480
491
|
enabled: boolean;
|
|
481
492
|
logToConsole: boolean;
|
|
@@ -522,4 +533,4 @@ declare function loggedOperation<T>(params: {
|
|
|
522
533
|
headers?: Record<string, string>;
|
|
523
534
|
}>): Promise<T>;
|
|
524
535
|
|
|
525
|
-
export { type BusinessConfig, type CreateShipmentParams, type CreateShipmentResult, type DPDAddress, type DPDAuthResponse, type DPDConsignment, type DPDContact, type DPDCredentials, type DPDError, type DPDLabelRequest, type DPDLabelResponse, type DPDLogDocument, type DPDModuleConfig, type DPDParcel, _default as DPDService, type DPDServiceCode, type DPDShipmentRequest, type DPDShipmentResponse, DPD_API, type DatabaseAdapter, type GenerateLabelParams, type GenerateLabelResult, type LabelConfig, type LogFilters, type NotificationConfig, type PricingConfig, SERVICE_DESCRIPTIONS, SERVICE_NAMES, type SavedAddress, type ServiceConfig, type ShipmentStatus, type ShipmentStatusUpdate, type ShippingData, type StorageAdapter, type TimestampType, type TrackShipmentParams, type TrackShipmentResult, type ValidateAddressParams, type ValidateAddressResult, authenticate, authenticatedRequest, calculateDPDCost, calculateDeliveryFee, calculateParcels, clearGeoSession, configureLogger, createCompleteShipment, createDPDConfig, createShipment,
|
|
536
|
+
export { type BusinessConfig, type CreateShipmentParams, type CreateShipmentResult, type DPDAddress, type DPDAuthResponse, type DPDConsignment, type DPDContact, type DPDCredentials, type DPDError, type DPDLabelRequest, type DPDLabelResponse, type DPDLogDocument, type DPDModuleConfig, type DPDParcel, _default as DPDService, type DPDServiceCode, type DPDShipmentRequest, type DPDShipmentResponse, DPD_API, type DatabaseAdapter, type GenerateLabelParams, type GenerateLabelResult, GeoSessionManager, type GeoSessionStorage, InMemoryGeoSessionStorage, type LabelConfig, type LogFilters, type NotificationConfig, type PricingConfig, SERVICE_DESCRIPTIONS, SERVICE_NAMES, type SavedAddress, type ServiceConfig, type ShipmentStatus, type ShipmentStatusUpdate, type ShippingData, type StorageAdapter, type TimestampType, type TrackShipmentParams, type TrackShipmentResult, type ValidateAddressParams, type ValidateAddressResult, authenticate, authenticatedRequest, calculateDPDCost, calculateDeliveryFee, calculateParcels, clearGeoSession, configureLogger, createCompleteShipment, createDPDConfig, createShipment, deleteSavedAddress, generateAndUploadLabel, generateConsignmentRef, generateLabel, getAuthStatus, getEstimatedDeliveryDate, getGeoSession, getLabelUrl, getNextCollectionDate, getSavedAddress, getSavedAddresses, getServiceDescription, getServiceName, getTokenExpiry, getTrackingUrl, hasValidToken, isValidServiceCode, logOperation, loggedOperation, meetsMinimumOrderValue, qualifiesForFreeDelivery, regenerateLabel, saveAddress, setLoggerAdapter, startTimer, testConnection, testDPDConnection, trackShipment, updateSavedAddress, validateAddress, validateDeliveryAddress, validateServiceCode };
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __export = (target, all) => {
|
|
9
7
|
for (var name in all)
|
|
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
15
|
}
|
|
18
16
|
return to;
|
|
19
17
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
19
|
|
|
30
20
|
// src/index.ts
|
|
@@ -32,6 +22,8 @@ var index_exports = {};
|
|
|
32
22
|
__export(index_exports, {
|
|
33
23
|
DPDService: () => dpd_service_default,
|
|
34
24
|
DPD_API: () => DPD_API,
|
|
25
|
+
GeoSessionManager: () => GeoSessionManager,
|
|
26
|
+
InMemoryGeoSessionStorage: () => InMemoryGeoSessionStorage,
|
|
35
27
|
SERVICE_DESCRIPTIONS: () => SERVICE_DESCRIPTIONS,
|
|
36
28
|
SERVICE_NAMES: () => SERVICE_NAMES,
|
|
37
29
|
authenticate: () => authenticate,
|
|
@@ -44,14 +36,9 @@ __export(index_exports, {
|
|
|
44
36
|
createCompleteShipment: () => createCompleteShipment,
|
|
45
37
|
createDPDConfig: () => createDPDConfig,
|
|
46
38
|
createShipment: () => createShipment,
|
|
47
|
-
decrypt: () => decrypt,
|
|
48
|
-
decryptCredentials: () => decryptCredentials,
|
|
49
39
|
deleteSavedAddress: () => deleteSavedAddress,
|
|
50
|
-
encrypt: () => encrypt,
|
|
51
|
-
encryptCredentials: () => encryptCredentials,
|
|
52
40
|
generateAndUploadLabel: () => generateAndUploadLabel,
|
|
53
41
|
generateConsignmentRef: () => generateConsignmentRef,
|
|
54
|
-
generateEncryptionKey: () => generateEncryptionKey,
|
|
55
42
|
generateLabel: () => generateLabel,
|
|
56
43
|
getAuthStatus: () => getAuthStatus,
|
|
57
44
|
getEstimatedDeliveryDate: () => getEstimatedDeliveryDate,
|
|
@@ -65,7 +52,6 @@ __export(index_exports, {
|
|
|
65
52
|
getTokenExpiry: () => getTokenExpiry,
|
|
66
53
|
getTrackingUrl: () => getTrackingUrl,
|
|
67
54
|
hasValidToken: () => hasValidToken,
|
|
68
|
-
hash: () => hash,
|
|
69
55
|
isValidServiceCode: () => isValidServiceCode,
|
|
70
56
|
logOperation: () => logOperation,
|
|
71
57
|
loggedOperation: () => loggedOperation,
|
|
@@ -81,11 +67,32 @@ __export(index_exports, {
|
|
|
81
67
|
updateSavedAddress: () => updateSavedAddress,
|
|
82
68
|
validateAddress: () => validateAddress,
|
|
83
69
|
validateDeliveryAddress: () => validateDeliveryAddress,
|
|
84
|
-
validateServiceCode: () => validateServiceCode
|
|
85
|
-
verifyHash: () => verifyHash
|
|
70
|
+
validateServiceCode: () => validateServiceCode
|
|
86
71
|
});
|
|
87
72
|
module.exports = __toCommonJS(index_exports);
|
|
88
73
|
|
|
74
|
+
// src/types/index.ts
|
|
75
|
+
var InMemoryGeoSessionStorage = class {
|
|
76
|
+
constructor() {
|
|
77
|
+
this.geoSession = null;
|
|
78
|
+
this.expiry = null;
|
|
79
|
+
}
|
|
80
|
+
async get() {
|
|
81
|
+
if (!this.geoSession || !this.expiry) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
return { geoSession: this.geoSession, expiry: this.expiry };
|
|
85
|
+
}
|
|
86
|
+
async set(geoSession, expiry) {
|
|
87
|
+
this.geoSession = geoSession;
|
|
88
|
+
this.expiry = expiry;
|
|
89
|
+
}
|
|
90
|
+
async clear() {
|
|
91
|
+
this.geoSession = null;
|
|
92
|
+
this.expiry = null;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
89
96
|
// src/config/index.ts
|
|
90
97
|
var DPD_API = {
|
|
91
98
|
BASE_URL: "https://api.dpdlocal.co.uk",
|
|
@@ -438,6 +445,164 @@ async function testConnection(credentials) {
|
|
|
438
445
|
};
|
|
439
446
|
}
|
|
440
447
|
}
|
|
448
|
+
var GeoSessionManager = class {
|
|
449
|
+
/**
|
|
450
|
+
* Create a new Geo Session Manager
|
|
451
|
+
*
|
|
452
|
+
* @param credentials - DPD API credentials
|
|
453
|
+
* @param storage - Storage adapter for persistence (optional, defaults to in-memory)
|
|
454
|
+
* @param options - Configuration options
|
|
455
|
+
*/
|
|
456
|
+
constructor(credentials, storage, options) {
|
|
457
|
+
this.credentials = credentials;
|
|
458
|
+
this.storage = storage || new InMemoryGeoSessionStorage();
|
|
459
|
+
this.maxRetries = options?.maxRetries ?? 3;
|
|
460
|
+
this.baseRetryDelay = options?.baseRetryDelay ?? 2e3;
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Get a valid geo session token
|
|
464
|
+
*
|
|
465
|
+
* - Loads from persistent storage if available and valid
|
|
466
|
+
* - Automatically refreshes if expired or not found
|
|
467
|
+
* - Retries with exponential backoff on failure
|
|
468
|
+
* - Saves to persistent storage after refresh
|
|
469
|
+
*
|
|
470
|
+
* @returns Valid geo session token
|
|
471
|
+
* @throws Error if authentication fails after retries
|
|
472
|
+
*/
|
|
473
|
+
async getValidGeoSession() {
|
|
474
|
+
try {
|
|
475
|
+
const stored = await this.storage.get();
|
|
476
|
+
if (stored && this.isSessionValid(stored.geoSession, stored.expiry)) {
|
|
477
|
+
console.log("\u2705 Using cached geo session from storage");
|
|
478
|
+
return stored.geoSession;
|
|
479
|
+
}
|
|
480
|
+
console.log("\u{1F504} Fetching new geo session from DPD API...");
|
|
481
|
+
const { geoSession, expiry } = await this.authenticateWithRetry();
|
|
482
|
+
console.log("\u2705 Successfully fetched new geo session");
|
|
483
|
+
await this.storage.set(geoSession, expiry);
|
|
484
|
+
return geoSession;
|
|
485
|
+
} catch (error) {
|
|
486
|
+
console.error("\u274C Error managing geo session:", error);
|
|
487
|
+
throw new Error(
|
|
488
|
+
`Failed to get valid geo session: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Force refresh the geo session
|
|
494
|
+
* Clears cache and fetches a new token
|
|
495
|
+
*
|
|
496
|
+
* @returns New geo session token
|
|
497
|
+
*/
|
|
498
|
+
async refreshGeoSession() {
|
|
499
|
+
await this.storage.clear();
|
|
500
|
+
return this.getValidGeoSession();
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Clear stored geo session
|
|
504
|
+
*/
|
|
505
|
+
async clearGeoSession() {
|
|
506
|
+
await this.storage.clear();
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Check if a session is valid
|
|
510
|
+
*/
|
|
511
|
+
isSessionValid(geoSession, expiry) {
|
|
512
|
+
if (!geoSession || !expiry) {
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
515
|
+
const now = /* @__PURE__ */ new Date();
|
|
516
|
+
const expiryDate = expiry instanceof Date ? expiry : new Date(expiry);
|
|
517
|
+
if (expiryDate <= now) {
|
|
518
|
+
return false;
|
|
519
|
+
}
|
|
520
|
+
const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
521
|
+
const expiryStartOfDay = new Date(
|
|
522
|
+
expiryDate.getFullYear(),
|
|
523
|
+
expiryDate.getMonth(),
|
|
524
|
+
expiryDate.getDate()
|
|
525
|
+
);
|
|
526
|
+
if (expiryStartOfDay.getTime() === startOfToday.getTime()) {
|
|
527
|
+
const sessionCreatedAt = new Date(expiryDate.getTime() - 90 * 60 * 1e3);
|
|
528
|
+
const hoursSinceCreation = (now.getTime() - sessionCreatedAt.getTime()) / (1e3 * 60 * 60);
|
|
529
|
+
if (hoursSinceCreation > 12) {
|
|
530
|
+
return false;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
return true;
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Authenticate with retry logic and exponential backoff
|
|
537
|
+
*/
|
|
538
|
+
async authenticateWithRetry() {
|
|
539
|
+
let lastError = null;
|
|
540
|
+
for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
|
|
541
|
+
try {
|
|
542
|
+
console.log(`\u{1F4E1} Attempt ${attempt}/${this.maxRetries} to fetch geo session...`);
|
|
543
|
+
const geoSession = await this.authenticate();
|
|
544
|
+
const expiry = new Date(Date.now() + 90 * 60 * 1e3);
|
|
545
|
+
return { geoSession, expiry };
|
|
546
|
+
} catch (error) {
|
|
547
|
+
lastError = error;
|
|
548
|
+
console.error(`\u274C Attempt ${attempt}/${this.maxRetries} failed:`, error);
|
|
549
|
+
if (attempt < this.maxRetries) {
|
|
550
|
+
const delay2 = this.baseRetryDelay * Math.pow(2, attempt - 1);
|
|
551
|
+
console.log(`\u23F3 Retrying in ${delay2}ms...`);
|
|
552
|
+
await this.delay(delay2);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
throw new Error(
|
|
557
|
+
`Failed to authenticate after ${this.maxRetries} attempts: ${lastError?.message || "Unknown error"}`
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Authenticate with DPD API
|
|
562
|
+
*/
|
|
563
|
+
async authenticate() {
|
|
564
|
+
const { username, password } = this.credentials;
|
|
565
|
+
const authHeader = Buffer.from(`${username}:${password}`).toString("base64");
|
|
566
|
+
const response = await fetch(`${DPD_API.BASE_URL}${DPD_API.ENDPOINTS.AUTH}`, {
|
|
567
|
+
method: "POST",
|
|
568
|
+
headers: {
|
|
569
|
+
"Content-Type": "application/json",
|
|
570
|
+
Accept: "application/json",
|
|
571
|
+
Authorization: `Basic ${authHeader}`
|
|
572
|
+
},
|
|
573
|
+
signal: AbortSignal.timeout(DPD_API.TIMEOUT)
|
|
574
|
+
});
|
|
575
|
+
const raw = await response.text();
|
|
576
|
+
let payload;
|
|
577
|
+
try {
|
|
578
|
+
payload = raw ? JSON.parse(raw) : null;
|
|
579
|
+
} catch {
|
|
580
|
+
if (!response.ok) {
|
|
581
|
+
throw new Error(`Authentication failed: ${raw || response.statusText}`);
|
|
582
|
+
}
|
|
583
|
+
throw new Error("Invalid JSON response from DPD API");
|
|
584
|
+
}
|
|
585
|
+
if (!response.ok) {
|
|
586
|
+
throw new Error(
|
|
587
|
+
payload?.error?.errorMessage ?? `Authentication failed: ${response.status} ${response.statusText}`
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
if (payload?.error) {
|
|
591
|
+
throw new Error(payload.error.errorMessage ?? "Authentication failed");
|
|
592
|
+
}
|
|
593
|
+
const geoSession = payload?.data?.geoSession;
|
|
594
|
+
if (!geoSession) {
|
|
595
|
+
throw new Error("No GeoSession token received from DPD");
|
|
596
|
+
}
|
|
597
|
+
return geoSession;
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Delay helper for retry backoff
|
|
601
|
+
*/
|
|
602
|
+
delay(ms) {
|
|
603
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
604
|
+
}
|
|
605
|
+
};
|
|
441
606
|
|
|
442
607
|
// src/utils/getAcceptHeader.ts
|
|
443
608
|
function getAcceptHeader(format) {
|
|
@@ -923,97 +1088,6 @@ var dpd_service_default = {
|
|
|
923
1088
|
getAuthStatus
|
|
924
1089
|
};
|
|
925
1090
|
|
|
926
|
-
// src/utils/encryption.ts
|
|
927
|
-
var import_crypto = __toESM(require("crypto"));
|
|
928
|
-
var ALGORITHM = "aes-256-gcm";
|
|
929
|
-
var KEY_LENGTH = 32;
|
|
930
|
-
var IV_LENGTH = 16;
|
|
931
|
-
var SALT_LENGTH = 64;
|
|
932
|
-
var TAG_LENGTH = 16;
|
|
933
|
-
var TAG_POSITION = SALT_LENGTH + IV_LENGTH;
|
|
934
|
-
var ENCRYPTED_POSITION = TAG_POSITION + TAG_LENGTH;
|
|
935
|
-
function getEncryptionKey() {
|
|
936
|
-
const envKey = process.env.DPD_ENCRYPTION_KEY;
|
|
937
|
-
if (envKey) {
|
|
938
|
-
return Buffer.from(envKey, "hex");
|
|
939
|
-
}
|
|
940
|
-
if (process.env.NODE_ENV !== "production") {
|
|
941
|
-
console.warn(
|
|
942
|
-
"\u26A0\uFE0F Using default encryption key. Set DPD_ENCRYPTION_KEY in production!"
|
|
943
|
-
);
|
|
944
|
-
return import_crypto.default.scryptSync("dpd-dev-key", "salt", KEY_LENGTH);
|
|
945
|
-
}
|
|
946
|
-
throw new Error(
|
|
947
|
-
"DPD_ENCRYPTION_KEY environment variable is required in production"
|
|
948
|
-
);
|
|
949
|
-
}
|
|
950
|
-
function generateEncryptionKey() {
|
|
951
|
-
const key = import_crypto.default.randomBytes(KEY_LENGTH);
|
|
952
|
-
return key.toString("hex");
|
|
953
|
-
}
|
|
954
|
-
function encrypt(text) {
|
|
955
|
-
try {
|
|
956
|
-
const salt = import_crypto.default.randomBytes(SALT_LENGTH);
|
|
957
|
-
const iv = import_crypto.default.randomBytes(IV_LENGTH);
|
|
958
|
-
const key = import_crypto.default.scryptSync(getEncryptionKey(), salt, KEY_LENGTH);
|
|
959
|
-
const cipher = import_crypto.default.createCipheriv(ALGORITHM, key, iv);
|
|
960
|
-
const encrypted = Buffer.concat([
|
|
961
|
-
cipher.update(text, "utf8"),
|
|
962
|
-
cipher.final()
|
|
963
|
-
]);
|
|
964
|
-
const tag = cipher.getAuthTag();
|
|
965
|
-
const result = Buffer.concat([salt, iv, tag, encrypted]);
|
|
966
|
-
return result.toString("hex");
|
|
967
|
-
} catch (error) {
|
|
968
|
-
console.error("Encryption error:", error);
|
|
969
|
-
throw new Error("Failed to encrypt data");
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
function decrypt(encryptedHex) {
|
|
973
|
-
try {
|
|
974
|
-
const data = Buffer.from(encryptedHex, "hex");
|
|
975
|
-
const salt = data.subarray(0, SALT_LENGTH);
|
|
976
|
-
const iv = data.subarray(SALT_LENGTH, TAG_POSITION);
|
|
977
|
-
const tag = data.subarray(TAG_POSITION, ENCRYPTED_POSITION);
|
|
978
|
-
const encrypted = data.subarray(ENCRYPTED_POSITION);
|
|
979
|
-
const key = import_crypto.default.scryptSync(getEncryptionKey(), salt, KEY_LENGTH);
|
|
980
|
-
const decipher = import_crypto.default.createDecipheriv(ALGORITHM, key, iv);
|
|
981
|
-
decipher.setAuthTag(tag);
|
|
982
|
-
const decrypted = Buffer.concat([
|
|
983
|
-
decipher.update(encrypted),
|
|
984
|
-
decipher.final()
|
|
985
|
-
]);
|
|
986
|
-
return decrypted.toString("utf8");
|
|
987
|
-
} catch (error) {
|
|
988
|
-
console.error("Decryption error:", error);
|
|
989
|
-
throw new Error("Failed to decrypt data");
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
function encryptCredentials(credentials) {
|
|
993
|
-
return {
|
|
994
|
-
accountNumber: credentials.accountNumber,
|
|
995
|
-
username: credentials.username,
|
|
996
|
-
passwordHash: encrypt(credentials.password)
|
|
997
|
-
};
|
|
998
|
-
}
|
|
999
|
-
function decryptCredentials(encryptedCredentials) {
|
|
1000
|
-
return {
|
|
1001
|
-
accountNumber: encryptedCredentials.accountNumber,
|
|
1002
|
-
username: encryptedCredentials.username,
|
|
1003
|
-
password: decrypt(encryptedCredentials.passwordHash)
|
|
1004
|
-
};
|
|
1005
|
-
}
|
|
1006
|
-
function hash(data) {
|
|
1007
|
-
return import_crypto.default.createHash("sha256").update(data).digest("hex");
|
|
1008
|
-
}
|
|
1009
|
-
function verifyHash(data, hashToVerify) {
|
|
1010
|
-
const computed = hash(data);
|
|
1011
|
-
return import_crypto.default.timingSafeEqual(
|
|
1012
|
-
Buffer.from(computed),
|
|
1013
|
-
Buffer.from(hashToVerify)
|
|
1014
|
-
);
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
1091
|
// src/utils/logger.ts
|
|
1018
1092
|
var defaultConfig = {
|
|
1019
1093
|
enabled: true,
|
|
@@ -1181,6 +1255,8 @@ function logToConsole(logData) {
|
|
|
1181
1255
|
0 && (module.exports = {
|
|
1182
1256
|
DPDService,
|
|
1183
1257
|
DPD_API,
|
|
1258
|
+
GeoSessionManager,
|
|
1259
|
+
InMemoryGeoSessionStorage,
|
|
1184
1260
|
SERVICE_DESCRIPTIONS,
|
|
1185
1261
|
SERVICE_NAMES,
|
|
1186
1262
|
authenticate,
|
|
@@ -1193,14 +1269,9 @@ function logToConsole(logData) {
|
|
|
1193
1269
|
createCompleteShipment,
|
|
1194
1270
|
createDPDConfig,
|
|
1195
1271
|
createShipment,
|
|
1196
|
-
decrypt,
|
|
1197
|
-
decryptCredentials,
|
|
1198
1272
|
deleteSavedAddress,
|
|
1199
|
-
encrypt,
|
|
1200
|
-
encryptCredentials,
|
|
1201
1273
|
generateAndUploadLabel,
|
|
1202
1274
|
generateConsignmentRef,
|
|
1203
|
-
generateEncryptionKey,
|
|
1204
1275
|
generateLabel,
|
|
1205
1276
|
getAuthStatus,
|
|
1206
1277
|
getEstimatedDeliveryDate,
|
|
@@ -1214,7 +1285,6 @@ function logToConsole(logData) {
|
|
|
1214
1285
|
getTokenExpiry,
|
|
1215
1286
|
getTrackingUrl,
|
|
1216
1287
|
hasValidToken,
|
|
1217
|
-
hash,
|
|
1218
1288
|
isValidServiceCode,
|
|
1219
1289
|
logOperation,
|
|
1220
1290
|
loggedOperation,
|
|
@@ -1230,8 +1300,7 @@ function logToConsole(logData) {
|
|
|
1230
1300
|
updateSavedAddress,
|
|
1231
1301
|
validateAddress,
|
|
1232
1302
|
validateDeliveryAddress,
|
|
1233
|
-
validateServiceCode
|
|
1234
|
-
verifyHash
|
|
1303
|
+
validateServiceCode
|
|
1235
1304
|
});
|
|
1236
1305
|
/**
|
|
1237
1306
|
* DPD Local SDK
|
|
@@ -1240,7 +1309,7 @@ function logToConsole(logData) {
|
|
|
1240
1309
|
* Database-agnostic and framework-independent
|
|
1241
1310
|
*
|
|
1242
1311
|
* @package @jazzdev/dpd-local-sdk
|
|
1243
|
-
* @version 1.
|
|
1244
|
-
* @author
|
|
1312
|
+
* @version 1.1.0
|
|
1313
|
+
* @author Taiow Babarinde <babsman4all@gmail.com>
|
|
1245
1314
|
* @license MIT
|
|
1246
1315
|
*/
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
// src/types/index.ts
|
|
2
|
+
var InMemoryGeoSessionStorage = class {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.geoSession = null;
|
|
5
|
+
this.expiry = null;
|
|
6
|
+
}
|
|
7
|
+
async get() {
|
|
8
|
+
if (!this.geoSession || !this.expiry) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
return { geoSession: this.geoSession, expiry: this.expiry };
|
|
12
|
+
}
|
|
13
|
+
async set(geoSession, expiry) {
|
|
14
|
+
this.geoSession = geoSession;
|
|
15
|
+
this.expiry = expiry;
|
|
16
|
+
}
|
|
17
|
+
async clear() {
|
|
18
|
+
this.geoSession = null;
|
|
19
|
+
this.expiry = null;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
1
23
|
// src/config/index.ts
|
|
2
24
|
var DPD_API = {
|
|
3
25
|
BASE_URL: "https://api.dpdlocal.co.uk",
|
|
@@ -350,6 +372,164 @@ async function testConnection(credentials) {
|
|
|
350
372
|
};
|
|
351
373
|
}
|
|
352
374
|
}
|
|
375
|
+
var GeoSessionManager = class {
|
|
376
|
+
/**
|
|
377
|
+
* Create a new Geo Session Manager
|
|
378
|
+
*
|
|
379
|
+
* @param credentials - DPD API credentials
|
|
380
|
+
* @param storage - Storage adapter for persistence (optional, defaults to in-memory)
|
|
381
|
+
* @param options - Configuration options
|
|
382
|
+
*/
|
|
383
|
+
constructor(credentials, storage, options) {
|
|
384
|
+
this.credentials = credentials;
|
|
385
|
+
this.storage = storage || new InMemoryGeoSessionStorage();
|
|
386
|
+
this.maxRetries = options?.maxRetries ?? 3;
|
|
387
|
+
this.baseRetryDelay = options?.baseRetryDelay ?? 2e3;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Get a valid geo session token
|
|
391
|
+
*
|
|
392
|
+
* - Loads from persistent storage if available and valid
|
|
393
|
+
* - Automatically refreshes if expired or not found
|
|
394
|
+
* - Retries with exponential backoff on failure
|
|
395
|
+
* - Saves to persistent storage after refresh
|
|
396
|
+
*
|
|
397
|
+
* @returns Valid geo session token
|
|
398
|
+
* @throws Error if authentication fails after retries
|
|
399
|
+
*/
|
|
400
|
+
async getValidGeoSession() {
|
|
401
|
+
try {
|
|
402
|
+
const stored = await this.storage.get();
|
|
403
|
+
if (stored && this.isSessionValid(stored.geoSession, stored.expiry)) {
|
|
404
|
+
console.log("\u2705 Using cached geo session from storage");
|
|
405
|
+
return stored.geoSession;
|
|
406
|
+
}
|
|
407
|
+
console.log("\u{1F504} Fetching new geo session from DPD API...");
|
|
408
|
+
const { geoSession, expiry } = await this.authenticateWithRetry();
|
|
409
|
+
console.log("\u2705 Successfully fetched new geo session");
|
|
410
|
+
await this.storage.set(geoSession, expiry);
|
|
411
|
+
return geoSession;
|
|
412
|
+
} catch (error) {
|
|
413
|
+
console.error("\u274C Error managing geo session:", error);
|
|
414
|
+
throw new Error(
|
|
415
|
+
`Failed to get valid geo session: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Force refresh the geo session
|
|
421
|
+
* Clears cache and fetches a new token
|
|
422
|
+
*
|
|
423
|
+
* @returns New geo session token
|
|
424
|
+
*/
|
|
425
|
+
async refreshGeoSession() {
|
|
426
|
+
await this.storage.clear();
|
|
427
|
+
return this.getValidGeoSession();
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Clear stored geo session
|
|
431
|
+
*/
|
|
432
|
+
async clearGeoSession() {
|
|
433
|
+
await this.storage.clear();
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Check if a session is valid
|
|
437
|
+
*/
|
|
438
|
+
isSessionValid(geoSession, expiry) {
|
|
439
|
+
if (!geoSession || !expiry) {
|
|
440
|
+
return false;
|
|
441
|
+
}
|
|
442
|
+
const now = /* @__PURE__ */ new Date();
|
|
443
|
+
const expiryDate = expiry instanceof Date ? expiry : new Date(expiry);
|
|
444
|
+
if (expiryDate <= now) {
|
|
445
|
+
return false;
|
|
446
|
+
}
|
|
447
|
+
const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
448
|
+
const expiryStartOfDay = new Date(
|
|
449
|
+
expiryDate.getFullYear(),
|
|
450
|
+
expiryDate.getMonth(),
|
|
451
|
+
expiryDate.getDate()
|
|
452
|
+
);
|
|
453
|
+
if (expiryStartOfDay.getTime() === startOfToday.getTime()) {
|
|
454
|
+
const sessionCreatedAt = new Date(expiryDate.getTime() - 90 * 60 * 1e3);
|
|
455
|
+
const hoursSinceCreation = (now.getTime() - sessionCreatedAt.getTime()) / (1e3 * 60 * 60);
|
|
456
|
+
if (hoursSinceCreation > 12) {
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return true;
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Authenticate with retry logic and exponential backoff
|
|
464
|
+
*/
|
|
465
|
+
async authenticateWithRetry() {
|
|
466
|
+
let lastError = null;
|
|
467
|
+
for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
|
|
468
|
+
try {
|
|
469
|
+
console.log(`\u{1F4E1} Attempt ${attempt}/${this.maxRetries} to fetch geo session...`);
|
|
470
|
+
const geoSession = await this.authenticate();
|
|
471
|
+
const expiry = new Date(Date.now() + 90 * 60 * 1e3);
|
|
472
|
+
return { geoSession, expiry };
|
|
473
|
+
} catch (error) {
|
|
474
|
+
lastError = error;
|
|
475
|
+
console.error(`\u274C Attempt ${attempt}/${this.maxRetries} failed:`, error);
|
|
476
|
+
if (attempt < this.maxRetries) {
|
|
477
|
+
const delay2 = this.baseRetryDelay * Math.pow(2, attempt - 1);
|
|
478
|
+
console.log(`\u23F3 Retrying in ${delay2}ms...`);
|
|
479
|
+
await this.delay(delay2);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
throw new Error(
|
|
484
|
+
`Failed to authenticate after ${this.maxRetries} attempts: ${lastError?.message || "Unknown error"}`
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Authenticate with DPD API
|
|
489
|
+
*/
|
|
490
|
+
async authenticate() {
|
|
491
|
+
const { username, password } = this.credentials;
|
|
492
|
+
const authHeader = Buffer.from(`${username}:${password}`).toString("base64");
|
|
493
|
+
const response = await fetch(`${DPD_API.BASE_URL}${DPD_API.ENDPOINTS.AUTH}`, {
|
|
494
|
+
method: "POST",
|
|
495
|
+
headers: {
|
|
496
|
+
"Content-Type": "application/json",
|
|
497
|
+
Accept: "application/json",
|
|
498
|
+
Authorization: `Basic ${authHeader}`
|
|
499
|
+
},
|
|
500
|
+
signal: AbortSignal.timeout(DPD_API.TIMEOUT)
|
|
501
|
+
});
|
|
502
|
+
const raw = await response.text();
|
|
503
|
+
let payload;
|
|
504
|
+
try {
|
|
505
|
+
payload = raw ? JSON.parse(raw) : null;
|
|
506
|
+
} catch {
|
|
507
|
+
if (!response.ok) {
|
|
508
|
+
throw new Error(`Authentication failed: ${raw || response.statusText}`);
|
|
509
|
+
}
|
|
510
|
+
throw new Error("Invalid JSON response from DPD API");
|
|
511
|
+
}
|
|
512
|
+
if (!response.ok) {
|
|
513
|
+
throw new Error(
|
|
514
|
+
payload?.error?.errorMessage ?? `Authentication failed: ${response.status} ${response.statusText}`
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
if (payload?.error) {
|
|
518
|
+
throw new Error(payload.error.errorMessage ?? "Authentication failed");
|
|
519
|
+
}
|
|
520
|
+
const geoSession = payload?.data?.geoSession;
|
|
521
|
+
if (!geoSession) {
|
|
522
|
+
throw new Error("No GeoSession token received from DPD");
|
|
523
|
+
}
|
|
524
|
+
return geoSession;
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Delay helper for retry backoff
|
|
528
|
+
*/
|
|
529
|
+
delay(ms) {
|
|
530
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
531
|
+
}
|
|
532
|
+
};
|
|
353
533
|
|
|
354
534
|
// src/utils/getAcceptHeader.ts
|
|
355
535
|
function getAcceptHeader(format) {
|
|
@@ -835,97 +1015,6 @@ var dpd_service_default = {
|
|
|
835
1015
|
getAuthStatus
|
|
836
1016
|
};
|
|
837
1017
|
|
|
838
|
-
// src/utils/encryption.ts
|
|
839
|
-
import crypto from "crypto";
|
|
840
|
-
var ALGORITHM = "aes-256-gcm";
|
|
841
|
-
var KEY_LENGTH = 32;
|
|
842
|
-
var IV_LENGTH = 16;
|
|
843
|
-
var SALT_LENGTH = 64;
|
|
844
|
-
var TAG_LENGTH = 16;
|
|
845
|
-
var TAG_POSITION = SALT_LENGTH + IV_LENGTH;
|
|
846
|
-
var ENCRYPTED_POSITION = TAG_POSITION + TAG_LENGTH;
|
|
847
|
-
function getEncryptionKey() {
|
|
848
|
-
const envKey = process.env.DPD_ENCRYPTION_KEY;
|
|
849
|
-
if (envKey) {
|
|
850
|
-
return Buffer.from(envKey, "hex");
|
|
851
|
-
}
|
|
852
|
-
if (process.env.NODE_ENV !== "production") {
|
|
853
|
-
console.warn(
|
|
854
|
-
"\u26A0\uFE0F Using default encryption key. Set DPD_ENCRYPTION_KEY in production!"
|
|
855
|
-
);
|
|
856
|
-
return crypto.scryptSync("dpd-dev-key", "salt", KEY_LENGTH);
|
|
857
|
-
}
|
|
858
|
-
throw new Error(
|
|
859
|
-
"DPD_ENCRYPTION_KEY environment variable is required in production"
|
|
860
|
-
);
|
|
861
|
-
}
|
|
862
|
-
function generateEncryptionKey() {
|
|
863
|
-
const key = crypto.randomBytes(KEY_LENGTH);
|
|
864
|
-
return key.toString("hex");
|
|
865
|
-
}
|
|
866
|
-
function encrypt(text) {
|
|
867
|
-
try {
|
|
868
|
-
const salt = crypto.randomBytes(SALT_LENGTH);
|
|
869
|
-
const iv = crypto.randomBytes(IV_LENGTH);
|
|
870
|
-
const key = crypto.scryptSync(getEncryptionKey(), salt, KEY_LENGTH);
|
|
871
|
-
const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
|
|
872
|
-
const encrypted = Buffer.concat([
|
|
873
|
-
cipher.update(text, "utf8"),
|
|
874
|
-
cipher.final()
|
|
875
|
-
]);
|
|
876
|
-
const tag = cipher.getAuthTag();
|
|
877
|
-
const result = Buffer.concat([salt, iv, tag, encrypted]);
|
|
878
|
-
return result.toString("hex");
|
|
879
|
-
} catch (error) {
|
|
880
|
-
console.error("Encryption error:", error);
|
|
881
|
-
throw new Error("Failed to encrypt data");
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
function decrypt(encryptedHex) {
|
|
885
|
-
try {
|
|
886
|
-
const data = Buffer.from(encryptedHex, "hex");
|
|
887
|
-
const salt = data.subarray(0, SALT_LENGTH);
|
|
888
|
-
const iv = data.subarray(SALT_LENGTH, TAG_POSITION);
|
|
889
|
-
const tag = data.subarray(TAG_POSITION, ENCRYPTED_POSITION);
|
|
890
|
-
const encrypted = data.subarray(ENCRYPTED_POSITION);
|
|
891
|
-
const key = crypto.scryptSync(getEncryptionKey(), salt, KEY_LENGTH);
|
|
892
|
-
const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
|
|
893
|
-
decipher.setAuthTag(tag);
|
|
894
|
-
const decrypted = Buffer.concat([
|
|
895
|
-
decipher.update(encrypted),
|
|
896
|
-
decipher.final()
|
|
897
|
-
]);
|
|
898
|
-
return decrypted.toString("utf8");
|
|
899
|
-
} catch (error) {
|
|
900
|
-
console.error("Decryption error:", error);
|
|
901
|
-
throw new Error("Failed to decrypt data");
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
function encryptCredentials(credentials) {
|
|
905
|
-
return {
|
|
906
|
-
accountNumber: credentials.accountNumber,
|
|
907
|
-
username: credentials.username,
|
|
908
|
-
passwordHash: encrypt(credentials.password)
|
|
909
|
-
};
|
|
910
|
-
}
|
|
911
|
-
function decryptCredentials(encryptedCredentials) {
|
|
912
|
-
return {
|
|
913
|
-
accountNumber: encryptedCredentials.accountNumber,
|
|
914
|
-
username: encryptedCredentials.username,
|
|
915
|
-
password: decrypt(encryptedCredentials.passwordHash)
|
|
916
|
-
};
|
|
917
|
-
}
|
|
918
|
-
function hash(data) {
|
|
919
|
-
return crypto.createHash("sha256").update(data).digest("hex");
|
|
920
|
-
}
|
|
921
|
-
function verifyHash(data, hashToVerify) {
|
|
922
|
-
const computed = hash(data);
|
|
923
|
-
return crypto.timingSafeEqual(
|
|
924
|
-
Buffer.from(computed),
|
|
925
|
-
Buffer.from(hashToVerify)
|
|
926
|
-
);
|
|
927
|
-
}
|
|
928
|
-
|
|
929
1018
|
// src/utils/logger.ts
|
|
930
1019
|
var defaultConfig = {
|
|
931
1020
|
enabled: true,
|
|
@@ -1092,6 +1181,8 @@ function logToConsole(logData) {
|
|
|
1092
1181
|
export {
|
|
1093
1182
|
dpd_service_default as DPDService,
|
|
1094
1183
|
DPD_API,
|
|
1184
|
+
GeoSessionManager,
|
|
1185
|
+
InMemoryGeoSessionStorage,
|
|
1095
1186
|
SERVICE_DESCRIPTIONS,
|
|
1096
1187
|
SERVICE_NAMES,
|
|
1097
1188
|
authenticate,
|
|
@@ -1104,14 +1195,9 @@ export {
|
|
|
1104
1195
|
createCompleteShipment,
|
|
1105
1196
|
createDPDConfig,
|
|
1106
1197
|
createShipment,
|
|
1107
|
-
decrypt,
|
|
1108
|
-
decryptCredentials,
|
|
1109
1198
|
deleteSavedAddress,
|
|
1110
|
-
encrypt,
|
|
1111
|
-
encryptCredentials,
|
|
1112
1199
|
generateAndUploadLabel,
|
|
1113
1200
|
generateConsignmentRef,
|
|
1114
|
-
generateEncryptionKey,
|
|
1115
1201
|
generateLabel,
|
|
1116
1202
|
getAuthStatus,
|
|
1117
1203
|
getEstimatedDeliveryDate,
|
|
@@ -1125,7 +1211,6 @@ export {
|
|
|
1125
1211
|
getTokenExpiry,
|
|
1126
1212
|
getTrackingUrl,
|
|
1127
1213
|
hasValidToken,
|
|
1128
|
-
hash,
|
|
1129
1214
|
isValidServiceCode,
|
|
1130
1215
|
logOperation,
|
|
1131
1216
|
loggedOperation,
|
|
@@ -1141,8 +1226,7 @@ export {
|
|
|
1141
1226
|
updateSavedAddress,
|
|
1142
1227
|
validateAddress,
|
|
1143
1228
|
validateDeliveryAddress,
|
|
1144
|
-
validateServiceCode
|
|
1145
|
-
verifyHash
|
|
1229
|
+
validateServiceCode
|
|
1146
1230
|
};
|
|
1147
1231
|
/**
|
|
1148
1232
|
* DPD Local SDK
|
|
@@ -1151,7 +1235,7 @@ export {
|
|
|
1151
1235
|
* Database-agnostic and framework-independent
|
|
1152
1236
|
*
|
|
1153
1237
|
* @package @jazzdev/dpd-local-sdk
|
|
1154
|
-
* @version 1.
|
|
1155
|
-
* @author
|
|
1238
|
+
* @version 1.1.0
|
|
1239
|
+
* @author Taiow Babarinde <babsman4all@gmail.com>
|
|
1156
1240
|
* @license MIT
|
|
1157
1241
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jazzdev/dpd-local-sdk",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
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",
|
|
@@ -15,8 +15,7 @@
|
|
|
15
15
|
"files": [
|
|
16
16
|
"dist",
|
|
17
17
|
"README.md",
|
|
18
|
-
"LICENSE"
|
|
19
|
-
"CHANGELOG.md"
|
|
18
|
+
"LICENSE"
|
|
20
19
|
],
|
|
21
20
|
"scripts": {
|
|
22
21
|
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
@@ -43,12 +42,12 @@
|
|
|
43
42
|
"license": "MIT",
|
|
44
43
|
"repository": {
|
|
45
44
|
"type": "git",
|
|
46
|
-
"url": "https://github.com/TheJazzDev/dpd-local-sdk
|
|
45
|
+
"url": "https://github.com/TheJazzDev/dpd-local-sdk"
|
|
47
46
|
},
|
|
48
47
|
"bugs": {
|
|
49
|
-
"url": "https://github.com/TheJazzDev/dpd-local-sdk
|
|
48
|
+
"url": "https://github.com/TheJazzDev/dpd-local-sdk/issues"
|
|
50
49
|
},
|
|
51
|
-
"homepage": "https://github.com/TheJazzDev/dpd-local-sdk
|
|
50
|
+
"homepage": "https://github.com/TheJazzDev/dpd-local-sdk#readme",
|
|
52
51
|
"devDependencies": {
|
|
53
52
|
"@types/node": "^20.0.0",
|
|
54
53
|
"dotenv": "^17.2.3",
|
package/CHANGELOG.md
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
|
|
5
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
-
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
-
|
|
8
|
-
## [1.0.0] - 2024-01-04
|
|
9
|
-
|
|
10
|
-
### Added
|
|
11
|
-
- Initial release of DPD Local SDK
|
|
12
|
-
- Complete DPD API integration (authentication, shipments, labels, tracking)
|
|
13
|
-
- Database-agnostic adapter pattern
|
|
14
|
-
- TypeScript-first design with full type definitions
|
|
15
|
-
- Address validation using postcodes.io API
|
|
16
|
-
- Automatic token management and caching
|
|
17
|
-
- Request retry logic with exponential backoff
|
|
18
|
-
- Comprehensive error handling
|
|
19
|
-
- Detailed logging system
|
|
20
|
-
- Encryption utilities for sensitive data
|
|
21
|
-
- Configuration factory function
|
|
22
|
-
- Helper functions for pricing, dates, and tracking
|
|
23
|
-
- Example adapters for Firestore and Firebase Storage
|
|
24
|
-
- Complete documentation and usage examples
|
|
25
|
-
|
|
26
|
-
### Features
|
|
27
|
-
- ✅ Create shipments with DPD
|
|
28
|
-
- ✅ Generate and upload shipping labels (thermal/A4)
|
|
29
|
-
- ✅ Validate UK delivery addresses
|
|
30
|
-
- ✅ Save and manage customer addresses
|
|
31
|
-
- ✅ Calculate shipping costs and delivery fees
|
|
32
|
-
- ✅ Track shipments
|
|
33
|
-
- ✅ Multi-parcel support
|
|
34
|
-
- ✅ Service selection (Next Day, By 12 PM)
|
|
35
|
-
- ✅ Customer notifications (email, SMS via DPD)
|
|
36
|
-
- ✅ Comprehensive logging and audit trail
|
|
37
|
-
|
|
38
|
-
[1.0.0]: https://github.com/your-org/dpd-local-sdk/releases/tag/v1.0.0
|