@plyaz/api 1.6.7 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -9148,6 +9148,9 @@ var UnifiedDebugger = class _UnifiedDebugger {
9148
9148
  performanceMode = "minimal";
9149
9149
  trackAllProperties = true;
9150
9150
  // If false, uses TRACKED_PROPERTIES filter
9151
+ // Debug report control - disabled by default, enable via config:
9152
+ // createApiClient({ debugEvents: { comprehensiveReport: true } })
9153
+ comprehensiveReportEnabled = false;
9151
9154
  // Tracking configuration from API config
9152
9155
  trackingConfig = {};
9153
9156
  // Configurable limits
@@ -9576,8 +9579,14 @@ var UnifiedDebugger = class _UnifiedDebugger {
9576
9579
  }
9577
9580
  /**
9578
9581
  * Log comprehensive report to console
9582
+ *
9583
+ * Controlled via API config: debugEvents.comprehensiveReport = true
9584
+ * Or programmatically via setComprehensiveReportEnabled(true)
9579
9585
  */
9580
9586
  async logComprehensiveReport() {
9587
+ if (!this.comprehensiveReportEnabled) {
9588
+ return;
9589
+ }
9581
9590
  try {
9582
9591
  const presetReport = this.getPresetChangeReport();
9583
9592
  if (presetReport) {
@@ -9599,6 +9608,20 @@ var UnifiedDebugger = class _UnifiedDebugger {
9599
9608
  throw error;
9600
9609
  }
9601
9610
  }
9611
+ /**
9612
+ * Enable or disable comprehensive debug report logging
9613
+ *
9614
+ * Typically configured via API config: debugEvents.comprehensiveReport
9615
+ */
9616
+ setComprehensiveReportEnabled(enabled) {
9617
+ this.comprehensiveReportEnabled = enabled;
9618
+ }
9619
+ /**
9620
+ * Get current comprehensive report enabled state
9621
+ */
9622
+ getComprehensiveReportEnabled() {
9623
+ return this.comprehensiveReportEnabled;
9624
+ }
9602
9625
  /**
9603
9626
  * Get debug report (alias for generateDebugReport for API consistency)
9604
9627
  */
@@ -16174,6 +16197,11 @@ var ClientEventManager = class _ClientEventManager {
16174
16197
  this.config.configOverride.eventScopes ??= [...api.EVENT_SCOPES];
16175
16198
  }
16176
16199
  eventManager.setEventScopes(this.config.configOverride.eventScopes);
16200
+ if (this.config.debugEvents?.comprehensiveReport !== void 0) {
16201
+ getUnifiedDebugger().setComprehensiveReportEnabled(
16202
+ this.config.debugEvents.comprehensiveReport
16203
+ );
16204
+ }
16177
16205
  this.setupEventHandlers();
16178
16206
  }
16179
16207
  static {
@@ -16831,6 +16859,9 @@ var ClientEventManager = class _ClientEventManager {
16831
16859
  const id = setInterval(() => this.getDebugInfo(), interval);
16832
16860
  this.monitoringState.intervals.push(id);
16833
16861
  }
16862
+ if (debugConfig?.comprehensiveReport !== void 0) {
16863
+ getUnifiedDebugger().setComprehensiveReportEnabled(debugConfig.comprehensiveReport);
16864
+ }
16834
16865
  }
16835
16866
  /**
16836
16867
  * Stop monitoring
@@ -21623,7 +21654,7 @@ function createOnErrorHandler(handlers, clearTemporaryOverrides2, clearOnComplet
21623
21654
  const apiError = new ApiPackageError(
21624
21655
  "request.failed",
21625
21656
  api.PACKAGE_STATUS_CODES.REQUEST_FAILED,
21626
- error.status ? `HTTP_${error.status}` : api.API_ERROR_CODES.NETWORK_ERROR,
21657
+ error.status ? errors$1.getErrorCodeByStatus(error.status) ?? api.API_ERROR_CODES.CLIENT_ERROR : api.API_ERROR_CODES.NETWORK_ERROR,
21627
21658
  {
21628
21659
  cause: error,
21629
21660
  context: {
@@ -22249,6 +22280,546 @@ function applyQualityBasedConfiguration(resolvedConfig, quality, networkAware, n
22249
22280
  }
22250
22281
  }
22251
22282
  __name(applyQualityBasedConfiguration, "applyQualityBasedConfiguration");
22283
+ var PROGRESS_CHUNK_SIZE_MULTIPLIER = 64;
22284
+ var UPLOAD_CONSTANTS = {
22285
+ DEFAULT_CHUNK_SIZE: PROGRESS_CHUNK_SIZE_MULTIPLIER * config.NUMBER_SYSTEM.BYTES_PER_KB,
22286
+ DEFAULT_THROTTLE_MS: config.TIME_CONSTANTS.HUNDRED_MS,
22287
+ DEFAULT_CONTENT_TYPE: "application/octet-stream",
22288
+ DEFAULT_TIMEOUT: config.TIME_CONSTANTS.TWO_MINUTES,
22289
+ DEFAULT_RETRY_DELAY: config.RETRY_DELAYS.SHORT,
22290
+ DEFAULT_RETRY_BACKOFF: config.RETRY_BACKOFF.MEDIUM,
22291
+ DEFAULT_RETRY_MAX_DELAY: config.RETRY_DELAYS.MAX,
22292
+ PROGRESS_PERCENTAGE_THRESHOLD: config.NUMERIC_CONSTANTS.FIVE,
22293
+ FULL_PERCENTAGE: config.MATH_CONSTANTS.PERCENTAGE_MAX,
22294
+ HTTPS_DEFAULT_PORT: config.TIME_CONSTANTS.HTTPS_PORT,
22295
+ HTTP_DEFAULT_PORT: config.TIME_CONSTANTS.HTTP_PORT,
22296
+ /** Max server error status code (exclusive boundary for 5xx range) */
22297
+ MAX_SERVER_ERROR_STATUS: 600
22298
+ };
22299
+ var RETRYABLE_ERROR_CODES = [
22300
+ "ETIMEDOUT",
22301
+ "ECONNRESET",
22302
+ "ECONNREFUSED",
22303
+ "ENOTFOUND",
22304
+ "ENETUNREACH",
22305
+ "EAI_AGAIN"
22306
+ ];
22307
+ var RETRYABLE_MESSAGE_PATTERNS = [
22308
+ "timeout",
22309
+ "timed out",
22310
+ "network",
22311
+ "econnreset",
22312
+ "econnrefused",
22313
+ "etimedout",
22314
+ "service unavailable",
22315
+ "rate limit",
22316
+ "too many requests"
22317
+ ];
22318
+
22319
+ // src/api/upload/config.ts
22320
+ function extractGlobalHeaders(globalConfig) {
22321
+ const globalHeaders = {};
22322
+ if (!globalConfig.headers || typeof globalConfig.headers !== "object") {
22323
+ return globalHeaders;
22324
+ }
22325
+ if (!("presets" in globalConfig.headers) && !("static" in globalConfig.headers)) {
22326
+ Object.entries(globalConfig.headers).forEach(([key, value]) => {
22327
+ if (typeof value === "string") {
22328
+ globalHeaders[key] = value;
22329
+ }
22330
+ });
22331
+ return globalHeaders;
22332
+ }
22333
+ if ("static" in globalConfig.headers) {
22334
+ const staticHeaders = globalConfig.headers.static;
22335
+ if (staticHeaders) {
22336
+ Object.entries(staticHeaders).forEach(([key, value]) => {
22337
+ if (typeof value === "string") {
22338
+ globalHeaders[key] = value;
22339
+ }
22340
+ });
22341
+ }
22342
+ }
22343
+ return globalHeaders;
22344
+ }
22345
+ __name(extractGlobalHeaders, "extractGlobalHeaders");
22346
+ function mergeRetryConfig(optionRetry, globalRetry) {
22347
+ if (optionRetry !== void 0) return optionRetry;
22348
+ if (globalRetry !== void 0) return globalRetry;
22349
+ return false;
22350
+ }
22351
+ __name(mergeRetryConfig, "mergeRetryConfig");
22352
+ function buildLocalConfig(options) {
22353
+ return {
22354
+ headers: options.headers ?? {},
22355
+ timeout: options.timeout ?? UPLOAD_CONSTANTS.DEFAULT_TIMEOUT,
22356
+ baseURL: options.baseURL,
22357
+ retry: options.retry ?? false,
22358
+ onError: options.onError,
22359
+ withCredentials: options.withCredentials ?? false
22360
+ };
22361
+ }
22362
+ __name(buildLocalConfig, "buildLocalConfig");
22363
+ function getMergedConfig(options) {
22364
+ if (options.useGlobalConfig === false) {
22365
+ return buildLocalConfig(options);
22366
+ }
22367
+ const globalConfig = getGlobalConfig();
22368
+ const globalHeaders = extractGlobalHeaders(globalConfig);
22369
+ return {
22370
+ headers: { ...globalHeaders, ...options.headers ?? {} },
22371
+ timeout: options.timeout ?? globalConfig.timeout ?? UPLOAD_CONSTANTS.DEFAULT_TIMEOUT,
22372
+ baseURL: options.baseURL ?? globalConfig.baseURL,
22373
+ retry: mergeRetryConfig(options.retry, globalConfig.retry),
22374
+ onError: options.onError,
22375
+ withCredentials: options.withCredentials ?? globalConfig.withCredentials ?? false
22376
+ };
22377
+ }
22378
+ __name(getMergedConfig, "getMergedConfig");
22379
+ function checkRetryableFlag(error) {
22380
+ if (typeof error.isRetryable === "function") return error.isRetryable();
22381
+ if (typeof error.isRetryable === "boolean") return error.isRetryable;
22382
+ if (typeof error.retryable === "boolean") return error.retryable;
22383
+ return void 0;
22384
+ }
22385
+ __name(checkRetryableFlag, "checkRetryableFlag");
22386
+ function isRetryableStatus(status) {
22387
+ if (status === void 0) return false;
22388
+ if (status === config.HTTP_STATUS.TOO_MANY_REQUESTS) return true;
22389
+ return status >= config.HTTP_STATUS.INTERNAL_SERVER_ERROR && status < UPLOAD_CONSTANTS.MAX_SERVER_ERROR_STATUS;
22390
+ }
22391
+ __name(isRetryableStatus, "isRetryableStatus");
22392
+ function hasRetryableErrorCode(error) {
22393
+ return Boolean(
22394
+ error.code && RETRYABLE_ERROR_CODES.includes(error.code)
22395
+ );
22396
+ }
22397
+ __name(hasRetryableErrorCode, "hasRetryableErrorCode");
22398
+ function hasRetryableMessage(error) {
22399
+ const message = error.message?.toLowerCase() ?? "";
22400
+ return RETRYABLE_MESSAGE_PATTERNS.some((pattern) => message.includes(pattern));
22401
+ }
22402
+ __name(hasRetryableMessage, "hasRetryableMessage");
22403
+ function isRetryableError(error, status) {
22404
+ if (!error) return false;
22405
+ const errorWithRetryable = error;
22406
+ const flagResult = checkRetryableFlag(errorWithRetryable);
22407
+ if (flagResult !== void 0) return flagResult;
22408
+ if (hasRetryableErrorCode(errorWithRetryable)) return true;
22409
+ if (hasRetryableMessage(error)) return true;
22410
+ const httpStatus = status ?? errorWithRetryable.statusCode;
22411
+ return isRetryableStatus(httpStatus);
22412
+ }
22413
+ __name(isRetryableError, "isRetryableError");
22414
+ function calculateRetryDelay(attempt, config) {
22415
+ const delay = config.delay ?? UPLOAD_CONSTANTS.DEFAULT_RETRY_DELAY;
22416
+ const backoff = config.backoff ?? UPLOAD_CONSTANTS.DEFAULT_RETRY_BACKOFF;
22417
+ const maxDelay = config.maxDelay ?? UPLOAD_CONSTANTS.DEFAULT_RETRY_MAX_DELAY;
22418
+ const calculatedDelay = delay * Math.pow(backoff, attempt);
22419
+ return Math.min(calculatedDelay, maxDelay);
22420
+ }
22421
+ __name(calculateRetryDelay, "calculateRetryDelay");
22422
+ function notifyRetryError(params) {
22423
+ const { ctx, message, status, statusText, cause } = params;
22424
+ if (!ctx.config.onError) return;
22425
+ ctx.config.onError({
22426
+ message,
22427
+ status,
22428
+ statusText,
22429
+ cause,
22430
+ retryable: true,
22431
+ attempt: ctx.attempt,
22432
+ maxAttempts: ctx.maxAttempts
22433
+ });
22434
+ }
22435
+ __name(notifyRetryError, "notifyRetryError");
22436
+ function notifyFinalError(ctx, error) {
22437
+ if (!ctx.config.onError) return;
22438
+ ctx.config.onError({
22439
+ message: error.message,
22440
+ cause: error,
22441
+ retryable: false,
22442
+ attempt: ctx.attempt,
22443
+ maxAttempts: ctx.maxAttempts
22444
+ });
22445
+ }
22446
+ __name(notifyFinalError, "notifyFinalError");
22447
+ function shouldRetryResult(result, config, attempt, maxAttempts) {
22448
+ if (result.success) return false;
22449
+ if (!config.retry) return false;
22450
+ if (attempt >= maxAttempts - 1) return false;
22451
+ return isRetryableError(new Error(result.statusText ?? "Upload failed"), result.status);
22452
+ }
22453
+ __name(shouldRetryResult, "shouldRetryResult");
22454
+ function shouldRetryError(error, config, attempt, maxAttempts) {
22455
+ if (!config.retry) return false;
22456
+ if (attempt >= maxAttempts - 1) return false;
22457
+ return isRetryableError(error);
22458
+ }
22459
+ __name(shouldRetryError, "shouldRetryError");
22460
+ async function handleRetryDelay(attempt, config) {
22461
+ await sleep(calculateRetryDelay(attempt, config));
22462
+ }
22463
+ __name(handleRetryDelay, "handleRetryDelay");
22464
+ function resolveUrl(url, baseURL) {
22465
+ if (url.startsWith("http://") || url.startsWith("https://")) {
22466
+ return url;
22467
+ }
22468
+ if (!baseURL) {
22469
+ return url;
22470
+ }
22471
+ const base = baseURL.replace(/\/$/, "");
22472
+ const path = url.startsWith("/") ? url : `/${url}`;
22473
+ return `${base}${path}`;
22474
+ }
22475
+ __name(resolveUrl, "resolveUrl");
22476
+ function normalizeData(data) {
22477
+ if (Buffer.isBuffer(data)) return data;
22478
+ if (data instanceof Uint8Array) return data;
22479
+ if (data instanceof ArrayBuffer) return new Uint8Array(data);
22480
+ throw new ApiPackageError(
22481
+ "Blob data type is only supported in browser environment",
22482
+ void 0,
22483
+ errors.API_ERROR_CODES.VALIDATION_ERROR
22484
+ );
22485
+ }
22486
+ __name(normalizeData, "normalizeData");
22487
+ function createUploadState(totalSize) {
22488
+ const now2 = Date.now();
22489
+ return {
22490
+ status: "uploading",
22491
+ startTime: now2,
22492
+ bytesUploaded: 0,
22493
+ totalBytes: totalSize,
22494
+ lastProgressTime: now2,
22495
+ lastBytesUploaded: 0
22496
+ };
22497
+ }
22498
+ __name(createUploadState, "createUploadState");
22499
+ function calculateProgress(state) {
22500
+ const now2 = Date.now();
22501
+ const timeDelta = (now2 - state.lastProgressTime) / config.TIME_CONSTANTS.SECOND;
22502
+ const bytesDelta = state.bytesUploaded - state.lastBytesUploaded;
22503
+ const speed = timeDelta > 0 ? bytesDelta / timeDelta : 0;
22504
+ const percentage2 = Math.round(
22505
+ state.bytesUploaded / state.totalBytes * UPLOAD_CONSTANTS.FULL_PERCENTAGE
22506
+ );
22507
+ const remainingBytes = state.totalBytes - state.bytesUploaded;
22508
+ return {
22509
+ loaded: state.bytesUploaded,
22510
+ total: state.totalBytes,
22511
+ percentage: percentage2,
22512
+ speed: speed > 0 ? speed : void 0,
22513
+ estimatedTimeRemaining: speed > 0 ? remainingBytes / speed : void 0
22514
+ };
22515
+ }
22516
+ __name(calculateProgress, "calculateProgress");
22517
+ function emitFinalProgress(onProgress, totalSize, startTime) {
22518
+ if (!onProgress) return;
22519
+ const elapsed = (Date.now() - startTime) / config.TIME_CONSTANTS.SECOND;
22520
+ onProgress({
22521
+ loaded: totalSize,
22522
+ total: totalSize,
22523
+ percentage: UPLOAD_CONSTANTS.FULL_PERCENTAGE,
22524
+ speed: elapsed > 0 ? totalSize / elapsed : void 0,
22525
+ estimatedTimeRemaining: 0
22526
+ });
22527
+ }
22528
+ __name(emitFinalProgress, "emitFinalProgress");
22529
+ function shouldEmitProgress(state, totalSize, throttleMs) {
22530
+ const now2 = Date.now();
22531
+ const timeSinceLastProgress = now2 - state.lastProgressTime;
22532
+ const currentPct = Math.round(
22533
+ state.bytesUploaded / totalSize * UPLOAD_CONSTANTS.FULL_PERCENTAGE
22534
+ );
22535
+ const lastPct = Math.round(
22536
+ state.lastBytesUploaded / totalSize * UPLOAD_CONSTANTS.FULL_PERCENTAGE
22537
+ );
22538
+ return timeSinceLastProgress >= throttleMs || currentPct - lastPct >= UPLOAD_CONSTANTS.PROGRESS_PERCENTAGE_THRESHOLD;
22539
+ }
22540
+ __name(shouldEmitProgress, "shouldEmitProgress");
22541
+ function parseNodeHeaders(headers2) {
22542
+ const result = {};
22543
+ for (const [key, value] of Object.entries(headers2)) {
22544
+ if (value !== void 0) {
22545
+ result[key] = Array.isArray(value) ? value.join(", ") : value;
22546
+ }
22547
+ }
22548
+ return result;
22549
+ }
22550
+ __name(parseNodeHeaders, "parseNodeHeaders");
22551
+
22552
+ // src/api/upload/node.ts
22553
+ var createTimeoutError = /* @__PURE__ */ __name((url) => new ApiPackageError("Upload timed out", void 0, errors.API_ERROR_CODES.REQUEST_TIMEOUT, {
22554
+ context: { url }
22555
+ }), "createTimeoutError");
22556
+ var createAbortError = /* @__PURE__ */ __name((url) => new ApiPackageError("Upload aborted", void 0, errors.API_ERROR_CODES.REQUEST_ABORTED, {
22557
+ context: { url }
22558
+ }), "createAbortError");
22559
+ var normalizeError = /* @__PURE__ */ __name((error) => error instanceof Error ? error : new ApiPackageError(String(error), void 0, errors.API_ERROR_CODES.UNKNOWN_ERROR), "normalizeError");
22560
+ async function uploadOnce(options, config$1, resolvedUrl) {
22561
+ const {
22562
+ data,
22563
+ method = "PUT",
22564
+ contentType = UPLOAD_CONSTANTS.DEFAULT_CONTENT_TYPE,
22565
+ onProgress,
22566
+ abortSignal
22567
+ } = options;
22568
+ const chunkSize = options.chunkSize ?? UPLOAD_CONSTANTS.DEFAULT_CHUNK_SIZE;
22569
+ const throttleMs = options.throttleMs ?? UPLOAD_CONSTANTS.DEFAULT_THROTTLE_MS;
22570
+ const { headers: mergedHeaders, timeout } = config$1;
22571
+ const buffer = normalizeData(data);
22572
+ const totalSize = buffer.length;
22573
+ const parsedUrl = new URL(resolvedUrl);
22574
+ const isHttps = parsedUrl.protocol === "https:";
22575
+ const httpModule = await (isHttps ? import('https') : import('http'));
22576
+ const state = createUploadState(totalSize);
22577
+ return new Promise((resolve, reject) => {
22578
+ let timeoutId;
22579
+ if (timeout > 0) timeoutId = setTimeout(() => reject(createTimeoutError(resolvedUrl)), timeout);
22580
+ const clearUploadTimeout = /* @__PURE__ */ __name(() => {
22581
+ if (timeoutId) {
22582
+ clearTimeout(timeoutId);
22583
+ timeoutId = void 0;
22584
+ }
22585
+ }, "clearUploadTimeout");
22586
+ onProgress?.({ loaded: 0, total: totalSize, percentage: 0 });
22587
+ const requestOptions = {
22588
+ hostname: parsedUrl.hostname,
22589
+ port: parsedUrl.port || (isHttps ? UPLOAD_CONSTANTS.HTTPS_DEFAULT_PORT : UPLOAD_CONSTANTS.HTTP_DEFAULT_PORT),
22590
+ path: parsedUrl.pathname + parsedUrl.search,
22591
+ method,
22592
+ headers: {
22593
+ "Content-Type": contentType,
22594
+ "Content-Length": totalSize.toString(),
22595
+ ...mergedHeaders
22596
+ }
22597
+ };
22598
+ const req = httpModule.request(requestOptions, (res) => {
22599
+ let responseData = "";
22600
+ res.on("data", (chunk) => {
22601
+ responseData += chunk;
22602
+ });
22603
+ res.on("end", () => {
22604
+ clearUploadTimeout();
22605
+ const success = res.statusCode !== void 0 && res.statusCode >= config.HTTP_STATUS.OK && res.statusCode < config.HTTP_STATUS.MULTIPLE_CHOICES;
22606
+ if (success) emitFinalProgress(onProgress, totalSize, state.startTime);
22607
+ resolve({
22608
+ status: res.statusCode ?? 0,
22609
+ statusText: res.statusMessage ?? "",
22610
+ data: responseData || void 0,
22611
+ headers: parseNodeHeaders(res.headers),
22612
+ success
22613
+ });
22614
+ });
22615
+ });
22616
+ if (abortSignal)
22617
+ abortSignal.addEventListener("abort", () => {
22618
+ clearUploadTimeout();
22619
+ req.destroy();
22620
+ state.status = "aborted";
22621
+ reject(createAbortError(resolvedUrl));
22622
+ });
22623
+ req.on("error", (error) => {
22624
+ clearUploadTimeout();
22625
+ state.status = "failed";
22626
+ state.error = error;
22627
+ reject(error);
22628
+ });
22629
+ let offset = 0;
22630
+ const writeNextChunk = /* @__PURE__ */ __name(() => {
22631
+ while (offset < totalSize) {
22632
+ const end = Math.min(offset + chunkSize, totalSize);
22633
+ const canContinue = req.write(buffer.subarray(offset, end));
22634
+ state.bytesUploaded = end;
22635
+ offset = end;
22636
+ if (onProgress && shouldEmitProgress(state, totalSize, throttleMs)) {
22637
+ onProgress(calculateProgress(state));
22638
+ state.lastProgressTime = Date.now();
22639
+ state.lastBytesUploaded = state.bytesUploaded;
22640
+ }
22641
+ if (!canContinue) {
22642
+ req.once("drain", writeNextChunk);
22643
+ return;
22644
+ }
22645
+ }
22646
+ state.status = "completed";
22647
+ req.end();
22648
+ }, "writeNextChunk");
22649
+ writeNextChunk();
22650
+ });
22651
+ }
22652
+ __name(uploadOnce, "uploadOnce");
22653
+ async function uploadWithProgressNode(options) {
22654
+ const config = getMergedConfig(options);
22655
+ const resolvedUrl = resolveUrl(options.url, config.baseURL);
22656
+ const maxAttempts = config.retry ? (config.retry.attempts ?? 0) + 1 : 1;
22657
+ let lastError;
22658
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
22659
+ const ctx = { config, maxAttempts, attempt };
22660
+ try {
22661
+ const result = await uploadOnce(options, config, resolvedUrl);
22662
+ if (shouldRetryResult(result, config, attempt, maxAttempts)) {
22663
+ notifyRetryError({
22664
+ ctx,
22665
+ message: `Upload failed: ${result.status}`,
22666
+ status: result.status,
22667
+ statusText: result.statusText
22668
+ });
22669
+ await handleRetryDelay(attempt, config.retry);
22670
+ continue;
22671
+ }
22672
+ return { ...result, attempts: attempt };
22673
+ } catch (error) {
22674
+ lastError = normalizeError(error);
22675
+ if (shouldRetryError(lastError, config, attempt, maxAttempts)) {
22676
+ notifyRetryError({ ctx, message: lastError.message, cause: lastError });
22677
+ await handleRetryDelay(attempt, config.retry);
22678
+ continue;
22679
+ }
22680
+ notifyFinalError(ctx, lastError);
22681
+ throw lastError;
22682
+ }
22683
+ }
22684
+ throw lastError ?? new ApiPackageError(
22685
+ "Upload failed after all retry attempts",
22686
+ void 0,
22687
+ errors.API_ERROR_CODES.NETWORK_ERROR
22688
+ );
22689
+ }
22690
+ __name(uploadWithProgressNode, "uploadWithProgressNode");
22691
+ var normalizeError2 = /* @__PURE__ */ __name((error) => error instanceof Error ? error : new ApiPackageError(String(error), void 0, errors.API_ERROR_CODES.UNKNOWN_ERROR), "normalizeError");
22692
+ async function uploadOnce2(options, config$1, resolvedUrl) {
22693
+ const {
22694
+ data,
22695
+ method = "PUT",
22696
+ contentType = UPLOAD_CONSTANTS.DEFAULT_CONTENT_TYPE,
22697
+ onProgress,
22698
+ abortSignal
22699
+ } = options;
22700
+ const { headers: mergedHeaders, timeout, withCredentials } = config$1;
22701
+ return new Promise((resolve, reject) => {
22702
+ const xhr = new XMLHttpRequest();
22703
+ const startTime = Date.now();
22704
+ if (timeout > 0) xhr.timeout = timeout;
22705
+ xhr.addEventListener(
22706
+ "timeout",
22707
+ () => reject(
22708
+ new ApiPackageError("Upload timed out", void 0, errors.API_ERROR_CODES.REQUEST_TIMEOUT, {
22709
+ context: { url: resolvedUrl }
22710
+ })
22711
+ )
22712
+ );
22713
+ xhr.upload.addEventListener("progress", (event) => {
22714
+ if (!event.lengthComputable || !onProgress) return;
22715
+ const elapsed = (Date.now() - startTime) / config.TIME_CONSTANTS.SECOND;
22716
+ const speed = elapsed > 0 ? event.loaded / elapsed : 0;
22717
+ const remaining = event.total - event.loaded;
22718
+ onProgress({
22719
+ loaded: event.loaded,
22720
+ total: event.total,
22721
+ percentage: Math.round(event.loaded / event.total * UPLOAD_CONSTANTS.FULL_PERCENTAGE),
22722
+ speed,
22723
+ estimatedTimeRemaining: speed > 0 ? remaining / speed : void 0
22724
+ });
22725
+ });
22726
+ xhr.addEventListener("load", () => {
22727
+ const success = xhr.status >= config.HTTP_STATUS.OK && xhr.status < config.HTTP_STATUS.MULTIPLE_CHOICES;
22728
+ const responseHeaders = {};
22729
+ const headerLines = xhr.getAllResponseHeaders().trim().split("\n");
22730
+ for (const line of headerLines) {
22731
+ const [key, ...valueParts] = line.split(":");
22732
+ if (key) responseHeaders[key.trim().toLowerCase()] = valueParts.join(":").trim();
22733
+ }
22734
+ resolve({
22735
+ status: xhr.status,
22736
+ statusText: xhr.statusText,
22737
+ data: xhr.responseText || void 0,
22738
+ headers: responseHeaders,
22739
+ success
22740
+ });
22741
+ });
22742
+ xhr.addEventListener(
22743
+ "error",
22744
+ () => reject(
22745
+ new ApiPackageError(
22746
+ `Upload failed: ${xhr.statusText || "Network error"}`,
22747
+ void 0,
22748
+ errors.API_ERROR_CODES.NETWORK_ERROR,
22749
+ { context: { url: resolvedUrl, statusText: xhr.statusText } }
22750
+ )
22751
+ )
22752
+ );
22753
+ xhr.addEventListener(
22754
+ "abort",
22755
+ () => reject(
22756
+ new ApiPackageError("Upload aborted", void 0, errors.API_ERROR_CODES.REQUEST_ABORTED, {
22757
+ context: { url: resolvedUrl }
22758
+ })
22759
+ )
22760
+ );
22761
+ if (abortSignal) abortSignal.addEventListener("abort", () => xhr.abort());
22762
+ xhr.open(method, resolvedUrl);
22763
+ if (withCredentials) xhr.withCredentials = true;
22764
+ xhr.setRequestHeader("Content-Type", contentType);
22765
+ for (const [key, value] of Object.entries(mergedHeaders)) xhr.setRequestHeader(key, value);
22766
+ if (data instanceof Blob || data instanceof ArrayBuffer) {
22767
+ xhr.send(data);
22768
+ } else if (data instanceof Uint8Array) {
22769
+ xhr.send(new Uint8Array(data));
22770
+ } else {
22771
+ xhr.send(data);
22772
+ }
22773
+ });
22774
+ }
22775
+ __name(uploadOnce2, "uploadOnce");
22776
+ async function uploadWithProgressBrowser(options) {
22777
+ const config = getMergedConfig(options);
22778
+ const resolvedUrl = resolveUrl(options.url, config.baseURL);
22779
+ const maxAttempts = config.retry ? (config.retry.attempts ?? 0) + 1 : 1;
22780
+ let lastError;
22781
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
22782
+ const ctx = { config, maxAttempts, attempt };
22783
+ try {
22784
+ const result = await uploadOnce2(options, config, resolvedUrl);
22785
+ if (shouldRetryResult(result, config, attempt, maxAttempts)) {
22786
+ notifyRetryError({
22787
+ ctx,
22788
+ message: `Upload failed: ${result.status}`,
22789
+ status: result.status,
22790
+ statusText: result.statusText
22791
+ });
22792
+ await handleRetryDelay(attempt, config.retry);
22793
+ continue;
22794
+ }
22795
+ return { ...result, attempts: attempt };
22796
+ } catch (error) {
22797
+ lastError = normalizeError2(error);
22798
+ if (shouldRetryError(lastError, config, attempt, maxAttempts)) {
22799
+ notifyRetryError({ ctx, message: lastError.message, cause: lastError });
22800
+ await handleRetryDelay(attempt, config.retry);
22801
+ continue;
22802
+ }
22803
+ notifyFinalError(ctx, lastError);
22804
+ throw lastError;
22805
+ }
22806
+ }
22807
+ throw lastError ?? new ApiPackageError(
22808
+ "Upload failed after all retry attempts",
22809
+ void 0,
22810
+ errors.API_ERROR_CODES.NETWORK_ERROR
22811
+ );
22812
+ }
22813
+ __name(uploadWithProgressBrowser, "uploadWithProgressBrowser");
22814
+
22815
+ // src/api/upload/uploadWithProgress.ts
22816
+ async function uploadWithProgress(options) {
22817
+ if (isNode()) {
22818
+ return uploadWithProgressNode(options);
22819
+ }
22820
+ return uploadWithProgressBrowser(options);
22821
+ }
22822
+ __name(uploadWithProgress, "uploadWithProgress");
22252
22823
 
