@shopickup/adapters-foxpost 0.0.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 (47) hide show
  1. package/README.md +48 -0
  2. package/dist/capabilities/index.d.ts +9 -0
  3. package/dist/capabilities/index.d.ts.map +1 -0
  4. package/dist/capabilities/index.js +8 -0
  5. package/dist/capabilities/label.d.ts +27 -0
  6. package/dist/capabilities/label.d.ts.map +1 -0
  7. package/dist/capabilities/label.js +370 -0
  8. package/dist/capabilities/parcels.d.ts +21 -0
  9. package/dist/capabilities/parcels.d.ts.map +1 -0
  10. package/dist/capabilities/parcels.js +233 -0
  11. package/dist/capabilities/pickup-points.d.ts +38 -0
  12. package/dist/capabilities/pickup-points.d.ts.map +1 -0
  13. package/dist/capabilities/pickup-points.js +225 -0
  14. package/dist/capabilities/track.d.ts +16 -0
  15. package/dist/capabilities/track.d.ts.map +1 -0
  16. package/dist/capabilities/track.js +99 -0
  17. package/dist/client/index.d.ts +17 -0
  18. package/dist/client/index.d.ts.map +1 -0
  19. package/dist/client/index.js +30 -0
  20. package/dist/errors.d.ts +34 -0
  21. package/dist/errors.d.ts.map +1 -0
  22. package/dist/errors.js +165 -0
  23. package/dist/index.d.ts +119 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +151 -0
  26. package/dist/mappers/index.d.ts +108 -0
  27. package/dist/mappers/index.d.ts.map +1 -0
  28. package/dist/mappers/index.js +270 -0
  29. package/dist/mappers/trackStatus.d.ts +58 -0
  30. package/dist/mappers/trackStatus.d.ts.map +1 -0
  31. package/dist/mappers/trackStatus.js +290 -0
  32. package/dist/types/generated.d.ts +177 -0
  33. package/dist/types/generated.d.ts.map +1 -0
  34. package/dist/types/generated.js +9 -0
  35. package/dist/types/index.d.ts +7 -0
  36. package/dist/types/index.d.ts.map +1 -0
  37. package/dist/types/index.js +6 -0
  38. package/dist/utils/httpUtils.d.ts +18 -0
  39. package/dist/utils/httpUtils.d.ts.map +1 -0
  40. package/dist/utils/httpUtils.js +33 -0
  41. package/dist/utils/resolveBaseUrl.d.ts +23 -0
  42. package/dist/utils/resolveBaseUrl.d.ts.map +1 -0
  43. package/dist/utils/resolveBaseUrl.js +19 -0
  44. package/dist/validation.d.ts +1723 -0
  45. package/dist/validation.d.ts.map +1 -0
  46. package/dist/validation.js +799 -0
  47. package/package.json +68 -0
