itd-api 0.7.2 → 0.9.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 +72 -27
- 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 +234 -200
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +70 -64
- package/dist/index.d.ts +70 -64
- package/dist/index.js +202 -179
- package/dist/index.js.map +1 -1
- package/dist/node/index.cjs +6 -5
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.d.cts +2 -2
- package/dist/node/index.d.ts +2 -2
- package/dist/node/index.js +5 -4
- package/dist/node/index.js.map +1 -1
- package/dist/rest/index.cjs +32 -26
- package/dist/rest/index.cjs.map +1 -1
- package/dist/rest/index.d.cts +9 -7
- package/dist/rest/index.d.ts +9 -7
- package/dist/rest/index.js +19 -21
- 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/{websocket-BLR8eVJV.js → events-C5wnTXPT.js} +770 -490
- package/dist/shared/events-C5wnTXPT.js.map +1 -0
- package/dist/shared/events-CqtkP65d.d.ts +698 -0
- package/dist/shared/events-DGAWlCaI.d.cts +698 -0
- package/dist/shared/{websocket-C_eI4H2o.cjs → events-FZfnEez0.cjs} +834 -518
- package/dist/shared/events-FZfnEez0.cjs.map +1 -0
- package/dist/shared/{storage-BPJR_k4-.cjs → key-value-store-B5GYVEYZ.cjs} +2 -86
- package/dist/shared/key-value-store-B5GYVEYZ.cjs.map +1 -0
- package/dist/shared/{storage-D86edNCB.js → key-value-store-Bt2PSMxY.js} +3 -69
- package/dist/shared/key-value-store-Bt2PSMxY.js.map +1 -0
- package/dist/shared/key-value-store-COZaNHZS.d.cts +69 -0
- package/dist/shared/key-value-store-COZaNHZS.d.ts +69 -0
- package/dist/shared/{multi-storage-DccjD7Ww.d.ts → multi-storage-BEL7tcKn.d.cts} +3 -2
- package/dist/shared/{multi-storage--yTEqiod.cjs → multi-storage-CDKLa956.cjs} +11 -10
- package/dist/shared/{multi-storage--yTEqiod.cjs.map → multi-storage-CDKLa956.cjs.map} +1 -1
- package/dist/shared/{multi-storage-CjAPB5Kq.d.cts → multi-storage-LkljOSzA.d.ts} +3 -2
- package/dist/shared/{multi-storage-CkvTUC5m.js → multi-storage-SoW05uzO.js} +5 -4
- package/dist/shared/{multi-storage-CkvTUC5m.js.map → multi-storage-SoW05uzO.js.map} +1 -1
- package/dist/shared/{options-Dg5N3r1V.cjs → options-DOJYtoti.cjs} +8 -6
- package/dist/shared/options-DOJYtoti.cjs.map +1 -0
- package/dist/shared/{options-DtATYdLr.js → options-DhgGg7Ms.js} +8 -6
- package/dist/shared/options-DhgGg7Ms.js.map +1 -0
- package/dist/shared/{cookies-DZwFq6kr.cjs → redact-BP00URmQ.cjs} +312 -2
- package/dist/shared/redact-BP00URmQ.cjs.map +1 -0
- package/dist/shared/{cookies-tX2sNwxb.js → redact-Ba5iSVYZ.js} +235 -3
- package/dist/shared/redact-Ba5iSVYZ.js.map +1 -0
- package/dist/shared/{render-CgwKdOzu.d.ts → render-B4qis7Sb.d.ts} +775 -313
- package/dist/shared/{render-DO0F5YSm.d.cts → render-DDwy2Ame.d.cts} +775 -313
- package/dist/shared/{render-mcuELiYi.cjs → render-Dqi8Owqk.cjs} +1464 -662
- package/dist/shared/render-Dqi8Owqk.cjs.map +1 -0
- package/dist/shared/{render-C6HRPs10.js → render-hiWFh2s4.js} +1366 -618
- package/dist/shared/render-hiWFh2s4.js.map +1 -0
- package/dist/shared/storage-BQrtKon9.d.cts +86 -0
- package/dist/shared/storage-CTRGT5wF.d.ts +86 -0
- package/dist/shared/storage-CfHKzVHf.js +71 -0
- package/dist/shared/storage-CfHKzVHf.js.map +1 -0
- package/dist/shared/storage-QNVxzpDB.cjs +88 -0
- package/dist/shared/storage-QNVxzpDB.cjs.map +1 -0
- package/dist/shared/{url-BaMCQpYH.cjs → url-Bsb3xE5U.cjs} +577 -466
- package/dist/shared/url-Bsb3xE5U.cjs.map +1 -0
- package/dist/shared/{url-IU0xN9wX.js → url-DP33mp3s.js} +508 -409
- package/dist/shared/url-DP33mp3s.js.map +1 -0
- package/dist/shared/{url-DTfZ2toq.d.ts → url-XBsMdAcv.d.cts} +1313 -1200
- package/dist/shared/{url-DTfZ2toq.d.cts → url-XBsMdAcv.d.ts} +1313 -1200
- package/dist/web/index.cjs +5 -4
- package/dist/web/index.cjs.map +1 -1
- package/dist/web/index.d.cts +1 -1
- package/dist/web/index.d.ts +1 -1
- package/dist/web/index.js +3 -2
- package/dist/web/index.js.map +1 -1
- 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/storage-BPJR_k4-.cjs.map +0 -1
- package/dist/shared/storage-C_eICCep.d.cts +0 -152
- package/dist/shared/storage-C_eICCep.d.ts +0 -152
- package/dist/shared/storage-D86edNCB.js.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,65 @@
|
|
|
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
|
|
2
|
+
const require_url = require("./shared/url-Bsb3xE5U.cjs");
|
|
3
|
+
const require_errors = require("./shared/errors-BmP3TKoW.cjs");
|
|
4
|
+
const require_redact = require("./shared/redact-BP00URmQ.cjs");
|
|
5
|
+
const require_render = require("./shared/render-Dqi8Owqk.cjs");
|
|
6
|
+
const require_options = require("./shared/options-DOJYtoti.cjs");
|
|
7
|
+
const require_events = require("./shared/events-FZfnEez0.cjs");
|
|
8
|
+
const require_key_value_store = require("./shared/key-value-store-B5GYVEYZ.cjs");
|
|
9
|
+
const require_storage = require("./shared/storage-QNVxzpDB.cjs");
|
|
10
|
+
const require_multi_storage = require("./shared/multi-storage-CDKLa956.cjs");
|
|
11
|
+
//#region src/notifications-api.ts
|
|
12
|
+
var ClientNotifications = class extends require_render.NotificationsResource {
|
|
13
|
+
#createEvents;
|
|
14
|
+
#events;
|
|
15
|
+
constructor(http, createEvents) {
|
|
16
|
+
super(http);
|
|
17
|
+
this.#createEvents = createEvents;
|
|
18
|
+
}
|
|
19
|
+
get events() {
|
|
20
|
+
this.#events ??= this.#createEvents(this);
|
|
21
|
+
return this.#events;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
/** Создаёт API уведомлений полного клиента. @internal */
|
|
25
|
+
function createNotificationsApi(http, createEvents) {
|
|
26
|
+
return new ClientNotifications(http, createEvents);
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/operations/auth.ts
|
|
30
|
+
/** Чем закончился запрос входа. */
|
|
31
|
+
const SignInStatus = Object.freeze({
|
|
32
|
+
Authenticated: "authenticated",
|
|
33
|
+
OtpRequired: "otp_required"
|
|
34
|
+
});
|
|
35
|
+
function requireString(body, key, message) {
|
|
36
|
+
const value = require_url.pickString(body, key);
|
|
37
|
+
if (!value) throw new require_errors.ItdConfigError(message);
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
const AUTH_CHECK = require_url.passthroughOperation("auth.check");
|
|
41
|
+
const AUTH_SIGN_UP = require_url.defineBuiltInOperation("auth.signUp", (body) => requireString(body, "flowToken", "Сервер не вернул flowToken при регистрации"));
|
|
42
|
+
const AUTH_SIGN_IN = require_url.defineBuiltInOperation("auth.signIn", (body) => {
|
|
43
|
+
const accessToken = require_url.pickString(body, "accessToken");
|
|
44
|
+
return accessToken ? {
|
|
45
|
+
status: SignInStatus.Authenticated,
|
|
46
|
+
accessToken
|
|
47
|
+
} : {
|
|
48
|
+
status: SignInStatus.OtpRequired,
|
|
49
|
+
flowToken: require_url.pickString(body, "flowToken")
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
const AUTH_VERIFY_OTP = require_url.defineBuiltInOperation("auth.verifyOtp", (body) => requireString(body, "accessToken", "Сервер не вернул accessToken после подтверждения кода"));
|
|
53
|
+
const AUTH_REFRESH = require_url.defineBuiltInOperation("auth.refresh", (body) => require_url.pickString(body, "accessToken"));
|
|
54
|
+
const AUTH_RESEND_OTP = require_url.voidOperation("auth.resendOtp");
|
|
55
|
+
const AUTH_LOGOUT = require_url.voidOperation("auth.logout");
|
|
56
|
+
const AUTH_FORGOT_PASSWORD = require_url.defineBuiltInOperation("auth.forgotPassword", (body) => requireString(body, "flowToken", "Сервер не вернул flowToken при запросе сброса пароля"));
|
|
57
|
+
const AUTH_RESET_PASSWORD = require_url.voidOperation("auth.resetPassword");
|
|
58
|
+
const AUTH_CHANGE_PASSWORD = require_url.voidOperation("auth.changePassword");
|
|
59
|
+
const AUTH_SESSIONS = require_url.defineBuiltInOperation("auth.sessions", (body) => require_url.pickArray(body, "sessions"));
|
|
60
|
+
const AUTH_REVOKE_SESSION = require_url.voidOperation("auth.revokeSession");
|
|
61
|
+
const AUTH_REVOKE_OTHER_SESSIONS = require_url.voidOperation("auth.revokeOtherSessions");
|
|
62
|
+
//#endregion
|
|
10
63
|
//#region src/session/jwt.ts
|
|
11
64
|
/**
|
|
12
65
|
* Разбирает строку base64url.
|
|
@@ -123,7 +176,7 @@ function resolveSessionConfig(options, runtime) {
|
|
|
123
176
|
* достижимой из любой сборки, включая анонимную.
|
|
124
177
|
*/
|
|
125
178
|
function createItdAuth(options, deps) {
|
|
126
|
-
return new AuthManager(resolveSessionConfig(options, deps.config), deps.
|
|
179
|
+
return new AuthManager(resolveSessionConfig(options, deps.config), deps.http, deps.cookies, { onAccountChange: deps.onAccountChange });
|
|
127
180
|
}
|
|
128
181
|
/** Пути эндпоинтов авторизации. */
|
|
129
182
|
const AUTH_PATHS = {
|
|
@@ -158,11 +211,6 @@ const AUTH_PATHS = {
|
|
|
158
211
|
* ```
|
|
159
212
|
*/
|
|
160
213
|
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
214
|
/** Убирает поле, которое сохраняли промежуточные версии с поддержкой `getUserId()`. */
|
|
167
215
|
function withoutLegacyUserId(session) {
|
|
168
216
|
const clean = { ...session };
|
|
@@ -184,7 +232,7 @@ function nextAuthScope() {
|
|
|
184
232
|
*/
|
|
185
233
|
var AuthManager = class {
|
|
186
234
|
#config;
|
|
187
|
-
#
|
|
235
|
+
#http;
|
|
188
236
|
#jar;
|
|
189
237
|
#emitter;
|
|
190
238
|
#hooks;
|
|
@@ -223,12 +271,12 @@ var AuthManager = class {
|
|
|
223
271
|
* воскресить уже очищенную сессию поверх `signOut`.
|
|
224
272
|
*/
|
|
225
273
|
#authEpoch = 0;
|
|
226
|
-
constructor(config,
|
|
274
|
+
constructor(config, http, jar, hooks = {}) {
|
|
227
275
|
this.#config = config;
|
|
228
|
-
this.#
|
|
276
|
+
this.#http = http;
|
|
229
277
|
this.#jar = jar;
|
|
230
278
|
this.#hooks = hooks;
|
|
231
|
-
this.#emitter = new
|
|
279
|
+
this.#emitter = new require_events.Emitter((error) => require_events.reportListenerError(config.logger, "авторизации", error));
|
|
232
280
|
}
|
|
233
281
|
/** Подписка на события авторизации. */
|
|
234
282
|
get on() {
|
|
@@ -238,7 +286,7 @@ var AuthManager = class {
|
|
|
238
286
|
get once() {
|
|
239
287
|
return this.#emitter.once.bind(this.#emitter);
|
|
240
288
|
}
|
|
241
|
-
/** Снимает
|
|
289
|
+
/** Снимает служебные подписки при окончательном освобождении владельца. @internal */
|
|
242
290
|
dispose() {
|
|
243
291
|
this.#invalidateInFlight();
|
|
244
292
|
this.#emitter.removeAllListeners();
|
|
@@ -294,7 +342,7 @@ var AuthManager = class {
|
|
|
294
342
|
this.#externalIdentity = current;
|
|
295
343
|
return token;
|
|
296
344
|
}
|
|
297
|
-
/**
|
|
345
|
+
/** Обновляет резервный идентификатор и закрывает события при смене аккаунта. */
|
|
298
346
|
#transitionAuth(accessToken, rotateFallback = true) {
|
|
299
347
|
const knownPrevious = this.#session !== void 0;
|
|
300
348
|
const previous = this.#identityForToken(this.#session?.accessToken);
|
|
@@ -367,7 +415,7 @@ var AuthManager = class {
|
|
|
367
415
|
}
|
|
368
416
|
async #resolveDeviceId() {
|
|
369
417
|
const session = await this.#loadSession();
|
|
370
|
-
const deviceId = this.#config.deviceId ?? session?.deviceId ??
|
|
418
|
+
const deviceId = this.#config.deviceId ?? session?.deviceId ?? require_redact.createDeviceId();
|
|
371
419
|
this.#deviceId = deviceId;
|
|
372
420
|
if (session?.deviceId !== deviceId) await this.#saveSession({
|
|
373
421
|
...session ?? {},
|
|
@@ -522,7 +570,7 @@ var AuthManager = class {
|
|
|
522
570
|
const refreshToken = this.#session?.refreshToken;
|
|
523
571
|
if (!refreshToken) return;
|
|
524
572
|
if (this.#jar.has("refresh_token")) return;
|
|
525
|
-
this.#jar.set(this.#config.baseUrl,
|
|
573
|
+
this.#jar.set(this.#config.baseUrl, require_redact.REFRESH_COOKIE, refreshToken, require_redact.REFRESH_COOKIE_PATH);
|
|
526
574
|
}
|
|
527
575
|
#sessionFromConfig(auth) {
|
|
528
576
|
if (!auth) return null;
|
|
@@ -566,16 +614,14 @@ var AuthManager = class {
|
|
|
566
614
|
if (!this.#hasRefreshSession()) return this.#reloginOrNull();
|
|
567
615
|
const epoch = this.#authEpoch;
|
|
568
616
|
try {
|
|
569
|
-
const accessToken =
|
|
570
|
-
operationId: "auth.refresh",
|
|
571
|
-
method: require_url.operationMethod("auth.refresh"),
|
|
617
|
+
const accessToken = await this.#http.execute(AUTH_REFRESH, {
|
|
572
618
|
path: AUTH_PATHS.refresh,
|
|
573
619
|
skipAuth: true,
|
|
574
620
|
skipAuthRefresh: true
|
|
575
|
-
})
|
|
621
|
+
});
|
|
576
622
|
if (!accessToken) return this.#reloginOrNull();
|
|
577
623
|
if (this.#authEpoch !== epoch) return this.#session?.accessToken ?? null;
|
|
578
|
-
const rotated = this.#jar.getValue(
|
|
624
|
+
const rotated = this.#jar.getValue(require_redact.REFRESH_COOKIE, this.#config.baseUrl + require_redact.REFRESH_COOKIE_PATH);
|
|
579
625
|
this.#transitionAuth(accessToken, false);
|
|
580
626
|
await this.#saveSession({
|
|
581
627
|
...this.#session ?? {},
|
|
@@ -639,9 +685,7 @@ var AuthManager = class {
|
|
|
639
685
|
}
|
|
640
686
|
async #performSignIn(credentials) {
|
|
641
687
|
const turnstileToken = await this.#resolveTurnstileToken(credentials);
|
|
642
|
-
const
|
|
643
|
-
operationId: "auth.signIn",
|
|
644
|
-
method: require_url.operationMethod("auth.signIn"),
|
|
688
|
+
const result = await this.#http.execute(AUTH_SIGN_IN, {
|
|
645
689
|
path: AUTH_PATHS.signIn,
|
|
646
690
|
body: {
|
|
647
691
|
email: credentials.email,
|
|
@@ -650,8 +694,9 @@ var AuthManager = class {
|
|
|
650
694
|
},
|
|
651
695
|
skipAuth: true,
|
|
652
696
|
skipAuthRefresh: true
|
|
653
|
-
})
|
|
654
|
-
if (
|
|
697
|
+
});
|
|
698
|
+
if (result.status !== SignInStatus.Authenticated) throw new require_errors.ItdConfigError("Вход по email и паролю требует подтверждения кодом из письма. Автоматический вход невозможен: воспользуйтесь itd.auth.signInWithOtp() и передайте полученный accessToken в конфигурацию клиента.");
|
|
699
|
+
const accessToken = result.accessToken;
|
|
655
700
|
this.#invalidateInFlight();
|
|
656
701
|
this.#transitionAuth(accessToken);
|
|
657
702
|
await this.#saveSession({
|
|
@@ -665,11 +710,12 @@ var AuthManager = class {
|
|
|
665
710
|
};
|
|
666
711
|
//#endregion
|
|
667
712
|
//#region src/resources/auth.ts
|
|
668
|
-
/**
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
713
|
+
/**
|
|
714
|
+
* Результат входа.
|
|
715
|
+
*
|
|
716
|
+
* Сервер может как сразу выдать токен, так и потребовать код подтверждения — размеченное
|
|
717
|
+
* объединение делает оба случая явными.
|
|
718
|
+
*/
|
|
673
719
|
/**
|
|
674
720
|
* Авторизация, сессии и пароли.
|
|
675
721
|
*
|
|
@@ -687,7 +733,7 @@ var AuthResource = class extends require_render.BaseResource {
|
|
|
687
733
|
* Без авторизации возвращает `authenticated: false` и `user: null`.
|
|
688
734
|
*/
|
|
689
735
|
check(options = {}) {
|
|
690
|
-
return this.http.
|
|
736
|
+
return this.http.execute(AUTH_CHECK, {
|
|
691
737
|
path: "/api/profile",
|
|
692
738
|
...options
|
|
693
739
|
});
|
|
@@ -697,17 +743,14 @@ var AuthResource = class extends require_render.BaseResource {
|
|
|
697
743
|
*
|
|
698
744
|
* @returns `flowToken`, который нужно передать в {@link verifyOtp}
|
|
699
745
|
*/
|
|
700
|
-
|
|
701
|
-
|
|
746
|
+
signUp(credentials, options = {}) {
|
|
747
|
+
return this.http.execute(AUTH_SIGN_UP, {
|
|
702
748
|
path: AUTH_PATHS.signUp,
|
|
703
749
|
body: credentials,
|
|
704
750
|
skipAuth: true,
|
|
705
751
|
skipAuthRefresh: true,
|
|
706
752
|
...options
|
|
707
753
|
});
|
|
708
|
-
const flowToken = require_url.pickString(body, "flowToken");
|
|
709
|
-
if (!flowToken) throw new require_errors.ItdConfigError("Сервер не вернул flowToken при регистрации");
|
|
710
|
-
return flowToken;
|
|
711
754
|
}
|
|
712
755
|
/**
|
|
713
756
|
* Выполняет вход.
|
|
@@ -720,25 +763,15 @@ var AuthResource = class extends require_render.BaseResource {
|
|
|
720
763
|
* @param credentials email, пароль и обязательный токен капчи — см. {@link CaptchaCredentials}
|
|
721
764
|
*/
|
|
722
765
|
async signIn(credentials, options = {}) {
|
|
723
|
-
const
|
|
766
|
+
const result = await this.http.execute(AUTH_SIGN_IN, {
|
|
724
767
|
path: AUTH_PATHS.signIn,
|
|
725
768
|
body: credentials,
|
|
726
769
|
skipAuth: true,
|
|
727
770
|
skipAuthRefresh: true,
|
|
728
771
|
...options
|
|
729
772
|
});
|
|
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
|
-
};
|
|
773
|
+
if (result.status === SignInStatus.Authenticated) await this.#auth.setAccessToken(result.accessToken);
|
|
774
|
+
return result;
|
|
742
775
|
}
|
|
743
776
|
/**
|
|
744
777
|
* Подтверждает вход кодом из письма.
|
|
@@ -746,21 +779,19 @@ var AuthResource = class extends require_render.BaseResource {
|
|
|
746
779
|
* Полученный токен сохраняется в клиенте автоматически.
|
|
747
780
|
*/
|
|
748
781
|
async verifyOtp(input, options = {}) {
|
|
749
|
-
const
|
|
782
|
+
const accessToken = await this.http.execute(AUTH_VERIFY_OTP, {
|
|
750
783
|
path: AUTH_PATHS.verifyOtp,
|
|
751
784
|
body: input,
|
|
752
785
|
skipAuth: true,
|
|
753
786
|
skipAuthRefresh: true,
|
|
754
787
|
...options
|
|
755
788
|
});
|
|
756
|
-
const accessToken = require_url.pickString(body, "accessToken");
|
|
757
|
-
if (!accessToken) throw new require_errors.ItdConfigError("Сервер не вернул accessToken после подтверждения кода");
|
|
758
789
|
await this.#auth.setAccessToken(accessToken);
|
|
759
790
|
return accessToken;
|
|
760
791
|
}
|
|
761
792
|
/** Отправляет код подтверждения повторно. */
|
|
762
793
|
resendOtp(input, options = {}) {
|
|
763
|
-
return this.
|
|
794
|
+
return this.voidOperation(AUTH_RESEND_OTP, {
|
|
764
795
|
path: AUTH_PATHS.resendOtp,
|
|
765
796
|
body: input,
|
|
766
797
|
skipAuth: true,
|
|
@@ -829,7 +860,7 @@ var AuthResource = class extends require_render.BaseResource {
|
|
|
829
860
|
}
|
|
830
861
|
/** Завершает текущую сессию на сервере и очищает локальную. */
|
|
831
862
|
async logout(options = {}) {
|
|
832
|
-
await this.
|
|
863
|
+
await this.voidOperation(AUTH_LOGOUT, {
|
|
833
864
|
path: AUTH_PATHS.logout,
|
|
834
865
|
skipAuthRefresh: true,
|
|
835
866
|
...options
|
|
@@ -857,17 +888,14 @@ var AuthResource = class extends require_render.BaseResource {
|
|
|
857
888
|
*
|
|
858
889
|
* @returns `flowToken`, который нужно передать в {@link resetPassword}
|
|
859
890
|
*/
|
|
860
|
-
|
|
861
|
-
|
|
891
|
+
forgotPassword(input, options = {}) {
|
|
892
|
+
return this.http.execute(AUTH_FORGOT_PASSWORD, {
|
|
862
893
|
path: AUTH_PATHS.forgotPassword,
|
|
863
894
|
body: input,
|
|
864
895
|
skipAuth: true,
|
|
865
896
|
skipAuthRefresh: true,
|
|
866
897
|
...options
|
|
867
898
|
});
|
|
868
|
-
const flowToken = require_url.pickString(body, "flowToken");
|
|
869
|
-
if (!flowToken) throw new require_errors.ItdConfigError("Сервер не вернул flowToken при запросе сброса пароля");
|
|
870
|
-
return flowToken;
|
|
871
899
|
}
|
|
872
900
|
/**
|
|
873
901
|
* Устанавливает новый пароль по коду из письма.
|
|
@@ -876,7 +904,7 @@ var AuthResource = class extends require_render.BaseResource {
|
|
|
876
904
|
* при нехватке любого отвечает `422`.
|
|
877
905
|
*/
|
|
878
906
|
resetPassword(input, options = {}) {
|
|
879
|
-
return this.
|
|
907
|
+
return this.voidOperation(AUTH_RESET_PASSWORD, {
|
|
880
908
|
path: AUTH_PATHS.resetPassword,
|
|
881
909
|
body: input,
|
|
882
910
|
skipAuth: true,
|
|
@@ -924,7 +952,7 @@ var AuthResource = class extends require_render.BaseResource {
|
|
|
924
952
|
* ```
|
|
925
953
|
*/
|
|
926
954
|
changePassword(input, options = {}) {
|
|
927
|
-
return this.
|
|
955
|
+
return this.voidOperation(AUTH_CHANGE_PASSWORD, {
|
|
928
956
|
path: AUTH_PATHS.changePassword,
|
|
929
957
|
body: {
|
|
930
958
|
currentPassword: input.currentPassword,
|
|
@@ -934,23 +962,22 @@ var AuthResource = class extends require_render.BaseResource {
|
|
|
934
962
|
});
|
|
935
963
|
}
|
|
936
964
|
/** Загружает список активных сессий. У текущей поле `isCurrent` равно `true`. */
|
|
937
|
-
|
|
938
|
-
|
|
965
|
+
sessions(options = {}) {
|
|
966
|
+
return this.http.execute(AUTH_SESSIONS, {
|
|
939
967
|
path: AUTH_PATHS.sessions,
|
|
940
968
|
...options
|
|
941
969
|
});
|
|
942
|
-
return require_url.pickArray(body, "sessions");
|
|
943
970
|
}
|
|
944
971
|
/** Завершает указанную сессию. */
|
|
945
972
|
revokeSession(sessionId, options = {}) {
|
|
946
|
-
return this.
|
|
973
|
+
return this.voidOperation(AUTH_REVOKE_SESSION, {
|
|
947
974
|
path: `${AUTH_PATHS.sessions}/${encodeURIComponent(sessionId)}`,
|
|
948
975
|
...options
|
|
949
976
|
});
|
|
950
977
|
}
|
|
951
978
|
/** Завершает все сессии, кроме текущей. */
|
|
952
979
|
revokeOtherSessions(options = {}) {
|
|
953
|
-
return this.
|
|
980
|
+
return this.voidOperation(AUTH_REVOKE_OTHER_SESSIONS, {
|
|
954
981
|
path: AUTH_PATHS.sessions,
|
|
955
982
|
...options
|
|
956
983
|
});
|
|
@@ -1014,8 +1041,6 @@ function createManagedClient(options, internals) {
|
|
|
1014
1041
|
var ItdClient = class ItdClient {
|
|
1015
1042
|
#runtime;
|
|
1016
1043
|
#features;
|
|
1017
|
-
/** Порождённые потоки уведомлений — чтобы `close()` мог закрыть их разом. */
|
|
1018
|
-
#streams = /* @__PURE__ */ new Set();
|
|
1019
1044
|
/** Общий результат терминальной очистки для идемпотентных повторных вызовов. */
|
|
1020
1045
|
#disposePromise;
|
|
1021
1046
|
/** Ресурсы конвейера запросов; создаются при первом обращении. */
|
|
@@ -1075,34 +1100,76 @@ var ItdClient = class ItdClient {
|
|
|
1075
1100
|
get telemetry() {
|
|
1076
1101
|
return this.#resources.telemetry;
|
|
1077
1102
|
}
|
|
1103
|
+
/** Каталог, доставка и заказы магазина ИТД. */
|
|
1104
|
+
get shop() {
|
|
1105
|
+
return this.#resources.shop;
|
|
1106
|
+
}
|
|
1078
1107
|
constructor(options = {}) {
|
|
1108
|
+
const notificationEventsOptions = require_events.resolveNotificationEventsOptions(options.events?.notifications);
|
|
1079
1109
|
const internals = CLIENT_INTERNALS.get(options) ?? {};
|
|
1080
1110
|
const catalog = new require_render.ExtensibleOperationCatalog(require_url.ITD_CATALOG);
|
|
1111
|
+
let featureHost;
|
|
1081
1112
|
this.#runtime = require_url.createClientRuntime(options, {
|
|
1082
1113
|
catalog,
|
|
1083
1114
|
queues: internals.queues,
|
|
1084
1115
|
assertActive: (action) => assertClientActive(this, action),
|
|
1085
1116
|
auth: (deps) => createItdAuth(options, {
|
|
1086
1117
|
...deps,
|
|
1087
|
-
onAccountChange: () =>
|
|
1118
|
+
onAccountChange: () => featureHost?.stop()
|
|
1088
1119
|
})
|
|
1089
1120
|
});
|
|
1090
|
-
this.#features =
|
|
1091
|
-
http: this.#runtime.http,
|
|
1092
|
-
services: this.#runtime.services,
|
|
1093
|
-
serviceOverrides: this.#runtime.config.services,
|
|
1121
|
+
this.#features = featureHost = require_render.createFeatureHost(this.#runtime, {
|
|
1094
1122
|
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)
|
|
1123
|
+
assertActive: (action) => assertClientActive(this, action)
|
|
1100
1124
|
});
|
|
1101
1125
|
const status = this.#features.install(require_render.createStatusFeature());
|
|
1102
1126
|
this.#resources = require_render.createResources({
|
|
1103
1127
|
http: this.#runtime.http,
|
|
1104
|
-
|
|
1105
|
-
status
|
|
1128
|
+
files: this.#features.files,
|
|
1129
|
+
status,
|
|
1130
|
+
createNotifications: (http) => createNotificationsApi(http, (notifications) => {
|
|
1131
|
+
let events;
|
|
1132
|
+
let lifecycleGeneration = 0;
|
|
1133
|
+
let lifecycleActive = false;
|
|
1134
|
+
let unregister;
|
|
1135
|
+
const releaseAfterDrain = (generation) => {
|
|
1136
|
+
events.drain().then(() => {
|
|
1137
|
+
if (lifecycleActive || generation !== lifecycleGeneration) return;
|
|
1138
|
+
unregister?.();
|
|
1139
|
+
unregister = void 0;
|
|
1140
|
+
});
|
|
1141
|
+
};
|
|
1142
|
+
events = new require_events.NotificationEvents({
|
|
1143
|
+
connection: this.#runtime.connection(),
|
|
1144
|
+
request: ({ operationId, path, query, signal }) => this.#runtime.http.execute(require_events.EVENT_OPERATIONS[operationId], {
|
|
1145
|
+
path,
|
|
1146
|
+
query,
|
|
1147
|
+
signal
|
|
1148
|
+
}),
|
|
1149
|
+
getAuthIdentity: () => this.#runtime.auth.getCurrentAuthIdentity(),
|
|
1150
|
+
getAuthScope: () => this.#runtime.auth.getAuthScope(),
|
|
1151
|
+
fetchUnreadCount: (signal) => notifications.count({ signal }),
|
|
1152
|
+
onConnect: () => {
|
|
1153
|
+
lifecycleGeneration += 1;
|
|
1154
|
+
unregister ??= this.#features.manage({
|
|
1155
|
+
kind: `notifications:${events.transport}`,
|
|
1156
|
+
stop: () => {
|
|
1157
|
+
if (lifecycleActive) events.disconnect();
|
|
1158
|
+
},
|
|
1159
|
+
drain: () => events.drain()
|
|
1160
|
+
});
|
|
1161
|
+
lifecycleActive = true;
|
|
1162
|
+
},
|
|
1163
|
+
onClose: () => {
|
|
1164
|
+
lifecycleActive = false;
|
|
1165
|
+
releaseAfterDrain(++lifecycleGeneration);
|
|
1166
|
+
},
|
|
1167
|
+
logger: this.#runtime.config.logger,
|
|
1168
|
+
clock: this.#runtime.config.clock
|
|
1169
|
+
}, notificationEventsOptions);
|
|
1170
|
+
require_events.setNotificationEventsConnectGuard(events, () => assertClientActive(this, "подключить канал событий уведомлений"));
|
|
1171
|
+
return events;
|
|
1172
|
+
})
|
|
1106
1173
|
});
|
|
1107
1174
|
CLIENT_PLUGIN_REGISTRIES.set(this, this.#runtime.plugins);
|
|
1108
1175
|
}
|
|
@@ -1146,19 +1213,19 @@ var ItdClient = class ItdClient {
|
|
|
1146
1213
|
return this.#runtime.rateLimitState();
|
|
1147
1214
|
}
|
|
1148
1215
|
/**
|
|
1149
|
-
* Устанавливает предметный модуль
|
|
1216
|
+
* Устанавливает предметный модуль с общей сессией и обработкой запросов клиента.
|
|
1150
1217
|
*
|
|
1151
|
-
* Сервисы, операции и бакеты
|
|
1152
|
-
*
|
|
1218
|
+
* Сервисы, операции и бакеты регистрируются до синхронного `setup()`. Возвращает
|
|
1219
|
+
* типизированный API модуля.
|
|
1153
1220
|
*/
|
|
1154
1221
|
install(feature) {
|
|
1155
1222
|
return this.#features.install(feature);
|
|
1156
1223
|
}
|
|
1157
1224
|
/**
|
|
1158
|
-
* Устанавливает
|
|
1225
|
+
* Устанавливает модуль и добавляет его API в свойство клиента только для чтения.
|
|
1159
1226
|
*
|
|
1160
1227
|
* Возвращаемое пересечение сохраняет тип уже подключённых свойств, поэтому вызовы можно
|
|
1161
|
-
* объединять в цепочку: `new ItdClient().withFeature('
|
|
1228
|
+
* объединять в цепочку: `new ItdClient().withFeature('pixelBattle', pixelBattleFeature)`.
|
|
1162
1229
|
*/
|
|
1163
1230
|
withFeature(key, feature) {
|
|
1164
1231
|
assertClientActive(this, "установить feature");
|
|
@@ -1174,20 +1241,18 @@ var ItdClient = class ItdClient {
|
|
|
1174
1241
|
});
|
|
1175
1242
|
return this;
|
|
1176
1243
|
}
|
|
1177
|
-
/** Имена установленных
|
|
1244
|
+
/** Имена установленных модулей в порядке установки. */
|
|
1178
1245
|
featureNames() {
|
|
1179
1246
|
return this.#features.names();
|
|
1180
1247
|
}
|
|
1181
|
-
/** Установлен ли
|
|
1248
|
+
/** Установлен ли модуль с таким именем. */
|
|
1182
1249
|
hasFeature(name) {
|
|
1183
1250
|
return this.#features.has(name);
|
|
1184
1251
|
}
|
|
1185
1252
|
/**
|
|
1186
1253
|
* Подключает плагин.
|
|
1187
1254
|
*
|
|
1188
|
-
* Плагин может
|
|
1189
|
-
* транспортной попытки. Оба контракта охватывают все методы клиента. Подключать плагин
|
|
1190
|
-
* можно в любой момент, но обычно это делают сразу после создания клиента.
|
|
1255
|
+
* Плагин может регистрировать обёртки операций и перехватчики сетевых попыток.
|
|
1191
1256
|
*
|
|
1192
1257
|
* @throws {ItdConfigError} если плагин задан неверно или уже подключён
|
|
1193
1258
|
* @throws {ItdStateError} если клиент уже освобождён через {@link dispose}
|
|
@@ -1290,85 +1355,27 @@ var ItdClient = class ItdClient {
|
|
|
1290
1355
|
return this.#runtime.auth.on(event, listener);
|
|
1291
1356
|
}
|
|
1292
1357
|
/**
|
|
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
1358
|
* Освобождает ресурсы клиента: закрывает все потоки уведомлений, отправляет открытые
|
|
1343
1359
|
* накопители {@link telemetry}, затем останавливает очередь запросов.
|
|
1344
1360
|
*
|
|
1345
|
-
* Метод дожидается активных обработчиков
|
|
1346
|
-
*
|
|
1347
|
-
* повторным `connect()`.
|
|
1361
|
+
* Метод дожидается завершения активных обработчиков и освобождения ресурсов остановленных
|
|
1362
|
+
* событийных соединений, но не дольше `shutdownTimeout`. После вызова клиентом можно
|
|
1363
|
+
* пользоваться снова; ранее созданный поток можно запустить повторным `connect()`.
|
|
1348
1364
|
*
|
|
1349
1365
|
* Общая очередь, полученная от {@link ItdAccounts}, не останавливается: её гасит сам
|
|
1350
1366
|
* контейнер, когда закрывает все аккаунты разом.
|
|
1351
1367
|
*
|
|
1352
1368
|
* Терминальное освобождение — это {@link dispose}.
|
|
1353
1369
|
*
|
|
1354
|
-
* @throws {ItdStateError} если
|
|
1370
|
+
* @throws {ItdStateError} если остановка событийного соединения не завершилась за отведённый срок
|
|
1355
1371
|
*/
|
|
1356
1372
|
async close() {
|
|
1357
1373
|
return this.#close(false);
|
|
1358
1374
|
}
|
|
1359
1375
|
async #close(disposeCleanup) {
|
|
1360
|
-
const streams = this.#disconnectStreams();
|
|
1361
1376
|
if (disposeCleanup) this.#resources.prepareTelemetryClose();
|
|
1362
|
-
const { shutdownTimeout, clock } = this.#runtime.config;
|
|
1363
|
-
const deadline = require_url.createDeadline(shutdownTimeout, clock);
|
|
1364
|
-
let stuck = [];
|
|
1365
1377
|
const errors = [];
|
|
1366
1378
|
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
1379
|
try {
|
|
1373
1380
|
await this.#features.close();
|
|
1374
1381
|
} catch (error) {
|
|
@@ -1380,10 +1387,8 @@ var ItdClient = class ItdClient {
|
|
|
1380
1387
|
errors.push(error);
|
|
1381
1388
|
}
|
|
1382
1389
|
} finally {
|
|
1383
|
-
deadline.cancel();
|
|
1384
1390
|
this.#runtime.close();
|
|
1385
1391
|
}
|
|
1386
|
-
if (stuck.length > 0) errors.push(new require_errors.ItdStateError(`обработчики потоков (${stuck.map((stream) => stream.transport).join(", ")}) не завершились за ${shutdownTimeout} мс; ожидание прекращено`));
|
|
1387
1392
|
if (errors.length === 1) throw errors[0];
|
|
1388
1393
|
if (errors.length > 1) throw new AggregateError(errors, "Не удалось закрыть клиент");
|
|
1389
1394
|
}
|
|
@@ -1393,10 +1398,11 @@ var ItdClient = class ItdClient {
|
|
|
1393
1398
|
*
|
|
1394
1399
|
* Терминальное состояние устанавливается сразу при первом вызове. После этого новые
|
|
1395
1400
|
* запросы, подключение плагинов, регистрация сервисов и создание или повторный запуск
|
|
1396
|
-
*
|
|
1401
|
+
* событийных каналов завершаются с {@link ItdStateError}. Повторные вызовы возвращают
|
|
1397
1402
|
* тот же результат очистки.
|
|
1398
1403
|
*
|
|
1399
|
-
* Ожидание
|
|
1404
|
+
* Ожидание остановки событийных соединений и операций плагинов ограничено
|
|
1405
|
+
* `shutdownTimeout`.
|
|
1400
1406
|
*
|
|
1401
1407
|
* @example
|
|
1402
1408
|
* ```ts
|
|
@@ -1430,13 +1436,6 @@ var ItdClient = class ItdClient {
|
|
|
1430
1436
|
}
|
|
1431
1437
|
if (errors.length > 0) throw new AggregateError(errors, "Не удалось освободить клиент");
|
|
1432
1438
|
}
|
|
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
1439
|
/** Позволяет использовать клиент с `await using`. */
|
|
1441
1440
|
[Symbol.asyncDispose]() {
|
|
1442
1441
|
return this.dispose();
|
|
@@ -1502,6 +1501,25 @@ function createClient(options = {}) {
|
|
|
1502
1501
|
function validateAccountName(name) {
|
|
1503
1502
|
if (typeof name !== "string" || name.trim() === "") throw new require_errors.ItdConfigError("имя аккаунта должно быть непустой строкой");
|
|
1504
1503
|
}
|
|
1504
|
+
/** Проверяет фабрики до создания первого аккаунта. */
|
|
1505
|
+
function resolveAccountFeatures(features) {
|
|
1506
|
+
if (features === void 0) return [];
|
|
1507
|
+
if (!Array.isArray(features)) throw new require_errors.ItdConfigError("features должен быть массивом фабрик подключаемых модулей");
|
|
1508
|
+
const keys = /* @__PURE__ */ new Set();
|
|
1509
|
+
return features.map((feature, index) => {
|
|
1510
|
+
if (typeof feature !== "object" || feature === null || typeof feature.create !== "function") throw new require_errors.ItdConfigError(`features[${index}] должен предоставлять create()`);
|
|
1511
|
+
if (feature.key !== void 0) {
|
|
1512
|
+
if (typeof feature.key !== "string" || feature.key.trim() === "" || feature.key !== feature.key.trim()) throw new require_errors.ItdConfigError(`features[${index}].key должен быть непустой строкой без пробелов`);
|
|
1513
|
+
if (keys.has(feature.key)) throw new require_errors.ItdConfigError(`Свойство подключаемого модуля «${feature.key}» объявлено повторно`);
|
|
1514
|
+
keys.add(feature.key);
|
|
1515
|
+
}
|
|
1516
|
+
const create = feature.create.bind(feature);
|
|
1517
|
+
return Object.freeze({
|
|
1518
|
+
...feature.key === void 0 ? {} : { key: feature.key },
|
|
1519
|
+
create
|
|
1520
|
+
});
|
|
1521
|
+
});
|
|
1522
|
+
}
|
|
1505
1523
|
const DISPOSED_ACCOUNTS = /* @__PURE__ */ new WeakSet();
|
|
1506
1524
|
function assertAccountsActive(accounts, action) {
|
|
1507
1525
|
if (!DISPOSED_ACCOUNTS.has(accounts)) return;
|
|
@@ -1553,6 +1571,8 @@ var ItdAccounts = class ItdAccounts {
|
|
|
1553
1571
|
#eventUnsubscribers = /* @__PURE__ */ new Map();
|
|
1554
1572
|
/** Плагины для всех: и для уже заведённых аккаунтов, и для будущих. */
|
|
1555
1573
|
#plugins;
|
|
1574
|
+
/** Фабрики модулей для новых и восстанавливаемых аккаунтов. */
|
|
1575
|
+
#features;
|
|
1556
1576
|
/** Имена плагинов, чья асинхронная очистка ещё не завершилась. */
|
|
1557
1577
|
#removingPlugins = /* @__PURE__ */ new Set();
|
|
1558
1578
|
/** Общая очередь. `undefined`, когда у каждого аккаунта своя. */
|
|
@@ -1563,17 +1583,18 @@ var ItdAccounts = class ItdAccounts {
|
|
|
1563
1583
|
/** Общий результат терминальной очистки для идемпотентных повторных вызовов. */
|
|
1564
1584
|
#disposePromise;
|
|
1565
1585
|
constructor(options = {}) {
|
|
1566
|
-
const { storage, plugins, rateLimitScope, ...base } = options;
|
|
1586
|
+
const { storage, plugins, features, rateLimitScope, ...base } = options;
|
|
1567
1587
|
if (rateLimitScope !== void 0 && rateLimitScope !== "account" && rateLimitScope !== "shared") throw new require_errors.ItdConfigError("rateLimitScope должен быть 'account' или 'shared'");
|
|
1568
1588
|
this.#base = base;
|
|
1569
1589
|
this.#storage = storage ?? new require_multi_storage.MemoryMultiTokenStorage();
|
|
1570
1590
|
this.#plugins = require_url.orderPluginDefinitions(plugins ?? []);
|
|
1591
|
+
this.#features = resolveAccountFeatures(features);
|
|
1571
1592
|
this.#rateLimitScope = rateLimitScope ?? "shared";
|
|
1572
1593
|
const rateLimit = this.#rateLimitScope === "shared" ? require_url.resolveRateLimit(base.rateLimit, require_url.ITD_CATALOG) : void 0;
|
|
1573
1594
|
this.#queues = rateLimit ? new require_url.RequestQueuePool(rateLimit, base.clock ?? require_url.systemClock) : void 0;
|
|
1574
1595
|
const logger = typeof base.logger === "object" ? base.logger : void 0;
|
|
1575
1596
|
this.#logger = logger;
|
|
1576
|
-
this.#emitter = new
|
|
1597
|
+
this.#emitter = new require_events.Emitter((error) => require_events.reportListenerError(logger, "аккаунтов", error));
|
|
1577
1598
|
}
|
|
1578
1599
|
/** Общее хранилище сессий — то же, что передано опцией `storage`. */
|
|
1579
1600
|
get storage() {
|
|
@@ -1594,7 +1615,7 @@ var ItdAccounts = class ItdAccounts {
|
|
|
1594
1615
|
/**
|
|
1595
1616
|
* Заводит аккаунт.
|
|
1596
1617
|
*
|
|
1597
|
-
* Возвращается обычный `ItdClient` — со всеми ресурсами, плагинами и
|
|
1618
|
+
* Возвращается обычный `ItdClient` — со всеми ресурсами, плагинами и каналом событий.
|
|
1598
1619
|
* Хранилище ему подставляется само: срез общего по имени аккаунта.
|
|
1599
1620
|
*
|
|
1600
1621
|
* Опция `auth` не обязательна: когда сессия этого аккаунта уже лежит в хранилище,
|
|
@@ -1620,10 +1641,15 @@ var ItdAccounts = class ItdAccounts {
|
|
|
1620
1641
|
try {
|
|
1621
1642
|
client = createManagedClient(this.#mergeOptions(options, storageControl.storage), this.#queues ? { queues: this.#queues } : {});
|
|
1622
1643
|
for (const plugin of this.#plugins) client.use(plugin);
|
|
1644
|
+
for (const feature of this.#features) {
|
|
1645
|
+
const manifest = feature.create();
|
|
1646
|
+
if (feature.key === void 0) client.install(manifest);
|
|
1647
|
+
else client.withFeature(feature.key, manifest);
|
|
1648
|
+
}
|
|
1623
1649
|
} catch (error) {
|
|
1624
1650
|
storageControl.revoke();
|
|
1625
1651
|
if (client) client.dispose().catch((cleanupError) => {
|
|
1626
|
-
this.#
|
|
1652
|
+
this.#reportCleanup("неудачного добавления аккаунта", cleanupError);
|
|
1627
1653
|
});
|
|
1628
1654
|
throw error;
|
|
1629
1655
|
}
|
|
@@ -1747,7 +1773,7 @@ var ItdAccounts = class ItdAccounts {
|
|
|
1747
1773
|
}
|
|
1748
1774
|
} catch (error) {
|
|
1749
1775
|
for (const client of installed.reverse()) client.unuse(plugin.name).catch((cleanupError) => {
|
|
1750
|
-
this.#
|
|
1776
|
+
this.#reportCleanup(`отката плагина «${plugin.name}»`, cleanupError);
|
|
1751
1777
|
});
|
|
1752
1778
|
throw error;
|
|
1753
1779
|
}
|
|
@@ -1863,6 +1889,7 @@ var ItdAccounts = class ItdAccounts {
|
|
|
1863
1889
|
Promise.resolve().then(() => this.#queues?.clear())
|
|
1864
1890
|
]);
|
|
1865
1891
|
this.#plugins.splice(0);
|
|
1892
|
+
this.#features.splice(0);
|
|
1866
1893
|
this.#removingPlugins.clear();
|
|
1867
1894
|
const errors = results.filter((result) => result.status === "rejected").map((result) => result.reason);
|
|
1868
1895
|
if (errors.length > 0) throw new AggregateError(errors, "Не удалось освободить аккаунты");
|
|
@@ -1872,11 +1899,7 @@ var ItdAccounts = class ItdAccounts {
|
|
|
1872
1899
|
return this.dispose();
|
|
1873
1900
|
}
|
|
1874
1901
|
static {
|
|
1875
|
-
|
|
1876
|
-
const prototype = ItdAccounts.prototype;
|
|
1877
|
-
prototype[Symbol.for("Symbol.asyncDispose")] = prototype.undefined;
|
|
1878
|
-
delete prototype.undefined;
|
|
1879
|
-
}
|
|
1902
|
+
require_url.installAsyncDisposeFallback(ItdAccounts);
|
|
1880
1903
|
}
|
|
1881
1904
|
/**
|
|
1882
1905
|
* Собирает опции клиента: общие, поверх них — аккаунтные, и обязательно свой срез
|
|
@@ -1901,9 +1924,9 @@ var ItdAccounts = class ItdAccounts {
|
|
|
1901
1924
|
storage
|
|
1902
1925
|
};
|
|
1903
1926
|
}
|
|
1904
|
-
/** Не теряет ошибку фонового
|
|
1905
|
-
#
|
|
1906
|
-
const message = `Не удалось
|
|
1927
|
+
/** Не теряет ошибку фонового освобождения ресурсов, которого синхронный API не ждёт. */
|
|
1928
|
+
#reportCleanup(scope, error) {
|
|
1929
|
+
const message = `Не удалось освободить ресурсы после ${scope}`;
|
|
1907
1930
|
if (this.#logger) this.#logger.error(message, error);
|
|
1908
1931
|
else console.error(`[itd-api] ${message}`, error);
|
|
1909
1932
|
}
|
|
@@ -1943,6 +1966,10 @@ exports.BUCKET_LIMITS = require_url.BUCKET_LIMITS;
|
|
|
1943
1966
|
exports.CommentSort = require_url.CommentSort;
|
|
1944
1967
|
exports.DEFAULT_BASE_URL = require_url.DEFAULT_BASE_URL;
|
|
1945
1968
|
exports.DEFAULT_RATE_LIMIT_BUCKET = require_url.DEFAULT_RATE_LIMIT_BUCKET;
|
|
1969
|
+
exports.EventChannel = require_events.EventChannel;
|
|
1970
|
+
exports.EventChannelStatus = require_url.EventChannelStatus;
|
|
1971
|
+
exports.EventComposer = require_events.EventComposer;
|
|
1972
|
+
exports.EventRouter = require_events.EventRouter;
|
|
1946
1973
|
exports.FeedTab = require_url.FeedTab;
|
|
1947
1974
|
exports.FileTransferMode = require_options.FileTransferMode;
|
|
1948
1975
|
exports.IMAGE_MIME_TYPES = require_render.IMAGE_MIME_TYPES;
|
|
@@ -1966,58 +1993,65 @@ exports.ItdNetworkError = require_errors.ItdNetworkError;
|
|
|
1966
1993
|
exports.ItdNotFoundError = require_errors.ItdNotFoundError;
|
|
1967
1994
|
exports.ItdPhoneVerificationError = require_errors.ItdPhoneVerificationError;
|
|
1968
1995
|
exports.ItdRateLimitError = require_errors.ItdRateLimitError;
|
|
1969
|
-
exports.ItdRealtime = require_websocket.ItdRealtime;
|
|
1970
1996
|
exports.ItdServerError = require_errors.ItdServerError;
|
|
1971
1997
|
exports.ItdStateError = require_errors.ItdStateError;
|
|
1972
1998
|
exports.ItdTimeoutError = require_errors.ItdTimeoutError;
|
|
1973
1999
|
exports.ItdValidationError = require_errors.ItdValidationError;
|
|
1974
2000
|
exports.LIBRARY_VERSION = require_url.LIBRARY_VERSION;
|
|
1975
2001
|
exports.LikesVisibility = require_url.LikesVisibility;
|
|
1976
|
-
exports.MemoryKeyValueStore =
|
|
2002
|
+
exports.MemoryKeyValueStore = require_key_value_store.MemoryKeyValueStore;
|
|
1977
2003
|
exports.MemoryMultiTokenStorage = require_multi_storage.MemoryMultiTokenStorage;
|
|
2004
|
+
exports.MemoryShopOrderAccessStorage = require_render.MemoryShopOrderAccessStorage;
|
|
1978
2005
|
exports.MemoryTokenStorage = require_storage.MemoryTokenStorage;
|
|
2006
|
+
exports.NotificationEvents = require_events.NotificationEvents;
|
|
2007
|
+
exports.NotificationEventsClient = require_events.NotificationEventsClient;
|
|
2008
|
+
exports.NotificationEventsTransport = require_events.NotificationEventsTransport;
|
|
1979
2009
|
exports.NotificationType = require_url.NotificationType;
|
|
2010
|
+
exports.NotificationUpdateOrigin = require_events.NotificationUpdateOrigin;
|
|
2011
|
+
exports.NotificationUpdateType = require_events.NotificationUpdateType;
|
|
1980
2012
|
exports.OPERATIONS = require_url.OPERATIONS;
|
|
1981
2013
|
exports.PaginationMode = require_render.PaginationMode;
|
|
1982
2014
|
exports.Paginator = require_render.Paginator;
|
|
1983
2015
|
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
2016
|
exports.ReportReason = require_url.ReportReason;
|
|
1991
2017
|
exports.ReportTargetType = require_url.ReportTargetType;
|
|
1992
2018
|
exports.RetrySafety = require_url.RetrySafety;
|
|
1993
|
-
exports.RuntimeMode =
|
|
2019
|
+
exports.RuntimeMode = require_redact.RuntimeMode;
|
|
1994
2020
|
exports.STATUS_SERVICE = require_url.STATUS_SERVICE;
|
|
1995
2021
|
exports.ServiceState = require_url.ServiceState;
|
|
2022
|
+
exports.ShopConsentKind = require_render.ShopConsentKind;
|
|
2023
|
+
exports.ShopOrderStatus = require_render.ShopOrderStatus;
|
|
2024
|
+
exports.ShopProductCategory = require_render.ShopProductCategory;
|
|
2025
|
+
exports.ShopProductStatus = require_render.ShopProductStatus;
|
|
1996
2026
|
exports.SignInStatus = SignInStatus;
|
|
1997
2027
|
exports.SpanRenderFormat = require_render.SpanRenderFormat;
|
|
1998
2028
|
exports.SpanType = require_url.SpanType;
|
|
1999
2029
|
exports.TURNSTILE_SITE_KEY = TURNSTILE_SITE_KEY;
|
|
2000
|
-
exports.UnauthorizedStreamError =
|
|
2030
|
+
exports.UnauthorizedStreamError = require_events.UnauthorizedStreamError;
|
|
2001
2031
|
exports.VIDEO_MIME_TYPES = require_render.VIDEO_MIME_TYPES;
|
|
2002
2032
|
exports.ViewReason = require_url.ViewReason;
|
|
2003
2033
|
exports.ViewSource = require_url.ViewSource;
|
|
2004
2034
|
exports.WallAccess = require_url.WallAccess;
|
|
2005
|
-
exports.WebSocketTransport =
|
|
2035
|
+
exports.WebSocketTransport = require_events.WebSocketTransport;
|
|
2006
2036
|
exports.autoSpans = require_render.autoSpans;
|
|
2007
2037
|
exports.canonicalNotificationType = require_url.canonicalNotificationType;
|
|
2008
2038
|
exports.comment = require_render.comment;
|
|
2009
2039
|
exports.createAccounts = createAccounts;
|
|
2010
2040
|
exports.createClient = createClient;
|
|
2011
|
-
exports.createKeyValueStore =
|
|
2041
|
+
exports.createKeyValueStore = require_key_value_store.createKeyValueStore;
|
|
2042
|
+
exports.createMemoryShopOrderAccessStorage = require_render.createMemoryShopOrderAccessStorage;
|
|
2012
2043
|
exports.createMultiTokenStorage = require_multi_storage.createMultiTokenStorage;
|
|
2013
|
-
exports.
|
|
2044
|
+
exports.createNotificationEventsClient = require_events.createNotificationEventsClient;
|
|
2045
|
+
exports.createRecordKeyValueStore = require_key_value_store.createRecordKeyValueStore;
|
|
2046
|
+
exports.createShopFeature = require_render.createShopFeature;
|
|
2047
|
+
exports.createShopOrderAccessStorage = require_render.createShopOrderAccessStorage;
|
|
2014
2048
|
exports.createTokenStorage = require_storage.createTokenStorage;
|
|
2015
2049
|
exports.formatNotificationText = require_url.formatNotificationText;
|
|
2016
2050
|
exports.fromStream = require_render.fromStream;
|
|
2017
2051
|
exports.fromUrl = require_render.fromUrl;
|
|
2018
2052
|
exports.isBuilder = require_render.isBuilder;
|
|
2019
2053
|
exports.isBuiltInOperationId = require_url.isBuiltInOperationId;
|
|
2020
|
-
exports.isEnumerableKeyValueStore =
|
|
2054
|
+
exports.isEnumerableKeyValueStore = require_key_value_store.isEnumerableKeyValueStore;
|
|
2021
2055
|
exports.isItdApiError = require_errors.isItdApiError;
|
|
2022
2056
|
exports.isItdAuthError = require_errors.isItdAuthError;
|
|
2023
2057
|
exports.isItdConflictError = require_errors.isItdConflictError;
|
|
@@ -2045,13 +2079,13 @@ exports.post = require_render.post;
|
|
|
2045
2079
|
exports.renderSpans = require_render.renderSpans;
|
|
2046
2080
|
exports.report = require_render.report;
|
|
2047
2081
|
exports.resolveNotificationUrl = require_url.resolveNotificationUrl;
|
|
2048
|
-
exports.
|
|
2082
|
+
exports.runEventMiddleware = require_events.runEventMiddleware;
|
|
2049
2083
|
exports.scopedTokenStorage = require_multi_storage.scopedTokenStorage;
|
|
2050
2084
|
exports.statusDays = require_render.statusDays;
|
|
2051
2085
|
exports.systemClock = require_url.systemClock;
|
|
2052
2086
|
exports.toDate = require_render.toDate;
|
|
2053
2087
|
exports.utcStampToIso = require_render.utcStampToIso;
|
|
2054
|
-
exports.withCodec =
|
|
2055
|
-
exports.withNamespace =
|
|
2088
|
+
exports.withCodec = require_key_value_store.withCodec;
|
|
2089
|
+
exports.withNamespace = require_key_value_store.withNamespace;
|
|
2056
2090
|
|
|
2057
2091
|
//# sourceMappingURL=index.cjs.map
|