22253
22824
  // src/api/hooks/factories/defaults.ts
22254
22825
  var DEFAULT_QUERY_OPTIONS = {};
@@ -24396,13 +24967,13 @@ function isAbortError(error) {
24396
24967
  return message.includes("abort") || message.includes("cancel");
24397
24968
  }
24398
24969
  __name(isAbortError, "isAbortError");
24399
- function createAbortError(message = "Request aborted") {
24970
+ function createAbortError2(message = "Request aborted") {
24400
24971
  if (message === null || message === void 0) {
24401
24972
  return "Request aborted";
24402
24973
  }
24403
24974
  return message;
24404
24975
  }
24405
- __name(createAbortError, "createAbortError");
24976
+ __name(createAbortError2, "createAbortError");
24406
24977
 
24407
24978
  // src/api/request/tracker.ts
24408
24979
  var RequestTracker = class {
@@ -24452,7 +25023,7 @@ var RequestTracker = class {
24452
25023
  controller.abort(reason);
24453
25024
  this.unregister(key);
24454
25025
  }
24455
- void abortRequest(key, createAbortError(reason ?? "Request aborted"));
25026
+ void abortRequest(key, createAbortError2(reason ?? "Request aborted"));
24456
25027
  }
24457
25028
  /**
24458
25029
  * Abort all requests in a group
@@ -24478,7 +25049,7 @@ var RequestTracker = class {
24478
25049
  });
24479
25050
  this.activeRequests.clear();
24480
25051
  this.requestGroups.clear();
24481
- void abortRequest("*", createAbortError(reason ?? "All requests aborted"));
25052
+ void abortRequest("*", createAbortError2(reason ?? "All requests aborted"));
24482
25053
  }
24483
25054
  /**
24484
25055
  * Get active request count
@@ -24535,14 +25106,14 @@ function useRequestCleanup() {
24535
25106
  }, "untrackRequest");
24536
25107
  const abortTracked = /* @__PURE__ */ __name((reason) => {
24537
25108
  requestKeys.current.forEach((key) => {
24538
- void abortRequest(key, createAbortError(reason ?? "Manual abort"));
25109
+ void abortRequest(key, createAbortError2(reason ?? "Manual abort"));
24539
25110
  });
24540
25111
  requestKeys.current.clear();
24541
25112
  }, "abortTracked");
24542
25113
  react.useEffect(() => {
24543
25114
  return () => {
24544
25115
  requestKeys.current.forEach((key) => {
24545
- void abortRequest(key, createAbortError("Component unmounted"));
25116
+ void abortRequest(key, createAbortError2("Component unmounted"));
24546
25117
  });
24547
25118
  requestKeys.current.clear();
24548
25119
  };
@@ -24563,14 +25134,14 @@ function useAbortableRequest(key) {
24563
25134
  controllerRef.current.abort("Component unmounted or dependency changed");
24564
25135
  requestTracker.unregister(key);
24565
25136
  }
24566
- void abortRequest(key, createAbortError("Request cancelled"));
25137
+ void abortRequest(key, createAbortError2("Request cancelled"));
24567
25138
  };
24568
25139
  }, [key]);
