@fjell/client-api 4.4.17 → 4.4.19

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/dist/index.js CHANGED
@@ -57,7 +57,7 @@ var getAllActionOperation = (api, apiOptions, utilities) => {
57
57
  return utilities.validatePK(
58
58
  await utilities.processArray(
59
59
  api.httpPost(
60
- utilities.getPath(loc),
60
+ `${utilities.getPath(loc)}/${action}`,
61
61
  body,
62
62
  requestOptions
63
63
  )
@@ -96,18 +96,119 @@ var getOneOperation = (api, apiOptions, utilities) => {
96
96
 
97
97
  // src/ops/create.ts
98
98
  var logger5 = logger_default.get("client-api", "ops", "create");
99
+ function shouldRetryError(error) {
100
+ if (error.code === "ECONNREFUSED" || error.code === "ENOTFOUND" || error.code === "ENETUNREACH" || error.message?.includes("timeout") || error.message?.includes("network")) {
101
+ return true;
102
+ }
103
+ if (error.status >= 500 || error.status === 429) {
104
+ return true;
105
+ }
106
+ if (error.status >= 400 && error.status < 500 && error.status !== 429) {
107
+ return false;
108
+ }
109
+ return true;
110
+ }
111
+ function calculateRetryDelay(attempt, config) {
112
+ const exponentialDelay = (config.initialDelayMs || 1e3) * Math.pow(config.backoffMultiplier || 2, attempt);
113
+ const cappedDelay = Math.min(exponentialDelay, config.maxDelayMs || 3e4);
114
+ const jitter = 0.5 + Math.random() * 0.5;
115
+ return Math.floor(cappedDelay * jitter);
116
+ }
117
+ function enhanceError(error, context) {
118
+ if (!error) return new Error("Unknown error occurred");
119
+ if (error.context) return error;
120
+ const enhancedError = new Error(error.message || "HTTP operation failed");
121
+ Object.assign(enhancedError, {
122
+ code: error.code || error.status || "UNKNOWN_ERROR",
123
+ status: error.status,
124
+ context,
125
+ originalError: error
126
+ });
127
+ return enhancedError;
128
+ }
99
129
  var getCreateOperation = (api, apiOptions, utilities) => {
100
130
  const create = async (item, locations = []) => {
101
131
  const requestOptions = Object.assign({}, apiOptions.postOptions, { isAuthenticated: apiOptions.writeAuthenticated });
102
132
  logger5.default("create", { item, locations, requestOptions });
103
133
  utilities.verifyLocations(locations);
104
134
  const loc = locations;
105
- const created = utilities.validatePK(await utilities.processOne(api.httpPost(
106
- utilities.getPath(loc),
107
- item,
108
- requestOptions
109
- )));
110
- return created;
135
+ const operationContext = {
136
+ operation: "create",
137
+ path: utilities.getPath(loc),
138
+ itemType: typeof item,
139
+ hasLocations: locations.length > 0
140
+ };
141
+ const retryConfig = {
142
+ maxRetries: 3,
143
+ initialDelayMs: 1e3,
144
+ maxDelayMs: 3e4,
145
+ backoffMultiplier: 2,
146
+ ...apiOptions.retryConfig
147
+ };
148
+ let lastError = null;
149
+ const startTime = Date.now();
150
+ for (let attempt = 0; attempt <= retryConfig.maxRetries; attempt++) {
151
+ try {
152
+ logger5.debug(`Creating item (attempt ${attempt + 1})`, operationContext);
153
+ const result = await utilities.processOne(api.httpPost(
154
+ utilities.getPath(loc),
155
+ item,
156
+ requestOptions
157
+ ));
158
+ const created = utilities.validatePK(result);
159
+ if (attempt > 0) {
160
+ logger5.info(`Create operation succeeded after ${attempt} retries`, {
161
+ ...operationContext,
162
+ totalAttempts: attempt + 1,
163
+ duration: Date.now() - startTime
164
+ });
165
+ }
166
+ return created;
167
+ } catch (error) {
168
+ lastError = error;
169
+ if (attempt === retryConfig.maxRetries) {
170
+ break;
171
+ }
172
+ const isRetryable = shouldRetryError(error);
173
+ if (!isRetryable) {
174
+ logger5.debug("Not retrying create operation due to non-retryable error", {
175
+ ...operationContext,
176
+ errorMessage: error.message,
177
+ errorCode: error.code || error.status,
178
+ attempt: attempt + 1
179
+ });
180
+ break;
181
+ }
182
+ const delay = calculateRetryDelay(attempt, retryConfig);
183
+ logger5.warning(`Retrying create operation (attempt ${attempt + 2}) after ${delay}ms`, {
184
+ ...operationContext,
185
+ errorMessage: error.message,
186
+ errorCode: error.code || error.status,
187
+ delay,
188
+ attemptNumber: attempt + 1
189
+ });
190
+ await new Promise((resolve) => setTimeout(resolve, delay));
191
+ }
192
+ }
193
+ const finalError = enhanceError(lastError, operationContext);
194
+ if (apiOptions.errorHandler) {
195
+ try {
196
+ apiOptions.errorHandler(finalError, operationContext);
197
+ } catch (handlerError) {
198
+ logger5.error("Custom error handler failed", {
199
+ originalError: finalError.message,
200
+ handlerError: handlerError?.message || String(handlerError)
201
+ });
202
+ }
203
+ }
204
+ logger5.error(`Create operation failed after ${retryConfig.maxRetries + 1} attempts`, {
205
+ ...operationContext,
206
+ errorMessage: finalError.message,
207
+ errorCode: finalError.code || finalError.status,
208
+ duration: Date.now() - startTime,
209
+ totalAttempts: retryConfig.maxRetries + 1
210
+ });
211
+ throw finalError;
111
212
  };
112
213
  return create;
113
214
  };
@@ -131,16 +232,121 @@ var getUpdateOperation = (api, apiOptions, utilities) => {
131
232
 
132
233
  // src/ops/get.ts
133
234
  var logger7 = logger_default.get("client-api", "ops", "get");
235
+ function shouldRetryError2(error) {
236
+ if (error.code === "ECONNREFUSED" || error.code === "ENOTFOUND" || error.code === "ENETUNREACH" || error.message?.includes("timeout") || error.message?.includes("network")) {
237
+ return true;
238
+ }
239
+ if (error.status >= 500 || error.status === 429) {
240
+ return true;
241
+ }
242
+ if (error.status >= 400 && error.status < 500 && error.status !== 429) {
243
+ return false;
244
+ }
245
+ return true;
246
+ }
247
+ function calculateRetryDelay2(attempt, config) {
248
+ const exponentialDelay = (config.initialDelayMs || 1e3) * Math.pow(config.backoffMultiplier || 2, attempt);
249
+ const cappedDelay = Math.min(exponentialDelay, config.maxDelayMs || 3e4);
250
+ const jitter = 0.5 + Math.random() * 0.5;
251
+ return Math.floor(cappedDelay * jitter);
252
+ }
253
+ function enhanceError2(error, context) {
254
+ if (!error) return new Error("Unknown error occurred");
255
+ if (error.context) return error;
256
+ const enhancedError = new Error(error.message || "HTTP operation failed");
257
+ Object.assign(enhancedError, {
258
+ code: error.code || error.status || "UNKNOWN_ERROR",
259
+ status: error.status,
260
+ context,
261
+ originalError: error
262
+ });
263
+ return enhancedError;
264
+ }
134
265
  var getGetOperation = (api, apiOptions, utilities) => {
135
266
  const get = async (ik) => {
136
267
  const requestOptions = Object.assign({}, apiOptions.getOptions, { isAuthenticated: apiOptions.readAuthenticated });
137
268
  logger7.default("get", { ik, requestOptions });
138
- return utilities.validatePK(await utilities.processOne(
139
- api.httpGet(
140
- utilities.getPath(ik),
141
- requestOptions
142
- )
143
- ));
269
+ const operationContext = {
270
+ operation: "get",
271
+ path: utilities.getPath(ik),
272
+ keyType: typeof ik
273
+ };
274
+ const retryConfig = {
275
+ maxRetries: 3,
276
+ initialDelayMs: 1e3,
277
+ maxDelayMs: 3e4,
278
+ backoffMultiplier: 2,
279
+ ...apiOptions.retryConfig
280
+ };
281
+ let lastError = null;
282
+ const startTime = Date.now();
283
+ for (let attempt = 0; attempt <= retryConfig.maxRetries; attempt++) {
284
+ try {
285
+ logger7.debug(`Getting item (attempt ${attempt + 1})`, operationContext);
286
+ const result = await utilities.processOne(
287
+ api.httpGet(
288
+ utilities.getPath(ik),
289
+ requestOptions
290
+ )
291
+ );
292
+ const item = utilities.validatePK(result);
293
+ if (attempt > 0) {
294
+ logger7.info(`Get operation succeeded after ${attempt} retries`, {
295
+ ...operationContext,
296
+ totalAttempts: attempt + 1,
297
+ duration: Date.now() - startTime
298
+ });
299
+ }
300
+ return item;
301
+ } catch (error) {
302
+ lastError = error;
303
+ if (error.status === 404) {
304
+ logger7.debug("Item not found (404)", operationContext);
305
+ return null;
306
+ }
307
+ if (attempt === retryConfig.maxRetries) {
308
+ break;
309
+ }
310
+ const isRetryable = shouldRetryError2(error);
311
+ if (!isRetryable) {
312
+ logger7.debug("Not retrying get operation due to non-retryable error", {
313
+ ...operationContext,
314
+ errorMessage: error.message,
315
+ errorCode: error.code || error.status,
316
+ attempt: attempt + 1
317
+ });
318
+ break;
319
+ }
320
+ const delay = calculateRetryDelay2(attempt, retryConfig);
321
+ logger7.warning(`Retrying get operation (attempt ${attempt + 2}) after ${delay}ms`, {
322
+ ...operationContext,
323
+ errorMessage: error.message,
324
+ errorCode: error.code || error.status,
325
+ delay,
326
+ attemptNumber: attempt + 1
327
+ });
328
+ await new Promise((resolve) => setTimeout(resolve, delay));
329
+ }
330
+ }
331
+ const finalError = enhanceError2(lastError, operationContext);
332
+ if (apiOptions.errorHandler) {
333
+ try {
334
+ apiOptions.errorHandler(finalError, operationContext);
335
+ } catch (handlerError) {
336
+ logger7.error("Custom error handler failed", {
337
+ originalError: finalError.message,
338
+ handlerError: handlerError?.message || String(handlerError)
339
+ });
340
+ }
341
+ }
342
+ logger7.error(`Get operation failed after ${retryConfig.maxRetries + 1} attempts`, {
343
+ ...operationContext,
344
+ errorMessage: finalError.message,
345
+ errorCode: finalError.code || finalError.status,
346
+ duration: Date.now() - startTime,
347
+ totalAttempts: retryConfig.maxRetries + 1
348
+ });
349
+ throw finalError;
144
350
  };
145
351
  return get;
146
352
  };
@@ -534,12 +740,510 @@ var createRegistry = (registryHub) => {
534
740
  ...baseRegistry
535
741
  };
536
742
  };
743
+
744
+ // src/errors/index.ts
745
+ var ClientApiError = class extends Error {
746
+ timestamp;
747
+ context;
748
+ constructor(message, context) {
749
+ super(message);
750
+ this.name = this.constructor.name;
751
+ this.timestamp = /* @__PURE__ */ new Date();
752
+ this.context = context;
753
+ Object.setPrototypeOf(this, new.target.prototype);
754
+ }
755
+ toJSON() {
756
+ return {
757
+ name: this.name,
758
+ code: this.code,
759
+ message: this.message,
760
+ isRetryable: this.isRetryable,
761
+ timestamp: this.timestamp,
762
+ context: this.context,
763
+ stack: this.stack
764
+ };
765
+ }
766
+ };
767
+ var NetworkError = class extends ClientApiError {
768
+ code = "NETWORK_ERROR";
769
+ isRetryable = true;
770
+ constructor(message, context) {
771
+ super(`Network error: ${message}`, context);
772
+ }
773
+ };
774
+ var TimeoutError = class extends ClientApiError {
775
+ code = "TIMEOUT_ERROR";
776
+ isRetryable = true;
777
+ constructor(timeout, context) {
778
+ super(`Request timed out after ${timeout}ms`, context);
779
+ }
780
+ };
781
+ var AuthenticationError = class extends ClientApiError {
782
+ code = "AUTHENTICATION_ERROR";
783
+ isRetryable = false;
784
+ constructor(message, context) {
785
+ super(message || "Authentication failed - invalid or expired credentials", context);
786
+ }
787
+ };
788
+ var AuthorizationError = class extends ClientApiError {
789
+ code = "AUTHORIZATION_ERROR";
790
+ isRetryable = false;
791
+ constructor(message, context) {
792
+ super(message || "Access forbidden - insufficient permissions", context);
793
+ }
794
+ };
795
+ var NotFoundError = class extends ClientApiError {
796
+ code = "NOT_FOUND_ERROR";
797
+ isRetryable = false;
798
+ constructor(resource, identifier, context) {
799
+ const message = identifier ? `${resource} with identifier '${identifier}' not found` : `${resource} not found`;
800
+ super(message, context);
801
+ }
802
+ };
803
+ var ValidationError = class extends ClientApiError {
804
+ code = "VALIDATION_ERROR";
805
+ isRetryable = false;
806
+ validationErrors;
807
+ constructor(message, validationErrors, context) {
808
+ super(`Validation error: ${message}`, context);
809
+ this.validationErrors = validationErrors;
810
+ }
811
+ };
812
+ var ConflictError = class extends ClientApiError {
813
+ code = "CONFLICT_ERROR";
814
+ isRetryable = false;
815
+ constructor(message, context) {
816
+ super(`Conflict: ${message}`, context);
817
+ }
818
+ };
819
+ var RateLimitError = class extends ClientApiError {
820
+ code = "RATE_LIMIT_ERROR";
821
+ isRetryable = true;
822
+ retryAfter;
823
+ constructor(retryAfter, context) {
824
+ const message = retryAfter ? `Rate limit exceeded - retry after ${retryAfter} seconds` : "Rate limit exceeded";
825
+ super(message, context);
826
+ this.retryAfter = retryAfter;
827
+ }
828
+ };
829
+ var ServerError = class extends ClientApiError {
830
+ code = "SERVER_ERROR";
831
+ isRetryable = true;
832
+ statusCode;
833
+ constructor(statusCode, message, context) {
834
+ super(message || `Server error (${statusCode})`, context);
835
+ this.statusCode = statusCode;
836
+ }
837
+ };
838
+ var PayloadTooLargeError = class extends ClientApiError {
839
+ code = "PAYLOAD_TOO_LARGE_ERROR";
840
+ isRetryable = false;
841
+ constructor(maxSize, context) {
842
+ const message = maxSize ? `Request payload too large - maximum size is ${maxSize}` : "Request payload too large";
843
+ super(message, context);
844
+ }
845
+ };
846
+ var HttpError = class extends ClientApiError {
847
+ code = "HTTP_ERROR";
848
+ isRetryable;
849
+ statusCode;
850
+ statusText;
851
+ constructor(statusCode, statusText, message, context) {
852
+ super(message || `HTTP error ${statusCode}: ${statusText}`, context);
853
+ this.statusCode = statusCode;
854
+ this.statusText = statusText;
855
+ this.isRetryable = statusCode >= 500;
856
+ }
857
+ };
858
+ var ConfigurationError = class extends ClientApiError {
859
+ code = "CONFIGURATION_ERROR";
860
+ isRetryable = false;
861
+ constructor(message, context) {
862
+ super(`Configuration error: ${message}`, context);
863
+ }
864
+ };
865
+ var ParseError = class extends ClientApiError {
866
+ code = "PARSE_ERROR";
867
+ isRetryable = false;
868
+ constructor(message, context) {
869
+ super(`Parse error: ${message}`, context);
870
+ }
871
+ };
872
+ function createHttpError(statusCode, statusText, responseBody, context) {
873
+ const errorContext = { statusCode, statusText, responseBody, ...context };
874
+ switch (statusCode) {
875
+ case 400:
876
+ if (responseBody?.validationErrors) {
877
+ return new ValidationError(
878
+ responseBody.message || "Request validation failed",
879
+ responseBody.validationErrors,
880
+ errorContext
881
+ );
882
+ }
883
+ return new ValidationError(responseBody?.message || statusText, [], errorContext);
884
+ case 401:
885
+ return new AuthenticationError(responseBody?.message, errorContext);
886
+ case 403:
887
+ return new AuthorizationError(responseBody?.message, errorContext);
888
+ case 404:
889
+ return new NotFoundError(
890
+ responseBody?.resource || "Resource",
891
+ responseBody?.identifier,
892
+ errorContext
893
+ );
894
+ case 409:
895
+ return new ConflictError(responseBody?.message || statusText, errorContext);
896
+ case 413:
897
+ return new PayloadTooLargeError(responseBody?.maxSize, errorContext);
898
+ case 429: {
899
+ let retryAfter;
900
+ if (responseBody?.retryAfter) {
901
+ retryAfter = responseBody.retryAfter;
902
+ } else if (context?.headers?.["retry-after"]) {
903
+ retryAfter = parseInt(context.headers["retry-after"]);
904
+ }
905
+ return new RateLimitError(retryAfter, errorContext);
906
+ }
907
+ default:
908
+ if (statusCode >= 500) {
909
+ return new ServerError(statusCode, responseBody?.message || statusText, errorContext);
910
+ }
911
+ return new HttpError(statusCode, statusText, responseBody?.message, errorContext);
912
+ }
913
+ }
914
+ function createNetworkError(error, context) {
915
+ const errorContext = { originalError: error, ...context };
916
+ if (error.code === "ECONNABORTED" || error.message?.includes("timeout")) {
917
+ return new TimeoutError(error.timeout || 5e3, errorContext);
918
+ }
919
+ if (error.code === "ECONNREFUSED" || error.code === "ENOTFOUND" || error.code === "ENETUNREACH" || error.message?.includes("network")) {
920
+ return new NetworkError(error.message || "Network connection failed", errorContext);
921
+ }
922
+ return new NetworkError(error.message || "Unknown network error", errorContext);
923
+ }
924
+ function isRetryableError(error) {
925
+ return error instanceof ClientApiError && error.isRetryable;
926
+ }
927
+ function isClientApiError(error) {
928
+ return error instanceof ClientApiError;
929
+ }
930
+
931
+ // src/ops/errorHandling.ts
932
+ function shouldRetryError3(error) {
933
+ if (error.code === "ECONNREFUSED" || error.code === "ENOTFOUND" || error.code === "ENETUNREACH" || error.message?.includes("timeout") || error.message?.includes("network")) {
934
+ return true;
935
+ }
936
+ if (error.status >= 500 || error.status === 429) {
937
+ return true;
938
+ }
939
+ if (error.status >= 400 && error.status < 500 && error.status !== 429) {
940
+ return false;
941
+ }
942
+ return true;
943
+ }
944
+ function calculateRetryDelay3(attempt, config) {
945
+ const exponentialDelay = (config.initialDelayMs || 1e3) * Math.pow(config.backoffMultiplier || 2, attempt);
946
+ const cappedDelay = Math.min(exponentialDelay, config.maxDelayMs || 3e4);
947
+ const jitter = 0.5 + Math.random() * 0.5;
948
+ return Math.floor(cappedDelay * jitter);
949
+ }
950
+ function enhanceError3(error, context) {
951
+ if (!error) return new Error("Unknown error occurred");
952
+ if (error.context) return error;
953
+ const enhancedError = new Error(error.message || "HTTP operation failed");
954
+ Object.assign(enhancedError, {
955
+ code: error.code || error.status || "UNKNOWN_ERROR",
956
+ status: error.status,
957
+ context,
958
+ originalError: error
959
+ });
960
+ return enhancedError;
961
+ }
962
+ function getRetryConfig(apiOptions) {
963
+ return {
964
+ maxRetries: 3,
965
+ initialDelayMs: 1e3,
966
+ maxDelayMs: 3e4,
967
+ backoffMultiplier: 2,
968
+ ...apiOptions.retryConfig
969
+ };
970
+ }
971
+ function executeErrorHandler(errorHandler, error, context, logger21) {
972
+ if (!errorHandler) return;
973
+ try {
974
+ errorHandler(error, context);
975
+ } catch (handlerError) {
976
+ logger21.error("Custom error handler failed", {
977
+ originalError: error.message,
978
+ handlerError: handlerError?.message || String(handlerError)
979
+ });
980
+ }
981
+ }
982
+ async function executeWithRetry(operation, operationName, operationContext, apiOptions, logger21, specialErrorHandling) {
983
+ const retryConfig = getRetryConfig(apiOptions);
984
+ let lastError = null;
985
+ const startTime = Date.now();
986
+ for (let attempt = 0; attempt <= retryConfig.maxRetries; attempt++) {
987
+ try {
988
+ logger21.debug(`Executing ${operationName} (attempt ${attempt + 1})`, operationContext);
989
+ const result = await operation();
990
+ if (attempt > 0) {
991
+ logger21.info(`${operationName} operation succeeded after ${attempt} retries`, {
992
+ ...operationContext,
993
+ totalAttempts: attempt + 1,
994
+ duration: Date.now() - startTime
995
+ });
996
+ }
997
+ return result;
998
+ } catch (error) {
999
+ lastError = error;
1000
+ if (specialErrorHandling) {
1001
+ const specialResult = specialErrorHandling(error);
1002
+ if (specialResult !== void 0) {
1003
+ return specialResult;
1004
+ }
1005
+ }
1006
+ if (attempt === retryConfig.maxRetries) {
1007
+ break;
1008
+ }
1009
+ const isRetryable = shouldRetryError3(error);
1010
+ if (!isRetryable) {
1011
+ logger21.debug(`Not retrying ${operationName} operation due to non-retryable error`, {
1012
+ ...operationContext,
1013
+ errorMessage: error.message,
1014
+ errorCode: error.code || error.status,
1015
+ attempt: attempt + 1
1016
+ });
1017
+ break;
1018
+ }
1019
+ const delay = calculateRetryDelay3(attempt, retryConfig);
1020
+ logger21.warning(`Retrying ${operationName} operation (attempt ${attempt + 2}) after ${delay}ms`, {
1021
+ ...operationContext,
1022
+ errorMessage: error.message,
1023
+ errorCode: error.code || error.status,
1024
+ delay,
1025
+ attemptNumber: attempt + 1
1026
+ });
1027
+ await new Promise((resolve) => setTimeout(resolve, delay));
1028
+ }
1029
+ }
1030
+ const finalError = enhanceError3(lastError, operationContext);
1031
+ executeErrorHandler(apiOptions.errorHandler, finalError, operationContext, logger21);
1032
+ logger21.error(`${operationName} operation failed after ${retryConfig.maxRetries + 1} attempts`, {
1033
+ ...operationContext,
1034
+ errorMessage: finalError.message,
1035
+ errorCode: finalError.code || finalError.status,
1036
+ duration: Date.now() - startTime,
1037
+ totalAttempts: retryConfig.maxRetries + 1
1038
+ });
1039
+ throw finalError;
1040
+ }
1041
+
1042
+ // src/http/HttpWrapper.ts
1043
+ var logger20 = {
1044
+ debug: (message, context) => console.debug(message, context),
1045
+ info: (message, context) => console.info(message, context),
1046
+ warning: (message, context) => console.warn(message, context),
1047
+ error: (message, context) => console.error(message, context)
1048
+ };
1049
+ var DEFAULT_RETRY_CONFIG = {
1050
+ maxRetries: 3,
1051
+ initialDelayMs: 1e3,
1052
+ maxDelayMs: 3e4,
1053
+ backoffMultiplier: 2,
1054
+ enableJitter: true,
1055
+ shouldRetry: (error, attemptNumber) => {
1056
+ if (attemptNumber >= 3) return false;
1057
+ if (error.isRetryable) return true;
1058
+ return false;
1059
+ },
1060
+ onRetry: (error, attemptNumber, delay) => {
1061
+ logger20.warning(`Retrying HTTP request (attempt ${attemptNumber + 1}) after ${delay}ms`, {
1062
+ errorCode: error.code,
1063
+ errorMessage: error.message,
1064
+ delay,
1065
+ attemptNumber
1066
+ });
1067
+ }
1068
+ };
1069
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
1070
+ function calculateDelay(attemptNumber, config) {
1071
+ const exponentialDelay = config.initialDelayMs * Math.pow(config.backoffMultiplier, attemptNumber);
1072
+ const cappedDelay = Math.min(exponentialDelay, config.maxDelayMs);
1073
+ if (!config.enableJitter) {
1074
+ return cappedDelay;
1075
+ }
1076
+ const jitter = 0.5 + Math.random() * 0.5;
1077
+ return Math.floor(cappedDelay * jitter);
1078
+ }
1079
+ var HttpWrapper = class {
1080
+ api;
1081
+ retryConfig;
1082
+ constructor(api, retryConfig = {}) {
1083
+ this.api = api;
1084
+ this.retryConfig = { ...DEFAULT_RETRY_CONFIG, ...retryConfig };
1085
+ }
1086
+ /**
1087
+ * Execute HTTP operation with retry logic and error handling
1088
+ */
1089
+ async executeWithRetry(operation, operationName, context) {
1090
+ let lastError = null;
1091
+ const startTime = Date.now();
1092
+ for (let attempt = 0; attempt <= this.retryConfig.maxRetries; attempt++) {
1093
+ try {
1094
+ logger20.debug(`Executing ${operationName}`, {
1095
+ attempt: attempt + 1,
1096
+ maxRetries: this.retryConfig.maxRetries + 1,
1097
+ ...context
1098
+ });
1099
+ const result = await operation();
1100
+ if (attempt > 0) {
1101
+ logger20.info(`${operationName} succeeded after ${attempt} retries`, {
1102
+ totalAttempts: attempt + 1,
1103
+ duration: Date.now() - startTime,
1104
+ ...context
1105
+ });
1106
+ }
1107
+ return result;
1108
+ } catch (error) {
1109
+ lastError = this.convertToClientApiError(error, operationName, context);
1110
+ if (attempt === this.retryConfig.maxRetries) {
1111
+ break;
1112
+ }
1113
+ if (!this.retryConfig.shouldRetry(lastError, attempt)) {
1114
+ logger20.debug(`Not retrying ${operationName} due to non-retryable error`, {
1115
+ errorCode: lastError.code,
1116
+ errorMessage: lastError.message,
1117
+ attempt: attempt + 1,
1118
+ ...context
1119
+ });
1120
+ break;
1121
+ }
1122
+ let delay = calculateDelay(attempt, this.retryConfig);
1123
+ if (lastError instanceof RateLimitError && lastError.retryAfter) {
1124
+ delay = Math.max(delay, lastError.retryAfter * 1e3);
1125
+ }
1126
+ this.retryConfig.onRetry(lastError, attempt, delay);
1127
+ await sleep(delay);
1128
+ }
1129
+ }
1130
+ logger20.error(`${operationName} failed after ${this.retryConfig.maxRetries + 1} attempts`, {
1131
+ errorCode: lastError?.code,
1132
+ errorMessage: lastError?.message,
1133
+ duration: Date.now() - startTime,
1134
+ ...context
1135
+ });
1136
+ throw lastError;
1137
+ }
1138
+ /**
1139
+ * Convert any error to a ClientApiError
1140
+ */
1141
+ convertToClientApiError(error, operationName, context) {
1142
+ const errorContext = { operation: operationName, ...context };
1143
+ if (error instanceof ClientApiError) {
1144
+ return error;
1145
+ }
1146
+ if (error.response) {
1147
+ const { status, statusText, data, headers } = error.response;
1148
+ return createHttpError(status, statusText, data, {
1149
+ ...errorContext,
1150
+ headers,
1151
+ url: error.config?.url
1152
+ });
1153
+ }
1154
+ if (error.request) {
1155
+ return createNetworkError(error, {
1156
+ ...errorContext,
1157
+ url: error.config?.url,
1158
+ method: error.config?.method
1159
+ });
1160
+ }
1161
+ return createNetworkError(error, errorContext);
1162
+ }
1163
+ /**
1164
+ * Wrapper for HTTP GET operations
1165
+ */
1166
+ async get(url, options, context) {
1167
+ return this.executeWithRetry(
1168
+ () => this.api.httpGet(url, options),
1169
+ "GET",
1170
+ { url, ...context }
1171
+ );
1172
+ }
1173
+ /**
1174
+ * Wrapper for HTTP POST operations
1175
+ */
1176
+ async post(url, data, options, context) {
1177
+ return this.executeWithRetry(
1178
+ () => this.api.httpPost(url, data, options),
1179
+ "POST",
1180
+ { url, hasData: !!data, ...context }
1181
+ );
1182
+ }
1183
+ /**
1184
+ * Wrapper for HTTP PUT operations
1185
+ */
1186
+ async put(url, data, options, context) {
1187
+ return this.executeWithRetry(
1188
+ () => this.api.httpPut(url, data, options),
1189
+ "PUT",
1190
+ { url, hasData: !!data, ...context }
1191
+ );
1192
+ }
1193
+ /**
1194
+ * Wrapper for HTTP DELETE operations
1195
+ */
1196
+ async delete(url, options, context) {
1197
+ return this.executeWithRetry(
1198
+ () => this.api.httpDelete(url, options),
1199
+ "DELETE",
1200
+ { url, ...context }
1201
+ );
1202
+ }
1203
+ /**
1204
+ * Update retry configuration
1205
+ */
1206
+ updateRetryConfig(newConfig) {
1207
+ Object.assign(this.retryConfig, newConfig);
1208
+ }
1209
+ /**
1210
+ * Get current retry configuration
1211
+ */
1212
+ getRetryConfig() {
1213
+ return { ...this.retryConfig };
1214
+ }
1215
+ };
537
1216
  export {
1217
+ AuthenticationError,
1218
+ AuthorizationError,
1219
+ ClientApiError,
1220
+ ConfigurationError,
1221
+ ConflictError,
1222
+ HttpError,
1223
+ HttpWrapper,
1224
+ NetworkError,
1225
+ NotFoundError,
1226
+ ParseError,
1227
+ PayloadTooLargeError,
1228
+ RateLimitError,
1229
+ ServerError,
1230
+ TimeoutError,
1231
+ ValidationError,
1232
+ calculateRetryDelay3 as calculateRetryDelay,
538
1233
  createCItemApi,
1234
+ createHttpError,
539
1235
  createInstance,
540
1236
  createInstanceFactory,
1237
+ createNetworkError,
541
1238
  createPItemApi,
542
1239
  createRegistry,
543
- createRegistryFactory
1240
+ createRegistryFactory,
1241
+ enhanceError3 as enhanceError,
1242
+ executeErrorHandler,
1243
+ executeWithRetry,
1244
+ getRetryConfig,
1245
+ isClientApiError,
1246
+ isRetryableError,
1247
+ shouldRetryError3 as shouldRetryError
544
1248
  };
545
1249
  //# sourceMappingURL=index.js.map