shipflow 0.1.0 → 0.1.1

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.
Files changed (34) hide show
  1. package/dist/carriers/aramex/adapter.d.ts +82 -0
  2. package/dist/carriers/aramex/adapter.d.ts.map +1 -0
  3. package/dist/carriers/aramex/index.d.ts +9 -0
  4. package/dist/carriers/aramex/index.d.ts.map +1 -0
  5. package/dist/carriers/aramex/index.js +661 -0
  6. package/dist/carriers/aramex/index.js.map +12 -0
  7. package/dist/carriers/aramex/mappers.d.ts +68 -0
  8. package/dist/carriers/aramex/mappers.d.ts.map +1 -0
  9. package/dist/carriers/aramex/services.d.ts +74 -0
  10. package/dist/carriers/aramex/services.d.ts.map +1 -0
  11. package/dist/carriers/aramex/types.d.ts +302 -0
  12. package/dist/carriers/aramex/types.d.ts.map +1 -0
  13. package/dist/carriers/aymakan/adapter.d.ts +3 -2
  14. package/dist/carriers/aymakan/adapter.d.ts.map +1 -1
  15. package/dist/carriers/aymakan/index.js +54 -43
  16. package/dist/carriers/aymakan/index.js.map +4 -4
  17. package/dist/carriers/aymakan/mappers.d.ts.map +1 -1
  18. package/dist/carriers/aymakan/types.d.ts +4 -6
  19. package/dist/carriers/aymakan/types.d.ts.map +1 -1
  20. package/dist/carriers/base.d.ts +2 -2
  21. package/dist/carriers/base.d.ts.map +1 -1
  22. package/dist/carriers/smsaexpress/adapter.d.ts +1 -1
  23. package/dist/carriers/smsaexpress/adapter.d.ts.map +1 -1
  24. package/dist/carriers/smsaexpress/index.js +12 -8
  25. package/dist/carriers/smsaexpress/index.js.map +4 -4
  26. package/dist/carriers/smsaexpress/mappers.d.ts.map +1 -1
  27. package/dist/core/http.d.ts.map +1 -1
  28. package/dist/core/schemas.d.ts +3 -3
  29. package/dist/core/types.d.ts +1 -1
  30. package/dist/core/types.d.ts.map +1 -1
  31. package/dist/{index-x8sk1kw9.js → index-qjtxhwzv.js} +5 -3
  32. package/dist/{index-x8sk1kw9.js.map → index-qjtxhwzv.js.map} +5 -5
  33. package/dist/index.js +1 -1
  34. package/package.json +8 -3
