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

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.
@@ -1,5 +1,5 @@
1
- import { B as BaseService } from '../BaseService-BhpVpA9b.cjs';
2
- import { P as PermissionHint, I as IService, R as Result } from '../types-qwMmB7qB.cjs';
1
+ import { B as BaseService } from '../BaseService-DWbPbov7.cjs';
2
+ import { P as PermissionHint, I as IService, R as Result } from '../types-CVwwxqXF.cjs';
3
3
  export { DecryptTransportResponseError } from '@tinycloud/sdk-services/internal/decrypt-transport-response-error';
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
- import { B as BaseService } from '../BaseService-CuV-ZVPs.js';
2
- import { P as PermissionHint, I as IService, R as Result } from '../types-qwMmB7qB.js';
1
+ import { B as BaseService } from '../BaseService-B_UKhVht.js';
2
+ import { P as PermissionHint, I as IService, R as Result } from '../types-CVwwxqXF.js';
3
3
  export { DecryptTransportResponseError } from '@tinycloud/sdk-services/internal/decrypt-transport-response-error';
4
4
 
5
5
  /**
@@ -5,6 +5,10 @@ var ErrorCodes = {
5
5
  AUTH_EXPIRED: "AUTH_EXPIRED",
6
6
  AUTH_REQUIRED: "AUTH_REQUIRED",
7
7
  AUTH_UNAUTHORIZED: "AUTH_UNAUTHORIZED",
8
+ /** HTTP 401: the delegation the invocation cites was revoked. */
9
+ AUTH_DELEGATION_REVOKED: "AUTH_DELEGATION_REVOKED",
10
+ /** HTTP 401: a delegation the cited one rests on was revoked. */
11
+ AUTH_DELEGATION_ANCESTOR_REVOKED: "AUTH_DELEGATION_ANCESTOR_REVOKED",
8
12
  NETWORK_ERROR: "NETWORK_ERROR",
9
13
  TIMEOUT: "TIMEOUT",
10
14
  ABORTED: "ABORTED",