@@ -0,0 +1,34 @@
1
+ import { CarrierError } from "@shopickup/core";
2
+ /**
3
+ * Translate Foxpost errors to structured CarrierError
4
+ *
5
+ * Supports errors from any HTTP client implementation:
6
+ * - axios
7
+ * - node-fetch
8
+ * - undici
9
+ * - custom HTTP clients
10
+ * - network errors
11
+ *
12
+ * Error categorization:
13
+ * - 400: Validation (client error, don't retry)
14
+ * - 401/403: Auth (authentication failure, check credentials)
15
+ * - 429: RateLimit (rate limited, retry with backoff)
16
+ * - 5xx: Transient (server error, retry)
17
+ * - Network: Transient (connection issue, retry)
18
+ */
19
+ export declare function translateFoxpostError(error: unknown): CarrierError;
20
+ /**
21
+ * Sanitize an HTTP response object for safe logging
22
+ * Removes sensitive headers (Authorization, Api-key, etc.) before serialization
23
+ *
24
+ * Safely handles various HTTP client response shapes:
25
+ * - axios: { data, status, headers, config }
26
+ * - fetch: { status, headers, body }
27
+ * - undici: { status, headers, body }
28
+ * - custom: any object with headers property
29
+ *
30
+ * @param response HTTP response object (may be from any HTTP client)
31
+ * @returns Sanitized copy safe for logging (original not modified)
32
+ */
33
+ export declare function sanitizeResponseForLog(response: unknown): unknown;
34
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA0C,MAAM,iBAAiB,CAAC;AAiFvF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,CAiElE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAqCjE"}
package/dist/errors.js ADDED
@@ -0,0 +1,165 @@
1
+ import { CarrierError, sanitizeHeadersForLog } from "@shopickup/core";
2
+ /**
3
+ * Foxpost-specific error code translations
4
+ */
5
+ const FoxpostErrorCodes = {
6
+ WRONG_USERNAME_OR_PASSWORD: {
7
+ category: "Auth",
8
+ message: "Invalid Foxpost credentials",
9
+ },
10
+ INVALID_APM_ID: {
11
+ category: "Validation",
12
+ message: "Invalid APM (locker) ID",
13
+ },
14
+ INVALID_RECIPIENT: {
15
+ category: "Validation",
16
+ message: "Invalid recipient information",
17
+ },
18
+ INVALID_ADDRESS: {
19
+ category: "Validation",
20
+ message: "Invalid address provided",
21
+ },
22
+ };
23
+ /**
24
+ * Extract HTTP status code from error object
25
+ * Works with errors from different HTTP clients (axios, fetch, undici, custom)
26
+ *
27
+ * Supports common error shapes:
28
+ * - axios: error.response.status
29
+ * - fetch: error.status (when wrapped)
30
+ * - undici: error.statusCode
31
+ * - generic: error.response?.status or error.status
32
+ */
33
+ function extractHttpStatus(error) {
34
+ const anyErr = error;
35
+ // Try multiple common locations for HTTP status
36
+ return (anyErr?.response?.status ?? // axios, fetch-like wrappers
37
+ anyErr?.status ?? // direct status property
38
+ anyErr?.statusCode ?? // undici, some node wrappers
39
+ anyErr?.code === 'ECONNREFUSED' ? undefined : undefined // network error, not HTTP status
40
+ );
41
+ }
42
+ /**
43
+ * Extract response body from error object
44
+ * Works with errors from different HTTP clients
45
+ *
46
+ * Supports common error shapes:
47
+ * - axios: error.response.data
48
+ * - fetch: error.response?.json() or error.data
49
+ * - undici: error.body or error.data
50
+ */
51
+ function extractResponseBody(error) {
52
+ const anyErr = error;
53
+ return (anyErr?.response?.data ?? // axios, generic response objects
54
+ anyErr?.data ?? // direct data property (undici, fetch wrappers)
55
+ anyErr?.body ?? // node-fetch, undici
56
+ anyErr?.response // fallback to whole response
57
+ );
58
+ }
59
+ /**
60
+ * Extract error code from response body
61
+ * Looks for common field names across different APIs
62
+ */
63
+ function extractErrorCode(responseBody) {
64
+ const body = responseBody;
65
+ return (body?.error ?? // common JSON API error field
66
+ body?.code ?? // error code field
67
+ body?.errorCode ?? // camelCase variant
68
+ body?.error_code // snake_case variant
69
+ );
70
+ }
71
+ /**
72
+ * Translate Foxpost errors to structured CarrierError
73
+ *
74
+ * Supports errors from any HTTP client implementation:
75
+ * - axios
76
+ * - node-fetch
77
+ * - undici
78
+ * - custom HTTP clients
79
+ * - network errors
80
+ *
81
+ * Error categorization:
82
+ * - 400: Validation (client error, don't retry)
83
+ * - 401/403: Auth (authentication failure, check credentials)
84
+ * - 429: RateLimit (rate limited, retry with backoff)
85
+ * - 5xx: Transient (server error, retry)
86
+ * - Network: Transient (connection issue, retry)
87
+ */
88
+ export function translateFoxpostError(error) {
89
+ const anyErr = error;
90
+ // Extract common error properties in a client-agnostic way
91
+ const status = extractHttpStatus(error);
92
+ const responseBody = extractResponseBody(error);
93
+ const errorCode = extractErrorCode(responseBody) || (typeof status === 'number' ? `HTTP_${status}` : undefined);
94
+ const errorMapping = errorCode ? FoxpostErrorCodes[errorCode] : undefined;
95
+ // Construct metadata with all available context
96
+ const meta = {
97
+ carrierCode: errorCode,
98
+ raw: responseBody ?? anyErr,
99
+ };
100
+ // Route by HTTP status code
101
+ if (typeof status === 'number') {
102
+ if (status === 400) {
103
+ return new CarrierError(`Validation error: ${errorMapping?.message || responseBody?.error || "Bad request"}`, "Validation", meta);
104
+ }
105
+ if (status === 401 || status === 403) {
106
+ return new CarrierError("Foxpost credentials invalid", "Auth", meta);
107
+ }
108
+ if (status === 429) {
109
+ return new CarrierError("Foxpost rate limit exceeded", "RateLimit", { ...meta, retryAfterMs: 60000 });
110
+ }
111
+ if (status >= 500) {
112
+ return new CarrierError("Foxpost server error", "Transient", meta);
113
+ }
114
+ }
115
+ // Network error (Error instance with no HTTP status)
116
+ if (error instanceof Error) {
117
+ return new CarrierError(`Foxpost connection error: ${error.message}`, "Transient", { raw: anyErr });
118
+ }
119
+ // Unknown error shape
120
+ return new CarrierError("Unknown Foxpost error", "Permanent", { raw: anyErr });
121
+ }
122
+ /**
123
+ * Sanitize an HTTP response object for safe logging
124
+ * Removes sensitive headers (Authorization, Api-key, etc.) before serialization
125
+ *
126
+ * Safely handles various HTTP client response shapes:
127
+ * - axios: { data, status, headers, config }
128
+ * - fetch: { status, headers, body }
129
+ * - undici: { status, headers, body }
130
+ * - custom: any object with headers property
131
+ *
132
+ * @param response HTTP response object (may be from any HTTP client)
133
+ * @returns Sanitized copy safe for logging (original not modified)
134
+ */
135
+ export function sanitizeResponseForLog(response) {
136
+ if (!response || typeof response !== 'object') {
137
+ return response;
138
+ }
139
+ const resp = response;
140
+ // Create a shallow copy to avoid modifying original
141
+ const sanitized = {};
142
+ for (const [key, value] of Object.entries(resp)) {
143
+ // Always skip request body (should not be in response, but be safe)
144
+ if (key === 'body' && typeof value === 'string' && value.length > 10000) {
145
+ sanitized[key] = '[Large binary or text body - truncated for logging]';
146
+ continue;
147
+ }
148
+ // Sanitize headers property if present
149
+ if (key === 'headers' && typeof value === 'object') {
150
+ sanitized[key] = sanitizeHeadersForLog(value);
151
+ continue;
152
+ }
153
+ // Sanitize config.headers (axios pattern)
154
+ if (key === 'config' && typeof value === 'object') {
155
+ sanitized[key] = {
156
+ ...value,
157
+ headers: sanitizeHeadersForLog(value?.headers),
158
+ };
159
+ continue;
160
+ }
161
+ // Include all other properties as-is
162
+ sanitized[key] = value;
163
+ }
164
+ return sanitized;
165
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Foxpost Carrier Adapter
3
+ * Implements the CarrierAdapter interface for Foxpost logistics
4
+ */
5
+ import type { CarrierAdapter, Capability, AdapterContext, CreateParcelRequest, CreateParcelsRequest, TrackingRequest, RatesRequest, CreateParcelsResponse, CreateLabelRequest, CreateLabelResponse, CreateLabelsRequest, CreateLabelsResponse, CarrierResource, TrackingUpdate, FetchPickupPointsRequest, FetchPickupPointsResponse } from "@shopickup/core";
6
+ /**
7
+ * FoxpostAdapter
8
+ *
9
+ * Foxpost (hu-foxpost) is a major Hungarian logistics carrier.
10
+ *
11
+ * Capabilities supported:
12
+ * - CREATE_PARCEL: Create parcels directly
13
+ * - CREATE_PARCELS: Batch create multiple parcels
14
+ * - CREATE_LABEL: Generate PDF labels for parcels
15
+ * - TRACK: Track parcels by barcode
16
+ * - TEST_MODE_SUPPORTED: Can switch to test API for sandbox testing
17
+ *
18
+ * Test API:
19
+ * - Production: https://webapi.foxpost.hu
20
+ * - Test/Sandbox: https://webapi-test.foxpost.hu
21
+ * - Pass options.useTestApi = true in request to switch to test endpoint for that call
22
+ * - Test API requires separate test credentials
23
+ *
24
+ * Notes:
25
+ * - Foxpost does NOT have a shipment concept; parcels are created directly
26
+ * - Labels are generated per parcel
27
+ * - Tracking available via barcode (FoxWeb barcode format: CLFOX...)
28
+ * - createLabel does not support per-call test mode (no request object in interface)
29
+ */
30
+ export declare class FoxpostAdapter implements CarrierAdapter {
31
+ readonly id = "hu-foxpost";
32
+ readonly displayName = "Foxpost Hungary";
33
+ readonly capabilities: Capability[];
34
+ readonly requires: {
35
+ createLabel: "CREATE_PARCEL"[];
36
+ };
37
+ private prodBaseUrl;
38
+ private testBaseUrl;
39
+ private resolveBaseUrl;
40
+ constructor(baseUrl?: string);
41
+ /**
42
+ * Create a parcel in Foxpost
43
+ *
44
+ * Note: Shipper information is not sent to Foxpost API.
45
+ * Foxpost derives the shipper from the API key's account settings.
46
+ * We require shipper in the core Parcel type for consistency across adapters.
47
+ *
48
+ * Maps canonical Parcel to Foxpost CreateParcelRequest (and carrier-specific type)
49
+ * Returns the parcel barcode as carrierId
50
+ */
51
+ createParcel(req: CreateParcelRequest, ctx: AdapterContext): Promise<CarrierResource>;
52
+ /**
53
+ * Create multiple parcels in one call
54
+ * Maps canonical Parcel array to Foxpost CreateParcelRequest and calls the
55
+ * Foxpost batch endpoint which accepts an array. Returns per-item CarrierResource
56
+ * so callers can handle partial failures.
57
+ *
58
+ * Validates both the incoming parcels and the mapped carrier-specific payloads.
59
+ *
60
+ * @returns CreateParcelsResponse with summary and per-item results
61
+ */
62
+ createParcels(req: CreateParcelsRequest, ctx: AdapterContext): Promise<CreateParcelsResponse>;
63
+ /**
64
+ * Create a label (generate PDF) for a parcel
65
+ *
66
+ * @param req CreateLabelRequest with parcelCarrierId (Foxpost barcode)
67
+ * @param ctx AdapterContext with HTTP client and logger
68
+ * @returns LabelResult with file mapping and page range
69
+ */
70
+ createLabel(req: CreateLabelRequest, ctx: AdapterContext): Promise<CreateLabelResponse>;
71
+ /**
72
+ * Create labels for multiple parcels in one batch call
73
+ *
74
+ * Generates a single PDF with all requested labels using Foxpost POST /api/label/{pageSize}
75
+ * Returns per-item results for tracking success/failure of each label
76
+ *
77
+ * @param req CreateLabelsRequest with array of parcelCarrierIds
78
+ * @param ctx AdapterContext with HTTP client and logger
79
+ * @returns CreateLabelsResponse with per-item results and summary
80
+ */
81
+ createLabels(req: CreateLabelsRequest, ctx: AdapterContext): Promise<CreateLabelsResponse>;
82
+ /**
83
+ * NOT IMPLEMENTED: Foxpost doesn't support voiding labels
84
+ */
85
+ voidLabel(_labelId: string, _ctx: AdapterContext): Promise<CarrierResource>;
86
+ /**
87
+ * Track a parcel by its clFoxId or uniqueBarcode using the new GET /api/tracking/{barcode} endpoint
88
+ *
89
+ * Returns normalized tracking information with all available traces in reverse chronological order
90
+ *
91
+ * To use test API, pass in request as:
92
+ * { trackingNumber: barcode, credentials: {...}, options?: { useTestApi: true } }
93
+ */
94
+ track(req: TrackingRequest, ctx: AdapterContext): Promise<TrackingUpdate>;
95
+ /**
96
+ * Fetch list of Foxpost pickup points (APMs)
97
+ *
98
+ * Fetches the public JSON feed from https://cdn.foxpost.hu/foxplus.json
99
+ * which is updated hourly and contains all active APM locations.
100
+ *
101
+ * No authentication is required as this is a public feed.
102
+ *
103
+ * @param req FetchPickupPointsRequest (optional filters)
104
+ * @param ctx AdapterContext with HTTP client
105
+ * @returns FetchPickupPointsResponse with normalized pickup points
106
+ */
107
+ fetchPickupPoints(req: FetchPickupPointsRequest, ctx: AdapterContext): Promise<FetchPickupPointsResponse>;
108
+ /**
109
+ * NOT IMPLEMENTED: Foxpost doesn't support pickup requests
110
+ */
111
+ requestPickup(_req: any, _ctx: AdapterContext): Promise<CarrierResource>;
112
+ /**
113
+ * NOT IMPLEMENTED: Foxpost doesn't expose rate quotes
114
+ */
115
+ getRates(_req: RatesRequest, _ctx: AdapterContext): Promise<any>;
116
+ }
117
+ export default FoxpostAdapter;
118
+ export { safeValidateTrackingRequest, safeValidateFoxpostTracking, validateFoxpostTracking, safeValidateFoxpostCredentials, validateFoxpostCredentials, type FoxpostTracking, type FoxpostTrace, type FoxpostTrackDTO, } from './validation.js';
119
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,UAAU,EACV,cAAc,EACd,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,EACf,YAAY,EACZ,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,EACf,cAAc,EACd,wBAAwB,EACxB,yBAAyB,EAC1B,MAAM,iBAAiB,CAAC;AAgBzB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,cAAe,YAAW,cAAc;IACnD,QAAQ,CAAC,EAAE,gBAAgB;IAC3B,QAAQ,CAAC,WAAW,qBAAqB;IAEzC,QAAQ,CAAC,YAAY,EAAE,UAAU,EAAE,CAOjC;IAGF,QAAQ,CAAC,QAAQ;;MAEf;IAEF,OAAO,CAAC,WAAW,CAA+B;IAClD,OAAO,CAAC,WAAW,CAAoC;IACvD,OAAO,CAAC,cAAc,CAAiB;gBAE3B,OAAO,GAAE,MAAoC;IAMzD;;;;;;;;;OASG;IACG,YAAY,CAChB,GAAG,EAAE,mBAAmB,EACxB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,eAAe,CAAC;IAM3B;;;;;;;;;OASG;IACG,aAAa,CACjB,GAAG,EAAE,oBAAoB,EACzB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,qBAAqB,CAAC;IAIjC;;;;;;OAMG;IACG,WAAW,CACf,GAAG,EAAE,kBAAkB,EACvB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,mBAAmB,CAAC;IAI/B;;;;;;;;;OASG;IACG,YAAY,CAChB,GAAG,EAAE,mBAAmB,EACxB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,oBAAoB,CAAC;IAIhC;;OAEG;IACG,SAAS,CACb,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,eAAe,CAAC;IAI3B;;;;;;;OAOG;IACG,KAAK,CACT,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,cAAc,CAAC;IAI1B;;;;;;;;;;;OAWG;IACG,iBAAiB,CACrB,GAAG,EAAE,wBAAwB,EAC7B,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,yBAAyB,CAAC;IAIrC;;OAEG;IACG,aAAa,CACjB,IAAI,EAAE,GAAG,EACT,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,eAAe,CAAC;IAI3B;;OAEG;IACG,QAAQ,CACZ,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,GAAG,CAAC;CAGhB;AAED,eAAe,cAAc,CAAC;AAG9B,OAAO,EACL,2BAA2B,EAC3B,2BAA2B,EAC3B,uBAAuB,EACvB,8BAA8B,EAC9B,0BAA0B,EAC1B,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,eAAe,GACrB,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Foxpost Carrier Adapter
3
+ * Implements the CarrierAdapter interface for Foxpost logistics
4
+ */
5
+ import { Capabilities, NotImplementedError } from "@shopickup/core";
6
+ import { createParcel as createParcelImpl, createParcels as createParcelsImpl, createLabel as createLabelImpl, createLabels as createLabelsImpl, track as trackImpl, fetchPickupPoints as fetchPickupPointsImpl, } from './capabilities/index.js';
7
+ import { createResolveBaseUrl } from './utils/resolveBaseUrl.js';
8
+ /**
9
+ * FoxpostAdapter
10
+ *
11
+ * Foxpost (hu-foxpost) is a major Hungarian logistics carrier.
12
+ *
13
+ * Capabilities supported:
14
+ * - CREATE_PARCEL: Create parcels directly
15
+ * - CREATE_PARCELS: Batch create multiple parcels
16
+ * - CREATE_LABEL: Generate PDF labels for parcels
17
+ * - TRACK: Track parcels by barcode
18
+ * - TEST_MODE_SUPPORTED: Can switch to test API for sandbox testing
19
+ *
20
+ * Test API:
21
+ * - Production: https://webapi.foxpost.hu
22
+ * - Test/Sandbox: https://webapi-test.foxpost.hu
23
+ * - Pass options.useTestApi = true in request to switch to test endpoint for that call
24
+ * - Test API requires separate test credentials
25
+ *
26
+ * Notes:
27
+ * - Foxpost does NOT have a shipment concept; parcels are created directly
28
+ * - Labels are generated per parcel
29
+ * - Tracking available via barcode (FoxWeb barcode format: CLFOX...)
30
+ * - createLabel does not support per-call test mode (no request object in interface)
31
+ */
32
+ export class FoxpostAdapter {
33
+ id = "hu-foxpost";
34
+ displayName = "Foxpost Hungary";
35
+ capabilities = [
36
+ Capabilities.CREATE_PARCEL,
37
+ Capabilities.CREATE_PARCELS,
38
+ Capabilities.CREATE_LABEL,
39
+ Capabilities.TRACK,
40
+ Capabilities.LIST_PICKUP_POINTS,
41
+ Capabilities.TEST_MODE_SUPPORTED,
42
+ ];
43
+ // Foxpost doesn't require close before label
44
+ requires = {
45
+ createLabel: [Capabilities.CREATE_PARCEL],
46
+ };
47
+ prodBaseUrl = "https://webapi.foxpost.hu";
48
+ testBaseUrl = "https://webapi-test.foxpost.hu";
49
+ resolveBaseUrl;
50
+ constructor(baseUrl = "https://webapi.foxpost.hu") {
51
+ this.prodBaseUrl = "https://webapi.foxpost.hu";
52
+ this.testBaseUrl = "https://webapi-test.foxpost.hu";
53
+ this.resolveBaseUrl = createResolveBaseUrl(this.prodBaseUrl, this.testBaseUrl);
54
+ }
55
+ /**
56
+ * Create a parcel in Foxpost
57
+ *
58
+ * Note: Shipper information is not sent to Foxpost API.
59
+ * Foxpost derives the shipper from the API key's account settings.
60
+ * We require shipper in the core Parcel type for consistency across adapters.
61
+ *
62
+ * Maps canonical Parcel to Foxpost CreateParcelRequest (and carrier-specific type)
63
+ * Returns the parcel barcode as carrierId
64
+ */
65
+ async createParcel(req, ctx) {
66
+ return createParcelImpl(req, ctx, (batchReq, batchCtx) => this.createParcels(batchReq, batchCtx));
67
+ }
68
+ /**
69
+ * Create multiple parcels in one call
70
+ * Maps canonical Parcel array to Foxpost CreateParcelRequest and calls the
71
+ * Foxpost batch endpoint which accepts an array. Returns per-item CarrierResource
72
+ * so callers can handle partial failures.
73
+ *
74
+ * Validates both the incoming parcels and the mapped carrier-specific payloads.
75
+ *
76
+ * @returns CreateParcelsResponse with summary and per-item results
77
+ */
78
+ async createParcels(req, ctx) {
79
+ return createParcelsImpl(req, ctx, this.resolveBaseUrl);
80
+ }
81
+ /**
82
+ * Create a label (generate PDF) for a parcel
83
+ *
84
+ * @param req CreateLabelRequest with parcelCarrierId (Foxpost barcode)
85
+ * @param ctx AdapterContext with HTTP client and logger
86
+ * @returns LabelResult with file mapping and page range
87
+ */
88
+ async createLabel(req, ctx) {
89
+ return createLabelImpl(req, ctx, this.resolveBaseUrl);
90
+ }
91
+ /**
92
+ * Create labels for multiple parcels in one batch call
93
+ *
94
+ * Generates a single PDF with all requested labels using Foxpost POST /api/label/{pageSize}
95
+ * Returns per-item results for tracking success/failure of each label
96
+ *
97
+ * @param req CreateLabelsRequest with array of parcelCarrierIds
98
+ * @param ctx AdapterContext with HTTP client and logger
99
+ * @returns CreateLabelsResponse with per-item results and summary
100
+ */
101
+ async createLabels(req, ctx) {
102
+ return createLabelsImpl(req, ctx, this.resolveBaseUrl);
103
+ }
104
+ /**
105
+ * NOT IMPLEMENTED: Foxpost doesn't support voiding labels
106
+ */
107
+ async voidLabel(_labelId, _ctx) {
108
+ throw new NotImplementedError("VOID_LABEL", this.id);
109
+ }
110
+ /**
111
+ * Track a parcel by its clFoxId or uniqueBarcode using the new GET /api/tracking/{barcode} endpoint
112
+ *
113
+ * Returns normalized tracking information with all available traces in reverse chronological order
114
+ *
115
+ * To use test API, pass in request as:
116
+ * { trackingNumber: barcode, credentials: {...}, options?: { useTestApi: true } }
117
+ */
118
+ async track(req, ctx) {
119
+ return trackImpl(req, ctx, this.resolveBaseUrl);
120
+ }
121
+ /**
122
+ * Fetch list of Foxpost pickup points (APMs)
123
+ *
124
+ * Fetches the public JSON feed from https://cdn.foxpost.hu/foxplus.json
125
+ * which is updated hourly and contains all active APM locations.
126
+ *
127
+ * No authentication is required as this is a public feed.
128
+ *
129
+ * @param req FetchPickupPointsRequest (optional filters)
130
+ * @param ctx AdapterContext with HTTP client
131
+ * @returns FetchPickupPointsResponse with normalized pickup points
132
+ */
133
+ async fetchPickupPoints(req, ctx) {
134
+ return fetchPickupPointsImpl(req, ctx);
135
+ }
136
+ /**
137
+ * NOT IMPLEMENTED: Foxpost doesn't support pickup requests
138
+ */
139
+ async requestPickup(_req, _ctx) {
140
+ throw new NotImplementedError("PICKUP", this.id);
141
+ }
142
+ /**
143
+ * NOT IMPLEMENTED: Foxpost doesn't expose rate quotes
144
+ */
145
+ async getRates(_req, _ctx) {
146
+ throw new NotImplementedError("RATES", this.id);
147
+ }
148
+ }
149
+ export default FoxpostAdapter;
150
+ // Export validation helpers for use in external code (e.g., dev-server)
151
+ export { safeValidateTrackingRequest, safeValidateFoxpostTracking, validateFoxpostTracking, safeValidateFoxpostCredentials, validateFoxpostCredentials, } from './validation.js';
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Mappers for Foxpost adapter
3
+ * Converts between canonical Shopickup types and Foxpost API types
4
+ */
5
+ import type { Parcel, TrackingEvent } from "@shopickup/core";
6
+ import type { CreateParcelRequest as FoxpostParcelRequest, TrackDTO as FoxpostTrackDTO, TraceDTO as FoxpostTraceDTO } from '../types/generated.js';
7
+ import type { FoxpostParcel, FoxCreateParcelRequestItem } from '../validation.js';
8
+ declare const FOXPOST_SIZES: readonly ["xs", "s", "m", "l", "xl"];
9
+ type FoxpostSize = typeof FOXPOST_SIZES[number];
10
+ /**
11
+ * Map canonical Address (from Parcel.sender or Parcel.recipient) to Foxpost address format
12
+ */
13
+ export declare function mapAddressToFoxpost(addr: {
14
+ name: string;
15
+ street: string;
16
+ city: string;
17
+ postalCode: string;
18
+ country: string;
19
+ phone?: string;
20
+ email?: string;
21
+ }): {
22
+ name: string;
23
+ phone: string;
24
+ email: string;
25
+ city?: string;
26
+ zip?: string;
27
+ address?: string;
28
+ country: string;
29
+ };
30
+ /**
31
+ * Determine parcel size based on dimensions or weight
32
+ * Foxpost sizes: xs, s, m, l, xl
33
+ */
34
+ export declare function determineFoxpostSize(parcel: Parcel): FoxpostSize | undefined;
35
+ /**
36
+ * Map canonical Parcel to Foxpost CreateParcelRequest (strongly-typed)
37
+ * Returns typed FoxCreateParcelRequestItem with lenient validation support
38
+ *
39
+ * Handles both HOME delivery (full address) and PICKUP_POINT delivery (APM/locker)
40
+ */
41
+ export declare function mapParcelToFoxpostRequest(parcel: Parcel, options?: {
42
+ isWeb?: boolean;
43
+ isRedirect?: boolean;
44
+ }): FoxCreateParcelRequestItem;
45
+ /**
46
+ * Map canonical Parcel to Foxpost CreateParcelRequest
47
+ * Parcel contains complete shipping details (sender, recipient, weight, service, etc.)
48
+ *
49
+ * Handles both HOME delivery (full address) and PICKUP_POINT delivery (APM/locker)
50
+ */
51
+ export declare function mapParcelToFoxpost(parcel: Parcel, options?: {
52
+ isWeb?: boolean;
53
+ isRedirect?: boolean;
54
+ }): FoxpostParcelRequest & {
55
+ destination?: string;
56
+ };
57
+ /**
58
+ * Map Foxpost tracking status code to canonical TrackingStatus
59
+ * Uses comprehensive status mapping from trackStatus.ts
60
+ * Unknown codes default to PENDING.
61
+ */
62
+ export declare function mapFoxpostStatusToCanonical(foxpostStatus: string): "PENDING" | "IN_TRANSIT" | "OUT_FOR_DELIVERY" | "DELIVERED" | "EXCEPTION" | "RETURNED" | "CANCELLED";
63
+ /**
64
+ * Map Foxpost TrackDTO to canonical TrackingEvent
65
+ *
66
+ * Normalizes the Foxpost status code to a canonical TrackingStatus while preserving
67
+ * the original carrier-specific code in `carrierStatusCode` for debugging and carrier-specific logic.
68
+ */
69
+ export declare function mapFoxpostTrackToCanonical(track: FoxpostTrackDTO): TrackingEvent;
70
+ /**
71
+ * Map Foxpost TraceDTO (from new /api/tracking/{barcode} endpoint) to canonical TrackingEvent
72
+ * TraceDTO is returned in reverse chronological order (latest first) from the API
73
+ *
74
+ * Normalizes the Foxpost status code to a canonical TrackingStatus while preserving
75
+ * the original carrier-specific code in `carrierStatusCode`.
76
+ *
77
+ * Includes both English and Hungarian human-readable descriptions from the status map.
78
+ *
79
+ * Accepts both string and Date types for statusDate to support both raw API responses
80
+ * and validated Zod-parsed responses (which transform to Date).
81
+ *
82
+ * Example mapping:
83
+ * - Foxpost "CREATE" -> canonical "PENDING" (carrierStatusCode: "CREATE", description: "Order created")
84
+ * - Foxpost "HDINTRANSIT" -> canonical "OUT_FOR_DELIVERY" (carrierStatusCode: "HDINTRANSIT", description: "Out for home delivery")
85
+ * - Foxpost "RECEIVE" -> canonical "DELIVERED" (carrierStatusCode: "RECEIVE", description: "Delivered to recipient")
86
+ */
87
+ export declare function mapFoxpostTraceToCanonical(trace: FoxpostTraceDTO | {
88
+ statusDate: string | Date;
89
+ status?: string;
90
+ shortName?: string;
91
+ longName?: string;
92
+ }): TrackingEvent;
93
+ /**
94
+ * Map canonical Parcel to Foxpost carrier-specific parcel (HD or APM)
95
+ * Discriminates based on Delivery type in the parcel
96
+ *
97
+ * @param parcel - Canonical parcel with full shipping details
98
+ * @param options - Additional mapping options (COD, comment, etc.)
99
+ * @returns FoxpostParcelHD | FoxpostParcelAPM with type discriminator set
100
+ */
101
+ export declare function mapParcelToFoxpostCarrierType(parcel: Parcel, options?: {
102
+ cod?: number;
103
+ comment?: string;
104
+ deliveryNote?: string;
105
+ fragile?: boolean;
106
+ }): FoxpostParcel;
107
+ export {};
108
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mappers/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAY,MAAM,iBAAiB,CAAC;AACvE,OAAO,KAAK,EACV,mBAAmB,IAAI,oBAAoB,EAC3C,QAAQ,IAAI,eAAe,EAC3B,QAAQ,IAAI,eAAe,EAC5B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,aAAa,EAAsB,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAGtG,QAAA,MAAM,aAAa,sCAAuC,CAAC;AAC3D,KAAK,WAAW,GAAG,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC;AAEhD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG;IAC9J,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAUA;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAwB5E;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IACP,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;CACjB,GACL,0BAA0B,CAuD5B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IACP,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;CACjB,GACL,oBAAoB,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CA8CjD;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,MAAM,GACpB,SAAS,GAAG,YAAY,GAAG,kBAAkB,GAAG,WAAW,GAAG,WAAW,GAAG,UAAU,GAAG,WAAW,CAGtG;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,eAAe,GACrB,aAAa,CAQf;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,eAAe,GAAG;IAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7G,aAAa,CAuBf;AAED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IACP,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;CACd,GACL,aAAa,CAoDf"}