itd-api 0.5.0 → 0.6.0
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/README.md +6 -4
- package/dist/index.cjs +216 -101
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +55 -179
- package/dist/index.d.ts +55 -179
- package/dist/index.js +217 -80
- package/dist/index.js.map +1 -1
- package/dist/{multi-storage-B0r0AInH.js → multi-storage-BUZaLAPO.js} +13 -9
- package/dist/{multi-storage-B0r0AInH.js.map → multi-storage-BUZaLAPO.js.map} +1 -1
- package/dist/{multi-storage-CLqmzq07.d.ts → multi-storage-BUoEoW8f.d.cts} +3 -7
- package/dist/{multi-storage-mBuCOVZY.cjs → multi-storage-Bf84xiO8.cjs} +12 -14
- package/dist/{multi-storage-mBuCOVZY.cjs.map → multi-storage-Bf84xiO8.cjs.map} +1 -1
- package/dist/{multi-storage-s_PcWPGH.d.cts → multi-storage-CQSlI_kn.d.ts} +3 -7
- package/dist/node.cjs +2 -2
- package/dist/node.d.cts +2 -2
- package/dist/node.d.ts +2 -2
- package/dist/node.js +2 -2
- package/dist/{storage-Doe3lpFQ.d.ts → storage-BqMxs76Y.d.cts} +4 -4
- package/dist/{storage-Doe3lpFQ.d.cts → storage-BqMxs76Y.d.ts} +4 -4
- package/dist/{storage-dF8Tio5y.cjs → storage-DnzZPS_9.cjs} +36 -27
- package/dist/{storage-dF8Tio5y.cjs.map → storage-DnzZPS_9.cjs.map} +1 -1
- package/dist/{storage-DWrK3Z4M.js → storage-IHdXw52v.js} +36 -27
- package/dist/{storage-DWrK3Z4M.js.map → storage-IHdXw52v.js.map} +1 -1
- package/dist/web.cjs +1 -1
- package/dist/web.d.cts +1 -1
- package/dist/web.d.ts +1 -1
- package/dist/web.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_multi_storage = require("./multi-storage-
|
|
3
|
-
const require_storage = require("./storage-
|
|
2
|
+
const require_multi_storage = require("./multi-storage-Bf84xiO8.cjs");
|
|
3
|
+
const require_storage = require("./storage-DnzZPS_9.cjs");
|
|
4
4
|
//#region src/core/emitter.ts
|
|
5
5
|
/**
|
|
6
6
|
* Минимальный типизированный источник событий.
|
|
@@ -435,6 +435,14 @@ const OPERATIONS = freezeOperations({
|
|
|
435
435
|
method: "PUT",
|
|
436
436
|
retrySafety: RetrySafety.Idempotent
|
|
437
437
|
},
|
|
438
|
+
"realtime.poll.updates": {
|
|
439
|
+
method: "GET",
|
|
440
|
+
retrySafety: RetrySafety.Safe
|
|
441
|
+
},
|
|
442
|
+
"realtime.poll.unread": {
|
|
443
|
+
method: "GET",
|
|
444
|
+
retrySafety: RetrySafety.Safe
|
|
445
|
+
},
|
|
438
446
|
"hashtags.search": {
|
|
439
447
|
method: "GET",
|
|
440
448
|
retrySafety: RetrySafety.Safe
|
|
@@ -668,6 +676,11 @@ const AUTH_PATHS = {
|
|
|
668
676
|
* Нужен, чтобы отрисовать виджет капчи и получить токен для `signIn`, `signUp`
|
|
669
677
|
* и `forgotPassword`.
|
|
670
678
|
*
|
|
679
|
+
* Ключ привязан к домену: на чужом origin Cloudflare отказывает виджету с кодом `110200`.
|
|
680
|
+
* Поэтому отрисовать его может только код, выполняемый на самом итд.com. Остальным
|
|
681
|
+
* подходит `@itd-api/turnstile`, готовый токен из другого источника или вовсе вход
|
|
682
|
+
* без капчи — по сохранённой сессии либо по токенам, взятым в браузере.
|
|
683
|
+
*
|
|
671
684
|
* @example
|
|
672
685
|
* ```ts
|
|
673
686
|
* turnstile.render('#captcha', {
|
|
@@ -677,8 +690,6 @@ const AUTH_PATHS = {
|
|
|
677
690
|
* ```
|
|
678
691
|
*/
|
|
679
692
|
const TURNSTILE_SITE_KEY = "0x4AAAAAACHhxczw6fJGwPBg";
|
|
680
|
-
/** Заголовок с идентификатором устройства. Сервер связывает с ним запись в списке сессий. */
|
|
681
|
-
const DEVICE_ID_HEADER = "X-Device-Id";
|
|
682
693
|
function readAccessToken(payload) {
|
|
683
694
|
if (typeof payload !== "object" || payload === null) return void 0;
|
|
684
695
|
const token = payload.accessToken;
|
|
@@ -1183,10 +1194,33 @@ const systemClock = Object.freeze({
|
|
|
1183
1194
|
return () => clearTimeout(timer);
|
|
1184
1195
|
}
|
|
1185
1196
|
});
|
|
1197
|
+
/**
|
|
1198
|
+
* Заводит срок, общий на все ожидания: от ожидания к ожиданию он не продлевается.
|
|
1199
|
+
*
|
|
1200
|
+
* @param timeout срок в миллисекундах; `0` — ждать без ограничения
|
|
1201
|
+
* @internal
|
|
1202
|
+
*/
|
|
1203
|
+
function createDeadline(timeout, clock = systemClock) {
|
|
1204
|
+
if (timeout <= 0) return {
|
|
1205
|
+
wait: async (promise) => {
|
|
1206
|
+
await promise;
|
|
1207
|
+
return true;
|
|
1208
|
+
},
|
|
1209
|
+
cancel: () => {}
|
|
1210
|
+
};
|
|
1211
|
+
let expire;
|
|
1212
|
+
const expired = new Promise((resolve) => {
|
|
1213
|
+
expire = resolve;
|
|
1214
|
+
});
|
|
1215
|
+
return {
|
|
1216
|
+
wait: (promise) => Promise.race([promise.then(() => true), expired.then(() => false)]),
|
|
1217
|
+
cancel: clock.schedule(() => expire(), timeout)
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1186
1220
|
//#endregion
|
|
1187
1221
|
//#region src/core/version.ts
|
|
1188
1222
|
/** Версия библиотеки. Попадает в `User-Agent`. */
|
|
1189
|
-
const LIBRARY_VERSION = "0.
|
|
1223
|
+
const LIBRARY_VERSION = "0.6.0";
|
|
1190
1224
|
//#endregion
|
|
1191
1225
|
//#region src/core/config.ts
|
|
1192
1226
|
/** Базовый URL API итд.com. Домен записан в punycode: `итд.com`. */
|
|
@@ -1201,8 +1235,6 @@ const BUILT_IN_SERVICES = Object.freeze([Object.freeze({
|
|
|
1201
1235
|
baseUrl: DEFAULT_STATUS_BASE_URL,
|
|
1202
1236
|
auth: false
|
|
1203
1237
|
})]);
|
|
1204
|
-
/** Таймаут запроса по умолчанию — 30 секунд. */
|
|
1205
|
-
const DEFAULT_TIMEOUT = 3e4;
|
|
1206
1238
|
/**
|
|
1207
1239
|
* `User-Agent` по умолчанию.
|
|
1208
1240
|
*
|
|
@@ -1412,6 +1444,7 @@ function resolveConfig(options = {}) {
|
|
|
1412
1444
|
const mode = options.mode ?? RuntimeMode.Auto;
|
|
1413
1445
|
if (!Object.values(RuntimeMode).includes(mode)) throw new require_storage.ItdConfigError(`mode должен быть одним из ${Object.values(RuntimeMode).join(", ")}, получено: ${mode}`);
|
|
1414
1446
|
const timeout = requirePositive(options.timeout ?? 3e4, "timeout");
|
|
1447
|
+
const shutdownTimeout = requirePositive(options.shutdownTimeout ?? 1e4, "shutdownTimeout");
|
|
1415
1448
|
if (options.clock !== void 0 && (typeof options.clock !== "object" || options.clock === null || typeof options.clock.now !== "function" || typeof options.clock.schedule !== "function")) throw new require_storage.ItdConfigError("clock должен предоставлять методы now() и schedule()");
|
|
1416
1449
|
requireOptionalBoolean(options.autoRefresh, "autoRefresh");
|
|
1417
1450
|
requireOptionalBoolean(options.reloginOnRefreshFailure, "reloginOnRefreshFailure");
|
|
@@ -1427,6 +1460,7 @@ function resolveConfig(options = {}) {
|
|
|
1427
1460
|
fetch: resolveFetch(options.fetch),
|
|
1428
1461
|
clock: options.clock ?? systemClock,
|
|
1429
1462
|
timeout,
|
|
1463
|
+
shutdownTimeout,
|
|
1430
1464
|
retry: resolveRetry(options.retry),
|
|
1431
1465
|
rateLimit: resolveRateLimit(options.rateLimit),
|
|
1432
1466
|
hooks: resolveHooks(options.hooks),
|
|
@@ -1995,7 +2029,11 @@ var PluginRegistry = class {
|
|
|
1995
2029
|
#entries = /* @__PURE__ */ new Map();
|
|
1996
2030
|
#removing = /* @__PURE__ */ new Set();
|
|
1997
2031
|
#cleanups = /* @__PURE__ */ new Set();
|
|
2032
|
+
#options;
|
|
1998
2033
|
#ordered = [];
|
|
2034
|
+
constructor(options) {
|
|
2035
|
+
this.#options = options;
|
|
2036
|
+
}
|
|
1999
2037
|
/** Сколько плагинов подключено. */
|
|
2000
2038
|
get size() {
|
|
2001
2039
|
return this.#entries.size;
|
|
@@ -2069,9 +2107,11 @@ var PluginRegistry = class {
|
|
|
2069
2107
|
* Отключает плагин и вызывает его функцию очистки.
|
|
2070
2108
|
*
|
|
2071
2109
|
* Новые запросы перестают видеть расширения плагина сразу. Снимок уже начавшейся операции,
|
|
2072
|
-
* включая её будущие retry, остаётся неизменным; очистка дождётся завершения
|
|
2110
|
+
* включая её будущие retry, остаётся неизменным; очистка дождётся завершения операции,
|
|
2111
|
+
* но не дольше отведённого срока.
|
|
2073
2112
|
*
|
|
2074
2113
|
* @returns `false`, если такого плагина не было
|
|
2114
|
+
* @throws {ItdStateError} если операции плагина не завершились за отведённый срок
|
|
2075
2115
|
*/
|
|
2076
2116
|
async remove(name) {
|
|
2077
2117
|
const entry = this.#entries.get(name);
|
|
@@ -2080,21 +2120,24 @@ var PluginRegistry = class {
|
|
|
2080
2120
|
this.#entries.delete(name);
|
|
2081
2121
|
this.#ordered = this.#ordered.filter((current) => current !== entry);
|
|
2082
2122
|
this.#removing.add(name);
|
|
2123
|
+
const deadline = createDeadline(this.#options.shutdownTimeout, this.#options.clock);
|
|
2083
2124
|
const cleanup = this.#trackCleanup((async () => {
|
|
2084
|
-
await this.#
|
|
2085
|
-
|
|
2125
|
+
const expired = await this.#release(entry, deadline);
|
|
2126
|
+
if (expired) throw expired;
|
|
2086
2127
|
})());
|
|
2087
2128
|
try {
|
|
2088
2129
|
await cleanup;
|
|
2089
2130
|
return true;
|
|
2090
2131
|
} finally {
|
|
2132
|
+
deadline.cancel();
|
|
2091
2133
|
this.#removing.delete(name);
|
|
2092
2134
|
}
|
|
2093
2135
|
}
|
|
2094
2136
|
/**
|
|
2095
2137
|
* Отключает все плагины окончательно.
|
|
2096
2138
|
*
|
|
2097
|
-
* Очистка идёт изнутри наружу — в порядке, обратном выполнению расширений.
|
|
2139
|
+
* Очистка идёт изнутри наружу — в порядке, обратном выполнению расширений. Срок ожидания
|
|
2140
|
+
* общий на все плагины.
|
|
2098
2141
|
*/
|
|
2099
2142
|
async dispose() {
|
|
2100
2143
|
const entries = [...this.#ordered].reverse();
|
|
@@ -2102,13 +2145,14 @@ var PluginRegistry = class {
|
|
|
2102
2145
|
this.#entries.clear();
|
|
2103
2146
|
this.#ordered = [];
|
|
2104
2147
|
for (const { plugin } of entries) this.#removing.add(plugin.name);
|
|
2105
|
-
|
|
2148
|
+
const deadline = createDeadline(this.#options.shutdownTimeout, this.#options.clock);
|
|
2149
|
+
const cleanup = this.#trackCleanup((async () => {
|
|
2106
2150
|
const errors = [];
|
|
2107
2151
|
const previous = await Promise.allSettled(previousCleanups);
|
|
2108
2152
|
for (const result of previous) if (result.status === "rejected") errors.push(result.reason);
|
|
2109
2153
|
for (const entry of entries) try {
|
|
2110
|
-
await this.#
|
|
2111
|
-
|
|
2154
|
+
const expired = await this.#release(entry, deadline);
|
|
2155
|
+
if (expired) errors.push(expired);
|
|
2112
2156
|
} catch (error) {
|
|
2113
2157
|
errors.push(error);
|
|
2114
2158
|
} finally {
|
|
@@ -2116,6 +2160,11 @@ var PluginRegistry = class {
|
|
|
2116
2160
|
}
|
|
2117
2161
|
if (errors.length > 0) throw new AggregateError(errors, "Не удалось освободить ресурсы плагинов");
|
|
2118
2162
|
})());
|
|
2163
|
+
try {
|
|
2164
|
+
await cleanup;
|
|
2165
|
+
} finally {
|
|
2166
|
+
deadline.cancel();
|
|
2167
|
+
}
|
|
2119
2168
|
}
|
|
2120
2169
|
/**
|
|
2121
2170
|
* Прогоняет запрос через operation transformers и прикрепляет attempt interceptors.
|
|
@@ -2123,6 +2172,9 @@ var PluginRegistry = class {
|
|
|
2123
2172
|
* Снимки обеих цепочек берутся в начале: `unuse()` влияет на новые операции, но не меняет
|
|
2124
2173
|
* уже выполняющуюся и не удаляет interceptors из её последующих retry.
|
|
2125
2174
|
*
|
|
2175
|
+
* Каждый `next` одноразовый: transformer может завершить операцию сам, но не может породить
|
|
2176
|
+
* вторую — для `posts.create` это была бы вторая публикация.
|
|
2177
|
+
*
|
|
2126
2178
|
* @param execute выполнение логической операции, вызываемое самым внутренним transformer
|
|
2127
2179
|
*/
|
|
2128
2180
|
async run(request, execute) {
|
|
@@ -2133,7 +2185,17 @@ var PluginRegistry = class {
|
|
|
2133
2185
|
interceptor
|
|
2134
2186
|
})));
|
|
2135
2187
|
const scoped = (current) => withAttemptInterceptorScope(current, interceptorScope);
|
|
2136
|
-
const chain = entries.flatMap((entry) => entry.transformers
|
|
2188
|
+
const chain = entries.flatMap((entry) => entry.transformers.map((transformer) => ({
|
|
2189
|
+
plugin: entry.plugin.name,
|
|
2190
|
+
transformer
|
|
2191
|
+
}))).reduceRight((next, { plugin, transformer }) => (current) => {
|
|
2192
|
+
let called = false;
|
|
2193
|
+
return transformer(scoped(current), (prepared) => {
|
|
2194
|
+
if (called) throw new require_storage.ItdConfigError(`operation transformer плагина «${plugin}» вызвал next() больше одного раза`);
|
|
2195
|
+
called = true;
|
|
2196
|
+
return next(scoped(prepared));
|
|
2197
|
+
});
|
|
2198
|
+
}, (current) => execute(scoped(current)));
|
|
2137
2199
|
try {
|
|
2138
2200
|
return await chain(scoped(request));
|
|
2139
2201
|
} finally {
|
|
@@ -2147,6 +2209,18 @@ var PluginRegistry = class {
|
|
|
2147
2209
|
}
|
|
2148
2210
|
}
|
|
2149
2211
|
}
|
|
2212
|
+
/**
|
|
2213
|
+
* Дожидается операций плагина и освобождает его ресурсы.
|
|
2214
|
+
*
|
|
2215
|
+
* `teardown` выполняется в любом случае, в том числе после истечения срока.
|
|
2216
|
+
*
|
|
2217
|
+
* @returns ошибка истёкшего срока, если ждать пришлось дольше отведённого
|
|
2218
|
+
*/
|
|
2219
|
+
async #release(entry, deadline) {
|
|
2220
|
+
const finished = await deadline.wait(this.#waitForDrain(entry));
|
|
2221
|
+
await entry.teardown?.();
|
|
2222
|
+
return finished ? void 0 : new require_storage.ItdStateError(`плагин «${entry.plugin.name}» не завершил операции за ${this.#options.shutdownTimeout} мс; ожидание прекращено, ресурсы плагина освобождены`);
|
|
2223
|
+
}
|
|
2150
2224
|
#waitForDrain(entry) {
|
|
2151
2225
|
if (entry.activeRequests === 0) return Promise.resolve();
|
|
2152
2226
|
entry.drain ??= new Promise((resolve) => {
|
|
@@ -2319,6 +2393,7 @@ var RequestQueuePool = class {
|
|
|
2319
2393
|
stop() {
|
|
2320
2394
|
this.#main.stop();
|
|
2321
2395
|
for (const queue of this.#byDestination.values()) queue.stop();
|
|
2396
|
+
this.#byDestination.clear();
|
|
2322
2397
|
}
|
|
2323
2398
|
};
|
|
2324
2399
|
//#endregion
|
|
@@ -2843,17 +2918,25 @@ function abortable(promise, signal) {
|
|
|
2843
2918
|
});
|
|
2844
2919
|
}
|
|
2845
2920
|
/**
|
|
2846
|
-
* Объединяет пользовательский `AbortSignal
|
|
2921
|
+
* Объединяет пользовательский `AbortSignal`, сигнал жизни клиента и таймаут.
|
|
2847
2922
|
*
|
|
2848
2923
|
* Реализовано вручную, а не через `AbortSignal.any`: последний появился только в Node 20,
|
|
2849
|
-
* а библиотека поддерживает Node 18.
|
|
2924
|
+
* а библиотека поддерживает Node 18. Причина отмены переносится от источника как есть.
|
|
2850
2925
|
*/
|
|
2851
|
-
function createAbortBundle(userSignal, timeout, clock) {
|
|
2926
|
+
function createAbortBundle(userSignal, lifetimeSignal, timeout, clock) {
|
|
2852
2927
|
const controller = new AbortController();
|
|
2853
2928
|
let timedOut = false;
|
|
2854
|
-
const
|
|
2855
|
-
|
|
2856
|
-
|
|
2929
|
+
const link = (source) => {
|
|
2930
|
+
if (!source) return void 0;
|
|
2931
|
+
if (source.aborted) {
|
|
2932
|
+
controller.abort(source.reason);
|
|
2933
|
+
return;
|
|
2934
|
+
}
|
|
2935
|
+
const onAbort = () => controller.abort(source.reason);
|
|
2936
|
+
source.addEventListener("abort", onAbort, { once: true });
|
|
2937
|
+
return () => source.removeEventListener("abort", onAbort);
|
|
2938
|
+
};
|
|
2939
|
+
const unlink = [link(userSignal), link(lifetimeSignal)];
|
|
2857
2940
|
const cancelTimer = timeout > 0 ? clock.schedule(() => {
|
|
2858
2941
|
timedOut = true;
|
|
2859
2942
|
controller.abort();
|
|
@@ -2863,7 +2946,7 @@ function createAbortBundle(userSignal, timeout, clock) {
|
|
|
2863
2946
|
timedOut: () => timedOut,
|
|
2864
2947
|
cleanup: () => {
|
|
2865
2948
|
cancelTimer?.();
|
|
2866
|
-
|
|
2949
|
+
for (const detach of unlink) detach?.();
|
|
2867
2950
|
}
|
|
2868
2951
|
};
|
|
2869
2952
|
}
|
|
@@ -2900,7 +2983,7 @@ var Transport = class {
|
|
|
2900
2983
|
const headers = await this.#buildHeaders(request, url);
|
|
2901
2984
|
const attempt = request.attempt ?? 1;
|
|
2902
2985
|
const timeout = request.timeout ?? this.#config.timeout;
|
|
2903
|
-
const abort = createAbortBundle(request.signal, timeout, this.#config.clock);
|
|
2986
|
+
const abort = createAbortBundle(request.signal, this.#deps.lifetimeSignal, timeout, this.#config.clock);
|
|
2904
2987
|
const startedAt = this.#config.clock.now();
|
|
2905
2988
|
let cleanupBody;
|
|
2906
2989
|
try {
|
|
@@ -3117,7 +3200,7 @@ var Transport = class {
|
|
|
3117
3200
|
path: request.path
|
|
3118
3201
|
});
|
|
3119
3202
|
if (aborted) {
|
|
3120
|
-
const reason =
|
|
3203
|
+
const reason = abort.signal.reason;
|
|
3121
3204
|
return new require_storage.ItdAbortError(`Запрос ${method} ${request.path} отменён`, reason !== void 0 ? { cause: reason } : void 0);
|
|
3122
3205
|
}
|
|
3123
3206
|
if (error instanceof require_storage.ItdError) return error;
|
|
@@ -3158,8 +3241,12 @@ function createServiceRegistry(config) {
|
|
|
3158
3241
|
function createClientRuntime(options = {}, internals = {}) {
|
|
3159
3242
|
const config = resolveConfig(options);
|
|
3160
3243
|
const jar = new require_multi_storage.CookieJar();
|
|
3161
|
-
const plugins = new PluginRegistry(
|
|
3244
|
+
const plugins = new PluginRegistry({
|
|
3245
|
+
shutdownTimeout: config.shutdownTimeout,
|
|
3246
|
+
clock: config.clock
|
|
3247
|
+
});
|
|
3162
3248
|
const services = createServiceRegistry(config);
|
|
3249
|
+
const lifetime = new AbortController();
|
|
3163
3250
|
const sharedQueues = config.rateLimit ? internals.queues : void 0;
|
|
3164
3251
|
const queues = sharedQueues ?? (config.rateLimit ? new RequestQueuePool(config.rateLimit, config.clock) : void 0);
|
|
3165
3252
|
const ownsQueues = sharedQueues === void 0;
|
|
@@ -3189,7 +3276,8 @@ function createClientRuntime(options = {}, internals = {}) {
|
|
|
3189
3276
|
}, {
|
|
3190
3277
|
cookies: config.useCookieJar ? jar : void 0,
|
|
3191
3278
|
getDeviceId: () => auth.getDeviceId(),
|
|
3192
|
-
onRateLimit: queues && config.rateLimit?.respectHeaders ? throttleByHeaders : void 0
|
|
3279
|
+
onRateLimit: queues && config.rateLimit?.respectHeaders ? throttleByHeaders : void 0,
|
|
3280
|
+
lifetimeSignal: lifetime.signal
|
|
3193
3281
|
});
|
|
3194
3282
|
const stages = [
|
|
3195
3283
|
{
|
|
@@ -3266,9 +3354,10 @@ function createClientRuntime(options = {}, internals = {}) {
|
|
|
3266
3354
|
close: () => {
|
|
3267
3355
|
if (ownsQueues) queues?.stop();
|
|
3268
3356
|
},
|
|
3269
|
-
dispose: () => {
|
|
3357
|
+
dispose: async () => {
|
|
3358
|
+
lifetime.abort(new require_storage.ItdAbortError("Клиент освобождён через dispose(), запрос отменён"));
|
|
3270
3359
|
auth.dispose();
|
|
3271
|
-
|
|
3360
|
+
await plugins.dispose();
|
|
3272
3361
|
}
|
|
3273
3362
|
};
|
|
3274
3363
|
}
|
|
@@ -3626,7 +3715,12 @@ var RealtimeDispatcher = class {
|
|
|
3626
3715
|
if (index >= 0) this.#handlers.splice(index, 1);
|
|
3627
3716
|
};
|
|
3628
3717
|
}
|
|
3629
|
-
|
|
3718
|
+
/**
|
|
3719
|
+
* Принимает обновление к обработке.
|
|
3720
|
+
*
|
|
3721
|
+
* @param coalesceKey ожидающая работа с тем же ключом заменяется новой
|
|
3722
|
+
*/
|
|
3723
|
+
dispatch(context, coalesceKey) {
|
|
3630
3724
|
let keys;
|
|
3631
3725
|
let middleware;
|
|
3632
3726
|
try {
|
|
@@ -3636,12 +3730,20 @@ var RealtimeDispatcher = class {
|
|
|
3636
3730
|
this.#hooks.middlewareError(error, context);
|
|
3637
3731
|
return;
|
|
3638
3732
|
}
|
|
3639
|
-
this.#queue.
|
|
3733
|
+
const replaced = coalesceKey === void 0 ? -1 : this.#queue.findIndex((pending) => pending.coalesceKey === coalesceKey);
|
|
3734
|
+
if (replaced < 0 && this.#queue.length >= 256) {
|
|
3735
|
+
this.#hooks.overflow();
|
|
3736
|
+
return;
|
|
3737
|
+
}
|
|
3738
|
+
const work = {
|
|
3640
3739
|
context,
|
|
3641
3740
|
middleware,
|
|
3642
3741
|
handlers: [...this.#handlers],
|
|
3643
|
-
keys
|
|
3644
|
-
|
|
3742
|
+
keys,
|
|
3743
|
+
coalesceKey
|
|
3744
|
+
};
|
|
3745
|
+
if (replaced >= 0) this.#queue[replaced] = work;
|
|
3746
|
+
else this.#queue.push(work);
|
|
3645
3747
|
this.#pump();
|
|
3646
3748
|
}
|
|
3647
3749
|
/** Отбрасывает обновления, обработка которых ещё не началась. */
|
|
@@ -3718,14 +3820,6 @@ const RECONNECT_BACKOFF = Object.freeze([
|
|
|
3718
3820
|
16e3,
|
|
3719
3821
|
3e4
|
|
3720
3822
|
]);
|
|
3721
|
-
/** Доля случайного разброса паузы. */
|
|
3722
|
-
const RECONNECT_JITTER = .3;
|
|
3723
|
-
/**
|
|
3724
|
-
* Сколько раз пытаться переподключиться подряд.
|
|
3725
|
-
*
|
|
3726
|
-
* После исчерпания поток сообщает `giveup` и ждёт ручного `connect()`.
|
|
3727
|
-
*/
|
|
3728
|
-
const MAX_RECONNECT_ATTEMPTS = 15;
|
|
3729
3823
|
/**
|
|
3730
3824
|
* Вычисляет паузу перед попыткой переподключения.
|
|
3731
3825
|
*
|
|
@@ -4026,7 +4120,8 @@ var RealtimeEngine = class {
|
|
|
4026
4120
|
}, {
|
|
4027
4121
|
deliver: (context) => this.#deps.deliver(context.update),
|
|
4028
4122
|
middlewareError: (error, context) => this.#reportDispatchError("middlewareError", error, context),
|
|
4029
|
-
handlerError: (error, context) => this.#reportDispatchError("handlerError", error, context)
|
|
4123
|
+
handlerError: (error, context) => this.#reportDispatchError("handlerError", error, context),
|
|
4124
|
+
overflow: () => this.#handleOverflow()
|
|
4030
4125
|
});
|
|
4031
4126
|
}
|
|
4032
4127
|
/** Текущее состояние соединения. */
|
|
@@ -4107,7 +4202,23 @@ var RealtimeEngine = class {
|
|
|
4107
4202
|
/** Пропускает актуальное обновление через цепочку обработчиков. */
|
|
4108
4203
|
#dispatch(update, raw, origin) {
|
|
4109
4204
|
if (!this.#wanted) return;
|
|
4110
|
-
this.#dispatcher.dispatch(this.#deps.createContext(update, raw, origin));
|
|
4205
|
+
this.#dispatcher.dispatch(this.#deps.createContext(update, raw, origin), this.#deps.coalesceKey?.(update));
|
|
4206
|
+
}
|
|
4207
|
+
/**
|
|
4208
|
+
* Очередь обновлений достигла предела: закрывает соединение и переподключается,
|
|
4209
|
+
* когда обработчики разберут очередь.
|
|
4210
|
+
*/
|
|
4211
|
+
#handleOverflow() {
|
|
4212
|
+
const controller = this.#controller;
|
|
4213
|
+
if (!this.#wanted || !controller) return;
|
|
4214
|
+
const generation = this.#generation;
|
|
4215
|
+
controller.abort();
|
|
4216
|
+
this.#controller = void 0;
|
|
4217
|
+
this.#setStatus(RealtimeStatus.Error);
|
|
4218
|
+
const error = /* @__PURE__ */ new Error("Обработчики не успевают за потоком: очередь обновлений переполнена");
|
|
4219
|
+
this.#dispatcher.drain().then(() => {
|
|
4220
|
+
if (this.#isCurrentGeneration(generation) && !this.#controller) this.#scheduleReconnect(error);
|
|
4221
|
+
});
|
|
4111
4222
|
}
|
|
4112
4223
|
/** Выполняет доменную синхронизацию, не роняя подключение из-за её ошибки. */
|
|
4113
4224
|
async #sync(reason, generation, starting) {
|
|
@@ -4132,6 +4243,7 @@ var RealtimeEngine = class {
|
|
|
4132
4243
|
baseUrl: this.#deps.baseUrl,
|
|
4133
4244
|
authorize: this.#deps.authorize,
|
|
4134
4245
|
fetch: this.#deps.fetch,
|
|
4246
|
+
request: this.#deps.request,
|
|
4135
4247
|
baseHeaders: this.#deps.baseHeaders,
|
|
4136
4248
|
getToken: this.#deps.getToken,
|
|
4137
4249
|
signal: controller.signal,
|
|
@@ -4230,7 +4342,12 @@ var RealtimeEngine = class {
|
|
|
4230
4342
|
this.#starting = void 0;
|
|
4231
4343
|
if (this.#isCurrentGeneration(generation)) this.#run(generation);
|
|
4232
4344
|
}
|
|
4233
|
-
/**
|
|
4345
|
+
/**
|
|
4346
|
+
* Завершает автоматические попытки переподключения.
|
|
4347
|
+
*
|
|
4348
|
+
* Владелец узнаёт об этом так же, как при {@link disconnect}. `onClose` вызывается
|
|
4349
|
+
* до событий: обработчик `giveup` может тут же вызвать `connect()`.
|
|
4350
|
+
*/
|
|
4234
4351
|
#giveUp(error) {
|
|
4235
4352
|
this.#wanted = false;
|
|
4236
4353
|
this.#generation += 1;
|
|
@@ -4238,6 +4355,7 @@ var RealtimeEngine = class {
|
|
|
4238
4355
|
this.#attempt = 0;
|
|
4239
4356
|
this.#detachEnvironment?.();
|
|
4240
4357
|
this.#detachEnvironment = void 0;
|
|
4358
|
+
this.#deps.onClose?.();
|
|
4241
4359
|
this.#emitEngine("error", {
|
|
4242
4360
|
error,
|
|
4243
4361
|
willReconnect: false
|
|
@@ -4310,26 +4428,15 @@ var PollTransport = class {
|
|
|
4310
4428
|
this.#limit = options.limit ?? 20;
|
|
4311
4429
|
}
|
|
4312
4430
|
async connect(context) {
|
|
4431
|
+
const request = context.request;
|
|
4432
|
+
if (!request) throw new require_storage.ItdConfigError("опрос уведомлений выполняется через конвейер клиента; создайте поток вызовом itd.realtime()");
|
|
4313
4433
|
const seen = /* @__PURE__ */ new Set();
|
|
4314
4434
|
let firstRun = true;
|
|
4315
4435
|
let lastUnreadCount;
|
|
4316
4436
|
while (!context.signal.aborted) {
|
|
4317
|
-
const
|
|
4318
|
-
if (context.authorize && !token) throw new UnauthorizedStreamError();
|
|
4319
|
-
const url = `${require_multi_storage.joinUrl(context.baseUrl, "/api/notifications/")}?limit=${this.#limit}&offset=0`;
|
|
4320
|
-
const headers = await context.baseHeaders(url);
|
|
4321
|
-
headers.set("Accept", "application/json");
|
|
4322
|
-
if (token) headers.set("Authorization", `Bearer ${token}`);
|
|
4323
|
-
const response = await context.fetch(url, {
|
|
4324
|
-
method: "GET",
|
|
4325
|
-
headers,
|
|
4326
|
-
signal: context.signal
|
|
4327
|
-
});
|
|
4328
|
-
if (context.authorize && response.status === 401) throw new UnauthorizedStreamError();
|
|
4329
|
-
if (!response.ok) throw new Error(`Опрос уведомлений вернул статус ${response.status}`);
|
|
4437
|
+
const payload = await this.#readUpdates(request, context.signal);
|
|
4330
4438
|
context.onOpen();
|
|
4331
|
-
const
|
|
4332
|
-
const items = pickArray(typeof body === "object" && body !== null && "data" in body ? body.data : body, "notifications");
|
|
4439
|
+
const items = pickArray(payload, "notifications");
|
|
4333
4440
|
for (const item of [...items].reverse()) {
|
|
4334
4441
|
const id = typeof item.id === "string" ? item.id : void 0;
|
|
4335
4442
|
if (!id || seen.has(id)) continue;
|
|
@@ -4343,7 +4450,7 @@ var PollTransport = class {
|
|
|
4343
4450
|
const excess = [...seen].slice(0, seen.size - this.#limit * 2);
|
|
4344
4451
|
for (const id of excess) seen.delete(id);
|
|
4345
4452
|
}
|
|
4346
|
-
const count = await this.#readCount(
|
|
4453
|
+
const count = await this.#readCount(request, context.signal);
|
|
4347
4454
|
if (count !== void 0 && count !== lastUnreadCount) {
|
|
4348
4455
|
lastUnreadCount = count;
|
|
4349
4456
|
context.onEvent({
|
|
@@ -4355,16 +4462,29 @@ var PollTransport = class {
|
|
|
4355
4462
|
await this.#wait(context.signal);
|
|
4356
4463
|
}
|
|
4357
4464
|
}
|
|
4358
|
-
async #
|
|
4465
|
+
async #readUpdates(request, signal) {
|
|
4359
4466
|
try {
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4467
|
+
return await request({
|
|
4468
|
+
operationId: "realtime.poll.updates",
|
|
4469
|
+
path: "/api/notifications/",
|
|
4470
|
+
query: {
|
|
4471
|
+
limit: this.#limit,
|
|
4472
|
+
offset: 0
|
|
4473
|
+
},
|
|
4474
|
+
signal
|
|
4364
4475
|
});
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4476
|
+
} catch (error) {
|
|
4477
|
+
if (require_storage.isItdAuthError(error)) throw new UnauthorizedStreamError();
|
|
4478
|
+
throw error;
|
|
4479
|
+
}
|
|
4480
|
+
}
|
|
4481
|
+
async #readCount(request, signal) {
|
|
4482
|
+
try {
|
|
4483
|
+
return pickNumber(await request({
|
|
4484
|
+
operationId: "realtime.poll.unread",
|
|
4485
|
+
path: "/api/notifications/count",
|
|
4486
|
+
signal
|
|
4487
|
+
}), "count", 0);
|
|
4368
4488
|
} catch {
|
|
4369
4489
|
return;
|
|
4370
4490
|
}
|
|
@@ -4724,6 +4844,7 @@ var ItdRealtime = class {
|
|
|
4724
4844
|
baseUrl: deps.baseUrl,
|
|
4725
4845
|
authorize: deps.authorize ?? true,
|
|
4726
4846
|
fetch: deps.fetch,
|
|
4847
|
+
request: deps.request,
|
|
4727
4848
|
clock: deps.clock,
|
|
4728
4849
|
baseHeaders: deps.baseHeaders,
|
|
4729
4850
|
getToken: deps.getToken,
|
|
@@ -4734,6 +4855,7 @@ var ItdRealtime = class {
|
|
|
4734
4855
|
transport: createTransport(deps, options),
|
|
4735
4856
|
handleFrame: (event) => this.#handleFrame(event),
|
|
4736
4857
|
readUpdate: readRealtimeUpdate,
|
|
4858
|
+
coalesceKey: (update) => update.type === RealtimeUpdateType.UnreadCount ? update.type : void 0,
|
|
4737
4859
|
createContext: (update, raw, origin) => ({
|
|
4738
4860
|
update,
|
|
4739
4861
|
stream: this,
|
|
@@ -6010,10 +6132,6 @@ function createMultipartFileBody(file) {
|
|
|
6010
6132
|
cancel
|
|
6011
6133
|
};
|
|
6012
6134
|
}
|
|
6013
|
-
//#endregion
|
|
6014
|
-
//#region src/resources/files.ts
|
|
6015
|
-
/** Таймаут одной попытки загрузки файла — 5 минут. */
|
|
6016
|
-
const DEFAULT_UPLOAD_TIMEOUT = 3e5;
|
|
6017
6135
|
/** Файлы и медиа. */
|
|
6018
6136
|
var FilesResource = class extends BaseResource {
|
|
6019
6137
|
#fetch;
|
|
@@ -9095,6 +9213,11 @@ var ItdClient = class ItdClient {
|
|
|
9095
9213
|
stream = new ItdRealtime({
|
|
9096
9214
|
baseUrl: this.#runtime.config.baseUrl,
|
|
9097
9215
|
fetch: this.#runtime.config.fetch,
|
|
9216
|
+
request: ({ operationId, path, query, signal }) => this.#runtime.http.operation(operationId, {
|
|
9217
|
+
path,
|
|
9218
|
+
query,
|
|
9219
|
+
signal
|
|
9220
|
+
}),
|
|
9098
9221
|
baseHeaders: (url) => this.#runtime.platformHeaders(url),
|
|
9099
9222
|
getAuthIdentity: () => this.#runtime.auth.getCurrentAuthIdentity(),
|
|
9100
9223
|
getAuthScope: () => this.#runtime.auth.getAuthScope(),
|
|
@@ -9114,13 +9237,16 @@ var ItdClient = class ItdClient {
|
|
|
9114
9237
|
* Освобождает ресурсы клиента: закрывает все потоки уведомлений, отправляет открытые
|
|
9115
9238
|
* накопители {@link telemetry}, затем останавливает очередь запросов.
|
|
9116
9239
|
*
|
|
9117
|
-
* Метод дожидается активных обработчиков
|
|
9118
|
-
* снова; ранее созданный поток можно запустить
|
|
9240
|
+
* Метод дожидается активных обработчиков потока, но не дольше `shutdownTimeout`. После
|
|
9241
|
+
* вызова клиентом можно пользоваться снова; ранее созданный поток можно запустить
|
|
9242
|
+
* повторным `connect()`.
|
|
9119
9243
|
*
|
|
9120
9244
|
* Общая очередь, полученная от {@link ItdAccounts}, не останавливается: её гасит сам
|
|
9121
9245
|
* контейнер, когда закрывает все аккаунты разом.
|
|
9122
9246
|
*
|
|
9123
9247
|
* Терминальное освобождение — это {@link dispose}.
|
|
9248
|
+
*
|
|
9249
|
+
* @throws {ItdStateError} если обработчики потока не завершились за отведённый срок
|
|
9124
9250
|
*/
|
|
9125
9251
|
async close() {
|
|
9126
9252
|
return this.#close(false);
|
|
@@ -9128,22 +9254,30 @@ var ItdClient = class ItdClient {
|
|
|
9128
9254
|
async #close(disposeCleanup) {
|
|
9129
9255
|
const streams = this.#disconnectStreams();
|
|
9130
9256
|
if (disposeCleanup) prepareTelemetryForDispose(this.#telemetry);
|
|
9257
|
+
const { shutdownTimeout, clock } = this.#runtime.config;
|
|
9258
|
+
const deadline = createDeadline(shutdownTimeout, clock);
|
|
9259
|
+
let stuck = [];
|
|
9131
9260
|
try {
|
|
9132
|
-
await Promise.all(streams.map((stream) => stream.drain()));
|
|
9261
|
+
stuck = (await Promise.all(streams.map(async (stream) => await deadline.wait(stream.drain()) ? void 0 : stream))).filter((stream) => stream !== void 0);
|
|
9133
9262
|
if (disposeCleanup) await closeTelemetryForDispose(this.#telemetry);
|
|
9134
9263
|
else await this.#telemetry?.close();
|
|
9135
9264
|
} finally {
|
|
9265
|
+
deadline.cancel();
|
|
9136
9266
|
this.#runtime.close();
|
|
9137
9267
|
}
|
|
9268
|
+
if (stuck.length > 0) throw new require_storage.ItdStateError(`обработчики потоков (${stuck.map((stream) => stream.transport).join(", ")}) не завершились за ${shutdownTimeout} мс; ожидание прекращено`);
|
|
9138
9269
|
}
|
|
9139
9270
|
/**
|
|
9140
|
-
* Окончательно освобождает клиент: выполняет {@link close}
|
|
9271
|
+
* Окончательно освобождает клиент: выполняет {@link close}, отменяет незавершённые
|
|
9272
|
+
* запросы и отключает все плагины.
|
|
9141
9273
|
*
|
|
9142
9274
|
* Терминальное состояние устанавливается сразу при первом вызове. После этого новые
|
|
9143
9275
|
* запросы, подключение плагинов, регистрация сервисов и создание или повторный запуск
|
|
9144
9276
|
* realtime-потоков завершаются с {@link ItdStateError}. Повторные вызовы возвращают
|
|
9145
9277
|
* тот же результат очистки.
|
|
9146
9278
|
*
|
|
9279
|
+
* Ожидание обработчиков потока и операций плагинов ограничено `shutdownTimeout`.
|
|
9280
|
+
*
|
|
9147
9281
|
* @example
|
|
9148
9282
|
* ```ts
|
|
9149
9283
|
* await using itd = new ItdClient({ auth: token });
|
|
@@ -10122,10 +10256,6 @@ var RealtimeComposer = class RealtimeComposer {
|
|
|
10122
10256
|
return (context, next) => runRealtimeMiddleware(snapshot, context, next);
|
|
10123
10257
|
}
|
|
10124
10258
|
};
|
|
10125
|
-
//#endregion
|
|
10126
|
-
//#region src/realtime/websocket.ts
|
|
10127
|
-
/** Стандартный путь WebSocket-подключения. */
|
|
10128
|
-
const WEBSOCKET_PATH = "/api/ws";
|
|
10129
10259
|
const CONNECTING = 0;
|
|
10130
10260
|
const OPEN = 1;
|
|
10131
10261
|
const NORMAL_CLOSURE = 1e3;
|
|
@@ -10263,6 +10393,7 @@ var WebSocketTransport = class {
|
|
|
10263
10393
|
let discardMessages = false;
|
|
10264
10394
|
let socketError;
|
|
10265
10395
|
let messageQueue = Promise.resolve();
|
|
10396
|
+
let pendingFrames = 0;
|
|
10266
10397
|
let cancelHandshake;
|
|
10267
10398
|
let cancelIdle;
|
|
10268
10399
|
let cancelKeepAlive;
|
|
@@ -10341,7 +10472,13 @@ var WebSocketTransport = class {
|
|
|
10341
10472
|
pending = Promise.resolve({ error });
|
|
10342
10473
|
}
|
|
10343
10474
|
if (pending === void 0) return;
|
|
10475
|
+
if (pendingFrames >= 256) {
|
|
10476
|
+
closeWithError(/* @__PURE__ */ new Error(`WebSocket ${redactUrl(url)}: очередь кадров переполнена`), 4e3, "queue overflow");
|
|
10477
|
+
return;
|
|
10478
|
+
}
|
|
10479
|
+
pendingFrames += 1;
|
|
10344
10480
|
messageQueue = messageQueue.then(async () => {
|
|
10481
|
+
pendingFrames -= 1;
|
|
10345
10482
|
if (settled || discardMessages) return;
|
|
10346
10483
|
const decoded = await pending;
|
|
10347
10484
|
if ("error" in decoded) {
|
|
@@ -10636,21 +10773,10 @@ function renderSpans(content, spans = [], options = {}) {
|
|
|
10636
10773
|
//#endregion
|
|
10637
10774
|
exports.ALLOWED_MIME_TYPES = ALLOWED_MIME_TYPES;
|
|
10638
10775
|
exports.AUDIO_MIME_TYPES = AUDIO_MIME_TYPES;
|
|
10639
|
-
exports.AUTH_FLAG_COOKIE = require_multi_storage.AUTH_FLAG_COOKIE;
|
|
10640
|
-
exports.AUTH_PATHS = AUTH_PATHS;
|
|
10641
10776
|
exports.AccessType = AccessType;
|
|
10642
10777
|
exports.AttachmentType = AttachmentType;
|
|
10643
|
-
exports.BUILT_IN_SERVICES = BUILT_IN_SERVICES;
|
|
10644
10778
|
exports.CommentSort = CommentSort;
|
|
10645
10779
|
exports.DEFAULT_BASE_URL = DEFAULT_BASE_URL;
|
|
10646
|
-
exports.DEFAULT_FILE_STREAM_BUFFER_BYTES = require_multi_storage.DEFAULT_FILE_STREAM_BUFFER_BYTES;
|
|
10647
|
-
exports.DEFAULT_STATUS_BASE_URL = DEFAULT_STATUS_BASE_URL;
|
|
10648
|
-
exports.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT;
|
|
10649
|
-
exports.DEFAULT_UPLOAD_TIMEOUT = DEFAULT_UPLOAD_TIMEOUT;
|
|
10650
|
-
exports.DEFAULT_URL_FILE_MAX_BYTES = require_multi_storage.DEFAULT_URL_FILE_MAX_BYTES;
|
|
10651
|
-
exports.DEFAULT_USER_AGENT = DEFAULT_USER_AGENT;
|
|
10652
|
-
exports.DEVICE_ID_HEADER = DEVICE_ID_HEADER;
|
|
10653
|
-
exports.DetectedRuntime = DetectedRuntime;
|
|
10654
10780
|
exports.FeedTab = FeedTab;
|
|
10655
10781
|
exports.FileTransferMode = require_multi_storage.FileTransferMode;
|
|
10656
10782
|
exports.IMAGE_MIME_TYPES = IMAGE_MIME_TYPES;
|
|
@@ -10681,19 +10807,13 @@ exports.ItdTimeoutError = require_storage.ItdTimeoutError;
|
|
|
10681
10807
|
exports.ItdValidationError = require_storage.ItdValidationError;
|
|
10682
10808
|
exports.LIBRARY_VERSION = LIBRARY_VERSION;
|
|
10683
10809
|
exports.LikesVisibility = LikesVisibility;
|
|
10684
|
-
exports.MAX_RECONNECT_ATTEMPTS = MAX_RECONNECT_ATTEMPTS;
|
|
10685
10810
|
exports.MemoryKeyValueStore = require_storage.MemoryKeyValueStore;
|
|
10686
10811
|
exports.MemoryMultiTokenStorage = require_multi_storage.MemoryMultiTokenStorage;
|
|
10687
10812
|
exports.MemoryTokenStorage = require_storage.MemoryTokenStorage;
|
|
10688
|
-
exports.NOTIFICATION_TYPE_ALIASES = NOTIFICATION_TYPE_ALIASES;
|
|
10689
10813
|
exports.NotificationType = NotificationType;
|
|
10690
10814
|
exports.OPERATIONS = OPERATIONS;
|
|
10691
10815
|
exports.PaginationMode = PaginationMode;
|
|
10692
10816
|
exports.Paginator = Paginator;
|
|
10693
|
-
exports.RECONNECT_BACKOFF = RECONNECT_BACKOFF;
|
|
10694
|
-
exports.RECONNECT_JITTER = RECONNECT_JITTER;
|
|
10695
|
-
exports.REFRESH_COOKIE = require_multi_storage.REFRESH_COOKIE;
|
|
10696
|
-
exports.REFRESH_COOKIE_PATH = require_multi_storage.REFRESH_COOKIE_PATH;
|
|
10697
10817
|
exports.RealtimeComposer = RealtimeComposer;
|
|
10698
10818
|
exports.RealtimeRouter = RealtimeRouter;
|
|
10699
10819
|
exports.RealtimeStatus = RealtimeStatus;
|
|
@@ -10705,8 +10825,6 @@ exports.ReportTargetType = ReportTargetType;
|
|
|
10705
10825
|
exports.RetrySafety = RetrySafety;
|
|
10706
10826
|
exports.RuntimeMode = RuntimeMode;
|
|
10707
10827
|
exports.STATUS_SERVICE = STATUS_SERVICE;
|
|
10708
|
-
exports.STREAM_PATH = STREAM_PATH;
|
|
10709
|
-
exports.ServiceRegistry = ServiceRegistry;
|
|
10710
10828
|
exports.ServiceState = ServiceState;
|
|
10711
10829
|
exports.SignInStatus = SignInStatus;
|
|
10712
10830
|
exports.SpanRenderFormat = SpanRenderFormat;
|
|
@@ -10716,7 +10834,6 @@ exports.UnauthorizedStreamError = UnauthorizedStreamError;
|
|
|
10716
10834
|
exports.VIDEO_MIME_TYPES = VIDEO_MIME_TYPES;
|
|
10717
10835
|
exports.ViewReason = ViewReason;
|
|
10718
10836
|
exports.ViewSource = ViewSource;
|
|
10719
|
-
exports.WEBSOCKET_PATH = WEBSOCKET_PATH;
|
|
10720
10837
|
exports.WallAccess = WallAccess;
|
|
10721
10838
|
exports.WebSocketTransport = WebSocketTransport;
|
|
10722
10839
|
exports.autoSpans = autoSpans;
|
|
@@ -10757,8 +10874,6 @@ exports.parseHtml = parseHtml;
|
|
|
10757
10874
|
exports.parseMarkdown = parseMarkdown;
|
|
10758
10875
|
exports.poll = poll;
|
|
10759
10876
|
exports.post = post;
|
|
10760
|
-
exports.readNotificationEvent = readNotificationEvent;
|
|
10761
|
-
exports.readUnreadCountEvent = readUnreadCountEvent;
|
|
10762
10877
|
exports.renderSpans = renderSpans;
|
|
10763
10878
|
exports.report = report;
|
|
10764
10879
|
exports.resolveNotificationUrl = resolveNotificationUrl;
|