@foxford/sdk 5.0.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/index.cjs ADDED
@@ -0,0 +1,1794 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __defProps = Object.defineProperties;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
9
+ var __getProtoOf = Object.getPrototypeOf;
10
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
11
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
12
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
13
+ var __spreadValues = (a, b) => {
14
+ for (var prop in b || (b = {}))
15
+ if (__hasOwnProp.call(b, prop))
16
+ __defNormalProp(a, prop, b[prop]);
17
+ if (__getOwnPropSymbols)
18
+ for (var prop of __getOwnPropSymbols(b)) {
19
+ if (__propIsEnum.call(b, prop))
20
+ __defNormalProp(a, prop, b[prop]);
21
+ }
22
+ return a;
23
+ };
24
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
25
+ var __export = (target, all) => {
26
+ for (var name in all)
27
+ __defProp(target, name, { get: all[name], enumerable: true });
28
+ };
29
+ var __copyProps = (to, from, except, desc) => {
30
+ if (from && typeof from === "object" || typeof from === "function") {
31
+ for (let key of __getOwnPropNames(from))
32
+ if (!__hasOwnProp.call(to, key) && key !== except)
33
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
34
+ }
35
+ return to;
36
+ };
37
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
38
+ // If the importer is in node compatibility mode or this is not an ESM
39
+ // file that has been converted to a CommonJS file using a Babel-
40
+ // compatible transform (i.e. "__esModule" has not been set), then set
41
+ // "default" to the CommonJS "module.exports" for node compatibility.
42
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
43
+ mod
44
+ ));
45
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
46
+ var __async = (__this, __arguments, generator) => {
47
+ return new Promise((resolve, reject) => {
48
+ var fulfilled = (value) => {
49
+ try {
50
+ step(generator.next(value));
51
+ } catch (e) {
52
+ reject(e);
53
+ }
54
+ };
55
+ var rejected = (value) => {
56
+ try {
57
+ step(generator.throw(value));
58
+ } catch (e) {
59
+ reject(e);
60
+ }
61
+ };
62
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
63
+ step((generator = generator.apply(__this, __arguments)).next());
64
+ });
65
+ };
66
+
67
+ // src/index.ts
68
+ var index_exports = {};
69
+ __export(index_exports, {
70
+ Analytics: () => Analytics,
71
+ ApiService: () => import_services3.ApiService,
72
+ AppOptionsService: () => AppOptionsService,
73
+ CaptchaError: () => import_services3.CaptchaError,
74
+ CaptchaService: () => import_services3.CaptchaService,
75
+ CartService: () => CartService,
76
+ CourseService: () => CourseService,
77
+ Foxford: () => Foxford,
78
+ FoxfordAntibot: () => FoxfordAntibot,
79
+ LeadRequestService: () => LeadRequestService,
80
+ LeadRequestType: () => LeadRequestType,
81
+ ProductPackService: () => ProductPackService,
82
+ PromoService: () => PromoService,
83
+ RequestPlugin: () => import_services3.RequestPlugin,
84
+ ResponseFailPlugin: () => import_services3.ResponseFailPlugin,
85
+ ResponseSuccessPlugin: () => import_services3.ResponseSuccessPlugin,
86
+ TagService: () => TagService,
87
+ User: () => User,
88
+ UserService: () => UserService,
89
+ Widgets: () => Widgets
90
+ });
91
+ module.exports = __toCommonJS(index_exports);
92
+
93
+ // src/foxford.ts
94
+ var import_services2 = require("@foxford/services");
95
+
96
+ // src/antibot/index.ts
97
+ if (window.antibotInitialized === void 0) window.antibotInitialized = false;
98
+ var _FoxfordAntibot = class _FoxfordAntibot {
99
+ constructor(config = _FoxfordAntibot.DEFAULT_CONFIG) {
100
+ this.createAntibotFrame = (params) => {
101
+ if (window.location.hostname.endsWith("foxford.ru") || window.location.hostname.endsWith("netology-group.services") || this.config.debug) {
102
+ const frame = _FoxfordAntibot.createFrame(params.src, params == null ? void 0 : params.onload, params == null ? void 0 : params.onerror);
103
+ document.body.appendChild(frame);
104
+ window.antibotInitialized = true;
105
+ }
106
+ };
107
+ this.config = __spreadValues(__spreadValues({}, _FoxfordAntibot.DEFAULT_CONFIG), config);
108
+ if (!document.body) throw new Error("Body element not found");
109
+ if (window.onCaptureReady !== void 0) {
110
+ console.debug("Seo4Ajax crawler injects own callback. FoxfordAntibot initialization will be ignored.");
111
+ return;
112
+ }
113
+ if (_FoxfordAntibot.antibotIsInitialized()) {
114
+ console.debug("FoxfordAntibot is already mounted");
115
+ return;
116
+ }
117
+ if (process.env.NODE_ENV === "production") {
118
+ this.createAntibotFrame({
119
+ onerror: this.config.antibotOnerror,
120
+ onload: this.config.antibotOnload,
121
+ src: this.config.antibotFrameSrc
122
+ });
123
+ }
124
+ }
125
+ static antibotIsInitialized() {
126
+ if (window.antibotInitialized || document.querySelectorAll(`iframe.${_FoxfordAntibot.FRAME_CLASSNAME}`).length > 0) {
127
+ return true;
128
+ }
129
+ try {
130
+ return window.top ? window.self !== window.top && Boolean(window.top.antibotInitialized) : false;
131
+ } catch (e) {
132
+ return false;
133
+ }
134
+ }
135
+ };
136
+ _FoxfordAntibot.FOXFORD_ANTIBOT_URL = "https://foxford.ru/antibot/ping";
137
+ _FoxfordAntibot.DEFAULT_CONFIG = {
138
+ antibotFrameSrc: _FoxfordAntibot.FOXFORD_ANTIBOT_URL
139
+ };
140
+ _FoxfordAntibot.FRAME_CLASSNAME = "antibot";
141
+ _FoxfordAntibot.createFrame = (src, onload, onerror) => {
142
+ const frame = document.createElement("iframe");
143
+ frame.classList.add(_FoxfordAntibot.FRAME_CLASSNAME);
144
+ frame.style.width = "1px";
145
+ frame.style.height = "1px";
146
+ frame.style.position = "fixed";
147
+ frame.style.zIndex = "-1";
148
+ frame.style.top = "0";
149
+ frame.style.left = "0";
150
+ frame.style.border = "0";
151
+ frame.referrerPolicy = "origin";
152
+ frame.src = src;
153
+ frame.onload = (e) => {
154
+ if (typeof onload === "function") onload(e);
155
+ };
156
+ frame.onerror = () => {
157
+ if (typeof onerror === "function") onerror();
158
+ };
159
+ return frame;
160
+ };
161
+ var FoxfordAntibot = _FoxfordAntibot;
162
+
163
+ // src/constants.ts
164
+ var CSRF_COOKIE_NAME = "_csrf_token";
165
+ var FOXFORD_HOST = "https://foxford.ru";
166
+
167
+ // src/api/config.ts
168
+ var apiBaseConfig = {
169
+ headers: { "X-Requested-With": "XMLHttpRequest" },
170
+ withXSRFToken: true,
171
+ xsrfCookieName: CSRF_COOKIE_NAME,
172
+ xsrfHeaderName: "X-CSRF-Token"
173
+ };
174
+ var apiConfig = __spreadProps(__spreadValues({}, apiBaseConfig), {
175
+ withCredentials: true
176
+ });
177
+
178
+ // src/utils/camelize.ts
179
+ var import_camelcase_keys_deep = __toESM(require("camelcase-keys-deep"), 1);
180
+ var import_decamelize_keys_deep = __toESM(require("decamelize-keys-deep"), 1);
181
+ var camelize = (obj) => (0, import_camelcase_keys_deep.default)(obj);
182
+ var decamelize = (obj) => (0, import_decamelize_keys_deep.default)(obj);
183
+
184
+ // src/api/plugins/CamelizeRequestPlugin.ts
185
+ var CamelizeRequestPlugin = class {
186
+ constructor() {
187
+ this.pluginType = "request";
188
+ this.pluginName = "camelizeRequestPlugin";
189
+ }
190
+ // требуется публичный метод, а для внутренней реализации может понадобиться this
191
+ // eslint-disable-next-line @typescript-eslint/class-methods-use-this
192
+ execute(config, instance) {
193
+ return new Promise((resolve) => {
194
+ const convert = typeof config.camelize === "boolean" ? config.camelize : true;
195
+ if (convert) {
196
+ const defaultTransform = instance.defaults.transformResponse;
197
+ const camelizeResponse = (data) => {
198
+ return camelize(data);
199
+ };
200
+ if (defaultTransform) {
201
+ config.transformResponse = Array.isArray(defaultTransform) ? [...defaultTransform, camelizeResponse] : [defaultTransform, camelizeResponse];
202
+ }
203
+ }
204
+ resolve(config);
205
+ });
206
+ }
207
+ // требуется публичный метод, а для внутренней реализации может понадобиться this
208
+ // eslint-disable-next-line @typescript-eslint/class-methods-use-this
209
+ isApplicable(config) {
210
+ return typeof config.camelize === "boolean" ? config.camelize : true;
211
+ }
212
+ };
213
+
214
+ // src/api/plugins/DataLayerEventDispatcherPlugin.ts
215
+ var DataLayerEventDispatcherPlugin = class {
216
+ constructor() {
217
+ this.pluginType = "responseSuccess";
218
+ this.pluginName = "dataLayerEventDispatcherPlugin";
219
+ }
220
+ // требуется публичный метод, а для внутренней реализации может понадобиться this
221
+ // eslint-disable-next-line @typescript-eslint/class-methods-use-this
222
+ execute(response) {
223
+ return new Promise((resolve) => {
224
+ try {
225
+ const rawResponse = JSON.parse(response.request.response);
226
+ if (Array.isArray(rawResponse["data_layer_events"])) {
227
+ if (!Array.isArray(window.dataLayer)) {
228
+ window.dataLayer = [];
229
+ }
230
+ window.dataLayer.push(...rawResponse["data_layer_events"]);
231
+ }
232
+ } catch (e) {
233
+ }
234
+ resolve(response);
235
+ });
236
+ }
237
+ // требуется публичный метод, а для внутренней реализации может понадобиться this
238
+ // eslint-disable-next-line @typescript-eslint/class-methods-use-this
239
+ isApplicable() {
240
+ return true;
241
+ }
242
+ };
243
+
244
+ // src/utils/pathToRegexp.ts
245
+ function lexer(str) {
246
+ const tokens = [];
247
+ let i = 0;
248
+ while (i < str.length) {
249
+ const char = str[i];
250
+ if (char === "*" || char === "+" || char === "?") {
251
+ tokens.push({ index: i, type: "MODIFIER", value: str[i++] });
252
+ continue;
253
+ }
254
+ if (char === "\\") {
255
+ tokens.push({ index: i++, type: "ESCAPED_CHAR", value: str[i++] });
256
+ continue;
257
+ }
258
+ if (char === "{") {
259
+ tokens.push({ index: i, type: "OPEN", value: str[i++] });
260
+ continue;
261
+ }
262
+ if (char === "}") {
263
+ tokens.push({ index: i, type: "CLOSE", value: str[i++] });
264
+ continue;
265
+ }
266
+ if (char === ":") {
267
+ let name = "";
268
+ let j = i + 1;
269
+ while (j < str.length) {
270
+ const code = str.charCodeAt(j);
271
+ if (
272
+ // `0-9`
273
+ code >= 48 && code <= 57 || // `A-Z`
274
+ code >= 65 && code <= 90 || // `a-z`
275
+ code >= 97 && code <= 122 || // `_`
276
+ code === 95
277
+ ) {
278
+ name += str[j++];
279
+ continue;
280
+ }
281
+ break;
282
+ }
283
+ if (!name) throw new TypeError(`Missing parameter name at ${i}`);
284
+ tokens.push({ index: i, type: "NAME", value: name });
285
+ i = j;
286
+ continue;
287
+ }
288
+ if (char === "(") {
289
+ let count = 1;
290
+ let pattern = "";
291
+ let j = i + 1;
292
+ if (str[j] === "?") {
293
+ throw new TypeError(`Pattern cannot start with "?" at ${j}`);
294
+ }
295
+ while (j < str.length) {
296
+ if (str[j] === "\\") {
297
+ pattern += str[j++] + str[j++];
298
+ continue;
299
+ }
300
+ if (str[j] === ")") {
301
+ count--;
302
+ if (count === 0) {
303
+ j++;
304
+ break;
305
+ }
306
+ } else if (str[j] === "(") {
307
+ count++;
308
+ if (str[j + 1] !== "?") {
309
+ throw new TypeError(`Capturing groups are not allowed at ${j}`);
310
+ }
311
+ }
312
+ pattern += str[j++];
313
+ }
314
+ if (count) throw new TypeError(`Unbalanced pattern at ${i}`);
315
+ if (!pattern) throw new TypeError(`Missing pattern at ${i}`);
316
+ tokens.push({ index: i, type: "PATTERN", value: pattern });
317
+ i = j;
318
+ continue;
319
+ }
320
+ tokens.push({ index: i, type: "CHAR", value: str[i++] });
321
+ }
322
+ tokens.push({ index: i, type: "END", value: "" });
323
+ return tokens;
324
+ }
325
+ function parse(str, options = {}) {
326
+ const tokens = lexer(str);
327
+ const { prefixes = "./" } = options;
328
+ const defaultPattern = `[^${escapeString(options.delimiter || "/#?")}]+?`;
329
+ const result = [];
330
+ let key = 0;
331
+ let i = 0;
332
+ let path = "";
333
+ const tryConsume = (type) => {
334
+ var _a, _b;
335
+ if (i < tokens.length && ((_a = tokens[i]) == null ? void 0 : _a.type) === type) return (_b = tokens[i++]) == null ? void 0 : _b.value;
336
+ return void 0;
337
+ };
338
+ const mustConsume = (type) => {
339
+ var _a, _b;
340
+ const value = tryConsume(type);
341
+ if (value !== void 0) return value;
342
+ throw new TypeError(`Unexpected ${(_a = tokens[i]) == null ? void 0 : _a.type} at ${(_b = tokens[i]) == null ? void 0 : _b.index}, expected ${type}`);
343
+ };
344
+ const consumeText = () => {
345
+ let result2 = "";
346
+ let value;
347
+ while (value = tryConsume("CHAR") || tryConsume("ESCAPED_CHAR")) {
348
+ result2 += value;
349
+ }
350
+ return result2;
351
+ };
352
+ while (i < tokens.length) {
353
+ const char = tryConsume("CHAR");
354
+ const name = tryConsume("NAME");
355
+ const pattern = tryConsume("PATTERN");
356
+ if (name || pattern) {
357
+ let prefix = char || "";
358
+ if (prefixes.indexOf(prefix) === -1) {
359
+ path += prefix;
360
+ prefix = "";
361
+ }
362
+ if (path) {
363
+ result.push(path);
364
+ path = "";
365
+ }
366
+ result.push({
367
+ modifier: tryConsume("MODIFIER") || "",
368
+ name: name || key++,
369
+ pattern: pattern || defaultPattern,
370
+ prefix,
371
+ suffix: ""
372
+ });
373
+ continue;
374
+ }
375
+ const value = char || tryConsume("ESCAPED_CHAR");
376
+ if (value) {
377
+ path += value;
378
+ continue;
379
+ }
380
+ if (path) {
381
+ result.push(path);
382
+ path = "";
383
+ }
384
+ const open = tryConsume("OPEN");
385
+ if (open) {
386
+ const prefix = consumeText();
387
+ const name2 = tryConsume("NAME") || "";
388
+ const pattern2 = tryConsume("PATTERN") || "";
389
+ const suffix = consumeText();
390
+ mustConsume("CLOSE");
391
+ result.push({
392
+ modifier: tryConsume("MODIFIER") || "",
393
+ name: name2 || (pattern2 ? key++ : ""),
394
+ pattern: name2 && !pattern2 ? defaultPattern : pattern2,
395
+ prefix,
396
+ suffix
397
+ });
398
+ continue;
399
+ }
400
+ mustConsume("END");
401
+ }
402
+ return result;
403
+ }
404
+ function escapeString(str) {
405
+ return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, "\\$1");
406
+ }
407
+ function flags(options) {
408
+ return options && options.sensitive ? "" : "i";
409
+ }
410
+ function regexpToRegexp(path, keys) {
411
+ if (!keys) return path;
412
+ const groupsRegex = /\((?:\?<(.*?)>)?(?!\?)/g;
413
+ let index = 0;
414
+ let execResult = groupsRegex.exec(path.source);
415
+ while (execResult) {
416
+ keys.push({
417
+ modifier: "",
418
+ // Use parenthesized substring match if available, index otherwise
419
+ name: execResult[1] || index++,
420
+ pattern: "",
421
+ prefix: "",
422
+ suffix: ""
423
+ });
424
+ execResult = groupsRegex.exec(path.source);
425
+ }
426
+ return path;
427
+ }
428
+ function arrayToRegexp(paths, keys, options) {
429
+ const parts = paths.map((path) => pathToRegexp(path, keys, options).source);
430
+ return new RegExp(`(?:${parts.join("|")})`, flags(options));
431
+ }
432
+ function stringToRegexp(path, keys, options) {
433
+ return tokensToRegexp(parse(path, options), keys, options);
434
+ }
435
+ function tokensToRegexp(tokens, keys, options = {}) {
436
+ const {
437
+ strict = false,
438
+ start = true,
439
+ end = true,
440
+ encode = (x) => x,
441
+ delimiter = "/#?",
442
+ endsWith = ""
443
+ } = options;
444
+ const endsWithRe = `[${escapeString(endsWith)}]|$`;
445
+ const delimiterRe = `[${escapeString(delimiter)}]`;
446
+ let route = start ? "^" : "";
447
+ for (const token of tokens) {
448
+ if (typeof token === "string") {
449
+ route += escapeString(encode(token));
450
+ } else {
451
+ const prefix = escapeString(encode(token.prefix));
452
+ const suffix = escapeString(encode(token.suffix));
453
+ if (token.pattern) {
454
+ if (keys) keys.push(token);
455
+ if (prefix || suffix) {
456
+ if (token.modifier === "+" || token.modifier === "*") {
457
+ const mod = token.modifier === "*" ? "?" : "";
458
+ route += `(?:${prefix}((?:${token.pattern})(?:${suffix}${prefix}(?:${token.pattern}))*)${suffix})${mod}`;
459
+ } else {
460
+ route += `(?:${prefix}(${token.pattern})${suffix})${token.modifier}`;
461
+ }
462
+ } else {
463
+ if (token.modifier === "+" || token.modifier === "*") {
464
+ route += `((?:${token.pattern})${token.modifier})`;
465
+ } else {
466
+ route += `(${token.pattern})${token.modifier}`;
467
+ }
468
+ }
469
+ } else {
470
+ route += `(?:${prefix}${suffix})${token.modifier}`;
471
+ }
472
+ }
473
+ }
474
+ if (end) {
475
+ if (!strict) route += `${delimiterRe}?`;
476
+ route += !options.endsWith ? "$" : `(?=${endsWithRe})`;
477
+ } else {
478
+ const endToken = tokens[tokens.length - 1];
479
+ const isEndDelimited = typeof endToken === "string" ? delimiterRe.indexOf(endToken[endToken.length - 1]) > -1 : endToken === void 0;
480
+ if (!strict) {
481
+ route += `(?:${delimiterRe}(?=${endsWithRe}))?`;
482
+ }
483
+ if (!isEndDelimited) {
484
+ route += `(?=${delimiterRe}|${endsWithRe})`;
485
+ }
486
+ }
487
+ return new RegExp(route, flags(options));
488
+ }
489
+ function pathToRegexp(path, keys, options) {
490
+ if (path instanceof RegExp) return regexpToRegexp(path, keys);
491
+ if (Array.isArray(path)) return arrayToRegexp(path, keys, options);
492
+ return stringToRegexp(path, keys, options);
493
+ }
494
+
495
+ // src/utils/matchPath.ts
496
+ var cache = {};
497
+ var cacheLimit = 1e4;
498
+ var cacheCount = 0;
499
+ function compilePath(path, options) {
500
+ const { end = false, strict = false, sensitive = false } = options;
501
+ const cacheKey = `${path}/${end.toString()}/${strict.toString()}/${sensitive.toString()}`;
502
+ const pathCache = cache[cacheKey] || (cache[cacheKey] = {});
503
+ if (pathCache[path]) return pathCache[path];
504
+ const keys = [];
505
+ const regexp = pathToRegexp(path, keys, options);
506
+ const result = { keys, regexp };
507
+ if (cacheCount < cacheLimit) {
508
+ pathCache[path] = result;
509
+ cacheCount += 1;
510
+ }
511
+ return result;
512
+ }
513
+ var matchPath = (pathname, options) => {
514
+ if (options === void 0) {
515
+ options = {};
516
+ }
517
+ if (typeof options === "string" || Array.isArray(options)) {
518
+ options = {
519
+ path: options
520
+ };
521
+ }
522
+ const _options = options, path = _options.path, _options$exact = _options.exact, exact = _options$exact === void 0 ? false : _options$exact, _options$strict = _options.strict, strict = _options$strict === void 0 ? false : _options$strict, _options$sensitive = _options.sensitive, sensitive = _options$sensitive === void 0 ? false : _options$sensitive;
523
+ const paths = [].concat(path);
524
+ return paths.reduce(function(matched, path2) {
525
+ if (!path2 && path2 !== "") return null;
526
+ if (matched) return matched;
527
+ const _compilePath = compilePath(path2, {
528
+ end: exact,
529
+ sensitive,
530
+ strict
531
+ }), regexp = _compilePath.regexp, keys = _compilePath.keys;
532
+ const match = regexp.exec(pathname);
533
+ if (!match) return null;
534
+ const url = match[0], values = match.slice(1);
535
+ const isExact = pathname === url;
536
+ if (exact && !isExact) return null;
537
+ return {
538
+ // the matched portion of the URL
539
+ isExact,
540
+ // whether or not we matched exactly
541
+ params: keys.reduce(function(memo, key, index) {
542
+ memo[key.name] = values[index];
543
+ return memo;
544
+ }, {}),
545
+ path: path2,
546
+ // the path used to match
547
+ url: path2 === "/" && url === "" ? "/" : url
548
+ };
549
+ }, null);
550
+ };
551
+
552
+ // src/api/plugins/ReferrerRequestPlugin.ts
553
+ var REFERRER_PAYLOAD_NAME = "referrer";
554
+ var REFERRER_ENDPOINTS = {
555
+ delete: [],
556
+ get: [],
557
+ patch: [],
558
+ post: ["/api/email_registration", "/api/phone_registration", "/api/auth/registration"],
559
+ put: []
560
+ };
561
+ var ReferrerRequestPlugin = class {
562
+ constructor() {
563
+ this.pluginType = "request";
564
+ this.pluginName = "referrerRequestPlugin";
565
+ }
566
+ // требуется публичный метод, а для внутренней реализации может понадобиться this
567
+ // eslint-disable-next-line @typescript-eslint/class-methods-use-this
568
+ execute(config) {
569
+ return new Promise((resolve) => {
570
+ const referrer = String(window.__fox_referrer__);
571
+ if (!referrer) {
572
+ resolve(config);
573
+ }
574
+ config.params = __spreadProps(__spreadValues({}, config.params), {
575
+ [REFERRER_PAYLOAD_NAME]: referrer
576
+ });
577
+ resolve(config);
578
+ });
579
+ }
580
+ // требуется публичный метод, а для внутренней реализации может понадобиться this
581
+ // eslint-disable-next-line @typescript-eslint/class-methods-use-this
582
+ getEndpoints() {
583
+ return REFERRER_ENDPOINTS;
584
+ }
585
+ isApplicable(config) {
586
+ var _a;
587
+ const { method, url: pathUrl = "" } = config;
588
+ const endpointMethod = method ? method : "post";
589
+ const endpoints = this.getEndpoints();
590
+ const referrerURLs = (_a = endpoints[endpointMethod]) != null ? _a : [];
591
+ return referrerURLs.some((url) => url === pathUrl || pathUrl && matchPath(pathUrl, { exact: true, path: url })) || config.withReferrer === true;
592
+ }
593
+ };
594
+
595
+ // src/api/index.ts
596
+ var referrerRequestPlugin = new ReferrerRequestPlugin();
597
+ var camelizeRequestPlugin = new CamelizeRequestPlugin();
598
+ var dataLayerEventDispatcherPlugin = new DataLayerEventDispatcherPlugin();
599
+ var defaultPlugins = [
600
+ camelizeRequestPlugin,
601
+ referrerRequestPlugin,
602
+ dataLayerEventDispatcherPlugin
603
+ ];
604
+
605
+ // src/api/plugins/CaptchaPlugin.ts
606
+ var import_services = require("@foxford/services");
607
+ var CaptchaPlugin = class {
608
+ constructor(captchaConfig) {
609
+ this.pluginType = "responseFail";
610
+ this.pluginName = "captchaPlugin";
611
+ this.captchaConfig = captchaConfig;
612
+ }
613
+ // требуется публичный метод, а для внутренней реализации может понадобиться this
614
+ // eslint-disable-next-line complexity
615
+ execute(error) {
616
+ return __async(this, null, function* () {
617
+ var _a, _b;
618
+ try {
619
+ const captchaConfig = typeof this.captchaConfig === "function" ? this.captchaConfig() : this.captchaConfig;
620
+ if (!captchaConfig) return error;
621
+ const { settings = {} } = (_b = (_a = error.response) == null ? void 0 : _a.data) != null ? _b : {};
622
+ const { provider } = settings;
623
+ const siteKey = settings.siteKey || settings.site_key || void 0;
624
+ if (!settings || !provider || !siteKey) return error;
625
+ this.captcha = new import_services.CaptchaService(__spreadProps(__spreadValues({}, captchaConfig), {
626
+ provider,
627
+ sitekey: siteKey
628
+ }));
629
+ const { config } = error;
630
+ const captchaAnswer = yield this.captcha.execute({
631
+ location: config.url,
632
+ method: config.method
633
+ });
634
+ if (captchaAnswer === null || captchaAnswer === void 0 || typeof (captchaAnswer == null ? void 0 : captchaAnswer.captcha_token) !== "string") {
635
+ return config;
636
+ }
637
+ const captchaPayload = {
638
+ verification: {
639
+ settings: {
640
+ token: captchaAnswer.captcha_token
641
+ },
642
+ type: "captcha"
643
+ }
644
+ };
645
+ if (config.method === "get") {
646
+ config.params = __spreadValues(__spreadValues({}, config.params), captchaPayload);
647
+ }
648
+ if (typeof config.data === "string") {
649
+ try {
650
+ let data = JSON.parse(config.data);
651
+ data = __spreadValues(__spreadValues({}, data), captchaPayload);
652
+ config.data = JSON.stringify(data);
653
+ } catch (err) {
654
+ console.error(err);
655
+ }
656
+ } else if (config.data instanceof FormData) {
657
+ const formData = config.data;
658
+ formData.append("verification[settings][token]", captchaPayload.verification.settings.token);
659
+ formData.append("verification[type]", captchaPayload.verification.type);
660
+ config.data = formData;
661
+ } else if (typeof config.data === "object") {
662
+ config.data = __spreadValues(__spreadValues({}, config.data), captchaPayload);
663
+ }
664
+ return config;
665
+ } catch (error2) {
666
+ return error2;
667
+ }
668
+ });
669
+ }
670
+ // требуется публичный метод, а для внутренней реализации может понадобиться this
671
+ // eslint-disable-next-line @typescript-eslint/class-methods-use-this
672
+ isApplicable(error) {
673
+ var _a;
674
+ return ((_a = error.response) == null ? void 0 : _a.status) === 449;
675
+ }
676
+ };
677
+
678
+ // src/api-plugins.ts
679
+ var getPlugins = (config, captchaConfig) => {
680
+ const apiPlugins = config.plugins || [];
681
+ const addedPlugins = [];
682
+ const resultPlugins = [];
683
+ apiPlugins.forEach((plugin) => {
684
+ if (!addedPlugins.includes(plugin.pluginName)) {
685
+ resultPlugins.push(plugin);
686
+ addedPlugins.push(plugin.pluginName);
687
+ }
688
+ });
689
+ defaultPlugins.forEach((plugin) => {
690
+ if (!addedPlugins.includes(plugin.pluginName)) {
691
+ resultPlugins.push(plugin);
692
+ addedPlugins.push(plugin.pluginName);
693
+ }
694
+ });
695
+ if (captchaConfig) {
696
+ const captchaRequestPlugin = new CaptchaPlugin(captchaConfig);
697
+ if (!addedPlugins.includes(captchaRequestPlugin.pluginName)) {
698
+ resultPlugins.push(captchaRequestPlugin);
699
+ addedPlugins.push(captchaRequestPlugin.pluginName);
700
+ }
701
+ }
702
+ return resultPlugins;
703
+ };
704
+
705
+ // src/services/app-options.ts
706
+ var AppOptionsService = class {
707
+ constructor(apiInstance, eventName) {
708
+ this.appOptions = null;
709
+ this.api = apiInstance;
710
+ this.eventName = eventName;
711
+ }
712
+ getCurrentAppOptions() {
713
+ return __async(this, null, function* () {
714
+ if (this.appOptions) return this.appOptions;
715
+ const data = yield this.getAppOptions();
716
+ return data;
717
+ });
718
+ }
719
+ /**
720
+ * Get app options data from api
721
+ */
722
+ getAppOptions() {
723
+ return __async(this, null, function* () {
724
+ const result = yield this.api.get(`/api/app_options`);
725
+ this.appOptions = result.data;
726
+ if (window) window.dispatchEvent(new CustomEvent(this.eventName, { detail: result.data }));
727
+ return result.data;
728
+ });
729
+ }
730
+ };
731
+
732
+ // src/services/cart.ts
733
+ var CartService = class {
734
+ constructor(apiInstance) {
735
+ this.api = apiInstance;
736
+ }
737
+ // eslint-disable-next-line @typescript-eslint/class-methods-use-this
738
+ createCartItem(id, type) {
739
+ return {
740
+ cart_item_type: type,
741
+ resource_id: id
742
+ };
743
+ }
744
+ addCartItemToCart(cartItem) {
745
+ return __async(this, null, function* () {
746
+ const { data } = yield this.api.post(`/api/cart_items`, {
747
+ cart_item: cartItem
748
+ });
749
+ return data;
750
+ });
751
+ }
752
+ };
753
+
754
+ // src/services/course.ts
755
+ var CourseService = class {
756
+ constructor(apiInstance) {
757
+ this.api = apiInstance;
758
+ }
759
+ getCourse(id) {
760
+ return __async(this, null, function* () {
761
+ if (typeof id !== "number") throw new TypeError("id is wrong");
762
+ const { data } = yield this.api.get(`/api/courses/${id}`);
763
+ return data;
764
+ });
765
+ }
766
+ enrollCourse(id) {
767
+ return __async(this, null, function* () {
768
+ if (typeof id !== "number") throw new TypeError("id is wrong");
769
+ yield this.api.post(`/api/courses/${id}/users_courses`);
770
+ });
771
+ }
772
+ };
773
+
774
+ // src/services/lead-request.ts
775
+ var LR_REGISTRATION_SET = "LeadRequest.registration.set";
776
+ var LeadRequestType = /* @__PURE__ */ ((LeadRequestType2) => {
777
+ LeadRequestType2["Algorithmics"] = "LeadRequests::Algorithmics";
778
+ LeadRequestType2["External"] = "LeadRequests::External";
779
+ LeadRequestType2["Callback"] = "LeadRequests::Callback";
780
+ LeadRequestType2["Basic"] = "LeadRequests::Basic";
781
+ LeadRequestType2["Main"] = "LeadRequests::Main";
782
+ LeadRequestType2["Coach"] = "LeadRequests::Coach";
783
+ LeadRequestType2["Media"] = "LeadRequests::Media";
784
+ LeadRequestType2["MiniGroup"] = "LeadRequests::MiniGroup";
785
+ LeadRequestType2["Externship"] = "LeadRequests::Externship";
786
+ LeadRequestType2["CoachUserCoursePlanUpgradeCallback"] = "LeadRequests::CoachUserCoursePlanUpgradeCallback";
787
+ LeadRequestType2["ParentCallback"] = "LeadRequests::ParentCallback";
788
+ LeadRequestType2["TeacherCallback"] = "LeadRequests::TeacherCallback";
789
+ LeadRequestType2["Email"] = "LeadRequests::EmailSubscription";
790
+ LeadRequestType2["IThubLead"] = "LeadRequests::IThubLead";
791
+ return LeadRequestType2;
792
+ })(LeadRequestType || {});
793
+ var LeadRequestService = class {
794
+ constructor(apiInstance) {
795
+ this.types = LeadRequestType;
796
+ this.api = apiInstance;
797
+ }
798
+ /**
799
+ * Create lead request
800
+ * @param {LeadRequestType} type
801
+ * @param {LeadRequest['context']} context
802
+ * @param {LeadRequestPayload} data
803
+ */
804
+ // eslint-disable-next-line @typescript-eslint/class-methods-use-this
805
+ createLeadRequest(type, context, data = {}) {
806
+ const payload = data;
807
+ return __spreadProps(__spreadValues({}, payload), {
808
+ agreement: true,
809
+ context,
810
+ type
811
+ });
812
+ }
813
+ /**
814
+ * Send lead request with specific data
815
+ * @param {LeadRequest} leadRequest
816
+ */
817
+ send(leadRequest) {
818
+ return __async(this, null, function* () {
819
+ const { data } = yield this.api.post(`/api/lead_requests`, {
820
+ lead_request: leadRequest
821
+ });
822
+ if (data.newUser) {
823
+ window.dispatchEvent(new CustomEvent(LR_REGISTRATION_SET));
824
+ }
825
+ return { leadRequest, response: data };
826
+ });
827
+ }
828
+ /**
829
+ * Update lead request with specific data
830
+ * @param {string} id
831
+ * @param {LeadRequestPayload} lrData
832
+ */
833
+ update(_0) {
834
+ return __async(this, arguments, function* (id, lrData = {}) {
835
+ const { data } = yield this.api.put(`/api/lead_requests/${id}`, {
836
+ lead_request: lrData
837
+ });
838
+ return data;
839
+ });
840
+ }
841
+ };
842
+
843
+ // src/services/product-pack.ts
844
+ var ProductPackService = class {
845
+ constructor(apiInstance) {
846
+ this.api = apiInstance;
847
+ }
848
+ getProductPack(id) {
849
+ return __async(this, null, function* () {
850
+ if (typeof id !== "number") throw new TypeError("id is wrong");
851
+ const { data } = yield this.api.get(`/api/product_packs/${id}`);
852
+ return data;
853
+ });
854
+ }
855
+ };
856
+
857
+ // src/services/promo.ts
858
+ var PromoService = class {
859
+ constructor(apiInstance) {
860
+ this.api = apiInstance;
861
+ }
862
+ checkPromocode(code) {
863
+ return __async(this, null, function* () {
864
+ const { data } = yield this.api.get(`/api/promo_codes/invite/${code}`);
865
+ return data;
866
+ });
867
+ }
868
+ /**
869
+ * Send data if user saw the promo code
870
+ * @param {string} promoCode
871
+ * @returns {Promise}
872
+ */
873
+ trackCodeCampaign(promoCode) {
874
+ return __async(this, null, function* () {
875
+ yield this.api.post(`/api/tracking/promo_code`, { promo_code: promoCode });
876
+ });
877
+ }
878
+ };
879
+
880
+ // src/services/tag.ts
881
+ var TagService = class {
882
+ constructor(apiInstance) {
883
+ this.api = apiInstance;
884
+ }
885
+ addTag(id) {
886
+ return __async(this, null, function* () {
887
+ const { data } = yield this.api.post(`/api/user/tag?id=${id}`);
888
+ return data;
889
+ });
890
+ }
891
+ };
892
+
893
+ // src/entities/user/constants.ts
894
+ var GRADE_MAP = {
895
+ 1: "1 \u043A\u043B\u0430\u0441\u0441",
896
+ 2: "2 \u043A\u043B\u0430\u0441\u0441",
897
+ 3: "3 \u043A\u043B\u0430\u0441\u0441",
898
+ 4: "4 \u043A\u043B\u0430\u0441\u0441",
899
+ 5: "5 \u043A\u043B\u0430\u0441\u0441",
900
+ 6: "6 \u043A\u043B\u0430\u0441\u0441",
901
+ 7: "7 \u043A\u043B\u0430\u0441\u0441",
902
+ 8: "8 \u043A\u043B\u0430\u0441\u0441",
903
+ 9: "9 \u043A\u043B\u0430\u0441\u0441",
904
+ 10: "10 \u043A\u043B\u0430\u0441\u0441",
905
+ 11: "11 \u043A\u043B\u0430\u0441\u0441"
906
+ };
907
+ var DEFAULT_USER = {
908
+ address: {
909
+ building: null,
910
+ cityId: null,
911
+ cityName: null,
912
+ countryId: null,
913
+ countryName: null,
914
+ house: null,
915
+ index: null,
916
+ regionId: null,
917
+ regionName: null,
918
+ room: null,
919
+ street: null
920
+ },
921
+ avatarUrl: "",
922
+ bonus: {
923
+ giftAmount: 0,
924
+ realMoneyAmount: 0
925
+ },
926
+ bonusAmount: 0,
927
+ cartItemsCount: 0,
928
+ cartTemplateId: null,
929
+ createdAt: null,
930
+ disciplineIds: [],
931
+ email: "",
932
+ emailConfirmed: false,
933
+ externshipUser: false,
934
+ fakeEmail: false,
935
+ fakeUser: false,
936
+ firstName: "",
937
+ freeAccessFinishesAt: null,
938
+ fullName: "",
939
+ grade: {
940
+ id: null,
941
+ index: null,
942
+ name: "",
943
+ translit: ""
944
+ },
945
+ gradeChecked: false,
946
+ hasAccessToAttestationSheets: false,
947
+ hasAccessToMultiDaysStreaks: false,
948
+ hasActivePurchases: false,
949
+ hasAttemptsSolveExamRehearsals: false,
950
+ hasBookmarks: false,
951
+ hasExternshipAttestationAccess: false,
952
+ hasPurchasedExternshipContracts: false,
953
+ id: null,
954
+ isAgent: false,
955
+ isCoach: false,
956
+ isCustomer: null,
957
+ isElementaryPupil: false,
958
+ isExternshipCoach: false,
959
+ isGraduated: false,
960
+ isMiniGroupTeacher: false,
961
+ isParent: false,
962
+ lastName: "",
963
+ locale: null,
964
+ methodist: false,
965
+ middleName: "",
966
+ onboardingFinished: false,
967
+ onboardingFinishedAt: null,
968
+ parentPhone: null,
969
+ parentPhoneConfirmed: false,
970
+ phone: null,
971
+ phoneConfirmed: false,
972
+ privacy: {
973
+ publicProfile: false
974
+ },
975
+ profileEnriched: false,
976
+ purchaseAnyExternshipContracts: false,
977
+ recapUuid: null,
978
+ shortName: "",
979
+ skype: null,
980
+ socialNets: [],
981
+ socializationProfile: null,
982
+ tags: null,
983
+ timezone: null,
984
+ type: null,
985
+ webSocketNotificationsJwt: null
986
+ };
987
+
988
+ // src/entities/user/index.ts
989
+ var _User = class _User {
990
+ constructor(props, isDefault = false) {
991
+ this.props = props;
992
+ this.isDefault = isDefault;
993
+ /**
994
+ * Возвращает роль пользователя
995
+ * @returns {UserRole} роль как строка
996
+ */
997
+ this.getRole = () => {
998
+ if (this.isCoach) return "\u0420\u0435\u043F\u0435\u0442\u0438\u0442\u043E\u0440";
999
+ if (this.isAgent) return "\u0423\u0447\u0438\u0442\u0435\u043B\u044C";
1000
+ if (this.isParent) return "\u0420\u043E\u0434\u0438\u0442\u0435\u043B\u044C";
1001
+ switch (this.type) {
1002
+ case "pupil":
1003
+ return this.getPupilRole();
1004
+ case "agent":
1005
+ return "\u0423\u0447\u0438\u0442\u0435\u043B\u044C";
1006
+ default:
1007
+ return "\u0423\u0447\u0435\u043D\u0438\u043A";
1008
+ }
1009
+ };
1010
+ /**
1011
+ * Возвращает фамилию и инициалы юзера
1012
+ * @param {User} user
1013
+ * @return {string} 'Пупкин В.'
1014
+ */
1015
+ this.getInitials = () => {
1016
+ var _a, _b;
1017
+ return `${this.lastName}${this.firstName ? ` ${(_a = this.firstName[0]) == null ? void 0 : _a.toUpperCase()}.` : ""}${this.middleName !== "" && this.middleName !== null ? ` ${(_b = this.middleName[0]) == null ? void 0 : _b.toUpperCase()}.` : ""}`;
1018
+ };
1019
+ }
1020
+ get id() {
1021
+ return this.props.id;
1022
+ }
1023
+ get email() {
1024
+ return this.props.email;
1025
+ }
1026
+ get firstName() {
1027
+ return this.props.firstName;
1028
+ }
1029
+ get middleName() {
1030
+ return this.props.middleName;
1031
+ }
1032
+ get lastName() {
1033
+ return this.props.lastName;
1034
+ }
1035
+ get fullName() {
1036
+ return this.props.fullName;
1037
+ }
1038
+ get shortName() {
1039
+ return this.props.shortName;
1040
+ }
1041
+ get createdAt() {
1042
+ return this.props.createdAt;
1043
+ }
1044
+ get timezone() {
1045
+ return this.props.timezone;
1046
+ }
1047
+ get locale() {
1048
+ return this.props.locale;
1049
+ }
1050
+ get grade() {
1051
+ return this.props.grade;
1052
+ }
1053
+ get phone() {
1054
+ return this.props.phone;
1055
+ }
1056
+ get avatarUrl() {
1057
+ return this.props.avatarUrl;
1058
+ }
1059
+ get isParent() {
1060
+ return this.props.isParent;
1061
+ }
1062
+ get isGraduated() {
1063
+ return this.props.isGraduated;
1064
+ }
1065
+ get gradeChecked() {
1066
+ return this.props.gradeChecked;
1067
+ }
1068
+ get type() {
1069
+ return this.props.type;
1070
+ }
1071
+ get isCoach() {
1072
+ return this.props.isCoach;
1073
+ }
1074
+ get isMiniGroupTeacher() {
1075
+ return this.props.isMiniGroupTeacher;
1076
+ }
1077
+ get isExternshipCoach() {
1078
+ return this.props.isExternshipCoach;
1079
+ }
1080
+ get isAgent() {
1081
+ return this.props.isAgent;
1082
+ }
1083
+ get methodist() {
1084
+ return this.props.methodist;
1085
+ }
1086
+ get address() {
1087
+ return this.props.address;
1088
+ }
1089
+ get socialNets() {
1090
+ return this.props.socialNets;
1091
+ }
1092
+ get skype() {
1093
+ return this.props.skype;
1094
+ }
1095
+ get settings() {
1096
+ return this.props.settings;
1097
+ }
1098
+ get bonus() {
1099
+ return this.props.bonus;
1100
+ }
1101
+ get bonusAmount() {
1102
+ return this.props.bonusAmount;
1103
+ }
1104
+ get hasActivePurchases() {
1105
+ return this.props.hasActivePurchases;
1106
+ }
1107
+ get hasAttemptsSolveExamRehearsals() {
1108
+ return this.props.hasAttemptsSolveExamRehearsals;
1109
+ }
1110
+ get hasBookmarks() {
1111
+ return this.props.hasBookmarks;
1112
+ }
1113
+ get tags() {
1114
+ return this.props.tags;
1115
+ }
1116
+ get cartTemplateId() {
1117
+ return this.props.cartTemplateId;
1118
+ }
1119
+ get cartItemsCount() {
1120
+ return this.props.cartItemsCount;
1121
+ }
1122
+ get onboardingFinished() {
1123
+ return this.props.onboardingFinished;
1124
+ }
1125
+ get onboardingFinishedAt() {
1126
+ return this.props.onboardingFinishedAt;
1127
+ }
1128
+ get emailConfirmed() {
1129
+ return this.props.emailConfirmed;
1130
+ }
1131
+ get phoneConfirmed() {
1132
+ return this.props.phoneConfirmed;
1133
+ }
1134
+ get fakeEmail() {
1135
+ return this.props.fakeEmail;
1136
+ }
1137
+ get fakeUser() {
1138
+ return this.props.fakeUser;
1139
+ }
1140
+ get profileEnriched() {
1141
+ return this.props.profileEnriched;
1142
+ }
1143
+ get recapUuid() {
1144
+ return this.props.recapUuid;
1145
+ }
1146
+ get disciplineIds() {
1147
+ return this.props.disciplineIds;
1148
+ }
1149
+ get privacy() {
1150
+ return this.props.privacy;
1151
+ }
1152
+ get parentPhone() {
1153
+ return this.props.parentPhone;
1154
+ }
1155
+ get parentPhoneConfirmed() {
1156
+ return this.props.parentPhoneConfirmed;
1157
+ }
1158
+ get isCustomer() {
1159
+ return this.props.isCustomer;
1160
+ }
1161
+ get hasAccessToMultiDaysStreaks() {
1162
+ return this.props.hasAccessToMultiDaysStreaks;
1163
+ }
1164
+ get isElementaryPupil() {
1165
+ return this.props.isElementaryPupil;
1166
+ }
1167
+ get webSocketNotificationsJwt() {
1168
+ return this.props.webSocketNotificationsJwt;
1169
+ }
1170
+ get hasAccessToAttestationSheets() {
1171
+ return this.props.hasAccessToAttestationSheets;
1172
+ }
1173
+ get externshipUser() {
1174
+ return this.props.externshipUser;
1175
+ }
1176
+ get hasPurchasedExternshipContracts() {
1177
+ return this.props.hasPurchasedExternshipContracts;
1178
+ }
1179
+ get hasExternshipAttestationAccess() {
1180
+ return this.props.hasExternshipAttestationAccess;
1181
+ }
1182
+ get socializationProfile() {
1183
+ return this.props.socializationProfile;
1184
+ }
1185
+ get freeAccessFinishesAt() {
1186
+ return this.props.freeAccessFinishesAt;
1187
+ }
1188
+ get hasUnseenRoomFeatures() {
1189
+ return this.props.hasUnseenRoomFeatures;
1190
+ }
1191
+ get purchaseAnyExternshipContracts() {
1192
+ return this.props.purchaseAnyExternshipContracts;
1193
+ }
1194
+ /**
1195
+ * Глубокое клонирование объекта с защитой от циклических ссылок
1196
+ * @private
1197
+ * @param obj - объект для клонирования
1198
+ * @param hash - WeakMap для отслеживания уже клонированных объектов
1199
+ * @returns клонированный объект
1200
+ */
1201
+ static deepClone(obj, hash = /* @__PURE__ */ new WeakMap()) {
1202
+ if (obj === null || typeof obj !== "object") {
1203
+ return obj;
1204
+ }
1205
+ if (hash.has(obj)) {
1206
+ return hash.get(obj);
1207
+ }
1208
+ if (obj instanceof Date) {
1209
+ return new Date(obj.getTime());
1210
+ }
1211
+ if (obj instanceof RegExp) {
1212
+ return new RegExp(obj.source, obj.flags);
1213
+ }
1214
+ if (Array.isArray(obj)) {
1215
+ const clonedArr = [];
1216
+ hash.set(obj, clonedArr);
1217
+ obj.forEach((item, index) => {
1218
+ clonedArr[index] = this.deepClone(item, hash);
1219
+ });
1220
+ return clonedArr;
1221
+ }
1222
+ const clonedObj = Object.create(Object.getPrototypeOf(obj));
1223
+ hash.set(obj, clonedObj);
1224
+ Object.keys(obj).forEach((key) => {
1225
+ clonedObj[key] = this.deepClone(obj[key], hash);
1226
+ });
1227
+ return clonedObj;
1228
+ }
1229
+ static createDefault() {
1230
+ return new _User(this.deepClone(DEFAULT_USER), true);
1231
+ }
1232
+ /**
1233
+ * Санитизирует строку: удаляет null-байты и обрезает пробелы
1234
+ * @private
1235
+ * @param str - исходная строка
1236
+ * @returns санитизированная строка
1237
+ */
1238
+ static sanitizeString(str) {
1239
+ if (typeof str !== "string") {
1240
+ console.warn("[User] Invalid string type:", typeof str);
1241
+ return String(str);
1242
+ }
1243
+ return str.replace(/\x00/g, "").trim();
1244
+ }
1245
+ static fromApi(input) {
1246
+ const sanitizedData = this.sanitizeUserData(this.deepClone(input));
1247
+ return new _User(sanitizedData);
1248
+ }
1249
+ /**
1250
+ * Санитизирует данные пользователя
1251
+ * @private
1252
+ * @param data - исходные данные
1253
+ * @returns санитизированные данные
1254
+ */
1255
+ static sanitizeUserData(data) {
1256
+ return __spreadProps(__spreadValues({}, data), {
1257
+ email: this.sanitizeString(data.email),
1258
+ firstName: this.sanitizeString(data.firstName),
1259
+ fullName: this.sanitizeString(data.fullName),
1260
+ lastName: this.sanitizeString(data.lastName),
1261
+ middleName: data.middleName ? this.sanitizeString(data.middleName) : data.middleName,
1262
+ shortName: this.sanitizeString(data.shortName)
1263
+ });
1264
+ }
1265
+ isDefaultUser() {
1266
+ return this.isDefault;
1267
+ }
1268
+ isLoggedIn() {
1269
+ return this.id && this.id > 0 ? true : false;
1270
+ }
1271
+ /**
1272
+ * Возвращает тектовое представление роли / класса пользователя
1273
+ *
1274
+ * @returns {UserRole}
1275
+ */
1276
+ getPupilRole() {
1277
+ if (this.grade.index === 0) {
1278
+ return "\u0414\u043E\u0448\u043A\u043E\u043B\u044C\u043D\u0438\u043A";
1279
+ }
1280
+ if (this.grade.index == null) return "\u0412\u044B\u043F\u0443\u0441\u043A\u043D\u0438\u043A";
1281
+ return _User.getGradeString(this.grade.index);
1282
+ }
1283
+ toJson() {
1284
+ return JSON.stringify(this.props);
1285
+ }
1286
+ };
1287
+ _User.getGradeString = (index) => GRADE_MAP[index] || GRADE_MAP[1];
1288
+ var User = _User;
1289
+
1290
+ // src/errors/login-error.ts
1291
+ var LogginError = class extends Error {
1292
+ constructor(message, options) {
1293
+ super(message);
1294
+ this.name = "LogginError";
1295
+ this.cause = options == null ? void 0 : options.cause;
1296
+ }
1297
+ };
1298
+
1299
+ // src/errors/confirmation-code-error.ts
1300
+ var ConfirmationCodeRequestError = class extends Error {
1301
+ constructor(message, options) {
1302
+ super(message);
1303
+ this.name = "ConfirmationCodeRequestError";
1304
+ this.cause = options == null ? void 0 : options.cause;
1305
+ }
1306
+ };
1307
+
1308
+ // src/services/user.ts
1309
+ var UserService = class {
1310
+ constructor(apiInstance, appOptionsService) {
1311
+ this.api = apiInstance;
1312
+ this.appOptionsService = appOptionsService;
1313
+ }
1314
+ /**
1315
+ * Create user instance
1316
+ * @param {UserDTO} data data of user
1317
+ */
1318
+ static createUser(data) {
1319
+ return User.fromApi(data);
1320
+ }
1321
+ /**
1322
+ * Create default user
1323
+ * @returns {User}
1324
+ */
1325
+ static createDefaultUser() {
1326
+ return User.createDefault();
1327
+ }
1328
+ /**
1329
+ * Get current user data
1330
+ * @return {Promise} Server response with user data
1331
+ */
1332
+ getUser() {
1333
+ return __async(this, null, function* () {
1334
+ try {
1335
+ const data = yield this.api.get("/api/user/me").then(({ data: data2 }) => data2);
1336
+ const user = User.fromApi(data);
1337
+ return user;
1338
+ } catch (e) {
1339
+ return User.createDefault();
1340
+ }
1341
+ });
1342
+ }
1343
+ /**
1344
+ * Логин или регистрация юзера по email
1345
+ * @param email email юзера
1346
+ * @param password пароль
1347
+ * @returns {Promise<{ user: User; result: LoginOrRegistrationResponse }>}
1348
+ */
1349
+ loginByEmail(email, password) {
1350
+ return __async(this, null, function* () {
1351
+ const data = yield this.api.post("/api/email_registration", {
1352
+ email,
1353
+ password
1354
+ }).then(({ data: data2 }) => data2);
1355
+ const user = yield this.getUser();
1356
+ return { result: data, user };
1357
+ });
1358
+ }
1359
+ /**
1360
+ * Запрос кода на подтвеждение телефона
1361
+ */
1362
+ getConfirmationCode(phone) {
1363
+ return __async(this, null, function* () {
1364
+ const appOptions = yield this.appOptionsService.getCurrentAppOptions();
1365
+ try {
1366
+ const payload = {
1367
+ phone,
1368
+ type: appOptions.phoneConfirmationType
1369
+ };
1370
+ const confirm = yield this.api.post("/api/phone_confirmation_codes", payload);
1371
+ return confirm;
1372
+ } catch (error) {
1373
+ throw new ConfirmationCodeRequestError("\u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u044F \u043A\u043E\u0434\u0430 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F", { cause: error });
1374
+ }
1375
+ });
1376
+ }
1377
+ /**
1378
+ * Логин или регистрация юзера по телефону
1379
+ * @param phone номер телефона
1380
+ * @param params
1381
+ * @returns {Promise<{ user: User; result: LoginOrRegistrationResponse }>}
1382
+ */
1383
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1384
+ loginByPhone(phone, params) {
1385
+ return __async(this, null, function* () {
1386
+ const appOptions = yield this.appOptionsService.getCurrentAppOptions();
1387
+ const phoneCheck = yield this.api.post("/api/phone_check", { phone });
1388
+ if (phoneCheck.data.state === "not_confirmed") {
1389
+ if (phoneCheck.data.fakeEmail === false) {
1390
+ let checkMethod = "email";
1391
+ const email = yield params.onEmailRequest(phoneCheck.data);
1392
+ try {
1393
+ yield this.api.post("/api/phone_check/verification", {
1394
+ check_method: checkMethod,
1395
+ email,
1396
+ phone,
1397
+ type: appOptions.phoneConfirmationType
1398
+ });
1399
+ } catch (e) {
1400
+ checkMethod = "name";
1401
+ }
1402
+ try {
1403
+ if (checkMethod === "name") {
1404
+ const { first_name, last_name } = yield params.onNameRequest();
1405
+ yield this.api.post("/api/phone_check/verification", {
1406
+ check_method: "name",
1407
+ first_name,
1408
+ last_name,
1409
+ phone,
1410
+ type: appOptions.phoneConfirmationType
1411
+ });
1412
+ }
1413
+ } catch (error) {
1414
+ throw new LogginError("\u041E\u0448\u0438\u0431\u043A\u0430 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438", { cause: error });
1415
+ }
1416
+ }
1417
+ }
1418
+ let confirm;
1419
+ try {
1420
+ confirm = yield this.getConfirmationCode(phone);
1421
+ params.onConfirmationCodeResponse(confirm.data);
1422
+ } catch (error) {
1423
+ throw new LogginError("\u041E\u0448\u0438\u0431\u043A\u0430 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438", { cause: error });
1424
+ }
1425
+ if (!confirm) return void 0;
1426
+ const code = yield params.onCodeRequest();
1427
+ let token;
1428
+ try {
1429
+ const resultConfirmation = yield this.api.post("/api/phone_confirmations", {
1430
+ code,
1431
+ phone
1432
+ });
1433
+ token = resultConfirmation.data.verificationToken;
1434
+ } catch (error) {
1435
+ params.onConfirmationCodeError(error);
1436
+ }
1437
+ const data = yield this.api.post("/api/phone_registration", {
1438
+ phone,
1439
+ phone_verification_token: token
1440
+ }).then(({ data: data2 }) => data2);
1441
+ const user = yield this.getUser();
1442
+ return { result: data, user };
1443
+ });
1444
+ }
1445
+ /**
1446
+ * Получение покупок текущего пользователя
1447
+ * @param {Number} params.resourceId Resource ID
1448
+ * @param {String} params.resourceType Resource type
1449
+ * @return {Promise} Server response with user purchases
1450
+ */
1451
+ purchases(_0) {
1452
+ return __async(this, arguments, function* ({ resourceId, resourceType }) {
1453
+ if (resourceId && typeof resourceId !== "number") {
1454
+ throw new Error("resourceId must be a number");
1455
+ }
1456
+ if (resourceType && typeof resourceType !== "string") {
1457
+ throw new Error("resourceType must be a string");
1458
+ }
1459
+ const params = [];
1460
+ if (resourceId) params.push(`resource_id=${encodeURIComponent(resourceId)}`);
1461
+ if (resourceType) params.push(`resource_type=${encodeURIComponent(resourceType)}`);
1462
+ const query = params.length ? `?${params.join("&")}` : "";
1463
+ const { data } = yield this.api.get(`/api/user/purchases${query}`);
1464
+ return data;
1465
+ });
1466
+ }
1467
+ /**
1468
+ * Навигация на страницу входа и перенаправление на указанный путь после успешного входа.
1469
+ * @param {String} options.redirectUrl URL для редиректа.
1470
+ */
1471
+ // eslint-disable-next-line @typescript-eslint/class-methods-use-this
1472
+ signIn({ redirectUrl = void 0 }) {
1473
+ if (redirectUrl && typeof redirectUrl !== "string") {
1474
+ throw new Error("redirectUrl must be a string");
1475
+ }
1476
+ let url = `${FOXFORD_HOST}/user/registration?redirect_url=`;
1477
+ if (redirectUrl) url += encodeURIComponent(document.location.href);
1478
+ document.location.href = url;
1479
+ }
1480
+ /**
1481
+ * Выход из аккаунта с перезагрузкой страницы
1482
+ */
1483
+ signOut(reloadAfter = true) {
1484
+ return __async(this, null, function* () {
1485
+ const data = yield this.api.delete(`/user/log_out`);
1486
+ if (reloadAfter) window.location.reload();
1487
+ return data;
1488
+ });
1489
+ }
1490
+ pushEvent(event) {
1491
+ return __async(this, null, function* () {
1492
+ yield this.api.post(`/api/user/event`, {
1493
+ event
1494
+ });
1495
+ });
1496
+ }
1497
+ /**
1498
+ * Установить подписку пользователю
1499
+ * @param {CommunicationSubscriptions} subscriptions пользовательские подписки
1500
+ */
1501
+ setSubscriptions(subscriptions) {
1502
+ return __async(this, null, function* () {
1503
+ yield this.api.put(`/api/user/communication_subscriptions`, {
1504
+ communication_subscriptions: subscriptions
1505
+ });
1506
+ });
1507
+ }
1508
+ /**
1509
+ * Получение интересов пользователя
1510
+ */
1511
+ getUserInterests() {
1512
+ return __async(this, null, function* () {
1513
+ const { data } = yield this.api.get("/api/user/user_interest");
1514
+ return data;
1515
+ });
1516
+ }
1517
+ /**
1518
+ * Обновление интересов пользователя
1519
+ * @param {Partial<UserInterests>} data интересы пользователя
1520
+ */
1521
+ updateUserInterests(data) {
1522
+ return __async(this, null, function* () {
1523
+ yield this.api.put("/api/user/user_interest", { user_interest: decamelize(data) });
1524
+ });
1525
+ }
1526
+ /**
1527
+ * Обновления множества интересов пользователя
1528
+ * @param {Partial<UserInterests>} data интересы пользователя
1529
+ */
1530
+ updateMultipleUserInterests(data) {
1531
+ return __async(this, null, function* () {
1532
+ yield this.api.put("/api/user/user_interest", { user_interests: data.map((i) => decamelize(i)) });
1533
+ });
1534
+ }
1535
+ };
1536
+
1537
+ // src/utils/merge.ts
1538
+ function isObject(item) {
1539
+ return Boolean(item) && typeof item === "object" && !Array.isArray(item);
1540
+ }
1541
+ function mergeDeep(target, ...sources) {
1542
+ if (!sources.length) return target;
1543
+ const output = Object.assign({}, target);
1544
+ const source = sources.shift();
1545
+ if (isObject(target) && isObject(source)) {
1546
+ for (const key in source) {
1547
+ if (isObject(source[key])) {
1548
+ if (!(key in target)) {
1549
+ Object.assign(output, { [key]: source[key] });
1550
+ } else {
1551
+ output[key] = mergeDeep(target[key], source[key]);
1552
+ }
1553
+ } else {
1554
+ Object.assign(output, { [key]: source[key] });
1555
+ }
1556
+ }
1557
+ }
1558
+ return output;
1559
+ }
1560
+
1561
+ // src/services/widgets.ts
1562
+ var _Widgets = class _Widgets {
1563
+ constructor(config = _Widgets.DEFAULT_CONFIG, apiInstance) {
1564
+ this.manifest = null;
1565
+ this.config = mergeDeep(_Widgets.DEFAULT_CONFIG, config);
1566
+ this.api = apiInstance;
1567
+ }
1568
+ create(config) {
1569
+ return __async(this, null, function* () {
1570
+ if (!config) throw new Error("You must specify config for creating widgets");
1571
+ yield this.loadManifest();
1572
+ yield this.loadAssets();
1573
+ if (!window.Foxford || !window.Foxford.Widgets) throw new Error("FoxfordWidgets not found in global scope");
1574
+ if (typeof window.Foxford.Widgets.create !== "function")
1575
+ throw new Error("Not found function create in FoxfordWidgets library");
1576
+ window.Foxford.Widgets.create(config);
1577
+ });
1578
+ }
1579
+ // Публичный метод у инстанса
1580
+ // eslint-disable-next-line @typescript-eslint/class-methods-use-this
1581
+ update(name, config) {
1582
+ return __async(this, null, function* () {
1583
+ if (window.Foxford && window.Foxford.Widgets) window.Foxford.Widgets.update(name, config);
1584
+ });
1585
+ }
1586
+ loadManifest() {
1587
+ return __async(this, null, function* () {
1588
+ const url = `https://dist.ngcdn.ru/libs/foxford-widgets/${this.config.version}/manifest.json`;
1589
+ const response = yield this.api.get(url);
1590
+ this.manifest = response.data;
1591
+ });
1592
+ }
1593
+ static appendScript(src) {
1594
+ return __async(this, null, function* () {
1595
+ return new Promise((resolve, reject) => {
1596
+ const script = document.createElement("script");
1597
+ script.type = "text/javascript";
1598
+ script.defer = true;
1599
+ script.onload = () => resolve(true);
1600
+ script.onerror = (event) => reject(event);
1601
+ script.src = src;
1602
+ document.body.appendChild(script);
1603
+ });
1604
+ });
1605
+ }
1606
+ loadAssets() {
1607
+ return __async(this, null, function* () {
1608
+ if (!this.config.version) this.config.version = "latest";
1609
+ yield Promise.all(
1610
+ _Widgets.ENTRY.map((entry) => {
1611
+ if (!this.manifest) return Promise.resolve;
1612
+ const src = this.manifest[entry];
1613
+ if (!src) return Promise.resolve;
1614
+ return _Widgets.appendScript(`https://dist.ngcdn.ru/libs/foxford-widgets/${this.config.version}/${src}`).then(
1615
+ (res) => res
1616
+ );
1617
+ })
1618
+ );
1619
+ });
1620
+ }
1621
+ };
1622
+ _Widgets.ENTRY = ["vendors~react.js", "vendors~ui.js", "main.js"];
1623
+ _Widgets.DEFAULT_CONFIG = {
1624
+ locale: "ru",
1625
+ version: "latest"
1626
+ };
1627
+ var Widgets = _Widgets;
1628
+
1629
+ // src/foxford.ts
1630
+ var _Foxford = class _Foxford {
1631
+ constructor(config = _Foxford.DEFAULT_CONFIG) {
1632
+ var _a, _b, _c, _d;
1633
+ this.config = mergeDeep(_Foxford.DEFAULT_CONFIG, config);
1634
+ this.foxApi = this.buildFoxApi();
1635
+ this.api = import_services2.ApiService.createApiInstance({ config: apiBaseConfig });
1636
+ this.staticApi = import_services2.ApiService.createStaticApiInstance();
1637
+ this.appOptions = new AppOptionsService(this.foxApi, _Foxford.events.FETCH_APP_OPTIONS);
1638
+ this.user = new UserService(this.foxApi, this.appOptions);
1639
+ this.promo = new PromoService(this.foxApi);
1640
+ this.tag = new TagService(this.foxApi);
1641
+ this.cart = new CartService(this.foxApi);
1642
+ this.course = new CourseService(this.foxApi);
1643
+ this.widgets = new Widgets(
1644
+ __spreadValues({
1645
+ version: this.config.widgetsVersion
1646
+ }, this.config.widgetsConfig),
1647
+ this.api
1648
+ );
1649
+ this.productPack = new ProductPackService(this.foxApi);
1650
+ this.leadrequest = new LeadRequestService(this.foxApi);
1651
+ this.captcha = new import_services2.CaptchaService(
1652
+ typeof ((_a = this.config) == null ? void 0 : _a.captchaConfig) === "function" ? (_b = this.config) == null ? void 0 : _b.captchaConfig() : (_d = (_c = this.config) == null ? void 0 : _c.captchaConfig) != null ? _d : {}
1653
+ );
1654
+ if (this.config.antibot === true) {
1655
+ new FoxfordAntibot(this.config.antibotConfig);
1656
+ }
1657
+ }
1658
+ buildFoxApi() {
1659
+ var _a, _b, _c, _d;
1660
+ const apiConfig2 = ((_a = this.config) == null ? void 0 : _a.api) || { config: {} };
1661
+ const captchaConfig = (_b = this.config) == null ? void 0 : _b.captchaConfig;
1662
+ const apiInstance = import_services2.ApiService.createFoxApiInstance({
1663
+ config: apiConfig2.config,
1664
+ plugins: getPlugins(apiConfig2, captchaConfig)
1665
+ });
1666
+ if (!((_d = (_c = this.config) == null ? void 0 : _c.api) == null ? void 0 : _d.config.baseURL) && this.config.host) apiInstance.defaults.baseURL = this.config.host;
1667
+ return apiInstance;
1668
+ }
1669
+ /**
1670
+ * Get short link
1671
+ * @param {string} url link for shortening
1672
+ */
1673
+ shortURL(url) {
1674
+ return this.foxApi.post(`/api/short_urls`, {
1675
+ link: url
1676
+ }).then((data) => data);
1677
+ }
1678
+ /**
1679
+ * Applies and throwing itself into plugin for access to Api
1680
+ * @param {SdkPlugin} plugin Plugin to apply
1681
+ */
1682
+ applyPlugin(plugin) {
1683
+ plugin.apply(this);
1684
+ }
1685
+ };
1686
+ _Foxford.events = {
1687
+ FETCH_APP_OPTIONS: "Foxford.app_options.fetch",
1688
+ LR_REGISTRATION_SET
1689
+ };
1690
+ _Foxford.DEFAULT_CONFIG = {
1691
+ antibot: true,
1692
+ api: {
1693
+ config: apiConfig
1694
+ },
1695
+ host: FOXFORD_HOST,
1696
+ widgetsConfig: {
1697
+ locale: "ru",
1698
+ version: "latest"
1699
+ },
1700
+ widgetsVersion: "latest"
1701
+ };
1702
+ var Foxford = _Foxford;
1703
+
1704
+ // src/analytics/external/abstract.external.ts
1705
+ var ExternalScript = class _ExternalScript {
1706
+ constructor(analytics) {
1707
+ this.sendCallstack = [];
1708
+ this.ready = false;
1709
+ this.analytics = analytics;
1710
+ }
1711
+ static appendScript(src) {
1712
+ return new Promise((resolve, reject) => {
1713
+ const script = document.createElement("script");
1714
+ script.type = "text/javascript";
1715
+ script.defer = true;
1716
+ script.onload = () => resolve(true);
1717
+ script.onerror = (event) => reject(event);
1718
+ script.src = src;
1719
+ document.body.appendChild(script);
1720
+ });
1721
+ }
1722
+ load() {
1723
+ return __async(this, null, function* () {
1724
+ if (!this.url) return;
1725
+ try {
1726
+ if (!this.ready) yield _ExternalScript.appendScript(this.url);
1727
+ this.ready = true;
1728
+ } catch (error) {
1729
+ console.error(error);
1730
+ }
1731
+ });
1732
+ }
1733
+ send(payload, forced) {
1734
+ return __async(this, null, function* () {
1735
+ if (!this.analytics.__isInitialized__ && !forced) {
1736
+ this.sendCallstack.push(payload);
1737
+ return Promise.resolve();
1738
+ }
1739
+ return yield this.sendHandler(payload);
1740
+ });
1741
+ }
1742
+ sendForce(_payload) {
1743
+ return __async(this, null, function* () {
1744
+ yield this.load();
1745
+ return yield this.send(_payload, true);
1746
+ });
1747
+ }
1748
+ runSendCallstack() {
1749
+ this.sendCallstack.forEach((payload) => this.send(payload));
1750
+ this.sendCallstack = [];
1751
+ }
1752
+ };
1753
+
1754
+ // src/analytics/index.ts
1755
+ var initObj = { __isInitialized__: false };
1756
+ var Analytics = {
1757
+ initGlobal() {
1758
+ return __async(this, null, function* () {
1759
+ if (initObj.__isInitialized__) return;
1760
+ initObj.__isInitialized__ = true;
1761
+ Object.values(this).forEach((provider) => {
1762
+ if (!(provider instanceof ExternalScript)) return;
1763
+ provider.load();
1764
+ provider.runSendCallstack();
1765
+ });
1766
+ });
1767
+ }
1768
+ };
1769
+
1770
+ // src/index.ts
1771
+ var import_services3 = require("@foxford/services");
1772
+ // Annotate the CommonJS export names for ESM import in node:
1773
+ 0 && (module.exports = {
1774
+ Analytics,
1775
+ ApiService,
1776
+ AppOptionsService,
1777
+ CaptchaError,
1778
+ CaptchaService,
1779
+ CartService,
1780
+ CourseService,
1781
+ Foxford,
1782
+ FoxfordAntibot,
1783
+ LeadRequestService,
1784
+ LeadRequestType,
1785
+ ProductPackService,
1786
+ PromoService,
1787
+ RequestPlugin,
1788
+ ResponseFailPlugin,
1789
+ ResponseSuccessPlugin,
1790
+ TagService,
1791
+ User,
1792
+ UserService,
1793
+ Widgets
1794
+ });