@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/README.mdx +493 -0
- package/index.cjs +1794 -0
- package/index.d.cts +780 -0
- package/index.d.ts +780 -0
- package/index.js +1748 -0
- package/index.js.flow +1005 -0
- package/package.json +65 -0
- package/plugins/autocomplete-email.cjs +305 -0
- package/plugins/autocomplete-email.d.cts +49 -0
- package/plugins/autocomplete-email.d.ts +49 -0
- package/plugins/autocomplete-email.js +270 -0
- package/plugins/autocomplete-email.js.flow +24 -0
- package/plugins/confirm-phone.cjs +503 -0
- package/plugins/confirm-phone.d.cts +95 -0
- package/plugins/confirm-phone.d.ts +95 -0
- package/plugins/confirm-phone.js +469 -0
- package/plugins/confirm-phone.js.flow +69 -0
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
|
+
});
|