@metamask-previews/bridge-status-controller 73.1.0-preview-e12e4a38f → 74.0.0-preview-4f9d41d
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/CHANGELOG.md +9 -1
- package/dist/bridge-status-controller.cjs +167 -21
- package/dist/bridge-status-controller.cjs.map +1 -1
- package/dist/bridge-status-controller.d.cts +6 -1
- package/dist/bridge-status-controller.d.cts.map +1 -1
- package/dist/bridge-status-controller.d.mts +6 -1
- package/dist/bridge-status-controller.d.mts.map +1 -1
- package/dist/bridge-status-controller.mjs +167 -21
- package/dist/bridge-status-controller.mjs.map +1 -1
- package/dist/constants.cjs +1 -0
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts.map +1 -1
- package/dist/constants.d.mts.map +1 -1
- package/dist/constants.mjs +1 -0
- package/dist/constants.mjs.map +1 -1
- package/dist/index.cjs +12 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +3 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3 -0
- package/dist/index.mjs.map +1 -1
- package/dist/quote-status-manager/constants.cjs +181 -0
- package/dist/quote-status-manager/constants.cjs.map +1 -0
- package/dist/quote-status-manager/constants.d.cts +137 -0
- package/dist/quote-status-manager/constants.d.cts.map +1 -0
- package/dist/quote-status-manager/constants.d.mts +137 -0
- package/dist/quote-status-manager/constants.d.mts.map +1 -0
- package/dist/quote-status-manager/constants.mjs +178 -0
- package/dist/quote-status-manager/constants.mjs.map +1 -0
- package/dist/quote-status-manager/errors.cjs +51 -0
- package/dist/quote-status-manager/errors.cjs.map +1 -0
- package/dist/quote-status-manager/errors.d.cts +45 -0
- package/dist/quote-status-manager/errors.d.cts.map +1 -0
- package/dist/quote-status-manager/errors.d.mts +45 -0
- package/dist/quote-status-manager/errors.d.mts.map +1 -0
- package/dist/quote-status-manager/errors.mjs +46 -0
- package/dist/quote-status-manager/errors.mjs.map +1 -0
- package/dist/quote-status-manager/quote-status-api-service.cjs +241 -0
- package/dist/quote-status-manager/quote-status-api-service.cjs.map +1 -0
- package/dist/quote-status-manager/quote-status-api-service.d.cts +93 -0
- package/dist/quote-status-manager/quote-status-api-service.d.cts.map +1 -0
- package/dist/quote-status-manager/quote-status-api-service.d.mts +93 -0
- package/dist/quote-status-manager/quote-status-api-service.d.mts.map +1 -0
- package/dist/quote-status-manager/quote-status-api-service.mjs +237 -0
- package/dist/quote-status-manager/quote-status-api-service.mjs.map +1 -0
- package/dist/quote-status-manager/quote-status-entry-store.cjs +271 -0
- package/dist/quote-status-manager/quote-status-entry-store.cjs.map +1 -0
- package/dist/quote-status-manager/quote-status-entry-store.d.cts +144 -0
- package/dist/quote-status-manager/quote-status-entry-store.d.cts.map +1 -0
- package/dist/quote-status-manager/quote-status-entry-store.d.mts +144 -0
- package/dist/quote-status-manager/quote-status-entry-store.d.mts.map +1 -0
- package/dist/quote-status-manager/quote-status-entry-store.mjs +267 -0
- package/dist/quote-status-manager/quote-status-entry-store.mjs.map +1 -0
- package/dist/quote-status-manager/quote-status-get-with-retry-outcome.cjs +29 -0
- package/dist/quote-status-manager/quote-status-get-with-retry-outcome.cjs.map +1 -0
- package/dist/quote-status-manager/quote-status-get-with-retry-outcome.d.cts +32 -0
- package/dist/quote-status-manager/quote-status-get-with-retry-outcome.d.cts.map +1 -0
- package/dist/quote-status-manager/quote-status-get-with-retry-outcome.d.mts +32 -0
- package/dist/quote-status-manager/quote-status-get-with-retry-outcome.d.mts.map +1 -0
- package/dist/quote-status-manager/quote-status-get-with-retry-outcome.mjs +25 -0
- package/dist/quote-status-manager/quote-status-get-with-retry-outcome.mjs.map +1 -0
- package/dist/quote-status-manager/quote-status-state-fsm.cjs +107 -0
- package/dist/quote-status-manager/quote-status-state-fsm.cjs.map +1 -0
- package/dist/quote-status-manager/quote-status-state-fsm.d.cts +57 -0
- package/dist/quote-status-manager/quote-status-state-fsm.d.cts.map +1 -0
- package/dist/quote-status-manager/quote-status-state-fsm.d.mts +57 -0
- package/dist/quote-status-manager/quote-status-state-fsm.d.mts.map +1 -0
- package/dist/quote-status-manager/quote-status-state-fsm.mjs +103 -0
- package/dist/quote-status-manager/quote-status-state-fsm.mjs.map +1 -0
- package/dist/quote-status-manager/quote-status-update-with-retry-outcome.cjs +27 -0
- package/dist/quote-status-manager/quote-status-update-with-retry-outcome.cjs.map +1 -0
- package/dist/quote-status-manager/quote-status-update-with-retry-outcome.d.cts +30 -0
- package/dist/quote-status-manager/quote-status-update-with-retry-outcome.d.cts.map +1 -0
- package/dist/quote-status-manager/quote-status-update-with-retry-outcome.d.mts +30 -0
- package/dist/quote-status-manager/quote-status-update-with-retry-outcome.d.mts.map +1 -0
- package/dist/quote-status-manager/quote-status-update-with-retry-outcome.mjs +23 -0
- package/dist/quote-status-manager/quote-status-update-with-retry-outcome.mjs.map +1 -0
- package/dist/quote-status-manager/quotes-status-manager.cjs +477 -0
- package/dist/quote-status-manager/quotes-status-manager.cjs.map +1 -0
- package/dist/quote-status-manager/quotes-status-manager.d.cts +124 -0
- package/dist/quote-status-manager/quotes-status-manager.d.cts.map +1 -0
- package/dist/quote-status-manager/quotes-status-manager.d.mts +124 -0
- package/dist/quote-status-manager/quotes-status-manager.d.mts.map +1 -0
- package/dist/quote-status-manager/quotes-status-manager.mjs +473 -0
- package/dist/quote-status-manager/quotes-status-manager.mjs.map +1 -0
- package/dist/quote-status-manager/types.cjs +8 -0
- package/dist/quote-status-manager/types.cjs.map +1 -0
- package/dist/quote-status-manager/types.d.cts +145 -0
- package/dist/quote-status-manager/types.d.cts.map +1 -0
- package/dist/quote-status-manager/types.d.mts +145 -0
- package/dist/quote-status-manager/types.d.mts.map +1 -0
- package/dist/quote-status-manager/types.mjs +6 -0
- package/dist/quote-status-manager/types.mjs.map +1 -0
- package/dist/quote-status-manager/utils.cjs +11 -0
- package/dist/quote-status-manager/utils.cjs.map +1 -0
- package/dist/quote-status-manager/utils.d.cts +7 -0
- package/dist/quote-status-manager/utils.d.cts.map +1 -0
- package/dist/quote-status-manager/utils.d.mts +7 -0
- package/dist/quote-status-manager/utils.d.mts.map +1 -0
- package/dist/quote-status-manager/utils.mjs +7 -0
- package/dist/quote-status-manager/utils.mjs.map +1 -0
- package/dist/quote-status-manager/validators.cjs +44 -0
- package/dist/quote-status-manager/validators.cjs.map +1 -0
- package/dist/quote-status-manager/validators.d.cts +172 -0
- package/dist/quote-status-manager/validators.d.cts.map +1 -0
- package/dist/quote-status-manager/validators.d.mts +172 -0
- package/dist/quote-status-manager/validators.d.mts.map +1 -0
- package/dist/quote-status-manager/validators.mjs +39 -0
- package/dist/quote-status-manager/validators.mjs.map +1 -0
- package/dist/types.cjs +2 -0
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +15 -3
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +15 -3
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs +2 -0
- package/dist/types.mjs.map +1 -1
- package/dist/utils/history.cjs +1 -0
- package/dist/utils/history.cjs.map +1 -1
- package/dist/utils/history.d.cts.map +1 -1
- package/dist/utils/history.d.mts.map +1 -1
- package/dist/utils/history.mjs +1 -0
- package/dist/utils/history.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
3
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
4
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
5
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
6
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
7
|
+
};
|
|
8
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
10
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
|
+
};
|
|
13
|
+
var _QuoteStatusApiService_messenger, _QuoteStatusApiService_clientId, _QuoteStatusApiService_clientProduct, _QuoteStatusApiService_clientVersion, _QuoteStatusApiService_apiBaseUrl, _QuoteStatusApiService_onError;
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.QuoteStatusApiService = void 0;
|
|
16
|
+
const bridge_controller_1 = require("@metamask/bridge-controller");
|
|
17
|
+
const superstruct_1 = require("@metamask/superstruct");
|
|
18
|
+
const types_1 = require("../types.cjs");
|
|
19
|
+
const authentication_1 = require("../utils/authentication.cjs");
|
|
20
|
+
const constants_1 = require("./constants.cjs");
|
|
21
|
+
const errors_1 = require("./errors.cjs");
|
|
22
|
+
const quote_status_get_with_retry_outcome_1 = require("./quote-status-get-with-retry-outcome.cjs");
|
|
23
|
+
const quote_status_update_with_retry_outcome_1 = require("./quote-status-update-with-retry-outcome.cjs");
|
|
24
|
+
const utils_1 = require("./utils.cjs");
|
|
25
|
+
const validators_1 = require("./validators.cjs");
|
|
26
|
+
/**
|
|
27
|
+
* Service responsible for calling bridge quote status update APIs.
|
|
28
|
+
*
|
|
29
|
+
* It performs authentication, sends properly-scoped client headers, and validates
|
|
30
|
+
* error responses so callers can handle known update-status failures.
|
|
31
|
+
*/
|
|
32
|
+
class QuoteStatusApiService {
|
|
33
|
+
/**
|
|
34
|
+
* Creates an API service for quote status update requests.
|
|
35
|
+
*
|
|
36
|
+
* @param options - Service dependencies and request configuration.
|
|
37
|
+
* @param options.messenger - Messenger used to retrieve the authentication token.
|
|
38
|
+
* @param options.clientId - Bridge client identifier used for request headers.
|
|
39
|
+
* @param options.clientProduct - Product name sent in client product headers.
|
|
40
|
+
* @param options.clientVersion - Optional client version sent in headers.
|
|
41
|
+
* @param options.apiBaseUrl - Base URL for the quote status API.
|
|
42
|
+
* @param options.onError - Optional callback for unexpected response-shape errors.
|
|
43
|
+
*/
|
|
44
|
+
constructor({ messenger, clientId, clientProduct, clientVersion, apiBaseUrl, onError, }) {
|
|
45
|
+
_QuoteStatusApiService_messenger.set(this, void 0);
|
|
46
|
+
_QuoteStatusApiService_clientId.set(this, void 0);
|
|
47
|
+
_QuoteStatusApiService_clientProduct.set(this, void 0);
|
|
48
|
+
_QuoteStatusApiService_clientVersion.set(this, void 0);
|
|
49
|
+
_QuoteStatusApiService_apiBaseUrl.set(this, void 0);
|
|
50
|
+
_QuoteStatusApiService_onError.set(this, void 0);
|
|
51
|
+
__classPrivateFieldSet(this, _QuoteStatusApiService_messenger, messenger, "f");
|
|
52
|
+
__classPrivateFieldSet(this, _QuoteStatusApiService_clientId, clientId, "f");
|
|
53
|
+
__classPrivateFieldSet(this, _QuoteStatusApiService_clientProduct, clientProduct, "f");
|
|
54
|
+
__classPrivateFieldSet(this, _QuoteStatusApiService_clientVersion, clientVersion, "f");
|
|
55
|
+
__classPrivateFieldSet(this, _QuoteStatusApiService_apiBaseUrl, apiBaseUrl, "f");
|
|
56
|
+
__classPrivateFieldSet(this, _QuoteStatusApiService_onError, onError, "f");
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Updates a quote status in the bridge quote-status API.
|
|
60
|
+
*
|
|
61
|
+
* The endpoint returns no payload on success (`2xx`) and a structured payload
|
|
62
|
+
* on non-`2xx` responses. This method returns `null` for successful updates and
|
|
63
|
+
* the validated error payload for unsuccessful updates.
|
|
64
|
+
*
|
|
65
|
+
* @param data - Request payload identifying quote and target status transition.
|
|
66
|
+
* @param data.quoteId - Unique quote identifier to update.
|
|
67
|
+
* @param data.srcTxHash - Source transaction hash associated with the quote.
|
|
68
|
+
* @param data.newStatus - Target quote status to persist.
|
|
69
|
+
* @param signal - Optional abort signal for canceling the request.
|
|
70
|
+
* @returns `null` for `2xx` responses, or a validated error response for non-`2xx`.
|
|
71
|
+
* @throws If the non-`2xx` response body does not match the expected schema.
|
|
72
|
+
*/
|
|
73
|
+
async updateQuoteStatus(data, signal) {
|
|
74
|
+
const jwt = await (0, authentication_1.getJwt)(__classPrivateFieldGet(this, _QuoteStatusApiService_messenger, "f"));
|
|
75
|
+
// This method uses `globalThis.fetch` and reads the raw
|
|
76
|
+
// `Response` (including JSON on non-2xx). Wrappers like `handleFetch` that
|
|
77
|
+
// throw on non-2xx would prevent typed error handling in callers.
|
|
78
|
+
const res = await globalThis.fetch(`${__classPrivateFieldGet(this, _QuoteStatusApiService_apiBaseUrl, "f")}/quote/updateStatus`, {
|
|
79
|
+
method: 'POST',
|
|
80
|
+
headers: {
|
|
81
|
+
'Content-Type': 'application/json',
|
|
82
|
+
'x-metamask-clientproduct': __classPrivateFieldGet(this, _QuoteStatusApiService_clientProduct, "f"),
|
|
83
|
+
...(__classPrivateFieldGet(this, _QuoteStatusApiService_clientVersion, "f")
|
|
84
|
+
? { 'x-metamask-clientversion': __classPrivateFieldGet(this, _QuoteStatusApiService_clientVersion, "f") }
|
|
85
|
+
: {}),
|
|
86
|
+
...(0, bridge_controller_1.getClientHeaders)({
|
|
87
|
+
clientId: __classPrivateFieldGet(this, _QuoteStatusApiService_clientId, "f"),
|
|
88
|
+
jwt,
|
|
89
|
+
}),
|
|
90
|
+
},
|
|
91
|
+
body: JSON.stringify(data),
|
|
92
|
+
signal,
|
|
93
|
+
});
|
|
94
|
+
if (res.ok) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
const responseData = await res.json();
|
|
98
|
+
try {
|
|
99
|
+
(0, validators_1.validateQuoteStatusUpdateResponse)(responseData);
|
|
100
|
+
return responseData;
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
__classPrivateFieldGet(this, _QuoteStatusApiService_onError, "f")?.call(this, new errors_1.QuoteStatusUpdateError('unexpected response shape from quote/updateStatus', { quoteId: data.quoteId }));
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async getQuoteStatus(data, signal) {
|
|
108
|
+
const jwt = await (0, authentication_1.getJwt)(__classPrivateFieldGet(this, _QuoteStatusApiService_messenger, "f"));
|
|
109
|
+
// This method uses `globalThis.fetch` and reads the raw
|
|
110
|
+
// `Response` (including JSON on non-2xx). Wrappers like `handleFetch` that
|
|
111
|
+
// throw on non-2xx would prevent typed error handling in callers.
|
|
112
|
+
const res = await globalThis.fetch(`${__classPrivateFieldGet(this, _QuoteStatusApiService_apiBaseUrl, "f")}/getQuoteStatus?quoteId=${data.quoteId}`, {
|
|
113
|
+
method: 'GET',
|
|
114
|
+
headers: {
|
|
115
|
+
'Content-Type': 'application/json',
|
|
116
|
+
'x-metamask-clientproduct': __classPrivateFieldGet(this, _QuoteStatusApiService_clientProduct, "f"),
|
|
117
|
+
...(__classPrivateFieldGet(this, _QuoteStatusApiService_clientVersion, "f")
|
|
118
|
+
? { 'x-metamask-clientversion': __classPrivateFieldGet(this, _QuoteStatusApiService_clientVersion, "f") }
|
|
119
|
+
: {}),
|
|
120
|
+
...(0, bridge_controller_1.getClientHeaders)({
|
|
121
|
+
clientId: __classPrivateFieldGet(this, _QuoteStatusApiService_clientId, "f"),
|
|
122
|
+
jwt,
|
|
123
|
+
}),
|
|
124
|
+
},
|
|
125
|
+
signal,
|
|
126
|
+
});
|
|
127
|
+
if (!res.ok) {
|
|
128
|
+
// 5xx errors are transient (server-side); 4xx errors are client-side and
|
|
129
|
+
// non-retryable. The `retryable` flag lets `getQuoteStatusWithRetry`
|
|
130
|
+
// distinguish the two and only exit early for permanent failures.
|
|
131
|
+
const retryable = res.status >= 500;
|
|
132
|
+
const error = new errors_1.QuoteStatusGetError(`request error to getQuoteStatus [${res.status}: ${res.statusText}]`, { quoteId: data.quoteId }, retryable);
|
|
133
|
+
__classPrivateFieldGet(this, _QuoteStatusApiService_onError, "f")?.call(this, error);
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
const responseData = await res.json();
|
|
137
|
+
try {
|
|
138
|
+
(0, validators_1.validateQuoteStatusGetResponse)(responseData);
|
|
139
|
+
return responseData;
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
if (error instanceof superstruct_1.StructError) {
|
|
143
|
+
const validationFailures = [];
|
|
144
|
+
for (const { path } of error.failures()) {
|
|
145
|
+
const aggregatorId = responseData?.submittedTx?.bridge ??
|
|
146
|
+
'unknown';
|
|
147
|
+
const pathString = path?.join('.') || 'unknown';
|
|
148
|
+
validationFailures.push([aggregatorId, pathString].join('|'));
|
|
149
|
+
}
|
|
150
|
+
const validationError = new errors_1.QuoteStatusGetError('unexpected response shape from getQuoteStatus', { quoteId: data.quoteId, validationFailures });
|
|
151
|
+
__classPrivateFieldGet(this, _QuoteStatusApiService_onError, "f")?.call(this, validationError);
|
|
152
|
+
throw validationError;
|
|
153
|
+
}
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Updates a quote status, retrying on transient backend failures.
|
|
159
|
+
*
|
|
160
|
+
* Wraps {@link updateQuoteStatus} in a bounded retry loop. A request is only
|
|
161
|
+
* retried when the backend returns an error whose type is in
|
|
162
|
+
* {@link QuoteStatusUpdateRetryableBackendTypes}; any other error response
|
|
163
|
+
* resolves immediately as non-retryable. Retries are spaced by
|
|
164
|
+
* `options.delayMsBetweenRetries`, and both the abort signal and the optional
|
|
165
|
+
* `options.retry` predicate are checked before each attempt so an
|
|
166
|
+
* in-flight or pending retry can be cancelled (e.g. when the entry's status
|
|
167
|
+
* changed while sleeping between retries).
|
|
168
|
+
*
|
|
169
|
+
* @param data - Request payload identifying the quote and target transition.
|
|
170
|
+
* @param data.quoteId - Unique quote identifier to update.
|
|
171
|
+
* @param data.srcTxHash - Source transaction hash associated with the quote.
|
|
172
|
+
* @param data.newStatus - Target quote status to persist.
|
|
173
|
+
* @param options - Retry configuration.
|
|
174
|
+
* @param options.maxRetries - Maximum number of retries after the initial attempt.
|
|
175
|
+
* @param options.delayMsBetweenRetries - Delay in milliseconds between attempts.
|
|
176
|
+
* @param options.retry - Optional predicate checked before each attempt;
|
|
177
|
+
* when it returns `false` the loop stops early and resolves as `Interrupted`.
|
|
178
|
+
* @param signal - Optional abort signal for canceling the request and its retries.
|
|
179
|
+
* @returns An outcome describing how the update resolved:
|
|
180
|
+
* `Accepted` when the backend accepted the update, `NonRetryable` for a
|
|
181
|
+
* non-retryable error response, `Interrupted` when aborted, or
|
|
182
|
+
* `RetryableExhausted` when all retries were used up on retryable errors.
|
|
183
|
+
* @throws If a request rejects for a reason other than the abort signal (e.g.
|
|
184
|
+
* an unexpected response shape from {@link updateQuoteStatus}).
|
|
185
|
+
*/
|
|
186
|
+
async updateQuoteStatusWithRetry(data, options, signal) {
|
|
187
|
+
for (let attempt = 0; attempt <= options.maxRetries; attempt += 1) {
|
|
188
|
+
if (attempt > 0) {
|
|
189
|
+
await (0, utils_1.sleep)(options.delayMsBetweenRetries);
|
|
190
|
+
}
|
|
191
|
+
if (signal?.aborted || options.retry?.() === false) {
|
|
192
|
+
return new quote_status_update_with_retry_outcome_1.QuoteStatusUpdateWithRetryOutcome(constants_1.QuoteStatusFetchWithRetryOutcomeType.Interrupted);
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
const response = await this.updateQuoteStatus(data, signal);
|
|
196
|
+
if (response === null) {
|
|
197
|
+
return new quote_status_update_with_retry_outcome_1.QuoteStatusUpdateWithRetryOutcome(constants_1.QuoteStatusFetchWithRetryOutcomeType.Accepted);
|
|
198
|
+
}
|
|
199
|
+
if (!constants_1.QuoteStatusUpdateRetryableBackendTypes.includes(response.type)) {
|
|
200
|
+
return new quote_status_update_with_retry_outcome_1.QuoteStatusUpdateWithRetryOutcome(constants_1.QuoteStatusFetchWithRetryOutcomeType.NonRetryable, response);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
if (signal?.aborted) {
|
|
205
|
+
return new quote_status_update_with_retry_outcome_1.QuoteStatusUpdateWithRetryOutcome(constants_1.QuoteStatusFetchWithRetryOutcomeType.Interrupted);
|
|
206
|
+
}
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return new quote_status_update_with_retry_outcome_1.QuoteStatusUpdateWithRetryOutcome(constants_1.QuoteStatusFetchWithRetryOutcomeType.RetryableExhausted);
|
|
211
|
+
}
|
|
212
|
+
async getQuoteStatusWithRetry(data, options, signal) {
|
|
213
|
+
for (let attempt = 0; attempt <= options.maxRetries; attempt += 1) {
|
|
214
|
+
if (attempt > 0) {
|
|
215
|
+
await (0, utils_1.sleep)(options.delayMsBetweenRetries);
|
|
216
|
+
}
|
|
217
|
+
if (signal?.aborted) {
|
|
218
|
+
return new quote_status_get_with_retry_outcome_1.QuoteStatusGetWithRetryOutcome(constants_1.QuoteStatusFetchWithRetryOutcomeType.Interrupted);
|
|
219
|
+
}
|
|
220
|
+
try {
|
|
221
|
+
const response = await this.getQuoteStatus(data, signal);
|
|
222
|
+
return new quote_status_get_with_retry_outcome_1.QuoteStatusGetWithRetryOutcome(constants_1.QuoteStatusFetchWithRetryOutcomeType.Accepted, response);
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
if (signal?.aborted) {
|
|
226
|
+
return new quote_status_get_with_retry_outcome_1.QuoteStatusGetWithRetryOutcome(constants_1.QuoteStatusFetchWithRetryOutcomeType.Interrupted);
|
|
227
|
+
}
|
|
228
|
+
// Only short-circuit for non-retryable errors (e.g. 4xx, validation
|
|
229
|
+
// failures). Retryable errors (e.g. 5xx) fall through so the loop can
|
|
230
|
+
// attempt the next retry instead of returning NonRetryable immediately.
|
|
231
|
+
if (error instanceof errors_1.QuoteStatusGetError && !error.retryable) {
|
|
232
|
+
return new quote_status_get_with_retry_outcome_1.QuoteStatusGetWithRetryOutcome(constants_1.QuoteStatusFetchWithRetryOutcomeType.NonRetryable, undefined, error);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return new quote_status_get_with_retry_outcome_1.QuoteStatusGetWithRetryOutcome(constants_1.QuoteStatusFetchWithRetryOutcomeType.RetryableExhausted);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
exports.QuoteStatusApiService = QuoteStatusApiService;
|
|
240
|
+
_QuoteStatusApiService_messenger = new WeakMap(), _QuoteStatusApiService_clientId = new WeakMap(), _QuoteStatusApiService_clientProduct = new WeakMap(), _QuoteStatusApiService_clientVersion = new WeakMap(), _QuoteStatusApiService_apiBaseUrl = new WeakMap(), _QuoteStatusApiService_onError = new WeakMap();
|
|
241
|
+
//# sourceMappingURL=quote-status-api-service.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quote-status-api-service.cjs","sourceRoot":"","sources":["../../src/quote-status-manager/quote-status-api-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { getClientHeaders } from '@metamask/bridge-controller';\nimport { StructError } from '@metamask/superstruct';\n\nimport { BridgeClientId, BridgeStatusControllerMessenger } from '../types';\nimport { getJwt } from '../utils/authentication';\nimport {\n QuoteStatusBackendStatus,\n QuoteStatusUpdateRetryableBackendTypes,\n QuoteStatusFetchWithRetryOutcomeType,\n} from './constants';\nimport { QuoteStatusGetError, QuoteStatusUpdateError } from './errors';\nimport { QuoteStatusGetWithRetryOutcome } from './quote-status-get-with-retry-outcome';\nimport { QuoteStatusUpdateWithRetryOutcome } from './quote-status-update-with-retry-outcome';\nimport {\n QuoteStatusApiServiceOptions,\n QuoteStatusGetResponse,\n QuoteStatusUpdateResponse,\n} from './types';\nimport { sleep } from './utils';\nimport {\n validateQuoteStatusGetResponse,\n validateQuoteStatusUpdateResponse,\n} from './validators';\n\n/**\n * Service responsible for calling bridge quote status update APIs.\n *\n * It performs authentication, sends properly-scoped client headers, and validates\n * error responses so callers can handle known update-status failures.\n */\nexport class QuoteStatusApiService {\n readonly #messenger: BridgeStatusControllerMessenger;\n\n readonly #clientId: BridgeClientId;\n\n readonly #clientProduct: string;\n\n readonly #clientVersion: string | undefined;\n\n readonly #apiBaseUrl: string;\n\n readonly #onError: ((error: QuoteStatusUpdateError) => void) | undefined;\n\n /**\n * Creates an API service for quote status update requests.\n *\n * @param options - Service dependencies and request configuration.\n * @param options.messenger - Messenger used to retrieve the authentication token.\n * @param options.clientId - Bridge client identifier used for request headers.\n * @param options.clientProduct - Product name sent in client product headers.\n * @param options.clientVersion - Optional client version sent in headers.\n * @param options.apiBaseUrl - Base URL for the quote status API.\n * @param options.onError - Optional callback for unexpected response-shape errors.\n */\n constructor({\n messenger,\n clientId,\n clientProduct,\n clientVersion,\n apiBaseUrl,\n onError,\n }: QuoteStatusApiServiceOptions) {\n this.#messenger = messenger;\n this.#clientId = clientId;\n this.#clientProduct = clientProduct;\n this.#clientVersion = clientVersion;\n this.#apiBaseUrl = apiBaseUrl;\n this.#onError = onError;\n }\n\n /**\n * Updates a quote status in the bridge quote-status API.\n *\n * The endpoint returns no payload on success (`2xx`) and a structured payload\n * on non-`2xx` responses. This method returns `null` for successful updates and\n * the validated error payload for unsuccessful updates.\n *\n * @param data - Request payload identifying quote and target status transition.\n * @param data.quoteId - Unique quote identifier to update.\n * @param data.srcTxHash - Source transaction hash associated with the quote.\n * @param data.newStatus - Target quote status to persist.\n * @param signal - Optional abort signal for canceling the request.\n * @returns `null` for `2xx` responses, or a validated error response for non-`2xx`.\n * @throws If the non-`2xx` response body does not match the expected schema.\n */\n async updateQuoteStatus(\n data: {\n quoteId: string;\n srcTxHash: string;\n newStatus: QuoteStatusBackendStatus;\n },\n signal?: AbortSignal,\n ): Promise<QuoteStatusUpdateResponse | null> {\n const jwt = await getJwt(this.#messenger);\n\n // This method uses `globalThis.fetch` and reads the raw\n // `Response` (including JSON on non-2xx). Wrappers like `handleFetch` that\n // throw on non-2xx would prevent typed error handling in callers.\n const res = await globalThis.fetch(\n `${this.#apiBaseUrl}/quote/updateStatus`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-metamask-clientproduct': this.#clientProduct,\n ...(this.#clientVersion\n ? { 'x-metamask-clientversion': this.#clientVersion }\n : {}),\n ...getClientHeaders({\n clientId: this.#clientId,\n jwt,\n }),\n },\n body: JSON.stringify(data),\n signal,\n },\n );\n\n if (res.ok) {\n return null;\n }\n\n const responseData = await res.json();\n\n try {\n validateQuoteStatusUpdateResponse(responseData);\n return responseData;\n } catch (error) {\n this.#onError?.(\n new QuoteStatusUpdateError(\n 'unexpected response shape from quote/updateStatus',\n { quoteId: data.quoteId },\n ),\n );\n throw error;\n }\n }\n\n async getQuoteStatus(\n data: {\n quoteId: string;\n },\n signal?: AbortSignal,\n ): Promise<QuoteStatusGetResponse> {\n const jwt = await getJwt(this.#messenger);\n\n // This method uses `globalThis.fetch` and reads the raw\n // `Response` (including JSON on non-2xx). Wrappers like `handleFetch` that\n // throw on non-2xx would prevent typed error handling in callers.\n const res = await globalThis.fetch(\n `${this.#apiBaseUrl}/getQuoteStatus?quoteId=${data.quoteId}`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'x-metamask-clientproduct': this.#clientProduct,\n ...(this.#clientVersion\n ? { 'x-metamask-clientversion': this.#clientVersion }\n : {}),\n ...getClientHeaders({\n clientId: this.#clientId,\n jwt,\n }),\n },\n signal,\n },\n );\n\n if (!res.ok) {\n // 5xx errors are transient (server-side); 4xx errors are client-side and\n // non-retryable. The `retryable` flag lets `getQuoteStatusWithRetry`\n // distinguish the two and only exit early for permanent failures.\n const retryable = res.status >= 500;\n const error = new QuoteStatusGetError(\n `request error to getQuoteStatus [${res.status}: ${res.statusText}]`,\n { quoteId: data.quoteId },\n retryable,\n );\n this.#onError?.(error);\n throw error;\n }\n\n const responseData = await res.json();\n\n try {\n validateQuoteStatusGetResponse(responseData);\n return responseData;\n } catch (error) {\n if (error instanceof StructError) {\n const validationFailures = [];\n\n for (const { path } of error.failures()) {\n const aggregatorId =\n (responseData as QuoteStatusGetResponse)?.submittedTx?.bridge ??\n ('unknown' as string);\n const pathString = path?.join('.') || 'unknown';\n validationFailures.push([aggregatorId, pathString].join('|'));\n }\n\n const validationError = new QuoteStatusGetError(\n 'unexpected response shape from getQuoteStatus',\n { quoteId: data.quoteId, validationFailures },\n );\n\n this.#onError?.(validationError);\n\n throw validationError;\n }\n\n throw error;\n }\n }\n\n /**\n * Updates a quote status, retrying on transient backend failures.\n *\n * Wraps {@link updateQuoteStatus} in a bounded retry loop. A request is only\n * retried when the backend returns an error whose type is in\n * {@link QuoteStatusUpdateRetryableBackendTypes}; any other error response\n * resolves immediately as non-retryable. Retries are spaced by\n * `options.delayMsBetweenRetries`, and both the abort signal and the optional\n * `options.retry` predicate are checked before each attempt so an\n * in-flight or pending retry can be cancelled (e.g. when the entry's status\n * changed while sleeping between retries).\n *\n * @param data - Request payload identifying the quote and target transition.\n * @param data.quoteId - Unique quote identifier to update.\n * @param data.srcTxHash - Source transaction hash associated with the quote.\n * @param data.newStatus - Target quote status to persist.\n * @param options - Retry configuration.\n * @param options.maxRetries - Maximum number of retries after the initial attempt.\n * @param options.delayMsBetweenRetries - Delay in milliseconds between attempts.\n * @param options.retry - Optional predicate checked before each attempt;\n * when it returns `false` the loop stops early and resolves as `Interrupted`.\n * @param signal - Optional abort signal for canceling the request and its retries.\n * @returns An outcome describing how the update resolved:\n * `Accepted` when the backend accepted the update, `NonRetryable` for a\n * non-retryable error response, `Interrupted` when aborted, or\n * `RetryableExhausted` when all retries were used up on retryable errors.\n * @throws If a request rejects for a reason other than the abort signal (e.g.\n * an unexpected response shape from {@link updateQuoteStatus}).\n */\n async updateQuoteStatusWithRetry(\n data: {\n quoteId: string;\n srcTxHash: string;\n newStatus: QuoteStatusBackendStatus;\n },\n options: {\n maxRetries: number;\n delayMsBetweenRetries: number;\n retry?: () => boolean;\n },\n signal?: AbortSignal,\n ): Promise<QuoteStatusUpdateWithRetryOutcome> {\n for (let attempt = 0; attempt <= options.maxRetries; attempt += 1) {\n if (attempt > 0) {\n await sleep(options.delayMsBetweenRetries);\n }\n\n if (signal?.aborted || options.retry?.() === false) {\n return new QuoteStatusUpdateWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.Interrupted,\n );\n }\n\n try {\n const response = await this.updateQuoteStatus(data, signal);\n\n if (response === null) {\n return new QuoteStatusUpdateWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.Accepted,\n );\n }\n\n if (!QuoteStatusUpdateRetryableBackendTypes.includes(response.type)) {\n return new QuoteStatusUpdateWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.NonRetryable,\n response,\n );\n }\n } catch (error) {\n if (signal?.aborted) {\n return new QuoteStatusUpdateWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.Interrupted,\n );\n }\n\n throw error;\n }\n }\n\n return new QuoteStatusUpdateWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.RetryableExhausted,\n );\n }\n\n async getQuoteStatusWithRetry(\n data: {\n quoteId: string;\n },\n options: {\n maxRetries: number;\n delayMsBetweenRetries: number;\n },\n signal?: AbortSignal,\n ): Promise<QuoteStatusGetWithRetryOutcome> {\n for (let attempt = 0; attempt <= options.maxRetries; attempt += 1) {\n if (attempt > 0) {\n await sleep(options.delayMsBetweenRetries);\n }\n\n if (signal?.aborted) {\n return new QuoteStatusGetWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.Interrupted,\n );\n }\n\n try {\n const response = await this.getQuoteStatus(data, signal);\n\n return new QuoteStatusGetWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.Accepted,\n response,\n );\n } catch (error) {\n if (signal?.aborted) {\n return new QuoteStatusGetWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.Interrupted,\n );\n }\n\n // Only short-circuit for non-retryable errors (e.g. 4xx, validation\n // failures). Retryable errors (e.g. 5xx) fall through so the loop can\n // attempt the next retry instead of returning NonRetryable immediately.\n if (error instanceof QuoteStatusGetError && !error.retryable) {\n return new QuoteStatusGetWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.NonRetryable,\n undefined,\n error,\n );\n }\n }\n }\n\n return new QuoteStatusGetWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.RetryableExhausted,\n );\n }\n}\n"]}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { QuoteStatusBackendStatus } from "./constants.cjs";
|
|
2
|
+
import { QuoteStatusGetWithRetryOutcome } from "./quote-status-get-with-retry-outcome.cjs";
|
|
3
|
+
import { QuoteStatusUpdateWithRetryOutcome } from "./quote-status-update-with-retry-outcome.cjs";
|
|
4
|
+
import { QuoteStatusApiServiceOptions, QuoteStatusGetResponse, QuoteStatusUpdateResponse } from "./types.cjs";
|
|
5
|
+
/**
|
|
6
|
+
* Service responsible for calling bridge quote status update APIs.
|
|
7
|
+
*
|
|
8
|
+
* It performs authentication, sends properly-scoped client headers, and validates
|
|
9
|
+
* error responses so callers can handle known update-status failures.
|
|
10
|
+
*/
|
|
11
|
+
export declare class QuoteStatusApiService {
|
|
12
|
+
#private;
|
|
13
|
+
/**
|
|
14
|
+
* Creates an API service for quote status update requests.
|
|
15
|
+
*
|
|
16
|
+
* @param options - Service dependencies and request configuration.
|
|
17
|
+
* @param options.messenger - Messenger used to retrieve the authentication token.
|
|
18
|
+
* @param options.clientId - Bridge client identifier used for request headers.
|
|
19
|
+
* @param options.clientProduct - Product name sent in client product headers.
|
|
20
|
+
* @param options.clientVersion - Optional client version sent in headers.
|
|
21
|
+
* @param options.apiBaseUrl - Base URL for the quote status API.
|
|
22
|
+
* @param options.onError - Optional callback for unexpected response-shape errors.
|
|
23
|
+
*/
|
|
24
|
+
constructor({ messenger, clientId, clientProduct, clientVersion, apiBaseUrl, onError, }: QuoteStatusApiServiceOptions);
|
|
25
|
+
/**
|
|
26
|
+
* Updates a quote status in the bridge quote-status API.
|
|
27
|
+
*
|
|
28
|
+
* The endpoint returns no payload on success (`2xx`) and a structured payload
|
|
29
|
+
* on non-`2xx` responses. This method returns `null` for successful updates and
|
|
30
|
+
* the validated error payload for unsuccessful updates.
|
|
31
|
+
*
|
|
32
|
+
* @param data - Request payload identifying quote and target status transition.
|
|
33
|
+
* @param data.quoteId - Unique quote identifier to update.
|
|
34
|
+
* @param data.srcTxHash - Source transaction hash associated with the quote.
|
|
35
|
+
* @param data.newStatus - Target quote status to persist.
|
|
36
|
+
* @param signal - Optional abort signal for canceling the request.
|
|
37
|
+
* @returns `null` for `2xx` responses, or a validated error response for non-`2xx`.
|
|
38
|
+
* @throws If the non-`2xx` response body does not match the expected schema.
|
|
39
|
+
*/
|
|
40
|
+
updateQuoteStatus(data: {
|
|
41
|
+
quoteId: string;
|
|
42
|
+
srcTxHash: string;
|
|
43
|
+
newStatus: QuoteStatusBackendStatus;
|
|
44
|
+
}, signal?: AbortSignal): Promise<QuoteStatusUpdateResponse | null>;
|
|
45
|
+
getQuoteStatus(data: {
|
|
46
|
+
quoteId: string;
|
|
47
|
+
}, signal?: AbortSignal): Promise<QuoteStatusGetResponse>;
|
|
48
|
+
/**
|
|
49
|
+
* Updates a quote status, retrying on transient backend failures.
|
|
50
|
+
*
|
|
51
|
+
* Wraps {@link updateQuoteStatus} in a bounded retry loop. A request is only
|
|
52
|
+
* retried when the backend returns an error whose type is in
|
|
53
|
+
* {@link QuoteStatusUpdateRetryableBackendTypes}; any other error response
|
|
54
|
+
* resolves immediately as non-retryable. Retries are spaced by
|
|
55
|
+
* `options.delayMsBetweenRetries`, and both the abort signal and the optional
|
|
56
|
+
* `options.retry` predicate are checked before each attempt so an
|
|
57
|
+
* in-flight or pending retry can be cancelled (e.g. when the entry's status
|
|
58
|
+
* changed while sleeping between retries).
|
|
59
|
+
*
|
|
60
|
+
* @param data - Request payload identifying the quote and target transition.
|
|
61
|
+
* @param data.quoteId - Unique quote identifier to update.
|
|
62
|
+
* @param data.srcTxHash - Source transaction hash associated with the quote.
|
|
63
|
+
* @param data.newStatus - Target quote status to persist.
|
|
64
|
+
* @param options - Retry configuration.
|
|
65
|
+
* @param options.maxRetries - Maximum number of retries after the initial attempt.
|
|
66
|
+
* @param options.delayMsBetweenRetries - Delay in milliseconds between attempts.
|
|
67
|
+
* @param options.retry - Optional predicate checked before each attempt;
|
|
68
|
+
* when it returns `false` the loop stops early and resolves as `Interrupted`.
|
|
69
|
+
* @param signal - Optional abort signal for canceling the request and its retries.
|
|
70
|
+
* @returns An outcome describing how the update resolved:
|
|
71
|
+
* `Accepted` when the backend accepted the update, `NonRetryable` for a
|
|
72
|
+
* non-retryable error response, `Interrupted` when aborted, or
|
|
73
|
+
* `RetryableExhausted` when all retries were used up on retryable errors.
|
|
74
|
+
* @throws If a request rejects for a reason other than the abort signal (e.g.
|
|
75
|
+
* an unexpected response shape from {@link updateQuoteStatus}).
|
|
76
|
+
*/
|
|
77
|
+
updateQuoteStatusWithRetry(data: {
|
|
78
|
+
quoteId: string;
|
|
79
|
+
srcTxHash: string;
|
|
80
|
+
newStatus: QuoteStatusBackendStatus;
|
|
81
|
+
}, options: {
|
|
82
|
+
maxRetries: number;
|
|
83
|
+
delayMsBetweenRetries: number;
|
|
84
|
+
retry?: () => boolean;
|
|
85
|
+
}, signal?: AbortSignal): Promise<QuoteStatusUpdateWithRetryOutcome>;
|
|
86
|
+
getQuoteStatusWithRetry(data: {
|
|
87
|
+
quoteId: string;
|
|
88
|
+
}, options: {
|
|
89
|
+
maxRetries: number;
|
|
90
|
+
delayMsBetweenRetries: number;
|
|
91
|
+
}, signal?: AbortSignal): Promise<QuoteStatusGetWithRetryOutcome>;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=quote-status-api-service.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quote-status-api-service.d.cts","sourceRoot":"","sources":["../../src/quote-status-manager/quote-status-api-service.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,wBAAwB,EAGzB,wBAAoB;AAErB,OAAO,EAAE,8BAA8B,EAAE,kDAA8C;AACvF,OAAO,EAAE,iCAAiC,EAAE,qDAAiD;AAC7F,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,EACtB,yBAAyB,EAC1B,oBAAgB;AAOjB;;;;;GAKG;AACH,qBAAa,qBAAqB;;IAahC;;;;;;;;;;OAUG;gBACS,EACV,SAAS,EACT,QAAQ,EACR,aAAa,EACb,aAAa,EACb,UAAU,EACV,OAAO,GACR,EAAE,4BAA4B;IAS/B;;;;;;;;;;;;;;OAcG;IACG,iBAAiB,CACrB,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,wBAAwB,CAAC;KACrC,EACD,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC;IA8CtC,cAAc,CAClB,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;KACjB,EACD,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,sBAAsB,CAAC;IAsElC;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACG,0BAA0B,CAC9B,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,wBAAwB,CAAC;KACrC,EACD,OAAO,EAAE;QACP,UAAU,EAAE,MAAM,CAAC;QACnB,qBAAqB,EAAE,MAAM,CAAC;QAC9B,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC;KACvB,EACD,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,iCAAiC,CAAC;IA2CvC,uBAAuB,CAC3B,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;KACjB,EACD,OAAO,EAAE;QACP,UAAU,EAAE,MAAM,CAAC;QACnB,qBAAqB,EAAE,MAAM,CAAC;KAC/B,EACD,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,8BAA8B,CAAC;CA2C3C"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { QuoteStatusBackendStatus } from "./constants.mjs";
|
|
2
|
+
import { QuoteStatusGetWithRetryOutcome } from "./quote-status-get-with-retry-outcome.mjs";
|
|
3
|
+
import { QuoteStatusUpdateWithRetryOutcome } from "./quote-status-update-with-retry-outcome.mjs";
|
|
4
|
+
import { QuoteStatusApiServiceOptions, QuoteStatusGetResponse, QuoteStatusUpdateResponse } from "./types.mjs";
|
|
5
|
+
/**
|
|
6
|
+
* Service responsible for calling bridge quote status update APIs.
|
|
7
|
+
*
|
|
8
|
+
* It performs authentication, sends properly-scoped client headers, and validates
|
|
9
|
+
* error responses so callers can handle known update-status failures.
|
|
10
|
+
*/
|
|
11
|
+
export declare class QuoteStatusApiService {
|
|
12
|
+
#private;
|
|
13
|
+
/**
|
|
14
|
+
* Creates an API service for quote status update requests.
|
|
15
|
+
*
|
|
16
|
+
* @param options - Service dependencies and request configuration.
|
|
17
|
+
* @param options.messenger - Messenger used to retrieve the authentication token.
|
|
18
|
+
* @param options.clientId - Bridge client identifier used for request headers.
|
|
19
|
+
* @param options.clientProduct - Product name sent in client product headers.
|
|
20
|
+
* @param options.clientVersion - Optional client version sent in headers.
|
|
21
|
+
* @param options.apiBaseUrl - Base URL for the quote status API.
|
|
22
|
+
* @param options.onError - Optional callback for unexpected response-shape errors.
|
|
23
|
+
*/
|
|
24
|
+
constructor({ messenger, clientId, clientProduct, clientVersion, apiBaseUrl, onError, }: QuoteStatusApiServiceOptions);
|
|
25
|
+
/**
|
|
26
|
+
* Updates a quote status in the bridge quote-status API.
|
|
27
|
+
*
|
|
28
|
+
* The endpoint returns no payload on success (`2xx`) and a structured payload
|
|
29
|
+
* on non-`2xx` responses. This method returns `null` for successful updates and
|
|
30
|
+
* the validated error payload for unsuccessful updates.
|
|
31
|
+
*
|
|
32
|
+
* @param data - Request payload identifying quote and target status transition.
|
|
33
|
+
* @param data.quoteId - Unique quote identifier to update.
|
|
34
|
+
* @param data.srcTxHash - Source transaction hash associated with the quote.
|
|
35
|
+
* @param data.newStatus - Target quote status to persist.
|
|
36
|
+
* @param signal - Optional abort signal for canceling the request.
|
|
37
|
+
* @returns `null` for `2xx` responses, or a validated error response for non-`2xx`.
|
|
38
|
+
* @throws If the non-`2xx` response body does not match the expected schema.
|
|
39
|
+
*/
|
|
40
|
+
updateQuoteStatus(data: {
|
|
41
|
+
quoteId: string;
|
|
42
|
+
srcTxHash: string;
|
|
43
|
+
newStatus: QuoteStatusBackendStatus;
|
|
44
|
+
}, signal?: AbortSignal): Promise<QuoteStatusUpdateResponse | null>;
|
|
45
|
+
getQuoteStatus(data: {
|
|
46
|
+
quoteId: string;
|
|
47
|
+
}, signal?: AbortSignal): Promise<QuoteStatusGetResponse>;
|
|
48
|
+
/**
|
|
49
|
+
* Updates a quote status, retrying on transient backend failures.
|
|
50
|
+
*
|
|
51
|
+
* Wraps {@link updateQuoteStatus} in a bounded retry loop. A request is only
|
|
52
|
+
* retried when the backend returns an error whose type is in
|
|
53
|
+
* {@link QuoteStatusUpdateRetryableBackendTypes}; any other error response
|
|
54
|
+
* resolves immediately as non-retryable. Retries are spaced by
|
|
55
|
+
* `options.delayMsBetweenRetries`, and both the abort signal and the optional
|
|
56
|
+
* `options.retry` predicate are checked before each attempt so an
|
|
57
|
+
* in-flight or pending retry can be cancelled (e.g. when the entry's status
|
|
58
|
+
* changed while sleeping between retries).
|
|
59
|
+
*
|
|
60
|
+
* @param data - Request payload identifying the quote and target transition.
|
|
61
|
+
* @param data.quoteId - Unique quote identifier to update.
|
|
62
|
+
* @param data.srcTxHash - Source transaction hash associated with the quote.
|
|
63
|
+
* @param data.newStatus - Target quote status to persist.
|
|
64
|
+
* @param options - Retry configuration.
|
|
65
|
+
* @param options.maxRetries - Maximum number of retries after the initial attempt.
|
|
66
|
+
* @param options.delayMsBetweenRetries - Delay in milliseconds between attempts.
|
|
67
|
+
* @param options.retry - Optional predicate checked before each attempt;
|
|
68
|
+
* when it returns `false` the loop stops early and resolves as `Interrupted`.
|
|
69
|
+
* @param signal - Optional abort signal for canceling the request and its retries.
|
|
70
|
+
* @returns An outcome describing how the update resolved:
|
|
71
|
+
* `Accepted` when the backend accepted the update, `NonRetryable` for a
|
|
72
|
+
* non-retryable error response, `Interrupted` when aborted, or
|
|
73
|
+
* `RetryableExhausted` when all retries were used up on retryable errors.
|
|
74
|
+
* @throws If a request rejects for a reason other than the abort signal (e.g.
|
|
75
|
+
* an unexpected response shape from {@link updateQuoteStatus}).
|
|
76
|
+
*/
|
|
77
|
+
updateQuoteStatusWithRetry(data: {
|
|
78
|
+
quoteId: string;
|
|
79
|
+
srcTxHash: string;
|
|
80
|
+
newStatus: QuoteStatusBackendStatus;
|
|
81
|
+
}, options: {
|
|
82
|
+
maxRetries: number;
|
|
83
|
+
delayMsBetweenRetries: number;
|
|
84
|
+
retry?: () => boolean;
|
|
85
|
+
}, signal?: AbortSignal): Promise<QuoteStatusUpdateWithRetryOutcome>;
|
|
86
|
+
getQuoteStatusWithRetry(data: {
|
|
87
|
+
quoteId: string;
|
|
88
|
+
}, options: {
|
|
89
|
+
maxRetries: number;
|
|
90
|
+
delayMsBetweenRetries: number;
|
|
91
|
+
}, signal?: AbortSignal): Promise<QuoteStatusGetWithRetryOutcome>;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=quote-status-api-service.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quote-status-api-service.d.mts","sourceRoot":"","sources":["../../src/quote-status-manager/quote-status-api-service.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,wBAAwB,EAGzB,wBAAoB;AAErB,OAAO,EAAE,8BAA8B,EAAE,kDAA8C;AACvF,OAAO,EAAE,iCAAiC,EAAE,qDAAiD;AAC7F,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,EACtB,yBAAyB,EAC1B,oBAAgB;AAOjB;;;;;GAKG;AACH,qBAAa,qBAAqB;;IAahC;;;;;;;;;;OAUG;gBACS,EACV,SAAS,EACT,QAAQ,EACR,aAAa,EACb,aAAa,EACb,UAAU,EACV,OAAO,GACR,EAAE,4BAA4B;IAS/B;;;;;;;;;;;;;;OAcG;IACG,iBAAiB,CACrB,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,wBAAwB,CAAC;KACrC,EACD,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC;IA8CtC,cAAc,CAClB,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;KACjB,EACD,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,sBAAsB,CAAC;IAsElC;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACG,0BAA0B,CAC9B,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,wBAAwB,CAAC;KACrC,EACD,OAAO,EAAE;QACP,UAAU,EAAE,MAAM,CAAC;QACnB,qBAAqB,EAAE,MAAM,CAAC;QAC9B,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC;KACvB,EACD,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,iCAAiC,CAAC;IA2CvC,uBAAuB,CAC3B,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;KACjB,EACD,OAAO,EAAE;QACP,UAAU,EAAE,MAAM,CAAC;QACnB,qBAAqB,EAAE,MAAM,CAAC;KAC/B,EACD,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,8BAA8B,CAAC;CA2C3C"}
|