@veho/turvo-integration-sdk 0.1.0-beta.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/README.md +473 -0
- package/index.ts +1 -0
- package/lib/cjs/api/turvoInternalApi.d.ts +23 -0
- package/lib/cjs/api/turvoInternalApi.js +36 -0
- package/lib/cjs/api/turvoPublicApi.d.ts +99 -0
- package/lib/cjs/api/turvoPublicApi.js +103 -0
- package/lib/cjs/client/turvoClient.d.ts +49 -0
- package/lib/cjs/client/turvoClient.js +180 -0
- package/lib/cjs/constants.d.ts +29 -0
- package/lib/cjs/constants.js +33 -0
- package/lib/cjs/index.d.ts +6 -0
- package/lib/cjs/index.js +37 -0
- package/lib/cjs/shipmentTracking/index.d.ts +22 -0
- package/lib/cjs/shipmentTracking/index.js +39 -0
- package/lib/cjs/shipmentTracking/trackingService.d.ts +25 -0
- package/lib/cjs/shipmentTracking/trackingService.js +85 -0
- package/lib/cjs/types/common.d.ts +64 -0
- package/lib/cjs/types/common.js +27 -0
- package/lib/cjs/types/config.d.ts +13 -0
- package/lib/cjs/types/config.js +3 -0
- package/lib/cjs/types/errors.d.ts +35 -0
- package/lib/cjs/types/errors.js +63 -0
- package/lib/cjs/types/index.d.ts +5 -0
- package/lib/cjs/types/index.js +27 -0
- package/lib/cjs/types/shipment.d.ts +379 -0
- package/lib/cjs/types/shipment.js +46 -0
- package/lib/cjs/types/tracking.d.ts +65 -0
- package/lib/cjs/types/tracking.js +3 -0
- package/lib/esm/api/turvoInternalApi.d.ts +23 -0
- package/lib/esm/api/turvoInternalApi.js +32 -0
- package/lib/esm/api/turvoPublicApi.d.ts +99 -0
- package/lib/esm/api/turvoPublicApi.js +99 -0
- package/lib/esm/client/turvoClient.d.ts +49 -0
- package/lib/esm/client/turvoClient.js +172 -0
- package/lib/esm/constants.d.ts +29 -0
- package/lib/esm/constants.js +30 -0
- package/lib/esm/index.d.ts +6 -0
- package/lib/esm/index.js +11 -0
- package/lib/esm/shipmentTracking/index.d.ts +22 -0
- package/lib/esm/shipmentTracking/index.js +36 -0
- package/lib/esm/shipmentTracking/trackingService.d.ts +25 -0
- package/lib/esm/shipmentTracking/trackingService.js +81 -0
- package/lib/esm/types/common.d.ts +64 -0
- package/lib/esm/types/common.js +23 -0
- package/lib/esm/types/config.d.ts +13 -0
- package/lib/esm/types/config.js +2 -0
- package/lib/esm/types/errors.d.ts +35 -0
- package/lib/esm/types/errors.js +55 -0
- package/lib/esm/types/index.d.ts +5 -0
- package/lib/esm/types/index.js +11 -0
- package/lib/esm/types/shipment.d.ts +379 -0
- package/lib/esm/types/shipment.js +43 -0
- package/lib/esm/types/tracking.d.ts +65 -0
- package/lib/esm/types/tracking.js +2 -0
- package/lib/tsconfig.cjs.tsbuildinfo +1 -0
- package/lib/tsconfig.esm.tsbuildinfo +1 -0
- package/package.json +126 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { TurvoApiMethod, } from '../types/common';
|
|
2
|
+
/**
|
|
3
|
+
* TurvoPublicApi provides access to documented Turvo API endpoints.
|
|
4
|
+
* All shipment management operations (create, update, cancel, query) go through this class.
|
|
5
|
+
*/
|
|
6
|
+
export class TurvoPublicApi {
|
|
7
|
+
client;
|
|
8
|
+
constructor(client) {
|
|
9
|
+
this.client = client;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* GET /v1/shipments/{id}
|
|
13
|
+
* Returns shipment details, stops, status
|
|
14
|
+
*/
|
|
15
|
+
async getShipment(params) {
|
|
16
|
+
const { shipmentId } = params;
|
|
17
|
+
const httpClient = await this.client.getAuthenticatedClient();
|
|
18
|
+
return httpClient.sendRequest(`/shipments/${shipmentId}`, TurvoApiMethod.GET, {});
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* POST /v1/shipments
|
|
22
|
+
* Upload properly formatted shipment to Turvo
|
|
23
|
+
*/
|
|
24
|
+
async uploadShipment(params) {
|
|
25
|
+
const { shipment } = params;
|
|
26
|
+
// Note: vehoLoadId is kept in the params for logging purposes by consumers
|
|
27
|
+
const httpClient = await this.client.getAuthenticatedClient();
|
|
28
|
+
return httpClient.sendRequest('/shipments', TurvoApiMethod.POST, {
|
|
29
|
+
body: shipment,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* PUT /v1/tags/attach/shipment/{id}
|
|
34
|
+
* Associate a list of tags with a shipment by ID
|
|
35
|
+
*/
|
|
36
|
+
async associateTagsToShipment(params) {
|
|
37
|
+
const { turvoShipmentId, tags } = params;
|
|
38
|
+
const httpClient = await this.client.getAuthenticatedClient();
|
|
39
|
+
return httpClient.sendRequest(`/tags/attach/shipment/${turvoShipmentId}`, TurvoApiMethod.PUT, {
|
|
40
|
+
body: {
|
|
41
|
+
tagNames: tags,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* PUT /v1/shipments/status/{id}
|
|
47
|
+
* Set shipment status to Cancelled in Turvo
|
|
48
|
+
*/
|
|
49
|
+
async cancelShipment(params) {
|
|
50
|
+
const { turvoShipmentId } = params;
|
|
51
|
+
const httpClient = await this.client.getAuthenticatedClient();
|
|
52
|
+
const body = {
|
|
53
|
+
id: turvoShipmentId,
|
|
54
|
+
status: {
|
|
55
|
+
code: { key: '2113', value: 'Canceled' },
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
return httpClient.sendRequest(`/shipments/status/${turvoShipmentId}`, TurvoApiMethod.PUT, {
|
|
59
|
+
body,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* PUT /v1/shipments/status/{id}
|
|
64
|
+
* Update shipment status at a specific stop
|
|
65
|
+
*/
|
|
66
|
+
async updateShipmentStatus(params) {
|
|
67
|
+
const { turvoShipmentId, turvoStopId, turvoStatusCode, statusDate, statusTimezone } = params;
|
|
68
|
+
const httpClient = await this.client.getAuthenticatedClient();
|
|
69
|
+
const body = {
|
|
70
|
+
id: turvoShipmentId,
|
|
71
|
+
status: {
|
|
72
|
+
globalShipLocationId: turvoStopId,
|
|
73
|
+
code: turvoStatusCode.code,
|
|
74
|
+
timezone: statusTimezone,
|
|
75
|
+
statusDate: {
|
|
76
|
+
date: statusDate,
|
|
77
|
+
timezone: statusTimezone,
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
return httpClient.sendRequest(`/shipments/status/${turvoShipmentId}`, TurvoApiMethod.PUT, { body });
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* GET /v1/shipments/list
|
|
85
|
+
* Query shipments from Turvo with pagination support
|
|
86
|
+
*/
|
|
87
|
+
async filterShipments(params) {
|
|
88
|
+
const { turvoLocationId, pickupDateStart, start = 0 } = params;
|
|
89
|
+
const httpClient = await this.client.getAuthenticatedClient();
|
|
90
|
+
return httpClient.sendRequest('/shipments/list', TurvoApiMethod.GET, {
|
|
91
|
+
query: {
|
|
92
|
+
'locationId[eq]': turvoLocationId.toString(),
|
|
93
|
+
'pickupDate[gte]': pickupDateStart,
|
|
94
|
+
start: start.toString(),
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHVydm9QdWJsaWNBcGkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBpL3R1cnZvUHVibGljQXBpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFDTCxjQUFjLEdBS2YsTUFBTSxpQkFBaUIsQ0FBQTtBQTBFeEI7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLGNBQWM7SUFDTDtJQUFwQixZQUFvQixNQUFtQjtRQUFuQixXQUFNLEdBQU4sTUFBTSxDQUFhO0lBQUcsQ0FBQztJQUUzQzs7O09BR0c7SUFDSCxLQUFLLENBQUMsV0FBVyxDQUFDLE1BQXlCO1FBQ3pDLE1BQU0sRUFBRSxVQUFVLEVBQUUsR0FBRyxNQUFNLENBQUE7UUFDN0IsTUFBTSxVQUFVLEdBQUcsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLHNCQUFzQixFQUFFLENBQUE7UUFFN0QsT0FBTyxVQUFVLENBQUMsV0FBVyxDQUFnQixjQUFjLFVBQVUsRUFBRSxFQUFFLGNBQWMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUE7SUFDbEcsQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxjQUFjLENBQUMsTUFBNEI7UUFDL0MsTUFBTSxFQUFFLFFBQVEsRUFBRSxHQUFHLE1BQU0sQ0FBQTtRQUMzQiwyRUFBMkU7UUFDM0UsTUFBTSxVQUFVLEdBQUcsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLHNCQUFzQixFQUFFLENBQUE7UUFFN0QsT0FBTyxVQUFVLENBQUMsV0FBVyxDQUErQixZQUFZLEVBQUUsY0FBYyxDQUFDLElBQUksRUFBRTtZQUM3RixJQUFJLEVBQUUsUUFBUTtTQUNmLENBQUMsQ0FBQTtJQUNKLENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsdUJBQXVCLENBQUMsTUFBMkI7UUFDdkQsTUFBTSxFQUFFLGVBQWUsRUFBRSxJQUFJLEVBQUUsR0FBRyxNQUFNLENBQUE7UUFDeEMsTUFBTSxVQUFVLEdBQUcsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLHNCQUFzQixFQUFFLENBQUE7UUFFN0QsT0FBTyxVQUFVLENBQUMsV0FBVyxDQUMzQix5QkFBeUIsZUFBZSxFQUFFLEVBQzFDLGNBQWMsQ0FBQyxHQUFHLEVBQ2xCO1lBQ0UsSUFBSSxFQUFFO2dCQUNKLFFBQVEsRUFBRSxJQUFJO2FBQ2Y7U0FDRixDQUNGLENBQUE7SUFDSCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsS0FBSyxDQUFDLGNBQWMsQ0FBQyxNQUE0QjtRQUMvQyxNQUFNLEVBQUUsZUFBZSxFQUFFLEdBQUcsTUFBTSxDQUFBO1FBQ2xDLE1BQU0sVUFBVSxHQUFHLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxzQkFBc0IsRUFBRSxDQUFBO1FBRTdELE1BQU0sSUFBSSxHQUFHO1lBQ1gsRUFBRSxFQUFFLGVBQWU7WUFDbkIsTUFBTSxFQUFFO2dCQUNOLElBQUksRUFBRSxFQUFFLEdBQUcsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBd0I7YUFDL0Q7U0FDRixDQUFBO1FBRUQsT0FBTyxVQUFVLENBQUMsV0FBVyxDQUMzQixxQkFBcUIsZUFBZSxFQUFFLEVBQ3RDLGNBQWMsQ0FBQyxHQUFHLEVBQ2xCO1lBQ0UsSUFBSTtTQUNMLENBQ0YsQ0FBQTtJQUNILENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsb0JBQW9CLENBQ3hCLE1BQWtDO1FBRWxDLE1BQU0sRUFBRSxlQUFlLEVBQUUsV0FBVyxFQUFFLGVBQWUsRUFBRSxVQUFVLEVBQUUsY0FBYyxFQUFFLEdBQUcsTUFBTSxDQUFBO1FBQzVGLE1BQU0sVUFBVSxHQUFHLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxzQkFBc0IsRUFBRSxDQUFBO1FBRTdELE1BQU0sSUFBSSxHQUFHO1lBQ1gsRUFBRSxFQUFFLGVBQWU7WUFDbkIsTUFBTSxFQUFFO2dCQUNOLG9CQUFvQixFQUFFLFdBQVc7Z0JBQ2pDLElBQUksRUFBRSxlQUFlLENBQUMsSUFBSTtnQkFDMUIsUUFBUSxFQUFFLGNBQWM7Z0JBQ3hCLFVBQVUsRUFBRTtvQkFDVixJQUFJLEVBQUUsVUFBVTtvQkFDaEIsUUFBUSxFQUFFLGNBQWM7aUJBQ3pCO2FBQ0Y7U0FDRixDQUFBO1FBRUQsT0FBTyxVQUFVLENBQUMsV0FBVyxDQUMzQixxQkFBcUIsZUFBZSxFQUFFLEVBQ3RDLGNBQWMsQ0FBQyxHQUFHLEVBQ2xCLEVBQUUsSUFBSSxFQUFFLENBQ1QsQ0FBQTtJQUNILENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsZUFBZSxDQUNuQixNQUE2QjtRQUU3QixNQUFNLEVBQUUsZUFBZSxFQUFFLGVBQWUsRUFBRSxLQUFLLEdBQUcsQ0FBQyxFQUFFLEdBQUcsTUFBTSxDQUFBO1FBQzlELE1BQU0sVUFBVSxHQUFHLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxzQkFBc0IsRUFBRSxDQUFBO1FBRTdELE9BQU8sVUFBVSxDQUFDLFdBQVcsQ0FDM0IsaUJBQWlCLEVBQ2pCLGNBQWMsQ0FBQyxHQUFHLEVBQ2xCO1lBQ0UsS0FBSyxFQUFFO2dCQUNMLGdCQUFnQixFQUFFLGVBQWUsQ0FBQyxRQUFRLEVBQUU7Z0JBQzVDLGlCQUFpQixFQUFFLGVBQWU7Z0JBQ2xDLEtBQUssRUFBRSxLQUFLLENBQUMsUUFBUSxFQUFFO2FBQ3hCO1NBQ0YsQ0FDRixDQUFBO0lBQ0gsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgVHVydm9DbGllbnQgfSBmcm9tICcuLi9jbGllbnQvdHVydm9DbGllbnQnXG5pbXBvcnQge1xuICBUdXJ2b0FwaU1ldGhvZCxcbiAgVHVydm9BcGlSZXN1bHQsXG4gIFR1cnZvRmlsdGVyU2hpcG1lbnRzUmVzdWx0SXRlbSxcbiAgVHVydm9Mb29rdXAsXG4gIFR1cnZvUGFnZWRSZXN1bHQsXG59IGZyb20gJy4uL3R5cGVzL2NvbW1vbidcbmltcG9ydCB7XG4gIFR1cnZvQXNzb2NpYXRlVGFnc0FwaVJlc3VsdCxcbiAgVHVydm9DYW5jZWxTaGlwbWVudEFwaVJlc3VsdCxcbiAgVHVydm9DcmVhdGVTaGlwbWVudEFwaVJlc3VsdCxcbiAgVHVydm9TaGlwbWVudCxcbiAgVHVydm9TaGlwbWVudFN0YXR1cyxcbiAgVHVydm9VcGRhdGVTaGlwbWVudFN0YXR1c0FwaVJlc3VsdCxcbn0gZnJvbSAnLi4vdHlwZXMvc2hpcG1lbnQnXG5cbi8qKlxuICogUGFyYW1ldGVycyBmb3IgdXBsb2FkaW5nIGEgc2hpcG1lbnQgdG8gVHVydm9cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBVcGxvYWRTaGlwbWVudFBhcmFtcyB7XG4gIC8qKiBUaGUgZm9ybWF0dGVkIHNoaXBtZW50IHRvIHVwbG9hZCAqL1xuICBzaGlwbWVudDogVHVydm9TaGlwbWVudFxuICAvKiogVGhlIExvYWQgSUQsIHNvbGVseSBmb3IgbG9nZ2luZyBwdXJwb3NlcyAqL1xuICB2ZWhvTG9hZElkOiBzdHJpbmdcbn1cblxuLyoqXG4gKiBQYXJhbWV0ZXJzIGZvciBhc3NvY2lhdGluZyB0YWdzIHRvIGEgc2hpcG1lbnRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBBc3NvY2lhdGVUYWdzUGFyYW1zIHtcbiAgLyoqIFRoZSBzaGlwbWVudCBJRCB0byBhc3NvY2lhdGUgdGFncyB3aXRoICovXG4gIHR1cnZvU2hpcG1lbnRJZDogbnVtYmVyXG4gIC8qKiBMaXN0IG9mIHRhZyBuYW1lcyB0byBhc3NpZ24gKi9cbiAgdGFnczogc3RyaW5nW11cbn1cblxuLyoqXG4gKiBQYXJhbWV0ZXJzIGZvciBjYW5jZWxsaW5nIGEgc2hpcG1lbnRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDYW5jZWxTaGlwbWVudFBhcmFtcyB7XG4gIC8qKiBUaGUgVHVydm8gc3lzdGVtIFNoaXBtZW50IElEIHRvIGNhbmNlbCAqL1xuICB0dXJ2b1NoaXBtZW50SWQ6IG51bWJlclxufVxuXG4vKipcbiAqIFBhcmFtZXRlcnMgZm9yIHVwZGF0aW5nIHNoaXBtZW50IHN0YXR1c1xuICovXG5leHBvcnQgaW50ZXJmYWNlIFVwZGF0ZVNoaXBtZW50U3RhdHVzUGFyYW1zIHtcbiAgLyoqIFRoZSBUdXJ2byBzaGlwbWVudCBJRCAqL1xuICB0dXJ2b1NoaXBtZW50SWQ6IG51bWJlclxuICAvKiogVGhlIFR1cnZvIHN0b3AgSUQgKi9cbiAgdHVydm9TdG9wSWQ6IG51bWJlclxuICAvKiogVGhlIHN0YXR1cyBjb2RlIHRvIHNldCAqL1xuICB0dXJ2b1N0YXR1c0NvZGU6IFR1cnZvU2hpcG1lbnRTdGF0dXNcbiAgLyoqIFRoZSBzdGF0dXMgZGF0ZSBpbiBJU08gZm9ybWF0ICovXG4gIHN0YXR1c0RhdGU6IHN0cmluZ1xuICAvKiogVGhlIHRpbWV6b25lIGZvciB0aGUgc3RhdHVzIGRhdGUgKi9cbiAgc3RhdHVzVGltZXpvbmU6IHN0cmluZ1xufVxuXG4vKipcbiAqIFBhcmFtZXRlcnMgZm9yIHJldHJpZXZpbmcgYSBzaGlwbWVudFxuICovXG5leHBvcnQgaW50ZXJmYWNlIEdldFNoaXBtZW50UGFyYW1zIHtcbiAgLyoqIFRoZSBzaGlwbWVudCBJRCB0byByZXRyaWV2ZSAqL1xuICBzaGlwbWVudElkOiBudW1iZXJcbn1cblxuLyoqXG4gKiBQYXJhbWV0ZXJzIGZvciBmaWx0ZXJpbmcgc2hpcG1lbnRzXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRmlsdGVyU2hpcG1lbnRzUGFyYW1zIHtcbiAgLyoqIFR1cnZvIGxvY2F0aW9uIElEIHRvIGZpbHRlciBieSAqL1xuICB0dXJ2b0xvY2F0aW9uSWQ6IG51bWJlclxuICAvKiogUGlja3VwIGRhdGUgc3RhcnQgZmlsdGVyIChJU08gZm9ybWF0KSAqL1xuICBwaWNrdXBEYXRlU3RhcnQ6IHN0cmluZ1xuICAvKiogT3B0aW9uYWwgcGFnaW5hdGlvbiBzdGFydCBvZmZzZXQgKi9cbiAgc3RhcnQ/OiBudW1iZXJcbn1cblxuLyoqXG4gKiBUdXJ2b1B1YmxpY0FwaSBwcm92aWRlcyBhY2Nlc3MgdG8gZG9jdW1lbnRlZCBUdXJ2byBBUEkgZW5kcG9pbnRzLlxuICogQWxsIHNoaXBtZW50IG1hbmFnZW1lbnQgb3BlcmF0aW9ucyAoY3JlYXRlLCB1cGRhdGUsIGNhbmNlbCwgcXVlcnkpIGdvIHRocm91Z2ggdGhpcyBjbGFzcy5cbiAqL1xuZXhwb3J0IGNsYXNzIFR1cnZvUHVibGljQXBpIHtcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBjbGllbnQ6IFR1cnZvQ2xpZW50KSB7fVxuXG4gIC8qKlxuICAgKiBHRVQgL3YxL3NoaXBtZW50cy97aWR9XG4gICAqIFJldHVybnMgc2hpcG1lbnQgZGV0YWlscywgc3RvcHMsIHN0YXR1c1xuICAgKi9cbiAgYXN5bmMgZ2V0U2hpcG1lbnQocGFyYW1zOiBHZXRTaGlwbWVudFBhcmFtcyk6IFByb21pc2U8VHVydm9BcGlSZXN1bHQ8VHVydm9TaGlwbWVudD4+IHtcbiAgICBjb25zdCB7IHNoaXBtZW50SWQgfSA9IHBhcmFtc1xuICAgIGNvbnN0IGh0dHBDbGllbnQgPSBhd2FpdCB0aGlzLmNsaWVudC5nZXRBdXRoZW50aWNhdGVkQ2xpZW50KClcblxuICAgIHJldHVybiBodHRwQ2xpZW50LnNlbmRSZXF1ZXN0PFR1cnZvU2hpcG1lbnQ+KGAvc2hpcG1lbnRzLyR7c2hpcG1lbnRJZH1gLCBUdXJ2b0FwaU1ldGhvZC5HRVQsIHt9KVxuICB9XG5cbiAgLyoqXG4gICAqIFBPU1QgL3YxL3NoaXBtZW50c1xuICAgKiBVcGxvYWQgcHJvcGVybHkgZm9ybWF0dGVkIHNoaXBtZW50IHRvIFR1cnZvXG4gICAqL1xuICBhc3luYyB1cGxvYWRTaGlwbWVudChwYXJhbXM6IFVwbG9hZFNoaXBtZW50UGFyYW1zKTogUHJvbWlzZTxUdXJ2b0FwaVJlc3VsdDxUdXJ2b0NyZWF0ZVNoaXBtZW50QXBpUmVzdWx0Pj4ge1xuICAgIGNvbnN0IHsgc2hpcG1lbnQgfSA9IHBhcmFtc1xuICAgIC8vIE5vdGU6IHZlaG9Mb2FkSWQgaXMga2VwdCBpbiB0aGUgcGFyYW1zIGZvciBsb2dnaW5nIHB1cnBvc2VzIGJ5IGNvbnN1bWVyc1xuICAgIGNvbnN0IGh0dHBDbGllbnQgPSBhd2FpdCB0aGlzLmNsaWVudC5nZXRBdXRoZW50aWNhdGVkQ2xpZW50KClcblxuICAgIHJldHVybiBodHRwQ2xpZW50LnNlbmRSZXF1ZXN0PFR1cnZvQ3JlYXRlU2hpcG1lbnRBcGlSZXN1bHQ+KCcvc2hpcG1lbnRzJywgVHVydm9BcGlNZXRob2QuUE9TVCwge1xuICAgICAgYm9keTogc2hpcG1lbnQsXG4gICAgfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBQVVQgL3YxL3RhZ3MvYXR0YWNoL3NoaXBtZW50L3tpZH1cbiAgICogQXNzb2NpYXRlIGEgbGlzdCBvZiB0YWdzIHdpdGggYSBzaGlwbWVudCBieSBJRFxuICAgKi9cbiAgYXN5bmMgYXNzb2NpYXRlVGFnc1RvU2hpcG1lbnQocGFyYW1zOiBBc3NvY2lhdGVUYWdzUGFyYW1zKTogUHJvbWlzZTxUdXJ2b0FwaVJlc3VsdDxUdXJ2b0Fzc29jaWF0ZVRhZ3NBcGlSZXN1bHQ+PiB7XG4gICAgY29uc3QgeyB0dXJ2b1NoaXBtZW50SWQsIHRhZ3MgfSA9IHBhcmFtc1xuICAgIGNvbnN0IGh0dHBDbGllbnQgPSBhd2FpdCB0aGlzLmNsaWVudC5nZXRBdXRoZW50aWNhdGVkQ2xpZW50KClcblxuICAgIHJldHVybiBodHRwQ2xpZW50LnNlbmRSZXF1ZXN0PFR1cnZvQXNzb2NpYXRlVGFnc0FwaVJlc3VsdD4oXG4gICAgICBgL3RhZ3MvYXR0YWNoL3NoaXBtZW50LyR7dHVydm9TaGlwbWVudElkfWAsXG4gICAgICBUdXJ2b0FwaU1ldGhvZC5QVVQsXG4gICAgICB7XG4gICAgICAgIGJvZHk6IHtcbiAgICAgICAgICB0YWdOYW1lczogdGFncyxcbiAgICAgICAgfSxcbiAgICAgIH1cbiAgICApXG4gIH1cblxuICAvKipcbiAgICogUFVUIC92MS9zaGlwbWVudHMvc3RhdHVzL3tpZH1cbiAgICogU2V0IHNoaXBtZW50IHN0YXR1cyB0byBDYW5jZWxsZWQgaW4gVHVydm9cbiAgICovXG4gIGFzeW5jIGNhbmNlbFNoaXBtZW50KHBhcmFtczogQ2FuY2VsU2hpcG1lbnRQYXJhbXMpOiBQcm9taXNlPFR1cnZvQXBpUmVzdWx0PFR1cnZvQ2FuY2VsU2hpcG1lbnRBcGlSZXN1bHQ+PiB7XG4gICAgY29uc3QgeyB0dXJ2b1NoaXBtZW50SWQgfSA9IHBhcmFtc1xuICAgIGNvbnN0IGh0dHBDbGllbnQgPSBhd2FpdCB0aGlzLmNsaWVudC5nZXRBdXRoZW50aWNhdGVkQ2xpZW50KClcblxuICAgIGNvbnN0IGJvZHkgPSB7XG4gICAgICBpZDogdHVydm9TaGlwbWVudElkLFxuICAgICAgc3RhdHVzOiB7XG4gICAgICAgIGNvZGU6IHsga2V5OiAnMjExMycsIHZhbHVlOiAnQ2FuY2VsZWQnIH0gc2F0aXNmaWVzIFR1cnZvTG9va3VwLFxuICAgICAgfSxcbiAgICB9XG5cbiAgICByZXR1cm4gaHR0cENsaWVudC5zZW5kUmVxdWVzdDxUdXJ2b0NhbmNlbFNoaXBtZW50QXBpUmVzdWx0PihcbiAgICAgIGAvc2hpcG1lbnRzL3N0YXR1cy8ke3R1cnZvU2hpcG1lbnRJZH1gLFxuICAgICAgVHVydm9BcGlNZXRob2QuUFVULFxuICAgICAge1xuICAgICAgICBib2R5LFxuICAgICAgfVxuICAgIClcbiAgfVxuXG4gIC8qKlxuICAgKiBQVVQgL3YxL3NoaXBtZW50cy9zdGF0dXMve2lkfVxuICAgKiBVcGRhdGUgc2hpcG1lbnQgc3RhdHVzIGF0IGEgc3BlY2lmaWMgc3RvcFxuICAgKi9cbiAgYXN5bmMgdXBkYXRlU2hpcG1lbnRTdGF0dXMoXG4gICAgcGFyYW1zOiBVcGRhdGVTaGlwbWVudFN0YXR1c1BhcmFtc1xuICApOiBQcm9taXNlPFR1cnZvQXBpUmVzdWx0PFR1cnZvVXBkYXRlU2hpcG1lbnRTdGF0dXNBcGlSZXN1bHQ+PiB7XG4gICAgY29uc3QgeyB0dXJ2b1NoaXBtZW50SWQsIHR1cnZvU3RvcElkLCB0dXJ2b1N0YXR1c0NvZGUsIHN0YXR1c0RhdGUsIHN0YXR1c1RpbWV6b25lIH0gPSBwYXJhbXNcbiAgICBjb25zdCBodHRwQ2xpZW50ID0gYXdhaXQgdGhpcy5jbGllbnQuZ2V0QXV0aGVudGljYXRlZENsaWVudCgpXG5cbiAgICBjb25zdCBib2R5ID0ge1xuICAgICAgaWQ6IHR1cnZvU2hpcG1lbnRJZCxcbiAgICAgIHN0YXR1czoge1xuICAgICAgICBnbG9iYWxTaGlwTG9jYXRpb25JZDogdHVydm9TdG9wSWQsXG4gICAgICAgIGNvZGU6IHR1cnZvU3RhdHVzQ29kZS5jb2RlLFxuICAgICAgICB0aW1lem9uZTogc3RhdHVzVGltZXpvbmUsXG4gICAgICAgIHN0YXR1c0RhdGU6IHtcbiAgICAgICAgICBkYXRlOiBzdGF0dXNEYXRlLFxuICAgICAgICAgIHRpbWV6b25lOiBzdGF0dXNUaW1lem9uZSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfVxuXG4gICAgcmV0dXJuIGh0dHBDbGllbnQuc2VuZFJlcXVlc3Q8VHVydm9VcGRhdGVTaGlwbWVudFN0YXR1c0FwaVJlc3VsdD4oXG4gICAgICBgL3NoaXBtZW50cy9zdGF0dXMvJHt0dXJ2b1NoaXBtZW50SWR9YCxcbiAgICAgIFR1cnZvQXBpTWV0aG9kLlBVVCxcbiAgICAgIHsgYm9keSB9XG4gICAgKVxuICB9XG5cbiAgLyoqXG4gICAqIEdFVCAvdjEvc2hpcG1lbnRzL2xpc3RcbiAgICogUXVlcnkgc2hpcG1lbnRzIGZyb20gVHVydm8gd2l0aCBwYWdpbmF0aW9uIHN1cHBvcnRcbiAgICovXG4gIGFzeW5jIGZpbHRlclNoaXBtZW50cyhcbiAgICBwYXJhbXM6IEZpbHRlclNoaXBtZW50c1BhcmFtc1xuICApOiBQcm9taXNlPFR1cnZvQXBpUmVzdWx0PFR1cnZvUGFnZWRSZXN1bHQ8J3NoaXBtZW50cycsIFR1cnZvRmlsdGVyU2hpcG1lbnRzUmVzdWx0SXRlbT4+PiB7XG4gICAgY29uc3QgeyB0dXJ2b0xvY2F0aW9uSWQsIHBpY2t1cERhdGVTdGFydCwgc3RhcnQgPSAwIH0gPSBwYXJhbXNcbiAgICBjb25zdCBodHRwQ2xpZW50ID0gYXdhaXQgdGhpcy5jbGllbnQuZ2V0QXV0aGVudGljYXRlZENsaWVudCgpXG5cbiAgICByZXR1cm4gaHR0cENsaWVudC5zZW5kUmVxdWVzdDxUdXJ2b1BhZ2VkUmVzdWx0PCdzaGlwbWVudHMnLCBUdXJ2b0ZpbHRlclNoaXBtZW50c1Jlc3VsdEl0ZW0+PihcbiAgICAgICcvc2hpcG1lbnRzL2xpc3QnLFxuICAgICAgVHVydm9BcGlNZXRob2QuR0VULFxuICAgICAge1xuICAgICAgICBxdWVyeToge1xuICAgICAgICAgICdsb2NhdGlvbklkW2VxXSc6IHR1cnZvTG9jYXRpb25JZC50b1N0cmluZygpLFxuICAgICAgICAgICdwaWNrdXBEYXRlW2d0ZV0nOiBwaWNrdXBEYXRlU3RhcnQsXG4gICAgICAgICAgc3RhcnQ6IHN0YXJ0LnRvU3RyaW5nKCksXG4gICAgICAgIH0sXG4gICAgICB9XG4gICAgKVxuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { TurvoApiMethod, TurvoApiResult } from '../types/common';
|
|
2
|
+
import { TurvoCredentials } from '../types/config';
|
|
3
|
+
/**
|
|
4
|
+
* Clear the cached access token (useful for testing or when token expires)
|
|
5
|
+
*/
|
|
6
|
+
export declare const clearCachedAccessToken: () => void;
|
|
7
|
+
/**
|
|
8
|
+
* HTTP client interface for making authenticated Turvo API requests
|
|
9
|
+
*/
|
|
10
|
+
export interface AuthenticatedHttpClient {
|
|
11
|
+
/**
|
|
12
|
+
* Send a request to the Turvo API
|
|
13
|
+
* @param apiRoute - API route path (e.g., '/shipments')
|
|
14
|
+
* @param method - HTTP method
|
|
15
|
+
* @param params - Request parameters (body, headers, query)
|
|
16
|
+
* @returns Typed API result
|
|
17
|
+
*/
|
|
18
|
+
sendRequest<T>(apiRoute: string, method: TurvoApiMethod, params: {
|
|
19
|
+
body?: object;
|
|
20
|
+
headers?: Record<string, string>;
|
|
21
|
+
query?: Record<string, string>;
|
|
22
|
+
}): Promise<TurvoApiResult<T>>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Main client for interacting with Turvo APIs.
|
|
26
|
+
* Handles authentication, token management, and HTTP requests.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* const client = new TurvoClient()
|
|
31
|
+
* const httpClient = await client.getAuthenticatedClient()
|
|
32
|
+
* const result = await httpClient.sendRequest('/shipments/123', TurvoApiMethod.GET, {})
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare class TurvoClient {
|
|
36
|
+
private secretPath;
|
|
37
|
+
private credentials?;
|
|
38
|
+
private httpClient?;
|
|
39
|
+
constructor(secretPath?: string);
|
|
40
|
+
/**
|
|
41
|
+
* Get authenticated HTTP client.
|
|
42
|
+
* Handles token refresh automatically.
|
|
43
|
+
*/
|
|
44
|
+
getAuthenticatedClient(): Promise<AuthenticatedHttpClient>;
|
|
45
|
+
/**
|
|
46
|
+
* Get raw secrets (for internal API auth which uses different flow)
|
|
47
|
+
*/
|
|
48
|
+
getCredentials(): Promise<TurvoCredentials>;
|
|
49
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { Client } from 'lambda-params-secrets';
|
|
2
|
+
import fetch from 'node-fetch';
|
|
3
|
+
import pRetry from 'p-retry';
|
|
4
|
+
import pThrottle from 'p-throttle';
|
|
5
|
+
import { DEFAULT_ALLOWED_RETRIES, DEFAULT_API_ROUTE_PREFIX, DEFAULT_RATE_LIMIT_RPS, TURVO_SECRET_PATH, } from '../constants';
|
|
6
|
+
import { TurvoApiError, TurvoApiResponseStatus } from '../types/common';
|
|
7
|
+
import { NoSecretError, TurvoAuthError } from '../types/errors';
|
|
8
|
+
let secretClient = null;
|
|
9
|
+
/**
|
|
10
|
+
* Get or create the secrets client instance
|
|
11
|
+
*/
|
|
12
|
+
const getSecretClientInstance = () => {
|
|
13
|
+
if (!secretClient) {
|
|
14
|
+
secretClient = new Client();
|
|
15
|
+
}
|
|
16
|
+
return secretClient;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Fetch Turvo API credentials from AWS Secrets Manager
|
|
20
|
+
*/
|
|
21
|
+
const getTurvoSecrets = async (secretsPath = TURVO_SECRET_PATH) => {
|
|
22
|
+
const fetchedSecret = await getSecretClientInstance().stringSecret(secretsPath);
|
|
23
|
+
if (!fetchedSecret) {
|
|
24
|
+
throw new NoSecretError(secretsPath);
|
|
25
|
+
}
|
|
26
|
+
return JSON.parse(fetchedSecret);
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Cached access token to avoid repeated OAuth requests
|
|
30
|
+
*/
|
|
31
|
+
let cachedAccessToken = null;
|
|
32
|
+
let tokenExpiry = null;
|
|
33
|
+
/**
|
|
34
|
+
* Fetch an access token from Turvo using OAuth2 password grant
|
|
35
|
+
*/
|
|
36
|
+
const getTurvoAccessToken = async (credentials, apiRoutePrefix = DEFAULT_API_ROUTE_PREFIX, allowedRetries = DEFAULT_ALLOWED_RETRIES) => {
|
|
37
|
+
// Check if we have a valid cached token
|
|
38
|
+
if (cachedAccessToken && tokenExpiry && tokenExpiry > new Date()) {
|
|
39
|
+
return cachedAccessToken;
|
|
40
|
+
}
|
|
41
|
+
const fullUrl = `${credentials.urlBase + apiRoutePrefix}/oauth/token`;
|
|
42
|
+
return pRetry(async () => {
|
|
43
|
+
const url = new URL(fullUrl);
|
|
44
|
+
url.searchParams.set('client_id', 'publicapi');
|
|
45
|
+
url.searchParams.set('client_secret', 'secret');
|
|
46
|
+
const response = await fetch(url, {
|
|
47
|
+
method: 'POST',
|
|
48
|
+
headers: {
|
|
49
|
+
'Content-Type': 'application/json',
|
|
50
|
+
'x-api-key': credentials.apiKey,
|
|
51
|
+
},
|
|
52
|
+
body: JSON.stringify({
|
|
53
|
+
grant_type: 'password',
|
|
54
|
+
scope: 'read+trust+write',
|
|
55
|
+
username: credentials.username,
|
|
56
|
+
password: credentials.password,
|
|
57
|
+
type: 'business',
|
|
58
|
+
}),
|
|
59
|
+
});
|
|
60
|
+
if (!response.ok) {
|
|
61
|
+
throw new TurvoAuthError(`Failed to authenticate: ${response.status} ${response.statusText}`);
|
|
62
|
+
}
|
|
63
|
+
const data = (await response.json());
|
|
64
|
+
const { access_token, expires_in } = data;
|
|
65
|
+
if (!access_token) {
|
|
66
|
+
throw new TurvoAuthError('No access token returned from Turvo');
|
|
67
|
+
}
|
|
68
|
+
cachedAccessToken = access_token;
|
|
69
|
+
// Set token expiry (expires_in is in seconds, default to 1 hour if not provided)
|
|
70
|
+
const expiresInMs = (expires_in || 3600) * 1000;
|
|
71
|
+
tokenExpiry = new Date(Date.now() + expiresInMs - 60000); // Refresh 1 minute early
|
|
72
|
+
return access_token;
|
|
73
|
+
}, { retries: allowedRetries });
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Clear the cached access token (useful for testing or when token expires)
|
|
77
|
+
*/
|
|
78
|
+
export const clearCachedAccessToken = () => {
|
|
79
|
+
cachedAccessToken = null;
|
|
80
|
+
tokenExpiry = null;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Main client for interacting with Turvo APIs.
|
|
84
|
+
* Handles authentication, token management, and HTTP requests.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* const client = new TurvoClient()
|
|
89
|
+
* const httpClient = await client.getAuthenticatedClient()
|
|
90
|
+
* const result = await httpClient.sendRequest('/shipments/123', TurvoApiMethod.GET, {})
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export class TurvoClient {
|
|
94
|
+
secretPath;
|
|
95
|
+
credentials;
|
|
96
|
+
httpClient;
|
|
97
|
+
constructor(secretPath = TURVO_SECRET_PATH) {
|
|
98
|
+
this.secretPath = secretPath;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Get authenticated HTTP client.
|
|
102
|
+
* Handles token refresh automatically.
|
|
103
|
+
*/
|
|
104
|
+
async getAuthenticatedClient() {
|
|
105
|
+
if (this.httpClient) {
|
|
106
|
+
return this.httpClient;
|
|
107
|
+
}
|
|
108
|
+
// Fetch credentials if not already loaded
|
|
109
|
+
if (!this.credentials) {
|
|
110
|
+
this.credentials = await getTurvoSecrets(this.secretPath);
|
|
111
|
+
}
|
|
112
|
+
// Create HTTP client with rate limiting and retries
|
|
113
|
+
const apiRoutePrefix = DEFAULT_API_ROUTE_PREFIX;
|
|
114
|
+
const allowedRetries = DEFAULT_ALLOWED_RETRIES;
|
|
115
|
+
const rateLimitRequestsPerSecond = DEFAULT_RATE_LIMIT_RPS;
|
|
116
|
+
// Create throttled version of the send function
|
|
117
|
+
const throttle = pThrottle({
|
|
118
|
+
limit: rateLimitRequestsPerSecond,
|
|
119
|
+
interval: 1000,
|
|
120
|
+
});
|
|
121
|
+
/**
|
|
122
|
+
* Internal function to send API request (with retry logic)
|
|
123
|
+
*/
|
|
124
|
+
const sendToTurvoAPI = async (apiRoute, method, params) => {
|
|
125
|
+
const accessToken = await getTurvoAccessToken(this.credentials, apiRoutePrefix, allowedRetries);
|
|
126
|
+
const { body, headers, query } = params;
|
|
127
|
+
let fullRoute = `${this.credentials.urlBase + apiRoutePrefix + apiRoute}`;
|
|
128
|
+
if (query && Object.keys(query).length > 0) {
|
|
129
|
+
fullRoute = `${fullRoute}?${new URLSearchParams(query)}`;
|
|
130
|
+
}
|
|
131
|
+
return pRetry(async () => {
|
|
132
|
+
return fetch(fullRoute, {
|
|
133
|
+
method,
|
|
134
|
+
headers: {
|
|
135
|
+
Authorization: `Bearer ${accessToken}`,
|
|
136
|
+
'Content-Type': 'application/json',
|
|
137
|
+
'x-api-key': this.credentials.apiKey,
|
|
138
|
+
...headers,
|
|
139
|
+
},
|
|
140
|
+
...(body && { body: JSON.stringify(body) }),
|
|
141
|
+
}).then(async (res) => {
|
|
142
|
+
const result = await res.json();
|
|
143
|
+
// Handle rate limiting (429)
|
|
144
|
+
if (res.status === 429) {
|
|
145
|
+
throw new TurvoApiError(res.status.toString(), result.message || 'Rate limited');
|
|
146
|
+
}
|
|
147
|
+
// Check for API-level errors
|
|
148
|
+
if (result.Status !== TurvoApiResponseStatus.SUCCESS) {
|
|
149
|
+
throw new TurvoApiError(result.details?.errorCode || 'UNKNOWN', result.details?.errorMessage || 'API error');
|
|
150
|
+
}
|
|
151
|
+
return result;
|
|
152
|
+
});
|
|
153
|
+
}, { retries: allowedRetries });
|
|
154
|
+
};
|
|
155
|
+
// Throttle the send function
|
|
156
|
+
const throttledSend = throttle(sendToTurvoAPI);
|
|
157
|
+
this.httpClient = {
|
|
158
|
+
sendRequest: throttledSend,
|
|
159
|
+
};
|
|
160
|
+
return this.httpClient;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Get raw secrets (for internal API auth which uses different flow)
|
|
164
|
+
*/
|
|
165
|
+
async getCredentials() {
|
|
166
|
+
if (!this.credentials) {
|
|
167
|
+
this.credentials = await getTurvoSecrets(this.secretPath);
|
|
168
|
+
}
|
|
169
|
+
return this.credentials;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHVydm9DbGllbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY2xpZW50L3R1cnZvQ2xpZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQTtBQUM5QyxPQUFPLEtBQUssTUFBTSxZQUFZLENBQUE7QUFDOUIsT0FBTyxNQUFNLE1BQU0sU0FBUyxDQUFBO0FBQzVCLE9BQU8sU0FBUyxNQUFNLFlBQVksQ0FBQTtBQUVsQyxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLHdCQUF3QixFQUN4QixzQkFBc0IsRUFDdEIsaUJBQWlCLEdBQ2xCLE1BQU0sY0FBYyxDQUFBO0FBQ3JCLE9BQU8sRUFBRSxhQUFhLEVBQWtCLHNCQUFzQixFQUFrQixNQUFNLGlCQUFpQixDQUFBO0FBRXZHLE9BQU8sRUFBRSxhQUFhLEVBQUUsY0FBYyxFQUFFLE1BQU0saUJBQWlCLENBQUE7QUFFL0QsSUFBSSxZQUFZLEdBQWtCLElBQUksQ0FBQTtBQUV0Qzs7R0FFRztBQUNILE1BQU0sdUJBQXVCLEdBQUcsR0FBVyxFQUFFO0lBQzNDLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUNsQixZQUFZLEdBQUcsSUFBSSxNQUFNLEVBQUUsQ0FBQTtJQUM3QixDQUFDO0lBQ0QsT0FBTyxZQUFZLENBQUE7QUFDckIsQ0FBQyxDQUFBO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLGVBQWUsR0FBRyxLQUFLLEVBQUUsY0FBc0IsaUJBQWlCLEVBQTZCLEVBQUU7SUFDbkcsTUFBTSxhQUFhLEdBQUcsTUFBTSx1QkFBdUIsRUFBRSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsQ0FBQTtJQUUvRSxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDbkIsTUFBTSxJQUFJLGFBQWEsQ0FBQyxXQUFXLENBQUMsQ0FBQTtJQUN0QyxDQUFDO0lBRUQsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBcUIs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NkJBQTZCO1FBQzdCLE1BQU0sYUFBYSxHQUFHLFFBQVEsQ0FBQyxjQUFjLENBQUMsQ0FBQTtRQUU5QyxJQUFJLENBQUMsVUFBVSxHQUFHO1lBQ2hCLFdBQVcsRUFBRSxhQUFhO1NBQzNCLENBQUE7UUFFRCxPQUFPLElBQUksQ0FBQyxVQUFVLENBQUE7SUFDeEIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLGNBQWM7UUFDbEIsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUN0QixJQUFJLENBQUMsV0FBVyxHQUFHLE1BQU0sZUFBZSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQTtRQUMzRCxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFBO0lBQ3pCLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENsaWVudCB9IGZyb20gJ2xhbWJkYS1wYXJhbXMtc2VjcmV0cydcbmltcG9ydCBmZXRjaCBmcm9tICdub2RlLWZldGNoJ1xuaW1wb3J0IHBSZXRyeSBmcm9tICdwLXJldHJ5J1xuaW1wb3J0IHBUaHJvdHRsZSBmcm9tICdwLXRocm90dGxlJ1xuXG5pbXBvcnQge1xuICBERUZBVUxUX0FMTE9XRURfUkVUUklFUyxcbiAgREVGQVVMVF9BUElfUk9VVEVfUFJFRklYLFxuICBERUZBVUxUX1JBVEVfTElNSVRfUlBTLFxuICBUVVJWT19TRUNSRVRfUEFUSCxcbn0gZnJvbSAnLi4vY29uc3RhbnRzJ1xuaW1wb3J0IHsgVHVydm9BcGlFcnJvciwgVHVydm9BcGlNZXRob2QsIFR1cnZvQXBpUmVzcG9uc2VTdGF0dXMsIFR1cnZvQXBpUmVzdWx0IH0gZnJvbSAnLi4vdHlwZXMvY29tbW9uJ1xuaW1wb3J0IHsgVHVydm9DcmVkZW50aWFscyB9IGZyb20gJy4uL3R5cGVzL2NvbmZpZydcbmltcG9ydCB7IE5vU2VjcmV0RXJyb3IsIFR1cnZvQXV0aEVycm9yIH0gZnJvbSAnLi4vdHlwZXMvZXJyb3JzJ1xuXG5sZXQgc2VjcmV0Q2xpZW50OiBDbGllbnQgfCBudWxsID0gbnVsbFxuXG4vKipcbiAqIEdldCBvciBjcmVhdGUgdGhlIHNlY3JldHMgY2xpZW50IGluc3RhbmNlXG4gKi9cbmNvbnN0IGdldFNlY3JldENsaWVudEluc3RhbmNlID0gKCk6IENsaWVudCA9PiB7XG4gIGlmICghc2VjcmV0Q2xpZW50KSB7XG4gICAgc2VjcmV0Q2xpZW50ID0gbmV3IENsaWVudCgpXG4gIH1cbiAgcmV0dXJuIHNlY3JldENsaWVudFxufVxuXG4vKipcbiAqIEZldGNoIFR1cnZvIEFQSSBjcmVkZW50aWFscyBmcm9tIEFXUyBTZWNyZXRzIE1hbmFnZXJcbiAqL1xuY29uc3QgZ2V0VHVydm9TZWNyZXRzID0gYXN5bmMgKHNlY3JldHNQYXRoOiBzdHJpbmcgPSBUVVJWT19TRUNSRVRfUEFUSCk6IFByb21pc2U8VHVydm9DcmVkZW50aWFscz4gPT4ge1xuICBjb25zdCBmZXRjaGVkU2VjcmV0ID0gYXdhaXQgZ2V0U2VjcmV0Q2xpZW50SW5zdGFuY2UoKS5zdHJpbmdTZWNyZXQoc2VjcmV0c1BhdGgpXG5cbiAgaWYgKCFmZXRjaGVkU2VjcmV0KSB7XG4gICAgdGhyb3cgbmV3IE5vU2VjcmV0RXJyb3Ioc2VjcmV0c1BhdGgpXG4gIH1cblxuICByZXR1cm4gSlNPTi5wYXJzZShmZXRjaGVkU2VjcmV0KSBhcyBUdXJ2b0NyZWRlbnRpYWxzXG59XG5cbi8qKlxuICogQ2FjaGVkIGFjY2VzcyB0b2tlbiB0byBhdm9pZCByZXBlYXRlZCBPQXV0aCByZXF1ZXN0c1xuICovXG5sZXQgY2FjaGVkQWNjZXNzVG9rZW46IHN0cmluZyB8IG51bGwgPSBudWxsXG5sZXQgdG9rZW5FeHBpcnk6IERhdGUgfCBudWxsID0gbnVsbFxuXG4vKipcbiAqIEZldGNoIGFuIGFjY2VzcyB0b2tlbiBmcm9tIFR1cnZvIHVzaW5nIE9BdXRoMiBwYXNzd29yZCBncmFudFxuICovXG5jb25zdCBnZXRUdXJ2b0FjY2Vzc1Rva2VuID0gYXN5bmMgKFxuICBjcmVkZW50aWFsczogVHVydm9DcmVkZW50aWFscyxcbiAgYXBpUm91dGVQcmVmaXg6IHN0cmluZyA9IERFRkFVTFRfQVBJX1JPVVRFX1BSRUZJWCxcbiAgYWxsb3dlZFJldHJpZXM6IG51bWJlciA9IERFRkFVTFRfQUxMT1dFRF9SRVRSSUVTXG4pOiBQcm9taXNlPHN0cmluZz4gPT4ge1xuICAvLyBDaGVjayBpZiB3ZSBoYXZlIGEgdmFsaWQgY2FjaGVkIHRva2VuXG4gIGlmIChjYWNoZWRBY2Nlc3NUb2tlbiAmJiB0b2tlbkV4cGlyeSAmJiB0b2tlbkV4cGlyeSA+IG5ldyBEYXRlKCkpIHtcbiAgICByZXR1cm4gY2FjaGVkQWNjZXNzVG9rZW5cbiAgfVxuXG4gIGNvbnN0IGZ1bGxVcmwgPSBgJHtjcmVkZW50aWFscy51cmxCYXNlICsgYXBpUm91dGVQcmVmaXh9L29hdXRoL3Rva2VuYFxuXG4gIHJldHVybiBwUmV0cnkoXG4gICAgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgdXJsID0gbmV3IFVSTChmdWxsVXJsKVxuICAgICAgdXJsLnNlYXJjaFBhcmFtcy5zZXQoJ2NsaWVudF9pZCcsICdwdWJsaWNhcGknKVxuICAgICAgdXJsLnNlYXJjaFBhcmFtcy5zZXQoJ2NsaWVudF9zZWNyZXQnLCAnc2VjcmV0JylcblxuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaCh1cmwsIHtcbiAgICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAgICd4LWFwaS1rZXknOiBjcmVkZW50aWFscy5hcGlLZXksXG4gICAgICAgIH0sXG4gICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICBncmFudF90eXBlOiAncGFzc3dvcmQnLFxuICAgICAgICAgIHNjb3BlOiAncmVhZCt0cnVzdCt3cml0ZScsXG4gICAgICAgICAgdXNlcm5hbWU6IGNyZWRlbnRpYWxzLnVzZXJuYW1lLFxuICAgICAgICAgIHBhc3N3b3JkOiBjcmVkZW50aWFscy5wYXNzd29yZCxcbiAgICAgICAgICB0eXBlOiAnYnVzaW5lc3MnLFxuICAgICAgICB9KSxcbiAgICAgIH0pXG5cbiAgICAgIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICAgICAgdGhyb3cgbmV3IFR1cnZvQXV0aEVycm9yKGBGYWlsZWQgdG8gYXV0aGVudGljYXRlOiAke3Jlc3BvbnNlLnN0YXR1c30gJHtyZXNwb25zZS5zdGF0dXNUZXh0fWApXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGRhdGEgPSAoYXdhaXQgcmVzcG9uc2UuanNvbigpKSBhcyB7IGFjY2Vzc190b2tlbjogc3RyaW5nOyBleHBpcmVzX2luPzogbnVtYmVyIH1cbiAgICAgIGNvbnN0IHsgYWNjZXNzX3Rva2VuLCBleHBpcmVzX2luIH0gPSBkYXRhXG5cbiAgICAgIGlmICghYWNjZXNzX3Rva2VuKSB7XG4gICAgICAgIHRocm93IG5ldyBUdXJ2b0F1dGhFcnJvcignTm8gYWNjZXNzIHRva2VuIHJldHVybmVkIGZyb20gVHVydm8nKVxuICAgICAgfVxuXG4gICAgICBjYWNoZWRBY2Nlc3NUb2tlbiA9IGFjY2Vzc190b2tlblxuXG4gICAgICAvLyBTZXQgdG9rZW4gZXhwaXJ5IChleHBpcmVzX2luIGlzIGluIHNlY29uZHMsIGRlZmF1bHQgdG8gMSBob3VyIGlmIG5vdCBwcm92aWRlZClcbiAgICAgIGNvbnN0IGV4cGlyZXNJbk1zID0gKGV4cGlyZXNfaW4gfHwgMzYwMCkgKiAxMDAwXG4gICAgICB0b2tlbkV4cGlyeSA9IG5ldyBEYXRlKERhdGUubm93KCkgKyBleHBpcmVzSW5NcyAtIDYwMDAwKSAvLyBSZWZyZXNoIDEgbWludXRlIGVhcmx5XG5cbiAgICAgIHJldHVybiBhY2Nlc3NfdG9rZW5cbiAgICB9LFxuICAgIHsgcmV0cmllczogYWxsb3dlZFJldHJpZXMgfVxuICApXG59XG5cbi8qKlxuICogQ2xlYXIgdGhlIGNhY2hlZCBhY2Nlc3MgdG9rZW4gKHVzZWZ1bCBmb3IgdGVzdGluZyBvciB3aGVuIHRva2VuIGV4cGlyZXMpXG4gKi9cbmV4cG9ydCBjb25zdCBjbGVhckNhY2hlZEFjY2Vzc1Rva2VuID0gKCk6IHZvaWQgPT4ge1xuICBjYWNoZWRBY2Nlc3NUb2tlbiA9IG51bGxcbiAgdG9rZW5FeHBpcnkgPSBudWxsXG59XG5cbi8qKlxuICogSFRUUCBjbGllbnQgaW50ZXJmYWNlIGZvciBtYWtpbmcgYXV0aGVudGljYXRlZCBUdXJ2byBBUEkgcmVxdWVzdHNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBBdXRoZW50aWNhdGVkSHR0cENsaWVudCB7XG4gIC8qKlxuICAgKiBTZW5kIGEgcmVxdWVzdCB0byB0aGUgVHVydm8gQVBJXG4gICAqIEBwYXJhbSBhcGlSb3V0ZSAtIEFQSSByb3V0ZSBwYXRoIChlLmcuLCAnL3NoaXBtZW50cycpXG4gICAqIEBwYXJhbSBtZXRob2QgLSBIVFRQIG1ldGhvZFxuICAgKiBAcGFyYW0gcGFyYW1zIC0gUmVxdWVzdCBwYXJhbWV0ZXJzIChib2R5LCBoZWFkZXJzLCBxdWVyeSlcbiAgICogQHJldHVybnMgVHlwZWQgQVBJIHJlc3VsdFxuICAgKi9cbiAgc2VuZFJlcXVlc3Q8VD4oXG4gICAgYXBpUm91dGU6IHN0cmluZyxcbiAgICBtZXRob2Q6IFR1cnZvQXBpTWV0aG9kLFxuICAgIHBhcmFtczogeyBib2R5Pzogb2JqZWN0OyBoZWFkZXJzPzogUmVjb3JkPHN0cmluZywgc3RyaW5nPjsgcXVlcnk/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IH1cbiAgKTogUHJvbWlzZTxUdXJ2b0FwaVJlc3VsdDxUPj5cbn1cblxuLyoqXG4gKiBNYWluIGNsaWVudCBmb3IgaW50ZXJhY3Rpbmcgd2l0aCBUdXJ2byBBUElzLlxuICogSGFuZGxlcyBhdXRoZW50aWNhdGlvbiwgdG9rZW4gbWFuYWdlbWVudCwgYW5kIEhUVFAgcmVxdWVzdHMuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IGNsaWVudCA9IG5ldyBUdXJ2b0NsaWVudCgpXG4gKiBjb25zdCBodHRwQ2xpZW50ID0gYXdhaXQgY2xpZW50LmdldEF1dGhlbnRpY2F0ZWRDbGllbnQoKVxuICogY29uc3QgcmVzdWx0ID0gYXdhaXQgaHR0cENsaWVudC5zZW5kUmVxdWVzdCgnL3NoaXBtZW50cy8xMjMnLCBUdXJ2b0FwaU1ldGhvZC5HRVQsIHt9KVxuICogYGBgXG4gKi9cbmV4cG9ydCBjbGFzcyBUdXJ2b0NsaWVudCB7XG4gIHByaXZhdGUgY3JlZGVudGlhbHM/OiBUdXJ2b0NyZWRlbnRpYWxzXG4gIHByaXZhdGUgaHR0cENsaWVudD86IEF1dGhlbnRpY2F0ZWRIdHRwQ2xpZW50XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBzZWNyZXRQYXRoOiBzdHJpbmcgPSBUVVJWT19TRUNSRVRfUEFUSCkge31cblxuICAvKipcbiAgICogR2V0IGF1dGhlbnRpY2F0ZWQgSFRUUCBjbGllbnQuXG4gICAqIEhhbmRsZXMgdG9rZW4gcmVmcmVzaCBhdXRvbWF0aWNhbGx5LlxuICAgKi9cbiAgYXN5bmMgZ2V0QXV0aGVudGljYXRlZENsaWVudCgpOiBQcm9taXNlPEF1dGhlbnRpY2F0ZWRIdHRwQ2xpZW50PiB7XG4gICAgaWYgKHRoaXMuaHR0cENsaWVudCkge1xuICAgICAgcmV0dXJuIHRoaXMuaHR0cENsaWVudFxuICAgIH1cblxuICAgIC8vIEZldGNoIGNyZWRlbnRpYWxzIGlmIG5vdCBhbHJlYWR5IGxvYWRlZFxuICAgIGlmICghdGhpcy5jcmVkZW50aWFscykge1xuICAgICAgdGhpcy5jcmVkZW50aWFscyA9IGF3YWl0IGdldFR1cnZvU2VjcmV0cyh0aGlzLnNlY3JldFBhdGgpXG4gICAgfVxuXG4gICAgLy8gQ3JlYXRlIEhUVFAgY2xpZW50IHdpdGggcmF0ZSBsaW1pdGluZyBhbmQgcmV0cmllc1xuICAgIGNvbnN0IGFwaVJvdXRlUHJlZml4ID0gREVGQVVMVF9BUElfUk9VVEVfUFJFRklYXG4gICAgY29uc3QgYWxsb3dlZFJldHJpZXMgPSBERUZBVUxUX0FMTE9XRURfUkVUUklFU1xuICAgIGNvbnN0IHJhdGVMaW1pdFJlcXVlc3RzUGVyU2Vjb25kID0gREVGQVVMVF9SQVRFX0xJTUlUX1JQU1xuXG4gICAgLy8gQ3JlYXRlIHRocm90dGxlZCB2ZXJzaW9uIG9mIHRoZSBzZW5kIGZ1bmN0aW9uXG4gICAgY29uc3QgdGhyb3R0bGUgPSBwVGhyb3R0bGUoe1xuICAgICAgbGltaXQ6IHJhdGVMaW1pdFJlcXVlc3RzUGVyU2Vjb25kLFxuICAgICAgaW50ZXJ2YWw6IDEwMDAsXG4gICAgfSlcblxuICAgIC8qKlxuICAgICAqIEludGVybmFsIGZ1bmN0aW9uIHRvIHNlbmQgQVBJIHJlcXVlc3QgKHdpdGggcmV0cnkgbG9naWMpXG4gICAgICovXG4gICAgY29uc3Qgc2VuZFRvVHVydm9BUEkgPSBhc3luYyA8VD4oXG4gICAgICBhcGlSb3V0ZTogc3RyaW5nLFxuICAgICAgbWV0aG9kOiBUdXJ2b0FwaU1ldGhvZCxcbiAgICAgIHBhcmFtczogeyBib2R5Pzogb2JqZWN0OyBoZWFkZXJzPzogUmVjb3JkPHN0cmluZywgc3RyaW5nPjsgcXVlcnk/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IH1cbiAgICApOiBQcm9taXNlPFR1cnZvQXBpUmVzdWx0PFQ+PiA9PiB7XG4gICAgICBjb25zdCBhY2Nlc3NUb2tlbiA9IGF3YWl0IGdldFR1cnZvQWNjZXNzVG9rZW4odGhpcy5jcmVkZW50aWFscyEsIGFwaVJvdXRlUHJlZml4LCBhbGxvd2VkUmV0cmllcylcbiAgICAgIGNvbnN0IHsgYm9keSwgaGVhZGVycywgcXVlcnkgfSA9IHBhcmFtc1xuICAgICAgbGV0IGZ1bGxSb3V0ZSA9IGAke3RoaXMuY3JlZGVudGlhbHMhLnVybEJhc2UgKyBhcGlSb3V0ZVByZWZpeCArIGFwaVJvdXRlfWBcblxuICAgICAgaWYgKHF1ZXJ5ICYmIE9iamVjdC5rZXlzKHF1ZXJ5KS5sZW5ndGggPiAwKSB7XG4gICAgICAgIGZ1bGxSb3V0ZSA9IGAke2Z1bGxSb3V0ZX0/JHtuZXcgVVJMU2VhcmNoUGFyYW1zKHF1ZXJ5KX1gXG4gICAgICB9XG5cbiAgICAgIHJldHVybiBwUmV0cnkoXG4gICAgICAgIGFzeW5jICgpID0+IHtcbiAgICAgICAgICByZXR1cm4gZmV0Y2goZnVsbFJvdXRlLCB7XG4gICAgICAgICAgICBtZXRob2QsXG4gICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgIEF1dGhvcml6YXRpb246IGBCZWFyZXIgJHthY2Nlc3NUb2tlbn1gLFxuICAgICAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAgICAgICAneC1hcGkta2V5JzogdGhpcy5jcmVkZW50aWFscyEuYXBpS2V5LFxuICAgICAgICAgICAgICAuLi5oZWFkZXJzLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIC4uLihib2R5ICYmIHsgYm9keTogSlNPTi5zdHJpbmdpZnkoYm9keSkgfSksXG4gICAgICAgICAgfSkudGhlbihhc3luYyByZXMgPT4ge1xuICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcmVzLmpzb24oKVxuXG4gICAgICAgICAgICAvLyBIYW5kbGUgcmF0ZSBsaW1pdGluZyAoNDI5KVxuICAgICAgICAgICAgaWYgKHJlcy5zdGF0dXMgPT09IDQyOSkge1xuICAgICAgICAgICAgICB0aHJvdyBuZXcgVHVydm9BcGlFcnJvcihyZXMuc3RhdHVzLnRvU3RyaW5nKCksIHJlc3VsdC5tZXNzYWdlIHx8ICdSYXRlIGxpbWl0ZWQnKVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBDaGVjayBmb3IgQVBJLWxldmVsIGVycm9yc1xuICAgICAgICAgICAgaWYgKHJlc3VsdC5TdGF0dXMgIT09IFR1cnZvQXBpUmVzcG9uc2VTdGF0dXMuU1VDQ0VTUykge1xuICAgICAgICAgICAgICB0aHJvdyBuZXcgVHVydm9BcGlFcnJvcihcbiAgICAgICAgICAgICAgICByZXN1bHQuZGV0YWlscz8uZXJyb3JDb2RlIHx8ICdVTktOT1dOJyxcbiAgICAgICAgICAgICAgICByZXN1bHQuZGV0YWlscz8uZXJyb3JNZXNzYWdlIHx8ICdBUEkgZXJyb3InXG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdFxuICAgICAgICAgIH0pXG4gICAgICAgIH0sXG4gICAgICAgIHsgcmV0cmllczogYWxsb3dlZFJldHJpZXMgfVxuICAgICAgKVxuICAgIH1cblxuICAgIC8vIFRocm90dGxlIHRoZSBzZW5kIGZ1bmN0aW9uXG4gICAgY29uc3QgdGhyb3R0bGVkU2VuZCA9IHRocm90dGxlKHNlbmRUb1R1cnZvQVBJKVxuXG4gICAgdGhpcy5odHRwQ2xpZW50ID0ge1xuICAgICAgc2VuZFJlcXVlc3Q6IHRocm90dGxlZFNlbmQsXG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuaHR0cENsaWVudFxuICB9XG5cbiAgLyoqXG4gICAqIEdldCByYXcgc2VjcmV0cyAoZm9yIGludGVybmFsIEFQSSBhdXRoIHdoaWNoIHVzZXMgZGlmZmVyZW50IGZsb3cpXG4gICAqL1xuICBhc3luYyBnZXRDcmVkZW50aWFscygpOiBQcm9taXNlPFR1cnZvQ3JlZGVudGlhbHM+IHtcbiAgICBpZiAoIXRoaXMuY3JlZGVudGlhbHMpIHtcbiAgICAgIHRoaXMuY3JlZGVudGlhbHMgPSBhd2FpdCBnZXRUdXJ2b1NlY3JldHModGhpcy5zZWNyZXRQYXRoKVxuICAgIH1cbiAgICByZXR1cm4gdGhpcy5jcmVkZW50aWFsc1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default secret path for Turvo credentials in AWS Secrets Manager.
|
|
3
|
+
* Export this so consumers can grant IAM permissions.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* import { TURVO_SECRET_PATH } from '@veho/turvo-sdk'
|
|
8
|
+
*
|
|
9
|
+
* // In CDK stack
|
|
10
|
+
* myLambda.addToRolePolicy(new iam.PolicyStatement({
|
|
11
|
+
* actions: ['secretsmanager:GetSecretValue'],
|
|
12
|
+
* resources: [`arn:aws:secretsmanager:*:*:secret:${TURVO_SECRET_PATH}*`],
|
|
13
|
+
* }))
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare const TURVO_SECRET_PATH = "/turvo/api";
|
|
17
|
+
/**
|
|
18
|
+
* Default API route prefix for Turvo endpoints.
|
|
19
|
+
* Currently, Turvo uses a common prefix of "/v1" for all documented API routes.
|
|
20
|
+
*/
|
|
21
|
+
export declare const DEFAULT_API_ROUTE_PREFIX = "/v1";
|
|
22
|
+
/**
|
|
23
|
+
* Default number of retry attempts for failed requests.
|
|
24
|
+
*/
|
|
25
|
+
export declare const DEFAULT_ALLOWED_RETRIES = 2;
|
|
26
|
+
/**
|
|
27
|
+
* Default rate limit (requests per second) for Turvo API calls.
|
|
28
|
+
*/
|
|
29
|
+
export declare const DEFAULT_RATE_LIMIT_RPS = 1;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default secret path for Turvo credentials in AWS Secrets Manager.
|
|
3
|
+
* Export this so consumers can grant IAM permissions.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* import { TURVO_SECRET_PATH } from '@veho/turvo-sdk'
|
|
8
|
+
*
|
|
9
|
+
* // In CDK stack
|
|
10
|
+
* myLambda.addToRolePolicy(new iam.PolicyStatement({
|
|
11
|
+
* actions: ['secretsmanager:GetSecretValue'],
|
|
12
|
+
* resources: [`arn:aws:secretsmanager:*:*:secret:${TURVO_SECRET_PATH}*`],
|
|
13
|
+
* }))
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export const TURVO_SECRET_PATH = '/turvo/api';
|
|
17
|
+
/**
|
|
18
|
+
* Default API route prefix for Turvo endpoints.
|
|
19
|
+
* Currently, Turvo uses a common prefix of "/v1" for all documented API routes.
|
|
20
|
+
*/
|
|
21
|
+
export const DEFAULT_API_ROUTE_PREFIX = '/v1';
|
|
22
|
+
/**
|
|
23
|
+
* Default number of retry attempts for failed requests.
|
|
24
|
+
*/
|
|
25
|
+
export const DEFAULT_ALLOWED_RETRIES = 2;
|
|
26
|
+
/**
|
|
27
|
+
* Default rate limit (requests per second) for Turvo API calls.
|
|
28
|
+
*/
|
|
29
|
+
export const DEFAULT_RATE_LIMIT_RPS = 1;
|
|
30
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc3RhbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbnN0YW50cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7R0FjRztBQUNILE1BQU0sQ0FBQyxNQUFNLGlCQUFpQixHQUFHLFlBQVksQ0FBQTtBQUU3Qzs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSx3QkFBd0IsR0FBRyxLQUFLLENBQUE7QUFFN0M7O0dBRUc7QUFDSCxNQUFNLENBQUMsTUFBTSx1QkFBdUIsR0FBRyxDQUFDLENBQUE7QUFFeEM7O0dBRUc7QUFDSCxNQUFNLENBQUMsTUFBTSxzQkFBc0IsR0FBRyxDQUFDLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIERlZmF1bHQgc2VjcmV0IHBhdGggZm9yIFR1cnZvIGNyZWRlbnRpYWxzIGluIEFXUyBTZWNyZXRzIE1hbmFnZXIuXG4gKiBFeHBvcnQgdGhpcyBzbyBjb25zdW1lcnMgY2FuIGdyYW50IElBTSBwZXJtaXNzaW9ucy5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgVFVSVk9fU0VDUkVUX1BBVEggfSBmcm9tICdAdmVoby90dXJ2by1zZGsnXG4gKlxuICogLy8gSW4gQ0RLIHN0YWNrXG4gKiBteUxhbWJkYS5hZGRUb1JvbGVQb2xpY3kobmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICogICBhY3Rpb25zOiBbJ3NlY3JldHNtYW5hZ2VyOkdldFNlY3JldFZhbHVlJ10sXG4gKiAgIHJlc291cmNlczogW2Bhcm46YXdzOnNlY3JldHNtYW5hZ2VyOio6KjpzZWNyZXQ6JHtUVVJWT19TRUNSRVRfUEFUSH0qYF0sXG4gKiB9KSlcbiAqIGBgYFxuICovXG5leHBvcnQgY29uc3QgVFVSVk9fU0VDUkVUX1BBVEggPSAnL3R1cnZvL2FwaSdcblxuLyoqXG4gKiBEZWZhdWx0IEFQSSByb3V0ZSBwcmVmaXggZm9yIFR1cnZvIGVuZHBvaW50cy5cbiAqIEN1cnJlbnRseSwgVHVydm8gdXNlcyBhIGNvbW1vbiBwcmVmaXggb2YgXCIvdjFcIiBmb3IgYWxsIGRvY3VtZW50ZWQgQVBJIHJvdXRlcy5cbiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfQVBJX1JPVVRFX1BSRUZJWCA9ICcvdjEnXG5cbi8qKlxuICogRGVmYXVsdCBudW1iZXIgb2YgcmV0cnkgYXR0ZW1wdHMgZm9yIGZhaWxlZCByZXF1ZXN0cy5cbiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfQUxMT1dFRF9SRVRSSUVTID0gMlxuXG4vKipcbiAqIERlZmF1bHQgcmF0ZSBsaW1pdCAocmVxdWVzdHMgcGVyIHNlY29uZCkgZm9yIFR1cnZvIEFQSSBjYWxscy5cbiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfUkFURV9MSU1JVF9SUFMgPSAxXG4iXX0=
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { getShipmentTracking } from './shipmentTracking';
|
|
2
|
+
export { TurvoInternalApi } from './api/turvoInternalApi';
|
|
3
|
+
export { TurvoPublicApi } from './api/turvoPublicApi';
|
|
4
|
+
export { clearCachedAccessToken, TurvoClient } from './client/turvoClient';
|
|
5
|
+
export * from './types';
|
|
6
|
+
export { DEFAULT_ALLOWED_RETRIES, DEFAULT_API_ROUTE_PREFIX, DEFAULT_RATE_LIMIT_RPS, TURVO_SECRET_PATH, } from './constants';
|
package/lib/esm/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Main tracking function
|
|
2
|
+
export { getShipmentTracking } from './shipmentTracking';
|
|
3
|
+
// Client classes (for advanced usage)
|
|
4
|
+
export { TurvoInternalApi } from './api/turvoInternalApi';
|
|
5
|
+
export { TurvoPublicApi } from './api/turvoPublicApi';
|
|
6
|
+
export { clearCachedAccessToken, TurvoClient } from './client/turvoClient';
|
|
7
|
+
// All types
|
|
8
|
+
export * from './types';
|
|
9
|
+
// Constants
|
|
10
|
+
export { DEFAULT_ALLOWED_RETRIES, DEFAULT_API_ROUTE_PREFIX, DEFAULT_RATE_LIMIT_RPS, TURVO_SECRET_PATH, } from './constants';
|
|
11
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEseUJBQXlCO0FBQ3pCLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLG9CQUFvQixDQUFBO0FBRXhELHNDQUFzQztBQUN0QyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQTtBQUN6RCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sc0JBQXNCLENBQUE7QUFDckQsT0FBTyxFQUFFLHNCQUFzQixFQUFFLFdBQVcsRUFBRSxNQUFNLHNCQUFzQixDQUFBO0FBRTFFLFlBQVk7QUFDWixjQUFjLFNBQVMsQ0FBQTtBQUV2QixZQUFZO0FBQ1osT0FBTyxFQUNMLHVCQUF1QixFQUN2Qix3QkFBd0IsRUFDeEIsc0JBQXNCLEVBQ3RCLGlCQUFpQixHQUNsQixNQUFNLGFBQWEsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbIi8vIE1haW4gdHJhY2tpbmcgZnVuY3Rpb25cbmV4cG9ydCB7IGdldFNoaXBtZW50VHJhY2tpbmcgfSBmcm9tICcuL3NoaXBtZW50VHJhY2tpbmcnXG5cbi8vIENsaWVudCBjbGFzc2VzIChmb3IgYWR2YW5jZWQgdXNhZ2UpXG5leHBvcnQgeyBUdXJ2b0ludGVybmFsQXBpIH0gZnJvbSAnLi9hcGkvdHVydm9JbnRlcm5hbEFwaSdcbmV4cG9ydCB7IFR1cnZvUHVibGljQXBpIH0gZnJvbSAnLi9hcGkvdHVydm9QdWJsaWNBcGknXG5leHBvcnQgeyBjbGVhckNhY2hlZEFjY2Vzc1Rva2VuLCBUdXJ2b0NsaWVudCB9IGZyb20gJy4vY2xpZW50L3R1cnZvQ2xpZW50J1xuXG4vLyBBbGwgdHlwZXNcbmV4cG9ydCAqIGZyb20gJy4vdHlwZXMnXG5cbi8vIENvbnN0YW50c1xuZXhwb3J0IHtcbiAgREVGQVVMVF9BTExPV0VEX1JFVFJJRVMsXG4gIERFRkFVTFRfQVBJX1JPVVRFX1BSRUZJWCxcbiAgREVGQVVMVF9SQVRFX0xJTUlUX1JQUyxcbiAgVFVSVk9fU0VDUkVUX1BBVEgsXG59IGZyb20gJy4vY29uc3RhbnRzJ1xuIl19
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { GetTrackingOptions, ShipmentTracking } from '../types/tracking';
|
|
2
|
+
/**
|
|
3
|
+
* Main function to fetch shipment tracking data from Turvo.
|
|
4
|
+
* Combines public API (shipment details) with internal API (GPS tracking).
|
|
5
|
+
*
|
|
6
|
+
* @param shipmentId - The Turvo shipment ID to track
|
|
7
|
+
* @param options - Optional configuration for tracking request
|
|
8
|
+
* @returns Complete shipment tracking information
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { getShipmentTracking } from '@veho/turvo-sdk'
|
|
13
|
+
*
|
|
14
|
+
* const tracking = await getShipmentTracking('12345', {
|
|
15
|
+
* includeGps: true,
|
|
16
|
+
* secretPath: '/turvo/api'
|
|
17
|
+
* })
|
|
18
|
+
*
|
|
19
|
+
* console.log(tracking.status, tracking.etaUtc, tracking.isLate)
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function getShipmentTracking(shipmentId: string, options?: GetTrackingOptions): Promise<ShipmentTracking>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { TurvoInternalApi } from '../api/turvoInternalApi';
|
|
2
|
+
import { TurvoPublicApi } from '../api/turvoPublicApi';
|
|
3
|
+
import { TurvoClient } from '../client/turvoClient';
|
|
4
|
+
import { TrackingService } from './trackingService';
|
|
5
|
+
/**
|
|
6
|
+
* Main function to fetch shipment tracking data from Turvo.
|
|
7
|
+
* Combines public API (shipment details) with internal API (GPS tracking).
|
|
8
|
+
*
|
|
9
|
+
* @param shipmentId - The Turvo shipment ID to track
|
|
10
|
+
* @param options - Optional configuration for tracking request
|
|
11
|
+
* @returns Complete shipment tracking information
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { getShipmentTracking } from '@veho/turvo-sdk'
|
|
16
|
+
*
|
|
17
|
+
* const tracking = await getShipmentTracking('12345', {
|
|
18
|
+
* includeGps: true,
|
|
19
|
+
* secretPath: '/turvo/api'
|
|
20
|
+
* })
|
|
21
|
+
*
|
|
22
|
+
* console.log(tracking.status, tracking.etaUtc, tracking.isLate)
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export async function getShipmentTracking(shipmentId, options = {}) {
|
|
26
|
+
// Create client with optional custom secret path
|
|
27
|
+
const client = new TurvoClient(options.secretPath);
|
|
28
|
+
// Create API instances
|
|
29
|
+
const publicApi = new TurvoPublicApi(client);
|
|
30
|
+
const internalApi = new TurvoInternalApi(client);
|
|
31
|
+
// Create tracking service
|
|
32
|
+
const trackingService = new TrackingService(publicApi, internalApi);
|
|
33
|
+
// Fetch and return tracking data
|
|
34
|
+
return trackingService.getTracking(shipmentId, options);
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2hpcG1lbnRUcmFja2luZy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQTtBQUMxRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sdUJBQXVCLENBQUE7QUFDdEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHVCQUF1QixDQUFBO0FBRW5ELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUVuRDs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1CRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsbUJBQW1CLENBQ3ZDLFVBQWtCLEVBQ2xCLFVBQThCLEVBQUU7SUFFaEMsaURBQWlEO0lBQ2pELE1BQU0sTUFBTSxHQUFHLElBQUksV0FBVyxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQTtJQUVsRCx1QkFBdUI7SUFDdkIsTUFBTSxTQUFTLEdBQUcsSUFBSSxjQUFjLENBQUMsTUFBTSxDQUFDLENBQUE7SUFDNUMsTUFBTSxXQUFXLEdBQUcsSUFBSSxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsQ0FBQTtJQUVoRCwwQkFBMEI7SUFDMUIsTUFBTSxlQUFlLEdBQUcsSUFBSSxlQUFlLENBQUMsU0FBUyxFQUFFLFdBQVcsQ0FBQyxDQUFBO0lBRW5FLGlDQUFpQztJQUNqQyxPQUFPLGVBQWUsQ0FBQyxXQUFXLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFBO0FBQ3pELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBUdXJ2b0ludGVybmFsQXBpIH0gZnJvbSAnLi4vYXBpL3R1cnZvSW50ZXJuYWxBcGknXG5pbXBvcnQgeyBUdXJ2b1B1YmxpY0FwaSB9IGZyb20gJy4uL2FwaS90dXJ2b1B1YmxpY0FwaSdcbmltcG9ydCB7IFR1cnZvQ2xpZW50IH0gZnJvbSAnLi4vY2xpZW50L3R1cnZvQ2xpZW50J1xuaW1wb3J0IHsgR2V0VHJhY2tpbmdPcHRpb25zLCBTaGlwbWVudFRyYWNraW5nIH0gZnJvbSAnLi4vdHlwZXMvdHJhY2tpbmcnXG5pbXBvcnQgeyBUcmFja2luZ1NlcnZpY2UgfSBmcm9tICcuL3RyYWNraW5nU2VydmljZSdcblxuLyoqXG4gKiBNYWluIGZ1bmN0aW9uIHRvIGZldGNoIHNoaXBtZW50IHRyYWNraW5nIGRhdGEgZnJvbSBUdXJ2by5cbiAqIENvbWJpbmVzIHB1YmxpYyBBUEkgKHNoaXBtZW50IGRldGFpbHMpIHdpdGggaW50ZXJuYWwgQVBJIChHUFMgdHJhY2tpbmcpLlxuICpcbiAqIEBwYXJhbSBzaGlwbWVudElkIC0gVGhlIFR1cnZvIHNoaXBtZW50IElEIHRvIHRyYWNrXG4gKiBAcGFyYW0gb3B0aW9ucyAtIE9wdGlvbmFsIGNvbmZpZ3VyYXRpb24gZm9yIHRyYWNraW5nIHJlcXVlc3RcbiAqIEByZXR1cm5zIENvbXBsZXRlIHNoaXBtZW50IHRyYWNraW5nIGluZm9ybWF0aW9uXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IGdldFNoaXBtZW50VHJhY2tpbmcgfSBmcm9tICdAdmVoby90dXJ2by1zZGsnXG4gKlxuICogY29uc3QgdHJhY2tpbmcgPSBhd2FpdCBnZXRTaGlwbWVudFRyYWNraW5nKCcxMjM0NScsIHtcbiAqICAgaW5jbHVkZUdwczogdHJ1ZSxcbiAqICAgc2VjcmV0UGF0aDogJy90dXJ2by9hcGknXG4gKiB9KVxuICpcbiAqIGNvbnNvbGUubG9nKHRyYWNraW5nLnN0YXR1cywgdHJhY2tpbmcuZXRhVXRjLCB0cmFja2luZy5pc0xhdGUpXG4gKiBgYGBcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdldFNoaXBtZW50VHJhY2tpbmcoXG4gIHNoaXBtZW50SWQ6IHN0cmluZyxcbiAgb3B0aW9uczogR2V0VHJhY2tpbmdPcHRpb25zID0ge31cbik6IFByb21pc2U8U2hpcG1lbnRUcmFja2luZz4ge1xuICAvLyBDcmVhdGUgY2xpZW50IHdpdGggb3B0aW9uYWwgY3VzdG9tIHNlY3JldCBwYXRoXG4gIGNvbnN0IGNsaWVudCA9IG5ldyBUdXJ2b0NsaWVudChvcHRpb25zLnNlY3JldFBhdGgpXG5cbiAgLy8gQ3JlYXRlIEFQSSBpbnN0YW5jZXNcbiAgY29uc3QgcHVibGljQXBpID0gbmV3IFR1cnZvUHVibGljQXBpKGNsaWVudClcbiAgY29uc3QgaW50ZXJuYWxBcGkgPSBuZXcgVHVydm9JbnRlcm5hbEFwaShjbGllbnQpXG5cbiAgLy8gQ3JlYXRlIHRyYWNraW5nIHNlcnZpY2VcbiAgY29uc3QgdHJhY2tpbmdTZXJ2aWNlID0gbmV3IFRyYWNraW5nU2VydmljZShwdWJsaWNBcGksIGludGVybmFsQXBpKVxuXG4gIC8vIEZldGNoIGFuZCByZXR1cm4gdHJhY2tpbmcgZGF0YVxuICByZXR1cm4gdHJhY2tpbmdTZXJ2aWNlLmdldFRyYWNraW5nKHNoaXBtZW50SWQsIG9wdGlvbnMpXG59XG4iXX0=
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { TurvoInternalApi } from '../api/turvoInternalApi';
|
|
2
|
+
import { TurvoPublicApi } from '../api/turvoPublicApi';
|
|
3
|
+
import { GetTrackingOptions, ShipmentTracking } from '../types/tracking';
|
|
4
|
+
/**
|
|
5
|
+
* TrackingService orchestrates calls to public and internal APIs
|
|
6
|
+
* to provide a unified shipment tracking interface.
|
|
7
|
+
*/
|
|
8
|
+
export declare class TrackingService {
|
|
9
|
+
private publicApi;
|
|
10
|
+
private internalApi;
|
|
11
|
+
constructor(publicApi: TurvoPublicApi, internalApi: TurvoInternalApi);
|
|
12
|
+
/**
|
|
13
|
+
* Main entry point - combines all API data to produce ShipmentTracking
|
|
14
|
+
*
|
|
15
|
+
* @param shipmentId - The shipment ID to track
|
|
16
|
+
* @param options - Tracking options
|
|
17
|
+
* @returns Complete shipment tracking information
|
|
18
|
+
*/
|
|
19
|
+
getTracking(shipmentId: string, options?: GetTrackingOptions): Promise<ShipmentTracking>;
|
|
20
|
+
/**
|
|
21
|
+
* Transform raw Turvo API responses into clean ShipmentTracking type
|
|
22
|
+
*
|
|
23
|
+
*/
|
|
24
|
+
private transformToTrackingDetails;
|
|
25
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { TurvoNotFoundError } from '../types/errors';
|
|
2
|
+
/**
|
|
3
|
+
* TrackingService orchestrates calls to public and internal APIs
|
|
4
|
+
* to provide a unified shipment tracking interface.
|
|
5
|
+
*/
|
|
6
|
+
export class TrackingService {
|
|
7
|
+
publicApi;
|
|
8
|
+
internalApi;
|
|
9
|
+
constructor(publicApi, internalApi) {
|
|
10
|
+
this.publicApi = publicApi;
|
|
11
|
+
this.internalApi = internalApi;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Main entry point - combines all API data to produce ShipmentTracking
|
|
15
|
+
*
|
|
16
|
+
* @param shipmentId - The shipment ID to track
|
|
17
|
+
* @param options - Tracking options
|
|
18
|
+
* @returns Complete shipment tracking information
|
|
19
|
+
*/
|
|
20
|
+
async getTracking(shipmentId, options = {}) {
|
|
21
|
+
// 1. Fetch public API data (required)
|
|
22
|
+
const shipmentResult = await this.publicApi.getShipment({ shipmentId: parseInt(shipmentId) });
|
|
23
|
+
if (!shipmentResult.details) {
|
|
24
|
+
throw new TurvoNotFoundError(shipmentId);
|
|
25
|
+
}
|
|
26
|
+
const shipment = shipmentResult.details;
|
|
27
|
+
// 2. Fetch internal API data (optional, may fail)
|
|
28
|
+
let locationUpdates = null;
|
|
29
|
+
let internalApiFailed = false;
|
|
30
|
+
if (options.includeGps !== false) {
|
|
31
|
+
try {
|
|
32
|
+
locationUpdates = await this.internalApi.getLocationUpdates(shipmentId);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
// Log but don't fail - internal API is optional
|
|
36
|
+
internalApiFailed = true;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// 3. Transform to clean response
|
|
40
|
+
return this.transformToTrackingDetails(shipment, locationUpdates, internalApiFailed);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Transform raw Turvo API responses into clean ShipmentTracking type
|
|
44
|
+
*
|
|
45
|
+
*/
|
|
46
|
+
transformToTrackingDetails(shipment, locationUpdates, internalApiFailed) {
|
|
47
|
+
const shipmentData = shipment;
|
|
48
|
+
return {
|
|
49
|
+
// Identifiers
|
|
50
|
+
shipmentId: shipmentData.id?.toString() || '',
|
|
51
|
+
loadReferenceNumber: shipmentData.customId || '',
|
|
52
|
+
// Status
|
|
53
|
+
status: shipmentData.status?.code?.value || 'Unknown',
|
|
54
|
+
lateBy: shipment.status.runningLate?.lateDurationString ?? null,
|
|
55
|
+
isLate: !!shipment.status.runningLate,
|
|
56
|
+
// Current location (if tracking available)
|
|
57
|
+
currentLocation: shipment.status.location ?? null,
|
|
58
|
+
hasGpsTracking: locationUpdates !== null && !internalApiFailed,
|
|
59
|
+
// Progress
|
|
60
|
+
completedStops: 0, // TODO: Count from shipmentData.globalRoute
|
|
61
|
+
totalStops: shipmentData.globalRoute?.length || 0, // TODO: parse from shipmentData.globalRoute
|
|
62
|
+
// Stops (ordered)
|
|
63
|
+
stops: [], // TODO: implment global route parsing
|
|
64
|
+
// ETA & Distance
|
|
65
|
+
etaUtc: shipment.status.attributes?.etaValUtc ?? null,
|
|
66
|
+
etaTimezone: shipment.status.attributes?.next_eta_cal_val_timezone ?? null,
|
|
67
|
+
milesRemaining: shipment.status.location?.nextMiles ?? null,
|
|
68
|
+
totalMiles: null, // TODO: Derive from global route -- find current stop, and figure out total distance leading to it
|
|
69
|
+
// GPS Pings (only populated if includeGps: true and hasGpsTracking)
|
|
70
|
+
locationUpdates: locationUpdates || null, // TODO: implment with scraper
|
|
71
|
+
pingCount: locationUpdates?.length || null, // TODO: implement with scraper
|
|
72
|
+
lastPingAt: locationUpdates?.[(locationUpdates?.length || 0) - 1]?.timestamp ||
|
|
73
|
+
null, // TODO: implement with scraper
|
|
74
|
+
// Shipment Attributes
|
|
75
|
+
laneType: shipment.flexAttributes?.find(attribute => attribute.name === 'Lane Type')?.value ?? null,
|
|
76
|
+
managementType: shipment.flexAttributes?.find(attribute => attribute.name === 'Management Type')?.value ?? null,
|
|
77
|
+
carrier: shipmentData.carrierOrder?.[0]?.carrier?.name || null,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhY2tpbmdTZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3NoaXBtZW50VHJhY2tpbmcvdHJhY2tpbmdTZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBR3BEOzs7R0FHRztBQUNILE1BQU0sT0FBTyxlQUFlO0lBRWhCO0lBQ0E7SUFGVixZQUNVLFNBQXlCLEVBQ3pCLFdBQTZCO1FBRDdCLGNBQVMsR0FBVCxTQUFTLENBQWdCO1FBQ3pCLGdCQUFXLEdBQVgsV0FBVyxDQUFrQjtJQUNwQyxDQUFDO0lBRUo7Ozs7OztPQU1HO0lBQ0gsS0FBSyxDQUFDLFdBQVcsQ0FBQyxVQUFrQixFQUFFLFVBQThCLEVBQUU7UUFDcEUsc0NBQXNDO1FBQ3RDLE1BQU0sY0FBYyxHQUFHLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyxXQUFXLENBQUMsRUFBRSxVQUFVLEVBQUUsUUFBUSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQTtRQUU3RixJQUFJLENBQUMsY0FBYyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQzVCLE1BQU0sSUFBSSxrQkFBa0IsQ0FBQyxVQUFVLENBQUMsQ0FBQTtRQUMxQyxDQUFDO1FBRUQsTUFBTSxRQUFRLEdBQUcsY0FBYyxDQUFDLE9BQU8sQ0FBQTtRQUV2QyxrREFBa0Q7UUFDbEQsSUFBSSxlQUFlLEdBQTRCLElBQUksQ0FBQTtRQUNuRCxJQUFJLGlCQUFpQixHQUFHLEtBQUssQ0FBQTtRQUU3QixJQUFJLE9BQU8sQ0FBQyxVQUFVLEtBQUssS0FBSyxFQUFFLENBQUM7WUFDakMsSUFBSSxDQUFDO2dCQUNILGVBQWUsR0FBRyxNQUFNLElBQUksQ0FBQyxXQUFXLENBQUMsa0JBQWtCLENBQUMsVUFBVSxDQUFDLENBQUE7WUFDekUsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YsZ0RBQWdEO2dCQUNoRCxpQkFBaUIsR0FBRyxJQUFJLENBQUE7WUFDMUIsQ0FBQztRQUNILENBQUM7UUFFRCxpQ0FBaUM7UUFDakMsT0FBTyxJQUFJLENBQUMsMEJBQTBCLENBQUMsUUFBUSxFQUFFLGVBQWUsRUFBRSxpQkFBaUIsQ0FBQyxDQUFBO0lBQ3RGLENBQUM7SUFFRDs7O09BR0c7SUFDSywwQkFBMEIsQ0FDaEMsUUFBdUIsRUFDdkIsZUFBd0MsRUFDeEMsaUJBQTBCO1FBRTFCLE1BQU0sWUFBWSxHQUFHLFFBQXlCLENBQUE7UUFDOUMsT0FBTztZQUNMLGNBQWM7WUFDZCxVQUFVLEVBQUcsWUFBWSxDQUFDLEVBQWEsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO1lBQ3pELG1CQUFtQixFQUFHLFlBQVksQ0FBQyxRQUFtQixJQUFJLEVBQUU7WUFFNUQsU0FBUztZQUNULE1BQU0sRUFBRyxZQUFZLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxLQUFnQixJQUFJLFNBQVM7WUFDakUsTUFBTSxFQUFFLFFBQVEsQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLGtCQUFrQixJQUFJLElBQUk7WUFDL0QsTUFBTSxFQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLFdBQVc7WUFFckMsMkNBQTJDO1lBQzNDLGVBQWUsRUFBRSxRQUFRLENBQUMsTUFBTSxDQUFDLFFBQVEsSUFBSSxJQUFJO1lBQ2pELGNBQWMsRUFBRSxlQUFlLEtBQUssSUFBSSxJQUFJLENBQUMsaUJBQWlCO1lBRTlELFdBQVc7WUFDWCxjQUFjLEVBQUUsQ0FBQyxFQUFFLDRDQUE0QztZQUMvRCxVQUFVLEVBQUcsWUFBWSxDQUFDLFdBQXlCLEVBQUUsTUFBTSxJQUFJLENBQUMsRUFBRSw0Q0FBNEM7WUFFOUcsa0JBQWtCO1lBQ2xCLEtBQUssRUFBRSxFQUFFLEVBQUUsc0NBQXNDO1lBRWpELGlCQUFpQjtZQUNqQixNQUFNLEVBQUUsUUFBUSxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUUsU0FBUyxJQUFJLElBQUk7WUFDckQsV0FBVyxFQUFFLFFBQVEsQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLHlCQUF5QixJQUFJLElBQUk7WUFDMUUsY0FBYyxFQUFFLFFBQVEsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLFNBQVMsSUFBSSxJQUFJO1lBQzNELFVBQVUsRUFBRSxJQUFJLEVBQUUsbUdBQW1HO1lBRXJILG9FQUFvRTtZQUNwRSxlQUFlLEVBQUcsZUFBb0MsSUFBSSxJQUFJLEVBQUUsOEJBQThCO1lBQzlGLFNBQVMsRUFBRyxlQUFvQyxFQUFFLE1BQU0sSUFBSSxJQUFJLEVBQUUsK0JBQStCO1lBQ2pHLFVBQVUsRUFDUCxlQUFvQyxFQUFFLENBQUMsQ0FBRSxlQUFvQyxFQUFFLE1BQU0sSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxTQUFTO2dCQUM1RyxJQUFJLEVBQUUsK0JBQStCO1lBRXZDLHNCQUFzQjtZQUN0QixRQUFRLEVBQUUsUUFBUSxDQUFDLGNBQWMsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxLQUFLLFdBQVcsQ0FBQyxFQUFFLEtBQUssSUFBSSxJQUFJO1lBQ25HLGNBQWMsRUFBRSxRQUFRLENBQUMsY0FBYyxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxJQUFJLEtBQUssaUJBQWlCLENBQUMsRUFBRSxLQUFLLElBQUksSUFBSTtZQUMvRyxPQUFPLEVBRUQsWUFBWSxDQUFDLFlBQTBCLEVBQUUsQ0FBQyxDQUFDLENBQTZCLEVBQUUsT0FDN0UsRUFBRSxJQUFlLElBQUksSUFBSTtTQUM3QixDQUFBO0lBQ0gsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgVHVydm9JbnRlcm5hbEFwaSB9IGZyb20gJy4uL2FwaS90dXJ2b0ludGVybmFsQXBpJ1xuaW1wb3J0IHsgVHVydm9QdWJsaWNBcGkgfSBmcm9tICcuLi9hcGkvdHVydm9QdWJsaWNBcGknXG5pbXBvcnQgeyBUdXJ2b1NoaXBtZW50IH0gZnJvbSAnLi4vdHlwZXMnXG5pbXBvcnQgeyBUdXJ2b05vdEZvdW5kRXJyb3IgfSBmcm9tICcuLi90eXBlcy9lcnJvcnMnXG5pbXBvcnQgeyBHZXRUcmFja2luZ09wdGlvbnMsIExvY2F0aW9uVXBkYXRlLCBTaGlwbWVudFRyYWNraW5nIH0gZnJvbSAnLi4vdHlwZXMvdHJhY2tpbmcnXG5cbi8qKlxuICogVHJhY2tpbmdTZXJ2aWNlIG9yY2hlc3RyYXRlcyBjYWxscyB0byBwdWJsaWMgYW5kIGludGVybmFsIEFQSXNcbiAqIHRvIHByb3ZpZGUgYSB1bmlmaWVkIHNoaXBtZW50IHRyYWNraW5nIGludGVyZmFjZS5cbiAqL1xuZXhwb3J0IGNsYXNzIFRyYWNraW5nU2VydmljZSB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcHVibGljQXBpOiBUdXJ2b1B1YmxpY0FwaSxcbiAgICBwcml2YXRlIGludGVybmFsQXBpOiBUdXJ2b0ludGVybmFsQXBpXG4gICkge31cblxuICAvKipcbiAgICogTWFpbiBlbnRyeSBwb2ludCAtIGNvbWJpbmVzIGFsbCBBUEkgZGF0YSB0byBwcm9kdWNlIFNoaXBtZW50VHJhY2tpbmdcbiAgICpcbiAgICogQHBhcmFtIHNoaXBtZW50SWQgLSBUaGUgc2hpcG1lbnQgSUQgdG8gdHJhY2tcbiAgICogQHBhcmFtIG9wdGlvbnMgLSBUcmFja2luZyBvcHRpb25zXG4gICAqIEByZXR1cm5zIENvbXBsZXRlIHNoaXBtZW50IHRyYWNraW5nIGluZm9ybWF0aW9uXG4gICAqL1xuICBhc3luYyBnZXRUcmFja2luZyhzaGlwbWVudElkOiBzdHJpbmcsIG9wdGlvbnM6IEdldFRyYWNraW5nT3B0aW9ucyA9IHt9KTogUHJvbWlzZTxTaGlwbWVudFRyYWNraW5nPiB7XG4gICAgLy8gMS4gRmV0Y2ggcHVibGljIEFQSSBkYXRhIChyZXF1aXJlZClcbiAgICBjb25zdCBzaGlwbWVudFJlc3VsdCA9IGF3YWl0IHRoaXMucHVibGljQXBpLmdldFNoaXBtZW50KHsgc2hpcG1lbnRJZDogcGFyc2VJbnQoc2hpcG1lbnRJZCkgfSlcblxuICAgIGlmICghc2hpcG1lbnRSZXN1bHQuZGV0YWlscykge1xuICAgICAgdGhyb3cgbmV3IFR1cnZvTm90Rm91bmRFcnJvcihzaGlwbWVudElkKVxuICAgIH1cblxuICAgIGNvbnN0IHNoaXBtZW50ID0gc2hpcG1lbnRSZXN1bHQuZGV0YWlsc1xuXG4gICAgLy8gMi4gRmV0Y2ggaW50ZXJuYWwgQVBJIGRhdGEgKG9wdGlvbmFsLCBtYXkgZmFpbClcbiAgICBsZXQgbG9jYXRpb25VcGRhdGVzOiBMb2NhdGlvblVwZGF0ZVtdIHwgbnVsbCA9IG51bGxcbiAgICBsZXQgaW50ZXJuYWxBcGlGYWlsZWQgPSBmYWxzZVxuXG4gICAgaWYgKG9wdGlvbnMuaW5jbHVkZUdwcyAhPT0gZmFsc2UpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGxvY2F0aW9uVXBkYXRlcyA9IGF3YWl0IHRoaXMuaW50ZXJuYWxBcGkuZ2V0TG9jYXRpb25VcGRhdGVzKHNoaXBtZW50SWQpXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAvLyBMb2cgYnV0IGRvbid0IGZhaWwgLSBpbnRlcm5hbCBBUEkgaXMgb3B0aW9uYWxcbiAgICAgICAgaW50ZXJuYWxBcGlGYWlsZWQgPSB0cnVlXG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gMy4gVHJhbnNmb3JtIHRvIGNsZWFuIHJlc3BvbnNlXG4gICAgcmV0dXJuIHRoaXMudHJhbnNmb3JtVG9UcmFja2luZ0RldGFpbHMoc2hpcG1lbnQsIGxvY2F0aW9uVXBkYXRlcywgaW50ZXJuYWxBcGlGYWlsZWQpXG4gIH1cblxuICAvKipcbiAgICogVHJhbnNmb3JtIHJhdyBUdXJ2byBBUEkgcmVzcG9uc2VzIGludG8gY2xlYW4gU2hpcG1lbnRUcmFja2luZyB0eXBlXG4gICAqXG4gICAqL1xuICBwcml2YXRlIHRyYW5zZm9ybVRvVHJhY2tpbmdEZXRhaWxzKFxuICAgIHNoaXBtZW50OiBUdXJ2b1NoaXBtZW50LFxuICAgIGxvY2F0aW9uVXBkYXRlczogTG9jYXRpb25VcGRhdGVbXSB8IG51bGwsXG4gICAgaW50ZXJuYWxBcGlGYWlsZWQ6IGJvb2xlYW5cbiAgKTogU2hpcG1lbnRUcmFja2luZyB7XG4gICAgY29uc3Qgc2hpcG1lbnREYXRhID0gc2hpcG1lbnQgYXMgVHVydm9TaGlwbWVudFxuICAgIHJldHVybiB7XG4gICAgICAvLyBJZGVudGlmaWVyc1xuICAgICAgc2hpcG1lbnRJZDogKHNoaXBtZW50RGF0YS5pZCBhcyBudW1iZXIpPy50b1N0cmluZygpIHx8ICcnLFxuICAgICAgbG9hZFJlZmVyZW5jZU51bWJlcjogKHNoaXBtZW50RGF0YS5jdXN0b21JZCBhcyBzdHJpbmcpIHx8ICcnLFxuXG4gICAgICAvLyBTdGF0dXNcbiAgICAgIHN0YXR1czogKHNoaXBtZW50RGF0YS5zdGF0dXM/LmNvZGU/LnZhbHVlIGFzIHN0cmluZykgfHwgJ1Vua25vd24nLFxuICAgICAgbGF0ZUJ5OiBzaGlwbWVudC5zdGF0dXMucnVubmluZ0xhdGU/LmxhdGVEdXJhdGlvblN0cmluZyA/PyBudWxsLFxuICAgICAgaXNMYXRlOiAhIXNoaXBtZW50LnN0YXR1cy5ydW5uaW5nTGF0ZSxcblxuICAgICAgLy8gQ3VycmVudCBsb2NhdGlvbiAoaWYgdHJhY2tpbmcgYXZhaWxhYmxlKVxuICAgICAgY3VycmVudExvY2F0aW9uOiBzaGlwbWVudC5zdGF0dXMubG9jYXRpb24gPz8gbnVsbCxcbiAgICAgIGhhc0dwc1RyYWNraW5nOiBsb2NhdGlvblVwZGF0ZXMgIT09IG51bGwgJiYgIWludGVybmFsQXBpRmFpbGVkLFxuXG4gICAgICAvLyBQcm9ncmVzc1xuICAgICAgY29tcGxldGVkU3RvcHM6IDAsIC8vIFRPRE86IENvdW50IGZyb20gc2hpcG1lbnREYXRhLmdsb2JhbFJvdXRlXG4gICAgICB0b3RhbFN0b3BzOiAoc2hpcG1lbnREYXRhLmdsb2JhbFJvdXRlIGFzIHVua25vd25bXSk/Lmxlbmd0aCB8fCAwLCAvLyBUT0RPOiBwYXJzZSBmcm9tIHNoaXBtZW50RGF0YS5nbG9iYWxSb3V0ZVxuXG4gICAgICAvLyBTdG9wcyAob3JkZXJlZClcbiAgICAgIHN0b3BzOiBbXSwgLy8gVE9ETzogaW1wbG1lbnQgZ2xvYmFsIHJvdXRlIHBhcnNpbmdcblxuICAgICAgLy8gRVRBICYgRGlzdGFuY2VcbiAgICAgIGV0YVV0Yzogc2hpcG1lbnQuc3RhdHVzLmF0dHJpYnV0ZXM/LmV0YVZhbFV0YyA/PyBudWxsLFxuICAgICAgZXRhVGltZXpvbmU6IHNoaXBtZW50LnN0YXR1cy5hdHRyaWJ1dGVzPy5uZXh0X2V0YV9jYWxfdmFsX3RpbWV6b25lID8/IG51bGwsXG4gICAgICBtaWxlc1JlbWFpbmluZzogc2hpcG1lbnQuc3RhdHVzLmxvY2F0aW9uPy5uZXh0TWlsZXMgPz8gbnVsbCxcbiAgICAgIHRvdGFsTWlsZXM6IG51bGwsIC8vIFRPRE86IERlcml2ZSBmcm9tIGdsb2JhbCByb3V0ZSAtLSBmaW5kIGN1cnJlbnQgc3RvcCwgYW5kIGZpZ3VyZSBvdXQgdG90YWwgZGlzdGFuY2UgbGVhZGluZyB0byBpdFxuXG4gICAgICAvLyBHUFMgUGluZ3MgKG9ubHkgcG9wdWxhdGVkIGlmIGluY2x1ZGVHcHM6IHRydWUgYW5kIGhhc0dwc1RyYWNraW5nKVxuICAgICAgbG9jYXRpb25VcGRhdGVzOiAobG9jYXRpb25VcGRhdGVzIGFzIExvY2F0aW9uVXBkYXRlW10pIHx8IG51bGwsIC8vIFRPRE86IGltcGxtZW50IHdpdGggc2NyYXBlclxuICAgICAgcGluZ0NvdW50OiAobG9jYXRpb25VcGRhdGVzIGFzIExvY2F0aW9uVXBkYXRlW10pPy5sZW5ndGggfHwgbnVsbCwgLy8gVE9ETzogaW1wbGVtZW50IHdpdGggc2NyYXBlclxuICAgICAgbGFzdFBpbmdBdDpcbiAgICAgICAgKGxvY2F0aW9uVXBkYXRlcyBhcyBMb2NhdGlvblVwZGF0ZVtdKT8uWygobG9jYXRpb25VcGRhdGVzIGFzIExvY2F0aW9uVXBkYXRlW10pPy5sZW5ndGggfHwgMCkgLSAxXT8udGltZXN0YW1wIHx8XG4gICAgICAgIG51bGwsIC8vIFRPRE86IGltcGxlbWVudCB3aXRoIHNjcmFwZXJcblxuICAgICAgLy8gU2hpcG1lbnQgQXR0cmlidXRlc1xuICAgICAgbGFuZVR5cGU6IHNoaXBtZW50LmZsZXhBdHRyaWJ1dGVzPy5maW5kKGF0dHJpYnV0ZSA9PiBhdHRyaWJ1dGUubmFtZSA9PT0gJ0xhbmUgVHlwZScpPy52YWx1ZSA/PyBudWxsLFxuICAgICAgbWFuYWdlbWVudFR5cGU6IHNoaXBtZW50LmZsZXhBdHRyaWJ1dGVzPy5maW5kKGF0dHJpYnV0ZSA9PiBhdHRyaWJ1dGUubmFtZSA9PT0gJ01hbmFnZW1lbnQgVHlwZScpPy52YWx1ZSA/PyBudWxsLFxuICAgICAgY2FycmllcjpcbiAgICAgICAgKChcbiAgICAgICAgICAoKHNoaXBtZW50RGF0YS5jYXJyaWVyT3JkZXIgYXMgdW5rbm93bltdKT8uWzBdIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KT8uY2FycmllciBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPlxuICAgICAgICApPy5uYW1lIGFzIHN0cmluZykgfHwgbnVsbCxcbiAgICB9XG4gIH1cbn1cbiJdfQ==
|