shipflow 0.1.1 → 0.3.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.
@@ -0,0 +1,1067 @@
1
+ // src/core/errors.ts
2
+ class ShipFlowError extends Error {
3
+ carrier;
4
+ code;
5
+ raw;
6
+ constructor(message, options) {
7
+ super(message, { cause: options?.cause });
8
+ this.name = "ShipFlowError";
9
+ this.carrier = options?.carrier;
10
+ this.code = options?.code;
11
+ this.raw = options?.raw;
12
+ }
13
+ }
14
+
15
+ class NetworkError extends ShipFlowError {
16
+ constructor(message, options) {
17
+ super(message, options);
18
+ this.name = "NetworkError";
19
+ }
20
+ }
21
+
22
+ class APIError extends ShipFlowError {
23
+ statusCode;
24
+ errors;
25
+ constructor(message, options) {
26
+ super(message, options);
27
+ this.name = "APIError";
28
+ this.statusCode = options?.statusCode;
29
+ this.errors = options?.errors;
30
+ }
31
+ }
32
+
33
+ class RateLimitError extends APIError {
34
+ retryAfterMs;
35
+ constructor(message, options) {
36
+ super(message, options);
37
+ this.name = "RateLimitError";
38
+ this.retryAfterMs = options?.retryAfterMs;
39
+ }
40
+ }
41
+
42
+ class ValidationError extends ShipFlowError {
43
+ field;
44
+ issues;
45
+ constructor(message, options) {
46
+ super(message, options);
47
+ this.name = "ValidationError";
48
+ this.field = options?.field;
49
+ this.issues = options?.issues;
50
+ }
51
+ }
52
+
53
+ class AuthenticationError extends ShipFlowError {
54
+ constructor(message, options) {
55
+ super(message, options);
56
+ this.name = "AuthenticationError";
57
+ }
58
+ }
59
+
60
+ class WebhookVerificationError extends ShipFlowError {
61
+ constructor(message, options) {
62
+ super(message, options);
63
+ this.name = "WebhookVerificationError";
64
+ }
65
+ }
66
+
67
+ class UnsupportedOperationError extends ShipFlowError {
68
+ operation;
69
+ constructor(carrier, operation) {
70
+ super(`${carrier} does not support operation: ${operation}`, { carrier });
71
+ this.name = "UnsupportedOperationError";
72
+ this.operation = operation;
73
+ }
74
+ }
75
+
76
+ // ../../node_modules/.bun/valibot@1.4.1+7524df1edfed9f02/node_modules/valibot/dist/index.mjs
77
+ var store$4;
78
+ var DEFAULT_CONFIG = {
79
+ lang: undefined,
80
+ message: undefined,
81
+ abortEarly: undefined,
82
+ abortPipeEarly: undefined
83
+ };
84
+ function getGlobalConfig(config$1) {
85
+ if (!config$1 && !store$4)
86
+ return DEFAULT_CONFIG;
87
+ return {
88
+ lang: config$1?.lang ?? store$4?.lang,
89
+ message: config$1?.message,
90
+ abortEarly: config$1?.abortEarly ?? store$4?.abortEarly,
91
+ abortPipeEarly: config$1?.abortPipeEarly ?? store$4?.abortPipeEarly
92
+ };
93
+ }
94
+ var store$3;
95
+ function getGlobalMessage(lang) {
96
+ return store$3?.get(lang);
97
+ }
98
+ var store$2;
99
+ function getSchemaMessage(lang) {
100
+ return store$2?.get(lang);
101
+ }
102
+ var store$1;
103
+ function getSpecificMessage(reference, lang) {
104
+ return store$1?.get(reference)?.get(lang);
105
+ }
106
+ function _stringify(input) {
107
+ const type = typeof input;
108
+ if (type === "string")
109
+ return `"${input}"`;
110
+ if (type === "number" || type === "bigint" || type === "boolean")
111
+ return `${input}`;
112
+ if (type === "object" || type === "function")
113
+ return (input && Object.getPrototypeOf(input)?.constructor?.name) ?? "null";
114
+ return type;
115
+ }
116
+ function _addIssue(context, label, dataset, config$1, other) {
117
+ const input = other && "input" in other ? other.input : dataset.value;
118
+ const expected = other?.expected ?? context.expects ?? null;
119
+ const received = other?.received ?? /* @__PURE__ */ _stringify(input);
120
+ const issue = {
121
+ kind: context.kind,
122
+ type: context.type,
123
+ input,
124
+ expected,
125
+ received,
126
+ message: `Invalid ${label}: ${expected ? `Expected ${expected} but r` : "R"}eceived ${received}`,
127
+ requirement: context.requirement,
128
+ path: other?.path,
129
+ issues: other?.issues,
130
+ lang: config$1.lang,
131
+ abortEarly: config$1.abortEarly,
132
+ abortPipeEarly: config$1.abortPipeEarly
133
+ };
134
+ const isSchema = context.kind === "schema";
135
+ const message$1 = other?.message ?? context.message ?? /* @__PURE__ */ getSpecificMessage(context.reference, issue.lang) ?? (isSchema ? /* @__PURE__ */ getSchemaMessage(issue.lang) : null) ?? config$1.message ?? /* @__PURE__ */ getGlobalMessage(issue.lang);
136
+ if (message$1 !== undefined)
137
+ issue.message = typeof message$1 === "function" ? message$1(issue) : message$1;
138
+ if (isSchema)
139
+ dataset.typed = false;
140
+ if (dataset.issues)
141
+ dataset.issues.push(issue);
142
+ else
143
+ dataset.issues = [issue];
144
+ }
145
+ var _standardCache = /* @__PURE__ */ new WeakMap;
146
+ function _getStandardProps(context) {
147
+ let cached = _standardCache.get(context);
148
+ if (!cached) {
149
+ cached = {
150
+ version: 1,
151
+ vendor: "valibot",
152
+ validate(value$1) {
153
+ return context["~run"]({ value: value$1 }, /* @__PURE__ */ getGlobalConfig());
154
+ }
155
+ };
156
+ _standardCache.set(context, cached);
157
+ }
158
+ return cached;
159
+ }
160
+ function _isValidObjectKey(object$1, key) {
161
+ return Object.prototype.hasOwnProperty.call(object$1, key) && key !== "__proto__" && key !== "prototype" && key !== "constructor";
162
+ }
163
+ function _joinExpects(values$1, separator) {
164
+ const list = [...new Set(values$1)];
165
+ if (list.length > 1)
166
+ return `(${list.join(` ${separator} `)})`;
167
+ return list[0] ?? "never";
168
+ }
169
+ function getDotPath(issue) {
170
+ if (issue.path) {
171
+ let key = "";
172
+ for (const item of issue.path)
173
+ if (typeof item.key === "string" || typeof item.key === "number")
174
+ if (key)
175
+ key += `.${item.key}`;
176
+ else
177
+ key += item.key;
178
+ else
179
+ return null;
180
+ return key;
181
+ }
182
+ return null;
183
+ }
184
+ var EMAIL_REGEX = /^[\w+-]+(?:\.[\w+-]+)*@[\da-z]+(?:[.-][\da-z]+)*\.[a-z]{2,}$/iu;
185
+ function email(message$1) {
186
+ return {
187
+ kind: "validation",
188
+ type: "email",
189
+ reference: email,
190
+ expects: null,
191
+ async: false,
192
+ requirement: EMAIL_REGEX,
193
+ message: message$1,
194
+ "~run"(dataset, config$1) {
195
+ if (dataset.typed && !this.requirement.test(dataset.value))
196
+ _addIssue(this, "email", dataset, config$1);
197
+ return dataset;
198
+ }
199
+ };
200
+ }
201
+ function gtValue(requirement, message$1) {
202
+ return {
203
+ kind: "validation",
204
+ type: "gt_value",
205
+ reference: gtValue,
206
+ async: false,
207
+ expects: `>${requirement instanceof Date ? requirement.toJSON() : /* @__PURE__ */ _stringify(requirement)}`,
208
+ requirement,
209
+ message: message$1,
210
+ "~run"(dataset, config$1) {
211
+ if (dataset.typed && !(dataset.value > this.requirement))
212
+ _addIssue(this, "value", dataset, config$1, { received: dataset.value instanceof Date ? dataset.value.toJSON() : /* @__PURE__ */ _stringify(dataset.value) });
213
+ return dataset;
214
+ }
215
+ };
216
+ }
217
+ function integer(message$1) {
218
+ return {
219
+ kind: "validation",
220
+ type: "integer",
221
+ reference: integer,
222
+ async: false,
223
+ expects: null,
224
+ requirement: Number.isInteger,
225
+ message: message$1,
226
+ "~run"(dataset, config$1) {
227
+ if (dataset.typed && !this.requirement(dataset.value))
228
+ _addIssue(this, "integer", dataset, config$1);
229
+ return dataset;
230
+ }
231
+ };
232
+ }
233
+ function length(requirement, message$1) {
234
+ return {
235
+ kind: "validation",
236
+ type: "length",
237
+ reference: length,
238
+ async: false,
239
+ expects: `${requirement}`,
240
+ requirement,
241
+ message: message$1,
242
+ "~run"(dataset, config$1) {
243
+ if (dataset.typed && dataset.value.length !== this.requirement)
244
+ _addIssue(this, "length", dataset, config$1, { received: `${dataset.value.length}` });
245
+ return dataset;
246
+ }
247
+ };
248
+ }
249
+ function maxValue(requirement, message$1) {
250
+ return {
251
+ kind: "validation",
252
+ type: "max_value",
253
+ reference: maxValue,
254
+ async: false,
255
+ expects: `<=${requirement instanceof Date ? requirement.toJSON() : /* @__PURE__ */ _stringify(requirement)}`,
256
+ requirement,
257
+ message: message$1,
258
+ "~run"(dataset, config$1) {
259
+ if (dataset.typed && !(dataset.value <= this.requirement))
260
+ _addIssue(this, "value", dataset, config$1, { received: dataset.value instanceof Date ? dataset.value.toJSON() : /* @__PURE__ */ _stringify(dataset.value) });
261
+ return dataset;
262
+ }
263
+ };
264
+ }
265
+ function minLength(requirement, message$1) {
266
+ return {
267
+ kind: "validation",
268
+ type: "min_length",
269
+ reference: minLength,
270
+ async: false,
271
+ expects: `>=${requirement}`,
272
+ requirement,
273
+ message: message$1,
274
+ "~run"(dataset, config$1) {
275
+ if (dataset.typed && dataset.value.length < this.requirement)
276
+ _addIssue(this, "length", dataset, config$1, { received: `${dataset.value.length}` });
277
+ return dataset;
278
+ }
279
+ };
280
+ }
281
+ function minValue(requirement, message$1) {
282
+ return {
283
+ kind: "validation",
284
+ type: "min_value",
285
+ reference: minValue,
286
+ async: false,
287
+ expects: `>=${requirement instanceof Date ? requirement.toJSON() : /* @__PURE__ */ _stringify(requirement)}`,
288
+ requirement,
289
+ message: message$1,
290
+ "~run"(dataset, config$1) {
291
+ if (dataset.typed && !(dataset.value >= this.requirement))
292
+ _addIssue(this, "value", dataset, config$1, { received: dataset.value instanceof Date ? dataset.value.toJSON() : /* @__PURE__ */ _stringify(dataset.value) });
293
+ return dataset;
294
+ }
295
+ };
296
+ }
297
+ function regex(requirement, message$1) {
298
+ return {
299
+ kind: "validation",
300
+ type: "regex",
301
+ reference: regex,
302
+ async: false,
303
+ expects: `${requirement}`,
304
+ requirement,
305
+ message: message$1,
306
+ "~run"(dataset, config$1) {
307
+ if (dataset.typed && !this.requirement.test(dataset.value))
308
+ _addIssue(this, "format", dataset, config$1);
309
+ return dataset;
310
+ }
311
+ };
312
+ }
313
+ function getFallback(schema, dataset, config$1) {
314
+ return typeof schema.fallback === "function" ? schema.fallback(dataset, config$1) : schema.fallback;
315
+ }
316
+ function getDefault(schema, dataset, config$1) {
317
+ return typeof schema.default === "function" ? schema.default(dataset, config$1) : schema.default;
318
+ }
319
+ function array(item, message$1) {
320
+ return {
321
+ kind: "schema",
322
+ type: "array",
323
+ reference: array,
324
+ expects: "Array",
325
+ async: false,
326
+ item,
327
+ message: message$1,
328
+ get "~standard"() {
329
+ return /* @__PURE__ */ _getStandardProps(this);
330
+ },
331
+ "~run"(dataset, config$1) {
332
+ const input = dataset.value;
333
+ if (Array.isArray(input)) {
334
+ dataset.typed = true;
335
+ dataset.value = [];
336
+ for (let key = 0;key < input.length; key++) {
337
+ const value$1 = input[key];
338
+ const itemDataset = this.item["~run"]({ value: value$1 }, config$1);
339
+ if (itemDataset.issues) {
340
+ const pathItem = {
341
+ type: "array",
342
+ origin: "value",
343
+ input,
344
+ key,
345
+ value: value$1
346
+ };
347
+ for (const issue of itemDataset.issues) {
348
+ if (issue.path)
349
+ issue.path.unshift(pathItem);
350
+ else
351
+ issue.path = [pathItem];
352
+ dataset.issues?.push(issue);
353
+ }
354
+ if (!dataset.issues)
355
+ dataset.issues = itemDataset.issues;
356
+ if (config$1.abortEarly) {
357
+ dataset.typed = false;
358
+ break;
359
+ }
360
+ }
361
+ if (!itemDataset.typed)
362
+ dataset.typed = false;
363
+ dataset.value.push(itemDataset.value);
364
+ }
365
+ } else
366
+ _addIssue(this, "type", dataset, config$1);
367
+ return dataset;
368
+ }
369
+ };
370
+ }
371
+ function boolean(message$1) {
372
+ return {
373
+ kind: "schema",
374
+ type: "boolean",
375
+ reference: boolean,
376
+ expects: "boolean",
377
+ async: false,
378
+ message: message$1,
379
+ get "~standard"() {
380
+ return /* @__PURE__ */ _getStandardProps(this);
381
+ },
382
+ "~run"(dataset, config$1) {
383
+ if (typeof dataset.value === "boolean")
384
+ dataset.typed = true;
385
+ else
386
+ _addIssue(this, "type", dataset, config$1);
387
+ return dataset;
388
+ }
389
+ };
390
+ }
391
+ function number(message$1) {
392
+ return {
393
+ kind: "schema",
394
+ type: "number",
395
+ reference: number,
396
+ expects: "number",
397
+ async: false,
398
+ message: message$1,
399
+ get "~standard"() {
400
+ return /* @__PURE__ */ _getStandardProps(this);
401
+ },
402
+ "~run"(dataset, config$1) {
403
+ if (typeof dataset.value === "number" && !isNaN(dataset.value))
404
+ dataset.typed = true;
405
+ else
406
+ _addIssue(this, "type", dataset, config$1);
407
+ return dataset;
408
+ }
409
+ };
410
+ }
411
+ function object(entries$1, message$1) {
412
+ return {
413
+ kind: "schema",
414
+ type: "object",
415
+ reference: object,
416
+ expects: "Object",
417
+ async: false,
418
+ entries: entries$1,
419
+ message: message$1,
420
+ get "~standard"() {
421
+ return /* @__PURE__ */ _getStandardProps(this);
422
+ },
423
+ "~run"(dataset, config$1) {
424
+ const input = dataset.value;
425
+ if (input && typeof input === "object") {
426
+ dataset.typed = true;
427
+ dataset.value = {};
428
+ for (const key in this.entries) {
429
+ const valueSchema = this.entries[key];
430
+ if (key in input || (valueSchema.type === "exact_optional" || valueSchema.type === "optional" || valueSchema.type === "nullish") && valueSchema.default !== undefined) {
431
+ const value$1 = key in input ? input[key] : /* @__PURE__ */ getDefault(valueSchema);
432
+ const valueDataset = valueSchema["~run"]({ value: value$1 }, config$1);
433
+ if (valueDataset.issues) {
434
+ const pathItem = {
435
+ type: "object",
436
+ origin: "value",
437
+ input,
438
+ key,
439
+ value: value$1
440
+ };
441
+ for (const issue of valueDataset.issues) {
442
+ if (issue.path)
443
+ issue.path.unshift(pathItem);
444
+ else
445
+ issue.path = [pathItem];
446
+ dataset.issues?.push(issue);
447
+ }
448
+ if (!dataset.issues)
449
+ dataset.issues = valueDataset.issues;
450
+ if (config$1.abortEarly) {
451
+ dataset.typed = false;
452
+ break;
453
+ }
454
+ }
455
+ if (!valueDataset.typed)
456
+ dataset.typed = false;
457
+ dataset.value[key] = valueDataset.value;
458
+ } else if (valueSchema.fallback !== undefined)
459
+ dataset.value[key] = /* @__PURE__ */ getFallback(valueSchema);
460
+ else if (valueSchema.type !== "exact_optional" && valueSchema.type !== "optional" && valueSchema.type !== "nullish") {
461
+ _addIssue(this, "key", dataset, config$1, {
462
+ input: undefined,
463
+ expected: `"${key}"`,
464
+ path: [{
465
+ type: "object",
466
+ origin: "key",
467
+ input,
468
+ key,
469
+ value: input[key]
470
+ }]
471
+ });
472
+ if (config$1.abortEarly)
473
+ break;
474
+ }
475
+ }
476
+ } else
477
+ _addIssue(this, "type", dataset, config$1);
478
+ return dataset;
479
+ }
480
+ };
481
+ }
482
+ function optional(wrapped, default_) {
483
+ return {
484
+ kind: "schema",
485
+ type: "optional",
486
+ reference: optional,
487
+ expects: `(${wrapped.expects} | undefined)`,
488
+ async: false,
489
+ wrapped,
490
+ default: default_,
491
+ get "~standard"() {
492
+ return /* @__PURE__ */ _getStandardProps(this);
493
+ },
494
+ "~run"(dataset, config$1) {
495
+ if (dataset.value === undefined) {
496
+ if (this.default !== undefined)
497
+ dataset.value = /* @__PURE__ */ getDefault(this, dataset, config$1);
498
+ if (dataset.value === undefined) {
499
+ dataset.typed = true;
500
+ return dataset;
501
+ }
502
+ }
503
+ return this.wrapped["~run"](dataset, config$1);
504
+ }
505
+ };
506
+ }
507
+ function picklist(options, message$1) {
508
+ return {
509
+ kind: "schema",
510
+ type: "picklist",
511
+ reference: picklist,
512
+ expects: /* @__PURE__ */ _joinExpects(options.map(_stringify), "|"),
513
+ async: false,
514
+ options,
515
+ message: message$1,
516
+ get "~standard"() {
517
+ return /* @__PURE__ */ _getStandardProps(this);
518
+ },
519
+ "~run"(dataset, config$1) {
520
+ if (this.options.includes(dataset.value))
521
+ dataset.typed = true;
522
+ else
523
+ _addIssue(this, "type", dataset, config$1);
524
+ return dataset;
525
+ }
526
+ };
527
+ }
528
+ function record(key, value$1, message$1) {
529
+ return {
530
+ kind: "schema",
531
+ type: "record",
532
+ reference: record,
533
+ expects: "Object",
534
+ async: false,
535
+ key,
536
+ value: value$1,
537
+ message: message$1,
538
+ get "~standard"() {
539
+ return /* @__PURE__ */ _getStandardProps(this);
540
+ },
541
+ "~run"(dataset, config$1) {
542
+ const input = dataset.value;
543
+ if (input && typeof input === "object") {
544
+ dataset.typed = true;
545
+ dataset.value = {};
546
+ for (const entryKey in input)
547
+ if (/* @__PURE__ */ _isValidObjectKey(input, entryKey)) {
548
+ const entryValue = input[entryKey];
549
+ const keyDataset = this.key["~run"]({ value: entryKey }, config$1);
550
+ if (keyDataset.issues) {
551
+ const pathItem = {
552
+ type: "object",
553
+ origin: "key",
554
+ input,
555
+ key: entryKey,
556
+ value: entryValue
557
+ };
558
+ for (const issue of keyDataset.issues) {
559
+ issue.path = [pathItem];
560
+ dataset.issues?.push(issue);
561
+ }
562
+ if (!dataset.issues)
563
+ dataset.issues = keyDataset.issues;
564
+ if (config$1.abortEarly) {
565
+ dataset.typed = false;
566
+ break;
567
+ }
568
+ }
569
+ const valueDataset = this.value["~run"]({ value: entryValue }, config$1);
570
+ if (valueDataset.issues) {
571
+ const pathItem = {
572
+ type: "object",
573
+ origin: "value",
574
+ input,
575
+ key: entryKey,
576
+ value: entryValue
577
+ };
578
+ for (const issue of valueDataset.issues) {
579
+ if (issue.path)
580
+ issue.path.unshift(pathItem);
581
+ else
582
+ issue.path = [pathItem];
583
+ dataset.issues?.push(issue);
584
+ }
585
+ if (!dataset.issues)
586
+ dataset.issues = valueDataset.issues;
587
+ if (config$1.abortEarly) {
588
+ dataset.typed = false;
589
+ break;
590
+ }
591
+ }
592
+ if (!keyDataset.typed || !valueDataset.typed)
593
+ dataset.typed = false;
594
+ if (keyDataset.typed)
595
+ dataset.value[keyDataset.value] = valueDataset.value;
596
+ }
597
+ } else
598
+ _addIssue(this, "type", dataset, config$1);
599
+ return dataset;
600
+ }
601
+ };
602
+ }
603
+ function string(message$1) {
604
+ return {
605
+ kind: "schema",
606
+ type: "string",
607
+ reference: string,
608
+ expects: "string",
609
+ async: false,
610
+ message: message$1,
611
+ get "~standard"() {
612
+ return /* @__PURE__ */ _getStandardProps(this);
613
+ },
614
+ "~run"(dataset, config$1) {
615
+ if (typeof dataset.value === "string")
616
+ dataset.typed = true;
617
+ else
618
+ _addIssue(this, "type", dataset, config$1);
619
+ return dataset;
620
+ }
621
+ };
622
+ }
623
+ function unknown() {
624
+ return {
625
+ kind: "schema",
626
+ type: "unknown",
627
+ reference: unknown,
628
+ expects: "unknown",
629
+ async: false,
630
+ get "~standard"() {
631
+ return /* @__PURE__ */ _getStandardProps(this);
632
+ },
633
+ "~run"(dataset) {
634
+ dataset.typed = true;
635
+ return dataset;
636
+ }
637
+ };
638
+ }
639
+ function pipe(...pipe$1) {
640
+ return {
641
+ ...pipe$1[0],
642
+ pipe: pipe$1,
643
+ get "~standard"() {
644
+ return /* @__PURE__ */ _getStandardProps(this);
645
+ },
646
+ "~run"(dataset, config$1) {
647
+ for (const item of pipe$1)
648
+ if (item.kind !== "metadata") {
649
+ if (dataset.issues && (item.kind === "schema" || item.kind === "transformation")) {
650
+ dataset.typed = false;
651
+ break;
652
+ }
653
+ if (!dataset.issues || !config$1.abortEarly && !config$1.abortPipeEarly)
654
+ dataset = item["~run"](dataset, config$1);
655
+ }
656
+ return dataset;
657
+ }
658
+ };
659
+ }
660
+ function safeParse(schema, input, config$1) {
661
+ const dataset = schema["~run"]({ value: input }, /* @__PURE__ */ getGlobalConfig(config$1));
662
+ return {
663
+ typed: dataset.typed,
664
+ success: !dataset.issues,
665
+ output: dataset.value,
666
+ issues: dataset.issues
667
+ };
668
+ }
669
+
670
+ // src/core/schemas.ts
671
+ var NationalAddressSchema = object({
672
+ shortCode: pipe(string(), minLength(1)),
673
+ buildingNumber: optional(string()),
674
+ streetName: optional(string()),
675
+ district: optional(string()),
676
+ additionalNumber: optional(string())
677
+ });
678
+ var AddressSchema = object({
679
+ name: pipe(string(), minLength(1, "Name is required")),
680
+ company: optional(string()),
681
+ email: optional(pipe(string(), email("Invalid email format"))),
682
+ phone: pipe(string(), minLength(1, "Phone is required")),
683
+ line1: pipe(string(), minLength(1, "Address line 1 is required")),
684
+ line2: optional(string()),
685
+ neighbourhood: optional(string()),
686
+ city: pipe(string(), minLength(1, "City is required")),
687
+ state: optional(string()),
688
+ postalCode: optional(string()),
689
+ countryCode: pipe(string(), length(2, "Country code must be ISO 3166-1 alpha-2 (2 characters)")),
690
+ coordinates: optional(object({
691
+ latitude: pipe(number(), minValue(-90), maxValue(90)),
692
+ longitude: pipe(number(), minValue(-180), maxValue(180))
693
+ })),
694
+ description: optional(string()),
695
+ nationalAddress: optional(NationalAddressSchema)
696
+ });
697
+ var WeightSchema = object({
698
+ value: pipe(number(), gtValue(0, "Weight must be positive")),
699
+ unit: picklist(["kg", "lb"])
700
+ });
701
+ var DimensionsSchema = object({
702
+ length: pipe(number(), gtValue(0, "Length must be positive")),
703
+ width: pipe(number(), gtValue(0, "Width must be positive")),
704
+ height: pipe(number(), gtValue(0, "Height must be positive")),
705
+ unit: picklist(["cm", "in"])
706
+ });
707
+ var ParcelSchema = object({
708
+ weight: WeightSchema,
709
+ dimensions: optional(DimensionsSchema),
710
+ pieces: pipe(number(), integer(), gtValue(0, "Pieces must be a positive integer")),
711
+ itemsCount: optional(pipe(number(), integer(), gtValue(0))),
712
+ description: optional(string())
713
+ });
714
+ var CODDetailsSchema = object({
715
+ enabled: boolean(),
716
+ amount: pipe(number(), minValue(0, "COD amount must be non-negative")),
717
+ currency: pipe(string(), minLength(1, "COD currency is required"))
718
+ });
719
+ var DeclaredValueSchema = object({
720
+ amount: pipe(number(), minValue(0, "Declared value must be non-negative")),
721
+ currency: pipe(string(), minLength(1, "Currency is required"))
722
+ });
723
+ var InternationalMetadataSchema = object({
724
+ taxId: optional(string()),
725
+ invoiceNumber: optional(string()),
726
+ invoiceDate: optional(string()),
727
+ documentId: optional(number())
728
+ });
729
+ var ShipmentOptionsSchema = object({
730
+ requestedBy: optional(string()),
731
+ isInsured: optional(boolean()),
732
+ customerTracking: optional(string()),
733
+ fulfilmentCustomerName: optional(string()),
734
+ internationalMetadata: optional(InternationalMetadataSchema),
735
+ metadata: optional(record(string(), unknown()))
736
+ });
737
+ var CreateShipmentInputSchema = object({
738
+ shipper: AddressSchema,
739
+ consignee: AddressSchema,
740
+ parcels: pipe(array(ParcelSchema), minLength(1, "At least one parcel is required")),
741
+ serviceType: optional(pipe(string(), minLength(1))),
742
+ reference: optional(string()),
743
+ cod: optional(CODDetailsSchema),
744
+ declaredValue: optional(DeclaredValueSchema),
745
+ labelFormat: optional(picklist(["PDF", "ZPL", "PNG"])),
746
+ options: optional(ShipmentOptionsSchema)
747
+ });
748
+ var PickupRequestSchema = object({
749
+ date: pipe(string(), regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be YYYY-MM-DD format")),
750
+ timeSlot: pipe(string(), minLength(1, "Time slot is required")),
751
+ city: pipe(string(), minLength(1, "City is required")),
752
+ contactName: pipe(string(), minLength(1, "Contact name is required")),
753
+ contactPhone: pipe(string(), minLength(1, "Contact phone is required")),
754
+ address: pipe(string(), minLength(1, "Address is required")),
755
+ shipmentCount: pipe(number(), integer(), gtValue(0, "Shipment count must be a positive integer")),
756
+ trackingNumbers: optional(array(string()))
757
+ });
758
+ var WebhookConfigSchema = object({
759
+ authHeader: optional(string()),
760
+ authValue: optional(string()),
761
+ authQueryParam: optional(string()),
762
+ authQueryValue: optional(string())
763
+ });
764
+ function formatIssues(issues) {
765
+ return issues.map((issue) => ({
766
+ path: getDotPath(issue) ?? "",
767
+ message: issue.message
768
+ }));
769
+ }
770
+ function validateCreateShipmentInput(input) {
771
+ const result = safeParse(CreateShipmentInputSchema, input);
772
+ if (!result.success) {
773
+ throw new ValidationError("Invalid shipment input", {
774
+ issues: formatIssues(result.issues),
775
+ raw: input
776
+ });
777
+ }
778
+ return result.output;
779
+ }
780
+ function validatePickupRequest(input) {
781
+ const result = safeParse(PickupRequestSchema, input);
782
+ if (!result.success) {
783
+ throw new ValidationError("Invalid pickup request", {
784
+ issues: formatIssues(result.issues),
785
+ raw: input
786
+ });
787
+ }
788
+ return result.output;
789
+ }
790
+
791
+ // src/carriers/base.ts
792
+ class BaseCarrierAdapter {
793
+ config;
794
+ constructor(config) {
795
+ this.config = config;
796
+ }
797
+ async createShipment(input) {
798
+ validateCreateShipmentInput(input);
799
+ return this.executeCreateShipment(input);
800
+ }
801
+ }
802
+
803
+ // src/core/retry.ts
804
+ import { setTimeout as sleep } from "node:timers/promises";
805
+ async function withRetry(fn, options) {
806
+ const {
807
+ retries,
808
+ baseMs = 500,
809
+ maxMs = 20000,
810
+ inlineCapMs = 15000,
811
+ shouldRetry,
812
+ retryAfterMs,
813
+ signal
814
+ } = options;
815
+ for (let attempt = 0;; attempt++) {
816
+ try {
817
+ return await fn();
818
+ } catch (error) {
819
+ if (attempt >= retries || !shouldRetry(error))
820
+ throw error;
821
+ const retryAfter = retryAfterMs?.(error);
822
+ let delay;
823
+ if (retryAfter != null) {
824
+ if (retryAfter > inlineCapMs)
825
+ throw error;
826
+ delay = retryAfter + Math.random() * 1000;
827
+ } else {
828
+ delay = Math.random() * Math.min(maxMs, baseMs * 2 ** attempt);
829
+ }
830
+ try {
831
+ await sleep(delay, undefined, { signal });
832
+ } catch {
833
+ throw error;
834
+ }
835
+ }
836
+ }
837
+ }
838
+ function parseRetryAfter(headerValue) {
839
+ if (headerValue == null)
840
+ return;
841
+ const trimmed = headerValue.trim();
842
+ if (trimmed === "")
843
+ return;
844
+ if (/^\d+$/.test(trimmed))
845
+ return Number(trimmed) * 1000;
846
+ const date = Date.parse(trimmed);
847
+ if (Number.isNaN(date))
848
+ return;
849
+ return Math.max(0, date - Date.now());
850
+ }
851
+
852
+ // src/core/http.ts
853
+ class HttpClient {
854
+ config;
855
+ retryConfig;
856
+ static DEFAULT_RETRYABLE = [429, 500, 502, 503, 504];
857
+ static SAFE_METHODS = new Set(["GET", "HEAD", "OPTIONS"]);
858
+ constructor(config) {
859
+ this.config = {
860
+ ...config,
861
+ timeout: config.timeout ?? 30000
862
+ };
863
+ const retry = config.retry === false ? { retries: 0 } : config.retry ?? {};
864
+ this.retryConfig = {
865
+ retries: retry.retries ?? 2,
866
+ retryableStatuses: retry.retryableStatuses ?? HttpClient.DEFAULT_RETRYABLE,
867
+ baseMs: retry.baseMs ?? 500,
868
+ maxMs: retry.maxMs ?? 20000,
869
+ inlineCapMs: retry.inlineCapMs ?? 15000
870
+ };
871
+ }
872
+ async request(endpoint, options = {}) {
873
+ const method = options.method ?? "GET";
874
+ const shouldRetry = this.shouldRetry(method, options.retry);
875
+ if (!shouldRetry) {
876
+ return this.executeRequest(endpoint, options);
877
+ }
878
+ return withRetry(() => this.executeRequest(endpoint, options), {
879
+ retries: this.retryConfig.retries,
880
+ baseMs: this.retryConfig.baseMs,
881
+ maxMs: this.retryConfig.maxMs,
882
+ inlineCapMs: this.retryConfig.inlineCapMs,
883
+ shouldRetry: (error) => this.isRetryable(error),
884
+ retryAfterMs: (error) => error instanceof RateLimitError ? error.retryAfterMs : undefined,
885
+ signal: options.signal
886
+ });
887
+ }
888
+ shouldRetry(method, requestRetry) {
889
+ if (this.retryConfig.retries === 0)
890
+ return false;
891
+ if (requestRetry !== undefined)
892
+ return requestRetry;
893
+ return HttpClient.SAFE_METHODS.has(method);
894
+ }
895
+ isRetryable(error) {
896
+ if (error instanceof NetworkError)
897
+ return true;
898
+ if (error instanceof RateLimitError)
899
+ return true;
900
+ if (error instanceof APIError && error.statusCode != null) {
901
+ return this.retryConfig.retryableStatuses.includes(error.statusCode);
902
+ }
903
+ return false;
904
+ }
905
+ async executeRequest(endpoint, options = {}) {
906
+ const {
907
+ method = "GET",
908
+ headers = {},
909
+ body,
910
+ params,
911
+ errorExtractor,
912
+ signal: callerSignal
913
+ } = options;
914
+ let url = `${this.config.baseUrl}${endpoint}`;
915
+ if (params) {
916
+ const searchParams = new URLSearchParams;
917
+ for (const [key, value] of Object.entries(params)) {
918
+ if (value !== undefined) {
919
+ searchParams.set(key, String(value));
920
+ }
921
+ }
922
+ const queryString = searchParams.toString();
923
+ if (queryString) {
924
+ url += `?${queryString}`;
925
+ }
926
+ }
927
+ const timeoutSignal = AbortSignal.timeout(this.config.timeout);
928
+ const signal = callerSignal ? AbortSignal.any([callerSignal, timeoutSignal]) : timeoutSignal;
929
+ try {
930
+ const response = await fetch(url, {
931
+ method,
932
+ headers: {
933
+ "Content-Type": "application/json",
934
+ Accept: "application/json",
935
+ ...this.config.headers,
936
+ ...headers
937
+ },
938
+ body: body ? JSON.stringify(body) : undefined,
939
+ signal
940
+ });
941
+ let json;
942
+ const contentType = response.headers.get("content-type") ?? "";
943
+ if (contentType.includes("application/json")) {
944
+ json = await response.json();
945
+ } else {
946
+ const text = await response.text();
947
+ try {
948
+ json = JSON.parse(text);
949
+ } catch {
950
+ json = text;
951
+ }
952
+ }
953
+ if (!response.ok) {
954
+ const retryAfterMs = response.status === 429 || response.status === 503 ? parseRetryAfter(response.headers.get("retry-after")) : undefined;
955
+ this.handleHttpError(response.status, json, retryAfterMs);
956
+ }
957
+ if (errorExtractor) {
958
+ const extracted = errorExtractor(json);
959
+ if (extracted.hasError) {
960
+ if (extracted.rateLimited) {
961
+ throw new RateLimitError(extracted.message ?? "Carrier rate limit", {
962
+ carrier: this.config.carrier,
963
+ statusCode: 200,
964
+ errors: extracted.errors,
965
+ retryAfterMs: extracted.retryAfterMs,
966
+ raw: json
967
+ });
968
+ }
969
+ throw new APIError(extracted.message ?? "API returned an error", {
970
+ carrier: this.config.carrier,
971
+ statusCode: 200,
972
+ errors: extracted.errors,
973
+ raw: json
974
+ });
975
+ }
976
+ }
977
+ return json;
978
+ } catch (error) {
979
+ if (error instanceof ShipFlowError) {
980
+ throw error;
981
+ }
982
+ if (callerSignal?.aborted) {
983
+ throw error;
984
+ }
985
+ if (error instanceof DOMException && (error.name === "TimeoutError" || error.name === "AbortError")) {
986
+ throw new NetworkError(`Request timeout after ${this.config.timeout}ms`, {
987
+ carrier: this.config.carrier
988
+ });
989
+ }
990
+ if (error instanceof TypeError && error.message.includes("fetch")) {
991
+ throw new NetworkError(`Network error: ${error.message}`, {
992
+ carrier: this.config.carrier,
993
+ cause: error
994
+ });
995
+ }
996
+ throw new NetworkError(`Unexpected error: ${error.message}`, {
997
+ carrier: this.config.carrier,
998
+ cause: error
999
+ });
1000
+ }
1001
+ }
1002
+ handleHttpError(status, json, retryAfterMs) {
1003
+ const message = this.extractErrorMessage(json) ?? `HTTP ${status}`;
1004
+ if (status === 401) {
1005
+ throw new AuthenticationError(message, {
1006
+ carrier: this.config.carrier,
1007
+ raw: json
1008
+ });
1009
+ }
1010
+ if (status === 429 || status === 503) {
1011
+ throw new RateLimitError(message, {
1012
+ carrier: this.config.carrier,
1013
+ statusCode: status,
1014
+ errors: this.extractValidationErrors(json),
1015
+ retryAfterMs,
1016
+ raw: json
1017
+ });
1018
+ }
1019
+ throw new APIError(message, {
1020
+ carrier: this.config.carrier,
1021
+ statusCode: status,
1022
+ errors: this.extractValidationErrors(json),
1023
+ raw: json
1024
+ });
1025
+ }
1026
+ extractErrorMessage(json) {
1027
+ if (typeof json === "string")
1028
+ return json.trim() || undefined;
1029
+ if (!json || typeof json !== "object")
1030
+ return;
1031
+ const obj = json;
1032
+ if (typeof obj.message === "string")
1033
+ return obj.message;
1034
+ if (typeof obj.error === "string")
1035
+ return obj.error;
1036
+ if (typeof obj.response === "string")
1037
+ return obj.response;
1038
+ if (obj.Message && typeof obj.Message === "string")
1039
+ return obj.Message;
1040
+ return;
1041
+ }
1042
+ extractValidationErrors(json) {
1043
+ if (!json || typeof json !== "object")
1044
+ return;
1045
+ const obj = json;
1046
+ if (obj.errors && typeof obj.errors === "object") {
1047
+ return obj.errors;
1048
+ }
1049
+ return;
1050
+ }
1051
+ get(endpoint, options) {
1052
+ return this.request(endpoint, { ...options, method: "GET" });
1053
+ }
1054
+ post(endpoint, body, options) {
1055
+ return this.request(endpoint, { ...options, method: "POST", body });
1056
+ }
1057
+ put(endpoint, body, options) {
1058
+ return this.request(endpoint, { ...options, method: "PUT", body });
1059
+ }
1060
+ delete(endpoint, options) {
1061
+ return this.request(endpoint, { ...options, method: "DELETE" });
1062
+ }
1063
+ }
1064
+
1065
+ export { ShipFlowError, NetworkError, APIError, RateLimitError, ValidationError, AuthenticationError, WebhookVerificationError, UnsupportedOperationError, AddressSchema, WeightSchema, DimensionsSchema, ParcelSchema, CODDetailsSchema, DeclaredValueSchema, CreateShipmentInputSchema, PickupRequestSchema, WebhookConfigSchema, validateCreateShipmentInput, validatePickupRequest, BaseCarrierAdapter, HttpClient };
1066
+
1067
+ //# debugId=B88EAD18635FEEDC64756E2164756E21