24569
25140
  const abort = /* @__PURE__ */ __name((reason) => {
24570
25141
  if (controllerRef.current) {
24571
25142
  controllerRef.current.abort(reason);
24572
25143
  }
24573
- void abortRequest(key, createAbortError(reason ?? "Request aborted by user"));
25144
+ void abortRequest(key, createAbortError2(reason ?? "Request aborted by user"));
24574
25145
  }, "abort");
24575
25146
  return {
24576
25147
  signal,
@@ -24632,9 +25203,9 @@ function setupRouteChangeCleanup(router, options = {}) {
24632
25203
  }
24633
25204
  const pattern = options.abortPattern ?? "*";
24634
25205
  if (options.preservePatterns && options.preservePatterns.length > 0) {
24635
- void abortRequest(pattern, createAbortError(`Route changed to ${url}`));
25206
+ void abortRequest(pattern, createAbortError2(`Route changed to ${url}`));
24636
25207
  } else {
24637
- void abortRequest(pattern, createAbortError(`Route changed to ${url}`));
25208
+ void abortRequest(pattern, createAbortError2(`Route changed to ${url}`));
24638
25209
  }
24639
25210
  }, "executeAbort");
24640
25211
  if (options.delay && options.delay > 0) {
@@ -24681,7 +25252,7 @@ function createRouteGuard(pattern = "*") {
24681
25252
  }, "enter"),
