@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.
Files changed (57) hide show
  1. package/README.md +473 -0
  2. package/index.ts +1 -0
  3. package/lib/cjs/api/turvoInternalApi.d.ts +23 -0
  4. package/lib/cjs/api/turvoInternalApi.js +36 -0
  5. package/lib/cjs/api/turvoPublicApi.d.ts +99 -0
  6. package/lib/cjs/api/turvoPublicApi.js +103 -0
  7. package/lib/cjs/client/turvoClient.d.ts +49 -0
  8. package/lib/cjs/client/turvoClient.js +180 -0
  9. package/lib/cjs/constants.d.ts +29 -0
  10. package/lib/cjs/constants.js +33 -0
  11. package/lib/cjs/index.d.ts +6 -0
  12. package/lib/cjs/index.js +37 -0
  13. package/lib/cjs/shipmentTracking/index.d.ts +22 -0
  14. package/lib/cjs/shipmentTracking/index.js +39 -0
  15. package/lib/cjs/shipmentTracking/trackingService.d.ts +25 -0
  16. package/lib/cjs/shipmentTracking/trackingService.js +85 -0
  17. package/lib/cjs/types/common.d.ts +64 -0
  18. package/lib/cjs/types/common.js +27 -0
  19. package/lib/cjs/types/config.d.ts +13 -0
  20. package/lib/cjs/types/config.js +3 -0
  21. package/lib/cjs/types/errors.d.ts +35 -0
  22. package/lib/cjs/types/errors.js +63 -0
  23. package/lib/cjs/types/index.d.ts +5 -0
  24. package/lib/cjs/types/index.js +27 -0
  25. package/lib/cjs/types/shipment.d.ts +379 -0
  26. package/lib/cjs/types/shipment.js +46 -0
  27. package/lib/cjs/types/tracking.d.ts +65 -0
  28. package/lib/cjs/types/tracking.js +3 -0
  29. package/lib/esm/api/turvoInternalApi.d.ts +23 -0
  30. package/lib/esm/api/turvoInternalApi.js +32 -0
  31. package/lib/esm/api/turvoPublicApi.d.ts +99 -0
  32. package/lib/esm/api/turvoPublicApi.js +99 -0
  33. package/lib/esm/client/turvoClient.d.ts +49 -0
  34. package/lib/esm/client/turvoClient.js +172 -0
  35. package/lib/esm/constants.d.ts +29 -0
  36. package/lib/esm/constants.js +30 -0
  37. package/lib/esm/index.d.ts +6 -0
  38. package/lib/esm/index.js +11 -0
  39. package/lib/esm/shipmentTracking/index.d.ts +22 -0
  40. package/lib/esm/shipmentTracking/index.js +36 -0
  41. package/lib/esm/shipmentTracking/trackingService.d.ts +25 -0
  42. package/lib/esm/shipmentTracking/trackingService.js +81 -0
  43. package/lib/esm/types/common.d.ts +64 -0
  44. package/lib/esm/types/common.js +23 -0
  45. package/lib/esm/types/config.d.ts +13 -0
  46. package/lib/esm/types/config.js +2 -0
  47. package/lib/esm/types/errors.d.ts +35 -0
  48. package/lib/esm/types/errors.js +55 -0
  49. package/lib/esm/types/index.d.ts +5 -0
  50. package/lib/esm/types/index.js +11 -0
  51. package/lib/esm/types/shipment.d.ts +379 -0
  52. package/lib/esm/types/shipment.js +43 -0
  53. package/lib/esm/types/tracking.d.ts +65 -0
  54. package/lib/esm/types/tracking.js +2 -0
  55. package/lib/tsconfig.cjs.tsbuildinfo +1 -0
  56. package/lib/tsconfig.esm.tsbuildinfo +1 -0
  57. 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';
@@ -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==