itd-api 0.0.10 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-BN4AC3DP.cjs → chunk-QD4UHJFF.cjs} +111 -23
- package/dist/chunk-QD4UHJFF.cjs.map +1 -0
- package/dist/{chunk-SMV7TF5P.js → chunk-TB7HW3VX.js} +111 -23
- package/dist/chunk-TB7HW3VX.js.map +1 -0
- package/dist/{index-CSjDNGCE.d.cts → index-CrlTO7sR.d.cts} +47 -10
- package/dist/{index-CSjDNGCE.d.ts → index-CrlTO7sR.d.ts} +47 -10
- package/dist/index.cjs +109 -109
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/node.cjs +112 -112
- package/dist/node.d.cts +2 -2
- package/dist/node.d.ts +2 -2
- package/dist/node.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-BN4AC3DP.cjs.map +0 -1
- package/dist/chunk-SMV7TF5P.js.map +0 -1
|
@@ -672,18 +672,24 @@ function decodeBase64Url(segment) {
|
|
|
672
672
|
const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
|
|
673
673
|
return new TextDecoder().decode(bytes);
|
|
674
674
|
}
|
|
675
|
-
function
|
|
675
|
+
function readTokenIdentity(token) {
|
|
676
676
|
try {
|
|
677
677
|
const payload = token.split(".")[1];
|
|
678
|
-
if (!payload) return
|
|
678
|
+
if (!payload) return {};
|
|
679
679
|
const parsed = JSON.parse(decodeBase64Url(payload));
|
|
680
|
-
if (typeof parsed !== "object" || parsed === null) return
|
|
681
|
-
const
|
|
682
|
-
return
|
|
680
|
+
if (typeof parsed !== "object" || parsed === null) return {};
|
|
681
|
+
const { sub, sid } = parsed;
|
|
682
|
+
return {
|
|
683
|
+
...typeof sub === "string" && sub.length > 0 ? { subject: sub } : {},
|
|
684
|
+
...typeof sid === "string" && sid.length > 0 ? { sessionId: sid } : {}
|
|
685
|
+
};
|
|
683
686
|
} catch {
|
|
684
|
-
return
|
|
687
|
+
return {};
|
|
685
688
|
}
|
|
686
689
|
}
|
|
690
|
+
function readTokenSubject(token) {
|
|
691
|
+
return readTokenIdentity(token).subject;
|
|
692
|
+
}
|
|
687
693
|
|
|
688
694
|
// src/core/runtime.ts
|
|
689
695
|
var RuntimeMode = Object.freeze({
|
|
@@ -876,6 +882,7 @@ var AuthManager = class {
|
|
|
876
882
|
#send;
|
|
877
883
|
#jar;
|
|
878
884
|
#emitter;
|
|
885
|
+
#hooks;
|
|
879
886
|
/** `undefined` — сессия ещё не читалась из хранилища. */
|
|
880
887
|
#session;
|
|
881
888
|
/**
|
|
@@ -887,8 +894,12 @@ var AuthManager = class {
|
|
|
887
894
|
#refreshing = null;
|
|
888
895
|
/** Общий промис входа по логину и паролю. */
|
|
889
896
|
#signingIn = null;
|
|
890
|
-
/**
|
|
897
|
+
/** Fallback-область для изоляции состояния плагинов, когда JWT-идентичность недоступна. */
|
|
891
898
|
#authScope = nextAuthScope();
|
|
899
|
+
/** Последний токен внешнего источника; `undefined` означает, что источник ещё не читался. */
|
|
900
|
+
#externalToken;
|
|
901
|
+
/** Идентификаторы последнего токена внешнего источника для синхронных потребителей. */
|
|
902
|
+
#externalIdentity;
|
|
892
903
|
/**
|
|
893
904
|
* Идентификатор устройства.
|
|
894
905
|
*
|
|
@@ -898,10 +909,11 @@ var AuthManager = class {
|
|
|
898
909
|
#deviceId;
|
|
899
910
|
/** Общий промис первичной выдачи `deviceId` — чтобы параллельные запросы получили один. */
|
|
900
911
|
#deviceIdLoading = null;
|
|
901
|
-
constructor(config, send, jar) {
|
|
912
|
+
constructor(config, send, jar, hooks = {}) {
|
|
902
913
|
this.#config = config;
|
|
903
914
|
this.#send = send;
|
|
904
915
|
this.#jar = jar;
|
|
916
|
+
this.#hooks = hooks;
|
|
905
917
|
this.#emitter = new Emitter(
|
|
906
918
|
(error) => reportListenerError(config.logger, "\u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438", error)
|
|
907
919
|
);
|
|
@@ -914,13 +926,63 @@ var AuthManager = class {
|
|
|
914
926
|
get once() {
|
|
915
927
|
return this.#emitter.once.bind(this.#emitter);
|
|
916
928
|
}
|
|
917
|
-
/**
|
|
929
|
+
/**
|
|
930
|
+
* Непрозрачная fallback-область авторизации.
|
|
931
|
+
*
|
|
932
|
+
* Изолирует состояние плагинов, когда идентичность аккаунта из JWT недоступна (непрозрачный
|
|
933
|
+
* токен): значение уникально для владельца и сменяется при замене или очистке сессии.
|
|
934
|
+
*/
|
|
918
935
|
getAuthScope() {
|
|
919
936
|
return this.#authScope;
|
|
920
937
|
}
|
|
938
|
+
/** Загружает сессию и возвращает идентификаторы аккаунта и сессии для плагинов. */
|
|
939
|
+
async getAuthIdentity() {
|
|
940
|
+
const session = await this.#loadSession();
|
|
941
|
+
if (session?.accessToken) return this.#identityForToken(session.accessToken);
|
|
942
|
+
const auth = this.#config.auth;
|
|
943
|
+
if (typeof auth === "object" && auth !== null && "getToken" in auth) {
|
|
944
|
+
const token = await this.#readExternalToken(() => auth.getToken());
|
|
945
|
+
return this.#identityForToken(token ?? void 0);
|
|
946
|
+
}
|
|
947
|
+
return {};
|
|
948
|
+
}
|
|
949
|
+
/** Идентификаторы аккаунта и сессии без чтения хранилища. @internal */
|
|
950
|
+
getCurrentAuthIdentity() {
|
|
951
|
+
const session = this.#session === void 0 ? this.#sessionFromConfig(this.#config.auth) : this.#session;
|
|
952
|
+
return session?.accessToken ? this.#identityForToken(session.accessToken) : this.#externalIdentity ?? {};
|
|
953
|
+
}
|
|
921
954
|
#rotateAuthScope() {
|
|
922
955
|
this.#authScope = nextAuthScope();
|
|
923
956
|
}
|
|
957
|
+
#identityForToken(accessToken) {
|
|
958
|
+
const token = accessToken ? readTokenIdentity(accessToken) : {};
|
|
959
|
+
return {
|
|
960
|
+
...token.subject ? { userId: token.subject } : {},
|
|
961
|
+
...token.sessionId ? { sessionId: token.sessionId } : {}
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
async #readExternalToken(getToken) {
|
|
965
|
+
const token = await getToken() ?? null;
|
|
966
|
+
const current = this.#identityForToken(token ?? void 0);
|
|
967
|
+
if (this.#externalToken !== void 0 && this.#externalToken !== token) {
|
|
968
|
+
this.#rotateAuthScope();
|
|
969
|
+
const previous = this.#externalIdentity ?? {};
|
|
970
|
+
const changed = previous.userId !== void 0 && current.userId !== void 0 ? previous.userId !== current.userId : true;
|
|
971
|
+
if (changed) this.#hooks.onAccountChange?.();
|
|
972
|
+
}
|
|
973
|
+
this.#externalToken = token;
|
|
974
|
+
this.#externalIdentity = current;
|
|
975
|
+
return token;
|
|
976
|
+
}
|
|
977
|
+
/** Меняет fallback и завершает realtime, только если фактически сменился аккаунт. */
|
|
978
|
+
#transitionAuth(accessToken, rotateFallback = true) {
|
|
979
|
+
const knownPrevious = this.#session !== void 0;
|
|
980
|
+
const previous = this.#identityForToken(this.#session?.accessToken);
|
|
981
|
+
const current = this.#identityForToken(accessToken);
|
|
982
|
+
const changed = previous.userId !== void 0 && current.userId !== void 0 ? previous.userId !== current.userId : previous.userId !== current.userId || rotateFallback;
|
|
983
|
+
if (rotateFallback || changed) this.#rotateAuthScope();
|
|
984
|
+
if (knownPrevious && changed) this.#hooks.onAccountChange?.();
|
|
985
|
+
}
|
|
924
986
|
/**
|
|
925
987
|
* Есть ли признак живой refresh-сессии.
|
|
926
988
|
*
|
|
@@ -981,7 +1043,7 @@ var AuthManager = class {
|
|
|
981
1043
|
const auth = this.#config.auth;
|
|
982
1044
|
if (!auth) return null;
|
|
983
1045
|
if (typeof auth === "object" && "getToken" in auth) {
|
|
984
|
-
return
|
|
1046
|
+
return this.#readExternalToken(() => auth.getToken());
|
|
985
1047
|
}
|
|
986
1048
|
if (typeof auth === "object" && "email" in auth) {
|
|
987
1049
|
return this.#signInWithCredentials(auth);
|
|
@@ -1036,7 +1098,8 @@ var AuthManager = class {
|
|
|
1036
1098
|
}
|
|
1037
1099
|
/** Сохраняет токен, полученный извне, — например после подтверждения OTP. */
|
|
1038
1100
|
async setAccessToken(accessToken) {
|
|
1039
|
-
this.#
|
|
1101
|
+
await this.#loadSession();
|
|
1102
|
+
this.#transitionAuth(accessToken);
|
|
1040
1103
|
await this.#saveSession({ ...this.#session ?? {}, accessToken, obtainedAt: Date.now() });
|
|
1041
1104
|
this.#emitter.emit("tokens", { accessToken });
|
|
1042
1105
|
}
|
|
@@ -1057,7 +1120,8 @@ var AuthManager = class {
|
|
|
1057
1120
|
}
|
|
1058
1121
|
/** Заменяет сессию и связанные с ней cookie целиком. */
|
|
1059
1122
|
async setSession(session) {
|
|
1060
|
-
this.#
|
|
1123
|
+
await this.#loadSession();
|
|
1124
|
+
this.#transitionAuth(session.accessToken);
|
|
1061
1125
|
this.#jar.clear();
|
|
1062
1126
|
this.#jar.deserialize(session.cookies);
|
|
1063
1127
|
if (session.deviceId) this.#deviceId = session.deviceId;
|
|
@@ -1072,8 +1136,9 @@ var AuthManager = class {
|
|
|
1072
1136
|
* новую запись в списке сессий.
|
|
1073
1137
|
*/
|
|
1074
1138
|
async clear() {
|
|
1139
|
+
await this.#loadSession();
|
|
1140
|
+
this.#transitionAuth(void 0);
|
|
1075
1141
|
this.#session = null;
|
|
1076
|
-
this.#rotateAuthScope();
|
|
1077
1142
|
this.#jar.clear();
|
|
1078
1143
|
await this.#config.storage.clear();
|
|
1079
1144
|
if (this.#deviceId) await this.#saveSession({ deviceId: this.#deviceId });
|
|
@@ -1170,6 +1235,7 @@ var AuthManager = class {
|
|
|
1170
1235
|
REFRESH_COOKIE,
|
|
1171
1236
|
this.#config.baseUrl + REFRESH_COOKIE_PATH
|
|
1172
1237
|
);
|
|
1238
|
+
this.#transitionAuth(accessToken, false);
|
|
1173
1239
|
await this.#saveSession({
|
|
1174
1240
|
...this.#session ?? {},
|
|
1175
1241
|
accessToken,
|
|
@@ -1180,8 +1246,8 @@ var AuthManager = class {
|
|
|
1180
1246
|
return accessToken;
|
|
1181
1247
|
} catch (error) {
|
|
1182
1248
|
if (error instanceof ItdApiError) {
|
|
1249
|
+
this.#transitionAuth(void 0);
|
|
1183
1250
|
this.#session = null;
|
|
1184
|
-
this.#rotateAuthScope();
|
|
1185
1251
|
this.#jar.clear();
|
|
1186
1252
|
await this.#config.storage.clear();
|
|
1187
1253
|
const relogged = await this.#reloginOrNull();
|
|
@@ -1249,7 +1315,7 @@ var AuthManager = class {
|
|
|
1249
1315
|
"\u0412\u0445\u043E\u0434 \u043F\u043E email \u0438 \u043F\u0430\u0440\u043E\u043B\u044E \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F \u043A\u043E\u0434\u043E\u043C \u0438\u0437 \u043F\u0438\u0441\u044C\u043C\u0430. \u0410\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438\u0439 \u0432\u0445\u043E\u0434 \u043D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u0435\u043D: \u0432\u043E\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439\u0442\u0435\u0441\u044C itd.auth.signInWithOtp() \u0438 \u043F\u0435\u0440\u0435\u0434\u0430\u0439\u0442\u0435 \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u043D\u044B\u0439 accessToken \u0432 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044E \u043A\u043B\u0438\u0435\u043D\u0442\u0430."
|
|
1250
1316
|
);
|
|
1251
1317
|
}
|
|
1252
|
-
this.#
|
|
1318
|
+
this.#transitionAuth(accessToken);
|
|
1253
1319
|
await this.#saveSession({ accessToken, obtainedAt: Date.now() });
|
|
1254
1320
|
this.#emitter.emit("tokens", { accessToken });
|
|
1255
1321
|
this.#emitter.emit("signIn", { accessToken });
|
|
@@ -1316,7 +1382,7 @@ function normalizeBaseUrl(baseUrl) {
|
|
|
1316
1382
|
}
|
|
1317
1383
|
|
|
1318
1384
|
// src/core/version.ts
|
|
1319
|
-
var LIBRARY_VERSION = "0.0.
|
|
1385
|
+
var LIBRARY_VERSION = "0.0.11";
|
|
1320
1386
|
|
|
1321
1387
|
// src/core/config.ts
|
|
1322
1388
|
var DEFAULT_BASE_URL = "https://xn--d1ah4a.com";
|
|
@@ -3290,6 +3356,18 @@ var ItdRealtime = class {
|
|
|
3290
3356
|
get transport() {
|
|
3291
3357
|
return this.#transport.name;
|
|
3292
3358
|
}
|
|
3359
|
+
/** Базовый URL клиента, создавшего поток. @internal */
|
|
3360
|
+
get baseUrl() {
|
|
3361
|
+
return this.#deps.baseUrl;
|
|
3362
|
+
}
|
|
3363
|
+
/** Идентификаторы аккаунта и сессии клиента, создавшего поток. @internal */
|
|
3364
|
+
getAuthIdentity() {
|
|
3365
|
+
return this.#deps.getAuthIdentity?.();
|
|
3366
|
+
}
|
|
3367
|
+
/** Непрозрачная область авторизации создавшего поток клиента. @internal */
|
|
3368
|
+
getAuthScope() {
|
|
3369
|
+
return this.#deps.getAuthScope?.();
|
|
3370
|
+
}
|
|
3293
3371
|
/** Подписывается на событие потока. @returns функция отписки */
|
|
3294
3372
|
on(event, listener) {
|
|
3295
3373
|
return this.#emitter.on(event, listener);
|
|
@@ -6166,7 +6244,9 @@ var ItdClient = class _ItdClient {
|
|
|
6166
6244
|
} : void 0;
|
|
6167
6245
|
const authPipeline = composePipeline([pluginsLayer, retriesLayer], transport.send);
|
|
6168
6246
|
const authHandler = (request) => authRetry && request.retry === void 0 ? authPipeline({ ...request, retry: authRetry }) : authPipeline(request);
|
|
6169
|
-
authManager = new AuthManager(config, authHandler, this.#jar
|
|
6247
|
+
authManager = new AuthManager(config, authHandler, this.#jar, {
|
|
6248
|
+
onAccountChange: () => this.#disconnectStreams()
|
|
6249
|
+
});
|
|
6170
6250
|
this.#authManager = authManager;
|
|
6171
6251
|
const middlewares = [];
|
|
6172
6252
|
if (queues) {
|
|
@@ -6245,7 +6325,8 @@ var ItdClient = class _ItdClient {
|
|
|
6245
6325
|
this.#plugins.add(plugin, {
|
|
6246
6326
|
baseUrl: this.#config.baseUrl,
|
|
6247
6327
|
logger: this.#config.logger,
|
|
6248
|
-
getAuthScope: () => this.#authManager.getAuthScope()
|
|
6328
|
+
getAuthScope: () => this.#authManager.getAuthScope(),
|
|
6329
|
+
getAuthIdentity: () => this.#authManager.getAuthIdentity()
|
|
6249
6330
|
});
|
|
6250
6331
|
return this;
|
|
6251
6332
|
}
|
|
@@ -6305,7 +6386,8 @@ var ItdClient = class _ItdClient {
|
|
|
6305
6386
|
* Создаёт поток уведомлений в реальном времени.
|
|
6306
6387
|
*
|
|
6307
6388
|
* Каждый вызов даёт новый независимый поток; обычно он нужен один на приложение.
|
|
6308
|
-
* Соединение поднимается методом `connect()` и держится само.
|
|
6389
|
+
* Соединение поднимается методом `connect()` и держится само. Замена авторизации на токен
|
|
6390
|
+
* другого пользователя завершает все потоки клиента; смена только сессии их не затрагивает.
|
|
6309
6391
|
*
|
|
6310
6392
|
* @example
|
|
6311
6393
|
* ```ts
|
|
@@ -6326,6 +6408,8 @@ var ItdClient = class _ItdClient {
|
|
|
6326
6408
|
baseUrl: this.#config.baseUrl,
|
|
6327
6409
|
fetch: this.#config.fetch,
|
|
6328
6410
|
baseHeaders: (url) => this.#transport.platformHeaders(url),
|
|
6411
|
+
getAuthIdentity: () => this.#authManager.getCurrentAuthIdentity(),
|
|
6412
|
+
getAuthScope: () => this.#authManager.getAuthScope(),
|
|
6329
6413
|
getToken: () => this.#authManager.getAccessToken(),
|
|
6330
6414
|
refresh: () => this.#authManager.onUnauthorized(),
|
|
6331
6415
|
fetchUnreadCount: () => this.notifications.count(),
|
|
@@ -6355,10 +6439,14 @@ var ItdClient = class _ItdClient {
|
|
|
6355
6439
|
* ```
|
|
6356
6440
|
*/
|
|
6357
6441
|
async close() {
|
|
6358
|
-
|
|
6359
|
-
this.#streams.clear();
|
|
6442
|
+
this.#disconnectStreams();
|
|
6360
6443
|
if (this.#ownsQueues) this.#queues?.stop();
|
|
6361
6444
|
}
|
|
6445
|
+
/** Завершает потоки до того, как запросы начнут использовать другой аккаунт. */
|
|
6446
|
+
#disconnectStreams() {
|
|
6447
|
+
for (const stream of [...this.#streams]) stream.disconnect();
|
|
6448
|
+
this.#streams.clear();
|
|
6449
|
+
}
|
|
6362
6450
|
/** Позволяет использовать клиент с `await using`. */
|
|
6363
6451
|
[Symbol.asyncDispose]() {
|
|
6364
6452
|
return this.close();
|
|
@@ -7185,5 +7273,5 @@ function statusDays(service) {
|
|
|
7185
7273
|
}
|
|
7186
7274
|
|
|
7187
7275
|
export { ALLOWED_MIME_TYPES, AUDIO_MIME_TYPES, AUTH_FLAG_COOKIE, AUTH_PATHS, AccessType, AttachmentType, BUILT_IN_SERVICES, CommentSort, DEFAULT_BASE_URL, DEFAULT_STATUS_BASE_URL, DEFAULT_TIMEOUT, DEFAULT_UPLOAD_TIMEOUT, DEFAULT_USER_AGENT, DEVICE_ID_HEADER, DetectedRuntime, FeedTab, IMAGE_MIME_TYPES, IncidentKind, InteractionType, ItdAbortError, ItdAccounts, ItdApiError, ItdApiErrorKind, ItdAuthError, ItdClient, ItdConfigError, ItdConflictError, ItdError, ItdErrorCode, ItdErrorKind, ItdForbiddenError, ItdNetworkError, ItdNotFoundError, ItdPhoneVerificationError, ItdRateLimitError, ItdRealtime, ItdServerError, ItdTimeoutError, ItdValidationError, LIBRARY_VERSION, LikesVisibility, LocalStorageTokenStorage, MAX_RECONNECT_ATTEMPTS, MemoryMultiTokenStorage, MemoryTokenStorage, NOTIFICATION_TYPE_ALIASES, NotificationType, OAuthProvider, PaginationMode, Paginator, RECONNECT_BACKOFF, RECONNECT_JITTER, REFRESH_COOKIE, REFRESH_COOKIE_PATH, REQUEST_OPTION_KEYS, RealtimeStatus, RealtimeTransportKind, ReportReason, ReportTargetType, RuntimeMode, STATUS_SERVICE, STREAM_PATH, ServiceRegistry, ServiceState, SignInStatus, SpanType, TURNSTILE_SITE_KEY, UnauthorizedStreamError, VIDEO_MIME_TYPES, ViewReason, ViewSource, WallAccess, autoSpans, canonicalNotificationType, comment, copySession, createAccounts, createClient, createMultiTokenStorage, createRecordMultiStorage, createTokenStorage, formatNotificationText, isBuilder, isItdApiError, isItdAuthError, isItdConflictError, isItdError, isItdForbiddenError, isItdNotFoundError, isItdPhoneVerificationError, isItdRateLimitError, isItdServerError, isItdValidationError, isKnownNotificationType, isMyProfile, mapPage, markup, normalizeNotification, poll, post, readNotificationEvent, readUnreadCountEvent, renderSpans, report, resolveNotificationUrl, scopedTokenStorage, statusDays, toDate, utcStampToIso };
|
|
7188
|
-
//# sourceMappingURL=chunk-
|
|
7189
|
-
//# sourceMappingURL=chunk-
|
|
7276
|
+
//# sourceMappingURL=chunk-TB7HW3VX.js.map
|
|
7277
|
+
//# sourceMappingURL=chunk-TB7HW3VX.js.map
|