@jazzdev/dpd-local-sdk 1.0.13 → 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/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>;
@@ -498,4 +533,4 @@ declare function loggedOperation<T>(params: {
498
533
  headers?: Record<string, string>;
499
534
  }>): Promise<T>;
500
535
 
501
- 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, 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 };
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>;
@@ -498,4 +533,4 @@ declare function loggedOperation<T>(params: {
498
533
  headers?: Record<string, string>;
499
534
  }>): Promise<T>;
500
535
 
501
- 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, 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 };
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
@@ -22,6 +22,8 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  DPDService: () => dpd_service_default,
24
24
  DPD_API: () => DPD_API,
25
+ GeoSessionManager: () => GeoSessionManager,
26
+ InMemoryGeoSessionStorage: () => InMemoryGeoSessionStorage,
25
27
  SERVICE_DESCRIPTIONS: () => SERVICE_DESCRIPTIONS,
26
28
  SERVICE_NAMES: () => SERVICE_NAMES,
27
29
  authenticate: () => authenticate,
@@ -69,6 +71,28 @@ __export(index_exports, {
69
71
  });
70
72
  module.exports = __toCommonJS(index_exports);
71
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
+
72
96
  // src/config/index.ts
73
97
  var DPD_API = {
74
98
  BASE_URL: "https://api.dpdlocal.co.uk",
@@ -421,6 +445,164 @@ async function testConnection(credentials) {
421
445
  };
422
446
  }
423
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
+ };
424
606
 
425
607
  // src/utils/getAcceptHeader.ts
426
608
  function getAcceptHeader(format) {
@@ -1073,6 +1255,8 @@ function logToConsole(logData) {
1073
1255
  0 && (module.exports = {
1074
1256
  DPDService,
1075
1257
  DPD_API,
1258
+ GeoSessionManager,
1259
+ InMemoryGeoSessionStorage,
1076
1260
  SERVICE_DESCRIPTIONS,
1077
1261
  SERVICE_NAMES,
1078
1262
  authenticate,
@@ -1125,7 +1309,7 @@ function logToConsole(logData) {
1125
1309
  * Database-agnostic and framework-independent
1126
1310
  *
1127
1311
  * @package @jazzdev/dpd-local-sdk
1128
- * @version 1.0.12
1312
+ * @version 1.1.0
1129
1313
  * @author Taiow Babarinde <babsman4all@gmail.com>
1130
1314
  * @license MIT
1131
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) {
@@ -1001,6 +1181,8 @@ function logToConsole(logData) {
1001
1181
  export {
1002
1182
  dpd_service_default as DPDService,
1003
1183
  DPD_API,
1184
+ GeoSessionManager,
1185
+ InMemoryGeoSessionStorage,
1004
1186
  SERVICE_DESCRIPTIONS,
1005
1187
  SERVICE_NAMES,
1006
1188
  authenticate,
@@ -1053,7 +1235,7 @@ export {
1053
1235
  * Database-agnostic and framework-independent
1054
1236
  *
1055
1237
  * @package @jazzdev/dpd-local-sdk
1056
- * @version 1.0.12
1238
+ * @version 1.1.0
1057
1239
  * @author Taiow Babarinde <babsman4all@gmail.com>
1058
1240
  * @license MIT
1059
1241
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jazzdev/dpd-local-sdk",
3
- "version": "1.0.13",
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",