@@ -16,6 +20,10 @@ var ErrorCodes = {
16
20
  KV_PRECONDITION_FAILED: "KV_PRECONDITION_FAILED",
17
21
  KV_CONFLICT: "KV_CONFLICT",
18
22
  KV_RESPONSE_TOO_LARGE: "KV_RESPONSE_TOO_LARGE",
23
+ /** HTTP 410 from the change feed: discard sync state and restart without a cursor; `meta.reason` says why. */
24
+ KV_SYNC_RESET_REQUIRED: "KV_SYNC_RESET_REQUIRED",
25
+ /** HTTP 403 from the change feed: the retention grant was refused; `meta.reason` says why. */
26
+ KV_RETENTION_GRANT_REFUSED: "KV_RETENTION_GRANT_REFUSED",
19
27
  // SQL-specific errors
20
28
  SQL_ERROR: "SQL_ERROR",
21
29
  SQL_PERMISSION_DENIED: "SQL_PERMISSION_DENIED",
@@ -159,11 +167,31 @@ var ENCRYPTION_NETWORK_URN_PREFIX = URN_PREFIX;
159
167
  var NETWORK_NAME_PATTERN = NETWORK_NAME_RE;
160
168
 
161
169
  // src/errors.ts
162
- function timeoutError(service) {
170
+ var RequestTimeoutError = class extends Error {
171
+ constructor(timeoutMs) {
172
+ super(`Request timed out after ${timeoutMs}ms.`);
173
+ this.name = "TimeoutError";
174
+ this.timeoutMs = timeoutMs;
175
+ }
176
+ };
177
+ function isRequestTimeoutError(error) {
178
+ return error instanceof RequestTimeoutError || error instanceof Error && error.name === "TimeoutError" && typeof error.timeoutMs === "number";
179
+ }
180
+ function timeoutError(service, timeoutMs, cause) {
181
+ if (timeoutMs === void 0) {
182
+ return {
183
+ code: ErrorCodes.TIMEOUT,
184
+ message: "Request timed out.",
185
+ service,
186
+ ...cause === void 0 ? {} : { cause }
187
+ };
188
+ }
163
189
  return {
164
190
  code: ErrorCodes.TIMEOUT,
165
- message: "Request timed out.",
166
- service
191
+ message: `Request timed out after ${timeoutMs}ms.`,
192
+ service,
193
+ ...cause === void 0 ? {} : { cause },
194
+ meta: { timeoutMs }
167
195
  };
168
196
  }
169
197
  function abortedError(service) {
@@ -181,6 +209,9 @@ var capabilityServices = new Set(
181
209
  );
182
210
  function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
183
211
  if (error instanceof Error) {
212
+ if (isRequestTimeoutError(error)) {
213
+ return timeoutError(service, error.timeoutMs, error);
214
+ }
184
215
  if (error.name === "AbortError") {
185
216
  return abortedError(service);
186
217
  }
@@ -202,6 +233,7 @@ function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
202
233
  }
203
234
 
204
235
  // src/base/BaseService.ts
236
+ var MAX_TIMER_DELAY_MS = 2147483647;
205
237
  var BaseService = class {
206
238
  constructor() {
207
239
  /**
@@ -382,6 +414,64 @@ var BaseService = class {
382
414
  }
383
415
  return controller.signal;
384
416
  }
417
+ /**
418
+ * Create the abort signal for one request, bounded by the request timeout.
419
+ *
420
+ * The signal aborts when the service signs out, the context aborts, the
421
+ * caller's `signal` aborts, or the timeout elapses, whichever comes first.
422
+ * A timeout aborts with a {@link RequestTimeoutError} (`TimeoutError`), which
423
+ * `wrapError` maps to `ErrorCodes.TIMEOUT`; the other sources keep their own
424
+ * reason (normally `AbortError`, mapped to `ErrorCodes.ABORTED`).
425
+ *
426
+ * The timeout is `timeoutMs` when given, otherwise `config.timeout`. Only a
427
+ * positive, finite value (at most 2^31-1 ms) applies; `undefined`, `0`, and
428
+ * `Infinity` mean no timeout, so a per-call `0` opts out of a configured one.
429
+ *
430
+ * Callers must call `dispose()` once the response body has been consumed,
431
+ * which clears the timer and removes the listeners this adds to the
432
+ * long-lived service and context signals.
433
+ *
434
+ * @param signal - The caller's abort signal for this request
435
+ * @param timeoutMs - Per-request timeout override in milliseconds
436
+ */
437
+ createRequestSignal(signal, timeoutMs) {
438
+ const controller = new AbortController();
439
+ const detachers = [];
440
+ let timer;
441
+ const dispose = () => {
442
+ if (timer !== void 0) {
443
+ clearTimeout(timer);
444
+ timer = void 0;
445
+ }
446
+ for (const detach of detachers.splice(0)) {
447
+ detach();
448
+ }
449
+ };
450
+ const abort = (reason) => {
451
+ dispose();
452
+ controller.abort(reason);
453
+ };
454
+ const requestSignal = { signal: controller.signal, dispose };
455
+ const parents = [
456
+ this.abortController.signal,
457
+ this.context?.abortSignal,
458
+ signal
459
+ ].filter((parent) => parent !== void 0);
460
+ for (const parent of parents) {
461
+ if (parent.aborted) {
462
+ abort(parent.reason);
463
+ return requestSignal;
464
+ }
465
+ const onAbort = () => abort(parent.reason);
466
+ parent.addEventListener("abort", onAbort, { once: true });
467
+ detachers.push(() => parent.removeEventListener("abort", onAbort));
468
+ }
469
+ const timeout = timeoutMs ?? this._config.timeout;
470
+ if (typeof timeout === "number" && timeout > 0 && timeout <= MAX_TIMER_DELAY_MS) {
471
+ timer = setTimeout(() => abort(new RequestTimeoutError(timeout)), timeout);
472
+ }
473
+ return requestSignal;
474
+ }
385
475
  /**
386
476
  * Wrap an operation with error handling and telemetry.
387
477
  *