@kosdev-code/kos-ui-sdk 0.1.0-next.808 → 0.1.0-next.810
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/core/core/transport/webSocketTransport.d.ts +30 -2
- package/core/core/transport/webSocketTransport.d.ts.map +1 -1
- package/core/types/utils/kos-fetch.d.ts +17 -0
- package/core/types/utils/kos-fetch.d.ts.map +1 -1
- package/core/util/abortable-when.d.ts +21 -0
- package/core/util/abortable-when.d.ts.map +1 -0
- package/core/util/index.d.ts +1 -0
- package/core/util/index.d.ts.map +1 -1
- package/core/util/kos-fetch.d.ts.map +1 -1
- package/core/util/kos-service-request.d.ts +10 -0
- package/core/util/kos-service-request.d.ts.map +1 -1
- package/core/util/transport-not-ready-error.d.ts +67 -0
- package/core/util/transport-not-ready-error.d.ts.map +1 -0
- package/index.cjs +113 -9
- package/index.cjs.map +1 -1
- package/index.js +113 -9
- package/index.js.map +1 -1
- package/package.json +3 -3
package/index.js
CHANGED
|
@@ -6362,8 +6362,38 @@ const getMessageBody = (payload, skipParse) => {
|
|
|
6362
6362
|
return payload.body || payload;
|
|
6363
6363
|
}
|
|
6364
6364
|
};
|
|
6365
|
+
const TRANSPORT_NOT_READY = "TRANSPORT_NOT_READY";
|
|
6366
|
+
class TransportNotReadyError extends Error {
|
|
6367
|
+
/** Stable discriminator; see {@link TRANSPORT_NOT_READY}. */
|
|
6368
|
+
code = TRANSPORT_NOT_READY;
|
|
6369
|
+
/**
|
|
6370
|
+
* The budget, in milliseconds, that expired while waiting. `undefined` when
|
|
6371
|
+
* the wait was cut short by a caller-supplied timeout signal rather than by
|
|
6372
|
+
* the request's own budget.
|
|
6373
|
+
*/
|
|
6374
|
+
timeout;
|
|
6375
|
+
/** The URL of the request that was never sent. */
|
|
6376
|
+
url;
|
|
6377
|
+
constructor(details = {}) {
|
|
6378
|
+
super(
|
|
6379
|
+
`Transport not ready${details.timeout === void 0 ? "" : ` after ${details.timeout}ms`}${details.url ? ` - url: ${details.url}` : ""}`
|
|
6380
|
+
);
|
|
6381
|
+
this.name = "TransportNotReadyError";
|
|
6382
|
+
this.timeout = details.timeout;
|
|
6383
|
+
this.url = details.url;
|
|
6384
|
+
}
|
|
6385
|
+
}
|
|
6386
|
+
const isTransportNotReadyError = (error) => !!error && error.code === TRANSPORT_NOT_READY;
|
|
6365
6387
|
const log$D = KosLog.createLogger({ name: "kos-fetch" });
|
|
6366
|
-
const
|
|
6388
|
+
const DEFAULT_WS_TIMEOUT = 3e4;
|
|
6389
|
+
const WS_TIMEOUT = (() => {
|
|
6390
|
+
const configured = process.env.KOS_WS_TIMEOUT ? parseInt(process.env.KOS_WS_TIMEOUT) : DEFAULT_WS_TIMEOUT;
|
|
6391
|
+
return Number.isNaN(configured) ? DEFAULT_WS_TIMEOUT : configured;
|
|
6392
|
+
})();
|
|
6393
|
+
const resolveTimeoutBudget = (timeout) => {
|
|
6394
|
+
const budget = timeout ?? WS_TIMEOUT;
|
|
6395
|
+
return Number.isFinite(budget) && budget > 0 ? budget : void 0;
|
|
6396
|
+
};
|
|
6367
6397
|
const delay = () => new Promise((resolve) => {
|
|
6368
6398
|
setTimeout(() => {
|
|
6369
6399
|
resolve(true);
|
|
@@ -6397,6 +6427,14 @@ const combineSignals = (signals) => {
|
|
|
6397
6427
|
}
|
|
6398
6428
|
return controller.signal;
|
|
6399
6429
|
};
|
|
6430
|
+
const createRequestSignal = (budget, callerSignal) => {
|
|
6431
|
+
const timeoutSignal = budget ? createTimeoutSignal(budget) : void 0;
|
|
6432
|
+
if (timeoutSignal && callerSignal) {
|
|
6433
|
+
return combineSignals([callerSignal, timeoutSignal]);
|
|
6434
|
+
}
|
|
6435
|
+
return timeoutSignal ?? callerSignal ?? new AbortController().signal;
|
|
6436
|
+
};
|
|
6437
|
+
const isTimeoutReason = (reason) => reason?.name === "TimeoutError";
|
|
6400
6438
|
const fetchMessageFactory = (options) => {
|
|
6401
6439
|
if (options?.studio) {
|
|
6402
6440
|
return createStudioMessage;
|
|
@@ -6408,15 +6446,25 @@ const fetchMessageFactory = (options) => {
|
|
|
6408
6446
|
};
|
|
6409
6447
|
const kosFetchWs = async (url, options) => {
|
|
6410
6448
|
const transport = KosCore.getInstance().transport;
|
|
6411
|
-
await transport.whenReady();
|
|
6412
6449
|
const requestId = uuid();
|
|
6413
6450
|
const urlObj = new URL(url);
|
|
6414
6451
|
const path = `${urlObj.pathname}${urlObj.search}`;
|
|
6415
6452
|
log$D.debug(`path: ${path}`);
|
|
6416
|
-
const
|
|
6453
|
+
const budget = resolveTimeoutBudget(options?.timeout);
|
|
6417
6454
|
const messageFactory = fetchMessageFactory(options);
|
|
6418
|
-
const
|
|
6419
|
-
|
|
6455
|
+
const signal = createRequestSignal(budget, options?.signal);
|
|
6456
|
+
try {
|
|
6457
|
+
await transport.whenReady({ signal });
|
|
6458
|
+
} catch (error) {
|
|
6459
|
+
if (isTimeoutReason(error)) {
|
|
6460
|
+
log$D.error(
|
|
6461
|
+
`Transport not ready${budget === void 0 ? "" : ` after ${budget}ms`} - request not sent - url: ${url}`
|
|
6462
|
+
);
|
|
6463
|
+
throw new TransportNotReadyError({ timeout: budget, url });
|
|
6464
|
+
}
|
|
6465
|
+
log$D.debug(`Request aborted while waiting for transport - url: ${url}`);
|
|
6466
|
+
throw error;
|
|
6467
|
+
}
|
|
6420
6468
|
const processedBody = await processRequestBody(options?.body);
|
|
6421
6469
|
const additionalHeaders = {};
|
|
6422
6470
|
if (processedBody.contentType) {
|
|
@@ -6579,6 +6627,7 @@ const resolveBaseUrl = () => {
|
|
|
6579
6627
|
};
|
|
6580
6628
|
const log$C = KosLog.createLogger({ name: "kos-service-request" });
|
|
6581
6629
|
const ERROR_UNKNOWN = "errUnknown";
|
|
6630
|
+
const ERROR_TRANSPORT_NOT_READY = "Transport not ready";
|
|
6582
6631
|
const MUTATING_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "DELETE", "PATCH"]);
|
|
6583
6632
|
const RETRY_DEFAULTS = {
|
|
6584
6633
|
maxAttempts: 3,
|
|
@@ -6628,6 +6677,10 @@ async function executeFetch(fullUrl, fetchOptions) {
|
|
|
6628
6677
|
const payload = await response.json();
|
|
6629
6678
|
return [null, payload.data ?? payload];
|
|
6630
6679
|
} catch (error) {
|
|
6680
|
+
if (isTransportNotReadyError(error)) {
|
|
6681
|
+
log$C.error(`Transport not ready, request not sent: ${fullUrl}`);
|
|
6682
|
+
return [ERROR_TRANSPORT_NOT_READY, null];
|
|
6683
|
+
}
|
|
6631
6684
|
if (error instanceof DOMException) {
|
|
6632
6685
|
if (error.name === "TimeoutError") {
|
|
6633
6686
|
log$C.error(`Request timed out: ${fullUrl}`);
|
|
@@ -6671,6 +6724,10 @@ async function executeFetchWithRetry(fullUrl, fetchOptions, config2) {
|
|
|
6671
6724
|
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
6672
6725
|
}
|
|
6673
6726
|
} catch (error) {
|
|
6727
|
+
if (isTransportNotReadyError(error)) {
|
|
6728
|
+
log$C.error(`Transport not ready, request not sent: ${fullUrl}`);
|
|
6729
|
+
return [ERROR_TRANSPORT_NOT_READY, null];
|
|
6730
|
+
}
|
|
6674
6731
|
if (error instanceof DOMException) {
|
|
6675
6732
|
if (error.name === "TimeoutError") {
|
|
6676
6733
|
log$C.error(`Request timed out: ${fullUrl}`);
|
|
@@ -7482,6 +7539,38 @@ class FlowControlManager {
|
|
|
7482
7539
|
return { ...this.stats };
|
|
7483
7540
|
}
|
|
7484
7541
|
}
|
|
7542
|
+
const abortReason = (signal) => signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
7543
|
+
const abortableWhen = async (predicate, signal) => {
|
|
7544
|
+
if (predicate()) {
|
|
7545
|
+
return;
|
|
7546
|
+
}
|
|
7547
|
+
if (!signal) {
|
|
7548
|
+
await when(predicate);
|
|
7549
|
+
return;
|
|
7550
|
+
}
|
|
7551
|
+
if (signal.aborted) {
|
|
7552
|
+
throw abortReason(signal);
|
|
7553
|
+
}
|
|
7554
|
+
const pending = when(predicate);
|
|
7555
|
+
let onAbort;
|
|
7556
|
+
try {
|
|
7557
|
+
await Promise.race([
|
|
7558
|
+
// `cancel()` below rejects this promise with MobX's WHEN_CANCELLED
|
|
7559
|
+
// sentinel. That rejection *is* the cancellation, never a real failure,
|
|
7560
|
+
// so it is swallowed here; the abort branch supplies the thrown reason.
|
|
7561
|
+
pending.catch(() => void 0),
|
|
7562
|
+
new Promise((_, reject) => {
|
|
7563
|
+
onAbort = () => reject(abortReason(signal));
|
|
7564
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
7565
|
+
})
|
|
7566
|
+
]);
|
|
7567
|
+
} finally {
|
|
7568
|
+
if (onAbort) {
|
|
7569
|
+
signal.removeEventListener("abort", onAbort);
|
|
7570
|
+
}
|
|
7571
|
+
pending.cancel();
|
|
7572
|
+
}
|
|
7573
|
+
};
|
|
7485
7574
|
class WebSocketBridgeTransport extends WebSocket {
|
|
7486
7575
|
constructor(address) {
|
|
7487
7576
|
super(address);
|
|
@@ -8114,15 +8203,26 @@ ${dstAddr}topics:${topic}
|
|
|
8114
8203
|
}
|
|
8115
8204
|
};
|
|
8116
8205
|
}
|
|
8117
|
-
|
|
8118
|
-
|
|
8206
|
+
/**
|
|
8207
|
+
* Resolves once the transport can carry requests: the socket (and the FOS
|
|
8208
|
+
* socket, when used) is connected and the connection is authorized.
|
|
8209
|
+
*
|
|
8210
|
+
* Pass `options.signal` to bound the wait. `connectionEstablished` flips back
|
|
8211
|
+
* to `false` on socket close, so an unbounded wait parks indefinitely while
|
|
8212
|
+
* the transport is down — callers with a deadline must supply a signal.
|
|
8213
|
+
*
|
|
8214
|
+
* @param options - See {@link KosTransportReadyOptions}.
|
|
8215
|
+
* @throws The signal's abort reason if it aborts before the transport is ready.
|
|
8216
|
+
*/
|
|
8217
|
+
async whenReady(options) {
|
|
8119
8218
|
if (!this.webSocketSupported) {
|
|
8120
8219
|
return {
|
|
8121
8220
|
status: `not supported`
|
|
8122
8221
|
};
|
|
8123
8222
|
}
|
|
8124
|
-
await
|
|
8125
|
-
() => !!
|
|
8223
|
+
await abortableWhen(
|
|
8224
|
+
() => !!this.socket?.connectionEstablished && (!this.useFosTransport || !!this.fosSocket?.connectionEstablished) && this.authorized,
|
|
8225
|
+
options?.signal
|
|
8126
8226
|
);
|
|
8127
8227
|
return {
|
|
8128
8228
|
status: `success`
|
|
@@ -26945,6 +27045,7 @@ export {
|
|
|
26945
27045
|
Device,
|
|
26946
27046
|
index$6 as DeviceServices,
|
|
26947
27047
|
DomIntersectionStrategy,
|
|
27048
|
+
ERROR_TRANSPORT_NOT_READY,
|
|
26948
27049
|
EVENT_KOS_MODEL_READY,
|
|
26949
27050
|
EVENT_TROUBLE_ADDED,
|
|
26950
27051
|
EVENT_TROUBLE_REMOVED,
|
|
@@ -27127,6 +27228,7 @@ export {
|
|
|
27127
27228
|
TIMER_END,
|
|
27128
27229
|
TIMER_EVENT,
|
|
27129
27230
|
TOPIC_TIMER_TICK_EVENT,
|
|
27231
|
+
TRANSPORT_NOT_READY,
|
|
27130
27232
|
TimerManager,
|
|
27131
27233
|
TokenContext,
|
|
27132
27234
|
TokenProvider,
|
|
@@ -27139,6 +27241,7 @@ export {
|
|
|
27139
27241
|
TranslationContainerContext,
|
|
27140
27242
|
TranslationContext,
|
|
27141
27243
|
TransportFactory,
|
|
27244
|
+
TransportNotReadyError,
|
|
27142
27245
|
Trouble,
|
|
27143
27246
|
TroubleAwareSetup,
|
|
27144
27247
|
TroubleContainer,
|
|
@@ -27277,6 +27380,7 @@ export {
|
|
|
27277
27380
|
isLocalRefId,
|
|
27278
27381
|
isNumber,
|
|
27279
27382
|
isPrintable,
|
|
27383
|
+
isTransportNotReadyError,
|
|
27280
27384
|
isTroubleAware,
|
|
27281
27385
|
isValidDate,
|
|
27282
27386
|
kosAction,
|