@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 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
- [![npm version](https://badge.fury.io/js/%40your-org%2Fdpd-local-sdk.svg)](https://www.npmjs.com/package/@jazzdev/dpd-local-sdk)
5
+ [![npm version](https://badge.fury.io/js/%40jazzdev%2Fdpd-local-sdk.svg)](https://www.npmjs.com/package/@jazzdev/dpd-local-sdk)
6
6
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.3+-blue.svg)](https://www.typescriptlang.org/)
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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
- ## Environment Variables
422
+ ## Configuration
423
423
 
424
- ```env
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
- import { generateEncryptionKey } from '@jazzdev/dpd-local-sdk';
441
-
442
- const key = generateEncryptionKey();
443
- console.log('DPD_ENCRYPTION_KEY=' + key);
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 read [CONTRIBUTING.md](CONTRIBUTING.md) for details.
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.git/issues)
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, decrypt, decryptCredentials, deleteSavedAddress, encrypt, encryptCredentials, generateAndUploadLabel, generateConsignmentRef, generateEncryptionKey, generateLabel, getAuthStatus, getEstimatedDeliveryDate, getGeoSession, getLabelUrl, getNextCollectionDate, getSavedAddress, getSavedAddresses, getServiceDescription, getServiceName, getTokenExpiry, getTrackingUrl, hasValidToken, hash, isValidServiceCode, logOperation, loggedOperation, meetsMinimumOrderValue, qualifiesForFreeDelivery, regenerateLabel, saveAddress, setLoggerAdapter, startTimer, testConnection, testDPDConnection, trackShipment, updateSavedAddress, validateAddress, validateDeliveryAddress, validateServiceCode, verifyHash };
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, decrypt, decryptCredentials, deleteSavedAddress, encrypt, encryptCredentials, generateAndUploadLabel, generateConsignmentRef, generateEncryptionKey, generateLabel, getAuthStatus, getEstimatedDeliveryDate, getGeoSession, getLabelUrl, getNextCollectionDate, getSavedAddress, getSavedAddresses, getServiceDescription, getServiceName, getTokenExpiry, getTrackingUrl, hasValidToken, hash, isValidServiceCode, logOperation, loggedOperation, meetsMinimumOrderValue, qualifiesForFreeDelivery, regenerateLabel, saveAddress, setLoggerAdapter, startTimer, testConnection, testDPDConnection, trackShipment, updateSavedAddress, validateAddress, validateDeliveryAddress, validateServiceCode, verifyHash };
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.0.0
1244
- * @author Your Name
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.0.0
1155
- * @author Your Name
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.12",
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.git"
45
+ "url": "https://github.com/TheJazzDev/dpd-local-sdk"
47
46
  },
48
47
  "bugs": {
49
- "url": "https://github.com/TheJazzDev/dpd-local-sdk.git/issues"
48
+ "url": "https://github.com/TheJazzDev/dpd-local-sdk/issues"
50
49
  },
51
- "homepage": "https://github.com/TheJazzDev/dpd-local-sdk.git#readme",
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