@camera.ui/transport 0.0.24 → 0.0.25

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
@@ -192,7 +192,7 @@ var RaceFirstError = class extends Error {
192
192
  }
193
193
  };
194
194
  function raceFirst(candidates, options = {}) {
195
- const { timeoutByMode = (mode) => DEFAULT_RACE_TIMEOUT_BY_MODE[mode] ?? 5e3, shortCircuit, parentSignal, prefer } = options;
195
+ const { timeoutByMode = (mode) => DEFAULT_RACE_TIMEOUT_BY_MODE[mode] ?? 5e3, shortCircuit, informative, parentSignal, prefer } = options;
196
196
  const preferGraceMs = options.preferGraceMs ?? DEFAULT_PREFER_GRACE_MS;
197
197
  return new Promise((resolve, reject) => {
198
198
  if (candidates.length === 0) {
@@ -215,7 +215,7 @@ function raceFirst(candidates, options = {}) {
215
215
  const timers = [];
216
216
  function cleanupAllExcept(except) {
217
217
  for (const t of timers) clearTimeout(t);
218
- for (const a of abortControllers) if (a !== except) a.abort();
218
+ for (const a of abortControllers) if (a !== except) a.abort("race-settled");
219
219
  }
220
220
  function finishSuccess(endpoint, value, except) {
221
221
  if (settled) return;
@@ -259,7 +259,7 @@ function raceFirst(candidates, options = {}) {
259
259
  const ctrl = new AbortController();
260
260
  abortControllers.push(ctrl);
261
261
  const delay = timeoutByMode(cand.endpoint.mode);
262
- const timer = setTimeout(() => ctrl.abort(), delay);
262
+ const timer = setTimeout(() => ctrl.abort("race-timeout"), delay);
263
263
  timers.push(timer);
264
264
  cand.run(ctrl.signal).then((value) => handleSuccess(cand.endpoint, value, ctrl), (err) => {
265
265
  if (settled) {
@@ -282,10 +282,11 @@ function raceFirst(candidates, options = {}) {
282
282
  }
283
283
  remaining--;
284
284
  if (remaining <= 0) {
285
- const [endpoint, cause] = [...lastErrors.entries()].find(([, e]) => {
285
+ const usable = [...lastErrors.entries()].filter(([, e]) => {
286
286
  if (e instanceof RaceFirstError) return e.kind !== "all-failed" || !(e.cause instanceof Error && e.cause.message === "aborted");
287
287
  return true;
288
- }) ?? [cand.endpoint, finalErr];
288
+ });
289
+ const [endpoint, cause] = (informative ? usable.find(([, e]) => informative(e instanceof RaceFirstError ? e.cause : e)) : void 0) ?? usable[0] ?? [cand.endpoint, finalErr];
289
290
  finishFail(new RaceFirstError("raceFirst: all candidates failed", endpoint, cause, "all-failed"));
290
291
  }
291
292
  });
@@ -778,9 +779,9 @@ function attachProbeLoop(options) {
778
779
  options.onProbeSuccess?.(endpoint, tokens);
779
780
  return tokens;
780
781
  } catch (err) {
781
- const isLocalTimeout = signal.aborted && !ctrl.signal.aborted && !isProbeFailure(err);
782
- const timeout = (options.timeoutByMode ?? ((m) => DEFAULT_RACE_TIMEOUT_BY_MODE[m] ?? 5e3))(endpoint.mode);
783
- const finalErr = isLocalTimeout ? makeProbeFailure("transient", `timeout (${timeout}ms)`) : err;
782
+ let finalErr = err;
783
+ if (signal.aborted && !ctrl.signal.aborted && !isProbeFailure(err)) if (signal.reason === "race-settled") finalErr = makeProbeFailure("transient", "superseded");
784
+ else finalErr = makeProbeFailure("transient", `timeout (${(options.timeoutByMode ?? ((m) => DEFAULT_RACE_TIMEOUT_BY_MODE[m] ?? 5e3))(endpoint.mode)}ms)`);
784
785
  options.onProbeError?.(endpoint, finalErr);
785
786
  throw finalErr;
786
787
  }
@@ -792,7 +793,8 @@ function attachProbeLoop(options) {
792
793
  parentSignal: ctrl.signal,
793
794
  prefer: options.prefer,
794
795
  preferGraceMs: options.preferGraceMs,
795
- shortCircuit: (err) => isProbeFailure(err) && (err.kind === "needs-auth" || err.kind === "fatal" || err.kind === "aborted")
796
+ shortCircuit: (err) => isProbeFailure(err) && (err.kind === "needs-auth" || err.kind === "fatal"),
797
+ informative: (cause) => !(isProbeFailure(cause) && cause.kind === "aborted")
796
798
  });
797
799
  if (ctrl.signal.aborted) return;
798
800
  options.kernel.dispatch({
package/dist/race.d.ts CHANGED
@@ -6,11 +6,12 @@ export interface RaceCandidate<T> {
6
6
  readonly run: (signal: AbortSignal) => Promise<T>;
7
7
  }
8
8
  export interface RaceFirstOptions {
9
+ readonly parentSignal?: AbortSignal;
10
+ readonly preferGraceMs?: number;
9
11
  readonly timeoutByMode?: TimeoutByModeFn;
10
12
  readonly shortCircuit?: (err: unknown) => boolean;
11
- readonly parentSignal?: AbortSignal;
13
+ readonly informative?: (cause: unknown) => boolean;
12
14
  readonly prefer?: (endpoint: Endpoint) => boolean;
13
- readonly preferGraceMs?: number;
14
15
  }
15
16
  export interface RaceFirstResult<T> {
16
17
  readonly endpoint: Endpoint;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camera.ui/transport",
3
- "version": "0.0.24",
3
+ "version": "0.0.25",
4
4
  "description": "camera.ui transport layer — framework-agnostic connection kernel, reducer state, pluggable transports (HTTP/WS/Socket.IO/NATS), lifecycle effects and worker bridge",
5
5
  "author": "seydx (https://github.com/cameraui/clients)",
6
6
  "type": "module",
@@ -66,7 +66,7 @@
66
66
  "@typescript-eslint/parser": "^8.65.0",
67
67
  "@vue/language-core": "^3.3.8",
68
68
  "eslint": "9.39.2",
69
- "globals": "^17.7.0",
69
+ "globals": "^17.8.0",
70
70
  "jiti": "^2.7.0",
71
71
  "prettier": "^3.9.6",
72
72
  "rimraf": "^6.1.3",