@@ -0,0 +1,661 @@
1
+ import {
2
+ APIError,
3
+ BaseCarrierAdapter,
4
+ HttpClient,
5
+ UnsupportedOperationError,
6
+ ValidationError,
7
+ validateCreateShipmentInput,
8
+ validatePickupRequest
9
+ } from "../../index-qjtxhwzv.js";
10
+
11
+ // src/carriers/aramex/services.ts
12
+ var AramexProductGroup = {
13
+ EXPRESS: "EXP",
14
+ DOMESTIC: "DOM"
15
+ };
16
+ var AramexProductType = {
17
+ DOMESTIC: "OND",
18
+ PRIORITY_DOCUMENT_EXPRESS: "PDX",
19
+ PRIORITY_PARCEL_EXPRESS: "PPX",
20
+ PRIORITY_LETTER_EXPRESS: "PLX",
21
+ DEFERRED_DOCUMENT_EXPRESS: "DDX",
22
+ DEFERRED_PARCEL_EXPRESS: "DPX",
23
+ GROUND_DOCUMENT_EXPRESS: "GDX",
24
+ GROUND_PARCEL_EXPRESS: "GPX",
25
+ ECONOMY_PARCEL_EXPRESS: "EPX",
26
+ RETURN: "RTN"
27
+ };
28
+ var AramexPaymentType = {
29
+ PREPAID: "P",
30
+ COLLECT: "C",
31
+ THIRD_PARTY: "3"
32
+ };
33
+ var AramexService = {
34
+ COD: "CODS",
35
+ INSURANCE: "INSR"
36
+ };
37
+ var AramexStatusCodes = {
38
+ SH001: "created",
39
+ SH002: "picked_up",
40
+ SH004: "at_warehouse",
41
+ SH005: "out_for_delivery",
42
+ SH014: "delivered",
43
+ SH060: "in_transit",
44
+ SH074: "exception",
45
+ SH159: "exception",
46
+ SH212: "returned",
47
+ SH235: "delivered"
48
+ };
49
+
50
+ // src/carriers/aramex/mappers.ts
51
+ function buildClientInfo(credentials, opts) {
52
+ return {
53
+ UserName: credentials.userName,
54
+ Password: credentials.password,
55
+ Version: opts?.version ?? "v1.0",
56
+ AccountNumber: credentials.accountNumber,
57
+ AccountPin: credentials.accountPin,
58
+ AccountEntity: credentials.accountEntity,
59
+ AccountCountryCode: credentials.accountCountryCode,
60
+ Source: opts?.source ?? 24
61
+ };
62
+ }
63
+ function mapAramexStatus(updateCode) {
64
+ const mapped = AramexStatusCodes[updateCode];
65
+ return mapped;
66
+ }
67
+ function statusFromDescription(description) {
68
+ if (!description)
69
+ return;
70
+ const d = description.toLowerCase();
71
+ if (/out for delivery|on delivery|with delivery courier/.test(d))
72
+ return "out_for_delivery";
73
+ if (/fail|unable|undeliver|exception|held|on hold|problem|refused|damaged/.test(d))
74
+ return "exception";
75
+ if (/deliver/.test(d))
76
+ return "delivered";
77
+ if (/return/.test(d))
78
+ return "returned";
79
+ if (/cancel/.test(d))
80
+ return "cancelled";
81
+ if (/picked up|collected|pickup/.test(d))
82
+ return "picked_up";
83
+ if (/transit|departed|forwarded|en route/.test(d))
84
+ return "in_transit";
85
+ if (/received at|arrived|facility|warehouse|sorting|hub/.test(d))
86
+ return "at_warehouse";
87
+ if (/created|information received|booked/.test(d))
88
+ return "created";
89
+ return;
90
+ }
91
+ function parseAramexDate(value) {
92
+ if (!value)
93
+ return new Date(Number.NaN);
94
+ const wcf = /\/Date\((-?\d+)(?:[+-]\d{4})?\)\//.exec(value);
95
+ if (wcf?.[1])
96
+ return new Date(Number.parseInt(wcf[1], 10));
97
+ return new Date(value);
98
+ }
99
+ function toWcfDate(date) {
100
+ return `/Date(${date.getTime()})/`;
101
+ }
102
+ function round(value) {
103
+ return Math.round(value * 1000) / 1000;
104
+ }
105
+ var VALID_PRODUCT_TYPES = new Set(Object.values(AramexProductType));
106
+ function getMeta(input, key) {
107
+ const value = input.options?.metadata?.[key];
108
+ return typeof value === "string" ? value : undefined;
109
+ }
110
+ function resolveProductGroupAndType(input) {
111
+ const sameCountry = input.shipper.countryCode.trim().toUpperCase() === input.consignee.countryCode.trim().toUpperCase();
112
+ const metaGroup = getMeta(input, "productGroup")?.toUpperCase();
113
+ const productGroup = metaGroup === "EXP" || metaGroup === "DOM" ? metaGroup : sameCountry ? "DOM" : "EXP";
114
+ const candidate = getMeta(input, "productType") ?? input.serviceType;
115
+ const productType = candidate && VALID_PRODUCT_TYPES.has(candidate) ? candidate : productGroup === "DOM" ? AramexProductType.DOMESTIC : AramexProductType.ECONOMY_PARCEL_EXPRESS;
116
+ return { productGroup, productType };
117
+ }
118
+ function resolvePaymentType(input) {
119
+ const meta = getMeta(input, "paymentType");
120
+ if (meta === "P" || meta === "C" || meta === "3")
121
+ return meta;
122
+ return input.cod?.enabled ? "C" : "P";
123
+ }
124
+ function aggregateWeight(input) {
125
+ const allLb = input.parcels.every((p) => p.weight.unit === "lb");
126
+ if (allLb) {
127
+ const value2 = input.parcels.reduce((s, p) => s + p.weight.value, 0);
128
+ return { Value: round(value2), Unit: "Lb" };
129
+ }
130
+ const value = input.parcels.reduce((s, p) => s + (p.weight.unit === "lb" ? p.weight.value * 0.453592 : p.weight.value), 0);
131
+ return { Value: round(value), Unit: "Kg" };
132
+ }
133
+ function mapDimensions(dims) {
134
+ if (!dims)
135
+ return null;
136
+ const factor = dims.unit === "in" ? 2.54 : 1;
137
+ return {
138
+ Length: round(dims.length * factor),
139
+ Width: round(dims.width * factor),
140
+ Height: round(dims.height * factor),
141
+ Unit: "CM"
142
+ };
143
+ }
144
+ function mapAddress(addr) {
145
+ return {
146
+ Line1: addr.line1,
147
+ Line2: addr.line2 ?? "",
148
+ Line3: addr.neighbourhood ?? "",
149
+ City: addr.city,
150
+ StateOrProvinceCode: addr.state,
151
+ PostCode: addr.postalCode ?? "",
152
+ CountryCode: addr.countryCode,
153
+ Longitude: addr.coordinates?.longitude,
154
+ Latitude: addr.coordinates?.latitude
155
+ };
156
+ }
157
+ function buildContact(opts) {
158
+ return {
159
+ Department: "",
160
+ PersonName: opts.personName,
161
+ Title: "",
162
+ CompanyName: opts.companyName,
163
+ PhoneNumber1: opts.phone,
164
+ PhoneNumber1Ext: "",
165
+ PhoneNumber2: "",
166
+ CellPhone: opts.phone,
167
+ EmailAddress: opts.email ?? "",
168
+ Type: ""
169
+ };
170
+ }
171
+ function mapContact(addr, fallbackCompany) {
172
+ return buildContact({
173
+ personName: addr.name,
174
+ companyName: addr.company ?? fallbackCompany ?? addr.name,
175
+ phone: addr.phone,
176
+ email: addr.email
177
+ });
178
+ }
179
+ function mapParty(addr, accountNumber, fallbackCompany) {
180
+ return {
181
+ AccountNumber: accountNumber,
182
+ PartyAddress: mapAddress(addr),
183
+ Contact: mapContact(addr, fallbackCompany)
184
+ };
185
+ }
186
+ function mapShipmentDetails(input, productGroup, productType, paymentType) {
187
+ const numberOfPieces = input.parcels.reduce((s, p) => s + p.pieces, 0) || 1;
188
+ const description = input.parcels.map((p) => p.description).filter(Boolean).join(", ") || "Goods";
189
+ const services = [];
190
+ let cashOnDelivery = null;
191
+ if (input.cod?.enabled) {
192
+ cashOnDelivery = {
193
+ Value: input.cod.amount,
194
+ CurrencyCode: input.cod.currency
195
+ };
196
+ services.push(AramexService.COD);
197
+ }
198
+ const customsValue = input.declaredValue ? {
199
+ Value: input.declaredValue.amount,
200
+ CurrencyCode: input.declaredValue.currency
201
+ } : null;
202
+ const insuranceAmount = input.options?.isInsured && customsValue ? customsValue : null;
203
+ if (insuranceAmount)
204
+ services.push(AramexService.INSURANCE);
205
+ return {
206
+ Dimensions: mapDimensions(input.parcels[0]?.dimensions),
207
+ ActualWeight: aggregateWeight(input),
208
+ ChargeableWeight: null,
209
+ DescriptionOfGoods: description,
210
+ GoodsOriginCountry: input.shipper.countryCode,
211
+ NumberOfPieces: numberOfPieces,
212
+ ProductGroup: productGroup,
213
+ ProductType: productType,
214
+ PaymentType: paymentType,
215
+ PaymentOptions: "",
216
+ CustomsValueAmount: customsValue,
217
+ CashOnDeliveryAmount: cashOnDelivery,
218
+ InsuranceAmount: insuranceAmount,
219
+ Services: services.join(",") || undefined
220
+ };
221
+ }
222
+ function mapCreateShipmentRequest(input, ctx) {
223
+ const { productGroup, productType } = resolveProductGroupAndType(input);
224
+ const paymentType = resolvePaymentType(input);
225
+ const now = new Date;
226
+ const due = new Date(now.getTime() + 24 * 60 * 60 * 1000);
227
+ return {
228
+ Reference1: input.reference,
229
+ Reference2: input.options?.customerTracking,
230
+ Shipper: mapParty(input.shipper, ctx.accountNumber, ctx.companyName),
231
+ Consignee: mapParty(input.consignee),
232
+ ThirdParty: null,
233
+ ShippingDateTime: toWcfDate(now),
234
+ DueDate: toWcfDate(due),
235
+ Comments: getMeta(input, "comments"),
236
+ PickupLocation: getMeta(input, "pickupLocation"),
237
+ Details: mapShipmentDetails(input, productGroup, productType, paymentType),
238
+ Attachments: null,
239
+ ForeignHAWB: null,
240
+ TransportType: 0,
241
+ Number: null
242
+ };
243
+ }
244
+ function mapCalculateRateRequest(input, preferredCurrency) {
245
+ const { productGroup, productType } = resolveProductGroupAndType(input);
246
+ const paymentType = resolvePaymentType(input);
247
+ return {
248
+ OriginAddress: mapAddress(input.shipper),
249
+ DestinationAddress: mapAddress(input.consignee),
250
+ ShipmentDetails: mapShipmentDetails(input, productGroup, productType, paymentType),
251
+ PreferredCurrencyCode: preferredCurrency ?? input.cod?.currency ?? input.declaredValue?.currency
252
+ };
253
+ }
254
+ function mapPickupRequest(input, ctx) {
255
+ const pickupDate = new Date(`${input.date}T00:00:00`);
256
+ const ready = new Date(`${input.date}T09:00:00`);
257
+ const closing = new Date(`${input.date}T17:00:00`);
258
+ return {
259
+ Reference1: input.trackingNumbers?.[0],
260
+ PickupAddress: {
261
+ Line1: input.address,
262
+ City: input.city,
263
+ CountryCode: ctx.countryCode
264
+ },
265
+ PickupContact: buildContact({
266
+ personName: input.contactName,
267
+ companyName: ctx.companyName ?? input.contactName,
268
+ phone: input.contactPhone
269
+ }),
270
+ PickupLocation: "Reception",
271
+ PickupDate: toWcfDate(pickupDate),
272
+ ReadyTime: toWcfDate(ready),
273
+ LastPickupTime: toWcfDate(closing),
274
+ ClosingTime: toWcfDate(closing),
275
+ Comments: input.timeSlot,
276
+ Status: "Ready",
277
+ PickupItems: {
278
+ PickupItemDetail: [
279
+ {
280
+ ProductGroup: "DOM",
281
+ ProductType: AramexProductType.DOMESTIC,
282
+ Payment: "P",
283
+ NumberOfShipments: input.shipmentCount,
284
+ NumberOfPieces: input.shipmentCount,
285
+ ShipmentWeight: { Value: 1, Unit: "Kg" }
286
+ }
287
+ ]
288
+ }
289
+ };
290
+ }
291
+ function mapShipmentResponse(processed, input) {
292
+ const trackingNumber = processed.ID || processed.ShipmentNumber || "";
293
+ const labelUrl = processed.ShipmentLabel?.LabelURL || undefined;
294
+ return {
295
+ carrier: "aramex",
296
+ trackingNumber,
297
+ customerTracking: input?.options?.customerTracking,
298
+ reference: input?.reference,
299
+ status: "created",
300
+ statusLabel: "Created",
301
+ labelUrl,
302
+ pdfLabelUrl: labelUrl,
303
+ codAmount: input?.cod?.enabled ? input.cod.amount : undefined,
304
+ declaredValue: input?.declaredValue?.amount,
305
+ currency: input?.cod?.currency ?? input?.declaredValue?.currency ?? "SAR",
306
+ createdAt: new Date,
307
+ raw: processed
308
+ };
309
+ }
310
+ function mapTrackingEvent(result) {
311
+ return {
312
+ timestamp: parseAramexDate(result.UpdateDateTime),
313
+ statusCode: result.UpdateCode,
314
+ status: mapAramexStatus(result.UpdateCode) ?? statusFromDescription(result.UpdateDescription) ?? "unknown",
315
+ description: result.UpdateDescription,
316
+ location: result.UpdateLocation || undefined
317
+ };
318
+ }
319
+ function mapTrackingResult(waybill, results) {
320
+ const events = results.map(mapTrackingEvent).sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
321
+ const latest = events[0];
322
+ const delivered = events.find((e) => e.status === "delivered");
323
+ const weightStr = [...results].reverse().find((r) => r.GrossWeight)?.GrossWeight;
324
+ const weight = weightStr ? Number.parseFloat(weightStr) : undefined;
325
+ return {
326
+ trackingNumber: waybill,
327
+ carrier: "aramex",
328
+ status: latest?.status ?? "unknown",
329
+ statusLabel: latest?.description ?? "Unknown",
330
+ events,
331
+ deliveryDate: delivered?.timestamp,
332
+ weight: weight != null && !Number.isNaN(weight) ? weight : undefined,
333
+ raw: results
334
+ };
335
+ }
336
+ function normalizeTrackingResults(raw) {
337
+ if (!raw)
338
+ return {};
339
+ if (Array.isArray(raw)) {
340
+ const map = {};
341
+ for (const kv of raw) {
342
+ if (kv && typeof kv === "object" && "Key" in kv) {
343
+ map[kv.Key] = kv.Value ?? [];
344
+ }
345
+ }
346
+ return map;
347
+ }
348
+ return raw;
349
+ }
350
+ function mapRate(response, input) {
351
+ const { productType } = resolveProductGroupAndType(input);
352
+ return {
353
+ carrier: "aramex",
354
+ serviceType: productType,
355
+ serviceName: productType,
356
+ amount: response.TotalAmount?.Value ?? 0,
357
+ currency: response.TotalAmount?.CurrencyCode ?? input.cod?.currency ?? input.declaredValue?.currency ?? "SAR",
358
+ raw: response
359
+ };
360
+ }
361
+ function mapPickupResponse(processed, input) {
362
+ return {
363
+ id: processed.GUID || processed.ID,
364
+ carrier: "aramex",
365
+ status: "pending",
366
+ date: input.date,
367
+ timeSlot: input.timeSlot,
368
+ city: input.city,
369
+ contactName: input.contactName,
370
+ contactPhone: input.contactPhone,
371
+ address: input.address,
372
+ shipmentCount: input.shipmentCount,
373
+ createdAt: new Date,
374
+ raw: processed
375
+ };
376
+ }
377
+ function mapCity(name) {
378
+ return { nameEn: name };
379
+ }
380
+ function mapOffice(office) {
381
+ const addr = office.Address;
382
+ const lines = [addr?.Line1, addr?.Line2, addr?.Line3].filter(Boolean);
383
+ return {
384
+ id: office.EntityCode,
385
+ name: office.EntityName ?? office.EntityCode,
386
+ address: lines.length ? lines.join(", ") : undefined,
387
+ city: addr?.City,
388
+ latitude: addr?.Latitude,
389
+ longitude: addr?.Longitude
390
+ };
391
+ }
392
+
393
+ // src/carriers/aramex/adapter.ts
394
+ var SHIPPING_SANDBOX_URL = "https://ws.dev.aramex.net/ShippingAPI.V2/Shipping/Service_1_0.svc";
395
+ var SHIPPING_PRODUCTION_URL = "https://ws.aramex.net/ShippingAPI.V2/Shipping/Service_1_0.svc";
396
+ var DEFAULT_LABEL_INFO = {
397
+ ReportID: 9201,
398
+ ReportType: "URL"
399
+ };
400
+ var EMPTY_TRANSACTION = {
401
+ Reference1: "",
402
+ Reference2: "",
403
+ Reference3: "",
404
+ Reference4: "",
405
+ Reference5: ""
406
+ };
407
+
408
+ class AramexAdapter extends BaseCarrierAdapter {
409
+ name = "aramex";
410
+ supportedCountries = [
411
+ "SA",
412
+ "AE",
413
+ "BH",
414
+ "KW",
415
+ "OM",
416
+ "QA",
417
+ "JO",
418
+ "EG",
419
+ "LB",
420
+ "IQ"
421
+ ];
422
+ shippingHttp;
423
+ trackingHttp;
424
+ rateHttp;
425
+ locationHttp;
426
+ constructor(config) {
427
+ super(config);
428
+ const shippingBase = this.getBaseUrl();
429
+ const common = {
430
+ carrier: "aramex"
431
+ };
432
+ this.shippingHttp = new HttpClient({ ...common, baseUrl: shippingBase });
433
+ this.trackingHttp = new HttpClient({
434
+ ...common,
435
+ baseUrl: this.serviceBase(shippingBase, "Tracking")
436
+ });
437
+ this.rateHttp = new HttpClient({
438
+ ...common,
439
+ baseUrl: this.serviceBase(shippingBase, "RateCalculator")
440
+ });
441
+ this.locationHttp = new HttpClient({
442
+ ...common,
443
+ baseUrl: config.locationBaseUrl ?? this.serviceBase(shippingBase, "Location")
444
+ });
445
+ }
446
+ getBaseUrl() {
447
+ return this.config.mode === "production" ? SHIPPING_PRODUCTION_URL : SHIPPING_SANDBOX_URL;
448
+ }
449
+ serviceBase(shippingBase, service) {
450
+ return shippingBase.replace("/Shipping/", `/${service}/`);
451
+ }
452
+ get aramexConfig() {
453
+ return this.config;
454
+ }
455
+ buildClientInfo() {
456
+ const cfg = this.aramexConfig;
457
+ return buildClientInfo(cfg.credentials, {
458
+ source: cfg.source,
459
+ version: cfg.version
460
+ });
461
+ }
462
+ static aramexErrorExtractor(json) {
463
+ const obj = json;
464
+ const notifications = obj?.Notifications ?? [];
465
+ const hasError = obj?.HasErrors === true;
466
+ const message = notifications.map((n) => n?.Message).filter(Boolean).join("; ") || (hasError ? "Aramex returned an error" : undefined);
467
+ return {
468
+ hasError,
469
+ message,
470
+ errors: notifications.length ? AramexAdapter.notificationsToErrors(notifications) : undefined
471
+ };
472
+ }
473
+ static notificationsToErrors(notifications) {
474
+ return {
475
+ _aramex: notifications.map((n) => `${n?.Code ?? ""}: ${n?.Message ?? ""}`.trim())
476
+ };
477
+ }
478
+ async executeCreateShipment(input) {
479
+ const cfg = this.aramexConfig;
480
+ const shipment = mapCreateShipmentRequest(input, {
481
+ accountNumber: cfg.credentials.accountNumber,
482
+ companyName: cfg.companyName
483
+ });
484
+ const response = await this.shippingHttp.post("/json/CreateShipments", {
485
+ ClientInfo: this.buildClientInfo(),
486
+ Transaction: EMPTY_TRANSACTION,
487
+ LabelInfo: DEFAULT_LABEL_INFO,
488
+ Shipments: [shipment]
489
+ }, { errorExtractor: AramexAdapter.aramexErrorExtractor });
490
+ const processed = response.Shipments?.[0];
491
+ if (!processed) {
492
+ throw new APIError("Aramex returned no shipment", {
493
+ carrier: "aramex",
494
+ raw: response
495
+ });
496
+ }
497
+ if (processed.HasErrors) {
498
+ const notifications = processed.Notifications ?? [];
499
+ throw new APIError(notifications.map((n) => n.Message).filter(Boolean).join("; ") || "Failed to create shipment", {
500
+ carrier: "aramex",
501
+ errors: AramexAdapter.notificationsToErrors(notifications),
502
+ raw: processed
503
+ });
504
+ }
505
+ return mapShipmentResponse(processed, input);
506
+ }
507
+ async createBulkShipments(inputs) {
508
+ if (inputs.length === 0) {
509
+ throw new ValidationError("At least one shipment is required for bulk create", { raw: { count: 0 } });
510
+ }
511
+ for (const input of inputs)
512
+ validateCreateShipmentInput(input);
513
+ const cfg = this.aramexConfig;
514
+ const shipments = inputs.map((input) => mapCreateShipmentRequest(input, {
515
+ accountNumber: cfg.credentials.accountNumber,
516
+ companyName: cfg.companyName
517
+ }));
518
+ const response = await this.shippingHttp.post("/json/CreateShipments", {
519
+ ClientInfo: this.buildClientInfo(),
520
+ Transaction: EMPTY_TRANSACTION,
521
+ LabelInfo: DEFAULT_LABEL_INFO,
522
+ Shipments: shipments
523
+ }, { errorExtractor: AramexAdapter.aramexErrorExtractor });
524
+ const processed = response.Shipments ?? [];
525
+ if (processed.length === 0) {
526
+ throw new APIError("Aramex returned no shipments", {
527
+ carrier: "aramex",
528
+ raw: response
529
+ });
530
+ }
531
+ const failed = processed.filter((p) => p.HasErrors);
532
+ if (failed.length > 0) {
533
+ const notifications = failed.flatMap((p) => p.Notifications ?? []);
534
+ throw new APIError(notifications.map((n) => n.Message).filter(Boolean).join("; ") || `Failed to create ${failed.length} of ${processed.length} shipments`, {
535
+ carrier: "aramex",
536
+ errors: AramexAdapter.notificationsToErrors(notifications),
537
+ raw: response
538
+ });
539
+ }
540
+ return processed.map((p, i) => mapShipmentResponse(p, inputs[i]));
541
+ }
542
+ cancelShipment(_trackingNumber) {
543
+ throw new UnsupportedOperationError("aramex", "cancelShipment");
544
+ }
545
+ async getLabel(trackingNumber, _format) {
546
+ const response = await this.shippingHttp.post("/json/PrintLabel", {
547
+ ClientInfo: this.buildClientInfo(),
548
+ Transaction: EMPTY_TRANSACTION,
549
+ ShipmentNumber: trackingNumber,
550
+ LabelInfo: DEFAULT_LABEL_INFO
551
+ }, { errorExtractor: AramexAdapter.aramexErrorExtractor });
552
+ const url = response.ShipmentLabel?.LabelURL;
553
+ if (!url) {
554
+ throw new APIError("Failed to get label", {
555
+ carrier: "aramex",
556
+ raw: response
557
+ });
558
+ }
559
+ return url;
560
+ }
561
+ async track(trackingNumber) {
562
+ const results = await this.trackMultiple([trackingNumber]);
563
+ const result = results[0];
564
+ if (!result) {
565
+ throw new APIError("Shipment not found", {
566
+ carrier: "aramex",
567
+ raw: { trackingNumber }
568
+ });
569
+ }
570
+ return result;
571
+ }
572
+ async trackMultiple(trackingNumbers) {
573
+ const response = await this.trackingHttp.post("/json/TrackShipments", {
574
+ ClientInfo: this.buildClientInfo(),
575
+ Transaction: EMPTY_TRANSACTION,
576
+ Shipments: trackingNumbers,
577
+ GetLastTrackingUpdateOnly: false
578
+ }, { retry: true, errorExtractor: AramexAdapter.aramexErrorExtractor });
579
+ const map = normalizeTrackingResults(response.TrackingResults);
580
+ return Object.entries(map).map(([waybill, results]) => mapTrackingResult(waybill, results));
581
+ }
582
+ async trackByReference(reference) {
583
+ const result = await this.track(reference);
584
+ return { ...result, reference };
585
+ }
586
+ async getRates(input) {
587
+ const rateRequest = mapCalculateRateRequest(input);
588
+ const response = await this.rateHttp.post("/json/CalculateRate", {
589
+ ClientInfo: this.buildClientInfo(),
590
+ Transaction: EMPTY_TRANSACTION,
591
+ ...rateRequest
592
+ }, { retry: true, errorExtractor: AramexAdapter.aramexErrorExtractor });
593
+ if (response.TotalAmount?.Value == null) {
594
+ throw new APIError("Aramex returned no rate for this shipment", {
595
+ carrier: "aramex",
596
+ raw: response
597
+ });
598
+ }
599
+ return [mapRate(response, input)];
600
+ }
601
+ async createPickup(input) {
602
+ validatePickupRequest(input);
603
+ const cfg = this.aramexConfig;
604
+ const pickup = mapPickupRequest(input, {
605
+ accountNumber: cfg.credentials.accountNumber,
606
+ countryCode: cfg.credentials.accountCountryCode,
607
+ companyName: cfg.companyName
608
+ });
609
+ const response = await this.shippingHttp.post("/json/CreatePickup", {
610
+ ClientInfo: this.buildClientInfo(),
611
+ Transaction: EMPTY_TRANSACTION,
612
+ Pickup: pickup
613
+ }, { errorExtractor: AramexAdapter.aramexErrorExtractor });
614
+ const processed = response.ProcessedPickup;
615
+ if (!processed || !processed.GUID && !processed.ID) {
616
+ throw new APIError("Failed to create pickup", {
617
+ carrier: "aramex",
618
+ raw: response
619
+ });
620
+ }
621
+ return mapPickupResponse(processed, input);
622
+ }
623
+ async cancelPickup(pickupId) {
624
+ const response = await this.shippingHttp.post("/json/CancelPickup", {
625
+ ClientInfo: this.buildClientInfo(),
626
+ Transaction: EMPTY_TRANSACTION,
627
+ PickupGUID: String(pickupId)
628
+ }, { errorExtractor: AramexAdapter.aramexErrorExtractor });
629
+ return response.HasErrors !== true;
630
+ }
631
+ async getCities(countryCode) {
632
+ const response = await this.locationHttp.post("/json/FetchCities", {
633
+ ClientInfo: this.buildClientInfo(),
634
+ Transaction: EMPTY_TRANSACTION,
635
+ CountryCode: countryCode ?? this.aramexConfig.credentials.accountCountryCode
636
+ }, { retry: true, errorExtractor: AramexAdapter.aramexErrorExtractor });
637
+ return (response.Cities ?? []).map(mapCity);
638
+ }
639
+ async getDropoffLocations(countryCode) {
640
+ const response = await this.locationHttp.post("/json/FetchOffices", {
641
+ ClientInfo: this.buildClientInfo(),
642
+ Transaction: EMPTY_TRANSACTION,
643
+ CountryCode: countryCode ?? this.aramexConfig.credentials.accountCountryCode
644
+ }, { retry: true, errorExtractor: AramexAdapter.aramexErrorExtractor });
645
+ return (response.Offices ?? []).map(mapOffice);
646
+ }
647
+ }
648
+ export {
649
+ statusFromDescription,
650
+ parseAramexDate,
651
+ mapAramexStatus,
652
+ buildClientInfo,
653
+ AramexStatusCodes,
654
+ AramexService,
655
+ AramexProductType,
656
+ AramexProductGroup,
657
+ AramexPaymentType,
658
+ AramexAdapter
659
+ };
660
+
661
+ //# debugId=F2518B67CA4397C364756E2164756E21