@tinycloud/sdk-services 3.1.0-beta.6 → 3.1.0-beta.7

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.
@@ -108,11 +108,31 @@ function authRequiredError(service) {
108
108
  service
109
109
  };
110
110
  }
111
- function timeoutError(service) {
111
+ var RequestTimeoutError = class extends Error {
112
+ constructor(timeoutMs) {
113
+ super(`Request timed out after ${timeoutMs}ms.`);
114
+ this.name = "TimeoutError";
115
+ this.timeoutMs = timeoutMs;
116
+ }
117
+ };
118
+ function isRequestTimeoutError(error) {
119
+ return error instanceof RequestTimeoutError || error instanceof Error && error.name === "TimeoutError" && typeof error.timeoutMs === "number";
120
+ }
121
+ function timeoutError(service, timeoutMs, cause) {
122
+ if (timeoutMs === void 0) {
123
+ return {
124
+ code: ErrorCodes.TIMEOUT,
125
+ message: "Request timed out.",
126
+ service,
127
+ ...cause === void 0 ? {} : { cause }
128
+ };
129
+ }
112
130
  return {
113
131
  code: ErrorCodes.TIMEOUT,
114
- message: "Request timed out.",
115
- service
132
+ message: `Request timed out after ${timeoutMs}ms.`,
133
+ service,
134
+ ...cause === void 0 ? {} : { cause },
135
+ meta: { timeoutMs }
116
136
  };
117
137
  }
118
138
  function abortedError(service) {
@@ -167,6 +187,9 @@ function storageRejectionError(service, status, meta, responseText) {
167
187
  }
168
188
  function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
169
189
  if (error instanceof Error) {
190
+ if (isRequestTimeoutError(error)) {
191
+ return timeoutError(service, error.timeoutMs, error);
192
+ }
170
193
  if (error.name === "AbortError") {
171
194
  return abortedError(service);
172
195
  }
@@ -188,6 +211,7 @@ function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
188
211
  }
189
212
 
190
213
  // src/base/BaseService.ts
214
+ var MAX_TIMER_DELAY_MS = 2147483647;
191
215
  var BaseService = class {
192
216
  constructor() {
193
217
  /**
@@ -368,6 +392,64 @@ var BaseService = class {
368
392
  }
369
393
  return controller.signal;
370
394
  }
395
+ /**
396
+ * Create the abort signal for one request, bounded by the request timeout.
397
+ *
398
+ * The signal aborts when the service signs out, the context aborts, the
399
+ * caller's `signal` aborts, or the timeout elapses, whichever comes first.
400
+ * A timeout aborts with a {@link RequestTimeoutError} (`TimeoutError`), which
401
+ * `wrapError` maps to `ErrorCodes.TIMEOUT`; the other sources keep their own
402
+ * reason (normally `AbortError`, mapped to `ErrorCodes.ABORTED`).
403
+ *
404
+ * The timeout is `timeoutMs` when given, otherwise `config.timeout`. Only a
405
+ * positive, finite value (at most 2^31-1 ms) applies; `undefined`, `0`, and
406
+ * `Infinity` mean no timeout, so a per-call `0` opts out of a configured one.
407
+ *
408
+ * Callers must call `dispose()` once the response body has been consumed,
409
+ * which clears the timer and removes the listeners this adds to the
410
+ * long-lived service and context signals.
411
+ *
412
+ * @param signal - The caller's abort signal for this request
413
+ * @param timeoutMs - Per-request timeout override in milliseconds
414
+ */
415
+ createRequestSignal(signal, timeoutMs) {
416
+ const controller = new AbortController();
417
+ const detachers = [];
418
+ let timer;
419
+ const dispose = () => {
420
+ if (timer !== void 0) {
421
+ clearTimeout(timer);
422
+ timer = void 0;
423
+ }
424
+ for (const detach of detachers.splice(0)) {
425
+ detach();
426
+ }
427
+ };
428
+ const abort = (reason) => {
429
+ dispose();
430
+ controller.abort(reason);
431
+ };
432
+ const requestSignal = { signal: controller.signal, dispose };
433
+ const parents = [
434
+ this.abortController.signal,
435
+ this.context?.abortSignal,
436
+ signal
437
+ ].filter((parent) => parent !== void 0);
438
+ for (const parent of parents) {
439
+ if (parent.aborted) {
440
+ abort(parent.reason);
441
+ return requestSignal;
442
+ }
443
+ const onAbort = () => abort(parent.reason);
444
+ parent.addEventListener("abort", onAbort, { once: true });
445
+ detachers.push(() => parent.removeEventListener("abort", onAbort));
446
+ }
447
+ const timeout = timeoutMs ?? this._config.timeout;
448
+ if (typeof timeout === "number" && timeout > 0 && timeout <= MAX_TIMER_DELAY_MS) {
449
+ timer = setTimeout(() => abort(new RequestTimeoutError(timeout)), timeout);
450
+ }
451
+ return requestSignal;
452
+ }
371
453
  /**
372
454
  * Wrap an operation with error handling and telemetry.
373
455
  *
@@ -556,6 +638,7 @@ var SQLService = class extends BaseService {
556
638
  if (!this.requireAuth()) {
557
639
  return err(authRequiredError("sql"));
558
640
  }
641
+ const request = this.createRequestSignal(options?.signal);
559
642
  try {
560
643
  const body = {
561
644
  action: "query",
@@ -569,7 +652,7 @@ var SQLService = class extends BaseService {
569
652
  dbName,
570
653
  action,
571
654
  body,
572
- options?.signal
655
+ request.signal
573
656
  );
574
657
  if (!response.ok) {
575
658
  return this.handleErrorResponse(response, "query", dbName, [action]);
@@ -578,6 +661,8 @@ var SQLService = class extends BaseService {
578
661
  return ok(data);
579
662
  } catch (error) {
580
663
  return err(wrapError("sql", error));
664
+ } finally {
665
+ request.dispose();
581
666
  }
582
667
  });
583
668
  }
@@ -586,6 +671,7 @@ var SQLService = class extends BaseService {
586
671
  if (!this.requireAuth()) {
587
672
  return err(authRequiredError("sql"));
588
673
  }
674
+ const request = this.createRequestSignal(options?.signal);
589
675
  try {
590
676
  const body = {
591
677
  action: "execute",
@@ -606,7 +692,7 @@ var SQLService = class extends BaseService {
606
692
  dbName,
607
693
  requestedActions,
608
694
  body,
609
- options?.signal
695
+ request.signal
610
696
  );
611
697
  if (!response.ok) {
612
698
  return this.handleErrorResponse(response, "execute", dbName, requestedActions);
@@ -615,6 +701,8 @@ var SQLService = class extends BaseService {
615
701
  return ok(data);
616
702
  } catch (error) {
617
703
  return err(wrapError("sql", error));
704
+ } finally {
705
+ request.dispose();
618
706
  }
619
707
  });
620
708
  }
@@ -623,13 +711,14 @@ var SQLService = class extends BaseService {
623
711
  if (!this.requireAuth()) {
624
712
  return err(authRequiredError("sql"));
625
713
  }
714
+ const request = this.createRequestSignal(options?.signal);
626
715
  try {
627
716
  const requestedActions = this.actionsForSqlBatch(statements);
628
717
  const response = await this.invokeSQL(
629
718
  dbName,
630
719
  requestedActions,
631
720
  { action: "batch", statements },
632
- options?.signal
721
+ request.signal
633
722
  );
634
723
  if (!response.ok) {
635
724
  return this.handleErrorResponse(response, "batch", dbName, requestedActions);
@@ -638,6 +727,8 @@ var SQLService = class extends BaseService {
638
727
  return ok(data);
639
728
  } catch (error) {
640
729
  return err(wrapError("sql", error));
730
+ } finally {
731
+ request.dispose();
641
732
  }
642
733
  });
643
734
  }
@@ -646,12 +737,13 @@ var SQLService = class extends BaseService {
646
737
  if (!this.requireAuth()) {
647
738
  return err(authRequiredError("sql"));
648
739
  }
740
+ const request = this.createRequestSignal(options?.signal);
649
741
  try {
650
742
  const response = await this.invokeSQL(
651
743
  dbName,
652
744
  SQLAction.WRITE,
653
745
  { action: "execute_statement", name, params: params ?? [] },
654
- options?.signal
746
+ request.signal
655
747
  );
656
748
  if (!response.ok) {
657
749
  return this.handleErrorResponse(response, "executeStatement", dbName, [SQLAction.WRITE]);
@@ -660,6 +752,8 @@ var SQLService = class extends BaseService {
660
752
  return ok(data);
661
753
  } catch (error) {
662
754
  return err(wrapError("sql", error));
755
+ } finally {
756
+ request.dispose();
663
757
  }
664
758
  });
665
759
  }
@@ -668,12 +762,13 @@ var SQLService = class extends BaseService {
668
762
  if (!this.requireAuth()) {
669
763
  return err(authRequiredError("sql"));
670
764
  }
765
+ const request = this.createRequestSignal(options?.signal);
671
766
  try {
672
767
  const response = await this.invokeSQL(
673
768
  dbName,
674
769
  SQLAction.READ,
675
770
  { action: "export" },
676
- options?.signal
771
+ request.signal
677
772
  );
678
773
  if (!response.ok) {
679
774
  return this.handleErrorResponse(response, "export", dbName, [SQLAction.READ]);
@@ -687,6 +782,8 @@ var SQLService = class extends BaseService {
687
782
  return ok(text);
688
783
  } catch (error) {
689
784
  return err(wrapError("sql", error));
785
+ } finally {
786
+ request.dispose();
690
787
  }
691
788
  });
692
789
  }
@@ -777,7 +874,7 @@ var SQLService = class extends BaseService {
777
874
  "Content-Type": "application/json"
778
875
  },
779
876
  body: JSON.stringify(body),
780
- signal: this.combineSignals(signal)
877
+ signal
781
878
  });
782
879
  }
783
880
  actionForSql(sql, fallback) {