@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 +38 -0
- package/LICENSE +21 -0
- package/README.md +442 -0
- package/dist/index.d.mts +525 -0
- package/dist/index.d.ts +525 -0
- package/dist/index.js +1195 -0
- package/dist/index.mjs +1106 -0
- package/package.json +60 -0
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
|
+
[](https://www.npmjs.com/package/@your-org/dpd-local-sdk)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](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**
|