itd-api 0.7.2 → 0.8.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 +12 -12
- package/dist/events/index.cjs +53 -0
- package/dist/events/index.d.cts +3 -0
- package/dist/events/index.d.ts +3 -0
- package/dist/events/index.js +5 -0
- package/dist/index.cjs +215 -194
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +66 -63
- package/dist/index.d.ts +66 -63
- package/dist/index.js +197 -179
- package/dist/index.js.map +1 -1
- package/dist/node/index.cjs +4 -4
- package/dist/node/index.d.cts +1 -1
- package/dist/node/index.d.ts +1 -1
- package/dist/node/index.js +4 -4
- package/dist/rest/index.cjs +20 -26
- package/dist/rest/index.cjs.map +1 -1
- package/dist/rest/index.d.cts +7 -7
- package/dist/rest/index.d.ts +7 -7
- package/dist/rest/index.js +14 -20
- package/dist/rest/index.js.map +1 -1
- package/dist/shared/{errors-DfU8M5eS.cjs → errors-BmP3TKoW.cjs} +3 -3
- package/dist/shared/{errors-DfU8M5eS.cjs.map → errors-BmP3TKoW.cjs.map} +1 -1
- package/dist/shared/{errors-Bhrd2fJd.js → errors-GI10kZxk.js} +3 -3
- package/dist/shared/{errors-Bhrd2fJd.js.map → errors-GI10kZxk.js.map} +1 -1
- package/dist/shared/events-Br2r7coi.d.cts +698 -0
- package/dist/shared/events-QyhQZrnC.d.ts +698 -0
- package/dist/shared/{websocket-BLR8eVJV.js → events-TfhKh26b.js} +770 -490
- package/dist/shared/events-TfhKh26b.js.map +1 -0
- package/dist/shared/{websocket-C_eI4H2o.cjs → events-iTteVsd_.cjs} +834 -518
- package/dist/shared/events-iTteVsd_.cjs.map +1 -0
- package/dist/shared/{multi-storage-CkvTUC5m.js → multi-storage-1AEZTczk.js} +4 -4
- package/dist/shared/{multi-storage-CkvTUC5m.js.map → multi-storage-1AEZTczk.js.map} +1 -1
- package/dist/shared/{multi-storage--yTEqiod.cjs → multi-storage-CCUgkqvI.cjs} +6 -6
- package/dist/shared/{multi-storage--yTEqiod.cjs.map → multi-storage-CCUgkqvI.cjs.map} +1 -1
- package/dist/shared/{options-DtATYdLr.js → options-BNP633A5.js} +8 -6
- package/dist/shared/options-BNP633A5.js.map +1 -0
- package/dist/shared/{options-Dg5N3r1V.cjs → options-BUfoHE9G.cjs} +8 -6
- package/dist/shared/options-BUfoHE9G.cjs.map +1 -0
- package/dist/shared/{cookies-DZwFq6kr.cjs → redact-DB9EMGJx.cjs} +301 -2
- package/dist/shared/redact-DB9EMGJx.cjs.map +1 -0
- package/dist/shared/{cookies-tX2sNwxb.js → redact-FNK29Fv-.js} +224 -3
- package/dist/shared/redact-FNK29Fv-.js.map +1 -0
- package/dist/shared/{render-DO0F5YSm.d.cts → render-BszcKF7S.d.cts} +430 -313
- package/dist/shared/{render-C6HRPs10.js → render-CiL1VS0b.js} +925 -582
- package/dist/shared/render-CiL1VS0b.js.map +1 -0
- package/dist/shared/{render-mcuELiYi.cjs → render-DNTESBSl.cjs} +967 -618
- package/dist/shared/render-DNTESBSl.cjs.map +1 -0
- package/dist/shared/{render-CgwKdOzu.d.ts → render-DVB7T8pm.d.ts} +430 -313
- package/dist/shared/{storage-BPJR_k4-.cjs → storage-BLmXmzKF.cjs} +2 -2
- package/dist/shared/{storage-BPJR_k4-.cjs.map → storage-BLmXmzKF.cjs.map} +1 -1
- package/dist/shared/{storage-D86edNCB.js → storage-CCxn0Kkv.js} +2 -2
- package/dist/shared/{storage-D86edNCB.js.map → storage-CCxn0Kkv.js.map} +1 -1
- package/dist/shared/{url-IU0xN9wX.js → url-B3ocFlHj.js} +434 -408
- package/dist/shared/url-B3ocFlHj.js.map +1 -0
- package/dist/shared/{url-DTfZ2toq.d.cts → url-Be9jlWRv.d.cts} +1228 -1188
- package/dist/shared/{url-DTfZ2toq.d.ts → url-Be9jlWRv.d.ts} +1228 -1188
- package/dist/shared/{url-BaMCQpYH.cjs → url-CFN1sT9S.cjs} +497 -465
- package/dist/shared/url-CFN1sT9S.cjs.map +1 -0
- package/dist/web/index.cjs +2 -2
- package/dist/web/index.js +2 -2
- package/package.json +16 -15
- package/dist/realtime/index.cjs +0 -165
- package/dist/realtime/index.cjs.map +0 -1
- package/dist/realtime/index.d.cts +0 -51
- package/dist/realtime/index.d.ts +0 -51
- package/dist/realtime/index.js +0 -120
- package/dist/realtime/index.js.map +0 -1
- package/dist/shared/auth-provider-CG8oCQ9F.cjs +0 -108
- package/dist/shared/auth-provider-CG8oCQ9F.cjs.map +0 -1
- package/dist/shared/auth-provider-mYqxsSVa.js +0 -91
- package/dist/shared/auth-provider-mYqxsSVa.js.map +0 -1
- package/dist/shared/cookies-DZwFq6kr.cjs.map +0 -1
- package/dist/shared/cookies-tX2sNwxb.js.map +0 -1
- package/dist/shared/options-Dg5N3r1V.cjs.map +0 -1
- package/dist/shared/options-DtATYdLr.js.map +0 -1
- package/dist/shared/render-C6HRPs10.js.map +0 -1
- package/dist/shared/render-mcuELiYi.cjs.map +0 -1
- package/dist/shared/url-BaMCQpYH.cjs.map +0 -1
- package/dist/shared/url-IU0xN9wX.js.map +0 -1
- package/dist/shared/websocket-BLR8eVJV.js.map +0 -1
- package/dist/shared/websocket-C_eI4H2o.cjs.map +0 -1
- package/dist/shared/websocket-DF7XIMiX.d.cts +0 -562
- package/dist/shared/websocket-DYKBr8HF.d.ts +0 -562
package/dist/index.cjs
CHANGED
|
@@ -1,12 +1,64 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_url = require("./shared/url-
|
|
3
|
-
const require_errors = require("./shared/errors-
|
|
4
|
-
const
|
|
5
|
-
const require_render = require("./shared/render-
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const require_multi_storage = require("./shared/multi-storage
|
|
2
|
+
const require_url = require("./shared/url-CFN1sT9S.cjs");
|
|
3
|
+
const require_errors = require("./shared/errors-BmP3TKoW.cjs");
|
|
4
|
+
const require_redact = require("./shared/redact-DB9EMGJx.cjs");
|
|
5
|
+
const require_render = require("./shared/render-DNTESBSl.cjs");
|
|
6
|
+
const require_options = require("./shared/options-BUfoHE9G.cjs");
|
|
7
|
+
const require_events = require("./shared/events-iTteVsd_.cjs");
|
|
8
|
+
const require_storage = require("./shared/storage-BLmXmzKF.cjs");
|
|
9
|
+
const require_multi_storage = require("./shared/multi-storage-CCUgkqvI.cjs");
|
|
10
|
+
//#region src/notifications-api.ts
|
|
11
|
+
var ClientNotifications = class extends require_render.NotificationsResource {
|
|
12
|
+
#createEvents;
|
|
13
|
+
#events;
|
|
14
|
+
constructor(http, createEvents) {
|
|
15
|
+
super(http);
|
|
16
|
+
this.#createEvents = createEvents;
|
|
17
|
+
}
|
|
18
|
+
get events() {
|
|
19
|
+
this.#events ??= this.#createEvents(this);
|
|
20
|
+
return this.#events;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
/** Создаёт API уведомлений полного клиента. @internal */
|
|
24
|
+
function createNotificationsApi(http, createEvents) {
|
|
25
|
+
return new ClientNotifications(http, createEvents);
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/operations/auth.ts
|
|
29
|
+
/** Чем закончился запрос входа. */
|
|
30
|
+
const SignInStatus = Object.freeze({
|
|
31
|
+
Authenticated: "authenticated",
|
|
32
|
+
OtpRequired: "otp_required"
|
|
33
|
+
});
|
|
34
|
+
function requireString(body, key, message) {
|
|
35
|
+
const value = require_url.pickString(body, key);
|
|
36
|
+
if (!value) throw new require_errors.ItdConfigError(message);
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
const AUTH_CHECK = require_url.passthroughOperation("auth.check");
|
|
40
|
+
const AUTH_SIGN_UP = require_url.defineBuiltInOperation("auth.signUp", (body) => requireString(body, "flowToken", "Сервер не вернул flowToken при регистрации"));
|
|
41
|
+
const AUTH_SIGN_IN = require_url.defineBuiltInOperation("auth.signIn", (body) => {
|
|
42
|
+
const accessToken = require_url.pickString(body, "accessToken");
|
|
43
|
+
return accessToken ? {
|
|
44
|
+
status: SignInStatus.Authenticated,
|
|
45
|
+
accessToken
|
|
46
|
+
} : {
|
|
47
|
+
status: SignInStatus.OtpRequired,
|
|
48
|
+
flowToken: require_url.pickString(body, "flowToken")
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
const AUTH_VERIFY_OTP = require_url.defineBuiltInOperation("auth.verifyOtp", (body) => requireString(body, "accessToken", "Сервер не вернул accessToken после подтверждения кода"));
|
|
52
|
+
const AUTH_REFRESH = require_url.defineBuiltInOperation("auth.refresh", (body) => require_url.pickString(body, "accessToken"));
|
|
53
|
+
const AUTH_RESEND_OTP = require_url.voidOperation("auth.resendOtp");
|
|
54
|
+
const AUTH_LOGOUT = require_url.voidOperation("auth.logout");
|
|
55
|
+
const AUTH_FORGOT_PASSWORD = require_url.defineBuiltInOperation("auth.forgotPassword", (body) => requireString(body, "flowToken", "Сервер не вернул flowToken при запросе сброса пароля"));
|
|
56
|
+
const AUTH_RESET_PASSWORD = require_url.voidOperation("auth.resetPassword");
|
|
57
|
+
const AUTH_CHANGE_PASSWORD = require_url.voidOperation("auth.changePassword");
|
|
58
|
+
const AUTH_SESSIONS = require_url.defineBuiltInOperation("auth.sessions", (body) => require_url.pickArray(body, "sessions"));
|
|
59
|
+
const AUTH_REVOKE_SESSION = require_url.voidOperation("auth.revokeSession");
|
|
60
|
+
const AUTH_REVOKE_OTHER_SESSIONS = require_url.voidOperation("auth.revokeOtherSessions");
|
|
61
|
+
//#endregion
|
|
10
62
|
//#region src/session/jwt.ts
|
|
11
63
|
/**
|
|
12
64
|
* Разбирает строку base64url.
|
|
@@ -123,7 +175,7 @@ function resolveSessionConfig(options, runtime) {
|
|
|
123
175
|
* достижимой из любой сборки, включая анонимную.
|
|
124
176
|
*/
|
|
125
177
|
function createItdAuth(options, deps) {
|
|
126
|
-
return new AuthManager(resolveSessionConfig(options, deps.config), deps.
|
|
178
|
+
return new AuthManager(resolveSessionConfig(options, deps.config), deps.http, deps.cookies, { onAccountChange: deps.onAccountChange });
|
|
127
179
|
}
|
|
128
180
|
/** Пути эндпоинтов авторизации. */
|
|
129
181
|
const AUTH_PATHS = {
|
|
@@ -158,11 +210,6 @@ const AUTH_PATHS = {
|
|
|
158
210
|
* ```
|
|
159
211
|
*/
|
|
160
212
|
const TURNSTILE_SITE_KEY = "0x4AAAAAACHhxczw6fJGwPBg";
|
|
161
|
-
function readAccessToken(payload) {
|
|
162
|
-
if (typeof payload !== "object" || payload === null) return void 0;
|
|
163
|
-
const token = payload.accessToken;
|
|
164
|
-
return typeof token === "string" && token.length > 0 ? token : void 0;
|
|
165
|
-
}
|
|
166
213
|
/** Убирает поле, которое сохраняли промежуточные версии с поддержкой `getUserId()`. */
|
|
167
214
|
function withoutLegacyUserId(session) {
|
|
168
215
|
const clean = { ...session };
|
|
@@ -184,7 +231,7 @@ function nextAuthScope() {
|
|
|
184
231
|
*/
|
|
185
232
|
var AuthManager = class {
|
|
186
233
|
#config;
|
|
187
|
-
#
|
|
234
|
+
#http;
|
|
188
235
|
#jar;
|
|
189
236
|
#emitter;
|
|
190
237
|
#hooks;
|
|
@@ -223,12 +270,12 @@ var AuthManager = class {
|
|
|
223
270
|
* воскресить уже очищенную сессию поверх `signOut`.
|
|
224
271
|
*/
|
|
225
272
|
#authEpoch = 0;
|
|
226
|
-
constructor(config,
|
|
273
|
+
constructor(config, http, jar, hooks = {}) {
|
|
227
274
|
this.#config = config;
|
|
228
|
-
this.#
|
|
275
|
+
this.#http = http;
|
|
229
276
|
this.#jar = jar;
|
|
230
277
|
this.#hooks = hooks;
|
|
231
|
-
this.#emitter = new
|
|
278
|
+
this.#emitter = new require_events.Emitter((error) => require_events.reportListenerError(config.logger, "авторизации", error));
|
|
232
279
|
}
|
|
233
280
|
/** Подписка на события авторизации. */
|
|
234
281
|
get on() {
|
|
@@ -238,7 +285,7 @@ var AuthManager = class {
|
|
|
238
285
|
get once() {
|
|
239
286
|
return this.#emitter.once.bind(this.#emitter);
|
|
240
287
|
}
|
|
241
|
-
/** Снимает
|
|
288
|
+
/** Снимает служебные подписки при окончательном освобождении владельца. @internal */
|
|
242
289
|
dispose() {
|
|
243
290
|
this.#invalidateInFlight();
|
|
244
291
|
this.#emitter.removeAllListeners();
|
|
@@ -294,7 +341,7 @@ var AuthManager = class {
|
|
|
294
341
|
this.#externalIdentity = current;
|
|
295
342
|
return token;
|
|
296
343
|
}
|
|
297
|
-
/**
|
|
344
|
+
/** Обновляет резервный идентификатор и закрывает события при смене аккаунта. */
|
|
298
345
|
#transitionAuth(accessToken, rotateFallback = true) {
|
|
299
346
|
const knownPrevious = this.#session !== void 0;
|
|
300
347
|
const previous = this.#identityForToken(this.#session?.accessToken);
|
|
@@ -367,7 +414,7 @@ var AuthManager = class {
|
|
|
367
414
|
}
|
|
368
415
|
async #resolveDeviceId() {
|
|
369
416
|
const session = await this.#loadSession();
|
|
370
|
-
const deviceId = this.#config.deviceId ?? session?.deviceId ??
|
|
417
|
+
const deviceId = this.#config.deviceId ?? session?.deviceId ?? require_redact.createDeviceId();
|
|
371
418
|
this.#deviceId = deviceId;
|
|
372
419
|
if (session?.deviceId !== deviceId) await this.#saveSession({
|
|
373
420
|
...session ?? {},
|
|
@@ -522,7 +569,7 @@ var AuthManager = class {
|
|
|
522
569
|
const refreshToken = this.#session?.refreshToken;
|
|
523
570
|
if (!refreshToken) return;
|
|
524
571
|
if (this.#jar.has("refresh_token")) return;
|
|
525
|
-
this.#jar.set(this.#config.baseUrl,
|
|
572
|
+
this.#jar.set(this.#config.baseUrl, require_redact.REFRESH_COOKIE, refreshToken, require_redact.REFRESH_COOKIE_PATH);
|
|
526
573
|
}
|
|
527
574
|
#sessionFromConfig(auth) {
|
|
528
575
|
if (!auth) return null;
|
|
@@ -566,16 +613,14 @@ var AuthManager = class {
|
|
|
566
613
|
if (!this.#hasRefreshSession()) return this.#reloginOrNull();
|
|
567
614
|
const epoch = this.#authEpoch;
|
|
568
615
|
try {
|
|
569
|
-
const accessToken =
|
|
570
|
-
operationId: "auth.refresh",
|
|
571
|
-
method: require_url.operationMethod("auth.refresh"),
|
|
616
|
+
const accessToken = await this.#http.execute(AUTH_REFRESH, {
|
|
572
617
|
path: AUTH_PATHS.refresh,
|
|
573
618
|
skipAuth: true,
|
|
574
619
|
skipAuthRefresh: true
|
|
575
|
-
})
|
|
620
|
+
});
|
|
576
621
|
if (!accessToken) return this.#reloginOrNull();
|
|
577
622
|
if (this.#authEpoch !== epoch) return this.#session?.accessToken ?? null;
|
|
578
|
-
const rotated = this.#jar.getValue(
|
|
623
|
+
const rotated = this.#jar.getValue(require_redact.REFRESH_COOKIE, this.#config.baseUrl + require_redact.REFRESH_COOKIE_PATH);
|
|
579
624
|
this.#transitionAuth(accessToken, false);
|
|
580
625
|
await this.#saveSession({
|
|
581
626
|
...this.#session ?? {},
|
|
@@ -639,9 +684,7 @@ var AuthManager = class {
|
|
|
639
684
|
}
|
|
640
685
|
async #performSignIn(credentials) {
|
|
641
686
|
const turnstileToken = await this.#resolveTurnstileToken(credentials);
|
|
642
|
-
const
|
|
643
|
-
operationId: "auth.signIn",
|
|
644
|
-
method: require_url.operationMethod("auth.signIn"),
|
|
687
|
+
const result = await this.#http.execute(AUTH_SIGN_IN, {
|
|
645
688
|
path: AUTH_PATHS.signIn,
|
|
646
689
|
body: {
|
|
647
690
|
email: credentials.email,
|
|
@@ -650,8 +693,9 @@ var AuthManager = class {
|
|
|
650
693
|
},
|
|
651
694
|
skipAuth: true,
|
|
652
695
|
skipAuthRefresh: true
|
|
653
|
-
})
|
|
654
|
-
if (
|
|
696
|
+
});
|
|
697
|
+
if (result.status !== SignInStatus.Authenticated) throw new require_errors.ItdConfigError("Вход по email и паролю требует подтверждения кодом из письма. Автоматический вход невозможен: воспользуйтесь itd.auth.signInWithOtp() и передайте полученный accessToken в конфигурацию клиента.");
|
|
698
|
+
const accessToken = result.accessToken;
|
|
655
699
|
this.#invalidateInFlight();
|
|
656
700
|
this.#transitionAuth(accessToken);
|
|
657
701
|
await this.#saveSession({
|
|
@@ -665,11 +709,12 @@ var AuthManager = class {
|
|
|
665
709
|
};
|
|
666
710
|
//#endregion
|
|
667
711
|
//#region src/resources/auth.ts
|
|
668
|
-
/**
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
712
|
+
/**
|
|
713
|
+
* Результат входа.
|
|
714
|
+
*
|
|
715
|
+
* Сервер может как сразу выдать токен, так и потребовать код подтверждения — размеченное
|
|
716
|
+
* объединение делает оба случая явными.
|
|
717
|
+
*/
|
|
673
718
|
/**
|
|
674
719
|
* Авторизация, сессии и пароли.
|
|
675
720
|
*
|
|
@@ -687,7 +732,7 @@ var AuthResource = class extends require_render.BaseResource {
|
|
|
687
732
|
* Без авторизации возвращает `authenticated: false` и `user: null`.
|
|
688
733
|
*/
|
|
689
734
|
check(options = {}) {
|
|
690
|
-
return this.http.
|
|
735
|
+
return this.http.execute(AUTH_CHECK, {
|
|
691
736
|
path: "/api/profile",
|
|
692
737
|
...options
|
|
693
738
|
});
|
|
@@ -697,17 +742,14 @@ var AuthResource = class extends require_render.BaseResource {
|
|
|
697
742
|
*
|
|
698
743
|
* @returns `flowToken`, который нужно передать в {@link verifyOtp}
|
|
699
744
|
*/
|
|
700
|
-
|
|
701
|
-
|
|
745
|
+
signUp(credentials, options = {}) {
|
|
746
|
+
return this.http.execute(AUTH_SIGN_UP, {
|
|
702
747
|
path: AUTH_PATHS.signUp,
|
|
703
748
|
body: credentials,
|
|
704
749
|
skipAuth: true,
|
|
705
750
|
skipAuthRefresh: true,
|
|
706
751
|
...options
|
|
707
752
|
});
|
|
708
|
-
const flowToken = require_url.pickString(body, "flowToken");
|
|
709
|
-
if (!flowToken) throw new require_errors.ItdConfigError("Сервер не вернул flowToken при регистрации");
|
|
710
|
-
return flowToken;
|
|
711
753
|
}
|
|
712
754
|
/**
|
|
713
755
|
* Выполняет вход.
|
|
@@ -720,25 +762,15 @@ var AuthResource = class extends require_render.BaseResource {
|
|
|
720
762
|
* @param credentials email, пароль и обязательный токен капчи — см. {@link CaptchaCredentials}
|
|
721
763
|
*/
|
|
722
764
|
async signIn(credentials, options = {}) {
|
|
723
|
-
const
|
|
765
|
+
const result = await this.http.execute(AUTH_SIGN_IN, {
|
|
724
766
|
path: AUTH_PATHS.signIn,
|
|
725
767
|
body: credentials,
|
|
726
768
|
skipAuth: true,
|
|
727
769
|
skipAuthRefresh: true,
|
|
728
770
|
...options
|
|
729
771
|
});
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
await this.#auth.setAccessToken(accessToken);
|
|
733
|
-
return {
|
|
734
|
-
status: SignInStatus.Authenticated,
|
|
735
|
-
accessToken
|
|
736
|
-
};
|
|
737
|
-
}
|
|
738
|
-
return {
|
|
739
|
-
status: SignInStatus.OtpRequired,
|
|
740
|
-
flowToken: require_url.pickString(body, "flowToken")
|
|
741
|
-
};
|
|
772
|
+
if (result.status === SignInStatus.Authenticated) await this.#auth.setAccessToken(result.accessToken);
|
|
773
|
+
return result;
|
|
742
774
|
}
|
|
743
775
|
/**
|
|
744
776
|
* Подтверждает вход кодом из письма.
|
|
@@ -746,21 +778,19 @@ var AuthResource = class extends require_render.BaseResource {
|
|
|
746
778
|
* Полученный токен сохраняется в клиенте автоматически.
|
|
747
779
|
*/
|
|
748
780
|
async verifyOtp(input, options = {}) {
|
|
749
|
-
const
|
|
781
|
+
const accessToken = await this.http.execute(AUTH_VERIFY_OTP, {
|
|
750
782
|
path: AUTH_PATHS.verifyOtp,
|
|
751
783
|
body: input,
|
|
752
784
|
skipAuth: true,
|
|
753
785
|
skipAuthRefresh: true,
|
|
754
786
|
...options
|
|
755
787
|
});
|
|
756
|
-
const accessToken = require_url.pickString(body, "accessToken");
|
|
757
|
-
if (!accessToken) throw new require_errors.ItdConfigError("Сервер не вернул accessToken после подтверждения кода");
|
|
758
788
|
await this.#auth.setAccessToken(accessToken);
|
|
759
789
|
return accessToken;
|
|
760
790
|
}
|
|
761
791
|
/** Отправляет код подтверждения повторно. */
|
|
762
792
|
resendOtp(input, options = {}) {
|
|
763
|
-
return this.
|
|
793
|
+
return this.voidOperation(AUTH_RESEND_OTP, {
|
|
764
794
|
path: AUTH_PATHS.resendOtp,
|
|
765
795
|
body: input,
|
|
766
796
|
skipAuth: true,
|
|
@@ -829,7 +859,7 @@ var AuthResource = class extends require_render.BaseResource {
|
|
|
829
859
|
}
|
|
830
860
|
/** Завершает текущую сессию на сервере и очищает локальную. */
|
|
831
861
|
async logout(options = {}) {
|
|
832
|
-
await this.
|
|
862
|
+
await this.voidOperation(AUTH_LOGOUT, {
|
|
833
863
|
path: AUTH_PATHS.logout,
|
|
834
864
|
skipAuthRefresh: true,
|
|
835
865
|
...options
|
|
@@ -857,17 +887,14 @@ var AuthResource = class extends require_render.BaseResource {
|
|
|
857
887
|
*
|
|
858
888
|
* @returns `flowToken`, который нужно передать в {@link resetPassword}
|
|
859
889
|
*/
|
|
860
|
-
|
|
861
|
-
|
|
890
|
+
forgotPassword(input, options = {}) {
|
|
891
|
+
return this.http.execute(AUTH_FORGOT_PASSWORD, {
|
|
862
892
|
path: AUTH_PATHS.forgotPassword,
|
|
863
893
|
body: input,
|
|
864
894
|
skipAuth: true,
|
|
865
895
|
skipAuthRefresh: true,
|
|
866
896
|
...options
|
|
867
897
|
});
|
|
868
|
-
const flowToken = require_url.pickString(body, "flowToken");
|
|
869
|
-
if (!flowToken) throw new require_errors.ItdConfigError("Сервер не вернул flowToken при запросе сброса пароля");
|
|
870
|
-
return flowToken;
|
|
871
898
|
}
|
|
872
899
|
/**
|
|
873
900
|
* Устанавливает новый пароль по коду из письма.
|
|
@@ -876,7 +903,7 @@ var AuthResource = class extends require_render.BaseResource {
|
|
|
876
903
|
* при нехватке любого отвечает `422`.
|
|
877
904
|
*/
|
|
878
905
|
resetPassword(input, options = {}) {
|
|
879
|
-
return this.
|
|
906
|
+
return this.voidOperation(AUTH_RESET_PASSWORD, {
|
|
880
907
|
path: AUTH_PATHS.resetPassword,
|
|
881
908
|
body: input,
|
|
882
909
|
skipAuth: true,
|
|
@@ -924,7 +951,7 @@ var AuthResource = class extends require_render.BaseResource {
|
|
|
924
951
|
* ```
|
|
925
952
|
*/
|
|
926
953
|
changePassword(input, options = {}) {
|
|
927
|
-
return this.
|
|
954
|
+
return this.voidOperation(AUTH_CHANGE_PASSWORD, {
|
|
928
955
|
path: AUTH_PATHS.changePassword,
|
|
929
956
|
body: {
|
|
930
957
|
currentPassword: input.currentPassword,
|
|
@@ -934,23 +961,22 @@ var AuthResource = class extends require_render.BaseResource {
|
|
|
934
961
|
});
|
|
935
962
|
}
|
|
936
963
|
/** Загружает список активных сессий. У текущей поле `isCurrent` равно `true`. */
|
|
937
|
-
|
|
938
|
-
|
|
964
|
+
sessions(options = {}) {
|
|
965
|
+
return this.http.execute(AUTH_SESSIONS, {
|
|
939
966
|
path: AUTH_PATHS.sessions,
|
|
940
967
|
...options
|
|
941
968
|
});
|
|
942
|
-
return require_url.pickArray(body, "sessions");
|
|
943
969
|
}
|
|
944
970
|
/** Завершает указанную сессию. */
|
|
945
971
|
revokeSession(sessionId, options = {}) {
|
|
946
|
-
return this.
|
|
972
|
+
return this.voidOperation(AUTH_REVOKE_SESSION, {
|
|
947
973
|
path: `${AUTH_PATHS.sessions}/${encodeURIComponent(sessionId)}`,
|
|
948
974
|
...options
|
|
949
975
|
});
|
|
950
976
|
}
|
|
951
977
|
/** Завершает все сессии, кроме текущей. */
|
|
952
978
|
revokeOtherSessions(options = {}) {
|
|
953
|
-
return this.
|
|
979
|
+
return this.voidOperation(AUTH_REVOKE_OTHER_SESSIONS, {
|
|
954
980
|
path: AUTH_PATHS.sessions,
|
|
955
981
|
...options
|
|
956
982
|
});
|
|
@@ -1014,8 +1040,6 @@ function createManagedClient(options, internals) {
|
|
|
1014
1040
|
var ItdClient = class ItdClient {
|
|
1015
1041
|
#runtime;
|
|
1016
1042
|
#features;
|
|
1017
|
-
/** Порождённые потоки уведомлений — чтобы `close()` мог закрыть их разом. */
|
|
1018
|
-
#streams = /* @__PURE__ */ new Set();
|
|
1019
1043
|
/** Общий результат терминальной очистки для идемпотентных повторных вызовов. */
|
|
1020
1044
|
#disposePromise;
|
|
1021
1045
|
/** Ресурсы конвейера запросов; создаются при первом обращении. */
|
|
@@ -1076,33 +1100,71 @@ var ItdClient = class ItdClient {
|
|
|
1076
1100
|
return this.#resources.telemetry;
|
|
1077
1101
|
}
|
|
1078
1102
|
constructor(options = {}) {
|
|
1103
|
+
const notificationEventsOptions = require_events.resolveNotificationEventsOptions(options.events?.notifications);
|
|
1079
1104
|
const internals = CLIENT_INTERNALS.get(options) ?? {};
|
|
1080
1105
|
const catalog = new require_render.ExtensibleOperationCatalog(require_url.ITD_CATALOG);
|
|
1106
|
+
let featureHost;
|
|
1081
1107
|
this.#runtime = require_url.createClientRuntime(options, {
|
|
1082
1108
|
catalog,
|
|
1083
1109
|
queues: internals.queues,
|
|
1084
1110
|
assertActive: (action) => assertClientActive(this, action),
|
|
1085
1111
|
auth: (deps) => createItdAuth(options, {
|
|
1086
1112
|
...deps,
|
|
1087
|
-
onAccountChange: () =>
|
|
1113
|
+
onAccountChange: () => featureHost?.stop()
|
|
1088
1114
|
})
|
|
1089
1115
|
});
|
|
1090
|
-
this.#features =
|
|
1091
|
-
http: this.#runtime.http,
|
|
1092
|
-
services: this.#runtime.services,
|
|
1093
|
-
serviceOverrides: this.#runtime.config.services,
|
|
1116
|
+
this.#features = featureHost = require_render.createFeatureHost(this.#runtime, {
|
|
1094
1117
|
catalog,
|
|
1095
|
-
|
|
1096
|
-
clock: this.#runtime.config.clock,
|
|
1097
|
-
logger: this.#runtime.config.logger,
|
|
1098
|
-
assertActive: (action) => assertClientActive(this, action),
|
|
1099
|
-
registerBucket: (name, definition) => this.#runtime.registerRateLimitBucket(name, definition)
|
|
1118
|
+
assertActive: (action) => assertClientActive(this, action)
|
|
1100
1119
|
});
|
|
1101
1120
|
const status = this.#features.install(require_render.createStatusFeature());
|
|
1102
1121
|
this.#resources = require_render.createResources({
|
|
1103
1122
|
http: this.#runtime.http,
|
|
1104
|
-
|
|
1105
|
-
status
|
|
1123
|
+
files: this.#features.files,
|
|
1124
|
+
status,
|
|
1125
|
+
createNotifications: (http) => createNotificationsApi(http, (notifications) => {
|
|
1126
|
+
let events;
|
|
1127
|
+
let lifecycleGeneration = 0;
|
|
1128
|
+
let lifecycleActive = false;
|
|
1129
|
+
let unregister;
|
|
1130
|
+
const releaseAfterDrain = (generation) => {
|
|
1131
|
+
events.drain().then(() => {
|
|
1132
|
+
if (lifecycleActive || generation !== lifecycleGeneration) return;
|
|
1133
|
+
unregister?.();
|
|
1134
|
+
unregister = void 0;
|
|
1135
|
+
});
|
|
1136
|
+
};
|
|
1137
|
+
events = new require_events.NotificationEvents({
|
|
1138
|
+
connection: this.#runtime.connection(),
|
|
1139
|
+
request: ({ operationId, path, query, signal }) => this.#runtime.http.execute(require_events.EVENT_OPERATIONS[operationId], {
|
|
1140
|
+
path,
|
|
1141
|
+
query,
|
|
1142
|
+
signal
|
|
1143
|
+
}),
|
|
1144
|
+
getAuthIdentity: () => this.#runtime.auth.getCurrentAuthIdentity(),
|
|
1145
|
+
getAuthScope: () => this.#runtime.auth.getAuthScope(),
|
|
1146
|
+
fetchUnreadCount: (signal) => notifications.count({ signal }),
|
|
1147
|
+
onConnect: () => {
|
|
1148
|
+
lifecycleGeneration += 1;
|
|
1149
|
+
unregister ??= this.#features.manage({
|
|
1150
|
+
kind: `notifications:${events.transport}`,
|
|
1151
|
+
stop: () => {
|
|
1152
|
+
if (lifecycleActive) events.disconnect();
|
|
1153
|
+
},
|
|
1154
|
+
drain: () => events.drain()
|
|
1155
|
+
});
|
|
1156
|
+
lifecycleActive = true;
|
|
1157
|
+
},
|
|
1158
|
+
onClose: () => {
|
|
1159
|
+
lifecycleActive = false;
|
|
1160
|
+
releaseAfterDrain(++lifecycleGeneration);
|
|
1161
|
+
},
|
|
1162
|
+
logger: this.#runtime.config.logger,
|
|
1163
|
+
clock: this.#runtime.config.clock
|
|
1164
|
+
}, notificationEventsOptions);
|
|
1165
|
+
require_events.setNotificationEventsConnectGuard(events, () => assertClientActive(this, "подключить канал событий уведомлений"));
|
|
1166
|
+
return events;
|
|
1167
|
+
})
|
|
1106
1168
|
});
|
|
1107
1169
|
CLIENT_PLUGIN_REGISTRIES.set(this, this.#runtime.plugins);
|
|
1108
1170
|
}
|
|
@@ -1146,19 +1208,19 @@ var ItdClient = class ItdClient {
|
|
|
1146
1208
|
return this.#runtime.rateLimitState();
|
|
1147
1209
|
}
|
|
1148
1210
|
/**
|
|
1149
|
-
* Устанавливает предметный модуль
|
|
1211
|
+
* Устанавливает предметный модуль с общей сессией и обработкой запросов клиента.
|
|
1150
1212
|
*
|
|
1151
|
-
* Сервисы, операции и бакеты
|
|
1152
|
-
*
|
|
1213
|
+
* Сервисы, операции и бакеты регистрируются до синхронного `setup()`. Возвращает
|
|
1214
|
+
* типизированный API модуля.
|
|
1153
1215
|
*/
|
|
1154
1216
|
install(feature) {
|
|
1155
1217
|
return this.#features.install(feature);
|
|
1156
1218
|
}
|
|
1157
1219
|
/**
|
|
1158
|
-
* Устанавливает
|
|
1220
|
+
* Устанавливает модуль и добавляет его API в свойство клиента только для чтения.
|
|
1159
1221
|
*
|
|
1160
1222
|
* Возвращаемое пересечение сохраняет тип уже подключённых свойств, поэтому вызовы можно
|
|
1161
|
-
* объединять в цепочку: `new ItdClient().withFeature('
|
|
1223
|
+
* объединять в цепочку: `new ItdClient().withFeature('pixelBattle', pixelBattleFeature)`.
|
|
1162
1224
|
*/
|
|
1163
1225
|
withFeature(key, feature) {
|
|
1164
1226
|
assertClientActive(this, "установить feature");
|
|
@@ -1174,20 +1236,18 @@ var ItdClient = class ItdClient {
|
|
|
1174
1236
|
});
|
|
1175
1237
|
return this;
|
|
1176
1238
|
}
|
|
1177
|
-
/** Имена установленных
|
|
1239
|
+
/** Имена установленных модулей в порядке установки. */
|
|
1178
1240
|
featureNames() {
|
|
1179
1241
|
return this.#features.names();
|
|
1180
1242
|
}
|
|
1181
|
-
/** Установлен ли
|
|
1243
|
+
/** Установлен ли модуль с таким именем. */
|
|
1182
1244
|
hasFeature(name) {
|
|
1183
1245
|
return this.#features.has(name);
|
|
1184
1246
|
}
|
|
1185
1247
|
/**
|
|
1186
1248
|
* Подключает плагин.
|
|
1187
1249
|
*
|
|
1188
|
-
* Плагин может
|
|
1189
|
-
* транспортной попытки. Оба контракта охватывают все методы клиента. Подключать плагин
|
|
1190
|
-
* можно в любой момент, но обычно это делают сразу после создания клиента.
|
|
1250
|
+
* Плагин может регистрировать обёртки операций и перехватчики сетевых попыток.
|
|
1191
1251
|
*
|
|
1192
1252
|
* @throws {ItdConfigError} если плагин задан неверно или уже подключён
|
|
1193
1253
|
* @throws {ItdStateError} если клиент уже освобождён через {@link dispose}
|
|
@@ -1290,85 +1350,27 @@ var ItdClient = class ItdClient {
|
|
|
1290
1350
|
return this.#runtime.auth.on(event, listener);
|
|
1291
1351
|
}
|
|
1292
1352
|
/**
|
|
1293
|
-
* Создаёт поток уведомлений в реальном времени.
|
|
1294
|
-
*
|
|
1295
|
-
* Каждый вызов даёт новый независимый поток; обычно он нужен один на приложение.
|
|
1296
|
-
* Соединение поднимается методом `connect()` и держится само. Замена авторизации на токен
|
|
1297
|
-
* другого пользователя завершает все потоки клиента; смена только сессии их не затрагивает.
|
|
1298
|
-
*
|
|
1299
|
-
* @example
|
|
1300
|
-
* ```ts
|
|
1301
|
-
* import { NotificationType } from 'itd-api';
|
|
1302
|
-
*
|
|
1303
|
-
* const stream = itd.realtime();
|
|
1304
|
-
*
|
|
1305
|
-
* stream.onNotification(NotificationType.PostComment, async ({ update }) => {
|
|
1306
|
-
* await handleComment(update.data.notification);
|
|
1307
|
-
* });
|
|
1308
|
-
* stream.on('unreadCount', (count) => setBadge(count));
|
|
1309
|
-
*
|
|
1310
|
-
* await stream.connect();
|
|
1311
|
-
* ```
|
|
1312
|
-
*
|
|
1313
|
-
* @throws {ItdStateError} если клиент уже освобождён через {@link dispose}
|
|
1314
|
-
*/
|
|
1315
|
-
realtime(options = {}) {
|
|
1316
|
-
assertClientActive(this, "создать realtime-поток");
|
|
1317
|
-
let stream;
|
|
1318
|
-
stream = new require_websocket.ItdRealtime({
|
|
1319
|
-
baseUrl: this.#runtime.config.baseUrl,
|
|
1320
|
-
fetch: this.#runtime.config.fetch,
|
|
1321
|
-
request: ({ operationId, path, query, signal }) => this.#runtime.http.operation(operationId, {
|
|
1322
|
-
path,
|
|
1323
|
-
query,
|
|
1324
|
-
signal
|
|
1325
|
-
}),
|
|
1326
|
-
baseHeaders: (url) => this.#runtime.platformHeaders(url),
|
|
1327
|
-
getAuthIdentity: () => this.#runtime.auth.getCurrentAuthIdentity(),
|
|
1328
|
-
getAuthScope: () => this.#runtime.auth.getAuthScope(),
|
|
1329
|
-
getToken: () => this.#runtime.auth.token(),
|
|
1330
|
-
refresh: () => this.#runtime.auth.onUnauthorized(),
|
|
1331
|
-
fetchUnreadCount: () => this.notifications.count(),
|
|
1332
|
-
onConnect: () => this.#streams.add(stream),
|
|
1333
|
-
onClose: () => this.#streams.delete(stream),
|
|
1334
|
-
logger: this.#runtime.config.logger,
|
|
1335
|
-
clock: this.#runtime.config.clock
|
|
1336
|
-
}, options);
|
|
1337
|
-
require_websocket.setRealtimeConnectGuard(stream, () => assertClientActive(this, "подключить realtime-поток"));
|
|
1338
|
-
this.#streams.add(stream);
|
|
1339
|
-
return stream;
|
|
1340
|
-
}
|
|
1341
|
-
/**
|
|
1342
1353
|
* Освобождает ресурсы клиента: закрывает все потоки уведомлений, отправляет открытые
|
|
1343
1354
|
* накопители {@link telemetry}, затем останавливает очередь запросов.
|
|
1344
1355
|
*
|
|
1345
|
-
* Метод дожидается активных обработчиков
|
|
1346
|
-
*
|
|
1347
|
-
* повторным `connect()`.
|
|
1356
|
+
* Метод дожидается завершения активных обработчиков и освобождения ресурсов остановленных
|
|
1357
|
+
* событийных соединений, но не дольше `shutdownTimeout`. После вызова клиентом можно
|
|
1358
|
+
* пользоваться снова; ранее созданный поток можно запустить повторным `connect()`.
|
|
1348
1359
|
*
|
|
1349
1360
|
* Общая очередь, полученная от {@link ItdAccounts}, не останавливается: её гасит сам
|
|
1350
1361
|
* контейнер, когда закрывает все аккаунты разом.
|
|
1351
1362
|
*
|
|
1352
1363
|
* Терминальное освобождение — это {@link dispose}.
|
|
1353
1364
|
*
|
|
1354
|
-
* @throws {ItdStateError} если
|
|
1365
|
+
* @throws {ItdStateError} если остановка событийного соединения не завершилась за отведённый срок
|
|
1355
1366
|
*/
|
|
1356
1367
|
async close() {
|
|
1357
1368
|
return this.#close(false);
|
|
1358
1369
|
}
|
|
1359
1370
|
async #close(disposeCleanup) {
|
|
1360
|
-
const streams = this.#disconnectStreams();
|
|
1361
1371
|
if (disposeCleanup) this.#resources.prepareTelemetryClose();
|
|
1362
|
-
const { shutdownTimeout, clock } = this.#runtime.config;
|
|
1363
|
-
const deadline = require_url.createDeadline(shutdownTimeout, clock);
|
|
1364
|
-
let stuck = [];
|
|
1365
1372
|
const errors = [];
|
|
1366
1373
|
try {
|
|
1367
|
-
try {
|
|
1368
|
-
stuck = (await Promise.all(streams.map(async (stream) => await deadline.wait(stream.drain()) ? void 0 : stream))).filter((stream) => stream !== void 0);
|
|
1369
|
-
} catch (error) {
|
|
1370
|
-
errors.push(error);
|
|
1371
|
-
}
|
|
1372
1374
|
try {
|
|
1373
1375
|
await this.#features.close();
|
|
1374
1376
|
} catch (error) {
|
|
@@ -1380,10 +1382,8 @@ var ItdClient = class ItdClient {
|
|
|
1380
1382
|
errors.push(error);
|
|
1381
1383
|
}
|
|
1382
1384
|
} finally {
|
|
1383
|
-
deadline.cancel();
|
|
1384
1385
|
this.#runtime.close();
|
|
1385
1386
|
}
|
|
1386
|
-
if (stuck.length > 0) errors.push(new require_errors.ItdStateError(`обработчики потоков (${stuck.map((stream) => stream.transport).join(", ")}) не завершились за ${shutdownTimeout} мс; ожидание прекращено`));
|
|
1387
1387
|
if (errors.length === 1) throw errors[0];
|
|
1388
1388
|
if (errors.length > 1) throw new AggregateError(errors, "Не удалось закрыть клиент");
|
|
1389
1389
|
}
|
|
@@ -1393,10 +1393,11 @@ var ItdClient = class ItdClient {
|
|
|
1393
1393
|
*
|
|
1394
1394
|
* Терминальное состояние устанавливается сразу при первом вызове. После этого новые
|
|
1395
1395
|
* запросы, подключение плагинов, регистрация сервисов и создание или повторный запуск
|
|
1396
|
-
*
|
|
1396
|
+
* событийных каналов завершаются с {@link ItdStateError}. Повторные вызовы возвращают
|
|
1397
1397
|
* тот же результат очистки.
|
|
1398
1398
|
*
|
|
1399
|
-
* Ожидание
|
|
1399
|
+
* Ожидание остановки событийных соединений и операций плагинов ограничено
|
|
1400
|
+
* `shutdownTimeout`.
|
|
1400
1401
|
*
|
|
1401
1402
|
* @example
|
|
1402
1403
|
* ```ts
|
|
@@ -1430,13 +1431,6 @@ var ItdClient = class ItdClient {
|
|
|
1430
1431
|
}
|
|
1431
1432
|
if (errors.length > 0) throw new AggregateError(errors, "Не удалось освободить клиент");
|
|
1432
1433
|
}
|
|
1433
|
-
/** Завершает потоки до того, как запросы начнут использовать другой аккаунт. */
|
|
1434
|
-
#disconnectStreams() {
|
|
1435
|
-
const streams = [...this.#streams];
|
|
1436
|
-
for (const stream of streams) stream.disconnect();
|
|
1437
|
-
this.#streams.clear();
|
|
1438
|
-
return streams;
|
|
1439
|
-
}
|
|
1440
1434
|
/** Позволяет использовать клиент с `await using`. */
|
|
1441
1435
|
[Symbol.asyncDispose]() {
|
|
1442
1436
|
return this.dispose();
|
|
@@ -1502,6 +1496,25 @@ function createClient(options = {}) {
|
|
|
1502
1496
|
function validateAccountName(name) {
|
|
1503
1497
|
if (typeof name !== "string" || name.trim() === "") throw new require_errors.ItdConfigError("имя аккаунта должно быть непустой строкой");
|
|
1504
1498
|
}
|
|
1499
|
+
/** Проверяет фабрики до создания первого аккаунта. */
|
|
1500
|
+
function resolveAccountFeatures(features) {
|
|
1501
|
+
if (features === void 0) return [];
|
|
1502
|
+
if (!Array.isArray(features)) throw new require_errors.ItdConfigError("features должен быть массивом фабрик подключаемых модулей");
|
|
1503
|
+
const keys = /* @__PURE__ */ new Set();
|
|
1504
|
+
return features.map((feature, index) => {
|
|
1505
|
+
if (typeof feature !== "object" || feature === null || typeof feature.create !== "function") throw new require_errors.ItdConfigError(`features[${index}] должен предоставлять create()`);
|
|
1506
|
+
if (feature.key !== void 0) {
|
|
1507
|
+
if (typeof feature.key !== "string" || feature.key.trim() === "" || feature.key !== feature.key.trim()) throw new require_errors.ItdConfigError(`features[${index}].key должен быть непустой строкой без пробелов`);
|
|
1508
|
+
if (keys.has(feature.key)) throw new require_errors.ItdConfigError(`Свойство подключаемого модуля «${feature.key}» объявлено повторно`);
|
|
1509
|
+
keys.add(feature.key);
|
|
1510
|
+
}
|
|
1511
|
+
const create = feature.create.bind(feature);
|
|
1512
|
+
return Object.freeze({
|
|
1513
|
+
...feature.key === void 0 ? {} : { key: feature.key },
|
|
1514
|
+
create
|
|
1515
|
+
});
|
|
1516
|
+
});
|
|
1517
|
+
}
|
|
1505
1518
|
const DISPOSED_ACCOUNTS = /* @__PURE__ */ new WeakSet();
|
|
1506
1519
|
function assertAccountsActive(accounts, action) {
|
|
1507
1520
|
if (!DISPOSED_ACCOUNTS.has(accounts)) return;
|
|
@@ -1553,6 +1566,8 @@ var ItdAccounts = class ItdAccounts {
|
|
|
1553
1566
|
#eventUnsubscribers = /* @__PURE__ */ new Map();
|
|
1554
1567
|
/** Плагины для всех: и для уже заведённых аккаунтов, и для будущих. */
|
|
1555
1568
|
#plugins;
|
|
1569
|
+
/** Фабрики модулей для новых и восстанавливаемых аккаунтов. */
|
|
1570
|
+
#features;
|
|
1556
1571
|
/** Имена плагинов, чья асинхронная очистка ещё не завершилась. */
|
|
1557
1572
|
#removingPlugins = /* @__PURE__ */ new Set();
|
|
1558
1573
|
/** Общая очередь. `undefined`, когда у каждого аккаунта своя. */
|
|
@@ -1563,17 +1578,18 @@ var ItdAccounts = class ItdAccounts {
|
|
|
1563
1578
|
/** Общий результат терминальной очистки для идемпотентных повторных вызовов. */
|
|
1564
1579
|
#disposePromise;
|
|
1565
1580
|
constructor(options = {}) {
|
|
1566
|
-
const { storage, plugins, rateLimitScope, ...base } = options;
|
|
1581
|
+
const { storage, plugins, features, rateLimitScope, ...base } = options;
|
|
1567
1582
|
if (rateLimitScope !== void 0 && rateLimitScope !== "account" && rateLimitScope !== "shared") throw new require_errors.ItdConfigError("rateLimitScope должен быть 'account' или 'shared'");
|
|
1568
1583
|
this.#base = base;
|
|
1569
1584
|
this.#storage = storage ?? new require_multi_storage.MemoryMultiTokenStorage();
|
|
1570
1585
|
this.#plugins = require_url.orderPluginDefinitions(plugins ?? []);
|
|
1586
|
+
this.#features = resolveAccountFeatures(features);
|
|
1571
1587
|
this.#rateLimitScope = rateLimitScope ?? "shared";
|
|
1572
1588
|
const rateLimit = this.#rateLimitScope === "shared" ? require_url.resolveRateLimit(base.rateLimit, require_url.ITD_CATALOG) : void 0;
|
|
1573
1589
|
this.#queues = rateLimit ? new require_url.RequestQueuePool(rateLimit, base.clock ?? require_url.systemClock) : void 0;
|
|
1574
1590
|
const logger = typeof base.logger === "object" ? base.logger : void 0;
|
|
1575
1591
|
this.#logger = logger;
|
|
1576
|
-
this.#emitter = new
|
|
1592
|
+
this.#emitter = new require_events.Emitter((error) => require_events.reportListenerError(logger, "аккаунтов", error));
|
|
1577
1593
|
}
|
|
1578
1594
|
/** Общее хранилище сессий — то же, что передано опцией `storage`. */
|
|
1579
1595
|
get storage() {
|
|
@@ -1594,7 +1610,7 @@ var ItdAccounts = class ItdAccounts {
|
|
|
1594
1610
|
/**
|
|
1595
1611
|
* Заводит аккаунт.
|
|
1596
1612
|
*
|
|
1597
|
-
* Возвращается обычный `ItdClient` — со всеми ресурсами, плагинами и
|
|
1613
|
+
* Возвращается обычный `ItdClient` — со всеми ресурсами, плагинами и каналом событий.
|
|
1598
1614
|
* Хранилище ему подставляется само: срез общего по имени аккаунта.
|
|
1599
1615
|
*
|
|
1600
1616
|
* Опция `auth` не обязательна: когда сессия этого аккаунта уже лежит в хранилище,
|
|
@@ -1620,10 +1636,15 @@ var ItdAccounts = class ItdAccounts {
|
|
|
1620
1636
|
try {
|
|
1621
1637
|
client = createManagedClient(this.#mergeOptions(options, storageControl.storage), this.#queues ? { queues: this.#queues } : {});
|
|
1622
1638
|
for (const plugin of this.#plugins) client.use(plugin);
|
|
1639
|
+
for (const feature of this.#features) {
|
|
1640
|
+
const manifest = feature.create();
|
|
1641
|
+
if (feature.key === void 0) client.install(manifest);
|
|
1642
|
+
else client.withFeature(feature.key, manifest);
|
|
1643
|
+
}
|
|
1623
1644
|
} catch (error) {
|
|
1624
1645
|
storageControl.revoke();
|
|
1625
1646
|
if (client) client.dispose().catch((cleanupError) => {
|
|
1626
|
-
this.#
|
|
1647
|
+
this.#reportCleanup("неудачного добавления аккаунта", cleanupError);
|
|
1627
1648
|
});
|
|
1628
1649
|
throw error;
|
|
1629
1650
|
}
|
|
@@ -1747,7 +1768,7 @@ var ItdAccounts = class ItdAccounts {
|
|
|
1747
1768
|
}
|
|
1748
1769
|
} catch (error) {
|
|
1749
1770
|
for (const client of installed.reverse()) client.unuse(plugin.name).catch((cleanupError) => {
|
|
1750
|
-
this.#
|
|
1771
|
+
this.#reportCleanup(`отката плагина «${plugin.name}»`, cleanupError);
|
|
1751
1772
|
});
|
|
1752
1773
|
throw error;
|
|
1753
1774
|
}
|
|
@@ -1863,6 +1884,7 @@ var ItdAccounts = class ItdAccounts {
|
|
|
1863
1884
|
Promise.resolve().then(() => this.#queues?.clear())
|
|
1864
1885
|
]);
|
|
1865
1886
|
this.#plugins.splice(0);
|
|
1887
|
+
this.#features.splice(0);
|
|
1866
1888
|
this.#removingPlugins.clear();
|
|
1867
1889
|
const errors = results.filter((result) => result.status === "rejected").map((result) => result.reason);
|
|
1868
1890
|
if (errors.length > 0) throw new AggregateError(errors, "Не удалось освободить аккаунты");
|
|
@@ -1872,11 +1894,7 @@ var ItdAccounts = class ItdAccounts {
|
|
|
1872
1894
|
return this.dispose();
|
|
1873
1895
|
}
|
|
1874
1896
|
static {
|
|
1875
|
-
|
|
1876
|
-
const prototype = ItdAccounts.prototype;
|
|
1877
|
-
prototype[Symbol.for("Symbol.asyncDispose")] = prototype.undefined;
|
|
1878
|
-
delete prototype.undefined;
|
|
1879
|
-
}
|
|
1897
|
+
require_url.installAsyncDisposeFallback(ItdAccounts);
|
|
1880
1898
|
}
|
|
1881
1899
|
/**
|
|
1882
1900
|
* Собирает опции клиента: общие, поверх них — аккаунтные, и обязательно свой срез
|
|
@@ -1901,9 +1919,9 @@ var ItdAccounts = class ItdAccounts {
|
|
|
1901
1919
|
storage
|
|
1902
1920
|
};
|
|
1903
1921
|
}
|
|
1904
|
-
/** Не теряет ошибку фонового
|
|
1905
|
-
#
|
|
1906
|
-
const message = `Не удалось
|
|
1922
|
+
/** Не теряет ошибку фонового освобождения ресурсов, которого синхронный API не ждёт. */
|
|
1923
|
+
#reportCleanup(scope, error) {
|
|
1924
|
+
const message = `Не удалось освободить ресурсы после ${scope}`;
|
|
1907
1925
|
if (this.#logger) this.#logger.error(message, error);
|
|
1908
1926
|
else console.error(`[itd-api] ${message}`, error);
|
|
1909
1927
|
}
|
|
@@ -1943,6 +1961,10 @@ exports.BUCKET_LIMITS = require_url.BUCKET_LIMITS;
|
|
|
1943
1961
|
exports.CommentSort = require_url.CommentSort;
|
|
1944
1962
|
exports.DEFAULT_BASE_URL = require_url.DEFAULT_BASE_URL;
|
|
1945
1963
|
exports.DEFAULT_RATE_LIMIT_BUCKET = require_url.DEFAULT_RATE_LIMIT_BUCKET;
|
|
1964
|
+
exports.EventChannel = require_events.EventChannel;
|
|
1965
|
+
exports.EventChannelStatus = require_url.EventChannelStatus;
|
|
1966
|
+
exports.EventComposer = require_events.EventComposer;
|
|
1967
|
+
exports.EventRouter = require_events.EventRouter;
|
|
1946
1968
|
exports.FeedTab = require_url.FeedTab;
|
|
1947
1969
|
exports.FileTransferMode = require_options.FileTransferMode;
|
|
1948
1970
|
exports.IMAGE_MIME_TYPES = require_render.IMAGE_MIME_TYPES;
|
|
@@ -1966,7 +1988,6 @@ exports.ItdNetworkError = require_errors.ItdNetworkError;
|
|
|
1966
1988
|
exports.ItdNotFoundError = require_errors.ItdNotFoundError;
|
|
1967
1989
|
exports.ItdPhoneVerificationError = require_errors.ItdPhoneVerificationError;
|
|
1968
1990
|
exports.ItdRateLimitError = require_errors.ItdRateLimitError;
|
|
1969
|
-
exports.ItdRealtime = require_websocket.ItdRealtime;
|
|
1970
1991
|
exports.ItdServerError = require_errors.ItdServerError;
|
|
1971
1992
|
exports.ItdStateError = require_errors.ItdStateError;
|
|
1972
1993
|
exports.ItdTimeoutError = require_errors.ItdTimeoutError;
|
|
@@ -1976,33 +1997,32 @@ exports.LikesVisibility = require_url.LikesVisibility;
|
|
|
1976
1997
|
exports.MemoryKeyValueStore = require_storage.MemoryKeyValueStore;
|
|
1977
1998
|
exports.MemoryMultiTokenStorage = require_multi_storage.MemoryMultiTokenStorage;
|
|
1978
1999
|
exports.MemoryTokenStorage = require_storage.MemoryTokenStorage;
|
|
2000
|
+
exports.NotificationEvents = require_events.NotificationEvents;
|
|
2001
|
+
exports.NotificationEventsClient = require_events.NotificationEventsClient;
|
|
2002
|
+
exports.NotificationEventsTransport = require_events.NotificationEventsTransport;
|
|
1979
2003
|
exports.NotificationType = require_url.NotificationType;
|
|
2004
|
+
exports.NotificationUpdateOrigin = require_events.NotificationUpdateOrigin;
|
|
2005
|
+
exports.NotificationUpdateType = require_events.NotificationUpdateType;
|
|
1980
2006
|
exports.OPERATIONS = require_url.OPERATIONS;
|
|
1981
2007
|
exports.PaginationMode = require_render.PaginationMode;
|
|
1982
2008
|
exports.Paginator = require_render.Paginator;
|
|
1983
2009
|
exports.RateLimitPacing = require_url.RateLimitPacing;
|
|
1984
|
-
exports.RealtimeComposer = require_websocket.RealtimeComposer;
|
|
1985
|
-
exports.RealtimeRouter = require_websocket.RealtimeRouter;
|
|
1986
|
-
exports.RealtimeStatus = require_url.RealtimeStatus;
|
|
1987
|
-
exports.RealtimeTransportKind = require_websocket.RealtimeTransportKind;
|
|
1988
|
-
exports.RealtimeUpdateOrigin = require_websocket.RealtimeUpdateOrigin;
|
|
1989
|
-
exports.RealtimeUpdateType = require_websocket.RealtimeUpdateType;
|
|
1990
2010
|
exports.ReportReason = require_url.ReportReason;
|
|
1991
2011
|
exports.ReportTargetType = require_url.ReportTargetType;
|
|
1992
2012
|
exports.RetrySafety = require_url.RetrySafety;
|
|
1993
|
-
exports.RuntimeMode =
|
|
2013
|
+
exports.RuntimeMode = require_redact.RuntimeMode;
|
|
1994
2014
|
exports.STATUS_SERVICE = require_url.STATUS_SERVICE;
|
|
1995
2015
|
exports.ServiceState = require_url.ServiceState;
|
|
1996
2016
|
exports.SignInStatus = SignInStatus;
|
|
1997
2017
|
exports.SpanRenderFormat = require_render.SpanRenderFormat;
|
|
1998
2018
|
exports.SpanType = require_url.SpanType;
|
|
1999
2019
|
exports.TURNSTILE_SITE_KEY = TURNSTILE_SITE_KEY;
|
|
2000
|
-
exports.UnauthorizedStreamError =
|
|
2020
|
+
exports.UnauthorizedStreamError = require_events.UnauthorizedStreamError;
|
|
2001
2021
|
exports.VIDEO_MIME_TYPES = require_render.VIDEO_MIME_TYPES;
|
|
2002
2022
|
exports.ViewReason = require_url.ViewReason;
|
|
2003
2023
|
exports.ViewSource = require_url.ViewSource;
|
|
2004
2024
|
exports.WallAccess = require_url.WallAccess;
|
|
2005
|
-
exports.WebSocketTransport =
|
|
2025
|
+
exports.WebSocketTransport = require_events.WebSocketTransport;
|
|
2006
2026
|
exports.autoSpans = require_render.autoSpans;
|
|
2007
2027
|
exports.canonicalNotificationType = require_url.canonicalNotificationType;
|
|
2008
2028
|
exports.comment = require_render.comment;
|
|
@@ -2010,6 +2030,7 @@ exports.createAccounts = createAccounts;
|
|
|
2010
2030
|
exports.createClient = createClient;
|
|
2011
2031
|
exports.createKeyValueStore = require_storage.createKeyValueStore;
|
|
2012
2032
|
exports.createMultiTokenStorage = require_multi_storage.createMultiTokenStorage;
|
|
2033
|
+
exports.createNotificationEventsClient = require_events.createNotificationEventsClient;
|
|
2013
2034
|
exports.createRecordKeyValueStore = require_storage.createRecordKeyValueStore;
|
|
2014
2035
|
exports.createTokenStorage = require_storage.createTokenStorage;
|
|
2015
2036
|
exports.formatNotificationText = require_url.formatNotificationText;
|
|
@@ -2045,7 +2066,7 @@ exports.post = require_render.post;
|
|
|
2045
2066
|
exports.renderSpans = require_render.renderSpans;
|
|
2046
2067
|
exports.report = require_render.report;
|
|
2047
2068
|
exports.resolveNotificationUrl = require_url.resolveNotificationUrl;
|
|
2048
|
-
exports.
|
|
2069
|
+
exports.runEventMiddleware = require_events.runEventMiddleware;
|
|
2049
2070
|
exports.scopedTokenStorage = require_multi_storage.scopedTokenStorage;
|
|
2050
2071
|
exports.statusDays = require_render.statusDays;
|
|
2051
2072
|
exports.systemClock = require_url.systemClock;
|