@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.
package/dist/sql/index.js CHANGED
@@ -79,11 +79,31 @@ function authRequiredError(service) {
79
79
  service
80
80
  };
81
81
  }
82
- function timeoutError(service) {
82
+ var RequestTimeoutError = class extends Error {
83
+ constructor(timeoutMs) {
84
+ super(`Request timed out after ${timeoutMs}ms.`);
85
+ this.name = "TimeoutError";
86
+ this.timeoutMs = timeoutMs;
87
+ }
88
+ };
89
+ function isRequestTimeoutError(error) {
90
+ return error instanceof RequestTimeoutError || error instanceof Error && error.name === "TimeoutError" && typeof error.timeoutMs === "number";
91
+ }
92
+ function timeoutError(service, timeoutMs, cause) {
93
+ if (timeoutMs === void 0) {
94
+ return {
95
+ code: ErrorCodes.TIMEOUT,
96
+ message: "Request timed out.",
97
+ service,
98
+ ...cause === void 0 ? {} : { cause }
99
+ };
100
+ }
83
101
  return {
84
102
  code: ErrorCodes.TIMEOUT,
85
- message: "Request timed out.",
86
- service
103
+ message: `Request timed out after ${timeoutMs}ms.`,
104
+ service,
105
+ ...cause === void 0 ? {} : { cause },
106
+ meta: { timeoutMs }
87
107
  };
88
108
  }
89
109
  function abortedError(service) {
@@ -138,6 +158,9 @@ function storageRejectionError(service, status, meta, responseText) {
138
158
  }
139
159
  function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
140
160
  if (error instanceof Error) {
161
+ if (isRequestTimeoutError(error)) {
162
+ return timeoutError(service, error.timeoutMs, error);
163
+ }
141
164
  if (error.name === "AbortError") {
142
165
  return abortedError(service);
143
166
  }
@@ -159,6 +182,7 @@ function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
159
182
  }
160
183
 
161
184
  // src/base/BaseService.ts
185
+ var MAX_TIMER_DELAY_MS = 2147483647;
162
186
  var BaseService = class {
163
187
  constructor() {
164
188
  /**
@@ -339,6 +363,64 @@ var BaseService = class {
339
363
  }
340
364
  return controller.signal;
341
365
  }
366
+ /**
367
+ * Create the abort signal for one request, bounded by the request timeout.
368
+ *
369
+ * The signal aborts when the service signs out, the context aborts, the
370
+ * caller's `signal` aborts, or the timeout elapses, whichever comes first.
371
+ * A timeout aborts with a {@link RequestTimeoutError} (`TimeoutError`), which
372
+ * `wrapError` maps to `ErrorCodes.TIMEOUT`; the other sources keep their own
373
+ * reason (normally `AbortError`, mapped to `ErrorCodes.ABORTED`).
374
+ *
375
+ * The timeout is `timeoutMs` when given, otherwise `config.timeout`. Only a
376
+ * positive, finite value (at most 2^31-1 ms) applies; `undefined`, `0`, and
377
+ * `Infinity` mean no timeout, so a per-call `0` opts out of a configured one.
378
+ *
379
+ * Callers must call `dispose()` once the response body has been consumed,
380
+ * which clears the timer and removes the listeners this adds to the
381
+ * long-lived service and context signals.
382
+ *
383
+ * @param signal - The caller's abort signal for this request
384
+ * @param timeoutMs - Per-request timeout override in milliseconds
385
+ */
386
+ createRequestSignal(signal, timeoutMs) {
387
+ const controller = new AbortController();
388
+ const detachers = [];
389
+ let timer;
390
+ const dispose = () => {
391
+ if (timer !== void 0) {
392
+ clearTimeout(timer);
393
+ timer = void 0;
394
+ }
395
+ for (const detach of detachers.splice(0)) {
396
+ detach();
397
+ }
398
+ };
399
+ const abort = (reason) => {
400
+ dispose();
401
+ controller.abort(reason);
402
+ };
403
+ const requestSignal = { signal: controller.signal, dispose };
404
+ const parents = [
405
+ this.abortController.signal,
406
+ this.context?.abortSignal,
407
+ signal
408
+ ].filter((parent) => parent !== void 0);
409
+ for (const parent of parents) {
410
+ if (parent.aborted) {
411
+ abort(parent.reason);
412
+ return requestSignal;
413
+ }
414
+ const onAbort = () => abort(parent.reason);
415
+ parent.addEventListener("abort", onAbort, { once: true });
416
+ detachers.push(() => parent.removeEventListener("abort", onAbort));
417
+ }
418
+ const timeout = timeoutMs ?? this._config.timeout;
419
+ if (typeof timeout === "number" && timeout > 0 && timeout <= MAX_TIMER_DELAY_MS) {
420
+ timer = setTimeout(() => abort(new RequestTimeoutError(timeout)), timeout);
421
+ }
422
+ return requestSignal;
423
+ }
342
424
  /**
343
425
  * Wrap an operation with error handling and telemetry.
344
426
  *
@@ -527,6 +609,7 @@ var SQLService = class extends BaseService {
527
609
  if (!this.requireAuth()) {
528
610
  return err(authRequiredError("sql"));
529
611
  }
612
+ const request = this.createRequestSignal(options?.signal);
530
613
  try {
531
614
  const body = {
532
615
  action: "query",
@@ -540,7 +623,7 @@ var SQLService = class extends BaseService {
540
623
  dbName,
541
624
  action,
542
625
  body,
543
- options?.signal
626
+ request.signal
544
627
  );
545
628
  if (!response.ok) {
546
629
  return this.handleErrorResponse(response, "query", dbName, [action]);
@@ -549,6 +632,8 @@ var SQLService = class extends BaseService {
549
632
  return ok(data);
550
633
  } catch (error) {
551
634
  return err(wrapError("sql", error));
635
+ } finally {
636
+ request.dispose();
552
637
  }
553
638
  });
554
639
  }
@@ -557,6 +642,7 @@ var SQLService = class extends BaseService {
557
642
  if (!this.requireAuth()) {
558
643
  return err(authRequiredError("sql"));
559
644
  }
645
+ const request = this.createRequestSignal(options?.signal);
560
646
  try {
561
647
  const body = {
562
648
  action: "execute",
@@ -577,7 +663,7 @@ var SQLService = class extends BaseService {
577
663
  dbName,
578
664
  requestedActions,
579
665
  body,
580
- options?.signal
666
+ request.signal
581
667
  );
582
668
  if (!response.ok) {
583
669
  return this.handleErrorResponse(response, "execute", dbName, requestedActions);
@@ -586,6 +672,8 @@ var SQLService = class extends BaseService {
586
672
  return ok(data);
587
673
  } catch (error) {
588
674
  return err(wrapError("sql", error));
675
+ } finally {
676
+ request.dispose();
589
677
  }
590
678
  });
591
679
  }
@@ -594,13 +682,14 @@ var SQLService = class extends BaseService {
594
682
  if (!this.requireAuth()) {
595
683
  return err(authRequiredError("sql"));
596
684
  }
685
+ const request = this.createRequestSignal(options?.signal);
597
686
  try {
598
687
  const requestedActions = this.actionsForSqlBatch(statements);
599
688
  const response = await this.invokeSQL(
600
689
  dbName,
601
690
  requestedActions,
602
691
  { action: "batch", statements },
603
- options?.signal
692
+ request.signal
604
693
  );
605
694
  if (!response.ok) {
606
695
  return this.handleErrorResponse(response, "batch", dbName, requestedActions);
@@ -609,6 +698,8 @@ var SQLService = class extends BaseService {
609
698
  return ok(data);
610
699
  } catch (error) {
611
700
  return err(wrapError("sql", error));
701
+ } finally {
702
+ request.dispose();
612
703
  }
613
704
  });
614
705
  }
@@ -617,12 +708,13 @@ var SQLService = class extends BaseService {
617
708
  if (!this.requireAuth()) {
618
709
  return err(authRequiredError("sql"));
619
710
  }
711
+ const request = this.createRequestSignal(options?.signal);
620
712
  try {
621
713
  const response = await this.invokeSQL(
622
714
  dbName,
623
715
  SQLAction.WRITE,
624
716
  { action: "execute_statement", name, params: params ?? [] },
625
- options?.signal
717
+ request.signal
626
718
  );
627
719
  if (!response.ok) {
628
720
  return this.handleErrorResponse(response, "executeStatement", dbName, [SQLAction.WRITE]);
@@ -631,6 +723,8 @@ var SQLService = class extends BaseService {
631
723
  return ok(data);
632
724
  } catch (error) {
633
725
  return err(wrapError("sql", error));
726
+ } finally {
727
+ request.dispose();
634
728
  }
635
729
  });
636
730
  }
@@ -639,12 +733,13 @@ var SQLService = class extends BaseService {
639
733
  if (!this.requireAuth()) {
640
734
  return err(authRequiredError("sql"));
641
735
  }
736
+ const request = this.createRequestSignal(options?.signal);
642
737
  try {
643
738
  const response = await this.invokeSQL(
644
739
  dbName,
645
740
  SQLAction.READ,
646
741
  { action: "export" },
647
- options?.signal
742
+ request.signal
648
743
  );
649
744
  if (!response.ok) {
650
745
  return this.handleErrorResponse(response, "export", dbName, [SQLAction.READ]);
@@ -658,6 +753,8 @@ var SQLService = class extends BaseService {
658
753
  return ok(text);
659
754
  } catch (error) {
660
755
  return err(wrapError("sql", error));
756
+ } finally {
757
+ request.dispose();
661
758
  }
662
759
  });
663
760
  }
@@ -748,7 +845,7 @@ var SQLService = class extends BaseService {
748
845
  "Content-Type": "application/json"
749
846
  },
750
847
  body: JSON.stringify(body),
751
- signal: this.combineSignals(signal)
848
+ signal
752
849
  });
753
850
  }
754
851
  actionForSql(sql, fallback) {