@jazzdev/dpd-local-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,38 @@
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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Your Name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,442 @@
1
+ # DPD Local SDK
2
+
3
+ > TypeScript SDK for integrating DPD Local shipping services into your application. Database-agnostic, framework-independent, and production-ready.
4
+
5
+ [![npm version](https://badge.fury.io/js/%40your-org%2Fdpd-local-sdk.svg)](https://www.npmjs.com/package/@your-org/dpd-local-sdk)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.3+-blue.svg)](https://www.typescriptlang.org/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+
9
+ ## Features
10
+
11
+ ✅ **Complete DPD Integration**
12
+ - Create shipments and generate labels
13
+ - Address validation (UK postcodes)
14
+ - Real-time tracking
15
+ - Multi-parcel support
16
+ - Service selection (Next Day, By 12 PM)
17
+
18
+ ✅ **Database-Agnostic**
19
+ - Works with any database (Firestore, MongoDB, PostgreSQL, etc.)
20
+ - Adapter pattern for easy integration
21
+ - TypeScript-first design
22
+
23
+ ✅ **Production-Ready**
24
+ - Battle-tested in production
25
+ - Comprehensive error handling
26
+ - Automatic token management
27
+ - Request retry logic
28
+ - Detailed logging
29
+
30
+ ✅ **Developer-Friendly**
31
+ - Full TypeScript support
32
+ - Comprehensive JSDoc comments
33
+ - Example implementations included
34
+ - Zero runtime dependencies (peer deps only)
35
+
36
+ ## Installation
37
+
38
+ ```bash
39
+ npm install @your-org/dpd-local-sdk
40
+ # or
41
+ yarn add @your-org/dpd-local-sdk
42
+ # or
43
+ pnpm add @your-org/dpd-local-sdk
44
+ ```
45
+
46
+ ## Quick Start
47
+
48
+ ### 1. Create Configuration
49
+
50
+ ```typescript
51
+ import { createDPDConfig } from "@your-org/dpd-local-sdk";
52
+
53
+ const config = createDPDConfig({
54
+ credentials: {
55
+ accountNumber: process.env.DPD_ACCOUNT_NUMBER!,
56
+ username: process.env.DPD_USERNAME!,
57
+ password: process.env.DPD_PASSWORD!,
58
+ },
59
+ business: {
60
+ name: "Your Business Name",
61
+ collectionAddress: {
62
+ organisation: "Your Company Ltd",
63
+ property: "Unit 1",
64
+ street: "123 Main Street",
65
+ locality: "",
66
+ town: "London",
67
+ county: "Greater London",
68
+ postcode: "SW1A 1AA",
69
+ countryCode: "GB",
70
+ },
71
+ contactName: "Your Name",
72
+ contactPhone: "+441234567890",
73
+ contactEmail: "shipping@yourcompany.com",
74
+ },
75
+ });
76
+ ```
77
+
78
+ ### 2. Implement Adapters
79
+
80
+ The SDK requires two adapters to work with your database and storage:
81
+
82
+ #### Database Adapter
83
+
84
+ ```typescript
85
+ import { DatabaseAdapter } from "@your-org/dpd-local-sdk";
86
+
87
+ const myDatabaseAdapter: DatabaseAdapter = {
88
+ async getOrder(orderId: string) {
89
+ // Your implementation
90
+ return await db.orders.findById(orderId);
91
+ },
92
+
93
+ async updateOrder(orderId: string, data: any) {
94
+ // Your implementation
95
+ await db.orders.update(orderId, data);
96
+ },
97
+
98
+ async getSavedAddresses(userId: string) {
99
+ // Your implementation
100
+ return await db.addresses.find({ userId });
101
+ },
102
+
103
+ async getSavedAddress(addressId: string) {
104
+ // Your implementation
105
+ return await db.addresses.findById(addressId);
106
+ },
107
+
108
+ async createSavedAddress(address) {
109
+ // Your implementation
110
+ const result = await db.addresses.create(address);
111
+ return result.id;
112
+ },
113
+
114
+ async updateSavedAddress(addressId: string, data) {
115
+ // Your implementation
116
+ await db.addresses.update(addressId, data);
117
+ },
118
+
119
+ async deleteSavedAddress(addressId: string) {
120
+ // Your implementation
121
+ await db.addresses.delete(addressId);
122
+ },
123
+
124
+ async createDPDLog(log) {
125
+ // Your implementation
126
+ const result = await db.dpdLogs.create(log);
127
+ return result.id;
128
+ },
129
+
130
+ async getDPDLogs(filters) {
131
+ // Your implementation
132
+ return await db.dpdLogs.find(filters);
133
+ },
134
+ };
135
+ ```
136
+
137
+ #### Storage Adapter
138
+
139
+ ```typescript
140
+ import { StorageAdapter } from "@your-org/dpd-local-sdk";
141
+
142
+ const myStorageAdapter: StorageAdapter = {
143
+ async uploadLabel(labelData: string, fileName: string) {
144
+ // Upload to your storage (S3, Firebase Storage, etc.)
145
+ const url = await storage.upload(labelData, `labels/${fileName}`);
146
+ return url;
147
+ },
148
+
149
+ async getLabel(fileName: string) {
150
+ // Get label URL from storage
151
+ return await storage.getUrl(`labels/${fileName}`);
152
+ },
153
+
154
+ async deleteLabel(fileName: string) {
155
+ // Delete label from storage
156
+ await storage.delete(`labels/${fileName}`);
157
+ },
158
+ };
159
+ ```
160
+
161
+ ### 3. Create a Shipment
162
+
163
+ ```typescript
164
+ import { createCompleteShipment } from "@your-org/dpd-local-sdk";
165
+
166
+ const result = await createCompleteShipment(
167
+ "ORDER123", // Your order ID
168
+ {
169
+ orderRef: "ORDER123",
170
+ service: "12", // Next Day Delivery
171
+ deliveryAddress: {
172
+ id: "addr_123",
173
+ userId: "user_123",
174
+ isDefault: true,
175
+ property: "10",
176
+ street: "Downing Street",
177
+ town: "London",
178
+ postcode: "SW1A 2AA",
179
+ countryCode: "GB",
180
+ contactName: "John Doe",
181
+ contactPhone: "+441234567890",
182
+ validated: true,
183
+ createdAt: new Date(),
184
+ updatedAt: new Date(),
185
+ },
186
+ totalWeight: 2.5, // kg
187
+ numberOfParcels: 1,
188
+ customerEmail: "customer@example.com",
189
+ customerPhone: "+441234567890",
190
+ deliveryInstructions: "Leave with neighbor if not home",
191
+ collectionDate: "2024-01-15",
192
+ },
193
+ config,
194
+ myDatabaseAdapter,
195
+ myStorageAdapter
196
+ );
197
+
198
+ if (result.success) {
199
+ console.log("Shipment created!");
200
+ console.log("Tracking URL:", result.trackingUrl);
201
+ console.log("Label URL:", result.labelUrl);
202
+ } else {
203
+ console.error("Failed:", result.error);
204
+ }
205
+ ```
206
+
207
+ ## API Reference
208
+
209
+ ### Configuration
210
+
211
+ #### `createDPDConfig(options)`
212
+
213
+ Creates a complete DPD module configuration.
214
+
215
+ **Parameters:**
216
+ - `options.credentials` - DPD API credentials
217
+ - `options.business` - Your business information
218
+ - `options.pricing` (optional) - Custom pricing configuration
219
+ - `options.services` (optional) - Service configuration
220
+ - `options.labels` (optional) - Label printer configuration
221
+ - `options.notifications` (optional) - Email/SMS configuration
222
+ - `options.testMode` (optional) - Enable test mode
223
+
224
+ **Returns:** `DPDModuleConfig`
225
+
226
+ ### Core Functions
227
+
228
+ #### `createCompleteShipment(orderId, params, config, dbAdapter, storageAdapter)`
229
+
230
+ Create a complete shipment including label generation and database update.
231
+
232
+ **Parameters:**
233
+ - `orderId` - Your internal order ID
234
+ - `params` - Shipment parameters (address, weight, service, etc.)
235
+ - `config` - DPD configuration
236
+ - `dbAdapter` - Database adapter
237
+ - `storageAdapter` - Storage adapter
238
+
239
+ **Returns:** `Promise<CreateShipmentResult>`
240
+
241
+ #### `validateDeliveryAddress(params, credentials)`
242
+
243
+ Validate a UK delivery address using postcodes.io API.
244
+
245
+ **Parameters:**
246
+ - `params.postcode` - UK postcode
247
+ - `params.town` - Town/city name
248
+ - `credentials` - DPD credentials
249
+
250
+ **Returns:** `Promise<ValidateAddressResult>`
251
+
252
+ #### `testDPDConnection(credentials)`
253
+
254
+ Test connection to DPD API.
255
+
256
+ **Parameters:**
257
+ - `credentials` - DPD credentials
258
+
259
+ **Returns:** `Promise<{ success: boolean; message: string }>`
260
+
261
+ ### Utility Functions
262
+
263
+ #### `calculateDeliveryFee(subtotal, service, config)`
264
+
265
+ Calculate customer-facing delivery fee.
266
+
267
+ #### `calculateDPDCost(weight, service, config)`
268
+
269
+ Calculate DPD shipping cost (what DPD charges you).
270
+
271
+ #### `getNextCollectionDate()`
272
+
273
+ Get next available collection date (excludes Sundays).
274
+
275
+ #### `getEstimatedDeliveryDate(service, collectionDate?)`
276
+
277
+ Calculate estimated delivery date.
278
+
279
+ #### `getTrackingUrl(parcelNumber)`
280
+
281
+ Generate DPD tracking URL.
282
+
283
+ ## Integration Examples
284
+
285
+ ### Next.js App Router
286
+
287
+ ```typescript
288
+ // app/api/shipping/create/route.ts
289
+ import { createCompleteShipment } from "@your-org/dpd-local-sdk";
290
+ import { NextRequest, NextResponse } from "next/server";
291
+
292
+ export async function POST(req: NextRequest) {
293
+ const { orderId, deliveryAddress, weight } = await req.json();
294
+
295
+ const result = await createCompleteShipment(
296
+ orderId,
297
+ {
298
+ orderRef: orderId,
299
+ service: "12",
300
+ deliveryAddress,
301
+ totalWeight: weight,
302
+ numberOfParcels: 1,
303
+ customerEmail: deliveryAddress.contactEmail,
304
+ collectionDate: new Date().toISOString().split("T")[0],
305
+ },
306
+ dpdConfig,
307
+ databaseAdapter,
308
+ storageAdapter
309
+ );
310
+
311
+ return NextResponse.json(result);
312
+ }
313
+ ```
314
+
315
+ ### Express.js
316
+
317
+ ```typescript
318
+ import express from "express";
319
+ import { createCompleteShipment } from "@your-org/dpd-local-sdk";
320
+
321
+ const app = express();
322
+
323
+ app.post("/api/shipping/create", async (req, res) => {
324
+ const { orderId, deliveryAddress, weight } = req.body;
325
+
326
+ const result = await createCompleteShipment(
327
+ orderId,
328
+ {
329
+ orderRef: orderId,
330
+ service: "12",
331
+ deliveryAddress,
332
+ totalWeight: weight,
333
+ numberOfParcels: 1,
334
+ customerEmail: deliveryAddress.contactEmail,
335
+ collectionDate: new Date().toISOString().split("T")[0],
336
+ },
337
+ dpdConfig,
338
+ databaseAdapter,
339
+ storageAdapter
340
+ );
341
+
342
+ res.json(result);
343
+ });
344
+ ```
345
+
346
+ ## Environment Variables
347
+
348
+ ```env
349
+ # DPD Credentials (Required)
350
+ DPD_ACCOUNT_NUMBER=your_account_number
351
+ DPD_USERNAME=your_username
352
+ DPD_PASSWORD=your_password
353
+
354
+ # Encryption (Required in production)
355
+ DPD_ENCRYPTION_KEY=your_32_byte_hex_key
356
+
357
+ # Optional
358
+ NODE_ENV=production
359
+ ```
360
+
361
+ ### Generating Encryption Key
362
+
363
+ ```typescript
364
+ import { generateEncryptionKey } from "@your-org/dpd-local-sdk";
365
+
366
+ const key = generateEncryptionKey();
367
+ console.log("DPD_ENCRYPTION_KEY=" + key);
368
+ ```
369
+
370
+ ## Adapter Examples
371
+
372
+ Complete adapter examples are available in the `examples/` directory:
373
+
374
+ - `examples/firestore-adapter.ts` - Firestore implementation
375
+ - `examples/mongodb-adapter.ts` - MongoDB implementation
376
+ - `examples/postgresql-adapter.ts` - PostgreSQL implementation
377
+ - `examples/firebase-storage-adapter.ts` - Firebase Storage implementation
378
+ - `examples/s3-storage-adapter.ts` - AWS S3 implementation
379
+
380
+ ## Error Handling
381
+
382
+ ```typescript
383
+ const result = await createCompleteShipment(...);
384
+
385
+ if (!result.success) {
386
+ console.error("Error Code:", result.errorCode);
387
+ console.error("Error Message:", result.error);
388
+
389
+ // Handle specific errors
390
+ switch (result.errorCode) {
391
+ case "AUTH_FAILED":
392
+ // Invalid credentials
393
+ break;
394
+ case "INVALID_ADDRESS":
395
+ // Address validation failed
396
+ break;
397
+ case "NETWORK_ERROR":
398
+ // Connection issues
399
+ break;
400
+ default:
401
+ // Generic error
402
+ }
403
+ }
404
+ ```
405
+
406
+ ## TypeScript Support
407
+
408
+ This SDK is written in TypeScript and provides complete type definitions:
409
+
410
+ ```typescript
411
+ import type {
412
+ DPDModuleConfig,
413
+ CreateShipmentParams,
414
+ CreateShipmentResult,
415
+ SavedAddress,
416
+ ShippingData,
417
+ DatabaseAdapter,
418
+ StorageAdapter,
419
+ } from "@your-org/dpd-local-sdk";
420
+ ```
421
+
422
+ ## Contributing
423
+
424
+ Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details.
425
+
426
+ ## License
427
+
428
+ MIT © [Your Name](https://github.com/your-org)
429
+
430
+ ## Support
431
+
432
+ - 📧 Email: support@your-org.com
433
+ - 🐛 Issues: [GitHub Issues](https://github.com/your-org/dpd-local-sdk/issues)
434
+ - 📖 Documentation: [Full Docs](https://docs.your-org.com/dpd-local-sdk)
435
+
436
+ ## Changelog
437
+
438
+ See [CHANGELOG.md](CHANGELOG.md) for release history.
439
+
440
+ ---
441
+
442
+ **Made with ❤️ for the developer community**