24682
25253
  leave: /* @__PURE__ */ __name((reason) => {
24683
25254
  if (isActive) {
24684
- void abortRequest(pattern, createAbortError(reason ?? "Leaving route"));
25255
+ void abortRequest(pattern, createAbortError2(reason ?? "Leaving route"));
24685
25256
  isActive = false;
24686
25257
  }
24687
25258
  }, "leave"),
@@ -24713,7 +25284,7 @@ __name(createRouteScope, "createRouteScope");
24713
25284
 
24714
25285
  // src/api/request/utils.ts
24715
25286
  function abortByPattern(pattern, reason) {
24716
- void abortRequest(pattern, createAbortError(reason ?? `Requests matching ${pattern} aborted`));
25287
+ void abortRequest(pattern, createAbortError2(reason ?? `Requests matching ${pattern} aborted`));
24717
25288
  }
24718
25289
  __name(abortByPattern, "abortByPattern");
24719
25290
  function abortSearchRequests(reason) {
@@ -24731,25 +25302,25 @@ __name(abortAllRequests, "abortAllRequests");
24731
25302
  function createScopedAbort(scope) {
24732
25303
  return (key, reason) => {
24733
25304
  const fullKey = key.startsWith("/") ? `${scope}${key}` : `${scope}/${key}`;
24734
- void abortRequest(fullKey, createAbortError(reason ?? "Scoped request aborted"));
25305
+ void abortRequest(fullKey, createAbortError2(reason ?? "Scoped request aborted"));
24735
25306
  };
24736
25307
  }
24737
25308
  __name(createScopedAbort, "createScopedAbort");
24738
25309
  function createDebouncedAbort(delay = 300) {
24739
25310
  return debounce((key, reason) => {
24740
- void abortRequest(key, createAbortError(reason ?? "Debounced abort"));
25311
+ void abortRequest(key, createAbortError2(reason ?? "Debounced abort"));
24741
25312
  }, delay);
24742
25313
  }
24743
25314
  __name(createDebouncedAbort, "createDebouncedAbort");
24744
25315
  function createThrottledAbort(limit = 1e3) {
24745
25316
  return throttle((key, reason) => {
24746
- void abortRequest(key, createAbortError(reason ?? "Throttled abort"));
25317
+ void abortRequest(key, createAbortError2(reason ?? "Throttled abort"));
24747
25318
  }, limit);
24748
25319
  }
24749
25320
  __name(createThrottledAbort, "createThrottledAbort");
24750
25321
  async function requestWithTimeout(key, fetcher, timeoutMs) {
24751
25322
  const timeoutId = setTimeout(() => {
24752
- void abortRequest(key, createAbortError(`Request timeout after ${timeoutMs}ms`));
25323
+ void abortRequest(key, createAbortError2(`Request timeout after ${timeoutMs}ms`));
24753
25324
  }, timeoutMs);
24754
25325
  try {
24755
25326
  return await fetcher();
@@ -24762,7 +25333,7 @@ async function raceRequests(requests) {
24762
25333
  const abortLosers = /* @__PURE__ */ __name((winnerKey) => {
24763
25334
  requests.forEach((req) => {
24764
25335
  if (req.key !== winnerKey) {
24765
- void abortRequest(req.key, createAbortError("Lost race"));
25336
+ void abortRequest(req.key, createAbortError2("Lost race"));
24766
25337
  }
24767
25338
  });
24768
25339
  }, "abortLosers");
@@ -24783,7 +25354,7 @@ async function sequentialRequests(requests) {
24783
25354
  results.push(result);
24784
25355
  } catch (error) {
24785
25356
  for (let j = i + 1; j < requests.length; j++) {
24786
- void abortRequest(requests[j].key, createAbortError("Previous request in chain failed"));
25357
+ void abortRequest(requests[j].key, createAbortError2("Previous request in chain failed"));
24787
25358
  }
24788
25359
  throw error;
24789
25360
  }
@@ -27039,7 +27610,7 @@ exports.configConflictDetector = configConflictDetector;
27039
27610
  exports.configureForEnvironment = configureForEnvironment;
27040
27611
  exports.containsAny = containsAny;
27041
27612
  exports.convertEndpointsToFetchff = convertEndpointsToFetchff;
27042
- exports.createAbortError = createAbortError;
27613
+ exports.createAbortError = createAbortError2;
27043
27614
  exports.createAdaptiveResponse = createAdaptiveResponse;
27044
27615
  exports.createApiClient = createApiClient;
27045
27616
  exports.createCachePattern = createCachePattern;
@@ -27490,6 +28061,7 @@ exports.updateInfobipScheduledEmailStatuses = updateInfobipScheduledEmailStatuse
27490
28061
  exports.uploadFile = uploadFile;
27491
28062
  exports.uploadFileForScanning = uploadFileForScanning;
27492
28063
  exports.uploadFiles = uploadFiles;
28064
+ exports.uploadWithProgress = uploadWithProgress;
27493
28065
  exports.useAbortableRequest = useAbortableRequest;
27494
28066
  exports.useApiConfigConflicts = useApiConfigConflicts;
27495
28067
  exports.useApiDebugInfo = useApiDebugInfo;