@bitrix24/b24jssdk 0.1.6 → 0.2.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.
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @version @bitrix24/b24jssdk v0.1.6
3
- * @copyright (c) 2024 Bitrix24
2
+ * @version @bitrix24/b24jssdk v0.2.0
3
+ * @copyright (c) 2025 Bitrix24
4
4
  * @licence MIT
5
5
  * @links https://github.com/bitrix24/b24jssdk - GitHub
6
6
  * @links https://bitrix24.github.io/b24jssdk/ - Documentation
@@ -664,7 +664,6 @@ class TextManager {
664
664
  return str;
665
665
  }
666
666
  const matches = str.match(
667
- // eslint-disable-next-line
668
667
  /[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g
669
668
  );
670
669
  if (!matches) {
@@ -1033,75 +1032,42 @@ var RpcMethod = /* @__PURE__ */ ((RpcMethod2) => {
1033
1032
  })(RpcMethod || {});
1034
1033
 
1035
1034
  class Result {
1036
- _errorCollection;
1035
+ _errors;
1037
1036
  _data;
1038
- constructor() {
1039
- this._errorCollection = /* @__PURE__ */ new Set();
1040
- this._data = null;
1037
+ constructor(data) {
1038
+ this._errors = /* @__PURE__ */ new Map();
1039
+ this._data = data ?? null;
1041
1040
  }
1042
- /**
1043
- * Getter for the `isSuccess` property.
1044
- * Checks if the `_errorCollection` is empty to determine success.
1045
- *
1046
- * @returns Whether the operation resulted in success (no errors).
1047
- */
1048
1041
  get isSuccess() {
1049
- return this._errorCollection.size === 0;
1042
+ return this._errors.size === 0;
1043
+ }
1044
+ get errors() {
1045
+ return this._errors;
1050
1046
  }
1051
- /**
1052
- * Sets the data associated with the result.
1053
- *
1054
- * @param data The data to be stored in the result.
1055
- * @returns The current Result object for chaining methods.
1056
- */
1057
1047
  setData(data) {
1058
1048
  this._data = data;
1059
1049
  return this;
1060
1050
  }
1061
- /**
1062
- * Retrieves the data associated with the result.
1063
- *
1064
- * @returns The data stored in the result, if any.
1065
- */
1066
1051
  getData() {
1067
1052
  return this._data;
1068
1053
  }
1069
- /**
1070
- * Adds an error message or Error object to the result.
1071
- *
1072
- * @param error The error message or Error object to be added.
1073
- * @returns The current Result object for chaining methods.
1074
- */
1075
- addError(error) {
1076
- if (error instanceof Error) {
1077
- this._errorCollection.add(error);
1078
- } else {
1079
- this._errorCollection.add(new Error(error.toString()));
1080
- }
1054
+ addError(error, key) {
1055
+ const errorKey = key ?? Text.getUuidRfc4122();
1056
+ const errorObj = typeof error === "string" ? new Error(error) : error;
1057
+ this._errors.set(errorKey, errorObj);
1081
1058
  return this;
1082
1059
  }
1083
- /**
1084
- * Adds multiple errors to the result in a single call.
1085
- *
1086
- * @param errors An array of errors or strings that will be converted to errors.
1087
- * @returns The current Result object for chaining methods.
1088
- */
1089
1060
  addErrors(errors) {
1090
1061
  for (const error of errors) {
1091
- if (error instanceof Error) {
1092
- this._errorCollection.add(error);
1093
- } else {
1094
- this._errorCollection.add(new Error(error.toString()));
1095
- }
1062
+ this.addError(error);
1096
1063
  }
1097
1064
  return this;
1098
1065
  }
1099
- /**
1100
- * Retrieves an iterator for the errors collected in the result.
1101
- * @returns An iterator over the stored Error objects.
1102
- */
1103
1066
  getErrors() {
1104
- return this._errorCollection.values();
1067
+ return this._errors.values();
1068
+ }
1069
+ hasError(key) {
1070
+ return this._errors.has(key);
1105
1071
  }
1106
1072
  /**
1107
1073
  * Retrieves an array of error messages from the collected errors.
@@ -1110,7 +1076,7 @@ class Result {
1110
1076
  * contains the message of a corresponding error object.
1111
1077
  */
1112
1078
  getErrorMessages() {
1113
- return [...this.getErrors()].map((error) => error.message);
1079
+ return Array.from(this._errors.values(), (e) => e.message);
1114
1080
  }
1115
1081
  /**
1116
1082
  * Converts the Result object to a string.
@@ -1118,36 +1084,168 @@ class Result {
1118
1084
  * @returns {string} Returns a string representation of the result operation
1119
1085
  */
1120
1086
  toString() {
1121
- if (this.isSuccess) {
1122
- return `Result (success): data: ${JSON.stringify(this._data)}`;
1087
+ const status = this.isSuccess ? "success" : "failure";
1088
+ const data = this.safeStringify(this._data);
1089
+ return this.isSuccess ? `Result(${status}): ${data}` : `Result(${status}): ${data}
1090
+ Errors: ${this.getErrorMessages().join(", ")}`;
1091
+ }
1092
+ safeStringify(data) {
1093
+ try {
1094
+ return JSON.stringify(data, this.replacer, 2);
1095
+ } catch {
1096
+ return "[Unable to serialize data]";
1123
1097
  }
1124
- return `Result (failure): errors: ${this.getErrorMessages().join(", ")}`;
1098
+ }
1099
+ replacer(_, value) {
1100
+ if (value instanceof Error) {
1101
+ return {
1102
+ name: value.name,
1103
+ message: value.message,
1104
+ stack: value.stack
1105
+ };
1106
+ }
1107
+ return value;
1108
+ }
1109
+ // Static constructors
1110
+ static ok(data) {
1111
+ return new Result(data);
1112
+ }
1113
+ static fail(error, key) {
1114
+ return new Result().addError(error, key);
1125
1115
  }
1126
1116
  }
1127
1117
 
1128
1118
  class AjaxError extends Error {
1129
- cause;
1119
+ code;
1130
1120
  _status;
1131
- _answerError;
1132
- constructor(params) {
1133
- const message = `${params.answerError.error}${params.answerError.errorDescription ? ": " + params.answerError.errorDescription : ""}`;
1121
+ requestInfo;
1122
+ timestamp;
1123
+ originalError;
1124
+ // override cause: null | Error
1125
+ // private _status: number
1126
+ // private _answerError: AnswerError
1127
+ constructor(details) {
1128
+ const message = AjaxError.formatErrorMessage(details);
1134
1129
  super(message);
1135
- this.cause = params.cause || null;
1136
- this.name = this.constructor.name;
1137
- this._status = params.status;
1138
- this._answerError = params.answerError;
1139
- }
1130
+ this.name = "AjaxError";
1131
+ this.code = details.code;
1132
+ this._status = details.status;
1133
+ this.requestInfo = details.requestInfo;
1134
+ this.originalError = details.originalError;
1135
+ this.timestamp = /* @__PURE__ */ new Date();
1136
+ this.cleanErrorStack();
1137
+ }
1138
+ // constructor(params: AjaxErrorParams) {
1139
+ // const message = `${ params.answerError.error }${
1140
+ // params.answerError.errorDescription
1141
+ // ? ': ' + params.answerError.errorDescription
1142
+ // : ''
1143
+ // }`
1144
+ //
1145
+ // super(message)
1146
+ // this.cause = params.cause || null
1147
+ // this.name = this.constructor.name
1148
+ //
1149
+ // this._status = params.status
1150
+ // this._answerError = params.answerError
1151
+ // }
1152
+ /**
1153
+ * @deprecated
1154
+ */
1140
1155
  get answerError() {
1141
- return this._answerError;
1156
+ return {
1157
+ error: this.message,
1158
+ errorDescription: ""
1159
+ };
1142
1160
  }
1143
1161
  get status() {
1144
1162
  return this._status;
1145
1163
  }
1164
+ /**
1165
+ * @deprecated
1166
+ */
1146
1167
  set status(status) {
1147
1168
  this._status = status;
1148
1169
  }
1170
+ /**
1171
+ * Creates AjaxError from HTTP response
1172
+ */
1173
+ static fromResponse(response) {
1174
+ return new AjaxError({
1175
+ code: response.data?.error || "unknown_error",
1176
+ description: response.data?.error_description,
1177
+ status: response.status,
1178
+ requestInfo: {
1179
+ method: response.config?.method?.toUpperCase(),
1180
+ url: response.config?.url,
1181
+ params: response.config?.params
1182
+ }
1183
+ });
1184
+ }
1185
+ /**
1186
+ * Creates AjaxError from exception
1187
+ */
1188
+ static fromException(error, context) {
1189
+ if (error instanceof AjaxError) return error;
1190
+ return new AjaxError({
1191
+ code: context?.code || "internal_error",
1192
+ status: context?.status || 500,
1193
+ description: error instanceof Error ? error.message : String(error),
1194
+ requestInfo: context?.requestInfo,
1195
+ originalError: error
1196
+ });
1197
+ }
1198
+ /**
1199
+ * Serializes error for logging and debugging
1200
+ */
1201
+ toJSON() {
1202
+ return {
1203
+ name: this.name,
1204
+ code: this.code,
1205
+ message: this.message,
1206
+ status: this._status,
1207
+ timestamp: this.timestamp.toISOString(),
1208
+ requestInfo: this.requestInfo,
1209
+ stack: this.stack
1210
+ };
1211
+ }
1212
+ // override toString(): string {
1213
+ // return `${ this.answerError.error }${
1214
+ // this.answerError.errorDescription
1215
+ // ? ': ' + this.answerError.errorDescription
1216
+ // : ''
1217
+ // } (${ this.status })`
1218
+ // }
1219
+ /**
1220
+ * Formats error information for human-readable output
1221
+ */
1149
1222
  toString() {
1150
- return `${this.answerError.error}${this.answerError.errorDescription ? ": " + this.answerError.errorDescription : ""} (${this.status})`;
1223
+ let output = `[${this.name}] ${this.code} (${this._status}): ${this.message}`;
1224
+ if (this.requestInfo) {
1225
+ output += `
1226
+ Request: ${this.requestInfo.method} ${this.requestInfo.url}`;
1227
+ }
1228
+ if (this.stack) {
1229
+ output += `
1230
+ Stack trace:
1231
+ ${this.stack}`;
1232
+ }
1233
+ return output;
1234
+ }
1235
+ static formatErrorMessage(details) {
1236
+ const parts = [details.code];
1237
+ if (details.description) {
1238
+ parts.push(`- ${details.description}`);
1239
+ }
1240
+ if (details.requestInfo?.method && details.requestInfo.url) {
1241
+ parts.push(`(on ${details.requestInfo.method} ${details.requestInfo.url})`);
1242
+ }
1243
+ return parts.join(" ");
1244
+ }
1245
+ cleanErrorStack() {
1246
+ if (typeof this.stack === "string") {
1247
+ this.stack = this.stack.split("\n").filter((line) => !line.includes("AjaxError.constructor")).join("\n");
1248
+ }
1151
1249
  }
1152
1250
  }
1153
1251
 
@@ -1155,31 +1253,48 @@ class AjaxResult extends Result {
1155
1253
  _status;
1156
1254
  _query;
1157
1255
  _data;
1158
- constructor(answer, query, status) {
1256
+ constructor(options) {
1159
1257
  super();
1160
- this._data = answer;
1161
- this._query = structuredClone(query);
1162
- this._status = status;
1163
- if (typeof this._data.error !== "undefined") {
1164
- const error = typeof this._data.error === "string" ? this._data : this._data.error;
1165
- this.addError(
1166
- new AjaxError({
1167
- status: this._status,
1168
- answerError: {
1169
- error: error.error || "",
1170
- errorDescription: error.error_description || ""
1171
- }
1172
- })
1173
- );
1174
- }
1175
- }
1176
- // @ts-ignore
1177
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1178
- setData(data) {
1179
- throw new Error("AjaxResult not support setData()");
1258
+ this._data = Object.freeze(options.answer);
1259
+ this._query = Object.freeze(structuredClone(options.query));
1260
+ this._status = options.status;
1261
+ this.#processErrors();
1262
+ }
1263
+ #processErrors() {
1264
+ const { error } = this._data;
1265
+ if (!error) return;
1266
+ const errorParams = this.#normalizeError(error);
1267
+ this.addError(this.#createAjaxError(errorParams), "base-error");
1268
+ }
1269
+ #normalizeError(error) {
1270
+ return typeof error === "string" ? { code: error, description: this._data.error_description || "" } : { code: error.error, description: error.error_description || "" };
1271
+ }
1272
+ #createAjaxError(params) {
1273
+ return new AjaxError({
1274
+ code: String(this._status),
1275
+ description: params.description,
1276
+ status: this._status,
1277
+ requestInfo: {
1278
+ method: this._query.method,
1279
+ // url: '?',
1280
+ params: this._query.params
1281
+ }
1282
+ // request:
1283
+ });
1180
1284
  }
1181
1285
  getData() {
1182
- return this._data;
1286
+ return Object.freeze({
1287
+ result: this._data.result,
1288
+ next: this._data.next,
1289
+ total: this._data.total,
1290
+ time: this._data.time
1291
+ });
1292
+ }
1293
+ /**
1294
+ * Alias for isMore
1295
+ */
1296
+ hasMore() {
1297
+ return this.isMore();
1183
1298
  }
1184
1299
  isMore() {
1185
1300
  return Type.isNumber(this._data?.next);
@@ -1193,16 +1308,35 @@ class AjaxResult extends Result {
1193
1308
  getQuery() {
1194
1309
  return this._query;
1195
1310
  }
1196
- async getNext(http) {
1197
- if (this.isMore() && this.isSuccess) {
1198
- this._query.start = Number.parseInt(this._data?.next);
1199
- return http.call(
1200
- this._query.method,
1201
- this._query.params,
1202
- this._query.start
1203
- );
1311
+ /**
1312
+ * Alias for getNext
1313
+ * @param http
1314
+ */
1315
+ async fetchNext(http) {
1316
+ const data = await this.getNext(http);
1317
+ if (data === false) {
1318
+ return null;
1204
1319
  }
1205
- return Promise.resolve(false);
1320
+ return data;
1321
+ }
1322
+ async getNext(http) {
1323
+ if (!this.isMore() || !this.isSuccess) return false;
1324
+ const nextPageQuery = this.#buildNextPageQuery();
1325
+ return http.call(
1326
+ nextPageQuery.method,
1327
+ nextPageQuery.params,
1328
+ nextPageQuery.start
1329
+ );
1330
+ }
1331
+ #buildNextPageQuery() {
1332
+ return {
1333
+ ...this._query,
1334
+ start: Text.toInteger(this._data.next)
1335
+ };
1336
+ }
1337
+ // Immutable API
1338
+ setData() {
1339
+ throw new ReferenceError("AjaxResult does not allow data modification");
1206
1340
  }
1207
1341
  }
1208
1342
 
@@ -1389,33 +1523,37 @@ class Http {
1389
1523
  // endregion ////
1390
1524
  // region Actions Call ////
1391
1525
  async batch(calls, isHaltOnError = true) {
1392
- const isArrayMode = Array.isArray(calls);
1393
- const cmd = isArrayMode ? [] : {};
1526
+ if (Array.isArray(calls)) {
1527
+ return this.#batchAsArray(
1528
+ calls,
1529
+ isHaltOnError
1530
+ );
1531
+ }
1532
+ return this.#batchAsObject(
1533
+ calls,
1534
+ isHaltOnError
1535
+ );
1536
+ }
1537
+ async #batchAsObject(calls, isHaltOnError = true) {
1538
+ const cmd = {};
1394
1539
  let cnt = 0;
1395
1540
  const processRow = (row, index) => {
1396
1541
  let method = null;
1397
1542
  let params = null;
1398
- if (Array.isArray(row)) {
1399
- method = row[0];
1400
- params = row[1];
1401
- } else if (row.method) {
1402
- method = row.method;
1403
- params = row.params;
1543
+ if (row.method) {
1544
+ method = row.method ?? null;
1545
+ params = row?.params ?? null;
1546
+ } else if (Array.isArray(row) && row.length > 0) {
1547
+ method = row[0] ?? null;
1548
+ params = row[1] ?? null;
1404
1549
  }
1405
1550
  if (method) {
1406
1551
  cnt++;
1407
- const data = method + "?" + qs.stringify(params);
1408
- if (isArrayMode || Array.isArray(cmd)) {
1409
- cmd.push(data);
1410
- } else {
1411
- cmd[index] = data;
1412
- }
1552
+ cmd[index] = method + "?" + qs.stringify(params);
1413
1553
  }
1414
1554
  };
1415
- if (isArrayMode) {
1416
- for (const [index, item] of calls.entries()) processRow(item, index);
1417
- } else {
1418
- for (const [index, item] of Object.entries(calls)) processRow(item, index);
1555
+ for (const [index, row] of Object.entries(calls)) {
1556
+ processRow(row, index);
1419
1557
  }
1420
1558
  if (cnt < 1) {
1421
1559
  return Promise.resolve(new Result());
@@ -1425,7 +1563,7 @@ class Http {
1425
1563
  cmd
1426
1564
  }).then((response) => {
1427
1565
  const responseResult = response.getData().result;
1428
- const results = isArrayMode ? [] : {};
1566
+ const results = {};
1429
1567
  const processResponse = (row, index) => {
1430
1568
  if (
1431
1569
  // @ts-ignore
@@ -1433,8 +1571,8 @@ class Http {
1433
1571
  typeof responseResult.result_error[index] !== "undefined"
1434
1572
  ) {
1435
1573
  const q = row.split("?");
1436
- const data = new AjaxResult(
1437
- {
1574
+ results[index] = new AjaxResult({
1575
+ answer: {
1438
1576
  // @ts-ignore
1439
1577
  result: Type.isUndefined(responseResult.result[index]) ? (
1440
1578
  // @ts-ignore
@@ -1448,67 +1586,154 @@ class Http {
1448
1586
  // @ts-ignore
1449
1587
  total: responseResult.result_total[index],
1450
1588
  // @ts-ignore
1451
- next: responseResult.result_next[index]
1589
+ next: responseResult.result_next[index],
1590
+ // @todo test this ////
1591
+ // @ts-ignore
1592
+ time: responseResult.result_time[index]
1452
1593
  },
1453
- {
1594
+ query: {
1454
1595
  method: q[0] || "",
1455
1596
  params: qs.parse(q[1] || ""),
1456
1597
  start: 0
1457
1598
  },
1458
- response.getStatus()
1459
- );
1460
- if (isArrayMode || Array.isArray(results)) {
1461
- results.push(data);
1462
- } else {
1463
- results[index] = data;
1464
- }
1599
+ status: response.getStatus()
1600
+ });
1465
1601
  }
1466
1602
  };
1467
- if (Array.isArray(cmd)) {
1468
- for (const [index, item] of cmd.entries()) processResponse(item, index);
1469
- } else {
1470
- for (const [index, item] of Object.entries(cmd))
1471
- processResponse(item, index);
1603
+ for (const [index, row] of Object.entries(cmd)) {
1604
+ processResponse(row, index);
1472
1605
  }
1473
- let dataResult;
1606
+ const dataResult = {};
1474
1607
  const initError = (result2) => {
1608
+ if (result2.hasError("base-error")) {
1609
+ return result2.errors.get("base-error");
1610
+ }
1475
1611
  return new AjaxError({
1612
+ code: "0",
1613
+ description: result2.getErrorMessages().join("; "),
1476
1614
  status: 0,
1477
- answerError: {
1478
- error: result2.getErrorMessages().join("; "),
1479
- errorDescription: `batch ${result2.getQuery().method}: ${qs.stringify(result2.getQuery().params, { encode: false })}`
1615
+ requestInfo: {
1616
+ method: result2.getQuery().method,
1617
+ params: result2.getQuery().params
1480
1618
  },
1481
- cause: result2.getErrors().next().value
1619
+ originalError: result2.getErrors().next().value
1482
1620
  });
1483
1621
  };
1484
1622
  const result = new Result();
1485
- if (isArrayMode || Array.isArray(results)) {
1486
- dataResult = [];
1487
- for (const data of results) {
1488
- if (data.getStatus() !== 200 || !data.isSuccess) {
1489
- const error = initError(data);
1490
- if (!isHaltOnError && !data.isSuccess) {
1491
- result.addError(error);
1492
- continue;
1493
- }
1494
- return Promise.reject(error);
1623
+ for (const key of Object.keys(results)) {
1624
+ const data = results[key];
1625
+ if (data.getStatus() !== 200 || !data.isSuccess) {
1626
+ const error = initError(data);
1627
+ if (!isHaltOnError && !data.isSuccess) {
1628
+ result.addError(error, key);
1629
+ continue;
1495
1630
  }
1496
- dataResult.push(data.getData().result);
1631
+ return Promise.reject(error);
1497
1632
  }
1498
- } else {
1499
- dataResult = {};
1500
- for (const key of Object.keys(results)) {
1501
- const data = results[key];
1502
- if (data.getStatus() !== 200 || !data.isSuccess) {
1503
- const error = initError(data);
1504
- if (!isHaltOnError && !data.isSuccess) {
1505
- result.addError(error);
1506
- continue;
1507
- }
1508
- return Promise.reject(error);
1633
+ dataResult[key] = data.getData().result;
1634
+ }
1635
+ result.setData(dataResult);
1636
+ return Promise.resolve(result);
1637
+ });
1638
+ }
1639
+ async #batchAsArray(calls, isHaltOnError = true) {
1640
+ const cmd = [];
1641
+ let cnt = 0;
1642
+ const processRow = (row) => {
1643
+ let method = null;
1644
+ let params = null;
1645
+ if (row.method) {
1646
+ method = row.method ?? null;
1647
+ params = row?.params ?? null;
1648
+ } else if (Array.isArray(row) && row.length > 0) {
1649
+ method = row[0] ?? null;
1650
+ params = row[1] ?? null;
1651
+ }
1652
+ if (method) {
1653
+ cnt++;
1654
+ const data = method + "?" + qs.stringify(params);
1655
+ cmd.push(data);
1656
+ }
1657
+ };
1658
+ for (const [_, row] of calls.entries()) {
1659
+ processRow(row);
1660
+ }
1661
+ if (cnt < 1) {
1662
+ return Promise.resolve(new Result());
1663
+ }
1664
+ return this.call("batch", {
1665
+ halt: isHaltOnError ? 1 : 0,
1666
+ cmd
1667
+ }).then((response) => {
1668
+ const responseResult = response.getData().result;
1669
+ const results = [];
1670
+ const processResponse = (row, index) => {
1671
+ if (
1672
+ // @ts-ignore
1673
+ typeof responseResult.result[index] !== "undefined" || // @ts-ignore
1674
+ typeof responseResult.result_error[index] !== "undefined"
1675
+ ) {
1676
+ const q = row.split("?");
1677
+ const data = new AjaxResult({
1678
+ answer: {
1679
+ // @ts-ignore
1680
+ result: Type.isUndefined(responseResult.result[index]) ? (
1681
+ // @ts-ignore
1682
+ {}
1683
+ ) : (
1684
+ // @ts-ignore
1685
+ responseResult.result[index]
1686
+ ),
1687
+ // @ts-ignore
1688
+ error: responseResult?.result_error[index] || void 0,
1689
+ // @ts-ignore
1690
+ total: responseResult.result_total[index],
1691
+ // @ts-ignore
1692
+ next: responseResult.result_next[index],
1693
+ // @todo test this ////
1694
+ // @ts-ignore
1695
+ time: responseResult.result_time[index]
1696
+ },
1697
+ query: {
1698
+ method: q[0] || "",
1699
+ params: qs.parse(q[1] || ""),
1700
+ start: 0
1701
+ },
1702
+ status: response.getStatus()
1703
+ });
1704
+ results.push(data);
1705
+ }
1706
+ };
1707
+ for (const [index, row] of cmd.entries()) {
1708
+ processResponse(row, index);
1709
+ }
1710
+ const dataResult = [];
1711
+ const initError = (result2) => {
1712
+ if (result2.hasError("base-error")) {
1713
+ return result2.errors.get("base-error");
1714
+ }
1715
+ return new AjaxError({
1716
+ code: "0",
1717
+ description: result2.getErrorMessages().join("; "),
1718
+ status: 0,
1719
+ requestInfo: {
1720
+ method: result2.getQuery().method,
1721
+ params: result2.getQuery().params
1722
+ },
1723
+ originalError: result2.getErrors().next().value
1724
+ });
1725
+ };
1726
+ const result = new Result();
1727
+ for (const data of results) {
1728
+ if (data.getStatus() !== 200 || !data.isSuccess) {
1729
+ const error = initError(data);
1730
+ if (!isHaltOnError && !data.isSuccess) {
1731
+ result.addError(error);
1732
+ continue;
1509
1733
  }
1510
- dataResult[key] = data.getData().result;
1734
+ return Promise.reject(error);
1511
1735
  }
1736
+ dataResult.push(data.getData().result);
1512
1737
  }
1513
1738
  result.setData(dataResult);
1514
1739
  return Promise.resolve(result);
@@ -1556,9 +1781,14 @@ class Http {
1556
1781
  };
1557
1782
  }
1558
1783
  const problemError = new AjaxError({
1784
+ code: String(answerError.error),
1785
+ description: answerError.errorDescription,
1559
1786
  status: error_.response?.status || 0,
1560
- answerError,
1561
- cause: error_
1787
+ requestInfo: {
1788
+ method,
1789
+ params
1790
+ },
1791
+ originalError: error_
1562
1792
  });
1563
1793
  if (problemError.status === 401 && ["expired_token", "invalid_token"].includes(
1564
1794
  problemError.answerError.error
@@ -1592,9 +1822,14 @@ class Http {
1592
1822
  };
1593
1823
  }
1594
1824
  const problemError2 = new AjaxError({
1595
- status: error__.response?.status || 0,
1596
- answerError: answerError2,
1597
- cause: error__
1825
+ code: String(answerError2.error),
1826
+ description: answerError2.errorDescription,
1827
+ status: error_.response?.status || 0,
1828
+ requestInfo: {
1829
+ method,
1830
+ params
1831
+ },
1832
+ originalError: error__
1598
1833
  });
1599
1834
  return Promise.reject(problemError2);
1600
1835
  }
@@ -1603,15 +1838,15 @@ class Http {
1603
1838
  return Promise.reject(problemError);
1604
1839
  }
1605
1840
  ).then((response) => {
1606
- const result = new AjaxResult(
1607
- response.payload,
1608
- {
1841
+ const result = new AjaxResult({
1842
+ answer: response.payload,
1843
+ query: {
1609
1844
  method,
1610
1845
  params,
1611
1846
  start
1612
1847
  },
1613
- response.status
1614
- );
1848
+ status: response.status
1849
+ });
1615
1850
  return Promise.resolve(result);
1616
1851
  });
1617
1852
  }
@@ -1632,7 +1867,7 @@ class Http {
1632
1867
  result.logTag = this.#logTag;
1633
1868
  }
1634
1869
  result[this.#requestIdGenerator.getQueryStringParameterName()] = this.#requestIdGenerator.getRequestId();
1635
- result[this.#requestIdGenerator.getQueryStringSdkParameterName()] = "0.1.6";
1870
+ result[this.#requestIdGenerator.getQueryStringSdkParameterName()] = "0.2.0";
1636
1871
  if (!!result.data && !!result.data.start) {
1637
1872
  delete result.data.start;
1638
1873
  }
@@ -2786,6 +3021,8 @@ var MessageCommands = /* @__PURE__ */ ((MessageCommands2) => {
2786
3021
  MessageCommands2["selectAccess"] = "selectAccess";
2787
3022
  MessageCommands2["selectCRM"] = "selectCRM";
2788
3023
  MessageCommands2["showAppForm"] = "showAppForm";
3024
+ MessageCommands2["getInterface"] = "getInterface";
3025
+ MessageCommands2["placementBindEvent"] = "placementBindEvent";
2789
3026
  return MessageCommands2;
2790
3027
  })(MessageCommands || {});
2791
3028
 
@@ -3591,9 +3828,11 @@ class SliderManager {
3591
3828
  }
3592
3829
 
3593
3830
  class PlacementManager {
3831
+ #messageManager;
3594
3832
  #title = "";
3595
3833
  #options = {};
3596
- constructor() {
3834
+ constructor(messageManager) {
3835
+ this.#messageManager = messageManager;
3597
3836
  }
3598
3837
  /**
3599
3838
  * Initializes the data received from the parent window message.
@@ -3617,6 +3856,54 @@ class PlacementManager {
3617
3856
  get isSliderMode() {
3618
3857
  return this.options?.IFRAME === "Y";
3619
3858
  }
3859
+ /**
3860
+ * Get Information About the JS Interface of the Current Embedding Location
3861
+ *
3862
+ * @return {Promise<any>}
3863
+ *
3864
+ * @link https://apidocs.bitrix24.com/api-reference/widgets/ui-interaction/bx24-placement-get-interface.html
3865
+ */
3866
+ async getInterface() {
3867
+ return this.#messageManager.send(
3868
+ MessageCommands.getInterface,
3869
+ {
3870
+ isSafely: true
3871
+ }
3872
+ );
3873
+ }
3874
+ /**
3875
+ * Set Up the Interface Event Handler
3876
+ * @param {string} eventName
3877
+ * @return {Promise<any>}
3878
+ *
3879
+ * @link https://apidocs.bitrix24.com/api-reference/widgets/ui-interaction/bx24-placement-bind-event.html
3880
+ */
3881
+ async bindEvent(eventName) {
3882
+ return this.#messageManager.send(
3883
+ MessageCommands.getInterface,
3884
+ {
3885
+ event: eventName,
3886
+ isSafely: true
3887
+ }
3888
+ );
3889
+ }
3890
+ /**
3891
+ * Call the Registered Interface Command
3892
+ * @param {string} command
3893
+ * @param {Record<string, any>} parameters
3894
+ * @return {Promise<any>}
3895
+ *
3896
+ * @link https://apidocs.bitrix24.com/api-reference/widgets/ui-interaction/bx24-placement-call.html
3897
+ */
3898
+ async call(command, parameters = {}) {
3899
+ return this.#messageManager.send(
3900
+ command,
3901
+ {
3902
+ ...parameters,
3903
+ isSafely: true
3904
+ }
3905
+ );
3906
+ }
3620
3907
  }
3621
3908
 
3622
3909
  class B24Frame extends AbstractB24 {
@@ -3644,7 +3931,7 @@ class B24Frame extends AbstractB24 {
3644
3931
  this.#appFrame,
3645
3932
  this.#messageManager
3646
3933
  );
3647
- this.#placementManager = new PlacementManager();
3934
+ this.#placementManager = new PlacementManager(this.#messageManager);
3648
3935
  this._isInit = false;
3649
3936
  }
3650
3937
  setLogger(logger) {
@@ -11552,7 +11839,7 @@ class PullClient {
11552
11839
  }
11553
11840
  if (message.extra.server_time_unix) {
11554
11841
  message.extra.server_time_ago = (Date.now() - message.extra.server_time_unix * 1e3) / 1e3 - (this._config?.server.timeShift || 0);
11555
- message.extra.server_time_ago = message.extra.server_time_ago > 0 ? message.extra.server_time_ago : 0;
11842
+ message.extra.server_time_ago = Math.max(message.extra.server_time_ago, 0);
11556
11843
  }
11557
11844
  this.logMessage(message);
11558
11845
  try {
@@ -12618,7 +12905,7 @@ Data string: ${pullEvent}
12618
12905
  }
12619
12906
  trimDuplicates() {
12620
12907
  if (this._session.lastMessageIds.length > MAX_IDS_TO_STORE) {
12621
- this._session.lastMessageIds = this._session.lastMessageIds.slice(-MAX_IDS_TO_STORE);
12908
+ this._session.lastMessageIds = this._session.lastMessageIds.slice(-10);
12622
12909
  }
12623
12910
  }
12624
12911
  // endregion ////
@@ -12696,19 +12983,19 @@ Data string: ${pullEvent}
12696
12983
  * @deprecated
12697
12984
  */
12698
12985
  /*/
12699
- getRestClientOptions()
12700
- {
12701
- let result = {};
12986
+ getRestClientOptions()
12987
+ {
12988
+ let result = {};
12702
12989
 
12703
- if (this.guestMode && this.guestUserId !== 0)
12704
- {
12705
- result.queryParams = {
12706
- pull_guest_id: this.guestUserId
12707
- }
12708
- }
12709
- return result;
12710
- }
12711
- //*/
12990
+ if (this.guestMode && this.guestUserId !== 0)
12991
+ {
12992
+ result.queryParams = {
12993
+ pull_guest_id: this.guestUserId
12994
+ }
12995
+ }
12996
+ return result;
12997
+ }
12998
+ //*/
12712
12999
  // endregion ////
12713
13000
  }
12714
13001