itd-api 0.0.8 → 0.0.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.
- package/README.md +79 -15
- package/dist/{chunk-ATCZ4T2K.cjs → chunk-HTF2MOM4.cjs} +517 -130
- package/dist/chunk-HTF2MOM4.cjs.map +1 -0
- package/dist/{chunk-JIYN33FG.js → chunk-MYAU2WJU.js} +507 -131
- package/dist/chunk-MYAU2WJU.js.map +1 -0
- package/dist/index.cjs +133 -89
- package/dist/index.d.cts +4206 -1
- package/dist/index.d.ts +4206 -1
- package/dist/index.js +1 -1
- package/dist/node.cjs +143 -95
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +3 -3
- package/dist/node.d.ts +3 -3
- package/dist/node.js +13 -9
- package/dist/node.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-ATCZ4T2K.cjs.map +0 -1
- package/dist/chunk-JIYN33FG.js.map +0 -1
- package/dist/index-Duh31Wnx.d.cts +0 -3933
- package/dist/index-Duh31Wnx.d.ts +0 -3933
|
@@ -616,6 +616,20 @@ var RealtimeStatus = Object.freeze({
|
|
|
616
616
|
Error: "error",
|
|
617
617
|
Disconnected: "disconnected"
|
|
618
618
|
});
|
|
619
|
+
var ServiceState = Object.freeze({
|
|
620
|
+
/** Работает штатно. */
|
|
621
|
+
Operational: "operational",
|
|
622
|
+
/** Работает с деградацией. */
|
|
623
|
+
Degraded: "degraded",
|
|
624
|
+
/** Недоступен. */
|
|
625
|
+
Downtime: "downtime"
|
|
626
|
+
});
|
|
627
|
+
var IncidentKind = Object.freeze({
|
|
628
|
+
/** Недоступен. */
|
|
629
|
+
Down: "down",
|
|
630
|
+
/** Деградация. */
|
|
631
|
+
Degraded: "deg"
|
|
632
|
+
});
|
|
619
633
|
var AccessType = Object.freeze({
|
|
620
634
|
/** Никто. */
|
|
621
635
|
Nobody: "nobody",
|
|
@@ -1285,8 +1299,18 @@ function hasLocalStorage() {
|
|
|
1285
1299
|
|
|
1286
1300
|
// src/core/auth.ts
|
|
1287
1301
|
var AUTH_PATHS = {
|
|
1302
|
+
signUp: "/api/v1/auth/sign-up",
|
|
1288
1303
|
signIn: "/api/v1/auth/sign-in",
|
|
1289
|
-
|
|
1304
|
+
verifyOtp: "/api/v1/auth/verify-otp",
|
|
1305
|
+
resendOtp: "/api/v1/auth/resend-otp",
|
|
1306
|
+
refresh: "/api/v1/auth/refresh",
|
|
1307
|
+
logout: "/api/v1/auth/logout",
|
|
1308
|
+
forgotPassword: "/api/v1/auth/forgot-password",
|
|
1309
|
+
resetPassword: "/api/v1/auth/reset-password",
|
|
1310
|
+
changePassword: "/api/v1/auth/change-password",
|
|
1311
|
+
sessions: "/api/v1/auth/sessions",
|
|
1312
|
+
/** Префикс внешнего входа: к нему дописывается имя провайдера. */
|
|
1313
|
+
oauthLogin: "/api/v1/auth/login"
|
|
1290
1314
|
};
|
|
1291
1315
|
var TURNSTILE_SITE_KEY = "0x4AAAAAACHhxczw6fJGwPBg";
|
|
1292
1316
|
var DEVICE_ID_HEADER = "X-Device-Id";
|
|
@@ -1358,7 +1382,7 @@ var AuthManager = class {
|
|
|
1358
1382
|
/** То же самое, но без чтения хранилища — для вызовов, где сессия уже загружена. */
|
|
1359
1383
|
#hasRefreshSession() {
|
|
1360
1384
|
if (!this.#config.useCookieJar) return true;
|
|
1361
|
-
if (this.#jar.has(AUTH_FLAG_COOKIE)) return true;
|
|
1385
|
+
if (this.#jar.has(AUTH_FLAG_COOKIE, this.#config.baseUrl)) return true;
|
|
1362
1386
|
return Boolean(this.#session?.refreshToken);
|
|
1363
1387
|
}
|
|
1364
1388
|
/** Заголовки авторизации для очередного запроса. Пустой объект, если токена нет. */
|
|
@@ -1463,12 +1487,14 @@ var AuthManager = class {
|
|
|
1463
1487
|
async getSession() {
|
|
1464
1488
|
return this.#loadSession();
|
|
1465
1489
|
}
|
|
1466
|
-
/** Заменяет сессию целиком. */
|
|
1490
|
+
/** Заменяет сессию и связанные с ней cookie целиком. */
|
|
1467
1491
|
async setSession(session) {
|
|
1492
|
+
this.#jar.clear();
|
|
1468
1493
|
this.#jar.deserialize(session.cookies);
|
|
1469
|
-
this.#deviceId
|
|
1470
|
-
|
|
1494
|
+
if (session.deviceId) this.#deviceId = session.deviceId;
|
|
1495
|
+
this.#session = session;
|
|
1471
1496
|
this.#seedRefreshCookie();
|
|
1497
|
+
await this.#saveSession(session);
|
|
1472
1498
|
}
|
|
1473
1499
|
/**
|
|
1474
1500
|
* Забывает сессию и cookie. Сетевой запрос не выполняется.
|
|
@@ -1632,7 +1658,7 @@ var AuthManager = class {
|
|
|
1632
1658
|
}
|
|
1633
1659
|
if (credentials.turnstileToken) return credentials.turnstileToken;
|
|
1634
1660
|
throw new ItdConfigError(
|
|
1635
|
-
"\u0412\u0445\u043E\u0434 \u043F\u043E email \u0438 \u043F\u0430\u0440\u043E\u043B\u044E \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0442\u043E\u043A\u0435\u043D \u043A\u0430\u043F\u0447\u0438 Cloudflare Turnstile: \u0431\u0435\u0437 \u043D\u0435\u0433\u043E \u0441\u0435\u0440\u0432\u0435\u0440 \u043E\u0442\u0432\u0435\u0447\u0430\u0435\u0442 422. \u041F\u0435\u0440\u0435\u0434\u0430\u0439\u0442\u0435 auth.getTurnstileToken (\u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A \u0441\u0432\u0435\u0436\u0435\u0433\u043E \u0442\u043E\u043A\u0435\u043D\u0430) \u043B\u0438\u0431\u043E \u0440\u0430\u0437\u043E\u0432\u044B\u0439 auth.turnstileToken. \u041A\u043B\u044E\u0447 \u0432\u0438\u0434\u0436\u0435\u0442\u0430 \u2014 TURNSTILE_SITE_KEY. \u0412 Node \u0442\u043E\u043A\u0435\u043D \u0443\u043C\u0435\u0435\u0442 \u0434\u043E\u0431\u044B\u0432\u0430\u0442\u044C \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u044B\u0439 \u043F\u0430\u043A\u0435\u0442: npm i itd-api
|
|
1661
|
+
"\u0412\u0445\u043E\u0434 \u043F\u043E email \u0438 \u043F\u0430\u0440\u043E\u043B\u044E \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0442\u043E\u043A\u0435\u043D \u043A\u0430\u043F\u0447\u0438 Cloudflare Turnstile: \u0431\u0435\u0437 \u043D\u0435\u0433\u043E \u0441\u0435\u0440\u0432\u0435\u0440 \u043E\u0442\u0432\u0435\u0447\u0430\u0435\u0442 422. \u041F\u0435\u0440\u0435\u0434\u0430\u0439\u0442\u0435 auth.getTurnstileToken (\u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A \u0441\u0432\u0435\u0436\u0435\u0433\u043E \u0442\u043E\u043A\u0435\u043D\u0430) \u043B\u0438\u0431\u043E \u0440\u0430\u0437\u043E\u0432\u044B\u0439 auth.turnstileToken. \u041A\u043B\u044E\u0447 \u0432\u0438\u0434\u0436\u0435\u0442\u0430 \u2014 TURNSTILE_SITE_KEY. \u0412 Node \u0442\u043E\u043A\u0435\u043D \u0443\u043C\u0435\u0435\u0442 \u0434\u043E\u0431\u044B\u0432\u0430\u0442\u044C \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u044B\u0439 \u043F\u0430\u043A\u0435\u0442: npm i @itd-api/turnstile, \u0437\u0430\u0442\u0435\u043C getTurnstileToken: createTurnstileSolver()."
|
|
1636
1662
|
);
|
|
1637
1663
|
}
|
|
1638
1664
|
async #performSignIn(credentials) {
|
|
@@ -1677,6 +1703,7 @@ var MemoryTokenStorage = class {
|
|
|
1677
1703
|
var LocalStorageTokenStorage = class {
|
|
1678
1704
|
#key;
|
|
1679
1705
|
#fallback = new MemoryTokenStorage();
|
|
1706
|
+
/** Доступен ли `localStorage` для дальнейших операций. */
|
|
1680
1707
|
#available;
|
|
1681
1708
|
/** @param key ключ в `localStorage`. По умолчанию `itd-api:session`. */
|
|
1682
1709
|
constructor(key = "itd-api:session") {
|
|
@@ -1695,26 +1722,31 @@ var LocalStorageTokenStorage = class {
|
|
|
1695
1722
|
}
|
|
1696
1723
|
}
|
|
1697
1724
|
set(session) {
|
|
1698
|
-
if (
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
this.#fallback.set(session);
|
|
1725
|
+
if (this.#available) {
|
|
1726
|
+
try {
|
|
1727
|
+
globalThis.localStorage.setItem(this.#key, JSON.stringify(session));
|
|
1728
|
+
return;
|
|
1729
|
+
} catch {
|
|
1730
|
+
this.#degrade();
|
|
1731
|
+
}
|
|
1706
1732
|
}
|
|
1733
|
+
this.#fallback.set(session);
|
|
1707
1734
|
}
|
|
1708
1735
|
clear() {
|
|
1709
|
-
if (
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
this.#fallback.clear();
|
|
1736
|
+
if (this.#available) {
|
|
1737
|
+
try {
|
|
1738
|
+
globalThis.localStorage.removeItem(this.#key);
|
|
1739
|
+
return;
|
|
1740
|
+
} catch {
|
|
1741
|
+
this.#degrade();
|
|
1742
|
+
}
|
|
1717
1743
|
}
|
|
1744
|
+
this.#fallback.clear();
|
|
1745
|
+
}
|
|
1746
|
+
/** Переводит хранилище в память без переноса прежнего значения. */
|
|
1747
|
+
#degrade() {
|
|
1748
|
+
this.#available = false;
|
|
1749
|
+
this.#fallback.clear();
|
|
1718
1750
|
}
|
|
1719
1751
|
};
|
|
1720
1752
|
function createTokenStorage(handlers) {
|
|
@@ -1770,10 +1802,15 @@ function normalizeBaseUrl(baseUrl) {
|
|
|
1770
1802
|
}
|
|
1771
1803
|
|
|
1772
1804
|
// src/core/version.ts
|
|
1773
|
-
var LIBRARY_VERSION = "0.0.
|
|
1805
|
+
var LIBRARY_VERSION = "0.0.9";
|
|
1774
1806
|
|
|
1775
1807
|
// src/core/config.ts
|
|
1776
1808
|
var DEFAULT_BASE_URL = "https://xn--d1ah4a.com";
|
|
1809
|
+
var DEFAULT_STATUS_BASE_URL = "https://xn--80a7abcbg.xn--d1ah4a.com";
|
|
1810
|
+
var STATUS_SERVICE = "status";
|
|
1811
|
+
var BUILT_IN_SERVICES = Object.freeze([
|
|
1812
|
+
Object.freeze({ name: STATUS_SERVICE, baseUrl: DEFAULT_STATUS_BASE_URL, auth: false })
|
|
1813
|
+
]);
|
|
1777
1814
|
var DEFAULT_TIMEOUT = 3e4;
|
|
1778
1815
|
var DEFAULT_USER_AGENT = `Mozilla/5.0 (compatible; itd-api/${LIBRARY_VERSION}; +https://github.com/KiowDev/itd-api)`;
|
|
1779
1816
|
var DEFAULT_RATE_LIMIT_DELAYS = Object.freeze([1e3, 5e3, 3e4, 6e4, 9e4]);
|
|
@@ -1886,6 +1923,12 @@ function validateAuth(auth) {
|
|
|
1886
1923
|
"auth \u043D\u0435 \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u043D. \u041E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F \u0441\u0442\u0440\u043E\u043A\u0430 \u0441 accessToken \u043B\u0438\u0431\u043E \u043E\u0431\u044A\u0435\u043A\u0442 { accessToken }, { email, password } \u0438\u043B\u0438 { getToken }"
|
|
1887
1924
|
);
|
|
1888
1925
|
}
|
|
1926
|
+
function resolveServices(services) {
|
|
1927
|
+
if (!services) return [];
|
|
1928
|
+
return Object.entries(services).map(
|
|
1929
|
+
([name, value]) => typeof value === "string" ? { name, baseUrl: value } : { ...value, name }
|
|
1930
|
+
);
|
|
1931
|
+
}
|
|
1889
1932
|
function resolveConfig(options = {}) {
|
|
1890
1933
|
const mode = options.mode ?? RuntimeMode.Auto;
|
|
1891
1934
|
if (!Object.values(RuntimeMode).includes(mode)) {
|
|
@@ -1899,6 +1942,7 @@ function resolveConfig(options = {}) {
|
|
|
1899
1942
|
}
|
|
1900
1943
|
return {
|
|
1901
1944
|
baseUrl: normalizeBaseUrl(options.baseUrl ?? DEFAULT_BASE_URL),
|
|
1945
|
+
services: resolveServices(options.services),
|
|
1902
1946
|
auth: validateAuth(options.auth),
|
|
1903
1947
|
storage: options.storage ?? new MemoryTokenStorage(),
|
|
1904
1948
|
autoRefresh: options.autoRefresh ?? true,
|
|
@@ -2005,7 +2049,7 @@ function sleep(ms) {
|
|
|
2005
2049
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2006
2050
|
}
|
|
2007
2051
|
function createQueueMiddleware(schedule) {
|
|
2008
|
-
return (request, next) => request.skipQueue ? next(request) : schedule(() => next(request));
|
|
2052
|
+
return (request, next) => request.skipQueue ? next(request) : schedule(request, () => next(request));
|
|
2009
2053
|
}
|
|
2010
2054
|
function createPluginsMiddleware(plugins) {
|
|
2011
2055
|
return (request, next) => {
|
|
@@ -2013,6 +2057,18 @@ function createPluginsMiddleware(plugins) {
|
|
|
2013
2057
|
return plugins.run(request, next);
|
|
2014
2058
|
};
|
|
2015
2059
|
}
|
|
2060
|
+
function createServicesMiddleware(registry) {
|
|
2061
|
+
return async (request, next) => {
|
|
2062
|
+
if (request.service === void 0) return next(request);
|
|
2063
|
+
const service = registry.require(request.service);
|
|
2064
|
+
let prepared = request.baseUrl === void 0 ? { ...request, baseUrl: service.baseUrl } : request;
|
|
2065
|
+
if (service.headers) prepared = withLayerHeaders(prepared, service.headers);
|
|
2066
|
+
if (service.auth === false && prepared.skipAuth === void 0) {
|
|
2067
|
+
prepared = { ...prepared, skipAuth: true };
|
|
2068
|
+
}
|
|
2069
|
+
return next(prepared);
|
|
2070
|
+
};
|
|
2071
|
+
}
|
|
2016
2072
|
async function applyAuth(request, deps) {
|
|
2017
2073
|
if (request.skipAuth) return request;
|
|
2018
2074
|
const headers = await deps.getAuthHeaders();
|
|
@@ -2042,11 +2098,11 @@ function resolveBackoff(retry, global) {
|
|
|
2042
2098
|
}
|
|
2043
2099
|
function createRetryMiddleware(deps) {
|
|
2044
2100
|
const globalScheduler = deps.retry ? createRetryScheduler(deps.retry) : void 0;
|
|
2045
|
-
const nextDelay = (error, attempt, method, backoff) => {
|
|
2101
|
+
const nextDelay = (error, attempt, request, method, backoff) => {
|
|
2046
2102
|
if (isItdRateLimitError(error)) {
|
|
2047
2103
|
const wait = error.retryAfter ?? deps.rateLimitDelays[attempt - 1];
|
|
2048
2104
|
if (wait === void 0) return void 0;
|
|
2049
|
-
deps.pauseQueue?.(wait);
|
|
2105
|
+
deps.pauseQueue?.(wait, request);
|
|
2050
2106
|
deps.logger?.debug(`\u043B\u0438\u043C\u0438\u0442 \u0447\u0430\u0441\u0442\u043E\u0442\u044B, \u043F\u043E\u043F\u044B\u0442\u043A\u0430 ${attempt + 1} \u0447\u0435\u0440\u0435\u0437 ${wait} \u043C\u0441`);
|
|
2051
2107
|
return wait;
|
|
2052
2108
|
}
|
|
@@ -2059,13 +2115,14 @@ function createRetryMiddleware(deps) {
|
|
|
2059
2115
|
try {
|
|
2060
2116
|
return await next({ ...request, attempt });
|
|
2061
2117
|
} catch (error) {
|
|
2062
|
-
const delay = nextDelay(error, attempt, method, backoff);
|
|
2118
|
+
const delay = nextDelay(error, attempt, request, method, backoff);
|
|
2063
2119
|
if (delay === void 0) throw error;
|
|
2064
2120
|
await deps.hooks.onRetry?.({
|
|
2065
2121
|
method,
|
|
2066
2122
|
path: request.path,
|
|
2067
2123
|
url: deps.buildUrl(request),
|
|
2068
|
-
|
|
2124
|
+
// Умолчания транспорта добавляются после слоя повторов и сюда не входят.
|
|
2125
|
+
headers: new Headers({ ...request.layerHeaders, ...request.headers }),
|
|
2069
2126
|
attempt,
|
|
2070
2127
|
error,
|
|
2071
2128
|
delay
|
|
@@ -2088,6 +2145,8 @@ var RESERVED_OPTION_KEYS = /* @__PURE__ */ new Set([
|
|
|
2088
2145
|
"retry",
|
|
2089
2146
|
"method",
|
|
2090
2147
|
"path",
|
|
2148
|
+
"service",
|
|
2149
|
+
"baseUrl",
|
|
2091
2150
|
"query",
|
|
2092
2151
|
"body",
|
|
2093
2152
|
"skipAuth",
|
|
@@ -2255,6 +2314,107 @@ var RequestQueue = class {
|
|
|
2255
2314
|
this.#drain();
|
|
2256
2315
|
}
|
|
2257
2316
|
};
|
|
2317
|
+
var RequestQueuePool = class {
|
|
2318
|
+
#options;
|
|
2319
|
+
#main;
|
|
2320
|
+
/** Очереди сервисов заводятся при первом запросе — обычно не нужна ни одна. */
|
|
2321
|
+
#byService = /* @__PURE__ */ new Map();
|
|
2322
|
+
constructor(options) {
|
|
2323
|
+
this.#options = options;
|
|
2324
|
+
this.#main = new RequestQueue(options);
|
|
2325
|
+
}
|
|
2326
|
+
/** Очередь хоста. */
|
|
2327
|
+
for(service) {
|
|
2328
|
+
if (service === void 0) return this.#main;
|
|
2329
|
+
let queue = this.#byService.get(service);
|
|
2330
|
+
if (!queue) {
|
|
2331
|
+
queue = new RequestQueue(this.#options);
|
|
2332
|
+
this.#byService.set(service, queue);
|
|
2333
|
+
}
|
|
2334
|
+
return queue;
|
|
2335
|
+
}
|
|
2336
|
+
/** Останавливает все очереди. */
|
|
2337
|
+
stop() {
|
|
2338
|
+
this.#main.stop();
|
|
2339
|
+
for (const queue of this.#byService.values()) queue.stop();
|
|
2340
|
+
}
|
|
2341
|
+
};
|
|
2342
|
+
|
|
2343
|
+
// src/core/services.ts
|
|
2344
|
+
function hostOf(url) {
|
|
2345
|
+
try {
|
|
2346
|
+
return new URL(url).hostname.toLowerCase();
|
|
2347
|
+
} catch {
|
|
2348
|
+
return "";
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2351
|
+
function isSameSite(primaryHost, host) {
|
|
2352
|
+
if (!primaryHost || !host) return false;
|
|
2353
|
+
return host === primaryHost || host.endsWith(`.${primaryHost}`);
|
|
2354
|
+
}
|
|
2355
|
+
var ServiceRegistry = class {
|
|
2356
|
+
#services = /* @__PURE__ */ new Map();
|
|
2357
|
+
/** Хост основного API. */
|
|
2358
|
+
#primaryHost;
|
|
2359
|
+
/** @param primaryBaseUrl базовый URL клиента */
|
|
2360
|
+
constructor(primaryBaseUrl) {
|
|
2361
|
+
this.#primaryHost = primaryBaseUrl ? hostOf(primaryBaseUrl) : "";
|
|
2362
|
+
}
|
|
2363
|
+
/**
|
|
2364
|
+
* Регистрирует сервис. Имя очищается от краевых пробелов, базовый URL приводится
|
|
2365
|
+
* к каноничному виду, а незаданный `auth` выводится из хоста.
|
|
2366
|
+
*
|
|
2367
|
+
* @throws {ItdConfigError} если имя пустое, имя занято или `baseUrl` не абсолютный URL
|
|
2368
|
+
*/
|
|
2369
|
+
define(definition) {
|
|
2370
|
+
const raw = definition?.name;
|
|
2371
|
+
if (typeof raw !== "string" || raw.trim() === "") {
|
|
2372
|
+
throw new ItdConfigError("\u0423 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0435\u043F\u0443\u0441\u0442\u043E\u0435 \u0438\u043C\u044F");
|
|
2373
|
+
}
|
|
2374
|
+
const name = raw.trim();
|
|
2375
|
+
if (this.#services.has(name)) {
|
|
2376
|
+
throw new ItdConfigError(`\u0421\u0435\u0440\u0432\u0438\u0441 \xAB${name}\xBB \u0443\u0436\u0435 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u043D \u0438 \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u0437\u0430\u043C\u0435\u043D\u0451\u043D`);
|
|
2377
|
+
}
|
|
2378
|
+
const baseUrl = normalizeBaseUrl(definition.baseUrl);
|
|
2379
|
+
this.#services.set(name, {
|
|
2380
|
+
...definition,
|
|
2381
|
+
name,
|
|
2382
|
+
baseUrl,
|
|
2383
|
+
auth: definition.auth ?? isSameSite(this.#primaryHost, hostOf(baseUrl))
|
|
2384
|
+
});
|
|
2385
|
+
}
|
|
2386
|
+
/** Определение сервиса либо `undefined`, если такого нет. */
|
|
2387
|
+
get(name) {
|
|
2388
|
+
return this.#services.get(name);
|
|
2389
|
+
}
|
|
2390
|
+
/** Зарегистрирован ли сервис с таким именем. */
|
|
2391
|
+
has(name) {
|
|
2392
|
+
return this.#services.has(name);
|
|
2393
|
+
}
|
|
2394
|
+
/**
|
|
2395
|
+
* Определение сервиса.
|
|
2396
|
+
*
|
|
2397
|
+
* @throws {ItdConfigError} если сервис не зарегистрирован
|
|
2398
|
+
*/
|
|
2399
|
+
require(name) {
|
|
2400
|
+
const service = this.#services.get(name);
|
|
2401
|
+
if (!service) {
|
|
2402
|
+
const known = [...this.#services.keys()];
|
|
2403
|
+
throw new ItdConfigError(
|
|
2404
|
+
`\u0421\u0435\u0440\u0432\u0438\u0441 \xAB${name}\xBB \u043D\u0435 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u043D. ` + (known.length > 0 ? `\u0418\u0437\u0432\u0435\u0441\u0442\u043D\u044B: ${known.join(", ")}` : "\u0417\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0439\u0442\u0435 \u0435\u0433\u043E \u0447\u0435\u0440\u0435\u0437 itd.defineService() \u0438\u043B\u0438 \u043E\u043F\u0446\u0438\u044E services")
|
|
2405
|
+
);
|
|
2406
|
+
}
|
|
2407
|
+
return service;
|
|
2408
|
+
}
|
|
2409
|
+
/**
|
|
2410
|
+
* Базовый URL сервиса.
|
|
2411
|
+
*
|
|
2412
|
+
* @throws {ItdConfigError} если сервис не зарегистрирован
|
|
2413
|
+
*/
|
|
2414
|
+
resolveBaseUrl(name) {
|
|
2415
|
+
return this.require(name).baseUrl;
|
|
2416
|
+
}
|
|
2417
|
+
};
|
|
2258
2418
|
|
|
2259
2419
|
// src/core/redact.ts
|
|
2260
2420
|
var SECRET_HEADERS = /* @__PURE__ */ new Set(["authorization", "cookie", "set-cookie", "x-api-key"]);
|
|
@@ -2532,6 +2692,29 @@ async function readBody(response) {
|
|
|
2532
2692
|
const text = await response.text();
|
|
2533
2693
|
return text === "" ? void 0 : text;
|
|
2534
2694
|
}
|
|
2695
|
+
function createAbortError() {
|
|
2696
|
+
const error = new Error("\u041E\u043F\u0435\u0440\u0430\u0446\u0438\u044F \u043F\u0440\u0435\u0440\u0432\u0430\u043D\u0430");
|
|
2697
|
+
error.name = "AbortError";
|
|
2698
|
+
return error;
|
|
2699
|
+
}
|
|
2700
|
+
function abortable(promise, signal) {
|
|
2701
|
+
if (signal.aborted) {
|
|
2702
|
+
return Promise.race([
|
|
2703
|
+
promise,
|
|
2704
|
+
new Promise((_resolve, reject) => {
|
|
2705
|
+
setTimeout(() => reject(createAbortError()), 0);
|
|
2706
|
+
})
|
|
2707
|
+
]);
|
|
2708
|
+
}
|
|
2709
|
+
let onAbort;
|
|
2710
|
+
const interrupted = new Promise((_resolve, reject) => {
|
|
2711
|
+
onAbort = () => reject(createAbortError());
|
|
2712
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
2713
|
+
});
|
|
2714
|
+
return Promise.race([promise, interrupted]).finally(() => {
|
|
2715
|
+
if (onAbort) signal.removeEventListener("abort", onAbort);
|
|
2716
|
+
});
|
|
2717
|
+
}
|
|
2535
2718
|
function createAbortBundle(userSignal, timeout) {
|
|
2536
2719
|
const controller = new AbortController();
|
|
2537
2720
|
let timedOut = false;
|
|
@@ -2595,70 +2778,104 @@ var Transport = class {
|
|
|
2595
2778
|
headers: redactHeaders(headers),
|
|
2596
2779
|
body: redactBody(request.body)
|
|
2597
2780
|
});
|
|
2598
|
-
let response;
|
|
2599
2781
|
try {
|
|
2600
|
-
response
|
|
2782
|
+
let response;
|
|
2783
|
+
try {
|
|
2784
|
+
response = await this.#config.fetch(url, {
|
|
2785
|
+
method,
|
|
2786
|
+
headers,
|
|
2787
|
+
signal: abort.signal,
|
|
2788
|
+
...body !== void 0 ? { body } : {},
|
|
2789
|
+
...this.#config.sendCredentials ? { credentials: "include" } : {}
|
|
2790
|
+
});
|
|
2791
|
+
} catch (error) {
|
|
2792
|
+
const duration2 = Date.now() - startedAt;
|
|
2793
|
+
const failure = this.#toTransportError(error, abort, request, method, timeout);
|
|
2794
|
+
await this.#config.hooks.onError?.({ ...context, duration: duration2, error: failure });
|
|
2795
|
+
this.#config.logger?.warn(
|
|
2796
|
+
`\xD7 ${method} ${request.path} (${duration2} \u043C\u0441): ${failure.message}`
|
|
2797
|
+
);
|
|
2798
|
+
throw failure;
|
|
2799
|
+
}
|
|
2800
|
+
if (this.#deps.onRateLimit) {
|
|
2801
|
+
const { limit, remaining } = readRateLimit(response.headers);
|
|
2802
|
+
this.#deps.onRateLimit(limit, remaining, request);
|
|
2803
|
+
}
|
|
2804
|
+
if (this.#config.useCookieJar) this.#deps.cookies?.setFromResponse(url, response);
|
|
2805
|
+
if (response.ok) {
|
|
2806
|
+
await this.#config.hooks.onResponse?.({
|
|
2807
|
+
...context,
|
|
2808
|
+
status: response.status,
|
|
2809
|
+
duration: Date.now() - startedAt,
|
|
2810
|
+
response
|
|
2811
|
+
});
|
|
2812
|
+
}
|
|
2813
|
+
const payload = await this.#readBodyOrFail(
|
|
2814
|
+
response,
|
|
2815
|
+
context,
|
|
2816
|
+
request,
|
|
2601
2817
|
method,
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2818
|
+
abort,
|
|
2819
|
+
timeout
|
|
2820
|
+
);
|
|
2821
|
+
const duration = Date.now() - startedAt;
|
|
2822
|
+
if (!response.ok) {
|
|
2823
|
+
const error = createApiError({
|
|
2824
|
+
method,
|
|
2825
|
+
path: request.path,
|
|
2826
|
+
status: response.status,
|
|
2827
|
+
statusText: response.statusText,
|
|
2828
|
+
headers: response.headers,
|
|
2829
|
+
response,
|
|
2830
|
+
body: payload
|
|
2831
|
+
});
|
|
2832
|
+
await this.#config.hooks.onError?.({ ...context, duration, error });
|
|
2833
|
+
this.#config.logger?.warn(
|
|
2834
|
+
`\u2190 ${response.status} ${method} ${request.path} (${duration} \u043C\u0441): ${error.message}`
|
|
2835
|
+
);
|
|
2836
|
+
throw error;
|
|
2837
|
+
}
|
|
2838
|
+
this.#config.logger?.debug(`\u2190 ${response.status} ${method} ${request.path} (${duration} \u043C\u0441)`);
|
|
2839
|
+
return request.raw ? payload : unwrapData(payload);
|
|
2613
2840
|
} finally {
|
|
2614
2841
|
abort.cleanup();
|
|
2615
2842
|
}
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
response,
|
|
2631
|
-
body: payload
|
|
2843
|
+
};
|
|
2844
|
+
/** Читает тело и преобразует ошибку чтения в транспортную ошибку библиотеки. */
|
|
2845
|
+
async #readBodyOrFail(response, context, request, method, abort, timeout) {
|
|
2846
|
+
const startedAt = Date.now();
|
|
2847
|
+
try {
|
|
2848
|
+
return await abortable(readBody(response), abort.signal);
|
|
2849
|
+
} catch (error) {
|
|
2850
|
+
await response.body?.cancel().catch(() => {
|
|
2851
|
+
});
|
|
2852
|
+
const failure = this.#toTransportError(error, abort, request, method, timeout);
|
|
2853
|
+
await this.#config.hooks.onError?.({
|
|
2854
|
+
...context,
|
|
2855
|
+
duration: Date.now() - startedAt,
|
|
2856
|
+
error: failure
|
|
2632
2857
|
});
|
|
2633
|
-
await this.#config.hooks.onError?.({ ...context, duration, error });
|
|
2634
2858
|
this.#config.logger?.warn(
|
|
2635
|
-
`\
|
|
2859
|
+
`\xD7 ${method} ${request.path}: \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C \u0442\u0435\u043B\u043E \u043E\u0442\u0432\u0435\u0442\u0430 \u2014 ${failure.message}`
|
|
2636
2860
|
);
|
|
2637
|
-
throw
|
|
2861
|
+
throw failure;
|
|
2638
2862
|
}
|
|
2639
|
-
await this.#config.hooks.onResponse?.({
|
|
2640
|
-
...context,
|
|
2641
|
-
status: response.status,
|
|
2642
|
-
duration,
|
|
2643
|
-
response
|
|
2644
|
-
});
|
|
2645
|
-
this.#config.logger?.debug(`\u2190 ${response.status} ${method} ${request.path} (${duration} \u043C\u0441)`);
|
|
2646
|
-
return request.raw ? payload : unwrapData(payload);
|
|
2647
|
-
};
|
|
2648
|
-
/** Итоговый URL со строкой запроса. Нужен и слою повторов — для хука `onRetry`. */
|
|
2649
|
-
buildUrl(request) {
|
|
2650
|
-
return joinUrl(this.#config.baseUrl, request.path) + buildQuery(request.query);
|
|
2651
2863
|
}
|
|
2652
2864
|
/**
|
|
2653
|
-
*
|
|
2865
|
+
* Итоговый URL со строкой запроса. Нужен и слою повторов — для хука `onRetry`.
|
|
2654
2866
|
*
|
|
2655
|
-
*
|
|
2656
|
-
* что добавили слои конвейера (авторизация), и только в самом конце — заголовки
|
|
2657
|
-
* конкретного вызова. Так пользователь может переопределить что угодно.
|
|
2867
|
+
* Хост берётся из самого запроса, если он там задан: у сервисов платформы свои домены.
|
|
2658
2868
|
*/
|
|
2659
|
-
|
|
2869
|
+
buildUrl(request) {
|
|
2870
|
+
const base = request.baseUrl ?? this.#config.baseUrl;
|
|
2871
|
+
return joinUrl(base, request.path) + buildQuery(request.query);
|
|
2872
|
+
}
|
|
2873
|
+
/**
|
|
2874
|
+
* Собирает общие заголовки клиента: `User-Agent`, идентификатор устройства,
|
|
2875
|
+
* заголовки конфигурации и cookie для указанного адреса.
|
|
2876
|
+
*/
|
|
2877
|
+
async platformHeaders(url) {
|
|
2660
2878
|
const headers = new Headers();
|
|
2661
|
-
headers.set("Accept", "application/json");
|
|
2662
2879
|
headers.set("X-Requested-With", "XMLHttpRequest");
|
|
2663
2880
|
if (this.#config.userAgent) setHeader(headers, "User-Agent", this.#config.userAgent);
|
|
2664
2881
|
if (this.#deps.getDeviceId) {
|
|
@@ -2666,12 +2883,21 @@ var Transport = class {
|
|
|
2666
2883
|
}
|
|
2667
2884
|
for (const [name, value] of Object.entries(this.#config.headers))
|
|
2668
2885
|
setHeader(headers, name, value);
|
|
2669
|
-
for (const [name, value] of Object.entries(request.layerHeaders ?? {}))
|
|
2670
|
-
setHeader(headers, name, value);
|
|
2671
2886
|
if (this.#config.useCookieJar && this.#deps.cookies) {
|
|
2672
2887
|
const cookie = this.#deps.cookies.getHeader(url);
|
|
2673
2888
|
if (cookie) setHeader(headers, "Cookie", cookie);
|
|
2674
2889
|
}
|
|
2890
|
+
return headers;
|
|
2891
|
+
}
|
|
2892
|
+
/**
|
|
2893
|
+
* Дополняет общие заголовки значением `Accept`, заголовками конвейера и вызова.
|
|
2894
|
+
* Заголовки вызова применяются последними.
|
|
2895
|
+
*/
|
|
2896
|
+
async #buildHeaders(request, url) {
|
|
2897
|
+
const headers = await this.platformHeaders(url);
|
|
2898
|
+
if (!headers.has("Accept")) headers.set("Accept", "application/json");
|
|
2899
|
+
for (const [name, value] of Object.entries(request.layerHeaders ?? {}))
|
|
2900
|
+
setHeader(headers, name, value);
|
|
2675
2901
|
for (const [name, value] of Object.entries(request.headers ?? {})) {
|
|
2676
2902
|
setHeader(headers, name, value);
|
|
2677
2903
|
}
|
|
@@ -2798,14 +3024,15 @@ var PollTransport = class {
|
|
|
2798
3024
|
while (!context.signal.aborted) {
|
|
2799
3025
|
const token = await context.getToken();
|
|
2800
3026
|
if (!token) throw new UnauthorizedStreamError();
|
|
2801
|
-
const
|
|
2802
|
-
|
|
2803
|
-
|
|
3027
|
+
const url = `${joinUrl(context.baseUrl, "/api/notifications/")}?limit=${this.#limit}&offset=0`;
|
|
3028
|
+
const headers = await context.baseHeaders(url);
|
|
3029
|
+
headers.set("Accept", "application/json");
|
|
3030
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
3031
|
+
const response = await context.fetch(url, {
|
|
3032
|
+
method: "GET",
|
|
3033
|
+
headers,
|
|
3034
|
+
signal: context.signal
|
|
2804
3035
|
});
|
|
2805
|
-
const response = await context.fetch(
|
|
2806
|
-
`${joinUrl(context.baseUrl, "/api/notifications/")}?limit=${this.#limit}&offset=0`,
|
|
2807
|
-
{ method: "GET", headers, signal: context.signal }
|
|
2808
|
-
);
|
|
2809
3036
|
if (response.status === 401) throw new UnauthorizedStreamError();
|
|
2810
3037
|
if (!response.ok) throw new Error(`\u041E\u043F\u0440\u043E\u0441 \u0443\u0432\u0435\u0434\u043E\u043C\u043B\u0435\u043D\u0438\u0439 \u0432\u0435\u0440\u043D\u0443\u043B \u0441\u0442\u0430\u0442\u0443\u0441 ${response.status}`);
|
|
2811
3038
|
const body = await response.json();
|
|
@@ -3061,13 +3288,13 @@ var SseTransport = class {
|
|
|
3061
3288
|
async connect(context) {
|
|
3062
3289
|
const token = await context.getToken();
|
|
3063
3290
|
if (!token) throw new UnauthorizedStreamError();
|
|
3064
|
-
const
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3291
|
+
const url = joinUrl(context.baseUrl, STREAM_PATH);
|
|
3292
|
+
const headers = await context.baseHeaders(url);
|
|
3293
|
+
headers.set("Accept", "text/event-stream");
|
|
3294
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
3295
|
+
headers.set("Cache-Control", "no-cache");
|
|
3069
3296
|
if (this.#lastEventId) headers.set("Last-Event-ID", this.#lastEventId);
|
|
3070
|
-
const response = await context.fetch(
|
|
3297
|
+
const response = await context.fetch(url, {
|
|
3071
3298
|
method: "GET",
|
|
3072
3299
|
headers,
|
|
3073
3300
|
signal: context.signal
|
|
@@ -3128,6 +3355,38 @@ var RealtimeTransportKind = Object.freeze({
|
|
|
3128
3355
|
/** Периодический опрос REST. */
|
|
3129
3356
|
Poll: "poll"
|
|
3130
3357
|
});
|
|
3358
|
+
function validateRealtimeOptions(options) {
|
|
3359
|
+
const positiveInteger = (value, name) => {
|
|
3360
|
+
if (value === void 0) return;
|
|
3361
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
3362
|
+
throw new ItdConfigError(
|
|
3363
|
+
`realtime.${name} \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0446\u0435\u043B\u044B\u043C \u043D\u0435\u043E\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0447\u0438\u0441\u043B\u043E\u043C, \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u043E: ${value}`
|
|
3364
|
+
);
|
|
3365
|
+
}
|
|
3366
|
+
};
|
|
3367
|
+
const duration = (value, name, min) => {
|
|
3368
|
+
if (value === void 0) return;
|
|
3369
|
+
if (!Number.isFinite(value) || value < min) {
|
|
3370
|
+
throw new ItdConfigError(
|
|
3371
|
+
`realtime.${name} \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0447\u0438\u0441\u043B\u043E\u043C \u043D\u0435 \u043C\u0435\u043D\u044C\u0448\u0435 ${min}, \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u043E: ${value}`
|
|
3372
|
+
);
|
|
3373
|
+
}
|
|
3374
|
+
};
|
|
3375
|
+
positiveInteger(options.maxAttempts, "maxAttempts");
|
|
3376
|
+
duration(options.pollInterval, "pollInterval", 1);
|
|
3377
|
+
duration(options.idleTimeout, "idleTimeout", 0);
|
|
3378
|
+
if (options.jitter !== void 0 && !(options.jitter >= 0 && options.jitter <= 1)) {
|
|
3379
|
+
throw new ItdConfigError(
|
|
3380
|
+
`realtime.jitter \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0432 \u0434\u0438\u0430\u043F\u0430\u0437\u043E\u043D\u0435 0\u20261, \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u043E: ${options.jitter}`
|
|
3381
|
+
);
|
|
3382
|
+
}
|
|
3383
|
+
if (options.backoff !== void 0) {
|
|
3384
|
+
if (!Array.isArray(options.backoff) || options.backoff.length === 0) {
|
|
3385
|
+
throw new ItdConfigError("realtime.backoff \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u043D\u0435\u043F\u0443\u0441\u0442\u044B\u043C \u0441\u043F\u0438\u0441\u043A\u043E\u043C \u043F\u0430\u0443\u0437");
|
|
3386
|
+
}
|
|
3387
|
+
for (const delay of options.backoff) duration(delay, "backoff", 0);
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3131
3390
|
var ItdRealtime = class {
|
|
3132
3391
|
#deps;
|
|
3133
3392
|
#options;
|
|
@@ -3149,6 +3408,7 @@ var ItdRealtime = class {
|
|
|
3149
3408
|
#timer;
|
|
3150
3409
|
#detachEnvironment;
|
|
3151
3410
|
constructor(deps, options = {}) {
|
|
3411
|
+
validateRealtimeOptions(options);
|
|
3152
3412
|
this.#deps = deps;
|
|
3153
3413
|
this.#options = options;
|
|
3154
3414
|
this.#maxAttempts = options.maxAttempts ?? MAX_RECONNECT_ATTEMPTS;
|
|
@@ -3229,6 +3489,7 @@ var ItdRealtime = class {
|
|
|
3229
3489
|
}
|
|
3230
3490
|
/** Запускает попытку подключения; повторы планирует сам. */
|
|
3231
3491
|
#run() {
|
|
3492
|
+
if (!this.#wanted) return;
|
|
3232
3493
|
this.#controller?.abort();
|
|
3233
3494
|
const controller = new AbortController();
|
|
3234
3495
|
this.#controller = controller;
|
|
@@ -3236,6 +3497,7 @@ var ItdRealtime = class {
|
|
|
3236
3497
|
void this.#transport.connect({
|
|
3237
3498
|
baseUrl: this.#deps.baseUrl,
|
|
3238
3499
|
fetch: this.#deps.fetch,
|
|
3500
|
+
baseHeaders: this.#deps.baseHeaders,
|
|
3239
3501
|
getToken: this.#deps.getToken,
|
|
3240
3502
|
signal: controller.signal,
|
|
3241
3503
|
onOpen: () => {
|
|
@@ -3286,17 +3548,17 @@ var ItdRealtime = class {
|
|
|
3286
3548
|
async #refreshAndReconnect(error) {
|
|
3287
3549
|
this.#setStatus(RealtimeStatus.Error);
|
|
3288
3550
|
const refreshed = await this.#deps.refresh().catch(() => false);
|
|
3551
|
+
if (!this.#wanted) return;
|
|
3289
3552
|
if (!refreshed) {
|
|
3290
|
-
this.#
|
|
3291
|
-
this.#emitter.emit("giveup", void 0);
|
|
3553
|
+
this.#giveUp(error);
|
|
3292
3554
|
return;
|
|
3293
3555
|
}
|
|
3294
3556
|
this.#scheduleReconnect(error);
|
|
3295
3557
|
}
|
|
3296
3558
|
#scheduleReconnect(error) {
|
|
3559
|
+
if (!this.#wanted) return;
|
|
3297
3560
|
if (this.#attempt >= this.#maxAttempts) {
|
|
3298
|
-
this.#
|
|
3299
|
-
this.#emitter.emit("giveup", void 0);
|
|
3561
|
+
this.#giveUp(error);
|
|
3300
3562
|
return;
|
|
3301
3563
|
}
|
|
3302
3564
|
const delay = reconnectDelay(this.#attempt, this.#options);
|
|
@@ -3308,6 +3570,15 @@ var ItdRealtime = class {
|
|
|
3308
3570
|
this.#run();
|
|
3309
3571
|
}, delay);
|
|
3310
3572
|
}
|
|
3573
|
+
/** Завершает автоматические попытки переподключения. */
|
|
3574
|
+
#giveUp(error) {
|
|
3575
|
+
this.#wanted = false;
|
|
3576
|
+
this.#attempt = 0;
|
|
3577
|
+
this.#detachEnvironment?.();
|
|
3578
|
+
this.#detachEnvironment = void 0;
|
|
3579
|
+
this.#emitter.emit("error", { error, willReconnect: false });
|
|
3580
|
+
this.#emitter.emit("giveup", void 0);
|
|
3581
|
+
}
|
|
3311
3582
|
/**
|
|
3312
3583
|
* Подписывается на события среды.
|
|
3313
3584
|
*
|
|
@@ -3355,6 +3626,9 @@ var PaginationMode = Object.freeze({
|
|
|
3355
3626
|
/** Следующая страница запрашивается смещением от начала списка. */
|
|
3356
3627
|
Offset: "offset"
|
|
3357
3628
|
});
|
|
3629
|
+
function mapPage(page, map) {
|
|
3630
|
+
return { ...page, items: page.items.map(map) };
|
|
3631
|
+
}
|
|
3358
3632
|
function readItems(body, fields) {
|
|
3359
3633
|
if (Array.isArray(body)) return body;
|
|
3360
3634
|
for (const field of fields) {
|
|
@@ -3631,7 +3905,7 @@ var AuthResource = class extends BaseResource {
|
|
|
3631
3905
|
async signUp(credentials, options = {}) {
|
|
3632
3906
|
const body = await this.http.request({
|
|
3633
3907
|
method: "POST",
|
|
3634
|
-
path:
|
|
3908
|
+
path: AUTH_PATHS.signUp,
|
|
3635
3909
|
body: credentials,
|
|
3636
3910
|
skipAuth: true,
|
|
3637
3911
|
skipAuthRefresh: true,
|
|
@@ -3656,7 +3930,7 @@ var AuthResource = class extends BaseResource {
|
|
|
3656
3930
|
async signIn(credentials, options = {}) {
|
|
3657
3931
|
const body = await this.http.request({
|
|
3658
3932
|
method: "POST",
|
|
3659
|
-
path:
|
|
3933
|
+
path: AUTH_PATHS.signIn,
|
|
3660
3934
|
body: credentials,
|
|
3661
3935
|
skipAuth: true,
|
|
3662
3936
|
skipAuthRefresh: true,
|
|
@@ -3677,7 +3951,7 @@ var AuthResource = class extends BaseResource {
|
|
|
3677
3951
|
async verifyOtp(input, options = {}) {
|
|
3678
3952
|
const body = await this.http.request({
|
|
3679
3953
|
method: "POST",
|
|
3680
|
-
path:
|
|
3954
|
+
path: AUTH_PATHS.verifyOtp,
|
|
3681
3955
|
body: input,
|
|
3682
3956
|
skipAuth: true,
|
|
3683
3957
|
skipAuthRefresh: true,
|
|
@@ -3694,7 +3968,7 @@ var AuthResource = class extends BaseResource {
|
|
|
3694
3968
|
resendOtp(input, options = {}) {
|
|
3695
3969
|
return this.http.request({
|
|
3696
3970
|
method: "POST",
|
|
3697
|
-
path:
|
|
3971
|
+
path: AUTH_PATHS.resendOtp,
|
|
3698
3972
|
body: input,
|
|
3699
3973
|
skipAuth: true,
|
|
3700
3974
|
skipAuthRefresh: true,
|
|
@@ -3771,7 +4045,7 @@ var AuthResource = class extends BaseResource {
|
|
|
3771
4045
|
async logout(options = {}) {
|
|
3772
4046
|
await this.http.request({
|
|
3773
4047
|
method: "POST",
|
|
3774
|
-
path:
|
|
4048
|
+
path: AUTH_PATHS.logout,
|
|
3775
4049
|
skipAuthRefresh: true,
|
|
3776
4050
|
...this.requestOptions(options)
|
|
3777
4051
|
});
|
|
@@ -3801,7 +4075,7 @@ var AuthResource = class extends BaseResource {
|
|
|
3801
4075
|
async forgotPassword(input, options = {}) {
|
|
3802
4076
|
const body = await this.http.request({
|
|
3803
4077
|
method: "POST",
|
|
3804
|
-
path:
|
|
4078
|
+
path: AUTH_PATHS.forgotPassword,
|
|
3805
4079
|
body: input,
|
|
3806
4080
|
skipAuth: true,
|
|
3807
4081
|
skipAuthRefresh: true,
|
|
@@ -3822,7 +4096,7 @@ var AuthResource = class extends BaseResource {
|
|
|
3822
4096
|
resetPassword(input, options = {}) {
|
|
3823
4097
|
return this.http.request({
|
|
3824
4098
|
method: "POST",
|
|
3825
|
-
path:
|
|
4099
|
+
path: AUTH_PATHS.resetPassword,
|
|
3826
4100
|
body: input,
|
|
3827
4101
|
skipAuth: true,
|
|
3828
4102
|
skipAuthRefresh: true,
|
|
@@ -3860,14 +4134,17 @@ var AuthResource = class extends BaseResource {
|
|
|
3860
4134
|
* Меняет пароль. Требует действующей сессии.
|
|
3861
4135
|
*
|
|
3862
4136
|
* При неверном текущем пароле сервер отвечает `ACCOUNT_CURRENT_PASSWORD_INCORRECT`.
|
|
4137
|
+
*
|
|
4138
|
+
* @example
|
|
4139
|
+
* ```ts
|
|
4140
|
+
* await itd.auth.changePassword({ currentPassword, newPassword });
|
|
4141
|
+
* ```
|
|
3863
4142
|
*/
|
|
3864
4143
|
changePassword(input, options = {}) {
|
|
3865
4144
|
return this.http.request({
|
|
3866
4145
|
method: "POST",
|
|
3867
|
-
path:
|
|
3868
|
-
|
|
3869
|
-
// не проверить, а лишнее поле он игнорирует.
|
|
3870
|
-
body: { ...input, currentPassword: input.oldPassword },
|
|
4146
|
+
path: AUTH_PATHS.changePassword,
|
|
4147
|
+
body: { currentPassword: input.currentPassword, newPassword: input.newPassword },
|
|
3871
4148
|
...this.requestOptions(options)
|
|
3872
4149
|
});
|
|
3873
4150
|
}
|
|
@@ -3883,13 +4160,13 @@ var AuthResource = class extends BaseResource {
|
|
|
3883
4160
|
* ```
|
|
3884
4161
|
*/
|
|
3885
4162
|
oauthUrl(provider) {
|
|
3886
|
-
return joinUrl(this.http.baseUrl,
|
|
4163
|
+
return joinUrl(this.http.baseUrl, `${AUTH_PATHS.oauthLogin}/${provider}`);
|
|
3887
4164
|
}
|
|
3888
4165
|
/** Загружает список активных сессий. У текущей поле `isCurrent` равно `true`. */
|
|
3889
4166
|
async sessions(options = {}) {
|
|
3890
4167
|
const body = await this.http.request({
|
|
3891
4168
|
method: "GET",
|
|
3892
|
-
path:
|
|
4169
|
+
path: AUTH_PATHS.sessions,
|
|
3893
4170
|
...this.requestOptions(options)
|
|
3894
4171
|
});
|
|
3895
4172
|
return pickArray(body, "sessions");
|
|
@@ -3898,7 +4175,7 @@ var AuthResource = class extends BaseResource {
|
|
|
3898
4175
|
revokeSession(sessionId, options = {}) {
|
|
3899
4176
|
return this.http.request({
|
|
3900
4177
|
method: "DELETE",
|
|
3901
|
-
path:
|
|
4178
|
+
path: `${AUTH_PATHS.sessions}/${encodeURIComponent(sessionId)}`,
|
|
3902
4179
|
...this.requestOptions(options)
|
|
3903
4180
|
});
|
|
3904
4181
|
}
|
|
@@ -3906,7 +4183,7 @@ var AuthResource = class extends BaseResource {
|
|
|
3906
4183
|
revokeOtherSessions(options = {}) {
|
|
3907
4184
|
return this.http.request({
|
|
3908
4185
|
method: "DELETE",
|
|
3909
|
-
path:
|
|
4186
|
+
path: AUTH_PATHS.sessions,
|
|
3910
4187
|
...this.requestOptions(options)
|
|
3911
4188
|
});
|
|
3912
4189
|
}
|
|
@@ -4378,7 +4655,25 @@ var NotificationsResource = class extends BaseResource {
|
|
|
4378
4655
|
}
|
|
4379
4656
|
};
|
|
4380
4657
|
|
|
4658
|
+
// src/core/time.ts
|
|
4659
|
+
var NAIVE_STAMP = /^(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}(?:\.\d+)?)$/;
|
|
4660
|
+
function utcStampToIso(value) {
|
|
4661
|
+
const match = typeof value === "string" ? NAIVE_STAMP.exec(value) : null;
|
|
4662
|
+
if (!match) return value;
|
|
4663
|
+
const iso = `${match[1]}T${match[2]}Z`;
|
|
4664
|
+
return Number.isFinite(Date.parse(iso)) ? iso : value;
|
|
4665
|
+
}
|
|
4666
|
+
|
|
4381
4667
|
// src/resources/platform.ts
|
|
4668
|
+
function normalizeStatus(body) {
|
|
4669
|
+
if (!isRecord(body) || !Array.isArray(body.services)) return body;
|
|
4670
|
+
return {
|
|
4671
|
+
...body,
|
|
4672
|
+
services: body.services.map(
|
|
4673
|
+
(service) => typeof service?.last_checked === "string" ? { ...service, last_checked: utcStampToIso(service.last_checked) } : service
|
|
4674
|
+
)
|
|
4675
|
+
};
|
|
4676
|
+
}
|
|
4382
4677
|
var PlatformResource = class extends BaseResource {
|
|
4383
4678
|
/** Загружает журнал изменений. */
|
|
4384
4679
|
async changelog(options = {}) {
|
|
@@ -4406,6 +4701,31 @@ var PlatformResource = class extends BaseResource {
|
|
|
4406
4701
|
...this.requestOptions(options)
|
|
4407
4702
|
});
|
|
4408
4703
|
}
|
|
4704
|
+
/**
|
|
4705
|
+
* Загружает состояние сервисов платформы за последние 90 суток.
|
|
4706
|
+
*
|
|
4707
|
+
* Идёт на хост `статус.итд.com` без авторизации. Ответ кэшируется сервером на минуту.
|
|
4708
|
+
* История по суткам приходит разреженной, ровный массив даёт `statusDays`.
|
|
4709
|
+
*
|
|
4710
|
+
* @example
|
|
4711
|
+
* ```ts
|
|
4712
|
+
* const status = await itd.platform.status();
|
|
4713
|
+
*
|
|
4714
|
+
* if (status.overall_status !== 'operational') {
|
|
4715
|
+
* const broken = status.services.filter((s) => s.current_status !== 'operational');
|
|
4716
|
+
* console.log('лежит:', broken.map((s) => s.name).join(', '));
|
|
4717
|
+
* }
|
|
4718
|
+
* ```
|
|
4719
|
+
*/
|
|
4720
|
+
async status(options = {}) {
|
|
4721
|
+
const body = await this.http.request({
|
|
4722
|
+
method: "GET",
|
|
4723
|
+
service: STATUS_SERVICE,
|
|
4724
|
+
path: "/api/status",
|
|
4725
|
+
...this.requestOptions(options)
|
|
4726
|
+
});
|
|
4727
|
+
return normalizeStatus(body);
|
|
4728
|
+
}
|
|
4409
4729
|
};
|
|
4410
4730
|
|
|
4411
4731
|
// src/resources/posts.ts
|
|
@@ -5170,13 +5490,15 @@ var VerificationResource = class extends BaseResource {
|
|
|
5170
5490
|
};
|
|
5171
5491
|
|
|
5172
5492
|
// src/client.ts
|
|
5173
|
-
var ItdClient = class {
|
|
5493
|
+
var ItdClient = class _ItdClient {
|
|
5174
5494
|
#config;
|
|
5175
5495
|
#http;
|
|
5496
|
+
#transport;
|
|
5176
5497
|
#authManager;
|
|
5177
5498
|
#jar;
|
|
5178
|
-
#
|
|
5499
|
+
#queues;
|
|
5179
5500
|
#plugins = new PluginRegistry();
|
|
5501
|
+
#services;
|
|
5180
5502
|
/** Порождённые потоки уведомлений — чтобы `close()` мог закрыть их разом. */
|
|
5181
5503
|
#streams = /* @__PURE__ */ new Set();
|
|
5182
5504
|
/** Авторизация, сессии и пароли. */
|
|
@@ -5213,19 +5535,23 @@ var ItdClient = class {
|
|
|
5213
5535
|
const config = resolveConfig(options);
|
|
5214
5536
|
this.#config = config;
|
|
5215
5537
|
this.#jar = new CookieJar();
|
|
5216
|
-
|
|
5217
|
-
this.#
|
|
5538
|
+
this.#services = new ServiceRegistry(config.baseUrl);
|
|
5539
|
+
for (const service of BUILT_IN_SERVICES) this.#services.define(service);
|
|
5540
|
+
for (const service of config.services) this.#services.define(service);
|
|
5541
|
+
const queues = config.rateLimit ? new RequestQueuePool(config.rateLimit) : void 0;
|
|
5542
|
+
this.#queues = queues;
|
|
5218
5543
|
let authManager;
|
|
5219
5544
|
const transport = new Transport(config, {
|
|
5220
5545
|
cookies: config.useCookieJar ? this.#jar : void 0,
|
|
5221
5546
|
getDeviceId: () => authManager.getDeviceId(),
|
|
5222
|
-
onRateLimit:
|
|
5547
|
+
onRateLimit: queues && config.rateLimit?.respectHeaders ? (limit, remaining, request) => this.#throttleByHeaders(limit, remaining, request) : void 0
|
|
5223
5548
|
});
|
|
5549
|
+
this.#transport = transport;
|
|
5224
5550
|
const pluginsLayer = createPluginsMiddleware(this.#plugins);
|
|
5225
5551
|
const retriesLayer = createRetryMiddleware({
|
|
5226
5552
|
retry: config.retry,
|
|
5227
5553
|
rateLimitDelays: config.rateLimit?.retryDelays ?? [],
|
|
5228
|
-
pauseQueue:
|
|
5554
|
+
pauseQueue: queues ? (ms, request) => queues.for(request.service).pause(ms) : void 0,
|
|
5229
5555
|
hooks: config.hooks,
|
|
5230
5556
|
logger: config.logger,
|
|
5231
5557
|
buildUrl: (request) => transport.buildUrl(request)
|
|
@@ -5243,8 +5569,13 @@ var ItdClient = class {
|
|
|
5243
5569
|
authManager = new AuthManager(config, authHandler, this.#jar);
|
|
5244
5570
|
this.#authManager = authManager;
|
|
5245
5571
|
const middlewares = [];
|
|
5246
|
-
if (
|
|
5572
|
+
if (queues) {
|
|
5573
|
+
middlewares.push(
|
|
5574
|
+
createQueueMiddleware((request, task) => queues.for(request.service).schedule(task))
|
|
5575
|
+
);
|
|
5576
|
+
}
|
|
5247
5577
|
middlewares.push(pluginsLayer);
|
|
5578
|
+
middlewares.push(createServicesMiddleware(this.#services));
|
|
5248
5579
|
middlewares.push(retriesLayer);
|
|
5249
5580
|
middlewares.push(
|
|
5250
5581
|
createAuthMiddleware({
|
|
@@ -5302,7 +5633,7 @@ var ItdClient = class {
|
|
|
5302
5633
|
*
|
|
5303
5634
|
* @example
|
|
5304
5635
|
* ```ts
|
|
5305
|
-
* import { crypt } from 'itd-api
|
|
5636
|
+
* import { crypt } from '@itd-api/crypto';
|
|
5306
5637
|
*
|
|
5307
5638
|
* itd.use(crypt());
|
|
5308
5639
|
* await itd.posts.create({ content: 'секрет' }, { encrypt: 'invis' });
|
|
@@ -5312,6 +5643,41 @@ var ItdClient = class {
|
|
|
5312
5643
|
this.#plugins.add(plugin, { baseUrl: this.#config.baseUrl, logger: this.#config.logger });
|
|
5313
5644
|
return this;
|
|
5314
5645
|
}
|
|
5646
|
+
/**
|
|
5647
|
+
* Регистрирует сервис платформы — домен, отличный от основного.
|
|
5648
|
+
*
|
|
5649
|
+
* Запросы с `{ service: 'имя' }` уходят на его хост с его заголовками. То же самое умеет
|
|
5650
|
+
* опция `services` конструктора. Занятое имя не переопределяется — ни своё, ни встроенное:
|
|
5651
|
+
* разовому запросу хост задаётся полем `baseUrl`.
|
|
5652
|
+
*
|
|
5653
|
+
* Заголовок авторизации по умолчанию уходит только своим — домену клиента и его
|
|
5654
|
+
* поддоменам. Стороннему хосту токен нужно разрешить явно: `auth: true`.
|
|
5655
|
+
*
|
|
5656
|
+
* @throws {ItdConfigError} если определение неверно или имя уже занято
|
|
5657
|
+
*
|
|
5658
|
+
* @example Сервис платформы на поддомене — токен уходит сам
|
|
5659
|
+
* ```ts
|
|
5660
|
+
* itd.defineService({
|
|
5661
|
+
* name: 'pb',
|
|
5662
|
+
* baseUrl: 'https://pbapi.xn--d1ah4a.com',
|
|
5663
|
+
* headers: { Referer: 'https://pixel.xn--d1ah4a.com/' },
|
|
5664
|
+
* });
|
|
5665
|
+
*
|
|
5666
|
+
* await itd.request({ method: 'GET', service: 'pb', path: '/api/pixel-info' });
|
|
5667
|
+
* ```
|
|
5668
|
+
*/
|
|
5669
|
+
defineService(definition) {
|
|
5670
|
+
this.#services.define(definition);
|
|
5671
|
+
return this;
|
|
5672
|
+
}
|
|
5673
|
+
/**
|
|
5674
|
+
* Базовый URL зарегистрированного сервиса.
|
|
5675
|
+
*
|
|
5676
|
+
* @throws {ItdConfigError} если сервис не зарегистрирован
|
|
5677
|
+
*/
|
|
5678
|
+
serviceBaseUrl(name) {
|
|
5679
|
+
return this.#services.resolveBaseUrl(name);
|
|
5680
|
+
}
|
|
5315
5681
|
/**
|
|
5316
5682
|
* Подписывается на события авторизации.
|
|
5317
5683
|
*
|
|
@@ -5353,6 +5719,7 @@ var ItdClient = class {
|
|
|
5353
5719
|
{
|
|
5354
5720
|
baseUrl: this.#config.baseUrl,
|
|
5355
5721
|
fetch: this.#config.fetch,
|
|
5722
|
+
baseHeaders: (url) => this.#transport.platformHeaders(url),
|
|
5356
5723
|
getToken: () => this.#authManager.getAccessToken(),
|
|
5357
5724
|
refresh: () => this.#authManager.onUnauthorized(),
|
|
5358
5725
|
fetchUnreadCount: () => this.notifications.count(),
|
|
@@ -5381,12 +5748,19 @@ var ItdClient = class {
|
|
|
5381
5748
|
async close() {
|
|
5382
5749
|
for (const stream of this.#streams) stream.disconnect();
|
|
5383
5750
|
this.#streams.clear();
|
|
5384
|
-
this.#
|
|
5751
|
+
this.#queues?.stop();
|
|
5385
5752
|
}
|
|
5386
5753
|
/** Позволяет использовать клиент с `await using`. */
|
|
5387
5754
|
[Symbol.asyncDispose]() {
|
|
5388
5755
|
return this.close();
|
|
5389
5756
|
}
|
|
5757
|
+
static {
|
|
5758
|
+
if (typeof Symbol.asyncDispose !== "symbol") {
|
|
5759
|
+
const prototype = _ItdClient.prototype;
|
|
5760
|
+
prototype[/* @__PURE__ */ Symbol.for("Symbol.asyncDispose")] = prototype.undefined;
|
|
5761
|
+
delete prototype.undefined;
|
|
5762
|
+
}
|
|
5763
|
+
}
|
|
5390
5764
|
/** Текущая сессия целиком — чтобы сохранить её самостоятельно. */
|
|
5391
5765
|
getSession() {
|
|
5392
5766
|
return this.#authManager.getSession();
|
|
@@ -5406,21 +5780,16 @@ var ItdClient = class {
|
|
|
5406
5780
|
* Смысл этой паузы прежде всего в том, чтобы при работе в несколько потоков остальные
|
|
5407
5781
|
* запросы не улетели в стену все разом.
|
|
5408
5782
|
*/
|
|
5409
|
-
#throttleByHeaders(limit, remaining) {
|
|
5783
|
+
#throttleByHeaders(limit, remaining, request) {
|
|
5410
5784
|
if (remaining === void 0 || remaining > 0) return;
|
|
5411
5785
|
const first = this.#config.rateLimit?.retryDelays[0];
|
|
5412
5786
|
if (first === void 0) return;
|
|
5413
|
-
this.#
|
|
5787
|
+
this.#queues?.for(request.service).pause(first);
|
|
5414
5788
|
this.#config.logger?.debug(
|
|
5415
5789
|
`\u043B\u0438\u043C\u0438\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438\u0441\u0447\u0435\u0440\u043F\u0430\u043D (${remaining} \u0438\u0437 ${limit ?? "?"}), \u043E\u0447\u0435\u0440\u0435\u0434\u044C \u0436\u0434\u0451\u0442 ${first} \u043C\u0441`
|
|
5416
5790
|
);
|
|
5417
5791
|
}
|
|
5418
5792
|
};
|
|
5419
|
-
if (typeof Symbol.asyncDispose !== "symbol") {
|
|
5420
|
-
const prototype = ItdClient.prototype;
|
|
5421
|
-
prototype[/* @__PURE__ */ Symbol.for("Symbol.asyncDispose")] = prototype.undefined;
|
|
5422
|
-
delete prototype.undefined;
|
|
5423
|
-
}
|
|
5424
5793
|
function createClient(options = {}) {
|
|
5425
5794
|
return new ItdClient(options);
|
|
5426
5795
|
}
|
|
@@ -5526,11 +5895,18 @@ function resolveNotificationUrl(notification) {
|
|
|
5526
5895
|
function isMyProfile(profile) {
|
|
5527
5896
|
return "subscription" in profile;
|
|
5528
5897
|
}
|
|
5898
|
+
var STATUS_WINDOW_DAYS = 90;
|
|
5529
5899
|
function toDate(value) {
|
|
5530
5900
|
if (!value) return null;
|
|
5531
5901
|
const date = new Date(value);
|
|
5532
5902
|
return Number.isFinite(date.getTime()) ? date : null;
|
|
5533
5903
|
}
|
|
5904
|
+
function statusDays(service) {
|
|
5905
|
+
return Array.from(
|
|
5906
|
+
{ length: STATUS_WINDOW_DAYS },
|
|
5907
|
+
(_, index) => service.days[String(index)] ?? null
|
|
5908
|
+
);
|
|
5909
|
+
}
|
|
5534
5910
|
|
|
5535
5911
|
exports.ALLOWED_MIME_TYPES = ALLOWED_MIME_TYPES;
|
|
5536
5912
|
exports.AUDIO_MIME_TYPES = AUDIO_MIME_TYPES;
|
|
@@ -5538,14 +5914,18 @@ exports.AUTH_FLAG_COOKIE = AUTH_FLAG_COOKIE;
|
|
|
5538
5914
|
exports.AUTH_PATHS = AUTH_PATHS;
|
|
5539
5915
|
exports.AccessType = AccessType;
|
|
5540
5916
|
exports.AttachmentType = AttachmentType;
|
|
5917
|
+
exports.BUILT_IN_SERVICES = BUILT_IN_SERVICES;
|
|
5541
5918
|
exports.CommentSort = CommentSort;
|
|
5542
5919
|
exports.DEFAULT_BASE_URL = DEFAULT_BASE_URL;
|
|
5920
|
+
exports.DEFAULT_STATUS_BASE_URL = DEFAULT_STATUS_BASE_URL;
|
|
5543
5921
|
exports.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT;
|
|
5922
|
+
exports.DEFAULT_UPLOAD_TIMEOUT = DEFAULT_UPLOAD_TIMEOUT;
|
|
5544
5923
|
exports.DEFAULT_USER_AGENT = DEFAULT_USER_AGENT;
|
|
5545
5924
|
exports.DEVICE_ID_HEADER = DEVICE_ID_HEADER;
|
|
5546
5925
|
exports.DetectedRuntime = DetectedRuntime;
|
|
5547
5926
|
exports.FeedTab = FeedTab;
|
|
5548
5927
|
exports.IMAGE_MIME_TYPES = IMAGE_MIME_TYPES;
|
|
5928
|
+
exports.IncidentKind = IncidentKind;
|
|
5549
5929
|
exports.InteractionType = InteractionType;
|
|
5550
5930
|
exports.ItdAbortError = ItdAbortError;
|
|
5551
5931
|
exports.ItdApiError = ItdApiError;
|
|
@@ -5580,12 +5960,16 @@ exports.RECONNECT_BACKOFF = RECONNECT_BACKOFF;
|
|
|
5580
5960
|
exports.RECONNECT_JITTER = RECONNECT_JITTER;
|
|
5581
5961
|
exports.REFRESH_COOKIE = REFRESH_COOKIE;
|
|
5582
5962
|
exports.REFRESH_COOKIE_PATH = REFRESH_COOKIE_PATH;
|
|
5963
|
+
exports.REQUEST_OPTION_KEYS = REQUEST_OPTION_KEYS;
|
|
5583
5964
|
exports.RealtimeStatus = RealtimeStatus;
|
|
5584
5965
|
exports.RealtimeTransportKind = RealtimeTransportKind;
|
|
5585
5966
|
exports.ReportReason = ReportReason;
|
|
5586
5967
|
exports.ReportTargetType = ReportTargetType;
|
|
5587
5968
|
exports.RuntimeMode = RuntimeMode;
|
|
5969
|
+
exports.STATUS_SERVICE = STATUS_SERVICE;
|
|
5588
5970
|
exports.STREAM_PATH = STREAM_PATH;
|
|
5971
|
+
exports.ServiceRegistry = ServiceRegistry;
|
|
5972
|
+
exports.ServiceState = ServiceState;
|
|
5589
5973
|
exports.SignInStatus = SignInStatus;
|
|
5590
5974
|
exports.SpanType = SpanType;
|
|
5591
5975
|
exports.TURNSTILE_SITE_KEY = TURNSTILE_SITE_KEY;
|
|
@@ -5612,6 +5996,7 @@ exports.isItdServerError = isItdServerError;
|
|
|
5612
5996
|
exports.isItdValidationError = isItdValidationError;
|
|
5613
5997
|
exports.isKnownNotificationType = isKnownNotificationType;
|
|
5614
5998
|
exports.isMyProfile = isMyProfile;
|
|
5999
|
+
exports.mapPage = mapPage;
|
|
5615
6000
|
exports.normalizeNotification = normalizeNotification;
|
|
5616
6001
|
exports.poll = poll;
|
|
5617
6002
|
exports.post = post;
|
|
@@ -5619,6 +6004,8 @@ exports.readNotificationEvent = readNotificationEvent;
|
|
|
5619
6004
|
exports.readUnreadCountEvent = readUnreadCountEvent;
|
|
5620
6005
|
exports.report = report;
|
|
5621
6006
|
exports.resolveNotificationUrl = resolveNotificationUrl;
|
|
6007
|
+
exports.statusDays = statusDays;
|
|
5622
6008
|
exports.toDate = toDate;
|
|
5623
|
-
|
|
5624
|
-
//# sourceMappingURL=chunk-
|
|
6009
|
+
exports.utcStampToIso = utcStampToIso;
|
|
6010
|
+
//# sourceMappingURL=chunk-HTF2MOM4.cjs.map
|
|
6011
|
+
//# sourceMappingURL=chunk-HTF2MOM4.cjs.map
|