@bitrix24/b24jssdk
Version:
Bitrix24 REST API JavaScript SDK
34,787 lines • 1.2 MB
JavaScript
/**
* @package @bitrix24/b24jssdk
* @version 2.2.0
* @copyright (c) 2026 Bitrix24
* @license MIT
* @see https://github.com/bitrix24/b24jssdk
* @see https://bitrix24.github.io/b24jssdk/
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.B24Js = {}));
})(this, (function (exports) { 'use strict';
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
LogLevel2[LogLevel2["NOTICE"] = 2] = "NOTICE";
LogLevel2[LogLevel2["WARNING"] = 3] = "WARNING";
LogLevel2[LogLevel2["ERROR"] = 4] = "ERROR";
LogLevel2[LogLevel2["CRITICAL"] = 5] = "CRITICAL";
LogLevel2[LogLevel2["ALERT"] = 6] = "ALERT";
LogLevel2[LogLevel2["EMERGENCY"] = 7] = "EMERGENCY";
return LogLevel2;
})(LogLevel || {});
// these aren't really private, but nor are they really useful to document
/**
* @private
*/
class LuxonError extends Error {}
/**
* @private
*/
class InvalidDateTimeError extends LuxonError {
constructor(reason) {
super(`Invalid DateTime: ${reason.toMessage()}`);
}
}
/**
* @private
*/
class InvalidIntervalError extends LuxonError {
constructor(reason) {
super(`Invalid Interval: ${reason.toMessage()}`);
}
}
/**
* @private
*/
class InvalidDurationError extends LuxonError {
constructor(reason) {
super(`Invalid Duration: ${reason.toMessage()}`);
}
}
/**
* @private
*/
class ConflictingSpecificationError extends LuxonError {}
/**
* @private
*/
class InvalidUnitError extends LuxonError {
constructor(unit) {
super(`Invalid unit ${unit}`);
}
}
/**
* @private
*/
class InvalidArgumentError extends LuxonError {}
/**
* @private
*/
class ZoneIsAbstractError extends LuxonError {
constructor() {
super("Zone is an abstract class");
}
}
/**
* @private
*/
const n = "numeric",
s = "short",
l = "long";
const DATE_SHORT = {
year: n,
month: n,
day: n,
};
const DATE_MED = {
year: n,
month: s,
day: n,
};
const DATE_MED_WITH_WEEKDAY = {
year: n,
month: s,
day: n,
weekday: s,
};
const DATE_FULL = {
year: n,
month: l,
day: n,
};
const DATE_HUGE = {
year: n,
month: l,
day: n,
weekday: l,
};
const TIME_SIMPLE = {
hour: n,
minute: n,
};
const TIME_WITH_SECONDS = {
hour: n,
minute: n,
second: n,
};
const TIME_WITH_SHORT_OFFSET = {
hour: n,
minute: n,
second: n,
timeZoneName: s,
};
const TIME_WITH_LONG_OFFSET = {
hour: n,
minute: n,
second: n,
timeZoneName: l,
};
const TIME_24_SIMPLE = {
hour: n,
minute: n,
hourCycle: "h23",
};
const TIME_24_WITH_SECONDS = {
hour: n,
minute: n,
second: n,
hourCycle: "h23",
};
const TIME_24_WITH_SHORT_OFFSET = {
hour: n,
minute: n,
second: n,
hourCycle: "h23",
timeZoneName: s,
};
const TIME_24_WITH_LONG_OFFSET = {
hour: n,
minute: n,
second: n,
hourCycle: "h23",
timeZoneName: l,
};
const DATETIME_SHORT = {
year: n,
month: n,
day: n,
hour: n,
minute: n,
};
const DATETIME_SHORT_WITH_SECONDS = {
year: n,
month: n,
day: n,
hour: n,
minute: n,
second: n,
};
const DATETIME_MED = {
year: n,
month: s,
day: n,
hour: n,
minute: n,
};
const DATETIME_MED_WITH_SECONDS = {
year: n,
month: s,
day: n,
hour: n,
minute: n,
second: n,
};
const DATETIME_MED_WITH_WEEKDAY = {
year: n,
month: s,
day: n,
weekday: s,
hour: n,
minute: n,
};
const DATETIME_FULL = {
year: n,
month: l,
day: n,
hour: n,
minute: n,
timeZoneName: s,
};
const DATETIME_FULL_WITH_SECONDS = {
year: n,
month: l,
day: n,
hour: n,
minute: n,
second: n,
timeZoneName: s,
};
const DATETIME_HUGE = {
year: n,
month: l,
day: n,
weekday: l,
hour: n,
minute: n,
timeZoneName: l,
};
const DATETIME_HUGE_WITH_SECONDS = {
year: n,
month: l,
day: n,
weekday: l,
hour: n,
minute: n,
second: n,
timeZoneName: l,
};
/**
* @interface
*/
class Zone {
/**
* The type of zone
* @abstract
* @type {string}
*/
get type() {
throw new ZoneIsAbstractError();
}
/**
* The name of this zone.
* @abstract
* @type {string}
*/
get name() {
throw new ZoneIsAbstractError();
}
/**
* The IANA name of this zone.
* Defaults to `name` if not overwritten by a subclass.
* @abstract
* @type {string}
*/
get ianaName() {
return this.name;
}
/**
* Returns whether the offset is known to be fixed for the whole year.
* @abstract
* @type {boolean}
*/
get isUniversal() {
throw new ZoneIsAbstractError();
}
/**
* Returns the offset's common name (such as EST) at the specified timestamp
* @abstract
* @param {number} ts - Epoch milliseconds for which to get the name
* @param {Object} opts - Options to affect the format
* @param {string} opts.format - What style of offset to return. Accepts 'long' or 'short'.
* @param {string} opts.locale - What locale to return the offset name in.
* @return {string}
*/
offsetName(ts, opts) {
throw new ZoneIsAbstractError();
}
/**
* Returns the offset's value as a string
* @abstract
* @param {number} ts - Epoch milliseconds for which to get the offset
* @param {string} format - What style of offset to return.
* Accepts 'narrow', 'short', or 'techie'. Returning '+6', '+06:00', or '+0600' respectively
* @return {string}
*/
formatOffset(ts, format) {
throw new ZoneIsAbstractError();
}
/**
* Return the offset in minutes for this zone at the specified timestamp.
* @abstract
* @param {number} ts - Epoch milliseconds for which to compute the offset
* @return {number}
*/
offset(ts) {
throw new ZoneIsAbstractError();
}
/**
* Return whether this Zone is equal to another zone
* @abstract
* @param {Zone} otherZone - the zone to compare
* @return {boolean}
*/
equals(otherZone) {
throw new ZoneIsAbstractError();
}
/**
* Return whether this Zone is valid.
* @abstract
* @type {boolean}
*/
get isValid() {
throw new ZoneIsAbstractError();
}
}
let singleton$1 = null;
/**
* Represents the local zone for this JavaScript environment.
* @implements {Zone}
*/
class SystemZone extends Zone {
/**
* Get a singleton instance of the local zone
* @return {SystemZone}
*/
static get instance() {
if (singleton$1 === null) {
singleton$1 = new SystemZone();
}
return singleton$1;
}
/** @override **/
get type() {
return "system";
}
/** @override **/
get name() {
return new Intl.DateTimeFormat().resolvedOptions().timeZone;
}
/** @override **/
get isUniversal() {
return false;
}
/** @override **/
offsetName(ts, { format, locale }) {
return parseZoneInfo(ts, format, locale);
}
/** @override **/
formatOffset(ts, format) {
return formatOffset(this.offset(ts), format);
}
/** @override **/
offset(ts) {
return -new Date(ts).getTimezoneOffset();
}
/** @override **/
equals(otherZone) {
return otherZone.type === "system";
}
/** @override **/
get isValid() {
return true;
}
}
const dtfCache = new Map();
function makeDTF(zoneName) {
let dtf = dtfCache.get(zoneName);
if (dtf === undefined) {
dtf = new Intl.DateTimeFormat("en-US", {
hour12: false,
timeZone: zoneName,
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
era: "short",
});
dtfCache.set(zoneName, dtf);
}
return dtf;
}
const typeToPos = {
year: 0,
month: 1,
day: 2,
era: 3,
hour: 4,
minute: 5,
second: 6,
};
function hackyOffset(dtf, date) {
const formatted = dtf.format(date).replace(/\u200E/g, ""),
parsed = /(\d+)\/(\d+)\/(\d+) (AD|BC),? (\d+):(\d+):(\d+)/.exec(formatted),
[, fMonth, fDay, fYear, fadOrBc, fHour, fMinute, fSecond] = parsed;
return [fYear, fMonth, fDay, fadOrBc, fHour, fMinute, fSecond];
}
function partsOffset(dtf, date) {
const formatted = dtf.formatToParts(date);
const filled = [];
for (let i = 0; i < formatted.length; i++) {
const { type, value } = formatted[i];
const pos = typeToPos[type];
if (type === "era") {
filled[pos] = value;
} else if (!isUndefined$1(pos)) {
filled[pos] = parseInt(value, 10);
}
}
return filled;
}
const ianaZoneCache = new Map();
/**
* A zone identified by an IANA identifier, like America/New_York
* @implements {Zone}
*/
class IANAZone extends Zone {
/**
* @param {string} name - Zone name
* @return {IANAZone}
*/
static create(name) {
let zone = ianaZoneCache.get(name);
if (zone === undefined) {
ianaZoneCache.set(name, (zone = new IANAZone(name)));
}
return zone;
}
/**
* Reset local caches. Should only be necessary in testing scenarios.
* @return {void}
*/
static resetCache() {
ianaZoneCache.clear();
dtfCache.clear();
}
/**
* Returns whether the provided string is a valid specifier. This only checks the string's format, not that the specifier identifies a known zone; see isValidZone for that.
* @param {string} s - The string to check validity on
* @example IANAZone.isValidSpecifier("America/New_York") //=> true
* @example IANAZone.isValidSpecifier("Sport~~blorp") //=> false
* @deprecated For backward compatibility, this forwards to isValidZone, better use `isValidZone()` directly instead.
* @return {boolean}
*/
static isValidSpecifier(s) {
return this.isValidZone(s);
}
/**
* Returns whether the provided string identifies a real zone
* @param {string} zone - The string to check
* @example IANAZone.isValidZone("America/New_York") //=> true
* @example IANAZone.isValidZone("Fantasia/Castle") //=> false
* @example IANAZone.isValidZone("Sport~~blorp") //=> false
* @return {boolean}
*/
static isValidZone(zone) {
if (!zone) {
return false;
}
try {
new Intl.DateTimeFormat("en-US", { timeZone: zone }).format();
return true;
} catch (e) {
return false;
}
}
constructor(name) {
super();
/** @private **/
this.zoneName = name;
/** @private **/
this.valid = IANAZone.isValidZone(name);
}
/**
* The type of zone. `iana` for all instances of `IANAZone`.
* @override
* @type {string}
*/
get type() {
return "iana";
}
/**
* The name of this zone (i.e. the IANA zone name).
* @override
* @type {string}
*/
get name() {
return this.zoneName;
}
/**
* Returns whether the offset is known to be fixed for the whole year:
* Always returns false for all IANA zones.
* @override
* @type {boolean}
*/
get isUniversal() {
return false;
}
/**
* Returns the offset's common name (such as EST) at the specified timestamp
* @override
* @param {number} ts - Epoch milliseconds for which to get the name
* @param {Object} opts - Options to affect the format
* @param {string} opts.format - What style of offset to return. Accepts 'long' or 'short'.
* @param {string} opts.locale - What locale to return the offset name in.
* @return {string}
*/
offsetName(ts, { format, locale }) {
return parseZoneInfo(ts, format, locale, this.name);
}
/**
* Returns the offset's value as a string
* @override
* @param {number} ts - Epoch milliseconds for which to get the offset
* @param {string} format - What style of offset to return.
* Accepts 'narrow', 'short', or 'techie'. Returning '+6', '+06:00', or '+0600' respectively
* @return {string}
*/
formatOffset(ts, format) {
return formatOffset(this.offset(ts), format);
}
/**
* Return the offset in minutes for this zone at the specified timestamp.
* @override
* @param {number} ts - Epoch milliseconds for which to compute the offset
* @return {number}
*/
offset(ts) {
if (!this.valid) return NaN;
const date = new Date(ts);
if (isNaN(date)) return NaN;
const dtf = makeDTF(this.name);
let [year, month, day, adOrBc, hour, minute, second] = dtf.formatToParts
? partsOffset(dtf, date)
: hackyOffset(dtf, date);
if (adOrBc === "BC") {
year = -Math.abs(year) + 1;
}
// because we're using hour12 and https://bugs.chromium.org/p/chromium/issues/detail?id=1025564&can=2&q=%2224%3A00%22%20datetimeformat
const adjustedHour = hour === 24 ? 0 : hour;
const asUTC = objToLocalTS({
year,
month,
day,
hour: adjustedHour,
minute,
second,
millisecond: 0,
});
let asTS = +date;
const over = asTS % 1000;
asTS -= over >= 0 ? over : 1000 + over;
return (asUTC - asTS) / (60 * 1000);
}
/**
* Return whether this Zone is equal to another zone
* @override
* @param {Zone} otherZone - the zone to compare
* @return {boolean}
*/
equals(otherZone) {
return otherZone.type === "iana" && otherZone.name === this.name;
}
/**
* Return whether this Zone is valid.
* @override
* @type {boolean}
*/
get isValid() {
return this.valid;
}
}
// todo - remap caching
let intlLFCache = {};
function getCachedLF(locString, opts = {}) {
const key = JSON.stringify([locString, opts]);
let dtf = intlLFCache[key];
if (!dtf) {
dtf = new Intl.ListFormat(locString, opts);
intlLFCache[key] = dtf;
}
return dtf;
}
const intlDTCache = new Map();
function getCachedDTF(locString, opts = {}) {
const key = JSON.stringify([locString, opts]);
let dtf = intlDTCache.get(key);
if (dtf === undefined) {
dtf = new Intl.DateTimeFormat(locString, opts);
intlDTCache.set(key, dtf);
}
return dtf;
}
const intlNumCache = new Map();
function getCachedINF(locString, opts = {}) {
const key = JSON.stringify([locString, opts]);
let inf = intlNumCache.get(key);
if (inf === undefined) {
inf = new Intl.NumberFormat(locString, opts);
intlNumCache.set(key, inf);
}
return inf;
}
const intlRelCache = new Map();
function getCachedRTF(locString, opts = {}) {
const { base, ...cacheKeyOpts } = opts; // exclude `base` from the options
const key = JSON.stringify([locString, cacheKeyOpts]);
let inf = intlRelCache.get(key);
if (inf === undefined) {
inf = new Intl.RelativeTimeFormat(locString, opts);
intlRelCache.set(key, inf);
}
return inf;
}
let sysLocaleCache = null;
function systemLocale() {
if (sysLocaleCache) {
return sysLocaleCache;
} else {
sysLocaleCache = new Intl.DateTimeFormat().resolvedOptions().locale;
return sysLocaleCache;
}
}
const intlResolvedOptionsCache = new Map();
function getCachedIntResolvedOptions(locString) {
let opts = intlResolvedOptionsCache.get(locString);
if (opts === undefined) {
opts = new Intl.DateTimeFormat(locString).resolvedOptions();
intlResolvedOptionsCache.set(locString, opts);
}
return opts;
}
const weekInfoCache = new Map();
function getCachedWeekInfo(locString) {
let data = weekInfoCache.get(locString);
if (!data) {
const locale = new Intl.Locale(locString);
// browsers currently implement this as a property, but spec says it should be a getter function
data = "getWeekInfo" in locale ? locale.getWeekInfo() : locale.weekInfo;
// minimalDays was removed from WeekInfo: https://github.com/tc39/proposal-intl-locale-info/issues/86
if (!("minimalDays" in data)) {
data = { ...fallbackWeekSettings, ...data };
}
weekInfoCache.set(locString, data);
}
return data;
}
function parseLocaleString(localeStr) {
// I really want to avoid writing a BCP 47 parser
// see, e.g. https://github.com/wooorm/bcp-47
// Instead, we'll do this:
// a) if the string has no -u extensions, just leave it alone
// b) if it does, use Intl to resolve everything
// c) if Intl fails, try again without the -u
// private subtags and unicode subtags have ordering requirements,
// and we're not properly parsing this, so just strip out the
// private ones if they exist.
const xIndex = localeStr.indexOf("-x-");
if (xIndex !== -1) {
localeStr = localeStr.substring(0, xIndex);
}
const uIndex = localeStr.indexOf("-u-");
if (uIndex === -1) {
return [localeStr];
} else {
let options;
let selectedStr;
try {
options = getCachedDTF(localeStr).resolvedOptions();
selectedStr = localeStr;
} catch (e) {
const smaller = localeStr.substring(0, uIndex);
options = getCachedDTF(smaller).resolvedOptions();
selectedStr = smaller;
}
const { numberingSystem, calendar } = options;
return [selectedStr, numberingSystem, calendar];
}
}
function intlConfigString(localeStr, numberingSystem, outputCalendar) {
if (outputCalendar || numberingSystem) {
if (!localeStr.includes("-u-")) {
localeStr += "-u";
}
if (outputCalendar) {
localeStr += `-ca-${outputCalendar}`;
}
if (numberingSystem) {
localeStr += `-nu-${numberingSystem}`;
}
return localeStr;
} else {
return localeStr;
}
}
function mapMonths(f) {
const ms = [];
for (let i = 1; i <= 12; i++) {
const dt = DateTime.utc(2009, i, 1);
ms.push(f(dt));
}
return ms;
}
function mapWeekdays(f) {
const ms = [];
for (let i = 1; i <= 7; i++) {
const dt = DateTime.utc(2016, 11, 13 + i);
ms.push(f(dt));
}
return ms;
}
function listStuff(loc, length, englishFn, intlFn) {
const mode = loc.listingMode();
if (mode === "error") {
return null;
} else if (mode === "en") {
return englishFn(length);
} else {
return intlFn(length);
}
}
function supportsFastNumbers(loc) {
if (loc.numberingSystem && loc.numberingSystem !== "latn") {
return false;
} else {
return (
loc.numberingSystem === "latn" ||
!loc.locale ||
loc.locale.startsWith("en") ||
getCachedIntResolvedOptions(loc.locale).numberingSystem === "latn"
);
}
}
/**
* @private
*/
class PolyNumberFormatter {
constructor(intl, forceSimple, opts) {
this.padTo = opts.padTo || 0;
this.floor = opts.floor || false;
const { padTo, floor, ...otherOpts } = opts;
if (!forceSimple || Object.keys(otherOpts).length > 0) {
const intlOpts = { useGrouping: false, ...opts };
if (opts.padTo > 0) intlOpts.minimumIntegerDigits = opts.padTo;
this.inf = getCachedINF(intl, intlOpts);
}
}
format(i) {
if (this.inf) {
const fixed = this.floor ? Math.floor(i) : i;
return this.inf.format(fixed);
} else {
// to match the browser's numberformatter defaults
const fixed = this.floor ? Math.floor(i) : roundTo(i, 3);
return padStart(fixed, this.padTo);
}
}
}
/**
* @private
*/
class PolyDateFormatter {
constructor(dt, intl, opts) {
this.opts = opts;
this.originalZone = undefined;
let z = undefined;
if (this.opts.timeZone) {
// Don't apply any workarounds if a timeZone is explicitly provided in opts
this.dt = dt;
} else if (dt.zone.type === "fixed") {
// UTC-8 or Etc/UTC-8 are not part of tzdata, only Etc/GMT+8 and the like.
// That is why fixed-offset TZ is set to that unless it is:
// 1. Representing offset 0 when UTC is used to maintain previous behavior and does not become GMT.
// 2. Unsupported by the browser:
// - some do not support Etc/
// - < Etc/GMT-14, > Etc/GMT+12, and 30-minute or 45-minute offsets are not part of tzdata
const gmtOffset = -1 * (dt.offset / 60);
const offsetZ = gmtOffset >= 0 ? `Etc/GMT+${gmtOffset}` : `Etc/GMT${gmtOffset}`;
if (dt.offset !== 0 && IANAZone.create(offsetZ).valid) {
z = offsetZ;
this.dt = dt;
} else {
// Not all fixed-offset zones like Etc/+4:30 are present in tzdata so
// we manually apply the offset and substitute the zone as needed.
z = "UTC";
this.dt = dt.offset === 0 ? dt : dt.setZone("UTC").plus({ minutes: dt.offset });
this.originalZone = dt.zone;
}
} else if (dt.zone.type === "system") {
this.dt = dt;
} else if (dt.zone.type === "iana") {
this.dt = dt;
z = dt.zone.name;
} else {
// Custom zones can have any offset / offsetName so we just manually
// apply the offset and substitute the zone as needed.
z = "UTC";
this.dt = dt.setZone("UTC").plus({ minutes: dt.offset });
this.originalZone = dt.zone;
}
const intlOpts = { ...this.opts };
intlOpts.timeZone = intlOpts.timeZone || z;
this.dtf = getCachedDTF(intl, intlOpts);
}
format() {
if (this.originalZone) {
// If we have to substitute in the actual zone name, we have to use
// formatToParts so that the timezone can be replaced.
return this.formatToParts()
.map(({ value }) => value)
.join("");
}
return this.dtf.format(this.dt.toJSDate());
}
formatToParts() {
const parts = this.dtf.formatToParts(this.dt.toJSDate());
if (this.originalZone) {
return parts.map((part) => {
if (part.type === "timeZoneName") {
const offsetName = this.originalZone.offsetName(this.dt.ts, {
locale: this.dt.locale,
format: this.opts.timeZoneName,
});
return {
...part,
value: offsetName,
};
} else {
return part;
}
});
}
return parts;
}
resolvedOptions() {
return this.dtf.resolvedOptions();
}
}
/**
* @private
*/
class PolyRelFormatter {
constructor(intl, isEnglish, opts) {
this.opts = { style: "long", ...opts };
if (!isEnglish && hasRelative()) {
this.rtf = getCachedRTF(intl, opts);
}
}
format(count, unit) {
if (this.rtf) {
return this.rtf.format(count, unit);
} else {
return formatRelativeTime(unit, count, this.opts.numeric, this.opts.style !== "long");
}
}
formatToParts(count, unit) {
if (this.rtf) {
return this.rtf.formatToParts(count, unit);
} else {
return [];
}
}
}
const fallbackWeekSettings = {
firstDay: 1,
minimalDays: 4,
weekend: [6, 7],
};
/**
* @private
*/
class Locale {
static fromOpts(opts) {
return Locale.create(
opts.locale,
opts.numberingSystem,
opts.outputCalendar,
opts.weekSettings,
opts.defaultToEN
);
}
static create(locale, numberingSystem, outputCalendar, weekSettings, defaultToEN = false) {
const specifiedLocale = locale || Settings.defaultLocale;
// the system locale is useful for human-readable strings but annoying for parsing/formatting known formats
const localeR = specifiedLocale || (defaultToEN ? "en-US" : systemLocale());
const numberingSystemR = numberingSystem || Settings.defaultNumberingSystem;
const outputCalendarR = outputCalendar || Settings.defaultOutputCalendar;
const weekSettingsR = validateWeekSettings(weekSettings) || Settings.defaultWeekSettings;
return new Locale(localeR, numberingSystemR, outputCalendarR, weekSettingsR, specifiedLocale);
}
static resetCache() {
sysLocaleCache = null;
intlDTCache.clear();
intlNumCache.clear();
intlRelCache.clear();
intlResolvedOptionsCache.clear();
weekInfoCache.clear();
}
static fromObject({ locale, numberingSystem, outputCalendar, weekSettings } = {}) {
return Locale.create(locale, numberingSystem, outputCalendar, weekSettings);
}
constructor(locale, numbering, outputCalendar, weekSettings, specifiedLocale) {
const [parsedLocale, parsedNumberingSystem, parsedOutputCalendar] = parseLocaleString(locale);
this.locale = parsedLocale;
this.numberingSystem = numbering || parsedNumberingSystem || null;
this.outputCalendar = outputCalendar || parsedOutputCalendar || null;
this.weekSettings = weekSettings;
this.intl = intlConfigString(this.locale, this.numberingSystem, this.outputCalendar);
this.weekdaysCache = { format: {}, standalone: {} };
this.monthsCache = { format: {}, standalone: {} };
this.meridiemCache = null;
this.eraCache = {};
this.specifiedLocale = specifiedLocale;
this.fastNumbersCached = null;
}
get fastNumbers() {
if (this.fastNumbersCached == null) {
this.fastNumbersCached = supportsFastNumbers(this);
}
return this.fastNumbersCached;
}
listingMode() {
const isActuallyEn = this.isEnglish();
const hasNoWeirdness =
(this.numberingSystem === null || this.numberingSystem === "latn") &&
(this.outputCalendar === null || this.outputCalendar === "gregory");
return isActuallyEn && hasNoWeirdness ? "en" : "intl";
}
clone(alts) {
if (!alts || Object.getOwnPropertyNames(alts).length === 0) {
return this;
} else {
return Locale.create(
alts.locale || this.specifiedLocale,
alts.numberingSystem || this.numberingSystem,
alts.outputCalendar || this.outputCalendar,
validateWeekSettings(alts.weekSettings) || this.weekSettings,
alts.defaultToEN || false
);
}
}
redefaultToEN(alts = {}) {
return this.clone({ ...alts, defaultToEN: true });
}
redefaultToSystem(alts = {}) {
return this.clone({ ...alts, defaultToEN: false });
}
months(length, format = false) {
return listStuff(this, length, months, () => {
// Workaround for "ja" locale: formatToParts does not label all parts of the month
// as "month" and for this locale there is no difference between "format" and "non-format".
// As such, just use format() instead of formatToParts() and take the whole string
const monthSpecialCase = this.intl === "ja" || this.intl.startsWith("ja-");
format &= !monthSpecialCase;
const intl = format ? { month: length, day: "numeric" } : { month: length },
formatStr = format ? "format" : "standalone";
if (!this.monthsCache[formatStr][length]) {
const mapper = !monthSpecialCase
? (dt) => this.extract(dt, intl, "month")
: (dt) => this.dtFormatter(dt, intl).format();
this.monthsCache[formatStr][length] = mapMonths(mapper);
}
return this.monthsCache[formatStr][length];
});
}
weekdays(length, format = false) {
return listStuff(this, length, weekdays, () => {
const intl = format
? { weekday: length, year: "numeric", month: "long", day: "numeric" }
: { weekday: length },
formatStr = format ? "format" : "standalone";
if (!this.weekdaysCache[formatStr][length]) {
this.weekdaysCache[formatStr][length] = mapWeekdays((dt) =>
this.extract(dt, intl, "weekday")
);
}
return this.weekdaysCache[formatStr][length];
});
}
meridiems() {
return listStuff(
this,
undefined,
() => meridiems,
() => {
// In theory there could be aribitrary day periods. We're gonna assume there are exactly two
// for AM and PM. This is probably wrong, but it's makes parsing way easier.
if (!this.meridiemCache) {
const intl = { hour: "numeric", hourCycle: "h12" };
this.meridiemCache = [DateTime.utc(2016, 11, 13, 9), DateTime.utc(2016, 11, 13, 19)].map(
(dt) => this.extract(dt, intl, "dayperiod")
);
}
return this.meridiemCache;
}
);
}
eras(length) {
return listStuff(this, length, eras, () => {
const intl = { era: length };
// This is problematic. Different calendars are going to define eras totally differently. What I need is the minimum set of dates
// to definitely enumerate them.
if (!this.eraCache[length]) {
this.eraCache[length] = [DateTime.utc(-40, 1, 1), DateTime.utc(2017, 1, 1)].map((dt) =>
this.extract(dt, intl, "era")
);
}
return this.eraCache[length];
});
}
extract(dt, intlOpts, field) {
const df = this.dtFormatter(dt, intlOpts),
results = df.formatToParts(),
matching = results.find((m) => m.type.toLowerCase() === field);
return matching ? matching.value : null;
}
numberFormatter(opts = {}) {
// this forcesimple option is never used (the only caller short-circuits on it, but it seems safer to leave)
// (in contrast, the rest of the condition is used heavily)
return new PolyNumberFormatter(this.intl, opts.forceSimple || this.fastNumbers, opts);
}
dtFormatter(dt, intlOpts = {}) {
return new PolyDateFormatter(dt, this.intl, intlOpts);
}
relFormatter(opts = {}) {
return new PolyRelFormatter(this.intl, this.isEnglish(), opts);
}
listFormatter(opts = {}) {
return getCachedLF(this.intl, opts);
}
isEnglish() {
return (
this.locale === "en" ||
this.locale.toLowerCase() === "en-us" ||
getCachedIntResolvedOptions(this.intl).locale.startsWith("en-us")
);
}
getWeekSettings() {
if (this.weekSettings) {
return this.weekSettings;
} else if (!hasLocaleWeekInfo()) {
return fallbackWeekSettings;
} else {
return getCachedWeekInfo(this.locale);
}
}
getStartOfWeek() {
return this.getWeekSettings().firstDay;
}
getMinDaysInFirstWeek() {
return this.getWeekSettings().minimalDays;
}
getWeekendDays() {
return this.getWeekSettings().weekend;
}
equals(other) {
return (
this.locale === other.locale &&
this.numberingSystem === other.numberingSystem &&
this.outputCalendar === other.outputCalendar
);
}
toString() {
return `Locale(${this.locale}, ${this.numberingSystem}, ${this.outputCalendar})`;
}
}
let singleton = null;
/**
* A zone with a fixed offset (meaning no DST)
* @implements {Zone}
*/
class FixedOffsetZone extends Zone {
/**
* Get a singleton instance of UTC
* @return {FixedOffsetZone}
*/
static get utcInstance() {
if (singleton === null) {
singleton = new FixedOffsetZone(0);
}
return singleton;
}
/**
* Get an instance with a specified offset
* @param {number} offset - The offset in minutes
* @return {FixedOffsetZone}
*/
static instance(offset) {
return offset === 0 ? FixedOffsetZone.utcInstance : new FixedOffsetZone(offset);
}
/**
* Get an instance of FixedOffsetZone from a UTC offset string, like "UTC+6"
* @param {string} s - The offset string to parse
* @example FixedOffsetZone.parseSpecifier("UTC+6")
* @example FixedOffsetZone.parseSpecifier("UTC+06")
* @example FixedOffsetZone.parseSpecifier("UTC-6:00")
* @return {FixedOffsetZone}
*/
static parseSpecifier(s) {
if (s) {
const r = s.match(/^utc(?:([+-]\d{1,2})(?::(\d{2}))?)?$/i);
if (r) {
return new FixedOffsetZone(signedOffset(r[1], r[2]));
}
}
return null;
}
constructor(offset) {
super();
/** @private **/
this.fixed = offset;
}
/**
* The type of zone. `fixed` for all instances of `FixedOffsetZone`.
* @override
* @type {string}
*/
get type() {
return "fixed";
}
/**
* The name of this zone.
* All fixed zones' names always start with "UTC" (plus optional offset)
* @override
* @type {string}
*/
get name() {
return this.fixed === 0 ? "UTC" : `UTC${formatOffset(this.fixed, "narrow")}`;
}
/**
* The IANA name of this zone, i.e. `Etc/UTC` or `Etc/GMT+/-nn`
*
* @override
* @type {string}
*/
get ianaName() {
if (this.fixed === 0) {
return "Etc/UTC";
} else {
return `Etc/GMT${formatOffset(-this.fixed, "narrow")}`;
}
}
/**
* Returns the offset's common name at the specified timestamp.
*
* For fixed offset zones this equals to the zone name.
* @override
*/
offsetName() {
return this.name;
}
/**
* Returns the offset's value as a string
* @override
* @param {number} ts - Epoch milliseconds for which to get the offset
* @param {string} format - What style of offset to return.
* Accepts 'narrow', 'short', or 'techie'. Returning '+6', '+06:00', or '+0600' respectively
* @return {string}
*/
formatOffset(ts, format) {
return formatOffset(this.fixed, format);
}
/**
* Returns whether the offset is known to be fixed for the whole year:
* Always returns true for all fixed offset zones.
* @override
* @type {boolean}
*/
get isUniversal() {
return true;
}
/**
* Return the offset in minutes for this zone at the specified timestamp.
*
* For fixed offset zones, this is constant and does not depend on a timestamp.
* @override
* @return {number}
*/
offset() {
return this.fixed;
}
/**
* Return whether this Zone is equal to another zone (i.e. also fixed and same offset)
* @override
* @param {Zone} otherZone - the zone to compare
* @return {boolean}
*/
equals(otherZone) {
return otherZone.type === "fixed" && otherZone.fixed === this.fixed;
}
/**
* Return whether this Zone is valid:
* All fixed offset zones are valid.
* @override
* @type {boolean}
*/
get isValid() {
return true;
}
}
/**
* A zone that failed to parse. You should never need to instantiate this.
* @implements {Zone}
*/
class InvalidZone extends Zone {
constructor(zoneName) {
super();
/** @private */
this.zoneName = zoneName;
}
/** @override **/
get type() {
return "invalid";
}
/** @override **/
get name() {
return this.zoneName;
}
/** @override **/
get isUniversal() {
return false;
}
/** @override **/
offsetName() {
return null;
}
/** @override **/
formatOffset() {
return "";
}
/** @override **/
offset() {
return NaN;
}
/** @override **/
equals() {
return false;
}
/** @override **/
get isValid() {
return false;
}
}
/**
* @private
*/
function normalizeZone(input, defaultZone) {
if (isUndefined$1(input) || input === null) {
return defaultZone;
} else if (input instanceof Zone) {
return input;
} else if (isString$1(input)) {
const lowered = input.toLowerCase();
if (lowered === "default") return defaultZone;
else if (lowered === "local" || lowered === "system") return SystemZone.instance;
else if (lowered === "utc" || lowered === "gmt") return FixedOffsetZone.utcInstance;
else return FixedOffsetZone.parseSpecifier(lowered) || IANAZone.create(input);
} else if (isNumber$1(input)) {
return FixedOffsetZone.instance(input);
} else if (typeof input === "object" && "offset" in input && typeof input.offset === "function") {
// This is dumb, but the instanceof check above doesn't seem to really work
// so we're duck checking it
return input;
} else {
return new InvalidZone(input);
}
}
const numberingSystems = {
arab: "[\u0660-\u0669]",
arabext: "[\u06F0-\u06F9]",
bali: "[\u1B50-\u1B59]",
beng: "[\u09E6-\u09EF]",
deva: "[\u0966-\u096F]",
fullwide: "[\uFF10-\uFF19]",
gujr: "[\u0AE6-\u0AEF]",
hanidec: "[〇|一|二|三|四|五|六|七|八|九]",
khmr: "[\u17E0-\u17E9]",
knda: "[\u0CE6-\u0CEF]",
laoo: "[\u0ED0-\u0ED9]",
limb: "[\u1946-\u194F]",
mlym: "[\u0D66-\u0D6F]",
mong: "[\u1810-\u1819]",
mymr: "[\u1040-\u1049]",
orya: "[\u0B66-\u0B6F]",
tamldec: "[\u0BE6-\u0BEF]",
telu: "[\u0C66-\u0C6F]",
thai: "[\u0E50-\u0E59]",
tibt: "[\u0F20-\u0F29]",
latn: "\\d",
};
const numberingSystemsUTF16 = {
arab: [1632, 1641],
arabext: [1776, 1785],
bali: [6992, 7001],
beng: [2534, 2543],
deva: [2406, 2415],
fullwide: [65296, 65303],
gujr: [2790, 2799],
khmr: [6112, 6121],
knda: [3302, 3311],
laoo: [3792, 3801],
limb: [6470, 6479],
mlym: [3430, 3439],
mong: [6160, 6169],
mymr: [4160, 4169],
orya: [2918, 2927],
tamldec: [3046, 3055],
telu: [3174, 3183],
thai: [3664, 3673],
tibt: [3872, 3881],
};
const hanidecChars = numberingSystems.hanidec.replace(/[\[|\]]/g, "").split("");
function parseDigits(str) {
let value = parseInt(str, 10);
if (isNaN(value)) {
value = "";
for (let i = 0; i < str.length; i++) {
const code = str.charCodeAt(i);
if (str[i].search(numberingSystems.hanidec) !== -1) {
value += hanidecChars.indexOf(str[i]);
} else {
for (const key in numberingSystemsUTF16) {
const [min, max] = numberingSystemsUTF16[key];
if (code >= min && code <= max) {
value += code - min;
}
}
}
}
return parseInt(value, 10);
} else {
return value;
}
}
// cache of {numberingSystem: {append: regex}}
const digitRegexCache = new Map();
function resetDigitRegexCache() {
digitRegexCache.clear();
}
function digitRegex({ numberingSystem }, append = "") {
const ns = numberingSystem || "latn";
let appendCache = digitRegexCache.get(ns);
if (appendCache === undefined) {
appendCache = new Map();
digitRegexCache.set(ns, appendCache);
}
let regex = appendCache.get(append);
if (regex === undefined) {
regex = new RegExp(`${numberingSystems[ns]}${append}`);
appendCache.set(append, regex);
}
return regex;
}
let now = () => Date.now(),
defaultZone = "system",
defaultLocale = null,
defaultNumberingSystem = null,
defaultOutputCalendar = null,
twoDigitCutoffYear = 60,
throwOnInvalid,
defaultWeekSettings = null;
/**
* Settings contains static getters and setters that control Luxon's overall behavior. Luxon is a simple library with few options, but the ones it does have live here.
*/
class Settings {
/**
* Get the callback for returning the current timestamp.
* @type {function}
*/
static get now() {
return now;
}
/**
* Set the callback for returning the current timestamp.
* The function should return a number, which will be interpreted as an Epoch millisecond count
* @type {function}
* @example Settings.now = () => Date.now() + 3000 // pretend it is 3 seconds in the future
* @example Settings.now = () => 0 // always pretend it's Jan 1, 1970 at midnight in UTC time
*/
static set now(n) {
now = n;
}
/**
* Set the default time zone to create DateTimes in. Does not affect existing instances.
* Use the value "system" to reset this value to the system's time zone.
* @type {string}
*/
static set defaultZone(zone) {
defaultZone = zone;
}
/**
* Get the default time zone object currently used to create DateTimes. Does not affect existing instances.
* The default value is the system's time zone (the one set on the machine that runs this code).
* @type {Zone}
*/
static get defaultZone() {
return normalizeZone(defaultZone, SystemZone.instance);
}
/**
* Get the default locale to create DateTimes with. Does not affect existing instances.
* @type {string}
*/
static get defaultLocale() {
return defaultLocale;
}
/**
* Set the default locale to create DateTimes with. Does not affect existing instances.
* @type {string}
*/
static set defaultLocale(locale) {
defaultLocale = locale;
}
/**
* Get the default numbering system to create DateTimes with. Does not affect existing instances.
* @type {string}
*/
static get defaultNumberingSystem() {
return defaultNumberingSystem;
}
/**
* Set the default numbering system to create DateTimes with. Does not affect existing instances.
* @type {string}
*/
static set defaultNumberingSystem(numberingSystem) {
defaultNumberingSystem = numberingSystem;
}
/**
* Get the default output calendar to create DateTimes with. Does not affect existing instances.
* @type {string}
*/
static get defaultOutputCalendar() {
return defaultOutputCalendar;
}
/**
* Set the default output calendar to create DateTimes with. Does not affect existing instances.
* @type {string}
*/
static set defaultOutputCalendar(outputCalendar) {
defaultOutputCalendar = outputCalendar;
}
/**
* @typedef {Object} WeekSettings
* @property {number} firstDay
* @property {number} minimalDays
* @property {number[]} weekend
*/
/**
* @return {WeekSettings|null}
*/
static get defaultWeekSettings() {
return defaultWeekSettings;
}
/**
* Allows overriding the default locale week settings, i.e. the start of the week, the weekend and
* how many days are required in the first week of a year.
* Does not affect existing instances.
*
* @param {WeekSettings|null} weekSettings
*/
static set defaultWeekSettings(weekSettings) {
defaultWeekSettings = validateWeekSettings(weekSettings);
}
/**
* Get the cutoff year for whether a 2-digit year string is interpreted in the current or previous century. Numbers higher than the cutoff will be considered to mean 19xx and numbers lower or equal to the cutoff will be considered 20xx.
* @type {number}
*/
static get twoDigitCutoffYear() {
return twoDigitCutoffYear;
}
/**
* Set the cutoff year for whether a 2-digit year string is interpreted in the current or previous century. Numbers higher than the cutoff will be considered to mean 19xx and numbers lower or equal to the cutoff will be considered 20xx.
* @type {number}
* @example Settings.twoDigitCutoffYear = 0 // all 'yy' are interpreted as 20th century
* @example Settings.twoDigitCutoffYear = 99 // all 'yy' are interpreted as 21st century
* @example Settings.twoDigitCutoffYear = 50 // '49' -> 2049; '50' -> 1950
* @example Settings.twoDigitCutoffYear = 1950 // interpreted as 50
* @example Settings.twoDigitCutoffYear = 2050 // ALSO interpreted as 50
*/
static set twoDigitCutoffYear(cutoffYear) {
twoDigitCutoffYear = cutoffYear % 100;
}
/**
* Get whether Luxon will throw when it encounters invalid DateTimes, Durations, or Intervals
* @type {boolean}
*/
static get throwOnInvalid() {
return throwOnInvalid;
}
/**
* Set whether Luxon will throw when it encounters invalid DateTimes, Durations, or Intervals
* @type {boolean}
*/
static set throwOnInvalid(t) {
throwOnInvalid = t;
}
/**
* Reset Luxon's global caches. Should only be necessary in testing scenarios.
* @return {void}
*/
static resetCaches() {
Locale.resetCache();
IANAZone.resetCache();
DateTime.resetCache();
resetDigitRegexCache();
}
}
class Invalid {
constructor(reason, explanation) {
this.reason = reason;
this.explanation = explanation;
}
toMessage() {
if (this.explanation) {
return `${this.reason}: ${this.explanation}`;
} else {
return this.reason;
}
}
}
const nonLeapLadder = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334],
leapLadder = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335];
function unitOutOfRange(unit, value) {
return new Invalid(
"unit out of range",
`you specified ${value} (of type ${typeof value}) as a ${unit}, which is invalid`
);
}
function dayOfWeek(year, month, day) {
const d = new Date(Date.UTC(year, month - 1, day));
if (year < 100 && year >= 0) {
d.setUTCFullYear(d.getUTCFullYear() - 1900);
}
const js = d.getUTCDay();
return js === 0 ? 7 : js;
}
function computeOrdinal(year, month, day) {
return day + (isLeapYear(year) ? leapLadder : nonLeapLadder)[month - 1];
}
function uncomputeOrdinal(year, ordinal) {
const table = isLeapYear(year) ? leapLadder : nonLeapLadder,
month0 = table.findIndex((i) => i < ordinal),
day = ordinal - table[month0];
return { month: month0 + 1, day };
}
function isoWeekdayToLocal(isoWeekday, startOfWeek) {
return ((isoWeekday - startOfWeek + 7) % 7) + 1;
}
/**
* @private
*/
function gregorianToWeek(gregObj, minDaysInFirstWeek = 4, startOfWeek = 1) {
const { year, month, day } = gregObj,
ordinal = computeOrdinal(year, month, day),
weekday = isoWeekdayToLocal(dayOfWeek(year, month, day), startOfWeek);
let weekNumber = Math.floor((ordinal - weekday + 14 - minDaysInFirstWeek) / 7),
weekYear;
if (weekNumber < 1) {
weekYear = year - 1;
weekNumber = weeksInWeekYear(weekYear, minDaysInFirstWeek, startOfWeek);
} else if (weekNumber > weeksInWeekYear(year, minDaysInFirstWeek, startOfWeek)) {
weekYear = year + 1;
weekNumber = 1;
} else {
weekYear = year;
}
return { weekYear, weekNumber, weekday, ...timeObject(gregObj) };
}
function weekToGregorian(weekData, minDaysInFirstWeek = 4, startOfWeek = 1) {
const { weekYear, weekNumber, weekday } = weekData,
weekdayOfJan4 = isoWeekdayToLocal(dayOfWeek(weekYear, 1, minDaysInFirstWeek), startOfWeek),
yearInDays = daysInYear(weekYear);
let ordinal = weekNumber * 7 + weekday - weekdayOfJan4 - 7 + minDaysInFirstWeek,
year;
if (ordinal < 1) {
year = weekYear - 1;
ordinal += daysInYear(year);
} else if (ordinal > yearInDays) {
year = weekYear + 1;
ordinal -= daysInYear(weekYear);
} else {
year = weekYear;
}
const { month, day } = uncomputeOrdinal(year, ordinal);
return { year, month, day, ...timeObject(weekData) };
}
function gregorianToOrdinal(gregData) {
const { year, month, day } = gregData;
const ordinal = computeOrdinal(year, month, day);
return { year, ordinal, ...timeObject(gregData) };
}
function ordinalToGregorian(ordinalData) {
const { year, ordinal } = ordinalData;
const { month, day } = uncomputeOrdinal(year, ordinal);
return { year, month, day, ...timeObject(ordinalData) };
}
/**
* Check if local week units like localWeekday are used in obj.
* If so, validates that they are not mixed with ISO week units and then copies them to the normal week unit properties.
* Modifies obj in-place!
* @param obj the object values
*/
function usesLocalWeekValues(obj, loc) {
const hasLocaleWeekData =
!isUndefined$1(obj.localWeekday) ||
!isUndefined$1(obj.localWeekNumber) ||
!isUndefined$1(obj.localWeekYear);
if (hasLocaleWeekData) {
const hasIsoWeekData =
!isUndefined$1(obj.weekday) || !isUndefined$1(obj.weekNumber) || !isUndefined$1(obj.weekYear);
if (hasIsoWeekData) {
throw new ConflictingSpecificationError(
"Cannot mix locale-based week fields with ISO-based week fields"
);
}
if (!isUndefined$1(obj.localWeekday)) obj.weekday = obj.localWeekday;
if (!isUndefined$1(obj.localWeekNumber)) obj.weekNumber = obj.localWeekNumber;
if (!isUndefined$1(obj.localWeekYear)) obj.weekYear = obj.localWeekYear;
delete obj.localWeekday;
delete obj.localWeekNumber;
delete obj.localWeekYear;
return {
minDaysInFirstWeek: loc.getMinDaysInFirstWeek(),
startOfWeek: loc.getStartOfWeek(),
};
} else {
return { minDaysInFirstWeek: 4, startOfWeek: 1 };
}
}
function hasInvalidWeekData(obj, minDaysInFirstWeek = 4, startOfWeek = 1) {
const validYear = isInteger(obj.weekYear),
validWeek = integerBetween(
obj.weekNumber,
1,
weeksInWeekYear(obj.weekYear, minDaysInFirstWeek, startOfWeek)
),
validWeekday = integerBetween(obj.weekday, 1, 7);
if (!validYear) {
return unitOutOfRange("weekYear", obj.weekYear);
} else if (!validWeek) {
return unitOutOfRange("week", obj.weekNumber);
} else if (!validWeekday) {
return unitOutOfRange("weekday", obj.weekday);
} else return false;
}
function hasInvalidOrdinalData(obj) {
const validYear = isInteger(obj.year),
validOrdinal = integerBetween(obj.ordinal, 1, daysInYear(obj.year));
if (!validYear) {
return unitOutOfRange("year", obj.year);
} else if (!validOrdinal) {
return unitOutOfRange("ordinal", obj.ordinal);
} else return false;
}
function hasInvalidGregorianData(obj) {
const validYear = isInteger(obj.year),
validMonth = integerBetween(obj.month, 1, 12),
validDay = integerBetween(obj.day, 1, daysInMonth(obj.year, obj.month));
if (!validYear) {
return unitOutOfRange("year", obj.year);
} else if (!validMonth) {
return unitOutOfRange("month", obj.month);
} else if (!validDay) {
return unitOutOfRange("day", obj.day);
} else return false;
}
function hasInvalidTimeData(obj) {
const { hour, minute, second, millisecond } = obj;
const validHour =
integerBetween(hour, 0, 23) ||
(hour === 24 && minute === 0 && second === 0 && millisecond === 0),
validMinute = integerBetween(minute, 0, 59),
validSecond = integerBetween(second, 0, 59),
validMillisecond = integerBetween(millisecond, 0, 999);
if (!validHour) {
return unitOutOfRange("hour", hour);
} else if (!validMinute) {
return unitOutOfRange("minute", minute);
} else if (!validSecond) {
return unitOutOfRange("second", second);
} else if (!validMillisecond) {
return unitOutOfRange("millisecond", millisecond);
} else return false;
}
/*
This is just a junk drawer, containing anything used across multiple classes.
Because Luxon is small(ish), this should stay small and we won't worry about splitting
it up into, say, parsingUtil.js and basicUtil.js and so on. But they are divided up by feature area.
*/
/**
* @private
*/
// TYPES
function isUndefined$1(o) {
return typeof o === "undefined";
}
function isNumber$1(o) {
return typeof o === "number";
}
function isInteger(o) {
return typeof o === "number" && o % 1 === 0;
}
function isString$1(o) {
return typeof o === "string";
}
function isDate$1(o) {
return Object.prototype.toString.call(o) === "[object Date]";
}
// CAPABILITIES
function hasRelative() {
try {
return typeof Intl !== "undefined" && !!Intl.RelativeTimeFormat;
} catch (e) {
return false;
}
}
function hasLocaleWeekInfo() {
try {
return (
typeof Intl !== "undefined" &&
!!Intl.Locale &&
("weekInfo" in Intl.Locale.prototype || "getWeekInfo" in Intl.Locale.prototype)
);
} catch (e) {
return false;
}
}
// OBJECTS AND ARRAYS
function maybeArray(thing) {
return Array.isArray(thing) ? thing : [thing];
}
function bestBy(arr, by, compare) {
if (arr.length === 0) {
return undefined;
}
return arr.reduce((best, next) => {
const pair = [by(next), next];
if (!best) {
return pair;
} else if (compare(best[0], pair[0]) === best[0]) {
return best;
} else {
return pair;
}
}, null)[1];
}
function pick$1(obj, keys) {
return keys.reduce((a, k) => {
a[k] = obj[k];
return a;
}, {});
}
function hasOwnProperty$1(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
function validateWeekSettings(settings) {
if (settings == null) {
return null;
} else if (typeof settings !== "object") {
throw new InvalidArgumentError("Week settings must be an object");
} else {
if (
!integerBetween(settings.firstDay, 1, 7) ||
!integerBetween(settings.minimalDays, 1, 7) ||
!Array.isArray(settings.weekend) ||
settings.weekend.some((v) => !integerBetween(v, 1, 7))
) {
throw new InvalidArgumentError("Invalid week settings");
}
return {
firstDay: settings.firstDay,
minimalDays: settings.minimalDays,
weekend: Array.from(settings.weekend),
};
}
}
// NUMBERS AND STRINGS
function integerBetween(thing, bottom, top) {
return isInteger(thing) && thing >= bottom && thing <= top;
}
// x % n but takes the sign of n instead of x
function floorMod(x, n) {
return x - n * Math.floor(x / n);
}
function padStart(input, n = 2) {
const isNeg = input < 0;
let padded;
if (isNeg) {
padded = "-" + ("" + -input).padStart(n, "0");
} else {
padded = ("" + input).padStart(n, "0");
}
return padded;
}
function parseInteger(string) {
if (isUndefined$1(string) || string === null || string === "") {
return undefined;
} else {
return parseInt(string, 10);
}
}
function parseFloating(string) {
if (isUndefined$1(string) || string === null || string === "") {
return undefined;
} else {
return parseFloat(string);
}
}
function parseMillis(fraction) {
// Return undefined (instead of 0) in these cases, where fraction is not set
if (isUndefined$1(fraction) || fraction === null || fraction === "") {
return undefined;
} else {
const f = parseFloat("0." + fraction) * 1000;
return Math.floor(f);
}
}
function roundTo(number, digits, rounding = "round") {
const factor = 10 ** digits;
switch (rounding) {
case "expand":
return number > 0
? Math.ceil(number * factor) / factor
: Math.floor(number * factor) / factor;
case "trunc":
return Math.trunc(number * factor) / factor;
case "round":
return Math.round(number * factor) / factor;
case "floor":
return Math.floor(number * factor) / factor;
case "ceil":
return Math.ceil(number * factor) / factor;
default:
throw new RangeError(`Value rounding ${rounding} is out of range`);
}
}
// DATE BASICS
function isLeapYear(year) {
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
}
function daysInYear(year) {
return isLeapYear(year) ? 366 : 365;
}
function daysInMonth(year, month) {
const modMonth = floorMod(month - 1, 12) + 1,
modYear = year + (month - modMonth) / 12;
if (modMonth === 2) {
return isLeapYear(modYear) ? 29 : 28;
} else {
return [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][modMonth - 1];
}
}
// convert a calendar object to a local timestamp (epoch, but with the offset baked in)
function objToLocalTS(obj) {
let d = Date.UTC(
obj.year,
obj.month - 1,
obj.day,
obj.hour,
obj.minute,
obj.second,
obj.millisecond
);
// for legacy reasons, years between 0 and 99 are interpreted as 19XX; revert that
if (obj.year < 100 && obj.year >= 0) {
d = new Date(d);
// set the month and day again, this is necessary because year 2000 is a leap year, but year 100 is not
// so if obj.year is in 99, but obj.day makes it roll over into year 100,
// the calculations done by Date.UTC are using year 2000 - which is incorrect
d.setUTCFullYear(obj.year, obj.month - 1, obj.day);
}
return +d;
}
// adapted from moment.js: https://github.com/moment/moment/blob/000ac1800e620f770f4eb31b5ae908f6167b0ab2/src/lib/units/week-calendar-utils.js
function firstWeekOffset(year, minDaysInFirstWeek, startOfWeek) {
const fwdlw = isoWeekdayToLocal(dayOfWeek(year, 1, minDaysInFirstWeek), startOfWeek);
return -fwdlw + minDaysInFirstWeek - 1;
}
function weeksInWeekYear(weekYear, minDaysInFirstWeek = 4, startOfWeek = 1) {
const weekOffset = firstWeekOffset(weekYear, minDaysInFirstWeek, startOfWeek);
const weekOffsetNext = firstWeekOffset(weekYear + 1, minDaysInFirstWeek, startOfWeek);
return (daysInYear(weekYear) - weekOffset + weekOffsetNext) / 7;
}
function untruncateYear(year) {
if (year > 99) {
return year;
} else return year > Settings.twoDigitCutoffYear ? 1900 + year : 2000 + year;
}
// PARSING
function parseZoneInfo(ts, offsetFormat, locale, timeZone = null) {
const date = new Date(ts),
intlOpts = {
hourCycle: "h23",
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
};
if (timeZone) {
intlOpts.timeZone = timeZone;
}
const modified = { timeZoneName: offsetFormat, ...intlOpts };
const parsed = new Intl.DateTimeFormat(locale, modified)
.formatToParts(date)
.find((m) => m.type.toLowerCase() === "timezonename");
return parsed ? parsed.value : null;
}
// signedOffset('-5', '30') -> -330
function signedOffset(offHourStr, offMinuteStr) {
let offHour = parseInt(offHourStr, 10);
// don't || this because we want to preserve -0
if (Number.isNaN(offHour)) {
offHour = 0;
}
const offMin = parseInt(offMinuteStr, 10) || 0,
offMinSigned = offHour < 0 || Object.is(offHour, -0) ? -offMin : offMin;
return offHour * 60 + offMinSigned;
}
// COERCION
function asNumber(value) {
const numericValue = Number(value);
if (typeof value === "boolean" || value === "" || !Number.isFinite(numericValue))
throw new InvalidArgumentError(`Invalid unit value ${value}`);
return numericValue;
}
function normalizeObject(obj, normalizer) {
const normalized = {};
for (const u in obj) {
if (hasOwnProperty$1(obj, u)) {
const v = obj[u];
if (v === undefined || v === null) continue;
normalized[normalizer(u)] = asNumber(v);
}
}
return normalized;
}
/**
* Returns the offset's value as a string
* @param {number} ts - Epoch milliseconds for which to get the offset
* @param {string} format - What style of offset to return.
* Accepts 'narrow', 'short', or 'techie'. Returning '+6', '+06:00', or '+0600' respectively
* @return {string}
*/
function formatOffset(offset, format) {
const hours = Math.trunc(Math.abs(offset / 60)),
minutes = Math.trunc(Math.abs(offset % 60)),
sign = offset >= 0 ? "+" : "-";
switch (format) {
case "short":
return `${sign}${padStart(hours, 2)}:${padStart(minutes, 2)}`;
case "narrow":
return `${sign}${hours}${minutes > 0 ? `:${minutes}` : ""}`;
case "techie":
return `${sign}${padStart(hours, 2)}${padStart(minutes, 2)}`;
default:
throw new RangeError(`Value format ${format} is out of range for property format`);
}
}
function timeObject(obj) {
return pick$1(obj, ["hour", "minute", "second", "millisecond"]);
}
/**
* @private
*/
const monthsLong = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
];
const monthsShort = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
];
const monthsNarrow = ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"];
function months(length) {
switch (length) {
case "narrow":
return [...monthsNarrow];
case "short":
return [...monthsShort];
case "long":
return [...monthsLong];
case "numeric":
return ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"];
case "2-digit":
return ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"];
default:
return null;
}
}
const weekdaysLong = [
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday",
];
const weekdaysShort = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
const weekdaysNarrow = ["M", "T", "W", "T", "F", "S", "S"];
function weekdays(length) {
switch (length) {
case "narrow":
return [...weekdaysNarrow];
case "short":
return [...weekdaysShort];
case "long":
return [...weekdaysLong];
case "numeric":
return ["1", "2", "3", "4", "5", "6", "7"];
default:
return null;
}
}
const meridiems = ["AM", "PM"];
const erasLong = ["Before Christ", "Anno Domini"];
const erasShort = ["BC", "AD"];
const erasNarrow = ["B", "A"];
function eras(length) {
switch (length) {
case "narrow":
return [...erasNarrow];
case "short":
return [...erasShort];
case "long":
return [...erasLong];
default:
return null;
}
}
function meridiemForDateTime(dt) {
return meridiems[dt.hour < 12 ? 0 : 1];
}
function weekdayForDateTime(dt, length) {
return weekdays(length)[dt.weekday - 1];
}
function monthForDateTime(dt, length) {
return months(length)[dt.month - 1];
}
function eraForDateTime(dt, length) {
return eras(length)[dt.year < 0 ? 0 : 1];
}
function formatRelativeTime(unit, count, numeric = "always", narrow = false) {
const units = {
years: ["year", "yr."],
quarters: ["quarter", "qtr."],
months: ["month", "mo."],
weeks: ["week", "wk."],
days: ["day", "day", "days"],
hours: ["hour", "hr."],
minutes: ["minute", "min."],
seconds: ["second", "sec."],
};
const lastable = ["hours", "minutes", "seconds"].indexOf(unit) === -1;
if (numeric === "auto" && lastable) {
const isDay = unit === "days";
switch (count) {
case 1:
return isDay ? "tomorrow" : `next ${units[unit][0]}`;
case -1:
return isDay ? "yesterday" : `last ${units[unit][0]}`;
case 0:
return isDay ? "today" : `this ${units[unit][0]}`;
}
}
const isInPast = Object.is(count, -0) || count < 0,
fmtValue = Math.abs(count),
singular = fmtValue === 1,
lilUnits = units[unit],
fmtUnit = narrow
? singular
? lilUnits[1]
: lilUnits[2] || lilUnits[1]
: singular
? units[unit][0]
: unit;
return isInPast ? `${fmtValue} ${fmtUnit} ago` : `in ${fmtValue} ${fmtUnit}`;
}
function stringifyTokens(splits, tokenToString) {
let s = "";
for (const token of splits) {
if (token.literal) {
s += token.val;
} else {
s += tokenToString(token.val);
}
}
return s;
}
const macroTokenToFormatOpts = {
D: DATE_SHORT,
DD: DATE_MED,
DDD: DATE_FULL,
DDDD: DATE_HUGE,
t: TIME_SIMPLE,
tt: TIME_WITH_SECONDS,
ttt: TIME_WITH_SHORT_OFFSET,
tttt: TIME_WITH_LONG_OFFSET,
T: TIME_24_SIMPLE,
TT: TIME_24_WITH_SECONDS,
TTT: TIME_24_WITH_SHORT_OFFSET,
TTTT: TIME_24_WITH_LONG_OFFSET,
f: DATETIME_SHORT,
ff: DATETIME_MED,
fff: DATETIME_FULL,
ffff: DATETIME_HUGE,
F: DATETIME_SHORT_WITH_SECONDS,
FF: DATETIME_MED_WITH_SECONDS,
FFF: DATETIME_FULL_WITH_SECONDS,
FFFF: DATETIME_HUGE_WITH_SECONDS,
};
/**
* @private
*/
class Formatter {
static create(locale, opts = {}) {
return new Formatter(locale, opts);
}
static parseFormat(fmt) {
// white-space is always considered a literal in user-provided formats
// the " " token has a special meaning (see unitForToken)
let current = null,
currentFull = "",
bracketed = false;
const splits = [];
for (let i = 0; i < fmt.length; i++) {
const c = fmt.charAt(i);
if (c === "'") {
// turn '' into a literal signal quote instead of just skipping the empty literal
if (currentFull.length > 0 || bracketed) {
splits.push({
literal: bracketed || /^\s+$/.test(currentFull),
val: currentFull === "" ? "'" : currentFull,
});
}
current = null;
currentFull = "";
bracketed = !bracketed;
} else if (bracketed) {
currentFull += c;
} else if (c === current) {
currentFull += c;
} else {
if (currentFull.length > 0) {
splits.push({ literal: /^\s+$/.test(currentFull), val: currentFull });
}
currentFull = c;
current = c;
}
}
if (currentFull.length > 0) {
splits.push({ literal: bracketed || /^\s+$/.test(currentFull), val: currentFull });
}
return splits;
}
static macroTokenToFormatOpts(token) {
return macroTokenToFormatOpts[token];
}
constructor(locale, formatOpts) {
this.opts = formatOpts;
this.loc = locale;
this.systemLoc = null;
}
formatWithSystemDefault(dt, opts) {
if (this.systemLoc === null) {
this.systemLoc = this.loc.redefaultToSystem();
}
const df = this.systemLoc.dtFormatter(dt, { ...this.opts, ...opts });
return df.format();
}
dtFormatter(dt, opts = {}) {
return this.loc.dtFormatter(dt, { ...this.opts, ...opts });
}
formatDateTime(dt, opts) {
return this.dtFormatter(dt, opts).format();
}
formatDateTimeParts(dt, opts) {
return this.dtFormatter(dt, opts).formatToParts();
}
formatInterval(interval, opts) {
const df = this.dtFormatter(interval.start, opts);
return df.dtf.formatRange(interval.start.toJSDate(), interval.end.toJSDate());
}
resolvedOptions(dt, opts) {
return this.dtFormatter(dt, opts).resolvedOptions();
}
num(n, p = 0, signDisplay = undefined) {
// we get some perf out of doing this here, annoyingly
if (this.opts.forceSimple) {
return padStart(n, p);
}
const opts = { ...this.opts };
if (p > 0) {
opts.padTo = p;
}
if (signDisplay) {
opts.signDisplay = signDisplay;
}
return this.loc.numberFormatter(opts).format(n);
}
formatDateTimeFromString(dt, fmt) {
const knownEnglish = this.loc.listingMode() === "en",
useDateTimeFormatter = this.loc.outputCalendar && this.loc.outputCalendar !== "gregory",
string = (opts, extract) => this.loc.extract(dt, opts, extract),
formatOffset = (opts) => {
if (dt.isOffsetFixed && dt.offset === 0 && opts.allowZ) {
return "Z";
}
return dt.isValid ? dt.zone.formatOffset(dt.ts, opts.format) : "";
},
meridiem = () =>
knownEnglish
? meridiemForDateTime(dt)
: string({ hour: "numeric", hourCycle: "h12" }, "dayperiod"),
month = (length, standalone) =>
knownEnglish
? monthForDateTime(dt, length)
: string(standalone ? { month: length } : { month: length, day: "numeric" }, "month"),
weekday = (length, standalone) =>
knownEnglish
? weekdayForDateTime(dt, length)
: string(
standalone ? { weekday: length } : { weekday: length, month: "long", day: "numeric" },
"weekday"
),
maybeMacro = (token) => {
const formatOpts = Formatter.macroTokenToFormatOpts(token);
if (formatOpts) {
return this.formatWithSystemDefault(dt, formatOpts);
} else {
return token;
}
},
era = (length) =>
knownEnglish ? eraForDateTime(dt, length) : string({ era: length }, "era"),
tokenToString = (token) => {
// Where possible: https://cldr.unicode.org/translation/date-time/date-time-symbols
switch (token) {
// ms
case "S":
return this.num(dt.millisecond);
case "u":
// falls through
case "SSS":
return this.num(dt.millisecond, 3);
// seconds
case "s":
return this.num(dt.second);
case "ss":
return this.num(dt.second, 2);
// fractional seconds
case "uu":
return this.num(Math.floor(dt.millisecond / 10), 2);
case "uuu":
return this.num(Math.floor(dt.millisecond / 100));
// minutes
case "m":
return this.num(dt.minute);
case "mm":
return this.num(dt.minute, 2);
// hours
case "h":
return this.num(dt.hour % 12 === 0 ? 12 : dt.hour % 12);
case "hh":
return this.num(dt.hour % 12 === 0 ? 12 : dt.hour % 12, 2);
case "H":
return this.num(dt.hour);
case "HH":
return this.num(dt.hour, 2);
// offset
case "Z":
// like +6
return formatOffset({ format: "narrow", allowZ: this.opts.allowZ });
case "ZZ":
// like +06:00
return formatOffset({ format: "short", allowZ: this.opts.allowZ });
case "ZZZ":
// like +0600
return formatOffset({ format: "techie", allowZ: this.opts.allowZ });
case "ZZZZ":
// like EST
return dt.zone.offsetName(dt.ts, { format: "short", locale: this.loc.locale });
case "ZZZZZ":
// like Eastern Standard Time
return dt.zone.offsetName(dt.ts, { format: "long", locale: this.loc.locale });
// zone
case "z":
// like America/New_York
return dt.zoneName;
// meridiems
case "a":
return meridiem();
// dates
case "d":
return useDateTimeFormatter ? string({ day: "numeric" }, "day") : this.num(dt.day);
case "dd":
return useDateTimeFormatter ? string({ day: "2-digit" }, "day") : this.num(dt.day, 2);
// weekdays - standalone
case "c":
// like 1
return this.num(dt.weekday);
case "ccc":
// like 'Tues'
return weekday("short", true);
case "cccc":
// like 'Tuesday'
return weekday("long", true);
case "ccccc":
// like 'T'
return weekday("narrow", true);
// weekdays - format
case "E":
// like 1
return this.num(dt.weekday);
case "EEE":
// like 'Tues'
return weekday("short", false);
case "EEEE":
// like 'Tuesday'
return weekday("long", false);
case "EEEEE":
// like 'T'
return weekday("narrow", false);
// months - standalone
case "L":
// like 1
return useDateTimeFormatter
? string({ month: "numeric", day: "numeric" }, "month")
: this.num(dt.month);
case "LL":
// like 01, doesn't seem to work
return useDateTimeFormatter
? string({ month: "2-digit", day: "numeric" }, "month")
: this.num(dt.month, 2);
case "LLL":
// like Jan
return month("short", true);
case "LLLL":
// like January
return month("long", true);
case "LLLLL":
// like J
return month("narrow", true);
// months - format
case "M":
// like 1
return useDateTimeFormatter
? string({ month: "numeric" }, "month")
: this.num(dt.month);
case "MM":
// like 01
return useDateTimeFormatter
? string({ month: "2-digit" }, "month")
: this.num(dt.month, 2);
case "MMM":
// like Jan
return month("short", false);
case "MMMM":
// like January
return month("long", false);
case "MMMMM":
// like J
return month("narrow", false);
// years
case "y":
// like 2014
return useDateTimeFormatter ? string({ year: "numeric" }, "year") : this.num(dt.year);
case "yy":
// like 14
return useDateTimeFormatter
? string({ year: "2-digit" }, "year")
: this.num(dt.year.toString().slice(-2), 2);
case "yyyy":
// like 0012
return useDateTimeFormatter
? string({ year: "numeric" }, "year")
: this.num(dt.year, 4);
case "yyyyyy":
// like 000012
return useDateTimeFormatter
? string({ year: "numeric" }, "year")
: this.num(dt.year, 6);
// eras
case "G":
// like AD
return era("short");
case "GG":
// like Anno Domini
return era("long");
case "GGGGG":
return era("narrow");
case "kk":
return this.num(dt.weekYear.toString().slice(-2), 2);
case "kkkk":
return this.num(dt.weekYear, 4);
case "W":
return this.num(dt.weekNumber);
case "WW":
return this.num(dt.weekNumber, 2);
case "n":
return this.num(dt.localWeekNumber);
case "nn":
return this.num(dt.localWeekNumber, 2);
case "ii":
return this.num(dt.localWeekYear.toString().slice(-2), 2);
case "iiii":
return this.num(dt.localWeekYear, 4);
case "o":
return this.num(dt.ordinal);
case "ooo":
return this.num(dt.ordinal, 3);
case "q":
// like 1
return this.num(dt.quarter);
case "qq":
// like 01
return this.num(dt.quarter, 2);
case "X":
return this.num(Math.floor(dt.ts / 1000));
case "x":
return this.num(dt.ts);
default:
return maybeMacro(token);
}
};
return stringifyTokens(Formatter.parseFormat(fmt), tokenToString);
}
formatDurationFromString(dur, fmt) {
const invertLargest = this.opts.signMode === "negativeLargestOnly" ? -1 : 1;
const tokenToField = (token) => {
switch (token[0]) {
case "S":
return "milliseconds";
case "s":
return "seconds";
case "m":
return "minutes";
case "h":
return "hours";
case "d":
return "days";
case "w":
return "weeks";
case "M":
return "months";
case "y":
return "years";
default:
return null;
}
},
tokenToString = (lildur, info) => (token) => {
const mapped = tokenToField(token);
if (mapped) {
const inversionFactor =
info.isNegativeDuration && mapped !== info.largestUnit ? invertLargest : 1;
let signDisplay;
if (this.opts.signMode === "negativeLargestOnly" && mapped !== info.largestUnit) {
signDisplay = "never";
} else if (this.opts.signMode === "all") {
signDisplay = "always";
} else {
// "auto" and "negative" are the same, but "auto" has better support
signDisplay = "auto";
}
return this.num(lildur.get(mapped) * inversionFactor, token.length, signDisplay);
} else {
return token;
}
},
tokens = Formatter.parseFormat(fmt),
realTokens = tokens.reduce(
(found, { literal, val }) => (literal ? found : found.concat(val)),
[]
),
collapsed = dur.shiftTo(...realTokens.map(tokenToField).filter((t) => t)),
durationInfo = {
isNegativeDuration: collapsed < 0,
// this relies on "collapsed" being based on "shiftTo", which builds up the object
// in order
largestUnit: Object.keys(collapsed.values)[0],
};
return stringifyTokens(tokens, tokenToString(collapsed, durationInfo));
}
}
/*
* This file handles parsing for well-specified formats. Here's how it works:
* Two things go into parsing: a regex to match with and an extractor to take apart the groups in the match.
* An extractor is just a function that takes a regex match array and returns a { year: ..., month: ... } object
* parse() does the work of executing the regex and applying the extractor. It takes multiple regex/extractor pairs to try in sequence.
* Extractors can take a "cursor" representing the offset in the match to look at. This makes it easy to combine extractors.
* combineExtractors() does the work of combining them, keeping track of the cursor through multiple extractions.
* Some extractions are super dumb and simpleParse and fromStrings help DRY them.
*/
const ianaRegex = /[A-Za-z_+-]{1,256}(?::?\/[A-Za-z0-9_+-]{1,256}(?:\/[A-Za-z0-9_+-]{1,256})?)?/;
function combineRegexes(...regexes) {
const full = regexes.reduce((f, r) => f + r.source, "");
return RegExp(`^${full}$`);
}
function combineExtractors(...extractors) {
return (m) =>
extractors
.reduce(
([mergedVals, mergedZone, cursor], ex) => {
const [val, zone, next] = ex(m, cursor);
return [{ ...mergedVals, ...val }, zone || mergedZone, next];
},
[{}, null, 1]
)
.slice(0, 2);
}
function parse(s, ...patterns) {
if (s == null) {
return [null, null];
}
for (const [regex, extractor] of patterns) {
const m = regex.exec(s);
if (m) {
return extractor(m);
}
}
return [null, null];
}
function simpleParse(...keys) {
return (match, cursor) => {
const ret = {};
let i;
for (i = 0; i < keys.length; i++) {
ret[keys[i]] = parseInteger(match[cursor + i]);
}
return [ret, null, cursor + i];
};
}
// ISO and SQL parsing
const offsetRegex = /(?:([Zz])|([+-]\d\d)(?::?(\d\d))?)/;
const isoExtendedZone = `(?:${offsetRegex.source}?(?:\\[(${ianaRegex.source})\\])?)?`;
const isoTimeBaseRegex = /(\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d{1,30}))?)?)?/;
const isoTimeRegex = RegExp(`${isoTimeBaseRegex.source}${isoExtendedZone}`);
const isoTimeExtensionRegex = RegExp(`(?:[Tt]${isoTimeRegex.source})?`);
const isoYmdRegex = /([+-]\d{6}|\d{4})(?:-?(\d\d)(?:-?(\d\d))?)?/;
const isoWeekRegex = /(\d{4})-?W(\d\d)(?:-?(\d))?/;
const isoOrdinalRegex = /(\d{4})-?(\d{3})/;
const extractISOWeekData = simpleParse("weekYear", "weekNumber", "weekDay");
const extractISOOrdinalData = simpleParse("year", "ordinal");
const sqlYmdRegex = /(\d{4})-(\d\d)-(\d\d)/; // dumbed-down version of the ISO one
const sqlTimeRegex = RegExp(
`${isoTimeBaseRegex.source} ?(?:${offsetRegex.source}|(${ianaRegex.source}))?`
);
const sqlTimeExtensionRegex = RegExp(`(?: ${sqlTimeRegex.source})?`);
function int(match, pos, fallback) {
const m = match[pos];
return isUndefined$1(m) ? fallback : parseInteger(m);
}
function extractISOYmd(match, cursor) {
const item = {
year: int(match, cursor),
month: int(match, cursor + 1, 1),
day: int(match, cursor + 2, 1),
};
return [item, null, cursor + 3];
}
function extractISOTime(match, cursor) {
const item = {
hours: int(match, cursor, 0),
minutes: int(match, cursor + 1, 0),
seconds: int(match, cursor + 2, 0),
milliseconds: parseMillis(match[cursor + 3]),
};
return [item, null, cursor + 4];
}
function extractISOOffset(match, cursor) {
const local = !match[cursor] && !match[cursor + 1],
fullOffset = signedOffset(match[cursor + 1], match[cursor + 2]),
zone = local ? null : FixedOffsetZone.instance(fullOffset);
return [{}, zone, cursor + 3];
}
function extractIANAZone(match, cursor) {
const zone = match[cursor] ? IANAZone.create(match[cursor]) : null;
return [{}, zone, cursor + 1];
}
// ISO time parsing
const isoTimeOnly = RegExp(`^T?${isoTimeBaseRegex.source}$`);
// ISO duration parsing
const isoDuration =
/^-?P(?:(?:(-?\d{1,20}(?:\.\d{1,20})?)Y)?(?:(-?\d{1,20}(?:\.\d{1,20})?)M)?(?:(-?\d{1,20}(?:\.\d{1,20})?)W)?(?:(-?\d{1,20}(?:\.\d{1,20})?)D)?(?:T(?:(-?\d{1,20}(?:\.\d{1,20})?)H)?(?:(-?\d{1,20}(?:\.\d{1,20})?)M)?(?:(-?\d{1,20})(?:[.,](-?\d{1,20}))?S)?)?)$/;
function extractISODuration(match) {
const [s, yearStr, monthStr, weekStr, dayStr, hourStr, minuteStr, secondStr, millisecondsStr] =
match;
const hasNegativePrefix = s[0] === "-";
const negativeSeconds = secondStr && secondStr[0] === "-";
const maybeNegate = (num, force = false) =>
num !== undefined && (force || (num && hasNegativePrefix)) ? -num : num;
return [
{
years: maybeNegate(parseFloating(yearStr)),
months: maybeNegate(parseFloating(monthStr)),
weeks: maybeNegate(parseFloating(weekStr)),
days: maybeNegate(parseFloating(dayStr)),
hours: maybeNegate(parseFloating(hourStr)),
minutes: maybeNegate(parseFloating(minuteStr)),
seconds: maybeNegate(parseFloating(secondStr), secondStr === "-0"),
milliseconds: maybeNegate(parseMillis(millisecondsStr), negativeSeconds),
},
];
}
// These are a little braindead. EDT *should* tell us that we're in, say, America/New_York
// and not just that we're in -240 *right now*. But since I don't think these are used that often
// I'm just going to ignore that
const obsOffsets = {
GMT: 0,
EDT: -4 * 60,
EST: -5 * 60,
CDT: -5 * 60,
CST: -6 * 60,
MDT: -6 * 60,
MST: -7 * 60,
PDT: -7 * 60,
PST: -8 * 60,
};
function fromStrings(weekdayStr, yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) {
const result = {
year: yearStr.length === 2 ? untruncateYear(parseInteger(yearStr)) : parseInteger(yearStr),
month: monthsShort.indexOf(monthStr) + 1,
day: parseInteger(dayStr),
hour: parseInteger(hourStr),
minute: parseInteger(minuteStr),
};
if (secondStr) result.second = parseInteger(secondStr);
if (weekdayStr) {
result.weekday =
weekdayStr.length > 3
? weekdaysLong.indexOf(weekdayStr) + 1
: weekdaysShort.indexOf(weekdayStr) + 1;
}
return result;
}
// RFC 2822/5322
const rfc2822 =
/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|(?:([+-]\d\d)(\d\d)))$/;
function extractRFC2822(match) {
const [
,
weekdayStr,
dayStr,
monthStr,
yearStr,
hourStr,
minuteStr,
secondStr,
obsOffset,
milOffset,
offHourStr,
offMinuteStr,
] = match,
result = fromStrings(weekdayStr, yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr);
let offset;
if (obsOffset) {
offset = obsOffsets[obsOffset];
} else if (milOffset) {
offset = 0;
} else {
offset = signedOffset(offHourStr, offMinuteStr);
}
return [result, new FixedOffsetZone(offset)];
}
function preprocessRFC2822(s) {
// Remove comments and folding whitespace and replace multiple-spaces with a single space
return s
.replace(/\([^()]*\)|[\n\t]/g, " ")
.replace(/(\s\s+)/g, " ")
.trim();
}
// http date
const rfc1123 =
/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (\d\d) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d\d):(\d\d):(\d\d) GMT$/,
rfc850 =
/^(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (\d\d)-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d\d) (\d\d):(\d\d):(\d\d) GMT$/,
ascii =
/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ( \d|\d\d) (\d\d):(\d\d):(\d\d) (\d{4})$/;
function extractRFC1123Or850(match) {
const [, weekdayStr, dayStr, monthStr, yearStr, hourStr, minuteStr, secondStr] = match,
result = fromStrings(weekdayStr, yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr);
return [result, FixedOffsetZone.utcInstance];
}
function extractASCII(match) {
const [, weekdayStr, monthStr, dayStr, hourStr, minuteStr, secondStr, yearStr] = match,
result = fromStrings(weekdayStr, yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr);
return [result, FixedOffsetZone.utcInstance];
}
const isoYmdWithTimeExtensionRegex = combineRegexes(isoYmdRegex, isoTimeExtensionRegex);
const isoWeekWithTimeExtensionRegex = combineRegexes(isoWeekRegex, isoTimeExtensionRegex);
const isoOrdinalWithTimeExtensionRegex = combineRegexes(isoOrdinalRegex, isoTimeExtensionRegex);
const isoTimeCombinedRegex = combineRegexes(isoTimeRegex);
const extractISOYmdTimeAndOffset = combineExtractors(
extractISOYmd,
extractISOTime,
extractISOOffset,
extractIANAZone
);
const extractISOWeekTimeAndOffset = combineExtractors(
extractISOWeekData,
extractISOTime,
extractISOOffset,
extractIANAZone
);
const extractISOOrdinalDateAndTime = combineExtractors(
extractISOOrdinalData,
extractISOTime,
extractISOOffset,
extractIANAZone
);
const extractISOTimeAndOffset = combineExtractors(
extractISOTime,
extractISOOffset,
extractIANAZone
);
/*
* @private
*/
function parseISODate(s) {
return parse(
s,
[isoYmdWithTimeExtensionRegex, extractISOYmdTimeAndOffset],
[isoWeekWithTimeExtensionRegex, extractISOWeekTimeAndOffset],
[isoOrdinalWithTimeExtensionRegex, extractISOOrdinalDateAndTime],
[isoTimeCombinedRegex, extractISOTimeAndOffset]
);
}
function parseRFC2822Date(s) {
return parse(preprocessRFC2822(s), [rfc2822, extractRFC2822]);
}
function parseHTTPDate(s) {
return parse(
s,
[rfc1123, extractRFC1123Or850],
[rfc850, extractRFC1123Or850],
[ascii, extractASCII]
);
}
function parseISODuration(s) {
return parse(s, [isoDuration, extractISODuration]);
}
const extractISOTimeOnly = combineExtractors(extractISOTime);
function parseISOTimeOnly(s) {
return parse(s, [isoTimeOnly, extractISOTimeOnly]);
}
const sqlYmdWithTimeExtensionRegex = combineRegexes(sqlYmdRegex, sqlTimeExtensionRegex);
const sqlTimeCombinedRegex = combineRegexes(sqlTimeRegex);
const extractISOTimeOffsetAndIANAZone = combineExtractors(
extractISOTime,
extractISOOffset,
extractIANAZone
);
function parseSQL(s) {
return parse(
s,
[sqlYmdWithTimeExtensionRegex, extractISOYmdTimeAndOffset],
[sqlTimeCombinedRegex, extractISOTimeOffsetAndIANAZone]
);
}
const INVALID$2 = "Invalid Duration";
// unit conversion constants
const lowOrderMatrix = {
weeks: {
days: 7,
hours: 7 * 24,
minutes: 7 * 24 * 60,
seconds: 7 * 24 * 60 * 60,
milliseconds: 7 * 24 * 60 * 60 * 1000,
},
days: {
hours: 24,
minutes: 24 * 60,
seconds: 24 * 60 * 60,
milliseconds: 24 * 60 * 60 * 1000,
},
hours: { minutes: 60, seconds: 60 * 60, milliseconds: 60 * 60 * 1000 },
minutes: { seconds: 60, milliseconds: 60 * 1000 },
seconds: { milliseconds: 1000 },
},
casualMatrix = {
years: {
quarters: 4,
months: 12,
weeks: 52,
days: 365,
hours: 365 * 24,
minutes: 365 * 24 * 60,
seconds: 365 * 24 * 60 * 60,
milliseconds: 365 * 24 * 60 * 60 * 1000,
},
quarters: {
months: 3,
weeks: 13,
days: 91,
hours: 91 * 24,
minutes: 91 * 24 * 60,
seconds: 91 * 24 * 60 * 60,
milliseconds: 91 * 24 * 60 * 60 * 1000,
},
months: {
weeks: 4,
days: 30,
hours: 30 * 24,
minutes: 30 * 24 * 60,
seconds: 30 * 24 * 60 * 60,
milliseconds: 30 * 24 * 60 * 60 * 1000,
},
...lowOrderMatrix,
},
daysInYearAccurate = 146097.0 / 400,
daysInMonthAccurate = 146097.0 / 4800,
accurateMatrix = {
years: {
quarters: 4,
months: 12,
weeks: daysInYearAccurate / 7,
days: daysInYearAccurate,
hours: daysInYearAccurate * 24,
minutes: daysInYearAccurate * 24 * 60,
seconds: daysInYearAccurate * 24 * 60 * 60,
milliseconds: daysInYearAccurate * 24 * 60 * 60 * 1000,
},
quarters: {
months: 3,
weeks: daysInYearAccurate / 28,
days: daysInYearAccurate / 4,
hours: (daysInYearAccurate * 24) / 4,
minutes: (daysInYearAccurate * 24 * 60) / 4,
seconds: (daysInYearAccurate * 24 * 60 * 60) / 4,
milliseconds: (daysInYearAccurate * 24 * 60 * 60 * 1000) / 4,
},
months: {
weeks: daysInMonthAccurate / 7,
days: daysInMonthAccurate,
hours: daysInMonthAccurate * 24,
minutes: daysInMonthAccurate * 24 * 60,
seconds: daysInMonthAccurate * 24 * 60 * 60,
milliseconds: daysInMonthAccurate * 24 * 60 * 60 * 1000,
},
...lowOrderMatrix,
};
// units ordered by size
const orderedUnits$1 = [
"years",
"quarters",
"months",
"weeks",
"days",
"hours",
"minutes",
"seconds",
"milliseconds",
];
const reverseUnits = orderedUnits$1.slice(0).reverse();
// clone really means "create another instance just like this one, but with these changes"
function clone$1(dur, alts, clear = false) {
// deep merge for vals
const conf = {
values: clear ? alts.values : { ...dur.values, ...(alts.values || {}) },
loc: dur.loc.clone(alts.loc),
conversionAccuracy: alts.conversionAccuracy || dur.conversionAccuracy,
matrix: alts.matrix || dur.matrix,
};
return new Duration(conf);
}
function durationToMillis(matrix, vals) {
let sum = vals.milliseconds ?? 0;
for (const unit of reverseUnits.slice(1)) {
if (vals[unit]) {
sum += vals[unit] * matrix[unit]["milliseconds"];
}
}
return sum;
}
// NB: mutates parameters
function normalizeValues(matrix, vals) {
// the logic below assumes the overall value of the duration is positive
// if this is not the case, factor is used to make it so
const factor = durationToMillis(matrix, vals) < 0 ? -1 : 1;
orderedUnits$1.reduceRight((previous, current) => {
if (!isUndefined$1(vals[current])) {
if (previous) {
const previousVal = vals[previous] * factor;
const conv = matrix[current][previous];
// if (previousVal < 0):
// lower order unit is negative (e.g. { years: 2, days: -2 })
// normalize this by reducing the higher order unit by the appropriate amount
// and increasing the lower order unit
// this can never make the higher order unit negative, because this function only operates
// on positive durations, so the amount of time represented by the lower order unit cannot
// be larger than the higher order unit
// else:
// lower order unit is positive (e.g. { years: 2, days: 450 } or { years: -2, days: 450 })
// in this case we attempt to convert as much as possible from the lower order unit into
// the higher order one
//
// Math.floor takes care of both of these cases, rounding away from 0
// if previousVal < 0 it makes the absolute value larger
// if previousVal >= it makes the absolute value smaller
const rollUp = Math.floor(previousVal / conv);
vals[current] += rollUp * factor;
vals[previous] -= rollUp * conv * factor;
}
return current;
} else {
return previous;
}
}, null);
// try to convert any decimals into smaller units if possible
// for example for { years: 2.5, days: 0, seconds: 0 } we want to get { years: 2, days: 182, hours: 12 }
orderedUnits$1.reduce((previous, current) => {
if (!isUndefined$1(vals[current])) {
if (previous) {
const fraction = vals[previous] % 1;
vals[previous] -= fraction;
vals[current] += fraction * matrix[previous][current];
}
return current;
} else {
return previous;
}
}, null);
}
// Remove all properties with a value of 0 from an object
function removeZeroes(vals) {
const newVals = {};
for (const [key, value] of Object.entries(vals)) {
if (value !== 0) {
newVals[key] = value;
}
}
return newVals;
}
/**
* A Duration object represents a period of time, like "2 months" or "1 day, 1 hour". Conceptually, it's just a map of units to their quantities, accompanied by some additional configuration and methods for creating, parsing, interrogating, transforming, and formatting them. They can be used on their own or in conjunction with other Luxon types; for example, you can use {@link DateTime#plus} to add a Duration object to a DateTime, producing another DateTime.
*
* Here is a brief overview of commonly used methods and getters in Duration:
*
* * **Creation** To create a Duration, use {@link Duration.fromMillis}, {@link Duration.fromObject}, or {@link Duration.fromISO}.
* * **Unit values** See the {@link Duration#years}, {@link Duration#months}, {@link Duration#weeks}, {@link Duration#days}, {@link Duration#hours}, {@link Duration#minutes}, {@link Duration#seconds}, {@link Duration#milliseconds} accessors.
* * **Configuration** See {@link Duration#locale} and {@link Duration#numberingSystem} accessors.
* * **Transformation** To create new Durations out of old ones use {@link Duration#plus}, {@link Duration#minus}, {@link Duration#normalize}, {@link Duration#set}, {@link Duration#reconfigure}, {@link Duration#shiftTo}, and {@link Duration#negate}.
* * **Output** To convert the Duration into other representations, see {@link Duration#as}, {@link Duration#toISO}, {@link Duration#toFormat}, and {@link Duration#toJSON}
*
* There's are more methods documented below. In addition, for more information on subtler topics like internationalization and validity, see the external documentation.
*/
class Duration {
/**
* @private
*/
constructor(config) {
const accurate = config.conversionAccuracy === "longterm" || false;
let matrix = accurate ? accurateMatrix : casualMatrix;
if (config.matrix) {
matrix = config.matrix;
}
/**
* @access private
*/
this.values = config.values;
/**
* @access private
*/
this.loc = config.loc || Locale.create();
/**
* @access private
*/
this.conversionAccuracy = accurate ? "longterm" : "casual";
/**
* @access private
*/
this.invalid = config.invalid || null;
/**
* @access private
*/
this.matrix = matrix;
/**
* @access private
*/
this.isLuxonDuration = true;
}
/**
* Create Duration from a number of milliseconds.
* @param {number} count of milliseconds
* @param {Object} opts - options for parsing
* @param {string} [opts.locale='en-US'] - the locale to use
* @param {string} opts.numberingSystem - the numbering system to use
* @param {string} [opts.conversionAccuracy='casual'] - the conversion system to use
* @return {Duration}
*/
static fromMillis(count, opts) {
return Duration.fromObject({ milliseconds: count }, opts);
}
/**
* Create a Duration from a JavaScript object with keys like 'years' and 'hours'.
* If this object is empty then a zero milliseconds duration is returned.
* @param {Object} obj - the object to create the DateTime from
* @param {number} obj.years
* @param {number} obj.quarters
* @param {number} obj.months
* @param {number} obj.weeks
* @param {number} obj.days
* @param {number} obj.hours
* @param {number} obj.minutes
* @param {number} obj.seconds
* @param {number} obj.milliseconds
* @param {Object} [opts=[]] - options for creating this Duration
* @param {string} [opts.locale='en-US'] - the locale to use
* @param {string} opts.numberingSystem - the numbering system to use
* @param {string} [opts.conversionAccuracy='casual'] - the preset conversion system to use
* @param {string} [opts.matrix=Object] - the custom conversion system to use
* @return {Duration}
*/
static fromObject(obj, opts = {}) {
if (obj == null || typeof obj !== "object") {
throw new InvalidArgumentError(
`Duration.fromObject: argument expected to be an object, got ${
obj === null ? "null" : typeof obj
}`
);
}
return new Duration({
values: normalizeObject(obj, Duration.normalizeUnit),
loc: Locale.fromObject(opts),
conversionAccuracy: opts.conversionAccuracy,
matrix: opts.matrix,
});
}
/**
* Create a Duration from DurationLike.
*
* @param {Object | number | Duration} durationLike
* One of:
* - object with keys like 'years' and 'hours'.
* - number representing milliseconds
* - Duration instance
* @return {Duration}
*/
static fromDurationLike(durationLike) {
if (isNumber$1(durationLike)) {
return Duration.fromMillis(durationLike);
} else if (Duration.isDuration(durationLike)) {
return durationLike;
} else if (typeof durationLike === "object") {
return Duration.fromObject(durationLike);
} else {
throw new InvalidArgumentError(
`Unknown duration argument ${durationLike} of type ${typeof durationLike}`
);
}
}
/**
* Create a Duration from an ISO 8601 duration string.
* @param {string} text - text to parse
* @param {Object} opts - options for parsing
* @param {string} [opts.locale='en-US'] - the locale to use
* @param {string} opts.numberingSystem - the numbering system to use
* @param {string} [opts.conversionAccuracy='casual'] - the preset conversion system to use
* @param {string} [opts.matrix=Object] - the preset conversion system to use
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations
* @example Duration.fromISO('P3Y6M1W4DT12H30M5S').toObject() //=> { years: 3, months: 6, weeks: 1, days: 4, hours: 12, minutes: 30, seconds: 5 }
* @example Duration.fromISO('PT23H').toObject() //=> { hours: 23 }
* @example Duration.fromISO('P5Y3M').toObject() //=> { years: 5, months: 3 }
* @return {Duration}
*/
static fromISO(text, opts) {
const [parsed] = parseISODuration(text);
if (parsed) {
return Duration.fromObject(parsed, opts);
} else {
return Duration.invalid("unparsable", `the input "${text}" can't be parsed as ISO 8601`);
}
}
/**
* Create a Duration from an ISO 8601 time string.
* @param {string} text - text to parse
* @param {Object} opts - options for parsing
* @param {string} [opts.locale='en-US'] - the locale to use
* @param {string} opts.numberingSystem - the numbering system to use
* @param {string} [opts.conversionAccuracy='casual'] - the preset conversion system to use
* @param {string} [opts.matrix=Object] - the conversion system to use
* @see https://en.wikipedia.org/wiki/ISO_8601#Times
* @example Duration.fromISOTime('11:22:33.444').toObject() //=> { hours: 11, minutes: 22, seconds: 33, milliseconds: 444 }
* @example Duration.fromISOTime('11:00').toObject() //=> { hours: 11, minutes: 0, seconds: 0 }
* @example Duration.fromISOTime('T11:00').toObject() //=> { hours: 11, minutes: 0, seconds: 0 }
* @example Duration.fromISOTime('1100').toObject() //=> { hours: 11, minutes: 0, seconds: 0 }
* @example Duration.fromISOTime('T1100').toObject() //=> { hours: 11, minutes: 0, seconds: 0 }
* @return {Duration}
*/
static fromISOTime(text, opts) {
const [parsed] = parseISOTimeOnly(text);
if (parsed) {
return Duration.fromObject(parsed, opts);
} else {
return Duration.invalid("unparsable", `the input "${text}" can't be parsed as ISO 8601`);
}
}
/**
* Create an invalid Duration.
* @param {string} reason - simple string of why this datetime is invalid. Should not contain parameters or anything else data-dependent
* @param {string} [explanation=null] - longer explanation, may include parameters and other useful debugging information
* @return {Duration}
*/
static invalid(reason, explanation = null) {
if (!reason) {
throw new InvalidArgumentError("need to specify a reason the Duration is invalid");
}
const invalid = reason instanceof Invalid ? reason : new Invalid(reason, explanation);
if (Settings.throwOnInvalid) {
throw new InvalidDurationError(invalid);
} else {
return new Duration({ invalid });
}
}
/**
* @private
*/
static normalizeUnit(unit) {
const normalized = {
year: "years",
years: "years",
quarter: "quarters",
quarters: "quarters",
month: "months",
months: "months",
week: "weeks",
weeks: "weeks",
day: "days",
days: "days",
hour: "hours",
hours: "hours",
minute: "minutes",
minutes: "minutes",
second: "seconds",
seconds: "seconds",
millisecond: "milliseconds",
milliseconds: "milliseconds",
}[unit ? unit.toLowerCase() : unit];
if (!normalized) throw new InvalidUnitError(unit);
return normalized;
}
/**
* Check if an object is a Duration. Works across context boundaries
* @param {object} o
* @return {boolean}
*/
static isDuration(o) {
return (o && o.isLuxonDuration) || false;
}
/**
* Get the locale of a Duration, such 'en-GB'
* @type {string}
*/
get locale() {
return this.isValid ? this.loc.locale : null;
}
/**
* Get the numbering system of a Duration, such 'beng'. The numbering system is used when formatting the Duration
*
* @type {string}
*/
get numberingSystem() {
return this.isValid ? this.loc.numberingSystem : null;
}
/**
* Returns a string representation of this Duration formatted according to the specified format string. You may use these tokens:
* * `S` for milliseconds
* * `s` for seconds
* * `m` for minutes
* * `h` for hours
* * `d` for days
* * `w` for weeks
* * `M` for months
* * `y` for years
* Notes:
* * Add padding by repeating the token, e.g. "yy" pads the years to two digits, "hhhh" pads the hours out to four digits
* * Tokens can be escaped by wrapping with single quotes.
* * The duration will be converted to the set of units in the format string using {@link Duration#shiftTo} and the Durations's conversion accuracy setting.
* @param {string} fmt - the format string
* @param {Object} opts - options
* @param {boolean} [opts.floor=true] - floor numerical values
* @param {'negative'|'all'|'negativeLargestOnly'} [opts.signMode=negative] - How to handle signs
* @example Duration.fromObject({ years: 1, days: 6, seconds: 2 }).toFormat("y d s") //=> "1 6 2"
* @example Duration.fromObject({ years: 1, days: 6, seconds: 2 }).toFormat("yy dd sss") //=> "01 06 002"
* @example Duration.fromObject({ years: 1, days: 6, seconds: 2 }).toFormat("M S") //=> "12 518402000"
* @example Duration.fromObject({ days: 6, seconds: 2 }).toFormat("d s", { signMode: "all" }) //=> "+6 +2"
* @example Duration.fromObject({ days: -6, seconds: -2 }).toFormat("d s", { signMode: "all" }) //=> "-6 -2"
* @example Duration.fromObject({ days: -6, seconds: -2 }).toFormat("d s", { signMode: "negativeLargestOnly" }) //=> "-6 2"
* @return {string}
*/
toFormat(fmt, opts = {}) {
// reverse-compat since 1.2; we always round down now, never up, and we do it by default
const fmtOpts = {
...opts,
floor: opts.round !== false && opts.floor !== false,
};
return this.isValid
? Formatter.create(this.loc, fmtOpts).formatDurationFromString(this, fmt)
: INVALID$2;
}
/**
* Returns a string representation of a Duration with all units included.
* To modify its behavior, use `listStyle` and any Intl.NumberFormat option, though `unitDisplay` is especially relevant.
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options
* @param {Object} opts - Formatting options. Accepts the same keys as the options parameter of the native `Intl.NumberFormat` constructor, as well as `listStyle`.
* @param {string} [opts.listStyle='narrow'] - How to format the merged list. Corresponds to the `style` property of the options parameter of the native `Intl.ListFormat` constructor.
* @param {boolean} [opts.showZeros=true] - Show all units previously used by the duration even if they are zero
* @example
* ```js
* var dur = Duration.fromObject({ months: 1, weeks: 0, hours: 5, minutes: 6 })
* dur.toHuman() //=> '1 month, 0 weeks, 5 hours, 6 minutes'
* dur.toHuman({ listStyle: "long" }) //=> '1 month, 0 weeks, 5 hours, and 6 minutes'
* dur.toHuman({ unitDisplay: "short" }) //=> '1 mth, 0 wks, 5 hr, 6 min'
* dur.toHuman({ showZeros: false }) //=> '1 month, 5 hours, 6 minutes'
* ```
*/
toHuman(opts = {}) {
if (!this.isValid) return INVALID$2;
const showZeros = opts.showZeros !== false;
const l = orderedUnits$1
.map((unit) => {
const val = this.values[unit];
if (isUndefined$1(val) || (val === 0 && !showZeros)) {
return null;
}
return this.loc
.numberFormatter({ style: "unit", unitDisplay: "long", ...opts, unit: unit.slice(0, -1) })
.format(val);
})
.filter((n) => n);
return this.loc
.listFormatter({ type: "conjunction", style: opts.listStyle || "narrow", ...opts })
.format(l);
}
/**
* Returns a JavaScript object with this Duration's values.
* @example Duration.fromObject({ years: 1, days: 6, seconds: 2 }).toObject() //=> { years: 1, days: 6, seconds: 2 }
* @return {Object}
*/
toObject() {
if (!this.isValid) return {};
return { ...this.values };
}
/**
* Returns an ISO 8601-compliant string representation of this Duration.
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations
* @example Duration.fromObject({ years: 3, seconds: 45 }).toISO() //=> 'P3YT45S'
* @example Duration.fromObject({ months: 4, seconds: 45 }).toISO() //=> 'P4MT45S'
* @example Duration.fromObject({ months: 5 }).toISO() //=> 'P5M'
* @example Duration.fromObject({ minutes: 5 }).toISO() //=> 'PT5M'
* @example Duration.fromObject({ milliseconds: 6 }).toISO() //=> 'PT0.006S'
* @return {string}
*/
toISO() {
// we could use the formatter, but this is an easier way to get the minimum string
if (!this.isValid) return null;
let s = "P";
if (this.years !== 0) s += this.years + "Y";
if (this.months !== 0 || this.quarters !== 0) s += this.months + this.quarters * 3 + "M";
if (this.weeks !== 0) s += this.weeks + "W";
if (this.days !== 0) s += this.days + "D";
if (this.hours !== 0 || this.minutes !== 0 || this.seconds !== 0 || this.milliseconds !== 0)
s += "T";
if (this.hours !== 0) s += this.hours + "H";
if (this.minutes !== 0) s += this.minutes + "M";
if (this.seconds !== 0 || this.milliseconds !== 0)
// this will handle "floating point madness" by removing extra decimal places
// https://stackoverflow.com/questions/588004/is-floating-point-math-broken
s += roundTo(this.seconds + this.milliseconds / 1000, 3) + "S";
if (s === "P") s += "T0S";
return s;
}
/**
* Returns an ISO 8601-compliant string representation of this Duration, formatted as a time of day.
* Note that this will return null if the duration is invalid, negative, or equal to or greater than 24 hours.
* @see https://en.wikipedia.org/wiki/ISO_8601#Times
* @param {Object} opts - options
* @param {boolean} [opts.suppressMilliseconds=false] - exclude milliseconds from the format if they're 0
* @param {boolean} [opts.suppressSeconds=false] - exclude seconds from the format if they're 0
* @param {boolean} [opts.includePrefix=false] - include the `T` prefix
* @param {string} [opts.format='extended'] - choose between the basic and extended format
* @example Duration.fromObject({ hours: 11 }).toISOTime() //=> '11:00:00.000'
* @example Duration.fromObject({ hours: 11 }).toISOTime({ suppressMilliseconds: true }) //=> '11:00:00'
* @example Duration.fromObject({ hours: 11 }).toISOTime({ suppressSeconds: true }) //=> '11:00'
* @example Duration.fromObject({ hours: 11 }).toISOTime({ includePrefix: true }) //=> 'T11:00:00.000'
* @example Duration.fromObject({ hours: 11 }).toISOTime({ format: 'basic' }) //=> '110000.000'
* @return {string}
*/
toISOTime(opts = {}) {
if (!this.isValid) return null;
const millis = this.toMillis();
if (millis < 0 || millis >= 86400000) return null;
opts = {
suppressMilliseconds: false,
suppressSeconds: false,
includePrefix: false,
format: "extended",
...opts,
includeOffset: false,
};
const dateTime = DateTime.fromMillis(millis, { zone: "UTC" });
return dateTime.toISOTime(opts);
}
/**
* Returns an ISO 8601 representation of this Duration appropriate for use in JSON.
* @return {string}
*/
toJSON() {
return this.toISO();
}
/**
* Returns an ISO 8601 representation of this Duration appropriate for use in debugging.
* @return {string}
*/
toString() {
return this.toISO();
}
/**
* Returns a string representation of this Duration appropriate for the REPL.
* @return {string}
*/
[Symbol.for("nodejs.util.inspect.custom")]() {
if (this.isValid) {
return `Duration { values: ${JSON.stringify(this.values)} }`;
} else {
return `Duration { Invalid, reason: ${this.invalidReason} }`;
}
}
/**
* Returns an milliseconds value of this Duration.
* @return {number}
*/
toMillis() {
if (!this.isValid) return NaN;
return durationToMillis(this.matrix, this.values);
}
/**
* Returns an milliseconds value of this Duration. Alias of {@link toMillis}
* @return {number}
*/
valueOf() {
return this.toMillis();
}
/**
* Make this Duration longer by the specified amount. Return a newly-constructed Duration.
* @param {Duration|Object|number} duration - The amount to add. Either a Luxon Duration, a number of milliseconds, the object argument to Duration.fromObject()
* @return {Duration}
*/
plus(duration) {
if (!this.isValid) return this;
const dur = Duration.fromDurationLike(duration),
result = {};
for (const k of orderedUnits$1) {
if (hasOwnProperty$1(dur.values, k) || hasOwnProperty$1(this.values, k)) {
result[k] = dur.get(k) + this.get(k);
}
}
return clone$1(this, { values: result }, true);
}
/**
* Make this Duration shorter by the specified amount. Return a newly-constructed Duration.
* @param {Duration|Object|number} duration - The amount to subtract. Either a Luxon Duration, a number of milliseconds, the object argument to Duration.fromObject()
* @return {Duration}
*/
minus(duration) {
if (!this.isValid) return this;
const dur = Duration.fromDurationLike(duration);
return this.plus(dur.negate());
}
/**
* Scale this Duration by the specified amount. Return a newly-constructed Duration.
* @param {function} fn - The function to apply to each unit. Arity is 1 or 2: the value of the unit and, optionally, the unit name. Must return a number.
* @example Duration.fromObject({ hours: 1, minutes: 30 }).mapUnits(x => x * 2) //=> { hours: 2, minutes: 60 }
* @example Duration.fromObject({ hours: 1, minutes: 30 }).mapUnits((x, u) => u === "hours" ? x * 2 : x) //=> { hours: 2, minutes: 30 }
* @return {Duration}
*/
mapUnits(fn) {
if (!this.isValid) return this;
const result = {};
for (const k of Object.keys(this.values)) {
result[k] = asNumber(fn(this.values[k], k));
}
return clone$1(this, { values: result }, true);
}
/**
* Get the value of unit.
* @param {string} unit - a unit such as 'minute' or 'day'
* @example Duration.fromObject({years: 2, days: 3}).get('years') //=> 2
* @example Duration.fromObject({years: 2, days: 3}).get('months') //=> 0
* @example Duration.fromObject({years: 2, days: 3}).get('days') //=> 3
* @return {number}
*/
get(unit) {
return this[Duration.normalizeUnit(unit)];
}
/**
* "Set" the values of specified units. Return a newly-constructed Duration.
* @param {Object} values - a mapping of units to numbers
* @example dur.set({ years: 2017 })
* @example dur.set({ hours: 8, minutes: 30 })
* @return {Duration}
*/
set(values) {
if (!this.isValid) return this;
const mixed = { ...this.values, ...normalizeObject(values, Duration.normalizeUnit) };
return clone$1(this, { values: mixed });
}
/**
* "Set" the locale and/or numberingSystem. Returns a newly-constructed Duration.
* @example dur.reconfigure({ locale: 'en-GB' })
* @return {Duration}
*/
reconfigure({ locale, numberingSystem, conversionAccuracy, matrix } = {}) {
const loc = this.loc.clone({ locale, numberingSystem });
const opts = { loc, matrix, conversionAccuracy };
return clone$1(this, opts);
}
/**
* Return the length of the duration in the specified unit.
* @param {string} unit - a unit such as 'minutes' or 'days'
* @example Duration.fromObject({years: 1}).as('days') //=> 365
* @example Duration.fromObject({years: 1}).as('months') //=> 12
* @example Duration.fromObject({hours: 60}).as('days') //=> 2.5
* @return {number}
*/
as(unit) {
return this.isValid ? this.shiftTo(unit).get(unit) : NaN;
}
/**
* Reduce this Duration to its canonical representation in its current units.
* Assuming the overall value of the Duration is positive, this means:
* - excessive values for lower-order units are converted to higher-order units (if possible, see first and second example)
* - negative lower-order units are converted to higher order units (there must be such a higher order unit, otherwise
* the overall value would be negative, see third example)
* - fractional values for higher-order units are converted to lower-order units (if possible, see fourth example)
*
* If the overall value is negative, the result of this method is equivalent to `this.negate().normalize().negate()`.
* @example Duration.fromObject({ years: 2, days: 5000 }).normalize().toObject() //=> { years: 15, days: 255 }
* @example Duration.fromObject({ days: 5000 }).normalize().toObject() //=> { days: 5000 }
* @example Duration.fromObject({ hours: 12, minutes: -45 }).normalize().toObject() //=> { hours: 11, minutes: 15 }
* @example Duration.fromObject({ years: 2.5, days: 0, hours: 0 }).normalize().toObject() //=> { years: 2, days: 182, hours: 12 }
* @return {Duration}
*/
normalize() {
if (!this.isValid) return this;
const vals = this.toObject();
normalizeValues(this.matrix, vals);
return clone$1(this, { values: vals }, true);
}
/**
* Rescale units to its largest representation
* @example Duration.fromObject({ milliseconds: 90000 }).rescale().toObject() //=> { minutes: 1, seconds: 30 }
* @return {Duration}
*/
rescale() {
if (!this.isValid) return this;
const vals = removeZeroes(this.normalize().shiftToAll().toObject());
return clone$1(this, { values: vals }, true);
}
/**
* Convert this Duration into its representation in a different set of units.
* @example Duration.fromObject({ hours: 1, seconds: 30 }).shiftTo('minutes', 'milliseconds').toObject() //=> { minutes: 60, milliseconds: 30000 }
* @return {Duration}
*/
shiftTo(...units) {
if (!this.isValid) return this;
if (units.length === 0) {
return this;
}
units = units.map((u) => Duration.normalizeUnit(u));
const built = {},
accumulated = {},
vals = this.toObject();
let lastUnit;
for (const k of orderedUnits$1) {
if (units.indexOf(k) >= 0) {
lastUnit = k;
let own = 0;
// anything we haven't boiled down yet should get boiled to this unit
for (const ak in accumulated) {
own += this.matrix[ak][k] * accumulated[ak];
accumulated[ak] = 0;
}
// plus anything that's already in this unit
if (isNumber$1(vals[k])) {
own += vals[k];
}
// only keep the integer part for now in the hopes of putting any decimal part
// into a smaller unit later
const i = Math.trunc(own);
built[k] = i;
accumulated[k] = (own * 1000 - i * 1000) / 1000;
// otherwise, keep it in the wings to boil it later
} else if (isNumber$1(vals[k])) {
accumulated[k] = vals[k];
}
}
// anything leftover becomes the decimal for the last unit
// lastUnit must be defined since units is not empty
for (const key in accumulated) {
if (accumulated[key] !== 0) {
built[lastUnit] +=
key === lastUnit ? accumulated[key] : accumulated[key] / this.matrix[lastUnit][key];
}
}
normalizeValues(this.matrix, built);
return clone$1(this, { values: built }, true);
}
/**
* Shift this Duration to all available units.
* Same as shiftTo("years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds")
* @return {Duration}
*/
shiftToAll() {
if (!this.isValid) return this;
return this.shiftTo(
"years",
"months",
"weeks",
"days",
"hours",
"minutes",
"seconds",
"milliseconds"
);
}
/**
* Return the negative of this Duration.
* @example Duration.fromObject({ hours: 1, seconds: 30 }).negate().toObject() //=> { hours: -1, seconds: -30 }
* @return {Duration}
*/
negate() {
if (!this.isValid) return this;
const negated = {};
for (const k of Object.keys(this.values)) {
negated[k] = this.values[k] === 0 ? 0 : -this.values[k];
}
return clone$1(this, { values: negated }, true);
}
/**
* Removes all units with values equal to 0 from this Duration.
* @example Duration.fromObject({ years: 2, days: 0, hours: 0, minutes: 0 }).removeZeros().toObject() //=> { years: 2 }
* @return {Duration}
*/
removeZeros() {
if (!this.isValid) return this;
const vals = removeZeroes(this.values);
return clone$1(this, { values: vals }, true);
}
/**
* Get the years.
* @type {number}
*/
get years() {
return this.isValid ? this.values.years || 0 : NaN;
}
/**
* Get the quarters.
* @type {number}
*/
get quarters() {
return this.isValid ? this.values.quarters || 0 : NaN;
}
/**
* Get the months.
* @type {number}
*/
get months() {
return this.isValid ? this.values.months || 0 : NaN;
}
/**
* Get the weeks
* @type {number}
*/
get weeks() {
return this.isValid ? this.values.weeks || 0 : NaN;
}
/**
* Get the days.
* @type {number}
*/
get days() {
return this.isValid ? this.values.days || 0 : NaN;
}
/**
* Get the hours.
* @type {number}
*/
get hours() {
return this.isValid ? this.values.hours || 0 : NaN;
}
/**
* Get the minutes.
* @type {number}
*/
get minutes() {
return this.isValid ? this.values.minutes || 0 : NaN;
}
/**
* Get the seconds.
* @return {number}
*/
get seconds() {
return this.isValid ? this.values.seconds || 0 : NaN;
}
/**
* Get the milliseconds.
* @return {number}
*/
get milliseconds() {
return this.isValid ? this.values.milliseconds || 0 : NaN;
}
/**
* Returns whether the Duration is invalid. Invalid durations are returned by diff operations
* on invalid DateTimes or Intervals.
* @return {boolean}
*/
get isValid() {
return this.invalid === null;
}
/**
* Returns an error code if this Duration became invalid, or null if the Duration is valid
* @return {string}
*/
get invalidReason() {
return this.invalid ? this.invalid.reason : null;
}
/**
* Returns an explanation of why this Duration became invalid, or null if the Duration is valid
* @type {string}
*/
get invalidExplanation() {
return this.invalid ? this.invalid.explanation : null;
}
/**
* Equality check
* Two Durations are equal iff they have the same units and the same values for each unit.
* @param {Duration} other
* @return {boolean}
*/
equals(other) {
if (!this.isValid || !other.isValid) {
return false;
}
if (!this.loc.equals(other.loc)) {
return false;
}
function eq(v1, v2) {
// Consider 0 and undefined as equal
if (v1 === undefined || v1 === 0) return v2 === undefined || v2 === 0;
return v1 === v2;
}
for (const u of orderedUnits$1) {
if (!eq(this.values[u], other.values[u])) {
return false;
}
}
return true;
}
}
const INVALID$1 = "Invalid Interval";
// checks if the start is equal to or before the end
function validateStartEnd(start, end) {
if (!start || !start.isValid) {
return Interval.invalid("missing or invalid start");
} else if (!end || !end.isValid) {
return Interval.invalid("missing or invalid end");
} else if (end < start) {
return Interval.invalid(
"end before start",
`The end of an interval must be after its start, but you had start=${start.toISO()} and end=${end.toISO()}`
);
} else {
return null;
}
}
/**
* An Interval object represents a half-open interval of time, where each endpoint is a {@link DateTime}. Conceptually, it's a container for those two endpoints, accompanied by methods for creating, parsing, interrogating, comparing, transforming, and formatting them.
*
* Here is a brief overview of the most commonly used methods and getters in Interval:
*
* * **Creation** To create an Interval, use {@link Interval.fromDateTimes}, {@link Interval.after}, {@link Interval.before}, or {@link Interval.fromISO}.
* * **Accessors** Use {@link Interval#start} and {@link Interval#end} to get the start and end.
* * **Interrogation** To analyze the Interval, use {@link Interval#count}, {@link Interval#length}, {@link Interval#hasSame}, {@link Interval#contains}, {@link Interval#isAfter}, or {@link Interval#isBefore}.
* * **Transformation** To create other Intervals out of this one, use {@link Interval#set}, {@link Interval#splitAt}, {@link Interval#splitBy}, {@link Interval#divideEqually}, {@link Interval.merge}, {@link Interval.xor}, {@link Interval#union}, {@link Interval#intersection}, or {@link Interval#difference}.
* * **Comparison** To compare this Interval to another one, use {@link Interval#equals}, {@link Interval#overlaps}, {@link Interval#abutsStart}, {@link Interval#abutsEnd}, {@link Interval#engulfs}
* * **Output** To convert the Interval into other representations, see {@link Interval#toString}, {@link Interval#toLocaleString}, {@link Interval#toISO}, {@link Interval#toISODate}, {@link Interval#toISOTime}, {@link Interval#toFormat}, and {@link Interval#toDuration}.
*/
class Interval {
/**
* @private
*/
constructor(config) {
/**
* @access private
*/
this.s = config.start;
/**
* @access private
*/
this.e = config.end;
/**
* @access private
*/
this.invalid = config.invalid || null;
/**
* @access private
*/
this.isLuxonInterval = true;
}
/**
* Create an invalid Interval.
* @param {string} reason - simple string of why this Interval is invalid. Should not contain parameters or anything else data-dependent
* @param {string} [explanation=null] - longer explanation, may include parameters and other useful debugging information
* @return {Interval}
*/
static invalid(reason, explanation = null) {
if (!reason) {
throw new InvalidArgumentError("need to specify a reason the Interval is invalid");
}
const invalid = reason instanceof Invalid ? reason : new Invalid(reason, explanation);
if (Settings.throwOnInvalid) {
throw new InvalidIntervalError(invalid);
} else {
return new Interval({ invalid });
}
}
/**
* Create an Interval from a start DateTime and an end DateTime. Inclusive of the start but not the end.
* @param {DateTime|Date|Object} start
* @param {DateTime|Date|Object} end
* @return {Interval}
*/
static fromDateTimes(start, end) {
const builtStart = friendlyDateTime(start),
builtEnd = friendlyDateTime(end);
const validateError = validateStartEnd(builtStart, builtEnd);
if (validateError == null) {
return new Interval({
start: builtStart,
end: builtEnd,
});
} else {
return validateError;
}
}
/**
* Create an Interval from a start DateTime and a Duration to extend to.
* @param {DateTime|Date|Object} start
* @param {Duration|Object|number} duration - the length of the Interval.
* @return {Interval}
*/
static after(start, duration) {
const dur = Duration.fromDurationLike(duration),
dt = friendlyDateTime(start);
return Interval.fromDateTimes(dt, dt.plus(dur));
}
/**
* Create an Interval from an end DateTime and a Duration to extend backwards to.
* @param {DateTime|Date|Object} end
* @param {Duration|Object|number} duration - the length of the Interval.
* @return {Interval}
*/
static before(end, duration) {
const dur = Duration.fromDurationLike(duration),
dt = friendlyDateTime(end);
return Interval.fromDateTimes(dt.minus(dur), dt);
}
/**
* Create an Interval from an ISO 8601 string.
* Accepts `<start>/<end>`, `<start>/<duration>`, and `<duration>/<end>` formats.
* @param {string} text - the ISO string to parse
* @param {Object} [opts] - options to pass {@link DateTime#fromISO} and optionally {@link Duration#fromISO}
* @see https://en.wikipedia.org/wiki/ISO_8601#Time_intervals
* @return {Interval}
*/
static fromISO(text, opts) {
const [s, e] = (text || "").split("/", 2);
if (s && e) {
let start, startIsValid;
try {
start = DateTime.fromISO(s, opts);
startIsValid = start.isValid;
} catch (e) {
startIsValid = false;
}
let end, endIsValid;
try {
end = DateTime.fromISO(e, opts);
endIsValid = end.isValid;
} catch (e) {
endIsValid = false;
}
if (startIsValid && endIsValid) {
return Interval.fromDateTimes(start, end);
}
if (startIsValid) {
const dur = Duration.fromISO(e, opts);
if (dur.isValid) {
return Interval.after(start, dur);
}
} else if (endIsValid) {
const dur = Duration.fromISO(s, opts);
if (dur.isValid) {
return Interval.before(end, dur);
}
}
}
return Interval.invalid("unparsable", `the input "${text}" can't be parsed as ISO 8601`);
}
/**
* Check if an object is an Interval. Works across context boundaries
* @param {object} o
* @return {boolean}
*/
static isInterval(o) {
return (o && o.isLuxonInterval) || false;
}
/**
* Returns the start of the Interval
* @type {DateTime}
*/
get start() {
return this.isValid ? this.s : null;
}
/**
* Returns the end of the Interval. This is the first instant which is not part of the interval
* (Interval is half-open).
* @type {DateTime}
*/
get end() {
return this.isValid ? this.e : null;
}
/**
* Returns the last DateTime included in the interval (since end is not part of the interval)
* @type {DateTime}
*/
get lastDateTime() {
return this.isValid ? (this.e ? this.e.minus(1) : null) : null;
}
/**
* Returns whether this Interval's end is at least its start, meaning that the Interval isn't 'backwards'.
* @type {boolean}
*/
get isValid() {
return this.invalidReason === null;
}
/**
* Returns an error code if this Interval is invalid, or null if the Interval is valid
* @type {string}
*/
get invalidReason() {
return this.invalid ? this.invalid.reason : null;
}
/**
* Returns an explanation of why this Interval became invalid, or null if the Interval is valid
* @type {string}
*/
get invalidExplanation() {
return this.invalid ? this.invalid.explanation : null;
}
/**
* Returns the length of the Interval in the specified unit.
* @param {string} unit - the unit (such as 'hours' or 'days') to return the length in.
* @return {number}
*/
length(unit = "milliseconds") {
return this.isValid ? this.toDuration(...[unit]).get(unit) : NaN;
}
/**
* Returns the count of minutes, hours, days, months, or years included in the Interval, even in part.
* Unlike {@link Interval#length} this counts sections of the calendar, not periods of time, e.g. specifying 'day'
* asks 'what dates are included in this interval?', not 'how many days long is this interval?'
* @param {string} [unit='milliseconds'] - the unit of time to count.
* @param {Object} opts - options
* @param {boolean} [opts.useLocaleWeeks=false] - If true, use weeks based on the locale, i.e. use the locale-dependent start of the week; this operation will always use the locale of the start DateTime
* @return {number}
*/
count(unit = "milliseconds", opts) {
if (!this.isValid) return NaN;
const start = this.start.startOf(unit, opts);
let end;
if (opts?.useLocaleWeeks) {
end = this.end.reconfigure({ locale: start.locale });
} else {
end = this.end;
}
end = end.startOf(unit, opts);
return Math.floor(end.diff(start, unit).get(unit)) + (end.valueOf() !== this.end.valueOf());
}
/**
* Returns whether this Interval's start and end are both in the same unit of time
* @param {string} unit - the unit of time to check sameness on
* @return {boolean}
*/
hasSame(unit) {
return this.isValid ? this.isEmpty() || this.e.minus(1).hasSame(this.s, unit) : false;
}
/**
* Return whether this Interval has the same start and end DateTimes.
* @return {boolean}
*/
isEmpty() {
return this.s.valueOf() === this.e.valueOf();
}
/**
* Return whether this Interval's start is after the specified DateTime.
* @param {DateTime} dateTime
* @return {boolean}
*/
isAfter(dateTime) {
if (!this.isValid) return false;
return this.s > dateTime;
}
/**
* Return whether this Interval's end is before the specified DateTime.
* @param {DateTime} dateTime
* @return {boolean}
*/
isBefore(dateTime) {
if (!this.isValid) return false;
return this.e <= dateTime;
}
/**
* Return whether this Interval contains the specified DateTime.
* @param {DateTime} dateTime
* @return {boolean}
*/
contains(dateTime) {
if (!this.isValid) return false;
return this.s <= dateTime && this.e > dateTime;
}
/**
* "Sets" the start and/or end dates. Returns a newly-constructed Interval.
* @param {Object} values - the values to set
* @param {DateTime} values.start - the starting DateTime
* @param {DateTime} values.end - the ending DateTime
* @return {Interval}
*/
set({ start, end } = {}) {
if (!this.isValid) return this;
return Interval.fromDateTimes(start || this.s, end || this.e);
}
/**
* Split this Interval at each of the specified DateTimes
* @param {...DateTime} dateTimes - the unit of time to count.
* @return {Array}
*/
splitAt(...dateTimes) {
if (!this.isValid) return [];
const sorted = dateTimes
.map(friendlyDateTime)
.filter((d) => this.contains(d))
.sort((a, b) => a.toMillis() - b.toMillis()),
results = [];
let { s } = this,
i = 0;
while (s < this.e) {
const added = sorted[i] || this.e,
next = +added > +this.e ? this.e : added;
results.push(Interval.fromDateTimes(s, next));
s = next;
i += 1;
}
return results;
}
/**
* Split this Interval into smaller Intervals, each of the specified length.
* Left over time is grouped into a smaller interval
* @param {Duration|Object|number} duration - The length of each resulting interval.
* @return {Array}
*/
splitBy(duration) {
const dur = Duration.fromDurationLike(duration);
if (!this.isValid || !dur.isValid || dur.as("milliseconds") === 0) {
return [];
}
let { s } = this,
idx = 1,
next;
const results = [];
while (s < this.e) {
const added = this.start.plus(dur.mapUnits((x) => x * idx));
next = +added > +this.e ? this.e : added;
results.push(Interval.fromDateTimes(s, next));
s = next;
idx += 1;
}
return results;
}
/**
* Split this Interval into the specified number of smaller intervals.
* @param {number} numberOfParts - The number of Intervals to divide the Interval into.
* @return {Array}
*/
divideEqually(numberOfParts) {
if (!this.isValid) return [];
return this.splitBy(this.length() / numberOfParts).slice(0, numberOfParts);
}
/**
* Return whether this Interval overlaps with the specified Interval
* @param {Interval} other
* @return {boolean}
*/
overlaps(other) {
return this.e > other.s && this.s < other.e;
}
/**
* Return whether this Interval's end is adjacent to the specified Interval's start.
* @param {Interval} other
* @return {boolean}
*/
abutsStart(other) {
if (!this.isValid) return false;
return +this.e === +other.s;
}
/**
* Return whether this Interval's start is adjacent to the specified Interval's end.
* @param {Interval} other
* @return {boolean}
*/
abutsEnd(other) {
if (!this.isValid) return false;
return +other.e === +this.s;
}
/**
* Returns true if this Interval fully contains the specified Interval, specifically if the intersect (of this Interval and the other Interval) is equal to the other Interval; false otherwise.
* @param {Interval} other
* @return {boolean}
*/
engulfs(other) {
if (!this.isValid) return false;
return this.s <= other.s && this.e >= other.e;
}
/**
* Return whether this Interval has the same start and end as the specified Interval.
* @param {Interval} other
* @return {boolean}
*/
equals(other) {
if (!this.isValid || !other.isValid) {
return false;
}
return this.s.equals(other.s) && this.e.equals(other.e);
}
/**
* Return an Interval representing the intersection of this Interval and the specified Interval.
* Specifically, the resulting Interval has the maximum start time and the minimum end time of the two Intervals.
* Returns null if the intersection is empty, meaning, the intervals don't intersect.
* @param {Interval} other
* @return {Interval}
*/
intersection(other) {
if (!this.isValid) return this;
const s = this.s > other.s ? this.s : other.s,
e = this.e < other.e ? this.e : other.e;
if (s >= e) {
return null;
} else {
return Interval.fromDateTimes(s, e);
}
}
/**
* Return an Interval representing the union of this Interval and the specified Interval.
* Specifically, the resulting Interval has the minimum start time and the maximum end time of the two Intervals.
* @param {Interval} other
* @return {Interval}
*/
union(other) {
if (!this.isValid) return this;
const s = this.s < other.s ? this.s : other.s,
e = this.e > other.e ? this.e : other.e;
return Interval.fromDateTimes(s, e);
}
/**
* Merge an array of Intervals into an equivalent minimal set of Intervals.
* Combines overlapping and adjacent Intervals.
* The resulting array will contain the Intervals in ascending order, that is, starting with the earliest Interval
* and ending with the latest.
*
* @param {Array} intervals
* @return {Array}
*/
static merge(intervals) {
const [found, final] = intervals
.sort((a, b) => a.s - b.s)
.reduce(
([sofar, current], item) => {
if (!current) {
return [sofar, item];
} else if (current.overlaps(item) || current.abutsStart(item)) {
return [sofar, current.union(item)];
} else {
return [sofar.concat([current]), item];
}
},
[[], null]
);
if (final) {
found.push(final);
}
return found;
}
/**
* Return an array of Intervals representing the spans of time that only appear in one of the specified Intervals.
* @param {Array} intervals
* @return {Array}
*/
static xor(intervals) {
let start = null,
currentCount = 0;
const results = [],
ends = intervals.map((i) => [
{ time: i.s, type: "s" },
{ time: i.e, type: "e" },
]),
flattened = Array.prototype.concat(...ends),
arr = flattened.sort((a, b) => a.time - b.time);
for (const i of arr) {
currentCount += i.type === "s" ? 1 : -1;
if (currentCount === 1) {
start = i.time;
} else {
if (start && +start !== +i.time) {
results.push(Interval.fromDateTimes(start, i.time));
}
start = null;
}
}
return Interval.merge(results);
}
/**
* Return an Interval representing the span of time in this Interval that doesn't overlap with any of the specified Intervals.
* @param {...Interval} intervals
* @return {Array}
*/
difference(...intervals) {
return Interval.xor([this].concat(intervals))
.map((i) => this.intersection(i))
.filter((i) => i && !i.isEmpty());
}
/**
* Returns a string representation of this Interval appropriate for debugging.
* @return {string}
*/
toString() {
if (!this.isValid) return INVALID$1;
return `[${this.s.toISO()} – ${this.e.toISO()})`;
}
/**
* Returns a string representation of this Interval appropriate for the REPL.
* @return {string}
*/
[Symbol.for("nodejs.util.inspect.custom")]() {
if (this.isValid) {
return `Interval { start: ${this.s.toISO()}, end: ${this.e.toISO()} }`;
} else {
return `Interval { Invalid, reason: ${this.invalidReason} }`;
}
}
/**
* Returns a localized string representing this Interval. Accepts the same options as the
* Intl.DateTimeFormat constructor and any presets defined by Luxon, such as
* {@link DateTime.DATE_FULL} or {@link DateTime.TIME_SIMPLE}. The exact behavior of this method
* is browser-specific, but in general it will return an appropriate representation of the
* Interval in the assigned locale. Defaults to the system's locale if no locale has been
* specified.
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
* @param {Object} [formatOpts=DateTime.DATE_SHORT] - Either a DateTime preset or
* Intl.DateTimeFormat constructor options.
* @param {Object} opts - Options to override the configuration of the start DateTime.
* @example Interval.fromISO('2022-11-07T09:00Z/2022-11-08T09:00Z').toLocaleString(); //=> 11/7/2022 – 11/8/2022
* @example Interval.fromISO('2022-11-07T09:00Z/2022-11-08T09:00Z').toLocaleString(DateTime.DATE_FULL); //=> November 7 – 8, 2022
* @example Interval.fromISO('2022-11-07T09:00Z/2022-11-08T09:00Z').toLocaleString(DateTime.DATE_FULL, { locale: 'fr-FR' }); //=> 7–8 novembre 2022
* @example Interval.fromISO('2022-11-07T17:00Z/2022-11-07T19:00Z').toLocaleString(DateTime.TIME_SIMPLE); //=> 6:00 – 8:00 PM
* @example Interval.fromISO('2022-11-07T17:00Z/2022-11-07T19:00Z').toLocaleString({ weekday: 'short', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }); //=> Mon, Nov 07, 6:00 – 8:00 p
* @return {string}
*/
toLocaleString(formatOpts = DATE_SHORT, opts = {}) {
return this.isValid
? Formatter.create(this.s.loc.clone(opts), formatOpts).formatInterval(this)
: INVALID$1;
}
/**
* Returns an ISO 8601-compliant string representation of this Interval.
* @see https://en.wikipedia.org/wiki/ISO_8601#Time_intervals
* @param {Object} opts - The same options as {@link DateTime#toISO}
* @return {string}
*/
toISO(opts) {
if (!this.isValid) return INVALID$1;
return `${this.s.toISO(opts)}/${this.e.toISO(opts)}`;
}
/**
* Returns an ISO 8601-compliant string representation of date of this Interval.
* The time components are ignored.
* @see https://en.wikipedia.org/wiki/ISO_8601#Time_intervals
* @return {string}
*/
toISODate() {
if (!this.isValid) return INVALID$1;
return `${this.s.toISODate()}/${this.e.toISODate()}`;
}
/**
* Returns an ISO 8601-compliant string representation of time of this Interval.
* The date components are ignored.
* @see https://en.wikipedia.org/wiki/ISO_8601#Time_intervals
* @param {Object} opts - The same options as {@link DateTime#toISO}
* @return {string}
*/
toISOTime(opts) {
if (!this.isValid) return INVALID$1;
return `${this.s.toISOTime(opts)}/${this.e.toISOTime(opts)}`;
}
/**
* Returns a string representation of this Interval formatted according to the specified format
* string. **You may not want this.** See {@link Interval#toLocaleString} for a more flexible
* formatting tool.
* @param {string} dateFormat - The format string. This string formats the start and end time.
* See {@link DateTime#toFormat} for details.
* @param {Object} opts - Options.
* @param {string} [opts.separator = ' – '] - A separator to place between the start and end
* representations.
* @return {string}
*/
toFormat(dateFormat, { separator = " – " } = {}) {
if (!this.isValid) return INVALID$1;
return `${this.s.toFormat(dateFormat)}${separator}${this.e.toFormat(dateFormat)}`;
}
/**
* Return a Duration representing the time spanned by this interval.
* @param {string|string[]} [unit=['milliseconds']] - the unit or units (such as 'hours' or 'days') to include in the duration.
* @param {Object} opts - options that affect the creation of the Duration
* @param {string} [opts.conversionAccuracy='casual'] - the conversion system to use
* @example Interval.fromDateTimes(dt1, dt2).toDuration().toObject() //=> { milliseconds: 88489257 }
* @example Interval.fromDateTimes(dt1, dt2).toDuration('days').toObject() //=> { days: 1.0241812152777778 }
* @example Interval.fromDateTimes(dt1, dt2).toDuration(['hours', 'minutes']).toObject() //=> { hours: 24, minutes: 34.82095 }
* @example Interval.fromDateTimes(dt1, dt2).toDuration(['hours', 'minutes', 'seconds']).toObject() //=> { hours: 24, minutes: 34, seconds: 49.257 }
* @example Interval.fromDateTimes(dt1, dt2).toDuration('seconds').toObject() //=> { seconds: 88489.257 }
* @return {Duration}
*/
toDuration(unit, opts) {
if (!this.isValid) {
return Duration.invalid(this.invalidReason);
}
return this.e.diff(this.s, unit, opts);
}
/**
* Run mapFn on the interval start and end, returning a new Interval from the resulting DateTimes
* @param {function} mapFn
* @return {Interval}
* @example Interval.fromDateTimes(dt1, dt2).mapEndpoints(endpoint => endpoint.toUTC())
* @example Interval.fromDateTimes(dt1, dt2).mapEndpoints(endpoint => endpoint.plus({ hours: 2 }))
*/
mapEndpoints(mapFn) {
return Interval.fromDateTimes(mapFn(this.s), mapFn(this.e));
}
}
/**
* The Info class contains static methods for retrieving general time and date related data. For example, it has methods for finding out if a time zone has a DST, for listing the months in any supported locale, and for discovering which of Luxon features are available in the current environment.
*/
class Info {
/**
* Return whether the specified zone contains a DST.
* @param {string|Zone} [zone='local'] - Zone to check. Defaults to the environment's local zone.
* @return {boolean}
*/
static hasDST(zone = Settings.defaultZone) {
const proto = DateTime.now().setZone(zone).set({ month: 12 });
return !zone.isUniversal && proto.offset !== proto.set({ month: 6 }).offset;
}
/**
* Return whether the specified zone is a valid IANA specifier.
* @param {string} zone - Zone to check
* @return {boolean}
*/
static isValidIANAZone(zone) {
return IANAZone.isValidZone(zone);
}
/**
* Converts the input into a {@link Zone} instance.
*
* * If `input` is already a Zone instance, it is returned unchanged.
* * If `input` is a string containing a valid time zone name, a Zone instance
* with that name is returned.
* * If `input` is a string that doesn't refer to a known time zone, a Zone
* instance with {@link Zone#isValid} == false is returned.
* * If `input is a number, a Zone instance with the specified fixed offset
* in minutes is returned.
* * If `input` is `null` or `undefined`, the default zone is returned.
* @param {string|Zone|number} [input] - the value to be converted
* @return {Zone}
*/
static normalizeZone(input) {
return normalizeZone(input, Settings.defaultZone);
}
/**
* Get the weekday on which the week starts according to the given locale.
* @param {Object} opts - options
* @param {string} [opts.locale] - the locale code
* @param {string} [opts.locObj=null] - an existing locale object to use
* @returns {number} the start of the week, 1 for Monday through 7 for Sunday
*/
static getStartOfWeek({ locale = null, locObj = null } = {}) {
return (locObj || Locale.create(locale)).getStartOfWeek();
}
/**
* Get the minimum number of days necessary in a week before it is considered part of the next year according
* to the given locale.
* @param {Object} opts - options
* @param {string} [opts.locale] - the locale code
* @param {string} [opts.locObj=null] - an existing locale object to use
* @returns {number}
*/
static getMinimumDaysInFirstWeek({ locale = null, locObj = null } = {}) {
return (locObj || Locale.create(locale)).getMinDaysInFirstWeek();
}
/**
* Get the weekdays, which are considered the weekend according to the given locale
* @param {Object} opts - options
* @param {string} [opts.locale] - the locale code
* @param {string} [opts.locObj=null] - an existing locale object to use
* @returns {number[]} an array of weekdays, 1 for Monday through 7 for Sunday
*/
static getWeekendWeekdays({ locale = null, locObj = null } = {}) {
// copy the array, because we cache it internally
return (locObj || Locale.create(locale)).getWeekendDays().slice();
}
/**
* Return an array of standalone month names.
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
* @param {string} [length='long'] - the length of the month representation, such as "numeric", "2-digit", "narrow", "short", "long"
* @param {Object} opts - options
* @param {string} [opts.locale] - the locale code
* @param {string} [opts.numberingSystem=null] - the numbering system
* @param {string} [opts.locObj=null] - an existing locale object to use
* @param {string} [opts.outputCalendar='gregory'] - the calendar
* @example Info.months()[0] //=> 'January'
* @example Info.months('short')[0] //=> 'Jan'
* @example Info.months('numeric')[0] //=> '1'
* @example Info.months('short', { locale: 'fr-CA' } )[0] //=> 'janv.'
* @example Info.months('numeric', { locale: 'ar' })[0] //=> '١'
* @example Info.months('long', { outputCalendar: 'islamic' })[0] //=> 'Rabiʻ I'
* @return {Array}
*/
static months(
length = "long",
{ locale = null, numberingSystem = null, locObj = null, outputCalendar = "gregory" } = {}
) {
return (locObj || Locale.create(locale, numberingSystem, outputCalendar)).months(length);
}
/**
* Return an array of format month names.
* Format months differ from standalone months in that they're meant to appear next to the day of the month. In some languages, that
* changes the string.
* See {@link Info#months}
* @param {string} [length='long'] - the length of the month representation, such as "numeric", "2-digit", "narrow", "short", "long"
* @param {Object} opts - options
* @param {string} [opts.locale] - the locale code
* @param {string} [opts.numberingSystem=null] - the numbering system
* @param {string} [opts.locObj=null] - an existing locale object to use
* @param {string} [opts.outputCalendar='gregory'] - the calendar
* @return {Array}
*/
static monthsFormat(
length = "long",
{ locale = null, numberingSystem = null, locObj = null, outputCalendar = "gregory" } = {}
) {
return (locObj || Locale.create(locale, numberingSystem, outputCalendar)).months(length, true);
}
/**
* Return an array of standalone week names.
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
* @param {string} [length='long'] - the length of the weekday representation, such as "narrow", "short", "long".
* @param {Object} opts - options
* @param {string} [opts.locale] - the locale code
* @param {string} [opts.numberingSystem=null] - the numbering system
* @param {string} [opts.locObj=null] - an existing locale object to use
* @example Info.weekdays()[0] //=> 'Monday'
* @example Info.weekdays('short')[0] //=> 'Mon'
* @example Info.weekdays('short', { locale: 'fr-CA' })[0] //=> 'lun.'
* @example Info.weekdays('short', { locale: 'ar' })[0] //=> 'الاثنين'
* @return {Array}
*/
static weekdays(length = "long", { locale = null, numberingSystem = null, locObj = null } = {}) {
return (locObj || Locale.create(locale, numberingSystem, null)).weekdays(length);
}
/**
* Return an array of format week names.
* Format weekdays differ from standalone weekdays in that they're meant to appear next to more date information. In some languages, that
* changes the string.
* See {@link Info#weekdays}
* @param {string} [length='long'] - the length of the month representation, such as "narrow", "short", "long".
* @param {Object} opts - options
* @param {string} [opts.locale=null] - the locale code
* @param {string} [opts.numberingSystem=null] - the numbering system
* @param {string} [opts.locObj=null] - an existing locale object to use
* @return {Array}
*/
static weekdaysFormat(
length = "long",
{ locale = null, numberingSystem = null, locObj = null } = {}
) {
return (locObj || Locale.create(locale, numberingSystem, null)).weekdays(length, true);
}
/**
* Return an array of meridiems.
* @param {Object} opts - options
* @param {string} [opts.locale] - the locale code
* @example Info.meridiems() //=> [ 'AM', 'PM' ]
* @example Info.meridiems({ locale: 'my' }) //=> [ 'နံနက်', 'ညနေ' ]
* @return {Array}
*/
static meridiems({ locale = null } = {}) {
return Locale.create(locale).meridiems();
}
/**
* Return an array of eras, such as ['BC', 'AD']. The locale can be specified, but the calendar system is always Gregorian.
* @param {string} [length='short'] - the length of the era representation, such as "short" or "long".
* @param {Object} opts - options
* @param {string} [opts.locale] - the locale code
* @example Info.eras() //=> [ 'BC', 'AD' ]
* @example Info.eras('long') //=> [ 'Before Christ', 'Anno Domini' ]
* @example Info.eras('long', { locale: 'fr' }) //=> [ 'avant Jésus-Christ', 'après Jésus-Christ' ]
* @return {Array}
*/
static eras(length = "short", { locale = null } = {}) {
return Locale.create(locale, null, "gregory").eras(length);
}
/**
* Return the set of available features in this environment.
* Some features of Luxon are not available in all environments. For example, on older browsers, relative time formatting support is not available. Use this function to figure out if that's the case.
* Keys:
* * `relative`: whether this environment supports relative time formatting
* * `localeWeek`: whether this environment supports different weekdays for the start of the week based on the locale
* @example Info.features() //=> { relative: false, localeWeek: true }
* @return {Object}
*/
static features() {
return { relative: hasRelative(), localeWeek: hasLocaleWeekInfo() };
}
}
function dayDiff(earlier, later) {
const utcDayStart = (dt) => dt.toUTC(0, { keepLocalTime: true }).startOf("day").valueOf(),
ms = utcDayStart(later) - utcDayStart(earlier);
return Math.floor(Duration.fromMillis(ms).as("days"));
}
function highOrderDiffs(cursor, later, units) {
const differs = [
["years", (a, b) => b.year - a.year],
["quarters", (a, b) => b.quarter - a.quarter + (b.year - a.year) * 4],
["months", (a, b) => b.month - a.month + (b.year - a.year) * 12],
[
"weeks",
(a, b) => {
const days = dayDiff(a, b);
return (days - (days % 7)) / 7;
},
],
["days", dayDiff],
];
const results = {};
const earlier = cursor;
let lowestOrder, highWater;
/* This loop tries to diff using larger units first.
If we overshoot, we backtrack and try the next smaller unit.
"cursor" starts out at the earlier timestamp and moves closer and closer to "later"
as we use smaller and smaller units.
highWater keeps track of where we would be if we added one more of the smallest unit,
this is used later to potentially convert any difference smaller than the smallest higher order unit
into a fraction of that smallest higher order unit
*/
for (const [unit, differ] of differs) {
if (units.indexOf(unit) >= 0) {
lowestOrder = unit;
results[unit] = differ(cursor, later);
highWater = earlier.plus(results);
if (highWater > later) {
// we overshot the end point, backtrack cursor by 1
results[unit]--;
cursor = earlier.plus(results);
// if we are still overshooting now, we need to backtrack again
// this happens in certain situations when diffing times in different zones,
// because this calculation ignores time zones
if (cursor > later) {
// keep the "overshot by 1" around as highWater
highWater = cursor;
// backtrack cursor by 1
results[unit]--;
cursor = earlier.plus(results);
}
} else {
cursor = highWater;
}
}
}
return [cursor, results, highWater, lowestOrder];
}
function diff (earlier, later, units, opts) {
let [cursor, results, highWater, lowestOrder] = highOrderDiffs(earlier, later, units);
const remainingMillis = later - cursor;
const lowerOrderUnits = units.filter(
(u) => ["hours", "minutes", "seconds", "milliseconds"].indexOf(u) >= 0
);
if (lowerOrderUnits.length === 0) {
if (highWater < later) {
highWater = cursor.plus({ [lowestOrder]: 1 });
}
if (highWater !== cursor) {
results[lowestOrder] = (results[lowestOrder] || 0) + remainingMillis / (highWater - cursor);
}
}
const duration = Duration.fromObject(results, opts);
if (lowerOrderUnits.length > 0) {
return Duration.fromMillis(remainingMillis, opts)
.shiftTo(...lowerOrderUnits)
.plus(duration);
} else {
return duration;
}
}
const MISSING_FTP = "missing Intl.DateTimeFormat.formatToParts support";
function intUnit(regex, post = (i) => i) {
return { regex, deser: ([s]) => post(parseDigits(s)) };
}
const NBSP = String.fromCharCode(160);
const spaceOrNBSP = `[ ${NBSP}]`;
const spaceOrNBSPRegExp = new RegExp(spaceOrNBSP, "g");
function fixListRegex(s) {
// make dots optional and also make them literal
// make space and non breakable space characters interchangeable
return s.replace(/\./g, "\\.?").replace(spaceOrNBSPRegExp, spaceOrNBSP);
}
function stripInsensitivities(s) {
return s
.replace(/\./g, "") // ignore dots that were made optional
.replace(spaceOrNBSPRegExp, " ") // interchange space and nbsp
.toLowerCase();
}
function oneOf(strings, startIndex) {
if (strings === null) {
return null;
} else {
return {
regex: RegExp(strings.map(fixListRegex).join("|")),
deser: ([s]) =>
strings.findIndex((i) => stripInsensitivities(s) === stripInsensitivities(i)) + startIndex,
};
}
}
function offset(regex, groups) {
return { regex, deser: ([, h, m]) => signedOffset(h, m), groups };
}
function simple(regex) {
return { regex, deser: ([s]) => s };
}
function escapeToken(value) {
return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
}
/**
* @param token
* @param {Locale} loc
*/
function unitForToken(token, loc) {
const one = digitRegex(loc),
two = digitRegex(loc, "{2}"),
three = digitRegex(loc, "{3}"),
four = digitRegex(loc, "{4}"),
six = digitRegex(loc, "{6}"),
oneOrTwo = digitRegex(loc, "{1,2}"),
oneToThree = digitRegex(loc, "{1,3}"),
oneToSix = digitRegex(loc, "{1,6}"),
oneToNine = digitRegex(loc, "{1,9}"),
twoToFour = digitRegex(loc, "{2,4}"),
fourToSix = digitRegex(loc, "{4,6}"),
literal = (t) => ({ regex: RegExp(escapeToken(t.val)), deser: ([s]) => s, literal: true }),
unitate = (t) => {
if (token.literal) {
return literal(t);
}
switch (t.val) {
// era
case "G":
return oneOf(loc.eras("short"), 0);
case "GG":
return oneOf(loc.eras("long"), 0);
// years
case "y":
return intUnit(oneToSix);
case "yy":
return intUnit(twoToFour, untruncateYear);
case "yyyy":
return intUnit(four);
case "yyyyy":
return intUnit(fourToSix);
case "yyyyyy":
return intUnit(six);
// months
case "M":
return intUnit(oneOrTwo);
case "MM":
return intUnit(two);
case "MMM":
return oneOf(loc.months("short", true), 1);
case "MMMM":
return oneOf(loc.months("long", true), 1);
case "L":
return intUnit(oneOrTwo);
case "LL":
return intUnit(two);
case "LLL":
return oneOf(loc.months("short", false), 1);
case "LLLL":
return oneOf(loc.months("long", false), 1);
// dates
case "d":
return intUnit(oneOrTwo);
case "dd":
return intUnit(two);
// ordinals
case "o":
return intUnit(oneToThree);
case "ooo":
return intUnit(three);
// time
case "HH":
return intUnit(two);
case "H":
return intUnit(oneOrTwo);
case "hh":
return intUnit(two);
case "h":
return intUnit(oneOrTwo);
case "mm":
return intUnit(two);
case "m":
return intUnit(oneOrTwo);
case "q":
return intUnit(oneOrTwo);
case "qq":
return intUnit(two);
case "s":
return intUnit(oneOrTwo);
case "ss":
return intUnit(two);
case "S":
return intUnit(oneToThree);
case "SSS":
return intUnit(three);
case "u":
return simple(oneToNine);
case "uu":
return simple(oneOrTwo);
case "uuu":
return intUnit(one);
// meridiem
case "a":
return oneOf(loc.meridiems(), 0);
// weekYear (k)
case "kkkk":
return intUnit(four);
case "kk":
return intUnit(twoToFour, untruncateYear);
// weekNumber (W)
case "W":
return intUnit(oneOrTwo);
case "WW":
return intUnit(two);
// weekdays
case "E":
case "c":
return intUnit(one);
case "EEE":
return oneOf(loc.weekdays("short", false), 1);
case "EEEE":
return oneOf(loc.weekdays("long", false), 1);
case "ccc":
return oneOf(loc.weekdays("short", true), 1);
case "cccc":
return oneOf(loc.weekdays("long", true), 1);
// offset/zone
case "Z":
case "ZZ":
return offset(new RegExp(`([+-]${oneOrTwo.source})(?::(${two.source}))?`), 2);
case "ZZZ":
return offset(new RegExp(`([+-]${oneOrTwo.source})(${two.source})?`), 2);
// we don't support ZZZZ (PST) or ZZZZZ (Pacific Standard Time) in parsing
// because we don't have any way to figure out what they are
case "z":
return simple(/[a-z_+-/]{1,256}?/i);
// this special-case "token" represents a place where a macro-token expanded into a white-space literal
// in this case we accept any non-newline white-space
case " ":
return simple(/[^\S\n\r]/);
default:
return literal(t);
}
};
const unit = unitate(token) || {
invalidReason: MISSING_FTP,
};
unit.token = token;
return unit;
}
const partTypeStyleToTokenVal = {
year: {
"2-digit": "yy",
numeric: "yyyyy",
},
month: {
numeric: "M",
"2-digit": "MM",
short: "MMM",
long: "MMMM",
},
day: {
numeric: "d",
"2-digit": "dd",
},
weekday: {
short: "EEE",
long: "EEEE",
},
dayperiod: "a",
dayPeriod: "a",
hour12: {
numeric: "h",
"2-digit": "hh",
},
hour24: {
numeric: "H",
"2-digit": "HH",
},
minute: {
numeric: "m",
"2-digit": "mm",
},
second: {
numeric: "s",
"2-digit": "ss",
},
timeZoneName: {
long: "ZZZZZ",
short: "ZZZ",
},
};
function tokenForPart(part, formatOpts, resolvedOpts) {
const { type, value } = part;
if (type === "literal") {
const isSpace = /^\s+$/.test(value);
return {
literal: !isSpace,
val: isSpace ? " " : value,
};
}
const style = formatOpts[type];
// The user might have explicitly specified hour12 or hourCycle
// if so, respect their decision
// if not, refer back to the resolvedOpts, which are based on the locale
let actualType = type;
if (type === "hour") {
if (formatOpts.hour12 != null) {
actualType = formatOpts.hour12 ? "hour12" : "hour24";
} else if (formatOpts.hourCycle != null) {
if (formatOpts.hourCycle === "h11" || formatOpts.hourCycle === "h12") {
actualType = "hour12";
} else {
actualType = "hour24";
}
} else {
// tokens only differentiate between 24 hours or not,
// so we do not need to check hourCycle here, which is less supported anyways
actualType = resolvedOpts.hour12 ? "hour12" : "hour24";
}
}
let val = partTypeStyleToTokenVal[actualType];
if (typeof val === "object") {
val = val[style];
}
if (val) {
return {
literal: false,
val,
};
}
return undefined;
}
function buildRegex(units) {
const re = units.map((u) => u.regex).reduce((f, r) => `${f}(${r.source})`, "");
return [`^${re}$`, units];
}
function match(input, regex, handlers) {
const matches = input.match(regex);
if (matches) {
const all = {};
let matchIndex = 1;
for (const i in handlers) {
if (hasOwnProperty$1(handlers, i)) {
const h = handlers[i],
groups = h.groups ? h.groups + 1 : 1;
if (!h.literal && h.token) {
all[h.token.val[0]] = h.deser(matches.slice(matchIndex, matchIndex + groups));
}
matchIndex += groups;
}
}
return [matches, all];
} else {
return [matches, {}];
}
}
function dateTimeFromMatches(matches) {
const toField = (token) => {
switch (token) {
case "S":
return "millisecond";
case "s":
return "second";
case "m":
return "minute";
case "h":
case "H":
return "hour";
case "d":
return "day";
case "o":
return "ordinal";
case "L":
case "M":
return "month";
case "y":
return "year";
case "E":
case "c":
return "weekday";
case "W":
return "weekNumber";
case "k":
return "weekYear";
case "q":
return "quarter";
default:
return null;
}
};
let zone = null;
let specificOffset;
if (!isUndefined$1(matches.z)) {
zone = IANAZone.create(matches.z);
}
if (!isUndefined$1(matches.Z)) {
if (!zone) {
zone = new FixedOffsetZone(matches.Z);
}
specificOffset = matches.Z;
}
if (!isUndefined$1(matches.q)) {
matches.M = (matches.q - 1) * 3 + 1;
}
if (!isUndefined$1(matches.h)) {
if (matches.h < 12 && matches.a === 1) {
matches.h += 12;
} else if (matches.h === 12 && matches.a === 0) {
matches.h = 0;
}
}
if (matches.G === 0 && matches.y) {
matches.y = -matches.y;
}
if (!isUndefined$1(matches.u)) {
matches.S = parseMillis(matches.u);
}
const vals = Object.keys(matches).reduce((r, k) => {
const f = toField(k);
if (f) {
r[f] = matches[k];
}
return r;
}, {});
return [vals, zone, specificOffset];
}
let dummyDateTimeCache = null;
function getDummyDateTime() {
if (!dummyDateTimeCache) {
dummyDateTimeCache = DateTime.fromMillis(1555555555555);
}
return dummyDateTimeCache;
}
function maybeExpandMacroToken(token, locale) {
if (token.literal) {
return token;
}
const formatOpts = Formatter.macroTokenToFormatOpts(token.val);
const tokens = formatOptsToTokens(formatOpts, locale);
if (tokens == null || tokens.includes(undefined)) {
return token;
}
return tokens;
}
function expandMacroTokens(tokens, locale) {
return Array.prototype.concat(...tokens.map((t) => maybeExpandMacroToken(t, locale)));
}
/**
* @private
*/
class TokenParser {
constructor(locale, format) {
this.locale = locale;
this.format = format;
this.tokens = expandMacroTokens(Formatter.parseFormat(format), locale);
this.units = this.tokens.map((t) => unitForToken(t, locale));
this.disqualifyingUnit = this.units.find((t) => t.invalidReason);
if (!this.disqualifyingUnit) {
const [regexString, handlers] = buildRegex(this.units);
this.regex = RegExp(regexString, "i");
this.handlers = handlers;
}
}
explainFromTokens(input) {
if (!this.isValid) {
return { input, tokens: this.tokens, invalidReason: this.invalidReason };
} else {
const [rawMatches, matches] = match(input, this.regex, this.handlers),
[result, zone, specificOffset] = matches
? dateTimeFromMatches(matches)
: [null, null, undefined];
if (hasOwnProperty$1(matches, "a") && hasOwnProperty$1(matches, "H")) {
throw new ConflictingSpecificationError(
"Can't include meridiem when specifying 24-hour format"
);
}
return {
input,
tokens: this.tokens,
regex: this.regex,
rawMatches,
matches,
result,
zone,
specificOffset,
};
}
}
get isValid() {
return !this.disqualifyingUnit;
}
get invalidReason() {
return this.disqualifyingUnit ? this.disqualifyingUnit.invalidReason : null;
}
}
function explainFromTokens(locale, input, format) {
const parser = new TokenParser(locale, format);
return parser.explainFromTokens(input);
}
function parseFromTokens(locale, input, format) {
const { result, zone, specificOffset, invalidReason } = explainFromTokens(locale, input, format);
return [result, zone, specificOffset, invalidReason];
}
function formatOptsToTokens(formatOpts, locale) {
if (!formatOpts) {
return null;
}
const formatter = Formatter.create(locale, formatOpts);
const df = formatter.dtFormatter(getDummyDateTime());
const parts = df.formatToParts();
const resolvedOpts = df.resolvedOptions();
return parts.map((p) => tokenForPart(p, formatOpts, resolvedOpts));
}
const INVALID = "Invalid DateTime";
const MAX_DATE = 8.64e15;
function unsupportedZone(zone) {
return new Invalid("unsupported zone", `the zone "${zone.name}" is not supported`);
}
// we cache week data on the DT object and this intermediates the cache
/**
* @param {DateTime} dt
*/
function possiblyCachedWeekData(dt) {
if (dt.weekData === null) {
dt.weekData = gregorianToWeek(dt.c);
}
return dt.weekData;
}
/**
* @param {DateTime} dt
*/
function possiblyCachedLocalWeekData(dt) {
if (dt.localWeekData === null) {
dt.localWeekData = gregorianToWeek(
dt.c,
dt.loc.getMinDaysInFirstWeek(),
dt.loc.getStartOfWeek()
);
}
return dt.localWeekData;
}
// clone really means, "make a new object with these modifications". all "setters" really use this
// to create a new object while only changing some of the properties
function clone(inst, alts) {
const current = {
ts: inst.ts,
zone: inst.zone,
c: inst.c,
o: inst.o,
loc: inst.loc,
invalid: inst.invalid,
};
return new DateTime({ ...current, ...alts, old: current });
}
// find the right offset a given local time. The o input is our guess, which determines which
// offset we'll pick in ambiguous cases (e.g. there are two 3 AMs b/c Fallback DST)
function fixOffset(localTS, o, tz) {
// Our UTC time is just a guess because our offset is just a guess
let utcGuess = localTS - o * 60 * 1000;
// Test whether the zone matches the offset for this ts
const o2 = tz.offset(utcGuess);
// If so, offset didn't change and we're done
if (o === o2) {
return [utcGuess, o];
}
// If not, change the ts by the difference in the offset
utcGuess -= (o2 - o) * 60 * 1000;
// If that gives us the local time we want, we're done
const o3 = tz.offset(utcGuess);
if (o2 === o3) {
return [utcGuess, o2];
}
// If it's different, we're in a hole time. The offset has changed, but the we don't adjust the time
return [localTS - Math.min(o2, o3) * 60 * 1000, Math.max(o2, o3)];
}
// convert an epoch timestamp into a calendar object with the given offset
function tsToObj(ts, offset) {
ts += offset * 60 * 1000;
const d = new Date(ts);
return {
year: d.getUTCFullYear(),
month: d.getUTCMonth() + 1,
day: d.getUTCDate(),
hour: d.getUTCHours(),
minute: d.getUTCMinutes(),
second: d.getUTCSeconds(),
millisecond: d.getUTCMilliseconds(),
};
}
// convert a calendar object to a epoch timestamp
function objToTS(obj, offset, zone) {
return fixOffset(objToLocalTS(obj), offset, zone);
}
// create a new DT instance by adding a duration, adjusting for DSTs
function adjustTime(inst, dur) {
const oPre = inst.o,
year = inst.c.year + Math.trunc(dur.years),
month = inst.c.month + Math.trunc(dur.months) + Math.trunc(dur.quarters) * 3,
c = {
...inst.c,
year,
month,
day:
Math.min(inst.c.day, daysInMonth(year, month)) +
Math.trunc(dur.days) +
Math.trunc(dur.weeks) * 7,
},
millisToAdd = Duration.fromObject({
years: dur.years - Math.trunc(dur.years),
quarters: dur.quarters - Math.trunc(dur.quarters),
months: dur.months - Math.trunc(dur.months),
weeks: dur.weeks - Math.trunc(dur.weeks),
days: dur.days - Math.trunc(dur.days),
hours: dur.hours,
minutes: dur.minutes,
seconds: dur.seconds,
milliseconds: dur.milliseconds,
}).as("milliseconds"),
localTS = objToLocalTS(c);
let [ts, o] = fixOffset(localTS, oPre, inst.zone);
if (millisToAdd !== 0) {
ts += millisToAdd;
// that could have changed the offset by going over a DST, but we want to keep the ts the same
o = inst.zone.offset(ts);
}
return { ts, o };
}
// helper useful in turning the results of parsing into real dates
// by handling the zone options
function parseDataToDateTime(parsed, parsedZone, opts, format, text, specificOffset) {
const { setZone, zone } = opts;
if ((parsed && Object.keys(parsed).length !== 0) || parsedZone) {
const interpretationZone = parsedZone || zone,
inst = DateTime.fromObject(parsed, {
...opts,
zone: interpretationZone,
specificOffset,
});
return setZone ? inst : inst.setZone(zone);
} else {
return DateTime.invalid(
new Invalid("unparsable", `the input "${text}" can't be parsed as ${format}`)
);
}
}
// if you want to output a technical format (e.g. RFC 2822), this helper
// helps handle the details
function toTechFormat(dt, format, allowZ = true) {
return dt.isValid
? Formatter.create(Locale.create("en-US"), {
allowZ,
forceSimple: true,
}).formatDateTimeFromString(dt, format)
: null;
}
function toISODate(o, extended, precision) {
const longFormat = o.c.year > 9999 || o.c.year < 0;
let c = "";
if (longFormat && o.c.year >= 0) c += "+";
c += padStart(o.c.year, longFormat ? 6 : 4);
if (precision === "year") return c;
if (extended) {
c += "-";
c += padStart(o.c.month);
if (precision === "month") return c;
c += "-";
} else {
c += padStart(o.c.month);
if (precision === "month") return c;
}
c += padStart(o.c.day);
return c;
}
function toISOTime(
o,
extended,
suppressSeconds,
suppressMilliseconds,
includeOffset,
extendedZone,
precision
) {
let showSeconds = !suppressSeconds || o.c.millisecond !== 0 || o.c.second !== 0,
c = "";
switch (precision) {
case "day":
case "month":
case "year":
break;
default:
c += padStart(o.c.hour);
if (precision === "hour") break;
if (extended) {
c += ":";
c += padStart(o.c.minute);
if (precision === "minute") break;
if (showSeconds) {
c += ":";
c += padStart(o.c.second);
}
} else {
c += padStart(o.c.minute);
if (precision === "minute") break;
if (showSeconds) {
c += padStart(o.c.second);
}
}
if (precision === "second") break;
if (showSeconds && (!suppressMilliseconds || o.c.millisecond !== 0)) {
c += ".";
c += padStart(o.c.millisecond, 3);
}
}
if (includeOffset) {
if (o.isOffsetFixed && o.offset === 0 && !extendedZone) {
c += "Z";
} else if (o.o < 0) {
c += "-";
c += padStart(Math.trunc(-o.o / 60));
c += ":";
c += padStart(Math.trunc(-o.o % 60));
} else {
c += "+";
c += padStart(Math.trunc(o.o / 60));
c += ":";
c += padStart(Math.trunc(o.o % 60));
}
}
if (extendedZone) {
c += "[" + o.zone.ianaName + "]";
}
return c;
}
// defaults for unspecified units in the supported calendars
const defaultUnitValues = {
month: 1,
day: 1,
hour: 0,
minute: 0,
second: 0,
millisecond: 0,
},
defaultWeekUnitValues = {
weekNumber: 1,
weekday: 1,
hour: 0,
minute: 0,
second: 0,
millisecond: 0,
},
defaultOrdinalUnitValues = {
ordinal: 1,
hour: 0,
minute: 0,
second: 0,
millisecond: 0,
};
// Units in the supported calendars, sorted by bigness
const orderedUnits = ["year", "month", "day", "hour", "minute", "second", "millisecond"],
orderedWeekUnits = [
"weekYear",
"weekNumber",
"weekday",
"hour",
"minute",
"second",
"millisecond",
],
orderedOrdinalUnits = ["year", "ordinal", "hour", "minute", "second", "millisecond"];
// standardize case and plurality in units
function normalizeUnit(unit) {
const normalized = {
year: "year",
years: "year",
month: "month",
months: "month",
day: "day",
days: "day",
hour: "hour",
hours: "hour",
minute: "minute",
minutes: "minute",
quarter: "quarter",
quarters: "quarter",
second: "second",
seconds: "second",
millisecond: "millisecond",
milliseconds: "millisecond",
weekday: "weekday",
weekdays: "weekday",
weeknumber: "weekNumber",
weeksnumber: "weekNumber",
weeknumbers: "weekNumber",
weekyear: "weekYear",
weekyears: "weekYear",
ordinal: "ordinal",
}[unit.toLowerCase()];
if (!normalized) throw new InvalidUnitError(unit);
return normalized;
}
function normalizeUnitWithLocalWeeks(unit) {
switch (unit.toLowerCase()) {
case "localweekday":
case "localweekdays":
return "localWeekday";
case "localweeknumber":
case "localweeknumbers":
return "localWeekNumber";
case "localweekyear":
case "localweekyears":
return "localWeekYear";
default:
return normalizeUnit(unit);
}
}
// cache offsets for zones based on the current timestamp when this function is
// first called. When we are handling a datetime from components like (year,
// month, day, hour) in a time zone, we need a guess about what the timezone
// offset is so that we can convert into a UTC timestamp. One way is to find the
// offset of now in the zone. The actual date may have a different offset (for
// example, if we handle a date in June while we're in December in a zone that
// observes DST), but we can check and adjust that.
//
// When handling many dates, calculating the offset for now every time is
// expensive. It's just a guess, so we can cache the offset to use even if we
// are right on a time change boundary (we'll just correct in the other
// direction). Using a timestamp from first read is a slight optimization for
// handling dates close to the current date, since those dates will usually be
// in the same offset (we could set the timestamp statically, instead). We use a
// single timestamp for all zones to make things a bit more predictable.
//
// This is safe for quickDT (used by local() and utc()) because we don't fill in
// higher-order units from tsNow (as we do in fromObject, this requires that
// offset is calculated from tsNow).
/**
* @param {Zone} zone
* @return {number}
*/
function guessOffsetForZone(zone) {
if (zoneOffsetTs === undefined) {
zoneOffsetTs = Settings.now();
}
// Do not cache anything but IANA zones, because it is not safe to do so.
// Guessing an offset which is not present in the zone can cause wrong results from fixOffset
if (zone.type !== "iana") {
return zone.offset(zoneOffsetTs);
}
const zoneName = zone.name;
let offsetGuess = zoneOffsetGuessCache.get(zoneName);
if (offsetGuess === undefined) {
offsetGuess = zone.offset(zoneOffsetTs);
zoneOffsetGuessCache.set(zoneName, offsetGuess);
}
return offsetGuess;
}
// this is a dumbed down version of fromObject() that runs about 60% faster
// but doesn't do any validation, makes a bunch of assumptions about what units
// are present, and so on.
function quickDT(obj, opts) {
const zone = normalizeZone(opts.zone, Settings.defaultZone);
if (!zone.isValid) {
return DateTime.invalid(unsupportedZone(zone));
}
const loc = Locale.fromObject(opts);
let ts, o;
// assume we have the higher-order units
if (!isUndefined$1(obj.year)) {
for (const u of orderedUnits) {
if (isUndefined$1(obj[u])) {
obj[u] = defaultUnitValues[u];
}
}
const invalid = hasInvalidGregorianData(obj) || hasInvalidTimeData(obj);
if (invalid) {
return DateTime.invalid(invalid);
}
const offsetProvis = guessOffsetForZone(zone);
[ts, o] = objToTS(obj, offsetProvis, zone);
} else {
ts = Settings.now();
}
return new DateTime({ ts, zone, loc, o });
}
function diffRelative(start, end, opts) {
const round = isUndefined$1(opts.round) ? true : opts.round,
rounding = isUndefined$1(opts.rounding) ? "trunc" : opts.rounding,
format = (c, unit) => {
c = roundTo(c, round || opts.calendary ? 0 : 2, opts.calendary ? "round" : rounding);
const formatter = end.loc.clone(opts).relFormatter(opts);
return formatter.format(c, unit);
},
differ = (unit) => {
if (opts.calendary) {
if (!end.hasSame(start, unit)) {
return end.startOf(unit).diff(start.startOf(unit), unit).get(unit);
} else return 0;
} else {
return end.diff(start, unit).get(unit);
}
};
if (opts.unit) {
return format(differ(opts.unit), opts.unit);
}
for (const unit of opts.units) {
const count = differ(unit);
if (Math.abs(count) >= 1) {
return format(count, unit);
}
}
return format(start > end ? -0 : 0, opts.units[opts.units.length - 1]);
}
function lastOpts(argList) {
let opts = {},
args;
if (argList.length > 0 && typeof argList[argList.length - 1] === "object") {
opts = argList[argList.length - 1];
args = Array.from(argList).slice(0, argList.length - 1);
} else {
args = Array.from(argList);
}
return [opts, args];
}
/**
* Timestamp to use for cached zone offset guesses (exposed for test)
*/
let zoneOffsetTs;
/**
* Cache for zone offset guesses (exposed for test).
*
* This optimizes quickDT via guessOffsetForZone to avoid repeated calls of
* zone.offset().
*/
const zoneOffsetGuessCache = new Map();
/**
* A DateTime is an immutable data structure representing a specific date and time and accompanying methods. It contains class and instance methods for creating, parsing, interrogating, transforming, and formatting them.
*
* A DateTime comprises of:
* * A timestamp. Each DateTime instance refers to a specific millisecond of the Unix epoch.
* * A time zone. Each instance is considered in the context of a specific zone (by default the local system's zone).
* * Configuration properties that effect how output strings are formatted, such as `locale`, `numberingSystem`, and `outputCalendar`.
*
* Here is a brief overview of the most commonly used functionality it provides:
*
* * **Creation**: To create a DateTime from its components, use one of its factory class methods: {@link DateTime.local}, {@link DateTime.utc}, and (most flexibly) {@link DateTime.fromObject}. To create one from a standard string format, use {@link DateTime.fromISO}, {@link DateTime.fromHTTP}, and {@link DateTime.fromRFC2822}. To create one from a custom string format, use {@link DateTime.fromFormat}. To create one from a native JS date, use {@link DateTime.fromJSDate}.
* * **Gregorian calendar and time**: To examine the Gregorian properties of a DateTime individually (i.e as opposed to collectively through {@link DateTime#toObject}), use the {@link DateTime#year}, {@link DateTime#month},
* {@link DateTime#day}, {@link DateTime#hour}, {@link DateTime#minute}, {@link DateTime#second}, {@link DateTime#millisecond} accessors.
* * **Week calendar**: For ISO week calendar attributes, see the {@link DateTime#weekYear}, {@link DateTime#weekNumber}, and {@link DateTime#weekday} accessors.
* * **Configuration** See the {@link DateTime#locale} and {@link DateTime#numberingSystem} accessors.
* * **Transformation**: To transform the DateTime into other DateTimes, use {@link DateTime#set}, {@link DateTime#reconfigure}, {@link DateTime#setZone}, {@link DateTime#setLocale}, {@link DateTime.plus}, {@link DateTime#minus}, {@link DateTime#endOf}, {@link DateTime#startOf}, {@link DateTime#toUTC}, and {@link DateTime#toLocal}.
* * **Output**: To convert the DateTime to other representations, use the {@link DateTime#toRelative}, {@link DateTime#toRelativeCalendar}, {@link DateTime#toJSON}, {@link DateTime#toISO}, {@link DateTime#toHTTP}, {@link DateTime#toObject}, {@link DateTime#toRFC2822}, {@link DateTime#toString}, {@link DateTime#toLocaleString}, {@link DateTime#toFormat}, {@link DateTime#toMillis} and {@link DateTime#toJSDate}.
*
* There's plenty others documented below. In addition, for more information on subtler topics like internationalization, time zones, alternative calendars, validity, and so on, see the external documentation.
*/
class DateTime {
/**
* @access private
*/
constructor(config) {
const zone = config.zone || Settings.defaultZone;
let invalid =
config.invalid ||
(Number.isNaN(config.ts) ? new Invalid("invalid input") : null) ||
(!zone.isValid ? unsupportedZone(zone) : null);
/**
* @access private
*/
this.ts = isUndefined$1(config.ts) ? Settings.now() : config.ts;
let c = null,
o = null;
if (!invalid) {
const unchanged = config.old && config.old.ts === this.ts && config.old.zone.equals(zone);
if (unchanged) {
[c, o] = [config.old.c, config.old.o];
} else {
// If an offset has been passed and we have not been called from
// clone(), we can trust it and avoid the offset calculation.
const ot = isNumber$1(config.o) && !config.old ? config.o : zone.offset(this.ts);
c = tsToObj(this.ts, ot);
invalid = Number.isNaN(c.year) ? new Invalid("invalid input") : null;
c = invalid ? null : c;
o = invalid ? null : ot;
}
}
/**
* @access private
*/
this._zone = zone;
/**
* @access private
*/
this.loc = config.loc || Locale.create();
/**
* @access private
*/
this.invalid = invalid;
/**
* @access private
*/
this.weekData = null;
/**
* @access private
*/
this.localWeekData = null;
/**
* @access private
*/
this.c = c;
/**
* @access private
*/
this.o = o;
/**
* @access private
*/
this.isLuxonDateTime = true;
}
// CONSTRUCT
/**
* Create a DateTime for the current instant, in the system's time zone.
*
* Use Settings to override these default values if needed.
* @example DateTime.now().toISO() //~> now in the ISO format
* @return {DateTime}
*/
static now() {
return new DateTime({});
}
/**
* Create a local DateTime
* @param {number} [year] - The calendar year. If omitted (as in, call `local()` with no arguments), the current time will be used
* @param {number} [month=1] - The month, 1-indexed
* @param {number} [day=1] - The day of the month, 1-indexed
* @param {number} [hour=0] - The hour of the day, in 24-hour time
* @param {number} [minute=0] - The minute of the hour, meaning a number between 0 and 59
* @param {number} [second=0] - The second of the minute, meaning a number between 0 and 59
* @param {number} [millisecond=0] - The millisecond of the second, meaning a number between 0 and 999
* @example DateTime.local() //~> now
* @example DateTime.local({ zone: "America/New_York" }) //~> now, in US east coast time
* @example DateTime.local(2017) //~> 2017-01-01T00:00:00
* @example DateTime.local(2017, 3) //~> 2017-03-01T00:00:00
* @example DateTime.local(2017, 3, 12, { locale: "fr" }) //~> 2017-03-12T00:00:00, with a French locale
* @example DateTime.local(2017, 3, 12, 5) //~> 2017-03-12T05:00:00
* @example DateTime.local(2017, 3, 12, 5, { zone: "utc" }) //~> 2017-03-12T05:00:00, in UTC
* @example DateTime.local(2017, 3, 12, 5, 45) //~> 2017-03-12T05:45:00
* @example DateTime.local(2017, 3, 12, 5, 45, 10) //~> 2017-03-12T05:45:10
* @example DateTime.local(2017, 3, 12, 5, 45, 10, 765) //~> 2017-03-12T05:45:10.765
* @return {DateTime}
*/
static local() {
const [opts, args] = lastOpts(arguments),
[year, month, day, hour, minute, second, millisecond] = args;
return quickDT({ year, month, day, hour, minute, second, millisecond }, opts);
}
/**
* Create a DateTime in UTC
* @param {number} [year] - The calendar year. If omitted (as in, call `utc()` with no arguments), the current time will be used
* @param {number} [month=1] - The month, 1-indexed
* @param {number} [day=1] - The day of the month
* @param {number} [hour=0] - The hour of the day, in 24-hour time
* @param {number} [minute=0] - The minute of the hour, meaning a number between 0 and 59
* @param {number} [second=0] - The second of the minute, meaning a number between 0 and 59
* @param {number} [millisecond=0] - The millisecond of the second, meaning a number between 0 and 999
* @param {Object} options - configuration options for the DateTime
* @param {string} [options.locale] - a locale to set on the resulting DateTime instance
* @param {string} [options.outputCalendar] - the output calendar to set on the resulting DateTime instance
* @param {string} [options.numberingSystem] - the numbering system to set on the resulting DateTime instance
* @param {string} [options.weekSettings] - the week settings to set on the resulting DateTime instance
* @example DateTime.utc() //~> now
* @example DateTime.utc(2017) //~> 2017-01-01T00:00:00Z
* @example DateTime.utc(2017, 3) //~> 2017-03-01T00:00:00Z
* @example DateTime.utc(2017, 3, 12) //~> 2017-03-12T00:00:00Z
* @example DateTime.utc(2017, 3, 12, 5) //~> 2017-03-12T05:00:00Z
* @example DateTime.utc(2017, 3, 12, 5, 45) //~> 2017-03-12T05:45:00Z
* @example DateTime.utc(2017, 3, 12, 5, 45, { locale: "fr" }) //~> 2017-03-12T05:45:00Z with a French locale
* @example DateTime.utc(2017, 3, 12, 5, 45, 10) //~> 2017-03-12T05:45:10Z
* @example DateTime.utc(2017, 3, 12, 5, 45, 10, 765, { locale: "fr" }) //~> 2017-03-12T05:45:10.765Z with a French locale
* @return {DateTime}
*/
static utc() {
const [opts, args] = lastOpts(arguments),
[year, month, day, hour, minute, second, millisecond] = args;
opts.zone = FixedOffsetZone.utcInstance;
return quickDT({ year, month, day, hour, minute, second, millisecond }, opts);
}
/**
* Create a DateTime from a JavaScript Date object. Uses the default zone.
* @param {Date} date - a JavaScript Date object
* @param {Object} options - configuration options for the DateTime
* @param {string|Zone} [options.zone='local'] - the zone to place the DateTime into
* @return {DateTime}
*/
static fromJSDate(date, options = {}) {
const ts = isDate$1(date) ? date.valueOf() : NaN;
if (Number.isNaN(ts)) {
return DateTime.invalid("invalid input");
}
const zoneToUse = normalizeZone(options.zone, Settings.defaultZone);
if (!zoneToUse.isValid) {
return DateTime.invalid(unsupportedZone(zoneToUse));
}
return new DateTime({
ts: ts,
zone: zoneToUse,
loc: Locale.fromObject(options),
});
}
/**
* Create a DateTime from a number of milliseconds since the epoch (meaning since 1 January 1970 00:00:00 UTC). Uses the default zone.
* @param {number} milliseconds - a number of milliseconds since 1970 UTC
* @param {Object} options - configuration options for the DateTime
* @param {string|Zone} [options.zone='local'] - the zone to place the DateTime into
* @param {string} [options.locale] - a locale to set on the resulting DateTime instance
* @param {string} options.outputCalendar - the output calendar to set on the resulting DateTime instance
* @param {string} options.numberingSystem - the numbering system to set on the resulting DateTime instance
* @param {string} options.weekSettings - the week settings to set on the resulting DateTime instance
* @return {DateTime}
*/
static fromMillis(milliseconds, options = {}) {
if (!isNumber$1(milliseconds)) {
throw new InvalidArgumentError(
`fromMillis requires a numerical input, but received a ${typeof milliseconds} with value ${milliseconds}`
);
} else if (milliseconds < -MAX_DATE || milliseconds > MAX_DATE) {
// this isn't perfect because we can still end up out of range because of additional shifting, but it's a start
return DateTime.invalid("Timestamp out of range");
} else {
return new DateTime({
ts: milliseconds,
zone: normalizeZone(options.zone, Settings.defaultZone),
loc: Locale.fromObject(options),
});
}
}
/**
* Create a DateTime from a number of seconds since the epoch (meaning since 1 January 1970 00:00:00 UTC). Uses the default zone.
* @param {number} seconds - a number of seconds since 1970 UTC
* @param {Object} options - configuration options for the DateTime
* @param {string|Zone} [options.zone='local'] - the zone to place the DateTime into
* @param {string} [options.locale] - a locale to set on the resulting DateTime instance
* @param {string} options.outputCalendar - the output calendar to set on the resulting DateTime instance
* @param {string} options.numberingSystem - the numbering system to set on the resulting DateTime instance
* @param {string} options.weekSettings - the week settings to set on the resulting DateTime instance
* @return {DateTime}
*/
static fromSeconds(seconds, options = {}) {
if (!isNumber$1(seconds)) {
throw new InvalidArgumentError("fromSeconds requires a numerical input");
} else {
return new DateTime({
ts: seconds * 1000,
zone: normalizeZone(options.zone, Settings.defaultZone),
loc: Locale.fromObject(options),
});
}
}
/**
* Create a DateTime from a JavaScript object with keys like 'year' and 'hour' with reasonable defaults.
* @param {Object} obj - the object to create the DateTime from
* @param {number} obj.year - a year, such as 1987
* @param {number} obj.month - a month, 1-12
* @param {number} obj.day - a day of the month, 1-31, depending on the month
* @param {number} obj.ordinal - day of the year, 1-365 or 366
* @param {number} obj.weekYear - an ISO week year
* @param {number} obj.weekNumber - an ISO week number, between 1 and 52 or 53, depending on the year
* @param {number} obj.weekday - an ISO weekday, 1-7, where 1 is Monday and 7 is Sunday
* @param {number} obj.localWeekYear - a week year, according to the locale
* @param {number} obj.localWeekNumber - a week number, between 1 and 52 or 53, depending on the year, according to the locale
* @param {number} obj.localWeekday - a weekday, 1-7, where 1 is the first and 7 is the last day of the week, according to the locale
* @param {number} obj.hour - hour of the day, 0-23
* @param {number} obj.minute - minute of the hour, 0-59
* @param {number} obj.second - second of the minute, 0-59
* @param {number} obj.millisecond - millisecond of the second, 0-999
* @param {Object} opts - options for creating this DateTime
* @param {string|Zone} [opts.zone='local'] - interpret the numbers in the context of a particular zone. Can take any value taken as the first argument to setZone()
* @param {string} [opts.locale='system\'s locale'] - a locale to set on the resulting DateTime instance
* @param {string} opts.outputCalendar - the output calendar to set on the resulting DateTime instance
* @param {string} opts.numberingSystem - the numbering system to set on the resulting DateTime instance
* @param {string} opts.weekSettings - the week settings to set on the resulting DateTime instance
* @example DateTime.fromObject({ year: 1982, month: 5, day: 25}).toISODate() //=> '1982-05-25'
* @example DateTime.fromObject({ year: 1982 }).toISODate() //=> '1982-01-01'
* @example DateTime.fromObject({ hour: 10, minute: 26, second: 6 }) //~> today at 10:26:06
* @example DateTime.fromObject({ hour: 10, minute: 26, second: 6 }, { zone: 'utc' }),
* @example DateTime.fromObject({ hour: 10, minute: 26, second: 6 }, { zone: 'local' })
* @example DateTime.fromObject({ hour: 10, minute: 26, second: 6 }, { zone: 'America/New_York' })
* @example DateTime.fromObject({ weekYear: 2016, weekNumber: 2, weekday: 3 }).toISODate() //=> '2016-01-13'
* @example DateTime.fromObject({ localWeekYear: 2022, localWeekNumber: 1, localWeekday: 1 }, { locale: "en-US" }).toISODate() //=> '2021-12-26'
* @return {DateTime}
*/
static fromObject(obj, opts = {}) {
obj = obj || {};
const zoneToUse = normalizeZone(opts.zone, Settings.defaultZone);
if (!zoneToUse.isValid) {
return DateTime.invalid(unsupportedZone(zoneToUse));
}
const loc = Locale.fromObject(opts);
const normalized = normalizeObject(obj, normalizeUnitWithLocalWeeks);
const { minDaysInFirstWeek, startOfWeek } = usesLocalWeekValues(normalized, loc);
const tsNow = Settings.now(),
offsetProvis = !isUndefined$1(opts.specificOffset)
? opts.specificOffset
: zoneToUse.offset(tsNow),
containsOrdinal = !isUndefined$1(normalized.ordinal),
containsGregorYear = !isUndefined$1(normalized.year),
containsGregorMD = !isUndefined$1(normalized.month) || !isUndefined$1(normalized.day),
containsGregor = containsGregorYear || containsGregorMD,
definiteWeekDef = normalized.weekYear || normalized.weekNumber;
// cases:
// just a weekday -> this week's instance of that weekday, no worries
// (gregorian data or ordinal) + (weekYear or weekNumber) -> error
// (gregorian month or day) + ordinal -> error
// otherwise just use weeks or ordinals or gregorian, depending on what's specified
if ((containsGregor || containsOrdinal) && definiteWeekDef) {
throw new ConflictingSpecificationError(
"Can't mix weekYear/weekNumber units with year/month/day or ordinals"
);
}
if (containsGregorMD && containsOrdinal) {
throw new ConflictingSpecificationError("Can't mix ordinal dates with month/day");
}
const useWeekData = definiteWeekDef || (normalized.weekday && !containsGregor);
// configure ourselves to deal with gregorian dates or week stuff
let units,
defaultValues,
objNow = tsToObj(tsNow, offsetProvis);
if (useWeekData) {
units = orderedWeekUnits;
defaultValues = defaultWeekUnitValues;
objNow = gregorianToWeek(objNow, minDaysInFirstWeek, startOfWeek);
} else if (containsOrdinal) {
units = orderedOrdinalUnits;
defaultValues = defaultOrdinalUnitValues;
objNow = gregorianToOrdinal(objNow);
} else {
units = orderedUnits;
defaultValues = defaultUnitValues;
}
// set default values for missing stuff
let foundFirst = false;
for (const u of units) {
const v = normalized[u];
if (!isUndefined$1(v)) {
foundFirst = true;
} else if (foundFirst) {
normalized[u] = defaultValues[u];
} else {
normalized[u] = objNow[u];
}
}
// make sure the values we have are in range
const higherOrderInvalid = useWeekData
? hasInvalidWeekData(normalized, minDaysInFirstWeek, startOfWeek)
: containsOrdinal
? hasInvalidOrdinalData(normalized)
: hasInvalidGregorianData(normalized),
invalid = higherOrderInvalid || hasInvalidTimeData(normalized);
if (invalid) {
return DateTime.invalid(invalid);
}
// compute the actual time
const gregorian = useWeekData
? weekToGregorian(normalized, minDaysInFirstWeek, startOfWeek)
: containsOrdinal
? ordinalToGregorian(normalized)
: normalized,
[tsFinal, offsetFinal] = objToTS(gregorian, offsetProvis, zoneToUse),
inst = new DateTime({
ts: tsFinal,
zone: zoneToUse,
o: offsetFinal,
loc,
});
// gregorian data + weekday serves only to validate
if (normalized.weekday && containsGregor && obj.weekday !== inst.weekday) {
return DateTime.invalid(
"mismatched weekday",
`you can't specify both a weekday of ${normalized.weekday} and a date of ${inst.toISO()}`
);
}
if (!inst.isValid) {
return DateTime.invalid(inst.invalid);
}
return inst;
}
/**
* Create a DateTime from an ISO 8601 string
* @param {string} text - the ISO string
* @param {Object} opts - options to affect the creation
* @param {string|Zone} [opts.zone='local'] - use this zone if no offset is specified in the input string itself. Will also convert the time to this zone
* @param {boolean} [opts.setZone=false] - override the zone with a fixed-offset zone specified in the string itself, if it specifies one
* @param {string} [opts.locale='system's locale'] - a locale to set on the resulting DateTime instance
* @param {string} [opts.outputCalendar] - the output calendar to set on the resulting DateTime instance
* @param {string} [opts.numberingSystem] - the numbering system to set on the resulting DateTime instance
* @param {string} [opts.weekSettings] - the week settings to set on the resulting DateTime instance
* @example DateTime.fromISO('2016-05-25T09:08:34.123')
* @example DateTime.fromISO('2016-05-25T09:08:34.123+06:00')
* @example DateTime.fromISO('2016-05-25T09:08:34.123+06:00', {setZone: true})
* @example DateTime.fromISO('2016-05-25T09:08:34.123', {zone: 'utc'})
* @example DateTime.fromISO('2016-W05-4')
* @return {DateTime}
*/
static fromISO(text, opts = {}) {
const [vals, parsedZone] = parseISODate(text);
return parseDataToDateTime(vals, parsedZone, opts, "ISO 8601", text);
}
/**
* Create a DateTime from an RFC 2822 string
* @param {string} text - the RFC 2822 string
* @param {Object} opts - options to affect the creation
* @param {string|Zone} [opts.zone='local'] - convert the time to this zone. Since the offset is always specified in the string itself, this has no effect on the interpretation of string, merely the zone the resulting DateTime is expressed in.
* @param {boolean} [opts.setZone=false] - override the zone with a fixed-offset zone specified in the string itself, if it specifies one
* @param {string} [opts.locale='system's locale'] - a locale to set on the resulting DateTime instance
* @param {string} opts.outputCalendar - the output calendar to set on the resulting DateTime instance
* @param {string} opts.numberingSystem - the numbering system to set on the resulting DateTime instance
* @param {string} opts.weekSettings - the week settings to set on the resulting DateTime instance
* @example DateTime.fromRFC2822('25 Nov 2016 13:23:12 GMT')
* @example DateTime.fromRFC2822('Fri, 25 Nov 2016 13:23:12 +0600')
* @example DateTime.fromRFC2822('25 Nov 2016 13:23 Z')
* @return {DateTime}
*/
static fromRFC2822(text, opts = {}) {
const [vals, parsedZone] = parseRFC2822Date(text);
return parseDataToDateTime(vals, parsedZone, opts, "RFC 2822", text);
}
/**
* Create a DateTime from an HTTP header date
* @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1
* @param {string} text - the HTTP header date
* @param {Object} opts - options to affect the creation
* @param {string|Zone} [opts.zone='local'] - convert the time to this zone. Since HTTP dates are always in UTC, this has no effect on the interpretation of string, merely the zone the resulting DateTime is expressed in.
* @param {boolean} [opts.setZone=false] - override the zone with the fixed-offset zone specified in the string. For HTTP dates, this is always UTC, so this option is equivalent to setting the `zone` option to 'utc', but this option is included for consistency with similar methods.
* @param {string} [opts.locale='system's locale'] - a locale to set on the resulting DateTime instance
* @param {string} opts.outputCalendar - the output calendar to set on the resulting DateTime instance
* @param {string} opts.numberingSystem - the numbering system to set on the resulting DateTime instance
* @param {string} opts.weekSettings - the week settings to set on the resulting DateTime instance
* @example DateTime.fromHTTP('Sun, 06 Nov 1994 08:49:37 GMT')
* @example DateTime.fromHTTP('Sunday, 06-Nov-94 08:49:37 GMT')
* @example DateTime.fromHTTP('Sun Nov 6 08:49:37 1994')
* @return {DateTime}
*/
static fromHTTP(text, opts = {}) {
const [vals, parsedZone] = parseHTTPDate(text);
return parseDataToDateTime(vals, parsedZone, opts, "HTTP", opts);
}
/**
* Create a DateTime from an input string and format string.
* Defaults to en-US if no locale has been specified, regardless of the system's locale. For a table of tokens and their interpretations, see [here](https://moment.github.io/luxon/#/parsing?id=table-of-tokens).
* @param {string} text - the string to parse
* @param {string} fmt - the format the string is expected to be in (see the link below for the formats)
* @param {Object} opts - options to affect the creation
* @param {string|Zone} [opts.zone='local'] - use this zone if no offset is specified in the input string itself. Will also convert the DateTime to this zone
* @param {boolean} [opts.setZone=false] - override the zone with a zone specified in the string itself, if it specifies one
* @param {string} [opts.locale='en-US'] - a locale string to use when parsing. Will also set the DateTime to this locale
* @param {string} opts.numberingSystem - the numbering system to use when parsing. Will also set the resulting DateTime to this numbering system
* @param {string} opts.weekSettings - the week settings to set on the resulting DateTime instance
* @param {string} opts.outputCalendar - the output calendar to set on the resulting DateTime instance
* @return {DateTime}
*/
static fromFormat(text, fmt, opts = {}) {
if (isUndefined$1(text) || isUndefined$1(fmt)) {
throw new InvalidArgumentError("fromFormat requires an input string and a format");
}
const { locale = null, numberingSystem = null } = opts,
localeToUse = Locale.fromOpts({
locale,
numberingSystem,
defaultToEN: true,
}),
[vals, parsedZone, specificOffset, invalid] = parseFromTokens(localeToUse, text, fmt);
if (invalid) {
return DateTime.invalid(invalid);
} else {
return parseDataToDateTime(vals, parsedZone, opts, `format ${fmt}`, text, specificOffset);
}
}
/**
* @deprecated use fromFormat instead
*/
static fromString(text, fmt, opts = {}) {
return DateTime.fromFormat(text, fmt, opts);
}
/**
* Create a DateTime from a SQL date, time, or datetime
* Defaults to en-US if no locale has been specified, regardless of the system's locale
* @param {string} text - the string to parse
* @param {Object} opts - options to affect the creation
* @param {string|Zone} [opts.zone='local'] - use this zone if no offset is specified in the input string itself. Will also convert the DateTime to this zone
* @param {boolean} [opts.setZone=false] - override the zone with a zone specified in the string itself, if it specifies one
* @param {string} [opts.locale='en-US'] - a locale string to use when parsing. Will also set the DateTime to this locale
* @param {string} opts.numberingSystem - the numbering system to use when parsing. Will also set the resulting DateTime to this numbering system
* @param {string} opts.weekSettings - the week settings to set on the resulting DateTime instance
* @param {string} opts.outputCalendar - the output calendar to set on the resulting DateTime instance
* @example DateTime.fromSQL('2017-05-15')
* @example DateTime.fromSQL('2017-05-15 09:12:34')
* @example DateTime.fromSQL('2017-05-15 09:12:34.342')
* @example DateTime.fromSQL('2017-05-15 09:12:34.342+06:00')
* @example DateTime.fromSQL('2017-05-15 09:12:34.342 America/Los_Angeles')
* @example DateTime.fromSQL('2017-05-15 09:12:34.342 America/Los_Angeles', { setZone: true })
* @example DateTime.fromSQL('2017-05-15 09:12:34.342', { zone: 'America/Los_Angeles' })
* @example DateTime.fromSQL('09:12:34.342')
* @return {DateTime}
*/
static fromSQL(text, opts = {}) {
const [vals, parsedZone] = parseSQL(text);
return parseDataToDateTime(vals, parsedZone, opts, "SQL", text);
}
/**
* Create an invalid DateTime.
* @param {string} reason - simple string of why this DateTime is invalid. Should not contain parameters or anything else data-dependent.
* @param {string} [explanation=null] - longer explanation, may include parameters and other useful debugging information
* @return {DateTime}
*/
static invalid(reason, explanation = null) {
if (!reason) {
throw new InvalidArgumentError("need to specify a reason the DateTime is invalid");
}
const invalid = reason instanceof Invalid ? reason : new Invalid(reason, explanation);
if (Settings.throwOnInvalid) {
throw new InvalidDateTimeError(invalid);
} else {
return new DateTime({ invalid });
}
}
/**
* Check if an object is an instance of DateTime. Works across context boundaries
* @param {object} o
* @return {boolean}
*/
static isDateTime(o) {
return (o && o.isLuxonDateTime) || false;
}
/**
* Produce the format string for a set of options
* @param formatOpts
* @param localeOpts
* @returns {string}
*/
static parseFormatForOpts(formatOpts, localeOpts = {}) {
const tokenList = formatOptsToTokens(formatOpts, Locale.fromObject(localeOpts));
return !tokenList ? null : tokenList.map((t) => (t ? t.val : null)).join("");
}
/**
* Produce the the fully expanded format token for the locale
* Does NOT quote characters, so quoted tokens will not round trip correctly
* @param fmt
* @param localeOpts
* @returns {string}
*/
static expandFormat(fmt, localeOpts = {}) {
const expanded = expandMacroTokens(Formatter.parseFormat(fmt), Locale.fromObject(localeOpts));
return expanded.map((t) => t.val).join("");
}
static resetCache() {
zoneOffsetTs = undefined;
zoneOffsetGuessCache.clear();
}
// INFO
/**
* Get the value of unit.
* @param {string} unit - a unit such as 'minute' or 'day'
* @example DateTime.local(2017, 7, 4).get('month'); //=> 7
* @example DateTime.local(2017, 7, 4).get('day'); //=> 4
* @return {number}
*/
get(unit) {
return this[unit];
}
/**
* Returns whether the DateTime is valid. Invalid DateTimes occur when:
* * The DateTime was created from invalid calendar information, such as the 13th month or February 30
* * The DateTime was created by an operation on another invalid date
* @type {boolean}
*/
get isValid() {
return this.invalid === null;
}
/**
* Returns an error code if this DateTime is invalid, or null if the DateTime is valid
* @type {string}
*/
get invalidReason() {
return this.invalid ? this.invalid.reason : null;
}
/**
* Returns an explanation of why this DateTime became invalid, or null if the DateTime is valid
* @type {string}
*/
get invalidExplanation() {
return this.invalid ? this.invalid.explanation : null;
}
/**
* Get the locale of a DateTime, such 'en-GB'. The locale is used when formatting the DateTime
*
* @type {string}
*/
get locale() {
return this.isValid ? this.loc.locale : null;
}
/**
* Get the numbering system of a DateTime, such 'beng'. The numbering system is used when formatting the DateTime
*
* @type {string}
*/
get numberingSystem() {
return this.isValid ? this.loc.numberingSystem : null;
}
/**
* Get the output calendar of a DateTime, such 'islamic'. The output calendar is used when formatting the DateTime
*
* @type {string}
*/
get outputCalendar() {
return this.isValid ? this.loc.outputCalendar : null;
}
/**
* Get the time zone associated with this DateTime.
* @type {Zone}
*/
get zone() {
return this._zone;
}
/**
* Get the name of the time zone.
* @type {string}
*/
get zoneName() {
return this.isValid ? this.zone.name : null;
}
/**
* Get the year
* @example DateTime.local(2017, 5, 25).year //=> 2017
* @type {number}
*/
get year() {
return this.isValid ? this.c.year : NaN;
}
/**
* Get the quarter
* @example DateTime.local(2017, 5, 25).quarter //=> 2
* @type {number}
*/
get quarter() {
return this.isValid ? Math.ceil(this.c.month / 3) : NaN;
}
/**
* Get the month (1-12).
* @example DateTime.local(2017, 5, 25).month //=> 5
* @type {number}
*/
get month() {
return this.isValid ? this.c.month : NaN;
}
/**
* Get the day of the month (1-30ish).
* @example DateTime.local(2017, 5, 25).day //=> 25
* @type {number}
*/
get day() {
return this.isValid ? this.c.day : NaN;
}
/**
* Get the hour of the day (0-23).
* @example DateTime.local(2017, 5, 25, 9).hour //=> 9
* @type {number}
*/
get hour() {
return this.isValid ? this.c.hour : NaN;
}
/**
* Get the minute of the hour (0-59).
* @example DateTime.local(2017, 5, 25, 9, 30).minute //=> 30
* @type {number}
*/
get minute() {
return this.isValid ? this.c.minute : NaN;
}
/**
* Get the second of the minute (0-59).
* @example DateTime.local(2017, 5, 25, 9, 30, 52).second //=> 52
* @type {number}
*/
get second() {
return this.isValid ? this.c.second : NaN;
}
/**
* Get the millisecond of the second (0-999).
* @example DateTime.local(2017, 5, 25, 9, 30, 52, 654).millisecond //=> 654
* @type {number}
*/
get millisecond() {
return this.isValid ? this.c.millisecond : NaN;
}
/**
* Get the week year
* @see https://en.wikipedia.org/wiki/ISO_week_date
* @example DateTime.local(2014, 12, 31).weekYear //=> 2015
* @type {number}
*/
get weekYear() {
return this.isValid ? possiblyCachedWeekData(this).weekYear : NaN;
}
/**
* Get the week number of the week year (1-52ish).
* @see https://en.wikipedia.org/wiki/ISO_week_date
* @example DateTime.local(2017, 5, 25).weekNumber //=> 21
* @type {number}
*/
get weekNumber() {
return this.isValid ? possiblyCachedWeekData(this).weekNumber : NaN;
}
/**
* Get the day of the week.
* 1 is Monday and 7 is Sunday
* @see https://en.wikipedia.org/wiki/ISO_week_date
* @example DateTime.local(2014, 11, 31).weekday //=> 4
* @type {number}
*/
get weekday() {
return this.isValid ? possiblyCachedWeekData(this).weekday : NaN;
}
/**
* Returns true if this date is on a weekend according to the locale, false otherwise
* @returns {boolean}
*/
get isWeekend() {
return this.isValid && this.loc.getWeekendDays().includes(this.weekday);
}
/**
* Get the day of the week according to the locale.
* 1 is the first day of the week and 7 is the last day of the week.
* If the locale assigns Sunday as the first day of the week, then a date which is a Sunday will return 1,
* @returns {number}
*/
get localWeekday() {
return this.isValid ? possiblyCachedLocalWeekData(this).weekday : NaN;
}
/**
* Get the week number of the week year according to the locale. Different locales assign week numbers differently,
* because the week can start on different days of the week (see localWeekday) and because a different number of days
* is required for a week to count as the first week of a year.
* @returns {number}
*/
get localWeekNumber() {
return this.isValid ? possiblyCachedLocalWeekData(this).weekNumber : NaN;
}
/**
* Get the week year according to the locale. Different locales assign week numbers (and therefor week years)
* differently, see localWeekNumber.
* @returns {number}
*/
get localWeekYear() {
return this.isValid ? possiblyCachedLocalWeekData(this).weekYear : NaN;
}
/**
* Get the ordinal (meaning the day of the year)
* @example DateTime.local(2017, 5, 25).ordinal //=> 145
* @type {number|DateTime}
*/
get ordinal() {
return this.isValid ? gregorianToOrdinal(this.c).ordinal : NaN;
}
/**
* Get the human readable short month name, such as 'Oct'.
* Defaults to the system's locale if no locale has been specified
* @example DateTime.local(2017, 10, 30).monthShort //=> Oct
* @type {string}
*/
get monthShort() {
return this.isValid ? Info.months("short", { locObj: this.loc })[this.month - 1] : null;
}
/**
* Get the human readable long month name, such as 'October'.
* Defaults to the system's locale if no locale has been specified
* @example DateTime.local(2017, 10, 30).monthLong //=> October
* @type {string}
*/
get monthLong() {
return this.isValid ? Info.months("long", { locObj: this.loc })[this.month - 1] : null;
}
/**
* Get the human readable short weekday, such as 'Mon'.
* Defaults to the system's locale if no locale has been specified
* @example DateTime.local(2017, 10, 30).weekdayShort //=> Mon
* @type {string}
*/
get weekdayShort() {
return this.isValid ? Info.weekdays("short", { locObj: this.loc })[this.weekday - 1] : null;
}
/**
* Get the human readable long weekday, such as 'Monday'.
* Defaults to the system's locale if no locale has been specified
* @example DateTime.local(2017, 10, 30).weekdayLong //=> Monday
* @type {string}
*/
get weekdayLong() {
return this.isValid ? Info.weekdays("long", { locObj: this.loc })[this.weekday - 1] : null;
}
/**
* Get the UTC offset of this DateTime in minutes
* @example DateTime.now().offset //=> -240
* @example DateTime.utc().offset //=> 0
* @type {number}
*/
get offset() {
return this.isValid ? +this.o : NaN;
}
/**
* Get the short human name for the zone's current offset, for example "EST" or "EDT".
* Defaults to the system's locale if no locale has been specified
* @type {string}
*/
get offsetNameShort() {
if (this.isValid) {
return this.zone.offsetName(this.ts, {
format: "short",
locale: this.locale,
});
} else {
return null;
}
}
/**
* Get the long human name for the zone's current offset, for example "Eastern Standard Time" or "Eastern Daylight Time".
* Defaults to the system's locale if no locale has been specified
* @type {string}
*/
get offsetNameLong() {
if (this.isValid) {
return this.zone.offsetName(this.ts, {
format: "long",
locale: this.locale,
});
} else {
return null;
}
}
/**
* Get whether this zone's offset ever changes, as in a DST.
* @type {boolean}
*/
get isOffsetFixed() {
return this.isValid ? this.zone.isUniversal : null;
}
/**
* Get whether the DateTime is in a DST.
* @type {boolean}
*/
get isInDST() {
if (this.isOffsetFixed) {
return false;
} else {
return (
this.offset > this.set({ month: 1, day: 1 }).offset ||
this.offset > this.set({ month: 5 }).offset
);
}
}
/**
* Get those DateTimes which have the same local time as this DateTime, but a different offset from UTC
* in this DateTime's zone. During DST changes local time can be ambiguous, for example
* `2023-10-29T02:30:00` in `Europe/Berlin` can have offset `+01:00` or `+02:00`.
* This method will return both possible DateTimes if this DateTime's local time is ambiguous.
* @returns {DateTime[]}
*/
getPossibleOffsets() {
if (!this.isValid || this.isOffsetFixed) {
return [this];
}
const dayMs = 86400000;
const minuteMs = 60000;
const localTS = objToLocalTS(this.c);
const oEarlier = this.zone.offset(localTS - dayMs);
const oLater = this.zone.offset(localTS + dayMs);
const o1 = this.zone.offset(localTS - oEarlier * minuteMs);
const o2 = this.zone.offset(localTS - oLater * minuteMs);
if (o1 === o2) {
return [this];
}
const ts1 = localTS - o1 * minuteMs;
const ts2 = localTS - o2 * minuteMs;
const c1 = tsToObj(ts1, o1);
const c2 = tsToObj(ts2, o2);
if (
c1.hour === c2.hour &&
c1.minute === c2.minute &&
c1.second === c2.second &&
c1.millisecond === c2.millisecond
) {
return [clone(this, { ts: ts1 }), clone(this, { ts: ts2 })];
}
return [this];
}
/**
* Returns true if this DateTime is in a leap year, false otherwise
* @example DateTime.local(2016).isInLeapYear //=> true
* @example DateTime.local(2013).isInLeapYear //=> false
* @type {boolean}
*/
get isInLeapYear() {
return isLeapYear(this.year);
}
/**
* Returns the number of days in this DateTime's month
* @example DateTime.local(2016, 2).daysInMonth //=> 29
* @example DateTime.local(2016, 3).daysInMonth //=> 31
* @type {number}
*/
get daysInMonth() {
return daysInMonth(this.year, this.month);
}
/**
* Returns the number of days in this DateTime's year
* @example DateTime.local(2016).daysInYear //=> 366
* @example DateTime.local(2013).daysInYear //=> 365
* @type {number}
*/
get daysInYear() {
return this.isValid ? daysInYear(this.year) : NaN;
}
/**
* Returns the number of weeks in this DateTime's year
* @see https://en.wikipedia.org/wiki/ISO_week_date
* @example DateTime.local(2004).weeksInWeekYear //=> 53
* @example DateTime.local(2013).weeksInWeekYear //=> 52
* @type {number}
*/
get weeksInWeekYear() {
return this.isValid ? weeksInWeekYear(this.weekYear) : NaN;
}
/**
* Returns the number of weeks in this DateTime's local week year
* @example DateTime.local(2020, 6, {locale: 'en-US'}).weeksInLocalWeekYear //=> 52
* @example DateTime.local(2020, 6, {locale: 'de-DE'}).weeksInLocalWeekYear //=> 53
* @type {number}
*/
get weeksInLocalWeekYear() {
return this.isValid
? weeksInWeekYear(
this.localWeekYear,
this.loc.getMinDaysInFirstWeek(),
this.loc.getStartOfWeek()
)
: NaN;
}
/**
* Returns the resolved Intl options for this DateTime.
* This is useful in understanding the behavior of formatting methods
* @param {Object} opts - the same options as toLocaleString
* @return {Object}
*/
resolvedLocaleOptions(opts = {}) {
const { locale, numberingSystem, calendar } = Formatter.create(
this.loc.clone(opts),
opts
).resolvedOptions(this);
return { locale, numberingSystem, outputCalendar: calendar };
}
// TRANSFORM
/**
* "Set" the DateTime's zone to UTC. Returns a newly-constructed DateTime.
*
* Equivalent to {@link DateTime#setZone}('utc')
* @param {number} [offset=0] - optionally, an offset from UTC in minutes
* @param {Object} [opts={}] - options to pass to `setZone()`
* @return {DateTime}
*/
toUTC(offset = 0, opts = {}) {
return this.setZone(FixedOffsetZone.instance(offset), opts);
}
/**
* "Set" the DateTime's zone to the host's local zone. Returns a newly-constructed DateTime.
*
* Equivalent to `setZone('local')`
* @return {DateTime}
*/
toLocal() {
return this.setZone(Settings.defaultZone);
}
/**
* "Set" the DateTime's zone to specified zone. Returns a newly-constructed DateTime.
*
* By default, the setter keeps the underlying time the same (as in, the same timestamp), but the new instance will report different local times and consider DSTs when making computations, as with {@link DateTime#plus}. You may wish to use {@link DateTime#toLocal} and {@link DateTime#toUTC} which provide simple convenience wrappers for commonly used zones.
* @param {string|Zone} [zone='local'] - a zone identifier. As a string, that can be any IANA zone supported by the host environment, or a fixed-offset name of the form 'UTC+3', or the strings 'local' or 'utc'. You may also supply an instance of a {@link DateTime#Zone} class.
* @param {Object} opts - options
* @param {boolean} [opts.keepLocalTime=false] - If true, adjust the underlying time so that the local time stays the same, but in the target zone. You should rarely need this.
* @return {DateTime}
*/
setZone(zone, { keepLocalTime = false, keepCalendarTime = false } = {}) {
zone = normalizeZone(zone, Settings.defaultZone);
if (zone.equals(this.zone)) {
return this;
} else if (!zone.isValid) {
return DateTime.invalid(unsupportedZone(zone));
} else {
let newTS = this.ts;
if (keepLocalTime || keepCalendarTime) {
const offsetGuess = zone.offset(this.ts);
const asObj = this.toObject();
[newTS] = objToTS(asObj, offsetGuess, zone);
}
return clone(this, { ts: newTS, zone });
}
}
/**
* "Set" the locale, numberingSystem, or outputCalendar. Returns a newly-constructed DateTime.
* @param {Object} properties - the properties to set
* @example DateTime.local(2017, 5, 25).reconfigure({ locale: 'en-GB' })
* @return {DateTime}
*/
reconfigure({ locale, numberingSystem, outputCalendar } = {}) {
const loc = this.loc.clone({ locale, numberingSystem, outputCalendar });
return clone(this, { loc });
}
/**
* "Set" the locale. Returns a newly-constructed DateTime.
* Just a convenient alias for reconfigure({ locale })
* @example DateTime.local(2017, 5, 25).setLocale('en-GB')
* @return {DateTime}
*/
setLocale(locale) {
return this.reconfigure({ locale });
}
/**
* "Set" the values of specified units. Returns a newly-constructed DateTime.
* You can only set units with this method; for "setting" metadata, see {@link DateTime#reconfigure} and {@link DateTime#setZone}.
*
* This method also supports setting locale-based week units, i.e. `localWeekday`, `localWeekNumber` and `localWeekYear`.
* They cannot be mixed with ISO-week units like `weekday`.
* @param {Object} values - a mapping of units to numbers
* @example dt.set({ year: 2017 })
* @example dt.set({ hour: 8, minute: 30 })
* @example dt.set({ weekday: 5 })
* @example dt.set({ year: 2005, ordinal: 234 })
* @return {DateTime}
*/
set(values) {
if (!this.isValid) return this;
const normalized = normalizeObject(values, normalizeUnitWithLocalWeeks);
const { minDaysInFirstWeek, startOfWeek } = usesLocalWeekValues(normalized, this.loc);
const settingWeekStuff =
!isUndefined$1(normalized.weekYear) ||
!isUndefined$1(normalized.weekNumber) ||
!isUndefined$1(normalized.weekday),
containsOrdinal = !isUndefined$1(normalized.ordinal),
containsGregorYear = !isUndefined$1(normalized.year),
containsGregorMD = !isUndefined$1(normalized.month) || !isUndefined$1(normalized.day),
containsGregor = containsGregorYear || containsGregorMD,
definiteWeekDef = normalized.weekYear || normalized.weekNumber;
if ((containsGregor || containsOrdinal) && definiteWeekDef) {
throw new ConflictingSpecificationError(
"Can't mix weekYear/weekNumber units with year/month/day or ordinals"
);
}
if (containsGregorMD && containsOrdinal) {
throw new ConflictingSpecificationError("Can't mix ordinal dates with month/day");
}
let mixed;
if (settingWeekStuff) {
mixed = weekToGregorian(
{ ...gregorianToWeek(this.c, minDaysInFirstWeek, startOfWeek), ...normalized },
minDaysInFirstWeek,
startOfWeek
);
} else if (!isUndefined$1(normalized.ordinal)) {
mixed = ordinalToGregorian({ ...gregorianToOrdinal(this.c), ...normalized });
} else {
mixed = { ...this.toObject(), ...normalized };
// if we didn't set the day but we ended up on an overflow date,
// use the last day of the right month
if (isUndefined$1(normalized.day)) {
mixed.day = Math.min(daysInMonth(mixed.year, mixed.month), mixed.day);
}
}
const [ts, o] = objToTS(mixed, this.o, this.zone);
return clone(this, { ts, o });
}
/**
* Add a period of time to this DateTime and return the resulting DateTime
*
* Adding hours, minutes, seconds, or milliseconds increases the timestamp by the right number of milliseconds. Adding days, months, or years shifts the calendar, accounting for DSTs and leap years along the way. Thus, `dt.plus({ hours: 24 })` may result in a different time than `dt.plus({ days: 1 })` if there's a DST shift in between.
* @param {Duration|Object|number} duration - The amount to add. Either a Luxon Duration, a number of milliseconds, the object argument to Duration.fromObject()
* @example DateTime.now().plus(123) //~> in 123 milliseconds
* @example DateTime.now().plus({ minutes: 15 }) //~> in 15 minutes
* @example DateTime.now().plus({ days: 1 }) //~> this time tomorrow
* @example DateTime.now().plus({ days: -1 }) //~> this time yesterday
* @example DateTime.now().plus({ hours: 3, minutes: 13 }) //~> in 3 hr, 13 min
* @example DateTime.now().plus(Duration.fromObject({ hours: 3, minutes: 13 })) //~> in 3 hr, 13 min
* @return {DateTime}
*/
plus(duration) {
if (!this.isValid) return this;
const dur = Duration.fromDurationLike(duration);
return clone(this, adjustTime(this, dur));
}
/**
* Subtract a period of time to this DateTime and return the resulting DateTime
* See {@link DateTime#plus}
* @param {Duration|Object|number} duration - The amount to subtract. Either a Luxon Duration, a number of milliseconds, the object argument to Duration.fromObject()
@return {DateTime}
*/
minus(duration) {
if (!this.isValid) return this;
const dur = Duration.fromDurationLike(duration).negate();
return clone(this, adjustTime(this, dur));
}
/**
* "Set" this DateTime to the beginning of a unit of time.
* @param {string} unit - The unit to go to the beginning of. Can be 'year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', or 'millisecond'.
* @param {Object} opts - options
* @param {boolean} [opts.useLocaleWeeks=false] - If true, use weeks based on the locale, i.e. use the locale-dependent start of the week
* @example DateTime.local(2014, 3, 3).startOf('month').toISODate(); //=> '2014-03-01'
* @example DateTime.local(2014, 3, 3).startOf('year').toISODate(); //=> '2014-01-01'
* @example DateTime.local(2014, 3, 3).startOf('week').toISODate(); //=> '2014-03-03', weeks always start on Mondays
* @example DateTime.local(2014, 3, 3, 5, 30).startOf('day').toISOTime(); //=> '00:00.000-05:00'
* @example DateTime.local(2014, 3, 3, 5, 30).startOf('hour').toISOTime(); //=> '05:00:00.000-05:00'
* @return {DateTime}
*/
startOf(unit, { useLocaleWeeks = false } = {}) {
if (!this.isValid) return this;
const o = {},
normalizedUnit = Duration.normalizeUnit(unit);
switch (normalizedUnit) {
case "years":
o.month = 1;
// falls through
case "quarters":
case "months":
o.day = 1;
// falls through
case "weeks":
case "days":
o.hour = 0;
// falls through
case "hours":
o.minute = 0;
// falls through
case "minutes":
o.second = 0;
// falls through
case "seconds":
o.millisecond = 0;
break;
// no default, invalid units throw in normalizeUnit()
}
if (normalizedUnit === "weeks") {
if (useLocaleWeeks) {
const startOfWeek = this.loc.getStartOfWeek();
const { weekday } = this;
if (weekday < startOfWeek) {
o.weekNumber = this.weekNumber - 1;
}
o.weekday = startOfWeek;
} else {
o.weekday = 1;
}
}
if (normalizedUnit === "quarters") {
const q = Math.ceil(this.month / 3);
o.month = (q - 1) * 3 + 1;
}
return this.set(o);
}
/**
* "Set" this DateTime to the end (meaning the last millisecond) of a unit of time
* @param {string} unit - The unit to go to the end of. Can be 'year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', or 'millisecond'.
* @param {Object} opts - options
* @param {boolean} [opts.useLocaleWeeks=false] - If true, use weeks based on the locale, i.e. use the locale-dependent start of the week
* @example DateTime.local(2014, 3, 3).endOf('month').toISO(); //=> '2014-03-31T23:59:59.999-05:00'
* @example DateTime.local(2014, 3, 3).endOf('year').toISO(); //=> '2014-12-31T23:59:59.999-05:00'
* @example DateTime.local(2014, 3, 3).endOf('week').toISO(); // => '2014-03-09T23:59:59.999-05:00', weeks start on Mondays
* @example DateTime.local(2014, 3, 3, 5, 30).endOf('day').toISO(); //=> '2014-03-03T23:59:59.999-05:00'
* @example DateTime.local(2014, 3, 3, 5, 30).endOf('hour').toISO(); //=> '2014-03-03T05:59:59.999-05:00'
* @return {DateTime}
*/
endOf(unit, opts) {
return this.isValid
? this.plus({ [unit]: 1 })
.startOf(unit, opts)
.minus(1)
: this;
}
// OUTPUT
/**
* Returns a string representation of this DateTime formatted according to the specified format string.
* **You may not want this.** See {@link DateTime#toLocaleString} for a more flexible formatting tool. For a table of tokens and their interpretations, see [here](https://moment.github.io/luxon/#/formatting?id=table-of-tokens).
* Defaults to en-US if no locale has been specified, regardless of the system's locale.
* @param {string} fmt - the format string
* @param {Object} opts - opts to override the configuration options on this DateTime
* @example DateTime.now().toFormat('yyyy LLL dd') //=> '2017 Apr 22'
* @example DateTime.now().setLocale('fr').toFormat('yyyy LLL dd') //=> '2017 avr. 22'
* @example DateTime.now().toFormat('yyyy LLL dd', { locale: "fr" }) //=> '2017 avr. 22'
* @example DateTime.now().toFormat("HH 'hours and' mm 'minutes'") //=> '20 hours and 55 minutes'
* @return {string}
*/
toFormat(fmt, opts = {}) {
return this.isValid
? Formatter.create(this.loc.redefaultToEN(opts)).formatDateTimeFromString(this, fmt)
: INVALID;
}
/**
* Returns a localized string representing this date. Accepts the same options as the Intl.DateTimeFormat constructor and any presets defined by Luxon, such as `DateTime.DATE_FULL` or `DateTime.TIME_SIMPLE`.
* The exact behavior of this method is browser-specific, but in general it will return an appropriate representation
* of the DateTime in the assigned locale.
* Defaults to the system's locale if no locale has been specified
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
* @param formatOpts {Object} - Intl.DateTimeFormat constructor options and configuration options
* @param {Object} opts - opts to override the configuration options on this DateTime
* @example DateTime.now().toLocaleString(); //=> 4/20/2017
* @example DateTime.now().setLocale('en-gb').toLocaleString(); //=> '20/04/2017'
* @example DateTime.now().toLocaleString(DateTime.DATE_FULL); //=> 'April 20, 2017'
* @example DateTime.now().toLocaleString(DateTime.DATE_FULL, { locale: 'fr' }); //=> '28 août 2022'
* @example DateTime.now().toLocaleString(DateTime.TIME_SIMPLE); //=> '11:32 AM'
* @example DateTime.now().toLocaleString(DateTime.DATETIME_SHORT); //=> '4/20/2017, 11:32 AM'
* @example DateTime.now().toLocaleString({ weekday: 'long', month: 'long', day: '2-digit' }); //=> 'Thursday, April 20'
* @example DateTime.now().toLocaleString({ weekday: 'short', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }); //=> 'Thu, Apr 20, 11:27 AM'
* @example DateTime.now().toLocaleString({ hour: '2-digit', minute: '2-digit', hourCycle: 'h23' }); //=> '11:32'
* @return {string}
*/
toLocaleString(formatOpts = DATE_SHORT, opts = {}) {
return this.isValid
? Formatter.create(this.loc.clone(opts), formatOpts).formatDateTime(this)
: INVALID;
}
/**
* Returns an array of format "parts", meaning individual tokens along with metadata. This is allows callers to post-process individual sections of the formatted output.
* Defaults to the system's locale if no locale has been specified
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat/formatToParts
* @param opts {Object} - Intl.DateTimeFormat constructor options, same as `toLocaleString`.
* @example DateTime.now().toLocaleParts(); //=> [
* //=> { type: 'day', value: '25' },
* //=> { type: 'literal', value: '/' },
* //=> { type: 'month', value: '05' },
* //=> { type: 'literal', value: '/' },
* //=> { type: 'year', value: '1982' }
* //=> ]
*/
toLocaleParts(opts = {}) {
return this.isValid
? Formatter.create(this.loc.clone(opts), opts).formatDateTimeParts(this)
: [];
}
/**
* Returns an ISO 8601-compliant string representation of this DateTime
* @param {Object} opts - options
* @param {boolean} [opts.suppressMilliseconds=false] - exclude milliseconds from the format if they're 0
* @param {boolean} [opts.suppressSeconds=false] - exclude seconds from the format if they're 0
* @param {boolean} [opts.includeOffset=true] - include the offset, such as 'Z' or '-04:00'
* @param {boolean} [opts.extendedZone=false] - add the time zone format extension
* @param {string} [opts.format='extended'] - choose between the basic and extended format
* @param {string} [opts.precision='milliseconds'] - truncate output to desired presicion: 'years', 'months', 'days', 'hours', 'minutes', 'seconds' or 'milliseconds'. When precision and suppressSeconds or suppressMilliseconds are used together, precision sets the maximum unit shown in the output, however seconds or milliseconds will still be suppressed if they are 0.
* @example DateTime.utc(1983, 5, 25).toISO() //=> '1982-05-25T00:00:00.000Z'
* @example DateTime.now().toISO() //=> '2017-04-22T20:47:05.335-04:00'
* @example DateTime.now().toISO({ includeOffset: false }) //=> '2017-04-22T20:47:05.335'
* @example DateTime.now().toISO({ format: 'basic' }) //=> '20170422T204705.335-0400'
* @example DateTime.now().toISO({ precision: 'day' }) //=> '2017-04-22Z'
* @example DateTime.now().toISO({ precision: 'minute' }) //=> '2017-04-22T20:47Z'
* @return {string|null}
*/
toISO({
format = "extended",
suppressSeconds = false,
suppressMilliseconds = false,
includeOffset = true,
extendedZone = false,
precision = "milliseconds",
} = {}) {
if (!this.isValid) {
return null;
}
precision = normalizeUnit(precision);
const ext = format === "extended";
let c = toISODate(this, ext, precision);
if (orderedUnits.indexOf(precision) >= 3) c += "T";
c += toISOTime(
this,
ext,
suppressSeconds,
suppressMilliseconds,
includeOffset,
extendedZone,
precision
);
return c;
}
/**
* Returns an ISO 8601-compliant string representation of this DateTime's date component
* @param {Object} opts - options
* @param {string} [opts.format='extended'] - choose between the basic and extended format
* @param {string} [opts.precision='day'] - truncate output to desired precision: 'years', 'months', or 'days'.
* @example DateTime.utc(1982, 5, 25).toISODate() //=> '1982-05-25'
* @example DateTime.utc(1982, 5, 25).toISODate({ format: 'basic' }) //=> '19820525'
* @example DateTime.utc(1982, 5, 25).toISODate({ precision: 'month' }) //=> '1982-05'
* @return {string|null}
*/
toISODate({ format = "extended", precision = "day" } = {}) {
if (!this.isValid) {
return null;
}
return toISODate(this, format === "extended", normalizeUnit(precision));
}
/**
* Returns an ISO 8601-compliant string representation of this DateTime's week date
* @example DateTime.utc(1982, 5, 25).toISOWeekDate() //=> '1982-W21-2'
* @return {string}
*/
toISOWeekDate() {
return toTechFormat(this, "kkkk-'W'WW-c");
}
/**
* Returns an ISO 8601-compliant string representation of this DateTime's time component
* @param {Object} opts - options
* @param {boolean} [opts.suppressMilliseconds=false] - exclude milliseconds from the format if they're 0
* @param {boolean} [opts.suppressSeconds=false] - exclude seconds from the format if they're 0
* @param {boolean} [opts.includeOffset=true] - include the offset, such as 'Z' or '-04:00'
* @param {boolean} [opts.extendedZone=true] - add the time zone format extension
* @param {boolean} [opts.includePrefix=false] - include the `T` prefix
* @param {string} [opts.format='extended'] - choose between the basic and extended format
* @param {string} [opts.precision='milliseconds'] - truncate output to desired presicion: 'hours', 'minutes', 'seconds' or 'milliseconds'. When precision and suppressSeconds or suppressMilliseconds are used together, precision sets the maximum unit shown in the output, however seconds or milliseconds will still be suppressed if they are 0.
* @example DateTime.utc().set({ hour: 7, minute: 34 }).toISOTime() //=> '07:34:19.361Z'
* @example DateTime.utc().set({ hour: 7, minute: 34, seconds: 0, milliseconds: 0 }).toISOTime({ suppressSeconds: true }) //=> '07:34Z'
* @example DateTime.utc().set({ hour: 7, minute: 34 }).toISOTime({ format: 'basic' }) //=> '073419.361Z'
* @example DateTime.utc().set({ hour: 7, minute: 34 }).toISOTime({ includePrefix: true }) //=> 'T07:34:19.361Z'
* @example DateTime.utc().set({ hour: 7, minute: 34, second: 56 }).toISOTime({ precision: 'minute' }) //=> '07:34Z'
* @return {string}
*/
toISOTime({
suppressMilliseconds = false,
suppressSeconds = false,
includeOffset = true,
includePrefix = false,
extendedZone = false,
format = "extended",
precision = "milliseconds",
} = {}) {
if (!this.isValid) {
return null;
}
precision = normalizeUnit(precision);
let c = includePrefix && orderedUnits.indexOf(precision) >= 3 ? "T" : "";
return (
c +
toISOTime(
this,
format === "extended",
suppressSeconds,
suppressMilliseconds,
includeOffset,
extendedZone,
precision
)
);
}
/**
* Returns an RFC 2822-compatible string representation of this DateTime
* @example DateTime.utc(2014, 7, 13).toRFC2822() //=> 'Sun, 13 Jul 2014 00:00:00 +0000'
* @example DateTime.local(2014, 7, 13).toRFC2822() //=> 'Sun, 13 Jul 2014 00:00:00 -0400'
* @return {string}
*/
toRFC2822() {
return toTechFormat(this, "EEE, dd LLL yyyy HH:mm:ss ZZZ", false);
}
/**
* Returns a string representation of this DateTime appropriate for use in HTTP headers. The output is always expressed in GMT.
* Specifically, the string conforms to RFC 1123.
* @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1
* @example DateTime.utc(2014, 7, 13).toHTTP() //=> 'Sun, 13 Jul 2014 00:00:00 GMT'
* @example DateTime.utc(2014, 7, 13, 19).toHTTP() //=> 'Sun, 13 Jul 2014 19:00:00 GMT'
* @return {string}
*/
toHTTP() {
return toTechFormat(this.toUTC(), "EEE, dd LLL yyyy HH:mm:ss 'GMT'");
}
/**
* Returns a string representation of this DateTime appropriate for use in SQL Date
* @example DateTime.utc(2014, 7, 13).toSQLDate() //=> '2014-07-13'
* @return {string|null}
*/
toSQLDate() {
if (!this.isValid) {
return null;
}
return toISODate(this, true);
}
/**
* Returns a string representation of this DateTime appropriate for use in SQL Time
* @param {Object} opts - options
* @param {boolean} [opts.includeZone=false] - include the zone, such as 'America/New_York'. Overrides includeOffset.
* @param {boolean} [opts.includeOffset=true] - include the offset, such as 'Z' or '-04:00'
* @param {boolean} [opts.includeOffsetSpace=true] - include the space between the time and the offset, such as '05:15:16.345 -04:00'
* @example DateTime.utc().toSQL() //=> '05:15:16.345'
* @example DateTime.now().toSQL() //=> '05:15:16.345 -04:00'
* @example DateTime.now().toSQL({ includeOffset: false }) //=> '05:15:16.345'
* @example DateTime.now().toSQL({ includeZone: false }) //=> '05:15:16.345 America/New_York'
* @return {string}
*/
toSQLTime({ includeOffset = true, includeZone = false, includeOffsetSpace = true } = {}) {
let fmt = "HH:mm:ss.SSS";
if (includeZone || includeOffset) {
if (includeOffsetSpace) {
fmt += " ";
}
if (includeZone) {
fmt += "z";
} else if (includeOffset) {
fmt += "ZZ";
}
}
return toTechFormat(this, fmt, true);
}
/**
* Returns a string representation of this DateTime appropriate for use in SQL DateTime
* @param {Object} opts - options
* @param {boolean} [opts.includeZone=false] - include the zone, such as 'America/New_York'. Overrides includeOffset.
* @param {boolean} [opts.includeOffset=true] - include the offset, such as 'Z' or '-04:00'
* @param {boolean} [opts.includeOffsetSpace=true] - include the space between the time and the offset, such as '05:15:16.345 -04:00'
* @example DateTime.utc(2014, 7, 13).toSQL() //=> '2014-07-13 00:00:00.000 Z'
* @example DateTime.local(2014, 7, 13).toSQL() //=> '2014-07-13 00:00:00.000 -04:00'
* @example DateTime.local(2014, 7, 13).toSQL({ includeOffset: false }) //=> '2014-07-13 00:00:00.000'
* @example DateTime.local(2014, 7, 13).toSQL({ includeZone: true }) //=> '2014-07-13 00:00:00.000 America/New_York'
* @return {string}
*/
toSQL(opts = {}) {
if (!this.isValid) {
return null;
}
return `${this.toSQLDate()} ${this.toSQLTime(opts)}`;
}
/**
* Returns a string representation of this DateTime appropriate for debugging
* @return {string}
*/
toString() {
return this.isValid ? this.toISO() : INVALID;
}
/**
* Returns a string representation of this DateTime appropriate for the REPL.
* @return {string}
*/
[Symbol.for("nodejs.util.inspect.custom")]() {
if (this.isValid) {
return `DateTime { ts: ${this.toISO()}, zone: ${this.zone.name}, locale: ${this.locale} }`;
} else {
return `DateTime { Invalid, reason: ${this.invalidReason} }`;
}
}
/**
* Returns the epoch milliseconds of this DateTime. Alias of {@link DateTime#toMillis}
* @return {number}
*/
valueOf() {
return this.toMillis();
}
/**
* Returns the epoch milliseconds of this DateTime.
* @return {number}
*/
toMillis() {
return this.isValid ? this.ts : NaN;
}
/**
* Returns the epoch seconds (including milliseconds in the fractional part) of this DateTime.
* @return {number}
*/
toSeconds() {
return this.isValid ? this.ts / 1000 : NaN;
}
/**
* Returns the epoch seconds (as a whole number) of this DateTime.
* @return {number}
*/
toUnixInteger() {
return this.isValid ? Math.floor(this.ts / 1000) : NaN;
}
/**
* Returns an ISO 8601 representation of this DateTime appropriate for use in JSON.
* @return {string}
*/
toJSON() {
return this.toISO();
}
/**
* Returns a BSON serializable equivalent to this DateTime.
* @return {Date}
*/
toBSON() {
return this.toJSDate();
}
/**
* Returns a JavaScript object with this DateTime's year, month, day, and so on.
* @param opts - options for generating the object
* @param {boolean} [opts.includeConfig=false] - include configuration attributes in the output
* @example DateTime.now().toObject() //=> { year: 2017, month: 4, day: 22, hour: 20, minute: 49, second: 42, millisecond: 268 }
* @return {Object}
*/
toObject(opts = {}) {
if (!this.isValid) return {};
const base = { ...this.c };
if (opts.includeConfig) {
base.outputCalendar = this.outputCalendar;
base.numberingSystem = this.loc.numberingSystem;
base.locale = this.loc.locale;
}
return base;
}
/**
* Returns a JavaScript Date equivalent to this DateTime.
* @return {Date}
*/
toJSDate() {
return new Date(this.isValid ? this.ts : NaN);
}
// COMPARE
/**
* Return the difference between two DateTimes as a Duration.
* @param {DateTime} otherDateTime - the DateTime to compare this one to
* @param {string|string[]} [unit=['milliseconds']] - the unit or array of units (such as 'hours' or 'days') to include in the duration.
* @param {Object} opts - options that affect the creation of the Duration
* @param {string} [opts.conversionAccuracy='casual'] - the conversion system to use
* @example
* var i1 = DateTime.fromISO('1982-05-25T09:45'),
* i2 = DateTime.fromISO('1983-10-14T10:30');
* i2.diff(i1).toObject() //=> { milliseconds: 43807500000 }
* i2.diff(i1, 'hours').toObject() //=> { hours: 12168.75 }
* i2.diff(i1, ['months', 'days']).toObject() //=> { months: 16, days: 19.03125 }
* i2.diff(i1, ['months', 'days', 'hours']).toObject() //=> { months: 16, days: 19, hours: 0.75 }
* @return {Duration}
*/
diff(otherDateTime, unit = "milliseconds", opts = {}) {
if (!this.isValid || !otherDateTime.isValid) {
return Duration.invalid("created by diffing an invalid DateTime");
}
const durOpts = { locale: this.locale, numberingSystem: this.numberingSystem, ...opts };
const units = maybeArray(unit).map(Duration.normalizeUnit),
otherIsLater = otherDateTime.valueOf() > this.valueOf(),
earlier = otherIsLater ? this : otherDateTime,
later = otherIsLater ? otherDateTime : this,
diffed = diff(earlier, later, units, durOpts);
return otherIsLater ? diffed.negate() : diffed;
}
/**
* Return the difference between this DateTime and right now.
* See {@link DateTime#diff}
* @param {string|string[]} [unit=['milliseconds']] - the unit or units units (such as 'hours' or 'days') to include in the duration
* @param {Object} opts - options that affect the creation of the Duration
* @param {string} [opts.conversionAccuracy='casual'] - the conversion system to use
* @return {Duration}
*/
diffNow(unit = "milliseconds", opts = {}) {
return this.diff(DateTime.now(), unit, opts);
}
/**
* Return an Interval spanning between this DateTime and another DateTime
* @param {DateTime} otherDateTime - the other end point of the Interval
* @return {Interval|DateTime}
*/
until(otherDateTime) {
return this.isValid ? Interval.fromDateTimes(this, otherDateTime) : this;
}
/**
* Return whether this DateTime is in the same unit of time as another DateTime.
* Higher-order units must also be identical for this function to return `true`.
* Note that time zones are **ignored** in this comparison, which compares the **local** calendar time. Use {@link DateTime#setZone} to convert one of the dates if needed.
* @param {DateTime} otherDateTime - the other DateTime
* @param {string} unit - the unit of time to check sameness on
* @param {Object} opts - options
* @param {boolean} [opts.useLocaleWeeks=false] - If true, use weeks based on the locale, i.e. use the locale-dependent start of the week; only the locale of this DateTime is used
* @example DateTime.now().hasSame(otherDT, 'day'); //~> true if otherDT is in the same current calendar day
* @return {boolean}
*/
hasSame(otherDateTime, unit, opts) {
if (!this.isValid) return false;
const inputMs = otherDateTime.valueOf();
const adjustedToZone = this.setZone(otherDateTime.zone, { keepLocalTime: true });
return (
adjustedToZone.startOf(unit, opts) <= inputMs && inputMs <= adjustedToZone.endOf(unit, opts)
);
}
/**
* Equality check
* Two DateTimes are equal if and only if they represent the same millisecond, have the same zone and location, and are both valid.
* To compare just the millisecond values, use `+dt1 === +dt2`.
* @param {DateTime} other - the other DateTime
* @return {boolean}
*/
equals(other) {
return (
this.isValid &&
other.isValid &&
this.valueOf() === other.valueOf() &&
this.zone.equals(other.zone) &&
this.loc.equals(other.loc)
);
}
/**
* Returns a string representation of a this time relative to now, such as "in two days". Can only internationalize if your
* platform supports Intl.RelativeTimeFormat. Rounds towards zero by default.
* @param {Object} options - options that affect the output
* @param {DateTime} [options.base=DateTime.now()] - the DateTime to use as the basis to which this time is compared. Defaults to now.
* @param {string} [options.style="long"] - the style of units, must be "long", "short", or "narrow"
* @param {string|string[]} options.unit - use a specific unit or array of units; if omitted, or an array, the method will pick the best unit. Use an array or one of "years", "quarters", "months", "weeks", "days", "hours", "minutes", or "seconds"
* @param {boolean} [options.round=true] - whether to round the numbers in the output.
* @param {string} [options.rounding="trunc"] - rounding method to use when rounding the numbers in the output. Can be "trunc" (toward zero), "expand" (away from zero), "round", "floor", or "ceil".
* @param {number} [options.padding=0] - padding in milliseconds. This allows you to round up the result if it fits inside the threshold. Don't use in combination with {round: false} because the decimal output will include the padding.
* @param {string} options.locale - override the locale of this DateTime
* @param {string} options.numberingSystem - override the numberingSystem of this DateTime. The Intl system may choose not to honor this
* @example DateTime.now().plus({ days: 1 }).toRelative() //=> "in 1 day"
* @example DateTime.now().setLocale("es").toRelative({ days: 1 }) //=> "dentro de 1 día"
* @example DateTime.now().plus({ days: 1 }).toRelative({ locale: "fr" }) //=> "dans 23 heures"
* @example DateTime.now().minus({ days: 2 }).toRelative() //=> "2 days ago"
* @example DateTime.now().minus({ days: 2 }).toRelative({ unit: "hours" }) //=> "48 hours ago"
* @example DateTime.now().minus({ hours: 36 }).toRelative({ round: false }) //=> "1.5 days ago"
*/
toRelative(options = {}) {
if (!this.isValid) return null;
const base = options.base || DateTime.fromObject({}, { zone: this.zone }),
padding = options.padding ? (this < base ? -options.padding : options.padding) : 0;
let units = ["years", "months", "days", "hours", "minutes", "seconds"];
let unit = options.unit;
if (Array.isArray(options.unit)) {
units = options.unit;
unit = undefined;
}
return diffRelative(base, this.plus(padding), {
...options,
numeric: "always",
units,
unit,
});
}
/**
* Returns a string representation of this date relative to today, such as "yesterday" or "next month".
* Only internationalizes on platforms that supports Intl.RelativeTimeFormat.
* @param {Object} options - options that affect the output
* @param {DateTime} [options.base=DateTime.now()] - the DateTime to use as the basis to which this time is compared. Defaults to now.
* @param {string} options.locale - override the locale of this DateTime
* @param {string} options.unit - use a specific unit; if omitted, the method will pick the unit. Use one of "years", "quarters", "months", "weeks", or "days"
* @param {string} options.numberingSystem - override the numberingSystem of this DateTime. The Intl system may choose not to honor this
* @example DateTime.now().plus({ days: 1 }).toRelativeCalendar() //=> "tomorrow"
* @example DateTime.now().setLocale("es").plus({ days: 1 }).toRelative() //=> ""mañana"
* @example DateTime.now().plus({ days: 1 }).toRelativeCalendar({ locale: "fr" }) //=> "demain"
* @example DateTime.now().minus({ days: 2 }).toRelativeCalendar() //=> "2 days ago"
*/
toRelativeCalendar(options = {}) {
if (!this.isValid) return null;
return diffRelative(options.base || DateTime.fromObject({}, { zone: this.zone }), this, {
...options,
numeric: "auto",
units: ["years", "months", "days"],
calendary: true,
});
}
/**
* Return the min of several date times
* @param {...DateTime} dateTimes - the DateTimes from which to choose the minimum
* @return {DateTime} the min DateTime, or undefined if called with no argument
*/
static min(...dateTimes) {
if (!dateTimes.every(DateTime.isDateTime)) {
throw new InvalidArgumentError("min requires all arguments be DateTimes");
}
return bestBy(dateTimes, (i) => i.valueOf(), Math.min);
}
/**
* Return the max of several date times
* @param {...DateTime} dateTimes - the DateTimes from which to choose the maximum
* @return {DateTime} the max DateTime, or undefined if called with no argument
*/
static max(...dateTimes) {
if (!dateTimes.every(DateTime.isDateTime)) {
throw new InvalidArgumentError("max requires all arguments be DateTimes");
}
return bestBy(dateTimes, (i) => i.valueOf(), Math.max);
}
// MISC
/**
* Explain how a string would be parsed by fromFormat()
* @param {string} text - the string to parse
* @param {string} fmt - the format the string is expected to be in (see description)
* @param {Object} options - options taken by fromFormat()
* @return {Object}
*/
static fromFormatExplain(text, fmt, options = {}) {
const { locale = null, numberingSystem = null } = options,
localeToUse = Locale.fromOpts({
locale,
numberingSystem,
defaultToEN: true,
});
return explainFromTokens(localeToUse, text, fmt);
}
/**
* @deprecated use fromFormatExplain instead
*/
static fromStringExplain(text, fmt, options = {}) {
return DateTime.fromFormatExplain(text, fmt, options);
}
/**
* Build a parser for `fmt` using the given locale. This parser can be passed
* to {@link DateTime.fromFormatParser} to a parse a date in this format. This
* can be used to optimize cases where many dates need to be parsed in a
* specific format.
*
* @param {String} fmt - the format the string is expected to be in (see
* description)
* @param {Object} options - options used to set locale and numberingSystem
* for parser
* @returns {TokenParser} - opaque object to be used
*/
static buildFormatParser(fmt, options = {}) {
const { locale = null, numberingSystem = null } = options,
localeToUse = Locale.fromOpts({
locale,
numberingSystem,
defaultToEN: true,
});
return new TokenParser(localeToUse, fmt);
}
/**
* Create a DateTime from an input string and format parser.
*
* The format parser must have been created with the same locale as this call.
*
* @param {String} text - the string to parse
* @param {TokenParser} formatParser - parser from {@link DateTime.buildFormatParser}
* @param {Object} opts - options taken by fromFormat()
* @returns {DateTime}
*/
static fromFormatParser(text, formatParser, opts = {}) {
if (isUndefined$1(text) || isUndefined$1(formatParser)) {
throw new InvalidArgumentError(
"fromFormatParser requires an input string and a format parser"
);
}
const { locale = null, numberingSystem = null } = opts,
localeToUse = Locale.fromOpts({
locale,
numberingSystem,
defaultToEN: true,
});
if (!localeToUse.equals(formatParser.locale)) {
throw new InvalidArgumentError(
`fromFormatParser called with a locale of ${localeToUse}, ` +
`but the format parser was created for ${formatParser.locale}`
);
}
const { result, zone, specificOffset, invalidReason } = formatParser.explainFromTokens(text);
if (invalidReason) {
return DateTime.invalid(invalidReason);
} else {
return parseDataToDateTime(
result,
zone,
opts,
`format ${formatParser.format}`,
text,
specificOffset
);
}
}
// FORMAT PRESETS
/**
* {@link DateTime#toLocaleString} format like 10/14/1983
* @type {Object}
*/
static get DATE_SHORT() {
return DATE_SHORT;
}
/**
* {@link DateTime#toLocaleString} format like 'Oct 14, 1983'
* @type {Object}
*/
static get DATE_MED() {
return DATE_MED;
}
/**
* {@link DateTime#toLocaleString} format like 'Fri, Oct 14, 1983'
* @type {Object}
*/
static get DATE_MED_WITH_WEEKDAY() {
return DATE_MED_WITH_WEEKDAY;
}
/**
* {@link DateTime#toLocaleString} format like 'October 14, 1983'
* @type {Object}
*/
static get DATE_FULL() {
return DATE_FULL;
}
/**
* {@link DateTime#toLocaleString} format like 'Tuesday, October 14, 1983'
* @type {Object}
*/
static get DATE_HUGE() {
return DATE_HUGE;
}
/**
* {@link DateTime#toLocaleString} format like '09:30 AM'. Only 12-hour if the locale is.
* @type {Object}
*/
static get TIME_SIMPLE() {
return TIME_SIMPLE;
}
/**
* {@link DateTime#toLocaleString} format like '09:30:23 AM'. Only 12-hour if the locale is.
* @type {Object}
*/
static get TIME_WITH_SECONDS() {
return TIME_WITH_SECONDS;
}
/**
* {@link DateTime#toLocaleString} format like '09:30:23 AM EDT'. Only 12-hour if the locale is.
* @type {Object}
*/
static get TIME_WITH_SHORT_OFFSET() {
return TIME_WITH_SHORT_OFFSET;
}
/**
* {@link DateTime#toLocaleString} format like '09:30:23 AM Eastern Daylight Time'. Only 12-hour if the locale is.
* @type {Object}
*/
static get TIME_WITH_LONG_OFFSET() {
return TIME_WITH_LONG_OFFSET;
}
/**
* {@link DateTime#toLocaleString} format like '09:30', always 24-hour.
* @type {Object}
*/
static get TIME_24_SIMPLE() {
return TIME_24_SIMPLE;
}
/**
* {@link DateTime#toLocaleString} format like '09:30:23', always 24-hour.
* @type {Object}
*/
static get TIME_24_WITH_SECONDS() {
return TIME_24_WITH_SECONDS;
}
/**
* {@link DateTime#toLocaleString} format like '09:30:23 EDT', always 24-hour.
* @type {Object}
*/
static get TIME_24_WITH_SHORT_OFFSET() {
return TIME_24_WITH_SHORT_OFFSET;
}
/**
* {@link DateTime#toLocaleString} format like '09:30:23 Eastern Daylight Time', always 24-hour.
* @type {Object}
*/
static get TIME_24_WITH_LONG_OFFSET() {
return TIME_24_WITH_LONG_OFFSET;
}
/**
* {@link DateTime#toLocaleString} format like '10/14/1983, 9:30 AM'. Only 12-hour if the locale is.
* @type {Object}
*/
static get DATETIME_SHORT() {
return DATETIME_SHORT;
}
/**
* {@link DateTime#toLocaleString} format like '10/14/1983, 9:30:33 AM'. Only 12-hour if the locale is.
* @type {Object}
*/
static get DATETIME_SHORT_WITH_SECONDS() {
return DATETIME_SHORT_WITH_SECONDS;
}
/**
* {@link DateTime#toLocaleString} format like 'Oct 14, 1983, 9:30 AM'. Only 12-hour if the locale is.
* @type {Object}
*/
static get DATETIME_MED() {
return DATETIME_MED;
}
/**
* {@link DateTime#toLocaleString} format like 'Oct 14, 1983, 9:30:33 AM'. Only 12-hour if the locale is.
* @type {Object}
*/
static get DATETIME_MED_WITH_SECONDS() {
return DATETIME_MED_WITH_SECONDS;
}
/**
* {@link DateTime#toLocaleString} format like 'Fri, 14 Oct 1983, 9:30 AM'. Only 12-hour if the locale is.
* @type {Object}
*/
static get DATETIME_MED_WITH_WEEKDAY() {
return DATETIME_MED_WITH_WEEKDAY;
}
/**
* {@link DateTime#toLocaleString} format like 'October 14, 1983, 9:30 AM EDT'. Only 12-hour if the locale is.
* @type {Object}
*/
static get DATETIME_FULL() {
return DATETIME_FULL;
}
/**
* {@link DateTime#toLocaleString} format like 'October 14, 1983, 9:30:33 AM EDT'. Only 12-hour if the locale is.
* @type {Object}
*/
static get DATETIME_FULL_WITH_SECONDS() {
return DATETIME_FULL_WITH_SECONDS;
}
/**
* {@link DateTime#toLocaleString} format like 'Friday, October 14, 1983, 9:30 AM Eastern Daylight Time'. Only 12-hour if the locale is.
* @type {Object}
*/
static get DATETIME_HUGE() {
return DATETIME_HUGE;
}
/**
* {@link DateTime#toLocaleString} format like 'Friday, October 14, 1983, 9:30:33 AM Eastern Daylight Time'. Only 12-hour if the locale is.
* @type {Object}
*/
static get DATETIME_HUGE_WITH_SECONDS() {
return DATETIME_HUGE_WITH_SECONDS;
}
}
/**
* @private
*/
function friendlyDateTime(dateTimeish) {
if (DateTime.isDateTime(dateTimeish)) {
return dateTimeish;
} else if (dateTimeish && dateTimeish.valueOf && isNumber$1(dateTimeish.valueOf())) {
return DateTime.fromJSDate(dateTimeish);
} else if (dateTimeish && typeof dateTimeish === "object") {
return DateTime.fromObject(dateTimeish);
} else {
throw new InvalidArgumentError(
`Unknown datetime argument: ${dateTimeish}, of type ${typeof dateTimeish}`
);
}
}
var __defProp$1S = Object.defineProperty;
var __name$1S = (target, value) => __defProp$1S(target, "name", { value, configurable: true });
class AbstractFormatter {
static {
__name$1S(this, "AbstractFormatter");
}
dateFormat;
constructor(dateFormat = "YYYY-MM-DD HH:mm:ss") {
this.dateFormat = dateFormat;
}
_formatTimestamp(date) {
const dt = DateTime.fromJSDate(date);
return Math.floor(dt.toSeconds()).toFixed(0);
}
_formatDate(date) {
const dt = DateTime.fromJSDate(date);
return dt.toFormat(
this.dateFormat.replace(/YYYY/g, "yyyy").replace(/YY/g, "yy").replace(/DD/g, "dd").replace(/D/g, "d")
);
}
}
var __defProp$1R = Object.defineProperty;
var __name$1R = (target, value) => __defProp$1R(target, "name", { value, configurable: true });
class JsonFormatter extends AbstractFormatter {
static {
__name$1R(this, "JsonFormatter");
}
constructor(dateFormat = "YYYY-MM-DD HH:mm:ss") {
super(dateFormat);
}
format(record) {
return JSON.stringify({
channel: record.channel,
levelName: record.levelName,
message: record.message,
context: record.context,
extra: record.extra,
timestamp: this._formatTimestamp(record.timestamp),
date: this._formatDate(record.timestamp)
});
}
}
var __defProp$1Q = Object.defineProperty;
var __name$1Q = (target, value) => __defProp$1Q(target, "name", { value, configurable: true });
class LineFormatter extends AbstractFormatter {
static {
__name$1Q(this, "LineFormatter");
}
formatString;
constructor(formatString = "[{channel}] {levelName}: {message} {context} {extra} {date}", dateFormat = "YYYY-MM-DD HH:mm:ss") {
super(dateFormat);
this.formatString = formatString;
}
format(record) {
let formatted = this.formatString;
const replacements = {
"{channel}": record.channel,
"{levelName}": record.levelName,
"{message}": record.message,
"{context}": JSON.stringify(record.context),
"{extra}": JSON.stringify(record.extra),
"{timestamp}": this._formatTimestamp(record.timestamp),
"{date}": this._formatDate(record.timestamp)
};
for (const [key, value] of Object.entries(replacements)) {
formatted = formatted.replace(key, value);
}
return formatted;
}
}
var __defProp$1P = Object.defineProperty;
var __name$1P = (target, value) => __defProp$1P(target, "name", { value, configurable: true });
class TelegramFormatter extends AbstractFormatter {
static {
__name$1P(this, "TelegramFormatter");
}
useHtml;
maxMessageLength;
constructor(useHtml = true, dateFormat = "YYYY-MM-DD HH:mm:ss", maxMessageLength = 4096) {
super(dateFormat);
this.useHtml = useHtml;
this.maxMessageLength = maxMessageLength;
}
format(record) {
let message = this._formatBaseMessage(record);
const additionalInfo = this._formatAdditionalInfo(record);
if (additionalInfo) {
message += `
${additionalInfo}`;
}
if (message.length > this.maxMessageLength) {
message = message.substring(0, this.maxMessageLength - 3) + "...";
}
return message;
}
_formatBaseMessage(record) {
const date = this._formatDate(record.timestamp);
const level = record.levelName;
if (this.useHtml) {
return `<b>${level}</b> | <code>${record.channel}</code>
<i>Time:</i> ${date}
<i>Message:</i>
${record.message}`;
} else {
return `*${level}* \`${record.channel}\`
_Time:_ \`${date}\`
_Message:_
${record.message}`;
}
}
_formatAdditionalInfo(record) {
const parts = [];
if (record.context && Object.keys(record.context).length > 0) {
const contextStr = JSON.stringify(record.context, null, 2);
if (this.useHtml) {
parts.push(`<i>Context:</i>
<pre><code class="language-json">${this._escapeHtml(contextStr)}</code></pre>`);
} else {
parts.push(`_Context:_
\`\`\`json
${contextStr}
\`\`\``);
}
}
if (record.extra && Object.keys(record.extra).length > 0) {
const extraStr = JSON.stringify(record.extra, null, 2);
if (this.useHtml) {
parts.push(`<i>Extra:</i>
<pre><code class="language-json">${this._escapeHtml(extraStr)}</code></pre>`);
} else {
parts.push(`_Extra:_
\`\`\`json
${extraStr}
\`\`\``);
}
}
return parts.join("\n\n");
}
_escapeHtml(text) {
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
}
_escapeMarkdownV2(text) {
return text.replace(/_/g, "\\_").replace(/\*/g, "\\*").replace(/\[/g, "\\[").replace(/\]/g, "\\]").replace(/\(/g, "\\(").replace(/\)/g, "\\)").replace(/~/g, "\\~").replace(/`/g, "\\`").replace(/>/g, "\\>").replace(/#/g, "\\#").replace(/\+/g, "\\+").replace(/-/g, "\\-").replace(/=/g, "\\=").replace(/\|/g, "\\|").replace(/\{/g, "\\{").replace(/\}/g, "\\}").replace(/\./g, "\\.").replace(/!/g, "\\!");
}
/**
* Set the use of HTML markup
*/
setUseHtml(useHtml) {
this.useHtml = useHtml;
return this;
}
/**
* // Set the maximum message length
*/
setMaxMessageLength(maxLength) {
this.maxMessageLength = maxLength;
return this;
}
}
var __defProp$1O = Object.defineProperty;
var __name$1O = (target, value) => __defProp$1O(target, "name", { value, configurable: true });
const pidProcessor = /* @__PURE__ */ __name$1O((record) => {
record.extra["pid"] = "?";
if (typeof process !== "undefined" && process.pid) {
record.extra["pid"] = process.pid;
}
return record;
}, "pidProcessor");
var __defProp$1N = Object.defineProperty;
var __name$1N = (target, value) => __defProp$1N(target, "name", { value, configurable: true });
const memoryUsageProcessor = /* @__PURE__ */ __name$1N((record) => {
record.extra["memoryUsage"] = "?";
if (typeof process !== "undefined" && process.memoryUsage) {
record.extra["memoryUsage"] = Math.round(process.memoryUsage().heapUsed / 1024 / 1024) + "MB";
}
return record;
}, "memoryUsageProcessor");
var __defProp$1M = Object.defineProperty;
var __name$1M = (target, value) => __defProp$1M(target, "name", { value, configurable: true });
class AbstractHandler {
static {
__name$1M(this, "AbstractHandler");
}
level;
formatter = null;
bubble = true;
constructor(level = LogLevel.DEBUG, bubble) {
this.level = level;
if (bubble !== void 0) this.bubble = bubble;
}
isHandling(level) {
return level >= this.level;
}
shouldBubble() {
return this.bubble;
}
setFormatter(formatter) {
this.formatter = formatter;
}
getFormatter() {
return this.formatter;
}
}
var __defProp$1L = Object.defineProperty;
var __name$1L = (target, value) => __defProp$1L(target, "name", { value, configurable: true });
class ConsoleHandler extends AbstractHandler {
static {
__name$1L(this, "ConsoleHandler");
}
_styles = /* @__PURE__ */ new Map();
_useStyles;
constructor(level = LogLevel.DEBUG, options) {
const opts = {
useStyles: true,
...options
};
super(level, opts.bubble);
this._useStyles = opts.useStyles;
this._initStyles();
this.setFormatter(new LineFormatter());
}
_initStyles() {
const style = "color: _color_; background: _bg_; padding: 2px 6px; border-radius: 3px; font-size: 11px;";
this._styles.set(LogLevel.DEBUG, [
"%cDEBUG",
style.replace("_color_", "#666666").replace("_bg_", "#F0F0F0")
]);
this._styles.set(LogLevel.INFO, [
"%cINFO",
style.replace("_color_", "white").replace("_bg_", "#2196F3")
]);
this._styles.set(LogLevel.NOTICE, [
"%cNOTICE",
style.replace("_color_", "white").replace("_bg_", "#213BF3")
]);
this._styles.set(LogLevel.WARNING, [
"%cWARN",
style.replace("_color_", "white").replace("_bg_", "#FF9800")
]);
this._styles.set(LogLevel.ERROR, [
"%cERROR",
style.replace("_color_", "white").replace("_bg_", "#F44336")
]);
this._styles.set(LogLevel.CRITICAL, [
"%cCRITICAL",
style.replace("_color_", "white").replace("_bg_", "#9C27B0")
]);
}
/**
* @inheritDoc
*/
async handle(record) {
const formatter = this.getFormatter();
const message = formatter.format(record);
let method = this._getConsoleMethod(record.level);
if (record.context["needTrace"] === true) {
method = "trace";
}
const params = [];
if (this._useStyles && this._styles.has(record.level)) {
const style = this._styles.get(record.level);
params.push(style[0], style[1]);
}
params.push(message);
console[method](
...params.filter(Boolean)
);
return true;
}
_getConsoleMethod(level) {
switch (level) {
case LogLevel.INFO:
case LogLevel.NOTICE:
return "info";
case LogLevel.WARNING:
return "warn";
case LogLevel.ERROR:
case LogLevel.CRITICAL:
case LogLevel.ALERT:
case LogLevel.EMERGENCY:
return "error";
default:
return "log";
}
}
}
var __defProp$1K = Object.defineProperty;
var __name$1K = (target, value) => __defProp$1K(target, "name", { value, configurable: true });
class ConsoleV2Handler extends ConsoleHandler {
static {
__name$1K(this, "ConsoleV2Handler");
}
constructor(level = LogLevel.DEBUG, options) {
super(level, options);
this.setFormatter(new LineFormatter("[{channel}]: {message}"));
}
/**
* @inheritDoc
*/
async handle(record) {
const formatter = this.getFormatter();
const message = formatter.format(record);
let method = this._getConsoleMethod(record.level);
if (record.context["needTrace"] === true) {
method = "trace";
}
const context = record.context && Object.keys(record.context).length > 0 ? record.context : void 0;
const extra = record.extra && Object.keys(record.extra).length > 0 ? record.extra : void 0;
const params = [];
if (this._useStyles && this._styles.has(record.level)) {
const style = this._styles.get(record.level);
params.push(style[0], style[1]);
}
params.push(message);
params.push(context);
params.push(extra);
console[method](
...params.filter(Boolean)
);
return true;
}
}
var __defProp$1J = Object.defineProperty;
var __name$1J = (target, value) => __defProp$1J(target, "name", { value, configurable: true });
class MemoryHandler extends AbstractHandler {
static {
__name$1J(this, "MemoryHandler");
}
records = [];
limit;
constructor(level = LogLevel.DEBUG, options) {
const opts = {
bubble: true,
limit: 1e3,
...options
};
super(level, opts.bubble);
this.limit = opts.limit;
}
/**
* @inheritDoc
*/
async handle(record) {
this.records.push(record);
if (this.records.length > this.limit) {
this.records.shift();
}
return true;
}
getRecords() {
return [...this.records];
}
clear() {
this.records = [];
}
}
var __defProp$1I = Object.defineProperty;
var __name$1I = (target, value) => __defProp$1I(target, "name", { value, configurable: true });
class StreamHandler extends AbstractHandler {
static {
__name$1I(this, "StreamHandler");
}
/**
* Stream for writing logs.
* @private
*/
stream;
/**
* Creates a StreamHandler instance.
*
* @param {LogLevel} level - Minimum log level.
* @param options
* - `stream: Writable` - Stream to write to (e.g., `process.stdout`, `process.stderr`, `fs.WriteStream`)
* - `bubble?: boolean` - Determines whether the handler should bubble the record to the next handler.
*/
constructor(level = LogLevel.DEBUG, options) {
const opts = {
bubble: true,
...options
};
super(level, opts.bubble);
this.stream = opts.stream;
this.setFormatter(new LineFormatter());
}
/**
* @inheritDoc
*/
async handle(record) {
try {
const formatter = this.getFormatter();
const message = formatter.format(record) + "\n";
this.stream.write(message);
} catch (error) {
console.error(`StreamHandler write error: ${error}`);
return false;
}
return true;
}
/**
* Closes the stream (if supported).
*
* @returns {Promise<void>}
*/
async close() {
if (typeof this.stream.end === "function") {
return new Promise((resolve, reject) => {
this.stream.end((error) => {
if (error) reject(error);
else resolve();
});
});
}
}
}
var __defProp$1H = Object.defineProperty;
var __name$1H = (target, value) => __defProp$1H(target, "name", { value, configurable: true });
class ConsolaAdapter extends AbstractHandler {
static {
__name$1H(this, "ConsolaAdapter");
}
consolaInstance;
constructor(level = LogLevel.DEBUG, options) {
const opts = {
bubble: true,
...options
};
super(level, opts.bubble);
this.consolaInstance = opts.consolaInstance;
}
setFormatter(_formatter) {
}
getFormatter() {
return null;
}
async handle(record) {
const message = `[${record.channel}] ${record.levelName}: ${record.message}`;
const args = { ...record.context, ...record.extra, timestamp: record.timestamp };
switch (record.level) {
case LogLevel.DEBUG:
this.consolaInstance.log(message, args);
break;
case LogLevel.INFO:
this.consolaInstance.info(message, args);
break;
case LogLevel.NOTICE:
this.consolaInstance.success(message, args);
break;
case LogLevel.WARNING:
this.consolaInstance.warn(message, args);
break;
case LogLevel.ERROR:
case LogLevel.CRITICAL:
case LogLevel.ALERT:
case LogLevel.EMERGENCY:
this.consolaInstance.error(message, args);
break;
default:
this.consolaInstance.log(message, args);
}
return true;
}
}
var __defProp$1G = Object.defineProperty;
var __name$1G = (target, value) => __defProp$1G(target, "name", { value, configurable: true });
class WinstonAdapter extends AbstractHandler {
static {
__name$1G(this, "WinstonAdapter");
}
winstonLogger;
constructor(level = LogLevel.DEBUG, options) {
const opts = {
bubble: true,
...options
};
super(level, opts.bubble);
this.winstonLogger = opts.winstonLogger;
}
setFormatter(_formatter) {
}
getFormatter() {
return null;
}
async handle(record) {
const levelMap = {
DEBUG: "debug",
INFO: "info",
NOTICE: "notice",
WARNING: "warn",
ERROR: "error",
CRITICAL: "error",
ALERT: "error",
EMERGENCY: "error"
};
const winstonLevel = levelMap[record.levelName] || levelMap.INFO;
this.winstonLogger.log({
level: winstonLevel,
channel: record.channel,
message: record.message,
context: record.context,
extra: record.extra,
timestamp: record.timestamp
});
return true;
}
}
var __defProp$1F = Object.defineProperty;
var __name$1F = (target, value) => __defProp$1F(target, "name", { value, configurable: true });
var Environment = /* @__PURE__ */ ((Environment2) => {
Environment2["UNKNOWN"] = "unknown";
Environment2["BROWSE"] = "browser";
Environment2["NODE"] = "node";
return Environment2;
})(Environment || {});
function getEnvironment() {
if (typeof window !== "undefined" && typeof window.document !== "undefined") {
return "browser" /* BROWSE */;
}
if (typeof process !== "undefined" && process.versions && process.versions.node) {
return "node" /* NODE */;
}
return "unknown" /* UNKNOWN */;
}
__name$1F(getEnvironment, "getEnvironment");
var __defProp$1E = Object.defineProperty;
var __name$1E = (target, value) => __defProp$1E(target, "name", { value, configurable: true });
class TelegramHandler extends AbstractHandler {
static {
__name$1E(this, "TelegramHandler");
}
botToken;
chatId;
parseMode;
disableNotification;
disableWebPagePreview;
environment;
warnInBrowser;
constructor(level = LogLevel.ERROR, options) {
super(level, options.bubble);
if (!options.botToken) {
throw new Error("botToken is required for TelegramHandler");
}
if (!options.chatId) {
throw new Error("chatId is required for TelegramHandler");
}
this.botToken = options.botToken;
this.chatId = options.chatId;
this.parseMode = options.parseMode || "HTML";
this.disableNotification = options.disableNotification || false;
this.disableWebPagePreview = options.disableWebPagePreview || true;
this.environment = getEnvironment();
this.warnInBrowser = options.warnInBrowser !== false;
this.setFormatter(new TelegramFormatter(this.parseMode === "HTML"));
}
/**
* @inheritDoc
*/
async handle(record) {
const formatter = this.getFormatter();
if (!formatter) {
console.error("TelegramHandler: No formatter set");
return false;
}
const message = formatter.format(record);
if (this.environment === Environment.BROWSE) {
return this._handleInBrowser(message, record);
} else if (this.environment === Environment.NODE) {
return this._handleInNode(message, record);
}
console.warn("TelegramHandler: Unknown environment, using fallback");
return this._handleFallback(message);
}
/**
* Processing in the browser
*/
async _handleInBrowser(_message, record) {
if (this.warnInBrowser) {
const warningMessage = `\u26A0\uFE0F TelegramHandler: Cannot send logs to Telegram from browser environment.
This would expose your bot token. Consider disabling this handler in browser.
Log message: ${record.message}
If you need to send logs from browser, use a proxy server.`;
console.warn(warningMessage);
const style = "color: #FF9800; background: #FFF3E0; padding: 8px; border: 1px solid #FFB74D; border-radius: 4px;";
console.log("%cTelegram Handler Warning", style, warningMessage);
}
return false;
}
/**
* Processing in Node.js
*/
async _handleInNode(message, _record) {
try {
const url = `https://api.telegram.org/bot${this.botToken}/sendMessage`;
const config = JSON.stringify({
chat_id: this.chatId,
text: message,
parse_mode: this.parseMode,
disable_notification: this.disableNotification,
disable_web_page_preview: this.disableWebPagePreview
});
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: config
});
const result = await response.json();
if (!result.ok) {
console.error("TelegramHandler: Failed to send message", result);
return false;
}
return true;
} catch (error) {
console.error("TelegramHandler: Error sending message", error);
return false;
}
}
/**
* Fallback processing for unknown environments
*/
async _handleFallback(message) {
console.log("TelegramHandler (fallback):", message);
return false;
}
updateSettings(options) {
if (options.botToken) this.botToken = options.botToken;
if (options.chatId) this.chatId = options.chatId;
if (options.parseMode) this.parseMode = options.parseMode;
if (options.disableNotification !== void 0) {
this.disableNotification = options.disableNotification;
}
if (options.disableWebPagePreview !== void 0) {
this.disableWebPagePreview = options.disableWebPagePreview;
}
if (options.warnInBrowser !== void 0) {
this.warnInBrowser = options.warnInBrowser;
}
return this;
}
/**
* Get current environment
*/
getEnvironment() {
return this.environment;
}
/**
* Check if the Telegram API is available
*/
async testConnection() {
if (this.environment === "browser") {
console.warn("TelegramHandler: Cannot test connection in browser environment");
return false;
}
try {
const url = `https://api.telegram.org/bot${this.botToken}/getMe`;
const response = await fetch(url);
const result = await response.json();
return result.ok === true;
} catch (error) {
console.error("TelegramHandler: Test connection failed", error);
return false;
}
}
}
var __defProp$1D = Object.defineProperty;
var __name$1D = (target, value) => __defProp$1D(target, "name", { value, configurable: true });
class AbstractLogger {
static {
__name$1D(this, "AbstractLogger");
}
/**
* @inheritDoc
*/
async debug(message, context) {
return this.log(LogLevel.DEBUG, message, context);
}
/**
* @inheritDoc
*/
async info(message, context) {
return this.log(LogLevel.INFO, message, context);
}
/**
* @inheritDoc
*/
async notice(message, context) {
return this.log(LogLevel.NOTICE, message, context);
}
/**
* @inheritDoc
*/
async warning(message, context) {
return this.log(LogLevel.WARNING, message, context);
}
/**
* @inheritDoc
*/
async error(message, context) {
return this.log(LogLevel.ERROR, message, context);
}
/**
* @inheritDoc
*/
async critical(message, context) {
return this.log(LogLevel.CRITICAL, message, context);
}
/**
* @inheritDoc
*/
async alert(message, context) {
return this.log(LogLevel.ALERT, message, context);
}
/**
* @inheritDoc
*/
async emergency(message, context) {
return this.log(LogLevel.EMERGENCY, message, context);
}
// endregion ////
}
var __defProp$1C = Object.defineProperty;
var __name$1C = (target, value) => __defProp$1C(target, "name", { value, configurable: true });
class NullLogger extends AbstractLogger {
static {
__name$1C(this, "NullLogger");
}
// region static methods for creation ////
static create() {
return new NullLogger();
}
// endregion ////
// region logging methods ////
/**
* @inheritDoc
*/
async log(_level, _message, _context) {
}
// endregion ////
}
var __defProp$1B = Object.defineProperty;
var __name$1B = (target, value) => __defProp$1B(target, "name", { value, configurable: true });
class Logger extends AbstractLogger {
static {
__name$1B(this, "Logger");
}
channel;
handlers = [];
processors = [];
constructor(channel) {
super();
this.channel = channel;
}
// region static methods for creation ////
static create(channel) {
return new Logger(channel);
}
// endregion ////
// region config ////
pushHandler(handler) {
this.handlers.push(handler);
return this;
}
popHandler() {
return this.handlers.pop() || null;
}
setHandlers(handlers) {
this.handlers = handlers;
return this;
}
pushProcessor(processor) {
this.processors.push(processor);
return this;
}
// endregion ////
/**
* **Never throws and never rejects.** Logging is a side channel: a failure in
* it must degrade observability, not the operation being observed. Every
* callsite in the SDK invokes this without `await` (`this.getLogger().info(…)`
* as a statement), so a rejected promise would surface as an *unhandled
* rejection* — which terminates the Node process by default. A handler doing
* network or file I/O (Telegram, a stream, a third-party adapter) rejects for
* ordinary operational reasons, so that path is reachable in normal operation,
* not just in principle (#346).
*
* A processor or handler that fails is skipped and reported via
* {@link reportLoggingFailure}; the remaining handlers still receive the
* record.
*
* This covers failures *inside* the logger. It does not cover an exception
* raised while a caller builds its log arguments — those are evaluated eagerly
* at the callsite, before `log()` is reached (see `truncateForLog`, #338).
*
* ### Deliberately outside this guarantee
*
* Three gaps sit outside `log()` and were each weighed and left open on
* purpose (#346). They are recorded here so they are not re-opened as
* oversights:
*
* 1. **A third-party `LoggerInterface` is not isolated.** This guarantee
* belongs to this class, not to the interface. Every SDK callsite is
* written `…info(…).catch(() => {})`, which absorbs a *rejected promise*;
* an implementation that throws *synchronously*, before returning one,
* escapes into the caller. `setLogger(...)` warns about the shape it can
* check without calling anything (see `warnOnNonPromiseLogger`); returning
* promises is the implementor's side of the contract. Wrapping every
* installed logger defensively was considered and rejected: it would make
* the SDK responsible for code it does not own, on every one of ~94
* callsites, to cover a case TypeScript already rejects at compile time.
*
* 2. **A handler that fails forever is never detached.** Each failure is
* reported, every time — see {@link reportLoggingFailure}. Auto-detaching
* after N failures was considered and rejected: it silently changes a
* configuration the application made, and "N failures" is a policy the SDK
* has no basis to pick on the application's behalf.
*
* 3. **The synchronous half — argument construction — stays the caller's.**
* Making it total would mean wrapping the argument list at every callsite,
* which trades a narrow, findable failure (#338 was one expression in one
* helper) for noise at every call. Individual helpers on the hot path are
* made total instead, as `truncateForLog` was.
*
* @inheritDoc
*/
async log(level, message, context) {
const record = {
channel: this.channel,
level,
levelName: LogLevel[level],
message,
context: context ?? {},
extra: {},
timestamp: /* @__PURE__ */ new Date()
};
let processedRecord = record;
for (const processor of this.processors) {
try {
processedRecord = processor(processedRecord);
} catch (error) {
this.reportLoggingFailure(processor, error);
}
}
for (const handler of this.handlers) {
try {
if (!handler.isHandling(level)) {
continue;
}
const handled = await handler.handle(processedRecord);
if (handled && !handler.shouldBubble()) {
break;
}
} catch (error) {
this.reportLoggingFailure(handler, error);
}
}
}
/**
* Report a processor/handler that threw.
*
* Reported on every failure, deliberately: suppressing repeats would hide how
* often a sink is failing, and a sink that has been broken for an hour looks
* identical to one that failed once. The volume is the signal — if it is
* noisy, the sink is failing that often. Filtering belongs to whoever reads
* the output, not to the SDK.
*
* `console` is used rather than the logger — routing a logging failure back
* through the logger that just failed is how this turns into recursion.
*
* The handler is **not** detached, however many times it fails. Doing so would
* silently discard part of a configuration the application built, and the
* threshold that would trigger it is a policy call the SDK cannot make for the
* application. A sink that is broken stays wired and stays loud; whoever reads
* the output decides what to do about it (#346).
*/
reportLoggingFailure(source, error) {
const name = source?.constructor?.name ?? "processor";
console.warn(
`[b24jssdk] logger channel "${this.channel}": ${name} failed; the record was skipped. Logging continues through the remaining handlers, and the operation being logged is unaffected.`,
error
);
}
}
var __defProp$1A = Object.defineProperty;
var __name$1A = (target, value) => __defProp$1A(target, "name", { value, configurable: true });
class LoggerFactory {
static {
__name$1A(this, "LoggerFactory");
}
static createNullLogger() {
return NullLogger.create();
}
static createForBrowser(channel, isDevMode = false) {
if (isDevMode) {
return LoggerFactory.createForBrowserDevelopment(channel);
}
return LoggerFactory.createForBrowserProduction(channel);
}
static createForBrowserDevelopment(channel, level = LogLevel.DEBUG) {
const logger = new Logger(channel);
const handler = new ConsoleV2Handler(level);
logger.pushHandler(handler);
return logger;
}
static createForBrowserProduction(channel, level = LogLevel.ERROR) {
const logger = new Logger(channel);
const handler = new ConsoleV2Handler(level);
logger.pushHandler(handler);
return logger;
}
static async forcedLog(logger, action, message, context) {
if (typeof globalThis !== "undefined" && "vitest" in globalThis) {
return;
}
if (logger instanceof NullLogger) {
switch (action) {
case "debug":
console.log(message, context);
return;
case "info":
case "notice":
console.info(message, context);
return;
case "warning":
console.warn(message, context);
return;
default:
console.error(message, context);
return;
}
}
return logger[action](message, context);
}
}
var __defProp$1z = Object.defineProperty;
var __name$1z = (target, value) => __defProp$1z(target, "name", { value, configurable: true });
const deprecateMessage = "@deprecated: use Logger. https://bitrix24.github.io/b24jssdk/docs/working-with-the-rest-api/logger/";
var LoggerType = /* @__PURE__ */ ((LoggerType2) => {
LoggerType2["desktop"] = "desktop";
LoggerType2["log"] = "log";
LoggerType2["info"] = "info";
LoggerType2["warn"] = "warn";
LoggerType2["error"] = "error";
LoggerType2["trace"] = "trace";
return LoggerType2;
})(LoggerType || {});
class LoggerBrowser {
static {
__name$1z(this, "LoggerBrowser");
}
#logger;
/**
* Create a LoggerBrowser instance
*
* @deprecated This method is deprecated and will be removed in version `3.0.0`
*
* @removed 3.0.0
*/
static build(title, isDevelopment = false) {
return new LoggerBrowser(title, isDevelopment);
}
constructor(title, isDevelopment = false) {
console.warn(deprecateMessage);
if (isDevelopment) {
this.#logger = LoggerFactory.createForBrowserDevelopment(title);
} else {
this.#logger = LoggerFactory.createForBrowserProduction(title);
}
}
// region Config ////
/**
* Set config
*
* @deprecated This method is deprecated and will be removed in version `3.0.0`
*
* @removed 3.0.0
*/
setConfig(_types) {
console.warn(deprecateMessage);
}
/**
* Set enable
*
* @deprecated This method is deprecated and will be removed in version `3.0.0`
*
* @removed 3.0.0
*/
enable(_type) {
console.warn(deprecateMessage);
return true;
}
/**
* Set disable
*
* @deprecated This method is deprecated and will be removed in version `3.0.0`
*
* @removed 3.0.0
*/
disable(_type) {
console.warn(deprecateMessage);
return true;
}
/**
* Test is enable
*
* @deprecated This method is deprecated and will be removed in version `3.0.0`
*
* @removed 3.0.0
*/
isEnabled(_type) {
console.warn(deprecateMessage);
return false;
}
// endregion ////
// region Functions ////
async desktop(...params) {
console.warn(deprecateMessage);
const context = {
needDesktop: true,
params: { ...params }
};
return this.#logger.debug("desktop", context);
}
async log(...params) {
console.warn(deprecateMessage);
const context = { params: { ...params } };
return this.#logger.debug("log", context);
}
async info(...params) {
console.warn(deprecateMessage);
const context = { params: { ...params } };
return this.#logger.info("info", context);
}
async warn(...params) {
console.warn(deprecateMessage);
const context = { params: { ...params } };
return this.#logger.warning("warn", context);
}
async error(...params) {
console.warn(deprecateMessage);
const context = { params: { ...params } };
return this.#logger.error("error", context);
}
async trace(...params) {
console.warn(deprecateMessage);
const context = {
needTrace: true,
params: { ...params }
};
return this.#logger.debug("trace", context);
}
async debug(...params) {
console.warn(deprecateMessage);
const context = { params: { ...params } };
return this.#logger.debug("debug", context);
}
async notice(...params) {
console.warn(deprecateMessage);
const context = { params: { ...params } };
return this.#logger.info("notice", context);
}
async warning(...params) {
console.warn(deprecateMessage);
const context = { params: { ...params } };
return this.#logger.warning("warning", context);
}
async critical(...params) {
console.warn(deprecateMessage);
const context = { params: { ...params } };
return this.#logger.critical("critical", context);
}
async alert(...params) {
console.warn(deprecateMessage);
const context = { params: { ...params } };
return this.#logger.alert("alert", context);
}
async emergency(...params) {
console.warn(deprecateMessage);
const context = { params: { ...params } };
return this.#logger.emergency("alert", context);
}
// endregion ////
}
var DataType = /* @__PURE__ */ ((DataType2) => {
DataType2["undefined"] = "undefined";
DataType2["any"] = "any";
DataType2["integer"] = "integer";
DataType2["boolean"] = "boolean";
DataType2["double"] = "double";
DataType2["date"] = "date";
DataType2["datetime"] = "datetime";
DataType2["string"] = "string";
DataType2["text"] = "text";
DataType2["file"] = "file";
DataType2["array"] = "array";
DataType2["object"] = "object";
DataType2["user"] = "user";
DataType2["location"] = "location";
DataType2["crmCategory"] = "crm_category";
DataType2["crmStatus"] = "crm_status";
DataType2["crmCurrency"] = "crm_currency";
return DataType2;
})(DataType || {});
var __defProp$1y = Object.defineProperty;
var __name$1y = (target, value) => __defProp$1y(target, "name", { value, configurable: true });
const OBJECT_CONSTRUCTOR_STRING = Function.prototype.toString.call(Object);
class TypeManager {
static {
__name$1y(this, "TypeManager");
}
/**
* Returns the internal `[[Class]]` tag of a value.
* @param value - The value to inspect.
* @returns The result of `Object.prototype.toString.call(value)`, e.g. `'[object Array]'`.
*/
getTag(value) {
return Object.prototype.toString.call(value);
}
/**
* Checks that value is string
* @param value
* @return {boolean}
*
* @memo get from pull.client.Utils
*/
isString(value) {
return typeof value === "string" || value instanceof String;
}
/**
* Returns true if a value is not an empty string
* @param value
* @returns {boolean} Returns true if a value is not an empty string
*/
isStringFilled(value) {
return this.isString(value) && value !== "";
}
/**
* Checks that value is function
* @param value
* @return {boolean}
*
* @memo get from pull.client.Utils
*/
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
isFunction(value) {
return value === null ? false : typeof value === "function" || value instanceof Function;
}
/**
* Checks that value is an object
* @param value
* @return {boolean}
*/
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
isObject(value) {
return !!value && (typeof value === "object" || typeof value === "function");
}
/**
* Checks that value is object like
* @param value
* @return {boolean}
*/
isObjectLike(value) {
return !!value && typeof value === "object";
}
/**
* Checks that value is plain object
* @param value
* @return {boolean}
*/
isPlainObject(value) {
if (!this.isObjectLike(value) || this.getTag(value) !== "[object Object]") {
return false;
}
const proto = Object.getPrototypeOf(value);
if (proto === null) {
return true;
}
const ctor = Object.prototype.hasOwnProperty.call(proto, "constructor") && proto.constructor;
return typeof ctor === "function" && Function.prototype.toString.call(ctor) === OBJECT_CONSTRUCTOR_STRING;
}
/**
* Checks that value looks like a JSON-RPC request object.
* @param value - The value to check.
* @returns True when `value` has a non-empty `jsonrpc` string and a non-empty `method` string.
*/
isJsonRpcRequest(value) {
return typeof value === "object" && value && "jsonrpc" in value && this.isStringFilled(value.jsonrpc) && "method" in value && this.isStringFilled(value.method);
}
/**
* Checks that value looks like a JSON-RPC response object.
* @param value - The value to check.
* @returns True when `value` has a non-empty `jsonrpc` string, an `id`, and either a `result` or an `error` property.
*/
isJsonRpcResponse(value) {
return typeof value === "object" && value && "jsonrpc" in value && this.isStringFilled(value.jsonrpc) && "id" in value && ("result" in value || "error" in value);
}
/**
* Checks that value is boolean
* @param value
* @return {boolean}
*/
isBoolean(value) {
return value === true || value === false;
}
/**
* Checks that value is number
* @param value
* @return {boolean}
*/
isNumber(value) {
return typeof value === "number" && !Number.isNaN(value);
}
/**
* Checks that value is integer
* @param value
* @return {boolean}
*/
isInteger(value) {
return Number.isInteger(value);
}
/**
* Checks that value is float
* @param value
* @return {boolean}
*/
isFloat(value) {
return this.isNumber(value) && !this.isInteger(value);
}
/**
* Checks that value is nil
* @param value
* @return {boolean}
*/
isNil(value) {
return value === null || value === void 0;
}
/**
* Checks that value is an array
* @param value
* @return {boolean}
*/
isArray(value) {
return !this.isNil(value) && Array.isArray(value);
}
/**
* Returns true if a value is an array, and it has at least one element
* @param value
* @returns {boolean} Returns true if a value is an array, and it has at least one element
*/
isArrayFilled(value) {
return this.isArray(value) && value.length > 0;
}
/**
* Checks that value is array like
* @param value
* @return {boolean}
*/
isArrayLike(value) {
return !this.isNil(value) && !this.isFunction(value) && value.length > -1 && value.length <= Number.MAX_SAFE_INTEGER;
}
/**
* Checks that value is Date
* @param value
* @return {boolean}
*/
isDate(value) {
return value instanceof Date;
}
/**
* Checks that is a DOM node
* @param value
* @return {boolean}
*/
isDomNode(value) {
return this.isObjectLike(value) && !this.isPlainObject(value) && "nodeType" in value;
}
/**
* Checks that value is element node
* @param value
* @return {boolean}
*/
isElementNode(value) {
return this.isDomNode(value) && value.nodeType === Node.ELEMENT_NODE;
}
/**
* Checks that value is a text node
* @param value
* @return {boolean}
*/
isTextNode(value) {
return this.isDomNode(value) && value.nodeType === Node.TEXT_NODE;
}
/**
* Checks that value is Map
* @param value
* @return {boolean}
*/
isMap(value) {
return this.isObjectLike(value) && this.getTag(value) === "[object Map]";
}
/**
* Checks that value is Set
* @param value
* @return {boolean}
*/
isSet(value) {
return this.isObjectLike(value) && this.getTag(value) === "[object Set]";
}
/**
* Checks that value is WeakMap
* @param value
* @return {boolean}
*/
isWeakMap(value) {
return this.isObjectLike(value) && this.getTag(value) === "[object WeakMap]";
}
/**
* Checks that value is WeakSet
* @param value
* @return {boolean}
*/
isWeakSet(value) {
return this.isObjectLike(value) && this.getTag(value) === "[object WeakSet]";
}
/**
* Checks that value is prototype
* @param value
* @return {boolean}
*/
isPrototype(value) {
return (typeof (value && value.constructor) === "function" && value.constructor.prototype || Object.prototype) === value;
}
/**
* Checks that value is regexp
* @param value
* @return {boolean}
*/
isRegExp(value) {
return this.isObjectLike(value) && this.getTag(value) === "[object RegExp]";
}
/**
* Checks that value is null
* @param value
* @return {boolean}
*/
isNull(value) {
return value === null;
}
/**
* Checks that value is undefined
* @param value
* @return {boolean}
*/
isUndefined(value) {
return typeof value === "undefined";
}
/**
* Checks that value is ArrayBuffer
* @param value
* @return {boolean}
*/
isArrayBuffer(value) {
return this.isObjectLike(value) && this.getTag(value) === "[object ArrayBuffer]";
}
/**
* Checks that value is typed array
* @param value
* @return {boolean}
*/
isTypedArray(value) {
const regExpTypedTag = /^\[object (?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)Array\]$/;
return this.isObjectLike(value) && regExpTypedTag.test(this.getTag(value));
}
/**
* Checks that value is Blob
* @param value
* @return {boolean}
*/
isBlob(value) {
return this.isObjectLike(value) && this.isNumber(value.size) && this.isString(value.type) && this.isFunction(value.slice);
}
/**
* Checks that value is File
* @param value
* @return {boolean}
*/
isFile(value) {
return this.isBlob(value) && this.isString(value.name) && (this.isNumber(value.lastModified) || this.isObjectLike(value.lastModifiedDate));
}
/**
* Checks that value is FormData
* @param value
* @return {boolean}
*/
isFormData(value) {
if (typeof FormData !== "undefined" && value instanceof FormData) {
return true;
}
return this.isObjectLike(value) && this.getTag(value) === "[object FormData]";
}
/**
* Deep-clones a value, with support for DOM nodes.
*
* Primitives and `null` / `undefined` are returned unchanged. `Date` instances
* are cloned via `new Date(obj)`, DOM nodes via `Node.cloneNode`, and plain
* objects/arrays are copied property by property (recursively, when `bCopyObj` is true).
*
* @param obj - The value to clone.
* @param bCopyObj - When true (default), nested objects/arrays are cloned recursively; when false, they are copied by reference.
* @returns A clone of `obj` (or `obj` itself for primitives).
*/
clone(obj, bCopyObj = true) {
let _obj, i, l;
if (this.isNil(obj) || typeof obj !== "object") {
return obj;
}
if (this.isDomNode(obj)) {
_obj = obj.cloneNode(bCopyObj);
} else if (typeof obj == "object") {
if (this.isArray(obj)) {
_obj = [];
for (i = 0, l = obj.length; i < l; i++) {
if (typeof obj[i] == "object" && bCopyObj) {
_obj[i] = this.clone(obj[i], bCopyObj);
} else {
_obj[i] = obj[i];
}
}
} else {
_obj = {};
if (obj.constructor) {
if (this.isDate(obj)) {
_obj = new Date(obj);
} else {
_obj = new obj.constructor();
}
}
for (i in obj) {
if (!Object.prototype.hasOwnProperty.call(obj, i)) {
continue;
}
if (typeof obj[i] === "object" && bCopyObj) {
_obj[i] = this.clone(obj[i], bCopyObj);
} else {
_obj[i] = obj[i];
}
}
}
} else {
_obj = obj;
}
return _obj;
}
}
const Type = new TypeManager();
var __defProp$1x = Object.defineProperty;
var __name$1x = (target, value) => __defProp$1x(target, "name", { value, configurable: true });
function pick(data, keys) {
const result = {};
for (const key of keys) {
result[key] = data[key];
}
return result;
}
__name$1x(pick, "pick");
function omit(data, keys) {
const result = { ...data };
for (const key of keys) {
delete result[key];
}
return result;
}
__name$1x(omit, "omit");
function isArrayOfArray(item) {
return Array.isArray(item[0]);
}
__name$1x(isArrayOfArray, "isArrayOfArray");
function getEnumValue(enumObj, value) {
return Object.values(enumObj).includes(value) ? value : void 0;
}
__name$1x(getEnumValue, "getEnumValue");
var __defProp$1w = Object.defineProperty;
var __name$1w = (target, value) => __defProp$1w(target, "name", { value, configurable: true });
const byteToHex = [];
for (let i = 0; i < 256; ++i) {
byteToHex.push((i + 256).toString(16).slice(1));
}
function sfc32(a, b, c, d) {
return () => {
a |= 0;
b |= 0;
c |= 0;
d |= 0;
const t = (a + b | 0) + d | 0;
d = d + 1 | 0;
a = b ^ b >>> 9;
b = c + (c << 3) | 0;
c = (c << 21 | c >>> 11) + t | 0;
return t >>> 0;
};
}
__name$1w(sfc32, "sfc32");
function uuidv7() {
const bytes = new Uint8Array(16);
const timestamp = BigInt(Date.now());
const perf = BigInt(Math.floor(performance.now() * 1e3) % 65535);
const combinedTime = timestamp << 16n | perf;
bytes[0] = Number(combinedTime >> 40n & 0xFFn);
bytes[1] = Number(combinedTime >> 32n & 0xFFn);
bytes[2] = Number(combinedTime >> 24n & 0xFFn);
bytes[3] = Number(combinedTime >> 16n & 0xFFn);
bytes[4] = Number(combinedTime >> 8n & 0xFFn);
bytes[5] = Number(combinedTime & 0xFFn);
const seed = (Math.random() * 4294967295 ^ Date.now() ^ performance.now()) >>> 0;
const rand = sfc32(2654435769, 608135816, 3084996962, seed);
const randView = new DataView(bytes.buffer);
randView.setUint32(6, rand());
randView.setUint32(10, rand());
randView.setUint16(14, rand());
bytes[6] = 112 | bytes[6] & 15;
bytes[8] = 128 | bytes[8] & 63;
return (byteToHex[bytes[0]] + byteToHex[bytes[1]] + byteToHex[bytes[2]] + byteToHex[bytes[3]] + "-" + byteToHex[bytes[4]] + byteToHex[bytes[5]] + "-" + byteToHex[bytes[6]] + byteToHex[bytes[7]] + "-" + byteToHex[bytes[8]] + byteToHex[bytes[9]] + "-" + byteToHex[bytes[10]] + byteToHex[bytes[11]] + byteToHex[bytes[12]] + byteToHex[bytes[13]] + byteToHex[bytes[14]] + byteToHex[bytes[15]]).toLowerCase();
}
__name$1w(uuidv7, "uuidv7");
var __defProp$1v = Object.defineProperty;
var __name$1v = (target, value) => __defProp$1v(target, "name", { value, configurable: true });
const reEscape = /[&<>'"]/g;
const reUnescape = /&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34)/g;
const escapeEntities = {
"&": "&",
"<": "<",
">": ">",
"'": "'",
'"': """
};
const unescapeEntities = {
"&": "&",
"&": "&",
"<": "<",
"<": "<",
">": ">",
">": ">",
"&apos": "'",
"'": "'",
""": '"',
""": '"'
};
class TextManager {
static {
__name$1v(this, "TextManager");
}
/**
* Generates a random `[a-z0-9]` string of the requested length.
*
* Each character is drawn from `Math.random()`, so the result is **not**
* cryptographically secure — use it for cache-busting keys and disposable
* ids, not for tokens or secrets.
*
* @param length - Number of characters to generate. Defaults to `8`.
* @returns A random lowercase alphanumeric string.
*
* @example
* ```ts
* Text.getRandom() // 'a7f3k1z9'
* Text.getRandom(4) // 'p2x8'
* ```
*/
getRandom(length = 8) {
return Array.from({ length }).map(() => Math.trunc(Math.random() * 36).toString(36)).join("");
}
/**
* Generates a locally-computed UUID v4 (random) string.
*
* The value is built from `Math.random()` and is **not**
* cryptographically secure. For a time-ordered, RFC 4122 identifier prefer
* {@link getUuidRfc4122}.
*
* @returns A UUID v4 formatted string (`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`).
*
* @example
* ```ts
* Text.getUniqId() // 'd2b8a1f0-3c4e-4a9b-8f7c-1e2d3a4b5c6d'
* ```
*/
getUniqId() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
const r = Math.trunc(Math.random() * 16);
const v = c === "x" ? r : r & 3 | 8;
return v.toString(16);
});
}
/**
* Generates a time-ordered UUID v7 (RFC 4122).
*
* This is the identifier the SDK uses as the default request id, because its
* leading timestamp keeps generated ids sortable by creation time.
*
* @returns A UUID v7 formatted string.
*
* @example
* ```ts
* Text.getUuidRfc4122() // '019323ac-8ace-725b-a3dc-6a7c333da066'
* ```
*/
getUuidRfc4122() {
return uuidv7();
}
/**
* Encodes the unsafe HTML characters `&`, `<`, `>`, `'`, and `"` into their
* entity codes.
*
* To match the legacy Bitrix Framework behaviour the trailing `;` is
* deliberately omitted (`&` instead of `&`). Non-string values are
* returned untouched.
*
* This is **not** a general-purpose HTML sanitizer: it only escapes those
* five characters and is not context-aware (it does not neutralise
* attribute-breakout, `javascript:` URLs, or markup outside the escaped set).
* Do not rely on it as the sole XSS defence for untrusted input rendered as
* HTML.
*
* @param value - The string to encode.
* @returns The encoded string, or the original value when it is not a string.
*
* @example
* ```ts
* Text.encode('<b>Tom & Jerry</b>') // '<b>Tom & Jerry</b>'
* ```
*/
encode(value) {
if (Type.isString(value)) {
return value.replace(reEscape, (item) => escapeEntities[item]);
}
return value;
}
/**
* Decodes HTML entities produced by {@link encode} back into their
* characters.
*
* Both the named entities (`&`, `<`, …) and their numeric equivalents
* (`&`, `<`, …) are recognised. Like {@link encode}, the tokens carry
* no trailing `;`, so a `;` that follows an entity in the input is left in
* place (`&` decodes to `&;`). Non-string values are returned untouched.
*
* @param value - The string to decode.
* @returns The decoded string, or the original value when it is not a string.
*
* @example
* ```ts
* Text.decode('<b>Tom & Jerry</b>') // '<b>Tom & Jerry</b>'
* ```
*/
decode(value) {
if (Type.isString(value)) {
return value.replace(reUnescape, (item) => unescapeEntities[item]);
}
return value;
}
/**
* Parses a value into a floating-point number.
*
* Uses `Number.parseFloat`, so a leading numeric portion is accepted
* (`'12px'` → `12`). Any value that cannot be parsed becomes `0`.
*
* @param value - The value to convert.
* @returns The parsed number, or `0` when parsing fails.
*
* @example
* ```ts
* Text.toNumber('12.5') // 12.5
* Text.toNumber('abc') // 0
* ```
*/
toNumber(value) {
const parsedValue = Number.parseFloat(value);
if (Type.isNumber(parsedValue)) {
return parsedValue;
}
return 0;
}
/**
* Parses a value into an integer (base 10).
*
* Any value that cannot be parsed becomes `0`.
*
* @param value - The value to convert.
* @returns The parsed integer, or `0` when parsing fails.
*
* @example
* ```ts
* Text.toInteger('42.9') // 42
* Text.toInteger('abc') // 0
* ```
*/
toInteger(value) {
return this.toNumber(Number.parseInt(value, 10));
}
/**
* Interprets a value as a boolean.
*
* `true` is returned for `true`, `1`, `'true'`, `'y'`, and `'1'`
* (string comparison is case-insensitive). Extra truthy tokens can be added
* through `trueValues`; everything else yields `false`.
*
* @param value - The value to interpret.
* @param trueValues - Additional values that should be treated as `true`.
* @returns `true` when the value matches a truthy token, otherwise `false`.
*
* @example
* ```ts
* Text.toBoolean('Y') // true
* Text.toBoolean('on', ['on']) // true
* Text.toBoolean('no') // false
* ```
*/
toBoolean(value, trueValues = []) {
const transformedValue = Type.isString(value) ? value.toLowerCase() : value;
return ["true", "y", "1", 1, true, ...trueValues].includes(transformedValue);
}
/**
* Converts a string to `camelCase`.
*
* Hyphens, underscores, and whitespace are treated as word separators. A
* fully uppercase string is lowercased (`'ABC'` → `'abc'`); an empty or
* non-filled string is returned untouched.
*
* @param str - The string to convert.
* @returns The `camelCase` string.
*
* @example
* ```ts
* Text.toCamelCase('get_user_id') // 'getUserId'
* Text.toCamelCase('Some Value') // 'someValue'
* ```
*/
toCamelCase(str) {
if (!Type.isStringFilled(str)) {
return str;
}
const separators = /[-_\s]+(.)?/g;
if (!separators.test(str)) {
return /^[A-Z]+$/.test(str) ? str.toLowerCase() : str[0].toLowerCase() + str.slice(1);
}
const camel = str.toLowerCase().replace(
separators,
(_match, letter) => letter ? letter.toUpperCase() : ""
);
return camel[0].toLowerCase() + camel.slice(1);
}
/**
* Converts a string to `PascalCase`.
*
* Equivalent to `capitalize(toCamelCase(str))`. An empty or non-filled string
* is returned untouched.
*
* @param str - The string to convert.
* @returns The `PascalCase` string.
*
* @example
* ```ts
* Text.toPascalCase('get_user_id') // 'GetUserId'
* ```
*/
toPascalCase(str) {
if (!Type.isStringFilled(str)) {
return str;
}
return this.capitalize(this.toCamelCase(str));
}
/**
* Converts a string to `kebab-case`.
*
* Splits on uppercase-letter boundaries as well as existing separators, so
* both `camelCase` and mixed-case acronyms are handled. An uppercase run that
* is immediately followed by a digit is split into single letters
* (`parseHTML5` → `parse-h-t-m-l-5`), because there is no word boundary
* between the acronym and the digit. An empty or non-filled string is
* returned untouched.
*
* @param str - The string to convert.
* @returns The `kebab-case` string.
*
* @example
* ```ts
* Text.toKebabCase('getUserId') // 'get-user-id'
* Text.toKebabCase('XMLHttpRequest') // 'xml-http-request'
* ```
*/
toKebabCase(str) {
if (!Type.isStringFilled(str)) {
return str;
}
const matches = str.match(
/[A-Z]{2,}(?=[A-Z][a-z]+\d*|\b)|[A-Z]?[a-z]+\d*|[A-Z]|\d+/g
);
if (!matches) {
return str;
}
return matches.map((word) => word.toLowerCase()).join("-");
}
/**
* Uppercases the first character of a string, leaving the rest untouched.
*
* An empty or non-filled string is returned untouched.
*
* @param str - The string to capitalize.
* @returns The capitalized string.
*
* @example
* ```ts
* Text.capitalize('hello') // 'Hello'
* ```
*/
capitalize(str) {
if (!Type.isStringFilled(str)) {
return str;
}
return str[0].toUpperCase() + str.slice(1);
}
/**
* Formats a number with grouped thousands and a fixed number of decimals.
*
* Mirrors the algorithm Bitrix24 uses on the server: non-finite inputs are
* treated as `0`, the fractional part is rounded to `decimals` places, and
* the thousands separator is inserted every three digits left of the decimal
* point.
*
* @param number - The number to format.
* @param decimals - Number of digits after the decimal point. Defaults to `0`.
* @param decPoint - The decimal-point character. Defaults to `'.'`.
* @param thousandsSep - The thousands separator. Defaults to `','`.
* @returns The formatted number as a string.
*
* @example
* ```ts
* Text.numberFormat(1234.567, 2) // '1,234.57'
* Text.numberFormat(1234.567, 2, ',', ' ') // '1 234,57'
* ```
*/
numberFormat(number, decimals = 0, decPoint = ".", thousandsSep = ",") {
const value = Number.isFinite(number) ? number : 0;
const fractionDigits = Number.isFinite(decimals) ? Math.abs(decimals) : 0;
const roundTo = /* @__PURE__ */ __name$1v((n, digits) => {
const factor = 10 ** digits;
return Math.round(n * factor) / factor;
}, "roundTo");
const parts = (fractionDigits ? roundTo(value, fractionDigits) : Math.round(value)).toString().split(".");
if (parts[0] && parts[0].length > 3) {
parts[0] = parts[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, thousandsSep);
}
if ((parts[1] || "").length < fractionDigits) {
parts[1] = (parts[1] || "").padEnd(fractionDigits, "0");
}
return parts.join(decPoint);
}
/**
* Converts a string into a Luxon `DateTime`.
*
* When `template` is provided the string is parsed with
* `DateTime.fromFormat`; otherwise it is parsed as ISO 8601 via
* `DateTime.fromISO`.
*
* @param dateString - The date string to parse.
* @param template - Optional Luxon format token describing `dateString`.
* @param opts - Optional Luxon parsing options (zone, locale, …).
* @returns The parsed `DateTime` (use `.isValid` to check the result).
*
* @see https://moment.github.io/luxon/#/parsing?id=parsing-technical-formats
*
* @example
* ```ts
* Text.toDateTime('2026-05-04T09:53:51+03:00')
* Text.toDateTime('04.05.2026', 'dd.MM.yyyy')
* ```
*/
toDateTime(dateString, template, opts) {
if (Type.isStringFilled(template)) {
return DateTime.fromFormat(dateString, template, opts);
}
return DateTime.fromISO(dateString, opts);
}
/**
* Formats a date into the string Bitrix24 expects in REST payloads
* (`yyyy-MM-dd'T'HH:mm:ssZZ`, i.e. PHP's `Y-m-d\TH:i:sP`).
*
* A string input is passed through unchanged (assumed already formatted); a
* JS `Date` is converted through Luxon first.
*
* @param date - The value to format: an already-formatted string, a JS `Date`,
* or a Luxon `DateTime`.
* @returns The Bitrix24-formatted date string.
*
* @example
* ```ts
* Text.toB24Format(new Date()) // '2026-05-04T09:53:51+03:00'
* ```
*/
toB24Format(date) {
if (typeof date === "string") {
return date;
} else if (date instanceof Date) {
return this.toB24Format(DateTime.fromJSDate(date));
}
return date.toFormat("yyyy-MM-dd'T'HH:mm:ssZZ");
}
/**
* Returns the current local timestamp formatted for log lines
* (`yyyy-MM-dd HH:mm:ss`).
*
* @returns The formatted current timestamp.
*
* @example
* ```ts
* Text.getDateForLog() // '2026-05-04 09:53:51'
* ```
*/
getDateForLog() {
return DateTime.now().toFormat("yyyy-MM-dd HH:mm:ss");
}
/**
* Serialises a plain object into an `application/x-www-form-urlencoded`
* query string.
*
* Keys and values are percent-encoded. Array values are expanded into
* indexed pairs (`key[0]=a&key[1]=b`). The leading `?` is **not** included.
*
* @param params - The object to serialise. A `null` / `undefined` value
* yields an empty string.
* @returns The encoded query string (without a leading `?`).
*
* @example
* ```ts
* Text.buildQueryString({ id: 7, tag: ['a', 'b'] })
* // 'id=7&tag%5B0%5D=a&tag%5B1%5D=b'
* ```
*/
buildQueryString(params) {
if (Type.isNil(params)) {
return "";
}
const pairs = [];
for (const [key, value] of Object.entries(params)) {
if (Type.isArray(value)) {
value.forEach((valueElement, index) => {
pairs.push(
`${encodeURIComponent(`${key}[${index}]`)}=${encodeURIComponent(valueElement)}`
);
});
} else {
pairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
}
}
return pairs.join("&");
}
}
const Text = new TextManager();
var __defProp$1u = Object.defineProperty;
var __name$1u = (target, value) => __defProp$1u(target, "name", { value, configurable: true });
let UA = "";
try {
UA = navigator?.userAgent.toLowerCase();
} catch {
UA = "?";
}
class BrowserManager {
static {
__name$1u(this, "BrowserManager");
}
/**
* Checks whether the current browser is Opera.
*
* @returns `true` if the user agent string contains `opera`.
*/
isOpera() {
return UA.includes("opera");
}
/**
* Checks whether the current browser is Internet Explorer (any version).
*
* @returns `true` if `document` exposes the legacy `attachEvent` API and the browser is not Opera.
*/
isIE() {
return "attachEvent" in document && !this.isOpera();
}
/**
* Checks whether the current browser is Internet Explorer 6.
*
* @returns `true` if the user agent string contains `msie 6`.
*/
isIE6() {
return UA.includes("msie 6");
}
/**
* Checks whether the current browser is Internet Explorer 7.
*
* @returns `true` if the user agent string contains `msie 7`.
*/
isIE7() {
return UA.includes("msie 7");
}
/**
* Checks whether the current browser is Internet Explorer 8.
*
* @returns `true` if the user agent string contains `msie 8`.
*/
isIE8() {
return UA.includes("msie 8");
}
/**
* Checks whether the current browser is Internet Explorer 9 or the document is rendered in IE9+ document mode.
*
* @returns `true` if `document.documentMode` is defined and `>= 9`.
*/
isIE9() {
return "documentMode" in document && document?.documentMode >= 9;
}
/**
* Checks whether the current browser is Internet Explorer 10 or the document is rendered in IE10+ document mode.
*
* @returns `true` if `document.documentMode` is defined and `>= 10`.
*/
isIE10() {
return "documentMode" in document && document?.documentMode >= 10;
}
/**
* Checks whether the current browser is Safari.
*
* @returns `true` if the user agent string contains `safari` and does not contain `chrome`.
*/
isSafari() {
return UA.includes("safari") && !UA.includes("chrome");
}
/**
* Checks whether the current browser is Firefox.
*
* @returns `true` if the user agent string contains `firefox`.
*/
isFirefox() {
return UA.includes("firefox");
}
/**
* Checks whether the current browser is Chrome.
*
* @returns `true` if the user agent string contains `chrome`.
*/
isChrome() {
return UA.includes("chrome");
}
/**
* Detects the Internet Explorer version using a chain of user-agent and
* `document`/`navigator` heuristics (including legacy Trident/MSIE detection).
*
* @returns The detected IE version number, or `-1` if the browser is Opera, Safari, Firefox, or Chrome (i.e. not IE).
*/
detectIEVersion() {
if (this.isOpera() || this.isSafari() || this.isFirefox() || this.isChrome()) {
return -1;
}
let rv = -1;
if (
// @ts-expect-error we detect IEVersion ////
!!window.MSStream && !window.ActiveXObject && "ActiveXObject" in window
) {
rv = 11;
} else if (this.isIE10()) {
rv = 10;
} else if (this.isIE9()) {
rv = 9;
} else if (this.isIE()) {
rv = 8;
}
if (rv === -1 || rv === 8) {
if (navigator.appName === "Microsoft Internet Explorer") {
const re = /MSIE (\d[.0-9]*)/;
const res = navigator.userAgent.match(re);
if (Type.isArrayLike(res) && res.length > 0) {
rv = Number.parseFloat(res[1]);
}
}
if (navigator.appName === "Netscape") {
rv = 11;
const re = /Trident\/.*rv:(\d[.0-9]*)/;
if (re.exec(navigator.userAgent) != null) {
const res = navigator.userAgent.match(re);
if (Type.isArrayLike(res) && res.length > 0) {
rv = Number.parseFloat(res[1]);
}
}
}
}
return rv;
}
/**
* Checks whether the current browser is Internet Explorer 11.
*
* @returns `true` if {@link detectIEVersion} resolves to `11` or higher.
*/
isIE11() {
return this.detectIEVersion() >= 11;
}
/**
* Checks whether the current OS is macOS.
*
* @returns `true` if the user agent string contains `macintosh`.
*/
isMac() {
return UA.includes("macintosh");
}
/**
* Checks whether the current OS is Windows.
*
* @returns `true` if the user agent string contains `windows`.
*/
isWin() {
return UA.includes("windows");
}
/**
* Checks whether the current OS is Linux (desktop, not Android).
*
* @returns `true` if the user agent string contains `linux` and the platform is not Android.
*/
isLinux() {
return UA.includes("linux") && !this.isAndroid();
}
/**
* Checks whether the current OS is Android.
*
* @returns `true` if the user agent string contains `android`.
*/
isAndroid() {
return UA.includes("android");
}
/**
* Checks whether the current device is an iPad.
*
* @returns `true` if the user agent string contains `ipad;`, or the platform is macOS with touch support (modern iPadOS reporting as Mac).
*/
isIPad() {
return UA.includes("ipad;") || this.isMac() && this.isTouchDevice();
}
/**
* Checks whether the current device is an iPhone.
*
* @returns `true` if the user agent string contains `iphone;`.
*/
isIPhone() {
return UA.includes("iphone;");
}
/**
* Checks whether the current device runs iOS.
*
* @returns `true` if {@link isIPad} or {@link isIPhone} is `true`.
*/
isIOS() {
return this.isIPad() || this.isIPhone();
}
/**
* Checks whether the current device is a mobile device.
*
* @returns `true` if the device is an iPhone, iPad, or Android device, or the user agent string contains `mobile` or `touch`.
*/
isMobile() {
return this.isIPhone() || this.isIPad() || this.isAndroid() || UA.includes("mobile") || UA.includes("touch");
}
/**
* Checks whether the current display is a high-density (Retina) screen.
*
* @returns `true` if `window.devicePixelRatio` is defined and `>= 2`.
*/
isRetina() {
return (window.devicePixelRatio && window.devicePixelRatio >= 2) === true;
}
/**
* Checks whether the current device supports touch input.
*
* @returns `true` if `window` exposes `ontouchstart` or `navigator.maxTouchPoints` is greater than `0`.
*/
isTouchDevice() {
return "ontouchstart" in window || navigator.maxTouchPoints > 0;
}
/**
* Checks whether a document is rendered in standards mode (as opposed to quirks mode).
*
* @param target - The document to inspect. Defaults to the global `document` when omitted/falsy.
* @returns `true` if `compatMode` is `'CSS1Compat'`, or a truthy fallback based on `documentElement.clientHeight` when `compatMode` is unavailable.
*/
isDoctype(target) {
const doc = target || document;
if (doc.compatMode) {
return doc.compatMode === "CSS1Compat";
}
return doc.documentElement && doc.documentElement.clientHeight;
}
/**
* Checks whether `localStorage` is available and writable in the current environment.
*
* @returns `true` if a test key can be written to and removed from `localStorage` without throwing.
*/
isLocalStorageSupported() {
try {
localStorage.setItem("test", "test");
localStorage.removeItem("test");
return true;
} catch {
return false;
}
}
/**
* Detects the Android OS version from the user agent string.
*
* @returns The parsed Android version number, or `0` if it cannot be detected (e.g. not Android).
*/
detectAndroidVersion() {
const re = /Android (\d[.0-9]*)/;
if (re.exec(navigator.userAgent) != null) {
const res = navigator.userAgent.match(re);
if (Type.isArrayLike(res) && res.length > 0) {
return Number.parseFloat(res[1]);
}
}
return 0;
}
}
const Browser = new BrowserManager();
var ApiVersion = /* @__PURE__ */ ((ApiVersion2) => {
ApiVersion2["v3"] = "v3";
ApiVersion2["v2"] = "v2";
return ApiVersion2;
})(ApiVersion || {});
var __defProp$1t = Object.defineProperty;
var __name$1t = (target, value) => __defProp$1t(target, "name", { value, configurable: true });
var EnumCrmEntityType = /* @__PURE__ */ ((EnumCrmEntityType2) => {
EnumCrmEntityType2["undefined"] = "UNDEFINED";
EnumCrmEntityType2["lead"] = "CRM_LEAD";
EnumCrmEntityType2["deal"] = "CRM_DEAL";
EnumCrmEntityType2["contact"] = "CRM_CONTACT";
EnumCrmEntityType2["company"] = "CRM_COMPANY";
EnumCrmEntityType2["oldInvoice"] = "CRM_INVOICE";
EnumCrmEntityType2["invoice"] = "CRM_SMART_INVOICE";
EnumCrmEntityType2["quote"] = "CRM_QUOTE";
EnumCrmEntityType2["requisite"] = "CRM_REQUISITE";
EnumCrmEntityType2["order"] = "ORDER";
return EnumCrmEntityType2;
})(EnumCrmEntityType || {});
var EnumCrmEntityTypeId = /* @__PURE__ */ ((EnumCrmEntityTypeId2) => {
EnumCrmEntityTypeId2[EnumCrmEntityTypeId2["undefined"] = 0] = "undefined";
EnumCrmEntityTypeId2[EnumCrmEntityTypeId2["lead"] = 1] = "lead";
EnumCrmEntityTypeId2[EnumCrmEntityTypeId2["deal"] = 2] = "deal";
EnumCrmEntityTypeId2[EnumCrmEntityTypeId2["contact"] = 3] = "contact";
EnumCrmEntityTypeId2[EnumCrmEntityTypeId2["company"] = 4] = "company";
EnumCrmEntityTypeId2[EnumCrmEntityTypeId2["oldInvoice"] = 5] = "oldInvoice";
EnumCrmEntityTypeId2[EnumCrmEntityTypeId2["invoice"] = 31] = "invoice";
EnumCrmEntityTypeId2[EnumCrmEntityTypeId2["quote"] = 7] = "quote";
EnumCrmEntityTypeId2[EnumCrmEntityTypeId2["requisite"] = 8] = "requisite";
EnumCrmEntityTypeId2[EnumCrmEntityTypeId2["order"] = 14] = "order";
return EnumCrmEntityTypeId2;
})(EnumCrmEntityTypeId || {});
var EnumCrmEntityTypeShort = /* @__PURE__ */ ((EnumCrmEntityTypeShort2) => {
EnumCrmEntityTypeShort2["undefined"] = "?";
EnumCrmEntityTypeShort2["lead"] = "L";
EnumCrmEntityTypeShort2["deal"] = "D";
EnumCrmEntityTypeShort2["contact"] = "C";
EnumCrmEntityTypeShort2["company"] = "CO";
EnumCrmEntityTypeShort2["oldInvoice"] = "I";
EnumCrmEntityTypeShort2["invoice"] = "SI";
EnumCrmEntityTypeShort2["quote"] = "Q";
EnumCrmEntityTypeShort2["requisite"] = "RQ";
EnumCrmEntityTypeShort2["order"] = "O";
return EnumCrmEntityTypeShort2;
})(EnumCrmEntityTypeShort || {});
function getEnumCrmEntityTypeShort(id) {
const key = EnumCrmEntityTypeId[id];
return EnumCrmEntityTypeShort[key] || "?" /* undefined */;
}
__name$1t(getEnumCrmEntityTypeShort, "getEnumCrmEntityTypeShort");
var ProductRowDiscountTypeId = /* @__PURE__ */ ((ProductRowDiscountTypeId2) => {
ProductRowDiscountTypeId2[ProductRowDiscountTypeId2["undefined"] = 0] = "undefined";
ProductRowDiscountTypeId2[ProductRowDiscountTypeId2["absolute"] = 1] = "absolute";
ProductRowDiscountTypeId2[ProductRowDiscountTypeId2["percentage"] = 2] = "percentage";
return ProductRowDiscountTypeId2;
})(ProductRowDiscountTypeId || {});
var CatalogProductType = /* @__PURE__ */ ((CatalogProductType2) => {
CatalogProductType2[CatalogProductType2["undefined"] = 0] = "undefined";
CatalogProductType2[CatalogProductType2["product"] = 1] = "product";
CatalogProductType2[CatalogProductType2["service"] = 7] = "service";
CatalogProductType2[CatalogProductType2["sku"] = 3] = "sku";
CatalogProductType2[CatalogProductType2["skuEmpty"] = 6] = "skuEmpty";
CatalogProductType2[CatalogProductType2["offer"] = 4] = "offer";
CatalogProductType2[CatalogProductType2["offerEmpty"] = 5] = "offerEmpty";
return CatalogProductType2;
})(CatalogProductType || {});
var CatalogProductImageType = /* @__PURE__ */ ((CatalogProductImageType2) => {
CatalogProductImageType2["undefined"] = "UNDEFINED";
CatalogProductImageType2["detail"] = "DETAIL_PICTURE";
CatalogProductImageType2["preview"] = "PREVIEW_PICTURE";
CatalogProductImageType2["morePhoto"] = "MORE_PHOTO";
return CatalogProductImageType2;
})(CatalogProductImageType || {});
var CatalogRoundingRuleType = /* @__PURE__ */ ((CatalogRoundingRuleType2) => {
CatalogRoundingRuleType2[CatalogRoundingRuleType2["undefined"] = 0] = "undefined";
CatalogRoundingRuleType2[CatalogRoundingRuleType2["mathematical"] = 1] = "mathematical";
CatalogRoundingRuleType2[CatalogRoundingRuleType2["roundingUp"] = 2] = "roundingUp";
CatalogRoundingRuleType2[CatalogRoundingRuleType2["roundingDown"] = 4] = "roundingDown";
return CatalogRoundingRuleType2;
})(CatalogRoundingRuleType || {});
var __defProp$1s = Object.defineProperty;
var __name$1s = (target, value) => __defProp$1s(target, "name", { value, configurable: true });
var EnumBitrix24Edition = /* @__PURE__ */ ((EnumBitrix24Edition2) => {
EnumBitrix24Edition2["undefined"] = "undefined";
EnumBitrix24Edition2["b24"] = "b24";
EnumBitrix24Edition2["box"] = "box";
return EnumBitrix24Edition2;
})(EnumBitrix24Edition || {});
var EnumBizprocBaseType = /* @__PURE__ */ ((EnumBizprocBaseType2) => {
EnumBizprocBaseType2["undefined"] = "undefined";
EnumBizprocBaseType2["crm"] = "crm";
EnumBizprocBaseType2["disk"] = "disk";
EnumBizprocBaseType2["lists"] = "lists";
return EnumBizprocBaseType2;
})(EnumBizprocBaseType || {});
var EnumBizprocDocumentType = /* @__PURE__ */ ((EnumBizprocDocumentType2) => {
EnumBizprocDocumentType2["undefined"] = "undefined";
EnumBizprocDocumentType2["lead"] = "CCrmDocumentLead";
EnumBizprocDocumentType2["company"] = "CCrmDocumentCompany";
EnumBizprocDocumentType2["contact"] = "CCrmDocumentContact";
EnumBizprocDocumentType2["deal"] = "CCrmDocumentDeal";
EnumBizprocDocumentType2["invoice"] = "Bitrix\\Crm\\Integration\\BizProc\\Document\\SmartInvoice";
EnumBizprocDocumentType2["quote"] = "Bitrix\\Crm\\Integration\\BizProc\\Document\\Quote";
EnumBizprocDocumentType2["order"] = "Bitrix\\Crm\\Integration\\BizProc\\Document\\Order";
EnumBizprocDocumentType2["dynamic"] = "Bitrix\\Crm\\Integration\\BizProc\\Document\\Dynamic";
EnumBizprocDocumentType2["disk"] = "Bitrix\\Disk\\BizProcDocument";
EnumBizprocDocumentType2["lists"] = "BizprocDocument";
EnumBizprocDocumentType2["listsList"] = "Bitrix\\Lists\\BizprocDocumentLists";
return EnumBizprocDocumentType2;
})(EnumBizprocDocumentType || {});
function convertBizprocDocumentTypeToCrmEntityTypeId(documentType) {
switch (documentType) {
case "CCrmDocumentLead" /* lead */:
return EnumCrmEntityTypeId.lead;
case "CCrmDocumentCompany" /* company */:
return EnumCrmEntityTypeId.company;
case "CCrmDocumentContact" /* contact */:
return EnumCrmEntityTypeId.contact;
case "CCrmDocumentDeal" /* deal */:
return EnumCrmEntityTypeId.deal;
case "Bitrix\\Crm\\Integration\\BizProc\\Document\\SmartInvoice" /* invoice */:
return EnumCrmEntityTypeId.invoice;
case "Bitrix\\Crm\\Integration\\BizProc\\Document\\Quote" /* quote */:
return EnumCrmEntityTypeId.quote;
case "Bitrix\\Crm\\Integration\\BizProc\\Document\\Order" /* order */:
return EnumCrmEntityTypeId.order;
}
return EnumCrmEntityTypeId.undefined;
}
__name$1s(convertBizprocDocumentTypeToCrmEntityTypeId, "convertBizprocDocumentTypeToCrmEntityTypeId");
function getDocumentType(documentType, entityId) {
let entityIdFormatted = "";
let base = "undefined" /* undefined */;
switch (documentType) {
case "CCrmDocumentLead" /* lead */:
base = "crm" /* crm */;
entityIdFormatted = "LEAD";
break;
case "CCrmDocumentCompany" /* company */:
base = "crm" /* crm */;
entityIdFormatted = "COMPANY";
break;
case "CCrmDocumentContact" /* contact */:
base = "crm" /* crm */;
entityIdFormatted = "CONTACT";
break;
case "CCrmDocumentDeal" /* deal */:
base = "crm" /* crm */;
entityIdFormatted = "DEAL";
break;
case "Bitrix\\Crm\\Integration\\BizProc\\Document\\SmartInvoice" /* invoice */:
base = "crm" /* crm */;
entityIdFormatted = "SMART_INVOICE";
break;
case "Bitrix\\Crm\\Integration\\BizProc\\Document\\Quote" /* quote */:
base = "crm" /* crm */;
entityIdFormatted = "QUOTE";
break;
case "Bitrix\\Crm\\Integration\\BizProc\\Document\\Order" /* order */:
base = "crm" /* crm */;
entityIdFormatted = "ORDER";
break;
case "Bitrix\\Crm\\Integration\\BizProc\\Document\\Dynamic" /* dynamic */:
base = "crm" /* crm */;
entityIdFormatted = `DYNAMIC_${entityId || 0}`;
if ((entityId || 0) < 1) {
throw new Error("Need set entityId");
}
break;
case "Bitrix\\Disk\\BizProcDocument" /* disk */:
base = "disk" /* disk */;
entityIdFormatted = `STORAGE_${entityId || 0}`;
if ((entityId || 0) < 1) {
throw new Error("Need set entityId");
}
break;
case "BizprocDocument" /* lists */:
base = "lists" /* lists */;
entityIdFormatted = `iblock_${entityId || 0}`;
if ((entityId || 0) < 1) {
throw new Error("Need set entityId");
}
break;
case "Bitrix\\Lists\\BizprocDocumentLists" /* listsList */:
base = "lists" /* lists */;
entityIdFormatted = `iblock_${entityId || 0}`;
if ((entityId || 0) < 1) {
throw new Error("Need set entityId");
}
break;
}
return [
base,
documentType,
entityIdFormatted
];
}
__name$1s(getDocumentType, "getDocumentType");
function getDocumentId(documentType, id, dynamicId) {
let entityIdFormatted = "";
const tmp = getDocumentType(documentType, 1);
switch (documentType) {
case "CCrmDocumentLead" /* lead */:
entityIdFormatted = `LEAD_${id}`;
break;
case "CCrmDocumentCompany" /* company */:
entityIdFormatted = `COMPANY_${id}`;
break;
case "CCrmDocumentContact" /* contact */:
entityIdFormatted = `CONTACT_${id}`;
break;
case "CCrmDocumentDeal" /* deal */:
entityIdFormatted = `DEAL_${id}`;
break;
case "Bitrix\\Crm\\Integration\\BizProc\\Document\\SmartInvoice" /* invoice */:
entityIdFormatted = `SMART_INVOICE_${id}`;
break;
case "Bitrix\\Crm\\Integration\\BizProc\\Document\\Quote" /* quote */:
entityIdFormatted = `QUOTE_${id}`;
break;
case "Bitrix\\Crm\\Integration\\BizProc\\Document\\Order" /* order */:
entityIdFormatted = `ORDER_${id}`;
break;
case "Bitrix\\Crm\\Integration\\BizProc\\Document\\Dynamic" /* dynamic */:
entityIdFormatted = `DYNAMIC_${dynamicId || 0}_${id}`;
if ((dynamicId || 0) < 1) {
throw new Error("Need set dynamicId");
}
break;
case "Bitrix\\Disk\\BizProcDocument" /* disk */:
entityIdFormatted = `${id}`;
break;
case "BizprocDocument" /* lists */:
entityIdFormatted = `${id}`;
break;
case "Bitrix\\Lists\\BizprocDocumentLists" /* listsList */:
entityIdFormatted = `${id}`;
break;
}
return [
tmp[0],
tmp[1],
entityIdFormatted
];
}
__name$1s(getDocumentId, "getDocumentId");
function getDocumentTypeForFilter(documentType) {
const result = getDocumentType(documentType, 1);
return [
result[0],
result[1]
];
}
__name$1s(getDocumentTypeForFilter, "getDocumentTypeForFilter");
var LoadDataType = /* @__PURE__ */ ((LoadDataType2) => {
LoadDataType2["App"] = "app";
LoadDataType2["Profile"] = "profile";
LoadDataType2["Currency"] = "currency";
LoadDataType2["AppOptions"] = "appOptions";
LoadDataType2["UserOptions"] = "userOptions";
return LoadDataType2;
})(LoadDataType || {});
const EnumAppStatus = {
// free ////
Free: "F",
// demo version ////
Demo: "D",
// trial version (limited time) ////
Trial: "T",
// paid application ////
Paid: "P",
// local application ////
Local: "L",
// subscription application ////
Subscription: "S"
};
const StatusDescriptions = {
[EnumAppStatus.Free]: "Free",
[EnumAppStatus.Demo]: "Demo",
[EnumAppStatus.Trial]: "Trial",
[EnumAppStatus.Paid]: "Paid",
[EnumAppStatus.Local]: "Local",
[EnumAppStatus.Subscription]: "Subscription"
};
const TypeSpecificUrl = {
MainSettings: "MainSettings",
UfList: "UfList",
UfPage: "UfPage"
};
var TypeOption = /* @__PURE__ */ ((TypeOption2) => {
TypeOption2["NotSet"] = "notSet";
TypeOption2["JsonArray"] = "jsonArray";
TypeOption2["JsonObject"] = "jsonObject";
TypeOption2["FloatVal"] = "float";
TypeOption2["IntegerVal"] = "integer";
TypeOption2["BoolYN"] = "boolYN";
TypeOption2["StringVal"] = "string";
return TypeOption2;
})(TypeOption || {});
var ConnectionType = /* @__PURE__ */ ((ConnectionType2) => {
ConnectionType2["Undefined"] = "undefined";
ConnectionType2["WebSocket"] = "webSocket";
ConnectionType2["LongPolling"] = "longPolling";
return ConnectionType2;
})(ConnectionType || {});
var LsKeys = /* @__PURE__ */ ((LsKeys2) => {
LsKeys2["PullConfig"] = "bx-pull-config";
LsKeys2["WebsocketBlocked"] = "bx-pull-websocket-blocked";
LsKeys2["LongPollingBlocked"] = "bx-pull-longpolling-blocked";
LsKeys2["LoggingEnabled"] = "bx-pull-logging-enabled";
return LsKeys2;
})(LsKeys || {});
var PullStatus = /* @__PURE__ */ ((PullStatus2) => {
PullStatus2["Online"] = "online";
PullStatus2["Offline"] = "offline";
PullStatus2["Connecting"] = "connect";
return PullStatus2;
})(PullStatus || {});
var SenderType = /* @__PURE__ */ ((SenderType2) => {
SenderType2[SenderType2["Unknown"] = 0] = "Unknown";
SenderType2[SenderType2["Client"] = 1] = "Client";
SenderType2[SenderType2["Backend"] = 2] = "Backend";
return SenderType2;
})(SenderType || {});
var SubscriptionType = /* @__PURE__ */ ((SubscriptionType2) => {
SubscriptionType2["Server"] = "server";
SubscriptionType2["Client"] = "client";
SubscriptionType2["Online"] = "online";
SubscriptionType2["Status"] = "status";
SubscriptionType2["Revision"] = "revision";
return SubscriptionType2;
})(SubscriptionType || {});
var CloseReasons = /* @__PURE__ */ ((CloseReasons2) => {
CloseReasons2[CloseReasons2["NORMAL_CLOSURE"] = 1e3] = "NORMAL_CLOSURE";
CloseReasons2[CloseReasons2["SERVER_DIE"] = 1001] = "SERVER_DIE";
CloseReasons2[CloseReasons2["CONFIG_REPLACED"] = 3e3] = "CONFIG_REPLACED";
CloseReasons2[CloseReasons2["CHANNEL_EXPIRED"] = 3001] = "CHANNEL_EXPIRED";
CloseReasons2[CloseReasons2["SERVER_RESTARTED"] = 3002] = "SERVER_RESTARTED";
CloseReasons2[CloseReasons2["CONFIG_EXPIRED"] = 3003] = "CONFIG_EXPIRED";
CloseReasons2[CloseReasons2["MANUAL"] = 3004] = "MANUAL";
CloseReasons2[CloseReasons2["STUCK"] = 3005] = "STUCK";
CloseReasons2[CloseReasons2["WRONG_CHANNEL_ID"] = 4010] = "WRONG_CHANNEL_ID";
return CloseReasons2;
})(CloseReasons || {});
var SystemCommands = /* @__PURE__ */ ((SystemCommands2) => {
SystemCommands2["CHANNEL_EXPIRE"] = "CHANNEL_EXPIRE";
SystemCommands2["CONFIG_EXPIRE"] = "CONFIG_EXPIRE";
SystemCommands2["SERVER_RESTART"] = "SERVER_RESTART";
return SystemCommands2;
})(SystemCommands || {});
var ServerMode = /* @__PURE__ */ ((ServerMode2) => {
ServerMode2["Shared"] = "shared";
ServerMode2["Personal"] = "personal";
return ServerMode2;
})(ServerMode || {});
const ListRpcError = {
Parse: { code: -32700, message: "Parse error" },
InvalidRequest: { code: -32600, message: "Invalid Request" },
MethodNotFound: { code: -32601, message: "Method not found" },
InvalidParams: { code: -32602, message: "Invalid params" },
Internal: { code: -32603, message: "Internal error" }
};
var RpcMethod = /* @__PURE__ */ ((RpcMethod2) => {
RpcMethod2["Publish"] = "publish";
RpcMethod2["GetUsersLastSeen"] = "getUsersLastSeen";
RpcMethod2["Ping"] = "ping";
RpcMethod2["ListChannels"] = "listChannels";
RpcMethod2["SubscribeStatusChange"] = "subscribeStatusChange";
RpcMethod2["UnsubscribeStatusChange"] = "unsubscribeStatusChange";
return RpcMethod2;
})(RpcMethod || {});
var B24LangList = /* @__PURE__ */ ((B24LangList2) => {
B24LangList2["ru"] = "ru";
B24LangList2["id"] = "id";
B24LangList2["ms"] = "ms";
B24LangList2["de"] = "de";
B24LangList2["en"] = "en";
B24LangList2["la"] = "la";
B24LangList2["fr"] = "fr";
B24LangList2["in"] = "in";
B24LangList2["it"] = "it";
B24LangList2["pl"] = "pl";
B24LangList2["br"] = "br";
B24LangList2["vn"] = "vn";
B24LangList2["tr"] = "tr";
B24LangList2["kz"] = "kz";
B24LangList2["ua"] = "ua";
B24LangList2["ar"] = "ar";
B24LangList2["th"] = "th";
B24LangList2["sc"] = "sc";
B24LangList2["tc"] = "tc";
B24LangList2["ja"] = "ja";
return B24LangList2;
})(B24LangList || {});
const B24LocaleMap = {
["ru" /* ru */]: "ru-RU",
["id" /* id */]: "id-ID",
["ms" /* ms */]: "ms-MY",
["de" /* de */]: "de-DE",
["en" /* en */]: "en-EN",
["la" /* la */]: "es-ES",
["fr" /* fr */]: "fr-FR",
["in" /* in */]: "hi-IN",
["it" /* it */]: "it-IT",
["pl" /* pl */]: "pl-PL",
["br" /* br */]: "pt-BR",
["vn" /* vn */]: "vi-VN",
["tr" /* tr */]: "tr-TR",
["kz" /* kz */]: "kk",
["ua" /* ua */]: "uk-UA",
["ar" /* ar */]: "ar-SA",
["th" /* th */]: "th-TH",
["sc" /* sc */]: "zh-CN",
["tc" /* tc */]: "zh-TW",
["ja" /* ja */]: "ja-JP"
};
var __defProp$1r = Object.defineProperty;
var __name$1r = (target, value) => __defProp$1r(target, "name", { value, configurable: true });
class Result {
static {
__name$1r(this, "Result");
}
_errors;
_data;
constructor(data) {
this._errors = /* @__PURE__ */ new Map();
this._data = data ?? null;
}
get isSuccess() {
return this._errors.size === 0;
}
get errors() {
return this._errors;
}
setData(data) {
this._data = data;
return this;
}
getData() {
return this._data;
}
addError(error, key) {
const errorKey = key ?? Text.getUuidRfc4122();
const errorObj = typeof error === "string" ? new Error(error) : error;
this._errors.set(errorKey, errorObj);
return this;
}
addErrors(errors) {
for (const error of errors) {
this.addError(error);
}
return this;
}
getErrors() {
return this._errors.values();
}
hasError(key) {
return this._errors.has(key);
}
/**
* Retrieves an array of error messages from the collected errors.
*
* @returns An array of strings representing the error messages. Each string
* contains the message of a corresponding error object.
*/
getErrorMessages() {
return Array.from(this._errors.values(), (e) => e.message);
}
/**
* Retrieves all errors as a plain object (a snapshot copy) keyed by their
* identifier, preserving which request produced each error. Unlike
* {@link Result.getErrors}, the keys are not discarded — useful for batch
* calls with `isHaltOnError: false`.
*
* For batch calls the key tells you *which* command failed:
* - an **object / named-command batch** keys each error by the command label;
* - an **array-mode batch** keys each per-command error by its **numeric
* position** (`'0'`, `'1'`, … as a string), matching the command order you
* passed in. (#255 — previously these fell back to a random UUID.)
*
* An envelope-level soft error (not tied to one command) lands under the
* internal `'base-error'` key, and {@link Result.addErrors} (no explicit key)
* still uses generated UUIDs — for those, prefer {@link Result.getErrors} /
* {@link Result.getErrorMessages}. (#230)
*
* @returns {Record<string, Error>} A map of error key to Error object.
*/
getErrorsByKey() {
return Object.fromEntries(this._errors);
}
/**
* Retrieves all error messages as a plain object (a snapshot copy) keyed by
* their identifier. Unlike {@link Result.getErrorMessages}, the keys are
* preserved. See {@link Result.getErrorsByKey} for when keys are meaningful.
*
* @returns {Record<string, string>} A map of error key to error message.
*/
getErrorMessagesByKey() {
return Object.fromEntries(
Array.from(this._errors, ([key, error]) => [key, error.message])
);
}
/**
* Converts the Result object to a string.
*
* @returns {string} Returns a string representation of the result operation
*/
toString() {
const status = this.isSuccess ? "success" : "failure";
const data = this.safeStringify(this._data);
return this.isSuccess ? `Result(${status}): ${data}` : `Result(${status}): ${data}
Errors: ${this.getErrorMessages().join(", ")}`;
}
safeStringify(data) {
try {
return JSON.stringify(data, this.replacer, 2);
} catch {
return "[Unable to serialize data]";
}
}
replacer(_, value) {
if (value instanceof Error) {
return {
name: value.name,
message: value.message,
stack: value.stack
};
}
return value;
}
// Static constructors
static ok(data) {
return new Result(data);
}
static fail(error, key) {
return new Result().addError(error, key);
}
}
var __defProp$1q = Object.defineProperty;
var __name$1q = (target, value) => __defProp$1q(target, "name", { value, configurable: true });
class SdkError extends Error {
static {
__name$1q(this, "SdkError");
}
code;
_status;
timestamp;
constructor(params) {
const message = SdkError.formatErrorMessage(params);
super(message);
this.name = "SdkError";
this.code = params.code;
this._status = params.status;
Object.defineProperty(this, "originalError", {
value: params.originalError,
enumerable: false,
writable: false,
configurable: true
});
this.timestamp = /* @__PURE__ */ new Date();
this.cleanErrorStack();
}
get status() {
return this._status;
}
/**
* Creates SdkError from exception
*/
static fromException(error, context) {
if (error instanceof SdkError) return error;
return new SdkError({
code: context?.code || "JSSDK_INTERNAL_ERROR",
status: context?.status || 500,
description: error instanceof Error ? error.message : `${error}`,
originalError: error
});
}
/**
* Serializes error for logging and debugging
*/
toJSON() {
return {
name: this.name,
code: this.code,
message: this.message,
status: this._status,
timestamp: this.timestamp.toISOString(),
stack: this.stack
};
}
/**
* Formats error information for human-readable output
*/
toString() {
let output = `[${this.name}] ${this.code} (${this._status}): ${this.message}`;
if (this.stack) {
output += `
Stack trace:
${this.stack}`;
}
return output;
}
static formatErrorMessage(params) {
if (!params?.description) {
return `Internal error`;
}
return `${params.description}`;
}
cleanErrorStack() {
if (typeof this.stack === "string") {
this.stack = this.stack.split("\n").filter((line) => !line.includes("SdkError.constructor")).join("\n");
}
}
}
var __defProp$1p = Object.defineProperty;
var __name$1p = (target, value) => __defProp$1p(target, "name", { value, configurable: true });
const SENSITIVE_PARAM_KEYS = [
"auth",
"password",
"token",
"secret",
"access_token",
"refresh_token",
"client_secret",
"application_token",
"sessid",
"key",
"signature"
];
const REDACTED_PLACEHOLDER = "***REDACTED***";
const QS_SENSITIVE_RE = new RegExp(
`([?&]|^)(${SENSITIVE_PARAM_KEYS.join("|")})=[^&#;]*`,
"gi"
);
function isPlainObject$1(value) {
return value !== null && typeof value === "object" && !Array.isArray(value);
}
__name$1p(isPlainObject$1, "isPlainObject");
function redactQueryString(value) {
if (!value.includes("=")) return value;
return value.replace(
QS_SENSITIVE_RE,
(_match, sep, key) => `${sep}${key}=${REDACTED_PLACEHOLDER}`
);
}
__name$1p(redactQueryString, "redactQueryString");
function redactValue(value, depth) {
if (typeof value === "string") return redactQueryString(value);
if (depth <= 0) return value;
if (isPlainObject$1(value)) return redactObject(value, depth - 1);
if (Array.isArray(value)) return value.map((item) => redactValue(item, depth));
return value;
}
__name$1p(redactValue, "redactValue");
function redactObject(source, depth) {
const sanitized = { ...source };
for (const key of Object.keys(sanitized)) {
if (SENSITIVE_PARAM_KEYS.includes(key.toLowerCase())) {
sanitized[key] = REDACTED_PLACEHOLDER;
continue;
}
sanitized[key] = redactValue(sanitized[key], depth);
}
return sanitized;
}
__name$1p(redactObject, "redactObject");
const DEFAULT_REDACT_DEPTH = 2;
function redactSensitiveParams(params) {
if (!isPlainObject$1(params)) return params;
return redactObject(params, DEFAULT_REDACT_DEPTH);
}
__name$1p(redactSensitiveParams, "redactSensitiveParams");
function redactSensitiveUrl(url, extraKeys = []) {
if (typeof url !== "string" || !url.includes("=")) return url;
if (extraKeys.length === 0) return redactQueryString(url);
const escaped = extraKeys.map((key) => key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
const re = new RegExp(
`([?&]|^)(${[...SENSITIVE_PARAM_KEYS, ...escaped].join("|")})=[^&#;]*`,
"gi"
);
return url.replace(re, (_match, sep, key) => `${sep}${key}=${REDACTED_PLACEHOLDER}`);
}
__name$1p(redactSensitiveUrl, "redactSensitiveUrl");
var __defProp$1o = Object.defineProperty;
var __name$1o = (target, value) => __defProp$1o(target, "name", { value, configurable: true });
class AjaxError extends SdkError {
static {
__name$1o(this, "AjaxError");
}
/**
* Redaction contract: `requestInfo.params` has already been run through
* {@link redactSensitiveParams} in the constructor, so credential-bearing
* keys are stored as `***REDACTED***` and are safe to surface via
* `toJSON()` / `toString()`. (#39, #73)
*/
requestInfo;
/**
* The `restApi:v3` `validation` array, when the portal sent one.
*
* `description` folds the validation messages into one string for display;
* this keeps them apart, **with the `field` each belongs to** — which the
* message alone does not carry, and which is what a form needs in order to
* mark the offending input rather than show a banner (#423).
*
* ```ts
* if (!response.isSuccess) {
* for (const error of response.getErrors()) {
* if (error instanceof AjaxError) {
* for (const detail of error.validation ?? []) {
* markInvalid(detail.field, detail.message)
* }
* }
* }
* }
* ```
*
* Absent under `restApi:v2`, which has no equivalent, and absent when v3
* reported an error without one. `field` is optional inside each entry
* because the portal's own shape says so.
*
* **Included in `toJSON()`**, but only when present — an error carrying no
* validation serializes exactly as it did before. It belongs there because
* `toJSON()` is what reaches a log or an error tracker, and that is where the
* field name matters most: `message` folds the validation *messages* in, but
* not the `field` each came from. A portal often names the field inside its
* own wording, as in `` Обязательное поле `id` не указано `` — but that is the
* portal's phrasing, not a guarantee, and nothing structured survives without
* this.
*
* **Redaction contract:** each entry has been run through
* {@link redactSensitiveParams} in the constructor, on the same terms as
* `requestInfo.params`. That matters because the portal's own shape permits
* extra keys beyond `field` and `message`, and only `message` is folded into
* `description` — so an extra key reaches a serializer without ever passing
* through the text. Before this was added, a row carrying `token: '…'` was
* masked inside `requestInfo.params` and printed verbatim here, from the same
* error object.
*
* What redaction does *not* cover is portal prose: a message that quotes a
* submitted value stays as the portal wrote it, exactly as it already does in
* `message`. Contrast `originalError`, which is genuinely hidden: it holds the
* raw transport error and its credentials.
*/
validation;
constructor(params) {
if (params.code === "AUTHORIZE_ERROR" || params.code === "WRONG_AUTH_TYPE") {
params.status = 403;
}
params.description = AjaxError.formatErrorMessage(params);
super(params);
this.name = "AjaxError";
this.validation = params.validation?.length ? Object.freeze(params.validation.map(
(row) => redactSensitiveParams(row)
)) : void 0;
this.requestInfo = params.requestInfo ? {
...params.requestInfo,
...params.requestInfo.params !== void 0 ? { params: redactSensitiveParams(params.requestInfo.params) } : {}
} : void 0;
this.cleanErrorStack();
}
/**
* Creates AjaxError from HTTP response
* @todo add support v3
*/
static fromResponse(response) {
return new AjaxError({
code: response.data?.error || "JSSDK_INTERNAL_AJAX_ERROR",
description: response.data?.error_description,
status: response.status,
requestInfo: response.config
});
}
/**
* @inheritDoc
*/
static fromException(error, context) {
if (error instanceof AjaxError) return error;
return new AjaxError({
code: context?.code || "JSSDK_INTERNAL_AJAX_ERROR",
status: context?.status || 500,
description: error instanceof Error ? error.message : String(error),
requestInfo: context?.requestInfo,
originalError: error
});
}
/**
* @inheritDoc
*/
toJSON() {
return {
name: this.name,
code: this.code,
message: this.message,
status: this._status,
timestamp: this.timestamp.toISOString(),
requestInfo: this.requestInfo,
// Only when present, so an error without validation serializes exactly as
// it did before this field existed (#423).
...this.validation ? { validation: this.validation } : {},
stack: this.stack
};
}
/**
* @inheritDoc
*/
toString() {
let output = `[${this.name}] ${this.code} (${this._status}): ${this.message}`;
if (this.requestInfo) {
output += `
Request: ${this.requestInfo?.requestId ? `[${this.requestInfo.requestId}] ` : ""}${this.requestInfo.method}`;
}
if (this.stack) {
output += `
Stack trace:
${this.stack}`;
}
return output;
}
/**
* @inheritDoc
*/
static formatErrorMessage(params) {
if (!params?.description) {
if (params.requestInfo?.method) {
return `${params.code} (on ${params.requestInfo.method})`;
} else {
return `Internal ajax error`;
}
}
return `${params.description}`;
}
/**
* @inheritDoc
*/
cleanErrorStack() {
if (typeof this.stack === "string") {
this.stack = this.stack.split("\n").filter((line) => !line.includes("AjaxError.constructor")).join("\n");
}
}
}
var __defProp$1n = Object.defineProperty;
var __name$1n = (target, value) => __defProp$1n(target, "name", { value, configurable: true });
const MESSAGE_SEPARATOR = " ";
function parseErrorPayload(body, fallbackCode, fallbackDescription) {
if (!body || typeof body !== "object" || !("error" in body)) {
return void 0;
}
const responseData = body;
if (responseData.error && typeof responseData.error === "object" && "code" in responseData.error) {
const error = responseData.error;
let description = String(error.message ?? "").trimEnd();
if (error.validation && error.validation.length > 0) {
const messages = error.validation.map((row) => row?.message || JSON.stringify(row)).filter((message) => message !== void 0 && message !== "");
if (messages.length > 0) {
if (description.length > 0) {
if (!description.endsWith(".")) {
description += ".";
}
description += MESSAGE_SEPARATOR;
}
description += messages.join(MESSAGE_SEPARATOR);
}
}
return {
code: error.code,
description,
// Kept verbatim rather than reshaped: `field` is what the caller came for,
// and the portal is free to add keys the SDK has not seen. The copy is
// what detaches it from the response body; the freeze stops a caller
// reordering or extending the array. Both are **shallow** — the `readonly`
// on each entry's fields is a type-level claim only, and nothing stops a
// caller writing to `validation[0].field` at runtime.
...error.validation ? { validation: Object.freeze([...error.validation]) } : {}
};
}
if (responseData.error && typeof responseData.error === "string") {
return {
code: responseData.error !== "0" ? responseData.error : fallbackCode,
description: responseData?.error_description ?? fallbackDescription
};
}
return void 0;
}
__name$1n(parseErrorPayload, "parseErrorPayload");
var __defProp$1m = Object.defineProperty;
var __name$1m = (target, value) => __defProp$1m(target, "name", { value, configurable: true });
class AjaxResult extends Result {
static {
__name$1m(this, "AjaxResult");
}
_status;
_query;
_data;
constructor(options) {
super();
this._data = options.answer ? Object.freeze(options.answer) : void 0;
this._query = Object.freeze(structuredClone(options.query));
this._status = options.status;
if (options.error) {
this.addError(options.error, "base-error");
} else {
this.#processErrors();
}
}
get isSuccess() {
return this.#getIsSuccess();
}
/**
* @todo test this predicate
*/
#getIsSuccess() {
return this._errors.size === 0;
}
getData() {
if (!this.isSuccess) {
return void 0;
}
const payload = this._data;
return Object.freeze({
result: payload.result,
time: payload.time
});
}
/**
* If the response contains error data, we'll restore it to an error.
*
* The parsing lives in {@link parseErrorPayload}, shared with
* `AbstractHttp._convertAxiosErrorToAjaxError()`. It used to be written out
* here as well, and the two copies had drifted into agreeing on everything
* except that neither read `validation[].field` (#423).
*/
#processErrors() {
const parsed = parseErrorPayload(this._data, "JSSDK_RESPONSE_ERROR", "Some error in response");
if (parsed === void 0) {
return;
}
this.addError(this.#createAjaxError({
code: parsed.code,
description: parsed.description,
status: this._status,
validation: parsed.validation
}), "base-error");
}
#createAjaxError(errorData) {
return new AjaxError({
code: errorData.code,
description: errorData.description,
status: errorData.status,
validation: errorData.validation,
requestInfo: {
method: this._query.method,
params: this._query.params,
requestId: this._query.requestId
}
});
}
/**
* Alias for {@link AjaxResult.isMore}.
*
* `restApi:v2` only — see {@link AjaxResult.isMore} for what this returns on
* a `restApi:v3` response.
*/
hasMore() {
return this.isMore();
}
/**
* Whether the `restApi:v2` envelope carries a `next` offset — i.e. the portal
* has more rows for this query.
*
* **`restApi:v2` only.** `restApi:v3` returns no `next` field, so this returns
* `false` on a v3 response — which is not the same statement as "there are no
* more rows". Do not branch on it for v3; there is nothing to read.
*
* This is a reader for a protocol field, not a deprecated API: it stays for as
* long as `restApi:v2` does, and so does its counterpart
* {@link AjaxResult.getNext} — the two together are the manual `restApi:v2`
* paging loop, and neither is going away. For new code prefer the list
* helpers, which hide the offset bookkeeping and work under both protocol
* versions:
* - `restApi:v2`: `b24.actions.v2.callList.make` or `b24.actions.v2.fetchList.make`
* - `restApi:v3`: `b24.actions.v3.callList.make` or `b24.actions.v3.fetchList.make`
*/
isMore() {
if (!this.isSuccess) {
return false;
}
const payload = this._data;
const nextValue = "next" in payload ? payload.next : void 0;
return Type.isNumber(nextValue);
}
/**
* The row count the `restApi:v2` envelope reports in its `total` field.
*
* **`restApi:v2` only.** `restApi:v3` returns no `total`, so this returns `0`
* on a v3 response — which is not the same statement as "no rows matched".
* Do not read it for v3; use
* `b24.actions.v3.aggregate.make` with `count` / `countDistinct` instead,
* bearing in mind that action is `@experimental` and unverified against a live
* portal.
*
* This is a reader for a protocol field, not a deprecated API. It is the only
* way to obtain a count under `restApi:v2` — the list helpers iterate without
* exposing `total`, {@link SuccessPayload} deliberately omits it, and the
* `aggregate` action exists for `restApi:v3` only. It therefore stays for as
* long as `restApi:v2` does, and is not part of the `3.0.0` removal set.
*
* That is a decision with a trigger, not an open-ended promise. Revisit it
* when either holds: `b24.actions.v3.aggregate` is verified against a live
* portal and loses its `@experimental` tag across the common modules (a v3
* count then exists, and `getTotal()` has a replacement for the first time),
* or Bitrix24 announces a `restApi:v2` sunset date (the field it reads goes
* away regardless). Until one of those happens there is nothing to migrate
* callers to, which is the whole reason it is still here.
*
* Note this trigger is specific to the readers. {@link AjaxResult.getNext} and
* {@link AjaxResult.fetchNext} already have a working replacement, so nothing
* about `aggregate` maturing changes anything for them — a `restApi:v2` sunset
* is their only exit condition.
*/
getTotal() {
if (!this.isSuccess) {
return 0;
}
const payload = this._data;
const totalValue = "total" in payload ? payload.total : void 0;
return Text.toInteger(totalValue);
}
getStatus() {
return this._status;
}
getQuery() {
return this._query;
}
/**
* Alias for {@link AjaxResult.getNext}, returning `null` where that returns
* `false`.
*
* **`restApi:v2` only** — see {@link AjaxResult.getNext}, including the throw
* on a `restApi:v3` client, which this inherits.
*/
async fetchNext(http) {
const data = await this.getNext(http);
if (data === false) {
return null;
}
return data;
}
/**
* Re-runs this result's own query with `params.start` set to the `next` offset
* the `restApi:v2` envelope reported, and resolves to the following page.
* Returns `false` when this result is unsuccessful or has no `next`.
*
* `restApi:v2` only, and permanently so. Unlike the readers above, this one
* acts on the envelope, and `restApi:v3` has no `next` to act on — so it
* throws rather than silently returning `false`, which would be
* indistinguishable from "last page". That throw is not a transitional
* measure; it is the honest answer for a protocol that does not have this
* operation.
*
* For new code prefer `b24.actions.v{2,3}.callList.make` (collect everything)
* or `b24.actions.v{2,3}.fetchList.make` (async generator, one page per
* iteration — the same page-by-page control this gives, without the manual
* offset bookkeeping, and it works under both protocol versions). This method
* is kept because it works under `restApi:v2` and deleting it would break
* running code for no gain, not because it is the better tool.
*
* @throws {SdkError} `JSSDK_CORE_METHOD_NOT_SUPPORT_IN_API_V3` when called against a `restApi:v3` HTTP client.
*/
async getNext(http) {
if (http.apiVersion === ApiVersion.v3) {
throw new SdkError({
code: "JSSDK_CORE_METHOD_NOT_SUPPORT_IN_API_V3",
description: `restApi:v3 not support method getNext`,
status: 500
});
}
if (!this.isSuccess || !this.isMore()) {
return false;
}
const nextPageQuery = this.#buildNextPageQuery();
return http.call(
nextPageQuery.method,
nextPageQuery.params
);
}
#buildNextPageQuery() {
const payload = this._data;
const nextValue = "next" in payload ? payload.next : void 0;
return {
...this._query,
params: { ...this._query.params, start: Text.toInteger(nextValue) }
};
}
// Immutable API
setData() {
throw new ReferenceError("AjaxResult does not allow data modification");
}
}
var __defProp$1l = Object.defineProperty;
var __name$1l = (target, value) => __defProp$1l(target, "name", { value, configurable: true });
class ParamsFactory {
static {
__name$1l(this, "ParamsFactory");
}
/**
* Default parameters for regular tariffs
*
* @see Http.#restrictionParams
*/
static getDefault() {
return {
rateLimit: {
burstLimit: 50,
drainRate: 2,
adaptiveEnabled: true
},
operatingLimit: {
windowMs: 6e5,
// 10 min
limitMs: 48e4,
// 480 sec
heavyPercent: 80
},
adaptiveConfig: {
enabled: true,
thresholdPercent: 80,
coefficient: 0.01,
maxDelay: 7e3
},
maxRetries: 3,
retryDelay: 1e3,
retryOnNetworkError: true
};
}
/**
* Parameters for the Enterprise plan
*/
static getEnterprise() {
return {
...this.getDefault(),
rateLimit: {
burstLimit: 250,
drainRate: 5,
adaptiveEnabled: true
}
};
}
/**
* Parameters for bulk data processing
*/
static getBatchProcessing() {
return {
...this.getDefault(),
rateLimit: {
burstLimit: 30,
drainRate: 1,
adaptiveEnabled: true
},
operatingLimit: {
windowMs: 6e5,
limitMs: 48e4,
heavyPercent: 50
// Higher threshold for notifications
},
adaptiveConfig: {
enabled: true,
thresholdPercent: 50,
// More threshold
coefficient: 0.015,
// More pause
maxDelay: 1e4
// Max 10 seconds
},
maxRetries: 5
// More attempts
};
}
/**
* Real-time parameters
*/
static getRealtime() {
return {
...this.getDefault(),
adaptiveConfig: {
enabled: false,
// Off
thresholdPercent: 100,
coefficient: 1e-3,
maxDelay: 48e4
},
maxRetries: 1
};
}
/**
* Tariff plan based parameters
*/
static fromTariffPlan(plan) {
switch (plan.toLowerCase()) {
case "enterprise":
return this.getEnterprise();
case "company":
case "start":
case "standard":
case "basic":
default:
return this.getDefault();
}
}
}
var __defProp$1k = Object.defineProperty;
var __name$1k = (target, value) => __defProp$1k(target, "name", { value, configurable: true });
class RateLimiter {
static {
__name$1k(this, "RateLimiter");
}
#tokens;
#lastRefill;
#refillIntervalMs;
#config;
#lockQueue = [];
#originalConfig;
// Original configuration for recovery
#errorThreshold = 5;
// 60-second error threshold to reduce limits
#successThreshold = 20;
// Consecutive success threshold for restoring limits
#minDrainRate = 0.5;
// Minimum drain rate
#minBurstLimit = 5;
// Minimum burst limit
#errorTimestamps = [];
// Error timestamps (last 60 seconds)
#successTimestamps = [];
// Timestamps of successful requests
_logger;
constructor(config) {
this._logger = LoggerFactory.createNullLogger();
this.#config = config;
this.#originalConfig = { ...config };
this.#tokens = config.burstLimit;
this.#lastRefill = Date.now();
this.#refillIntervalMs = 1e3 / config.drainRate;
}
getTitle() {
return "rateLimiter";
}
// region Logger ////
setLogger(logger) {
this._logger = logger;
}
getLogger() {
return this._logger;
}
// endregion ////
/**
* @inheritDoc
*/
async canProceed(requestId, _method, _params) {
await this.#acquireLock(requestId);
try {
const now = Date.now();
const timePassed = now - this.#lastRefill;
const refillAmount = timePassed * this.#config.drainRate / 1e3;
this.#tokens = Math.min(
this.#config.burstLimit,
this.#tokens + refillAmount
);
this.#lastRefill = now;
return this.#tokens >= 1;
} finally {
this.#releaseLock();
}
}
/**
* @inheritDoc
*/
async waitIfNeeded(requestId, _method, _params) {
await this.#acquireLock(requestId);
try {
const now = Date.now();
const timePassed = now - this.#lastRefill;
const refillAmount = timePassed * this.#config.drainRate / 1e3;
this.#tokens = Math.min(
this.#config.burstLimit,
this.#tokens + refillAmount
);
this.#lastRefill = now;
if (this.#tokens >= 1) {
this.#tokens -= 1;
return 0;
}
const deficit = 1 - this.#tokens;
return Math.ceil(deficit * this.#refillIntervalMs);
} finally {
this.#releaseLock();
}
}
/**
* Error handler.
* If there are a lot of errors, we'll lower the limits.
*/
async handleExceeded(requestId) {
await this.#acquireLock(requestId);
try {
this.#recordError();
if (this.#config.adaptiveEnabled && this.#shouldReduceLimits()) {
this.#reduceLimits(requestId);
}
this.#tokens = 0;
return this.#refillIntervalMs + 1e3;
} finally {
this.#releaseLock();
}
}
/**
* Successful request handler.
* If everything is OK, we'll restore the limits.
*/
async updateStats(requestId, method, _data) {
if (method.startsWith("batch::")) {
return;
}
await this.#acquireLock(requestId);
try {
this.#recordSuccess();
if (this.#config.adaptiveEnabled) {
this.#logStat(requestId);
}
if (this.#config.adaptiveEnabled && this.#shouldRestoreLimits()) {
this.#restoreLimits(requestId);
}
} finally {
this.#releaseLock();
}
}
/**
* @inheritDoc
*/
async reset() {
await this.#acquireLock("reset");
try {
this.#tokens = this.#config.burstLimit;
this.#lastRefill = Date.now();
this.#errorTimestamps = [];
this.#successTimestamps = [];
this.#config.drainRate = this.#originalConfig.drainRate;
this.#config.burstLimit = this.#originalConfig.burstLimit;
this.#refillIntervalMs = 1e3 / this.#config.drainRate;
} finally {
this.#releaseLock();
}
}
/**
* @inheritDoc
*/
getStats() {
return {
tokens: this.#tokens,
burstLimit: this.#config.burstLimit,
originalBurstLimit: this.#originalConfig.burstLimit,
drainRate: this.#config.drainRate,
originalDrainRate: this.#originalConfig.drainRate,
refillIntervalMs: this.#refillIntervalMs,
lastRefill: this.#lastRefill,
pendingRequests: this.#lockQueue.length,
recentErrors: this.#errorTimestamps.length,
recentSuccesses: this.#successTimestamps.length
};
}
/**
* @inheritDoc
*/
async setConfig(config) {
await this.#acquireLock("setConfig");
try {
this.#config = config;
this.#originalConfig = { ...config };
this.#refillIntervalMs = 1e3 / this.#config.drainRate;
if (config.burstLimit > this.#tokens) {
this.#tokens = Math.min(config.burstLimit, this.#tokens);
}
this.#errorTimestamps = [];
this.#successTimestamps = [];
} finally {
this.#releaseLock();
}
}
/**
* Acquire a lock for the critical section
* Uses a promise queue
*/
async #acquireLock(requestId) {
return new Promise((resolve) => {
const queueLength = this.#lockQueue.push(resolve);
if (queueLength > 1) {
this.#logAcquireQueue(requestId, queueLength);
}
if (this.#lockQueue.length === 1) {
resolve();
}
});
}
/**
* Releases the lock and allows the next person in the queue to proceed
*/
#releaseLock() {
this.#lockQueue.shift();
if (this.#lockQueue.length > 0) {
const nextResolve = this.#lockQueue[0];
nextResolve();
}
}
/**
* Checks whether the limits need to be reduced
*/
#shouldReduceLimits() {
return this.#errorTimestamps.length >= this.#errorThreshold;
}
/**
* Checks whether limits need to be restored
* Restore if:
* 1. Many successful requests (more than the threshold)
* 2. Few errors (less than half the threshold)
* 3. Current limits are lower than the original ones
*/
#shouldRestoreLimits() {
return this.#successTimestamps.length >= this.#successThreshold && this.#errorTimestamps.length < this.#errorThreshold / 2 && (this.#config.drainRate < this.#originalConfig.drainRate || this.#config.burstLimit < this.#originalConfig.burstLimit);
}
/**
* Reduces limits for frequent errors
*/
#reduceLimits(requestId) {
const newDrainRate = Math.max(
this.#minDrainRate,
Number.parseFloat((this.#config.drainRate * 0.8).toFixed(2))
);
const newBurstLimit = Math.max(
this.#minBurstLimit,
Number.parseFloat((this.#config.burstLimit * 0.8).toFixed(2))
);
this.#config.drainRate = newDrainRate;
this.#config.burstLimit = newBurstLimit;
this.#refillIntervalMs = 1e3 / newDrainRate;
this.#logReduceLimits(requestId, newDrainRate, newBurstLimit);
this.#errorTimestamps = [];
this.#successTimestamps = [];
}
/**
* Restores limits during stable operation
*/
#restoreLimits(requestId) {
if (this.#config.drainRate === this.#originalConfig.drainRate && this.#config.burstLimit === this.#originalConfig.burstLimit) {
return;
}
const newDrainRate = Math.min(
this.#originalConfig.drainRate,
Number.parseFloat((this.#config.drainRate * 1.1).toFixed(2))
);
const newBurstLimit = Math.min(
this.#originalConfig.burstLimit,
Number.parseFloat((this.#config.burstLimit * 1.1).toFixed(2))
);
this.#config.drainRate = newDrainRate;
this.#config.burstLimit = newBurstLimit;
this.#refillIntervalMs = 1e3 / newDrainRate;
this.#logRestoreLimits(requestId, newDrainRate, newBurstLimit);
this.#errorTimestamps = [];
this.#successTimestamps = [];
}
/**
* Writes an error to the temporary history
*/
#recordError() {
const now = Date.now();
this.#errorTimestamps.push(now);
this.#successTimestamps = [];
this.#cleanupOldErrors(now);
}
/**
* Clears old errors (older than 60 seconds)
*/
#cleanupOldErrors(now) {
const cutoff = now - 6e4;
this.#errorTimestamps = this.#errorTimestamps.filter((timestamp) => timestamp > cutoff);
}
/**
* Writes a successful request to the temporary history
*/
#recordSuccess() {
const now = Date.now();
this.#successTimestamps.push(now);
this.#cleanupOldSuccesses();
this.#cleanupOldErrors(now);
}
/**
* Clears old progress
*/
#cleanupOldSuccesses() {
this.#successTimestamps = this.#successTimestamps.slice(-1 * this.#successThreshold);
}
// region Log ////
#logReduceLimits(requestId, currentDrainRate, currentBurstLimit) {
const originalDrainRate = this.#originalConfig.drainRate;
const drainRateCondition = currentDrainRate < originalDrainRate;
const originalBurstLimit = this.#originalConfig.burstLimit;
const burstLimitCondition = currentBurstLimit < originalBurstLimit;
this.getLogger().warning(
`${this.getTitle()} is lowering limits due to frequent errors`,
{
requestId,
drainRate: {
current: currentDrainRate,
original: originalDrainRate,
condition: drainRateCondition,
formatted: `(${currentDrainRate} < ${originalDrainRate}) ${drainRateCondition}`
},
burstLimit: {
current: currentBurstLimit,
original: originalBurstLimit,
condition: burstLimitCondition,
formatted: `(${currentBurstLimit} < ${originalBurstLimit}) ${burstLimitCondition}`
}
}
).catch(() => {
});
}
#logRestoreLimits(requestId, currentDrainRate, currentBurstLimit) {
const originalDrainRate = this.#originalConfig.drainRate;
const drainRateCondition = currentDrainRate < originalDrainRate;
const originalBurstLimit = this.#originalConfig.burstLimit;
const burstLimitCondition = currentBurstLimit < originalBurstLimit;
this.getLogger().warning(
`${this.getTitle()} increases limits during stable operation`,
{
requestId,
drainRate: {
current: currentDrainRate,
original: originalDrainRate,
condition: drainRateCondition,
formatted: `(${currentDrainRate} < ${originalDrainRate}) ${drainRateCondition}`
},
burstLimit: {
current: currentBurstLimit,
original: originalBurstLimit,
condition: burstLimitCondition,
formatted: `(${currentBurstLimit} < ${originalBurstLimit}) ${burstLimitCondition}`
}
}
).catch(() => {
});
}
#logAcquireQueue(requestId, queueLength) {
this.getLogger().debug(`${this.getTitle()} request in queue`, {
requestId,
queueLength
}).catch(() => {
});
}
#logStat(requestId) {
const successCount = this.#successTimestamps.length;
const successThreshold = this.#successThreshold;
const successCondition = successCount >= successThreshold;
const errorCount = this.#errorTimestamps.length;
const errorThreshold = this.#errorThreshold;
const failCondition = errorCount < errorThreshold / 2;
const currentDrainRate = this.#config.drainRate;
const originalDrainRate = this.#originalConfig.drainRate;
const drainRateCondition = currentDrainRate < originalDrainRate;
const currentBurstLimit = this.#config.burstLimit;
const originalBurstLimit = this.#originalConfig.burstLimit;
const burstLimitCondition = currentBurstLimit < originalBurstLimit;
this.getLogger().debug(`${this.getTitle()} state`, {
requestId,
success: {
count: successCount,
threshold: successThreshold,
condition: successCondition,
formatted: `(${successCount} >= ${successThreshold}) ${successCondition}`
},
fail: {
count: errorCount,
threshold: errorThreshold / 2,
condition: failCondition,
formatted: `(${errorCount} < ${errorThreshold / 2}) ${failCondition}`
},
drainRate: {
current: currentDrainRate,
original: originalDrainRate,
condition: drainRateCondition,
formatted: `(${currentDrainRate} < ${originalDrainRate}) ${drainRateCondition}`
},
burstLimit: {
current: currentBurstLimit,
original: originalBurstLimit,
condition: burstLimitCondition,
formatted: `(${currentBurstLimit} < ${originalBurstLimit}) ${burstLimitCondition}`
}
}).catch(() => {
});
}
// endregion ////
}
var __defProp$1j = Object.defineProperty;
var __name$1j = (target, value) => __defProp$1j(target, "name", { value, configurable: true });
class OperatingLimiter {
static {
__name$1j(this, "OperatingLimiter");
}
#config;
#methodStats = /* @__PURE__ */ new Map();
#stats = {
/** Heavy requests */
heavyRequestCount: 0
};
_logger;
getTitle() {
return "operatingLimiter";
}
constructor(config) {
this._logger = LoggerFactory.createNullLogger();
this.#config = config;
}
// region Logger ////
setLogger(logger) {
this._logger = logger;
}
getLogger() {
return this._logger;
}
// endregion ////
get limitMs() {
return this.#config.limitMs;
}
getMethodStat(method) {
const stats = this.#methodStats.get(method);
if (!stats) {
return void 0;
}
return stats;
}
async canProceed(requestId, method, params) {
const timeToFree = await this.getTimeToFree(requestId, method, params);
return timeToFree === 0;
}
async waitIfNeeded(requestId, method, params) {
return this.getTimeToFree(requestId, method, params);
}
/**
* Returns the time until the method's operating limit is released (in ms)
* The analysis is based on the previous function call.
* It's important to understand that we're talking about locks of up to 10 minutes.
* This is a fairly strict lock based on the limit:
* - not reached - no lock
* - reached - lock until the unlock time + 1 second
*/
async getTimeToFree(requestId, method, params, _error) {
this.#cleanupOldStats();
if (method === "batch") {
return this.#getTimeToFreeBatch(requestId, params);
}
const stats = this.#methodStats.get(method);
if (!stats) {
return 0;
}
const limitWithBuffer = Math.max(1e3, this.#config.limitMs - 5e3);
if (stats.operating >= limitWithBuffer) {
const now = Date.now();
if (stats.operating_reset_at > now) {
return stats.operating_reset_at - now + 1e3;
}
return 5e3;
}
return 0;
}
/**
* For `batch` commands, returns the maximum time until the method reaches the operating limit (in ms)
*/
async #getTimeToFreeBatch(requestId, params) {
let maxWait = 0;
if (!params?.cmd || !Array.isArray(params.cmd)) {
return maxWait;
}
const batchMethods = params.cmd.map((row) => row.split("?")[0]).filter(Boolean);
for (const methodName of batchMethods) {
const waitTime = await this.getTimeToFree(requestId, `batch::${methodName}`, {});
maxWait = Math.max(maxWait, waitTime);
}
return maxWait;
}
/**
* Updates operating time statistics for the method
*/
async updateStats(requestId, method, data) {
this.#cleanupOldStats();
const { operating, operating_reset_at } = data;
if (operating === void 0 || operating === null) {
return;
}
if (!this.#methodStats.has(method)) {
this.#methodStats.set(method, {
operating: 0,
operating_reset_at: 0,
lastUpdated: Date.now()
});
}
const stats = this.#methodStats.get(method);
stats.operating = operating * 1e3;
stats.operating_reset_at = operating_reset_at * 1e3;
stats.lastUpdated = Date.now();
const usagePercent = stats.operating / this.#config.limitMs * 100;
if (usagePercent > this.#config.heavyPercent) {
this.#stats.heavyRequestCount++;
this.#logStat(requestId, method, usagePercent, stats.operating);
}
}
/**
* Clearing outdated operating limit data
*/
#cleanupOldStats() {
const now = Date.now();
const maxAge = this.#config.windowMs + 1e4;
for (const [method, stats] of this.#methodStats.entries()) {
if (now - stats.lastUpdated > maxAge) {
this.#methodStats.delete(method);
}
}
}
async reset() {
this.#methodStats.clear();
this.#stats = {
heavyRequestCount: 0
};
}
getStats() {
const operatingStats = {};
for (const [method, stats] of this.#methodStats.entries()) {
operatingStats[method] = Number.parseFloat((stats.operating / 1e3).toFixed(2));
}
return {
...this.#stats,
operatingStats
};
}
async setConfig(config) {
this.#config = config;
}
// region Log ////
#logStat(requestId, method, percent, operating) {
this.getLogger().debug(`${this.getTitle()} detected limit for method ${method}`, {
requestId,
method,
operating: {
percent: Number.parseFloat(percent.toFixed(2)),
current: Number.parseFloat((operating / 1e3).toFixed(0)),
max: Number.parseFloat((this.#config.limitMs / 1e3).toFixed(0))
}
}).catch(() => {
});
}
// endregion ////
}
var __defProp$1i = Object.defineProperty;
var __name$1i = (target, value) => __defProp$1i(target, "name", { value, configurable: true });
class AdaptiveDelayer {
static {
__name$1i(this, "AdaptiveDelayer");
}
#config;
#operatingLimiter;
#stats = {
adaptiveDelays: 0,
totalAdaptiveDelay: 0
};
_logger;
getTitle() {
return "adaptiveDelayer";
}
constructor(config, operatingLimiter) {
this._logger = LoggerFactory.createNullLogger();
this.#config = config;
this.#operatingLimiter = operatingLimiter;
}
// region Logger ////
setLogger(logger) {
this._logger = logger;
}
getLogger() {
return this._logger;
}
// endregion ////
async canProceed(_requestId, _method, _params) {
return true;
}
/**
* Returns an adaptive delay based on previous experience
*/
async waitIfNeeded(requestId, method, params) {
if (!this.#config.enabled) {
return 0;
}
const delay = this.#calculateDelay(requestId, method, params);
if (delay > 0) {
this.incrementAdaptiveDelays();
this.#stats.totalAdaptiveDelay += delay;
}
return delay;
}
/**
* Calculates adaptive delay based on previous experience
*/
#calculateDelay(requestId, method, params) {
if (method === "batch") {
return this.#calculateBatchDelay(requestId, params);
}
const stats = this.#operatingLimiter.getMethodStat(method);
if (typeof stats === "undefined") {
return 0;
}
const usagePercent = stats.operating / this.#operatingLimiter.limitMs * 100;
if (usagePercent > this.#config.thresholdPercent) {
let adaptiveDelay = 0;
const now = Date.now();
if (stats.operating_reset_at > now) {
adaptiveDelay += (stats.operating_reset_at - now) * this.#config.coefficient;
} else {
adaptiveDelay += 7e3;
}
const waitDelay = Number.parseInt(Math.min(adaptiveDelay, this.#config.maxDelay).toFixed(0));
this.#logStat(requestId, method, usagePercent, adaptiveDelay, waitDelay);
return waitDelay;
}
return 0;
}
/**
* For `batch`, applies adaptive delay based on previous experience from commands
*/
#calculateBatchDelay(requestId, params) {
let maxDelay = 0;
if (!params?.cmd || !Array.isArray(params.cmd)) {
return maxDelay;
}
const batchMethods = params.cmd.map((row) => row.split("?")[0]).filter(Boolean);
const batchMethodsUnique = [...new Set(batchMethods)];
for (const methodName of batchMethodsUnique) {
const delay = this.#calculateDelay(requestId, `batch::${methodName}`, {});
maxDelay = Math.max(maxDelay, delay);
}
return maxDelay;
}
async updateStats(_requestId, _method, _data) {
}
async reset() {
this.#stats = {
adaptiveDelays: 0,
totalAdaptiveDelay: 0
};
}
getStats() {
return {
...this.#stats,
adaptiveDelayAvg: this.#stats.adaptiveDelays > 0 ? this.#stats.totalAdaptiveDelay / this.#stats.adaptiveDelays : 0
};
}
async setConfig(config) {
this.#config = config;
}
incrementAdaptiveDelays() {
this.#stats.adaptiveDelays++;
}
// region Log ////
#logStat(requestId, method, percent, adaptiveDelay, waitDelay) {
this.getLogger().debug(`${this.getTitle()} state for method ${method}`, {
requestId,
method,
percent: Number.parseFloat(percent.toFixed(2)),
delays: {
calculated: adaptiveDelay,
actual: waitDelay
}
}).catch(() => {
});
}
// endregion ////
}
var __defProp$1h = Object.defineProperty;
var __name$1h = (target, value) => __defProp$1h(target, "name", { value, configurable: true });
class RestrictionManager {
static {
__name$1h(this, "RestrictionManager");
}
#rateLimiter;
#operatingLimiter;
#adaptiveDelayer;
#config;
#stats = {
/** Retry attempts */
retries: 0,
/** Consecutive errors */
consecutiveErrors: 0,
/** Limit triggers */
limitHits: 0
};
#errorCounts = /* @__PURE__ */ new Map();
_logger;
constructor(params) {
this._logger = LoggerFactory.createNullLogger();
this.#config = params;
this.#rateLimiter = new RateLimiter(params.rateLimit);
this.#operatingLimiter = new OperatingLimiter(params.operatingLimit);
this.#adaptiveDelayer = new AdaptiveDelayer(params.adaptiveConfig, this.#operatingLimiter);
}
// region Logger ////
setLogger(logger) {
this._logger = logger;
this.#rateLimiter.setLogger(this._logger);
this.#operatingLimiter.setLogger(this._logger);
this.#adaptiveDelayer.setLogger(this._logger);
}
getLogger() {
return this._logger;
}
// endregion ////
async applyOperatingLimits(requestId, method, params) {
const operatingWait = await this.#operatingLimiter.waitIfNeeded(requestId, method, params);
if (operatingWait > 0) {
this.incrementStats("limitHits");
this.#logMethodBlocked(this.#operatingLimiter.getTitle(), requestId, method, operatingWait);
await this.#delay(operatingWait);
} else {
const adaptiveDelay = await this.#adaptiveDelayer.waitIfNeeded(requestId, method, params);
if (adaptiveDelay > 0) {
this.incrementStats("limitHits");
this.#logMethodBlocked(this.#adaptiveDelayer.getTitle(), requestId, method, adaptiveDelay);
await this.#delay(adaptiveDelay);
}
}
}
/**
* Checks and waits for the rate limit
* The loop is needed for parallel requests (Promise.all())
*/
async checkRateLimit(requestId, method) {
let waitTime;
let times = 1;
do {
waitTime = await this.#rateLimiter.waitIfNeeded(requestId, method);
if (waitTime > 0) {
this.incrementStats("limitHits");
this.#logMethodBlockedWithTimes(this.#rateLimiter.getTitle(), requestId, method, waitTime, times);
await this.#delay(waitTime);
times++;
}
} while (waitTime > 0);
}
async updateStats(requestId, method, timeData) {
await this.#operatingLimiter.updateStats(requestId, method, timeData);
await this.#adaptiveDelayer.updateStats(requestId, method, timeData);
await this.#rateLimiter.updateStats(requestId, method, timeData);
}
async handleError(requestId, method, params, error, attempt) {
if (this.#isRateLimitError(error)) {
const wait = await this.#handleRateLimitExceeded(requestId) * Math.pow(1.5, attempt);
this.#logError(this.#rateLimiter.getTitle(), requestId, "QUERY_LIMIT_EXCEEDED", error.message, method, wait);
return wait;
}
if (this.#isOperatingLimitError(error)) {
const wait = Math.max(1e4, await this.#handleOperatingLimitError(requestId, method, params, error));
this.#logError(this.#operatingLimiter.getTitle(), requestId, "OPERATION_TIME_LIMIT", error.message, method, wait);
return wait;
}
if (this.#isNonRetryableClientError(error)) {
this.#logNonRetryableClientError(requestId, error?.code ? `${error.code}` : "?", error?.message ?? "", method, Number(error?.status ?? 0));
return 0;
}
if (!this.#isNeedThrowError(error)) {
const baseDelay = await this.#getErrorBackoff(requestId);
const maxDelay = Math.max(3e4, baseDelay);
const delay = Math.min(maxDelay, baseDelay * Math.pow(2, attempt));
const jitter = delay * 0.1 * (Math.random() * 2 - 1);
const wait = Math.max(100, delay + jitter);
this.#logSomeError(requestId, error?.code ? `${error.code}` : "?", error.message, method, wait);
return wait;
}
return 0;
}
/**
* Checks if the error is a rate limit
*/
#isRateLimitError(error) {
return error.status === 503 || error.code === "QUERY_LIMIT_EXCEEDED";
}
/**
* Delay when exceeding the rate limit
*/
async #handleRateLimitExceeded(requestId) {
return this.#rateLimiter.handleExceeded(requestId);
}
/**
* Checks if the error is an operating limit
*
* @memo `OPERATION_TIME_LIMIT` && `429` - obtained through practical means
* @memo This doesn't work for `batch` queries.
*/
#isOperatingLimitError(error) {
return error.status === 429 || error.code === "OPERATION_TIME_LIMIT";
}
/**
* Operating limit error delay
*
* @memo Currently, the errors don't include timings for operations.
* For this reason, we will take data from the previous request
*/
async #handleOperatingLimitError(requestId, method, params, _error) {
return this.#operatingLimiter.getTimeToFree(requestId, method, params, _error);
}
/**
* Checks if the error is a non-retryable client error (HTTP 4xx).
*
* `429` is excluded — it is handled as a rate/operating limit and is retried
* with backoff. `408` (request timeout) is excluded — it is transient and is
* governed by `retryOnNetworkError`.
*/
#isNonRetryableClientError(error) {
const status = Number(error?.status ?? 0);
if (Number.isNaN(status)) {
return false;
}
return status >= 400 && status < 500 && status !== 408 && status !== 429;
}
/**
* Checks whether attempts should be stopped if errors are encountered that are unclear.
*/
#isNeedThrowError(error) {
const answerError = {
code: error?.code ?? "-1",
description: error?.message ?? ""
};
return [
...this.exceptionCodeForHard,
...this.exceptionCodeForSoft
].includes(answerError.code) || (answerError.description ?? "").includes("Could not find value for parameter");
}
/**
* Built-in hard error codes (always throw, never retry).
*
* Includes authorization and fatal codes that must never be silently retried.
* Use `RestrictionParams.hardErrorCodes` to extend this list with custom codes.
*/
static BUILT_IN_HARD_ERROR_CODES = [
"ERR_BAD_REQUEST",
"JSSDK_UNKNOWN_ERROR",
"100",
"INTERNAL_SERVER_ERROR",
"ERROR_UNEXPECTED_ANSWER",
"PORTAL_DELETED",
"ERROR_BATCH_METHOD_NOT_ALLOWED",
"ERROR_BATCH_LENGTH_EXCEEDED",
"NO_AUTH_FOUND",
"INVALID_REQUEST",
"OVERLOAD_LIMIT",
"expired_token",
"invalid_token",
"ACCESS_DENIED",
"INVALID_CREDENTIALS",
"user_access_error",
"insufficient_scope",
"ERROR_MANIFEST_IS_NOT_AVAILABLE",
"allowed_only_intranet_user",
"NOT_FOUND",
"INVALID_ARG_VALUE"
];
/**
* Built-in soft error codes (returned as `AjaxResult` with error, never thrown).
*
* Use `RestrictionParams.softErrorCodes` to extend this list with custom codes.
*/
static BUILT_IN_SOFT_ERROR_CODES = [
"ERROR_ENTITY_NOT_FOUND",
"BITRIX_REST_V3_EXCEPTION_ACCESSDENIEDEXCEPTION",
"BITRIX_REST_V3_EXCEPTION_INVALIDJSONEXCEPTION",
"BITRIX_REST_V3_EXCEPTION_INVALIDFILTEREXCEPTION",
"BITRIX_REST_V3_EXCEPTION_INVALIDSELECTEXCEPTION",
"BITRIX_REST_V3_EXCEPTION_ENTITYNOTFOUNDEXCEPTION",
"BITRIX_REST_V3_EXCEPTION_METHODNOTFOUNDEXCEPTION",
"BITRIX_REST_V3_EXCEPTION_UNKNOWNDTOPROPERTYEXCEPTION",
"BITRIX_REST_V3_EXCEPTION_VALIDATION_REQUESTVALIDATIONEXCEPTION",
"BITRIX_REST_V3_EXCEPTION_VALIDATION_DTOVALIDATIONEXCEPTION"
];
/**
* Codes that cause the SDK to throw immediately.
*
* Composed of:
* - `BUILT_IN_HARD_ERROR_CODES` (always included)
* - `NETWORK_ERROR` and `REQUEST_TIMEOUT` when `retryOnNetworkError === false`
* - `RestrictionParams.hardErrorCodes` (user-provided extensions)
*/
get exceptionCodeForHard() {
const codes = [...RestrictionManager.BUILT_IN_HARD_ERROR_CODES];
if (this.#config.retryOnNetworkError === false) {
codes.push("NETWORK_ERROR", "REQUEST_TIMEOUT");
}
if (this.#config.hardErrorCodes && this.#config.hardErrorCodes.length > 0) {
codes.push(...this.#config.hardErrorCodes);
}
return codes;
}
/**
* Codes returned as `AjaxResult` with an `AjaxError` payload instead of thrown.
*
* Composed of:
* - `BUILT_IN_SOFT_ERROR_CODES` (always included)
* - `RestrictionParams.softErrorCodes` (user-provided extensions)
*/
get exceptionCodeForSoft() {
const codes = [...RestrictionManager.BUILT_IN_SOFT_ERROR_CODES];
if (this.#config.softErrorCodes && this.#config.softErrorCodes.length > 0) {
codes.push(...this.#config.softErrorCodes);
}
return codes;
}
/**
* Delay due to unknown errors
*/
async #getErrorBackoff(_requestId) {
return this.#config.retryDelay;
}
incrementError(method) {
const current = this.#errorCounts.get(method) || 0;
this.#errorCounts.set(method, current + 1);
this.incrementStats("consecutiveErrors");
}
resetErrors(method) {
this.#errorCounts.delete(method);
this.#stats.consecutiveErrors = 0;
}
incrementStats(stat) {
this.#stats[stat]++;
}
/**
* Returns job statistics
*/
getStats() {
return {
...this.#stats,
...this.#rateLimiter.getStats(),
...this.#adaptiveDelayer.getStats(),
...this.#operatingLimiter.getStats(),
errorCounts: Object.fromEntries(this.#errorCounts)
};
}
/**
* Resets limiters and statistics
*/
async reset() {
await this.#rateLimiter.reset();
await this.#operatingLimiter.reset();
await this.#adaptiveDelayer.reset();
this.#errorCounts.clear();
this.#stats = {
retries: 0,
consecutiveErrors: 0,
limitHits: 0
};
}
async setConfig(params) {
this.#config = params;
await this.#rateLimiter.setConfig(params.rateLimit);
await this.#operatingLimiter.setConfig(params.operatingLimit);
await this.#adaptiveDelayer.setConfig(params.adaptiveConfig);
}
getParams() {
return { ...this.#config };
}
/**
* Delay function
*/
async #delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
/**
* Public access to the delay function
*/
async waiteDelay(ms) {
return this.#delay(ms);
}
// region Log ////
#logMethodBlocked(limiter, requestId, method, wait) {
this.getLogger().notice(`${limiter} blocked method ${method}`, {
requestId,
method,
wait,
limiter
}).catch(() => {
});
}
#logMethodBlockedWithTimes(limiter, requestId, method, wait, times) {
this.getLogger().notice(`${limiter} blocked method ${method} | ${times} times`, {
requestId,
method,
times,
wait,
limiter
}).catch(() => {
});
}
#logError(limiter, requestId, code, message, method, wait) {
this.getLogger().error(`${limiter} recognized the ${code} error for the ${method} method`, {
requestId,
method,
wait,
limiter,
error: {
code,
message
}
}).catch(() => {
});
}
#logSomeError(requestId, code, message, method, wait) {
this.getLogger().error(`recognized the ${code} error for the ${method} method`, {
requestId,
method,
wait,
error: {
code,
message
}
}).catch(() => {
});
}
#logNonRetryableClientError(requestId, code, message, method, status) {
this.getLogger().error(`client error ${status} (${code}) for the ${method} method is not retryable`, {
requestId,
method,
status,
error: {
code,
message
}
}).catch(() => {
});
}
// endregion ////
}
var __defProp$1g = Object.defineProperty;
var __name$1g = (target, value) => __defProp$1g(target, "name", { value, configurable: true });
class VersionManager {
static {
__name$1g(this, "VersionManager");
}
static create() {
return new VersionManager();
}
/**
* List of supported API versions.
* The highest version must be first.
*/
getAllApiVersions() {
return [ApiVersion.v3, ApiVersion.v2];
}
/**
* Retained for backward compatibility. The SDK no longer keeps a v3 method
* allowlist, so support is not decided client-side any more — always returns
* `true`. Method existence is validated by the server.
*/
isSupport(_version, _method) {
return true;
}
/**
* Returns the API version to use when the caller did not specify one. With the
* allowlist removed there is no client-side signal that a method is a v3
* method, so this defaults to v2 (the universal endpoint). Use the explicit
* `actions.v3.*` surface to call a method on v3.
*/
automaticallyObtainApiVersion(_method) {
return ApiVersion.v2;
}
/**
* Batch counterpart of {@link automaticallyObtainApiVersion}. Defaults to v2;
* call `actions.v3.batch.make` explicitly to run a batch on v3.
*/
automaticallyObtainApiVersionForBatch(_calls) {
return ApiVersion.v2;
}
}
const versionManager = VersionManager.create();
var __defProp$1f = Object.defineProperty;
var __name$1f = (target, value) => __defProp$1f(target, "name", { value, configurable: true });
const LOG_METHODS = [
"log",
"debug",
"info",
"notice",
"warning",
"error",
"critical",
"alert",
"emergency"
];
function warnOnNonPromiseLogger(logger, source) {
if (logger === null || typeof logger !== "object") {
console.warn(
`[b24jssdk] ${source}: the value passed to setLogger() is not an object. Expected an implementation of LoggerInterface.`
);
return;
}
const missing = LOG_METHODS.filter((name) => typeof logger[name] !== "function");
if (missing.length > 0) {
console.warn(
`[b24jssdk] ${source}: the logger passed to setLogger() is missing ${missing.join(", ")}. LoggerInterface declares every level as Promise<void>; the SDK calls them fire-and-forget, so a missing or non-promise method raises a TypeError at the callsite.`
);
}
}
__name$1f(warnOnNonPromiseLogger, "warnOnNonPromiseLogger");
var __defProp$1e = Object.defineProperty;
var __name$1e = (target, value) => __defProp$1e(target, "name", { value, configurable: true });
class AbstractAction {
static {
__name$1e(this, "AbstractAction");
}
_b24;
_logger;
constructor(b24, logger) {
this._b24 = b24;
this._logger = logger;
}
/**
* Warns when an option that belongs inside a nested bag was passed at the top
* level, where it is read by nobody.
*
* The action option types no longer carry an index signature, so a TypeScript
* caller writing an object literal gets a compile error instead. This covers
* everyone else: JavaScript callers, a literal widened through a variable, and
* anything crossing a `JSON.parse` boundary. Without it the call simply
* behaves as though the flag were never set — and a dropped
* `returnAjaxResult` turns a batch where every command succeeded into one that
* reads as wholly failed, because `isSuccess` on a raw payload is `undefined`
* (#426).
*
* @param options the argument as received
* @param nestedKeys names that belong in the nested bag
* @param nestedName the bag they belong in, for the message
*/
_warnMisplacedOptions(options, nestedKeys, nestedName) {
if (!options) return;
const misplaced = nestedKeys.filter((key) => Object.hasOwn(options, key));
if (misplaced.length === 0) return;
this._logger.warning(
`[b24jssdk] ${misplaced.join(", ")} passed at the top level ${misplaced.length === 1 ? "is" : "are"} ignored \u2014 ${misplaced.length === 1 ? "it belongs" : "they belong"} in \`${nestedName}\`. Write \`${nestedName}: { ${misplaced.join(", ")} }\`.`
).catch(() => {
});
}
}
var __defProp$1d = Object.defineProperty;
var __name$1d = (target, value) => __defProp$1d(target, "name", { value, configurable: true });
class CallV2 extends AbstractAction {
static {
__name$1d(this, "CallV2");
}
/**
* Calls the Bitrix24 REST API method.
*
* @template T - The expected data type in the response (default is `unknown`).
*
* @param {ActionCallV2} options - parameters for executing the request.
* - `method: string` - REST API method name (eg: `crm.item.get`)
* - `params?: TypeCallParamsV2` - Parameters for calling the method.
* - `requestId?: string` - Unique request identifier for tracking. Used for query deduplication and debugging.
*
* @returns {Promise<AjaxResult<T>>} A promise that resolves to the result of an REST API call.
*
* @example
* import { EnumCrmEntityTypeId } from '@bitrix24/b24jssdk'
*
* interface CrmItem { id: number, name: string, lastName: string }
* const response = await b24.actions.v2.call.make<{ item: CrmItem }>({
* method: 'crm.item.get',
* params: {
* entityTypeId: EnumCrmEntityTypeId.contact,
* id: 123
* },
* requestId: 'item-123'
* })
* if (!response.isSuccess) {
* throw new Error(`Problem: ${response.getErrorMessages().join('; ')}`)
* }
* console.log(response.getData().result.item.name)
*/
async make(options) {
const params = options.params || {};
return this._b24.getHttpClient(ApiVersion.v2).call(options.method, params, options.requestId);
}
}
var __defProp$1c = Object.defineProperty;
var __name$1c = (target, value) => __defProp$1c(target, "name", { value, configurable: true });
class CallListV2 extends AbstractAction {
static {
__name$1c(this, "CallListV2");
}
/**
* Fast data retrieval without counting the total number of records.
*
* @template T - The type of the elements of the returned array (default is `unknown`).
*
* @param {ActionCallListV2} options - parameters for executing the request.
* - `method: string` - The name of the REST API method that returns a list of data (for example: `crm.item.list`, `tasks.task.list`)
* - `params?: Omit<TypeCallParamsV2, 'start' | 'order'>` - Request parameters, excluding the `start` and `order` parameters,
* since the method is designed to obtain all data in one call.
* Note: Use `filter`, `order`, and `select` to control the selection.
* - `idKey?: string` - The name of the id field as it appears in each RESPONSE item; its value
* drives the cursor. Default is 'ID' (uppercase). For methods that return a lowercase /
* camelCase id (for example `tasks.task.list` returns `id`), set `idKey: 'id'`.
* - `cursorIdKey?: string` - The field name used in the REQUEST for `order` and the `>` page
* filter. Defaults to `idKey`. Set it only when the sortable / filterable field name differs
* from the response field name — e.g. `tasks.task.list` sorts and filters by `ID` (uppercase)
* but returns `id` (lowercase): pass `idKey: 'id', cursorIdKey: 'ID'`.
* - `customKeyForResult?: string` - A custom key indicating that the response REST API will be
* grouped by this field.
* Example: `items` to group a list of CRM items.
* - `requestId?: string` - Unique request identifier for tracking. Used for query deduplication and debugging.
*
* @returns {Promise<Result<T[]>>} A promise that resolves to the result of an REST API call.
*
* @example
* import { EnumCrmEntityTypeId, Text } from '@bitrix24/b24jssdk'
*
* interface CrmItem { id: number, title: string }
* const sixMonthAgo = new Date()
* sixMonthAgo.setMonth((new Date()).getMonth() - 6)
* sixMonthAgo.setHours(0, 0, 0)
* const response = await b24.actions.v2.callList.make<CrmItem>({
* method: 'crm.item.list',
* params: {
* entityTypeId: EnumCrmEntityTypeId.company,
* filter: {
* '=%title': 'A%',
* '>=createdTime': Text.toB24Format(sixMonthAgo) // created at least 6 months ago
* },
* select: ['id', 'title']
* },
* idKey: 'id',
* customKeyForResult: 'items',
* requestId: 'list-123'
* })
* if (!response.isSuccess) {
* throw new Error(`Problem: ${response.getErrorMessages().join('; ')}`)
* }
* const list = response.getData()
* console.log(`Result: ${list?.length}`) // Number of items received
*/
async make(options) {
const batchSize = 50;
const result = new Result();
const idKey = options?.idKey ?? "ID";
const cursorIdKey = options?.cursorIdKey ?? idKey;
const customKeyForResult = options?.customKeyForResult ?? null;
const params = options?.params ?? {};
if ("order" in params && params["order"]) {
this._logger.warning("callList.make: user-provided `order` parameter is ignored because cursor-based pagination requires ordering by cursorIdKey. Use `filter` to narrow results instead.").catch(() => {
});
}
const moreIdKey = `>${cursorIdKey}`;
const { order: _ignoredOrder, ...restParams } = params;
const requestParams = {
...restParams,
order: { [cursorIdKey]: "ASC" },
filter: { ...params["filter"] || {}, [moreIdKey]: 0 },
start: -1
};
let allItems = [];
while (true) {
const response = await this._b24.actions.v2.call.make({
method: options.method,
params: requestParams,
requestId: options.requestId
});
if (!response.isSuccess) {
this._logger.error("callFastListMethod", {
method: options.method,
requestId: options.requestId,
messages: response.getErrorMessages()
}).catch(() => {
});
for (const [index, error] of response.errors) {
result.addError(error, index);
}
break;
}
const responseData = response.getData();
if (!responseData) {
break;
}
const resultData = null === customKeyForResult ? responseData.result : responseData.result[customKeyForResult];
if (resultData.length === 0) {
break;
}
allItems = [...allItems, ...resultData];
if (resultData.length < batchSize) {
break;
}
const lastItem = resultData[resultData.length - 1];
const cursorValue = lastItem ? Number.parseInt(lastItem[idKey], 10) : Number.NaN;
if (Number.isFinite(cursorValue)) {
requestParams.filter[moreIdKey] = cursorValue;
} else {
this._logger.warning(`callList.make: pagination stops here \u2014 no numeric id could be read from the returned items via idKey "${idKey}". Make sure idKey matches the id field in the response; if the sortable field name differs from it, also set cursorIdKey (e.g. idKey: 'id', cursorIdKey: 'ID').`).catch(() => {
});
break;
}
}
return result.setData(allItems);
}
}
var __defProp$1b = Object.defineProperty;
var __name$1b = (target, value) => __defProp$1b(target, "name", { value, configurable: true });
class FetchListV2 extends AbstractAction {
static {
__name$1b(this, "FetchListV2");
}
/**
* Calls a REST API list method and returns an async generator for efficient large data retrieval.
* Implements the fast algorithm for iterating over large datasets without loading all data into memory at once.
*
* @template T - The type of items in the returned arrays (default is `unknown`).
*
* @param {ActionFetchListV2} options - parameters for executing the request.
* - `method: string` - The name of the REST API method that returns a list of data (for example: `crm.item.list`, `tasks.task.list`)
* - `params?: Omit<TypeCallParamsV2, 'start' | 'order'>` - Request parameters, excluding the `start` and `order` parameters,
* since the method is designed to obtain all data in one call.
* Note: Use `filter`, `order`, and `select` to control the selection.
* - `idKey?: string` - The name of the id field as it appears in each RESPONSE item; its value
* drives the cursor. Default is 'ID' (uppercase). For methods that return a lowercase /
* camelCase id (for example `tasks.task.list` returns `id`), set `idKey: 'id'`.
* - `cursorIdKey?: string` - The field name used in the REQUEST for `order` and the `>` page
* filter. Defaults to `idKey`. Set it only when the sortable / filterable field name differs
* from the response field name — e.g. `tasks.task.list` sorts and filters by `ID` (uppercase)
* but returns `id` (lowercase): pass `idKey: 'id', cursorIdKey: 'ID'`.
* - `customKeyForResult?: string` - A custom key indicating that the response REST API will be
* grouped by this field.
* Example: `items` to group a list of CRM items.
* - `requestId?: string` - Unique request identifier for tracking. Used for query deduplication and debugging.
*
* @returns {AsyncGenerator<T[]>} An async generator that yields chunks of data as arrays of type `T`.
* Each iteration returns the next page/batch of results until all data is fetched.
*
* @example
* import { EnumCrmEntityTypeId, Text } from '@bitrix24/b24jssdk'
*
* interface CrmItem { id: number, title: string }
* const sixMonthAgo = new Date()
* sixMonthAgo.setMonth((new Date()).getMonth() - 6)
* sixMonthAgo.setHours(0, 0, 0)
* const generator = b24.actions.v2.fetchList.make<CrmItem>({
* method: 'crm.item.list',
* params: {
* entityTypeId: EnumCrmEntityTypeId.company,
* filter: {
* '=%title': 'A%',
* '>=createdTime': Text.toB24Format(sixMonthAgo) // created at least 6 months ago
* },
* select: ['id', 'title']
* },
* idKey: 'id',
* customKeyForResult: 'items',
* requestId: 'list-123'
* })
*
* for await (const chunk of generator) {
* // Process chunk (e.g., save to database, analyze, etc.)
* console.log(`Processing ${chunk.length} items`)
* }
*
* @see {@link https://apidocs.bitrix24.com/settings/performance/huge-data.html Bitrix24: Fast algorithm for large data}
*/
async *make(options) {
const batchSize = 50;
const idKey = options?.idKey ?? "ID";
const cursorIdKey = options?.cursorIdKey ?? idKey;
const customKeyForResult = options?.customKeyForResult ?? null;
const params = options?.params ?? {};
if ("order" in params && params["order"]) {
this._logger.warning("fetchList.make: user-provided `order` parameter is ignored because cursor-based pagination requires ordering by cursorIdKey. Use `filter` to narrow results instead.").catch(() => {
});
}
const moreIdKey = `>${cursorIdKey}`;
const { order: _ignoredOrder, ...restParams } = params;
const requestParams = {
...restParams,
order: { [cursorIdKey]: "ASC" },
filter: { ...params["filter"] || {}, [moreIdKey]: 0 },
start: -1
};
while (true) {
const response = await this._b24.actions.v2.call.make({
method: options.method,
params: requestParams,
requestId: options.requestId
});
if (!response.isSuccess) {
this._logger.error("fetchListMethod", {
method: options.method,
requestId: options.requestId,
messages: response.getErrorMessages()
}).catch(() => {
});
throw new SdkError({
code: "JSSDK_CORE_B24_FETCH_LIST_METHOD_API_V2",
description: `API Error: ${response.getErrorMessages().join("; ")}`,
status: 500
});
}
const responseData = response.getData();
if (!responseData) {
break;
}
const resultData = null === customKeyForResult ? responseData.result : responseData.result[customKeyForResult];
if (resultData.length === 0) {
break;
}
yield resultData;
if (resultData.length < batchSize) {
break;
}
const lastItem = resultData[resultData.length - 1];
const cursorValue = lastItem ? Number.parseInt(lastItem[idKey], 10) : Number.NaN;
if (Number.isFinite(cursorValue)) {
requestParams.filter[moreIdKey] = cursorValue;
} else {
this._logger.warning(`fetchList.make: pagination stops here \u2014 no numeric id could be read from the returned items via idKey "${idKey}". Make sure idKey matches the id field in the response; if the sortable field name differs from it, also set cursorIdKey (e.g. idKey: 'id', cursorIdKey: 'ID').`).catch(() => {
});
break;
}
}
}
}
var __defProp$1a = Object.defineProperty;
var __name$1a = (target, value) => __defProp$1a(target, "name", { value, configurable: true });
class AbstractBatch extends AbstractAction {
static {
__name$1a(this, "AbstractBatch");
}
_addBatchErrorsIfAny(response, result) {
if (!response.isSuccess) {
for (const [index, error] of response.errors) {
result.addError(error, index);
}
}
}
_processBatchResponse(response, calls, options) {
const isArrayCall = Array.isArray(calls);
if (options.returnAjaxResult) {
return this._createBatchResultWithAjax(response, isArrayCall);
} else {
return this._createBatchResultSimple(response, isArrayCall);
}
}
// region BatchResultWithAjax ////
_createBatchResultWithAjax(response, isArrayCall) {
return isArrayCall ? this._createBatchArrayResult(response) : this._createBatchObjectResult(response);
}
_createBatchArrayResult(response) {
const result = new Result();
this._addBatchErrorsIfAny(response, result);
const dataResult = [];
for (const [_index, data] of response.getData().result) {
dataResult.push(data);
}
return result.setData(dataResult);
}
_createBatchObjectResult(response) {
const result = new Result();
this._addBatchErrorsIfAny(response, result);
const dataResult = {};
for (const [index, data] of response.getData().result) {
dataResult[index] = data;
}
return result.setData(dataResult);
}
// endregion ////
// region BatchResultSimple ////
_createBatchResultSimple(response, isArrayCall) {
const result = new Result();
this._addBatchErrorsIfAny(response, result);
return result.setData(
this._extractBatchSimpleData(response, isArrayCall)
);
}
_extractBatchSimpleData(response, isArrayCall) {
if (isArrayCall) {
const dataResult = [];
for (const [_index, data] of response.getData().result) {
if (data.isSuccess) {
dataResult.push(data.getData().result);
}
}
return dataResult;
} else {
const dataResult = {};
for (const [index, data] of response.getData().result) {
if (data.isSuccess) {
dataResult[index] = data.getData().result;
}
}
return dataResult;
}
}
// endregion ////
chunkArray(array, chunkSize = 50) {
const result = [];
for (let i = 0; i < array.length; i += chunkSize) {
const chunk = array.slice(i, i + chunkSize);
result.push(chunk);
}
return result;
}
}
var __defProp$19 = Object.defineProperty;
var __name$19 = (target, value) => __defProp$19(target, "name", { value, configurable: true });
class BatchV2 extends AbstractBatch {
static {
__name$19(this, "BatchV2");
}
/**
* Executes a batch request to the Bitrix24 REST API with a maximum number of commands of no more than 50.
* Allows you to execute multiple requests in a single API call, significantly improving performance.
*
* @template T - The data type returned by batch query commands (default is `unknown`)
*
* @param {ActionBatchV2} options - parameters for executing the request.
* - `calls: BatchCommandsArrayUniversal | BatchCommandsObjectUniversal | BatchNamedCommandsUniversal` - Commands to execute in a batch.
* Supports several formats:
* 1. Array of tuples: `[['method1', params1], ['method2', params2], ...]`
* 2. Array of objects: `[{ method: 'method1', params: params1 }, { method: 'method2', params: params2 }, ...]`
* 3. An object with named commands: `{ cmd1: { method: 'method1', params: params1 }, cmd2: ['method2', params2], ...}`
* - `options?: IB24BatchOptions` - Additional options for executing a batch request.
* - `isHaltOnError?: boolean` - Whether to stop execution on the first error (default: true)
* - `requestId?: string` - Unique request identifier for tracking. Used for query deduplication and debugging (default: undefined)
* - `returnAjaxResult?: boolean` - Whether to return an AjaxResult object instead of data (default: false)
*
* @returns {Promise<CallBatchResult<T>>} A promise that is resolved by the result of executing a batch request:
* - On success: a `Result` object with the command execution results
* - The structure of the results depends on the format of the `calls` input data:
* - For an array of commands, an array of results in the same order
* - For named commands, an object with keys corresponding to the command names
*
* @example
* import { EnumCrmEntityTypeId } from '@bitrix24/b24jssdk'
*
* interface Contact { id: number, name: string }
* const response = await b24.actions.v2.batch.make<{ item: Contact }>({
* calls: [
* ['crm.item.get', { entityTypeId: EnumCrmEntityTypeId.contact, id: 1 }],
* ['crm.item.get', { entityTypeId: EnumCrmEntityTypeId.contact, id: 2 }],
* ['crm.item.get', { entityTypeId: EnumCrmEntityTypeId.contact, id: 3 }]
* ],
* options: {
* isHaltOnError: true,
* returnAjaxResult: true,
* requestId: 'batch-123'
* }
* })
* if (!response.isSuccess) {
* throw new Error(`Problem: ${response.getErrorMessages().join('; ')}`)
* }
*
* const resultData = (response as Result<AjaxResult<{ item: Contact }>[]>).getData()
* resultData.forEach((resultRow, index) => {
* if (resultRow.isSuccess) {
* console.log(`Item ${index + 1}:`, resultRow.getData()!.result.item)
* }
* })
*
* @example
* import { EnumCrmEntityTypeId } from '@bitrix24/b24jssdk'
*
* const response = await b24.actions.v2.batch.make({
* calls: [
* { method: 'crm.item.get', params: { entityTypeId: EnumCrmEntityTypeId.contact, id: 1 } },
* { method: 'crm.item.get', params: { entityTypeId: EnumCrmEntityTypeId.contact, id: 2 } }
* ],
* options: {
* isHaltOnError: true,
* returnAjaxResult: true,
* requestId: 'batch-123'
* }
* })
* if (!response.isSuccess) {
* throw new Error(`Problem: ${response.getErrorMessages().join('; ')}`)
* }
*
* @example
* import { EnumCrmEntityTypeId } from '@bitrix24/b24jssdk'
*
* interface Contact { id: number, name: string }
* interface Deal { id: number, title: string }
* const response = await b24.actions.v2.batch.make<{ item: Contact } | { item: Deal }>({
* calls: {
* Contact: { method: 'crm.item.get', params: { entityTypeId: EnumCrmEntityTypeId.contact, id: 1 } },
* Deal: ['crm.item.get', { entityTypeId: EnumCrmEntityTypeId.deal, id: 2 }]
* },
* options: {
* isHaltOnError: true,
* returnAjaxResult: true,
* requestId: 'batch-123'
* }
* })
* if (!response.isSuccess) {
* throw new Error(`Problem: ${response.getErrorMessages().join('; ')}`)
* }
*
* const results = response.getData() as Record<string, AjaxResult<{ item: Contact } | { item: Deal }>>
* console.log('Contact:', results.Contact.getData()?.result.item as Contact)
* console.log('Deal:', results.Deal.getData()?.result.item as Deal)
*
* @warning The maximum number of commands in one batch request is 50.
* @note A batch request executes faster than sequential single calls,
* but if one command fails, the entire batch may fail
* (depending on API settings and options).
*/
async make(options) {
this._warnMisplacedOptions(
options,
["isHaltOnError", "returnAjaxResult", "requestId"],
"options"
);
const opts = {
...options.options,
apiVersion: ApiVersion.v2
};
const response = await this._b24.getHttpClient(ApiVersion.v2).batch(options.calls, opts);
return this._processBatchResponse(response, options.calls, opts);
}
}
var __defProp$18 = Object.defineProperty;
var __name$18 = (target, value) => __defProp$18(target, "name", { value, configurable: true });
class BatchByChunkV2 extends AbstractBatch {
static {
__name$18(this, "BatchByChunkV2");
}
/**
* Executes a batch request with automatic chunking for any number of commands.
* Unlike `BatchV2`, which is limited to 50 commands, this method automatically splits
* a large set of commands into multiple batches and executes them sequentially.
*
* @template T - The data type returned by commands (default: `unknown`)
*
* @param {ActionBatchByChunkV2} options - parameters for executing the request.
* - `calls: BatchCommandsArrayUniversal | BatchCommandsObjectUniversal` - Commands to execute in a batch.
* Supports several formats:
* 1. Array of tuples: `[['method1', params1], ['method2', params2], ...]`
* 2. Array of objects: `[{ method: 'method1', params: params1 }, { method: 'method2', params: params2 }, ...]`
* - Note: Named commands are not supported as they are difficult to process when chunking.
* - `options?: Omit<IB24BatchOptions, 'returnAjaxResult'>` - Additional options for executing a batch request.
* - `isHaltOnError?: boolean` - Whether to stop execution on the first error (default: true)
* - `requestId?: string` - Unique request identifier for tracking. Used for query deduplication and debugging (default: undefined)
*
* @returns {Promise<Result<T[]>>} A promise that is resolved by the result of executing all commands.
*
* @example
* import { EnumCrmEntityTypeId, Text } from '@bitrix24/b24jssdk'
*
* interface Contact { id: number, name: string }
* const commands = Array.from({ length: 150 }, (_, i) =>
* ['crm.item.get', { entityTypeId: EnumCrmEntityTypeId.contact, id: i + 1 }]
* )
*
* const response = await b24.actions.v2.batchByChunk.make<{ item: Contact }>({
* calls: commands,
* options: {
* isHaltOnError: false,
* requestId: 'batch-by-chunk-123'
* }
* })
*
* if (!response.isSuccess) {
* throw new Error(`Problem: ${response.getErrorMessages().join('; ')}`)
* }
*
* const resultData = response.getData()
* const items: Contact[] = []
* resultData.forEach((chunkRow) => {
* items.push(chunkRow.item)
* })
* console.log(`Successfully retrieved ${items.length} items`)
*
* @tip For very large command sets, consider using server-side task queues instead of bulk batch requests.
*/
async make(options) {
this._warnMisplacedOptions(options, ["isHaltOnError", "requestId"], "options");
const batchSize = 50;
const opts = {
...options.options,
returnAjaxResult: false,
apiVersion: ApiVersion.v2
};
const result = new Result();
const dataResult = [];
const chunks = this.chunkArray(options.calls, batchSize);
for (const chunkRequest of chunks) {
const response = await this._b24.getHttpClient(ApiVersion.v2).batch(chunkRequest, opts);
if (!response.isSuccess) {
this._addBatchErrorsIfAny(response, result);
}
for (const [_index, data] of response.getData().result) {
if (data.isSuccess) {
dataResult.push(data.getData().result);
}
}
}
return result.setData(dataResult);
}
}
var __defProp$17 = Object.defineProperty;
var __name$17 = (target, value) => __defProp$17(target, "name", { value, configurable: true });
const callName$1 = /* @__PURE__ */ Symbol("call_V2");
const callListName$1 = /* @__PURE__ */ Symbol("callList_V2");
const fetchListName$1 = /* @__PURE__ */ Symbol("fetchList_V2");
const batchName$1 = /* @__PURE__ */ Symbol("batch_V2");
const batchByChunkName$1 = /* @__PURE__ */ Symbol("batchByChunk_V2");
class ActionsManagerV2 {
static {
__name$17(this, "ActionsManagerV2");
}
_b24;
_logger;
_mapActions;
constructor(b24) {
this._b24 = b24;
this._logger = LoggerFactory.createNullLogger();
this._mapActions = /* @__PURE__ */ new Map();
}
setLogger(logger) {
this._logger = logger;
}
getLogger() {
return this._logger;
}
get call() {
if (!this._mapActions.has(callName$1)) {
this._mapActions.set(callName$1, new CallV2(this._b24, this._logger));
}
return this._mapActions.get(callName$1);
}
get callList() {
if (!this._mapActions.has(callListName$1)) {
this._mapActions.set(callListName$1, new CallListV2(this._b24, this._logger));
}
return this._mapActions.get(callListName$1);
}
get fetchList() {
if (!this._mapActions.has(fetchListName$1)) {
this._mapActions.set(fetchListName$1, new FetchListV2(this._b24, this._logger));
}
return this._mapActions.get(fetchListName$1);
}
get batch() {
if (!this._mapActions.has(batchName$1)) {
this._mapActions.set(batchName$1, new BatchV2(this._b24, this._logger));
}
return this._mapActions.get(batchName$1);
}
get batchByChunk() {
if (!this._mapActions.has(batchByChunkName$1)) {
this._mapActions.set(batchByChunkName$1, new BatchByChunkV2(this._b24, this._logger));
}
return this._mapActions.get(batchByChunkName$1);
}
}
var __defProp$16 = Object.defineProperty;
var __name$16 = (target, value) => __defProp$16(target, "name", { value, configurable: true });
class CallV3 extends AbstractAction {
static {
__name$16(this, "CallV3");
}
/**
* Calls the Bitrix24 REST API method.
*
* @template T - The expected data type in the response (default is `unknown`).
*
* @param {ActionCallV3} options - parameters for executing the request.
* - `method: string` - REST API method name (eg: `crm.item.get`)
* - `params?: TypeCallParamsV3` - Parameters for calling the method.
* - `requestId?: string` - Unique request identifier for tracking. Used for query deduplication and debugging.
*
* @returns {Promise<AjaxResult<T>>} A promise that resolves to the result of an REST API call.
*
* @example
* interface TaskItem { id: number, title: string }
* const response = await b24.actions.v3.call.make<{ item: TaskItem }>({
* method: 'tasks.task.get',
* params: { id: 123, select: ['id', 'title'] },
* requestId: 'task-123'
* })
* if (!response.isSuccess) {
* throw new Error(`Problem: ${response.getErrorMessages().join('; ')}`)
* }
* console.log(response.getData().result.item.title)
*/
async make(options) {
const params = options.params || {};
return this._b24.getHttpClient(ApiVersion.v3).call(options.method, params, options.requestId);
}
}
var __defProp$15 = Object.defineProperty;
var __name$15 = (target, value) => __defProp$15(target, "name", { value, configurable: true });
function assertArrayFilter(filter, action) {
if (filter === void 0 || Array.isArray(filter)) {
return;
}
throw new SdkError({
code: "JSSDK_ACTION_V3_LIST_FILTER_NOT_ARRAY",
description: `${action}: \`filter\` must be the restApi:v3 array form, e.g. [['id', '>', 100]] or FilterV3.build(...). The restApi:v2 object dialect ({ '>id': 100 }) cannot be used here, because keyset pagination extends the filter with a cursor condition.`,
status: 500
});
}
__name$15(assertArrayFilter, "assertArrayFilter");
class KeysetPaginationError extends Error {
static {
__name$15(this, "KeysetPaginationError");
}
errors;
messages;
constructor(errors, messages) {
super(messages.join("; "));
this.name = "KeysetPaginationError";
this.errors = errors;
this.messages = messages;
}
}
async function* keysetPaginate(b24, logger, strategy) {
let cursor = strategy.initialCursor;
let maxPageSize = 0;
while (true) {
const response = await b24.actions.v3.call.make({
method: strategy.method,
params: strategy.buildParams(cursor),
requestId: strategy.requestId
});
if (!response.isSuccess) {
logger.error(strategy.errorLabel, {
method: strategy.method,
requestId: strategy.requestId,
messages: response.getErrorMessages()
}).catch(() => {
});
throw new KeysetPaginationError(response.errors, response.getErrorMessages());
}
const responseData = response.getData();
if (!responseData) {
break;
}
const resultData = responseData.result[strategy.customKeyForResult];
if (!Array.isArray(resultData) || resultData.length === 0) {
break;
}
yield resultData;
maxPageSize = Math.max(maxPageSize, resultData.length);
if (resultData.length < maxPageSize) {
break;
}
const lastItem = resultData[resultData.length - 1];
const next = lastItem ? strategy.readNextCursor(lastItem) : null;
if (next === null || next === void 0) {
logger.warning(strategy.noCursorWarning).catch(() => {
});
break;
}
cursor = next;
}
}
__name$15(keysetPaginate, "keysetPaginate");
var __defProp$14 = Object.defineProperty;
var __name$14 = (target, value) => __defProp$14(target, "name", { value, configurable: true });
class CallListV3 extends AbstractAction {
static {
__name$14(this, "CallListV3");
}
/**
* Fast data retrieval without counting the total number of records.
*
* @template T - The type of the elements of the returned array (default is `unknown`).
*
* @param {ActionCallListV3} options - parameters for executing the request.
* - `method: string` - The name of the REST API method that returns a list of data (for example: `crm.item.list`, `tasks.task.list`)
* - `params?: Omit<TypeCallParamsV3, 'pagination' | 'order'>` - Request parameters, excluding the `pagination` and `order` parameters,
* since the method is designed to obtain all data in one call.
* Note: Use `filter`, `order`, and `select` to control the selection.
* - `idKey?: string` - The name of the id field as it appears in each RESPONSE item; its value
* drives the cursor. Default is 'id'. Set it to match the id field the method returns.
* - `cursorIdKey?: string` - The field name used in the REQUEST for `order` and the
* `[field, '>', n]` page filter. Defaults to `idKey`. Set it only when the sortable /
* filterable field name differs from the response field name (e.g. an uppercase request
* field but a lowercase response id): pass `idKey: 'id', cursorIdKey: 'ID'`.
* - `customKeyForResult: string` - A custom key indicating that the response REST API will be
* grouped by this field.
* Example: `items` to group a list of CRM items.
* - `requestId?: string` - Unique request identifier for tracking. Used for query deduplication and debugging.
* - `limit?: number` - How many records to retrieve at a time. Default is `50`. Maximum is `1000`.
*
* @returns {Promise<Result<T[]>>} A promise that resolves to the result of an REST API call.
*
* @example
* import { Text } from '@bitrix24/b24jssdk'
*
* interface MainEventLogItem { id: number, userId: number }
* const sixMonthAgo = new Date()
* sixMonthAgo.setMonth((new Date()).getMonth() - 6)
* sixMonthAgo.setHours(0, 0, 0)
* const response = await b24.actions.v3.callList.make<MainEventLogItem>({
* method: 'main.eventlog.list',
* params: {
* filter: [
* ['timestampX', '>=', Text.toB24Format(sixMonthAgo)] // created at least 6 months ago
* ],
* select: ['id', 'userId']
* },
* idKey: 'id',
* customKeyForResult: 'items',
* requestId: 'eventlog-123',
* limit: 60
* })
* if (!response.isSuccess) {
* throw new Error(`Problem: ${response.getErrorMessages().join('; ')}`)
* }
* const list = response.getData()
* console.log(`Result: ${list?.length}`) // Number of items received
*/
async make(options) {
const batchSize = options?.limit ?? 50;
const result = new Result();
const idKey = options?.idKey ?? "id";
const cursorIdKey = options?.cursorIdKey ?? idKey;
const customKeyForResult = options?.customKeyForResult ?? null;
const params = options?.params ?? {};
if ("order" in params && params["order"]) {
this._logger.warning("callList.make: user-provided `order` parameter is ignored because cursor-based pagination requires ordering by cursorIdKey. Use `filter` to narrow results instead.").catch(() => {
});
}
assertArrayFilter(params["filter"], "callList.make");
const { order: _ignoredOrder, ...restParams } = params;
const requestParams = {
...restParams,
order: { [cursorIdKey]: "ASC" },
filter: [...params["filter"] ?? []],
pagination: { page: 0, limit: batchSize }
};
const allItems = [];
try {
for await (const page of keysetPaginate(this._b24, this._logger, {
method: options.method,
requestId: options.requestId,
customKeyForResult,
initialCursor: 0,
// Emulated keyset: append the `[cursorIdKey, '>', cursor]` page filter.
buildParams: /* @__PURE__ */ __name$14((cursor) => ({ ...requestParams, filter: [...requestParams.filter, [cursorIdKey, ">", cursor]] }), "buildParams"),
// Advance by the numeric id read from the last item via `idKey`. A
// non-numeric value (almost always an `idKey` that doesn't match the
// response field — e.g. sorting by `ID` while the response carries a
// lowercase `id`) stops the walk instead of silently truncating.
readNextCursor: /* @__PURE__ */ __name$14((lastItem) => {
const value = Number.parseInt(lastItem[idKey], 10);
return Number.isFinite(value) ? value : null;
}, "readNextCursor"),
noCursorWarning: `callList.make: pagination stops here \u2014 no numeric id could be read from the returned items via idKey "${idKey}". Make sure idKey matches the id field in the response; if the sortable field name differs from it, also set cursorIdKey (e.g. idKey: 'id', cursorIdKey: 'ID').`,
errorLabel: "callFastListMethod"
})) {
for (const item of page) {
allItems.push(item);
}
}
} catch (error) {
if (error instanceof KeysetPaginationError) {
for (const [index, err] of error.errors) {
result.addError(err, index);
}
} else {
throw error;
}
}
return result.setData(allItems);
}
}
var __defProp$13 = Object.defineProperty;
var __name$13 = (target, value) => __defProp$13(target, "name", { value, configurable: true });
class FetchListV3 extends AbstractAction {
static {
__name$13(this, "FetchListV3");
}
/**
* Calls a REST API list method and returns an async generator for efficient large data retrieval.
* Implements the fast algorithm for iterating over large datasets without loading all data into memory at once.
*
* @template T - The type of items in the returned arrays (default is `unknown`).
*
* @param {ActionFetchListV3} options - parameters for executing the request.
* - `method: string` - The name of the REST API method that returns a list of data (for example: `crm.item.list`, `tasks.task.list`)
* - `params?: Omit<TypeCallParamsV3, 'pagination' | 'order'>` - Request parameters, excluding the `pagination` and `order` parameters,
* since the method is designed to obtain all data in one call.
* Note: Use `filter`, `order`, and `select` to control the selection.
* - `idKey?: string` - The name of the id field as it appears in each RESPONSE item; its value
* drives the cursor. Default is 'id'. Set it to match the id field the method returns.
* - `cursorIdKey?: string` - The field name used in the REQUEST for `order` and the
* `[field, '>', n]` page filter. Defaults to `idKey`. Set it only when the sortable /
* filterable field name differs from the response field name (e.g. an uppercase request
* field but a lowercase response id): pass `idKey: 'id', cursorIdKey: 'ID'`.
* - `customKeyForResult: string` - A custom key indicating that the response REST API will be
* grouped by this field.
* Example: `items` to group a list of CRM items.
* - `requestId?: string` - Unique request identifier for tracking. Used for query deduplication and debugging.
* - `limit?: number` - How many records to retrieve at a time. Default is `50`. Maximum is `1000`.
*
* @returns {AsyncGenerator<T[]>} An async generator that yields chunks of data as arrays of type `T`.
* Each iteration returns the next page/batch of results until all data is fetched.
*
* @example
* import { Text } from '@bitrix24/b24jssdk'
*
* interface MainEventLogItem { id: number, userId: number }
* const sixMonthAgo = new Date()
* sixMonthAgo.setMonth((new Date()).getMonth() - 6)
* sixMonthAgo.setHours(0, 0, 0)
* const generator = b24.actions.v3.fetchList.make<MainEventLogItem>({
* method: 'main.eventlog.list',
* params: {
* filter: [
* ['timestampX', '>=', Text.toB24Format(sixMonthAgo)] // created at least 6 months ago
* ],
* select: ['id', 'userId']
* },
* idKey: 'id',
* customKeyForResult: 'items',
* requestId: 'eventlog-123',
* limit: 60
* })
*
* for await (const chunk of generator) {
* // Process chunk (e.g., save to database, analyze, etc.)
* console.log(`Processing ${chunk.length} items`)
* }
*/
async *make(options) {
const batchSize = options?.limit ?? 50;
const idKey = options?.idKey ?? "id";
const cursorIdKey = options?.cursorIdKey ?? idKey;
const customKeyForResult = options?.customKeyForResult ?? null;
const params = options?.params ?? {};
if ("order" in params && params["order"]) {
this._logger.warning("fetchList.make: user-provided `order` parameter is ignored because cursor-based pagination requires ordering by cursorIdKey. Use `filter` to narrow results instead.").catch(() => {
});
}
assertArrayFilter(params["filter"], "fetchList.make");
const { order: _ignoredOrder, ...restParams } = params;
const requestParams = {
...restParams,
order: { [cursorIdKey]: "ASC" },
filter: [...params["filter"] ?? []],
pagination: { page: 0, limit: batchSize }
};
try {
yield* keysetPaginate(this._b24, this._logger, {
method: options.method,
requestId: options.requestId,
customKeyForResult,
initialCursor: 0,
// Emulated keyset: append the `[cursorIdKey, '>', cursor]` page filter.
buildParams: /* @__PURE__ */ __name$13((cursor) => ({ ...requestParams, filter: [...requestParams.filter, [cursorIdKey, ">", cursor]] }), "buildParams"),
// Advance by the numeric id read from the last item via `idKey`. A
// non-numeric value (almost always an `idKey` that doesn't match the
// response field — e.g. sorting by `ID` while the response carries a
// lowercase `id`) stops the walk instead of silently truncating.
readNextCursor: /* @__PURE__ */ __name$13((lastItem) => {
const value = Number.parseInt(lastItem[idKey], 10);
return Number.isFinite(value) ? value : null;
}, "readNextCursor"),
noCursorWarning: `fetchList.make: pagination stops here \u2014 no numeric id could be read from the returned items via idKey "${idKey}". Make sure idKey matches the id field in the response; if the sortable field name differs from it, also set cursorIdKey (e.g. idKey: 'id', cursorIdKey: 'ID').`,
errorLabel: "fetchListMethod"
});
} catch (error) {
if (error instanceof KeysetPaginationError) {
throw new SdkError({
code: "JSSDK_CORE_B24_FETCH_LIST_METHOD_API_V3",
description: `API Error: ${error.messages.join("; ")}`,
status: 500
});
}
throw error;
}
}
}
var __defProp$12 = Object.defineProperty;
var __name$12 = (target, value) => __defProp$12(target, "name", { value, configurable: true });
class CallTailV3 extends AbstractAction {
static {
__name$12(this, "CallTailV3");
}
/**
* Returns every record of a `tail` method as one array.
*
* @template T - The type of the elements of the returned array (default is `unknown`).
*
* @param {ActionCallTailV3} options - parameters for executing the request.
* - `method: string` - A REST API `tail` method name (for example: `main.eventlog.tail`).
* - `params?: Omit<TypeCallParamsV3, 'pagination' | 'order' | 'cursor'>` - Request parameters
* (`filter`, `select`). `pagination`, `order` and `cursor` are managed by this helper.
* The cursor field must NOT be used in `filter`.
* - `cursorField?: string` - The DTO field that drives the cursor. Default is `id`.
* - `order?: 'ASC' | 'DESC'` - Cursor direction. Default is `ASC`. For `DESC` you MUST pass
* `initialValue` (the server pages by `field < value`, so the default `0` returns nothing).
* - `customKeyForResult?: string` - The key the response groups rows under. Default is `items`.
* - `requestId?: string` - Unique request identifier for tracking.
* - `limit?: number` - How many records to retrieve at a time. Default is `50`. Maximum is `1000`.
* - `initialValue?: number | string` - Cursor start value for the first page. Default is `0`
* (valid for ascending numeric fields); required for `DESC` and for non-numeric fields.
*
* @returns {Promise<Result<T[]>>} A promise that resolves to the result of an REST API call.
*
* @example
* const response = await b24.actions.v3.callTail.make<{ id: string }>({
* method: 'main.eventlog.tail',
* params: { select: ['id', 'auditType'] },
* cursorField: 'id',
* customKeyForResult: 'items'
* })
* if (!response.isSuccess) {
* throw new Error(`Problem: ${response.getErrorMessages().join('; ')}`)
* }
* console.log(`Result: ${response.getData()?.length}`)
*/
async make(options) {
const batchSize = options?.limit ?? 50;
const result = new Result();
const cursorField = options?.cursorField ?? "id";
const order = options?.order ?? "ASC";
const customKeyForResult = options?.customKeyForResult ?? "items";
const params = options?.params ?? {};
if (/desc/i.test(order) && options?.initialValue === void 0) {
throw new SdkError({
code: "JSSDK_CORE_B24_CALL_TAIL_DESC_REQUIRES_INITIAL_VALUE",
description: 'callTail.make: order "DESC" requires an explicit `initialValue` (the server pages by `field < value`, so the default 0 returns nothing). Pass `initialValue` set to the type maximum / newest value.',
status: 500
});
}
if (Array.isArray(params["filter"]) && params["filter"].some((c) => Array.isArray(c) && c[0] === cursorField)) {
this._logger.warning(`callTail.make: the cursor field "${cursorField}" must not appear in \`filter\` \u2014 the server orders and pages by it and will reject a filter on the same field (INVALIDFILTEREXCEPTION). Remove it from \`filter\`.`).catch(() => {
});
}
let select = params["select"];
if (Array.isArray(select)) {
if (!select.includes(cursorField)) {
select = [...select, cursorField];
}
} else if (cursorField !== "id") {
this._logger.warning(`callTail.make: no \`select\` provided with a non-default cursorField "${cursorField}" \u2014 make sure it is in the server's default field set, otherwise pass \`select\` including "${cursorField}" so the cursor can advance.`).catch(() => {
});
}
const { select: _ignoredSelect, ...restParams } = params;
const allItems = [];
try {
for await (const page of keysetPaginate(this._b24, this._logger, {
method: options.method,
requestId: options.requestId,
customKeyForResult,
initialCursor: options?.initialValue ?? 0,
// Native keyset: drive the server's `cursor: { field, value, order, limit }`.
buildParams: /* @__PURE__ */ __name$12((cursor) => ({
...restParams,
...select ? { select } : {},
cursor: { field: cursorField, value: cursor, order, limit: batchSize }
}), "buildParams"),
// Advance by the raw cursor-field value from the last item; a missing
// value (cursorField not selected / wrong name) stops the walk.
readNextCursor: /* @__PURE__ */ __name$12((lastItem) => lastItem[cursorField] ?? null, "readNextCursor"),
noCursorWarning: `callTail.make: pagination stops here \u2014 no value could be read from the returned items via cursorField "${cursorField}". Make sure cursorField matches a field present in the response (and in \`select\`).`,
errorLabel: "callTailMethod"
})) {
for (const item of page) {
allItems.push(item);
}
}
} catch (error) {
if (error instanceof KeysetPaginationError) {
for (const [index, err] of error.errors) {
result.addError(err, index);
}
} else {
throw error;
}
}
return result.setData(allItems);
}
}
var __defProp$11 = Object.defineProperty;
var __name$11 = (target, value) => __defProp$11(target, "name", { value, configurable: true });
class FetchTailV3 extends AbstractAction {
static {
__name$11(this, "FetchTailV3");
}
/**
* Streams every record of a `tail` method as chunks, advancing the keyset
* cursor between requests.
*
* @template T - The type of items in the returned arrays (default is `unknown`).
*
* @param {ActionFetchTailV3} options - parameters for executing the request.
* - `method: string` - A REST API `tail` method name (for example: `main.eventlog.tail`).
* - `params?: Omit<TypeCallParamsV3, 'pagination' | 'order' | 'cursor'>` - Request parameters.
* Use `filter` and `select` to control the selection. `pagination`, `order` and `cursor`
* are managed by this helper and must not be passed. The cursor field must NOT be used in `filter`.
* - `cursorField?: string` - The DTO field that drives the cursor. Must be monotonic and
* preferably unique, and present in `select`. Default is `id`.
* - `order?: 'ASC' | 'DESC'` - Cursor direction. Default is `ASC`. For `DESC` you MUST pass
* `initialValue` (the server pages by `field < value`, so the default `0` returns nothing).
* - `customKeyForResult?: string` - The key the response groups rows under. Default is `items`.
* - `requestId?: string` - Unique request identifier for tracking.
* - `limit?: number` - How many records to retrieve at a time. Default is `50`. Maximum is `1000`.
* - `initialValue?: number | string` - Cursor start value for the first page. Default is `0`
* (valid for ascending numeric fields); required for `DESC` and for non-numeric fields.
*
* @returns {AsyncGenerator<T[]>} An async generator that yields chunks of data as arrays of type `T`.
*
* @example
* const generator = b24.actions.v3.fetchTail.make<{ id: string }>({
* method: 'main.eventlog.tail',
* params: { select: ['id', 'auditType'] },
* cursorField: 'id',
* customKeyForResult: 'items'
* })
* for await (const chunk of generator) {
* console.log(`Processing ${chunk.length} items`)
* }
*/
async *make(options) {
const batchSize = options?.limit ?? 50;
const cursorField = options?.cursorField ?? "id";
const order = options?.order ?? "ASC";
const customKeyForResult = options?.customKeyForResult ?? "items";
const params = options?.params ?? {};
if (/desc/i.test(order) && options?.initialValue === void 0) {
throw new SdkError({
code: "JSSDK_CORE_B24_FETCH_TAIL_DESC_REQUIRES_INITIAL_VALUE",
description: 'fetchTail.make: order "DESC" requires an explicit `initialValue` (the server pages by `field < value`, so the default 0 returns nothing). Pass `initialValue` set to the type maximum / newest value.',
status: 500
});
}
if (Array.isArray(params["filter"]) && params["filter"].some((c) => Array.isArray(c) && c[0] === cursorField)) {
this._logger.warning(`fetchTail.make: the cursor field "${cursorField}" must not appear in \`filter\` \u2014 the server orders and pages by it and will reject a filter on the same field (INVALIDFILTEREXCEPTION). Remove it from \`filter\`.`).catch(() => {
});
}
let select = params["select"];
if (Array.isArray(select)) {
if (!select.includes(cursorField)) {
select = [...select, cursorField];
}
} else if (cursorField !== "id") {
this._logger.warning(`fetchTail.make: no \`select\` provided with a non-default cursorField "${cursorField}" \u2014 make sure it is in the server's default field set, otherwise pass \`select\` including "${cursorField}" so the cursor can advance.`).catch(() => {
});
}
const { select: _ignoredSelect, ...restParams } = params;
try {
yield* keysetPaginate(this._b24, this._logger, {
method: options.method,
requestId: options.requestId,
customKeyForResult,
initialCursor: options?.initialValue ?? 0,
// Native keyset: drive the server's `cursor: { field, value, order, limit }`.
buildParams: /* @__PURE__ */ __name$11((cursor) => ({
...restParams,
...select ? { select } : {},
cursor: { field: cursorField, value: cursor, order, limit: batchSize }
}), "buildParams"),
// Advance by the raw cursor-field value from the last item; a missing
// value (cursorField not selected / wrong name) stops the walk.
readNextCursor: /* @__PURE__ */ __name$11((lastItem) => lastItem[cursorField] ?? null, "readNextCursor"),
noCursorWarning: `fetchTail.make: pagination stops here \u2014 no value could be read from the returned items via cursorField "${cursorField}". Make sure cursorField matches a field present in the response (and in \`select\`).`,
errorLabel: "fetchTailMethod"
});
} catch (error) {
if (error instanceof KeysetPaginationError) {
throw new SdkError({
code: "JSSDK_CORE_B24_FETCH_TAIL_METHOD_API_V3",
description: `API Error: ${error.messages.join("; ")}`,
status: 500
});
}
throw error;
}
}
}
var __defProp$10 = Object.defineProperty;
var __name$10 = (target, value) => __defProp$10(target, "name", { value, configurable: true });
const AGGREGATE_FUNCTIONS = ["sum", "avg", "min", "max", "count", "countDistinct"];
class AggregateV3 extends AbstractAction {
static {
__name$10(this, "AggregateV3");
}
/**
* @param {ActionAggregateV3} options
* - `method: string` - an `*.aggregate` method name.
* - `select: AggregateSelectV3` - per-function field selection (`sum`/`avg`/`min`/`max`/`count`/`countDistinct`).
* - `params?: { filter }` - optional v3 filter (array-of-triples; use `FilterV3` to build it).
* - `requestId?: string` - tracking id.
*
* @returns {Promise<Result<AggregateResultV3>>} buckets keyed by function then field name.
*
* @example
* const response = await b24.actions.v3.aggregate.make({
* method: 'some.entity.aggregate',
* select: { sum: { amount: 'totalAmount' }, count: ['id'] },
* params: { filter: FilterV3.build(FilterV3.eq('status', 'NEW')) }
* })
* if (response.isSuccess) {
* const total = response.getData()?.sum?.amount
* }
*/
async make(options) {
const result = new Result();
const select = options?.select ?? {};
for (const fn of Object.keys(select)) {
if (!AGGREGATE_FUNCTIONS.includes(fn)) {
throw new SdkError({
code: "JSSDK_AGGREGATE_V3_INVALID_FUNCTION",
description: `AggregateV3: "${fn}" is not an aggregate function \u2014 use one of ${AGGREGATE_FUNCTIONS.join(" ")}.`,
status: 400
});
}
const fields = select[fn];
if (!Array.isArray(fields) && (typeof fields !== "object" || fields === null)) {
throw new SdkError({
code: "JSSDK_AGGREGATE_V3_INVALID_SELECT",
description: `AggregateV3: select.${fn} must be a string[] (default alias) or a { field: alias } map.`,
status: 400
});
}
}
const params = { select };
if (options?.params?.filter) {
params.filter = options.params.filter;
}
const response = await this._b24.actions.v3.call.make({
method: options.method,
params,
requestId: options.requestId
});
if (!response.isSuccess) {
this._logger.error("aggregateMethod", {
method: options.method,
requestId: options.requestId,
messages: response.getErrorMessages()
}).catch(() => {
});
for (const [index, error] of response.errors) {
result.addError(error, index);
}
return result;
}
const payload = response.getData()?.result;
let buckets;
if (payload && typeof payload === "object" && "result" in payload) {
buckets = payload.result ?? {};
} else if (payload && typeof payload === "object") {
this._logger.warning(`aggregate.make: response has no nested 'result.result' envelope (the v3 reference \xA77 specifies double nesting); falling back to the top-level 'result'. method=${options.method}`).catch(() => {
});
buckets = payload;
} else {
buckets = {};
}
return result.setData(buckets);
}
}
var __defProp$$ = Object.defineProperty;
var __name$$ = (target, value) => __defProp$$(target, "name", { value, configurable: true });
class BatchV3 extends AbstractBatch {
static {
__name$$(this, "BatchV3");
}
/**
* Executes a batch request to the Bitrix24 REST API with a maximum number of commands of no more than 50.
* Allows you to execute multiple requests in a single API call, significantly improving performance.
*
* @template T - The data type returned by batch query commands (default is `unknown`)
*
* @param {ActionBatchV3} options - parameters for executing the request.
* - `calls: BatchCommandsArrayUniversal | BatchCommandsObjectUniversal | BatchNamedCommandsUniversal` - Commands to execute in a batch.
* Supports several formats:
* 1. Array of tuples: `[['method1', params1], ['method2', params2], ...]`
* 2. Array of objects: `[{ method: 'method1', params: params1 }, { method: 'method2', params: params2 }, ...]`
* 3. An object with named commands: `{ cmd1: { method: 'method1', params: params1 }, cmd2: ['method2', params2], ...}`
* - `options?: IB24BatchOptions` - Additional options for executing a batch request.
* - `isHaltOnError?: boolean` - Whether to stop execution on the first error (default: true)
* - `requestId?: string` - Unique request identifier for tracking. Used for query deduplication and debugging (default: undefined)
* - `returnAjaxResult?: boolean` - Whether to return an AjaxResult object instead of data (default: false)
*
* @returns {Promise<CallBatchResult<T>>} A promise that is resolved by the result of executing a batch request:
* - On success: a `Result` object with the command execution results
* - The structure of the results depends on the format of the `calls` input data:
* - For an array of commands, an array of results in the same order
* - For named commands, an object with keys corresponding to the command names
*
* @example
* interface TaskItem { id: number, title: string }
* const response = await b24.actions.v3.batch.make<{ item: TaskItem }>({
* calls: [
* ['tasks.task.get', { id: 1, select: ['id', 'title'] }],
* ['tasks.task.get', { id: 2, select: ['id', 'title'] }],
* ['tasks.task.get', { id: 3, select: ['id', 'title'] }]
* ],
* options: {
* isHaltOnError: true,
* returnAjaxResult: true,
* requestId: 'batch-123'
* }
* })
* if (!response.isSuccess) {
* throw new Error(`Problem: ${response.getErrorMessages().join('; ')}`)
* }
*
* const resultData = (response as Result<AjaxResult<{ item: TaskItem }>[]>).getData()
* resultData.forEach((resultRow, index) => {
* if (resultRow.isSuccess) {
* console.log(`Item ${index + 1}:`, resultRow.getData()!.result.item)
* }
* })
*
* @example
* const response = await b24.actions.v3.batch.make({
* calls: [
* { method: 'tasks.task.get', params: { id: 1, select: ['id', 'title'] } },
* { method: 'tasks.task.get', params: { id: 2, select: ['id', 'title'] } }
* ],
* options: {
* isHaltOnError: true,
* returnAjaxResult: true,
* requestId: 'batch-123'
* }
* })
* if (!response.isSuccess) {
* throw new Error(`Problem: ${response.getErrorMessages().join('; ')}`)
* }
*
* @example
* interface TaskItem { id: number, title: string }
* interface MainEventLogItem { id: number, userId: number }
* const response = await b24.actions.v3.batch.make<{ item: TaskItem } | { items: MainEventLogItem[] }>({
* calls: {
* Task: { method: 'tasks.task.get', params: { id: 1, select: ['id', 'title'] } },
* MainEventLog: ['main.eventlog.list', { select: ['id', 'userId'], pagination: { limit: 5 } }]
* },
* options: {
* isHaltOnError: true,
* returnAjaxResult: true,
* requestId: 'batch-123'
* }
* })
* if (!response.isSuccess) {
* throw new Error(`Problem: ${response.getErrorMessages().join('; ')}`)
* }
*
* const results = response.getData() as Record<string, AjaxResult<{ item: TaskItem } | { items: MainEventLogItem[] }>>
* console.log('Task:', results.Task.getData()?.result.item as TaskItem)
* console.log('MainEventLog:', results.MainEventLog.getData()?.result.items as MainEventLogItem[])
*
* @warning The maximum number of commands in one batch request is 50.
* @note A batch request executes faster than sequential single calls,
* but if one command fails, the entire batch may fail
* (depending on API settings and options).
*/
async make(options) {
this._warnMisplacedOptions(
options,
["isHaltOnError", "returnAjaxResult", "requestId"],
"options"
);
const opts = {
...options.options,
apiVersion: ApiVersion.v3
};
const response = await this._b24.getHttpClient(ApiVersion.v3).batch(options.calls, opts);
return this._processBatchResponse(response, options.calls, opts);
}
}
var __defProp$_ = Object.defineProperty;
var __name$_ = (target, value) => __defProp$_(target, "name", { value, configurable: true });
class BatchByChunkV3 extends AbstractBatch {
static {
__name$_(this, "BatchByChunkV3");
}
/**
* Executes a batch request with automatic chunking for any number of commands.
* Unlike `BatchV3`, which is limited to 50 commands, this method automatically splits
* a large set of commands into multiple batches and executes them sequentially.
*
* @template T - The data type returned by commands (default: `unknown`)
*
* @param {ActionBatchByChunkV3} options - parameters for executing the request.
* - `calls: BatchCommandsArrayUniversal | BatchCommandsObjectUniversal` - Commands to execute in a batch.
* Supports several formats:
* 1. Array of tuples: `[['method1', params1], ['method2', params2], ...]`
* 2. Array of objects: `[{ method: 'method1', params: params1 }, { method: 'method2', params: params2 }, ...]`
* - Note: Named commands are not supported as they are difficult to process when chunking.
* - `options?: Omit<IB24BatchOptions, 'returnAjaxResult'>` - Additional options for executing a batch request.
* - `isHaltOnError?: boolean` - Whether to stop execution on the first error (default: true)
* - `requestId?: string` - Unique request identifier for tracking. Used for query deduplication and debugging (default: undefined)
*
* @returns {Promise<Result<T[]>>} A promise that is resolved by the result of executing all commands.
*
* @example
* interface TaskItem { id: number, title: string }
* const commands: BatchCommandsArrayUniversal = Array.from({ length: 150 }, (_, i) =>
* ['tasks.task.get', { id: i + 1, select: ['id', 'title'] }]
* )
*
* const response = await b24.actions.v3.batchByChunk.make<{ item: TaskItem }>({
* calls: commands,
* options: {
* isHaltOnError: false,
* requestId: 'batch-by-chunk-123'
* }
* })
*
* if (!response.isSuccess) {
* throw new Error(`Problem: ${response.getErrorMessages().join('; ')}`)
* }
*
* const resultData = response.getData()
* const items: TaskItem[] = []
* resultData.forEach((chunkRow) => {
* items.push(chunkRow.item)
* })
* console.log(`Successfully retrieved ${items.length} items`)
*
* @tip For very large command sets, consider using server-side task queues instead of bulk batch requests.
*/
async make(options) {
this._warnMisplacedOptions(options, ["isHaltOnError", "requestId"], "options");
const batchSize = 50;
const opts = {
...options.options,
returnAjaxResult: false,
apiVersion: ApiVersion.v3
};
const result = new Result();
const dataResult = [];
const chunks = this.chunkArray(options.calls, batchSize);
for (const chunkRequest of chunks) {
const response = await this._b24.getHttpClient(ApiVersion.v3).batch(chunkRequest, opts);
if (!response.isSuccess) {
this._addBatchErrorsIfAny(response, result);
}
for (const [_index, data] of response.getData().result) {
if (data.isSuccess) {
dataResult.push(data.getData().result);
}
}
}
return result.setData(dataResult);
}
}
var __defProp$Z = Object.defineProperty;
var __name$Z = (target, value) => __defProp$Z(target, "name", { value, configurable: true });
const callName = /* @__PURE__ */ Symbol("call_V3");
const callListName = /* @__PURE__ */ Symbol("callList_V3");
const fetchListName = /* @__PURE__ */ Symbol("fetchList_V3");
const callTailName = /* @__PURE__ */ Symbol("callTail_V3");
const fetchTailName = /* @__PURE__ */ Symbol("fetchTail_V3");
const aggregateName = /* @__PURE__ */ Symbol("aggregate_V3");
const batchName = /* @__PURE__ */ Symbol("batch_V3");
const batchByChunkName = /* @__PURE__ */ Symbol("batchByChunk_V3");
class ActionsManagerV3 {
static {
__name$Z(this, "ActionsManagerV3");
}
_b24;
_logger;
_mapActions;
constructor(b24) {
this._b24 = b24;
this._logger = LoggerFactory.createNullLogger();
this._mapActions = /* @__PURE__ */ new Map();
}
setLogger(logger) {
this._logger = logger;
}
getLogger() {
return this._logger;
}
get call() {
if (!this._mapActions.has(callName)) {
this._mapActions.set(callName, new CallV3(this._b24, this._logger));
}
return this._mapActions.get(callName);
}
get callList() {
if (!this._mapActions.has(callListName)) {
this._mapActions.set(callListName, new CallListV3(this._b24, this._logger));
}
return this._mapActions.get(callListName);
}
get fetchList() {
if (!this._mapActions.has(fetchListName)) {
this._mapActions.set(fetchListName, new FetchListV3(this._b24, this._logger));
}
return this._mapActions.get(fetchListName);
}
get callTail() {
if (!this._mapActions.has(callTailName)) {
this._mapActions.set(callTailName, new CallTailV3(this._b24, this._logger));
}
return this._mapActions.get(callTailName);
}
get fetchTail() {
if (!this._mapActions.has(fetchTailName)) {
this._mapActions.set(fetchTailName, new FetchTailV3(this._b24, this._logger));
}
return this._mapActions.get(fetchTailName);
}
get aggregate() {
if (!this._mapActions.has(aggregateName)) {
this._mapActions.set(aggregateName, new AggregateV3(this._b24, this._logger));
}
return this._mapActions.get(aggregateName);
}
get batch() {
if (!this._mapActions.has(batchName)) {
this._mapActions.set(batchName, new BatchV3(this._b24, this._logger));
}
return this._mapActions.get(batchName);
}
get batchByChunk() {
if (!this._mapActions.has(batchByChunkName)) {
this._mapActions.set(batchByChunkName, new BatchByChunkV3(this._b24, this._logger));
}
return this._mapActions.get(batchByChunkName);
}
}
var __defProp$Y = Object.defineProperty;
var __name$Y = (target, value) => __defProp$Y(target, "name", { value, configurable: true });
const apiV2Name = Symbol(ApiVersion.v2);
const apiV3Name = Symbol(ApiVersion.v3);
class ActionsManager {
static {
__name$Y(this, "ActionsManager");
}
_b24;
_logger;
_mapActions;
constructor(b24) {
this._b24 = b24;
this._logger = LoggerFactory.createNullLogger();
this._mapActions = /* @__PURE__ */ new Map();
}
setLogger(logger) {
this._logger = logger;
this.v2.setLogger(this._logger);
this.v3.setLogger(this._logger);
}
getLogger() {
return this._logger;
}
get v2() {
if (!this._mapActions.has(apiV2Name)) {
this._mapActions.set(apiV2Name, new ActionsManagerV2(this._b24));
}
return this._mapActions.get(apiV2Name);
}
get v3() {
if (!this._mapActions.has(apiV3Name)) {
this._mapActions.set(apiV3Name, new ActionsManagerV3(this._b24));
}
return this._mapActions.get(apiV3Name);
}
}
var __defProp$X = Object.defineProperty;
var __name$X = (target, value) => __defProp$X(target, "name", { value, configurable: true });
class AbstractTool {
static {
__name$X(this, "AbstractTool");
}
_b24;
_logger;
constructor(b24, logger) {
this._b24 = b24;
this._logger = logger;
}
}
var __defProp$W = Object.defineProperty;
var __name$W = (target, value) => __defProp$W(target, "name", { value, configurable: true });
class Ping extends AbstractTool {
static {
__name$W(this, "Ping");
}
/**
* Measures the response speed of the Bitrix24 REST API.
* Performs a test request and returns the response time in milliseconds.
* Useful for performance monitoring and diagnosing latency issues.
*
* @note The method uses a minimal API request (`server.time`) to check availability.
* Does not overload the server with large amounts of data.
*
* @warning Response time may vary depending on server load, network conditions
* and HTTP client settings (timeouts, retries).
*
* @tip For consistent results, it is recommended to perform multiple measurements
* and use the median value.
*
* @param options Some options for executing
* - `requestId?: string` - Unique request identifier for tracking. Used for query deduplication and debugging (default: undefined)
*
* @returns {Promise<number>} Promise that resolves to a response time in milliseconds:
* - Positive number: time from sending the request to receiving the response
* - In case of an error or timeout: `-1`
*
* @see {@link HealthCheck} To check API availability
*/
async make(options) {
const startTime = Date.now();
try {
await this._b24.actions.v2.call.make({
method: "server.time",
params: {},
requestId: options?.requestId
});
return Date.now() - startTime;
} catch {
return -1;
}
}
}
var __defProp$V = Object.defineProperty;
var __name$V = (target, value) => __defProp$V(target, "name", { value, configurable: true });
class HealthCheck extends AbstractTool {
static {
__name$V(this, "HealthCheck");
}
/**
* Checks the availability of the Bitrix24 REST API.
* Performs a simple request to the API to verify the service is operational and that the required access rights are present.
*
* @note The method uses a minimal API request (`server.time`) to check availability.
* Does not overload the server with large amounts of data.
*
* @param options Some options for executing
* - `requestId?: string` - Unique request identifier for tracking. Used for query deduplication and debugging (default: undefined)
*
* @returns {Promise<false>} Promise that resolves to a Boolean value:
* - `true`: the API is available and responding
* - `false`: the API is unavailable, an error occurred, or the required access rights are missing
*
* @see {@link Ping} To measure API response speed
*/
async make(options) {
try {
const response = await this._b24.actions.v2.call.make({
method: "server.time",
params: {},
requestId: options?.requestId
});
return response.isSuccess;
} catch {
return false;
}
}
}
var __defProp$U = Object.defineProperty;
var __name$U = (target, value) => __defProp$U(target, "name", { value, configurable: true });
const pingName = /* @__PURE__ */ Symbol("ping");
const healthCheckName = /* @__PURE__ */ Symbol("healthCheck");
class ToolsManager {
static {
__name$U(this, "ToolsManager");
}
_b24;
_logger;
_mapTools;
constructor(b24) {
this._b24 = b24;
this._logger = LoggerFactory.createNullLogger();
this._mapTools = /* @__PURE__ */ new Map();
}
setLogger(logger) {
this._logger = logger;
}
getLogger() {
return this._logger;
}
get ping() {
if (!this._mapTools.has(pingName)) {
this._mapTools.set(pingName, new Ping(this._b24, this._logger));
}
return this._mapTools.get(pingName);
}
get healthCheck() {
if (!this._mapTools.has(healthCheckName)) {
this._mapTools.set(healthCheckName, new HealthCheck(this._b24, this._logger));
}
return this._mapTools.get(healthCheckName);
}
}
var __defProp$T = Object.defineProperty;
var __name$T = (target, value) => __defProp$T(target, "name", { value, configurable: true });
class AbstractB24 {
static {
__name$T(this, "AbstractB24");
}
/**
* Maximum length for batch response.
*
* @deprecated This const is deprecated and will be removed in version `3.0.0`
* @removed 3.0.0
*/
static batchSize = 50;
_isInit = false;
_httpV2 = null;
_httpV3 = null;
_logger;
_actionsManager;
_toolsManager;
// region Init ////
constructor() {
this._isInit = false;
this._logger = LoggerFactory.createNullLogger();
this._actionsManager = new ActionsManager(this);
this._toolsManager = new ToolsManager(this);
}
/**
* @inheritDoc
*/
get isInit() {
return this._isInit;
}
async init() {
this._isInit = true;
return;
}
destroy() {
}
get actions() {
this._ensureInitialized();
return this._actionsManager;
}
get tools() {
this._ensureInitialized();
return this._toolsManager;
}
/**
* Calls the Bitrix24 REST API method.
*
* @deprecated This method is deprecated and will be removed in version `3.0.0`
* - for `restApi:v3` use {@link CallV3.make `b24.actions.v3.call.make(options)`}
* - for `restApi:v2` use {@link CallV2.make `b24.actions.v2.call.make(options)`}
*
* @removed 3.0.0
* @memo Only for `restApi:v2`
*/
async callMethod(method, params, start) {
LoggerFactory.forcedLog(
this._logger,
"warning",
`The AbstractB24.callMethod() method is deprecated and will be removed in version 3.0.0. Use b24.actions.v3.call.make(options) or b24.actions.v2.call.make(options)`,
{
class: "AbstractB24",
method: "callMethod",
replacement: "b24.actions.v3.call.make(options) | b24.actions.v2.call.make(options)",
removalVersion: "3.0.0",
code: "JSSDK_CORE_DEPRECATED_METHOD"
}
);
params = { ...params };
if (!("start" in params && Number.isInteger(params.start)) && Number.isInteger(start)) {
params.start = start;
}
return this._actionsManager.v2.call.make({ method, params });
}
/**
* Calls a Bitrix24 REST API list method to retrieve all data.
*
* @deprecated This method is deprecated and will be removed in version `3.0.0`
* - for `restApi:v3` use {@link CallListV3.make `b24.actions.v3.callList.make(options)`}
* - for `restApi:v2` use {@link CallListV2.make `b24.actions.v2.callList.make(options)`}
*
* @removed 3.0.0
* @memo Only for `restApi:v2`
*/
async callListMethod(method, params, progress, customKeyForResult) {
LoggerFactory.forcedLog(
this._logger,
"warning",
`The AbstractB24.callListMethod() method is deprecated and will be removed in version 3.0.0. Use b24.actions.v3.callList.make(options) or b24.actions.v2.callList.make(options)`,
{
class: "AbstractB24",
method: "callListMethod",
replacement: "b24.actions.v3.callList.make(options) | b24.actions.v2.callList.make(options)",
removalVersion: "3.0.0",
code: "JSSDK_CORE_DEPRECATED_METHOD"
}
);
const result = new Result();
if (Type.isFunction(progress) && null !== progress) {
progress(0);
}
const sendParams = {
...params,
start: 0
};
return this.actions.v2.call.make({
method,
params: sendParams
}).then(async (response) => {
let list = [];
const resultData = customKeyForResult ? response.getData().result[customKeyForResult] : response.getData().result;
list = [...list, ...resultData];
if (response.isMore()) {
let responseLoop = response;
while (true) {
responseLoop = await responseLoop.getNext(this.getHttpClient(ApiVersion.v2));
if (responseLoop === false) {
break;
}
const resultData2 = customKeyForResult ? responseLoop.getData().result[customKeyForResult] : responseLoop.getData().result;
list = [...list, ...resultData2];
if (progress) {
const total = responseLoop.getTotal();
progress(total > 0 ? Math.round(100 * list.length / total) : 100);
}
}
}
result.setData(list);
if (progress) {
progress(100);
}
return result;
});
}
/**
* Calls a Bitrix24 REST API list method and returns an async generator.
*
* @deprecated This method is deprecated and will be removed in version `3.0.0`
* - for `restApi:v3` use {@link FetchListV3.make `b24.actions.v3.fetchList.make(options)`}
* - for `restApi:v2` use {@link FetchListV2.make `b24.actions.v2.fetchList.make(options)`}
*
* @removed 3.0.0
* @memo Only for `restApi:v2`
*/
async *fetchListMethod(method, params, idKey, customKeyForResult) {
LoggerFactory.forcedLog(
this._logger,
"warning",
`The AbstractB24.fetchListMethod() method is deprecated and will be removed in version 3.0.0. Use b24.actions.v3.fetchList.make(options) or b24.actions.v2.fetchList.make(options)`,
{
class: "AbstractB24",
method: "fetchListMethod",
replacement: "b24.actions.v3.fetchList.make(options) | b24.actions.v2.fetchList.make(options)",
removalVersion: "3.0.0",
code: "JSSDK_CORE_DEPRECATED_METHOD"
}
);
const options = {
method,
params,
idKey,
customKeyForResult: customKeyForResult === null ? void 0 : customKeyForResult
};
yield* this.actions.v2.fetchList.make(options);
}
/**
* Executes a batch request to the Bitrix24 REST API.
*
* @deprecated This method is deprecated and will be removed in version `3.0.0`
* - for `restApi:v3` use {@link BatchV3.make `b24.actions.v3.batch.make(options)`}
* - for `restApi:v2` use {@link BatchV2.make `b24.actions.v2.batch.make(options)`}
*
* @removed 3.0.0
* @memo Only for `restApi:v2`
*/
async callBatch(calls, isHaltOnError, returnAjaxResult) {
LoggerFactory.forcedLog(
this._logger,
"warning",
`The AbstractB24.callBatch() method is deprecated and will be removed in version 3.0.0. Use b24.actions.v3.batch.make(options) or b24.actions.v2.batch.make(options)`,
{
class: "AbstractB24",
method: "callBatch",
replacement: "b24.actions.v3.batch.make(options) | b24.actions.v2.batch.make(options)",
removalVersion: "3.0.0",
code: "JSSDK_CORE_DEPRECATED_METHOD"
}
);
const callsTyped = calls;
const options = {
isHaltOnError: isHaltOnError ?? true,
returnAjaxResult: returnAjaxResult ?? false
};
return this.actions.v2.batch.make({
calls: callsTyped,
options
});
}
/**
* Executes a batch request to the Bitrix24 REST API with automatic chunking for any number of commands.
*
* @deprecated This method is deprecated and will be removed in version `3.0.0`
* - for `restApi:v3` use {@link BatchByChunkV3.make `b24.actions.v3.batchByChunk.make(options)`}
* - for `restApi:v2` use {@link BatchByChunkV2.make `b24.actions.v2.batchByChunk.make(options)`}
*
* @removed 3.0.0
* @memo Only for `restApi:v2`
*/
async callBatchByChunk(calls, isHaltOnError) {
LoggerFactory.forcedLog(
this._logger,
"warning",
`The AbstractB24.callBatchByChunk() method is deprecated and will be removed in version 3.0.0. Use b24.actions.v3.batchByChunk.make(options) or b24.actions.v2.batchByChunk.make(options)`,
{
class: "AbstractB24",
method: "callBatchByChunk",
replacement: "b24.actions.v3.batchByChunk.make(options) | b24.actions.v2.batchByChunk.make(options)",
removalVersion: "3.0.0",
code: "JSSDK_CORE_DEPRECATED_METHOD"
}
);
const callsTyped = calls;
const options = {
isHaltOnError,
returnAjaxResult: false
};
return this.actions.v2.batchByChunk.make({
calls: callsTyped,
options
});
}
// endregion ////
// region Tools ////
/**
* @inheritDoc
*/
getHttpClient(version) {
this._ensureInitialized();
switch (version) {
case ApiVersion.v3:
if (null === this._httpV3) {
throw new SdkError({
code: "JSSDK_CORE_B24_HTTP_V3_NOT_INIT",
description: `HttpV3 not init`,
status: 500
});
}
return this._httpV3;
case ApiVersion.v2:
if (null === this._httpV2) {
throw new SdkError({
code: "JSSDK_CORE_B24_HTTP_V2_NOT_INIT",
description: `HttpV2 not init`,
status: 500
});
}
return this._httpV2;
}
throw new SdkError({
code: "JSSDK_CORE_B24_API_WRONG",
description: `Wrong Api Version ${version}`,
status: 500
});
}
/**
* @inheritDoc
*/
setHttpClient(version, client) {
switch (version) {
case ApiVersion.v3:
this._httpV3 = client;
return;
case ApiVersion.v2:
this._httpV2 = client;
return;
}
throw new SdkError({
code: "JSSDK_CORE_B24_API_WRONG",
description: `Wrong Api Version ${version}`,
status: 500
});
}
setLogger(logger) {
warnOnNonPromiseLogger(logger, "B24 client");
this._logger = logger;
this._actionsManager.setLogger(this._logger);
this._toolsManager.setLogger(this._logger);
versionManager.getAllApiVersions().forEach((version) => {
this.getHttpClient(version).setLogger(this._logger);
});
}
getLogger() {
return this._logger;
}
/**
* @inheritDoc
*/
async setRestrictionManagerParams(params) {
const promises = versionManager.getAllApiVersions().map(
(version) => this.getHttpClient(version).setRestrictionManagerParams(params)
);
await Promise.allSettled(promises);
}
/**
* Returns settings for http connection
* @protected
*/
_getHttpOptions() {
return null;
}
/**
* Generates an object not initialized error
* @protected
*/
_ensureInitialized() {
if (!this._isInit) {
throw new SdkError({
code: "JSSDK_CORE_B24_NOT_INIT",
description: `B24 not initialized`,
status: 500
});
}
}
// endregion ////
}
/**
* Create a bound version of a function with a specified `this` context
*
* @param {Function} fn - The function to bind
* @param {*} thisArg - The value to be passed as the `this` parameter
* @returns {Function} A new function that will call the original function with the specified `this` context
*/
function bind(fn, thisArg) {
return function wrap() {
return fn.apply(thisArg, arguments);
};
}
// utils is a library of generic helper functions non-specific to axios
const { toString } = Object.prototype;
const { getPrototypeOf } = Object;
const { iterator, toStringTag } = Symbol;
/* Creating a function that will check if an object has a property. */
const hasOwnProperty = (
({ hasOwnProperty }) =>
(obj, prop) =>
hasOwnProperty.call(obj, prop)
)(Object.prototype);
/**
* Walk the prototype chain (excluding the shared Object.prototype) looking for
* an own `prop`. This distinguishes genuine own/inherited members — including
* class accessors and template prototypes — from members injected via
* Object.prototype pollution (e.g. `Object.prototype.username = '...'`), which
* live on Object.prototype itself and are therefore never matched.
*
* @param {*} thing The value whose chain to inspect
* @param {string|symbol} prop The property key to look for
*
* @returns {boolean} True when `prop` is owned below Object.prototype
*/
const hasOwnInPrototypeChain = (thing, prop) => {
let obj = thing;
const seen = [];
while (obj != null && obj !== Object.prototype) {
if (seen.indexOf(obj) !== -1) {
return false;
}
seen.push(obj);
if (hasOwnProperty(obj, prop)) {
return true;
}
obj = getPrototypeOf(obj);
}
return false;
};
/**
* Read `obj[prop]` only when it is safe from Object.prototype pollution. Own
* properties and members inherited from a non-Object.prototype source (a class
* instance or template object) are honored; a value reachable only through a
* polluted Object.prototype is ignored and `undefined` is returned.
*
* @param {*} obj The source object
* @param {string|symbol} prop The property key to read
*
* @returns {*} The resolved value, or undefined when unsafe/absent
*/
const getSafeProp = (obj, prop) =>
obj != null && hasOwnInPrototypeChain(obj, prop) ? obj[prop] : undefined;
const kindOf = ((cache) => (thing) => {
const str = toString.call(thing);
return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase());
})(Object.create(null));
const kindOfTest = (type) => {
type = type.toLowerCase();
return (thing) => kindOf(thing) === type;
};
const typeOfTest = (type) => (thing) => typeof thing === type;
/**
* Determine if a value is a non-null object
*
* @param {Object} val The value to test
*
* @returns {boolean} True if value is an Array, otherwise false
*/
const { isArray: isArray$2 } = Array;
/**
* Determine if a value is undefined
*
* @param {*} val The value to test
*
* @returns {boolean} True if the value is undefined, otherwise false
*/
const isUndefined = typeOfTest('undefined');
/**
* Determine if a value is a Buffer
*
* @param {*} val The value to test
*
* @returns {boolean} True if value is a Buffer, otherwise false
*/
function isBuffer$1(val) {
return (
val !== null &&
!isUndefined(val) &&
val.constructor !== null &&
!isUndefined(val.constructor) &&
isFunction$1(val.constructor.isBuffer) &&
val.constructor.isBuffer(val)
);
}
/**
* Determine if a value is an ArrayBuffer
*
* @param {*} val The value to test
*
* @returns {boolean} True if value is an ArrayBuffer, otherwise false
*/
const isArrayBuffer = kindOfTest('ArrayBuffer');
/**
* Determine if a value is a view on an ArrayBuffer
*
* @param {*} val The value to test
*
* @returns {boolean} True if value is a view on an ArrayBuffer, otherwise false
*/
function isArrayBufferView(val) {
let result;
if (typeof ArrayBuffer !== 'undefined' && ArrayBuffer.isView) {
result = ArrayBuffer.isView(val);
} else {
result = val && val.buffer && isArrayBuffer(val.buffer);
}
return result;
}
/**
* Determine if a value is a String
*
* @param {*} val The value to test
*
* @returns {boolean} True if value is a String, otherwise false
*/
const isString = typeOfTest('string');
/**
* Determine if a value is a Function
*
* @param {*} val The value to test
* @returns {boolean} True if value is a Function, otherwise false
*/
const isFunction$1 = typeOfTest('function');
/**
* Determine if a value is a Number
*
* @param {*} val The value to test
*
* @returns {boolean} True if value is a Number, otherwise false
*/
const isNumber = typeOfTest('number');
/**
* Determine if a value is an Object
*
* @param {*} thing The value to test
*
* @returns {boolean} True if value is an Object, otherwise false
*/
const isObject = (thing) => thing !== null && typeof thing === 'object';
/**
* Determine if a value is a Boolean
*
* @param {*} thing The value to test
* @returns {boolean} True if value is a Boolean, otherwise false
*/
const isBoolean = (thing) => thing === true || thing === false;
/**
* Determine if a value is a plain Object
*
* @param {*} val The value to test
*
* @returns {boolean} True if value is a plain Object, otherwise false
*/
const isPlainObject = (val) => {
if (!isObject(val)) {
return false;
}
const prototype = getPrototypeOf(val);
return (
(prototype === null ||
prototype === Object.prototype ||
getPrototypeOf(prototype) === null) &&
// Treat any genuine (non-Object.prototype-polluted) Symbol.toStringTag or
// Symbol.iterator as evidence the value is a tagged/iterable type rather
// than a plain object, while ignoring keys injected onto Object.prototype.
!hasOwnInPrototypeChain(val, toStringTag) &&
!hasOwnInPrototypeChain(val, iterator)
);
};
/**
* Determine if a value is an empty object (safely handles Buffers)
*
* @param {*} val The value to test
*
* @returns {boolean} True if value is an empty object, otherwise false
*/
const isEmptyObject = (val) => {
// Early return for non-objects or Buffers to prevent RangeError
if (!isObject(val) || isBuffer$1(val)) {
return false;
}
try {
return Object.keys(val).length === 0 && Object.getPrototypeOf(val) === Object.prototype;
} catch (e) {
// Fallback for any other objects that might cause RangeError with Object.keys()
return false;
}
};
/**
* Determine if a value is a Date
*
* @param {*} val The value to test
*
* @returns {boolean} True if value is a Date, otherwise false
*/
const isDate = kindOfTest('Date');
/**
* Determine if a value is a File
*
* @param {*} val The value to test
*
* @returns {boolean} True if value is a File, otherwise false
*/
const isFile = kindOfTest('File');
/**
* Determine if a value is a React Native Blob
* React Native "blob": an object with a `uri` attribute. Optionally, it can
* also have a `name` and `type` attribute to specify filename and content type
*
* @see https://github.com/facebook/react-native/blob/26684cf3adf4094eb6c405d345a75bf8c7c0bf88/Libraries/Network/FormData.js#L68-L71
*
* @param {*} value The value to test
*
* @returns {boolean} True if value is a React Native Blob, otherwise false
*/
const isReactNativeBlob = (value) => {
return !!(value && typeof value.uri !== 'undefined');
};
/**
* Determine if environment is React Native
* ReactNative `FormData` has a non-standard `getParts()` method
*
* @param {*} formData The formData to test
*
* @returns {boolean} True if environment is React Native, otherwise false
*/
const isReactNative = (formData) => formData && typeof formData.getParts !== 'undefined';
/**
* Determine if a value is a Blob
*
* @param {*} val The value to test
*
* @returns {boolean} True if value is a Blob, otherwise false
*/
const isBlob = kindOfTest('Blob');
/**
* Determine if a value is a FileList
*
* @param {*} val The value to test
*
* @returns {boolean} True if value is a FileList, otherwise false
*/
const isFileList = kindOfTest('FileList');
const isSet = kindOfTest('Set');
/**
* Determine if a value is a Stream
*
* @param {*} val The value to test
*
* @returns {boolean} True if value is a Stream, otherwise false
*/
const isStream = (val) => isObject(val) && isFunction$1(val.pipe);
/**
* Determine if a value is a FormData
*
* @param {*} thing The value to test
*
* @returns {boolean} True if value is an FormData, otherwise false
*/
function getGlobal() {
if (typeof globalThis !== 'undefined') return globalThis;
if (typeof self !== 'undefined') return self;
if (typeof window !== 'undefined') return window;
if (typeof global !== 'undefined') return global;
return {};
}
const G = getGlobal();
const FormDataCtor = typeof G.FormData !== 'undefined' ? G.FormData : undefined;
const isFormData = (thing) => {
if (!thing) return false;
if (FormDataCtor && thing instanceof FormDataCtor) return true;
// Reject plain objects inheriting directly from Object.prototype so prototype-pollution gadgets can't spoof FormData.
const proto = getPrototypeOf(thing);
if (!proto || proto === Object.prototype) return false;
if (!isFunction$1(thing.append)) return false;
const kind = kindOf(thing);
return (
kind === 'formdata' ||
// detect form-data instance
(kind === 'object' && isFunction$1(thing.toString) && thing.toString() === '[object FormData]')
);
};
/**
* Determine if a value is a URLSearchParams object
*
* @param {*} val The value to test
*
* @returns {boolean} True if value is a URLSearchParams object, otherwise false
*/
const isURLSearchParams = kindOfTest('URLSearchParams');
const [isReadableStream, isRequest, isResponse, isHeaders] = [
'ReadableStream',
'Request',
'Response',
'Headers',
].map(kindOfTest);
/**
* Trim excess whitespace off the beginning and end of a string
*
* @param {String} str The String to trim
*
* @returns {String} The String freed of excess whitespace
*/
const trim = (str) => {
return str.trim ? str.trim() : str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
};
/**
* Iterate over an Array or an Object invoking a function for each item.
*
* If `obj` is an Array callback will be called passing
* the value, index, and complete array for each item.
*
* If 'obj' is an Object callback will be called passing
* the value, key, and complete object for each property.
*
* @param {Object|Array<unknown>} obj The object to iterate
* @param {Function} fn The callback to invoke for each item
*
* @param {Object} [options]
* @param {Boolean} [options.allOwnKeys = false]
* @returns {any}
*/
function forEach(obj, fn, { allOwnKeys = false } = {}) {
// Don't bother if no value provided
if (obj === null || typeof obj === 'undefined') {
return;
}
let i;
let l;
// Force an array if not already something iterable
if (typeof obj !== 'object') {
/*eslint no-param-reassign:0*/
obj = [obj];
}
if (isArray$2(obj)) {
// Iterate over array values
for (i = 0, l = obj.length; i < l; i++) {
fn.call(null, obj[i], i, obj);
}
} else {
// Buffer check
if (isBuffer$1(obj)) {
return;
}
// Iterate over object keys
const keys = allOwnKeys ? Object.getOwnPropertyNames(obj) : Object.keys(obj);
const len = keys.length;
let key;
for (i = 0; i < len; i++) {
key = keys[i];
fn.call(null, obj[key], key, obj);
}
}
}
/**
* Finds a key in an object, case-insensitive, returning the actual key name.
* Returns null if the object is a Buffer or if no match is found.
*
* @param {Object} obj - The object to search.
* @param {string} key - The key to find (case-insensitive).
* @returns {?string} The actual key name if found, otherwise null.
*/
function findKey(obj, key) {
if (isBuffer$1(obj)) {
return null;
}
key = key.toLowerCase();
const keys = Object.keys(obj);
let i = keys.length;
let _key;
while (i-- > 0) {
_key = keys[i];
if (key === _key.toLowerCase()) {
return _key;
}
}
return null;
}
const _global = (() => {
/*eslint no-undef:0*/
if (typeof globalThis !== 'undefined') return globalThis;
return typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : global;
})();
const isContextDefined = (context) => !isUndefined(context) && context !== _global;
/**
* Accepts varargs expecting each argument to be an object, then
* immutably merges the properties of each object and returns result.
*
* When multiple objects contain the same key the later object in
* the arguments list will take precedence.
*
* Example:
*
* ```js
* const result = merge({foo: 123}, {foo: 456});
* console.log(result.foo); // outputs 456
* ```
*
* @param {Object} obj1 Object to merge
*
* @returns {Object} Result of all merge properties
*/
function merge(...objs) {
const { caseless, skipUndefined } = (isContextDefined(this) && this) || {};
const result = {};
const assignValue = (val, key) => {
// Skip dangerous property names to prevent prototype pollution
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
return;
}
// findKey lowercases the key, so caseless lookup only applies to strings —
// symbol keys are identity-matched.
const targetKey = (caseless && typeof key === 'string' && findKey(result, key)) || key;
// Read via own-prop only — a bare `result[targetKey]` walks the prototype
// chain, so a polluted Object.prototype value could surface here and get
// copied into the merged result.
const existing = hasOwnProperty(result, targetKey) ? result[targetKey] : undefined;
if (isPlainObject(existing) && isPlainObject(val)) {
result[targetKey] = merge(existing, val);
} else if (isPlainObject(val)) {
result[targetKey] = merge({}, val);
} else if (isArray$2(val)) {
result[targetKey] = val.slice();
} else if (!skipUndefined || !isUndefined(val)) {
result[targetKey] = val;
}
};
for (let i = 0, l = objs.length; i < l; i++) {
const source = objs[i];
if (!source || isBuffer$1(source)) {
continue;
}
forEach(source, assignValue);
if (typeof source !== 'object' || isArray$2(source)) {
continue;
}
const symbols = Object.getOwnPropertySymbols(source);
for (let j = 0; j < symbols.length; j++) {
const symbol = symbols[j];
if (propertyIsEnumerable.call(source, symbol)) {
assignValue(source[symbol], symbol);
}
}
}
return result;
}
/**
* Extends object a by mutably adding to it the properties of object b.
*
* @param {Object} a The object to be extended
* @param {Object} b The object to copy properties from
* @param {Object} thisArg The object to bind function to
*
* @param {Object} [options]
* @param {Boolean} [options.allOwnKeys]
* @returns {Object} The resulting value of object a
*/
const extend = (a, b, thisArg, { allOwnKeys } = {}) => {
forEach(
b,
(val, key) => {
if (thisArg && isFunction$1(val)) {
Object.defineProperty(a, key, {
// Null-proto descriptor so a polluted Object.prototype.get cannot
// hijack defineProperty's accessor-vs-data resolution.
__proto__: null,
value: bind(val, thisArg),
writable: true,
enumerable: true,
configurable: true,
});
} else {
Object.defineProperty(a, key, {
__proto__: null,
value: val,
writable: true,
enumerable: true,
configurable: true,
});
}
},
{ allOwnKeys }
);
return a;
};
/**
* Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
*
* @param {string} content with BOM
*
* @returns {string} content value without BOM
*/
const stripBOM = (content) => {
if (content.charCodeAt(0) === 0xfeff) {
content = content.slice(1);
}
return content;
};
/**
* Inherit the prototype methods from one constructor into another
* @param {function} constructor
* @param {function} superConstructor
* @param {object} [props]
* @param {object} [descriptors]
*
* @returns {void}
*/
const inherits = (constructor, superConstructor, props, descriptors) => {
constructor.prototype = Object.create(superConstructor.prototype, descriptors);
Object.defineProperty(constructor.prototype, 'constructor', {
__proto__: null,
value: constructor,
writable: true,
enumerable: false,
configurable: true,
});
Object.defineProperty(constructor, 'super', {
__proto__: null,
value: superConstructor.prototype,
});
props && Object.assign(constructor.prototype, props);
};
/**
* Resolve object with deep prototype chain to a flat object
* @param {Object} sourceObj source object
* @param {Object} [destObj]
* @param {Function|Boolean} [filter]
* @param {Function} [propFilter]
*
* @returns {Object}
*/
const toFlatObject = (sourceObj, destObj, filter, propFilter) => {
let props;
let i;
let prop;
const merged = {};
destObj = destObj || {};
// eslint-disable-next-line no-eq-null,eqeqeq
if (sourceObj == null) return destObj;
do {
props = Object.getOwnPropertyNames(sourceObj);
i = props.length;
while (i-- > 0) {
prop = props[i];
if ((!propFilter || propFilter(prop, sourceObj, destObj)) && !merged[prop]) {
destObj[prop] = sourceObj[prop];
merged[prop] = true;
}
}
sourceObj = filter !== false && getPrototypeOf(sourceObj);
} while (sourceObj && (!filter || filter(sourceObj, destObj)) && sourceObj !== Object.prototype);
return destObj;
};
/**
* Determines whether a string ends with the characters of a specified string
*
* @param {String} str
* @param {String} searchString
* @param {Number} [position= 0]
*
* @returns {boolean}
*/
const endsWith = (str, searchString, position) => {
str = String(str);
if (position === undefined || position > str.length) {
position = str.length;
}
position -= searchString.length;
const lastIndex = str.indexOf(searchString, position);
return lastIndex !== -1 && lastIndex === position;
};
/**
* Returns new array from array like object or null if failed
*
* @param {*} [thing]
*
* @returns {?Array}
*/
const toArray = (thing) => {
if (!thing) return null;
if (isArray$2(thing)) return thing;
let i = thing.length;
if (!isNumber(i)) return null;
const arr = new Array(i);
while (i-- > 0) {
arr[i] = thing[i];
}
return arr;
};
/**
* Checking if the Uint8Array exists and if it does, it returns a function that checks if the
* thing passed in is an instance of Uint8Array
*
* @param {TypedArray}
*
* @returns {Array}
*/
// eslint-disable-next-line func-names
const isTypedArray = ((TypedArray) => {
// eslint-disable-next-line func-names
return (thing) => {
return TypedArray && thing instanceof TypedArray;
};
})(typeof Uint8Array !== 'undefined' && getPrototypeOf(Uint8Array));
/**
* For each entry in the object, call the function with the key and value.
*
* @param {Object<any, any>} obj - The object to iterate over.
* @param {Function} fn - The function to call for each entry.
*
* @returns {void}
*/
const forEachEntry = (obj, fn) => {
const generator = obj && obj[iterator];
const _iterator = generator.call(obj);
let result;
while ((result = _iterator.next()) && !result.done) {
const pair = result.value;
fn.call(obj, pair[0], pair[1]);
}
};
/**
* It takes a regular expression and a string, and returns an array of all the matches
*
* @param {string} regExp - The regular expression to match against.
* @param {string} str - The string to search.
*
* @returns {Array<boolean>}
*/
const matchAll = (regExp, str) => {
let matches;
const arr = [];
while ((matches = regExp.exec(str)) !== null) {
arr.push(matches);
}
return arr;
};
/* Checking if the kindOfTest function returns true when passed an HTMLFormElement. */
const isHTMLForm = kindOfTest('HTMLFormElement');
const toCamelCase = (str) => {
return str.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g, function replacer(m, p1, p2) {
return p1.toUpperCase() + p2;
});
};
const { propertyIsEnumerable } = Object.prototype;
/**
* Determine if a value is a RegExp object
*
* @param {*} val The value to test
*
* @returns {boolean} True if value is a RegExp object, otherwise false
*/
const isRegExp = kindOfTest('RegExp');
const reduceDescriptors = (obj, reducer) => {
const descriptors = Object.getOwnPropertyDescriptors(obj);
const reducedDescriptors = {};
forEach(descriptors, (descriptor, name) => {
let ret;
if ((ret = reducer(descriptor, name, obj)) !== false) {
reducedDescriptors[name] = ret || descriptor;
}
});
Object.defineProperties(obj, reducedDescriptors);
};
/**
* Makes all methods read-only
* @param {Object} obj
*/
const freezeMethods = (obj) => {
reduceDescriptors(obj, (descriptor, name) => {
// skip restricted props in strict mode
if (isFunction$1(obj) && ['arguments', 'caller', 'callee'].includes(name)) {
return false;
}
const value = obj[name];
if (!isFunction$1(value)) return;
descriptor.enumerable = false;
if ('writable' in descriptor) {
descriptor.writable = false;
return;
}
if (!descriptor.set) {
descriptor.set = () => {
throw Error("Can not rewrite read-only method '" + name + "'");
};
}
});
};
/**
* Converts an array or a delimited string into an object set with values as keys and true as values.
* Useful for fast membership checks.
*
* @param {Array|string} arrayOrString - The array or string to convert.
* @param {string} delimiter - The delimiter to use if input is a string.
* @returns {Object} An object with keys from the array or string, values set to true.
*/
const toObjectSet = (arrayOrString, delimiter) => {
const obj = {};
const define = (arr) => {
arr.forEach((value) => {
obj[value] = true;
});
};
isArray$2(arrayOrString) ? define(arrayOrString) : define(String(arrayOrString).split(delimiter));
return obj;
};
const noop = () => {};
const toFiniteNumber = (value, defaultValue) => {
return value != null && Number.isFinite((value = +value)) ? value : defaultValue;
};
/**
* If the thing is a FormData object, return true, otherwise return false.
*
* @param {unknown} thing - The thing to check.
*
* @returns {boolean}
*/
function isSpecCompliantForm(thing) {
return !!(
thing &&
isFunction$1(thing.append) &&
thing[toStringTag] === 'FormData' &&
thing[iterator]
);
}
/**
* Recursively converts an object to a JSON-compatible object, handling circular references and Buffers.
*
* @param {Object} obj - The object to convert.
* @returns {Object} The JSON-compatible object.
*/
const toJSONObject = (obj) => {
const visited = new WeakSet();
const visit = (source) => {
if (isObject(source)) {
if (visited.has(source)) {
return;
}
//Buffer check
if (isBuffer$1(source)) {
return source;
}
if (!('toJSON' in source)) {
// add-on descent / delete-on-ascent: preserves path semantics, so DAG nodes serialise at every occurrence (see #7230).
visited.add(source);
let target;
if (isSet(source)) {
target = [];
for (const value of source) {
const reducedValue = visit(value);
!isUndefined(reducedValue) && target.push(reducedValue);
}
} else {
target = isArray$2(source) ? [] : {};
forEach(source, (value, key) => {
const reducedValue = visit(value);
!isUndefined(reducedValue) && (target[key] = reducedValue);
});
}
visited.delete(source);
return target;
}
}
return source;
};
return visit(obj);
};
/**
* Determines if a value is an async function.
*
* @param {*} thing - The value to test.
* @returns {boolean} True if value is an async function, otherwise false.
*/
const isAsyncFn = kindOfTest('AsyncFunction');
/**
* Determines if a value is thenable (has then and catch methods).
*
* @param {*} thing - The value to test.
* @returns {boolean} True if value is thenable, otherwise false.
*/
const isThenable = (thing) =>
thing &&
(isObject(thing) || isFunction$1(thing)) &&
isFunction$1(thing.then) &&
isFunction$1(thing.catch);
// original code
// https://github.com/DigitalBrainJS/AxiosPromise/blob/16deab13710ec09779922131f3fa5954320f83ab/lib/utils.js#L11-L34
/**
* Provides a cross-platform setImmediate implementation.
* Uses native setImmediate if available, otherwise falls back to postMessage or setTimeout.
*
* @param {boolean} setImmediateSupported - Whether setImmediate is supported.
* @param {boolean} postMessageSupported - Whether postMessage is supported.
* @returns {Function} A function to schedule a callback asynchronously.
*/
const _setImmediate = ((setImmediateSupported, postMessageSupported) => {
if (setImmediateSupported) {
return setImmediate;
}
return postMessageSupported
? ((token, callbacks) => {
_global.addEventListener(
'message',
({ source, data }) => {
if (source === _global && data === token) {
callbacks.length && callbacks.shift()();
}
},
false
);
return (cb) => {
callbacks.push(cb);
_global.postMessage(token, '*');
};
})(`axios@${Math.random()}`, [])
: (cb) => setTimeout(cb);
})(typeof setImmediate === 'function', isFunction$1(_global.postMessage));
/**
* Schedules a microtask or asynchronous callback as soon as possible.
* Uses queueMicrotask if available, otherwise falls back to process.nextTick or _setImmediate.
*
* @type {Function}
*/
const asap =
typeof queueMicrotask !== 'undefined'
? queueMicrotask.bind(_global)
: (typeof process !== 'undefined' && process.nextTick) || _setImmediate;
// *********************
const isIterable = (thing) => thing != null && isFunction$1(thing[iterator]);
/**
* Determine if a value is iterable via an iterator that is NOT sourced solely
* from a polluted Object.prototype. Use this instead of `isIterable` whenever
* the iterable comes from untrusted input (e.g. user-supplied header sources),
* so `Object.prototype[Symbol.iterator] = ...` cannot turn an ordinary object
* into an attacker-controlled entries iterator.
*
* @param {*} thing The value to test
*
* @returns {boolean} True if value has a non-polluted iterator
*/
const isSafeIterable = (thing) =>
thing != null && hasOwnInPrototypeChain(thing, iterator) && isIterable(thing);
const utils$1 = {
isArray: isArray$2,
isArrayBuffer,
isBuffer: isBuffer$1,
isFormData,
isArrayBufferView,
isString,
isNumber,
isBoolean,
isObject,
isPlainObject,
isEmptyObject,
isReadableStream,
isRequest,
isResponse,
isHeaders,
isUndefined,
isDate,
isFile,
isReactNativeBlob,
isReactNative,
isBlob,
isRegExp,
isFunction: isFunction$1,
isStream,
isURLSearchParams,
isTypedArray,
isFileList,
forEach,
merge,
extend,
trim,
stripBOM,
inherits,
toFlatObject,
kindOf,
kindOfTest,
endsWith,
toArray,
forEachEntry,
matchAll,
isHTMLForm,
hasOwnProperty,
hasOwnProp: hasOwnProperty, // an alias to avoid ESLint no-prototype-builtins detection
hasOwnInPrototypeChain,
getSafeProp,
reduceDescriptors,
freezeMethods,
toObjectSet,
toCamelCase,
noop,
toFiniteNumber,
findKey,
global: _global,
isContextDefined,
isSpecCompliantForm,
toJSONObject,
isAsyncFn,
isThenable,
setImmediate: _setImmediate,
asap,
isIterable,
isSafeIterable,
};
// RawAxiosHeaders whose duplicates are ignored by node
// c.f. https://nodejs.org/api/http.html#http_message_headers
const ignoreDuplicateOf = utils$1.toObjectSet([
'age',
'authorization',
'content-length',
'content-type',
'etag',
'expires',
'from',
'host',
'if-modified-since',
'if-unmodified-since',
'last-modified',
'location',
'max-forwards',
'proxy-authorization',
'referer',
'retry-after',
'user-agent',
]);
/**
* Parse headers into an object
*
* ```
* Date: Wed, 27 Aug 2014 08:58:49 GMT
* Content-Type: application/json
* Connection: keep-alive
* Transfer-Encoding: chunked
* ```
*
* @param {String} rawHeaders Headers needing to be parsed
*
* @returns {Object} Headers parsed into an object
*/
const parseHeaders = (rawHeaders) => {
const parsed = {};
let key;
let val;
let i;
rawHeaders &&
rawHeaders.split('\n').forEach(function parser(line) {
i = line.indexOf(':');
key = line.substring(0, i).trim().toLowerCase();
val = line.substring(i + 1).trim();
const hasKey = utils$1.hasOwnProp(parsed, key);
if (!key || (hasKey && utils$1.hasOwnProp(ignoreDuplicateOf, key))) {
return;
}
if (key === 'set-cookie') {
if (hasKey) {
parsed[key].push(val);
} else {
parsed[key] = [val];
}
} else {
parsed[key] = hasKey ? parsed[key] + ', ' + val : val;
}
});
return parsed;
};
function trimSPorHTAB(str) {
let start = 0;
let end = str.length;
while (start < end) {
const code = str.charCodeAt(start);
if (code !== 0x09 && code !== 0x20) {
break;
}
start += 1;
}
while (end > start) {
const code = str.charCodeAt(end - 1);
if (code !== 0x09 && code !== 0x20) {
break;
}
end -= 1;
}
return start === 0 && end === str.length ? str : str.slice(start, end);
}
// The control-code ranges are intentional: header sanitization strips C0/DEL bytes.
// eslint-disable-next-line no-control-regex
const INVALID_UNICODE_HEADER_VALUE_CHARS = new RegExp('[\\u0000-\\u0008\\u000a-\\u001f\\u007f]+', 'g');
// eslint-disable-next-line no-control-regex
const INVALID_BYTE_STRING_HEADER_VALUE_CHARS = new RegExp('[^\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+', 'g');
function sanitizeValue(value, invalidChars) {
if (utils$1.isArray(value)) {
return value.map((item) => sanitizeValue(item, invalidChars));
}
return trimSPorHTAB(String(value).replace(invalidChars, ''));
}
const sanitizeHeaderValue = (value) =>
sanitizeValue(value, INVALID_UNICODE_HEADER_VALUE_CHARS);
const sanitizeByteStringHeaderValue = (value) =>
sanitizeValue(value, INVALID_BYTE_STRING_HEADER_VALUE_CHARS);
function toByteStringHeaderObject(headers) {
const byteStringHeaders = Object.create(null);
utils$1.forEach(headers.toJSON(), (value, header) => {
byteStringHeaders[header] = sanitizeByteStringHeaderValue(value);
});
return byteStringHeaders;
}
const $internals = Symbol('internals');
function normalizeHeader(header) {
return header && String(header).trim().toLowerCase();
}
function normalizeValue(value) {
if (value === false || value == null) {
return value;
}
return utils$1.isArray(value) ? value.map(normalizeValue) : sanitizeHeaderValue(String(value));
}
function parseTokens(str) {
const tokens = Object.create(null);
const tokensRE = /([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;
let match;
while ((match = tokensRE.exec(str))) {
tokens[match[1]] = match[2];
}
return tokens;
}
const parameterNameRE = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
function trimOWS(value) {
let start = 0;
let end = value.length;
while (start < end) {
const code = value.charCodeAt(start);
if (code !== 0x09 && code !== 0x20) {
break;
}
start += 1;
}
while (end > start) {
const code = value.charCodeAt(end - 1);
if (code !== 0x09 && code !== 0x20) {
break;
}
end -= 1;
}
return start === 0 && end === value.length ? value : value.slice(start, end);
}
function decodeQuotedString(value) {
const last = value.length - 1;
if (last < 1 || value.charCodeAt(0) !== 0x22 || value.charCodeAt(last) !== 0x22) {
return value;
}
let decoded = '';
for (let i = 1; i < last; i++) {
const code = value.charCodeAt(i);
if (code === 0x22) {
return value;
}
if (code === 0x5c) {
i += 1;
if (i >= last) {
return value;
}
}
decoded += value[i];
}
return decoded;
}
function parseParameters(value) {
const parameters = Object.create(null);
const str = String(value);
let start = 0;
let quoted = false;
let escaped = false;
function parseParameter(end) {
const part = trimOWS(str.slice(start, end));
const equals = part.indexOf('=');
if (equals < 1) {
return;
}
const name = trimOWS(part.slice(0, equals));
if (!parameterNameRE.test(name)) {
return;
}
const normalizedName = name.toLowerCase();
if (
normalizedName === '__proto__' ||
normalizedName === 'constructor' ||
normalizedName === 'prototype'
) {
return;
}
const parameterValue = trimOWS(part.slice(equals + 1));
parameters[normalizedName] = decodeQuotedString(parameterValue);
}
for (let i = 0; i < str.length; i++) {
const code = str.charCodeAt(i);
if (quoted) {
if (escaped) {
escaped = false;
} else if (code === 0x5c) {
escaped = true;
} else if (code === 0x22) {
quoted = false;
}
} else if (code === 0x22) {
quoted = true;
} else if (code === 0x2c || code === 0x3b) {
parseParameter(i);
start = i + 1;
}
}
parseParameter(str.length);
return parameters;
}
const isValidHeaderName = (str) => /^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(str.trim());
function matchHeaderValue(context, value, header, filter, isHeaderNameFilter) {
if (utils$1.isFunction(filter)) {
return filter.call(this, value, header);
}
if (isHeaderNameFilter) {
value = header;
}
if (!utils$1.isString(value)) return;
if (utils$1.isString(filter)) {
return value.indexOf(filter) !== -1;
}
if (utils$1.isRegExp(filter)) {
return filter.test(value);
}
}
function formatHeader(header) {
return header
.trim()
.toLowerCase()
.replace(/([a-z\d])(\w*)/g, (w, char, str) => {
return char.toUpperCase() + str;
});
}
function buildAccessors(obj, header) {
const accessorName = utils$1.toCamelCase(' ' + header);
['get', 'set', 'has'].forEach((methodName) => {
Object.defineProperty(obj, methodName + accessorName, {
// Null-proto descriptor so a polluted Object.prototype.get cannot turn
// this data descriptor into an accessor descriptor on the way in.
__proto__: null,
value: function (arg1, arg2, arg3) {
return this[methodName].call(this, header, arg1, arg2, arg3);
},
configurable: true,
});
});
}
let AxiosHeaders$1 = class AxiosHeaders {
constructor(headers) {
headers && this.set(headers);
}
set(header, valueOrRewrite, rewrite) {
const self = this;
function setHeader(_value, _header, _rewrite) {
const lHeader = normalizeHeader(_header);
if (!lHeader) {
return;
}
const key = utils$1.findKey(self, lHeader);
if (
!key ||
self[key] === undefined ||
_rewrite === true ||
(_rewrite === undefined && self[key] !== false)
) {
self[key || _header] = normalizeValue(_value);
}
}
const setHeaders = (headers, _rewrite) =>
utils$1.forEach(headers, (_value, _header) => setHeader(_value, _header, _rewrite));
if (utils$1.isPlainObject(header) || header instanceof this.constructor) {
setHeaders(header, valueOrRewrite);
} else if (utils$1.isString(header) && (header = header.trim()) && !isValidHeaderName(header)) {
setHeaders(parseHeaders(header), valueOrRewrite);
} else if (utils$1.isObject(header) && utils$1.isSafeIterable(header)) {
let obj = Object.create(null),
dest,
key;
for (const entry of header) {
if (!utils$1.isArray(entry)) {
throw new TypeError('Object iterator must return a key-value pair');
}
key = entry[0];
if (utils$1.hasOwnProp(obj, key)) {
dest = obj[key];
obj[key] = utils$1.isArray(dest) ? [...dest, entry[1]] : [dest, entry[1]];
} else {
obj[key] = entry[1];
}
}
setHeaders(obj, valueOrRewrite);
} else {
header != null && setHeader(valueOrRewrite, header, rewrite);
}
return this;
}
get(header, parser) {
header = normalizeHeader(header);
if (header) {
const key = utils$1.findKey(this, header);
if (key) {
const value = this[key];
if (!parser) {
return value;
}
if (parser === true) {
return parseTokens(value);
}
if (utils$1.isFunction(parser)) {
return parser.call(this, value, key);
}
if (utils$1.isRegExp(parser)) {
return parser.exec(value);
}
throw new TypeError('parser must be boolean|regexp|function');
}
}
}
has(header, matcher) {
header = normalizeHeader(header);
if (header) {
const key = utils$1.findKey(this, header);
return !!(
key &&
this[key] !== undefined &&
(!matcher || matchHeaderValue(this, this[key], key, matcher))
);
}
return false;
}
delete(header, matcher) {
const self = this;
let deleted = false;
function deleteHeader(_header) {
_header = normalizeHeader(_header);
if (_header) {
const key = utils$1.findKey(self, _header);
if (key && (!matcher || matchHeaderValue(self, self[key], key, matcher))) {
delete self[key];
deleted = true;
}
}
}
if (utils$1.isArray(header)) {
header.forEach(deleteHeader);
} else {
deleteHeader(header);
}
return deleted;
}
clear(matcher) {
const keys = Object.keys(this);
let i = keys.length;
let deleted = false;
while (i--) {
const key = keys[i];
if (!matcher || matchHeaderValue(this, this[key], key, matcher, true)) {
delete this[key];
deleted = true;
}
}
return deleted;
}
normalize(format) {
const self = this;
const headers = {};
utils$1.forEach(this, (value, header) => {
const key = utils$1.findKey(headers, header);
if (key) {
self[key] = normalizeValue(value);
delete self[header];
return;
}
const normalized = format ? formatHeader(header) : String(header).trim();
if (normalized !== header) {
delete self[header];
}
self[normalized] = normalizeValue(value);
headers[normalized] = true;
});
return this;
}
concat(...targets) {
return this.constructor.concat(this, ...targets);
}
toJSON(asStrings) {
const obj = Object.create(null);
utils$1.forEach(this, (value, header) => {
value != null &&
value !== false &&
(obj[header] = asStrings && utils$1.isArray(value) ? value.join(', ') : value);
});
return obj;
}
[Symbol.iterator]() {
return Object.entries(this.toJSON())[Symbol.iterator]();
}
toString() {
return Object.entries(this.toJSON())
.map(([header, value]) => header + ': ' + value)
.join('\n');
}
getSetCookie() {
const value = this.get('set-cookie');
return utils$1.isArray(value) ? value : value == null || value === false ? [] : [value];
}
get [Symbol.toStringTag]() {
return 'AxiosHeaders';
}
static from(thing) {
return thing instanceof this ? thing : new this(thing);
}
static parseParameters(value) {
return parseParameters(value);
}
static concat(first, ...targets) {
const computed = new this(first);
targets.forEach((target) => computed.set(target));
return computed;
}
static accessor(header) {
const internals =
(this[$internals] =
this[$internals] =
{
accessors: {},
});
const accessors = internals.accessors;
const prototype = this.prototype;
function defineAccessor(_header) {
const lHeader = normalizeHeader(_header);
if (!accessors[lHeader]) {
buildAccessors(prototype, _header);
accessors[lHeader] = true;
}
}
utils$1.isArray(header) ? header.forEach(defineAccessor) : defineAccessor(header);
return this;
}
};
AxiosHeaders$1.accessor([
'Content-Type',
'Content-Length',
'Accept',
'Accept-Encoding',
'User-Agent',
'Authorization',
]);
// reserved names hotfix
utils$1.reduceDescriptors(AxiosHeaders$1.prototype, ({ value }, key) => {
let mapped = key[0].toUpperCase() + key.slice(1); // map `set` => `Set`
return {
get: () => value,
set(headerValue) {
this[mapped] = headerValue;
},
};
});
utils$1.freezeMethods(AxiosHeaders$1);
const REDACTED = '[REDACTED ****]';
function hasOwnOrPrototypeToJSON(source) {
if (utils$1.hasOwnProp(source, 'toJSON')) {
return true;
}
let prototype = Object.getPrototypeOf(source);
while (prototype && prototype !== Object.prototype) {
if (utils$1.hasOwnProp(prototype, 'toJSON')) {
return true;
}
prototype = Object.getPrototypeOf(prototype);
}
return false;
}
// Build a plain-object snapshot of `config` and replace the value of any key
// (case-insensitive) listed in `redactKeys` with REDACTED. Walks through arrays
// and AxiosHeaders, and short-circuits on circular references.
function redactConfig(config, redactKeys) {
const lowerKeys = new Set(redactKeys.map((k) => String(k).toLowerCase()));
const seen = [];
const visit = (source) => {
if (source === null || typeof source !== 'object') return source;
if (utils$1.isBuffer(source)) return source;
if (seen.indexOf(source) !== -1) return undefined;
if (source instanceof AxiosHeaders$1) {
source = source.toJSON();
}
seen.push(source);
let result;
if (utils$1.isArray(source)) {
result = [];
source.forEach((v, i) => {
const reducedValue = visit(v);
if (!utils$1.isUndefined(reducedValue)) {
result[i] = reducedValue;
}
});
} else {
if (!utils$1.isPlainObject(source) && hasOwnOrPrototypeToJSON(source)) {
seen.pop();
return source;
}
result = Object.create(null);
for (const [key, value] of Object.entries(source)) {
const reducedValue = lowerKeys.has(key.toLowerCase()) ? REDACTED : visit(value);
if (!utils$1.isUndefined(reducedValue)) {
result[key] = reducedValue;
}
}
}
seen.pop();
return result;
};
return visit(config);
}
function stringifySafely$1(value) {
try {
return String(value);
} catch (err) {
return '';
}
}
function aggregateErrorMessage(error) {
const message = error.errors
.map((entry) => {
try {
return entry && entry.message ? stringifySafely$1(entry.message) : stringifySafely$1(entry);
} catch (err) {
return '';
}
})
.filter(Boolean)
.join('; ');
return message || error.name || 'AggregateError';
}
let AxiosError$1 = class AxiosError extends Error {
static from(error, code, config, request, response, customProps) {
// `AggregateError` (thrown by Node on dual-stack/Happy-Eyeballs connection
// failures) has an empty `message`; its detail lives in `errors[]`. Without
// this, the wrapped error surfaces with a blank message (see #6721).
let message = error.message;
if (!message && utils$1.isArray(error.errors) && error.errors.length) {
message = aggregateErrorMessage(error);
}
const axiosError = new AxiosError(message, code || error.code, config, request, response);
// Match native `Error` `cause` semantics: non-enumerable. The wrapped
// error often carries circular internals (sockets, requests, agents), so
// an enumerable `cause` makes structured loggers (pino/winston) and any
// own-property walk throw "Converting circular structure to JSON".
// Regression from #6982; see #7205. `__proto__: null` mirrors the
// `message` descriptor below (prototype-pollution-safe descriptor).
Object.defineProperty(axiosError, 'cause', {
__proto__: null,
value: error,
writable: true,
enumerable: false,
configurable: true,
});
axiosError.name = error.name;
// Preserve status from the original error if not already set from response
if (error.status != null && axiosError.status == null) {
axiosError.status = error.status;
}
customProps && Object.assign(axiosError, customProps);
return axiosError;
}
/**
* Create an Error with the specified message, config, error code, request and response.
*
* @param {string} message The error message.
* @param {string} [code] The error code (for example, 'ECONNABORTED').
* @param {Object} [config] The config.
* @param {Object} [request] The request.
* @param {Object} [response] The response.
*
* @returns {Error} The created error.
*/
constructor(message, code, config, request, response) {
super(message);
// Make message enumerable to maintain backward compatibility
// The native Error constructor sets message as non-enumerable,
// but axios < v1.13.3 had it as enumerable
Object.defineProperty(this, 'message', {
// Null-proto descriptor so a polluted Object.prototype.get cannot turn
// this data descriptor into an accessor descriptor on the way in.
__proto__: null,
value: message,
enumerable: true,
writable: true,
configurable: true,
});
this.name = 'AxiosError';
this.isAxiosError = true;
code && (this.code = code);
config && (this.config = config);
request && (this.request = request);
if (response) {
this.response = response;
this.status = response.status;
}
}
toJSON() {
// Opt-in redaction: when the request config carries a `redact` array, the
// value of any matching key (case-insensitive, at any depth) is replaced
// with REDACTED in the serialized snapshot. Undefined or empty leaves the
// existing serialization behavior unchanged.
const config = this.config;
const redactKeys = config && utils$1.hasOwnProp(config, 'redact') ? config.redact : undefined;
const serializedConfig =
utils$1.isArray(redactKeys) && redactKeys.length > 0
? redactConfig(config, redactKeys)
: utils$1.toJSONObject(config);
return {
// Standard
message: this.message,
name: this.name,
// Microsoft
description: this.description,
number: this.number,
// Mozilla
fileName: this.fileName,
lineNumber: this.lineNumber,
columnNumber: this.columnNumber,
stack: this.stack,
// Axios
config: serializedConfig,
code: this.code,
status: this.status,
};
}
};
// This can be changed to static properties as soon as the parser options in .eslint.cjs are updated.
AxiosError$1.ERR_BAD_OPTION_VALUE = 'ERR_BAD_OPTION_VALUE';
AxiosError$1.ERR_BAD_OPTION = 'ERR_BAD_OPTION';
AxiosError$1.ECONNABORTED = 'ECONNABORTED';
AxiosError$1.ETIMEDOUT = 'ETIMEDOUT';
AxiosError$1.ECONNREFUSED = 'ECONNREFUSED';
AxiosError$1.ERR_NETWORK = 'ERR_NETWORK';
AxiosError$1.ERR_FR_TOO_MANY_REDIRECTS = 'ERR_FR_TOO_MANY_REDIRECTS';
AxiosError$1.ERR_DEPRECATED = 'ERR_DEPRECATED';
AxiosError$1.ERR_BAD_RESPONSE = 'ERR_BAD_RESPONSE';
AxiosError$1.ERR_BAD_REQUEST = 'ERR_BAD_REQUEST';
AxiosError$1.ERR_CANCELED = 'ERR_CANCELED';
AxiosError$1.ERR_NOT_SUPPORT = 'ERR_NOT_SUPPORT';
AxiosError$1.ERR_INVALID_URL = 'ERR_INVALID_URL';
AxiosError$1.ERR_FORM_DATA_DEPTH_EXCEEDED = 'ERR_FORM_DATA_DEPTH_EXCEEDED';
// eslint-disable-next-line strict
const httpAdapter = null;
// Default nesting limit shared with the inverse transform (formDataToJSON) so
// the FormData <-> JSON round-trip stays symmetric.
const DEFAULT_FORM_DATA_MAX_DEPTH = 100;
/**
* Determines if the given thing is a array or js object.
*
* @param {string} thing - The object or array to be visited.
*
* @returns {boolean}
*/
function isVisitable(thing) {
return utils$1.isPlainObject(thing) || utils$1.isArray(thing);
}
/**
* It removes the brackets from the end of a string
*
* @param {string} key - The key of the parameter.
*
* @returns {string} the key without the brackets.
*/
function removeBrackets(key) {
return utils$1.endsWith(key, '[]') ? key.slice(0, -2) : key;
}
/**
* It takes a path, a key, and a boolean, and returns a string
*
* @param {string} path - The path to the current key.
* @param {string} key - The key of the current object being iterated over.
* @param {string} dots - If true, the key will be rendered with dots instead of brackets.
*
* @returns {string} The path to the current key.
*/
function renderKey(path, key, dots) {
if (!path) return key;
return path
.concat(key)
.map(function each(token, i) {
// eslint-disable-next-line no-param-reassign
token = removeBrackets(token);
return !dots && i ? '[' + token + ']' : token;
})
.join(dots ? '.' : '');
}
/**
* If the array is an array and none of its elements are visitable, then it's a flat array.
*
* @param {Array<any>} arr - The array to check
*
* @returns {boolean}
*/
function isFlatArray(arr) {
return utils$1.isArray(arr) && !arr.some(isVisitable);
}
const predicates = utils$1.toFlatObject(utils$1, {}, null, function filter(prop) {
return /^is[A-Z]/.test(prop);
});
/**
* Convert a data object to FormData
*
* @param {Object} obj
* @param {?Object} [formData]
* @param {?Object} [options]
* @param {Function} [options.visitor]
* @param {Boolean} [options.metaTokens = true]
* @param {Boolean} [options.dots = false]
* @param {?Boolean} [options.indexes = false]
*
* @returns {Object}
**/
/**
* It converts an object into a FormData object
*
* @param {Object<any, any>} obj - The object to convert to form data.
* @param {string} formData - The FormData object to append to.
* @param {Object<string, any>} options
*
* @returns
*/
function toFormData$1(obj, formData, options) {
if (!utils$1.isObject(obj)) {
throw new TypeError('target must be an object');
}
// eslint-disable-next-line no-param-reassign
formData = formData || new (FormData)();
// eslint-disable-next-line no-param-reassign
options = utils$1.toFlatObject(
options,
{
metaTokens: true,
dots: false,
indexes: false,
},
false,
function defined(option, source) {
// eslint-disable-next-line no-eq-null,eqeqeq
return !utils$1.isUndefined(source[option]);
}
);
const metaTokens = options.metaTokens;
// eslint-disable-next-line no-use-before-define
const visitor = options.visitor || defaultVisitor;
const dots = options.dots;
const indexes = options.indexes;
const _Blob = options.Blob || (typeof Blob !== 'undefined' && Blob);
const maxDepth = options.maxDepth === undefined ? DEFAULT_FORM_DATA_MAX_DEPTH : options.maxDepth;
const useBlob = _Blob && utils$1.isSpecCompliantForm(formData);
const stack = [];
if (!utils$1.isFunction(visitor)) {
throw new TypeError('visitor must be a function');
}
function convertValue(value) {
if (value === null) return '';
if (utils$1.isDate(value)) {
return value.toISOString();
}
if (utils$1.isBoolean(value)) {
return value.toString();
}
if (!useBlob && utils$1.isBlob(value)) {
throw new AxiosError$1('Blob is not supported. Use a Buffer instead.');
}
if (utils$1.isArrayBuffer(value) || utils$1.isTypedArray(value)) {
if (useBlob && typeof _Blob === 'function') {
return new _Blob([value]);
}
throw new AxiosError$1('Blob is not supported. Use a Buffer instead.', AxiosError$1.ERR_NOT_SUPPORT);
}
return value;
}
function throwIfMaxDepthExceeded(depth) {
if (depth > maxDepth) {
throw new AxiosError$1(
'Object is too deeply nested (' + depth + ' levels). Max depth: ' + maxDepth,
AxiosError$1.ERR_FORM_DATA_DEPTH_EXCEEDED
);
}
}
function stringifyWithDepthLimit(value, depth) {
if (maxDepth === Infinity) {
return JSON.stringify(value);
}
const ancestors = [];
return JSON.stringify(value, function limitDepth(_key, currentValue) {
if (!utils$1.isObject(currentValue)) {
return currentValue;
}
while (ancestors.length && ancestors[ancestors.length - 1] !== this) {
ancestors.pop();
}
ancestors.push(currentValue);
throwIfMaxDepthExceeded(depth + ancestors.length - 1);
return currentValue;
});
}
/**
* Default visitor.
*
* @param {*} value
* @param {String|Number} key
* @param {Array<String|Number>} path
* @this {FormData}
*
* @returns {boolean} return true to visit the each prop of the value recursively
*/
function defaultVisitor(value, key, path) {
let arr = value;
if (utils$1.isReactNative(formData) && utils$1.isReactNativeBlob(value)) {
formData.append(renderKey(path, key, dots), convertValue(value));
return false;
}
if (value && !path && typeof value === 'object') {
if (utils$1.endsWith(key, '{}')) {
// eslint-disable-next-line no-param-reassign
key = metaTokens ? key : key.slice(0, -2);
// eslint-disable-next-line no-param-reassign
value = stringifyWithDepthLimit(value, 1);
} else if (
(utils$1.isArray(value) && isFlatArray(value)) ||
((utils$1.isFileList(value) || utils$1.endsWith(key, '[]')) && (arr = utils$1.toArray(value)))
) {
// eslint-disable-next-line no-param-reassign
key = removeBrackets(key);
arr.forEach(function each(el, index) {
!(utils$1.isUndefined(el) || el === null) &&
formData.append(
// eslint-disable-next-line no-nested-ternary
indexes === true
? renderKey([key], index, dots)
: indexes === null
? key
: key + '[]',
convertValue(el)
);
});
return false;
}
}
if (isVisitable(value)) {
return true;
}
formData.append(renderKey(path, key, dots), convertValue(value));
return false;
}
const exposedHelpers = Object.assign(predicates, {
defaultVisitor,
convertValue,
isVisitable,
});
function build(value, path, depth = 0) {
if (utils$1.isUndefined(value)) return;
throwIfMaxDepthExceeded(depth);
if (stack.indexOf(value) !== -1) {
throw new Error('Circular reference detected in ' + path.join('.'));
}
stack.push(value);
utils$1.forEach(value, function each(el, key) {
const result =
!(utils$1.isUndefined(el) || el === null) &&
visitor.call(formData, el, utils$1.isString(key) ? key.trim() : key, path, exposedHelpers);
if (result === true) {
build(el, path ? path.concat(key) : [key], depth + 1);
}
});
stack.pop();
}
if (!utils$1.isObject(obj)) {
throw new TypeError('data must be an object');
}
build(obj);
return formData;
}
/**
* It encodes a string by replacing all characters that are not in the unreserved set with
* their percent-encoded equivalents
*
* @param {string} str - The string to encode.
*
* @returns {string} The encoded string.
*/
function encode$2(str) {
const charMap = {
'!': '%21',
"'": '%27',
'(': '%28',
')': '%29',
'~': '%7E',
'%20': '+',
};
return encodeURIComponent(str).replace(/[!'()~]|%20/g, function replacer(match) {
return charMap[match];
});
}
/**
* It takes a params object and converts it to a FormData object
*
* @param {Object<string, any>} params - The parameters to be converted to a FormData object.
* @param {Object<string, any>} options - The options object passed to the Axios constructor.
*
* @returns {void}
*/
function AxiosURLSearchParams(params, options) {
this._pairs = [];
params && toFormData$1(params, this, options);
}
const prototype = AxiosURLSearchParams.prototype;
prototype.append = function append(name, value) {
this._pairs.push([name, value]);
};
prototype.toString = function toString(encoder) {
const _encode = encoder
? (value) => encoder.call(this, value, encode$2)
: encode$2;
return this._pairs
.map(function each(pair) {
return _encode(pair[0]) + '=' + _encode(pair[1]);
}, '')
.join('&');
};
/**
* It replaces URL-encoded forms of `:`, `$`, `,`, and spaces with
* their plain counterparts (`:`, `$`, `,`, `+`).
*
* @param {string} val The value to be encoded.
*
* @returns {string} The encoded value.
*/
function encode$1(val) {
return encodeURIComponent(val)
.replace(/%3A/gi, ':')
.replace(/%24/g, '$')
.replace(/%2C/gi, ',')
.replace(/%20/g, '+');
}
/**
* Build a URL by appending params to the end
*
* @param {string} url The base of the url (e.g., http://www.google.com)
* @param {object} [params] The params to be appended
* @param {?(object|Function)} options
*
* @returns {string} The formatted url
*/
function buildURL(url, params, options) {
if (!params) {
return url;
}
url = url || '';
const _options = utils$1.isFunction(options)
? {
serialize: options,
}
: options;
// Read serializer options pollution-safely: own properties and methods on a
// class/template prototype are honored, but values injected onto a polluted
// Object.prototype are ignored.
const _encode = utils$1.getSafeProp(_options, 'encode') || encode$1;
const serializeFn = utils$1.getSafeProp(_options, 'serialize');
let serializedParams;
if (serializeFn) {
serializedParams = serializeFn(params, _options);
} else {
serializedParams = utils$1.isURLSearchParams(params)
? params.toString()
: new AxiosURLSearchParams(params, _options).toString(_encode);
}
if (serializedParams) {
const hashmarkIndex = url.indexOf('#');
if (hashmarkIndex !== -1) {
url = url.slice(0, hashmarkIndex);
}
url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams;
}
return url;
}
class InterceptorManager {
constructor() {
this.handlers = [];
}
/**
* Add a new interceptor to the stack
*
* @param {Function} fulfilled The function to handle `then` for a `Promise`
* @param {Function} rejected The function to handle `reject` for a `Promise`
* @param {Object} options The options for the interceptor, synchronous and runWhen
*
* @return {Number} An ID used to remove interceptor later
*/
use(fulfilled, rejected, options) {
this.handlers.push({
fulfilled,
rejected,
synchronous: options ? options.synchronous : false,
runWhen: options ? options.runWhen : null,
});
return this.handlers.length - 1;
}
/**
* Remove an interceptor from the stack
*
* @param {Number} id The ID that was returned by `use`
*
* @returns {void}
*/
eject(id) {
if (this.handlers[id]) {
this.handlers[id] = null;
}
}
/**
* Clear all interceptors from the stack
*
* @returns {void}
*/
clear() {
if (this.handlers) {
this.handlers = [];
}
}
/**
* Iterate over all the registered interceptors
*
* This method is particularly useful for skipping over any
* interceptors that may have become `null` calling `eject`.
*
* @param {Function} fn The function to call for each interceptor
*
* @returns {void}
*/
forEach(fn) {
utils$1.forEach(this.handlers, function forEachHandler(h) {
if (h !== null) {
fn(h);
}
});
}
}
const transitionalDefaults = {
silentJSONParsing: true,
forcedJSONParsing: true,
clarifyTimeoutError: false,
legacyInterceptorReqResOrdering: true,
advertiseZstdAcceptEncoding: false,
validateStatusUndefinedResolves: true,
};
const URLSearchParams$1 = typeof URLSearchParams !== 'undefined' ? URLSearchParams : AxiosURLSearchParams;
const FormData$1 = typeof FormData !== 'undefined' ? FormData : null;
const Blob$1 = typeof Blob !== 'undefined' ? Blob : null;
const platform$1 = {
isBrowser: true,
classes: {
URLSearchParams: URLSearchParams$1,
FormData: FormData$1,
Blob: Blob$1,
},
protocols: ['http', 'https', 'file', 'blob', 'url', 'data'],
};
const hasBrowserEnv = typeof window !== 'undefined' && typeof document !== 'undefined';
const _navigator = (typeof navigator === 'object' && navigator) || undefined;
/**
* Determine if we're running in a standard browser environment
*
* This allows axios to run in a web worker, and react-native.
* Both environments support XMLHttpRequest, but not fully standard globals.
*
* web workers:
* typeof window -> undefined
* typeof document -> undefined
*
* react-native:
* navigator.product -> 'ReactNative'
* nativescript
* navigator.product -> 'NativeScript' or 'NS'
*
* @returns {boolean}
*/
const hasStandardBrowserEnv =
hasBrowserEnv &&
(!_navigator || ['ReactNative', 'NativeScript', 'NS'].indexOf(_navigator.product) < 0);
/**
* Determine if we're running in a standard browser webWorker environment
*
* Although the `isStandardBrowserEnv` method indicates that
* `allows axios to run in a web worker`, the WebWorker will still be
* filtered out due to its judgment standard
* `typeof window !== 'undefined' && typeof document !== 'undefined'`.
* This leads to a problem when axios post `FormData` in webWorker
*/
const hasStandardBrowserWebWorkerEnv = (() => {
return (
typeof WorkerGlobalScope !== 'undefined' &&
// eslint-disable-next-line no-undef
self instanceof WorkerGlobalScope &&
typeof self.importScripts === 'function'
);
})();
const origin = (hasBrowserEnv && window.location.href) || 'http://localhost';
const utils = {
__proto__: null,
hasBrowserEnv: hasBrowserEnv,
hasStandardBrowserEnv: hasStandardBrowserEnv,
hasStandardBrowserWebWorkerEnv: hasStandardBrowserWebWorkerEnv,
navigator: _navigator,
origin: origin
};
const platform = {
...utils,
...platform$1,
};
function toURLEncodedForm(data, options) {
return toFormData$1(data, new platform.classes.URLSearchParams(), {
visitor: function (value, key, path, helpers) {
if (platform.isNode && utils$1.isBuffer(value)) {
this.append(key, value.toString('base64'));
return false;
}
return helpers.defaultVisitor.apply(this, arguments);
},
...options,
});
}
const MAX_DEPTH = DEFAULT_FORM_DATA_MAX_DEPTH;
function throwIfDepthExceeded(index) {
if (index > MAX_DEPTH) {
throw new AxiosError$1(
'FormData field is too deeply nested (' + index + ' levels). Max depth: ' + MAX_DEPTH,
AxiosError$1.ERR_FORM_DATA_DEPTH_EXCEEDED
);
}
}
/**
* It takes a string like `foo[x][y][z]` and returns an array like `['foo', 'x', 'y', 'z']
*
* @param {string} name - The name of the property to get.
*
* @returns An array of strings.
*/
function parsePropPath(name) {
// foo[x][y][z] -> ['foo', 'x', 'y', 'z']
// foo.x.y.z -> ['foo', 'x', 'y', 'z']
// A path is split on `.` and on `[...]` groups. A segment — whether written
// in dot notation or captured inside brackets — may contain any character
// except `.`, `[` and `]`, so a key like `user-name` or `user name` is kept
// literal instead of being split (#5402). `.`, `[` and `]` keep their existing
// meaning, e.g. `foo[bar.baz]` -> ['foo', 'bar', 'baz'] and `[]` is an array push.
// Excluding `[` from the bracket group also makes the match fail fast at the
// next `[`, so a malformed name cannot rescan to the end of the string from
// every unmatched `[` — parsing stays linear in the length of the name.
const path = [];
const pattern = /[^.[\]]+|\[([^.[\]]*)]/g;
let match;
while ((match = pattern.exec(name)) !== null) {
throwIfDepthExceeded(path.length);
path.push(match[0] === '[]' ? '' : match[1] || match[0]);
}
return path;
}
/**
* Convert an array to an object.
*
* @param {Array<any>} arr - The array to convert to an object.
*
* @returns An object with the same keys and values as the array.
*/
function arrayToObject(arr) {
const obj = {};
const keys = Object.keys(arr);
let i;
const len = keys.length;
let key;
for (i = 0; i < len; i++) {
key = keys[i];
obj[key] = arr[key];
}
return obj;
}
/**
* It takes a FormData object and returns a JavaScript object
*
* @param {string} formData The FormData object to convert to JSON.
*
* @returns {Object<string, any> | null} The converted object.
*/
function formDataToJSON(formData) {
function buildPath(path, value, target, index) {
throwIfDepthExceeded(index);
let name = path[index++];
if (name === '__proto__') return true;
const isNumericKey = Number.isFinite(+name);
const isLast = index >= path.length;
name = !name && utils$1.isArray(target) ? target.length : name;
if (isLast) {
if (utils$1.hasOwnProp(target, name)) {
target[name] = utils$1.isArray(target[name])
? target[name].concat(value)
: [target[name], value];
} else {
target[name] = value;
}
return !isNumericKey;
}
if (!utils$1.hasOwnProp(target, name) || !utils$1.isObject(target[name])) {
target[name] = [];
}
const result = buildPath(path, value, target[name], index);
if (result && utils$1.isArray(target[name])) {
target[name] = arrayToObject(target[name]);
}
return !isNumericKey;
}
if (utils$1.isFormData(formData) && utils$1.isFunction(formData.entries)) {
const obj = {};
utils$1.forEachEntry(formData, (name, value) => {
buildPath(parsePropPath(name), value, obj, 0);
});
return obj;
}
return null;
}
const own = (obj, key) => (obj != null && utils$1.hasOwnProp(obj, key) ? obj[key] : undefined);
/**
* It takes a string, tries to parse it, and if it fails, it returns the stringified version
* of the input
*
* @param {any} rawValue - The value to be stringified.
* @param {Function} parser - A function that parses a string into a JavaScript object.
* @param {Function} encoder - A function that takes a value and returns a string.
*
* @returns {string} A stringified version of the rawValue.
*/
function stringifySafely(rawValue, parser, encoder) {
if (utils$1.isString(rawValue)) {
try {
(parser || JSON.parse)(rawValue);
return utils$1.trim(rawValue);
} catch (e) {
if (e.name !== 'SyntaxError') {
throw e;
}
}
}
return (encoder || JSON.stringify)(rawValue);
}
const defaults$1 = {
transitional: transitionalDefaults,
adapter: ['xhr', 'http', 'fetch'],
transformRequest: [
function transformRequest(data, headers) {
const contentType = headers.getContentType() || '';
const hasJSONContentType = contentType.indexOf('application/json') > -1;
const isObjectPayload = utils$1.isObject(data);
if (isObjectPayload && utils$1.isHTMLForm(data)) {
data = new FormData(data);
}
const isFormData = utils$1.isFormData(data);
if (isFormData) {
return hasJSONContentType ? JSON.stringify(formDataToJSON(data)) : data;
}
if (
utils$1.isArrayBuffer(data) ||
utils$1.isBuffer(data) ||
utils$1.isStream(data) ||
utils$1.isFile(data) ||
utils$1.isBlob(data) ||
utils$1.isReadableStream(data)
) {
return data;
}
if (utils$1.isArrayBufferView(data)) {
return data.buffer;
}
if (utils$1.isURLSearchParams(data)) {
headers.setContentType('application/x-www-form-urlencoded;charset=utf-8', false);
return data.toString();
}
let isFileList;
if (isObjectPayload) {
const formSerializer = own(this, 'formSerializer');
if (contentType.indexOf('application/x-www-form-urlencoded') > -1) {
return toURLEncodedForm(data, formSerializer).toString();
}
if (
(isFileList = utils$1.isFileList(data)) ||
contentType.indexOf('multipart/form-data') > -1
) {
const env = own(this, 'env');
const _FormData = env && env.FormData;
return toFormData$1(
isFileList ? { 'files[]': data } : data,
_FormData && new _FormData(),
formSerializer
);
}
}
if (isObjectPayload || hasJSONContentType) {
headers.setContentType('application/json', false);
return stringifySafely(data);
}
return data;
},
],
transformResponse: [
function transformResponse(data) {
const transitional = own(this, 'transitional') || defaults$1.transitional;
const forcedJSONParsing = transitional && transitional.forcedJSONParsing;
const responseType = own(this, 'responseType');
const JSONRequested = responseType === 'json';
if (utils$1.isResponse(data) || utils$1.isReadableStream(data)) {
return data;
}
if (
data &&
utils$1.isString(data) &&
((forcedJSONParsing && !responseType) || JSONRequested)
) {
const silentJSONParsing = transitional && transitional.silentJSONParsing;
const strictJSONParsing = !silentJSONParsing && JSONRequested;
try {
return JSON.parse(data, own(this, 'parseReviver'));
} catch (e) {
if (strictJSONParsing) {
if (e.name === 'SyntaxError') {
throw AxiosError$1.from(e, AxiosError$1.ERR_BAD_RESPONSE, this, null, own(this, 'response'));
}
throw e;
}
}
}
return data;
},
],
/**
* A timeout in milliseconds to abort a request. If set to 0 (default) a
* timeout is not created.
*/
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
env: {
FormData: platform.classes.FormData,
Blob: platform.classes.Blob,
},
validateStatus: function validateStatus(status) {
return status >= 200 && status < 300;
},
headers: {
common: {
Accept: 'application/json, text/plain, */*',
'Content-Type': undefined,
},
},
};
utils$1.forEach(['delete', 'get', 'head', 'post', 'put', 'patch', 'query'], (method) => {
defaults$1.headers[method] = {};
});
/**
* Transform the data for a request or a response
*
* @param {Array|Function} fns A single function or Array of functions
* @param {?Object} response The response object
*
* @returns {*} The resulting transformed data
*/
function transformData(fns, response) {
const config = this || defaults$1;
const context = response || config;
const headers = AxiosHeaders$1.from(context.headers);
let data = context.data;
utils$1.forEach(fns, function transform(fn) {
data = fn.call(config, data, headers.normalize(), response ? response.status : undefined);
});
headers.normalize();
return data;
}
function isCancel$1(value) {
return !!(value && value.__CANCEL__);
}
let CanceledError$1 = class CanceledError extends AxiosError$1 {
/**
* A `CanceledError` is an object that is thrown when an operation is canceled.
*
* @param {string=} message The message.
* @param {Object=} config The config.
* @param {Object=} request The request.
*
* @returns {CanceledError} The created error.
*/
constructor(message, config, request) {
super(message == null ? 'canceled' : message, AxiosError$1.ERR_CANCELED, config, request);
this.name = 'CanceledError';
this.__CANCEL__ = true;
}
};
/**
* Resolve or reject a Promise based on response status.
*
* @param {Function} resolve A function that resolves the promise.
* @param {Function} reject A function that rejects the promise.
* @param {object} response The response.
*
* @returns {object} The response.
*/
function settle(resolve, reject, response) {
const validateStatus = response.config.validateStatus;
if (!response.status || !validateStatus || validateStatus(response.status)) {
resolve(response);
} else {
reject(new AxiosError$1(
'Request failed with status code ' + response.status,
response.status >= 400 && response.status < 500 ? AxiosError$1.ERR_BAD_REQUEST : AxiosError$1.ERR_BAD_RESPONSE,
response.config,
response.request,
response
));
}
}
function parseProtocol(url) {
const match = /^([-+\w]{1,25}):(?:\/\/)?/.exec(url);
return (match && match[1]) || '';
}
/**
* Calculate data maxRate
* @param {Number} [samplesCount= 10]
* @param {Number} [min= 1000]
* @returns {Function}
*/
function speedometer(samplesCount, min) {
samplesCount = samplesCount || 10;
const bytes = new Array(samplesCount);
const timestamps = new Array(samplesCount);
let head = 0;
let tail = 0;
let firstSampleTS;
min = min !== undefined ? min : 1000;
return function push(chunkLength) {
const now = Date.now();
const startedAt = timestamps[tail];
if (!firstSampleTS) {
firstSampleTS = now;
}
bytes[head] = chunkLength;
timestamps[head] = now;
let i = tail;
let bytesCount = 0;
while (i !== head) {
bytesCount += bytes[i++];
i = i % samplesCount;
}
head = (head + 1) % samplesCount;
if (head === tail) {
tail = (tail + 1) % samplesCount;
}
if (now - firstSampleTS < min) {
return;
}
const passed = startedAt && now - startedAt;
return passed ? Math.round((bytesCount * 1000) / passed) : undefined;
};
}
/**
* Throttle decorator
* @param {Function} fn
* @param {Number} freq
* @return {Function}
*/
function throttle(fn, freq) {
let timestamp = 0;
let threshold = 1000 / freq;
let lastArgs;
let timer;
const invoke = (args, now = Date.now()) => {
timestamp = now;
lastArgs = null;
if (timer) {
clearTimeout(timer);
timer = null;
}
fn(...args);
};
const throttled = (...args) => {
const now = Date.now();
const passed = now - timestamp;
if (passed >= threshold) {
invoke(args, now);
} else {
lastArgs = args;
if (!timer) {
timer = setTimeout(() => {
timer = null;
invoke(lastArgs);
}, threshold - passed);
}
}
};
const flush = () => lastArgs && invoke(lastArgs);
return [throttled, flush];
}
const progressEventReducer = (listener, isDownloadStream, freq = 3) => {
let bytesNotified = 0;
const _speedometer = speedometer(50, 250);
return throttle((e) => {
if (!e || typeof e.loaded !== 'number') {
return;
}
const rawLoaded = e.loaded;
const total = e.lengthComputable ? e.total : undefined;
const loaded = Math.max(0, total != null ? Math.min(rawLoaded, total) : rawLoaded);
const progressBytes = Math.max(0, loaded - bytesNotified);
const rate = _speedometer(progressBytes);
bytesNotified = Math.max(bytesNotified, loaded);
const data = {
loaded,
total,
progress: total ? loaded / total : undefined,
bytes: progressBytes,
rate: rate ? rate : undefined,
estimated: rate && total ? (total - loaded) / rate : undefined,
event: e,
lengthComputable: total != null,
[isDownloadStream ? 'download' : 'upload']: true,
};
listener(data);
}, freq);
};
const progressEventDecorator = (total, throttled) => {
const lengthComputable = total != null;
return [
(loaded) =>
throttled[0]({
lengthComputable,
total,
loaded,
}),
throttled[1],
];
};
const asyncDecorator =
(fn, scheduler = utils$1.asap) =>
(...args) =>
scheduler(() => fn(...args));
const isURLSameOrigin = platform.hasStandardBrowserEnv
? ((origin, isMSIE) => (url) => {
url = new URL(url, platform.origin);
return (
origin.protocol === url.protocol &&
origin.host === url.host &&
(isMSIE || origin.port === url.port)
);
})(
new URL(platform.origin),
platform.navigator && /(msie|trident)/i.test(platform.navigator.userAgent)
)
: () => true;
const cookies = platform.hasStandardBrowserEnv
? // Standard browser envs support document.cookie
{
write(name, value, expires, path, domain, secure, sameSite) {
if (typeof document === 'undefined') return;
const cookie = [`${name}=${encodeURIComponent(value)}`];
if (utils$1.isNumber(expires)) {
cookie.push(`expires=${new Date(expires).toUTCString()}`);
}
if (utils$1.isString(path)) {
cookie.push(`path=${path}`);
}
if (utils$1.isString(domain)) {
cookie.push(`domain=${domain}`);
}
if (secure === true) {
cookie.push('secure');
}
if (utils$1.isString(sameSite)) {
cookie.push(`SameSite=${sameSite}`);
}
document.cookie = cookie.join('; ');
},
read(name) {
if (typeof document === 'undefined') return null;
// Match name=value by splitting on the semicolon separator instead of building a
// RegExp from `name` — interpolating an unescaped string into a RegExp would let
// metacharacters (e.g. `.+?` in an attacker-influenced cookie name) cause ReDoS or
// match the wrong cookie. Browsers may serialize cookie pairs as either ";" or
// "; ", so ignore optional whitespace before each cookie name.
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].replace(/^\s+/, '');
const eq = cookie.indexOf('=');
if (eq !== -1 && cookie.slice(0, eq) === name) {
try {
return decodeURIComponent(cookie.slice(eq + 1));
} catch (e) {
return cookie.slice(eq + 1);
}
}
}
return null;
},
remove(name) {
this.write(name, '', Date.now() - 86400000, '/');
},
}
: // Non-standard browser env (web workers, react-native) lack needed support.
{
write() {},
read() {
return null;
},
remove() {},
};
/**
* Determines whether the specified URL is absolute
*
* @param {string} url The URL to test
*
* @returns {boolean} True if the specified URL is absolute, otherwise false
*/
function isAbsoluteURL(url) {
// A URL is considered absolute if it begins with "<scheme>://" or "//" (protocol-relative URL).
// RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed
// by any combination of letters, digits, plus, period, or hyphen.
if (typeof url !== 'string') {
return false;
}
return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url);
}
/**
* Creates a new URL by combining the specified URLs
*
* @param {string} baseURL The base URL
* @param {string} relativeURL The relative URL
*
* @returns {string} The combined URL
*/
function combineURLs(baseURL, relativeURL) {
if (!relativeURL) {
return baseURL;
}
let end = baseURL.length;
while (end > 0 && baseURL.charCodeAt(end - 1) === 47) {
end--;
}
return baseURL.slice(0, end) + '/' + relativeURL.replace(/^\/+/, '');
}
const malformedHttpProtocol = /^https?:(?!\/\/)/i;
const httpProtocolControlCharacters = /[\t\n\r]/g;
function stripLeadingC0ControlOrSpace(url) {
let i = 0;
while (i < url.length && url.charCodeAt(i) <= 0x20) {
i++;
}
return url.slice(i);
}
function normalizeURLForProtocolCheck(url) {
return stripLeadingC0ControlOrSpace(url).replace(httpProtocolControlCharacters, '');
}
// Redact the parts of a URL that can carry secrets before it is embedded in an
// error message. AxiosError.toJSON() serializes `message` verbatim and errors
// are commonly logged, while the opt-in `config.redact` model only cleans
// config keys — it cannot reach the message. Redact only the genuinely
// sensitive substrings — userinfo (credentials), query parameter values and
// fragment contents — with the same REDACTED marker the config redaction uses,
// while keeping the scheme, host, path and parameter names so the offending
// request stays accurately identifiable.
function redactFragment(fragment) {
if (!fragment) {
return fragment;
}
return fragment.replace(/(^|&)([^=&]*=)?[^&]+/g, (match, separator, parameterName = '') => {
return `${separator}${parameterName}${REDACTED}`;
});
}
function redactSensitiveURLParts(url) {
const redactedURL = url.replace(/^(https?:\/{0,2})[^/?#]*@/i, `$1${REDACTED}@`);
const fragmentIndex = redactedURL.indexOf('#');
const urlWithoutFragment =
fragmentIndex === -1 ? redactedURL : redactedURL.slice(0, fragmentIndex);
const redactedURLWithoutFragment = urlWithoutFragment.replace(
/([?&][^=&#]*=)[^&#]*/g,
`$1${REDACTED}`
);
if (fragmentIndex === -1) {
return redactedURLWithoutFragment;
}
return `${redactedURLWithoutFragment}#${redactFragment(redactedURL.slice(fragmentIndex + 1))}`;
}
function assertValidHttpProtocolURL(url, config) {
if (typeof url === 'string') {
const normalizedURL = normalizeURLForProtocolCheck(url);
if (malformedHttpProtocol.test(normalizedURL)) {
throw new AxiosError$1(
`Invalid URL ${JSON.stringify(redactSensitiveURLParts(normalizedURL))}: missing "//" after protocol`,
AxiosError$1.ERR_INVALID_URL,
config
);
}
}
}
/**
* Creates a new URL by combining the baseURL with the requestedURL,
* only when the requestedURL is not already an absolute URL.
* If the requestURL is absolute, this function returns the requestedURL untouched.
*
* @param {string} baseURL The base URL
* @param {string} requestedURL Absolute or relative URL to combine
*
* @returns {string} The combined full path
*/
function buildFullPath(baseURL, requestedURL, allowAbsoluteUrls, config) {
assertValidHttpProtocolURL(requestedURL, config);
let isRelativeUrl = !isAbsoluteURL(requestedURL);
if (baseURL && (isRelativeUrl || allowAbsoluteUrls === false)) {
assertValidHttpProtocolURL(baseURL, config);
return combineURLs(baseURL, requestedURL);
}
return requestedURL;
}
const headersToObject = (thing) => (thing instanceof AxiosHeaders$1 ? { ...thing } : thing);
const ownEnumerableKeys = (thing) => {
if (Object.getOwnPropertySymbols && Object.getOwnPropertyDescriptor) {
return Object.keys(thing).concat(
Object.getOwnPropertySymbols(thing).filter(
(symbol) => Object.getOwnPropertyDescriptor(thing, symbol).enumerable
)
);
}
return Object.keys(thing);
};
/**
* Config-specific merge-function which creates a new config-object
* by merging two configuration objects together.
*
* @param {Object} config1
* @param {Object} config2
*
* @returns {Object} New object resulting from merging config2 to config1
*/
function mergeConfig$1(config1, config2) {
// eslint-disable-next-line no-param-reassign
config1 = config1 || {};
config2 = config2 || {};
// Use a null-prototype object so that downstream reads such as `config.auth`
// or `config.baseURL` cannot inherit polluted values from Object.prototype.
// `hasOwnProperty` is restored as a non-enumerable own slot to preserve
// ergonomics for user code that relies on it.
const config = Object.create(null);
Object.defineProperty(config, 'hasOwnProperty', {
// Null-proto descriptor so a polluted Object.prototype.get cannot turn
// this data descriptor into an accessor descriptor on the way in.
__proto__: null,
value: Object.prototype.hasOwnProperty,
enumerable: false,
writable: true,
configurable: true,
});
function getMergedValue(target, source, prop, caseless) {
if (utils$1.isPlainObject(target) && utils$1.isPlainObject(source)) {
return utils$1.merge.call({ caseless }, target, source);
} else if (utils$1.isPlainObject(source)) {
return utils$1.merge({}, source);
} else if (utils$1.isArray(source)) {
return source.slice();
}
return source;
}
function mergeDeepProperties(a, b, prop, caseless) {
if (!utils$1.isUndefined(b)) {
return getMergedValue(a, b, prop, caseless);
} else if (!utils$1.isUndefined(a)) {
return getMergedValue(undefined, a, prop, caseless);
}
}
// eslint-disable-next-line consistent-return
function valueFromConfig2(a, b) {
if (!utils$1.isUndefined(b)) {
return getMergedValue(undefined, b);
}
}
// eslint-disable-next-line consistent-return
function defaultToConfig2(a, b) {
if (!utils$1.isUndefined(b)) {
return getMergedValue(undefined, b);
} else if (!utils$1.isUndefined(a)) {
return getMergedValue(undefined, a);
}
}
function getMergedTransitionalOption(prop) {
const transitional2 = utils$1.hasOwnProp(config2, 'transitional')
? config2.transitional
: undefined;
if (!utils$1.isUndefined(transitional2)) {
if (utils$1.isPlainObject(transitional2)) {
if (utils$1.hasOwnProp(transitional2, prop)) {
return transitional2[prop];
}
} else {
return undefined;
}
}
const transitional1 = utils$1.hasOwnProp(config1, 'transitional')
? config1.transitional
: undefined;
if (utils$1.isPlainObject(transitional1) && utils$1.hasOwnProp(transitional1, prop)) {
return transitional1[prop];
}
return undefined;
}
// eslint-disable-next-line consistent-return
function mergeDirectKeys(a, b, prop) {
if (utils$1.hasOwnProp(config2, prop)) {
return getMergedValue(a, b);
} else if (utils$1.hasOwnProp(config1, prop)) {
return getMergedValue(undefined, a);
}
}
const mergeMap = {
url: valueFromConfig2,
method: valueFromConfig2,
data: valueFromConfig2,
baseURL: defaultToConfig2,
transformRequest: defaultToConfig2,
transformResponse: defaultToConfig2,
paramsSerializer: defaultToConfig2,
timeout: defaultToConfig2,
timeoutMessage: defaultToConfig2,
withCredentials: defaultToConfig2,
withXSRFToken: defaultToConfig2,
adapter: defaultToConfig2,
responseType: defaultToConfig2,
xsrfCookieName: defaultToConfig2,
xsrfHeaderName: defaultToConfig2,
onUploadProgress: defaultToConfig2,
onDownloadProgress: defaultToConfig2,
decompress: defaultToConfig2,
maxContentLength: defaultToConfig2,
maxBodyLength: defaultToConfig2,
beforeRedirect: defaultToConfig2,
transport: defaultToConfig2,
httpAgent: defaultToConfig2,
httpsAgent: defaultToConfig2,
cancelToken: defaultToConfig2,
socketPath: defaultToConfig2,
allowedSocketPaths: defaultToConfig2,
responseEncoding: defaultToConfig2,
validateStatus: mergeDirectKeys,
headers: (a, b, prop) =>
mergeDeepProperties(headersToObject(a), headersToObject(b), prop, true),
};
utils$1.forEach(ownEnumerableKeys({ ...config1, ...config2 }), function computeConfigValue(prop) {
if (prop === '__proto__' || prop === 'constructor' || prop === 'prototype') return;
const merge = utils$1.hasOwnProp(mergeMap, prop) ? mergeMap[prop] : mergeDeepProperties;
const a = utils$1.hasOwnProp(config1, prop) ? config1[prop] : undefined;
const b = utils$1.hasOwnProp(config2, prop) ? config2[prop] : undefined;
const configValue = merge(a, b, prop);
(utils$1.isUndefined(configValue) && merge !== mergeDirectKeys) || (config[prop] = configValue);
});
if (
utils$1.hasOwnProp(config2, 'validateStatus') &&
utils$1.isUndefined(config2.validateStatus) &&
getMergedTransitionalOption('validateStatusUndefinedResolves') === false
) {
if (utils$1.hasOwnProp(config1, 'validateStatus')) {
config.validateStatus = getMergedValue(undefined, config1.validateStatus);
} else {
delete config.validateStatus;
}
}
return config;
}
const FORM_DATA_CONTENT_HEADERS = ['content-type', 'content-length'];
/**
* Apply the headers generated by a FormData implementation to the request headers,
* honoring the `formDataHeaderPolicy` option: with 'content-only', copy only the
* content-* headers; otherwise merge all of them.
*
* @param {AxiosHeaders} headers - the request headers to mutate
* @param {Object | null | undefined} formHeaders - headers produced by the FormData implementation
* @param {String} [policy] - the resolved `formDataHeaderPolicy` config value
*
* @returns {void}
*/
function setFormDataHeaders(headers, formHeaders, policy) {
if (policy !== 'content-only') {
headers.set(formHeaders);
return;
}
Object.entries(formHeaders || {}).forEach(([key, val]) => {
if (FORM_DATA_CONTENT_HEADERS.includes(key.toLowerCase())) {
headers.set(key, val);
}
});
}
/**
* Encode a UTF-8 string to a Latin-1 byte string for use with btoa().
* This is a modern replacement for the deprecated unescape(encodeURIComponent(str)) pattern.
*
* @param {string} str The string to encode
*
* @returns {string} UTF-8 bytes as a Latin-1 string
*/
const encodeUTF8$1 = (str) =>
encodeURIComponent(str).replace(/%([0-9A-F]{2})/gi, (_, hex) =>
String.fromCharCode(parseInt(hex, 16))
);
function resolveConfig(config) {
const newConfig = mergeConfig$1({}, config);
// Read only own properties to prevent prototype pollution gadgets
// (e.g. Object.prototype.baseURL = 'https://evil.com').
const own = (key) => (utils$1.hasOwnProp(newConfig, key) ? newConfig[key] : undefined);
const data = own('data');
let withXSRFToken = own('withXSRFToken');
const xsrfHeaderName = own('xsrfHeaderName');
const xsrfCookieName = own('xsrfCookieName');
let headers = own('headers');
const auth = own('auth');
const baseURL = own('baseURL');
const allowAbsoluteUrls = own('allowAbsoluteUrls');
const url = own('url');
newConfig.headers = headers = AxiosHeaders$1.from(headers);
newConfig.url = buildURL(
buildFullPath(baseURL, url, allowAbsoluteUrls, newConfig),
own('params'),
own('paramsSerializer')
);
// HTTP basic authentication
if (auth) {
const username = utils$1.getSafeProp(auth, 'username') || '';
const password = utils$1.getSafeProp(auth, 'password') || '';
try {
headers.set(
'Authorization',
'Basic ' + btoa(username + ':' + (password ? encodeUTF8$1(password) : ''))
);
} catch (e) {
throw AxiosError$1.from(e, AxiosError$1.ERR_BAD_OPTION_VALUE, config);
}
}
if (utils$1.isFormData(data)) {
if (
platform.hasStandardBrowserEnv ||
platform.hasStandardBrowserWebWorkerEnv ||
utils$1.isReactNative(data)
) {
headers.setContentType(undefined); // browser/web worker/RN handles it
} else if (utils$1.isFunction(data.getHeaders)) {
// Node.js FormData (like form-data package)
setFormDataHeaders(headers, data.getHeaders(), own('formDataHeaderPolicy'));
}
}
// Add xsrf header
// This is only done if running in a standard browser environment.
// Specifically not if we're in a web worker, or react-native.
if (platform.hasStandardBrowserEnv) {
if (utils$1.isFunction(withXSRFToken)) {
withXSRFToken = withXSRFToken(newConfig);
}
// Strict boolean check — prevents proto-pollution gadgets (e.g. Object.prototype.withXSRFToken = 1)
// and misconfigurations (e.g. "false") from short-circuiting the same-origin check and leaking
// the XSRF token cross-origin.
const shouldSendXSRF =
withXSRFToken === true || (withXSRFToken == null && isURLSameOrigin(newConfig.url));
if (shouldSendXSRF) {
const xsrfValue = xsrfHeaderName && xsrfCookieName && cookies.read(xsrfCookieName);
if (xsrfValue) {
headers.set(xsrfHeaderName, xsrfValue);
}
}
}
return newConfig;
}
const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined';
const xhrAdapter = isXHRAdapterSupported &&
function (config) {
return new Promise(function dispatchXhrRequest(resolve, reject) {
const _config = resolveConfig(config);
let requestData = _config.data;
const requestHeaders = AxiosHeaders$1.from(_config.headers).normalize();
let { responseType, onUploadProgress, onDownloadProgress } = _config;
let onCanceled;
let uploadThrottled, downloadThrottled;
let flushUpload, flushDownload;
function done() {
flushUpload && flushUpload(); // flush events
flushDownload && flushDownload(); // flush events
_config.cancelToken && _config.cancelToken.unsubscribe(onCanceled);
_config.signal && _config.signal.removeEventListener('abort', onCanceled);
}
let request = new XMLHttpRequest();
request.open(_config.method.toUpperCase(), _config.url, true);
// Set the request timeout in MS
request.timeout = _config.timeout;
function onloadend() {
if (!request) {
return;
}
// Prepare the response
const responseHeaders = AxiosHeaders$1.from(
'getAllResponseHeaders' in request && request.getAllResponseHeaders()
);
const responseData =
!responseType || responseType === 'text' || responseType === 'json'
? request.responseText
: request.response;
const response = {
data: responseData,
status: request.status,
statusText: request.statusText,
headers: responseHeaders,
config,
request,
};
settle(
function _resolve(value) {
resolve(value);
done();
},
function _reject(err) {
reject(err);
done();
},
response
);
// Clean up request
request = null;
}
if ('onloadend' in request) {
// Use onloadend if available
request.onloadend = onloadend;
} else {
// Listen for ready state to emulate onloadend
request.onreadystatechange = function handleLoad() {
if (!request || request.readyState !== 4) {
return;
}
// The request errored out and we didn't get a response, this will be
// handled by onerror instead
// With one exception: request that using file: protocol, most browsers
// will return status as 0 even though it's a successful request
if (
request.status === 0 &&
!(request.responseURL && request.responseURL.startsWith('file:'))
) {
return;
}
// readystate handler is calling before onerror or ontimeout handlers,
// so we should call onloadend on the next 'tick'
setTimeout(onloadend);
};
}
// Handle browser request cancellation (as opposed to a manual cancellation)
request.onabort = function handleAbort() {
if (!request) {
return;
}
reject(new AxiosError$1('Request aborted', AxiosError$1.ECONNABORTED, config, request));
done();
// Clean up request
request = null;
};
// Handle low level network errors
request.onerror = function handleError(event) {
// Browsers deliver a ProgressEvent in XHR onerror
// (message may be empty; when present, surface it)
// See https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/error_event
const msg = event && event.message ? event.message : 'Network Error';
const err = new AxiosError$1(msg, AxiosError$1.ERR_NETWORK, config, request);
// attach the underlying event for consumers who want details
err.event = event || null;
reject(err);
done();
request = null;
};
// Handle timeout
request.ontimeout = function handleTimeout() {
let timeoutErrorMessage = _config.timeout
? 'timeout of ' + _config.timeout + 'ms exceeded'
: 'timeout exceeded';
const transitional = _config.transitional || transitionalDefaults;
if (_config.timeoutErrorMessage) {
timeoutErrorMessage = _config.timeoutErrorMessage;
}
reject(
new AxiosError$1(
timeoutErrorMessage,
transitional.clarifyTimeoutError ? AxiosError$1.ETIMEDOUT : AxiosError$1.ECONNABORTED,
config,
request
)
);
done();
// Clean up request
request = null;
};
// Remove Content-Type if data is undefined
requestData === undefined && requestHeaders.setContentType(null);
// Add headers to the request
if ('setRequestHeader' in request) {
utils$1.forEach(toByteStringHeaderObject(requestHeaders), function setRequestHeader(val, key) {
request.setRequestHeader(key, val);
});
}
// Add withCredentials to request if needed
if (!utils$1.isUndefined(_config.withCredentials)) {
request.withCredentials = !!_config.withCredentials;
}
// Add responseType to request if needed
if (responseType && responseType !== 'json') {
request.responseType = _config.responseType;
}
// Handle progress if needed
if (onDownloadProgress) {
[downloadThrottled, flushDownload] = progressEventReducer(onDownloadProgress, true);
request.addEventListener('progress', downloadThrottled);
}
// Not all browsers support upload events
if (onUploadProgress && request.upload) {
[uploadThrottled, flushUpload] = progressEventReducer(onUploadProgress);
request.upload.addEventListener('progress', uploadThrottled);
request.upload.addEventListener('loadend', flushUpload);
}
if (_config.cancelToken || _config.signal) {
// Handle cancellation
// eslint-disable-next-line func-names
onCanceled = (cancel) => {
if (!request) {
return;
}
reject(!cancel || cancel.type ? new CanceledError$1(null, config, request) : cancel);
request.abort();
done();
request = null;
};
_config.cancelToken && _config.cancelToken.subscribe(onCanceled);
if (_config.signal) {
_config.signal.aborted
? onCanceled()
: _config.signal.addEventListener('abort', onCanceled);
}
}
const protocol = parseProtocol(_config.url);
if (protocol && !platform.protocols.includes(protocol)) {
reject(
new AxiosError$1(
'Unsupported protocol ' + protocol + ':',
AxiosError$1.ERR_BAD_REQUEST,
config
)
);
done();
return;
}
// Send the request
request.send(requestData || null);
});
};
const composeSignals = (signals, timeout) => {
signals = signals ? signals.filter(Boolean) : [];
if (!timeout && !signals.length) {
return;
}
const controller = new AbortController();
let aborted = false;
const onabort = function (reason) {
if (!aborted) {
aborted = true;
unsubscribe();
const err = reason instanceof Error ? reason : this.reason;
controller.abort(
err instanceof AxiosError$1
? err
: new CanceledError$1(err instanceof Error ? err.message : err)
);
}
};
let timer =
timeout &&
setTimeout(() => {
timer = null;
onabort(new AxiosError$1(`timeout of ${timeout}ms exceeded`, AxiosError$1.ETIMEDOUT));
}, timeout);
const unsubscribe = () => {
if (!signals) { return; }
timer && clearTimeout(timer);
timer = null;
signals.forEach((signal) => {
signal.unsubscribe
? signal.unsubscribe(onabort)
: signal.removeEventListener('abort', onabort);
});
signals = null;
};
signals.forEach((signal) => {
if (aborted) {
return;
}
if (signal.aborted) {
onabort.call(signal);
return;
}
signal.addEventListener('abort', onabort, { once: true });
});
const { signal } = controller;
signal.unsubscribe = () => utils$1.asap(unsubscribe);
return signal;
};
const streamChunk = function* (chunk, chunkSize) {
let len = chunk.byteLength;
if (len < chunkSize) {
yield chunk;
return;
}
let pos = 0;
let end;
while (pos < len) {
end = pos + chunkSize;
yield chunk.slice(pos, end);
pos = end;
}
};
const readBytes = async function* (iterable, chunkSize) {
for await (const chunk of readStream(iterable)) {
yield* streamChunk(chunk, chunkSize);
}
};
const readStream = async function* (stream) {
if (stream[Symbol.asyncIterator]) {
yield* stream;
return;
}
const reader = stream.getReader();
try {
for (;;) {
const { done, value } = await reader.read();
if (done) {
break;
}
yield value;
}
} finally {
await reader.cancel();
}
};
const trackStream = (stream, chunkSize, onProgress, onFinish) => {
const iterator = readBytes(stream, chunkSize);
let bytes = 0;
let done;
let _onFinish = (e) => {
if (!done) {
done = true;
onFinish && onFinish(e);
}
};
return new ReadableStream(
{
async pull(controller) {
try {
const { done, value } = await iterator.next();
if (done) {
_onFinish();
controller.close();
return;
}
let len = value.byteLength;
if (onProgress) {
let loadedBytes = (bytes += len);
onProgress(loadedBytes);
}
controller.enqueue(new Uint8Array(value));
} catch (err) {
_onFinish(err);
throw err;
}
},
cancel(reason) {
_onFinish(reason);
return iterator.return();
},
},
{
highWaterMark: 2,
}
);
};
/**
* Estimate data: URL byte lengths *without* allocating large buffers.
* - Fetch percent-decodes a base64 body before decoding it.
* - Node's Buffer.from(body, 'base64') sizes its backing allocation from the
* raw body, including ignored characters and content after padding.
* - Non-base64 data is percent-decoded and then encoded as UTF-8.
*/
const isHexDigit = (charCode) =>
(charCode >= 48 && charCode <= 57) ||
(charCode >= 65 && charCode <= 70) ||
(charCode >= 97 && charCode <= 102);
const isPercentEncodedByte = (str, i, len) =>
i + 2 < len && isHexDigit(str.charCodeAt(i + 1)) && isHexDigit(str.charCodeAt(i + 2));
const hexValue = (charCode) => (charCode <= 57 ? charCode - 48 : (charCode & 0xdf) - 55);
const isBase64Char = (charCode) =>
(charCode >= 65 && charCode <= 90) || // A-Z
(charCode >= 97 && charCode <= 122) || // a-z
(charCode >= 48 && charCode <= 57) || // 0-9
charCode === 43 || // +
charCode === 47 || // /
charCode === 45 || // - (base64url)
charCode === 95; // _ (base64url)
const isBase64Whitespace = (charCode) =>
charCode === 9 || charCode === 10 || charCode === 12 || charCode === 13 || charCode === 32;
const base64Bytes = (significant) => {
const groups = Math.floor(significant / 4);
const remainder = significant % 4;
return groups * 3 + (remainder === 2 ? 1 : remainder === 3 ? 2 : 0);
};
// Buffer.byteLength(body, 'base64') uses the raw string length as an allocation
// upper bound even when Buffer.from later ignores characters or stops at '='.
const estimateBase64BufferAllocation = (body) => {
const len = body.length;
let padding = 0;
if (len > 0 && body.charCodeAt(len - 1) === 61 /* '=' */) {
padding++;
if (len > 1 && body.charCodeAt(len - 2) === 61 /* '=' */) {
padding++;
}
}
return Math.floor(((len - padding) * 3) / 4);
};
const estimatePercentDecodedBase64Bytes = (body) => {
const len = body.length;
let significant = 0;
let padding = 0;
let invalid = false;
for (let i = 0; i < len; i++) {
let code = body.charCodeAt(i);
if (code === 37 /* '%' */ && isPercentEncodedByte(body, i, len)) {
code = hexValue(body.charCodeAt(i + 1)) * 16 + hexValue(body.charCodeAt(i + 2));
i += 2;
}
if (isBase64Whitespace(code)) {
continue;
}
if (code === 61 /* '=' */) {
padding++;
continue;
}
if (!isBase64Char(code) || padding > 0) {
invalid = true;
continue;
}
significant++;
}
// Fetch rejects malformed forgiving-base64 input. Returning the raw-size
// allocation bound keeps that invalid input from becoming a pre-check bypass.
if (
invalid ||
padding > 2 ||
(padding > 0 && (significant + padding) % 4 !== 0) ||
significant % 4 === 1
) {
return estimateBase64BufferAllocation(body);
}
return base64Bytes(significant);
};
const estimateDataURLBytes = (url, estimateBase64) => {
if (!url || typeof url !== 'string') return 0;
if (!url.startsWith('data:')) return 0;
const comma = url.indexOf(',');
if (comma < 0) return 0;
const meta = url.slice(5, comma);
const body = url.slice(comma + 1);
const isBase64 = /;base64/i.test(meta);
if (isBase64) {
return estimateBase64(body);
}
// Compute UTF-8 byte length directly from UTF-16 code units without allocating
// a byte buffer (TextEncoder.encode would defeat the DoS guard on large bodies).
// Valid %XX triplets count as one decoded byte; this matches the bytes that
// decodeURIComponent(body) would produce before Buffer re-encodes the string.
let bytes = 0;
for (let i = 0, len = body.length; i < len; i++) {
const c = body.charCodeAt(i);
if (c === 37 /* '%' */ && isPercentEncodedByte(body, i, len)) {
bytes += 1;
i += 2;
} else if (c < 0x80) {
bytes += 1;
} else if (c < 0x800) {
bytes += 2;
} else if (c >= 0xd800 && c <= 0xdbff && i + 1 < len) {
const next = body.charCodeAt(i + 1);
if (next >= 0xdc00 && next <= 0xdfff) {
bytes += 4;
i++;
} else {
bytes += 3;
}
} else {
bytes += 3;
}
}
return bytes;
};
/**
* Estimate the percent-decoded payload size used by Fetch data: URLs.
*
* @param {string} url
* @returns {number}
*/
function estimateDataURLDecodedBytes(url) {
// Fetch removes URL fragments before processing a data: URL.
const fragmentIndex = typeof url === 'string' ? url.indexOf('#') : -1;
return estimateDataURLBytes(
fragmentIndex === -1 ? url : url.slice(0, fragmentIndex),
estimatePercentDecodedBase64Bytes
);
}
const VERSION$1 = "1.19.0";
const DEFAULT_CHUNK_SIZE = 64 * 1024;
const { isFunction } = utils$1;
/**
* Encode a UTF-8 string to a Latin-1 byte string for use with btoa().
* This is a modern replacement for the deprecated unescape(encodeURIComponent(str)) pattern.
*
* @param {string} str The string to encode
*
* @returns {string} UTF-8 bytes as a Latin-1 string
*/
const encodeUTF8 = (str) =>
encodeURIComponent(str).replace(/%([0-9A-F]{2})/gi, (_, hex) =>
String.fromCharCode(parseInt(hex, 16))
);
// Node's WHATWG URL parser returns `username` and `password` percent-encoded.
// Decode before composing the `auth` option so credentials such as
// `my%40email.com:pass` are sent as `my@email.com:pass`. Falls back to the
// original value for malformed input so a bad encoding never throws.
const decodeURIComponentSafe = (value) => {
if (!utils$1.isString(value)) {
return value;
}
try {
return decodeURIComponent(value);
} catch (error) {
return value;
}
};
const test = (fn, ...args) => {
try {
return !!fn(...args);
} catch (e) {
return false;
}
};
const maybeWithAuthCredentials = (url) => {
const protocolIndex = url.indexOf('://');
let urlToCheck = url;
if (protocolIndex !== -1) {
urlToCheck = urlToCheck.slice(protocolIndex + 3);
}
return urlToCheck.includes('@') || urlToCheck.includes(':');
};
const factory = (env) => {
const globalObject =
utils$1.global !== undefined && utils$1.global !== null
? utils$1.global
: globalThis;
const { ReadableStream, TextEncoder } = globalObject;
env = utils$1.merge.call(
{
skipUndefined: true,
},
{
Request: globalObject.Request,
Response: globalObject.Response,
},
env
);
const { fetch: envFetch, Request, Response } = env;
const isFetchSupported = envFetch ? isFunction(envFetch) : typeof fetch === 'function';
const isRequestSupported = isFunction(Request);
const isResponseSupported = isFunction(Response);
if (!isFetchSupported) {
return false;
}
const isReadableStreamSupported = isFetchSupported && isFunction(ReadableStream);
const encodeText =
isFetchSupported &&
(typeof TextEncoder === 'function'
? (
(encoder) => (str) =>
encoder.encode(str)
)(new TextEncoder())
: async (str) => new Uint8Array(await new Request(str).arrayBuffer()));
const supportsRequestStream =
isRequestSupported &&
isReadableStreamSupported &&
test(() => {
let duplexAccessed = false;
const request = new Request(platform.origin, {
body: new ReadableStream(),
method: 'POST',
get duplex() {
duplexAccessed = true;
return 'half';
},
});
const hasContentType = request.headers.has('Content-Type');
if (request.body != null) {
request.body.cancel();
}
return duplexAccessed && !hasContentType;
});
const supportsResponseStream =
isResponseSupported &&
isReadableStreamSupported &&
test(() => utils$1.isReadableStream(new Response('').body));
const resolvers = {
stream: supportsResponseStream && ((res) => res.body),
};
isFetchSupported &&
(() => {
['text', 'arrayBuffer', 'blob', 'formData', 'stream'].forEach((type) => {
!resolvers[type] &&
(resolvers[type] = (res, config) => {
let method = res && res[type];
if (method) {
return method.call(res);
}
throw new AxiosError$1(
`Response type '${type}' is not supported`,
AxiosError$1.ERR_NOT_SUPPORT,
config
);
});
});
})();
const getBodyLength = async (body) => {
if (body == null) {
return 0;
}
if (utils$1.isBlob(body)) {
return body.size;
}
if (utils$1.isSpecCompliantForm(body)) {
const _request = new Request(platform.origin, {
method: 'POST',
body,
});
return (await _request.arrayBuffer()).byteLength;
}
if (utils$1.isArrayBufferView(body) || utils$1.isArrayBuffer(body)) {
return body.byteLength;
}
if (utils$1.isURLSearchParams(body)) {
body = body + '';
}
if (utils$1.isString(body)) {
return (await encodeText(body)).byteLength;
}
};
const resolveBodyLength = async (headers, body) => {
const length = utils$1.toFiniteNumber(headers.getContentLength());
return length == null ? getBodyLength(body) : length;
};
return async (config) => {
let {
url,
method,
data,
signal,
cancelToken,
timeout,
onDownloadProgress,
onUploadProgress,
responseType,
headers,
withCredentials = 'same-origin',
fetchOptions,
maxContentLength,
maxBodyLength,
} = resolveConfig(config);
const hasMaxContentLength = utils$1.isNumber(maxContentLength) && maxContentLength > -1;
const hasMaxBodyLength = utils$1.isNumber(maxBodyLength) && maxBodyLength > -1;
const own = (key) => (utils$1.hasOwnProp(config, key) ? config[key] : undefined);
let _fetch = envFetch || fetch;
responseType = responseType ? (responseType + '').toLowerCase() : 'text';
let composedSignal = composeSignals(
[signal, cancelToken && cancelToken.toAbortSignal()],
timeout
);
let request = null;
const unsubscribe =
composedSignal &&
composedSignal.unsubscribe &&
(() => {
composedSignal.unsubscribe();
});
let requestContentLength;
// AxiosError we raise while the request body is being streamed. Captured
// by identity so the catch block can surface it directly, regardless of
// how the runtime wraps the resulting fetch rejection (undici exposes it
// as `err.cause`; some browsers drop the original error entirely).
let pendingBodyError = null;
const maxBodyLengthError = () =>
new AxiosError$1(
'Request body larger than maxBodyLength limit',
AxiosError$1.ERR_BAD_REQUEST,
config,
request
);
try {
// HTTP basic authentication
let auth = undefined;
const configAuth = own('auth');
if (configAuth) {
const username = utils$1.getSafeProp(configAuth, 'username') || '';
const password = utils$1.getSafeProp(configAuth, 'password') || '';
auth = {
username,
password
};
}
if (maybeWithAuthCredentials(url)) {
const parsedURL = new URL(url, platform.origin);
if (!auth && (parsedURL.username || parsedURL.password)) {
const urlUsername = decodeURIComponentSafe(parsedURL.username);
const urlPassword = decodeURIComponentSafe(parsedURL.password);
auth = {
username: urlUsername,
password: urlPassword
};
}
if (parsedURL.username || parsedURL.password) {
parsedURL.username = '';
parsedURL.password = '';
url = parsedURL.href;
}
}
if (auth) {
headers.delete('authorization');
headers.set(
'Authorization',
'Basic ' + btoa(encodeUTF8((auth.username || '') + ':' + (auth.password || '')))
);
}
// Enforce maxContentLength for data: URLs up-front so we never materialize
// an oversized payload. The HTTP adapter applies the same check (see http.js
// "if (protocol === 'data:')" branch).
if (hasMaxContentLength && typeof url === 'string' && url.startsWith('data:')) {
const estimated = estimateDataURLDecodedBytes(url);
if (estimated > maxContentLength) {
throw new AxiosError$1(
'maxContentLength size of ' + maxContentLength + ' exceeded',
AxiosError$1.ERR_BAD_RESPONSE,
config,
request
);
}
}
// Enforce maxBodyLength against known-size bodies before dispatch using
// the body's *actual* size — never a caller-declared Content-Length,
// which could under-report to slip an oversized body past the check.
// Unknown-size streams return undefined here and are counted per-chunk
// below as fetch consumes them.
if (hasMaxBodyLength && method !== 'get' && method !== 'head') {
const outboundLength = await getBodyLength(data);
if (typeof outboundLength === 'number' && isFinite(outboundLength)) {
requestContentLength = outboundLength;
if (outboundLength > maxBodyLength) {
throw maxBodyLengthError();
}
}
}
// A streamed body under maxBodyLength must be counted as fetch consumes
// it; its size is never trusted from a caller-declared Content-Length.
const mustEnforceStreamBody =
hasMaxBodyLength && (utils$1.isReadableStream(data) || utils$1.isStream(data));
const trackRequestStream = (stream, onProgress, flush) =>
trackStream(
stream,
DEFAULT_CHUNK_SIZE,
(loadedBytes) => {
if (hasMaxBodyLength && loadedBytes > maxBodyLength) {
throw (pendingBodyError = maxBodyLengthError());
}
onProgress && onProgress(loadedBytes);
},
flush
);
if (
supportsRequestStream &&
method !== 'get' &&
method !== 'head' &&
(onUploadProgress || mustEnforceStreamBody)
) {
requestContentLength =
requestContentLength == null ? await resolveBodyLength(headers, data) : requestContentLength;
// A declared length of 0 is only trusted to skip the wrap when we are
// not enforcing a stream limit (which must not rely on that header).
if (requestContentLength !== 0 || mustEnforceStreamBody) {
let _request = new Request(url, {
method: 'POST',
body: data,
duplex: 'half',
});
let contentTypeHeader;
if (utils$1.isFormData(data) && (contentTypeHeader = _request.headers.get('content-type'))) {
headers.setContentType(contentTypeHeader);
}
if (_request.body) {
const [onProgress, flush] =
(onUploadProgress &&
progressEventDecorator(
requestContentLength,
progressEventReducer(asyncDecorator(onUploadProgress))
)) ||
[];
data = trackRequestStream(_request.body, onProgress, flush);
}
}
} else if (
mustEnforceStreamBody &&
!isRequestSupported &&
isReadableStreamSupported &&
method !== 'get' &&
method !== 'head'
) {
data = trackRequestStream(data);
} else if (
mustEnforceStreamBody &&
isRequestSupported &&
!supportsRequestStream &&
method !== 'get' &&
method !== 'head'
) {
throw new AxiosError$1(
'Stream request bodies are not supported by the current fetch implementation',
AxiosError$1.ERR_NOT_SUPPORT,
config,
request
);
}
if (!utils$1.isString(withCredentials)) {
withCredentials = withCredentials ? 'include' : 'omit';
}
// Cloudflare Workers throws when credentials are defined
// see https://github.com/cloudflare/workerd/issues/902
const isCredentialsSupported = isRequestSupported && 'credentials' in Request.prototype;
// If data is FormData and Content-Type is multipart/form-data without boundary,
// delete it so fetch can set it correctly with the boundary
if (utils$1.isFormData(data)) {
const contentType = headers.getContentType();
if (
contentType &&
/^multipart\/form-data/i.test(contentType) &&
!/boundary=/i.test(contentType)
) {
headers.delete('content-type');
}
}
// Set User-Agent header if not already set (fetch defaults to 'node' in Node.js)
headers.set('User-Agent', 'axios/' + VERSION$1, false);
const resolvedOptions = {
...fetchOptions,
signal: composedSignal,
method: method.toUpperCase(),
headers: toByteStringHeaderObject(headers.normalize()),
body: data,
duplex: 'half',
credentials: isCredentialsSupported ? withCredentials : undefined,
};
request = isRequestSupported && new Request(url, resolvedOptions);
let response = await (isRequestSupported
? _fetch(request, fetchOptions)
: _fetch(url, resolvedOptions));
const responseHeaders = AxiosHeaders$1.from(response.headers);
// Cheap pre-check: if the server honestly declares a content-length that
// already exceeds the cap, reject before we start streaming.
if (hasMaxContentLength) {
const declaredLength = utils$1.toFiniteNumber(responseHeaders.getContentLength());
if (declaredLength != null && declaredLength > maxContentLength) {
throw new AxiosError$1(
'maxContentLength size of ' + maxContentLength + ' exceeded',
AxiosError$1.ERR_BAD_RESPONSE,
config,
request
);
}
}
const isStreamResponse =
supportsResponseStream && (responseType === 'stream' || responseType === 'response');
if (
supportsResponseStream &&
response.body &&
(onDownloadProgress || hasMaxContentLength || (isStreamResponse && unsubscribe))
) {
const options = {};
['status', 'statusText', 'headers'].forEach((prop) => {
options[prop] = response[prop];
});
const responseContentLength = utils$1.toFiniteNumber(responseHeaders.getContentLength());
const [onProgress, flush] =
(onDownloadProgress &&
progressEventDecorator(
responseContentLength,
progressEventReducer(asyncDecorator(onDownloadProgress), true)
)) ||
[];
let bytesRead = 0;
const onChunkProgress = (loadedBytes) => {
if (hasMaxContentLength) {
bytesRead = loadedBytes;
if (bytesRead > maxContentLength) {
throw new AxiosError$1(
'maxContentLength size of ' + maxContentLength + ' exceeded',
AxiosError$1.ERR_BAD_RESPONSE,
config,
request
);
}
}
onProgress && onProgress(loadedBytes);
};
response = new Response(
trackStream(response.body, DEFAULT_CHUNK_SIZE, onChunkProgress, () => {
flush && flush();
unsubscribe && unsubscribe();
}),
options
);
}
responseType = responseType || 'text';
let responseData = await resolvers[utils$1.findKey(resolvers, responseType) || 'text'](
response,
config
);
// Fallback enforcement for environments without ReadableStream support
// (legacy runtimes). Detect materialized size from typed output; skip
// streams/Response passthrough since the user will read those themselves.
if (hasMaxContentLength && !supportsResponseStream && !isStreamResponse) {
let materializedSize;
if (responseData != null) {
if (typeof responseData.byteLength === 'number') {
materializedSize = responseData.byteLength;
} else if (typeof responseData.size === 'number') {
materializedSize = responseData.size;
} else if (typeof responseData === 'string') {
materializedSize =
typeof TextEncoder === 'function'
? new TextEncoder().encode(responseData).byteLength
: responseData.length;
}
}
if (typeof materializedSize === 'number' && materializedSize > maxContentLength) {
throw new AxiosError$1(
'maxContentLength size of ' + maxContentLength + ' exceeded',
AxiosError$1.ERR_BAD_RESPONSE,
config,
request
);
}
}
!isStreamResponse && unsubscribe && unsubscribe();
return await new Promise((resolve, reject) => {
settle(resolve, reject, {
data: responseData,
headers: AxiosHeaders$1.from(response.headers),
status: response.status,
statusText: response.statusText,
config,
request,
});
});
} catch (err) {
unsubscribe && unsubscribe();
// Safari can surface fetch aborts as a DOMException-like object whose
// branded getters throw. Prefer our composed signal reason before reading
// the caught error, preserving timeout vs cancellation semantics.
if (composedSignal && composedSignal.aborted && composedSignal.reason instanceof AxiosError$1) {
const canceledError = composedSignal.reason;
canceledError.config = config;
request && (canceledError.request = request);
if (err !== canceledError) {
// Non-enumerable to match native Error `cause` semantics so loggers
// don't recurse into circular fetch internals (see #7205).
Object.defineProperty(canceledError, 'cause', {
__proto__: null,
value: err,
writable: true,
enumerable: false,
configurable: true,
});
}
throw canceledError;
}
// Surface a maxBodyLength violation we raised while the request body was
// being streamed. Matching by identity (rather than reading
// `err.cause.isAxiosError`) keeps the error deterministic across runtimes
// and avoids both prototype-pollution reads and mis-attributing a foreign
// AxiosError that merely happened to land in `err.cause`.
if (pendingBodyError) {
request && !pendingBodyError.request && (pendingBodyError.request = request);
throw pendingBodyError;
}
// Re-throw AxiosErrors we raised synchronously (data: URL / content-length
// pre-checks, response size enforcement) without re-wrapping them.
if (err instanceof AxiosError$1) {
request && !err.request && (err.request = request);
throw err;
}
if (err && err.name === 'TypeError' && /Load failed|fetch/i.test(err.message)) {
const networkError = new AxiosError$1(
'Network Error',
AxiosError$1.ERR_NETWORK,
config,
request,
err && err.response
);
// Non-enumerable to match native Error `cause` semantics so loggers
// don't recurse into circular fetch internals (see #7205).
Object.defineProperty(networkError, 'cause', {
__proto__: null,
value: err.cause || err,
writable: true,
enumerable: false,
configurable: true,
});
throw networkError;
}
throw AxiosError$1.from(err, err && err.code, config, request, err && err.response);
}
};
};
const seedCache = new Map();
const getFetch = (config) => {
let env = (config && config.env) || {};
const { fetch, Request, Response } = env;
const seeds = [Request, Response, fetch];
let len = seeds.length,
i = len,
seed,
target,
map = seedCache;
while (i--) {
seed = seeds[i];
target = map.get(seed);
target === undefined && map.set(seed, (target = i ? new Map() : factory(env)));
map = target;
}
return target;
};
getFetch();
/**
* Known adapters mapping.
* Provides environment-specific adapters for Axios:
* - `http` for Node.js
* - `xhr` for browsers
* - `fetch` for fetch API-based requests
*
* @type {Object<string, Function|Object>}
*/
const knownAdapters = {
http: httpAdapter,
xhr: xhrAdapter,
fetch: {
get: getFetch,
},
};
// Assign adapter names for easier debugging and identification
utils$1.forEach(knownAdapters, (fn, value) => {
if (fn) {
try {
// Null-proto descriptors so a polluted Object.prototype.get cannot turn
// these data descriptors into accessor descriptors on the way in.
Object.defineProperty(fn, 'name', { __proto__: null, value });
} catch (e) {
// eslint-disable-next-line no-empty
}
Object.defineProperty(fn, 'adapterName', { __proto__: null, value });
}
});
/**
* Render a rejection reason string for unknown or unsupported adapters
*
* @param {string} reason
* @returns {string}
*/
const renderReason = (reason) => `- ${reason}`;
/**
* Check if the adapter is resolved (function, null, or false)
*
* @param {Function|null|false} adapter
* @returns {boolean}
*/
const isResolvedHandle = (adapter) =>
utils$1.isFunction(adapter) || adapter === null || adapter === false;
/**
* Get the first suitable adapter from the provided list.
* Tries each adapter in order until a supported one is found.
* Throws an AxiosError if no adapter is suitable.
*
* @param {Array<string|Function>|string|Function} adapters - Adapter(s) by name or function.
* @param {Object} config - Axios request configuration
* @throws {AxiosError} If no suitable adapter is available
* @returns {Function} The resolved adapter function
*/
function getAdapter$1(adapters, config) {
adapters = utils$1.isArray(adapters) ? adapters : [adapters];
const { length } = adapters;
let nameOrAdapter;
let adapter;
const rejectedReasons = {};
for (let i = 0; i < length; i++) {
nameOrAdapter = adapters[i];
let id;
adapter = nameOrAdapter;
if (!isResolvedHandle(nameOrAdapter)) {
adapter = knownAdapters[(id = String(nameOrAdapter)).toLowerCase()];
if (adapter === undefined) {
throw new AxiosError$1(`Unknown adapter '${id}'`);
}
}
if (adapter && (utils$1.isFunction(adapter) || (adapter = adapter.get(config)))) {
break;
}
rejectedReasons[id || '#' + i] = adapter;
}
if (!adapter) {
const reasons = Object.entries(rejectedReasons).map(
([id, state]) =>
`adapter ${id} ` +
(state === false ? 'is not supported by the environment' : 'is not available in the build')
);
let s = length
? reasons.length > 1
? 'since :\n' + reasons.map(renderReason).join('\n')
: ' ' + renderReason(reasons[0])
: 'as no adapter specified';
throw new AxiosError$1(
`There is no suitable adapter to dispatch the request ` + s,
AxiosError$1.ERR_NOT_SUPPORT
);
}
return adapter;
}
/**
* Exports Axios adapters and utility to resolve an adapter
*/
const adapters = {
/**
* Resolve an adapter from a list of adapter names or functions.
* @type {Function}
*/
getAdapter: getAdapter$1,
/**
* Exposes all known adapters
* @type {Object<string, Function|Object>}
*/
adapters: knownAdapters,
};
/**
* Throws a `CanceledError` if cancellation has been requested.
*
* @param {Object} config The config that is to be used for the request
*
* @returns {void}
*/
function throwIfCancellationRequested(config) {
if (config.cancelToken) {
config.cancelToken.throwIfRequested();
}
if (config.signal && config.signal.aborted) {
throw new CanceledError$1(null, config);
}
}
/**
* Dispatch a request to the server using the configured adapter.
*
* @param {object} config The config that is to be used for the request
*
* @returns {Promise} The Promise to be fulfilled
*/
function dispatchRequest(config) {
throwIfCancellationRequested(config);
config.headers = AxiosHeaders$1.from(config.headers);
// Transform request data
config.data = transformData.call(config, config.transformRequest);
if (['post', 'put', 'patch'].indexOf(config.method) !== -1) {
config.headers.setContentType('application/x-www-form-urlencoded', false);
}
const adapter = adapters.getAdapter(config.adapter || defaults$1.adapter, config);
return adapter(config).then(
function onAdapterResolution(response) {
throwIfCancellationRequested(config);
// Expose the current response on config so that transformResponse can
// attach it to any AxiosError it throws (e.g. on JSON parse failure).
// We clean it up afterwards to avoid polluting the config object.
config.response = response;
try {
response.data = transformData.call(config, config.transformResponse, response);
} finally {
delete config.response;
}
response.headers = AxiosHeaders$1.from(response.headers);
return response;
},
function onAdapterRejection(reason) {
if (!isCancel$1(reason)) {
throwIfCancellationRequested(config);
// Transform response data
if (reason && reason.response) {
config.response = reason.response;
try {
reason.response.data = transformData.call(
config,
config.transformResponse,
reason.response
);
} finally {
delete config.response;
}
reason.response.headers = AxiosHeaders$1.from(reason.response.headers);
}
}
return Promise.reject(reason);
}
);
}
const validators$1 = {};
// eslint-disable-next-line func-names
['object', 'boolean', 'number', 'function', 'string', 'symbol'].forEach((type, i) => {
validators$1[type] = function validator(thing) {
return typeof thing === type || 'a' + (i < 1 ? 'n ' : ' ') + type;
};
});
const deprecatedWarnings = {};
/**
* Transitional option validator
*
* @param {function|boolean?} validator - set to false if the transitional option has been removed
* @param {string?} version - deprecated version / removed since version
* @param {string?} message - some message with additional info
*
* @returns {function}
*/
validators$1.transitional = function transitional(validator, version, message) {
function formatMessage(opt, desc) {
return (
'[Axios v' +
VERSION$1 +
"] Transitional option '" +
opt +
"'" +
desc +
(message ? '. ' + message : '')
);
}
// eslint-disable-next-line func-names
return (value, opt, opts) => {
if (validator === false) {
throw new AxiosError$1(
formatMessage(opt, ' has been removed' + (version ? ' in ' + version : '')),
AxiosError$1.ERR_DEPRECATED
);
}
if (version && !deprecatedWarnings[opt]) {
deprecatedWarnings[opt] = true;
// eslint-disable-next-line no-console
console.warn(
formatMessage(
opt,
' has been deprecated since v' + version + ' and will be removed in the near future'
)
);
}
return validator ? validator(value, opt, opts) : true;
};
};
validators$1.spelling = function spelling(correctSpelling) {
return (value, opt) => {
// eslint-disable-next-line no-console
console.warn(`${opt} is likely a misspelling of ${correctSpelling}`);
return true;
};
};
/**
* Assert object's properties type
*
* @param {object} options
* @param {object} schema
* @param {boolean?} allowUnknown
*
* @returns {object}
*/
function assertOptions(options, schema, allowUnknown) {
if (typeof options !== 'object' || options === null) {
throw new AxiosError$1('options must be an object', AxiosError$1.ERR_BAD_OPTION_VALUE);
}
const keys = Object.keys(options);
let i = keys.length;
while (i-- > 0) {
const opt = keys[i];
// Use hasOwnProperty so a polluted Object.prototype.<opt> cannot supply
// a non-function validator and cause a TypeError.
const validator = Object.prototype.hasOwnProperty.call(schema, opt) ? schema[opt] : undefined;
if (validator) {
const value = options[opt];
const result = value === undefined || validator(value, opt, options);
if (result !== true) {
throw new AxiosError$1(
'option ' + opt + ' must be ' + result,
AxiosError$1.ERR_BAD_OPTION_VALUE
);
}
continue;
}
if (allowUnknown !== true) {
throw new AxiosError$1('Unknown option ' + opt, AxiosError$1.ERR_BAD_OPTION);
}
}
}
const validator = {
assertOptions,
validators: validators$1,
};
const validators = validator.validators;
/**
* Create a new instance of Axios
*
* @param {Object} instanceConfig The default config for the instance
*
* @return {Axios} A new instance of Axios
*/
let Axios$1 = class Axios {
constructor(instanceConfig) {
this.defaults = instanceConfig || {};
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager(),
};
}
/**
* Dispatch a request
*
* @param {String|Object} configOrUrl The config specific for this request (merged with this.defaults)
* @param {?Object} config
*
* @returns {Promise} The Promise to be fulfilled
*/
async request(configOrUrl, config) {
try {
return await this._request(configOrUrl, config);
} catch (err) {
if (err instanceof Error) {
let dummy = {};
Error.captureStackTrace ? Error.captureStackTrace(dummy) : (dummy = new Error());
// slice off the Error: ... line
const stack = (() => {
if (!dummy.stack) {
return '';
}
const firstNewlineIndex = dummy.stack.indexOf('\n');
return firstNewlineIndex === -1 ? '' : dummy.stack.slice(firstNewlineIndex + 1);
})();
try {
if (!err.stack) {
err.stack = stack;
// match without the 2 top stack lines
} else if (stack) {
const firstNewlineIndex = stack.indexOf('\n');
const secondNewlineIndex =
firstNewlineIndex === -1 ? -1 : stack.indexOf('\n', firstNewlineIndex + 1);
const stackWithoutTwoTopLines =
secondNewlineIndex === -1 ? '' : stack.slice(secondNewlineIndex + 1);
if (!String(err.stack).endsWith(stackWithoutTwoTopLines)) {
err.stack += '\n' + stack;
}
}
} catch (e) {
// ignore the case where "stack" is an un-writable property
}
}
throw err;
}
}
_request(configOrUrl, config) {
/*eslint no-param-reassign:0*/
// Allow for axios('example/url'[, config]) a la fetch API
if (typeof configOrUrl === 'string') {
config = config || {};
config.url = configOrUrl;
} else {
config = configOrUrl || {};
}
config = mergeConfig$1(this.defaults, config);
const { transitional, paramsSerializer, headers } = config;
if (transitional !== undefined) {
validator.assertOptions(
transitional,
{
silentJSONParsing: validators.transitional(validators.boolean),
forcedJSONParsing: validators.transitional(validators.boolean),
clarifyTimeoutError: validators.transitional(validators.boolean),
legacyInterceptorReqResOrdering: validators.transitional(validators.boolean),
advertiseZstdAcceptEncoding: validators.transitional(validators.boolean),
validateStatusUndefinedResolves: validators.transitional(validators.boolean),
},
false
);
}
if (paramsSerializer != null) {
if (utils$1.isFunction(paramsSerializer)) {
config.paramsSerializer = {
serialize: paramsSerializer,
};
} else {
validator.assertOptions(
paramsSerializer,
{
encode: validators.function,
serialize: validators.function,
},
true
);
}
}
// Set config.allowAbsoluteUrls
if (config.allowAbsoluteUrls !== undefined) ; else if (this.defaults.allowAbsoluteUrls !== undefined) {
config.allowAbsoluteUrls = this.defaults.allowAbsoluteUrls;
} else {
config.allowAbsoluteUrls = true;
}
validator.assertOptions(
config,
{
baseUrl: validators.spelling('baseURL'),
withXsrfToken: validators.spelling('withXSRFToken'),
},
true
);
// Set config.method
config.method = (config.method || this.defaults.method || 'get').toLowerCase();
// Flatten headers
let contextHeaders = headers && utils$1.merge(headers.common, headers[config.method]);
headers &&
utils$1.forEach(['delete', 'get', 'head', 'post', 'put', 'patch', 'query', 'common'], (method) => {
delete headers[method];
});
config.headers = AxiosHeaders$1.concat(contextHeaders, headers);
// filter out skipped interceptors
const requestInterceptorChain = [];
let synchronousRequestInterceptors = true;
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) {
return;
}
synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;
const transitional = config.transitional || transitionalDefaults;
const legacyInterceptorReqResOrdering =
transitional && transitional.legacyInterceptorReqResOrdering;
if (legacyInterceptorReqResOrdering) {
requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
} else {
requestInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
}
});
const responseInterceptorChain = [];
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
});
let promise;
let i = 0;
let len;
if (!synchronousRequestInterceptors) {
const chain = [dispatchRequest.bind(this), undefined];
chain.unshift(...requestInterceptorChain);
chain.push(...responseInterceptorChain);
len = chain.length;
promise = Promise.resolve(config);
while (i < len) {
promise = promise.then(chain[i++], chain[i++]);
}
return promise;
}
len = requestInterceptorChain.length;
let newConfig = config;
while (i < len) {
const onFulfilled = requestInterceptorChain[i++];
const onRejected = requestInterceptorChain[i++];
try {
newConfig = onFulfilled ? onFulfilled(newConfig) : newConfig;
} catch (error) {
if (!onRejected) {
promise = Promise.reject(error);
break;
}
try {
const rejectedResult = onRejected.call(this, error);
if (utils$1.isThenable(rejectedResult)) {
promise = Promise.resolve(rejectedResult).then(() =>
dispatchRequest.call(this, newConfig)
);
}
} catch (rejectedError) {
promise = Promise.reject(rejectedError);
}
break;
}
}
if (!promise) {
try {
promise = dispatchRequest.call(this, newConfig);
} catch (error) {
promise = Promise.reject(error);
}
}
i = 0;
len = responseInterceptorChain.length;
while (i < len) {
promise = promise.then(responseInterceptorChain[i++], responseInterceptorChain[i++]);
}
return promise;
}
getUri(config) {
config = mergeConfig$1(this.defaults, config);
const fullPath = buildFullPath(config.baseURL, config.url, config.allowAbsoluteUrls, config);
return buildURL(fullPath, config.params, config.paramsSerializer);
}
};
// Provide aliases for supported request methods
utils$1.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
/*eslint func-names:0*/
Axios$1.prototype[method] = function (url, config) {
return this.request(
mergeConfig$1(config || {}, {
method,
url,
data: config && utils$1.hasOwnProp(config, 'data') ? config.data : undefined,
})
);
};
});
utils$1.forEach(['post', 'put', 'patch', 'query'], function forEachMethodWithData(method) {
function generateHTTPMethod(isForm) {
return function httpMethod(url, data, config) {
return this.request(
mergeConfig$1(config || {}, {
method,
headers: isForm
? {
'Content-Type': 'multipart/form-data',
}
: {},
url,
data,
})
);
};
}
Axios$1.prototype[method] = generateHTTPMethod();
// QUERY is a safe/idempotent read method; multipart form bodies don't fit
// its semantics, so no queryForm shorthand is generated.
if (method !== 'query') {
Axios$1.prototype[method + 'Form'] = generateHTTPMethod(true);
}
});
/**
* A `CancelToken` is an object that can be used to request cancellation of an operation.
*
* @param {Function} executor The executor function.
*
* @returns {CancelToken}
*/
let CancelToken$1 = class CancelToken {
constructor(executor) {
if (typeof executor !== 'function') {
throw new TypeError('executor must be a function.');
}
let resolvePromise;
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve;
});
const token = this;
// eslint-disable-next-line func-names
this.promise.then((cancel) => {
if (!token._listeners) return;
let i = token._listeners.length;
while (i-- > 0) {
token._listeners[i](cancel);
}
token._listeners = null;
});
// eslint-disable-next-line func-names
this.promise.then = (onfulfilled) => {
let _resolve;
// eslint-disable-next-line func-names
const promise = new Promise((resolve) => {
token.subscribe(resolve);
_resolve = resolve;
}).then(onfulfilled);
promise.cancel = function reject() {
token.unsubscribe(_resolve);
};
return promise;
};
executor(function cancel(message, config, request) {
if (token.reason) {
// Cancellation has already been requested
return;
}
token.reason = new CanceledError$1(message, config, request);
resolvePromise(token.reason);
});
}
/**
* Throws a `CanceledError` if cancellation has been requested.
*/
throwIfRequested() {
if (this.reason) {
throw this.reason;
}
}
/**
* Subscribe to the cancel signal
*/
subscribe(listener) {
if (this.reason) {
listener(this.reason);
return;
}
if (this._listeners) {
this._listeners.push(listener);
} else {
this._listeners = [listener];
}
}
/**
* Unsubscribe from the cancel signal
*/
unsubscribe(listener) {
if (!this._listeners) {
return;
}
const index = this._listeners.indexOf(listener);
if (index !== -1) {
this._listeners.splice(index, 1);
}
}
toAbortSignal() {
const controller = new AbortController();
const abort = (err) => {
controller.abort(err);
};
this.subscribe(abort);
controller.signal.unsubscribe = () => this.unsubscribe(abort);
return controller.signal;
}
/**
* Returns an object that contains a new `CancelToken` and a function that, when called,
* cancels the `CancelToken`.
*/
static source() {
let cancel;
const token = new CancelToken(function executor(c) {
cancel = c;
});
return {
token,
cancel,
};
}
};
/**
* Syntactic sugar for invoking a function and expanding an array for arguments.
*
* Common use case would be to use `Function.prototype.apply`.
*
* ```js
* function f(x, y, z) {}
* const args = [1, 2, 3];
* f.apply(null, args);
* ```
*
* With `spread` this example can be re-written.
*
* ```js
* spread(function(x, y, z) {})([1, 2, 3]);
* ```
*
* @param {Function} callback
*
* @returns {Function}
*/
function spread$1(callback) {
return function wrap(arr) {
return callback.apply(null, arr);
};
}
/**
* Determines whether the payload is an error thrown by Axios
*
* @param {*} payload The value to test
*
* @returns {boolean} True if the payload is an error thrown by Axios, otherwise false
*/
function isAxiosError$1(payload) {
return utils$1.isObject(payload) && payload.isAxiosError === true;
}
const HttpStatusCode$1 = {
Continue: 100,
SwitchingProtocols: 101,
Processing: 102,
EarlyHints: 103,
Ok: 200,
Created: 201,
Accepted: 202,
NonAuthoritativeInformation: 203,
NoContent: 204,
ResetContent: 205,
PartialContent: 206,
MultiStatus: 207,
AlreadyReported: 208,
ImUsed: 226,
MultipleChoices: 300,
MovedPermanently: 301,
Found: 302,
SeeOther: 303,
NotModified: 304,
UseProxy: 305,
Unused: 306,
TemporaryRedirect: 307,
PermanentRedirect: 308,
BadRequest: 400,
Unauthorized: 401,
PaymentRequired: 402,
Forbidden: 403,
NotFound: 404,
MethodNotAllowed: 405,
NotAcceptable: 406,
ProxyAuthenticationRequired: 407,
RequestTimeout: 408,
Conflict: 409,
Gone: 410,
LengthRequired: 411,
PreconditionFailed: 412,
PayloadTooLarge: 413,
UriTooLong: 414,
UnsupportedMediaType: 415,
RangeNotSatisfiable: 416,
ExpectationFailed: 417,
ImATeapot: 418,
MisdirectedRequest: 421,
UnprocessableEntity: 422,
Locked: 423,
FailedDependency: 424,
TooEarly: 425,
UpgradeRequired: 426,
PreconditionRequired: 428,
TooManyRequests: 429,
RequestHeaderFieldsTooLarge: 431,
UnavailableForLegalReasons: 451,
InternalServerError: 500,
NotImplemented: 501,
BadGateway: 502,
ServiceUnavailable: 503,
GatewayTimeout: 504,
HttpVersionNotSupported: 505,
VariantAlsoNegotiates: 506,
InsufficientStorage: 507,
LoopDetected: 508,
NotExtended: 510,
NetworkAuthenticationRequired: 511,
WebServerReturnsAnUnknownError: 520,
WebServerIsDown: 521,
ConnectionTimedOut: 522,
OriginIsUnreachable: 523,
TimeoutOccurred: 524,
SslHandshakeFailed: 525,
InvalidSslCertificate: 526,
};
Object.entries(HttpStatusCode$1).forEach(([key, value]) => {
HttpStatusCode$1[value] = key;
});
/**
* Create an instance of Axios
*
* @param {Object} defaultConfig The default config for the instance
*
* @returns {Axios} A new instance of Axios
*/
function createInstance(defaultConfig) {
const context = new Axios$1(defaultConfig);
const instance = bind(Axios$1.prototype.request, context);
// Copy axios.prototype to instance
utils$1.extend(instance, Axios$1.prototype, context, { allOwnKeys: true });
// Copy context to instance
utils$1.extend(instance, context, null, { allOwnKeys: true });
// Factory for creating new instances
instance.create = function create(instanceConfig) {
return createInstance(mergeConfig$1(defaultConfig, instanceConfig));
};
return instance;
}
// Create the default instance to be exported
const axios = createInstance(defaults$1);
// Expose Axios class to allow class inheritance
axios.Axios = Axios$1;
// Expose Cancel & CancelToken
axios.CanceledError = CanceledError$1;
axios.CancelToken = CancelToken$1;
axios.isCancel = isCancel$1;
axios.VERSION = VERSION$1;
axios.toFormData = toFormData$1;
// Expose AxiosError class
axios.AxiosError = AxiosError$1;
// alias for CanceledError for backward compatibility
axios.Cancel = axios.CanceledError;
// Expose all/spread
axios.all = function all(promises) {
return Promise.all(promises);
};
axios.spread = spread$1;
// Expose isAxiosError
axios.isAxiosError = isAxiosError$1;
// Expose mergeConfig
axios.mergeConfig = mergeConfig$1;
axios.AxiosHeaders = AxiosHeaders$1;
axios.formToJSON = (thing) => formDataToJSON(utils$1.isHTMLForm(thing) ? new FormData(thing) : thing);
axios.getAdapter = adapters.getAdapter;
axios.HttpStatusCode = HttpStatusCode$1;
axios.default = axios;
// This module is intended to unwrap Axios default export as named.
// Keep top-level export same with static properties
// so that it can keep same with es module or cjs
const {
Axios,
AxiosError,
CanceledError,
isCancel,
CancelToken,
VERSION,
all,
Cancel,
isAxiosError,
spread,
toFormData,
AxiosHeaders,
HttpStatusCode,
formToJSON,
getAdapter,
mergeConfig,
create,
} = axios;
var __defProp$S = Object.defineProperty;
var __name$S = (target, value) => __defProp$S(target, "name", { value, configurable: true });
const DEFAULT_REQUEST_ID_HEADER_FIELD_NAME = "X-Request-ID";
const DEFAULT_QUERY_STRING_PARAMETER_NAME = "bx24_request_id";
const DEFAULT_QUERY_STRING_SDK_VER_PARAMETER_NAME = "bx24_sdk_ver";
const DEFAULT_QUERY_STRING_SDK_TYPE_PARAMETER_NAME = "bx24_sdk_type";
class RequestIdGenerator {
static {
__name$S(this, "RequestIdGenerator");
}
getQueryStringParameterName() {
return DEFAULT_QUERY_STRING_PARAMETER_NAME;
}
getQueryStringSdkParameterName() {
return DEFAULT_QUERY_STRING_SDK_VER_PARAMETER_NAME;
}
getQueryStringSdkTypeParameterName() {
return DEFAULT_QUERY_STRING_SDK_TYPE_PARAMETER_NAME;
}
generate() {
return Text.getUuidRfc4122();
}
getRequestId() {
return this.generate();
}
getHeaderFieldName() {
return DEFAULT_REQUEST_ID_HEADER_FIELD_NAME;
}
}
var __defProp$R = Object.defineProperty;
var __name$R = (target, value) => __defProp$R(target, "name", { value, configurable: true });
const LOG_MAX_LENGTH = 300;
const LOG_SLICE_LENGTH = 100;
function truncateForLog(value) {
const text = typeof value === "string" ? value : String(value);
return text.length > LOG_MAX_LENGTH ? text.slice(0, LOG_SLICE_LENGTH) + "..." : text;
}
__name$R(truncateForLog, "truncateForLog");
class AbstractHttp {
static {
__name$R(this, "AbstractHttp");
}
_clientAxios;
_authActions;
_requestIdGenerator;
_restrictionManager;
/**
* In-flight token refresh, shared so concurrent 401s coalesce into a single
* `refreshAuth()` round-trip — avoids OAuth refresh-token reuse errors when a
* burst of requests expires together. (#182)
*/
_pendingRefresh = null;
_logger;
_isClientSideWarning = false;
_clientSideWarningMessage = "";
_version;
_metrics = {
totalRequests: 0,
successfulRequests: 0,
failedRequests: 0,
totalDuration: 0,
byMethod: /* @__PURE__ */ new Map(),
lastErrors: []
};
constructor(authActions, options, restrictionParams) {
this._version = ApiVersion.v2;
this._logger = LoggerFactory.createNullLogger();
const defaultHeaders = {};
if (this.isServerSide()) {
defaultHeaders["User-Agent"] = "b24-js-sdk/2.2.0";
}
this._authActions = authActions;
this._requestIdGenerator = new RequestIdGenerator();
this._clientAxios = axios.create({
timeout: 3e4,
timeoutErrorMessage: "Request timeout exceeded",
...options ?? {},
// headers last so the merged default + caller headers aren't wiped by an
// `options.headers` (or the previous `headers: undefined`) spread (#144).
headers: {
...defaultHeaders,
...options?.headers ?? {}
}
});
const params = {
...ParamsFactory.getDefault(),
...restrictionParams
};
this._restrictionManager = new RestrictionManager(params);
}
get apiVersion() {
return this._version;
}
get ajaxClient() {
return this._clientAxios;
}
// region Logger ////
setLogger(logger) {
this._logger = logger;
this._restrictionManager.setLogger(this._logger);
}
getLogger() {
return this._logger;
}
// endregion ////
// region RestrictionManager ////
async setRestrictionManagerParams(params) {
await this._restrictionManager.setConfig(params);
}
getRestrictionManagerParams() {
return this._restrictionManager.getParams();
}
/**
* @inheritDoc
*/
getStats() {
return {
...this._restrictionManager.getStats(),
totalRequests: this._metrics.totalRequests,
successfulRequests: this._metrics.successfulRequests,
failedRequests: this._metrics.failedRequests,
totalDuration: this._metrics.totalDuration,
byMethod: this._metrics.byMethod,
lastErrors: this._metrics.lastErrors
};
}
/**
* @inheritDoc
*/
async reset() {
this._metrics.totalRequests = 0;
this._metrics.successfulRequests = 0;
this._metrics.failedRequests = 0;
this._metrics.totalDuration = 0;
this._metrics.byMethod.clear();
this._metrics.lastErrors = [];
return this._restrictionManager.reset();
}
// endregion ////
// region Metrics ////
_updateMetrics(method, isSuccess, duration, error) {
this._metrics.totalRequests++;
if (isSuccess) {
this._metrics.successfulRequests++;
} else {
this._metrics.failedRequests++;
if (error instanceof AjaxError) {
this._metrics.lastErrors.push({
method,
error: error.message,
timestamp: Date.now()
});
if (this._metrics.lastErrors.length > 100) {
this._metrics.lastErrors = this._metrics.lastErrors.slice(-100);
}
}
}
if (!this._metrics.byMethod.has(method)) {
this._metrics.byMethod.set(method, { count: 0, totalDuration: 0 });
}
const methodMetrics = this._metrics.byMethod.get(method);
methodMetrics.count++;
methodMetrics.totalDuration += duration;
}
// endregion ////
_validateParams(requestId, method, params) {
try {
JSON.stringify(params);
} catch (error) {
throw new AjaxError({
code: "JSSDK_INVALID_PARAMS",
description: "Parameters contain circular references",
status: 400,
requestInfo: { method, params, requestId },
originalError: error
});
}
}
/**
* Calling the RestApi function
* @param method - REST API method name
* @param params - Parameters for the method.
* @param requestId - Request id
* @returns Promise with AjaxResult
*/
async call(method, params, requestId) {
requestId = requestId ?? this._requestIdGenerator.getRequestId();
const maxRetries = this._restrictionManager.getParams().maxRetries;
this._validateParams(requestId, method, params);
this._logRequest(requestId, method, params);
let lastError = null;
const startTime = Date.now();
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
this._logAttempt(requestId, method, attempt + 1, maxRetries);
await this._restrictionManager.applyOperatingLimits(requestId, method, params);
const result = await this._executeSingleCall(requestId, method, params);
const duration = Date.now() - startTime;
this._restrictionManager.resetErrors(method);
this._updateMetrics(method, true, duration);
this._logSuccessfulRequest(requestId, method, duration);
return result;
} catch (error) {
lastError = this._convertToAjaxError(requestId, error, method, params);
const duration = Date.now() - startTime;
this._restrictionManager.incrementError(method);
this._updateMetrics(method, false, duration, lastError);
this._logFailedRequest(requestId, method, attempt + 1, maxRetries, lastError);
if (attempt + 1 < maxRetries) {
const waitTime = await this._restrictionManager.handleError(requestId, method, params, lastError, attempt);
if (waitTime > 0) {
this._restrictionManager.incrementStats("limitHits");
this._logAttemptRetryWaiteDelay(requestId, method, waitTime, attempt + 1, maxRetries);
await this._restrictionManager.waiteDelay(waitTime);
this._restrictionManager.incrementStats("retries");
continue;
}
}
if (attempt + 1 === maxRetries) {
this._logAllAttemptsExhausted(requestId, method, attempt + 1, maxRetries);
}
if (this._restrictionManager.exceptionCodeForSoft.includes(lastError.code)) {
return this._createAjaxResultWithErrorFromResponse(lastError, requestId, method, params);
}
throw lastError;
}
}
throw new AjaxError({
code: "JSSDK_CALL_ALL_ATTEMPTS_EXHAUSTED",
description: "All attempts exhausted",
status: lastError?.status || 500,
requestInfo: { method, params, requestId },
originalError: lastError?.originalError || null
});
}
_convertToAjaxError(requestId, error, method, params) {
if (error instanceof AjaxError) {
return error;
}
if (error instanceof AxiosError) {
return this._convertAxiosErrorToAjaxError(requestId, error, method, params);
}
return this._convertUnknownErrorToAjaxError(requestId, error, method, params);
}
_convertAxiosErrorToAjaxError(requestId, axiosError, method, params) {
const errorCode = `${axiosError.code || "JSSDK_AXIOS_ERROR"}`;
const errorDescription = axiosError.message;
const status = axiosError.response?.status || 0;
if (errorCode === "ERR_NETWORK") {
return new AjaxError({
code: "NETWORK_ERROR",
description: "Network connection failed",
status: 0,
requestInfo: { method, params, requestId },
originalError: axiosError
});
}
if (errorCode === "ECONNABORTED" || axiosError.message.includes("timeout")) {
return new AjaxError({
code: "REQUEST_TIMEOUT",
description: "Request timeout exceeded",
status: 408,
requestInfo: { method, params, requestId },
originalError: axiosError
});
}
const parsed = parseErrorPayload(axiosError.response?.data, errorCode, errorDescription);
return new AjaxError({
code: parsed?.code ?? errorCode,
description: parsed?.description ?? errorDescription,
status,
validation: parsed?.validation,
requestInfo: { method, params, requestId },
originalError: axiosError
});
}
_convertUnknownErrorToAjaxError(requestId, error, method, params) {
return new AjaxError({
code: "JSSDK_UNKNOWN_ERROR",
description: error instanceof Error ? error.message : String(error),
status: 0,
requestInfo: { method, params, requestId },
originalError: error
});
}
// region Execute Single Call ////
/**
* Performs a single call with
* - 401 error handling
* - rate limit check
* - updating operating statistics
*/
async _executeSingleCall(requestId, method, params) {
this._checkClientSideWarning(requestId);
const authData = await this._ensureAuth(requestId);
const response = await this._makeRequestWithAuthRetry(requestId, method, params, authData);
return this._createAjaxResultFromResponse(response, requestId, method, params);
}
// Get/update authorization
async _ensureAuth(requestId) {
let authData = this._authActions.getAuthData();
if (authData === false) {
this._logRefreshingAuthToken(requestId);
authData = await this._refreshAuth();
}
return authData;
}
/**
* Refresh the auth token, coalescing concurrent callers onto a single
* in-flight `refreshAuth()` so a burst of 401s triggers exactly one refresh
* round-trip. The slot clears once the refresh settles. (#182)
*/
_refreshAuth() {
if (this._pendingRefresh) {
return this._pendingRefresh;
}
const refresh = this._authActions.refreshAuth();
this._pendingRefresh = refresh;
refresh.finally(() => {
this._pendingRefresh = null;
}).catch(() => {
});
return refresh;
}
// Execute the request with 401 error handling
async _makeRequestWithAuthRetry(requestId, method, params, authData) {
try {
await this._restrictionManager.checkRateLimit(requestId, method);
return await this._makeAxiosRequest(requestId, method, params, authData);
} catch (error) {
if (error instanceof AxiosError) {
this.getLogger().info(
`post/catchError`,
{
requestId,
status: error.status,
// Redact in case a future portal response embeds credentials in
// the error body (today it doesn't, but the channel is open) (#39),
// and cap the length so a large error body can't flood the sink (#236).
responseData: truncateForLog(JSON.stringify(redactSensitiveParams(error?.response?.data), null, 0))
}
).catch(() => {
});
}
const ajaxError = this._convertToAjaxError(requestId, error, method, params);
if (this._isAuthError(ajaxError)) {
this._logAuthErrorDetected(requestId);
this._logRefreshingAuthToken(requestId);
const refreshedAuthData = await this._refreshAuth();
await this._restrictionManager.checkRateLimit(requestId, method);
return await this._makeAxiosRequest(requestId, method, params, refreshedAuthData);
}
throw ajaxError;
}
}
async _makeAxiosRequest(requestId, method, params, authData) {
const methodFormatted = this._prepareMethod(requestId, method, this.getBaseUrl());
const paramsFormatted = this._prepareParams(authData, params);
const paramsFormattedForLog = JSON.stringify(redactSensitiveParams(paramsFormatted), null, 0);
this.getLogger().info(
`post/send`,
{
requestId,
method,
params: truncateForLog(paramsFormattedForLog)
}
).catch(() => {
});
const response = await this._clientAxios.post(methodFormatted, paramsFormatted);
const resultFormattedForLog = JSON.stringify(redactSensitiveParams(response.data.result), null, 0);
this.getLogger().info(
`post/response`,
{
requestId,
// responseFull: JSON.stringify(response.data, null, 2),
result: truncateForLog(resultFormattedForLog),
time: JSON.stringify(response.data.time, null, 0)
}
).catch(() => {
});
return {
status: response.status,
payload: response.data
};
}
_isAuthError(error) {
if (!(error instanceof AjaxError)) {
return false;
}
return error.status === 401 && ["expired_token", "invalid_token"].includes(error.code);
}
async _createAjaxResultFromResponse(response, requestId, method, params) {
const result = new AjaxResult({
answer: response.payload,
query: { method, params, requestId },
status: response.status
});
if (result.isSuccess) {
const time = result.getData()?.time;
await this._restrictionManager.updateStats(requestId, method, time);
}
return result;
}
/**
* Turns an error the transport already built into the soft `AjaxResult` a
* caller receives, for the codes in `RestrictionManager.exceptionCodeForSoft`.
*
* It used to rebuild the error from a synthetic answer holding only `code` and
* `message`, so the portal's real body was discarded here — which is why
* `validation` was unreachable even though `_convertAxiosErrorToAjaxError` had
* just parsed it (#423).
*
* The error is now **carried** rather than re-derived: the synthetic `answer`
* is kept so `_data` still describes the failure for anything reading it, but
* it is no longer what produces the error — which also means the two can no
* longer disagree. `validation` is deliberately not copied into that synthetic
* answer: nothing parses it back out, so it would be dead weight that a future
* refactor could mistake for the source of truth.
*
* The carried error keeps its `originalError` — the raw `AxiosError`, whose
* `config.url` holds the webhook secret. It is non-enumerable (see
* `SdkError`), so spreads and `JSON.stringify` still cannot reach it, but it
* is now readable via `result.getErrors()` on this path as well as on the
* throwing one. That is deliberate: the two paths differ only in how the error
* is delivered, and a caller debugging one should not find less on the other.
*/
_createAjaxResultWithErrorFromResponse(ajaxError, requestId, method, params) {
return new AjaxResult({
answer: {
error: {
code: ajaxError.code,
message: ajaxError.message
}
},
query: { method, params, requestId },
status: ajaxError.status,
// The error itself, not a reconstruction: it was parsed from the portal's
// body a moment ago, and re-deriving it here would fold the validation
// messages onto a description that already holds them (#423).
error: ajaxError
});
}
// endregion ////
// endregion ////
// region Prepare ////
/**
* Builds the request URL: the method path plus the SDK telemetry query params
* (`bx24_request_id` / `bx24_sdk_ver` / `bx24_sdk_type` — request tracing and
* SDK identification, not auth material).
*
* Carve-out for the legacy positional `task.*` methods (`task.commentitem.*`,
* `task.checklistitem.*`, `task.elapseditem.*`, …): these read the request
* **query string positionally**, so appending the telemetry params shifts
* `Param #0` and the server rejects the call —
* `WRONG_ARGUMENTS: Param #0 (taskId) ... expected integer, but given
* something else`. Verified live against a portal: the same
* `task.commentitem.getlist` / `task.checklistitem.getlist` call succeeds
* without the telemetry params and fails with them; modern `tasks.task.*`
* (named params) is unaffected. So telemetry is omitted only for methods whose
* name STARTS WITH `task.`.
*
* Shared by v2 and v3 (rather than per-transport): once the v3 method
* allowlist was dropped (#259) a positional `task.*` method can be routed via
* `actions.v3.*` too, so v3 needs the same suppression — keeping the rule in
* one place stops the two transports drifting apart again (#207).
*
* The match is anchored (`^task\.`): only legacy positional `task.*` methods
* are suppressed. Modern named-param methods `tasks.task.*` / `bizproc.task.*`
* do NOT start with `task.`, so they KEEP telemetry and stay traceable — the
* boundary was pinned live in #271/#272 (`tasks.task.list` works WITH
* telemetry; legacy `task.*` breaks WITH it). Bitrix24 method names are
* lowercase by convention, so the case-sensitive match is sufficient.
*
* @see https://apidocs.bitrix24.com/settings/how-to-call-rest-api/data-encoding.html#order-of-parameters
*/
_prepareMethod(requestId, method, baseUrl) {
const methodUrl = `/${encodeURIComponent(method)}`;
if (/^task\./.test(method)) {
return `${baseUrl}${methodUrl}`;
}
const queryParams = new URLSearchParams({
[this._requestIdGenerator.getQueryStringParameterName()]: requestId,
[this._requestIdGenerator.getQueryStringSdkParameterName()]: "2.2.0",
[this._requestIdGenerator.getQueryStringSdkTypeParameterName()]: "b24-js-sdk"
});
return `${baseUrl}${methodUrl}?${queryParams.toString()}`;
}
/**
* Processes function parameters and adds authorization
*/
_prepareParams(authData, params) {
const result = { ...params };
if (authData.refresh_token !== "hook") {
result.auth = authData.access_token;
}
if (result?.data && "start" in result.data) {
const { start, ...dataWithoutStart } = result.data;
result.data = dataWithoutStart;
}
return result;
}
/**
* @inheritDoc
*/
setClientSideWarning(value, message) {
this._isClientSideWarning = value;
this._clientSideWarningMessage = message;
}
// endregion ////
// region Tools ////
/**
* Tests whether the code is executed on the client side
* @return {boolean}
* @protected
*/
isServerSide() {
return getEnvironment() !== Environment.BROWSE;
}
/**
* Get the BX24 account address with the path based on the API version
*/
getBaseUrl() {
return this._authActions.getTargetOriginWithPath().get(this._version);
}
// endregion ////
// region Log ////
/**
* Redaction contract: runs caller params through {@link redactSensitiveParams}
* (see `redact.ts`) so credential-bearing keys are masked before they reach any
* logger context. (#39, #73)
* @see redactSensitiveParams
*/
_sanitizeParams(params) {
return redactSensitiveParams(params);
}
/**
* Redaction contract: params are redacted via {@link _sanitizeParams} →
* {@link redactSensitiveParams} before logging. (#73)
* @see redactSensitiveParams
*/
_logRequest(requestId, method, params) {
this.getLogger().debug(`http request starting`, {
requestId,
method,
params: this._sanitizeParams(params),
api: this.apiVersion,
timestamp: Date.now()
}).catch(() => {
});
}
_logAttempt(requestId, method, attempt, maxRetries) {
this.getLogger().info(`http request attempt`, {
requestId,
method,
api: this.apiVersion,
attempt: {
current: attempt,
max: maxRetries
}
}).catch(() => {
});
}
_logRefreshingAuthToken(requestId) {
this.getLogger().info(`http refreshing auth token`, {
requestId,
api: this.apiVersion
}).catch(() => {
});
}
_logAuthErrorDetected(requestId) {
this.getLogger().info(`http auth error detected`, {
requestId,
api: this.apiVersion
}).catch(() => {
});
}
_logSuccessfulRequest(requestId, method, duration) {
this.getLogger().debug(`http request successful`, {
requestId,
method,
api: this.apiVersion,
duration: {
ms: duration,
sec: Number.parseFloat((duration / 1e3).toFixed(2))
}
}).catch(() => {
});
}
_logFailedRequest(requestId, method, attempt, maxRetries, error) {
this.getLogger().debug(`http request failed`, {
requestId,
method,
api: this.apiVersion,
attempt: {
current: attempt,
max: maxRetries
},
error: {
code: error.code,
message: error.message,
status: error.status
}
}).catch(() => {
});
}
_logAttemptRetryWaiteDelay(requestId, method, wait, attempt, maxRetries) {
this.getLogger().debug(
`http wait ${(wait / 1e3).toFixed(2)} sec.`,
{
requestId,
method,
api: this.apiVersion,
wait,
attempt: {
current: attempt,
max: maxRetries
}
}
).catch(() => {
});
}
_logAllAttemptsExhausted(requestId, method, attempt, maxRetries) {
this.getLogger().warning(`http all retry attempts exhausted`, {
requestId,
method,
api: this.apiVersion,
attempt: {
current: attempt,
max: maxRetries
}
}).catch(() => {
});
}
_logBatchStart(requestId, calls, options) {
const callCount = Array.isArray(calls) ? calls.length : Object.keys(calls).length;
this.getLogger().debug(`http batch request starting `, {
requestId,
callCount,
api: this.apiVersion,
isHaltOnError: options.isHaltOnError,
timestamp: Date.now()
}).catch(() => {
});
}
_logBatchCompletion(requestId, total, errors) {
this.getLogger().debug(`http batch request completed`, {
requestId,
api: this.apiVersion,
totalCalls: total,
successful: total - errors,
failed: errors,
successRate: total > 0 ? ((total - errors) / total * 100).toFixed(1) + "%" : "??"
}).catch(() => {
});
}
// Check client-side warnings
_checkClientSideWarning(requestId) {
if (this._isClientSideWarning && !this.isServerSide() && Type.isStringFilled(this._clientSideWarningMessage)) {
LoggerFactory.forcedLog(
this.getLogger(),
"warning",
this._clientSideWarningMessage,
{
requestId,
code: "JSSDK_CLIENT_SIDE_WARNING"
}
);
}
}
// endregion ////
}
var __defProp$Q = Object.defineProperty;
var __name$Q = (target, value) => __defProp$Q(target, "name", { value, configurable: true });
class AbstractInteractionBatch {
static {
__name$Q(this, "AbstractInteractionBatch");
}
parallelDefaultValue;
requestId;
restrictionManager;
// @memo this regeneration -> isObjectMode
processingStrategy;
_commands = [];
constructor(options) {
this.parallelDefaultValue = options.parallelDefaultValue;
this.requestId = options.requestId;
this.restrictionManager = options.restrictionManager;
this.processingStrategy = options.processingStrategy;
}
// region Setter Strategy ////
setProcessingStrategy(processingStrategy) {
this.processingStrategy = processingStrategy;
}
// endregion ////
// region Getter ////
get size() {
return this._commands.length;
}
get maxSize() {
return 0;
}
// endregion ////
// region Request ////
addCommands(calls) {
if (!this.processingStrategy) {
throw new SdkError({
code: "JSSDK_INTERACTION_BATCH_EMPTY_PROCESSING_STRATEGY",
description: "ProcessingStrategy not set",
status: 500
});
}
this._commands = this.processingStrategy.prepareCommands(calls, {
parallelDefaultValue: this.parallelDefaultValue
});
}
getCommandsForCall() {
if (!this.processingStrategy) {
throw new SdkError({
code: "JSSDK_INTERACTION_BATCH_EMPTY_PROCESSING_STRATEGY",
description: "ProcessingStrategy not set",
status: 500
});
}
return this.processingStrategy.buildCommands(this._commands);
}
// endregion ////
}
var __defProp$P = Object.defineProperty;
var __name$P = (target, value) => __defProp$P(target, "name", { value, configurable: true });
const MAX_BATCH_COMMANDS_V2 = 50;
class InteractionBatchV2 extends AbstractInteractionBatch {
static {
__name$P(this, "InteractionBatchV2");
}
get maxSize() {
return MAX_BATCH_COMMANDS_V2;
}
// region Response ////
async prepareResponse(response) {
if (!this.processingStrategy) {
throw new SdkError({
code: "JSSDK_INTERACTION_BATCH_EMPTY_PROCESSING_STRATEGY",
description: "ProcessingStrategy not set",
status: 500
});
}
const responseHelper = {
requestId: response.getQuery().requestId,
parallelDefaultValue: this.parallelDefaultValue,
restrictionManager: this.restrictionManager,
response
};
const results = await this.processingStrategy.prepareItems(this._commands, responseHelper);
return this.processingStrategy.handleResults(this._commands, results, responseHelper);
}
// endregion ////
}
const replace = String.prototype.replace;
const percentTwenties = /%20/g;
const Format = {
RFC1738: 'RFC1738',
RFC3986: 'RFC3986',
};
const formatters = {
RFC1738: function (value) {
return replace.call(value, percentTwenties, '+')
},
RFC3986: function (value) {
return String(value)
},
};
const RFC1738 = Format.RFC1738;
const formats = Format.RFC3986;
const isArray$1 = Array.isArray;
const hexTable = (function () {
const array = [];
for (let i = 0; i < 256; ++i) {
array.push('%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase());
}
return array
})();
const limit = 1024;
const encode = function encode(str, _defaultEncoder, _kind, format) {
// This code was originally written by Brian White (mscdex) for the io.js core querystring library.
// It has been adapted here for stricter adherence to RFC 3986
if (str.length === 0) {
return str
}
let string = str;
if (typeof str === 'symbol') {
string = Symbol.prototype.toString.call(str);
} else if (typeof str !== 'string') {
string = String(str);
}
let out = '';
for (let j = 0; j < string.length; j += limit) {
const segment = string.length >= limit ? string.slice(j, j + limit) : string;
const arr = [];
for (let i = 0; i < segment.length; ++i) {
let c = segment.charCodeAt(i);
if (
c === 0x2d || // -
c === 0x2e || // .
c === 0x5f || // _
c === 0x7e || // ~
(c >= 0x30 && c <= 0x39) || // 0-9
(c >= 0x41 && c <= 0x5a) || // a-z
(c >= 0x61 && c <= 0x7a) || // A-Z
(format === RFC1738 && (c === 0x28 || c === 0x29)) // ( )
) {
arr[arr.length] = segment.charAt(i);
continue
}
if (c < 0x80) {
arr[arr.length] = hexTable[c];
continue
}
if (c < 0x800) {
arr[arr.length] = hexTable[0xc0 | (c >> 6)] + hexTable[0x80 | (c & 0x3f)];
continue
}
if (c < 0xd800 || c >= 0xe000) {
arr[arr.length] =
hexTable[0xe0 | (c >> 12)] +
hexTable[0x80 | ((c >> 6) & 0x3f)] +
hexTable[0x80 | (c & 0x3f)];
continue
}
i += 1;
c = 0x10000 + (((c & 0x3ff) << 10) | (segment.charCodeAt(i) & 0x3ff));
arr[arr.length] =
hexTable[0xf0 | (c >> 18)] +
hexTable[0x80 | ((c >> 12) & 0x3f)] +
hexTable[0x80 | ((c >> 6) & 0x3f)] +
hexTable[0x80 | (c & 0x3f)];
}
out += arr.join('');
}
return out
};
const isBuffer = function isBuffer(obj) {
if (!obj || typeof obj !== 'object') {
return false
}
return !!(obj.constructor && obj.constructor.isBuffer && obj.constructor.isBuffer(obj))
};
const maybeMap = function maybeMap(val, fn) {
if (isArray$1(val)) {
const mapped = [];
for (let i = 0; i < val.length; i += 1) {
mapped.push(fn(val[i]));
}
return mapped
}
return fn(val)
};
const arrayPrefixGenerators = {
brackets: function brackets(prefix) {
return prefix + '[]'
},
comma: 'comma',
indices: function indices(prefix, key) {
return prefix + '[' + key + ']'
},
repeat: function repeat(prefix) {
return prefix
},
};
const isArray = Array.isArray;
const push = Array.prototype.push;
const pushToArray = function (arr, valueOrArray) {
push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
};
const toISO = Date.prototype.toISOString;
const defaultFormat = formats;
const defaults = {
addQueryPrefix: false,
allowDots: false,
allowEmptyArrays: false,
arrayFormat: 'indices',
delimiter: '&',
encode: true,
encodeDotInKeys: false,
encoder: encode,
encodeValuesOnly: false,
format: defaultFormat,
formatter: formatters[defaultFormat],
// deprecated
indices: false,
serializeDate: function serializeDate(date) {
return toISO.call(date)
},
skipNulls: false,
strictNullHandling: false,
};
const isNonNullishPrimitive = function isNonNullishPrimitive(v) {
return (
typeof v === 'string' ||
typeof v === 'number' ||
typeof v === 'boolean' ||
typeof v === 'symbol' ||
typeof v === 'bigint'
)
};
const sentinel = {};
const _stringify = function stringify(
object,
prefix,
generateArrayPrefix,
commaRoundTrip,
allowEmptyArrays,
strictNullHandling,
skipNulls,
encodeDotInKeys,
encoder,
filter,
sort,
allowDots,
serializeDate,
format,
formatter,
encodeValuesOnly,
sideChannel,
) {
let obj = object;
let tmpSc = sideChannel;
let step = 0;
let findFlag = false;
while ((tmpSc = tmpSc.get(sentinel)) !== void undefined && !findFlag) {
// Where object last appeared in the ref tree
const pos = tmpSc.get(object);
step += 1;
if (typeof pos !== 'undefined') {
if (pos === step) {
throw new RangeError('Cyclic object value')
} else {
findFlag = true; // Break while
}
}
if (typeof tmpSc.get(sentinel) === 'undefined') {
step = 0;
}
}
if (typeof filter === 'function') {
obj = filter(prefix, obj);
} else if (obj instanceof Date) {
obj = serializeDate(obj);
} else if (generateArrayPrefix === 'comma' && isArray(obj)) {
obj = maybeMap(obj, function (value) {
if (value instanceof Date) {
return serializeDate(value)
}
return value
});
}
if (obj === null) {
if (strictNullHandling) {
return encoder && !encodeValuesOnly
? encoder(prefix, defaults.encoder, 'key', format)
: prefix
}
obj = '';
}
if (isNonNullishPrimitive(obj) || isBuffer(obj)) {
if (encoder) {
const keyValue = encodeValuesOnly
? prefix
: encoder(prefix, defaults.encoder, 'key', format);
return [
formatter(keyValue) +
'=' +
formatter(encoder(obj, defaults.encoder, 'value', format)),
]
}
return [formatter(prefix) + '=' + formatter(String(obj))]
}
const values = [];
if (typeof obj === 'undefined') {
return values
}
let objKeys;
if (generateArrayPrefix === 'comma' && isArray(obj)) {
// we need to join elements in
if (encodeValuesOnly && encoder) {
obj = maybeMap(obj, encoder);
}
objKeys = [{ value: obj.length > 0 ? obj.join(',') || null : void undefined }];
} else if (isArray(filter)) {
objKeys = filter;
} else {
const keys = Object.keys(obj);
objKeys = sort ? keys.sort(sort) : keys;
}
const encodedPrefix = encodeDotInKeys ? prefix.replace(/\./g, '%2E') : prefix;
const adjustedPrefix =
commaRoundTrip && isArray(obj) && obj.length === 1 ? encodedPrefix + '[]' : encodedPrefix;
if (allowEmptyArrays && isArray(obj) && obj.length === 0) {
return adjustedPrefix + '[]'
}
for (let j = 0; j < objKeys.length; ++j) {
const key = objKeys[j];
const value = typeof key === 'object' && typeof key.value !== 'undefined' ? key.value : obj[key];
if (skipNulls && value === null) {
continue
}
const encodedKey = allowDots && encodeDotInKeys ? key.replace(/\./g, '%2E') : key;
const keyPrefix = isArray(obj)
? typeof generateArrayPrefix === 'function'
? generateArrayPrefix(adjustedPrefix, encodedKey)
: adjustedPrefix
: adjustedPrefix + (allowDots ? '.' + encodedKey : '[' + encodedKey + ']');
sideChannel.set(object, step);
const valueSideChannel = new WeakMap();
valueSideChannel.set(sentinel, sideChannel);
pushToArray(
values,
_stringify(
value,
keyPrefix,
generateArrayPrefix,
commaRoundTrip,
allowEmptyArrays,
strictNullHandling,
skipNulls,
encodeDotInKeys,
generateArrayPrefix === 'comma' && encodeValuesOnly && isArray(obj) ? null : encoder,
filter,
sort,
allowDots,
serializeDate,
format,
formatter,
encodeValuesOnly,
valueSideChannel,
),
);
}
return values
};
const normalizeStringifyOptions = function normalizeStringifyOptions(opts) {
{
return defaults
}
};
function stringify(object, opts) {
let obj = object;
const options = normalizeStringifyOptions();
let objKeys;
let filter;
if (typeof options.filter === 'function') {
filter = options.filter;
obj = filter('', obj);
} else if (isArray(options.filter)) {
filter = options.filter;
objKeys = filter;
}
const keys = [];
if (typeof obj !== 'object' || obj === null) {
return ''
}
const generateArrayPrefix = arrayPrefixGenerators[options.arrayFormat];
const commaRoundTrip = generateArrayPrefix === 'comma' && options.commaRoundTrip;
if (!objKeys) {
objKeys = Object.keys(obj);
}
if (options.sort) {
objKeys.sort(options.sort);
}
const sideChannel = new WeakMap();
for (let i = 0; i < objKeys.length; ++i) {
const key = objKeys[i];
if (options.skipNulls && obj[key] === null) {
continue
}
pushToArray(
keys,
_stringify(
obj[key],
key,
generateArrayPrefix,
commaRoundTrip,
options.allowEmptyArrays,
options.strictNullHandling,
options.skipNulls,
options.encodeDotInKeys,
options.encode ? options.encoder : null,
options.filter,
options.sort,
options.allowDots,
options.serializeDate,
options.format,
options.formatter,
options.encodeValuesOnly,
sideChannel,
),
);
}
const joined = keys.join(options.delimiter);
const prefix = options.addQueryPrefix === true ? '?' : '';
return joined.length > 0 ? prefix + joined : ''
}
var __defProp$O = Object.defineProperty;
var __name$O = (target, value) => __defProp$O(target, "name", { value, configurable: true });
class AbstractProcessing {
static {
__name$O(this, "AbstractProcessing");
}
// region prepareItems ////
/**
* Template method. The soft-error envelope guard lives here ONCE so v2 and v3
* can't drift on it (#228 — hoisted from the duplicated #145 fix).
*
* When the batch CALL itself soft-errors (a top-level code in the restriction
* manager's `exceptionCodeForSoft` set, surfaced as a soft `Result` instead of
* a throw), the envelope carries `{ error }` and no `result`, so
* `response.getData()` is `undefined`. Skip per-row parsing — it would
* dereference `getData()!.result` — and let {@link handleResults} surface the
* top-level errors. The version-specific success path is {@link _prepareItemsSuccess}.
*/
async prepareItems(commands, responseHelper) {
const results = /* @__PURE__ */ new Map();
if (!responseHelper.response.isSuccess) {
return results;
}
return this._prepareItemsSuccess(commands, responseHelper, results);
}
// endregion ////
// region handleResults ////
/**
* Template method. Same single soft-error guard as {@link prepareItems} (#228):
* there is no per-row data and `getData()` is `undefined`, so surface the
* envelope's top-level errors and return an empty data map instead of
* dereferencing `getData()!.time`. The version-specific success path is
* {@link _handleResultsSuccess}.
*/
async handleResults(commands, results, responseHelper) {
const result = new Result();
if (!responseHelper.response.isSuccess) {
for (const [index, error] of responseHelper.response.errors) {
result.addError(error, index);
}
result.setData({
result: /* @__PURE__ */ new Map(),
time: void 0
});
return result;
}
return this._handleResultsSuccess(commands, results, responseHelper, result);
}
// endregion ////
// region Tools ////
_getBatchResultByIndex(data, index) {
if (!data) return void 0;
if (Array.isArray(data)) {
return data[index];
}
return data[index];
}
_createErrorFromAjaxResult(ajaxResult) {
if (ajaxResult.hasError("base-error")) {
return ajaxResult.errors.get("base-error");
}
return new AjaxError({
code: "JSSDK_BATCH_SUB_ERROR",
description: ajaxResult.getErrorMessages().join("; "),
status: ajaxResult.getStatus(),
requestInfo: { ...ajaxResult.getQuery() },
originalError: ajaxResult.getErrors().next().value
});
}
// endregion ////
}
var __defProp$N = Object.defineProperty;
var __name$N = (target, value) => __defProp$N(target, "name", { value, configurable: true });
class AbstractProcessingV2 extends AbstractProcessing {
static {
__name$N(this, "AbstractProcessingV2");
}
_buildRow(command) {
return `${command.method}?${stringify(command.query || {})}`;
}
buildCommands(commands) {
if (commands.length < 1) {
throw new SdkError({
code: "JSSDK_INTERACTION_BATCH_STRATEGY_V2_EMPTY_COMMANDS",
description: "commands not set",
status: 500
});
}
const firstCommand = commands[0];
const asObject = typeof firstCommand.as === "string" && firstCommand.as.length > 0;
if (asObject) {
const result2 = {};
for (const command of commands) {
result2[command.as] = this._buildRow(command);
}
return result2;
}
const result = [];
for (const command of commands) {
result.push(this._buildRow(command));
}
return result;
}
// region prepareItems ////
// Soft-error guard lives in AbstractProcessing.prepareItems (#228); this is the
// success-only path for apiVer2.
async _prepareItemsSuccess(commands, responseHelper, results) {
for (const [index, command] of commands.entries()) {
await this._processResponseItem(
command,
// @memo for apiVer2 in this pace we get objectIndex from `command.as` OR array `index` from `commands[]`
command.as ?? index,
responseHelper,
results
);
}
return results;
}
async _processResponseItem(command, index, responseHelper, results) {
const responseResult = responseHelper.response.getData().result;
const resultData = this._getBatchResultByIndex(responseResult.result, index);
const resultError = this._getBatchResultByIndex(responseResult.result_error, index);
if (typeof resultData !== "undefined" || typeof resultError !== "undefined") {
const methodName = command.method;
const resultTime = this._getBatchResultByIndex(responseResult.result_time, index);
if (typeof resultTime !== "undefined") {
await responseHelper.restrictionManager.updateStats(responseHelper.requestId, `batch::${methodName}`, resultTime);
}
const result = new AjaxResult({
answer: {
error: resultError ? typeof resultError === "string" ? resultError : resultError.error : void 0,
error_description: resultError ? typeof resultError === "string" ? void 0 : resultError.error_description : void 0,
result: resultData,
total: Number.parseInt(this._getBatchResultByIndex(responseResult.result_total, index) || "0"),
next: Number.parseInt(this._getBatchResultByIndex(responseResult.result_next, index) || "0"),
time: resultTime
},
query: {
method: methodName,
params: command.query || {},
requestId: responseHelper.requestId
},
status: responseHelper.response.getStatus()
});
results.set(index, result);
return;
}
if (responseHelper.parallelDefaultValue) {
throw new SdkError({
code: "JSSDK_INTERACTION_BATCH_STRATEGY_V2_EMPTY_COMMAND_RESPONSE",
description: `There were difficulties parsing the response for batch { index: ${index}, method: ${command.method} }`,
status: 500
});
}
}
// endregion ////
// region handleResults ////
// Soft-error guard lives in AbstractProcessing.handleResults (#228); this is the
// success-only path for apiVer2.
async _handleResultsSuccess(_commands, results, responseHelper, result) {
const dataResult = /* @__PURE__ */ new Map();
for (const [index, data] of results) {
if (data.getStatus() !== 200 || !data.isSuccess) {
const ajaxError = this._createErrorFromAjaxResult(data);
this._processResponseError(result, ajaxError, `${index}`);
dataResult.set(index, data);
}
dataResult.set(index, data);
}
result.setData({
result: dataResult,
time: responseHelper.response.getData().time
});
return result;
}
// endregion ////
}
var __defProp$M = Object.defineProperty;
var __name$M = (target, value) => __defProp$M(target, "name", { value, configurable: true });
class ParseRow {
static {
__name$M(this, "ParseRow");
}
static getBatchCommand(row, options) {
if (row) {
if (typeof row === "object" && "method" in row && typeof row.method === "string") {
return {
method: row.method,
query: row.params,
as: row.as ?? options.asDefaultValue,
parallel: row.parallel ?? options.parallelDefaultValue
};
}
if (Array.isArray(row) && row.length > 0 && typeof row[0] === "string") {
return {
method: row[0],
query: row[1],
as: options.asDefaultValue,
parallel: options.parallelDefaultValue
};
}
}
throw new SdkError({
code: "JSSDK_INTERACTION_BATCH_ROW_FAIL",
description: `There were difficulties parsing the command for batch.
${JSON.stringify({
row,
options
})}`,
status: 500
});
}
static getMethodsFromCommands(calls) {
const result = [];
const optsFake = {
parallelDefaultValue: false
};
if (Array.isArray(calls)) {
calls.forEach((row) => {
const command = ParseRow.getBatchCommand(row, optsFake);
result.push(command.method);
});
} else {
Object.entries(calls).forEach(([index, row]) => {
const command = ParseRow.getBatchCommand(row, { ...optsFake, asDefaultValue: index });
result.push(command.method);
});
}
return result;
}
}
var __defProp$L = Object.defineProperty;
var __name$L = (target, value) => __defProp$L(target, "name", { value, configurable: true });
class ProcessingAsArrayV2 extends AbstractProcessingV2 {
static {
__name$L(this, "ProcessingAsArrayV2");
}
prepareCommands(calls, options) {
const result = [];
calls.forEach((row) => {
const command = ParseRow.getBatchCommand(row, options);
result.push(command);
});
return result;
}
_processResponseError(result, ajaxError, index) {
result.addError(ajaxError, index);
}
}
var __defProp$K = Object.defineProperty;
var __name$K = (target, value) => __defProp$K(target, "name", { value, configurable: true });
class ProcessingAsObjectV2 extends AbstractProcessingV2 {
static {
__name$K(this, "ProcessingAsObjectV2");
}
prepareCommands(calls, options) {
const result = [];
Object.entries(calls).forEach(([index, row]) => {
const command = ParseRow.getBatchCommand(row, { ...options, asDefaultValue: index });
result.push(command);
});
return result;
}
_processResponseError(result, ajaxError, index) {
result.addError(ajaxError, index);
}
}
var __defProp$J = Object.defineProperty;
var __name$J = (target, value) => __defProp$J(target, "name", { value, configurable: true });
class HttpV2 extends AbstractHttp {
static {
__name$J(this, "HttpV2");
}
constructor(authActions, options, restrictionParams) {
super(authActions, options, restrictionParams);
this._version = ApiVersion.v2;
}
// region batch ////
async batch(calls, options) {
const opts = {
isHaltOnError: true,
...options
};
const requestId = opts.requestId ?? this._requestIdGenerator.getRequestId();
this._logBatchStart(requestId, calls, opts);
const interactionBatch = new InteractionBatchV2({
requestId,
parallelDefaultValue: !opts.isHaltOnError,
restrictionManager: this._restrictionManager
});
if (Array.isArray(calls)) {
interactionBatch.setProcessingStrategy(new ProcessingAsArrayV2());
} else {
interactionBatch.setProcessingStrategy(new ProcessingAsObjectV2());
}
interactionBatch.addCommands(calls);
if (interactionBatch.size > interactionBatch.maxSize) {
throw new AjaxError({
code: "JSSDK_BATCH_TOO_LARGE",
description: `Batch too large: ${interactionBatch.size} commands (max: ${interactionBatch.maxSize})`,
status: 400,
requestInfo: { method: "batch", params: { cmd: calls }, requestId },
originalError: null
});
}
if (interactionBatch.size === 0) {
throw new AjaxError({
code: "JSSDK_BATCH_EMPTY",
description: "Batch must contain at least one command",
status: 400,
requestInfo: { method: "batch", params: { cmd: calls }, requestId },
originalError: null
});
}
const envelope = {
halt: opts.isHaltOnError ? 1 : 0,
cmd: interactionBatch.getCommandsForCall()
};
const responseBatch = await this.call(
"batch",
envelope,
requestId
);
const response = await interactionBatch.prepareResponse(responseBatch);
this._logBatchCompletion(
requestId,
response.getData()?.result?.size ?? 0,
response.getErrorMessages().length
);
return response;
}
// endregion ////
}
var __defProp$I = Object.defineProperty;
var __name$I = (target, value) => __defProp$I(target, "name", { value, configurable: true });
const MAX_BATCH_COMMANDS_V3 = 50;
class InteractionBatchV3 extends AbstractInteractionBatch {
static {
__name$I(this, "InteractionBatchV3");
}
get maxSize() {
return MAX_BATCH_COMMANDS_V3;
}
async prepareResponse(response) {
if (!this.processingStrategy) {
throw new SdkError({
code: "JSSDK_INTERACTION_BATCH_EMPTY_PROCESSING_STRATEGY",
description: "ProcessingStrategy not set",
status: 500
});
}
const responseHelper = {
requestId: response.getQuery().requestId,
parallelDefaultValue: this.parallelDefaultValue,
restrictionManager: this.restrictionManager,
response
};
const results = await this.processingStrategy.prepareItems(this._commands, responseHelper);
return this.processingStrategy.handleResults(this._commands, results, responseHelper);
}
}
var __defProp$H = Object.defineProperty;
var __name$H = (target, value) => __defProp$H(target, "name", { value, configurable: true });
class AbstractProcessingV3 extends AbstractProcessing {
static {
__name$H(this, "AbstractProcessingV3");
}
buildCommands(commands) {
if (commands.length < 1) {
throw new SdkError({
code: "JSSDK_INTERACTION_BATCH_BUILD_STRATEGY_V3_EMPTY_COMMANDS",
description: "commands not set",
status: 500
});
}
return commands;
}
// region prepareItems ////
// Soft-error guard lives in AbstractProcessing.prepareItems (#228); this is the
// success-only path for apiVer3 (all-or-nothing — no per-command errors).
async _prepareItemsSuccess(commands, responseHelper, results) {
for (const [index, command] of commands.entries()) {
await this._processResponseItem(
command,
// @memo for apiVer3 in this pace we get objectIndex from array `index` from `commands[]`
index,
responseHelper,
results
);
}
return results;
}
/**
* In `restApi:v3`, `response.getData().result` is the array/record of per-command
* results directly (no `result_error`/`result_time`/`result_total`/`result_next`
* split as in v2). Per-command errors do not exist in this format.
*
* The per-command `result` value is forwarded as-is, including `null` when the
* underlying REST method returns `null` (see issue #23).
*/
async _processResponseItem(command, index, responseHelper, results) {
const responseResult = responseHelper.response.getData().result;
const resultData = this._getBatchResultByIndex(responseResult, index);
if (typeof resultData === "undefined") {
throw new SdkError({
code: "JSSDK_INTERACTION_BATCH_STRATEGY_V3_EMPTY_COMMAND_RESPONSE",
description: `There were difficulties parsing the response for batch { index: ${index}, method: ${command.method} }`,
status: 500
});
}
const resultTime = responseHelper.response.getData().time;
const result = new AjaxResult({
answer: {
result: resultData,
error: void 0,
time: resultTime
},
query: {
method: command.method,
params: command.query || {},
requestId: responseHelper.requestId
},
status: responseHelper.response.getStatus()
});
results.set(index, result);
return;
}
// endregion ////
// region handleResults ////
// Soft-error guard lives in AbstractProcessing.handleResults (#228); this is the
// success-only path for apiVer3.
async _handleResultsSuccess(commands, results, responseHelper, result) {
const dataResult = /* @__PURE__ */ new Map();
for (const [index, data] of results) {
const rowIndex = Number.parseInt(`${index}`);
const command = commands[rowIndex];
if (typeof command === "undefined") {
throw new SdkError({
code: "JSSDK_INTERACTION_BATCH_BUILD_STRATEGY_V3_EMPTY_COMMAND",
description: `command for index ${index} not set`,
status: 500
});
}
const commandIndex = command.as ?? index;
if (data.getStatus() !== 200 || !data.isSuccess) {
const ajaxError = this._createErrorFromAjaxResult(data);
this._processResponseError(result, ajaxError, `${commandIndex}`);
dataResult.set(commandIndex, data);
}
dataResult.set(commandIndex, data);
}
result.setData({
result: dataResult,
time: responseHelper.response.getData().time
});
return result;
}
// endregion ////
}
var __defProp$G = Object.defineProperty;
var __name$G = (target, value) => __defProp$G(target, "name", { value, configurable: true });
class ProcessingAsArrayV3 extends AbstractProcessingV3 {
static {
__name$G(this, "ProcessingAsArrayV3");
}
prepareCommands(calls, options) {
const result = [];
calls.forEach((row) => {
const command = ParseRow.getBatchCommand(row, options);
result.push(command);
});
return result;
}
_processResponseError(result, ajaxError, index) {
result.addError(ajaxError, index);
}
}
var __defProp$F = Object.defineProperty;
var __name$F = (target, value) => __defProp$F(target, "name", { value, configurable: true });
class ProcessingAsObjectV3 extends AbstractProcessingV3 {
static {
__name$F(this, "ProcessingAsObjectV3");
}
prepareCommands(calls, options) {
const result = [];
Object.entries(calls).forEach(([index, row]) => {
const command = ParseRow.getBatchCommand(row, { ...options, asDefaultValue: index });
result.push(command);
});
return result;
}
_processResponseError(result, ajaxError, index) {
result.addError(ajaxError, index);
}
}
var __defProp$E = Object.defineProperty;
var __name$E = (target, value) => __defProp$E(target, "name", { value, configurable: true });
class HttpV3 extends AbstractHttp {
static {
__name$E(this, "HttpV3");
}
constructor(authActions, options, restrictionParams) {
super(authActions, options, restrictionParams);
this._version = ApiVersion.v3;
}
// region batch ////
async batch(calls, options) {
const opts = {
isHaltOnError: true,
...options
};
const requestId = opts.requestId ?? this._requestIdGenerator.getRequestId();
this._logBatchStart(requestId, calls, opts);
const interactionBatch = new InteractionBatchV3({
requestId,
parallelDefaultValue: !opts.isHaltOnError,
restrictionManager: this._restrictionManager
});
if (Array.isArray(calls)) {
interactionBatch.setProcessingStrategy(new ProcessingAsArrayV3());
} else {
interactionBatch.setProcessingStrategy(new ProcessingAsObjectV3());
}
interactionBatch.addCommands(calls);
if (interactionBatch.size > interactionBatch.maxSize) {
throw new AjaxError({
code: "JSSDK_BATCH_TOO_LARGE",
description: `Batch too large: ${interactionBatch.size} commands (max: ${interactionBatch.maxSize})`,
status: 400,
requestInfo: { method: "batch", params: { cmd: calls }, requestId },
originalError: null
});
}
if (interactionBatch.size === 0) {
throw new AjaxError({
code: "JSSDK_BATCH_EMPTY",
description: "Batch must contain at least one command",
status: 400,
requestInfo: { method: "batch", params: { cmd: calls }, requestId },
originalError: null
});
}
const responseBatch = await this.call(
"batch",
// A cast, and an honest one: `restApi:v3` sends the commands AS the request
// body — there is no `{ halt, cmd }` envelope to wrap them in — while
// `call` types its params as `TypeCallParams`. So the request body is not
// call params on this path either, and the cast is what bridges that until
// `call` distinguishes the two. See BatchRequestEnvelopeV2 for the v2 side.
interactionBatch.getCommandsForCall(),
requestId
);
const response = await interactionBatch.prepareResponse(responseBatch);
this._logBatchCompletion(
requestId,
response.getData()?.result?.size ?? 0,
response.getErrorMessages().length
);
return response;
}
// endregion ////
}
var __defProp$D = Object.defineProperty;
var __name$D = (target, value) => __defProp$D(target, "name", { value, configurable: true });
const useScrollSize = /* @__PURE__ */ __name$D(() => {
return {
scrollWidth: Math.max(
document.documentElement.scrollWidth,
document.documentElement.offsetWidth
),
scrollHeight: Math.max(
document.documentElement.scrollHeight,
document.documentElement.offsetHeight
)
};
}, "useScrollSize");
var __defProp$C = Object.defineProperty;
var __name$C = (target, value) => __defProp$C(target, "name", { value, configurable: true });
class FormatterNumbers {
static {
__name$C(this, "FormatterNumbers");
}
static isInternalConstructing = false;
static instance = null;
_defLocale = null;
constructor() {
if (!FormatterNumbers.isInternalConstructing) {
throw new TypeError("FormatterNumber is not constructable");
}
FormatterNumbers.isInternalConstructing = false;
}
/**
* Returns the shared `FormatterNumbers` singleton, creating it on first use.
*
* @returns The shared instance.
*/
static getInstance() {
if (!FormatterNumbers.instance) {
FormatterNumbers.isInternalConstructing = true;
FormatterNumbers.instance = new FormatterNumbers();
}
return FormatterNumbers.instance;
}
/**
* Sets the default locale used by {@link format} when no explicit locale is
* passed. Affects every consumer of the shared instance.
*
* @param locale - A BCP 47 locale tag (e.g. `'de'`, `'ru'`).
*/
setDefLocale(locale) {
this._defLocale = locale;
}
/**
* Formats a number for the given (or default) locale.
*
* The locale falls back to the value set via {@link setDefLocale}, then to
* `navigator.language`, then to `'en'`. Integers get no fraction digits and
* non-integers exactly two. For `ru`-based locales the decimal comma is
* normalised to a dot.
*
* @param value - The number to format.
* @param locale - Optional BCP 47 locale tag overriding the default.
* @returns The formatted number.
*
* @example
* ```ts
* formatterNumber.format(1234.5) // '1,234.50'
* formatterNumber.format(1234.5, 'de') // '1.234,50'
* ```
*/
format(value, locale) {
let formatter;
if (typeof locale === "undefined" || !Type.isStringFilled(locale)) {
locale = Type.isStringFilled(this._defLocale) ? this._defLocale || "en" : typeof navigator === "undefined" ? "en" : navigator?.language || "en";
}
if (Number.isInteger(value)) {
formatter = new Intl.NumberFormat(locale, {
minimumFractionDigits: 0,
maximumFractionDigits: 0
});
} else {
formatter = new Intl.NumberFormat(locale, {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
}
let result = formatter.format(value);
if (locale.includes("ru")) {
result = result.replace(",", ".");
}
return result;
}
}
var __defProp$B = Object.defineProperty;
var __name$B = (target, value) => __defProp$B(target, "name", { value, configurable: true });
class IbanSpecification {
static {
__name$B(this, "IbanSpecification");
}
/**
* the code of the country
*/
countryCode;
/**
* the length of the IBAN
*/
length;
/**
* the structure of the underlying BBAN (for validation and formatting)
*/
structure;
/**
* an example valid IBAN
*/
example;
_cachedRegex = null;
constructor(countryCode, length, structure, example) {
this.countryCode = countryCode;
this.length = length;
this.structure = structure;
this.example = example;
}
/**
* Check if the passed iban is valid, according to this specification.
*
* @param {string} iban the iban to validate
* @returns {boolean} true if valid, false otherwise
*/
isValid(iban) {
return this.length === iban.length && this.countryCode === iban.slice(0, 2) && this._regex().test(iban.slice(4)) && this._iso7064Mod9710(this._iso13616Prepare(iban)) == 1;
}
/**
* Convert the passed IBAN to a country-specific BBAN.
*
* @param iban the IBAN to convert
* @param separator the separator to use between BBAN blocks
* @returns {string} the BBAN
*/
toBBAN(iban, separator) {
return (this._regex().exec(iban.slice(4) || "") || []).slice(1).join(separator);
}
/**
* Convert the passed BBAN to an IBAN for this country specification.
* Please note that <i>"generation of the IBAN shall be the exclusive responsibility of the bank/branch servicing the account"</i>.
* This method implements the preferred algorithm described in http://en.wikipedia.org/wiki/International_Bank_Account_Number#Generating_IBAN_check_digits
*
* @param bban the BBAN to convert to IBAN
* @returns {string} the IBAN
*/
fromBBAN(bban) {
if (!this.isValidBBAN(bban)) {
throw new Error("Invalid BBAN");
}
const remainder = this._iso7064Mod9710(
this._iso13616Prepare(this.countryCode + "00" + bban)
);
const checkDigit = ("0" + (98 - remainder)).slice(-2);
return this.countryCode + checkDigit + bban;
}
/**
* Check of the passed BBAN is valid.
* This function only checks the format of the BBAN (length and compliance with alphanumeric specifications) but does not
* verify the check digit.
*
* @param bban the BBAN to validate
* @returns {boolean} true if the passed bban is a valid BBAN, according to this specification, false otherwise
*/
isValidBBAN(bban) {
return this.length - 4 === bban.length && this._regex().test(bban);
}
/**
* Lazy-loaded regex (parse the structure and construct the regular expression the first time we need it for validation)
*/
_regex() {
if (null === this._cachedRegex) {
this._cachedRegex = this._parseStructure(this.structure);
}
return this._cachedRegex;
}
/**
* Parse the BBAN structure used to configure each IBAN Specification and returns a matching regular expression.
* A structure is composed of blocks of three characters (one letter and two digits).
* Each block represents
* a logical group in the typical representation of the BBAN.
* For each group, the letter indicates which characters
* are allowed in this group, and the following 2-digits number tells the length of the group.
*
* @param {string} structure the structure to parse
* @returns {RegExp}
*/
_parseStructure(structure) {
const regex = (structure.match(/(.{3})/g) || []).map(
(block) => {
let format;
const pattern = block.slice(0, 1);
const repeats = Number.parseInt(block.slice(1), 10);
switch (pattern) {
case "A":
format = "0-9A-Za-z";
break;
case "B":
format = "0-9A-Z";
break;
case "C":
format = "A-Za-z";
break;
case "F":
format = "0-9";
break;
case "L":
format = "a-z";
break;
case "U":
format = "A-Z";
break;
case "W":
format = "0-9a-z";
break;
}
return "([" + format + "]{" + repeats + "})";
}
);
return new RegExp("^" + regex.join("") + "$");
}
/**
* Prepare an IBAN for mod 97 computation by moving the first 4 chars to the end and transforming the letters to
* numbers (A = 10, B = 11, ..., Z = 35), as specified in ISO13616.
*
* @param {string} iban the IBAN
* @returns {string} the prepared IBAN
*/
_iso13616Prepare(iban) {
const A = "A".charCodeAt(0);
const Z = "Z".charCodeAt(0);
iban = iban.toUpperCase();
iban = iban.substring(4) + iban.substring(0, 4);
return iban.split("").map((n) => {
const code = n.charCodeAt(0);
if (code >= A && code <= Z) {
return (code - A + 10).toString();
} else {
return n;
}
}).join("");
}
/**
* Calculates MOD 97 10 of the passed IBAN as specified in ISO7064.
*
* @param iban
* @returns {number} MOD
*/
_iso7064Mod9710(iban) {
let remainder = iban;
let block;
while (remainder.length > 2) {
block = remainder.slice(0, 9);
remainder = Number.parseInt(block, 10) % 97 + remainder.slice(block.length);
}
return Number.parseInt(remainder, 10) % 97;
}
}
class FormatterIban {
static {
__name$B(this, "FormatterIban");
}
static isInternalConstructing = false;
static instance = null;
_countries;
// region Init ////
constructor() {
if (!FormatterIban.isInternalConstructing) {
throw new TypeError("FormatterIban is not constructable");
}
FormatterIban.isInternalConstructing = false;
this._countries = /* @__PURE__ */ new Map();
}
/**
* @return FormatterIban
*/
static getInstance() {
if (!FormatterIban.instance) {
FormatterIban.isInternalConstructing = true;
FormatterIban.instance = new FormatterIban();
}
return FormatterIban.instance;
}
addSpecification(IBAN) {
this._countries.set(IBAN.countryCode, IBAN);
}
// endregion ////
// region IBAN ////
/**
* Check if an IBAN is valid.
*
* @param {string} iban the IBAN to validate.
* @returns {boolean} true if the passed IBAN is valid, false otherwise
*/
isValid(iban) {
if (!Type.isString(iban)) {
return false;
}
iban = this.electronicFormat(iban);
const countryCode = iban.slice(0, 2);
if (!this._countries.has(countryCode)) {
throw new Error(`No country with code ${countryCode}`);
}
const countryStructure = this._countries.get(countryCode);
return !!countryStructure && countryStructure.isValid(iban);
}
printFormat(iban, separator) {
if (typeof separator == "undefined") {
separator = " ";
}
const EVERY_FOUR_CHARS = /(.{4})(?!$)/g;
return this.electronicFormat(iban).replace(
EVERY_FOUR_CHARS,
"$1" + separator
);
}
electronicFormat(iban) {
const NON_ALPHANUM = /[^a-z0-9]/gi;
return iban.replace(NON_ALPHANUM, "").toUpperCase();
}
// endregion ////
// region BBAN ////
/**
* Convert an IBAN to a BBAN.
*
* @param iban
* @param {string} [separator] the separator to use between the blocks of the BBAN, defaults to ' '
* @returns {string|*} Convert an IBAN to a BBAN.
*/
toBBAN(iban, separator) {
if (typeof separator == "undefined") {
separator = " ";
}
iban = this.electronicFormat(iban);
const countryCode = iban.slice(0, 2);
if (!this._countries.has(countryCode)) {
throw new Error(`No country with code ${countryCode}`);
}
const countryStructure = this._countries.get(countryCode);
if (!countryStructure) {
throw new Error(`No country with code ${countryCode}`);
}
return countryStructure.toBBAN(iban, separator);
}
/**
* Convert the passed BBAN to an IBAN for this country specification.
* Please note that <i>"generation of the IBAN shall be the exclusive responsibility of the bank/branch servicing the account"</i>.
* This method implements the preferred algorithm described in http://en.wikipedia.org/wiki/International_Bank_Account_Number#Generating_IBAN_check_digits
*
* @param countryCode the country of the BBAN
* @param bban the BBAN to convert to IBAN
* @returns {string} the IBAN
*/
fromBBAN(countryCode, bban) {
if (!this._countries.has(countryCode)) {
throw new Error(`No country with code ${countryCode}`);
}
const countryStructure = this._countries.get(countryCode);
if (!countryStructure) {
throw new Error(`No country with code ${countryCode}`);
}
return countryStructure.fromBBAN(this.electronicFormat(bban));
}
/**
* Check the validity of the passed BBAN.
*
* @param countryCode the country of the BBAN
* @param bban the BBAN to check the validity of
*/
isValidBBAN(countryCode, bban) {
if (!Type.isString(bban)) {
return false;
}
if (!this._countries.has(countryCode)) {
throw new Error(`No country with code ${countryCode}`);
}
const countryStructure = this._countries.get(countryCode);
return !!countryStructure && countryStructure.isValidBBAN(this.electronicFormat(bban));
}
// endregion ////
}
var __defProp$A = Object.defineProperty;
var __name$A = (target, value) => __defProp$A(target, "name", { value, configurable: true });
const useFormatter = /* @__PURE__ */ __name$A(() => {
const formatterNumber = FormatterNumbers.getInstance();
const formatterIban = FormatterIban.getInstance();
formatterIban.addSpecification(
new IbanSpecification("AD", 24, "F04F04A12", "AD1200012030200359100100")
);
formatterIban.addSpecification(
new IbanSpecification("AE", 23, "F03F16", "AE070331234567890123456")
);
formatterIban.addSpecification(
new IbanSpecification("AL", 28, "F08A16", "AL47212110090000000235698741")
);
formatterIban.addSpecification(
new IbanSpecification("AT", 20, "F05F11", "AT611904300234573201")
);
formatterIban.addSpecification(
new IbanSpecification("AZ", 28, "U04A20", "AZ21NABZ00000000137010001944")
);
formatterIban.addSpecification(
new IbanSpecification("BA", 20, "F03F03F08F02", "BA391290079401028494")
);
formatterIban.addSpecification(
new IbanSpecification("BE", 16, "F03F07F02", "BE68539007547034")
);
formatterIban.addSpecification(
new IbanSpecification("BG", 22, "U04F04F02A08", "BG80BNBG96611020345678")
);
formatterIban.addSpecification(
new IbanSpecification("BH", 22, "U04A14", "BH67BMAG00001299123456")
);
formatterIban.addSpecification(
new IbanSpecification(
"BR",
29,
"F08F05F10U01A01",
"BR9700360305000010009795493P1"
)
);
formatterIban.addSpecification(
new IbanSpecification("BY", 28, "A04F04A16", "BY13NBRB3600900000002Z00AB00")
);
formatterIban.addSpecification(
new IbanSpecification("CH", 21, "F05A12", "CH9300762011623852957")
);
formatterIban.addSpecification(
new IbanSpecification("CR", 22, "F04F14", "CR72012300000171549015")
);
formatterIban.addSpecification(
new IbanSpecification("CY", 28, "F03F05A16", "CY17002001280000001200527600")
);
formatterIban.addSpecification(
new IbanSpecification("CZ", 24, "F04F06F10", "CZ6508000000192000145399")
);
formatterIban.addSpecification(
new IbanSpecification("DE", 22, "F08F10", "DE89370400440532013000")
);
formatterIban.addSpecification(
new IbanSpecification("DK", 18, "F04F09F01", "DK5000400440116243")
);
formatterIban.addSpecification(
new IbanSpecification("DO", 28, "U04F20", "DO28BAGR00000001212453611324")
);
formatterIban.addSpecification(
new IbanSpecification("EE", 20, "F02F02F11F01", "EE382200221020145685")
);
formatterIban.addSpecification(
new IbanSpecification(
"EG",
29,
"F04F04F17",
"EG800002000156789012345180002"
)
);
formatterIban.addSpecification(
new IbanSpecification(
"ES",
24,
"F04F04F01F01F10",
"ES9121000418450200051332"
)
);
formatterIban.addSpecification(
new IbanSpecification("FI", 18, "F06F07F01", "FI2112345600000785")
);
formatterIban.addSpecification(
new IbanSpecification("FO", 18, "F04F09F01", "FO6264600001631634")
);
formatterIban.addSpecification(
new IbanSpecification(
"FR",
27,
"F05F05A11F02",
"FR1420041010050500013M02606"
)
);
formatterIban.addSpecification(
new IbanSpecification("GB", 22, "U04F06F08", "GB29NWBK60161331926819")
);
formatterIban.addSpecification(
new IbanSpecification("GE", 22, "U02F16", "GE29NB0000000101904917")
);
formatterIban.addSpecification(
new IbanSpecification("GI", 23, "U04A15", "GI75NWBK000000007099453")
);
formatterIban.addSpecification(
new IbanSpecification("GL", 18, "F04F09F01", "GL8964710001000206")
);
formatterIban.addSpecification(
new IbanSpecification("GR", 27, "F03F04A16", "GR1601101250000000012300695")
);
formatterIban.addSpecification(
new IbanSpecification("GT", 28, "A04A20", "GT82TRAJ01020000001210029690")
);
formatterIban.addSpecification(
new IbanSpecification("HR", 21, "F07F10", "HR1210010051863000160")
);
formatterIban.addSpecification(
new IbanSpecification(
"HU",
28,
"F03F04F01F15F01",
"HU42117730161111101800000000"
)
);
formatterIban.addSpecification(
new IbanSpecification("IE", 22, "U04F06F08", "IE29AIBK93115212345678")
);
formatterIban.addSpecification(
new IbanSpecification("IL", 23, "F03F03F13", "IL620108000000099999999")
);
formatterIban.addSpecification(
new IbanSpecification(
"IS",
26,
"F04F02F06F10",
"IS140159260076545510730339"
)
);
formatterIban.addSpecification(
new IbanSpecification(
"IT",
27,
"U01F05F05A12",
"IT60X0542811101000000123456"
)
);
formatterIban.addSpecification(
new IbanSpecification("IQ", 23, "U04F03A12", "IQ98NBIQ850123456789012")
);
formatterIban.addSpecification(
new IbanSpecification("JO", 30, "A04F22", "JO15AAAA1234567890123456789012")
);
formatterIban.addSpecification(
new IbanSpecification("KW", 30, "U04A22", "KW81CBKU0000000000001234560101")
);
formatterIban.addSpecification(
new IbanSpecification("KZ", 20, "F03A13", "KZ86125KZT5004100100")
);
formatterIban.addSpecification(
new IbanSpecification("LB", 28, "F04A20", "LB62099900000001001901229114")
);
formatterIban.addSpecification(
new IbanSpecification(
"LC",
32,
"U04F24",
"LC07HEMM000100010012001200013015"
)
);
formatterIban.addSpecification(
new IbanSpecification("LI", 21, "F05A12", "LI21088100002324013AA")
);
formatterIban.addSpecification(
new IbanSpecification("LT", 20, "F05F11", "LT121000011101001000")
);
formatterIban.addSpecification(
new IbanSpecification("LU", 20, "F03A13", "LU280019400644750000")
);
formatterIban.addSpecification(
new IbanSpecification("LV", 21, "U04A13", "LV80BANK0000435195001")
);
formatterIban.addSpecification(
new IbanSpecification(
"MC",
27,
"F05F05A11F02",
"MC5811222000010123456789030"
)
);
formatterIban.addSpecification(
new IbanSpecification("MD", 24, "U02A18", "MD24AG000225100013104168")
);
formatterIban.addSpecification(
new IbanSpecification("ME", 22, "F03F13F02", "ME25505000012345678951")
);
formatterIban.addSpecification(
new IbanSpecification("MK", 19, "F03A10F02", "MK07250120000058984")
);
formatterIban.addSpecification(
new IbanSpecification(
"MR",
27,
"F05F05F11F02",
"MR1300020001010000123456753"
)
);
formatterIban.addSpecification(
new IbanSpecification(
"MT",
31,
"U04F05A18",
"MT84MALT011000012345MTLCAST001S"
)
);
formatterIban.addSpecification(
new IbanSpecification(
"MU",
30,
"U04F02F02F12F03U03",
"MU17BOMM0101101030300200000MUR"
)
);
formatterIban.addSpecification(
new IbanSpecification("NL", 18, "U04F10", "NL91ABNA0417164300")
);
formatterIban.addSpecification(
new IbanSpecification("NO", 15, "F04F06F01", "NO9386011117947")
);
formatterIban.addSpecification(
new IbanSpecification("PK", 24, "U04A16", "PK36SCBL0000001123456702")
);
formatterIban.addSpecification(
new IbanSpecification("PL", 28, "F08F16", "PL61109010140000071219812874")
);
formatterIban.addSpecification(
new IbanSpecification("PS", 29, "U04A21", "PS92PALS000000000400123456702")
);
formatterIban.addSpecification(
new IbanSpecification("PT", 25, "F04F04F11F02", "PT50000201231234567890154")
);
formatterIban.addSpecification(
new IbanSpecification("QA", 29, "U04A21", "QA30AAAA123456789012345678901")
);
formatterIban.addSpecification(
new IbanSpecification("RO", 24, "U04A16", "RO49AAAA1B31007593840000")
);
formatterIban.addSpecification(
new IbanSpecification("RS", 22, "F03F13F02", "RS35260005601001611379")
);
formatterIban.addSpecification(
new IbanSpecification("SA", 24, "F02A18", "SA0380000000608010167519")
);
formatterIban.addSpecification(
new IbanSpecification(
"SC",
31,
"U04F04F16U03",
"SC18SSCB11010000000000001497USD"
)
);
formatterIban.addSpecification(
new IbanSpecification("SE", 24, "F03F16F01", "SE4550000000058398257466")
);
formatterIban.addSpecification(
new IbanSpecification("SI", 19, "F05F08F02", "SI56263300012039086")
);
formatterIban.addSpecification(
new IbanSpecification("SK", 24, "F04F06F10", "SK3112000000198742637541")
);
formatterIban.addSpecification(
new IbanSpecification(
"SM",
27,
"U01F05F05A12",
"SM86U0322509800000000270100"
)
);
formatterIban.addSpecification(
new IbanSpecification("ST", 25, "F08F11F02", "ST68000100010051845310112")
);
formatterIban.addSpecification(
new IbanSpecification("SV", 28, "U04F20", "SV62CENR00000000000000700025")
);
formatterIban.addSpecification(
new IbanSpecification("TL", 23, "F03F14F02", "TL380080012345678910157")
);
formatterIban.addSpecification(
new IbanSpecification("TN", 24, "F02F03F13F02", "TN5910006035183598478831")
);
formatterIban.addSpecification(
new IbanSpecification("TR", 26, "F05F01A16", "TR330006100519786457841326")
);
formatterIban.addSpecification(
new IbanSpecification("UA", 29, "F25", "UA511234567890123456789012345")
);
formatterIban.addSpecification(
new IbanSpecification("VA", 22, "F18", "VA59001123000012345678")
);
formatterIban.addSpecification(
new IbanSpecification("VG", 24, "U04F16", "VG96VPVG0000012345678901")
);
formatterIban.addSpecification(
new IbanSpecification("XK", 20, "F04F10F02", "XK051212012345678906")
);
formatterIban.addSpecification(
new IbanSpecification("AO", 25, "F21", "AO69123456789012345678901")
);
formatterIban.addSpecification(
new IbanSpecification("BF", 27, "F23", "BF2312345678901234567890123")
);
formatterIban.addSpecification(
new IbanSpecification("BI", 16, "F12", "BI41123456789012")
);
formatterIban.addSpecification(
new IbanSpecification("BJ", 28, "F24", "BJ39123456789012345678901234")
);
formatterIban.addSpecification(
new IbanSpecification("CI", 28, "U02F22", "CI70CI1234567890123456789012")
);
formatterIban.addSpecification(
new IbanSpecification("CM", 27, "F23", "CM9012345678901234567890123")
);
formatterIban.addSpecification(
new IbanSpecification("CV", 25, "F21", "CV30123456789012345678901")
);
formatterIban.addSpecification(
new IbanSpecification("DZ", 24, "F20", "DZ8612345678901234567890")
);
formatterIban.addSpecification(
new IbanSpecification("IR", 26, "F22", "IR861234568790123456789012")
);
formatterIban.addSpecification(
new IbanSpecification("MG", 27, "F23", "MG1812345678901234567890123")
);
formatterIban.addSpecification(
new IbanSpecification("ML", 28, "U01F23", "ML15A12345678901234567890123")
);
formatterIban.addSpecification(
new IbanSpecification("MZ", 25, "F21", "MZ25123456789012345678901")
);
formatterIban.addSpecification(
new IbanSpecification("SN", 28, "U01F23", "SN52A12345678901234567890123")
);
formatterIban.addSpecification(
new IbanSpecification(
"GF",
27,
"F05F05A11F02",
"GF121234512345123456789AB13"
)
);
formatterIban.addSpecification(
new IbanSpecification(
"GP",
27,
"F05F05A11F02",
"GP791234512345123456789AB13"
)
);
formatterIban.addSpecification(
new IbanSpecification(
"MQ",
27,
"F05F05A11F02",
"MQ221234512345123456789AB13"
)
);
formatterIban.addSpecification(
new IbanSpecification(
"RE",
27,
"F05F05A11F02",
"RE131234512345123456789AB13"
)
);
formatterIban.addSpecification(
new IbanSpecification(
"PF",
27,
"F05F05A11F02",
"PF281234512345123456789AB13"
)
);
formatterIban.addSpecification(
new IbanSpecification(
"TF",
27,
"F05F05A11F02",
"TF891234512345123456789AB13"
)
);
formatterIban.addSpecification(
new IbanSpecification(
"YT",
27,
"F05F05A11F02",
"YT021234512345123456789AB13"
)
);
formatterIban.addSpecification(
new IbanSpecification(
"NC",
27,
"F05F05A11F02",
"NC551234512345123456789AB13"
)
);
formatterIban.addSpecification(
new IbanSpecification(
"BL",
27,
"F05F05A11F02",
"BL391234512345123456789AB13"
)
);
formatterIban.addSpecification(
new IbanSpecification(
"MF",
27,
"F05F05A11F02",
"MF551234512345123456789AB13"
)
);
formatterIban.addSpecification(
new IbanSpecification(
"PM",
27,
"F05F05A11F02",
"PM071234512345123456789AB13"
)
);
formatterIban.addSpecification(
new IbanSpecification(
"WF",
27,
"F05F05A11F02",
"WF621234512345123456789AB13"
)
);
return {
formatterNumber,
formatterIban
};
}, "useFormatter");
var __defProp$z = Object.defineProperty;
var __name$z = (target, value) => __defProp$z(target, "name", { value, configurable: true });
const FILTER_V3_OPERATORS = ["=", "!=", ">", ">=", "<", "<=", "in", "between"];
function condition(field, operator, value) {
if (typeof field !== "string" || field.length === 0) {
throw new SdkError({
code: "JSSDK_FILTER_V3_INVALID_FIELD",
description: `FilterV3: field name must be a non-empty string, got ${JSON.stringify(field)}.`,
status: 400
});
}
if (!FILTER_V3_OPERATORS.includes(operator)) {
throw new SdkError({
code: "JSSDK_FILTER_V3_INVALID_OPERATOR",
description: `FilterV3: operator "${operator}" is not one of ${FILTER_V3_OPERATORS.join(" ")}.`,
status: 400
});
}
return [field, operator, value];
}
__name$z(condition, "condition");
const FilterV3 = Object.freeze({
/** `field = value` */
eq(field, value) {
return condition(field, "=", value);
},
/** `field != value` */
ne(field, value) {
return condition(field, "!=", value);
},
/** `field > value` */
gt(field, value) {
return condition(field, ">", value);
},
/** `field >= value` */
ge(field, value) {
return condition(field, ">=", value);
},
/** `field < value` */
lt(field, value) {
return condition(field, "<", value);
},
/** `field <= value` */
le(field, value) {
return condition(field, "<=", value);
},
/** `field in [values]` — `values` must be a non-empty array. */
in(field, values) {
if (!Array.isArray(values) || values.length === 0) {
throw new SdkError({
code: "JSSDK_FILTER_V3_INVALID_IN",
description: `FilterV3.in("${field}"): value must be a non-empty array.`,
status: 400
});
}
return condition(field, "in", values);
},
/** `field between [from, to]` — inclusive range of exactly two defined operands. */
between(field, from, to) {
if (from === void 0 || from === null || to === void 0 || to === null) {
throw new SdkError({
code: "JSSDK_FILTER_V3_INVALID_BETWEEN",
description: `FilterV3.between("${field}"): both range operands must be defined (got [${String(from)}, ${String(to)}]).`,
status: 400
});
}
return condition(field, "between", [from, to]);
},
/** Combine nodes with AND (for nesting inside an OR; the top level is already AND). */
and(...conditions) {
return { logic: "and", conditions };
},
/** Combine nodes with OR. */
or(...conditions) {
return { logic: "or", conditions };
},
/**
* Negate a condition or group (wraps it in a NOT). A bare condition is wrapped
* in a single-item AND group so the `negative` flag has somewhere to live.
* Returns a fresh group (the input's `conditions` array is copied, not shared).
*/
not(node) {
if (isGroup(node)) {
return { ...node, conditions: [...node.conditions], negative: true };
}
return { logic: "and", negative: true, conditions: [node] };
},
/**
* Assemble the top-level filter array (its elements are AND-joined) ready to
* pass as `params.filter`. Falsy nodes are skipped, so you can inline
* conditionals: `F.build(F.eq('a', 1), flag && F.gt('b', 2))`.
*
* Always wrap with `build` (or an array) even for a single condition —
* `params.filter` must be an array, so pass `build(F.eq('a', 1))`, not the bare
* `F.eq('a', 1)`. Each surviving node is shape-checked, so a forgotten spread
* (`build([F.eq(...)])`) or a hand-rolled malformed triple fails fast here
* instead of as an opaque server error.
*/
build(...nodes) {
const result = nodes.filter(Boolean);
for (const node of result) {
assertNode(node);
}
return result;
}
});
function isGroup(node) {
return !Array.isArray(node) && typeof node === "object" && node !== null && "conditions" in node;
}
__name$z(isGroup, "isGroup");
function assertNode(node) {
if (isGroup(node)) {
return;
}
const ok = Array.isArray(node) && node.length === 3 && typeof node[0] === "string" && FILTER_V3_OPERATORS.includes(node[1]);
if (!ok) {
throw new SdkError({
code: "JSSDK_FILTER_V3_INVALID_NODE",
description: `FilterV3.build: each node must be a [field, operator, value] condition or a group \u2014 got ${JSON.stringify(node)}. Did you forget to spread (build(...nodes)) or build a condition with FilterV3 helpers?`,
status: 400
});
}
}
__name$z(assertNode, "assertNode");
var __defProp$y = Object.defineProperty;
var __name$y = (target, value) => __defProp$y(target, "name", { value, configurable: true });
function assertPath(path, who) {
if (typeof path !== "string" || path.length === 0) {
throw new SdkError({
code: "JSSDK_BATCH_REF_V3_INVALID_PATH",
description: `${who}: path must be a non-empty dotted string (e.g. "tasks.id").`,
status: 400
});
}
}
__name$y(assertPath, "assertPath");
const BatchRefV3 = Object.freeze({
/**
* `{ $ref: path }` — substitute a single value from context, e.g.
* `ref('newTask.item.id')`. `add` → id / `update` → bool results are NOT in
* context (reference §8); only `item` (get) and `items` (list/tail) are.
*/
ref(path) {
assertPath(path, "BatchRefV3.ref");
return { $ref: path };
},
/**
* `{ $refArray: path }` — collect one field across the `items[]` of an earlier
* list/tail command, e.g. `refArray('tasks.id')`. The path MUST contain a dot
* (`alias.field`); the server rejects a dot-less path with INVALIDSELECTEXCEPTION.
*/
refArray(path) {
assertPath(path, "BatchRefV3.refArray");
if (!path.includes(".")) {
throw new SdkError({
code: "JSSDK_BATCH_REF_V3_INVALID_REF_ARRAY",
description: `BatchRefV3.refArray: path "${path}" must contain a dot ("alias.field") \u2014 the server collects <field> across the alias's items[].`,
status: 400
});
}
return { $refArray: path };
}
});
var __defProp$x = Object.defineProperty;
var __name$x = (target, value) => __defProp$x(target, "name", { value, configurable: true });
class AuthHookManager {
static {
__name$x(this, "AuthHookManager");
}
#b24HookParams;
#domain;
#b24TargetRest;
#b24Target;
#b24TargetRestWithPath;
constructor(b24HookParams) {
this.#b24HookParams = Object.freeze(Object.assign({}, b24HookParams));
this.#domain = this.#b24HookParams.b24Url.replaceAll("https://", "").replaceAll("http://", "").replace(/:(80|443)$/, "");
this.#b24TargetRest = `https://${this.#domain}/rest`;
this.#b24Target = `https://${this.#domain}`;
this.#b24TargetRestWithPath = /* @__PURE__ */ new Map();
this.#b24TargetRestWithPath.set(ApiVersion.v2, `${this.#b24TargetRest}/${this.#b24HookParams.userId}/${this.#b24HookParams.secret}`);
this.#b24TargetRestWithPath.set(ApiVersion.v3, `${this.#b24TargetRest}/api/${this.#b24HookParams.userId}/${this.#b24HookParams.secret}`);
}
/**
* @see Http.#prepareParams
*/
getAuthData() {
return {
access_token: this.#b24HookParams.secret,
refresh_token: "hook",
expires: 0,
expires_in: 0,
domain: this.#domain,
member_id: this.#domain
};
}
refreshAuth() {
return Promise.resolve(this.getAuthData());
}
getUniq(prefix) {
const authData = this.getAuthData();
if (authData === false) {
throw new Error("AuthData not init");
}
return [prefix, authData.member_id].join("_");
}
/**
* @inheritDoc
*/
getTargetOrigin() {
return `${this.#b24Target}`;
}
/**
* Get the account address BX24 with path
* - ver2 `https://your_domain.bitrix24.com/rest/{id}/{webhook}`
* - ver3` https://your_domain.bitrix24.com/rest/api/{id}/{webhook}`
*/
getTargetOriginWithPath() {
return this.#b24TargetRestWithPath;
}
/**
* We believe that hooks are created only by the admin
*/
get isAdmin() {
return true;
}
}
var __defProp$w = Object.defineProperty;
var __name$w = (target, value) => __defProp$w(target, "name", { value, configurable: true });
class B24Hook extends AbstractB24 {
static {
__name$w(this, "B24Hook");
}
#authHookManager;
// region Init ////
constructor(b24HookParams, options) {
super();
this.#authHookManager = new AuthHookManager(
b24HookParams
);
const warningText = "The B24Hook object is intended exclusively for use on the server.\nA webhook contains a secret access key, which MUST NOT be used in client-side code (browser, mobile app).";
this._httpV2 = new HttpV2(this.#authHookManager, this._getHttpOptions(), options?.restrictionParams);
this._httpV2.setClientSideWarning(true, warningText);
this._httpV3 = new HttpV3(this.#authHookManager, this._getHttpOptions(), options?.restrictionParams);
this._httpV3.setClientSideWarning(true, warningText);
this._isInit = true;
}
// endregion ////
get auth() {
return this.#authHookManager;
}
// region Core ////
/**
* Disables warning about client-side query execution
*/
offClientSideWarning() {
versionManager.getAllApiVersions().forEach((version) => {
this.getHttpClient(version).setClientSideWarning(false, "");
});
}
// endregion ////
// region Get ////
/**
* @inheritDoc
*/
getTargetOrigin() {
this._ensureInitialized();
return this.#authHookManager.getTargetOrigin();
}
/**
* @inheritDoc
*/
getTargetOriginWithPath() {
this._ensureInitialized();
return this.#authHookManager.getTargetOriginWithPath();
}
// endregion ////
// region Tools ////
/**
* Creates a `B24Hook` instance from a webhook URL.
*
* Accepts both REST API v2 and v3 webhook formats:
* - v2: `https://your_domain.bitrix24.com/rest/{userId}/{secret}`
* - v3: `https://your_domain.bitrix24.com/rest/api/{userId}/{secret}`
*
* Validates that the URL uses HTTPS, has the correct path structure, and
* contains a numeric user ID. Throws a descriptive `Error` on any violation
* without echoing the URL (which contains the secret).
*
* @param url - Full webhook URL as shown in the Bitrix24 admin panel.
* @param options - Optional restriction parameters (rate limits, etc.).
* @returns A ready-to-use `B24Hook` instance.
* @throws {SdkError} If the URL is empty (`JSSDK_HOOK_URL_EMPTY`), unparseable
* (`JSSDK_HOOK_URL_INVALID`), not HTTPS (`JSSDK_HOOK_URL_NOT_HTTPS`),
* malformed (`JSSDK_HOOK_URL_MALFORMED`), or the userId segment is not
* numeric (`JSSDK_HOOK_URL_USER_ID_NOT_NUMERIC`).
*/
static fromWebhookUrl(url, options) {
if (!url.trim()) {
throw new SdkError({ code: "JSSDK_HOOK_URL_EMPTY", description: "Webhook URL cannot be empty", status: 0 });
}
let parsedUrl;
try {
parsedUrl = new URL(url.replace("/rest/api", "/rest"));
} catch {
throw new SdkError({ code: "JSSDK_HOOK_URL_INVALID", description: "Invalid webhook URL format", status: 0 });
}
if (parsedUrl.protocol !== "https:") {
throw new SdkError({ code: "JSSDK_HOOK_URL_NOT_HTTPS", description: "Webhook requires HTTPS protocol", status: 0 });
}
const pathParts = parsedUrl.pathname.split("/").filter(Boolean);
const isValidFormat = (
// Format: /rest/{id}/{webhook}
pathParts.length === 3 && pathParts[0] === "rest" || pathParts.length === 4 && pathParts[0] === "rest" && pathParts[1] === "api"
);
if (!isValidFormat) {
throw new SdkError({ code: "JSSDK_HOOK_URL_MALFORMED", description: "Webhook URL must follow format: /rest/<userId>/<secret> or /rest/api/<userId>/<secret>", status: 0 });
}
const userIdIndex = pathParts[1] === "api" ? 2 : 1;
const secretIndex = pathParts[1] === "api" ? 3 : 2;
const userIdStr = pathParts[userIdIndex];
const secret = pathParts[secretIndex];
if (!/^\d+$/.test(userIdStr)) {
throw new SdkError({ code: "JSSDK_HOOK_URL_USER_ID_NOT_NUMERIC", description: "User ID must be numeric in webhook URL", status: 0 });
}
const userId = Number.parseInt(userIdStr, 10);
return new B24Hook(
{
b24Url: parsedUrl.origin,
userId,
secret
},
options
);
}
// endregion ////
}
var MessageCommands = /* @__PURE__ */ ((MessageCommands2) => {
MessageCommands2["getInitData"] = "getInitData";
MessageCommands2["setInstallFinish"] = "setInstallFinish";
MessageCommands2["setInstall"] = "setInstall";
MessageCommands2["refreshAuth"] = "refreshAuth";
MessageCommands2["setAppOption"] = "setAppOption";
MessageCommands2["setUserOption"] = "setUserOption";
MessageCommands2["resizeWindow"] = "resizeWindow";
MessageCommands2["reloadWindow"] = "reloadWindow";
MessageCommands2["setTitle"] = "setTitle";
MessageCommands2["setScroll"] = "setScroll";
MessageCommands2["openApplication"] = "openApplication";
MessageCommands2["closeApplication"] = "closeApplication";
MessageCommands2["openPath"] = "openPath";
MessageCommands2["imCallTo"] = "imCallTo";
MessageCommands2["imPhoneTo"] = "imPhoneTo";
MessageCommands2["imOpenMessenger"] = "imOpenMessenger";
MessageCommands2["imOpenHistory"] = "imOpenHistory";
MessageCommands2["selectUser"] = "selectUser";
MessageCommands2["selectAccess"] = "selectAccess";
MessageCommands2["selectCRM"] = "selectCRM";
MessageCommands2["showAppForm"] = "showAppForm";
MessageCommands2["getInterface"] = "getInterface";
MessageCommands2["placementBindEvent"] = "placementBindEvent";
return MessageCommands2;
})(MessageCommands || {});
var __defProp$v = Object.defineProperty;
var __name$v = (target, value) => __defProp$v(target, "name", { value, configurable: true });
const MAX_REJECTED_ORIGINS = 50;
const MAX_CALLBACK_ID_IN_ERROR = 64;
class MessageManager {
static {
__name$v(this, "MessageManager");
}
#appFrame;
#callbackPromises;
#callbackSingletone;
// origins already warned about (#244) — dedup so a peer spamming postMessage
// from a foreign origin can't flood a wired logger sink. Capped, because the
// dedup key is attacker-chosen: a peer can post from an unbounded supply of
// distinct origins (`a.evil.test`, `b.evil.test`, …) and every unseen one adds
// an entry. Past the cap the set stops growing and later origins are simply
// not warned about — losing a log line is the right trade against unbounded
// memory in a long-lived frame (#146).
#rejectedOrigins = /* @__PURE__ */ new Set();
_logger;
runCallbackHandler;
constructor(appFrame) {
this._logger = LoggerFactory.createNullLogger();
this.#appFrame = appFrame;
this.#callbackPromises = /* @__PURE__ */ new Map();
this.#callbackSingletone = /* @__PURE__ */ new Map();
this.runCallbackHandler = this._runCallback.bind(this);
}
setLogger(logger) {
this._logger = logger;
}
getLogger() {
return this._logger;
}
// region Events ////
/**
* Subscribe to the onMessage event of the parent window
*/
subscribe() {
window.addEventListener("message", this.runCallbackHandler);
}
/**
* Unsubscribe from the onMessage event of the parent window, and tear the
* manager down.
*
* Removing the listener is not enough. Every in-flight `send()` is waiting on
* a promise that only the listener could settle, so dropping the listener
* alone strands each of them **forever** — with its `isSafely` timer still
* armed and its entry still in the callback map. `B24Frame.destroy()` calls
* this, so an SPA that mounts and unmounts the frame accumulated one such set
* per cycle (#146; the same class of leak as #222 in `PullClient`).
*
* Pending sends are therefore **rejected**, not left hanging, with
* `JSSDK_FRAME_DISPOSED` — mirroring how a disposed `PullClient` rejects
* `start()` with `PULL_DISPOSED`. A caller awaiting a command that can no
* longer be answered should learn that; silence is the one outcome it cannot
* act on.
*
* Note the consequence: a `send()` whose result was discarded without a
* `.catch()` turns into an unhandled rejection at teardown. Most SDK commands
* pass `isSafely`, which settles them on their own timer, so they are normally
* already gone by the time this runs — but **not all of them do**.
* `ParentManager.closeApplication()` and `SliderManager.closeSliderAppPage()`
* deliberately pass `isSafely: false` ("everything will be closed, and timeout
* will not be able to do anything"), and those are exactly the calls made as
* an app tears itself down — the likeliest race with this method. The awaited
* commands (`getInitData`, `refreshAuth`, the dialog selectors) send without
* `isSafely` too, but their callers await them, so the rejection surfaces
* where it can be handled.
*
* A caller that fires `closeApplication()` without awaiting it should attach
* `.catch(() => {})` if it also tears the frame down in the same breath.
*/
unsubscribe() {
window.removeEventListener("message", this.runCallbackHandler);
for (const [key, promise] of this.#callbackPromises) {
if (promise.timeoutId) {
clearTimeout(promise.timeoutId);
}
this.#callbackPromises.delete(key);
promise.reject(new SdkError({
code: "JSSDK_FRAME_DISPOSED",
description: "The B24Frame was destroyed before the parent window answered this command.",
status: 0
}));
}
this.#callbackSingletone.clear();
this.#rejectedOrigins.clear();
}
// endregion ////
/**
* Send message to parent window
* The answer (if) we will get in _runCallback
*
* @param command
* @param params
*/
async send(command, params = null) {
return new Promise((resolve, reject) => {
let cmd;
const promiseHandler = {
resolve,
reject,
timeoutId: null
};
const keyPromise = this.#setCallbackPromise(promiseHandler);
let paramsSend = null;
const optionsSend = omit(params || {}, ["singleOption", "callBack", "isSafely", "safelyTime", "requestId"]);
const { callBack, singleOption, requestId } = params || {};
if (callBack) {
this.#callbackSingletone.set(keyPromise, callBack);
}
if (singleOption) {
paramsSend = singleOption;
} else if (Object.keys(optionsSend).length > 0) {
paramsSend = { ...optionsSend };
}
if (command.toString().includes(":")) {
cmd = {
method: command.toString(),
params: paramsSend || "",
callback: keyPromise,
appSid: this.#appFrame.getAppSid(),
requestId
};
} else {
cmd = command.toString();
if (params?.isRawValue !== true && paramsSend) {
paramsSend = JSON.stringify(paramsSend);
} else if (params?.isRawValue === true && paramsSend && Type.isPlainObject(paramsSend) && paramsSend["value"]) {
paramsSend = paramsSend["value"];
}
const listParams = [
paramsSend || "",
keyPromise,
this.#appFrame.getAppSid()
];
cmd += ":" + listParams.filter(Boolean).join(":");
}
this.getLogger().debug(`send to ${this.#appFrame.getTargetOrigin()}`, {
command: command.toString(),
callbackKey: keyPromise,
origin: this.#appFrame.getTargetOrigin()
}).catch(() => {
});
parent.postMessage(cmd, this.#appFrame.getTargetOrigin());
if (params?.isSafely) {
const safelyTime = Number.parseInt(String(params?.safelyTime || 900));
this.#callbackPromises.get(keyPromise).timeoutId = window.setTimeout(
() => {
if (this.#callbackPromises.has(keyPromise)) {
this.getLogger().warning(`action ${command.toString()} stop by timeout`, {
command: command.toString(),
safelyTime
}).catch(() => {
});
this.#callbackPromises.delete(keyPromise);
resolve({ isSafely: true });
}
},
safelyTime
);
}
});
}
/**
* Fulfilling a promise based on messages from the parent window
*
* @param event
* @private
*/
_runCallback(event) {
if (event.origin !== this.#appFrame.getTargetOrigin()) {
if (!this.#rejectedOrigins.has(event.origin) && this.#rejectedOrigins.size < MAX_REJECTED_ORIGINS) {
this.#rejectedOrigins.add(event.origin);
this.getLogger().warning("message rejected: unexpected origin", {
origin: event.origin,
expected: this.#appFrame.getTargetOrigin()
}).catch(() => {
});
}
return;
}
if (typeof event.data === "string" && event.data.length > 0) {
const [id = "", ...rest] = event.data.split(":");
const cmd = {
id,
args: rest.join(":")
};
this.getLogger().debug(`get from ${event.origin}`, {
id: cmd.id,
origin: event.origin
}).catch(() => {
});
if (cmd.args) {
try {
cmd.args = JSON.parse(cmd.args);
} catch {
this.getLogger().warning("message dropped: payload is not valid JSON", {
id: cmd.id,
origin: event.origin
}).catch(() => {
});
this.#rejectPromise(cmd.id, new SdkError({
code: "JSSDK_FRAME_BAD_PAYLOAD",
description: `The parent window answered command "${cmd.id.slice(0, MAX_CALLBACK_ID_IN_ERROR)}" with a payload that is not valid JSON.`,
status: 0
}));
return;
}
}
if (this.#callbackPromises.has(cmd.id)) {
const promise = this.#callbackPromises.get(cmd.id);
if (promise.timeoutId) {
clearTimeout(promise.timeoutId);
}
this.#callbackPromises.delete(cmd.id);
promise.resolve(cmd.args);
} else if (this.#callbackSingletone.has(cmd.id)) {
const callBack = this.#callbackSingletone.get(cmd.id);
if (callBack) {
callBack.apply(globalThis, [cmd.args]);
}
}
}
}
/**
* Settle a waiting promise with a rejection, if one is still waiting.
*
* Silent when the key is unknown: a payload can arrive for a command that
* already timed out under `isSafely`, and there is nothing left to reject.
*/
#rejectPromise(key, error) {
const promise = this.#callbackPromises.get(key);
if (!promise) {
return;
}
if (promise.timeoutId) {
clearTimeout(promise.timeoutId);
}
this.#callbackPromises.delete(key);
promise.reject(error);
}
/**
* Storing a promise for a message from the parent window
*
* @param promiseHandler
* @private
*
* @memo We don't use Symbol here, because we need to pass it to the parent and then find and restore it.
*/
#setCallbackPromise(promiseHandler) {
const key = Text.getUniqId();
this.#callbackPromises.set(key, promiseHandler);
return key;
}
}
var __defProp$u = Object.defineProperty;
var __name$u = (target, value) => __defProp$u(target, "name", { value, configurable: true });
class AppFrame {
static {
__name$u(this, "AppFrame");
}
#domain = "";
#protocol = true;
#appSid = null;
#path = null;
#lang = null;
#b24TargetRest;
#b24Target;
#b24TargetRestWithPath;
constructor(queryParams) {
if (queryParams.DOMAIN) {
this.#domain = queryParams.DOMAIN;
this.#domain = this.#domain.replace(/:(80|443)$/, "");
}
this.#protocol = queryParams.PROTOCOL === true;
if (queryParams.LANG) {
this.#lang = queryParams.LANG;
}
if (queryParams.APP_SID) {
this.#appSid = queryParams.APP_SID;
}
this.#b24TargetRestWithPath = /* @__PURE__ */ new Map();
this.#b24Target = `${this.#protocol ? "https" : "http"}://${this.#domain}`;
this.#b24TargetRest = `${this.#b24Target}/rest`;
this.#b24TargetRestWithPath.set(ApiVersion.v2, `${this.#b24TargetRest}`);
this.#b24TargetRestWithPath.set(ApiVersion.v3, `${this.#b24TargetRest}/api`);
}
/**
* Initializes the data received from the parent window message.
* @param data
*/
initData(data) {
if (!this.#domain) {
this.#domain = data.DOMAIN;
}
if (!this.#path) {
this.#path = data.PATH;
}
if (!this.#lang) {
this.#lang = data.LANG;
}
this.#protocol = Number.parseInt(data.PROTOCOL) === 1;
this.#domain = this.#domain.replace(/:(80|443)$/, "");
this.#b24Target = `${this.#protocol ? "https" : "http"}://${this.#domain}`;
this.#b24TargetRest = `${this.#b24Target}/rest`;
this.#b24TargetRestWithPath.set(ApiVersion.v2, `${this.#b24TargetRest}`);
this.#b24TargetRestWithPath.set(ApiVersion.v3, `${this.#b24TargetRest}/api`);
return this;
}
/**
* Returns the sid of the application relative to the parent window like this `9c33468728e1d2c8c97562475edfd96`
*/
getAppSid() {
if (null === this.#appSid) {
throw new SdkError({ code: "JSSDK_FRAME_APP_SID_NOT_INIT", description: "Not init appSid", status: 0 });
}
return this.#appSid;
}
/**
* Get the account address BX24 (https://your_domain.bitrix24.com)
*/
getTargetOrigin() {
return this.#b24Target;
}
/**
* Get the account address BX24 with path
* - ver2 `https://your_domain.bitrix24.com/rest/`
* - ver3` https://your_domain.bitrix24.com/rest/api/`
*/
getTargetOriginWithPath() {
return this.#b24TargetRestWithPath;
}
/**
* Returns the localization of the B24 interface
* @return {B24LangList} - default `B24LangList.en`
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/additional-functions/bx24-get-lang.html
*/
getLang() {
return this.#lang || B24LangList.en;
}
}
var __defProp$t = Object.defineProperty;
var __name$t = (target, value) => __defProp$t(target, "name", { value, configurable: true });
const REFRESH_AUTH_TIMEOUT = 1e4;
class AuthManager {
static {
__name$t(this, "AuthManager");
}
#accessToken = null;
#refreshId = null;
#authExpires = 0;
#authExpiresIn = 0;
#memberId = null;
#isAdmin = false;
#appFrame;
#messageManager;
constructor(appFrame, messageManager) {
this.#appFrame = appFrame;
this.#messageManager = messageManager;
}
/**
* Initializes the data received from the parent window message.
* @param data
*/
initData(data) {
if (data.AUTH_ID) {
this.#accessToken = data.AUTH_ID;
this.#refreshId = data.REFRESH_ID;
this.#authExpiresIn = Number.parseInt(data.AUTH_EXPIRES);
this.#authExpires = Date.now() + this.#authExpiresIn * 1e3;
this.#isAdmin = data.IS_ADMIN;
this.#memberId = data.MEMBER_ID || "";
}
return this;
}
/**
* Returns authorization data
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/system-functions/bx24-get-auth.html
*/
getAuthData() {
return this.#authExpires > Date.now() ? {
access_token: this.#accessToken,
refresh_token: this.#refreshId,
expires: this.#authExpires / 1e3,
expires_in: this.#authExpiresIn,
domain: this.#appFrame.getTargetOrigin(),
member_id: this.#memberId
} : false;
}
/**
* Updates authorization data through the parent window
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/system-functions/bx24-refresh-auth.html
*/
async refreshAuth() {
let timer;
const timeout = new Promise((_resolve, reject) => {
timer = setTimeout(
() => reject(new SdkError({
code: "JSSDK_FRAME_REFRESH_AUTH_TIMEOUT",
status: 408,
description: `refreshAuth: the parent window did not answer within ${REFRESH_AUTH_TIMEOUT}ms`
})),
REFRESH_AUTH_TIMEOUT
);
});
try {
const data = await Promise.race([
this.#messageManager.send(MessageCommands.refreshAuth, {}),
timeout
]);
this.#accessToken = data.AUTH_ID;
this.#refreshId = data.REFRESH_ID;
this.#authExpires = Date.now() + Number.parseInt(data.AUTH_EXPIRES) * 1e3;
return this.getAuthData();
} finally {
if (timer) {
clearTimeout(timer);
}
}
}
getUniq(prefix) {
return [prefix, this.#memberId || ""].join("_");
}
/**
* Determines whether the current user has administrator rights
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/additional-functions/bx24-is-admin.html
*/
get isAdmin() {
return this.#isAdmin;
}
/**
* @inheritDoc
*/
getTargetOrigin() {
return this.#appFrame.getTargetOrigin();
}
/**
* @inheritDoc
*/
getTargetOriginWithPath() {
return this.#appFrame.getTargetOriginWithPath();
}
}
var __defProp$s = Object.defineProperty;
var __name$s = (target, value) => __defProp$s(target, "name", { value, configurable: true });
class ParentManager {
static {
__name$s(this, "ParentManager");
}
#messageManager;
constructor(messageManager) {
this.#messageManager = messageManager;
}
get message() {
return this.#messageManager;
}
/**
* The method closes the open modal window with the application
*
* @return {Promise<void>}
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/additional-functions/bx24-close-application.html
*/
async closeApplication() {
return this.#messageManager.send(MessageCommands.closeApplication, {
/**
* @memo There is no point - everything will be closed, and timeout will not be able to do anything
*/
isSafely: false
});
}
/**
* Sets the size of the frame containing the application to the size of the frame's content.
*
* @return {Promise<void>}
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/additional-functions/bx24-fit-window.html
*
* @memo in certain situations it may not be executed (placement of the main window after installing the application), in this case isSafely mode will work
*/
async fitWindow() {
const width = "100%";
const height = this.getScrollSize().scrollHeight;
return this.#messageManager.send(MessageCommands.resizeWindow, {
width,
height,
isSafely: true
});
}
/**
* Sets the size of the frame containing the application to the size of the frame's content.
*
* @param {number} width
* @param {number} height
*
* @return {Promise<void>}
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/additional-functions/bx24-resize-window.html
*
* @memo in certain situations it may not be executed, in this case isSafely mode will be triggered
*/
async resizeWindow(width, height) {
if (width > 0 && height > 0) {
return this.#messageManager.send(MessageCommands.resizeWindow, {
width,
height,
isSafely: true
});
}
return Promise.reject(
new Error(`Wrong width:number = ${width} or height:number = ${height}`)
);
}
/**
* Automatically resize `document.body` of frame with application according to frame content dimensions
* If you pass appNode, the height will be calculated relative to it
*
* @param {HTMLElement|null} appNode
* @param {number} minHeight
* @param {number} minWidth
*
* @return {Promise<void>}
*/
async resizeWindowAuto(appNode = null, minHeight = 0, minWidth = 0) {
const body = document.body;
let width = Math.max(
body.scrollWidth,
body.offsetWidth
// html.clientWidth,
// html.scrollWidth,
// html.offsetWidth
);
if (minWidth > 0) {
width = Math.max(minWidth, width);
}
let height = Math.max(
body.scrollHeight,
body.offsetHeight
// html.clientHeight,
// html.scrollHeight,
// html.offsetHeight
);
if (appNode) {
height = Math.max(appNode.scrollHeight, appNode.offsetHeight);
}
if (minHeight > 0) {
height = Math.max(minHeight, height);
}
return this.resizeWindow(width, height);
}
/**
* This function returns the inner dimensions of the application frame
*
* @return {Promise<{scrollWidth: number; scrollHeight: number}>}
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/additional-functions/bx24-get-scroll-size.html
*/
getScrollSize() {
return useScrollSize();
}
/**
* Scrolls the parent window
*
* @param {number} scroll should specify the vertical scrollbar position (0 - scroll to the very top)
* @return {Promise<void>}
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/additional-functions/bx24-scroll-parent-window.html
*/
async scrollParentWindow(scroll) {
if (!Number.isInteger(scroll)) {
return Promise.reject(new Error("Wrong scroll number"));
}
if (scroll < 0) {
scroll = 0;
}
return this.#messageManager.send(MessageCommands.setScroll, {
scroll,
isSafely: true
});
}
/**
* Reload the page with the application (the whole page, not just the frame).
*
* @return {Promise<void>}
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/additional-functions/bx24-reload-window.html
*/
async reloadWindow() {
return this.#messageManager.send(MessageCommands.reloadWindow, {
isSafely: true
});
}
/**
* Sets the in-layout page title (the `#pagetitle` element the portal renders around the app).
*
* Does NOT change the browser tab title (`document.title`): the portal applies this command to
* `#pagetitle`, never to the tab. To set the browser tab title, open the view as a slider via
* `SliderManager.openSliderAppPage` with a `bx24_title` option.
*
* @param {string} title
*
* @return {Promise<void>}
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/additional-functions/bx24-set-title.html
*/
async setTitle(title) {
return this.#messageManager.send(MessageCommands.setTitle, {
title: title.toString(),
isSafely: true
});
}
/**
* Initiates a call via internal communication.
*
* **Fire-and-forget.** The portal's bridge handler is declared as
* `function(params)` — it does not accept the callback argument the message
* layer offers, so it never reports back. The returned promise means "the
* command was posted", not "the call started"; it resolves on the SDK's own
* `isSafely` timer, and the accompanying `stop by timeout` log line is the
* normal outcome rather than a fault. See {@link ParentManager} — the same
* holds for every `im*` method here. (#331)
*
* The portal reaches the current API underneath: `BXIM.callTo` →
* `Messenger.Public.startVideoCall`. The deprecation warning in the portal
* console is emitted by the portal's own compatibility layer, not by this
* call, and an application cannot avoid it — the newer names are not part of
* the placement's command vocabulary.
*
* @param {number} userId The identifier of the account user
* @param {boolean} isVideo true - video call, false - audio call. Optional parameter.
*
* @return {Promise<void>} resolves once the command has been posted.
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/additional-functions/bx24-im-call-to.html
*/
async imCallTo(userId, isVideo = true) {
return this.#messageManager.send(MessageCommands.imCallTo, {
userId,
video: isVideo,
isSafely: true
});
}
/**
* Makes a call to the phone number.
*
* **Fire-and-forget** — see {@link imCallTo} for what the returned promise
* does and does not mean.
*
* `params` is forwarded for the phone manager, matching the second argument of
* the portal's `Messenger.startPhoneCall(number, params)`. The portal's bridge
* handler currently enumerates fields by hand and reads only `phone`, so this
* is dropped on the way today; sending it costs nothing (an unknown field is
* ignored) and starts working without an application change once the portal
* forwards it. (#331)
*
* @param {string} phone Phone number. The number can be in the format: `+44 20 1234 5678` or `x (xxx) xxx-xx-xx`
* @param {Record<string, unknown>} [params] Extra call parameters for the phone manager.
*
* @return {Promise<void>} resolves once the command has been posted.
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/additional-functions/bx24-im-phone-to.html
*/
async imPhoneTo(phone, params) {
return this.#messageManager.send(MessageCommands.imPhoneTo, {
phone,
...params === void 0 ? {} : { params },
isSafely: true
});
}
/**
* Opens the messenger window
* userId or chatXXX - chat, where XXX is the chat identifier, which can simply be a number.
* sgXXX - group chat, where XXX is the social network group number (the chat must be enabled in this group).
*
* XXXX** - open line, where XXX is the code obtained via the Rest method imopenlines.network.join.
*
* If nothing is passed, the chat interface will open with the last opened dialog.
*
* **Fire-and-forget** — see {@link imCallTo} for what the returned promise
* does and does not mean.
*
* `messageId` matches the second argument of the portal's
* `Messenger.openChat(dialogId, messageId)`, which focuses a specific message.
* The portal's bridge handler reads only `dialogId` today, so it is dropped on
* the way; sending it is free and starts working without an application change
* once the portal forwards it. (#331)
*
* @param {number|`chat${number}`|`sg${number}`|`imol|${number}`|undefined} dialogId
* @param {number} [messageId] Message to focus once the chat opens.
*
* @return {Promise<void>} resolves once the command has been posted.
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/additional-functions/bx24-im-open-messenger.html
* @link https://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=93&LESSON_ID=20152&LESSON_PATH=7657.7883.8025.20150.20152
*
*/
async imOpenMessenger(dialogId, messageId) {
return this.#messageManager.send(MessageCommands.imOpenMessenger, {
dialogId,
...messageId === void 0 ? {} : { messageId },
isSafely: true
});
}
/**
* Opens the history window
* Identifier of the dialog:
*
* userId or chatXXX - chat, where XXX is the chat identifier, which can simply be a number.
* imol|XXXX - open line, where XXX is the session number of the open line.
*
* **Fire-and-forget** — see {@link imCallTo} for what the returned promise
* does and does not mean.
*
* Note the portal routes this differently from the other three: its
* compatibility layer calls the opener directly, bypassing
* `Messenger.Public`. For an ordinary `dialogId` it lands in `openChat`, which
* is what the deprecation notice recommends; for an open-line id
* (`imol|…`) it takes a separate branch whose public equivalent is
* `openLinesHistory`, not `openChat`. (#331)
*
* @param {number|`chat${number}`|`imol|${number}`} dialogId
*
* @return {Promise<void>} resolves once the command has been posted.
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/additional-functions/bx24-im-open-history.html
*/
async imOpenHistory(dialogId) {
return this.#messageManager.send(MessageCommands.imOpenHistory, {
dialogId,
isSafely: true
});
}
}
var __defProp$r = Object.defineProperty;
var __name$r = (target, value) => __defProp$r(target, "name", { value, configurable: true });
let OptionsManager$1 = class OptionsManager {
static {
__name$r(this, "OptionsManager");
}
#messageManager;
#appOptions = null;
#userOptions = null;
constructor(messageManager) {
this.#messageManager = messageManager;
}
/**
* Initializes the data received from the parent window message.
* @param data
*/
initData(data) {
if (data.APP_OPTIONS) {
this.#appOptions = data.APP_OPTIONS;
}
if (data.USER_OPTIONS) {
this.#userOptions = data.USER_OPTIONS;
}
return this;
}
/**
* Getting application option
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/options/bx24-app-option-get.html
*/
appGet(option) {
if (this.#appOptions && !!this.#appOptions[option]) {
return this.#appOptions[option];
}
throw new Error(`app.option.${option} not set`);
}
/**
* Updates application data through the parent window
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/options/bx24-app-option-set.html
*/
async appSet(option, value) {
if (!this.#appOptions) {
this.#appOptions = [];
}
this.#appOptions[option] = value;
return this.#sendParentMessage(
MessageCommands.setAppOption,
option,
this.#appOptions[option]
);
}
/**
* Getting user option
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/options/bx24-user-option-get.html
*/
userGet(option) {
if (this.#userOptions && !!this.#userOptions[option]) {
return this.#userOptions[option];
}
throw new Error(`user.option.${option} not set`);
}
/**
* Updates user data through the parent window
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/options/bx24-user-option-set.html
*/
async userSet(option, value) {
if (!this.#appOptions) {
this.#appOptions = [];
}
if (!this.#appOptions[option]) {
this.#appOptions[option] = null;
}
this.#userOptions[option] = value;
return this.#sendParentMessage(
MessageCommands.setUserOption,
option,
// @ts-expect-error this code work success
this.#userOptions[option]
);
}
async #sendParentMessage(command, option, value) {
return this.#messageManager.send(command, {
name: option,
value,
isSafely: true
}).then(() => {
return Promise.resolve();
});
}
};
var __defProp$q = Object.defineProperty;
var __name$q = (target, value) => __defProp$q(target, "name", { value, configurable: true });
class DialogManager {
static {
__name$q(this, "DialogManager");
}
#messageManager;
constructor(messageManager) {
this.#messageManager = messageManager;
}
/**
* Method displays the standard single user selection dialog
* It only shows company employees
*
* @return {Promise<null|SelectedUser>}
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/system-dialogues/bx24-select-user.html
*/
async selectUser() {
return this.#messageManager.send(MessageCommands.selectUser, {
mult: false
});
}
/**
* Method displays the standard multiple user selection dialog
* It only shows company employees
*
* @return {Promise<SelectedUser[]>}
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/system-dialogues/bx24-select-users.html
*/
async selectUsers() {
return this.#messageManager.send(MessageCommands.selectUser, {
mult: true
});
}
/**
* Method displays a standard access permission selection dialog
*
* @param {string[]} blockedAccessPermissions
* @return {Promise<SelectedAccess[]>}
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/system-dialogues/bx24-select-access.html
*/
async selectAccess(blockedAccessPermissions = []) {
return this.#messageManager.send(MessageCommands.selectAccess, {
value: blockedAccessPermissions
});
}
/**
* Invokes the system dialog for selecting CRM entities
* (leads, contacts, companies, deals, quotes).
*
* The resolved `SelectedCRM` object contains a separate bucket per
* entity type. Each present bucket is a real `Array`, so consumers can
* use `.length`, `.map()`, `for..of`, etc. directly. Buckets for entity
* types that were not selected (or not requested via `entityType`) are
* left `undefined` rather than being set to an empty array.
*
* Note: the parent window historically returned each bucket as a
* `Record<string, SelectedCRMEntity>` (e.g. `{ 0: {...}, 1: {...} }`).
* The SDK normalizes that response to a real array before returning it.
*
* @param {SelectCRMParams} [params] - Filter and behavior options.
* - `entityType`: which entity types are shown in the dialog.
* - `multiple`: allow multiple selection (default `false`).
* - `value`: pre-selected entities (only applied when `multiple` is `true`).
* @return {Promise<SelectedCRM>} Resolves to an object whose properties
* (`lead`, `contact`, `company`, `deal`, `quote`) are arrays of
* {@link SelectedCRMEntity} objects.
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/system-dialogues/bx24-select-crm.html
*/
async selectCRM(params) {
const response = await this.#messageManager.send(MessageCommands.selectCRM, {
entityType: params?.entityType,
multiple: params?.multiple,
value: params?.value
});
const result = {};
if (!response) {
return result;
}
const toArray = /* @__PURE__ */ __name$q((bucket) => {
if (bucket === void 0 || bucket === null) {
return void 0;
}
if (Array.isArray(bucket)) {
return bucket;
}
return Object.values(bucket);
}, "toArray");
const lead = toArray(response.lead);
if (lead) result.lead = lead;
const contact = toArray(response.contact);
if (contact) result.contact = contact;
const company = toArray(response.company);
if (company) result.company = company;
const deal = toArray(response.deal);
if (deal) result.deal = deal;
const quote = toArray(response.quote);
if (quote) result.quote = quote;
return result;
}
}
var __defProp$p = Object.defineProperty;
var __name$p = (target, value) => __defProp$p(target, "name", { value, configurable: true });
class SliderManager {
static {
__name$p(this, "SliderManager");
}
#appFrame;
#messageManager;
constructor(appFrame, messageManager) {
this.#appFrame = appFrame;
this.#messageManager = messageManager;
}
/**
* Returns the URL relative to the domain name and path
*/
getUrl(path = "/") {
return new URL(path, this.#appFrame.getTargetOrigin());
}
/**
* Get the account address BX24
*/
getTargetOrigin() {
return this.#appFrame.getTargetOrigin();
}
/**
* When the method is called, a pop-up window with the application frame will be opened.
*
* Settings are passed via `bx24_`-prefixed keys (e.g. `bx24_title`, `bx24_width`).
* `bx24_title` sets the slider title; the portal also reflects it to the browser tab title
* (`document.title`) — unlike `ParentManager.setTitle`, which only updates the in-layout `#pagetitle`.
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/additional-functions/bx24-open-application.html
*/
async openSliderAppPage(params = {}) {
return this.#messageManager.send(MessageCommands.openApplication, params);
}
/**
* The method closes the open modal window with the application
*
* @return {Promise<void>}
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/additional-functions/bx24-close-application.html
*/
async closeSliderAppPage() {
return this.#messageManager.send(MessageCommands.closeApplication, {
/**
* @memo There is no point - everything will be closed, and timeout will not be able to do anything
*/
isSafely: false
});
}
/**
* Defines the base path for width sampling.
*
* @param width
* @private
*/
#getBaseUrlByWidth(width = 1640) {
if (width > 0) {
if (width > 1200 && width <= 1640) {
return "/crm/type/0/details/0/../../../../..";
} else if (width > 950 && width <= 1200) {
return "/company/personal/user/0/groups/create/../../../../../..";
} else if (width > 900 && width <= 950) {
return "/crm/company/requisite/0/../../../..";
} else if (width <= 900) {
return "/workgroups/group/0/card/../../../..";
} else {
return "/crm/deal/../..";
}
} else {
return "/crm/deal/../..";
}
}
/**
* Opens the specified path inside the portal in the slider.
* @param {URL} url
* @param {number} width - Number in the range from 1640 to 1200, from 1200 to 950, from 950 to 900, from 900 ...
* @return {Promise<StatusClose>}
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/additional-functions/bx24-open-path.html
* @memo /^\/(crm\/(deal|lead|contact|company|type)|marketplace|company\/personal\/user\/[0-9]+|workgroups\/group\/[0-9]+)\//
*/
async openPath(url, width = 1640) {
const openSliderUrl = new URL(url);
openSliderUrl.searchParams.set("IFRAME", "Y");
openSliderUrl.searchParams.set("IFRAME_TYPE", "SIDE_SLIDER");
return this.#messageManager.send(MessageCommands.openPath, {
path: [
this.#getBaseUrlByWidth(width),
openSliderUrl.pathname,
openSliderUrl.search
].join("")
}).then((response) => {
if (response?.result === "error") {
if (response?.errorCode === "METHOD_NOT_SUPPORTED_ON_DEVICE") {
return new Promise((resolve, reject) => {
const windowObjectReference = window.open(url, "_blank");
if (!windowObjectReference) {
reject(new Error("Error open window"));
return;
}
let iterator = 0;
const iteratorMax = 1e3 * 60 * 5;
const waitCloseWindow = window.setInterval(() => {
iterator = iterator + 1;
if (windowObjectReference.closed) {
clearInterval(waitCloseWindow);
resolve({
isOpenAtNewWindow: true,
isClose: true
});
} else if (iterator > iteratorMax) {
clearInterval(waitCloseWindow);
resolve({
isOpenAtNewWindow: true,
isClose: false
});
}
}, 1e3);
});
} else {
return Promise.reject(new Error(response?.errorCode));
}
} else if (response?.result === "close") {
return Promise.resolve({
isOpenAtNewWindow: false,
isClose: true
});
}
return Promise.resolve({
isOpenAtNewWindow: false,
isClose: false
});
});
}
/**
* @todo test this and remove
*/
// async showAppForm(params: any): Promise<void> {
// console.warn(`deprecated showAppForm`)
// return this.#messageManager.send(MessageCommands.showAppForm, {
// params: params,
// isSafely: true
// })
// }
}
var __defProp$o = Object.defineProperty;
var __name$o = (target, value) => __defProp$o(target, "name", { value, configurable: true });
class PlacementManager {
static {
__name$o(this, "PlacementManager");
}
#messageManager;
#placement = "";
#options = {};
constructor(messageManager) {
this.#messageManager = messageManager;
}
/**
* Initializes the data received from the parent window message.
* @param data
*/
initData(data) {
this.#placement = data.PLACEMENT || "DEFAULT";
this.#options = Object.freeze(data.PLACEMENT_OPTIONS);
return this;
}
/**
* Symlink on `placement`
* For backward compatibility
*/
get title() {
return this.#placement;
}
get placement() {
return this.#placement;
}
get isDefault() {
return this.placement === "DEFAULT";
}
get options() {
return this.#options;
}
get isSliderMode() {
return this.options?.IFRAME === "Y";
}
/**
* Get Information About the JS Interface of the Current Embedding Location
*
* @return {Promise<any>}
*
* @link https://apidocs.bitrix24.com/api-reference/widgets/ui-interaction/bx24-placement-get-interface.html
*/
async getInterface() {
return this.#messageManager.send(
MessageCommands.getInterface,
{
isSafely: true
}
);
}
/**
* Set Up the Interface Event Handler
* @param {string} eventName
* @param {(...args: any[]) => void} callBack
* @return {Promise<any>}
*
* @link https://apidocs.bitrix24.com/api-reference/widgets/ui-interaction/bx24-placement-bind-event.html
*/
async bindEvent(eventName, callBack) {
return this.#messageManager.send(
MessageCommands.placementBindEvent,
{
event: eventName,
callBack,
isSafely: true
}
);
}
async call(command, parameters = {}) {
if (command === "setValue" && !Type.isString(parameters?.["value"])) {
throw new TypeError(
"placement.call('setValue', { value }) expects `value` to be a JSON-serialized string. Use placement.setValue(value) to serialize automatically, or call JSON.stringify yourself."
);
}
return this.#messageManager.send(
command,
{
...parameters,
isSafely: true,
isRawValue: ["setValue"].includes(command)
}
);
}
/**
* Set Value for the Current Embedding Location
*
* Convenience wrapper around `placement.call('setValue', ...)` that handles
* JSON serialization. Pass any value (string, number, boolean, object, array)
* — it will be serialized via `JSON.stringify` before being sent to the
* parent window, which performs `JSON.parse` on receipt.
*
* @param { unknown } value Any JSON-serializable value
* @return { Promise<any> }
*
* @link https://apidocs.bitrix24.com/api-reference/widgets/ui-interaction/bx24-placement-call.html
*
* @example
* await b24.placement.setValue('test')
* await b24.placement.setValue({ id: 1, title: 'demo' })
*/
async setValue(value) {
return this.#messageManager.send(
"setValue",
{
value: JSON.stringify(value),
isSafely: true,
isRawValue: true
}
);
}
/**
* Set Up the Interface Event Handler
* @param {string} command
* @param {null | string | Record<string, any>} parameters
* @param {(...args: any[]) => void} callBack
*
* @return {Promise<any>}
*/
async callCustomBind(command, parameters = null, callBack) {
let options = {};
if (Type.isString(parameters)) {
options["singleOption"] = parameters;
} else if (Type.isObjectLike(parameters)) {
options = { ...parameters };
}
return this.#messageManager.send(
command,
{
...options,
callBack,
isSafely: true
}
);
}
}
var __defProp$n = Object.defineProperty;
var __name$n = (target, value) => __defProp$n(target, "name", { value, configurable: true });
class B24Frame extends AbstractB24 {
static {
__name$n(this, "B24Frame");
}
#isInstallMode = false;
#isFirstRun = false;
#appFrame;
#messageManager;
#authManager;
#parentManager;
#optionsManager;
#dialogManager;
#sliderManager;
#placementManager;
#restrictionParams;
// region Init ////
constructor(queryParams, options) {
super();
this.#restrictionParams = options?.restrictionParams;
this.#appFrame = new AppFrame(queryParams);
this.#messageManager = new MessageManager(this.#appFrame);
this.#messageManager.subscribe();
this.#authManager = new AuthManager(
this.#appFrame,
this.#messageManager
);
this.#parentManager = new ParentManager(this.#messageManager);
this.#optionsManager = new OptionsManager$1(this.#messageManager);
this.#dialogManager = new DialogManager(this.#messageManager);
this.#sliderManager = new SliderManager(
this.#appFrame,
this.#messageManager
);
this.#placementManager = new PlacementManager(this.#messageManager);
this._isInit = false;
}
setLogger(logger) {
super.setLogger(logger);
this.#messageManager.setLogger(this.getLogger());
}
get isFirstRun() {
this._ensureInitialized();
return this.#isFirstRun;
}
get isInstallMode() {
this._ensureInitialized();
return this.#isInstallMode;
}
get parent() {
this._ensureInitialized();
return this.#parentManager;
}
get auth() {
this._ensureInitialized();
return this.#authManager;
}
get slider() {
this._ensureInitialized();
return this.#sliderManager;
}
get placement() {
this._ensureInitialized();
return this.#placementManager;
}
get options() {
this._ensureInitialized();
return this.#optionsManager;
}
get dialog() {
this._ensureInitialized();
return this.#dialogManager;
}
async init() {
const data = await this.#messageManager.send(MessageCommands.getInitData, {});
this.getLogger().debug("init data", {
PLACEMENT: data.PLACEMENT,
LANG: data.LANG,
INSTALL: data.INSTALL,
IS_ADMIN: data.IS_ADMIN,
FIRST_RUN: data.FIRST_RUN
}).catch(() => {
});
this.#appFrame.initData(data);
this.#authManager.initData(data);
this.#placementManager.initData(data);
this.#optionsManager.initData(data);
this.#isInstallMode = data.INSTALL;
this.#isFirstRun = data.FIRST_RUN;
this._httpV2 = new HttpV2(this.#authManager, this._getHttpOptions(), this.#restrictionParams);
this._httpV3 = new HttpV3(this.#authManager, this._getHttpOptions(), this.#restrictionParams);
this._isInit = true;
if (this.#isFirstRun) {
return this.#messageManager.send(MessageCommands.setInstall, { install: true });
}
return Promise.resolve();
}
/**
* Destructor.
* Removes an event subscription
*/
destroy() {
this.#messageManager.unsubscribe();
super.destroy();
}
// endregion ////
// region Core ////
/**
* Signals that the installer or application setup has finished running.
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/system-functions/bx24-install-finish.html
*/
async installFinish() {
if (!this.isInstallMode) {
return Promise.reject(new SdkError({ code: "JSSDK_FRAME_INSTALL_ALREADY_FINISHED", description: "Application was previously installed. You cannot call installFinish", status: 0 }));
}
return this.#messageManager.send(MessageCommands.setInstallFinish, {});
}
// endregion ////
// region Get ////
/**
* @inheritDoc
*/
getTargetOrigin() {
this._ensureInitialized();
return this.#authManager.getTargetOrigin();
}
/**
* @inheritDoc
*/
getTargetOriginWithPath() {
this._ensureInitialized();
return this.#authManager.getTargetOriginWithPath();
}
/**
* Returns the sid of the application relative to the parent window like this `9c33468728e1d2c8c97562475edfd96`
*/
getAppSid() {
this._ensureInitialized();
return this.#appFrame.getAppSid();
}
/**
* Returns the localization of the B24 interface
*
* @link https://apidocs.bitrix24.com/sdk/bx24-js-sdk/additional-functions/bx24-get-lang.html
*/
getLang() {
this._ensureInitialized();
return this.#appFrame.getLang();
}
// endregion ////
}
var __defProp$m = Object.defineProperty;
var __name$m = (target, value) => __defProp$m(target, "name", { value, configurable: true });
class RefreshTokenError extends SdkError {
static {
__name$m(this, "RefreshTokenError");
}
}
var __defProp$l = Object.defineProperty;
var __name$l = (target, value) => __defProp$l(target, "name", { value, configurable: true });
class AuthOAuthManager {
static {
__name$l(this, "AuthOAuthManager");
}
#clientAxios;
#callbackRefreshAuth = null;
#customRefreshAuth = null;
#authOptions;
#oAuthSecret;
#authExpires = 0;
#authExpiresIn = 0;
#domain;
#b24TargetRest;
#b24Target;
#b24TargetRestWithPath;
#oAuthTarget;
// from serverEndpoint, e.g. 'https://oauth.bitrix24.tech'
#isAdmin = null;
constructor(b24OAuthParams, oAuthSecret) {
this.#authOptions = Object.assign({}, b24OAuthParams);
this.#oAuthSecret = Object.freeze(Object.assign({}, oAuthSecret));
this.#domain = this.#authOptions.domain.replaceAll("https://", "").replaceAll("http://", "").replace(/:(80|443)$/, "");
this.#b24TargetRest = this.#authOptions.clientEndpoint;
this.#b24Target = this.#b24TargetRest.replace("/rest/", "");
this.#oAuthTarget = this.#authOptions.serverEndpoint.replace("/rest/", "");
this.#authExpires = this.#authOptions.expires * 1e3;
this.#authExpiresIn = this.#authOptions.expiresIn;
this.#clientAxios = axios.create({
baseURL: this.#oAuthTarget
});
this.#b24TargetRestWithPath = /* @__PURE__ */ new Map();
this.#b24TargetRestWithPath.set(ApiVersion.v2, `${this.#b24TargetRest}`);
this.#b24TargetRestWithPath.set(ApiVersion.v3, `${this.#b24TargetRest}/api`);
}
/**
* Returns authorization data
* @see Http.#prepareParams
*/
getAuthData() {
return this.#authExpires > Date.now() ? {
access_token: this.#authOptions.accessToken,
refresh_token: this.#authOptions.refreshToken,
expires: this.#authExpires / 1e3,
expires_in: this.#authExpiresIn,
domain: this.#domain,
member_id: this.#authOptions.memberId
} : false;
}
// region RefreshAuth ////
/**
* Updates authorization data
*/
async refreshAuth() {
try {
let payload = void 0;
if (this.#customRefreshAuth) {
payload = await this.#customRefreshAuth();
} else {
const body = new URLSearchParams({
grant_type: "refresh_token",
client_id: this.#oAuthSecret.clientId,
client_secret: this.#oAuthSecret.clientSecret,
refresh_token: this.#authOptions.refreshToken
});
const response = await this.#clientAxios.post(
"/oauth/token/",
body,
{ headers: { "Content-Type": "application/x-www-form-urlencoded" } }
);
if (response.data.error) {
throw new SdkError({ code: "JSSDK_OAUTH_TOKEN_REFRESH_FAILED", description: `Token update error: ${response.data.error}`, status: 0 });
}
if (response.status !== 200) {
throw new SdkError({ code: "JSSDK_OAUTH_TOKEN_REFRESH_BAD_STATUS", description: `Token update error status code: ${response.status}`, status: response.status });
}
payload = response.data;
}
if (!payload) {
throw new SdkError({ code: "JSSDK_OAUTH_TOKEN_REFRESH_NO_DATA", description: "Unable to obtain authorization update data", status: 0 });
}
this.#authOptions.accessToken = payload.access_token;
this.#authOptions.refreshToken = payload.refresh_token;
this.#authOptions.expires = Number.parseInt(payload.expires || "0");
this.#authOptions.expiresIn = Number.parseInt(payload.expires_in || "3600");
this.#authOptions.clientEndpoint = payload.client_endpoint;
this.#authOptions.serverEndpoint = payload.server_endpoint;
this.#authOptions.scope = payload.scope;
this.#authOptions.status = Object.values(EnumAppStatus).find((value) => value === payload.status) || EnumAppStatus.Free;
this.#authExpires = this.#authOptions.expires * 1e3;
const authData = this.getAuthData();
if (this.#callbackRefreshAuth) {
await this.#callbackRefreshAuth({ authData, b24OAuthParams: this.#authOptions });
}
return authData;
} catch (error) {
if (error instanceof AxiosError) {
const answerError = {
code: error?.code || 0,
description: error?.message || ""
};
if (error.response && error.response.data && !Type.isUndefined(error.response.data.error)) {
const responseData = error.response.data;
if (responseData.error && typeof responseData.error === "object" && "code" in responseData.error) {
answerError.code = responseData.error.code;
answerError.description = responseData.error.message;
if (responseData.error.validation) {
responseData.error.validation.forEach((row) => {
answerError.description += `${row?.message || JSON.stringify(row)}`;
});
}
} else if (responseData.error && typeof responseData.error === "string") {
answerError.code = responseData.error;
answerError.description = responseData?.error_description ?? answerError.description;
}
}
throw new RefreshTokenError({
code: String(answerError.code),
description: answerError.description,
status: error.response?.status || 0
});
} else if (error instanceof Error) {
throw error;
}
throw new Error(`Strange error: ${String(error)}`, { cause: error });
}
}
setCallbackRefreshAuth(cb) {
this.#callbackRefreshAuth = cb;
}
removeCallbackRefreshAuth() {
this.#callbackRefreshAuth = null;
}
setCustomRefreshAuth(cb) {
this.#customRefreshAuth = cb;
}
removeCustomRefreshAuth() {
this.#customRefreshAuth = null;
}
// endregion ////
getUniq(prefix) {
return [prefix, this.#authOptions.memberId || ""].join("_");
}
/**
* @inheritDoc
*/
getTargetOrigin() {
return `${this.#b24Target}`;
}
/**
* @inheritDoc
*/
getTargetOriginWithPath() {
return this.#b24TargetRestWithPath;
}
/**
* Determines whether the current user has administrator rights
*/
get isAdmin() {
if (null === this.#isAdmin) {
throw new SdkError({ code: "JSSDK_OAUTH_IS_ADMIN_NOT_INIT", description: "isAdmin not init. You need call B24OAuth::initIsAdmin().", status: 0 });
}
return this.#isAdmin;
}
async initIsAdmin(http, requestId) {
this.#isAdmin = false;
if (http.apiVersion === ApiVersion.v3) {
const response2 = await http.call("profile", {}, requestId);
if (!response2.isSuccess) {
throw new SdkError({ code: "JSSDK_OAUTH_PROFILE_FAILED", description: response2.getErrorMessages().join(";"), status: 0 });
}
const data2 = response2.getData().result;
if (data2.profile?.admin) {
this.#isAdmin = true;
}
return;
}
const response = await http.call("profile", {}, requestId);
if (!response.isSuccess) {
throw new SdkError({ code: "JSSDK_OAUTH_PROFILE_FAILED", description: response.getErrorMessages().join(";"), status: 0 });
}
const data = response.getData().result;
if (data?.ADMIN) {
this.#isAdmin = true;
}
}
}
var __defProp$k = Object.defineProperty;
var __name$k = (target, value) => __defProp$k(target, "name", { value, configurable: true });
class B24OAuth extends AbstractB24 {
static {
__name$k(this, "B24OAuth");
}
#authOAuthManager;
// region Init ////
constructor(authOptions, oAuthSecret, options) {
super();
this.#authOAuthManager = new AuthOAuthManager(
authOptions,
oAuthSecret
);
const warningText = "The B24OAuth object is intended exclusively for use on the server.\nA webhook contains a secret access key, which MUST NOT be used in client-side code (browser, mobile app).";
this._httpV2 = new HttpV2(this.#authOAuthManager, this._getHttpOptions(), options?.restrictionParams);
this._httpV2.setClientSideWarning(true, warningText);
this._httpV3 = new HttpV3(this.#authOAuthManager, this._getHttpOptions(), options?.restrictionParams);
this._httpV3.setClientSideWarning(true, warningText);
this._isInit = true;
}
/**
* Used to initialize information about the current user.
*/
// TODO: add integration-test coverage for the admin-flag fetch
async initIsAdmin(requestId) {
const method = "profile";
this._ensureInitialized();
try {
const version = versionManager.automaticallyObtainApiVersion(method);
const client = this.getHttpClient(version);
return this.#authOAuthManager.initIsAdmin(client, requestId);
} catch (error) {
this.getLogger().error("initIsAdmin: setup failed before the profile call; treating the user as non-admin", {
code: error instanceof SdkError ? error.code : "JSSDK_OAUTH_IS_ADMIN_LOOKUP_FAILED"
}).catch(() => {
});
return;
}
}
/**
* Sets an asynchronous Callback to receive updated authorization data
* @param cb
*/
setCallbackRefreshAuth(cb) {
this._ensureInitialized();
this.#authOAuthManager.setCallbackRefreshAuth(cb);
}
/**
* Removes Callback to receive updated authorization data
*/
removeCallbackRefreshAuth() {
this._ensureInitialized();
this.#authOAuthManager.removeCallbackRefreshAuth();
}
/**
* Sets an asynchronous function for custom get new refresh token
* @param cb
*/
setCustomRefreshAuth(cb) {
this._ensureInitialized();
this.#authOAuthManager.setCustomRefreshAuth(cb);
}
/**
* Removes function for custom get new refresh token
*/
removeCustomRefreshAuth() {
this._ensureInitialized();
this.#authOAuthManager.removeCustomRefreshAuth();
}
// endregion ////
// region Core ////
/**
* Disables warning about client-side query execution
*/
offClientSideWarning() {
versionManager.getAllApiVersions().forEach((version) => {
this.getHttpClient(version).setClientSideWarning(false, "");
});
}
// endregion ////
get auth() {
return this.#authOAuthManager;
}
// region Get ////
/**
* @inheritDoc
*/
getTargetOrigin() {
this._ensureInitialized();
return this.#authOAuthManager.getTargetOrigin();
}
/**
* @inheritDoc
*/
getTargetOriginWithPath() {
this._ensureInitialized();
return this.#authOAuthManager.getTargetOriginWithPath();
}
// endregion ////
// region Tools ////
// endregion ////
}
var __defProp$j = Object.defineProperty;
var __name$j = (target, value) => __defProp$j(target, "name", { value, configurable: true });
class UnhandledMatchError extends Error {
static {
__name$j(this, "UnhandledMatchError");
}
constructor(value, ...args) {
super(...args);
this.name = "UnhandledMatchError";
this.message = `Unhandled match value of type ${value}`;
this.stack = `${new Error("for stack").stack}`;
}
}
class AbstractHelper {
static {
__name$j(this, "AbstractHelper");
}
_b24;
_data = null;
_logger;
// region Init ////
constructor(b24) {
this._b24 = b24;
this._logger = LoggerFactory.createNullLogger();
}
setLogger(logger) {
this._logger = logger;
}
getLogger() {
return this._logger;
}
// endregion ////
/**
* Initializes the data received
*/
async initData(_data) {
return Promise.reject(new Error("Rewrite this function"));
}
}
var __defProp$i = Object.defineProperty;
var __name$i = (target, value) => __defProp$i(target, "name", { value, configurable: true });
class ProfileManager extends AbstractHelper {
static {
__name$i(this, "ProfileManager");
}
_data = null;
/**
* @inheritDoc
*/
async initData(data) {
this._data = data;
}
get data() {
if (null === this._data) {
throw new Error("ProfileManager.data not initialized");
}
return this._data;
}
}
var __defProp$h = Object.defineProperty;
var __name$h = (target, value) => __defProp$h(target, "name", { value, configurable: true });
class AppManager extends AbstractHelper {
static {
__name$h(this, "AppManager");
}
_data = null;
/**
* @inheritDoc
*/
async initData(data) {
this._data = data;
}
get data() {
if (null === this._data) {
throw new Error("AppManager.data not initialized");
}
return this._data;
}
get statusCode() {
return StatusDescriptions[this.data.status] || "Unknown status";
}
}
var __defProp$g = Object.defineProperty;
var __name$g = (target, value) => __defProp$g(target, "name", { value, configurable: true });
class PaymentManager extends AbstractHelper {
static {
__name$g(this, "PaymentManager");
}
_data = null;
/**
* @inheritDoc
*/
async initData(data) {
this._data = data;
}
get data() {
if (null === this._data) {
throw new Error("PaymentManager.data not initialized");
}
return this._data;
}
}
var __defProp$f = Object.defineProperty;
var __name$f = (target, value) => __defProp$f(target, "name", { value, configurable: true });
class LicenseManager extends AbstractHelper {
static {
__name$f(this, "LicenseManager");
}
_data = null;
/**
* @inheritDoc
*/
async initData(data) {
this._data = data;
await this.makeRestrictionManagerParams();
}
get data() {
if (null === this._data) {
throw new Error("LicenseManager.data not initialized");
}
return this._data;
}
/**
* Set RestrictionManager params by license
* @link https://apidocs.bitrix24.com/api-reference/common/system/app-info.html
*/
async makeRestrictionManagerParams() {
if (!this.data?.license) {
return;
}
const restrictionParams = ParamsFactory.fromTariffPlan(this.data.license);
this.getLogger().debug("set restriction manager params", {
license: this.data.license,
restrictionParams
}).catch(() => {
});
await this._b24.setRestrictionManagerParams(restrictionParams);
}
}
var __defProp$e = Object.defineProperty;
var __name$e = (target, value) => __defProp$e(target, "name", { value, configurable: true });
class CurrencyManager extends AbstractHelper {
static {
__name$e(this, "CurrencyManager");
}
/**
* @inheritDoc
*/
async initData(data) {
this._data = {
currencyBase: "?",
currencyList: /* @__PURE__ */ new Map()
};
this.setBaseCurrency(data.currencyBase);
this.setCurrencyList(data.currencyList);
try {
await this.loadData();
} catch (error) {
if (error instanceof Error) {
throw error;
}
this.getLogger().error("Failed to load data", { error }).catch(() => {
});
throw new Error("Failed to load data", { cause: error });
}
}
async loadData() {
const batchRequest = this.currencyList.map((currencyCode) => {
return {
method: "crm.currency.get",
params: {
id: currencyCode
}
};
});
if (batchRequest.length === 0) {
return Promise.resolve();
}
try {
const response = await this._b24.actions.v2.batchByChunk.make({
calls: batchRequest,
options: { isHaltOnError: true }
});
const data = response.getData();
if (!Array.isArray(data)) {
return Promise.resolve();
}
data.forEach((row) => {
if (typeof row.LANG === "undefined") {
return;
}
const currencyCode = row.CURRENCY;
const currency = this.data.currencyList.get(currencyCode);
if (typeof currency === "undefined") {
return;
}
for (const [langCode, formatData] of Object.entries(row.LANG)) {
currency.lang[langCode] = {
decimals: Number.parseInt(formatData.DECIMALS),
decPoint: formatData.DEC_POINT,
formatString: formatData.FORMAT_STRING,
fullName: formatData.FULL_NAME,
isHideZero: formatData.HIDE_ZERO === "Y",
thousandsSep: formatData.THOUSANDS_SEP,
thousandsVariant: formatData.THOUSANDS_VARIANT
};
switch (currency.lang[langCode].thousandsVariant) {
case "N":
currency.lang[langCode].thousandsSep = "";
break;
case "D":
currency.lang[langCode].thousandsSep = ".";
break;
case "C":
currency.lang[langCode].thousandsSep = ",";
break;
case "S":
currency.lang[langCode].thousandsSep = " ";
break;
case "B":
currency.lang[langCode].thousandsSep = " ";
break;
// case 'OWN': ////
default:
if (!Type.isStringFilled(currency.lang[langCode].thousandsSep)) {
currency.lang[langCode].thousandsSep = " ";
}
break;
}
}
});
} catch (error) {
this.getLogger().error("Failed to load data", { error }).catch(() => {
});
}
}
get data() {
if (null === this._data) {
throw new Error("CurrencyManager.data not initialized");
}
return this._data;
}
// region BaseCurrency ////
setBaseCurrency(currencyBase) {
this._data.currencyBase = currencyBase;
}
get baseCurrency() {
return this.data.currencyBase;
}
// endregion ////
// region CurrencyList ////
setCurrencyList(list = []) {
this.data.currencyList.clear();
for (const row of list) {
this.data.currencyList.set(row.CURRENCY, {
amount: Number.parseFloat(row.CURRENCY),
amountCnt: Number.parseInt(row.AMOUNT_CNT),
isBase: row.BASE === "Y",
currencyCode: row.CURRENCY,
dateUpdate: Text.toDateTime(row.DATE_UPDATE),
decimals: Number.parseInt(row.DECIMALS),
decPoint: row.DEC_POINT,
formatString: row.FORMAT_STRING,
fullName: row.FULL_NAME,
lid: row.LID,
sort: Number.parseInt(row.SORT),
thousandsSep: row?.THOUSANDS_SEP || null,
lang: {}
});
}
}
// endregion ////
// region Info ////
getCurrencyFullName(currencyCode, langCode) {
const currency = this.data.currencyList.get(currencyCode);
if (typeof currency === "undefined") {
throw new UnhandledMatchError(currencyCode);
}
let fullName = currency.fullName;
if (!(typeof langCode === "undefined")) {
const langFormatter = currency.lang[langCode];
if (!Type.isUndefined(langFormatter)) {
fullName = langFormatter.fullName;
}
}
return fullName;
}
getCurrencyLiteral(currencyCode, langCode) {
const currency = this.data.currencyList.get(currencyCode);
if (typeof currency === "undefined") {
throw new UnhandledMatchError(currencyCode);
}
let formatString = currency.formatString;
if (!(typeof langCode === "undefined")) {
const langFormatter = currency.lang[langCode];
if (!Type.isUndefined(langFormatter)) {
formatString = langFormatter.formatString;
}
}
return formatString.replaceAll("&#", "&%").replaceAll("#", "").replaceAll("&%", "&#").trim() || "";
}
get currencyList() {
return [...this.data.currencyList.keys()];
}
// endregion ////
// region Format ////
format(value, currencyCode, langCode) {
const currency = this.data.currencyList.get(currencyCode);
if (typeof currency === "undefined") {
throw new UnhandledMatchError(currencyCode);
}
const options = {
formatString: currency.formatString,
decimals: currency.decimals,
decPoint: currency.decPoint,
thousandsSep: currency.thousandsSep
};
if (!Type.isStringFilled(options.thousandsSep)) {
options.thousandsSep = "";
}
const langFormatter = currency.lang[langCode];
if (!Type.isUndefined(langFormatter)) {
options.formatString = langFormatter.formatString;
options.decimals = langFormatter.decimals;
options.decPoint = langFormatter.decPoint;
options.thousandsSep = langFormatter.thousandsSep;
}
return options.formatString.replaceAll("&#", "&%").replace(
"#",
Text.numberFormat(
value,
options.decimals,
options.decPoint,
options.thousandsSep
)
).replaceAll("&%", "&#") || "";
}
// endregion ////
}
var __defProp$d = Object.defineProperty;
var __name$d = (target, value) => __defProp$d(target, "name", { value, configurable: true });
class OptionsManager extends AbstractHelper {
static {
__name$d(this, "OptionsManager");
}
_data;
_type;
// region static ////
static getSupportTypes() {
return [
TypeOption.NotSet,
TypeOption.JsonArray,
TypeOption.JsonObject,
TypeOption.FloatVal,
TypeOption.IntegerVal,
TypeOption.BoolYN,
TypeOption.StringVal
];
}
static prepareArrayList(list) {
if (Type.isArray(list)) {
return list;
}
if (Type.isObject(list)) {
return Object.values(list);
}
return [];
}
// endregion ////
// region Init ////
constructor(b24, type) {
super(b24);
this._type = type;
this._data = /* @__PURE__ */ new Map();
}
get data() {
return this._data;
}
reset() {
this.data.clear();
}
/**
* @inheritDoc
*/
async initData(data) {
this.reset();
if (Type.isObject(data)) {
for (const [key, value] of Object.entries(data)) {
this.data.set(key, value);
}
}
}
// endregion ////
// region Get ////
getJsonArray(key, defValue = []) {
if (!this.data.has(key)) {
return defValue;
}
let data = this.data.get(key);
try {
data = JSON.parse(data);
if (!Type.isArray(data) && !Type.isObject(data)) {
data = defValue;
}
} catch (error) {
this.getLogger().error("Failed JSON parse", { error }).catch(() => {
});
data = defValue;
}
return OptionsManager.prepareArrayList(data);
}
getJsonObject(key, defValue = {}) {
if (!this.data.has(key)) {
return defValue;
}
let data = this.data.get(key);
try {
data = JSON.parse(data);
} catch (error) {
this.getLogger().error("Failed JSON parse", { error }).catch(() => {
});
data = defValue;
}
if (!Type.isObject(data)) {
data = defValue;
}
return data;
}
getFloat(key, defValue = 0) {
if (!this.data.has(key)) {
return defValue;
}
return Text.toNumber(this.data.get(key));
}
getInteger(key, defValue = 0) {
if (!this.data.has(key)) {
return defValue;
}
return Text.toInteger(this.data.get(key));
}
getBoolYN(key, defValue = true) {
if (!this.data.has(key)) {
return defValue;
}
return Text.toBoolean(this.data.get(key));
}
getBoolNY(key, defValue = false) {
if (!this.data.has(key)) {
return defValue;
}
return Text.toBoolean(this.data.get(key));
}
getString(key, defValue = "") {
if (!this.data.has(key)) {
return defValue;
}
return this.data.get(key).toString();
}
getDate(key, defValue = null) {
if (!this.data.has(key)) {
return defValue;
}
try {
const result = Text.toDateTime(this.data.get(key).toString());
if (result.isValid) {
return result;
} else {
return defValue;
}
} catch {
return defValue;
}
}
// endregion ////
// region Tools ////
encode(value) {
return JSON.stringify(value);
}
decode(data, defaultValue) {
try {
if (data.length > 0) {
return JSON.parse(data);
}
return defaultValue;
} catch (error) {
this.getLogger().error("Failed JSON parse", { error }).catch(() => {
});
}
return defaultValue;
}
// endregion ////
// region Save ////
getMethodSave() {
switch (this._type) {
case "app":
return "app.option.set";
case "user":
return "user.option.set";
}
}
async save(options, optionsPull, requestId) {
const calls = [];
calls.push({
method: this.getMethodSave(),
params: {
options
}
});
if (Type.isObject(optionsPull)) {
calls.push({
method: "pull.application.event.add",
params: {
COMMAND: optionsPull?.command,
PARAMS: optionsPull?.params,
MODULE_ID: optionsPull?.moduleId
}
});
}
return this._b24.actions.v2.batch.make({
calls,
options: {
isHaltOnError: true,
returnAjaxResult: false,
requestId
}
});
}
// endregion ////
}
var __defProp$c = Object.defineProperty;
var __name$c = (target, value) => __defProp$c(target, "name", { value, configurable: true });
class StorageManager {
static {
__name$c(this, "StorageManager");
}
_logger;
userId;
siteId;
constructor(params = {}) {
this._logger = LoggerFactory.createNullLogger();
this.userId = params.userId ? Text.toInteger(params.userId) : 0;
this.siteId = params.siteId ?? "none";
}
setLogger(logger) {
this._logger = logger;
}
getLogger() {
return this._logger;
}
set(name, value) {
if (typeof window === "undefined" || typeof window.localStorage === "undefined") {
this.getLogger().error("localStorage undefined", {
error: new Error("undefined window.localStorage")
}).catch(() => {
});
return;
}
if (typeof value !== "string" && value) {
value = JSON.stringify(value);
}
window.localStorage.setItem(this._getKey(name), value);
}
get(name, defaultValue) {
if (typeof window === "undefined" || typeof window.localStorage === "undefined") {
return defaultValue || null;
}
const result = window.localStorage.getItem(this._getKey(name));
if (result === null) {
return defaultValue || null;
}
return JSON.parse(result);
}
remove(name) {
if (typeof window === "undefined" || typeof window.localStorage === "undefined") {
this.getLogger().error("localStorage undefined", {
error: new Error("undefined window.localStorage")
}).catch(() => {
});
return;
}
return window.localStorage.removeItem(this._getKey(name));
}
_getKey(name) {
return `@bitrix24/b24jssdk-pull-${this.userId}-${this.siteId}-${name}`;
}
compareKey(eventKey, userKey) {
return eventKey === this._getKey(userKey);
}
}
var __defProp$b = Object.defineProperty;
var __name$b = (target, value) => __defProp$b(target, "name", { value, configurable: true });
class ErrorNotConnected extends Error {
static {
__name$b(this, "ErrorNotConnected");
}
constructor(message) {
super(message);
this.name = "ErrorNotConnected";
}
}
class ErrorTimeout extends Error {
static {
__name$b(this, "ErrorTimeout");
}
constructor(message) {
super(message);
this.name = "ErrorTimeout";
}
}
var __defProp$a = Object.defineProperty;
var __name$a = (target, value) => __defProp$a(target, "name", { value, configurable: true });
const JSON_RPC_VERSION = "2.0";
class JsonRpc {
static {
__name$a(this, "JsonRpc");
}
_logger;
_connector;
_idCounter = 0;
_handlers = {};
_rpcResponseAwaiters = /* @__PURE__ */ new Map();
constructor(options) {
this._logger = LoggerFactory.createNullLogger();
this._connector = options.connector;
if (Type.isPlainObject(options.handlers)) {
for (const method in options.handlers) {
this.handle(method, options.handlers[method]);
}
}
}
setLogger(logger) {
this._logger = logger;
}
getLogger() {
return this._logger;
}
/**
* @param {string} method
* @param {function} handler
*/
handle(method, handler) {
this._handlers[method] = handler;
}
/**
* Sends RPC command to the server.
*
* @param {string} method Method name
* @param {object} params
* @param {int} timeout
* @returns {Promise}
*/
async executeOutgoingRpcCommand(method, params, timeout = 5) {
return new Promise((resolve, reject) => {
const request = this.createRequest(method, params);
if (!this._connector.send(JSON.stringify(request))) {
reject(new ErrorNotConnected("websocket is not connected"));
}
const timeoutHandler = setTimeout(() => {
this._rpcResponseAwaiters.delete(request.id);
reject(new ErrorTimeout("no response"));
}, timeout * 1e3);
this._rpcResponseAwaiters.set(request.id, {
resolve,
reject,
timeout: timeoutHandler
});
});
}
/**
* Executes array or rpc commands.
* Returns an array of promises, each promise will be resolved individually.
*
* @param {JsonRpcRequest[]} batch
* @returns {Promise[]}
*/
// @ts-expect-error When we rewrite it to something more modern, then we'll remove this
executeOutgoingRpcBatch(batch) {
const requests = [];
const promises = [];
batch.forEach(({ method, params, id }) => {
const request = this.createRequest(method, params, id);
requests.push(request);
promises.push(
new Promise(
(resolve, reject) => this._rpcResponseAwaiters.set(request.id, {
resolve,
reject
})
)
);
});
this._connector.send(JSON.stringify(requests));
return promises;
}
processRpcResponse(response) {
if ("id" in response && this._rpcResponseAwaiters.has(Number(response.id))) {
const awaiter = this._rpcResponseAwaiters.get(Number(response.id));
if (awaiter) {
if ("result" in response) {
awaiter.resolve(response.result);
} else if ("error" in response) {
awaiter.reject(response?.error || "error");
} else {
awaiter.reject("wrong response structure");
}
clearTimeout(awaiter.timeout);
this._rpcResponseAwaiters.delete(Number(response.id));
}
return;
}
this.getLogger().error(`${Text.getDateForLog()}: Pull: Received rpc response with unknown id`, redactSensitiveParams({ response })).catch(() => {
});
}
parseJsonRpcMessage(message) {
let decoded;
try {
decoded = JSON.parse(message);
} catch (error) {
this.getLogger().error(
`${Text.getDateForLog()}: Pull: Could not decode json rpc message`,
{ error }
).catch(() => {
});
return [];
}
if (Type.isArray(decoded)) {
return this.executeIncomingRpcBatch(decoded);
} else if (Type.isJsonRpcRequest(decoded)) {
return this.executeIncomingRpcCommand(decoded);
} else if (Type.isJsonRpcResponse(decoded)) {
this.processRpcResponse(decoded);
return [];
} else {
this.getLogger().error(
`${Text.getDateForLog()}: Pull: unknown rpc packet`,
redactSensitiveParams({ decoded })
).catch(() => {
});
}
return [];
}
/**
* Executes RPC command, received from the server
*
* @param {string} method
* @param {object} params
* @returns {object} RpcCommandResult
*/
executeIncomingRpcCommand({
method,
params
}) {
if (method in this._handlers) {
return this._handlers[method].call(this, params || {});
}
return {
jsonrpc: JSON_RPC_VERSION,
error: ListRpcError.MethodNotFound
};
}
executeIncomingRpcBatch(batch) {
const result = [];
for (const command of batch) {
if ("jsonrpc" in command) {
if ("method" in command) {
const commandResult = this.executeIncomingRpcCommand(command);
if (commandResult) {
commandResult["jsonrpc"] = JSON_RPC_VERSION;
commandResult["id"] = command["id"];
result.push(commandResult);
}
} else {
this.processRpcResponse(command);
}
} else {
this.getLogger().error(
`${Text.getDateForLog()}: Pull: unknown rpc command in batch`,
redactSensitiveParams({ command })
).catch(() => {
});
result.push({
jsonrpc: JSON_RPC_VERSION,
error: ListRpcError.InvalidRequest
});
}
}
return result;
}
nextId() {
return ++this._idCounter;
}
createPublishRequest(messageBatch) {
return messageBatch.map((message) => this.createRequest("publish", message));
}
createRequest(method, params, id) {
if (!id) {
id = this.nextId();
}
return {
jsonrpc: JSON_RPC_VERSION,
method,
params,
id
};
}
}
var __defProp$9 = Object.defineProperty;
var __name$9 = (target, value) => __defProp$9(target, "name", { value, configurable: true });
class SharedConfig {
static {
__name$9(this, "SharedConfig");
}
_logger;
_storage;
_ttl = 24 * 60 * 60;
_callbacks;
constructor(params = {}) {
this._logger = LoggerFactory.createNullLogger();
params = params || {};
this._storage = params.storage || new StorageManager();
this._callbacks = {
onWebSocketBlockChanged: Type.isFunction(params.onWebSocketBlockChanged) ? params.onWebSocketBlockChanged : () => {
}
};
if (this._storage && typeof window !== "undefined") {
window.addEventListener("storage", this.onLocalStorageSet.bind(this));
}
}
setLogger(logger) {
this._logger = logger;
}
getLogger() {
return this._logger;
}
onLocalStorageSet(params) {
if (this._storage.compareKey(
params.key || "",
LsKeys.WebsocketBlocked
) && params.newValue !== params.oldValue) {
this._callbacks.onWebSocketBlockChanged({
isWebSocketBlocked: this.isWebSocketBlocked()
});
}
}
isWebSocketBlocked() {
if (!this._storage) {
return false;
}
return this._storage.get(LsKeys.WebsocketBlocked, 0) > Date.now();
}
setWebSocketBlocked(isWebSocketBlocked) {
if (!this._storage) {
return false;
}
try {
this._storage.set(
LsKeys.WebsocketBlocked,
isWebSocketBlocked ? Date.now() + this._ttl : 0
);
} catch (error) {
this.getLogger().error(
`${Text.getDateForLog()}: Pull: Could not save WS_blocked flag in local storage`,
{ error }
).catch(() => {
});
return false;
}
return true;
}
isLongPollingBlocked() {
if (!this._storage) {
return false;
}
return this._storage.get(LsKeys.LongPollingBlocked, 0) > Date.now();
}
setLongPollingBlocked(isLongPollingBlocked) {
if (!this._storage) {
return false;
}
try {
this._storage.set(
LsKeys.LongPollingBlocked,
isLongPollingBlocked ? Date.now() + this._ttl : 0
);
} catch (error) {
this.getLogger().error(
`${Text.getDateForLog()}: Pull: Could not save LP_blocked flag in local storage.`,
{ error }
).catch(() => {
});
return false;
}
return true;
}
isLoggingEnabled() {
if (!this._storage) {
return false;
}
return this._storage.get(LsKeys.LoggingEnabled, 0) > this.getTimestamp();
}
setLoggingEnabled(isLoggingEnabled) {
if (!this._storage) {
return false;
}
try {
this._storage.set(
LsKeys.LoggingEnabled,
isLoggingEnabled ? this.getTimestamp() + this._ttl : 0
);
} catch (error) {
this.getLogger().error(
`${Text.getDateForLog()}: LocalStorage error.`,
{ error }
).catch(() => {
});
return false;
}
return true;
}
// region Tools ////
getTimestamp() {
return Date.now();
}
// endregion ////
}
var __defProp$8 = Object.defineProperty;
var __name$8 = (target, value) => __defProp$8(target, "name", { value, configurable: true });
class ChannelManager {
static {
__name$8(this, "ChannelManager");
}
_logger;
_publicIds;
_restClient;
_getPublicListMethod;
constructor(params) {
this._logger = LoggerFactory.createNullLogger();
this._publicIds = /* @__PURE__ */ new Map();
this._restClient = params.b24;
this._getPublicListMethod = params.getPublicListMethod;
}
setLogger(logger) {
this._logger = logger;
}
getLogger() {
return this._logger;
}
/**
* @param {Array} users Array of user ids.
* @return {Promise}
*/
async getPublicIds(users) {
const now = /* @__PURE__ */ new Date();
const result = {};
const unknownUsers = [];
for (const userId of users) {
const chanel = this._publicIds.get(userId);
if (chanel && chanel.end > now) {
result[chanel.userId] = chanel;
} else {
unknownUsers.push(userId);
}
}
if (unknownUsers.length === 0) {
return Promise.resolve(result);
}
return new Promise((resolve) => {
this._restClient.callMethod(this._getPublicListMethod, {
users: unknownUsers
}).then((response) => {
const data = response.getData().result;
this.setPublicIds(Object.values(data));
for (const userId of unknownUsers) {
const chanel = this._publicIds.get(userId);
if (chanel) {
result[chanel.userId] = chanel;
}
}
resolve(result);
}).catch((error) => {
this.getLogger().error("some error in getPublicIds", { error }).catch(() => {
});
return resolve({});
});
});
}
/**
* @param {TypePublicIdDescriptor[]} publicIds
*/
setPublicIds(publicIds) {
publicIds.forEach((publicIdDescriptor) => {
const userId = Number(publicIdDescriptor.user_id);
this._publicIds.set(userId, {
userId,
publicId: publicIdDescriptor.public_id,
signature: publicIdDescriptor.signature,
start: new Date(publicIdDescriptor.start),
end: new Date(publicIdDescriptor.end)
});
});
}
}
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
var protobuf = {exports: {}};
var hasRequiredProtobuf;
function requireProtobuf () {
if (hasRequiredProtobuf) return protobuf.exports;
hasRequiredProtobuf = 1;
(function (module) {
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
/*!
* protobuf.js v6.8.6 (c) 2016, daniel wirtz
* compiled mon, 26 feb 2018 11:35:34 utc
* licensed under the bsd-3-clause license
* see: https://github.com/dcodeio/protobuf.js for details
*
* Modify a list for integration with Bitrix Framework:
* - removed integration with RequireJS and AMD package builders;
*/
(function(undefined$1) {
(/* @__PURE__ */ __name((function prelude(modules, cache, entries) {
function $require(name) {
var $module = cache[name];
if (!$module)
modules[name][0].call($module = cache[name] = { exports: {} }, $require, $module, $module.exports);
return $module.exports;
}
__name($require, "$require");
var protobuf = $require(entries[0]);
if (module && module.exports)
module.exports = protobuf;
}), "prelude"))({ 1: [function(require2, module2, exports) {
module2.exports = asPromise;
function asPromise(fn, ctx) {
var params = new Array(arguments.length - 1), offset = 0, index = 2, pending = true;
while (index < arguments.length)
params[offset++] = arguments[index++];
return new Promise(/* @__PURE__ */ __name(function executor(resolve, reject) {
params[offset] = /* @__PURE__ */ __name(function callback(err) {
if (pending) {
pending = false;
if (err)
reject(err);
else {
var params2 = new Array(arguments.length - 1), offset2 = 0;
while (offset2 < params2.length)
params2[offset2++] = arguments[offset2];
resolve.apply(null, params2);
}
}
}, "callback");
try {
fn.apply(ctx || null, params);
} catch (err) {
if (pending) {
pending = false;
reject(err);
}
}
}, "executor"));
}
__name(asPromise, "asPromise");
}, {}], 2: [function(require2, module2, exports) {
var base64 = exports;
base64.length = /* @__PURE__ */ __name(function length(string) {
var p = string.length;
if (!p)
return 0;
var n = 0;
while (--p % 4 > 1 && string.charAt(p) === "=")
++n;
return Math.ceil(string.length * 3) / 4 - n;
}, "length");
var b64 = new Array(64);
var s64 = new Array(123);
for (var i = 0; i < 64; )
s64[b64[i] = i < 26 ? i + 65 : i < 52 ? i + 71 : i < 62 ? i - 4 : i - 59 | 43] = i++;
base64.encode = /* @__PURE__ */ __name(function encode(buffer, start, end) {
var parts = null, chunk = [];
var i2 = 0, j = 0, t;
while (start < end) {
var b = buffer[start++];
switch (j) {
case 0:
chunk[i2++] = b64[b >> 2];
t = (b & 3) << 4;
j = 1;
break;
case 1:
chunk[i2++] = b64[t | b >> 4];
t = (b & 15) << 2;
j = 2;
break;
case 2:
chunk[i2++] = b64[t | b >> 6];
chunk[i2++] = b64[b & 63];
j = 0;
break;
}
if (i2 > 8191) {
(parts || (parts = [])).push(String.fromCharCode.apply(String, chunk));
i2 = 0;
}
}
if (j) {
chunk[i2++] = b64[t];
chunk[i2++] = 61;
if (j === 1)
chunk[i2++] = 61;
}
if (parts) {
if (i2)
parts.push(String.fromCharCode.apply(String, chunk.slice(0, i2)));
return parts.join("");
}
return String.fromCharCode.apply(String, chunk.slice(0, i2));
}, "encode");
var invalidEncoding = "invalid encoding";
base64.decode = /* @__PURE__ */ __name(function decode(string, buffer, offset) {
var start = offset;
var j = 0, t;
for (var i2 = 0; i2 < string.length; ) {
var c = string.charCodeAt(i2++);
if (c === 61 && j > 1)
break;
if ((c = s64[c]) === undefined$1)
throw Error(invalidEncoding);
switch (j) {
case 0:
t = c;
j = 1;
break;
case 1:
buffer[offset++] = t << 2 | (c & 48) >> 4;
t = c;
j = 2;
break;
case 2:
buffer[offset++] = (t & 15) << 4 | (c & 60) >> 2;
t = c;
j = 3;
break;
case 3:
buffer[offset++] = (t & 3) << 6 | c;
j = 0;
break;
}
}
if (j === 1)
throw Error(invalidEncoding);
return offset - start;
}, "decode");
base64.test = /* @__PURE__ */ __name(function test(string) {
return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(string);
}, "test");
}, {}], 3: [function(require2, module2, exports) {
module2.exports = codegen;
function codegen(functionParams, functionName) {
if (typeof functionParams === "string") {
functionName = functionParams;
functionParams = undefined$1;
}
var body = [];
function Codegen(formatStringOrScope) {
if (typeof formatStringOrScope !== "string") {
var source = toString();
if (codegen.verbose)
console.log("codegen: " + source);
source = "return " + source;
if (formatStringOrScope) {
var scopeKeys = Object.keys(formatStringOrScope), scopeParams = new Array(scopeKeys.length + 1), scopeValues = new Array(scopeKeys.length), scopeOffset = 0;
while (scopeOffset < scopeKeys.length) {
scopeParams[scopeOffset] = scopeKeys[scopeOffset];
scopeValues[scopeOffset] = formatStringOrScope[scopeKeys[scopeOffset++]];
}
scopeParams[scopeOffset] = source;
return Function.apply(null, scopeParams).apply(null, scopeValues);
}
return Function(source)();
}
var formatParams = new Array(arguments.length - 1), formatOffset = 0;
while (formatOffset < formatParams.length)
formatParams[formatOffset] = arguments[++formatOffset];
formatOffset = 0;
formatStringOrScope = formatStringOrScope.replace(/%([%dfijs])/g, /* @__PURE__ */ __name(function replace($0, $1) {
var value = formatParams[formatOffset++];
switch ($1) {
case "d":
case "f":
return String(Number(value));
case "i":
return String(Math.floor(value));
case "j":
return JSON.stringify(value);
case "s":
return String(value);
}
return "%";
}, "replace"));
if (formatOffset !== formatParams.length)
throw Error("parameter count mismatch");
body.push(formatStringOrScope);
return Codegen;
}
__name(Codegen, "Codegen");
function toString(functionNameOverride) {
return "function " + (functionNameOverride || functionName || "") + "(" + (functionParams && functionParams.join(",") || "") + "){\n " + body.join("\n ") + "\n}";
}
__name(toString, "toString");
Codegen.toString = toString;
return Codegen;
}
__name(codegen, "codegen");
codegen.verbose = false;
}, {}], 4: [function(require2, module2, exports) {
module2.exports = EventEmitter;
function EventEmitter() {
this._listeners = {};
}
__name(EventEmitter, "EventEmitter");
EventEmitter.prototype.on = /* @__PURE__ */ __name(function on(evt, fn, ctx) {
(this._listeners[evt] || (this._listeners[evt] = [])).push({
fn,
ctx: ctx || this
});
return this;
}, "on");
EventEmitter.prototype.off = /* @__PURE__ */ __name(function off(evt, fn) {
if (evt === undefined$1)
this._listeners = {};
else {
if (fn === undefined$1)
this._listeners[evt] = [];
else {
var listeners = this._listeners[evt];
for (var i = 0; i < listeners.length; )
if (listeners[i].fn === fn)
listeners.splice(i, 1);
else
++i;
}
}
return this;
}, "off");
EventEmitter.prototype.emit = /* @__PURE__ */ __name(function emit(evt) {
var listeners = this._listeners[evt];
if (listeners) {
var args = [], i = 1;
for (; i < arguments.length; )
args.push(arguments[i++]);
for (i = 0; i < listeners.length; )
listeners[i].fn.apply(listeners[i++].ctx, args);
}
return this;
}, "emit");
}, {}], 5: [function(require2, module2, exports) {
module2.exports = fetch;
var asPromise = require2(1), inquire = require2(7);
var fs = inquire("fs");
function fetch(filename, options, callback) {
if (typeof options === "function") {
callback = options;
options = {};
} else if (!options)
options = {};
if (!callback)
return asPromise(fetch, this, filename, options);
if (!options.xhr && fs && fs.readFile)
return fs.readFile(filename, /* @__PURE__ */ __name(function fetchReadFileCallback(err, contents) {
return err && typeof XMLHttpRequest !== "undefined" ? fetch.xhr(filename, options, callback) : err ? callback(err) : callback(null, options.binary ? contents : contents.toString("utf8"));
}, "fetchReadFileCallback"));
return fetch.xhr(filename, options, callback);
}
__name(fetch, "fetch");
fetch.xhr = /* @__PURE__ */ __name(function fetch_xhr(filename, options, callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = /* @__PURE__ */ __name(function fetchOnReadyStateChange() {
if (xhr.readyState !== 4)
return undefined$1;
if (xhr.status !== 0 && xhr.status !== 200)
return callback(Error("status " + xhr.status));
if (options.binary) {
var buffer = xhr.response;
if (!buffer) {
buffer = [];
for (var i = 0; i < xhr.responseText.length; ++i)
buffer.push(xhr.responseText.charCodeAt(i) & 255);
}
return callback(null, typeof Uint8Array !== "undefined" ? new Uint8Array(buffer) : buffer);
}
return callback(null, xhr.responseText);
}, "fetchOnReadyStateChange");
if (options.binary) {
if ("overrideMimeType" in xhr)
xhr.overrideMimeType("text/plain; charset=x-user-defined");
xhr.responseType = "arraybuffer";
}
xhr.open("GET", filename);
xhr.send();
}, "fetch_xhr");
}, { "1": 1, "7": 7 }], 6: [function(require2, module2, exports) {
module2.exports = factory(factory);
function factory(exports2) {
if (typeof Float32Array !== "undefined") (function() {
var f32 = new Float32Array([-0]), f8b = new Uint8Array(f32.buffer), le = f8b[3] === 128;
function writeFloat_f32_cpy(val, buf, pos) {
f32[0] = val;
buf[pos] = f8b[0];
buf[pos + 1] = f8b[1];
buf[pos + 2] = f8b[2];
buf[pos + 3] = f8b[3];
}
__name(writeFloat_f32_cpy, "writeFloat_f32_cpy");
function writeFloat_f32_rev(val, buf, pos) {
f32[0] = val;
buf[pos] = f8b[3];
buf[pos + 1] = f8b[2];
buf[pos + 2] = f8b[1];
buf[pos + 3] = f8b[0];
}
__name(writeFloat_f32_rev, "writeFloat_f32_rev");
exports2.writeFloatLE = le ? writeFloat_f32_cpy : writeFloat_f32_rev;
exports2.writeFloatBE = le ? writeFloat_f32_rev : writeFloat_f32_cpy;
function readFloat_f32_cpy(buf, pos) {
f8b[0] = buf[pos];
f8b[1] = buf[pos + 1];
f8b[2] = buf[pos + 2];
f8b[3] = buf[pos + 3];
return f32[0];
}
__name(readFloat_f32_cpy, "readFloat_f32_cpy");
function readFloat_f32_rev(buf, pos) {
f8b[3] = buf[pos];
f8b[2] = buf[pos + 1];
f8b[1] = buf[pos + 2];
f8b[0] = buf[pos + 3];
return f32[0];
}
__name(readFloat_f32_rev, "readFloat_f32_rev");
exports2.readFloatLE = le ? readFloat_f32_cpy : readFloat_f32_rev;
exports2.readFloatBE = le ? readFloat_f32_rev : readFloat_f32_cpy;
})();
else (function() {
function writeFloat_ieee754(writeUint, val, buf, pos) {
var sign = val < 0 ? 1 : 0;
if (sign)
val = -val;
if (val === 0)
writeUint(1 / val > 0 ? (
/* positive */
0
) : (
/* negative 0 */
2147483648
), buf, pos);
else if (isNaN(val))
writeUint(2143289344, buf, pos);
else if (val > 34028234663852886e22)
writeUint((sign << 31 | 2139095040) >>> 0, buf, pos);
else if (val < 11754943508222875e-54)
writeUint((sign << 31 | Math.round(val / 1401298464324817e-60)) >>> 0, buf, pos);
else {
var exponent = Math.floor(Math.log(val) / Math.LN2), mantissa = Math.round(val * Math.pow(2, -exponent) * 8388608) & 8388607;
writeUint((sign << 31 | exponent + 127 << 23 | mantissa) >>> 0, buf, pos);
}
}
__name(writeFloat_ieee754, "writeFloat_ieee754");
exports2.writeFloatLE = writeFloat_ieee754.bind(null, writeUintLE);
exports2.writeFloatBE = writeFloat_ieee754.bind(null, writeUintBE);
function readFloat_ieee754(readUint, buf, pos) {
var uint = readUint(buf, pos), sign = (uint >> 31) * 2 + 1, exponent = uint >>> 23 & 255, mantissa = uint & 8388607;
return exponent === 255 ? mantissa ? NaN : sign * Infinity : exponent === 0 ? sign * 1401298464324817e-60 * mantissa : sign * Math.pow(2, exponent - 150) * (mantissa + 8388608);
}
__name(readFloat_ieee754, "readFloat_ieee754");
exports2.readFloatLE = readFloat_ieee754.bind(null, readUintLE);
exports2.readFloatBE = readFloat_ieee754.bind(null, readUintBE);
})();
if (typeof Float64Array !== "undefined") (function() {
var f64 = new Float64Array([-0]), f8b = new Uint8Array(f64.buffer), le = f8b[7] === 128;
function writeDouble_f64_cpy(val, buf, pos) {
f64[0] = val;
buf[pos] = f8b[0];
buf[pos + 1] = f8b[1];
buf[pos + 2] = f8b[2];
buf[pos + 3] = f8b[3];
buf[pos + 4] = f8b[4];
buf[pos + 5] = f8b[5];
buf[pos + 6] = f8b[6];
buf[pos + 7] = f8b[7];
}
__name(writeDouble_f64_cpy, "writeDouble_f64_cpy");
function writeDouble_f64_rev(val, buf, pos) {
f64[0] = val;
buf[pos] = f8b[7];
buf[pos + 1] = f8b[6];
buf[pos + 2] = f8b[5];
buf[pos + 3] = f8b[4];
buf[pos + 4] = f8b[3];
buf[pos + 5] = f8b[2];
buf[pos + 6] = f8b[1];
buf[pos + 7] = f8b[0];
}
__name(writeDouble_f64_rev, "writeDouble_f64_rev");
exports2.writeDoubleLE = le ? writeDouble_f64_cpy : writeDouble_f64_rev;
exports2.writeDoubleBE = le ? writeDouble_f64_rev : writeDouble_f64_cpy;
function readDouble_f64_cpy(buf, pos) {
f8b[0] = buf[pos];
f8b[1] = buf[pos + 1];
f8b[2] = buf[pos + 2];
f8b[3] = buf[pos + 3];
f8b[4] = buf[pos + 4];
f8b[5] = buf[pos + 5];
f8b[6] = buf[pos + 6];
f8b[7] = buf[pos + 7];
return f64[0];
}
__name(readDouble_f64_cpy, "readDouble_f64_cpy");
function readDouble_f64_rev(buf, pos) {
f8b[7] = buf[pos];
f8b[6] = buf[pos + 1];
f8b[5] = buf[pos + 2];
f8b[4] = buf[pos + 3];
f8b[3] = buf[pos + 4];
f8b[2] = buf[pos + 5];
f8b[1] = buf[pos + 6];
f8b[0] = buf[pos + 7];
return f64[0];
}
__name(readDouble_f64_rev, "readDouble_f64_rev");
exports2.readDoubleLE = le ? readDouble_f64_cpy : readDouble_f64_rev;
exports2.readDoubleBE = le ? readDouble_f64_rev : readDouble_f64_cpy;
})();
else (function() {
function writeDouble_ieee754(writeUint, off0, off1, val, buf, pos) {
var sign = val < 0 ? 1 : 0;
if (sign)
val = -val;
if (val === 0) {
writeUint(0, buf, pos + off0);
writeUint(1 / val > 0 ? (
/* positive */
0
) : (
/* negative 0 */
2147483648
), buf, pos + off1);
} else if (isNaN(val)) {
writeUint(0, buf, pos + off0);
writeUint(2146959360, buf, pos + off1);
} else if (val > 17976931348623157e292) {
writeUint(0, buf, pos + off0);
writeUint((sign << 31 | 2146435072) >>> 0, buf, pos + off1);
} else {
var mantissa;
if (val < 22250738585072014e-324) {
mantissa = val / 5e-324;
writeUint(mantissa >>> 0, buf, pos + off0);
writeUint((sign << 31 | mantissa / 4294967296) >>> 0, buf, pos + off1);
} else {
var exponent = Math.floor(Math.log(val) / Math.LN2);
if (exponent === 1024)
exponent = 1023;
mantissa = val * Math.pow(2, -exponent);
writeUint(mantissa * 4503599627370496 >>> 0, buf, pos + off0);
writeUint((sign << 31 | exponent + 1023 << 20 | mantissa * 1048576 & 1048575) >>> 0, buf, pos + off1);
}
}
}
__name(writeDouble_ieee754, "writeDouble_ieee754");
exports2.writeDoubleLE = writeDouble_ieee754.bind(null, writeUintLE, 0, 4);
exports2.writeDoubleBE = writeDouble_ieee754.bind(null, writeUintBE, 4, 0);
function readDouble_ieee754(readUint, off0, off1, buf, pos) {
var lo = readUint(buf, pos + off0), hi = readUint(buf, pos + off1);
var sign = (hi >> 31) * 2 + 1, exponent = hi >>> 20 & 2047, mantissa = 4294967296 * (hi & 1048575) + lo;
return exponent === 2047 ? mantissa ? NaN : sign * Infinity : exponent === 0 ? sign * 5e-324 * mantissa : sign * Math.pow(2, exponent - 1075) * (mantissa + 4503599627370496);
}
__name(readDouble_ieee754, "readDouble_ieee754");
exports2.readDoubleLE = readDouble_ieee754.bind(null, readUintLE, 0, 4);
exports2.readDoubleBE = readDouble_ieee754.bind(null, readUintBE, 4, 0);
})();
return exports2;
}
__name(factory, "factory");
function writeUintLE(val, buf, pos) {
buf[pos] = val & 255;
buf[pos + 1] = val >>> 8 & 255;
buf[pos + 2] = val >>> 16 & 255;
buf[pos + 3] = val >>> 24;
}
__name(writeUintLE, "writeUintLE");
function writeUintBE(val, buf, pos) {
buf[pos] = val >>> 24;
buf[pos + 1] = val >>> 16 & 255;
buf[pos + 2] = val >>> 8 & 255;
buf[pos + 3] = val & 255;
}
__name(writeUintBE, "writeUintBE");
function readUintLE(buf, pos) {
return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16 | buf[pos + 3] << 24) >>> 0;
}
__name(readUintLE, "readUintLE");
function readUintBE(buf, pos) {
return (buf[pos] << 24 | buf[pos + 1] << 16 | buf[pos + 2] << 8 | buf[pos + 3]) >>> 0;
}
__name(readUintBE, "readUintBE");
}, {}], 7: [function(require2, module2, exports) {
module2.exports = inquire;
function inquire(moduleName) {
try {
var mod = require2(moduleName);
if (mod && (mod.length || Object.keys(mod).length))
return mod;
} catch (e) {
}
return null;
}
__name(inquire, "inquire");
}, {}], 8: [function(require2, module2, exports) {
var path = exports;
var isAbsolute = (
/**
* Tests if the specified path is absolute.
* @param {string} path Path to test
* @returns {boolean} `true` if path is absolute
*/
path.isAbsolute = /* @__PURE__ */ __name(function isAbsolute2(path2) {
return /^(?:\/|\w+:)/.test(path2);
}, "isAbsolute")
);
var normalize = (
/**
* Normalizes the specified path.
* @param {string} path Path to normalize
* @returns {string} Normalized path
*/
path.normalize = /* @__PURE__ */ __name(function normalize2(path2) {
path2 = path2.replace(/\\/g, "/").replace(/\/{2,}/g, "/");
var parts = path2.split("/"), absolute = isAbsolute(path2), prefix = "";
if (absolute)
prefix = parts.shift() + "/";
for (var i = 0; i < parts.length; ) {
if (parts[i] === "..") {
if (i > 0 && parts[i - 1] !== "..")
parts.splice(--i, 2);
else if (absolute)
parts.splice(i, 1);
else
++i;
} else if (parts[i] === ".")
parts.splice(i, 1);
else
++i;
}
return prefix + parts.join("/");
}, "normalize")
);
path.resolve = /* @__PURE__ */ __name(function resolve(originPath, includePath, alreadyNormalized) {
if (!alreadyNormalized)
includePath = normalize(includePath);
if (isAbsolute(includePath))
return includePath;
if (!alreadyNormalized)
originPath = normalize(originPath);
return (originPath = originPath.replace(/(?:\/|^)[^/]+$/, "")).length ? normalize(originPath + "/" + includePath) : includePath;
}, "resolve");
}, {}], 9: [function(require2, module2, exports) {
module2.exports = pool;
function pool(alloc, slice, size) {
var SIZE = size || 8192;
var MAX = SIZE >>> 1;
var slab = null;
var offset = SIZE;
return /* @__PURE__ */ __name(function pool_alloc(size2) {
if (size2 < 1 || size2 > MAX)
return alloc(size2);
if (offset + size2 > SIZE) {
slab = alloc(SIZE);
offset = 0;
}
var buf = slice.call(slab, offset, offset += size2);
if (offset & 7)
offset = (offset | 7) + 1;
return buf;
}, "pool_alloc");
}
__name(pool, "pool");
}, {}], 10: [function(require2, module2, exports) {
var utf8 = exports;
utf8.length = /* @__PURE__ */ __name(function utf8_length(string) {
var len = 0, c = 0;
for (var i = 0; i < string.length; ++i) {
c = string.charCodeAt(i);
if (c < 128)
len += 1;
else if (c < 2048)
len += 2;
else if ((c & 64512) === 55296 && (string.charCodeAt(i + 1) & 64512) === 56320) {
++i;
len += 4;
} else
len += 3;
}
return len;
}, "utf8_length");
utf8.read = /* @__PURE__ */ __name(function utf8_read(buffer, start, end) {
var len = end - start;
if (len < 1)
return "";
var parts = null, chunk = [], i = 0, t;
while (start < end) {
t = buffer[start++];
if (t < 128)
chunk[i++] = t;
else if (t > 191 && t < 224)
chunk[i++] = (t & 31) << 6 | buffer[start++] & 63;
else if (t > 239 && t < 365) {
t = ((t & 7) << 18 | (buffer[start++] & 63) << 12 | (buffer[start++] & 63) << 6 | buffer[start++] & 63) - 65536;
chunk[i++] = 55296 + (t >> 10);
chunk[i++] = 56320 + (t & 1023);
} else
chunk[i++] = (t & 15) << 12 | (buffer[start++] & 63) << 6 | buffer[start++] & 63;
if (i > 8191) {
(parts || (parts = [])).push(String.fromCharCode.apply(String, chunk));
i = 0;
}
}
if (parts) {
if (i)
parts.push(String.fromCharCode.apply(String, chunk.slice(0, i)));
return parts.join("");
}
return String.fromCharCode.apply(String, chunk.slice(0, i));
}, "utf8_read");
utf8.write = /* @__PURE__ */ __name(function utf8_write(string, buffer, offset) {
var start = offset, c1, c2;
for (var i = 0; i < string.length; ++i) {
c1 = string.charCodeAt(i);
if (c1 < 128) {
buffer[offset++] = c1;
} else if (c1 < 2048) {
buffer[offset++] = c1 >> 6 | 192;
buffer[offset++] = c1 & 63 | 128;
} else if ((c1 & 64512) === 55296 && ((c2 = string.charCodeAt(i + 1)) & 64512) === 56320) {
c1 = 65536 + ((c1 & 1023) << 10) + (c2 & 1023);
++i;
buffer[offset++] = c1 >> 18 | 240;
buffer[offset++] = c1 >> 12 & 63 | 128;
buffer[offset++] = c1 >> 6 & 63 | 128;
buffer[offset++] = c1 & 63 | 128;
} else {
buffer[offset++] = c1 >> 12 | 224;
buffer[offset++] = c1 >> 6 & 63 | 128;
buffer[offset++] = c1 & 63 | 128;
}
}
return offset - start;
}, "utf8_write");
}, {}], 11: [function(require2, module2, exports) {
module2.exports = common;
var commonRe = /\/|\./;
function common(name, json) {
if (!commonRe.test(name)) {
name = "google/protobuf/" + name + ".proto";
json = { nested: { google: { nested: { protobuf: { nested: json } } } } };
}
common[name] = json;
}
__name(common, "common");
common("any", {
/**
* Properties of a google.protobuf.Any message.
* @interface IAny
* @type {Object}
* @property {string} [typeUrl]
* @property {Uint8Array} [bytes]
* @memberof common
*/
Any: {
fields: {
type_url: {
type: "string",
id: 1
},
value: {
type: "bytes",
id: 2
}
}
}
});
var timeType;
common("duration", {
/**
* Properties of a google.protobuf.Duration message.
* @interface IDuration
* @type {Object}
* @property {number|Long} [seconds]
* @property {number} [nanos]
* @memberof common
*/
Duration: timeType = {
fields: {
seconds: {
type: "int64",
id: 1
},
nanos: {
type: "int32",
id: 2
}
}
}
});
common("timestamp", {
/**
* Properties of a google.protobuf.Timestamp message.
* @interface ITimestamp
* @type {Object}
* @property {number|Long} [seconds]
* @property {number} [nanos]
* @memberof common
*/
Timestamp: timeType
});
common("empty", {
/**
* Properties of a google.protobuf.Empty message.
* @interface IEmpty
* @memberof common
*/
Empty: {
fields: {}
}
});
common("struct", {
/**
* Properties of a google.protobuf.Struct message.
* @interface IStruct
* @type {Object}
* @property {Object.<string,IValue>} [fields]
* @memberof common
*/
Struct: {
fields: {
fields: {
keyType: "string",
type: "Value",
id: 1
}
}
},
/**
* Properties of a google.protobuf.Value message.
* @interface IValue
* @type {Object}
* @property {string} [kind]
* @property {0} [nullValue]
* @property {number} [numberValue]
* @property {string} [stringValue]
* @property {boolean} [boolValue]
* @property {IStruct} [structValue]
* @property {IListValue} [listValue]
* @memberof common
*/
Value: {
oneofs: {
kind: {
oneof: [
"nullValue",
"numberValue",
"stringValue",
"boolValue",
"structValue",
"listValue"
]
}
},
fields: {
nullValue: {
type: "NullValue",
id: 1
},
numberValue: {
type: "double",
id: 2
},
stringValue: {
type: "string",
id: 3
},
boolValue: {
type: "bool",
id: 4
},
structValue: {
type: "Struct",
id: 5
},
listValue: {
type: "ListValue",
id: 6
}
}
},
NullValue: {
values: {
NULL_VALUE: 0
}
},
/**
* Properties of a google.protobuf.ListValue message.
* @interface IListValue
* @type {Object}
* @property {Array.<IValue>} [values]
* @memberof common
*/
ListValue: {
fields: {
values: {
rule: "repeated",
type: "Value",
id: 1
}
}
}
});
common("wrappers", {
/**
* Properties of a google.protobuf.DoubleValue message.
* @interface IDoubleValue
* @type {Object}
* @property {number} [value]
* @memberof common
*/
DoubleValue: {
fields: {
value: {
type: "double",
id: 1
}
}
},
/**
* Properties of a google.protobuf.FloatValue message.
* @interface IFloatValue
* @type {Object}
* @property {number} [value]
* @memberof common
*/
FloatValue: {
fields: {
value: {
type: "float",
id: 1
}
}
},
/**
* Properties of a google.protobuf.Int64Value message.
* @interface IInt64Value
* @type {Object}
* @property {number|Long} [value]
* @memberof common
*/
Int64Value: {
fields: {
value: {
type: "int64",
id: 1
}
}
},
/**
* Properties of a google.protobuf.UInt64Value message.
* @interface IUInt64Value
* @type {Object}
* @property {number|Long} [value]
* @memberof common
*/
UInt64Value: {
fields: {
value: {
type: "uint64",
id: 1
}
}
},
/**
* Properties of a google.protobuf.Int32Value message.
* @interface IInt32Value
* @type {Object}
* @property {number} [value]
* @memberof common
*/
Int32Value: {
fields: {
value: {
type: "int32",
id: 1
}
}
},
/**
* Properties of a google.protobuf.UInt32Value message.
* @interface IUInt32Value
* @type {Object}
* @property {number} [value]
* @memberof common
*/
UInt32Value: {
fields: {
value: {
type: "uint32",
id: 1
}
}
},
/**
* Properties of a google.protobuf.BoolValue message.
* @interface IBoolValue
* @type {Object}
* @property {boolean} [value]
* @memberof common
*/
BoolValue: {
fields: {
value: {
type: "bool",
id: 1
}
}
},
/**
* Properties of a google.protobuf.StringValue message.
* @interface IStringValue
* @type {Object}
* @property {string} [value]
* @memberof common
*/
StringValue: {
fields: {
value: {
type: "string",
id: 1
}
}
},
/**
* Properties of a google.protobuf.BytesValue message.
* @interface IBytesValue
* @type {Object}
* @property {Uint8Array} [value]
* @memberof common
*/
BytesValue: {
fields: {
value: {
type: "bytes",
id: 1
}
}
}
});
common("field_mask", {
/**
* Properties of a google.protobuf.FieldMask message.
* @interface IDoubleValue
* @type {Object}
* @property {number} [value]
* @memberof common
*/
FieldMask: {
fields: {
paths: {
rule: "repeated",
type: "string",
id: 1
}
}
}
});
common.get = /* @__PURE__ */ __name(function get(file) {
return common[file] || null;
}, "get");
}, {}], 12: [function(require2, module2, exports) {
var converter = exports;
var Enum = require2(15), util = require2(37);
function genValuePartial_fromObject(gen, field, fieldIndex, prop) {
if (field.resolvedType) {
if (field.resolvedType instanceof Enum) {
gen("switch(d%s){", prop);
for (var values = field.resolvedType.values, keys = Object.keys(values), i = 0; i < keys.length; ++i) {
if (field.repeated && values[keys[i]] === field.typeDefault) gen("default:");
gen("case%j:", keys[i])("case %i:", values[keys[i]])("m%s=%j", prop, values[keys[i]])("break");
}
gen("}");
} else gen('if(typeof d%s!=="object")', prop)("throw TypeError(%j)", field.fullName + ": object expected")("m%s=types[%i].fromObject(d%s)", prop, fieldIndex, prop);
} else {
var isUnsigned = false;
switch (field.type) {
case "double":
case "float":
gen("m%s=Number(d%s)", prop, prop);
break;
case "uint32":
case "fixed32":
gen("m%s=d%s>>>0", prop, prop);
break;
case "int32":
case "sint32":
case "sfixed32":
gen("m%s=d%s|0", prop, prop);
break;
case "uint64":
isUnsigned = true;
// eslint-disable-line no-fallthrough
case "int64":
case "sint64":
case "fixed64":
case "sfixed64":
gen("if(util.Long)")("(m%s=util.Long.fromValue(d%s)).unsigned=%j", prop, prop, isUnsigned)('else if(typeof d%s==="string")', prop)("m%s=parseInt(d%s,10)", prop, prop)('else if(typeof d%s==="number")', prop)("m%s=d%s", prop, prop)('else if(typeof d%s==="object")', prop)("m%s=new util.LongBits(d%s.low>>>0,d%s.high>>>0).toNumber(%s)", prop, prop, prop, isUnsigned ? "true" : "");
break;
case "bytes":
gen('if(typeof d%s==="string")', prop)("util.base64.decode(d%s,m%s=util.newBuffer(util.base64.length(d%s)),0)", prop, prop, prop)("else if(d%s.length)", prop)("m%s=d%s", prop, prop);
break;
case "string":
gen("m%s=String(d%s)", prop, prop);
break;
case "bool":
gen("m%s=Boolean(d%s)", prop, prop);
break;
}
}
return gen;
}
__name(genValuePartial_fromObject, "genValuePartial_fromObject");
converter.fromObject = /* @__PURE__ */ __name(function fromObject(mtype) {
var fields = mtype.fieldsArray;
var gen = util.codegen(["d"], mtype.name + "$fromObject")("if(d instanceof this.ctor)")("return d");
if (!fields.length) return gen("return new this.ctor");
gen("var m=new this.ctor");
for (var i = 0; i < fields.length; ++i) {
var field = fields[i].resolve(), prop = util.safeProp(field.name);
if (field.map) {
gen("if(d%s){", prop)('if(typeof d%s!=="object")', prop)("throw TypeError(%j)", field.fullName + ": object expected")("m%s={}", prop)("for(var ks=Object.keys(d%s),i=0;i<ks.length;++i){", prop);
genValuePartial_fromObject(
gen,
field,
/* not sorted */
i,
prop + "[ks[i]]"
)("}")("}");
} else if (field.repeated) {
gen("if(d%s){", prop)("if(!Array.isArray(d%s))", prop)("throw TypeError(%j)", field.fullName + ": array expected")("m%s=[]", prop)("for(var i=0;i<d%s.length;++i){", prop);
genValuePartial_fromObject(
gen,
field,
/* not sorted */
i,
prop + "[i]"
)("}")("}");
} else {
if (!(field.resolvedType instanceof Enum)) gen("if(d%s!=null){", prop);
genValuePartial_fromObject(
gen,
field,
/* not sorted */
i,
prop
);
if (!(field.resolvedType instanceof Enum)) gen("}");
}
}
return gen("return m");
}, "fromObject");
function genValuePartial_toObject(gen, field, fieldIndex, prop) {
if (field.resolvedType) {
if (field.resolvedType instanceof Enum) gen("d%s=o.enums===String?types[%i].values[m%s]:m%s", prop, fieldIndex, prop, prop);
else gen("d%s=types[%i].toObject(m%s,o)", prop, fieldIndex, prop);
} else {
var isUnsigned = false;
switch (field.type) {
case "double":
case "float":
gen("d%s=o.json&&!isFinite(m%s)?String(m%s):m%s", prop, prop, prop, prop);
break;
case "uint64":
isUnsigned = true;
// eslint-disable-line no-fallthrough
case "int64":
case "sint64":
case "fixed64":
case "sfixed64":
gen('if(typeof m%s==="number")', prop)("d%s=o.longs===String?String(m%s):m%s", prop, prop, prop)("else")("d%s=o.longs===String?util.Long.prototype.toString.call(m%s):o.longs===Number?new util.LongBits(m%s.low>>>0,m%s.high>>>0).toNumber(%s):m%s", prop, prop, prop, prop, isUnsigned ? "true" : "", prop);
break;
case "bytes":
gen("d%s=o.bytes===String?util.base64.encode(m%s,0,m%s.length):o.bytes===Array?Array.prototype.slice.call(m%s):m%s", prop, prop, prop, prop, prop);
break;
default:
gen("d%s=m%s", prop, prop);
break;
}
}
return gen;
}
__name(genValuePartial_toObject, "genValuePartial_toObject");
converter.toObject = /* @__PURE__ */ __name(function toObject(mtype) {
var fields = mtype.fieldsArray.slice().sort(util.compareFieldsById);
if (!fields.length)
return util.codegen()("return {}");
var gen = util.codegen(["m", "o"], mtype.name + "$toObject")("if(!o)")("o={}")("var d={}");
var repeatedFields = [], mapFields = [], normalFields = [], i = 0;
for (; i < fields.length; ++i)
if (!fields[i].partOf)
(fields[i].resolve().repeated ? repeatedFields : fields[i].map ? mapFields : normalFields).push(fields[i]);
if (repeatedFields.length) {
gen("if(o.arrays||o.defaults){");
for (i = 0; i < repeatedFields.length; ++i) gen("d%s=[]", util.safeProp(repeatedFields[i].name));
gen("}");
}
if (mapFields.length) {
gen("if(o.objects||o.defaults){");
for (i = 0; i < mapFields.length; ++i) gen("d%s={}", util.safeProp(mapFields[i].name));
gen("}");
}
if (normalFields.length) {
gen("if(o.defaults){");
for (i = 0; i < normalFields.length; ++i) {
var field = normalFields[i], prop = util.safeProp(field.name);
if (field.resolvedType instanceof Enum) gen("d%s=o.enums===String?%j:%j", prop, field.resolvedType.valuesById[field.typeDefault], field.typeDefault);
else if (field.long) gen("if(util.Long){")("var n=new util.Long(%i,%i,%j)", field.typeDefault.low, field.typeDefault.high, field.typeDefault.unsigned)("d%s=o.longs===String?n.toString():o.longs===Number?n.toNumber():n", prop)("}else")("d%s=o.longs===String?%j:%i", prop, field.typeDefault.toString(), field.typeDefault.toNumber());
else if (field.bytes) gen("d%s=o.bytes===String?%j:%s", prop, String.fromCharCode.apply(String, field.typeDefault), "[" + Array.prototype.slice.call(field.typeDefault).join(",") + "]");
else gen("d%s=%j", prop, field.typeDefault);
}
gen("}");
}
var hasKs2 = false;
for (i = 0; i < fields.length; ++i) {
var field = fields[i], index = mtype._fieldsArray.indexOf(field), prop = util.safeProp(field.name);
if (field.map) {
if (!hasKs2) {
hasKs2 = true;
gen("var ks2");
}
gen("if(m%s&&(ks2=Object.keys(m%s)).length){", prop, prop)("d%s={}", prop)("for(var j=0;j<ks2.length;++j){");
genValuePartial_toObject(
gen,
field,
/* sorted */
index,
prop + "[ks2[j]]"
)("}");
} else if (field.repeated) {
gen("if(m%s&&m%s.length){", prop, prop)("d%s=[]", prop)("for(var j=0;j<m%s.length;++j){", prop);
genValuePartial_toObject(
gen,
field,
/* sorted */
index,
prop + "[j]"
)("}");
} else {
gen("if(m%s!=null&&m.hasOwnProperty(%j)){", prop, field.name);
genValuePartial_toObject(
gen,
field,
/* sorted */
index,
prop
);
if (field.partOf) gen("if(o.oneofs)")("d%s=%j", util.safeProp(field.partOf.name), field.name);
}
gen("}");
}
return gen("return d");
}, "toObject");
}, { "15": 15, "37": 37 }], 13: [function(require2, module2, exports) {
module2.exports = decoder;
var Enum = require2(15), types = require2(36), util = require2(37);
function missing(field) {
return "missing required '" + field.name + "'";
}
__name(missing, "missing");
function decoder(mtype) {
var gen = util.codegen(["r", "l"], mtype.name + "$decode")("if(!(r instanceof Reader))")("r=Reader.create(r)")("var c=l===undefined?r.len:r.pos+l,m=new this.ctor" + (mtype.fieldsArray.filter(function(field2) {
return field2.map;
}).length ? ",k" : ""))("while(r.pos<c){")("var t=r.uint32()");
if (mtype.group) gen("if((t&7)===4)")("break");
gen("switch(t>>>3){");
var i = 0;
for (; i < /* initializes */
mtype.fieldsArray.length; ++i) {
var field = mtype._fieldsArray[i].resolve(), type = field.resolvedType instanceof Enum ? "int32" : field.type, ref = "m" + util.safeProp(field.name);
gen("case %i:", field.id);
if (field.map) {
gen("r.skip().pos++")("if(%s===util.emptyObject)", ref)("%s={}", ref)("k=r.%s()", field.keyType)("r.pos++");
if (types.long[field.keyType] !== undefined$1) {
if (types.basic[type] === undefined$1) gen('%s[typeof k==="object"?util.longToHash(k):k]=types[%i].decode(r,r.uint32())', ref, i);
else gen('%s[typeof k==="object"?util.longToHash(k):k]=r.%s()', ref, type);
} else {
if (types.basic[type] === undefined$1) gen("%s[k]=types[%i].decode(r,r.uint32())", ref, i);
else gen("%s[k]=r.%s()", ref, type);
}
} else if (field.repeated) {
gen("if(!(%s&&%s.length))", ref, ref)("%s=[]", ref);
if (types.packed[type] !== undefined$1) gen("if((t&7)===2){")("var c2=r.uint32()+r.pos")("while(r.pos<c2)")("%s.push(r.%s())", ref, type)("}else");
if (types.basic[type] === undefined$1) gen(field.resolvedType.group ? "%s.push(types[%i].decode(r))" : "%s.push(types[%i].decode(r,r.uint32()))", ref, i);
else gen("%s.push(r.%s())", ref, type);
} else if (types.basic[type] === undefined$1) gen(field.resolvedType.group ? "%s=types[%i].decode(r)" : "%s=types[%i].decode(r,r.uint32())", ref, i);
else gen("%s=r.%s()", ref, type);
gen("break");
}
gen("default:")("r.skipType(t&7)")("break")("}")("}");
for (i = 0; i < mtype._fieldsArray.length; ++i) {
var rfield = mtype._fieldsArray[i];
if (rfield.required) gen("if(!m.hasOwnProperty(%j))", rfield.name)("throw util.ProtocolError(%j,{instance:m})", missing(rfield));
}
return gen("return m");
}
__name(decoder, "decoder");
}, { "15": 15, "36": 36, "37": 37 }], 14: [function(require2, module2, exports) {
module2.exports = encoder;
var Enum = require2(15), types = require2(36), util = require2(37);
function genTypePartial(gen, field, fieldIndex, ref) {
return field.resolvedType.group ? gen("types[%i].encode(%s,w.uint32(%i)).uint32(%i)", fieldIndex, ref, (field.id << 3 | 3) >>> 0, (field.id << 3 | 4) >>> 0) : gen("types[%i].encode(%s,w.uint32(%i).fork()).ldelim()", fieldIndex, ref, (field.id << 3 | 2) >>> 0);
}
__name(genTypePartial, "genTypePartial");
function encoder(mtype) {
var gen = util.codegen(["m", "w"], mtype.name + "$encode")("if(!w)")("w=Writer.create()");
var i, ref;
var fields = (
/* initializes */
mtype.fieldsArray.slice().sort(util.compareFieldsById)
);
for (var i = 0; i < fields.length; ++i) {
var field = fields[i].resolve(), index = mtype._fieldsArray.indexOf(field), type = field.resolvedType instanceof Enum ? "int32" : field.type, wireType = types.basic[type];
ref = "m" + util.safeProp(field.name);
if (field.map) {
gen("if(%s!=null&&m.hasOwnProperty(%j)){", ref, field.name)("for(var ks=Object.keys(%s),i=0;i<ks.length;++i){", ref)("w.uint32(%i).fork().uint32(%i).%s(ks[i])", (field.id << 3 | 2) >>> 0, 8 | types.mapKey[field.keyType], field.keyType);
if (wireType === undefined$1) gen("types[%i].encode(%s[ks[i]],w.uint32(18).fork()).ldelim().ldelim()", index, ref);
else gen(".uint32(%i).%s(%s[ks[i]]).ldelim()", 16 | wireType, type, ref);
gen("}")("}");
} else if (field.repeated) {
gen("if(%s!=null&&%s.length){", ref, ref);
if (field.packed && types.packed[type] !== undefined$1) {
gen("w.uint32(%i).fork()", (field.id << 3 | 2) >>> 0)("for(var i=0;i<%s.length;++i)", ref)("w.%s(%s[i])", type, ref)("w.ldelim()");
} else {
gen("for(var i=0;i<%s.length;++i)", ref);
if (wireType === undefined$1)
genTypePartial(gen, field, index, ref + "[i]");
else gen("w.uint32(%i).%s(%s[i])", (field.id << 3 | wireType) >>> 0, type, ref);
}
gen("}");
} else {
if (field.optional) gen("if(%s!=null&&m.hasOwnProperty(%j))", ref, field.name);
if (wireType === undefined$1)
genTypePartial(gen, field, index, ref);
else gen("w.uint32(%i).%s(%s)", (field.id << 3 | wireType) >>> 0, type, ref);
}
}
return gen("return w");
}
__name(encoder, "encoder");
}, { "15": 15, "36": 36, "37": 37 }], 15: [function(require2, module2, exports) {
module2.exports = Enum;
var ReflectionObject = require2(24);
((Enum.prototype = Object.create(ReflectionObject.prototype)).constructor = Enum).className = "Enum";
var Namespace = require2(23), util = require2(37);
function Enum(name, values, options, comment, comments) {
ReflectionObject.call(this, name, options);
if (values && typeof values !== "object")
throw TypeError("values must be an object");
this.valuesById = {};
this.values = Object.create(this.valuesById);
this.comment = comment;
this.comments = comments || {};
this.reserved = undefined$1;
if (values) {
for (var keys = Object.keys(values), i = 0; i < keys.length; ++i)
if (typeof values[keys[i]] === "number")
this.valuesById[this.values[keys[i]] = values[keys[i]]] = keys[i];
}
}
__name(Enum, "Enum");
Enum.fromJSON = /* @__PURE__ */ __name(function fromJSON(name, json) {
var enm = new Enum(name, json.values, json.options, json.comment, json.comments);
enm.reserved = json.reserved;
return enm;
}, "fromJSON");
Enum.prototype.toJSON = /* @__PURE__ */ __name(function toJSON(toJSONOptions) {
var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
return util.toObject([
"options",
this.options,
"values",
this.values,
"reserved",
this.reserved && this.reserved.length ? this.reserved : undefined$1,
"comment",
keepComments ? this.comment : undefined$1,
"comments",
keepComments ? this.comments : undefined$1
]);
}, "toJSON");
Enum.prototype.add = /* @__PURE__ */ __name(function add(name, id, comment) {
if (!util.isString(name))
throw TypeError("name must be a string");
if (!util.isInteger(id))
throw TypeError("id must be an integer");
if (this.values[name] !== undefined$1)
throw Error("duplicate name '" + name + "' in " + this);
if (this.isReservedId(id))
throw Error("id " + id + " is reserved in " + this);
if (this.isReservedName(name))
throw Error("name '" + name + "' is reserved in " + this);
if (this.valuesById[id] !== undefined$1) {
if (!(this.options && this.options.allow_alias))
throw Error("duplicate id " + id + " in " + this);
this.values[name] = id;
} else
this.valuesById[this.values[name] = id] = name;
this.comments[name] = comment || null;
return this;
}, "add");
Enum.prototype.remove = /* @__PURE__ */ __name(function remove(name) {
if (!util.isString(name))
throw TypeError("name must be a string");
var val = this.values[name];
if (val == null)
throw Error("name '" + name + "' does not exist in " + this);
delete this.valuesById[val];
delete this.values[name];
delete this.comments[name];
return this;
}, "remove");
Enum.prototype.isReservedId = /* @__PURE__ */ __name(function isReservedId(id) {
return Namespace.isReservedId(this.reserved, id);
}, "isReservedId");
Enum.prototype.isReservedName = /* @__PURE__ */ __name(function isReservedName(name) {
return Namespace.isReservedName(this.reserved, name);
}, "isReservedName");
}, { "23": 23, "24": 24, "37": 37 }], 16: [function(require2, module2, exports) {
module2.exports = Field;
var ReflectionObject = require2(24);
((Field.prototype = Object.create(ReflectionObject.prototype)).constructor = Field).className = "Field";
var Enum = require2(15), types = require2(36), util = require2(37);
var Type;
var ruleRe = /^required|optional|repeated$/;
Field.fromJSON = /* @__PURE__ */ __name(function fromJSON(name, json) {
return new Field(name, json.id, json.type, json.rule, json.extend, json.options, json.comment);
}, "fromJSON");
function Field(name, id, type, rule, extend, options, comment) {
if (util.isObject(rule)) {
comment = extend;
options = rule;
rule = extend = undefined$1;
} else if (util.isObject(extend)) {
comment = options;
options = extend;
extend = undefined$1;
}
ReflectionObject.call(this, name, options);
if (!util.isInteger(id) || id < 0)
throw TypeError("id must be a non-negative integer");
if (!util.isString(type))
throw TypeError("type must be a string");
if (rule !== undefined$1 && !ruleRe.test(rule = rule.toString().toLowerCase()))
throw TypeError("rule must be a string rule");
if (extend !== undefined$1 && !util.isString(extend))
throw TypeError("extend must be a string");
this.rule = rule && rule !== "optional" ? rule : undefined$1;
this.type = type;
this.id = id;
this.extend = extend || undefined$1;
this.required = rule === "required";
this.optional = !this.required;
this.repeated = rule === "repeated";
this.map = false;
this.message = null;
this.partOf = null;
this.typeDefault = null;
this.defaultValue = null;
this.long = util.Long ? types.long[type] !== undefined$1 : (
/* istanbul ignore next */
false
);
this.bytes = type === "bytes";
this.resolvedType = null;
this.extensionField = null;
this.declaringField = null;
this._packed = null;
this.comment = comment;
}
__name(Field, "Field");
Object.defineProperty(Field.prototype, "packed", {
get: /* @__PURE__ */ __name(function() {
if (this._packed === null)
this._packed = this.getOption("packed") !== false;
return this._packed;
}, "get")
});
Field.prototype.setOption = /* @__PURE__ */ __name(function setOption(name, value, ifNotSet) {
if (name === "packed")
this._packed = null;
return ReflectionObject.prototype.setOption.call(this, name, value, ifNotSet);
}, "setOption");
Field.prototype.toJSON = /* @__PURE__ */ __name(function toJSON(toJSONOptions) {
var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
return util.toObject([
"rule",
this.rule !== "optional" && this.rule || undefined$1,
"type",
this.type,
"id",
this.id,
"extend",
this.extend,
"options",
this.options,
"comment",
keepComments ? this.comment : undefined$1
]);
}, "toJSON");
Field.prototype.resolve = /* @__PURE__ */ __name(function resolve() {
if (this.resolved)
return this;
if ((this.typeDefault = types.defaults[this.type]) === undefined$1) {
this.resolvedType = (this.declaringField ? this.declaringField.parent : this.parent).lookupTypeOrEnum(this.type);
if (this.resolvedType instanceof Type)
this.typeDefault = null;
else
this.typeDefault = this.resolvedType.values[Object.keys(this.resolvedType.values)[0]];
}
if (this.options && this.options["default"] != null) {
this.typeDefault = this.options["default"];
if (this.resolvedType instanceof Enum && typeof this.typeDefault === "string")
this.typeDefault = this.resolvedType.values[this.typeDefault];
}
if (this.options) {
if (this.options.packed === true || this.options.packed !== undefined$1 && this.resolvedType && !(this.resolvedType instanceof Enum))
delete this.options.packed;
if (!Object.keys(this.options).length)
this.options = undefined$1;
}
if (this.long) {
this.typeDefault = util.Long.fromNumber(this.typeDefault, this.type.charAt(0) === "u");
if (Object.freeze)
Object.freeze(this.typeDefault);
} else if (this.bytes && typeof this.typeDefault === "string") {
var buf;
if (util.base64.test(this.typeDefault))
util.base64.decode(this.typeDefault, buf = util.newBuffer(util.base64.length(this.typeDefault)), 0);
else
util.utf8.write(this.typeDefault, buf = util.newBuffer(util.utf8.length(this.typeDefault)), 0);
this.typeDefault = buf;
}
if (this.map)
this.defaultValue = util.emptyObject;
else if (this.repeated)
this.defaultValue = util.emptyArray;
else
this.defaultValue = this.typeDefault;
if (this.parent instanceof Type)
this.parent.ctor.prototype[this.name] = this.defaultValue;
return ReflectionObject.prototype.resolve.call(this);
}, "resolve");
Field.d = /* @__PURE__ */ __name(function decorateField(fieldId, fieldType, fieldRule, defaultValue) {
if (typeof fieldType === "function")
fieldType = util.decorateType(fieldType).name;
else if (fieldType && typeof fieldType === "object")
fieldType = util.decorateEnum(fieldType).name;
return /* @__PURE__ */ __name(function fieldDecorator(prototype, fieldName) {
util.decorateType(prototype.constructor).add(new Field(fieldName, fieldId, fieldType, fieldRule, { "default": defaultValue }));
}, "fieldDecorator");
}, "decorateField");
Field._configure = /* @__PURE__ */ __name(function configure(Type_) {
Type = Type_;
}, "configure");
}, { "15": 15, "24": 24, "36": 36, "37": 37 }], 17: [function(require2, module2, exports) {
var protobuf = module2.exports = require2(18);
protobuf.build = "light";
function load(filename, root, callback) {
if (typeof root === "function") {
callback = root;
root = new protobuf.Root();
} else if (!root)
root = new protobuf.Root();
return root.load(filename, callback);
}
__name(load, "load");
protobuf.load = load;
function loadSync(filename, root) {
if (!root)
root = new protobuf.Root();
return root.loadSync(filename);
}
__name(loadSync, "loadSync");
protobuf.loadSync = loadSync;
protobuf.encoder = require2(14);
protobuf.decoder = require2(13);
protobuf.verifier = require2(40);
protobuf.converter = require2(12);
protobuf.ReflectionObject = require2(24);
protobuf.Namespace = require2(23);
protobuf.Root = require2(29);
protobuf.Enum = require2(15);
protobuf.Type = require2(35);
protobuf.Field = require2(16);
protobuf.OneOf = require2(25);
protobuf.MapField = require2(20);
protobuf.Service = require2(33);
protobuf.Method = require2(22);
protobuf.Message = require2(21);
protobuf.wrappers = require2(41);
protobuf.types = require2(36);
protobuf.util = require2(37);
protobuf.ReflectionObject._configure(protobuf.Root);
protobuf.Namespace._configure(protobuf.Type, protobuf.Service);
protobuf.Root._configure(protobuf.Type);
protobuf.Field._configure(protobuf.Type);
}, { "12": 12, "13": 13, "14": 14, "15": 15, "16": 16, "18": 18, "20": 20, "21": 21, "22": 22, "23": 23, "24": 24, "25": 25, "29": 29, "33": 33, "35": 35, "36": 36, "37": 37, "40": 40, "41": 41 }], 18: [function(require2, module2, exports) {
var protobuf = exports;
protobuf.build = "minimal";
protobuf.Writer = require2(42);
protobuf.BufferWriter = require2(43);
protobuf.Reader = require2(27);
protobuf.BufferReader = require2(28);
protobuf.util = require2(39);
protobuf.rpc = require2(31);
protobuf.roots = require2(30);
protobuf.configure = configure;
function configure() {
protobuf.Reader._configure(protobuf.BufferReader);
protobuf.util._configure();
}
__name(configure, "configure");
protobuf.Writer._configure(protobuf.BufferWriter);
configure();
}, { "27": 27, "28": 28, "30": 30, "31": 31, "39": 39, "42": 42, "43": 43 }], 19: [function(require2, module2, exports) {
var protobuf = module2.exports = require2(17);
protobuf.build = "full";
protobuf.tokenize = require2(34);
protobuf.parse = require2(26);
protobuf.common = require2(11);
protobuf.Root._configure(protobuf.Type, protobuf.parse, protobuf.common);
}, { "11": 11, "17": 17, "26": 26, "34": 34 }], 20: [function(require2, module2, exports) {
module2.exports = MapField;
var Field = require2(16);
((MapField.prototype = Object.create(Field.prototype)).constructor = MapField).className = "MapField";
var types = require2(36), util = require2(37);
function MapField(name, id, keyType, type, options, comment) {
Field.call(this, name, id, type, undefined$1, undefined$1, options, comment);
if (!util.isString(keyType))
throw TypeError("keyType must be a string");
this.keyType = keyType;
this.resolvedKeyType = null;
this.map = true;
}
__name(MapField, "MapField");
MapField.fromJSON = /* @__PURE__ */ __name(function fromJSON(name, json) {
return new MapField(name, json.id, json.keyType, json.type, json.options, json.comment);
}, "fromJSON");
MapField.prototype.toJSON = /* @__PURE__ */ __name(function toJSON(toJSONOptions) {
var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
return util.toObject([
"keyType",
this.keyType,
"type",
this.type,
"id",
this.id,
"extend",
this.extend,
"options",
this.options,
"comment",
keepComments ? this.comment : undefined$1
]);
}, "toJSON");
MapField.prototype.resolve = /* @__PURE__ */ __name(function resolve() {
if (this.resolved)
return this;
if (types.mapKey[this.keyType] === undefined$1)
throw Error("invalid key type: " + this.keyType);
return Field.prototype.resolve.call(this);
}, "resolve");
MapField.d = /* @__PURE__ */ __name(function decorateMapField(fieldId, fieldKeyType, fieldValueType) {
if (typeof fieldValueType === "function")
fieldValueType = util.decorateType(fieldValueType).name;
else if (fieldValueType && typeof fieldValueType === "object")
fieldValueType = util.decorateEnum(fieldValueType).name;
return /* @__PURE__ */ __name(function mapFieldDecorator(prototype, fieldName) {
util.decorateType(prototype.constructor).add(new MapField(fieldName, fieldId, fieldKeyType, fieldValueType));
}, "mapFieldDecorator");
}, "decorateMapField");
}, { "16": 16, "36": 36, "37": 37 }], 21: [function(require2, module2, exports) {
module2.exports = Message;
var util = require2(39);
function Message(properties) {
if (properties)
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
this[keys[i]] = properties[keys[i]];
}
__name(Message, "Message");
Message.create = /* @__PURE__ */ __name(function create(properties) {
return this.$type.create(properties);
}, "create");
Message.encode = /* @__PURE__ */ __name(function encode(message, writer) {
return this.$type.encode(message, writer);
}, "encode");
Message.encodeDelimited = /* @__PURE__ */ __name(function encodeDelimited(message, writer) {
return this.$type.encodeDelimited(message, writer);
}, "encodeDelimited");
Message.decode = /* @__PURE__ */ __name(function decode(reader) {
return this.$type.decode(reader);
}, "decode");
Message.decodeDelimited = /* @__PURE__ */ __name(function decodeDelimited(reader) {
return this.$type.decodeDelimited(reader);
}, "decodeDelimited");
Message.verify = /* @__PURE__ */ __name(function verify(message) {
return this.$type.verify(message);
}, "verify");
Message.fromObject = /* @__PURE__ */ __name(function fromObject(object) {
return this.$type.fromObject(object);
}, "fromObject");
Message.toObject = /* @__PURE__ */ __name(function toObject(message, options) {
return this.$type.toObject(message, options);
}, "toObject");
Message.prototype.toJSON = /* @__PURE__ */ __name(function toJSON() {
return this.$type.toObject(this, util.toJSONOptions);
}, "toJSON");
}, { "39": 39 }], 22: [function(require2, module2, exports) {
module2.exports = Method;
var ReflectionObject = require2(24);
((Method.prototype = Object.create(ReflectionObject.prototype)).constructor = Method).className = "Method";
var util = require2(37);
function Method(name, type, requestType, responseType, requestStream, responseStream, options, comment) {
if (util.isObject(requestStream)) {
options = requestStream;
requestStream = responseStream = undefined$1;
} else if (util.isObject(responseStream)) {
options = responseStream;
responseStream = undefined$1;
}
if (!(type === undefined$1 || util.isString(type)))
throw TypeError("type must be a string");
if (!util.isString(requestType))
throw TypeError("requestType must be a string");
if (!util.isString(responseType))
throw TypeError("responseType must be a string");
ReflectionObject.call(this, name, options);
this.type = type || "rpc";
this.requestType = requestType;
this.requestStream = requestStream ? true : undefined$1;
this.responseType = responseType;
this.responseStream = responseStream ? true : undefined$1;
this.resolvedRequestType = null;
this.resolvedResponseType = null;
this.comment = comment;
}
__name(Method, "Method");
Method.fromJSON = /* @__PURE__ */ __name(function fromJSON(name, json) {
return new Method(name, json.type, json.requestType, json.responseType, json.requestStream, json.responseStream, json.options, json.comment);
}, "fromJSON");
Method.prototype.toJSON = /* @__PURE__ */ __name(function toJSON(toJSONOptions) {
var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
return util.toObject([
"type",
this.type !== "rpc" && /* istanbul ignore next */
this.type || undefined$1,
"requestType",
this.requestType,
"requestStream",
this.requestStream,
"responseType",
this.responseType,
"responseStream",
this.responseStream,
"options",
this.options,
"comment",
keepComments ? this.comment : undefined$1
]);
}, "toJSON");
Method.prototype.resolve = /* @__PURE__ */ __name(function resolve() {
if (this.resolved)
return this;
this.resolvedRequestType = this.parent.lookupType(this.requestType);
this.resolvedResponseType = this.parent.lookupType(this.responseType);
return ReflectionObject.prototype.resolve.call(this);
}, "resolve");
}, { "24": 24, "37": 37 }], 23: [function(require2, module2, exports) {
module2.exports = Namespace;
var ReflectionObject = require2(24);
((Namespace.prototype = Object.create(ReflectionObject.prototype)).constructor = Namespace).className = "Namespace";
var Enum = require2(15), Field = require2(16), util = require2(37);
var Type, Service;
Namespace.fromJSON = /* @__PURE__ */ __name(function fromJSON(name, json) {
return new Namespace(name, json.options).addJSON(json.nested);
}, "fromJSON");
function arrayToJSON(array, toJSONOptions) {
if (!(array && array.length))
return undefined$1;
var obj = {};
for (var i = 0; i < array.length; ++i)
obj[array[i].name] = array[i].toJSON(toJSONOptions);
return obj;
}
__name(arrayToJSON, "arrayToJSON");
Namespace.arrayToJSON = arrayToJSON;
Namespace.isReservedId = /* @__PURE__ */ __name(function isReservedId(reserved, id) {
if (reserved) {
for (var i = 0; i < reserved.length; ++i)
if (typeof reserved[i] !== "string" && reserved[i][0] <= id && reserved[i][1] >= id)
return true;
}
return false;
}, "isReservedId");
Namespace.isReservedName = /* @__PURE__ */ __name(function isReservedName(reserved, name) {
if (reserved) {
for (var i = 0; i < reserved.length; ++i)
if (reserved[i] === name)
return true;
}
return false;
}, "isReservedName");
function Namespace(name, options) {
ReflectionObject.call(this, name, options);
this.nested = undefined$1;
this._nestedArray = null;
}
__name(Namespace, "Namespace");
function clearCache(namespace) {
namespace._nestedArray = null;
return namespace;
}
__name(clearCache, "clearCache");
Object.defineProperty(Namespace.prototype, "nestedArray", {
get: /* @__PURE__ */ __name(function() {
return this._nestedArray || (this._nestedArray = util.toArray(this.nested));
}, "get")
});
Namespace.prototype.toJSON = /* @__PURE__ */ __name(function toJSON(toJSONOptions) {
return util.toObject([
"options",
this.options,
"nested",
arrayToJSON(this.nestedArray, toJSONOptions)
]);
}, "toJSON");
Namespace.prototype.addJSON = /* @__PURE__ */ __name(function addJSON(nestedJson) {
var ns = this;
if (nestedJson) {
for (var names = Object.keys(nestedJson), i = 0, nested; i < names.length; ++i) {
nested = nestedJson[names[i]];
ns.add(
// most to least likely
(nested.fields !== undefined$1 ? Type.fromJSON : nested.values !== undefined$1 ? Enum.fromJSON : nested.methods !== undefined$1 ? Service.fromJSON : nested.id !== undefined$1 ? Field.fromJSON : Namespace.fromJSON)(names[i], nested)
);
}
}
return this;
}, "addJSON");
Namespace.prototype.get = /* @__PURE__ */ __name(function get(name) {
return this.nested && this.nested[name] || null;
}, "get");
Namespace.prototype.getEnum = /* @__PURE__ */ __name(function getEnum(name) {
if (this.nested && this.nested[name] instanceof Enum)
return this.nested[name].values;
throw Error("no such enum: " + name);
}, "getEnum");
Namespace.prototype.add = /* @__PURE__ */ __name(function add(object) {
if (!(object instanceof Field && object.extend !== undefined$1 || object instanceof Type || object instanceof Enum || object instanceof Service || object instanceof Namespace))
throw TypeError("object must be a valid nested object");
if (!this.nested)
this.nested = {};
else {
var prev = this.get(object.name);
if (prev) {
if (prev instanceof Namespace && object instanceof Namespace && !(prev instanceof Type || prev instanceof Service)) {
var nested = prev.nestedArray;
for (var i = 0; i < nested.length; ++i)
object.add(nested[i]);
this.remove(prev);
if (!this.nested)
this.nested = {};
object.setOptions(prev.options, true);
} else
throw Error("duplicate name '" + object.name + "' in " + this);
}
}
this.nested[object.name] = object;
object.onAdd(this);
return clearCache(this);
}, "add");
Namespace.prototype.remove = /* @__PURE__ */ __name(function remove(object) {
if (!(object instanceof ReflectionObject))
throw TypeError("object must be a ReflectionObject");
if (object.parent !== this)
throw Error(object + " is not a member of " + this);
delete this.nested[object.name];
if (!Object.keys(this.nested).length)
this.nested = undefined$1;
object.onRemove(this);
return clearCache(this);
}, "remove");
Namespace.prototype.define = /* @__PURE__ */ __name(function define(path, json) {
if (util.isString(path))
path = path.split(".");
else if (!Array.isArray(path))
throw TypeError("illegal path");
if (path && path.length && path[0] === "")
throw Error("path must be relative");
var ptr = this;
while (path.length > 0) {
var part = path.shift();
if (ptr.nested && ptr.nested[part]) {
ptr = ptr.nested[part];
if (!(ptr instanceof Namespace))
throw Error("path conflicts with non-namespace objects");
} else
ptr.add(ptr = new Namespace(part));
}
if (json)
ptr.addJSON(json);
return ptr;
}, "define");
Namespace.prototype.resolveAll = /* @__PURE__ */ __name(function resolveAll() {
var nested = this.nestedArray, i = 0;
while (i < nested.length)
if (nested[i] instanceof Namespace)
nested[i++].resolveAll();
else
nested[i++].resolve();
return this.resolve();
}, "resolveAll");
Namespace.prototype.lookup = /* @__PURE__ */ __name(function lookup(path, filterTypes, parentAlreadyChecked) {
if (typeof filterTypes === "boolean") {
parentAlreadyChecked = filterTypes;
filterTypes = undefined$1;
} else if (filterTypes && !Array.isArray(filterTypes))
filterTypes = [filterTypes];
if (util.isString(path) && path.length) {
if (path === ".")
return this.root;
path = path.split(".");
} else if (!path.length)
return this;
if (path[0] === "")
return this.root.lookup(path.slice(1), filterTypes);
var found = this.get(path[0]);
if (found) {
if (path.length === 1) {
if (!filterTypes || filterTypes.indexOf(found.constructor) > -1)
return found;
} else if (found instanceof Namespace && (found = found.lookup(path.slice(1), filterTypes, true)))
return found;
} else
for (var i = 0; i < this.nestedArray.length; ++i)
if (this._nestedArray[i] instanceof Namespace && (found = this._nestedArray[i].lookup(path, filterTypes, true)))
return found;
if (this.parent === null || parentAlreadyChecked)
return null;
return this.parent.lookup(path, filterTypes);
}, "lookup");
Namespace.prototype.lookupType = /* @__PURE__ */ __name(function lookupType(path) {
var found = this.lookup(path, [Type]);
if (!found)
throw Error("no such type: " + path);
return found;
}, "lookupType");
Namespace.prototype.lookupEnum = /* @__PURE__ */ __name(function lookupEnum(path) {
var found = this.lookup(path, [Enum]);
if (!found)
throw Error("no such Enum '" + path + "' in " + this);
return found;
}, "lookupEnum");
Namespace.prototype.lookupTypeOrEnum = /* @__PURE__ */ __name(function lookupTypeOrEnum(path) {
var found = this.lookup(path, [Type, Enum]);
if (!found)
throw Error("no such Type or Enum '" + path + "' in " + this);
return found;
}, "lookupTypeOrEnum");
Namespace.prototype.lookupService = /* @__PURE__ */ __name(function lookupService(path) {
var found = this.lookup(path, [Service]);
if (!found)
throw Error("no such Service '" + path + "' in " + this);
return found;
}, "lookupService");
Namespace._configure = function(Type_, Service_) {
Type = Type_;
Service = Service_;
};
}, { "15": 15, "16": 16, "24": 24, "37": 37 }], 24: [function(require2, module2, exports) {
module2.exports = ReflectionObject;
ReflectionObject.className = "ReflectionObject";
var util = require2(37);
var Root;
function ReflectionObject(name, options) {
if (!util.isString(name))
throw TypeError("name must be a string");
if (options && !util.isObject(options))
throw TypeError("options must be an object");
this.options = options;
this.name = name;
this.parent = null;
this.resolved = false;
this.comment = null;
this.filename = null;
}
__name(ReflectionObject, "ReflectionObject");
Object.defineProperties(ReflectionObject.prototype, {
/**
* Reference to the root namespace.
* @name ReflectionObject#root
* @type {Root}
* @readonly
*/
root: {
get: /* @__PURE__ */ __name(function() {
var ptr = this;
while (ptr.parent !== null)
ptr = ptr.parent;
return ptr;
}, "get")
},
/**
* Full name including leading dot.
* @name ReflectionObject#fullName
* @type {string}
* @readonly
*/
fullName: {
get: /* @__PURE__ */ __name(function() {
var path = [this.name], ptr = this.parent;
while (ptr) {
path.unshift(ptr.name);
ptr = ptr.parent;
}
return path.join(".");
}, "get")
}
});
ReflectionObject.prototype.toJSON = /* istanbul ignore next */
/* @__PURE__ */ __name(function toJSON() {
throw Error();
}, "toJSON");
ReflectionObject.prototype.onAdd = /* @__PURE__ */ __name(function onAdd(parent) {
if (this.parent && this.parent !== parent)
this.parent.remove(this);
this.parent = parent;
this.resolved = false;
var root = parent.root;
if (root instanceof Root)
root._handleAdd(this);
}, "onAdd");
ReflectionObject.prototype.onRemove = /* @__PURE__ */ __name(function onRemove(parent) {
var root = parent.root;
if (root instanceof Root)
root._handleRemove(this);
this.parent = null;
this.resolved = false;
}, "onRemove");
ReflectionObject.prototype.resolve = /* @__PURE__ */ __name(function resolve() {
if (this.resolved)
return this;
if (this.root instanceof Root)
this.resolved = true;
return this;
}, "resolve");
ReflectionObject.prototype.getOption = /* @__PURE__ */ __name(function getOption(name) {
if (this.options)
return this.options[name];
return undefined$1;
}, "getOption");
ReflectionObject.prototype.setOption = /* @__PURE__ */ __name(function setOption(name, value, ifNotSet) {
if (!ifNotSet || !this.options || this.options[name] === undefined$1)
(this.options || (this.options = {}))[name] = value;
return this;
}, "setOption");
ReflectionObject.prototype.setOptions = /* @__PURE__ */ __name(function setOptions(options, ifNotSet) {
if (options)
for (var keys = Object.keys(options), i = 0; i < keys.length; ++i)
this.setOption(keys[i], options[keys[i]], ifNotSet);
return this;
}, "setOptions");
ReflectionObject.prototype.toString = /* @__PURE__ */ __name(function toString() {
var className = this.constructor.className, fullName = this.fullName;
if (fullName.length)
return className + " " + fullName;
return className;
}, "toString");
ReflectionObject._configure = function(Root_) {
Root = Root_;
};
}, { "37": 37 }], 25: [function(require2, module2, exports) {
module2.exports = OneOf;
var ReflectionObject = require2(24);
((OneOf.prototype = Object.create(ReflectionObject.prototype)).constructor = OneOf).className = "OneOf";
var Field = require2(16), util = require2(37);
function OneOf(name, fieldNames, options, comment) {
if (!Array.isArray(fieldNames)) {
options = fieldNames;
fieldNames = undefined$1;
}
ReflectionObject.call(this, name, options);
if (!(fieldNames === undefined$1 || Array.isArray(fieldNames)))
throw TypeError("fieldNames must be an Array");
this.oneof = fieldNames || [];
this.fieldsArray = [];
this.comment = comment;
}
__name(OneOf, "OneOf");
OneOf.fromJSON = /* @__PURE__ */ __name(function fromJSON(name, json) {
return new OneOf(name, json.oneof, json.options, json.comment);
}, "fromJSON");
OneOf.prototype.toJSON = /* @__PURE__ */ __name(function toJSON(toJSONOptions) {
var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
return util.toObject([
"options",
this.options,
"oneof",
this.oneof,
"comment",
keepComments ? this.comment : undefined$1
]);
}, "toJSON");
function addFieldsToParent(oneof) {
if (oneof.parent) {
for (var i = 0; i < oneof.fieldsArray.length; ++i)
if (!oneof.fieldsArray[i].parent)
oneof.parent.add(oneof.fieldsArray[i]);
}
}
__name(addFieldsToParent, "addFieldsToParent");
OneOf.prototype.add = /* @__PURE__ */ __name(function add(field) {
if (!(field instanceof Field))
throw TypeError("field must be a Field");
if (field.parent && field.parent !== this.parent)
field.parent.remove(field);
this.oneof.push(field.name);
this.fieldsArray.push(field);
field.partOf = this;
addFieldsToParent(this);
return this;
}, "add");
OneOf.prototype.remove = /* @__PURE__ */ __name(function remove(field) {
if (!(field instanceof Field))
throw TypeError("field must be a Field");
var index = this.fieldsArray.indexOf(field);
if (index < 0)
throw Error(field + " is not a member of " + this);
this.fieldsArray.splice(index, 1);
index = this.oneof.indexOf(field.name);
if (index > -1)
this.oneof.splice(index, 1);
field.partOf = null;
return this;
}, "remove");
OneOf.prototype.onAdd = /* @__PURE__ */ __name(function onAdd(parent) {
ReflectionObject.prototype.onAdd.call(this, parent);
var self = this;
for (var i = 0; i < this.oneof.length; ++i) {
var field = parent.get(this.oneof[i]);
if (field && !field.partOf) {
field.partOf = self;
self.fieldsArray.push(field);
}
}
addFieldsToParent(this);
}, "onAdd");
OneOf.prototype.onRemove = /* @__PURE__ */ __name(function onRemove(parent) {
for (var i = 0, field; i < this.fieldsArray.length; ++i)
if ((field = this.fieldsArray[i]).parent)
field.parent.remove(field);
ReflectionObject.prototype.onRemove.call(this, parent);
}, "onRemove");
OneOf.d = /* @__PURE__ */ __name(function decorateOneOf() {
var fieldNames = new Array(arguments.length), index = 0;
while (index < arguments.length)
fieldNames[index] = arguments[index++];
return /* @__PURE__ */ __name(function oneOfDecorator(prototype, oneofName) {
util.decorateType(prototype.constructor).add(new OneOf(oneofName, fieldNames));
Object.defineProperty(prototype, oneofName, {
get: util.oneOfGetter(fieldNames),
set: util.oneOfSetter(fieldNames)
});
}, "oneOfDecorator");
}, "decorateOneOf");
}, { "16": 16, "24": 24, "37": 37 }], 26: [function(require2, module2, exports) {
module2.exports = parse;
parse.filename = null;
parse.defaults = { keepCase: false };
var tokenize = require2(34), Root = require2(29), Type = require2(35), Field = require2(16), MapField = require2(20), OneOf = require2(25), Enum = require2(15), Service = require2(33), Method = require2(22), types = require2(36), util = require2(37);
var base10Re = /^[1-9][0-9]*$/, base10NegRe = /^-?[1-9][0-9]*$/, base16Re = /^0[x][0-9a-fA-F]+$/, base16NegRe = /^-?0[x][0-9a-fA-F]+$/, base8Re = /^0[0-7]+$/, base8NegRe = /^-?0[0-7]+$/, numberRe = /^(?![eE])[0-9]*(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?$/, nameRe = /^[a-zA-Z_][a-zA-Z_0-9]*$/, typeRefRe = /^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*$/, fqTypeRefRe = /^(?:\.[a-zA-Z_][a-zA-Z_0-9]*)+$/;
function parse(source, root, options) {
if (!(root instanceof Root)) {
options = root;
root = new Root();
}
if (!options)
options = parse.defaults;
var tn = tokenize(source, options.alternateCommentMode || false), next = tn.next, push = tn.push, peek = tn.peek, skip = tn.skip, cmnt = tn.cmnt;
var head = true, pkg, imports, weakImports, syntax, isProto3 = false;
var ptr = root;
var applyCase = options.keepCase ? function(name) {
return name;
} : util.camelCase;
function illegal(token2, name, insideTryCatch) {
var filename = parse.filename;
if (!insideTryCatch)
parse.filename = null;
return Error("illegal " + (name || "token") + " '" + token2 + "' (" + (filename ? filename + ", " : "") + "line " + tn.line + ")");
}
__name(illegal, "illegal");
function readString() {
var values = [], token2;
do {
if ((token2 = next()) !== '"' && token2 !== "'")
throw illegal(token2);
values.push(next());
skip(token2);
token2 = peek();
} while (token2 === '"' || token2 === "'");
return values.join("");
}
__name(readString, "readString");
function readValue(acceptTypeRef) {
var token2 = next();
switch (token2) {
case "'":
case '"':
push(token2);
return readString();
case "true":
case "TRUE":
return true;
case "false":
case "FALSE":
return false;
}
try {
return parseNumber(
token2,
/* insideTryCatch */
true
);
} catch (e) {
if (acceptTypeRef && typeRefRe.test(token2))
return token2;
throw illegal(token2, "value");
}
}
__name(readValue, "readValue");
function readRanges(target, acceptStrings) {
var token2, start;
do {
if (acceptStrings && ((token2 = peek()) === '"' || token2 === "'"))
target.push(readString());
else
target.push([start = parseId(next()), skip("to", true) ? parseId(next()) : start]);
} while (skip(",", true));
skip(";");
}
__name(readRanges, "readRanges");
function parseNumber(token2, insideTryCatch) {
var sign = 1;
if (token2.charAt(0) === "-") {
sign = -1;
token2 = token2.substring(1);
}
switch (token2) {
case "inf":
case "INF":
case "Inf":
return sign * Infinity;
case "nan":
case "NAN":
case "Nan":
case "NaN":
return NaN;
case "0":
return 0;
}
if (base10Re.test(token2))
return sign * parseInt(token2, 10);
if (base16Re.test(token2))
return sign * parseInt(token2, 16);
if (base8Re.test(token2))
return sign * parseInt(token2, 8);
if (numberRe.test(token2))
return sign * parseFloat(token2);
throw illegal(token2, "number", insideTryCatch);
}
__name(parseNumber, "parseNumber");
function parseId(token2, acceptNegative) {
switch (token2) {
case "max":
case "MAX":
case "Max":
return 536870911;
case "0":
return 0;
}
if (!acceptNegative && token2.charAt(0) === "-")
throw illegal(token2, "id");
if (base10NegRe.test(token2))
return parseInt(token2, 10);
if (base16NegRe.test(token2))
return parseInt(token2, 16);
if (base8NegRe.test(token2))
return parseInt(token2, 8);
throw illegal(token2, "id");
}
__name(parseId, "parseId");
function parsePackage() {
if (pkg !== undefined$1)
throw illegal("package");
pkg = next();
if (!typeRefRe.test(pkg))
throw illegal(pkg, "name");
ptr = ptr.define(pkg);
skip(";");
}
__name(parsePackage, "parsePackage");
function parseImport() {
var token2 = peek();
var whichImports;
switch (token2) {
case "weak":
whichImports = weakImports || (weakImports = []);
next();
break;
case "public":
next();
// eslint-disable-line no-fallthrough
default:
whichImports = imports || (imports = []);
break;
}
token2 = readString();
skip(";");
whichImports.push(token2);
}
__name(parseImport, "parseImport");
function parseSyntax() {
skip("=");
syntax = readString();
isProto3 = syntax === "proto3";
if (!isProto3 && syntax !== "proto2")
throw illegal(syntax, "syntax");
skip(";");
}
__name(parseSyntax, "parseSyntax");
function parseCommon(parent, token2) {
switch (token2) {
case "option":
parseOption(parent, token2);
skip(";");
return true;
case "message":
parseType(parent, token2);
return true;
case "enum":
parseEnum(parent, token2);
return true;
case "service":
parseService(parent, token2);
return true;
case "extend":
parseExtension(parent, token2);
return true;
}
return false;
}
__name(parseCommon, "parseCommon");
function ifBlock(obj, fnIf, fnElse) {
var trailingLine = tn.line;
if (obj) {
obj.comment = cmnt();
obj.filename = parse.filename;
}
if (skip("{", true)) {
var token2;
while ((token2 = next()) !== "}")
fnIf(token2);
skip(";", true);
} else {
if (fnElse)
fnElse();
skip(";");
if (obj && typeof obj.comment !== "string")
obj.comment = cmnt(trailingLine);
}
}
__name(ifBlock, "ifBlock");
function parseType(parent, token2) {
if (!nameRe.test(token2 = next()))
throw illegal(token2, "type name");
var type = new Type(token2);
ifBlock(type, /* @__PURE__ */ __name(function parseType_block(token3) {
if (parseCommon(type, token3))
return;
switch (token3) {
case "map":
parseMapField(type);
break;
case "required":
case "optional":
case "repeated":
parseField(type, token3);
break;
case "oneof":
parseOneOf(type, token3);
break;
case "extensions":
readRanges(type.extensions || (type.extensions = []));
break;
case "reserved":
readRanges(type.reserved || (type.reserved = []), true);
break;
default:
if (!isProto3 || !typeRefRe.test(token3))
throw illegal(token3);
push(token3);
parseField(type, "optional");
break;
}
}, "parseType_block"));
parent.add(type);
}
__name(parseType, "parseType");
function parseField(parent, rule, extend) {
var type = next();
if (type === "group") {
parseGroup(parent, rule);
return;
}
if (!typeRefRe.test(type))
throw illegal(type, "type");
var name = next();
if (!nameRe.test(name))
throw illegal(name, "name");
name = applyCase(name);
skip("=");
var field = new Field(name, parseId(next()), type, rule, extend);
ifBlock(field, /* @__PURE__ */ __name(function parseField_block(token2) {
if (token2 === "option") {
parseOption(field, token2);
skip(";");
} else
throw illegal(token2);
}, "parseField_block"), /* @__PURE__ */ __name(function parseField_line() {
parseInlineOptions(field);
}, "parseField_line"));
parent.add(field);
if (!isProto3 && field.repeated && (types.packed[type] !== undefined$1 || types.basic[type] === undefined$1))
field.setOption(
"packed",
false,
/* ifNotSet */
true
);
}
__name(parseField, "parseField");
function parseGroup(parent, rule) {
var name = next();
if (!nameRe.test(name))
throw illegal(name, "name");
var fieldName = util.lcFirst(name);
if (name === fieldName)
name = util.ucFirst(name);
skip("=");
var id = parseId(next());
var type = new Type(name);
type.group = true;
var field = new Field(fieldName, id, name, rule);
field.filename = parse.filename;
ifBlock(type, /* @__PURE__ */ __name(function parseGroup_block(token2) {
switch (token2) {
case "option":
parseOption(type, token2);
skip(";");
break;
case "required":
case "optional":
case "repeated":
parseField(type, token2);
break;
/* istanbul ignore next */
default:
throw illegal(token2);
}
}, "parseGroup_block"));
parent.add(type).add(field);
}
__name(parseGroup, "parseGroup");
function parseMapField(parent) {
skip("<");
var keyType = next();
if (types.mapKey[keyType] === undefined$1)
throw illegal(keyType, "type");
skip(",");
var valueType = next();
if (!typeRefRe.test(valueType))
throw illegal(valueType, "type");
skip(">");
var name = next();
if (!nameRe.test(name))
throw illegal(name, "name");
skip("=");
var field = new MapField(applyCase(name), parseId(next()), keyType, valueType);
ifBlock(field, /* @__PURE__ */ __name(function parseMapField_block(token2) {
if (token2 === "option") {
parseOption(field, token2);
skip(";");
} else
throw illegal(token2);
}, "parseMapField_block"), /* @__PURE__ */ __name(function parseMapField_line() {
parseInlineOptions(field);
}, "parseMapField_line"));
parent.add(field);
}
__name(parseMapField, "parseMapField");
function parseOneOf(parent, token2) {
if (!nameRe.test(token2 = next()))
throw illegal(token2, "name");
var oneof = new OneOf(applyCase(token2));
ifBlock(oneof, /* @__PURE__ */ __name(function parseOneOf_block(token3) {
if (token3 === "option") {
parseOption(oneof, token3);
skip(";");
} else {
push(token3);
parseField(oneof, "optional");
}
}, "parseOneOf_block"));
parent.add(oneof);
}
__name(parseOneOf, "parseOneOf");
function parseEnum(parent, token2) {
if (!nameRe.test(token2 = next()))
throw illegal(token2, "name");
var enm = new Enum(token2);
ifBlock(enm, /* @__PURE__ */ __name(function parseEnum_block(token3) {
switch (token3) {
case "option":
parseOption(enm, token3);
skip(";");
break;
case "reserved":
readRanges(enm.reserved || (enm.reserved = []), true);
break;
default:
parseEnumValue(enm, token3);
}
}, "parseEnum_block"));
parent.add(enm);
}
__name(parseEnum, "parseEnum");
function parseEnumValue(parent, token2) {
if (!nameRe.test(token2))
throw illegal(token2, "name");
skip("=");
var value = parseId(next(), true), dummy = {};
ifBlock(dummy, /* @__PURE__ */ __name(function parseEnumValue_block(token3) {
if (token3 === "option") {
parseOption(dummy, token3);
skip(";");
} else
throw illegal(token3);
}, "parseEnumValue_block"), /* @__PURE__ */ __name(function parseEnumValue_line() {
parseInlineOptions(dummy);
}, "parseEnumValue_line"));
parent.add(token2, value, dummy.comment);
}
__name(parseEnumValue, "parseEnumValue");
function parseOption(parent, token2) {
var isCustom = skip("(", true);
if (!typeRefRe.test(token2 = next()))
throw illegal(token2, "name");
var name = token2;
if (isCustom) {
skip(")");
name = "(" + name + ")";
token2 = peek();
if (fqTypeRefRe.test(token2)) {
name += token2;
next();
}
}
skip("=");
parseOptionValue(parent, name);
}
__name(parseOption, "parseOption");
function parseOptionValue(parent, name) {
if (skip("{", true)) {
do {
if (!nameRe.test(token = next()))
throw illegal(token, "name");
if (peek() === "{")
parseOptionValue(parent, name + "." + token);
else {
skip(":");
if (peek() === "{")
parseOptionValue(parent, name + "." + token);
else
setOption(parent, name + "." + token, readValue(true));
}
} while (!skip("}", true));
} else
setOption(parent, name, readValue(true));
}
__name(parseOptionValue, "parseOptionValue");
function setOption(parent, name, value) {
if (parent.setOption)
parent.setOption(name, value);
}
__name(setOption, "setOption");
function parseInlineOptions(parent) {
if (skip("[", true)) {
do {
parseOption(parent, "option");
} while (skip(",", true));
skip("]");
}
return parent;
}
__name(parseInlineOptions, "parseInlineOptions");
function parseService(parent, token2) {
if (!nameRe.test(token2 = next()))
throw illegal(token2, "service name");
var service = new Service(token2);
ifBlock(service, /* @__PURE__ */ __name(function parseService_block(token3) {
if (parseCommon(service, token3))
return;
if (token3 === "rpc")
parseMethod(service, token3);
else
throw illegal(token3);
}, "parseService_block"));
parent.add(service);
}
__name(parseService, "parseService");
function parseMethod(parent, token2) {
var type = token2;
if (!nameRe.test(token2 = next()))
throw illegal(token2, "name");
var name = token2, requestType, requestStream, responseType, responseStream;
skip("(");
if (skip("stream", true))
requestStream = true;
if (!typeRefRe.test(token2 = next()))
throw illegal(token2);
requestType = token2;
skip(")");
skip("returns");
skip("(");
if (skip("stream", true))
responseStream = true;
if (!typeRefRe.test(token2 = next()))
throw illegal(token2);
responseType = token2;
skip(")");
var method = new Method(name, type, requestType, responseType, requestStream, responseStream);
ifBlock(method, /* @__PURE__ */ __name(function parseMethod_block(token3) {
if (token3 === "option") {
parseOption(method, token3);
skip(";");
} else
throw illegal(token3);
}, "parseMethod_block"));
parent.add(method);
}
__name(parseMethod, "parseMethod");
function parseExtension(parent, token2) {
if (!typeRefRe.test(token2 = next()))
throw illegal(token2, "reference");
var reference = token2;
ifBlock(null, /* @__PURE__ */ __name(function parseExtension_block(token3) {
switch (token3) {
case "required":
case "repeated":
case "optional":
parseField(parent, token3, reference);
break;
default:
if (!isProto3 || !typeRefRe.test(token3))
throw illegal(token3);
push(token3);
parseField(parent, "optional", reference);
break;
}
}, "parseExtension_block"));
}
__name(parseExtension, "parseExtension");
var token;
while ((token = next()) !== null) {
switch (token) {
case "package":
if (!head)
throw illegal(token);
parsePackage();
break;
case "import":
if (!head)
throw illegal(token);
parseImport();
break;
case "syntax":
if (!head)
throw illegal(token);
parseSyntax();
break;
case "option":
if (!head)
throw illegal(token);
parseOption(ptr, token);
skip(";");
break;
default:
if (parseCommon(ptr, token)) {
head = false;
continue;
}
throw illegal(token);
}
}
parse.filename = null;
return {
"package": pkg,
"imports": imports,
weakImports,
syntax,
root
};
}
__name(parse, "parse");
}, { "15": 15, "16": 16, "20": 20, "22": 22, "25": 25, "29": 29, "33": 33, "34": 34, "35": 35, "36": 36, "37": 37 }], 27: [function(require2, module2, exports) {
module2.exports = Reader;
var util = require2(39);
var BufferReader;
var LongBits = util.LongBits, utf8 = util.utf8;
function indexOutOfRange(reader, writeLength) {
return RangeError("index out of range: " + reader.pos + " + " + (writeLength || 1) + " > " + reader.len);
}
__name(indexOutOfRange, "indexOutOfRange");
function Reader(buffer) {
this.buf = buffer;
this.pos = 0;
this.len = buffer.length;
}
__name(Reader, "Reader");
var create_array = typeof Uint8Array !== "undefined" ? /* @__PURE__ */ __name(function create_typed_array(buffer) {
if (buffer instanceof Uint8Array || Array.isArray(buffer))
return new Reader(buffer);
throw Error("illegal buffer");
}, "create_typed_array") : /* @__PURE__ */ __name(function create_array2(buffer) {
if (Array.isArray(buffer))
return new Reader(buffer);
throw Error("illegal buffer");
}, "create_array");
Reader.create = util.Buffer ? /* @__PURE__ */ __name(function create_buffer_setup(buffer) {
return (Reader.create = /* @__PURE__ */ __name(function create_buffer(buffer2) {
return util.Buffer.isBuffer(buffer2) ? new BufferReader(buffer2) : create_array(buffer2);
}, "create_buffer"))(buffer);
}, "create_buffer_setup") : create_array;
Reader.prototype._slice = util.Array.prototype.subarray || /* istanbul ignore next */
util.Array.prototype.slice;
Reader.prototype.uint32 = (/* @__PURE__ */ __name((function read_uint32_setup() {
var value = 4294967295;
return /* @__PURE__ */ __name(function read_uint32() {
value = (this.buf[this.pos] & 127) >>> 0;
if (this.buf[this.pos++] < 128) return value;
value = (value | (this.buf[this.pos] & 127) << 7) >>> 0;
if (this.buf[this.pos++] < 128) return value;
value = (value | (this.buf[this.pos] & 127) << 14) >>> 0;
if (this.buf[this.pos++] < 128) return value;
value = (value | (this.buf[this.pos] & 127) << 21) >>> 0;
if (this.buf[this.pos++] < 128) return value;
value = (value | (this.buf[this.pos] & 15) << 28) >>> 0;
if (this.buf[this.pos++] < 128) return value;
if ((this.pos += 5) > this.len) {
this.pos = this.len;
throw indexOutOfRange(this, 10);
}
return value;
}, "read_uint32");
}), "read_uint32_setup"))();
Reader.prototype.int32 = /* @__PURE__ */ __name(function read_int32() {
return this.uint32() | 0;
}, "read_int32");
Reader.prototype.sint32 = /* @__PURE__ */ __name(function read_sint32() {
var value = this.uint32();
return value >>> 1 ^ -(value & 1) | 0;
}, "read_sint32");
function readLongVarint() {
var bits = new LongBits(0, 0);
var i = 0;
if (this.len - this.pos > 4) {
for (; i < 4; ++i) {
bits.lo = (bits.lo | (this.buf[this.pos] & 127) << i * 7) >>> 0;
if (this.buf[this.pos++] < 128)
return bits;
}
bits.lo = (bits.lo | (this.buf[this.pos] & 127) << 28) >>> 0;
bits.hi = (bits.hi | (this.buf[this.pos] & 127) >> 4) >>> 0;
if (this.buf[this.pos++] < 128)
return bits;
i = 0;
} else {
for (; i < 3; ++i) {
if (this.pos >= this.len)
throw indexOutOfRange(this);
bits.lo = (bits.lo | (this.buf[this.pos] & 127) << i * 7) >>> 0;
if (this.buf[this.pos++] < 128)
return bits;
}
bits.lo = (bits.lo | (this.buf[this.pos++] & 127) << i * 7) >>> 0;
return bits;
}
if (this.len - this.pos > 4) {
for (; i < 5; ++i) {
bits.hi = (bits.hi | (this.buf[this.pos] & 127) << i * 7 + 3) >>> 0;
if (this.buf[this.pos++] < 128)
return bits;
}
} else {
for (; i < 5; ++i) {
if (this.pos >= this.len)
throw indexOutOfRange(this);
bits.hi = (bits.hi | (this.buf[this.pos] & 127) << i * 7 + 3) >>> 0;
if (this.buf[this.pos++] < 128)
return bits;
}
}
throw Error("invalid varint encoding");
}
__name(readLongVarint, "readLongVarint");
Reader.prototype.bool = /* @__PURE__ */ __name(function read_bool() {
return this.uint32() !== 0;
}, "read_bool");
function readFixed32_end(buf, end) {
return (buf[end - 4] | buf[end - 3] << 8 | buf[end - 2] << 16 | buf[end - 1] << 24) >>> 0;
}
__name(readFixed32_end, "readFixed32_end");
Reader.prototype.fixed32 = /* @__PURE__ */ __name(function read_fixed32() {
if (this.pos + 4 > this.len)
throw indexOutOfRange(this, 4);
return readFixed32_end(this.buf, this.pos += 4);
}, "read_fixed32");
Reader.prototype.sfixed32 = /* @__PURE__ */ __name(function read_sfixed32() {
if (this.pos + 4 > this.len)
throw indexOutOfRange(this, 4);
return readFixed32_end(this.buf, this.pos += 4) | 0;
}, "read_sfixed32");
function readFixed64() {
if (this.pos + 8 > this.len)
throw indexOutOfRange(this, 8);
return new LongBits(readFixed32_end(this.buf, this.pos += 4), readFixed32_end(this.buf, this.pos += 4));
}
__name(readFixed64, "readFixed64");
Reader.prototype.float = /* @__PURE__ */ __name(function read_float() {
if (this.pos + 4 > this.len)
throw indexOutOfRange(this, 4);
var value = util.float.readFloatLE(this.buf, this.pos);
this.pos += 4;
return value;
}, "read_float");
Reader.prototype.double = /* @__PURE__ */ __name(function read_double() {
if (this.pos + 8 > this.len)
throw indexOutOfRange(this, 4);
var value = util.float.readDoubleLE(this.buf, this.pos);
this.pos += 8;
return value;
}, "read_double");
Reader.prototype.bytes = /* @__PURE__ */ __name(function read_bytes() {
var length = this.uint32(), start = this.pos, end = this.pos + length;
if (end > this.len)
throw indexOutOfRange(this, length);
this.pos += length;
if (Array.isArray(this.buf))
return this.buf.slice(start, end);
return start === end ? new this.buf.constructor(0) : this._slice.call(this.buf, start, end);
}, "read_bytes");
Reader.prototype.string = /* @__PURE__ */ __name(function read_string() {
var bytes = this.bytes();
return utf8.read(bytes, 0, bytes.length);
}, "read_string");
Reader.prototype.skip = /* @__PURE__ */ __name(function skip(length) {
if (typeof length === "number") {
if (this.pos + length > this.len)
throw indexOutOfRange(this, length);
this.pos += length;
} else {
do {
if (this.pos >= this.len)
throw indexOutOfRange(this);
} while (this.buf[this.pos++] & 128);
}
return this;
}, "skip");
Reader.prototype.skipType = function(wireType) {
switch (wireType) {
case 0:
this.skip();
break;
case 1:
this.skip(8);
break;
case 2:
this.skip(this.uint32());
break;
case 3:
do {
if ((wireType = this.uint32() & 7) === 4)
break;
this.skipType(wireType);
} while (true);
break;
case 5:
this.skip(4);
break;
/* istanbul ignore next */
default:
throw Error("invalid wire type " + wireType + " at offset " + this.pos);
}
return this;
};
Reader._configure = function(BufferReader_) {
BufferReader = BufferReader_;
var fn = util.Long ? "toLong" : (
/* istanbul ignore next */
"toNumber"
);
util.merge(Reader.prototype, {
int64: /* @__PURE__ */ __name(function read_int64() {
return readLongVarint.call(this)[fn](false);
}, "read_int64"),
uint64: /* @__PURE__ */ __name(function read_uint64() {
return readLongVarint.call(this)[fn](true);
}, "read_uint64"),
sint64: /* @__PURE__ */ __name(function read_sint64() {
return readLongVarint.call(this).zzDecode()[fn](false);
}, "read_sint64"),
fixed64: /* @__PURE__ */ __name(function read_fixed64() {
return readFixed64.call(this)[fn](true);
}, "read_fixed64"),
sfixed64: /* @__PURE__ */ __name(function read_sfixed64() {
return readFixed64.call(this)[fn](false);
}, "read_sfixed64")
});
};
}, { "39": 39 }], 28: [function(require2, module2, exports) {
module2.exports = BufferReader;
var Reader = require2(27);
(BufferReader.prototype = Object.create(Reader.prototype)).constructor = BufferReader;
var util = require2(39);
function BufferReader(buffer) {
Reader.call(this, buffer);
}
__name(BufferReader, "BufferReader");
if (util.Buffer)
BufferReader.prototype._slice = util.Buffer.prototype.slice;
BufferReader.prototype.string = /* @__PURE__ */ __name(function read_string_buffer() {
var len = this.uint32();
return this.buf.utf8Slice(this.pos, this.pos = Math.min(this.pos + len, this.len));
}, "read_string_buffer");
}, { "27": 27, "39": 39 }], 29: [function(require2, module2, exports) {
module2.exports = Root;
var Namespace = require2(23);
((Root.prototype = Object.create(Namespace.prototype)).constructor = Root).className = "Root";
var Field = require2(16), Enum = require2(15), OneOf = require2(25), util = require2(37);
var Type, parse, common;
function Root(options) {
Namespace.call(this, "", options);
this.deferred = [];
this.files = [];
}
__name(Root, "Root");
Root.fromJSON = /* @__PURE__ */ __name(function fromJSON(json, root) {
if (!root)
root = new Root();
if (json.options)
root.setOptions(json.options);
return root.addJSON(json.nested);
}, "fromJSON");
Root.prototype.resolvePath = util.path.resolve;
function SYNC() {
}
__name(SYNC, "SYNC");
Root.prototype.load = /* @__PURE__ */ __name(function load(filename, options, callback) {
if (typeof options === "function") {
callback = options;
options = undefined$1;
}
var self = this;
if (!callback)
return util.asPromise(load, self, filename, options);
var sync = callback === SYNC;
function finish(err, root) {
if (!callback)
return;
var cb = callback;
callback = null;
if (sync)
throw err;
cb(err, root);
}
__name(finish, "finish");
function process(filename2, source) {
try {
if (util.isString(source) && source.charAt(0) === "{")
source = JSON.parse(source);
if (!util.isString(source))
self.setOptions(source.options).addJSON(source.nested);
else {
parse.filename = filename2;
var parsed = parse(source, self, options), resolved2, i2 = 0;
if (parsed.imports) {
for (; i2 < parsed.imports.length; ++i2)
if (resolved2 = self.resolvePath(filename2, parsed.imports[i2]))
fetch(resolved2);
}
if (parsed.weakImports) {
for (i2 = 0; i2 < parsed.weakImports.length; ++i2)
if (resolved2 = self.resolvePath(filename2, parsed.weakImports[i2]))
fetch(resolved2, true);
}
}
} catch (err) {
finish(err);
}
if (!sync && !queued)
finish(null, self);
}
__name(process, "process");
function fetch(filename2, weak) {
var idx = filename2.lastIndexOf("google/protobuf/");
if (idx > -1) {
var altname = filename2.substring(idx);
if (altname in common)
filename2 = altname;
}
if (self.files.indexOf(filename2) > -1)
return;
self.files.push(filename2);
if (filename2 in common) {
if (sync)
process(filename2, common[filename2]);
else {
++queued;
setTimeout(function() {
--queued;
process(filename2, common[filename2]);
});
}
return;
}
if (sync) {
var source;
try {
source = util.fs.readFileSync(filename2).toString("utf8");
} catch (err) {
if (!weak)
finish(err);
return;
}
process(filename2, source);
} else {
++queued;
util.fetch(filename2, function(err, source2) {
--queued;
if (!callback)
return;
if (err) {
if (!weak)
finish(err);
else if (!queued)
finish(null, self);
return;
}
process(filename2, source2);
});
}
}
__name(fetch, "fetch");
var queued = 0;
if (util.isString(filename))
filename = [filename];
for (var i = 0, resolved; i < filename.length; ++i)
if (resolved = self.resolvePath("", filename[i]))
fetch(resolved);
if (sync)
return self;
if (!queued)
finish(null, self);
return undefined$1;
}, "load");
Root.prototype.loadSync = /* @__PURE__ */ __name(function loadSync(filename, options) {
if (!util.isNode)
throw Error("not supported");
return this.load(filename, options, SYNC);
}, "loadSync");
Root.prototype.resolveAll = /* @__PURE__ */ __name(function resolveAll() {
if (this.deferred.length)
throw Error("unresolvable extensions: " + this.deferred.map(function(field) {
return "'extend " + field.extend + "' in " + field.parent.fullName;
}).join(", "));
return Namespace.prototype.resolveAll.call(this);
}, "resolveAll");
var exposeRe = /^[A-Z]/;
function tryHandleExtension(root, field) {
var extendedType = field.parent.lookup(field.extend);
if (extendedType) {
var sisterField = new Field(field.fullName, field.id, field.type, field.rule, undefined$1, field.options);
sisterField.declaringField = field;
field.extensionField = sisterField;
extendedType.add(sisterField);
return true;
}
return false;
}
__name(tryHandleExtension, "tryHandleExtension");
Root.prototype._handleAdd = /* @__PURE__ */ __name(function _handleAdd(object) {
if (object instanceof Field) {
if (
/* an extension field (implies not part of a oneof) */
object.extend !== undefined$1 && /* not already handled */
!object.extensionField
) {
if (!tryHandleExtension(this, object))
this.deferred.push(object);
}
} else if (object instanceof Enum) {
if (exposeRe.test(object.name))
object.parent[object.name] = object.values;
} else if (!(object instanceof OneOf)) {
if (object instanceof Type)
for (var i = 0; i < this.deferred.length; )
if (tryHandleExtension(this, this.deferred[i]))
this.deferred.splice(i, 1);
else
++i;
for (var j = 0; j < /* initializes */
object.nestedArray.length; ++j)
this._handleAdd(object._nestedArray[j]);
if (exposeRe.test(object.name))
object.parent[object.name] = object;
}
}, "_handleAdd");
Root.prototype._handleRemove = /* @__PURE__ */ __name(function _handleRemove(object) {
if (object instanceof Field) {
if (
/* an extension field */
object.extend !== undefined$1
) {
if (
/* already handled */
object.extensionField
) {
object.extensionField.parent.remove(object.extensionField);
object.extensionField = null;
} else {
var index = this.deferred.indexOf(object);
if (index > -1)
this.deferred.splice(index, 1);
}
}
} else if (object instanceof Enum) {
if (exposeRe.test(object.name))
delete object.parent[object.name];
} else if (object instanceof Namespace) {
for (var i = 0; i < /* initializes */
object.nestedArray.length; ++i)
this._handleRemove(object._nestedArray[i]);
if (exposeRe.test(object.name))
delete object.parent[object.name];
}
}, "_handleRemove");
Root._configure = function(Type_, parse_, common_) {
Type = Type_;
parse = parse_;
common = common_;
};
}, { "15": 15, "16": 16, "23": 23, "25": 25, "37": 37 }], 30: [function(require2, module2, exports) {
module2.exports = {};
}, {}], 31: [function(require2, module2, exports) {
var rpc = exports;
rpc.Service = require2(32);
}, { "32": 32 }], 32: [function(require2, module2, exports) {
module2.exports = Service;
var util = require2(39);
(Service.prototype = Object.create(util.EventEmitter.prototype)).constructor = Service;
function Service(rpcImpl, requestDelimited, responseDelimited) {
if (typeof rpcImpl !== "function")
throw TypeError("rpcImpl must be a function");
util.EventEmitter.call(this);
this.rpcImpl = rpcImpl;
this.requestDelimited = Boolean(requestDelimited);
this.responseDelimited = Boolean(responseDelimited);
}
__name(Service, "Service");
Service.prototype.rpcCall = /* @__PURE__ */ __name(function rpcCall(method, requestCtor, responseCtor, request, callback) {
if (!request)
throw TypeError("request must be specified");
var self = this;
if (!callback)
return util.asPromise(rpcCall, self, method, requestCtor, responseCtor, request);
if (!self.rpcImpl) {
setTimeout(function() {
callback(Error("already ended"));
}, 0);
return undefined$1;
}
try {
return self.rpcImpl(
method,
requestCtor[self.requestDelimited ? "encodeDelimited" : "encode"](request).finish(),
/* @__PURE__ */ __name(function rpcCallback(err, response) {
if (err) {
self.emit("error", err, method);
return callback(err);
}
if (response === null) {
self.end(
/* endedByRPC */
true
);
return undefined$1;
}
if (!(response instanceof responseCtor)) {
try {
response = responseCtor[self.responseDelimited ? "decodeDelimited" : "decode"](response);
} catch (err2) {
self.emit("error", err2, method);
return callback(err2);
}
}
self.emit("data", response, method);
return callback(null, response);
}, "rpcCallback")
);
} catch (err) {
self.emit("error", err, method);
setTimeout(function() {
callback(err);
}, 0);
return undefined$1;
}
}, "rpcCall");
Service.prototype.end = /* @__PURE__ */ __name(function end(endedByRPC) {
if (this.rpcImpl) {
if (!endedByRPC)
this.rpcImpl(null, null, null);
this.rpcImpl = null;
this.emit("end").off();
}
return this;
}, "end");
}, { "39": 39 }], 33: [function(require2, module2, exports) {
module2.exports = Service;
var Namespace = require2(23);
((Service.prototype = Object.create(Namespace.prototype)).constructor = Service).className = "Service";
var Method = require2(22), util = require2(37), rpc = require2(31);
function Service(name, options) {
Namespace.call(this, name, options);
this.methods = {};
this._methodsArray = null;
}
__name(Service, "Service");
Service.fromJSON = /* @__PURE__ */ __name(function fromJSON(name, json) {
var service = new Service(name, json.options);
if (json.methods)
for (var names = Object.keys(json.methods), i = 0; i < names.length; ++i)
service.add(Method.fromJSON(names[i], json.methods[names[i]]));
if (json.nested)
service.addJSON(json.nested);
service.comment = json.comment;
return service;
}, "fromJSON");
Service.prototype.toJSON = /* @__PURE__ */ __name(function toJSON(toJSONOptions) {
var inherited = Namespace.prototype.toJSON.call(this, toJSONOptions);
var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
return util.toObject([
"options",
inherited && inherited.options || undefined$1,
"methods",
Namespace.arrayToJSON(this.methodsArray, toJSONOptions) || /* istanbul ignore next */
{},
"nested",
inherited && inherited.nested || undefined$1,
"comment",
keepComments ? this.comment : undefined$1
]);
}, "toJSON");
Object.defineProperty(Service.prototype, "methodsArray", {
get: /* @__PURE__ */ __name(function() {
return this._methodsArray || (this._methodsArray = util.toArray(this.methods));
}, "get")
});
function clearCache(service) {
service._methodsArray = null;
return service;
}
__name(clearCache, "clearCache");
Service.prototype.get = /* @__PURE__ */ __name(function get(name) {
return this.methods[name] || Namespace.prototype.get.call(this, name);
}, "get");
Service.prototype.resolveAll = /* @__PURE__ */ __name(function resolveAll() {
var methods = this.methodsArray;
for (var i = 0; i < methods.length; ++i)
methods[i].resolve();
return Namespace.prototype.resolve.call(this);
}, "resolveAll");
Service.prototype.add = /* @__PURE__ */ __name(function add(object) {
if (this.get(object.name))
throw Error("duplicate name '" + object.name + "' in " + this);
if (object instanceof Method) {
this.methods[object.name] = object;
object.parent = this;
return clearCache(this);
}
return Namespace.prototype.add.call(this, object);
}, "add");
Service.prototype.remove = /* @__PURE__ */ __name(function remove(object) {
if (object instanceof Method) {
if (this.methods[object.name] !== object)
throw Error(object + " is not a member of " + this);
delete this.methods[object.name];
object.parent = null;
return clearCache(this);
}
return Namespace.prototype.remove.call(this, object);
}, "remove");
Service.prototype.create = /* @__PURE__ */ __name(function create(rpcImpl, requestDelimited, responseDelimited) {
var rpcService = new rpc.Service(rpcImpl, requestDelimited, responseDelimited);
for (var i = 0, method; i < /* initializes */
this.methodsArray.length; ++i) {
var methodName = util.lcFirst((method = this._methodsArray[i]).resolve().name).replace(/[^$\w_]/g, "");
rpcService[methodName] = util.codegen(["r", "c"], util.isReserved(methodName) ? methodName + "_" : methodName)("return this.rpcCall(m,q,s,r,c)")({
m: method,
q: method.resolvedRequestType.ctor,
s: method.resolvedResponseType.ctor
});
}
return rpcService;
}, "create");
}, { "22": 22, "23": 23, "31": 31, "37": 37 }], 34: [function(require2, module2, exports) {
module2.exports = tokenize;
var delimRe = /[\s{}=;:[\],'"()<>]/g, stringDoubleRe = /(?:"([^"\\]*(?:\\.[^"\\]*)*)")/g, stringSingleRe = /(?:'([^'\\]*(?:\\.[^'\\]*)*)')/g;
var setCommentRe = /^ *[*/]+ */, setCommentAltRe = /^\s*\*?\/*/, setCommentSplitRe = /\n/g, whitespaceRe = /\s/, unescapeRe = /\\(.?)/g;
var unescapeMap = {
"0": "\0",
"r": "\r",
"n": "\n",
"t": " "
};
function unescape(str) {
return str.replace(unescapeRe, function($0, $1) {
switch ($1) {
case "\\":
case "":
return $1;
default:
return unescapeMap[$1] || "";
}
});
}
__name(unescape, "unescape");
tokenize.unescape = unescape;
function tokenize(source, alternateCommentMode) {
source = source.toString();
var offset = 0, length = source.length, line = 1, commentType = null, commentText = null, commentLine = 0, commentLineEmpty = false;
var stack = [];
var stringDelim = null;
function illegal(subject) {
return Error("illegal " + subject + " (line " + line + ")");
}
__name(illegal, "illegal");
function readString() {
var re = stringDelim === "'" ? stringSingleRe : stringDoubleRe;
re.lastIndex = offset - 1;
var match = re.exec(source);
if (!match)
throw illegal("string");
offset = re.lastIndex;
push(stringDelim);
stringDelim = null;
return unescape(match[1]);
}
__name(readString, "readString");
function charAt(pos) {
return source.charAt(pos);
}
__name(charAt, "charAt");
function setComment(start, end) {
commentType = source.charAt(start++);
commentLine = line;
commentLineEmpty = false;
var lookback;
if (alternateCommentMode) {
lookback = 2;
} else {
lookback = 3;
}
var commentOffset = start - lookback, c;
do {
if (--commentOffset < 0 || (c = source.charAt(commentOffset)) === "\n") {
commentLineEmpty = true;
break;
}
} while (c === " " || c === " ");
var lines = source.substring(start, end).split(setCommentSplitRe);
for (var i = 0; i < lines.length; ++i)
lines[i] = lines[i].replace(alternateCommentMode ? setCommentAltRe : setCommentRe, "").trim();
commentText = lines.join("\n").trim();
}
__name(setComment, "setComment");
function isDoubleSlashCommentLine(startOffset) {
var endOffset = findEndOfLine(startOffset);
var lineText = source.substring(startOffset, endOffset);
var isComment = /^\s*\/{1,2}/.test(lineText);
return isComment;
}
__name(isDoubleSlashCommentLine, "isDoubleSlashCommentLine");
function findEndOfLine(cursor) {
var endOffset = cursor;
while (endOffset < length && charAt(endOffset) !== "\n") {
endOffset++;
}
return endOffset;
}
__name(findEndOfLine, "findEndOfLine");
function next() {
if (stack.length > 0)
return stack.shift();
if (stringDelim)
return readString();
var repeat, prev, curr, start, isDoc;
do {
if (offset === length)
return null;
repeat = false;
while (whitespaceRe.test(curr = charAt(offset))) {
if (curr === "\n")
++line;
if (++offset === length)
return null;
}
if (charAt(offset) === "/") {
if (++offset === length) {
throw illegal("comment");
}
if (charAt(offset) === "/") {
if (!alternateCommentMode) {
isDoc = charAt(start = offset + 1) === "/";
while (charAt(++offset) !== "\n") {
if (offset === length) {
return null;
}
}
++offset;
if (isDoc) {
setComment(start, offset - 1);
}
++line;
repeat = true;
} else {
start = offset;
isDoc = false;
if (isDoubleSlashCommentLine(offset)) {
isDoc = true;
do {
offset = findEndOfLine(offset);
if (offset === length) {
break;
}
offset++;
} while (isDoubleSlashCommentLine(offset));
} else {
offset = Math.min(length, findEndOfLine(offset) + 1);
}
if (isDoc) {
setComment(start, offset);
}
line++;
repeat = true;
}
} else if ((curr = charAt(offset)) === "*") {
start = offset + 1;
isDoc = alternateCommentMode || charAt(start) === "*";
do {
if (curr === "\n") {
++line;
}
if (++offset === length) {
throw illegal("comment");
}
prev = curr;
curr = charAt(offset);
} while (prev !== "*" || curr !== "/");
++offset;
if (isDoc) {
setComment(start, offset - 2);
}
repeat = true;
} else {
return "/";
}
}
} while (repeat);
var end = offset;
delimRe.lastIndex = 0;
var delim = delimRe.test(charAt(end++));
if (!delim)
while (end < length && !delimRe.test(charAt(end)))
++end;
var token = source.substring(offset, offset = end);
if (token === '"' || token === "'")
stringDelim = token;
return token;
}
__name(next, "next");
function push(token) {
stack.push(token);
}
__name(push, "push");
function peek() {
if (!stack.length) {
var token = next();
if (token === null)
return null;
push(token);
}
return stack[0];
}
__name(peek, "peek");
function skip(expected, optional) {
var actual = peek(), equals = actual === expected;
if (equals) {
next();
return true;
}
if (!optional)
throw illegal("token '" + actual + "', '" + expected + "' expected");
return false;
}
__name(skip, "skip");
function cmnt(trailingLine) {
var ret = null;
if (trailingLine === undefined$1) {
if (commentLine === line - 1 && (alternateCommentMode || commentType === "*" || commentLineEmpty)) {
ret = commentText;
}
} else {
if (commentLine < trailingLine) {
peek();
}
if (commentLine === trailingLine && !commentLineEmpty && (alternateCommentMode || commentType === "/")) {
ret = commentText;
}
}
return ret;
}
__name(cmnt, "cmnt");
return Object.defineProperty({
next,
peek,
push,
skip,
cmnt
}, "line", {
get: /* @__PURE__ */ __name(function() {
return line;
}, "get")
});
}
__name(tokenize, "tokenize");
}, {}], 35: [function(require2, module2, exports) {
module2.exports = Type;
var Namespace = require2(23);
((Type.prototype = Object.create(Namespace.prototype)).constructor = Type).className = "Type";
var Enum = require2(15), OneOf = require2(25), Field = require2(16), MapField = require2(20), Service = require2(33), Message = require2(21), Reader = require2(27), Writer = require2(42), util = require2(37), encoder = require2(14), decoder = require2(13), verifier = require2(40), converter = require2(12), wrappers = require2(41);
function Type(name, options) {
Namespace.call(this, name, options);
this.fields = {};
this.oneofs = undefined$1;
this.extensions = undefined$1;
this.reserved = undefined$1;
this.group = undefined$1;
this._fieldsById = null;
this._fieldsArray = null;
this._oneofsArray = null;
this._ctor = null;
}
__name(Type, "Type");
Object.defineProperties(Type.prototype, {
/**
* Message fields by id.
* @name Type#fieldsById
* @type {Object.<number,Field>}
* @readonly
*/
fieldsById: {
get: /* @__PURE__ */ __name(function() {
if (this._fieldsById)
return this._fieldsById;
this._fieldsById = {};
for (var names = Object.keys(this.fields), i = 0; i < names.length; ++i) {
var field = this.fields[names[i]], id = field.id;
if (this._fieldsById[id])
throw Error("duplicate id " + id + " in " + this);
this._fieldsById[id] = field;
}
return this._fieldsById;
}, "get")
},
/**
* Fields of this message as an array for iteration.
* @name Type#fieldsArray
* @type {Field[]}
* @readonly
*/
fieldsArray: {
get: /* @__PURE__ */ __name(function() {
return this._fieldsArray || (this._fieldsArray = util.toArray(this.fields));
}, "get")
},
/**
* Oneofs of this message as an array for iteration.
* @name Type#oneofsArray
* @type {OneOf[]}
* @readonly
*/
oneofsArray: {
get: /* @__PURE__ */ __name(function() {
return this._oneofsArray || (this._oneofsArray = util.toArray(this.oneofs));
}, "get")
},
/**
* The registered constructor, if any registered, otherwise a generic constructor.
* Assigning a function replaces the internal constructor. If the function does not extend {@link Message} yet, its prototype will be setup accordingly and static methods will be populated. If it already extends {@link Message}, it will just replace the internal constructor.
* @name Type#ctor
* @type {Constructor<{}>}
*/
ctor: {
get: /* @__PURE__ */ __name(function() {
return this._ctor || (this.ctor = Type.generateConstructor(this)());
}, "get"),
set: /* @__PURE__ */ __name(function(ctor) {
var prototype = ctor.prototype;
if (!(prototype instanceof Message)) {
(ctor.prototype = new Message()).constructor = ctor;
util.merge(ctor.prototype, prototype);
}
ctor.$type = ctor.prototype.$type = this;
util.merge(ctor, Message, true);
this._ctor = ctor;
var i = 0;
for (; i < /* initializes */
this.fieldsArray.length; ++i)
this._fieldsArray[i].resolve();
var ctorProperties = {};
for (i = 0; i < /* initializes */
this.oneofsArray.length; ++i)
ctorProperties[this._oneofsArray[i].resolve().name] = {
get: util.oneOfGetter(this._oneofsArray[i].oneof),
set: util.oneOfSetter(this._oneofsArray[i].oneof)
};
if (i)
Object.defineProperties(ctor.prototype, ctorProperties);
}, "set")
}
});
Type.generateConstructor = /* @__PURE__ */ __name(function generateConstructor(mtype) {
var gen = util.codegen(["p"], mtype.name);
for (var i = 0, field; i < mtype.fieldsArray.length; ++i)
if ((field = mtype._fieldsArray[i]).map) gen("this%s={}", util.safeProp(field.name));
else if (field.repeated) gen("this%s=[]", util.safeProp(field.name));
return gen("if(p)for(var ks=Object.keys(p),i=0;i<ks.length;++i)if(p[ks[i]]!=null)")("this[ks[i]]=p[ks[i]]");
}, "generateConstructor");
function clearCache(type) {
type._fieldsById = type._fieldsArray = type._oneofsArray = null;
delete type.encode;
delete type.decode;
delete type.verify;
return type;
}
__name(clearCache, "clearCache");
Type.fromJSON = /* @__PURE__ */ __name(function fromJSON(name, json) {
var type = new Type(name, json.options);
type.extensions = json.extensions;
type.reserved = json.reserved;
var names = Object.keys(json.fields), i = 0;
for (; i < names.length; ++i)
type.add(
(typeof json.fields[names[i]].keyType !== "undefined" ? MapField.fromJSON : Field.fromJSON)(names[i], json.fields[names[i]])
);
if (json.oneofs)
for (names = Object.keys(json.oneofs), i = 0; i < names.length; ++i)
type.add(OneOf.fromJSON(names[i], json.oneofs[names[i]]));
if (json.nested)
for (names = Object.keys(json.nested), i = 0; i < names.length; ++i) {
var nested = json.nested[names[i]];
type.add(
// most to least likely
(nested.id !== undefined$1 ? Field.fromJSON : nested.fields !== undefined$1 ? Type.fromJSON : nested.values !== undefined$1 ? Enum.fromJSON : nested.methods !== undefined$1 ? Service.fromJSON : Namespace.fromJSON)(names[i], nested)
);
}
if (json.extensions && json.extensions.length)
type.extensions = json.extensions;
if (json.reserved && json.reserved.length)
type.reserved = json.reserved;
if (json.group)
type.group = true;
if (json.comment)
type.comment = json.comment;
return type;
}, "fromJSON");
Type.prototype.toJSON = /* @__PURE__ */ __name(function toJSON(toJSONOptions) {
var inherited = Namespace.prototype.toJSON.call(this, toJSONOptions);
var keepComments = toJSONOptions ? Boolean(toJSONOptions.keepComments) : false;
return util.toObject([
"options",
inherited && inherited.options || undefined$1,
"oneofs",
Namespace.arrayToJSON(this.oneofsArray, toJSONOptions),
"fields",
Namespace.arrayToJSON(this.fieldsArray.filter(function(obj) {
return !obj.declaringField;
}), toJSONOptions) || {},
"extensions",
this.extensions && this.extensions.length ? this.extensions : undefined$1,
"reserved",
this.reserved && this.reserved.length ? this.reserved : undefined$1,
"group",
this.group || undefined$1,
"nested",
inherited && inherited.nested || undefined$1,
"comment",
keepComments ? this.comment : undefined$1
]);
}, "toJSON");
Type.prototype.resolveAll = /* @__PURE__ */ __name(function resolveAll() {
var fields = this.fieldsArray, i = 0;
while (i < fields.length)
fields[i++].resolve();
var oneofs = this.oneofsArray;
i = 0;
while (i < oneofs.length)
oneofs[i++].resolve();
return Namespace.prototype.resolveAll.call(this);
}, "resolveAll");
Type.prototype.get = /* @__PURE__ */ __name(function get(name) {
return this.fields[name] || this.oneofs && this.oneofs[name] || this.nested && this.nested[name] || null;
}, "get");
Type.prototype.add = /* @__PURE__ */ __name(function add(object) {
if (this.get(object.name))
throw Error("duplicate name '" + object.name + "' in " + this);
if (object instanceof Field && object.extend === undefined$1) {
if (this._fieldsById ? (
/* istanbul ignore next */
this._fieldsById[object.id]
) : this.fieldsById[object.id])
throw Error("duplicate id " + object.id + " in " + this);
if (this.isReservedId(object.id))
throw Error("id " + object.id + " is reserved in " + this);
if (this.isReservedName(object.name))
throw Error("name '" + object.name + "' is reserved in " + this);
if (object.parent)
object.parent.remove(object);
this.fields[object.name] = object;
object.message = this;
object.onAdd(this);
return clearCache(this);
}
if (object instanceof OneOf) {
if (!this.oneofs)
this.oneofs = {};
this.oneofs[object.name] = object;
object.onAdd(this);
return clearCache(this);
}
return Namespace.prototype.add.call(this, object);
}, "add");
Type.prototype.remove = /* @__PURE__ */ __name(function remove(object) {
if (object instanceof Field && object.extend === undefined$1) {
if (!this.fields || this.fields[object.name] !== object)
throw Error(object + " is not a member of " + this);
delete this.fields[object.name];
object.parent = null;
object.onRemove(this);
return clearCache(this);
}
if (object instanceof OneOf) {
if (!this.oneofs || this.oneofs[object.name] !== object)
throw Error(object + " is not a member of " + this);
delete this.oneofs[object.name];
object.parent = null;
object.onRemove(this);
return clearCache(this);
}
return Namespace.prototype.remove.call(this, object);
}, "remove");
Type.prototype.isReservedId = /* @__PURE__ */ __name(function isReservedId(id) {
return Namespace.isReservedId(this.reserved, id);
}, "isReservedId");
Type.prototype.isReservedName = /* @__PURE__ */ __name(function isReservedName(name) {
return Namespace.isReservedName(this.reserved, name);
}, "isReservedName");
Type.prototype.create = /* @__PURE__ */ __name(function create(properties) {
return new this.ctor(properties);
}, "create");
Type.prototype.setup = /* @__PURE__ */ __name(function setup() {
var fullName = this.fullName, types = [];
for (var i = 0; i < /* initializes */
this.fieldsArray.length; ++i)
types.push(this._fieldsArray[i].resolve().resolvedType);
this.encode = encoder(this)({
Writer,
types,
util
});
this.decode = decoder(this)({
Reader,
types,
util
});
this.verify = verifier(this)({
types,
util
});
this.fromObject = converter.fromObject(this)({
types,
util
});
this.toObject = converter.toObject(this)({
types,
util
});
var wrapper = wrappers[fullName];
if (wrapper) {
var originalThis = Object.create(this);
originalThis.fromObject = this.fromObject;
this.fromObject = wrapper.fromObject.bind(originalThis);
originalThis.toObject = this.toObject;
this.toObject = wrapper.toObject.bind(originalThis);
}
return this;
}, "setup");
Type.prototype.encode = /* @__PURE__ */ __name(function encode_setup(message, writer) {
return this.setup().encode(message, writer);
}, "encode_setup");
Type.prototype.encodeDelimited = /* @__PURE__ */ __name(function encodeDelimited(message, writer) {
return this.encode(message, writer && writer.len ? writer.fork() : writer).ldelim();
}, "encodeDelimited");
Type.prototype.decode = /* @__PURE__ */ __name(function decode_setup(reader, length) {
return this.setup().decode(reader, length);
}, "decode_setup");
Type.prototype.decodeDelimited = /* @__PURE__ */ __name(function decodeDelimited(reader) {
if (!(reader instanceof Reader))
reader = Reader.create(reader);
return this.decode(reader, reader.uint32());
}, "decodeDelimited");
Type.prototype.verify = /* @__PURE__ */ __name(function verify_setup(message) {
return this.setup().verify(message);
}, "verify_setup");
Type.prototype.fromObject = /* @__PURE__ */ __name(function fromObject(object) {
return this.setup().fromObject(object);
}, "fromObject");
Type.prototype.toObject = /* @__PURE__ */ __name(function toObject(message, options) {
return this.setup().toObject(message, options);
}, "toObject");
Type.d = /* @__PURE__ */ __name(function decorateType(typeName) {
return /* @__PURE__ */ __name(function typeDecorator(target) {
util.decorateType(target, typeName);
}, "typeDecorator");
}, "decorateType");
}, { "12": 12, "13": 13, "14": 14, "15": 15, "16": 16, "20": 20, "21": 21, "23": 23, "25": 25, "27": 27, "33": 33, "37": 37, "40": 40, "41": 41, "42": 42 }], 36: [function(require2, module2, exports) {
var types = exports;
var util = require2(37);
var s = [
"double",
// 0
"float",
// 1
"int32",
// 2
"uint32",
// 3
"sint32",
// 4
"fixed32",
// 5
"sfixed32",
// 6
"int64",
// 7
"uint64",
// 8
"sint64",
// 9
"fixed64",
// 10
"sfixed64",
// 11
"bool",
// 12
"string",
// 13
"bytes"
// 14
];
function bake(values, offset) {
var i = 0, o = {};
offset |= 0;
while (i < values.length) o[s[i + offset]] = values[i++];
return o;
}
__name(bake, "bake");
types.basic = bake([
/* double */
1,
/* float */
5,
/* int32 */
0,
/* uint32 */
0,
/* sint32 */
0,
/* fixed32 */
5,
/* sfixed32 */
5,
/* int64 */
0,
/* uint64 */
0,
/* sint64 */
0,
/* fixed64 */
1,
/* sfixed64 */
1,
/* bool */
0,
/* string */
2,
/* bytes */
2
]);
types.defaults = bake([
/* double */
0,
/* float */
0,
/* int32 */
0,
/* uint32 */
0,
/* sint32 */
0,
/* fixed32 */
0,
/* sfixed32 */
0,
/* int64 */
0,
/* uint64 */
0,
/* sint64 */
0,
/* fixed64 */
0,
/* sfixed64 */
0,
/* bool */
false,
/* string */
"",
/* bytes */
util.emptyArray,
/* message */
null
]);
types.long = bake([
/* int64 */
0,
/* uint64 */
0,
/* sint64 */
0,
/* fixed64 */
1,
/* sfixed64 */
1
], 7);
types.mapKey = bake([
/* int32 */
0,
/* uint32 */
0,
/* sint32 */
0,
/* fixed32 */
5,
/* sfixed32 */
5,
/* int64 */
0,
/* uint64 */
0,
/* sint64 */
0,
/* fixed64 */
1,
/* sfixed64 */
1,
/* bool */
0,
/* string */
2
], 2);
types.packed = bake([
/* double */
1,
/* float */
5,
/* int32 */
0,
/* uint32 */
0,
/* sint32 */
0,
/* fixed32 */
5,
/* sfixed32 */
5,
/* int64 */
0,
/* uint64 */
0,
/* sint64 */
0,
/* fixed64 */
1,
/* sfixed64 */
1,
/* bool */
0
]);
}, { "37": 37 }], 37: [function(require2, module2, exports) {
var util = module2.exports = require2(39);
var roots = require2(30);
var Type, Enum;
util.codegen = require2(3);
util.fetch = require2(5);
util.path = require2(8);
util.fs = util.inquire("fs");
util.toArray = /* @__PURE__ */ __name(function toArray(object) {
if (object) {
var keys = Object.keys(object), array = new Array(keys.length), index = 0;
while (index < keys.length)
array[index] = object[keys[index++]];
return array;
}
return [];
}, "toArray");
util.toObject = /* @__PURE__ */ __name(function toObject(array) {
var object = {}, index = 0;
while (index < array.length) {
var key = array[index++], val = array[index++];
if (val !== undefined$1)
object[key] = val;
}
return object;
}, "toObject");
var safePropBackslashRe = /\\/g, safePropQuoteRe = /"/g;
util.isReserved = /* @__PURE__ */ __name(function isReserved(name) {
return /^(?:do|if|in|for|let|new|try|var|case|else|enum|eval|false|null|this|true|void|with|break|catch|class|const|super|throw|while|yield|delete|export|import|public|return|static|switch|typeof|default|extends|finally|package|private|continue|debugger|function|arguments|interface|protected|implements|instanceof)$/.test(name);
}, "isReserved");
util.safeProp = /* @__PURE__ */ __name(function safeProp(prop) {
if (!/^[$\w_]+$/.test(prop) || util.isReserved(prop))
return '["' + prop.replace(safePropBackslashRe, "\\\\").replace(safePropQuoteRe, '\\"') + '"]';
return "." + prop;
}, "safeProp");
util.ucFirst = /* @__PURE__ */ __name(function ucFirst(str) {
return str.charAt(0).toUpperCase() + str.substring(1);
}, "ucFirst");
var camelCaseRe = /_([a-z])/g;
util.camelCase = /* @__PURE__ */ __name(function camelCase(str) {
return str.substring(0, 1) + str.substring(1).replace(camelCaseRe, function($0, $1) {
return $1.toUpperCase();
});
}, "camelCase");
util.compareFieldsById = /* @__PURE__ */ __name(function compareFieldsById(a, b) {
return a.id - b.id;
}, "compareFieldsById");
util.decorateType = /* @__PURE__ */ __name(function decorateType(ctor, typeName) {
if (ctor.$type) {
if (typeName && ctor.$type.name !== typeName) {
util.decorateRoot.remove(ctor.$type);
ctor.$type.name = typeName;
util.decorateRoot.add(ctor.$type);
}
return ctor.$type;
}
if (!Type)
Type = require2(35);
var type = new Type(typeName || ctor.name);
util.decorateRoot.add(type);
type.ctor = ctor;
Object.defineProperty(ctor, "$type", { value: type, enumerable: false });
Object.defineProperty(ctor.prototype, "$type", { value: type, enumerable: false });
return type;
}, "decorateType");
var decorateEnumIndex = 0;
util.decorateEnum = /* @__PURE__ */ __name(function decorateEnum(object) {
if (object.$type)
return object.$type;
if (!Enum)
Enum = require2(15);
var enm = new Enum("Enum" + decorateEnumIndex++, object);
util.decorateRoot.add(enm);
Object.defineProperty(object, "$type", { value: enm, enumerable: false });
return enm;
}, "decorateEnum");
Object.defineProperty(util, "decorateRoot", {
get: /* @__PURE__ */ __name(function() {
return roots["decorated"] || (roots["decorated"] = new (require2(29))());
}, "get")
});
}, { "15": 15, "29": 29, "3": 3, "30": 30, "35": 35, "39": 39, "5": 5, "8": 8 }], 38: [function(require2, module2, exports) {
module2.exports = LongBits;
var util = require2(39);
function LongBits(lo, hi) {
this.lo = lo >>> 0;
this.hi = hi >>> 0;
}
__name(LongBits, "LongBits");
var zero = LongBits.zero = new LongBits(0, 0);
zero.toNumber = function() {
return 0;
};
zero.zzEncode = zero.zzDecode = function() {
return this;
};
zero.length = function() {
return 1;
};
var zeroHash = LongBits.zeroHash = "\0\0\0\0\0\0\0\0";
LongBits.fromNumber = /* @__PURE__ */ __name(function fromNumber(value) {
if (value === 0)
return zero;
var sign = value < 0;
if (sign)
value = -value;
var lo = value >>> 0, hi = (value - lo) / 4294967296 >>> 0;
if (sign) {
hi = ~hi >>> 0;
lo = ~lo >>> 0;
if (++lo > 4294967295) {
lo = 0;
if (++hi > 4294967295)
hi = 0;
}
}
return new LongBits(lo, hi);
}, "fromNumber");
LongBits.from = /* @__PURE__ */ __name(function from(value) {
if (typeof value === "number")
return LongBits.fromNumber(value);
if (util.isString(value)) {
if (util.Long)
value = util.Long.fromString(value);
else
return LongBits.fromNumber(parseInt(value, 10));
}
return value.low || value.high ? new LongBits(value.low >>> 0, value.high >>> 0) : zero;
}, "from");
LongBits.prototype.toNumber = /* @__PURE__ */ __name(function toNumber(unsigned) {
if (!unsigned && this.hi >>> 31) {
var lo = ~this.lo + 1 >>> 0, hi = ~this.hi >>> 0;
if (!lo)
hi = hi + 1 >>> 0;
return -(lo + hi * 4294967296);
}
return this.lo + this.hi * 4294967296;
}, "toNumber");
LongBits.prototype.toLong = /* @__PURE__ */ __name(function toLong(unsigned) {
return util.Long ? new util.Long(this.lo | 0, this.hi | 0, Boolean(unsigned)) : { low: this.lo | 0, high: this.hi | 0, unsigned: Boolean(unsigned) };
}, "toLong");
var charCodeAt = String.prototype.charCodeAt;
LongBits.fromHash = /* @__PURE__ */ __name(function fromHash(hash) {
if (hash === zeroHash)
return zero;
return new LongBits(
(charCodeAt.call(hash, 0) | charCodeAt.call(hash, 1) << 8 | charCodeAt.call(hash, 2) << 16 | charCodeAt.call(hash, 3) << 24) >>> 0,
(charCodeAt.call(hash, 4) | charCodeAt.call(hash, 5) << 8 | charCodeAt.call(hash, 6) << 16 | charCodeAt.call(hash, 7) << 24) >>> 0
);
}, "fromHash");
LongBits.prototype.toHash = /* @__PURE__ */ __name(function toHash() {
return String.fromCharCode(
this.lo & 255,
this.lo >>> 8 & 255,
this.lo >>> 16 & 255,
this.lo >>> 24,
this.hi & 255,
this.hi >>> 8 & 255,
this.hi >>> 16 & 255,
this.hi >>> 24
);
}, "toHash");
LongBits.prototype.zzEncode = /* @__PURE__ */ __name(function zzEncode() {
var mask = this.hi >> 31;
this.hi = ((this.hi << 1 | this.lo >>> 31) ^ mask) >>> 0;
this.lo = (this.lo << 1 ^ mask) >>> 0;
return this;
}, "zzEncode");
LongBits.prototype.zzDecode = /* @__PURE__ */ __name(function zzDecode() {
var mask = -(this.lo & 1);
this.lo = ((this.lo >>> 1 | this.hi << 31) ^ mask) >>> 0;
this.hi = (this.hi >>> 1 ^ mask) >>> 0;
return this;
}, "zzDecode");
LongBits.prototype.length = /* @__PURE__ */ __name(function length() {
var part0 = this.lo, part1 = (this.lo >>> 28 | this.hi << 4) >>> 0, part2 = this.hi >>> 24;
return part2 === 0 ? part1 === 0 ? part0 < 16384 ? part0 < 128 ? 1 : 2 : part0 < 2097152 ? 3 : 4 : part1 < 16384 ? part1 < 128 ? 5 : 6 : part1 < 2097152 ? 7 : 8 : part2 < 128 ? 9 : 10;
}, "length");
}, { "39": 39 }], 39: [function(require2, module2, exports) {
var util = exports;
util.asPromise = require2(1);
util.base64 = require2(2);
util.EventEmitter = require2(4);
util.float = require2(6);
util.inquire = require2(7);
util.utf8 = require2(10);
util.pool = require2(9);
util.LongBits = require2(38);
util.emptyArray = Object.freeze ? Object.freeze([]) : (
/* istanbul ignore next */
[]
);
util.emptyObject = Object.freeze ? Object.freeze({}) : (
/* istanbul ignore next */
{}
);
util.isNode = Boolean(commonjsGlobal.process && commonjsGlobal.process.versions && commonjsGlobal.process.versions.node);
util.isInteger = Number.isInteger || /* istanbul ignore next */
/* @__PURE__ */ __name(function isInteger(value) {
return typeof value === "number" && isFinite(value) && Math.floor(value) === value;
}, "isInteger");
util.isString = /* @__PURE__ */ __name(function isString(value) {
return typeof value === "string" || value instanceof String;
}, "isString");
util.isObject = /* @__PURE__ */ __name(function isObject(value) {
return value && typeof value === "object";
}, "isObject");
util.isset = /**
* Checks if a property on a message is considered to be present.
* @param {Object} obj Plain object or message instance
* @param {string} prop Property name
* @returns {boolean} `true` if considered to be present, otherwise `false`
*/
util.isSet = /* @__PURE__ */ __name(function isSet(obj, prop) {
var value = obj[prop];
if (value != null && obj.hasOwnProperty(prop))
return typeof value !== "object" || (Array.isArray(value) ? value.length : Object.keys(value).length) > 0;
return false;
}, "isSet");
util.Buffer = (function() {
try {
var Buffer2 = util.inquire("buffer").Buffer;
return Buffer2.prototype.utf8Write ? Buffer2 : (
/* istanbul ignore next */
null
);
} catch (e) {
return null;
}
})();
util._Buffer_from = null;
util._Buffer_allocUnsafe = null;
util.newBuffer = /* @__PURE__ */ __name(function newBuffer(sizeOrArray) {
return typeof sizeOrArray === "number" ? util.Buffer ? util._Buffer_allocUnsafe(sizeOrArray) : new util.Array(sizeOrArray) : util.Buffer ? util._Buffer_from(sizeOrArray) : typeof Uint8Array === "undefined" ? sizeOrArray : new Uint8Array(sizeOrArray);
}, "newBuffer");
util.Array = typeof Uint8Array !== "undefined" ? Uint8Array : Array;
util.Long = /* istanbul ignore next */
commonjsGlobal.dcodeIO && /* istanbul ignore next */
commonjsGlobal.dcodeIO.Long || util.inquire("long");
util.key2Re = /^true|false|0|1$/;
util.key32Re = /^-?(?:0|[1-9][0-9]*)$/;
util.key64Re = /^(?:[\\x00-\\xff]{8}|-?(?:0|[1-9][0-9]*))$/;
util.longToHash = /* @__PURE__ */ __name(function longToHash(value) {
return value ? util.LongBits.from(value).toHash() : util.LongBits.zeroHash;
}, "longToHash");
util.longFromHash = /* @__PURE__ */ __name(function longFromHash(hash, unsigned) {
var bits = util.LongBits.fromHash(hash);
if (util.Long)
return util.Long.fromBits(bits.lo, bits.hi, unsigned);
return bits.toNumber(Boolean(unsigned));
}, "longFromHash");
function merge(dst, src, ifNotSet) {
for (var keys = Object.keys(src), i = 0; i < keys.length; ++i)
if (dst[keys[i]] === undefined$1 || !ifNotSet)
dst[keys[i]] = src[keys[i]];
return dst;
}
__name(merge, "merge");
util.merge = merge;
util.lcFirst = /* @__PURE__ */ __name(function lcFirst(str) {
return str.charAt(0).toLowerCase() + str.substring(1);
}, "lcFirst");
function newError(name) {
function CustomError(message, properties) {
if (!(this instanceof CustomError))
return new CustomError(message, properties);
Object.defineProperty(this, "message", { get: /* @__PURE__ */ __name(function() {
return message;
}, "get") });
if (Error.captureStackTrace)
Error.captureStackTrace(this, CustomError);
else
Object.defineProperty(this, "stack", { value: new Error().stack || "" });
if (properties)
merge(this, properties);
}
__name(CustomError, "CustomError");
(CustomError.prototype = Object.create(Error.prototype)).constructor = CustomError;
Object.defineProperty(CustomError.prototype, "name", { get: /* @__PURE__ */ __name(function() {
return name;
}, "get") });
CustomError.prototype.toString = /* @__PURE__ */ __name(function toString() {
return this.name + ": " + this.message;
}, "toString");
return CustomError;
}
__name(newError, "newError");
util.newError = newError;
util.ProtocolError = newError("ProtocolError");
util.oneOfGetter = /* @__PURE__ */ __name(function getOneOf(fieldNames) {
var fieldMap = {};
for (var i = 0; i < fieldNames.length; ++i)
fieldMap[fieldNames[i]] = 1;
return function() {
for (var keys = Object.keys(this), i2 = keys.length - 1; i2 > -1; --i2)
if (fieldMap[keys[i2]] === 1 && this[keys[i2]] !== undefined$1 && this[keys[i2]] !== null)
return keys[i2];
};
}, "getOneOf");
util.oneOfSetter = /* @__PURE__ */ __name(function setOneOf(fieldNames) {
return function(name) {
for (var i = 0; i < fieldNames.length; ++i)
if (fieldNames[i] !== name)
delete this[fieldNames[i]];
};
}, "setOneOf");
util.toJSONOptions = {
longs: String,
enums: String,
bytes: String,
json: true
};
util._configure = function() {
var Buffer2 = util.Buffer;
if (!Buffer2) {
util._Buffer_from = util._Buffer_allocUnsafe = null;
return;
}
util._Buffer_from = Buffer2.from !== Uint8Array.from && Buffer2.from || /* istanbul ignore next */
/* @__PURE__ */ __name(function Buffer_from(value, encoding) {
return new Buffer2(value, encoding);
}, "Buffer_from");
util._Buffer_allocUnsafe = Buffer2.allocUnsafe || /* istanbul ignore next */
/* @__PURE__ */ __name(function Buffer_allocUnsafe(size) {
return new Buffer2(size);
}, "Buffer_allocUnsafe");
};
}, { "1": 1, "10": 10, "2": 2, "38": 38, "4": 4, "6": 6, "7": 7, "9": 9 }], 40: [function(require2, module2, exports) {
module2.exports = verifier;
var Enum = require2(15), util = require2(37);
function invalid(field, expected) {
return field.name + ": " + expected + (field.repeated && expected !== "array" ? "[]" : field.map && expected !== "object" ? "{k:" + field.keyType + "}" : "") + " expected";
}
__name(invalid, "invalid");
function genVerifyValue(gen, field, fieldIndex, ref) {
if (field.resolvedType) {
if (field.resolvedType instanceof Enum) {
gen("switch(%s){", ref)("default:")("return%j", invalid(field, "enum value"));
for (var keys = Object.keys(field.resolvedType.values), j = 0; j < keys.length; ++j) gen("case %i:", field.resolvedType.values[keys[j]]);
gen("break")("}");
} else {
gen("{")("var e=types[%i].verify(%s);", fieldIndex, ref)("if(e)")("return%j+e", field.name + ".")("}");
}
} else {
switch (field.type) {
case "int32":
case "uint32":
case "sint32":
case "fixed32":
case "sfixed32":
gen("if(!util.isInteger(%s))", ref)("return%j", invalid(field, "integer"));
break;
case "int64":
case "uint64":
case "sint64":
case "fixed64":
case "sfixed64":
gen("if(!util.isInteger(%s)&&!(%s&&util.isInteger(%s.low)&&util.isInteger(%s.high)))", ref, ref, ref, ref)("return%j", invalid(field, "integer|Long"));
break;
case "float":
case "double":
gen('if(typeof %s!=="number")', ref)("return%j", invalid(field, "number"));
break;
case "bool":
gen('if(typeof %s!=="boolean")', ref)("return%j", invalid(field, "boolean"));
break;
case "string":
gen("if(!util.isString(%s))", ref)("return%j", invalid(field, "string"));
break;
case "bytes":
gen('if(!(%s&&typeof %s.length==="number"||util.isString(%s)))', ref, ref, ref)("return%j", invalid(field, "buffer"));
break;
}
}
return gen;
}
__name(genVerifyValue, "genVerifyValue");
function genVerifyKey(gen, field, ref) {
switch (field.keyType) {
case "int32":
case "uint32":
case "sint32":
case "fixed32":
case "sfixed32":
gen("if(!util.key32Re.test(%s))", ref)("return%j", invalid(field, "integer key"));
break;
case "int64":
case "uint64":
case "sint64":
case "fixed64":
case "sfixed64":
gen("if(!util.key64Re.test(%s))", ref)("return%j", invalid(field, "integer|Long key"));
break;
case "bool":
gen("if(!util.key2Re.test(%s))", ref)("return%j", invalid(field, "boolean key"));
break;
}
return gen;
}
__name(genVerifyKey, "genVerifyKey");
function verifier(mtype) {
var gen = util.codegen(["m"], mtype.name + "$verify")('if(typeof m!=="object"||m===null)')("return%j", "object expected");
var oneofs = mtype.oneofsArray, seenFirstField = {};
if (oneofs.length) gen("var p={}");
for (var i = 0; i < /* initializes */
mtype.fieldsArray.length; ++i) {
var field = mtype._fieldsArray[i].resolve(), ref = "m" + util.safeProp(field.name);
if (field.optional) gen("if(%s!=null&&m.hasOwnProperty(%j)){", ref, field.name);
if (field.map) {
gen("if(!util.isObject(%s))", ref)("return%j", invalid(field, "object"))("var k=Object.keys(%s)", ref)("for(var i=0;i<k.length;++i){");
genVerifyKey(gen, field, "k[i]");
genVerifyValue(gen, field, i, ref + "[k[i]]")("}");
} else if (field.repeated) {
gen("if(!Array.isArray(%s))", ref)("return%j", invalid(field, "array"))("for(var i=0;i<%s.length;++i){", ref);
genVerifyValue(gen, field, i, ref + "[i]")("}");
} else {
if (field.partOf) {
var oneofProp = util.safeProp(field.partOf.name);
if (seenFirstField[field.partOf.name] === 1) gen("if(p%s===1)", oneofProp)("return%j", field.partOf.name + ": multiple values");
seenFirstField[field.partOf.name] = 1;
gen("p%s=1", oneofProp);
}
genVerifyValue(gen, field, i, ref);
}
if (field.optional) gen("}");
}
return gen("return null");
}
__name(verifier, "verifier");
}, { "15": 15, "37": 37 }], 41: [function(require2, module2, exports) {
var wrappers = exports;
var Message = require2(21);
wrappers[".google.protobuf.Any"] = {
fromObject: /* @__PURE__ */ __name(function(object) {
if (object && object["@type"]) {
var type = this.lookup(object["@type"]);
if (type) {
var type_url = object["@type"].charAt(0) === "." ? object["@type"].substr(1) : object["@type"];
return this.create({
type_url: "/" + type_url,
value: type.encode(type.fromObject(object)).finish()
});
}
}
return this.fromObject(object);
}, "fromObject"),
toObject: /* @__PURE__ */ __name(function(message, options) {
if (options && options.json && message.type_url && message.value) {
var name = message.type_url.substring(message.type_url.lastIndexOf("/") + 1);
var type = this.lookup(name);
if (type)
message = type.decode(message.value);
}
if (!(message instanceof this.ctor) && message instanceof Message) {
var object = message.$type.toObject(message, options);
object["@type"] = message.$type.fullName;
return object;
}
return this.toObject(message, options);
}, "toObject")
};
}, { "21": 21 }], 42: [function(require2, module2, exports) {
module2.exports = Writer;
var util = require2(39);
var BufferWriter;
var LongBits = util.LongBits, base64 = util.base64, utf8 = util.utf8;
function Op(fn, len, val) {
this.fn = fn;
this.len = len;
this.next = undefined$1;
this.val = val;
}
__name(Op, "Op");
function noop() {
}
__name(noop, "noop");
function State(writer) {
this.head = writer.head;
this.tail = writer.tail;
this.len = writer.len;
this.next = writer.states;
}
__name(State, "State");
function Writer() {
this.len = 0;
this.head = new Op(noop, 0, 0);
this.tail = this.head;
this.states = null;
}
__name(Writer, "Writer");
Writer.create = util.Buffer ? /* @__PURE__ */ __name(function create_buffer_setup() {
return (Writer.create = /* @__PURE__ */ __name(function create_buffer() {
return new BufferWriter();
}, "create_buffer"))();
}, "create_buffer_setup") : /* @__PURE__ */ __name(function create_array() {
return new Writer();
}, "create_array");
Writer.alloc = /* @__PURE__ */ __name(function alloc(size) {
return new util.Array(size);
}, "alloc");
if (util.Array !== Array)
Writer.alloc = util.pool(Writer.alloc, util.Array.prototype.subarray);
Writer.prototype._push = /* @__PURE__ */ __name(function push(fn, len, val) {
this.tail = this.tail.next = new Op(fn, len, val);
this.len += len;
return this;
}, "push");
function writeByte(val, buf, pos) {
buf[pos] = val & 255;
}
__name(writeByte, "writeByte");
function writeVarint32(val, buf, pos) {
while (val > 127) {
buf[pos++] = val & 127 | 128;
val >>>= 7;
}
buf[pos] = val;
}
__name(writeVarint32, "writeVarint32");
function VarintOp(len, val) {
this.len = len;
this.next = undefined$1;
this.val = val;
}
__name(VarintOp, "VarintOp");
VarintOp.prototype = Object.create(Op.prototype);
VarintOp.prototype.fn = writeVarint32;
Writer.prototype.uint32 = /* @__PURE__ */ __name(function write_uint32(value) {
this.len += (this.tail = this.tail.next = new VarintOp(
(value = value >>> 0) < 128 ? 1 : value < 16384 ? 2 : value < 2097152 ? 3 : value < 268435456 ? 4 : 5,
value
)).len;
return this;
}, "write_uint32");
Writer.prototype.int32 = /* @__PURE__ */ __name(function write_int32(value) {
return value < 0 ? this._push(writeVarint64, 10, LongBits.fromNumber(value)) : this.uint32(value);
}, "write_int32");
Writer.prototype.sint32 = /* @__PURE__ */ __name(function write_sint32(value) {
return this.uint32((value << 1 ^ value >> 31) >>> 0);
}, "write_sint32");
function writeVarint64(val, buf, pos) {
while (val.hi) {
buf[pos++] = val.lo & 127 | 128;
val.lo = (val.lo >>> 7 | val.hi << 25) >>> 0;
val.hi >>>= 7;
}
while (val.lo > 127) {
buf[pos++] = val.lo & 127 | 128;
val.lo = val.lo >>> 7;
}
buf[pos++] = val.lo;
}
__name(writeVarint64, "writeVarint64");
Writer.prototype.uint64 = /* @__PURE__ */ __name(function write_uint64(value) {
var bits = LongBits.from(value);
return this._push(writeVarint64, bits.length(), bits);
}, "write_uint64");
Writer.prototype.int64 = Writer.prototype.uint64;
Writer.prototype.sint64 = /* @__PURE__ */ __name(function write_sint64(value) {
var bits = LongBits.from(value).zzEncode();
return this._push(writeVarint64, bits.length(), bits);
}, "write_sint64");
Writer.prototype.bool = /* @__PURE__ */ __name(function write_bool(value) {
return this._push(writeByte, 1, value ? 1 : 0);
}, "write_bool");
function writeFixed32(val, buf, pos) {
buf[pos] = val & 255;
buf[pos + 1] = val >>> 8 & 255;
buf[pos + 2] = val >>> 16 & 255;
buf[pos + 3] = val >>> 24;
}
__name(writeFixed32, "writeFixed32");
Writer.prototype.fixed32 = /* @__PURE__ */ __name(function write_fixed32(value) {
return this._push(writeFixed32, 4, value >>> 0);
}, "write_fixed32");
Writer.prototype.sfixed32 = Writer.prototype.fixed32;
Writer.prototype.fixed64 = /* @__PURE__ */ __name(function write_fixed64(value) {
var bits = LongBits.from(value);
return this._push(writeFixed32, 4, bits.lo)._push(writeFixed32, 4, bits.hi);
}, "write_fixed64");
Writer.prototype.sfixed64 = Writer.prototype.fixed64;
Writer.prototype.float = /* @__PURE__ */ __name(function write_float(value) {
return this._push(util.float.writeFloatLE, 4, value);
}, "write_float");
Writer.prototype.double = /* @__PURE__ */ __name(function write_double(value) {
return this._push(util.float.writeDoubleLE, 8, value);
}, "write_double");
var writeBytes = util.Array.prototype.set ? /* @__PURE__ */ __name(function writeBytes_set(val, buf, pos) {
buf.set(val, pos);
}, "writeBytes_set") : /* @__PURE__ */ __name(function writeBytes_for(val, buf, pos) {
for (var i = 0; i < val.length; ++i)
buf[pos + i] = val[i];
}, "writeBytes_for");
Writer.prototype.bytes = /* @__PURE__ */ __name(function write_bytes(value) {
var len = value.length >>> 0;
if (!len)
return this._push(writeByte, 1, 0);
if (util.isString(value)) {
var buf = Writer.alloc(len = base64.length(value));
base64.decode(value, buf, 0);
value = buf;
}
return this.uint32(len)._push(writeBytes, len, value);
}, "write_bytes");
Writer.prototype.string = /* @__PURE__ */ __name(function write_string(value) {
var len = utf8.length(value);
return len ? this.uint32(len)._push(utf8.write, len, value) : this._push(writeByte, 1, 0);
}, "write_string");
Writer.prototype.fork = /* @__PURE__ */ __name(function fork() {
this.states = new State(this);
this.head = this.tail = new Op(noop, 0, 0);
this.len = 0;
return this;
}, "fork");
Writer.prototype.reset = /* @__PURE__ */ __name(function reset() {
if (this.states) {
this.head = this.states.head;
this.tail = this.states.tail;
this.len = this.states.len;
this.states = this.states.next;
} else {
this.head = this.tail = new Op(noop, 0, 0);
this.len = 0;
}
return this;
}, "reset");
Writer.prototype.ldelim = /* @__PURE__ */ __name(function ldelim() {
var head = this.head, tail = this.tail, len = this.len;
this.reset().uint32(len);
if (len) {
this.tail.next = head.next;
this.tail = tail;
this.len += len;
}
return this;
}, "ldelim");
Writer.prototype.finish = /* @__PURE__ */ __name(function finish() {
var head = this.head.next, buf = this.constructor.alloc(this.len), pos = 0;
while (head) {
head.fn(head.val, buf, pos);
pos += head.len;
head = head.next;
}
return buf;
}, "finish");
Writer._configure = function(BufferWriter_) {
BufferWriter = BufferWriter_;
};
}, { "39": 39 }], 43: [function(require2, module2, exports) {
module2.exports = BufferWriter;
var Writer = require2(42);
(BufferWriter.prototype = Object.create(Writer.prototype)).constructor = BufferWriter;
var util = require2(39);
var Buffer2 = util.Buffer;
function BufferWriter() {
Writer.call(this);
}
__name(BufferWriter, "BufferWriter");
BufferWriter.alloc = /* @__PURE__ */ __name(function alloc_buffer(size) {
return (BufferWriter.alloc = util._Buffer_allocUnsafe)(size);
}, "alloc_buffer");
var writeBytesBuffer = Buffer2 && Buffer2.prototype instanceof Uint8Array && Buffer2.prototype.set.name === "set" ? /* @__PURE__ */ __name(function writeBytesBuffer_set(val, buf, pos) {
buf.set(val, pos);
}, "writeBytesBuffer_set") : /* @__PURE__ */ __name(function writeBytesBuffer_copy(val, buf, pos) {
if (val.copy)
val.copy(buf, pos, 0, val.length);
else for (var i = 0; i < val.length; )
buf[pos++] = val[i++];
}, "writeBytesBuffer_copy");
BufferWriter.prototype.bytes = /* @__PURE__ */ __name(function write_bytes_buffer(value) {
if (util.isString(value))
value = util._Buffer_from(value, "base64");
var len = value.length >>> 0;
this.uint32(len);
if (len)
this._push(writeBytesBuffer, len, value);
return this;
}, "write_bytes_buffer");
function writeStringBuffer(val, buf, pos) {
if (val.length < 40)
util.utf8.write(val, buf, pos);
else
buf.utf8Write(val, pos);
}
__name(writeStringBuffer, "writeStringBuffer");
BufferWriter.prototype.string = /* @__PURE__ */ __name(function write_string_buffer(value) {
var len = Buffer2.byteLength(value);
this.uint32(len);
if (len)
this._push(writeStringBuffer, len, value);
return this;
}, "write_string_buffer");
}, { "39": 39, "42": 42 }] }, {}, [19]);
})();
} (protobuf));
return protobuf.exports;
}
var protobufExports = /*@__PURE__*/ requireProtobuf();
const $protobuf = /*@__PURE__*/getDefaultExportFromCjs(protobufExports);
var __defProp$7 = Object.defineProperty;
var __name$7 = (target, value) => __defProp$7(target, "name", { value, configurable: true });
let $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
const $root = $protobuf.roots["push-server"] || ($protobuf.roots["push-server"] = {});
$root.RequestBatch = (function() {
function RequestBatch(properties) {
this.requests = [];
if (properties) {
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null) {
this[keys[i]] = properties[keys[i]];
}
}
}
__name$7(RequestBatch, "RequestBatch");
RequestBatch.prototype.requests = $util.emptyArray;
RequestBatch.create = /* @__PURE__ */ __name$7(function create(properties) {
return new RequestBatch(properties);
}, "create");
RequestBatch.encode = /* @__PURE__ */ __name$7(function encode(message, writer) {
if (!writer) {
writer = $Writer.create();
}
if (message.requests != null && message.requests.length) {
for (var i = 0; i < message.requests.length; ++i)
$root.Request.encode(
message.requests[i],
writer.uint32(
/* id 1, wireType 2 =*/
10
).fork()
).ldelim();
}
return writer;
}, "encode");
RequestBatch.decode = /* @__PURE__ */ __name$7(function decode(reader, length) {
if (!(reader instanceof $Reader)) {
reader = $Reader.create(reader);
}
var end = length === void 0 ? reader.len : reader.pos + length, message = new $root.RequestBatch();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (!(message.requests && message.requests.length)) {
message.requests = [];
}
message.requests.push($root.Request.decode(reader, reader.uint32()));
break;
default:
reader.skipType(tag & 7);
break;
}
}
return message;
}, "decode");
return RequestBatch;
})();
$root.Request = (function() {
function Request(properties) {
if (properties) {
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null) {
this[keys[i]] = properties[keys[i]];
}
}
}
__name$7(Request, "Request");
Request.prototype.incomingMessages = null;
Request.prototype.channelStats = null;
Request.prototype.serverStats = null;
var $oneOfFields;
Object.defineProperty(Request.prototype, "command", {
get: $util.oneOfGetter(
$oneOfFields = ["incomingMessages", "channelStats", "serverStats"]
),
set: $util.oneOfSetter($oneOfFields)
});
Request.create = /* @__PURE__ */ __name$7(function create(properties) {
return new Request(properties);
}, "create");
Request.encode = /* @__PURE__ */ __name$7(function encode(message, writer) {
if (!writer) {
writer = $Writer.create();
}
if (message.incomingMessages != null && message.hasOwnProperty("incomingMessages")) {
$root.IncomingMessagesRequest.encode(
message.incomingMessages,
writer.uint32(
/* id 1, wireType 2 =*/
10
).fork()
).ldelim();
}
if (message.channelStats != null && message.hasOwnProperty("channelStats")) {
$root.ChannelStatsRequest.encode(
message.channelStats,
writer.uint32(
/* id 2, wireType 2 =*/
18
).fork()
).ldelim();
}
if (message.serverStats != null && message.hasOwnProperty("serverStats")) {
$root.ServerStatsRequest.encode(
message.serverStats,
writer.uint32(
/* id 3, wireType 2 =*/
26
).fork()
).ldelim();
}
return writer;
}, "encode");
Request.decode = /* @__PURE__ */ __name$7(function decode(reader, length) {
if (!(reader instanceof $Reader)) {
reader = $Reader.create(reader);
}
var end = length === void 0 ? reader.len : reader.pos + length, message = new $root.Request();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
case 1:
message.incomingMessages = $root.IncomingMessagesRequest.decode(
reader,
reader.uint32()
);
break;
case 2:
message.channelStats = $root.ChannelStatsRequest.decode(
reader,
reader.uint32()
);
break;
case 3:
message.serverStats = $root.ServerStatsRequest.decode(
reader,
reader.uint32()
);
break;
default:
reader.skipType(tag & 7);
break;
}
}
return message;
}, "decode");
return Request;
})();
$root.IncomingMessagesRequest = (function() {
function IncomingMessagesRequest(properties) {
this.messages = [];
if (properties) {
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null) {
this[keys[i]] = properties[keys[i]];
}
}
}
__name$7(IncomingMessagesRequest, "IncomingMessagesRequest");
IncomingMessagesRequest.prototype.messages = $util.emptyArray;
IncomingMessagesRequest.create = /* @__PURE__ */ __name$7(function create(properties) {
return new IncomingMessagesRequest(properties);
}, "create");
IncomingMessagesRequest.encode = /* @__PURE__ */ __name$7(function encode(message, writer) {
if (!writer) {
writer = $Writer.create();
}
if (message.messages != null && message.messages.length) {
for (var i = 0; i < message.messages.length; ++i)
$root.IncomingMessage.encode(
message.messages[i],
writer.uint32(
/* id 1, wireType 2 =*/
10
).fork()
).ldelim();
}
return writer;
}, "encode");
IncomingMessagesRequest.decode = /* @__PURE__ */ __name$7(function decode(reader, length) {
if (!(reader instanceof $Reader)) {
reader = $Reader.create(reader);
}
var end = length === void 0 ? reader.len : reader.pos + length, message = new $root.IncomingMessagesRequest();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (!(message.messages && message.messages.length)) {
message.messages = [];
}
message.messages.push(
$root.IncomingMessage.decode(reader, reader.uint32())
);
break;
default:
reader.skipType(tag & 7);
break;
}
}
return message;
}, "decode");
return IncomingMessagesRequest;
})();
$root.IncomingMessage = (function() {
function IncomingMessage(properties) {
this.receivers = [];
if (properties) {
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null) {
this[keys[i]] = properties[keys[i]];
}
}
}
__name$7(IncomingMessage, "IncomingMessage");
IncomingMessage.prototype.receivers = $util.emptyArray;
IncomingMessage.prototype.sender = null;
IncomingMessage.prototype.body = "";
IncomingMessage.prototype.expiry = 0;
IncomingMessage.prototype.type = "";
IncomingMessage.create = /* @__PURE__ */ __name$7(function create(properties) {
return new IncomingMessage(properties);
}, "create");
IncomingMessage.encode = /* @__PURE__ */ __name$7(function encode(message, writer) {
if (!writer) {
writer = $Writer.create();
}
if (message.receivers != null && message.receivers.length) {
for (var i = 0; i < message.receivers.length; ++i)
$root.Receiver.encode(
message.receivers[i],
writer.uint32(
/* id 1, wireType 2 =*/
10
).fork()
).ldelim();
}
if (message.sender != null && message.hasOwnProperty("sender")) {
$root.Sender.encode(
message.sender,
writer.uint32(
/* id 2, wireType 2 =*/
18
).fork()
).ldelim();
}
if (message.body != null && message.hasOwnProperty("body")) {
writer.uint32(
/* id 3, wireType 2 =*/
26
).string(message.body);
}
if (message.expiry != null && message.hasOwnProperty("expiry")) {
writer.uint32(
/* id 4, wireType 0 =*/
32
).uint32(message.expiry);
}
if (message.type != null && message.hasOwnProperty("type")) {
writer.uint32(
/* id 5, wireType 2 =*/
42
).string(message.type);
}
return writer;
}, "encode");
IncomingMessage.decode = /* @__PURE__ */ __name$7(function decode(reader, length) {
if (!(reader instanceof $Reader)) {
reader = $Reader.create(reader);
}
var end = length === void 0 ? reader.len : reader.pos + length, message = new $root.IncomingMessage();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (!(message.receivers && message.receivers.length)) {
message.receivers = [];
}
message.receivers.push($root.Receiver.decode(reader, reader.uint32()));
break;
case 2:
message.sender = $root.Sender.decode(reader, reader.uint32());
break;
case 3:
message.body = reader.string();
break;
case 4:
message.expiry = reader.uint32();
break;
case 5:
message.type = reader.string();
break;
default:
reader.skipType(tag & 7);
break;
}
}
return message;
}, "decode");
return IncomingMessage;
})();
$root.ChannelStatsRequest = (function() {
function ChannelStatsRequest(properties) {
this.channels = [];
if (properties) {
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null) {
this[keys[i]] = properties[keys[i]];
}
}
}
__name$7(ChannelStatsRequest, "ChannelStatsRequest");
ChannelStatsRequest.prototype.channels = $util.emptyArray;
ChannelStatsRequest.create = /* @__PURE__ */ __name$7(function create(properties) {
return new ChannelStatsRequest(properties);
}, "create");
ChannelStatsRequest.encode = /* @__PURE__ */ __name$7(function encode(message, writer) {
if (!writer) {
writer = $Writer.create();
}
if (message.channels != null && message.channels.length) {
for (var i = 0; i < message.channels.length; ++i)
$root.ChannelId.encode(
message.channels[i],
writer.uint32(
/* id 1, wireType 2 =*/
10
).fork()
).ldelim();
}
return writer;
}, "encode");
ChannelStatsRequest.decode = /* @__PURE__ */ __name$7(function decode(reader, length) {
if (!(reader instanceof $Reader)) {
reader = $Reader.create(reader);
}
var end = length === void 0 ? reader.len : reader.pos + length, message = new $root.ChannelStatsRequest();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (!(message.channels && message.channels.length)) {
message.channels = [];
}
message.channels.push($root.ChannelId.decode(reader, reader.uint32()));
break;
default:
reader.skipType(tag & 7);
break;
}
}
return message;
}, "decode");
return ChannelStatsRequest;
})();
$root.ChannelId = (function() {
function ChannelId(properties) {
if (properties) {
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null) {
this[keys[i]] = properties[keys[i]];
}
}
}
__name$7(ChannelId, "ChannelId");
ChannelId.prototype.id = $util.newBuffer([]);
ChannelId.prototype.isPrivate = false;
ChannelId.prototype.signature = $util.newBuffer([]);
ChannelId.create = /* @__PURE__ */ __name$7(function create(properties) {
return new ChannelId(properties);
}, "create");
ChannelId.encode = /* @__PURE__ */ __name$7(function encode(message, writer) {
if (!writer) {
writer = $Writer.create();
}
if (message.id != null && message.hasOwnProperty("id")) {
writer.uint32(
/* id 1, wireType 2 =*/
10
).bytes(message.id);
}
if (message.isPrivate != null && message.hasOwnProperty("isPrivate")) {
writer.uint32(
/* id 2, wireType 0 =*/
16
).bool(message.isPrivate);
}
if (message.signature != null && message.hasOwnProperty("signature")) {
writer.uint32(
/* id 3, wireType 2 =*/
26
).bytes(message.signature);
}
return writer;
}, "encode");
ChannelId.decode = /* @__PURE__ */ __name$7(function decode(reader, length) {
if (!(reader instanceof $Reader)) {
reader = $Reader.create(reader);
}
var end = length === void 0 ? reader.len : reader.pos + length, message = new $root.ChannelId();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
case 1:
message.id = reader.bytes();
break;
case 2:
message.isPrivate = reader.bool();
break;
case 3:
message.signature = reader.bytes();
break;
default:
reader.skipType(tag & 7);
break;
}
}
return message;
}, "decode");
return ChannelId;
})();
$root.ServerStatsRequest = (function() {
function ServerStatsRequest(properties) {
if (properties) {
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null) {
this[keys[i]] = properties[keys[i]];
}
}
}
__name$7(ServerStatsRequest, "ServerStatsRequest");
ServerStatsRequest.create = /* @__PURE__ */ __name$7(function create(properties) {
return new ServerStatsRequest(properties);
}, "create");
ServerStatsRequest.encode = /* @__PURE__ */ __name$7(function encode(message, writer) {
if (!writer) {
writer = $Writer.create();
}
return writer;
}, "encode");
ServerStatsRequest.decode = /* @__PURE__ */ __name$7(function decode(reader, length) {
if (!(reader instanceof $Reader)) {
reader = $Reader.create(reader);
}
var end = length === void 0 ? reader.len : reader.pos + length, message = new $root.ServerStatsRequest();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
default:
reader.skipType(tag & 7);
break;
}
}
return message;
}, "decode");
return ServerStatsRequest;
})();
$root.Sender = (function() {
function Sender(properties) {
if (properties) {
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null) {
this[keys[i]] = properties[keys[i]];
}
}
}
__name$7(Sender, "Sender");
Sender.prototype.type = 0;
Sender.prototype.id = $util.newBuffer([]);
Sender.create = /* @__PURE__ */ __name$7(function create(properties) {
return new Sender(properties);
}, "create");
Sender.encode = /* @__PURE__ */ __name$7(function encode(message, writer) {
if (!writer) {
writer = $Writer.create();
}
if (message.type != null && message.hasOwnProperty("type")) {
writer.uint32(
/* id 1, wireType 0 =*/
8
).int32(message.type);
}
if (message.id != null && message.hasOwnProperty("id")) {
writer.uint32(
/* id 2, wireType 2 =*/
18
).bytes(message.id);
}
return writer;
}, "encode");
Sender.decode = /* @__PURE__ */ __name$7(function decode(reader, length) {
if (!(reader instanceof $Reader)) {
reader = $Reader.create(reader);
}
var end = length === void 0 ? reader.len : reader.pos + length, message = new $root.Sender();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
case 1:
message.type = reader.int32();
break;
case 2:
message.id = reader.bytes();
break;
default:
reader.skipType(tag & 7);
break;
}
}
return message;
}, "decode");
return Sender;
})();
$root.SenderType = (function() {
var valuesById = {}, values = Object.create(valuesById);
values[valuesById[0] = "UNKNOWN"] = 0;
values[valuesById[1] = "CLIENT"] = 1;
values[valuesById[2] = "BACKEND"] = 2;
return values;
})();
$root.Receiver = (function() {
function Receiver(properties) {
if (properties) {
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null) {
this[keys[i]] = properties[keys[i]];
}
}
}
__name$7(Receiver, "Receiver");
Receiver.prototype.id = $util.newBuffer([]);
Receiver.prototype.isPrivate = false;
Receiver.prototype.signature = $util.newBuffer([]);
Receiver.create = /* @__PURE__ */ __name$7(function create(properties) {
return new Receiver(properties);
}, "create");
Receiver.encode = /* @__PURE__ */ __name$7(function encode(message, writer) {
if (!writer) {
writer = $Writer.create();
}
if (message.id != null && message.hasOwnProperty("id")) {
writer.uint32(
/* id 1, wireType 2 =*/
10
).bytes(message.id);
}
if (message.isPrivate != null && message.hasOwnProperty("isPrivate")) {
writer.uint32(
/* id 2, wireType 0 =*/
16
).bool(message.isPrivate);
}
if (message.signature != null && message.hasOwnProperty("signature")) {
writer.uint32(
/* id 3, wireType 2 =*/
26
).bytes(message.signature);
}
return writer;
}, "encode");
Receiver.decode = /* @__PURE__ */ __name$7(function decode(reader, length) {
if (!(reader instanceof $Reader)) {
reader = $Reader.create(reader);
}
var end = length === void 0 ? reader.len : reader.pos + length, message = new $root.Receiver();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
case 1:
message.id = reader.bytes();
break;
case 2:
message.isPrivate = reader.bool();
break;
case 3:
message.signature = reader.bytes();
break;
default:
reader.skipType(tag & 7);
break;
}
}
return message;
}, "decode");
return Receiver;
})();
$root.ResponseBatch = (function() {
function ResponseBatch(properties) {
this.responses = [];
if (properties) {
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null) {
this[keys[i]] = properties[keys[i]];
}
}
}
__name$7(ResponseBatch, "ResponseBatch");
ResponseBatch.prototype.responses = $util.emptyArray;
ResponseBatch.create = /* @__PURE__ */ __name$7(function create(properties) {
return new ResponseBatch(properties);
}, "create");
ResponseBatch.encode = /* @__PURE__ */ __name$7(function encode(message, writer) {
if (!writer) {
writer = $Writer.create();
}
if (message.responses != null && message.responses.length) {
for (var i = 0; i < message.responses.length; ++i)
$root.Response.encode(
message.responses[i],
writer.uint32(
/* id 1, wireType 2 =*/
10
).fork()
).ldelim();
}
return writer;
}, "encode");
ResponseBatch.decode = /* @__PURE__ */ __name$7(function decode(reader, length) {
if (!(reader instanceof $Reader)) {
reader = $Reader.create(reader);
}
var end = length === void 0 ? reader.len : reader.pos + length, message = new $root.ResponseBatch();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (!(message.responses && message.responses.length)) {
message.responses = [];
}
message.responses.push($root.Response.decode(reader, reader.uint32()));
break;
default:
reader.skipType(tag & 7);
break;
}
}
return message;
}, "decode");
return ResponseBatch;
})();
$root.Response = (function() {
function Response(properties) {
if (properties) {
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null) {
this[keys[i]] = properties[keys[i]];
}
}
}
__name$7(Response, "Response");
Response.prototype.outgoingMessages = null;
Response.prototype.channelStats = null;
Response.prototype.serverStats = null;
var $oneOfFields;
Object.defineProperty(Response.prototype, "command", {
get: $util.oneOfGetter(
$oneOfFields = ["outgoingMessages", "channelStats", "serverStats"]
),
set: $util.oneOfSetter($oneOfFields)
});
Response.create = /* @__PURE__ */ __name$7(function create(properties) {
return new Response(properties);
}, "create");
Response.encode = /* @__PURE__ */ __name$7(function encode(message, writer) {
if (!writer) {
writer = $Writer.create();
}
if (message.outgoingMessages != null && message.hasOwnProperty("outgoingMessages")) {
$root.OutgoingMessagesResponse.encode(
message.outgoingMessages,
writer.uint32(
/* id 1, wireType 2 =*/
10
).fork()
).ldelim();
}
if (message.channelStats != null && message.hasOwnProperty("channelStats")) {
$root.ChannelStatsResponse.encode(
message.channelStats,
writer.uint32(
/* id 2, wireType 2 =*/
18
).fork()
).ldelim();
}
if (message.serverStats != null && message.hasOwnProperty("serverStats")) {
$root.JsonResponse.encode(
message.serverStats,
writer.uint32(
/* id 3, wireType 2 =*/
26
).fork()
).ldelim();
}
return writer;
}, "encode");
Response.decode = /* @__PURE__ */ __name$7(function decode(reader, length) {
if (!(reader instanceof $Reader)) {
reader = $Reader.create(reader);
}
var end = length === void 0 ? reader.len : reader.pos + length, message = new $root.Response();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
case 1:
message.outgoingMessages = $root.OutgoingMessagesResponse.decode(
reader,
reader.uint32()
);
break;
case 2:
message.channelStats = $root.ChannelStatsResponse.decode(
reader,
reader.uint32()
);
break;
case 3:
message.serverStats = $root.JsonResponse.decode(
reader,
reader.uint32()
);
break;
default:
reader.skipType(tag & 7);
break;
}
}
return message;
}, "decode");
return Response;
})();
$root.OutgoingMessagesResponse = (function() {
function OutgoingMessagesResponse(properties) {
this.messages = [];
if (properties) {
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null) {
this[keys[i]] = properties[keys[i]];
}
}
}
__name$7(OutgoingMessagesResponse, "OutgoingMessagesResponse");
OutgoingMessagesResponse.prototype.messages = $util.emptyArray;
OutgoingMessagesResponse.create = /* @__PURE__ */ __name$7(function create(properties) {
return new OutgoingMessagesResponse(properties);
}, "create");
OutgoingMessagesResponse.encode = /* @__PURE__ */ __name$7(function encode(message, writer) {
if (!writer) {
writer = $Writer.create();
}
if (message.messages != null && message.messages.length) {
for (var i = 0; i < message.messages.length; ++i)
$root.OutgoingMessage.encode(
message.messages[i],
writer.uint32(
/* id 1, wireType 2 =*/
10
).fork()
).ldelim();
}
return writer;
}, "encode");
OutgoingMessagesResponse.decode = /* @__PURE__ */ __name$7(function decode(reader, length) {
if (!(reader instanceof $Reader)) {
reader = $Reader.create(reader);
}
var end = length === void 0 ? reader.len : reader.pos + length, message = new $root.OutgoingMessagesResponse();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (!(message.messages && message.messages.length)) {
message.messages = [];
}
message.messages.push(
$root.OutgoingMessage.decode(reader, reader.uint32())
);
break;
default:
reader.skipType(tag & 7);
break;
}
}
return message;
}, "decode");
return OutgoingMessagesResponse;
})();
$root.OutgoingMessage = (function() {
function OutgoingMessage(properties) {
if (properties) {
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null) {
this[keys[i]] = properties[keys[i]];
}
}
}
__name$7(OutgoingMessage, "OutgoingMessage");
OutgoingMessage.prototype.id = $util.newBuffer([]);
OutgoingMessage.prototype.body = "";
OutgoingMessage.prototype.expiry = 0;
OutgoingMessage.prototype.created = 0;
OutgoingMessage.prototype.sender = null;
OutgoingMessage.create = /* @__PURE__ */ __name$7(function create(properties) {
return new OutgoingMessage(properties);
}, "create");
OutgoingMessage.encode = /* @__PURE__ */ __name$7(function encode(message, writer) {
if (!writer) {
writer = $Writer.create();
}
if (message.id != null && message.hasOwnProperty("id")) {
writer.uint32(
/* id 1, wireType 2 =*/
10
).bytes(message.id);
}
if (message.body != null && message.hasOwnProperty("body")) {
writer.uint32(
/* id 2, wireType 2 =*/
18
).string(message.body);
}
if (message.expiry != null && message.hasOwnProperty("expiry")) {
writer.uint32(
/* id 3, wireType 0 =*/
24
).uint32(message.expiry);
}
if (message.created != null && message.hasOwnProperty("created")) {
writer.uint32(
/* id 4, wireType 5 =*/
37
).fixed32(message.created);
}
if (message.sender != null && message.hasOwnProperty("sender")) {
$root.Sender.encode(
message.sender,
writer.uint32(
/* id 5, wireType 2 =*/
42
).fork()
).ldelim();
}
return writer;
}, "encode");
OutgoingMessage.decode = /* @__PURE__ */ __name$7(function decode(reader, length) {
if (!(reader instanceof $Reader)) {
reader = $Reader.create(reader);
}
var end = length === void 0 ? reader.len : reader.pos + length, message = new $root.OutgoingMessage();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
case 1:
message.id = reader.bytes();
break;
case 2:
message.body = reader.string();
break;
case 3:
message.expiry = reader.uint32();
break;
case 4:
message.created = reader.fixed32();
break;
case 5:
message.sender = $root.Sender.decode(reader, reader.uint32());
break;
default:
reader.skipType(tag & 7);
break;
}
}
return message;
}, "decode");
return OutgoingMessage;
})();
$root.ChannelStatsResponse = (function() {
function ChannelStatsResponse(properties) {
this.channels = [];
if (properties) {
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null) {
this[keys[i]] = properties[keys[i]];
}
}
}
__name$7(ChannelStatsResponse, "ChannelStatsResponse");
ChannelStatsResponse.prototype.channels = $util.emptyArray;
ChannelStatsResponse.create = /* @__PURE__ */ __name$7(function create(properties) {
return new ChannelStatsResponse(properties);
}, "create");
ChannelStatsResponse.encode = /* @__PURE__ */ __name$7(function encode(message, writer) {
if (!writer) {
writer = $Writer.create();
}
if (message.channels != null && message.channels.length) {
for (var i = 0; i < message.channels.length; ++i)
$root.ChannelStats.encode(
message.channels[i],
writer.uint32(
/* id 1, wireType 2 =*/
10
).fork()
).ldelim();
}
return writer;
}, "encode");
ChannelStatsResponse.decode = /* @__PURE__ */ __name$7(function decode(reader, length) {
if (!(reader instanceof $Reader)) {
reader = $Reader.create(reader);
}
var end = length === void 0 ? reader.len : reader.pos + length, message = new $root.ChannelStatsResponse();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (!(message.channels && message.channels.length)) {
message.channels = [];
}
message.channels.push(
$root.ChannelStats.decode(reader, reader.uint32())
);
break;
default:
reader.skipType(tag & 7);
break;
}
}
return message;
}, "decode");
return ChannelStatsResponse;
})();
$root.ChannelStats = (function() {
function ChannelStats(properties) {
if (properties) {
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null) {
this[keys[i]] = properties[keys[i]];
}
}
}
__name$7(ChannelStats, "ChannelStats");
ChannelStats.prototype.id = $util.newBuffer([]);
ChannelStats.prototype.isPrivate = false;
ChannelStats.prototype.isOnline = false;
ChannelStats.create = /* @__PURE__ */ __name$7(function create(properties) {
return new ChannelStats(properties);
}, "create");
ChannelStats.encode = /* @__PURE__ */ __name$7(function encode(message, writer) {
if (!writer) {
writer = $Writer.create();
}
if (message.id != null && message.hasOwnProperty("id")) {
writer.uint32(
/* id 1, wireType 2 =*/
10
).bytes(message.id);
}
if (message.isPrivate != null && message.hasOwnProperty("isPrivate")) {
writer.uint32(
/* id 2, wireType 0 =*/
16
).bool(message.isPrivate);
}
if (message.isOnline != null && message.hasOwnProperty("isOnline")) {
writer.uint32(
/* id 3, wireType 0 =*/
24
).bool(message.isOnline);
}
return writer;
}, "encode");
ChannelStats.decode = /* @__PURE__ */ __name$7(function decode(reader, length) {
if (!(reader instanceof $Reader)) {
reader = $Reader.create(reader);
}
var end = length === void 0 ? reader.len : reader.pos + length, message = new $root.ChannelStats();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
case 1:
message.id = reader.bytes();
break;
case 2:
message.isPrivate = reader.bool();
break;
case 3:
message.isOnline = reader.bool();
break;
default:
reader.skipType(tag & 7);
break;
}
}
return message;
}, "decode");
return ChannelStats;
})();
$root.JsonResponse = (function() {
function JsonResponse(properties) {
if (properties) {
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null) {
this[keys[i]] = properties[keys[i]];
}
}
}
__name$7(JsonResponse, "JsonResponse");
JsonResponse.prototype.json = "";
JsonResponse.create = /* @__PURE__ */ __name$7(function create(properties) {
return new JsonResponse(properties);
}, "create");
JsonResponse.encode = /* @__PURE__ */ __name$7(function encode(message, writer) {
if (!writer) {
writer = $Writer.create();
}
if (message.json != null && message.hasOwnProperty("json")) {
writer.uint32(
/* id 1, wireType 2 =*/
10
).string(message.json);
}
return writer;
}, "encode");
JsonResponse.decode = /* @__PURE__ */ __name$7(function decode(reader, length) {
if (!(reader instanceof $Reader)) {
reader = $Reader.create(reader);
}
var end = length === void 0 ? reader.len : reader.pos + length, message = new $root.JsonResponse();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
case 1:
message.json = reader.string();
break;
default:
reader.skipType(tag & 7);
break;
}
}
return message;
}, "decode");
return JsonResponse;
})();
const ResponseBatch = $root["ResponseBatch"];
const RequestBatch = $root["RequestBatch"];
const IncomingMessage = $root["IncomingMessage"];
const Receiver = $root["Receiver"];
var __defProp$6 = Object.defineProperty;
var __name$6 = (target, value) => __defProp$6(target, "name", { value, configurable: true });
class AbstractConnector {
static {
__name$6(this, "AbstractConnector");
}
_logger;
_connected = false;
_connectionType;
_disconnectCode = 0;
_disconnectReason = "";
_parent;
_callbacks;
constructor(config) {
this._logger = LoggerFactory.createNullLogger();
this._parent = config.parent;
this._connectionType = ConnectionType.Undefined;
this._callbacks = {
onOpen: Type.isFunction(config.onOpen) ? config.onOpen : () => {
},
onDisconnect: Type.isFunction(config.onDisconnect) ? config.onDisconnect : () => {
},
onError: Type.isFunction(config.onError) ? config.onError : () => {
},
onMessage: Type.isFunction(config.onMessage) ? config.onMessage : () => {
}
};
}
setLogger(logger) {
this._logger = logger;
}
getLogger() {
return this._logger;
}
destroy() {
}
get connected() {
return this._connected;
}
set connected(value) {
if (value == this._connected) {
return;
}
this._connected = value;
if (this._connected) {
this._callbacks.onOpen();
} else {
this._callbacks.onDisconnect({
code: this.disconnectCode,
reason: this.disconnectReason
});
}
}
get disconnectCode() {
return this._disconnectCode;
}
get disconnectReason() {
return this._disconnectReason;
}
get connectionPath() {
return this._parent.getConnectionPath(this._connectionType);
}
}
var __defProp$5 = Object.defineProperty;
var __name$5 = (target, value) => __defProp$5(target, "name", { value, configurable: true });
class WebSocketConnector extends AbstractConnector {
static {
__name$5(this, "WebSocketConnector");
}
_socket;
_onSocketOpenHandler;
_onSocketCloseHandler;
_onSocketErrorHandler;
_onSocketMessageHandler;
constructor(config) {
super(config);
this._connectionType = ConnectionType.WebSocket;
this._socket = null;
this._onSocketOpenHandler = this._onSocketOpen.bind(this);
this._onSocketCloseHandler = this._onSocketClose.bind(this);
this._onSocketErrorHandler = this._onSocketError.bind(this);
this._onSocketMessageHandler = this._onSocketMessage.bind(this);
}
destroy() {
super.destroy();
if (this._socket) {
this._socket.close();
this._socket = null;
}
}
/**
* @inheritDoc
*/
connect() {
if (this._socket) {
if (this._socket.readyState === 1) {
return;
} else {
this.clearEventListener();
this._socket.close();
this._socket = null;
}
}
this._createSocket();
}
get socket() {
return this._socket;
}
/**
* @inheritDoc
* @param code
* @param reason
*/
disconnect(code, reason) {
if (this._socket !== null) {
this.clearEventListener();
this._socket.close(code, reason);
}
this._socket = null;
this._disconnectCode = code;
this._disconnectReason = reason;
this.connected = false;
}
/**
* Via websocket connection
* @inheritDoc
*/
send(buffer) {
if (!this._socket || this._socket.readyState !== 1) {
this.getLogger().error(`${Text.getDateForLog()}: Pull: WebSocket is not connected`).catch(() => {
});
return false;
}
this._socket.send(buffer);
return true;
}
// region Event Handlers ////
_onSocketOpen() {
this.connected = true;
}
_onSocketClose(event) {
this._socket = null;
this._disconnectCode = Number(event.code);
this._disconnectReason = event.reason;
this.connected = false;
}
_onSocketError(event) {
this._callbacks.onError(new Error(`Socket error: ${event}`));
}
_onSocketMessage(event) {
this._callbacks.onMessage(event.data);
}
// endregion ////
// region Tools ////
clearEventListener() {
if (this._socket) {
this._socket.removeEventListener("open", this._onSocketOpenHandler);
this._socket.removeEventListener("close", this._onSocketCloseHandler);
this._socket.removeEventListener("error", this._onSocketErrorHandler);
this._socket.removeEventListener("message", this._onSocketMessageHandler);
}
}
_createSocket() {
if (this._socket) {
throw new Error("Socket already exists");
}
if (!this.connectionPath) {
throw new Error("Websocket connection path is not defined");
}
this._socket = new WebSocket(this.connectionPath);
this._socket.binaryType = "arraybuffer";
this._socket.addEventListener("open", this._onSocketOpenHandler);
this._socket.addEventListener("close", this._onSocketCloseHandler);
this._socket.addEventListener("error", this._onSocketErrorHandler);
this._socket.addEventListener("message", this._onSocketMessageHandler);
}
// endregion ////
}
var __defProp$4 = Object.defineProperty;
var __name$4 = (target, value) => __defProp$4(target, "name", { value, configurable: true });
const LONG_POLLING_TIMEOUT = 60;
class LongPollingConnector extends AbstractConnector {
static {
__name$4(this, "LongPollingConnector");
}
_active;
_requestTimeout;
_failureTimeout;
// Created lazily on the first connect() rather than in the constructor: the
// connector is built eagerly by PullClient.init() (which runs inside start())
// regardless of the chosen transport, and `new XMLHttpRequest()` throws a
// ReferenceError under SSR/Node where the global is absent. Deferring it keeps
// construct + init + start SSR-safe; connect() degrades gracefully instead. (#222)
_xhr;
_requestAborted;
constructor(config) {
super(config);
this._active = false;
this._connectionType = ConnectionType.LongPolling;
this._requestTimeout = null;
this._failureTimeout = null;
this._xhr = null;
this._requestAborted = false;
}
/**
* @inheritDoc
*/
connect() {
if (!this._xhr) {
if (typeof XMLHttpRequest === "undefined") {
this._callbacks.onError(
new Error(
"LongPollingConnector: XMLHttpRequest is not available in this environment (SSR/Node); a long-polling connection requires a browser"
)
);
return;
}
this._xhr = this.createXhr();
}
this._active = true;
this.performRequest();
}
/**
* @inheritDoc
* @param code
* @param reason
*/
disconnect(code, reason) {
this._active = false;
this.clearTimeOut();
if (this._xhr) {
this._requestAborted = true;
this._xhr.abort();
}
this._disconnectCode = code;
this._disconnectReason = reason;
this.connected = false;
}
performRequest() {
if (!this._active) {
return;
}
if (!this.connectionPath) {
throw new Error("Long polling connection path is not defined");
}
const xhr = this._xhr;
if (!xhr) {
return;
}
if (xhr.readyState !== 0 && xhr.readyState !== 4) {
return;
}
this.clearTimeOut();
this._failureTimeout = setTimeout(() => {
this.connected = true;
}, 5e3);
this._requestTimeout = setTimeout(
this.onRequestTimeout.bind(this),
LONG_POLLING_TIMEOUT * 1e3
);
xhr.open("GET", this.connectionPath);
xhr.send();
}
onRequestTimeout() {
this._requestAborted = true;
this._xhr?.abort();
this.performRequest();
}
onXhrReadyStateChange() {
const xhr = this._xhr;
if (!xhr) {
return;
}
if (xhr.readyState === 4) {
if (!this._requestAborted || xhr.status == 200) {
this.onResponse(xhr.response);
}
this._requestAborted = false;
}
}
/**
* Via http request
* @inheritDoc
*/
send(buffer) {
const path = this._parent.getPublicationPath();
if (!path) {
this.getLogger().error(`${Text.getDateForLog()}: Pull: publication path is empty`).catch(() => {
});
return false;
}
if (typeof XMLHttpRequest === "undefined") {
this.getLogger().error(
`${Text.getDateForLog()}: Pull: XMLHttpRequest is not available; cannot publish`
).catch(() => {
});
return false;
}
const xhr = new XMLHttpRequest();
xhr.open("POST", path);
xhr.send(buffer);
return true;
}
onResponse(response) {
this.clearTimeOut();
const xhr = this._xhr;
if (!xhr) {
return;
}
if (xhr.status === 200) {
this.connected = true;
if (Type.isStringFilled(response) || response instanceof ArrayBuffer) {
this._callbacks.onMessage(response);
} else {
this._parent.session.mid = null;
}
this.performRequest();
} else if (xhr.status === 304) {
this.connected = true;
if (xhr.getResponseHeader("Expires") === "Thu, 01 Jan 1973 11:11:01 GMT") {
const lastMessageId = xhr.getResponseHeader("Last-Message-Id");
if (Type.isStringFilled(lastMessageId)) {
this._parent.setLastMessageId(lastMessageId || "");
}
}
this.performRequest();
} else {
this._callbacks.onError(new Error("Could not connect to the server"));
this.connected = false;
}
}
// region Tools ////
clearTimeOut() {
if (this._failureTimeout) {
clearTimeout(this._failureTimeout);
this._failureTimeout = null;
}
if (this._requestTimeout) {
clearTimeout(this._requestTimeout);
this._requestTimeout = null;
}
}
createXhr() {
const result = new XMLHttpRequest();
if (this._parent.isProtobufSupported() && !this._parent.isJsonRpc()) {
result.responseType = "arraybuffer";
}
result.addEventListener(
"readystatechange",
this.onXhrReadyStateChange.bind(this)
);
return result;
}
// endregion ////
}
var __defProp$3 = Object.defineProperty;
var __name$3 = (target, value) => __defProp$3(target, "name", { value, configurable: true });
const REVISION = 19;
const RESTORE_WEBSOCKET_TIMEOUT = 30 * 60;
const OFFLINE_STATUS_DELAY = 5e3;
const CONFIG_CHECK_INTERVAL = 60 * 1e3;
const MAX_IDS_TO_STORE = 10;
const PING_TIMEOUT = 10;
const JSON_RPC_PING = "ping";
const JSON_RPC_PONG = "pong";
const LS_SESSION = "bx-pull-session";
const LS_SESSION_CACHE_TIME = 20;
const EmptyConfig = {
api: {},
channels: {},
publicChannels: {},
server: { timeShift: 0 },
clientId: null,
jwt: null,
exp: 0
};
class PullClient {
static {
__name$3(this, "PullClient");
}
// region Params ////
_logger;
_restClient;
_status;
_context;
_guestMode;
_guestUserId;
_userId;
_configGetMethod;
_getPublicListMethod;
_siteId;
_enabled;
_unloading = false;
_starting = false;
_debug = false;
_connectionAttempt = 0;
_connectionType = ConnectionType.WebSocket;
_skipStorageInit;
_skipCheckRevision;
_subscribers = {};
_watchTagsQueue = /* @__PURE__ */ new Map();
_watchUpdateInterval = 174e4;
_watchForceUpdateInterval = 5e3;
_configTimestamp = 0;
_session = {
mid: null,
tag: null,
time: null,
history: {},
lastMessageIds: [],
messageCount: 0
};
_connectors = {
[ConnectionType.Undefined]: null,
[ConnectionType.WebSocket]: null,
[ConnectionType.LongPolling]: null
};
_isSecure;
_config = null;
_storage = null;
_sharedConfig;
_channelManager;
_jsonRpcAdapter = null;
/**
* @depricate
*/
// private _notificationPopup: null = null
// timers ////
_reconnectTimeout = null;
_restartTimeout = null;
_restoreWebSocketTimeout = null;
_checkInterval = null;
_offlineTimeout = null;
_watchUpdateTimeout = null;
_pingWaitTimeout = null;
// Single source of truth for every tracked timer field. armTimeout()/
// clearAllTimers() route through this list so a future timer cannot be added
// without a matching teardown — the leak class behind #141 (#222). Individual
// fields are kept because call-sites read their identity (e.g. `if
// (this._reconnectTimeout)`), but clearAllTimers() is the one teardown path.
_timerFields = [
"_reconnectTimeout",
"_restartTimeout",
"_restoreWebSocketTimeout",
"_checkInterval",
"_offlineTimeout",
"_watchUpdateTimeout",
"_pingWaitTimeout"
];
// Records every window listener init() registered so removeAllWindowListeners()
// can drop exactly what was added, keeping arm/teardown symmetric (#222).
_windowListeners = [];
// manual stop workaround ////
_isManualDisconnect = false;
// set once destroy() has run; gates reconnect / watch / online so a torn-down
// client never schedules new work (#141) ////
_disposed = false;
_loggingEnabled = false;
// bound event handlers, stored so they can be removed in destroy() (#141) ////
_onPingTimeoutHandler;
_onBeforeUnloadHandler;
_onOfflineHandler;
_onOnlineHandler;
// [userId] => array of callbacks
_userStatusCallbacks = {};
_connectPromise = null;
_startingPromise = null;
// Monotonic token bumped on every start() and on destroy(). start()'s
// loadConfig()/connect() continuations capture the value at kick-off and bail
// if it no longer matches — deterministically neutralising an in-flight start()
// when destroy() (or a fresh start()) supersedes it, even for overlapping
// start/destroy/start. The underlying rest transport
// (this._restClient.actions.v2.call.make) does not accept an AbortSignal, so
// this generation-token approach is used instead of an AbortController; the
// network round-trip itself is not cancelled (remaining follow-up). (#222)
_startGeneration = 0;
// endregion ////
// region Init ////
/**
* @param params
*/
constructor(params) {
this._logger = LoggerFactory.createNullLogger();
this._restClient = params.b24;
this._status = PullStatus.Offline;
this._context = "master";
if (params.restApplication) {
if (typeof params.configGetMethod === "undefined") {
params.configGetMethod = "pull.application.config.get";
}
if (typeof params.skipCheckRevision === "undefined") {
params.skipCheckRevision = true;
}
if (Type.isStringFilled(params.restApplication)) {
params.siteId = params.restApplication;
}
params.serverEnabled = true;
}
this._guestMode = params.guestMode ? Text.toBoolean(params.guestMode) : false;
this._guestUserId = params.guestUserId ? Text.toInteger(params.guestUserId) : 0;
if (this._guestMode && this._guestUserId > 0) {
this._userId = this._guestUserId;
} else {
this._guestMode = false;
this._userId = params.userId ? Text.toInteger(params.userId) : 0;
}
this._siteId = params.siteId ?? "none";
this._enabled = !Type.isUndefined(params.serverEnabled) ? params.serverEnabled === true : true;
this._configGetMethod = !Type.isStringFilled(params.configGetMethod) ? "pull.config.get" : params.configGetMethod || "";
this._getPublicListMethod = !Type.isStringFilled(params.getPublicListMethod) ? "pull.channel.public.list" : params.getPublicListMethod || "";
this._skipStorageInit = params.skipStorageInit === true;
this._skipCheckRevision = params.skipCheckRevision === true;
if (!Type.isUndefined(params.configTimestamp)) {
this._configTimestamp = Text.toInteger(params.configTimestamp);
}
this._isSecure = typeof document !== "undefined" && document?.location.href.indexOf("https") === 0;
if (this._userId && !this._skipStorageInit) {
this._storage = new StorageManager({
userId: this._userId,
siteId: this._siteId
});
}
this._sharedConfig = new SharedConfig({
onWebSocketBlockChanged: this.onWebSocketBlockChanged.bind(this),
storage: this._storage
});
this._channelManager = new ChannelManager({
b24: this._restClient,
getPublicListMethod: this._getPublicListMethod
});
this._loggingEnabled = this._sharedConfig.isLoggingEnabled();
this._onPingTimeoutHandler = this.onPingTimeout.bind(this);
this._onBeforeUnloadHandler = this.onBeforeUnload.bind(this);
this._onOfflineHandler = this.onOffline.bind(this);
this._onOnlineHandler = this.onOnline.bind(this);
}
setLogger(logger) {
this._logger = logger;
this._jsonRpcAdapter?.setLogger(this.getLogger());
this._storage?.setLogger(this.getLogger());
this._sharedConfig.setLogger(this.getLogger());
this._channelManager.setLogger(this.getLogger());
this._connectors.webSocket?.setLogger(this.getLogger());
this._connectors.longPolling?.setLogger(this.getLogger());
}
getLogger() {
return this._logger;
}
/**
* Terminal teardown: removes the window listeners, cancels every pending timer,
* persists the session for a quick re-init, and disconnects. Irreversible — a
* destroyed client schedules no further work and `start()` rejects with
* `PULL_DISPOSED`; create a new instance to reconnect.
*/
destroy() {
this._disposed = true;
this._startGeneration++;
this.stop(CloseReasons.NORMAL_CLOSURE, "manual stop");
this.removeAllWindowListeners();
if (this._storage) {
this._storage.remove(LsKeys.PullConfig);
}
this.persistSession();
}
init() {
if (this._disposed) {
return;
}
this._connectors.webSocket = new WebSocketConnector({
parent: this,
onOpen: this.onWebSocketOpen.bind(this),
onMessage: this.onIncomingMessage.bind(this),
onDisconnect: this.onWebSocketDisconnect.bind(this),
onError: this.onWebSocketError.bind(this)
});
this._connectors.longPolling = new LongPollingConnector({
parent: this,
onOpen: this.onLongPollingOpen.bind(this),
onMessage: this.onIncomingMessage.bind(this),
onDisconnect: this.onLongPollingDisconnect.bind(this),
onError: this.onLongPollingError.bind(this)
});
this._connectionType = this.isWebSocketAllowed() ? ConnectionType.WebSocket : ConnectionType.LongPolling;
this.addWindowListener("beforeunload", this._onBeforeUnloadHandler);
this.addWindowListener("offline", this._onOfflineHandler);
this.addWindowListener("online", this._onOnlineHandler);
this._jsonRpcAdapter = new JsonRpc({
connector: this._connectors.webSocket,
handlers: {
"incoming.message": this.handleRpcIncomingMessage.bind(this)
}
});
}
// endregion ////
// region Get-Set ////
get connector() {
return this._connectors[this._connectionType];
}
get status() {
return this._status;
}
/**
* @param status
*/
set status(status) {
if (this._status === status) {
return;
}
this._status = status;
if (this._offlineTimeout) {
clearTimeout(this._offlineTimeout);
this._offlineTimeout = null;
}
if (status === PullStatus.Offline) {
this.sendPullStatusDelayed(status, OFFLINE_STATUS_DELAY);
} else {
this.sendPullStatus(status);
}
}
get session() {
return this._session;
}
// endregion ////
// region Public /////
/**
* Creates a subscription to incoming messages.
*
* @param {TypeSubscriptionOptions | TypeSubscriptionCommandHandler} params
* @returns { () => void } - Unsubscribe callback function
*/
subscribe(params) {
if (!Type.isPlainObject(params)) {
return this.attachCommandHandler(params);
}
params = params;
params.type = params.type || SubscriptionType.Server;
params.command = params.command || null;
if (params.type == SubscriptionType.Server || params.type == SubscriptionType.Client) {
if (typeof params.moduleId === "undefined") {
throw new TypeError(
`${Text.getDateForLog()}: Pull.subscribe: parameter moduleId is not specified`
);
}
if (typeof this._subscribers[params.type] === "undefined") {
this._subscribers[params.type] = {};
}
if (typeof this._subscribers[params.type][params.moduleId] === "undefined") {
this._subscribers[params.type][params.moduleId] = {
callbacks: [],
commands: {}
};
}
if (params.command) {
if (typeof this._subscribers[params.type][params.moduleId]["commands"][params.command] === "undefined") {
this._subscribers[params.type][params.moduleId]["commands"][params.command] = [];
}
this._subscribers[params.type][params.moduleId]["commands"][params.command].push(params.callback);
return () => {
if (typeof params.type === "undefined" || typeof params.moduleId === "undefined" || typeof params.command === "undefined" || null === params.command) {
return;
}
this._subscribers[params.type][params.moduleId]["commands"][params.command] = this._subscribers[params.type][params.moduleId]["commands"][params.command].filter((element) => {
return element !== params.callback;
});
};
} else {
this._subscribers[params.type][params.moduleId]["callbacks"].push(
params.callback
);
return () => {
if (typeof params.type === "undefined" || typeof params.moduleId === "undefined") {
return;
}
this._subscribers[params.type][params.moduleId]["callbacks"] = this._subscribers[params.type][params.moduleId]["callbacks"].filter(
(element) => {
return element !== params.callback;
}
);
};
}
} else {
if (typeof this._subscribers[params.type] === "undefined") {
this._subscribers[params.type] = [];
}
this._subscribers[params.type].push(params.callback);
return () => {
if (typeof params.type === "undefined") {
return;
}
this._subscribers[params.type] = this._subscribers[params.type].filter(
(element) => {
return element !== params.callback;
}
);
};
}
}
/**
* @param {TypeSubscriptionCommandHandler} handler
* @returns {() => void} - Unsubscribe callback function
*/
attachCommandHandler(handler) {
if (typeof handler.getModuleId !== "function" || typeof handler.getModuleId() !== "string") {
this.getLogger().error(`${Text.getDateForLog()}: Pull.attachCommandHandler: result of handler.getModuleId() is not a string.`).catch(() => {
});
return () => {
};
}
let type = SubscriptionType.Server;
if (typeof handler.getSubscriptionType === "function") {
type = handler.getSubscriptionType();
}
return this.subscribe({
type,
moduleId: handler.getModuleId(),
callback: /* @__PURE__ */ __name$3((data) => {
let method = null;
if (typeof handler.getMap === "function") {
const mapping = handler.getMap();
if (mapping && typeof mapping === "object") {
const rowMapping = mapping[data.command];
if (typeof rowMapping === "function") {
method = rowMapping.bind(handler);
} else if (typeof rowMapping === "string" && typeof handler[rowMapping] === "function") {
method = handler[rowMapping].bind(handler);
}
}
}
if (!method) {
const methodName = `handle${Text.capitalize(data.command)}`;
if (typeof handler[methodName] === "function") {
method = handler[methodName].bind(handler);
}
}
if (method) {
if (this._debug && this._context !== "master") {
this.getLogger().warning(
`${Text.getDateForLog()}: Pull.attachCommandHandler: result of handler.getModuleId() is not a string`,
// data.params / data.extra are app-defined and may carry a credential key (#43)
redactSensitiveParams({ data })
).catch(() => {
});
}
method(data.params, data.extra, data.command);
}
}, "callback")
});
}
/**
* Connects the client and begins receiving events.
*
* @param config
* @throws Rejects with `{ ex: { error: 'PULL_DISPOSED' } }` when called after
* `destroy()` — a destroyed client cannot be restarted; create a new instance.
*/
async start(config = null) {
if (this._disposed) {
return Promise.reject({
ex: {
error: "PULL_DISPOSED",
error_description: "PullClient has been destroyed; create a new instance"
}
});
}
let allowConfigCaching = true;
if (this.isConnected()) {
return Promise.resolve(true);
}
if (this._starting && this._startingPromise) {
return this._startingPromise;
}
if (!this._userId) {
throw new Error("Not set userId");
}
if (this._siteId === "none") {
throw new Error("Not set siteId");
}
let skipReconnectToLastSession = false;
if (!!config && Type.isPlainObject(config)) {
if (typeof config?.skipReconnectToLastSession !== "undefined") {
skipReconnectToLastSession = config.skipReconnectToLastSession;
delete config.skipReconnectToLastSession;
}
this._config = config;
allowConfigCaching = false;
}
if (!this._enabled) {
return Promise.reject({
ex: {
error: "PULL_DISABLED",
error_description: "Push & Pull server is disabled"
}
});
}
const now = Date.now();
let oldSession;
if (!skipReconnectToLastSession && this._storage) {
oldSession = this._storage.get(LS_SESSION, null);
}
if (Type.isPlainObject(oldSession) && Object.prototype.hasOwnProperty.call(oldSession, "ttl") && oldSession["ttl"] >= now) {
this._session.mid = oldSession["mid"];
}
this._starting = true;
const startGeneration = ++this._startGeneration;
return this._startingPromise = new Promise((resolve, reject) => {
this.loadConfig("client_start").then((config2) => {
if (this._disposed || this._startGeneration !== startGeneration) {
this._starting = false;
reject({
ex: {
error: "PULL_DISPOSED",
error_description: "PullClient has been destroyed; create a new instance"
}
});
return;
}
this.setConfig(config2, allowConfigCaching);
this.init();
this.updateWatch(true);
this.startCheckConfig();
this.connect().then(
() => resolve(true),
(error) => reject(error)
);
}).catch((error) => {
this._starting = false;
this.status = PullStatus.Offline;
this.stopCheckConfig();
this.getLogger().error(
`${Text.getDateForLog()}: Pull: could not read push-server config`,
{ error }
).catch(() => {
});
reject(error);
});
});
}
/**
* @param disconnectCode
* @param disconnectReason
*/
restart(disconnectCode = CloseReasons.NORMAL_CLOSURE, disconnectReason = "manual restart") {
if (this._disposed) {
return;
}
if (this._restartTimeout) {
clearTimeout(this._restartTimeout);
this._restartTimeout = null;
}
this.getLogger().debug(
`${Text.getDateForLog()}: Pull: restarting with code ${disconnectCode}`
).catch(() => {
});
this.disconnect(disconnectCode, disconnectReason);
if (this._storage) {
this._storage.remove(LsKeys.PullConfig);
}
this._config = null;
const loadConfigReason = `${disconnectCode}_${disconnectReason.replaceAll(" ", "_")}`;
this.loadConfig(loadConfigReason).then(
(config) => {
this.setConfig(config, true);
this.updateWatch();
this.startCheckConfig();
this.connect().catch((error) => {
this.getLogger().error("restart error", { error }).catch(() => {
});
});
},
(error) => {
this.getLogger().error(
`${Text.getDateForLog()}: Pull: could not read push-server config `,
{ error }
).catch(() => {
});
this.status = PullStatus.Offline;
if (this._reconnectTimeout) {
clearTimeout(this._reconnectTimeout);
this._reconnectTimeout = null;
}
if (error?.status == 401 || error?.status == 403) {
this.stopCheckConfig();
this.onCustomEvent("onPullError", ["AUTHORIZE_ERROR"]);
}
}
);
}
stop(disconnectCode = CloseReasons.NORMAL_CLOSURE, disconnectReason = "manual stop") {
this.disconnect(disconnectCode, disconnectReason);
this.stopCheckConfig();
this.clearAllTimers();
}
// Cancel every pending timer so a stopped/destroyed client leaves nothing
// running. Previously only _checkInterval was cleared, so the other six timers
// (including the self-rescheduling watch-extend) survived teardown (#141).
clearAllTimers() {
for (const field of this._timerFields) {
const timer = this[field];
if (timer) {
if (field === "_checkInterval") {
clearInterval(timer);
} else {
clearTimeout(timer);
}
}
this[field] = null;
}
}
// Arm a tracked setTimeout: clears any existing id for the field first (same
// clear-before-set the call-sites did by hand), then stores the new id. The
// interval-backed _checkInterval keeps its own setInterval path. (#222)
armTimeout(field, fn, ms) {
const existing = this[field];
if (existing) {
clearTimeout(existing);
}
this[field] = setTimeout(fn, ms);
}
// Window-listener registry: init() adds through here, destroy() drops through
// removeAllWindowListeners(), so a listener can't be added without teardown. (#222)
addWindowListener(type, handler) {
if (typeof window === "undefined") {
return;
}
window.addEventListener(type, handler);
this._windowListeners.push({ type, handler });
}
removeAllWindowListeners() {
if (typeof window !== "undefined") {
for (const { type, handler } of this._windowListeners) {
window.removeEventListener(type, handler);
}
}
this._windowListeners = [];
}
reconnect(disconnectCode, disconnectReason, delay = 1) {
this.disconnect(disconnectCode, disconnectReason);
this.scheduleReconnect(delay);
}
/**
* @param lastMessageId
*/
setLastMessageId(lastMessageId) {
this._session.mid = lastMessageId;
}
/**
* Send a single message to the specified users.
*
* @param users User ids of the message receivers.
* @param moduleId Name of the module to receive a message,
* @param command Command name.
* @param {object} params Command parameters.
* @param [expiry] Message expiry time in seconds.
* @return {Promise}
*/
async sendMessage(users, moduleId, command, params, expiry) {
const message = {
userList: users,
body: {
module_id: moduleId,
command,
params
},
expiry
};
if (this.isJsonRpc()) {
return this._jsonRpcAdapter?.executeOutgoingRpcCommand(
RpcMethod.Publish,
message
);
} else {
return this.sendMessageBatch([message]);
}
}
/**
* Send a single message to the specified public channels.
*
* @param publicChannels Public ids of the channels to receive a message.
* @param moduleId Name of the module to receive a message,
* @param command Command name.
* @param {object} params Command parameters.
* @param [expiry] Message expiry time in seconds.
* @return {Promise}
*/
async sendMessageToChannels(publicChannels, moduleId, command, params, expiry) {
const message = {
channelList: publicChannels,
body: {
module_id: moduleId,
command,
params
},
expiry
};
if (this.isJsonRpc()) {
return this._jsonRpcAdapter?.executeOutgoingRpcCommand(
RpcMethod.Publish,
message
);
} else {
return this.sendMessageBatch([message]);
}
}
/**
* @param debugFlag
*/
capturePullEvent(debugFlag = true) {
this._debug = debugFlag;
}
/**
* @param loggingFlag
*/
enableLogging(loggingFlag = true) {
this._sharedConfig.setLoggingEnabled(loggingFlag);
this._loggingEnabled = loggingFlag;
}
/**
* Returns list channels that the connection is subscribed to.
*
* @returns {Promise}
*/
async listChannels() {
return this._jsonRpcAdapter?.executeOutgoingRpcCommand(
RpcMethod.ListChannels,
{}
) || Promise.reject(new Error("jsonRpcAdapter not init"));
}
/**
* Returns "last seen" time in seconds for the users.
* Result format: Object{userId: int}
* If the user is currently connected - will return 0.
* If the user is offline - will return the diff between the current timestamp and the last seen timestamp in seconds.
* If the user was never online - the record for the user will be missing from the result object.
*
* @param {integer[]} userList List of user ids.
* @returns {Promise}
*/
async getUsersLastSeen(userList) {
if (!Type.isArray(userList) || !userList.every((item) => typeof item === "number")) {
throw new Error("userList must be an array of numbers");
}
const result = {};
return new Promise((resolve, reject) => {
this._jsonRpcAdapter?.executeOutgoingRpcCommand(RpcMethod.GetUsersLastSeen, {
userList
}).then((response) => {
const unresolved = [];
for (let i = 0; i < userList.length; i++) {
if (!Object.prototype.hasOwnProperty.call(response, userList[i])) {
unresolved.push(userList[i]);
}
}
if (unresolved.length === 0) {
return resolve(result);
}
const params = {
userIds: unresolved,
sendToQueueSever: true
};
this._restClient.actions.v2.call.make({
method: "pull.api.user.getLastSeen",
params
}).then((response2) => {
const data = response2.getData().result;
for (const userId in data) {
result[Number(userId)] = Number(data[userId]);
}
return resolve(result);
}).catch((error) => {
this.getLogger().error("getUsersLastSeen", { error }).catch(() => {
});
reject(error);
});
}).catch((error) => {
this.getLogger().error("getUsersLastSeen", { error }).catch(() => {
});
reject(error);
});
});
}
/**
* Pings server.
* In case of success promise will be resolved, otherwise - rejected.
*
* @param {number} timeout Request timeout in seconds
* @returns {Promise}
*/
async ping(timeout = 5) {
return this._jsonRpcAdapter?.executeOutgoingRpcCommand(
RpcMethod.Ping,
{},
timeout
);
}
/**
* @param userId {number}
* @param callback {UserStatusCallback}
* @returns {Promise}
*/
async subscribeUserStatusChange(userId, callback) {
return new Promise((resolve, reject) => {
this._jsonRpcAdapter?.executeOutgoingRpcCommand(RpcMethod.SubscribeStatusChange, {
userId
}).then(() => {
if (!this._userStatusCallbacks[userId]) {
this._userStatusCallbacks[userId] = [];
}
if (Type.isFunction(callback)) {
this._userStatusCallbacks[userId].push(callback);
}
return resolve();
}).catch((error) => reject(error));
});
}
/**
* @param {number} userId
* @param {UserStatusCallback} callback
* @returns {Promise}
*/
async unsubscribeUserStatusChange(userId, callback) {
if (this._userStatusCallbacks[userId]) {
this._userStatusCallbacks[userId] = this._userStatusCallbacks[userId].filter((cb) => cb !== callback);
if (this._userStatusCallbacks[userId].length === 0) {
return this._jsonRpcAdapter?.executeOutgoingRpcCommand(
RpcMethod.UnsubscribeStatusChange,
{
userId
}
);
}
}
return Promise.resolve();
}
// endregion ////
// region Get ////
getRevision() {
return this._config && this._config.api ? this._config.api.revision_web : null;
}
getServerVersion() {
return this._config && this._config.server ? this._config.server.version : 0;
}
getServerMode() {
return this._config && this._config.server ? this._config.server.mode : null;
}
getConfig() {
return this._config;
}
getDebugInfo() {
if (!JSON || !JSON.stringify) {
return {};
}
let configDump;
if (this._config && this._config.channels) {
configDump = {
// The private channel id is a subscription secret — mask it here too, not
// just in `Path` below, so the debug dump never surfaces it (#148). Expiry
// timestamps are non-sensitive and kept for diagnostics.
ChannelID: this._config.channels.private?.id ? REDACTED_PLACEHOLDER : "n/a",
ChannelDie: this._config.channels.private?.end || "n/a",
ChannelDieShared: this._config.channels.shared?.end || "n/a"
};
} else {
configDump = {
ConfigError: "config is not loaded"
};
}
let websocketMode = "-";
if (this._connectors.webSocket && this._connectors.webSocket?.socket) {
if (this.isJsonRpc()) {
websocketMode = "json-rpc";
} else {
websocketMode = this._connectors.webSocket?.socket?.url.search("binaryMode=true") != -1 ? "protobuf" : "text";
}
}
const connectionPath = this.connector?.connectionPath;
return {
"UserId": this._userId + (this._userId > 0 ? "" : "(guest)"),
"Guest userId": this._guestMode && this._guestUserId !== 0 ? this._guestUserId : "-",
"Browser online": typeof navigator !== "undefined" && navigator.onLine ? "Y" : "N",
"Connect": this.isConnected() ? "Y" : "N",
"Server type": this.isSharedMode() ? "cloud" : "local",
"WebSocket supported": this.isWebSocketSupported() ? "Y" : "N",
"WebSocket connected": this._connectors.webSocket && this._connectors.webSocket.connected ? "Y" : "N",
"WebSocket mode": websocketMode,
"Try connect": this._reconnectTimeout ? "Y" : "N",
"Try number": this._connectionAttempt,
// Mask the push JWT (`token`) and private `CHANNEL_ID`s before exposing
// the connection path through this developer-facing debug dump (#148).
"Path": connectionPath ? redactSensitiveUrl(connectionPath, ["CHANNEL_ID"]) : "-",
...configDump,
"Last message": this._session.mid || "-",
"Session history": this._session.history,
"Watch tags": this._watchTagsQueue.entries()
};
}
/**
* @process
* @param connectionType
*/
getConnectionPath(connectionType) {
let path;
const params = {};
switch (connectionType) {
case ConnectionType.WebSocket:
path = this._isSecure ? this._config?.server.websocket_secure : this._config?.server.websocket;
break;
case ConnectionType.LongPolling:
path = this._isSecure ? this._config?.server.long_pooling_secure : this._config?.server.long_polling;
break;
default:
throw new Error(`Unknown connection type ${connectionType}`);
}
if (!Type.isStringFilled(path)) {
throw new Error(`Empty path`);
}
if (typeof this._config?.jwt === "string" && this._config?.jwt !== "") {
params["token"] = this._config?.jwt;
} else {
const channels = [];
if (this._config?.channels?.private?.id) {
channels.push(this._config.channels.private.id);
}
if (this._config?.channels?.shared?.id) {
channels.push(this._config.channels.shared.id);
}
if (channels.length === 0) {
throw new Error(`Empty channels`);
}
params["CHANNEL_ID"] = channels.join("/");
}
if (this.isJsonRpc()) {
params.jsonRpc = "true";
} else if (this.isProtobufSupported()) {
params.binaryMode = "true";
}
if (this.isSharedMode()) {
if (!this._config?.clientId) {
throw new Error(
"Push-server is in shared mode, but clientId is not set"
);
}
params.clientId = this._config.clientId;
}
if (this._session.mid) {
params.mid = this._session.mid;
}
if (this._session.tag) {
params.tag = this._session.tag;
}
if (this._session.time) {
params.time = this._session.time;
}
params.revision = REVISION;
return `${path}?${Text.buildQueryString(params)}`;
}
/**
* @process
*/
getPublicationPath() {
const path = this._isSecure ? this._config?.server.publish_secure : this._config?.server.publish;
if (!path) {
return "";
}
const channels = [];
if (this._config?.channels.private?.id) {
channels.push(this._config.channels.private.id);
}
if (this._config?.channels.shared?.id) {
channels.push(this._config.channels.shared.id);
}
const params = {
CHANNEL_ID: channels.join("/")
};
return path + "?" + Text.buildQueryString(params);
}
// endregion ////
// region Is* ////
isConnected() {
return this.connector ? this.connector.connected : false;
}
isWebSocketSupported() {
return typeof window !== "undefined" && typeof window.WebSocket !== "undefined";
}
isWebSocketAllowed() {
if (this._sharedConfig.isWebSocketBlocked()) {
return false;
}
return this.isWebSocketEnabled();
}
isWebSocketEnabled() {
if (!this.isWebSocketSupported()) {
return false;
}
if (!this._config) {
return false;
}
if (!this._config.server) {
return false;
}
return this._config.server.websocket_enabled;
}
isPublishingSupported() {
return this.getServerVersion() > 3;
}
isPublishingEnabled() {
if (!this.isPublishingSupported()) {
return false;
}
return this._config?.server.publish_enabled === true;
}
isProtobufSupported() {
return this.getServerVersion() == 4 && !Browser.isIE();
}
isJsonRpc() {
return this.getServerVersion() >= 5;
}
isSharedMode() {
return this.getServerMode() === ServerMode.Shared;
}
// endregion ////
// region Events ////
/**
* @param {TypePullClientEmitConfig} params
* @returns {boolean}
*/
emit(params) {
if (params.type == SubscriptionType.Server || params.type == SubscriptionType.Client) {
if (typeof this._subscribers[params.type] === "undefined") {
this._subscribers[params.type] = {};
}
if (typeof params.moduleId === "undefined") {
throw new TypeError(
`${Text.getDateForLog()}: Pull.emit: parameter moduleId is not specified`
);
}
if (typeof this._subscribers[params.type][params.moduleId] === "undefined") {
this._subscribers[params.type][params.moduleId] = {
callbacks: [],
commands: {}
};
}
if (this._subscribers[params.type][params.moduleId]["callbacks"].length > 0) {
this._subscribers[params.type][params.moduleId]["callbacks"].forEach(
(callback) => {
callback(params.data, {
type: params.type,
moduleId: params.moduleId ?? "?"
});
}
);
}
if (!(typeof params.data === "undefined") && !(typeof params.data["command"] === "undefined") && this._subscribers[params.type][params.moduleId]["commands"][params.data["command"]] && this._subscribers[params.type][params.moduleId]["commands"][params.data["command"]].length > 0) {
this._subscribers[params.type][params.moduleId]["commands"][params.data["command"]].forEach((callback) => {
if (typeof params.data === "undefined") {
return;
}
callback(
params.data["params"],
params.data["extra"],
params.data["command"],
{
type: params.type,
moduleId: params.moduleId
}
);
});
}
return true;
} else {
if (typeof this._subscribers[params.type] === "undefined") {
this._subscribers[params.type] = [];
}
if (this._subscribers[params.type].length <= 0) {
return true;
}
this._subscribers[params.type].forEach(
(callback) => {
callback(params.data, {
type: params.type
});
}
);
return true;
}
}
/**
* @process
*
* @param message
*/
broadcastMessage(message) {
const moduleId = message.module_id = message.module_id.toLowerCase();
const command = message.command;
if (!message.extra) {
message.extra = {};
}
if (message.extra.server_time_unix) {
message.extra.server_time_ago = (Date.now() - message.extra.server_time_unix * 1e3) / 1e3 - (this._config?.server.timeShift || 0);
message.extra.server_time_ago = Math.max(message.extra.server_time_ago, 0);
}
this.logMessage(message);
try {
if (message.extra.sender && message.extra.sender.type === SenderType.Client) {
this.onCustomEvent(
"onPullClientEvent-" + moduleId,
[command, message.params, message.extra],
true
);
this.onCustomEvent(
"onPullClientEvent",
[moduleId, command, message.params, message.extra],
true
);
this.emit({
type: SubscriptionType.Client,
moduleId,
data: {
command,
params: Type.clone(message.params),
extra: Type.clone(message.extra)
}
});
} else if (moduleId === "pull") {
this.handleInternalPullEvent(command, message);
} else if (moduleId == "online") {
if ((message?.extra?.server_time_ago || 0) < 240) {
this.onCustomEvent(
"onPullOnlineEvent",
[command, message.params, message.extra],
true
);
this.emit({
type: SubscriptionType.Online,
data: {
command,
params: Type.clone(message.params),
extra: Type.clone(message.extra)
}
});
}
if (command === "userStatusChange") {
this.emitUserStatusChange(
message.params.user_id,
message.params.online
);
}
} else {
this.onCustomEvent(
"onPullEvent-" + moduleId,
[command, message.params, message.extra],
true
);
this.onCustomEvent(
"onPullEvent",
[moduleId, command, message.params, message.extra],
true
);
this.emit({
type: SubscriptionType.Server,
moduleId,
data: {
command,
params: Type.clone(message.params),
extra: Type.clone(message.extra)
}
});
}
} catch (error) {
this.getLogger().warning("PULL ERROR", {
errorType: "broadcastMessages execute error",
errorEvent: error,
// app-defined message.params / extra may carry a credential key (#43)
message: redactSensitiveParams(message)
}).catch(() => {
});
}
if (message.extra && message.extra.revision_web) {
this.checkRevision(Text.toInteger(message.extra.revision_web));
}
}
/**
* @process
*
* @param messages
*/
broadcastMessages(messages) {
for (const message of messages) {
this.broadcastMessage(message);
}
}
// endregion ////
// region sendMessage ////
/**
* Sends batch of messages to the multiple public channels.
*
* @param messageBatchList Array of messages to send.
* @return void
*/
async sendMessageBatch(messageBatchList) {
if (!this.isPublishingEnabled()) {
this.getLogger().error(`Client publishing is not supported or is disabled`).catch(() => {
});
return Promise.reject(
new Error(`Client publishing is not supported or is disabled`)
);
}
if (this.isJsonRpc()) {
const rpcRequest = this._jsonRpcAdapter?.createPublishRequest(messageBatchList);
this.connector?.send(JSON.stringify(rpcRequest));
return Promise.resolve(true);
} else {
const userIds = {};
for (const messageBatch of messageBatchList) {
if (typeof messageBatch.userList !== "undefined") {
for (const user of messageBatch.userList) {
const userId = Number(user);
userIds[userId] = userId;
}
}
}
this._channelManager?.getPublicIds(Object.values(userIds)).then((publicIds) => {
const response = this.connector?.send(
this.encodeMessageBatch(messageBatchList, publicIds)
);
return Promise.resolve(response);
});
}
}
/**
* @param messageBatchList
* @param publicIds
*/
encodeMessageBatch(messageBatchList, publicIds) {
const messages = [];
messageBatchList.forEach((messageFields) => {
const messageBody = messageFields.body;
let receivers = [];
if (messageFields.userList) {
receivers = this.createMessageReceivers(
messageFields.userList,
publicIds
);
}
if (messageFields.channelList) {
if (!Type.isArray(messageFields.channelList)) {
throw new TypeError("messageFields.publicChannels must be an array");
}
messageFields.channelList.forEach((publicChannel) => {
let publicId;
let signature;
if (typeof publicChannel === "string" && publicChannel.includes(".")) {
const fields = publicChannel.toString().split(".");
publicId = fields[0];
signature = fields[1];
} else if (typeof publicChannel === "object" && "publicId" in publicChannel && "signature" in publicChannel) {
publicId = publicChannel?.publicId;
signature = publicChannel?.signature;
} else {
throw new Error(
`Public channel MUST be either a string, formatted like "{publicId}.{signature}" or an object with fields 'publicId' and 'signature'`
);
}
receivers.push(
Receiver.create({
id: this.encodeId(publicId),
signature: this.encodeId(signature)
})
);
});
}
const message = IncomingMessage.create({
receivers,
body: JSON.stringify(messageBody),
expiry: messageFields.expiry || 0
});
messages.push(message);
});
const requestBatch = RequestBatch.create({
requests: [
{
incomingMessages: {
messages
}
}
]
});
return RequestBatch.encode(requestBatch).finish();
}
/**
* @memo fix return type
* @param users
* @param publicIds
*/
createMessageReceivers(users, publicIds) {
const result = [];
for (const userId of users) {
if (!publicIds[userId] || !publicIds[userId].publicId) {
throw new Error(`Could not determine public id for user ${userId}`);
}
result.push(
Receiver.create({
id: this.encodeId(publicIds[userId].publicId),
signature: this.encodeId(publicIds[userId].signature)
})
);
}
return result;
}
// endregion ////
// region _userStatusCallbacks ////
/**
* @param userId
* @param isOnline
*/
emitUserStatusChange(userId, isOnline) {
if (this._userStatusCallbacks[userId]) {
for (const callback of this._userStatusCallbacks[userId]) {
callback({
userId,
isOnline
});
}
}
}
restoreUserStatusSubscription() {
for (const userId in this._userStatusCallbacks) {
if (Object.prototype.hasOwnProperty.call(this._userStatusCallbacks, userId) && this._userStatusCallbacks[userId].length > 0) {
this._jsonRpcAdapter?.executeOutgoingRpcCommand(
RpcMethod.SubscribeStatusChange,
{
userId
}
);
}
}
}
// endregion ////
// region Config ////
async loadConfig(_logTag) {
if (!this._config) {
this._config = Object.assign({}, EmptyConfig);
let config;
if (this._storage) {
config = this._storage.get(LsKeys.PullConfig, null);
}
if (this.isConfigActual(config) && this.checkRevision(config.api.revision_web)) {
return Promise.resolve(config);
} else if (this._storage) {
this._storage.remove(LsKeys.PullConfig);
}
} else if (this.isConfigActual(this._config) && this.checkRevision(this._config.api.revision_web)) {
return Promise.resolve(this._config);
} else {
this._config = Object.assign({}, EmptyConfig);
}
return new Promise((resolve, reject) => {
this._restClient.actions.v2.call.make({
method: this._configGetMethod,
params: { CACHE: "N" }
}).then((response) => {
const data = response.getData().result;
const timeShift = Math.floor(
(Date.now() - new Date(data.serverTime).getTime()) / 1e3
);
delete data.serverTime;
const config = Object.assign({}, data);
config.server.timeShift = timeShift;
resolve(config);
}).catch((error) => {
reject(error);
});
});
}
/**
* @param config
*/
isConfigActual(config) {
if (!Type.isPlainObject(config)) {
return false;
}
if (Number(config["server"].config_timestamp) !== this._configTimestamp) {
return false;
}
const now = /* @__PURE__ */ new Date();
if (Type.isNumber(config["exp"]) && config["exp"] > 0 && config["exp"] < now.getTime() / 1e3) {
return false;
}
const channelCount = Object.keys(config["channels"]).length;
if (channelCount === 0) {
return false;
}
for (const channelType in config["channels"]) {
if (!Object.prototype.hasOwnProperty.call(config["channels"], channelType)) {
continue;
}
const channel = config["channels"][channelType];
const channelEnd = new Date(channel.end);
if (channelEnd < now) {
return false;
}
}
return true;
}
startCheckConfig() {
if (this._disposed) {
return;
}
if (this._checkInterval) {
clearInterval(this._checkInterval);
this._checkInterval = null;
}
this._checkInterval = setInterval(
this.checkConfig.bind(this),
CONFIG_CHECK_INTERVAL
);
}
stopCheckConfig() {
if (this._checkInterval) {
clearInterval(this._checkInterval);
}
this._checkInterval = null;
}
checkConfig() {
if (this.isConfigActual(this._config)) {
if (!this.checkRevision(Text.toInteger(this._config?.api.revision_web))) {
return false;
}
} else {
this.logToConsole("Stale config detected. Restarting");
this.restart(CloseReasons.CONFIG_EXPIRED, "config expired");
}
return true;
}
/**
* @param config
* @param allowCaching
*/
setConfig(config, allowCaching) {
for (const key in config) {
if (Object.prototype.hasOwnProperty.call(config, key) && Object.prototype.hasOwnProperty.call(this._config, key)) {
this._config[key] = config[key];
}
}
if (config.publicChannels) {
this.setPublicIds(Object.values(config.publicChannels));
}
this._configTimestamp = Number(config.server.config_timestamp);
if (this._storage && allowCaching && !this._disposed) {
try {
this._storage.set(LsKeys.PullConfig, config);
} catch (error) {
if (typeof localStorage !== "undefined" && localStorage.removeItem) {
localStorage.removeItem("history");
}
this.getLogger().error(
`${Text.getDateForLog()}: Pull: Could not cache config in local storage.`,
{ error }
).catch(() => {
});
}
}
}
setPublicIds(publicIds) {
this._channelManager.setPublicIds(publicIds);
}
/**
* @param serverRevision
*/
checkRevision(serverRevision) {
if (this._skipCheckRevision) {
return true;
}
if (serverRevision > 0 && serverRevision !== REVISION) {
this._enabled = false;
this.showNotification("PULL_OLD_REVISION");
this.disconnect(CloseReasons.NORMAL_CLOSURE, "check_revision");
this.onCustomEvent("onPullRevisionUp", [serverRevision, REVISION]);
this.emit({
type: SubscriptionType.Revision,
data: {
server: serverRevision,
client: REVISION
}
});
this.logToConsole(
`Pull revision changed from ${REVISION} to ${serverRevision}. Reload required`
);
return false;
}
return true;
}
// endregion ////
// region Connect|ReConnect|DisConnect ////
disconnect(disconnectCode, disconnectReason) {
if (this.connector) {
this._isManualDisconnect = true;
this.connector.disconnect(disconnectCode, disconnectReason);
}
}
restoreWebSocketConnection() {
if (this._connectionType === ConnectionType.WebSocket) {
return;
}
this._connectors.webSocket?.connect();
}
/**
* @param connectionDelay
*/
scheduleReconnect(connectionDelay = 0) {
if (this._disposed || !this._enabled) {
return;
}
if (!connectionDelay) {
{
connectionDelay = this.getConnectionAttemptDelay(
this._connectionAttempt
);
}
}
this.logToConsole(
`Pull: scheduling reconnection in ${connectionDelay} seconds; attempt # ${this._connectionAttempt}`
);
this.armTimeout("_reconnectTimeout", () => {
this.connect().catch((error) => {
this.getLogger().error("scheduleReconnect", { error }).catch(() => {
});
});
}, connectionDelay * 1e3);
}
scheduleRestoreWebSocketConnection() {
if (this._disposed) {
return;
}
this.logToConsole(
`Pull: scheduling restoration of websocket connection in ${RESTORE_WEBSOCKET_TIMEOUT} seconds`
);
if (this._restoreWebSocketTimeout) {
return;
}
this.armTimeout("_restoreWebSocketTimeout", () => {
this._restoreWebSocketTimeout = null;
this.restoreWebSocketConnection();
}, RESTORE_WEBSOCKET_TIMEOUT * 1e3);
}
/**
* @returns {Promise}
*/
async connect() {
if (this._disposed || !this._enabled) {
return Promise.reject();
}
if (this.connector?.connected) {
return Promise.resolve();
}
if (this._reconnectTimeout) {
clearTimeout(this._reconnectTimeout);
this._reconnectTimeout = null;
}
this.status = PullStatus.Connecting;
this._connectionAttempt++;
return new Promise((resolve, reject) => {
this._connectPromise = {
resolve,
reject
};
this.connector?.connect();
});
}
/**
* @param disconnectCode
* @param disconnectReason
* @param restartDelay
*/
scheduleRestart(disconnectCode, disconnectReason, restartDelay = 0) {
if (this._disposed) {
return;
}
if (restartDelay < 1) {
restartDelay = Math.ceil(Math.random() * 30) + 5;
}
this.armTimeout(
"_restartTimeout",
() => this.restart(disconnectCode, disconnectReason),
restartDelay * 1e3
);
}
// endregion ////
// region Handlers ////
/**
* @param messageFields
*/
handleRpcIncomingMessage(messageFields) {
this._session.mid = messageFields.mid;
const body = messageFields.body;
if (!messageFields.body.extra) {
body.extra = {};
}
body.extra.sender = messageFields.sender;
if ("user_params" in messageFields && Type.isPlainObject(messageFields.user_params)) {
Object.assign(body.params, messageFields.user_params);
}
if ("dictionary" in messageFields && Type.isPlainObject(messageFields.dictionary)) {
Object.assign(body.params, messageFields.dictionary);
}
if (this.checkDuplicate(messageFields.mid)) {
this.addMessageToStat(body);
this.trimDuplicates();
this.broadcastMessage(body);
}
this.connector?.send(`mack:${messageFields.mid}`);
return {};
}
/**
* @param events
*/
handleIncomingEvents(events) {
const messages = [];
if (events.length === 0) {
this._session.mid = null;
return;
}
for (const event of events) {
this.updateSessionFromEvent(event);
if (event.mid && !this.checkDuplicate(event.mid)) {
continue;
}
this.addMessageToStat(
event.text
);
messages.push(event.text);
}
this.trimDuplicates();
this.broadcastMessages(messages);
}
/**
* @param event
*/
updateSessionFromEvent(event) {
this._session.mid = event.mid || null;
this._session.tag = event.tag || null;
this._session.time = event.time || null;
}
/**
* @process
*
* @param command
* @param message
*/
handleInternalPullEvent(command, message) {
switch (command.toUpperCase()) {
case SystemCommands.CHANNEL_EXPIRE: {
if (message.params.action === "reconnect") {
const typeChanel = message.params?.channel.type;
if (typeChanel === "private" && this._config?.channels?.private) {
this._config.channels.private = message.params.new_channel;
this.logToConsole(
`Pull: new config for ${message.params.channel.type} channel set: [updated]`
);
}
if (typeChanel === "shared" && this._config?.channels?.shared) {
this._config.channels.shared = message.params.new_channel;
this.logToConsole(
`Pull: new config for ${message.params.channel.type} channel set: [updated]`
);
}
this.reconnect(CloseReasons.CONFIG_REPLACED, "config was replaced");
} else {
this.restart(CloseReasons.CHANNEL_EXPIRED, "channel expired received");
}
break;
}
case SystemCommands.CONFIG_EXPIRE: {
this.restart(CloseReasons.CONFIG_EXPIRED, "config expired received");
break;
}
case SystemCommands.SERVER_RESTART: {
this.reconnect(
CloseReasons.SERVER_RESTARTED,
"server was restarted",
15
);
break;
}
}
}
// region Handlers For Message ////
/**
* @param response
*/
onIncomingMessage(response) {
if (this.isJsonRpc()) {
if (response === JSON_RPC_PING) {
this.onJsonRpcPing();
} else {
this._jsonRpcAdapter?.parseJsonRpcMessage(response);
}
} else {
const events = this.extractMessages(response);
this.handleIncomingEvents(events);
}
}
// region onLongPolling ////
onLongPollingOpen() {
this._unloading = false;
this._starting = false;
this._connectionAttempt = 0;
this._isManualDisconnect = false;
this.status = PullStatus.Online;
this.logToConsole("Pull: Long polling connection with push-server opened");
if (this.isWebSocketEnabled()) {
this.scheduleRestoreWebSocketConnection();
}
if (this._connectPromise) {
this._connectPromise.resolve({});
}
}
/**
* @param response
*/
onLongPollingDisconnect(response) {
if (this._connectionType === ConnectionType.LongPolling) {
this.status = PullStatus.Offline;
}
this.logToConsole(
`Pull: Long polling connection with push-server closed. Code: ${response.code}, reason: ${response.reason}`
);
if (!this._isManualDisconnect) {
this.scheduleReconnect();
}
this._isManualDisconnect = false;
this.clearPingWaitTimeout();
}
/**
* @param error
*/
onLongPollingError(error) {
this._starting = false;
if (this._connectionType === ConnectionType.LongPolling) {
this.status = PullStatus.Offline;
}
this.getLogger().error(
`${Text.getDateForLog()}: Pull: Long polling connection error`,
{ error }
).catch(() => {
});
this.scheduleReconnect();
if (this._connectPromise) {
this._connectPromise.reject(error);
}
this.clearPingWaitTimeout();
}
// endregion ////
// region onWebSocket ////
/**
* @param response
*/
onWebSocketBlockChanged(response) {
const isWebSocketBlocked = response.isWebSocketBlocked;
if (isWebSocketBlocked && this._connectionType === ConnectionType.WebSocket && !this.isConnected()) {
if (this._reconnectTimeout) {
clearTimeout(this._reconnectTimeout);
this._reconnectTimeout = null;
}
this._connectionAttempt = 0;
this._connectionType = ConnectionType.LongPolling;
this.scheduleReconnect(1);
} else if (!isWebSocketBlocked && this._connectionType === ConnectionType.LongPolling) {
if (this._reconnectTimeout) {
clearTimeout(this._reconnectTimeout);
this._reconnectTimeout = null;
}
if (this._restoreWebSocketTimeout) {
clearTimeout(this._restoreWebSocketTimeout);
this._restoreWebSocketTimeout = null;
}
this._connectionAttempt = 0;
this._connectionType = ConnectionType.WebSocket;
this.scheduleReconnect(1);
}
}
onWebSocketOpen() {
this._unloading = false;
this._starting = false;
this._connectionAttempt = 0;
this._isManualDisconnect = false;
this.status = PullStatus.Online;
this._sharedConfig.setWebSocketBlocked(false);
this._sharedConfig.setLongPollingBlocked(true);
if (this._connectionType == ConnectionType.LongPolling) {
this._connectionType = ConnectionType.WebSocket;
this._connectors.longPolling?.disconnect(
CloseReasons.CONFIG_REPLACED,
"Fire at onWebSocketOpen"
);
}
if (this._restoreWebSocketTimeout) {
clearTimeout(this._restoreWebSocketTimeout);
this._restoreWebSocketTimeout = null;
}
this.logToConsole("Pull: Websocket connection with push-server opened");
if (this._connectPromise) {
this._connectPromise.resolve({});
}
this.restoreUserStatusSubscription();
}
/**
* @param response
*/
onWebSocketDisconnect(response) {
if (this._connectionType === ConnectionType.WebSocket) {
this.status = PullStatus.Offline;
}
this.logToConsole(
`Pull: Websocket connection with push-server closed. Code: ${response.code}, reason: ${response.reason}`,
true
);
if (!this._isManualDisconnect) {
if (response.code == CloseReasons.WRONG_CHANNEL_ID) {
this.scheduleRestart(
CloseReasons.WRONG_CHANNEL_ID,
"wrong channel signature"
);
} else {
this.scheduleReconnect();
}
}
this._sharedConfig.setLongPollingBlocked(true);
this._isManualDisconnect = false;
this.clearPingWaitTimeout();
}
/**
* @param error
*/
onWebSocketError(error) {
this._starting = false;
if (this._connectionType === ConnectionType.WebSocket) {
this.status = PullStatus.Offline;
}
this.getLogger().error(
`${Text.getDateForLog()}: Pull: WebSocket connection error`,
{ error }
).catch(() => {
});
this.scheduleReconnect();
if (this._connectPromise) {
this._connectPromise.reject(error);
}
this.clearPingWaitTimeout();
}
// endregion ////
// endregion ////
// endregion ////
// region extractMessages ////
/**
* @param pullEvent
*/
extractMessages(pullEvent) {
if (pullEvent instanceof ArrayBuffer) {
return this.extractProtobufMessages(pullEvent);
} else if (Type.isStringFilled(pullEvent)) {
return this.extractPlainTextMessages(pullEvent);
}
throw new Error("Error pullEvent type");
}
/**
* @param pullEvent
*/
extractProtobufMessages(pullEvent) {
const result = [];
try {
const responseBatch = ResponseBatch.decode(new Uint8Array(pullEvent));
for (let i = 0; i < responseBatch.responses.length; i++) {
const response = responseBatch.responses[i];
if (response.command !== "outgoingMessages") {
continue;
}
const messages = response.outgoingMessages.messages;
for (const message of messages) {
let messageFields;
try {
messageFields = JSON.parse(message.body);
} catch (error) {
this.getLogger().error(
`${Text.getDateForLog()}: Pull: Could not parse message body`,
{ error }
).catch(() => {
});
continue;
}
if (!messageFields.extra) {
messageFields.extra = {};
}
messageFields.extra.sender = {
type: message.sender.type
};
if (message.sender.id instanceof Uint8Array) {
messageFields.extra.sender.id = this.decodeId(message.sender.id);
}
const compatibleMessage = {
mid: this.decodeId(message.id),
text: messageFields
};
result.push(compatibleMessage);
}
}
} catch (error) {
this.getLogger().error(
`${Text.getDateForLog()}: Pull: Could not parse message`,
{ error }
).catch(() => {
});
}
return result;
}
/**
* @param pullEvent
*/
extractPlainTextMessages(pullEvent) {
const result = [];
const dataArray = pullEvent.match(/#!NGINXNMS!#(.*?)#!NGINXNME!#/g);
if (dataArray === null) {
this.getLogger().warning("PULL ERROR", {
errorType: "parseResponse error parsing message",
// The frame failed the NGINX-delimiter match, so its content is
// unparseable anyway and could carry a credential (e.g. a channel
// `signature`); log only its size, never the bytes (#43).
byteLength: pullEvent.length
}).catch(() => {
});
return [];
}
for (let i = 0; i < dataArray.length; i++) {
dataArray[i] = dataArray[i].substring(12, dataArray[i].length - 12);
if (dataArray[i].length <= 0) {
continue;
}
let data;
try {
data = JSON.parse(dataArray[i]);
} catch {
continue;
}
result.push(data);
}
return result;
}
/**
* Converts message id from byte[] to string
* @param {Uint8Array} encodedId
* @return {string}
*/
decodeId(encodedId) {
let result = "";
for (const element_ of encodedId) {
const hexByte = element_.toString(16);
if (hexByte.length === 1) {
result += "0";
}
result += hexByte;
}
return result;
}
/**
* Converts message id from hex-encoded string to byte[]
* @param {string} id Hex-encoded string.
* @return {Uint8Array}
*/
encodeId(id) {
if (!id) {
return new Uint8Array();
}
const result = [];
for (let i = 0; i < id.length; i += 2) {
result.push(Number.parseInt(id.slice(i, i + 2), 16));
}
return new Uint8Array(result);
}
// endregion ////
// region Events.Status /////
onOffline() {
if (this._disposed) {
return;
}
this.disconnect(CloseReasons.NORMAL_CLOSURE, "offline");
}
onOnline() {
if (this._disposed) {
return;
}
this.connect().catch((error) => {
this.getLogger().error("onOnline", { error }).catch(() => {
});
});
}
onBeforeUnload() {
this._unloading = true;
this.persistSession();
this.scheduleReconnect(15);
}
// Persist the current session (with a short TTL) so a quick reload / re-init can
// resume it. Shared by onBeforeUnload and destroy() — destroy() saves WITHOUT
// scheduling a reconnect (#141).
persistSession() {
const session = Type.clone(this.session);
session.ttl = Date.now() + LS_SESSION_CACHE_TIME * 1e3;
if (this._storage) {
try {
this._storage.set(
LS_SESSION,
JSON.stringify(session)
// LS_SESSION_CACHE_TIME
);
} catch (error) {
this.getLogger().error(
`${Text.getDateForLog()}: Pull: Could not save session info in local storage. Error: `,
{ error }
).catch(() => {
});
}
}
}
// endregion ////
// region PullStatus ////
/**
* @param status
* @param delay
*/
sendPullStatusDelayed(status, delay) {
if (this._disposed) {
return;
}
this.armTimeout("_offlineTimeout", () => {
this._offlineTimeout = null;
this.sendPullStatus(status);
}, delay);
}
/**
* @param status
*/
sendPullStatus(status) {
if (this._unloading) {
return;
}
this.onCustomEvent("onPullStatus", [status]);
this.emit({
type: SubscriptionType.Status,
data: {
status
}
});
}
// endregion ////
// region _watchTagsQueue ////
/**
* @memo if private?
* @param tagId
* @param force
*/
// @ts-expect-error When we rewrite it to something more modern, then we'll remove this
extendWatch(tagId, force = false) {
if (this._watchTagsQueue.get(tagId)) {
return;
}
this._watchTagsQueue.set(tagId, true);
if (force) {
this.updateWatch(force);
}
}
/**
* @param force
*/
updateWatch(force = false) {
if (this._disposed) {
return;
}
this.armTimeout(
"_watchUpdateTimeout",
() => {
const watchTags = [...this._watchTagsQueue.keys()];
if (watchTags.length > 0) {
this._restClient.actions.v2.call.make({
method: "pull.watch.extend",
params: { tags: watchTags }
}).then((response) => {
const updatedTags = response.getData().result;
for (const tagId of updatedTags) {
this.clearWatch(tagId);
}
this.updateWatch();
}).catch(() => {
this.updateWatch();
});
} else {
this.updateWatch();
}
},
force ? this._watchForceUpdateInterval : this._watchUpdateInterval
);
}
/**
* @param tagId
*/
clearWatch(tagId) {
this._watchTagsQueue.delete(tagId);
}
// endregion ////
// region Ping ////
onJsonRpcPing() {
this.updatePingWaitTimeout();
this.connector?.send(JSON_RPC_PONG);
}
updatePingWaitTimeout() {
if (this._disposed) {
return;
}
this.armTimeout(
"_pingWaitTimeout",
this._onPingTimeoutHandler,
PING_TIMEOUT * 2 * 1e3
);
}
clearPingWaitTimeout() {
if (this._pingWaitTimeout) {
clearTimeout(this._pingWaitTimeout);
}
this._pingWaitTimeout = null;
}
onPingTimeout() {
this._pingWaitTimeout = null;
if (this._disposed || !this._enabled || !this.isConnected()) {
return;
}
this.getLogger().warning(`No pings are received in ${PING_TIMEOUT * 2} seconds. Reconnecting`).catch(() => {
});
this.disconnect(CloseReasons.STUCK, "connection stuck");
this.scheduleReconnect();
}
// endregion ////
// region Time ////
/**
* Returns reconnect delay in seconds
*
* @param attemptNumber
* @return {number}
*/
getConnectionAttemptDelay(attemptNumber) {
let result;
if (attemptNumber < 1) {
result = 0.5;
} else if (attemptNumber < 3) {
result = 15;
} else if (attemptNumber < 5) {
result = 45;
} else if (attemptNumber < 10) {
result = 600;
} else {
result = 3600;
}
return result + result * Math.random() * 0.2;
}
// endregion ////
// region Tools ////
/**
* @param mid
*/
checkDuplicate(mid) {
if (this._session.lastMessageIds.includes(mid)) {
this.getLogger().warning(`Duplicate message ${mid} skipped`).catch(() => {
});
return false;
} else {
this._session.lastMessageIds.push(mid);
return true;
}
}
trimDuplicates() {
if (this._session.lastMessageIds.length > MAX_IDS_TO_STORE) {
this._session.lastMessageIds = this._session.lastMessageIds.slice(-MAX_IDS_TO_STORE);
}
}
// endregion ////
// region Logging ////
/**
* @param message
*/
logMessage(message) {
if (!this._debug) {
return;
}
if (message.extra?.sender && message.extra.sender.type === SenderType.Client) {
this.getLogger().info(
`onPullClientEvent-${message.module_id}`,
redactSensitiveParams({
command: message.command,
params: message.params,
extra: message.extra
})
).catch(() => {
});
} else if (message.module_id == "online") {
this.getLogger().info(
`onPullOnlineEvent`,
redactSensitiveParams({
command: message.command,
params: message.params,
extra: message.extra
})
).catch(() => {
});
} else {
this.getLogger().info(
`onPullEvent`,
redactSensitiveParams({
moduleId: message.module_id,
command: message.command,
params: message.params,
extra: message.extra
})
).catch(() => {
});
}
}
/**
* @param message
* @param force
*/
logToConsole(message, force = false) {
if (this._loggingEnabled || force) {
this.getLogger().debug(`${Text.getDateForLog()}: ${message}`).catch(() => {
});
}
}
/**
* @param message
*/
addMessageToStat(message) {
if (!this._session.history[message.module_id]) {
this._session.history[message.module_id] = {};
}
if (!this._session.history[message.module_id][message.command]) {
this.session.history[message.module_id][message.command] = 0;
}
this._session.history[message.module_id][message.command]++;
this._session.messageCount++;
}
/**
* @param text
*/
showNotification(text) {
this.getLogger().notice(text).catch(() => {
});
}
// endregion ////
// region onCustomEvent ////
/**
* @memo may be need to use onCustomEvent
* @memo ? force
*/
onCustomEvent(eventName, data, force = false) {
}
// endregion ////
}
var __defProp$2 = Object.defineProperty;
var __name$2 = (target, value) => __defProp$2(target, "name", { value, configurable: true });
class B24HelperManager {
static {
__name$2(this, "B24HelperManager");
}
_b24;
_isInit = false;
_profile = null;
_app = null;
_payment = null;
_license = null;
_currency = null;
_appOptions = null;
_userOptions = null;
_b24PullClient = null;
_pullClientUnSubscribe = [];
_pullClientModuleId = "";
_logger;
constructor(b24) {
this._logger = LoggerFactory.createNullLogger();
this._b24 = b24;
}
setLogger(logger) {
this._logger = logger;
if (null !== this._profile) {
this._profile.setLogger(this.getLogger());
}
if (null !== this._app) {
this._app.setLogger(this.getLogger());
}
if (null !== this._payment) {
this._payment.setLogger(this.getLogger());
}
if (null !== this._license) {
this._license.setLogger(this.getLogger());
}
if (null !== this._currency) {
this._currency.setLogger(this.getLogger());
}
if (null !== this._appOptions) {
this._appOptions.setLogger(this.getLogger());
}
if (null !== this._userOptions) {
this._userOptions.setLogger(this.getLogger());
}
}
getLogger() {
return this._logger;
}
destroy() {
this._destroyPullClient();
}
// region loadData ////
async loadData(dataTypes = [LoadDataType.App, LoadDataType.Profile], requestId = `helper-load-data`) {
const batchMethods = {
[LoadDataType.App]: { method: "app.info" },
[LoadDataType.Profile]: { method: "profile" },
[LoadDataType.Currency]: [
{ method: "crm.currency.base.get" },
{ method: "crm.currency.list" }
],
[LoadDataType.AppOptions]: { method: "app.option.get" },
[LoadDataType.UserOptions]: { method: "user.option.get" }
};
const batchRequest = dataTypes.reduce(
(acc, type) => {
if (batchMethods[type]) {
if (Array.isArray(batchMethods[type])) {
for (const [index, row] of batchMethods[type].entries()) {
acc[`get_${type}_${index}`] = row;
}
} else {
acc[`get_${type}`] = batchMethods[type];
}
}
return acc;
},
{}
);
try {
const response = await this._b24.actions.v2.batch.make({
calls: batchRequest,
options: {
isHaltOnError: true,
returnAjaxResult: false,
requestId
}
});
const data = response.getData();
if (data[`get_${LoadDataType.App}`]) {
this._app = await this.parseAppData(data[`get_${LoadDataType.App}`]);
this._payment = await this.parsePaymentData(
data[`get_${LoadDataType.App}`]
);
this._license = await this.parseLicenseData(
data[`get_${LoadDataType.App}`]
);
}
if (data[`get_${LoadDataType.Profile}`]) {
this._profile = await this.parseUserData(
data[`get_${LoadDataType.Profile}`]
);
}
if (data[`get_${LoadDataType.Currency}_0`] && data[`get_${LoadDataType.Currency}_1`]) {
this._currency = await this.parseCurrencyData({
currencyBase: data[`get_${LoadDataType.Currency}_0`],
currencyList: data[`get_${LoadDataType.Currency}_1`]
});
}
if (data[`get_${LoadDataType.AppOptions}`]) {
this._appOptions = await this.parseOptionsData(
"app",
data[`get_${LoadDataType.AppOptions}`]
);
}
if (data[`get_${LoadDataType.UserOptions}`]) {
this._userOptions = await this.parseOptionsData(
"user",
data[`get_${LoadDataType.UserOptions}`]
);
}
this._isInit = true;
} catch (error) {
if (error instanceof Error) {
throw error;
}
this.getLogger().error("Failed to load data", { error }).catch(() => {
});
throw new Error("Failed to load data", { cause: error });
}
}
async parseUserData(profileData) {
const manager = new ProfileManager(this._b24);
manager.setLogger(this.getLogger());
return manager.initData({
id: Number(profileData.ID),
isAdmin: profileData.ADMIN === true,
lastName: profileData?.LAST_NAME || "",
name: profileData?.NAME || "",
gender: profileData?.PERSONAL_GENDER || "",
photo: profileData?.PERSONAL_PHOTO || "",
TimeZone: profileData?.TIME_ZONE || "",
TimeZoneOffset: profileData?.TIME_ZONE_OFFSET
}).then(() => {
return manager;
});
}
async parseAppData(appData) {
const manager = new AppManager(this._b24);
manager.setLogger(this.getLogger());
return manager.initData({
id: Number.parseInt(appData.ID),
code: appData.CODE,
version: Number.parseInt(appData.VERSION),
status: appData.STATUS,
isInstalled: appData.INSTALLED
}).then(() => {
return manager;
});
}
async parsePaymentData(appData) {
const manager = new PaymentManager(this._b24);
manager.setLogger(this.getLogger());
return manager.initData({
isExpired: appData.PAYMENT_EXPIRED === "Y",
days: Number.parseInt(appData.DAYS || "0")
}).then(() => {
return manager;
});
}
async parseLicenseData(appData) {
const manager = new LicenseManager(this._b24);
manager.setLogger(this.getLogger());
return manager.initData({
languageId: appData.LANGUAGE_ID,
license: appData.LICENSE,
licensePrevious: appData.LICENSE_PREVIOUS,
licenseType: appData.LICENSE_TYPE,
licenseFamily: appData.LICENSE_FAMILY,
isSelfHosted: appData.LICENSE.includes("selfhosted")
}).then(() => {
return manager;
});
}
async parseCurrencyData(currencyData) {
const manager = new CurrencyManager(this._b24);
manager.setLogger(this.getLogger());
return manager.initData(currencyData).then(() => {
return manager;
});
}
async parseOptionsData(type, optionsData) {
const manager = new OptionsManager(this._b24, type);
manager.setLogger(this.getLogger());
return manager.initData(optionsData).then(() => {
return manager;
});
}
// endregion ////
// region Get ////
get isInit() {
return this._isInit;
}
get forB24Form() {
this.ensureInitialized();
if (null === this._profile) {
throw new Error("B24HelperManager.profileInfo not initialized");
}
if (null === this._app) {
throw new Error("B24HelperManager.appInfo not initialized");
}
return {
app_code: this.appInfo.data.code,
app_status: this.appInfo.data.status,
payment_expired: this.paymentInfo.data.isExpired ? "Y" : "N",
days: this.paymentInfo.data.days,
b24_plan: this.licenseInfo.data.license,
c_name: this.profileInfo.data.name,
c_last_name: this.profileInfo.data.lastName,
hostname: this.hostName
};
}
/**
* Get the account address BX24 (https://your_domain.bitrix24.com)
*/
get hostName() {
return this._b24.getTargetOrigin();
}
get profileInfo() {
this.ensureInitialized();
if (null === this._profile) {
throw new Error("B24HelperManager.profileInfo not initialized");
}
return this._profile;
}
get appInfo() {
this.ensureInitialized();
if (null === this._app) {
throw new Error("B24HelperManager.appInfo not initialized");
}
return this._app;
}
get paymentInfo() {
this.ensureInitialized();
if (null === this._payment) {
throw new Error("B24HelperManager.paymentInfo not initialized");
}
return this._payment;
}
get licenseInfo() {
this.ensureInitialized();
if (null === this._license) {
throw new Error("B24HelperManager.licenseInfo not initialized");
}
return this._license;
}
get currency() {
this.ensureInitialized();
if (null === this._currency) {
throw new Error("B24HelperManager.currency not initialized");
}
return this._currency;
}
get appOptions() {
this.ensureInitialized();
if (null === this._appOptions) {
throw new Error("B24HelperManager.appOptions not initialized");
}
return this._appOptions;
}
get userOptions() {
this.ensureInitialized();
if (null === this._userOptions) {
throw new Error("B24HelperManager.userOptions not initialized");
}
return this._userOptions;
}
// endregion ////
// region Custom SelfHosted && Cloud ////
get isSelfHosted() {
return this.licenseInfo.data.isSelfHosted;
}
/**
* Returns the increment step of fields of type ID
* @memo in a cloud step = 2 in box step = 1
*
* @returns {number}
*/
get primaryKeyIncrementValue() {
if (this.isSelfHosted) {
return 1;
}
return 2;
}
/**
* Defines specific URLs for a Bitrix24 box or cloud
*/
get b24SpecificUrl() {
if (this.isSelfHosted) {
return {
[TypeSpecificUrl.MainSettings]: "/configs/",
[TypeSpecificUrl.UfList]: "/configs/userfield_list.php",
[TypeSpecificUrl.UfPage]: "/configs/userfield.php"
};
}
return {
[TypeSpecificUrl.MainSettings]: "/settings/configs/",
[TypeSpecificUrl.UfList]: "/settings/configs/userfield_list.php",
[TypeSpecificUrl.UfPage]: "/settings/configs/userfield.php"
};
}
// endregion ////
// region Pull.Client ////
usePullClient(prefix = "prefix", userId) {
if (this._b24PullClient) {
return this;
}
this.initializePullClient(
typeof userId === "undefined" ? this.profileInfo.data.id || 0 : userId,
prefix
);
return this;
}
initializePullClient(userId, prefix = "prefix") {
this._b24PullClient = new PullClient({
b24: this._b24,
restApplication: this._b24.auth.getUniq(prefix),
userId
});
}
subscribePullClient(callback, moduleId = "application") {
if (!this._b24PullClient) {
throw new Error("PullClient not init");
}
this._pullClientModuleId = moduleId;
this._pullClientUnSubscribe.push(
this._b24PullClient.subscribe({
moduleId: this._pullClientModuleId,
callback
})
);
return this;
}
startPullClient() {
if (!this._b24PullClient) {
throw new Error("PullClient not init");
}
this._b24PullClient.start().catch((error) => {
this.getLogger().error(`${Text.getDateForLog()}: Pull not running`, { error }).catch(() => {
});
});
}
getModuleIdPullClient() {
if (!this._b24PullClient) {
throw new Error("PullClient not init");
}
return this._pullClientModuleId;
}
_destroyPullClient() {
for (const unsubscribeCallback of this._pullClientUnSubscribe) {
unsubscribeCallback();
}
this._b24PullClient?.destroy();
this._b24PullClient = null;
}
// endregion ////
// region Tools ////
ensureInitialized() {
if (!this._isInit) {
throw new Error("B24HelperManager not initialized");
}
}
// endregion ////
}
var __defProp$1 = Object.defineProperty;
var __name$1 = (target, value) => __defProp$1(target, "name", { value, configurable: true });
const useB24Helper = /* @__PURE__ */ __name$1(() => {
let $isInitB24Helper = false;
let $isInitPullClient = false;
let $b24Helper = null;
const initB24Helper = /* @__PURE__ */ __name$1(async ($b24, dataTypes = [LoadDataType.App, LoadDataType.Profile], requestId = `helper-load-data`) => {
if (null === $b24Helper) {
$b24Helper = new B24HelperManager($b24);
}
if ($isInitB24Helper) {
return $b24Helper;
}
await $b24Helper.loadData(dataTypes, requestId);
$isInitB24Helper = true;
return $b24Helper;
}, "initB24Helper");
const destroyB24Helper = /* @__PURE__ */ __name$1(() => {
$b24Helper?.destroy();
$b24Helper = null;
$isInitB24Helper = false;
$isInitPullClient = false;
}, "destroyB24Helper");
const isInitB24Helper = /* @__PURE__ */ __name$1(() => {
return $isInitB24Helper;
}, "isInitB24Helper");
const getB24Helper = /* @__PURE__ */ __name$1(() => {
if (null === $b24Helper) {
throw new SdkError({
code: "JSSDK_HELPER_NOT_INIT",
description: "B24HelperManager is not initialized. You need to call initB24Helper first.",
status: 0
});
}
return $b24Helper;
}, "getB24Helper");
const usePullClient = /* @__PURE__ */ __name$1(() => {
if (null === $b24Helper) {
throw new SdkError({
code: "JSSDK_HELPER_NOT_INIT",
description: "B24HelperManager is not initialized. You need to call initB24Helper first.",
status: 0
});
}
$b24Helper.usePullClient();
$isInitPullClient = true;
}, "usePullClient");
const useSubscribePullClient = /* @__PURE__ */ __name$1((callback, moduleId = "application") => {
if (!$isInitPullClient) {
throw new SdkError({
code: "JSSDK_HELPER_PULL_CLIENT_NOT_INIT",
description: "PullClient is not initialized. You need to call usePullClient first.",
status: 0
});
}
$b24Helper?.subscribePullClient(callback, moduleId);
}, "useSubscribePullClient");
const startPullClient = /* @__PURE__ */ __name$1(() => {
if (!$isInitPullClient) {
throw new SdkError({
code: "JSSDK_HELPER_PULL_CLIENT_NOT_INIT",
description: "PullClient is not initialized. You need to call usePullClient first.",
status: 0
});
}
$b24Helper?.startPullClient();
}, "startPullClient");
return {
initB24Helper,
isInitB24Helper,
destroyB24Helper,
getB24Helper,
usePullClient,
useSubscribePullClient,
startPullClient
};
}, "useB24Helper");
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
let initPromise = null;
function parseFrameQueryParams() {
const queryParams = {
DOMAIN: null,
PROTOCOL: false,
APP_SID: null,
LANG: null
};
if (window.name) {
const [domain, protocol, appSid] = window.name.split("|");
queryParams.DOMAIN = domain;
queryParams.PROTOCOL = Number.parseInt(protocol ?? "0") === 1;
queryParams.APP_SID = appSid;
queryParams.LANG = null;
}
return queryParams;
}
__name(parseFrameQueryParams, "parseFrameQueryParams");
async function makeFrame(options) {
const queryParams = parseFrameQueryParams();
if (!queryParams.DOMAIN || !queryParams.APP_SID) {
throw new SdkError({
code: "JSSDK_CLIENT_SIDE_WARNING",
description: "Well done! Now paste this URL into the Bitrix24 app settings",
status: 500
});
}
const b24Frame = new B24Frame(queryParams, options);
try {
await b24Frame.init();
} catch (error) {
try {
b24Frame.destroy();
} catch {
}
throw error;
}
return b24Frame;
}
__name(makeFrame, "makeFrame");
async function initializeB24Frame(options) {
if (initPromise !== null) {
return initPromise;
}
const pending = makeFrame(options);
initPromise = pending;
pending.catch(() => {
if (initPromise === pending) {
initPromise = null;
}
});
return pending;
}
__name(initializeB24Frame, "initializeB24Frame");
exports.AbstractB24 = AbstractB24;
exports.AbstractLogger = AbstractLogger;
exports.AdaptiveDelayer = AdaptiveDelayer;
exports.AjaxError = AjaxError;
exports.AjaxResult = AjaxResult;
exports.ApiVersion = ApiVersion;
exports.AppFrame = AppFrame;
exports.AuthHookManager = AuthHookManager;
exports.AuthManager = AuthManager;
exports.AuthOAuthManager = AuthOAuthManager;
exports.B24Frame = B24Frame;
exports.B24HelperManager = B24HelperManager;
exports.B24Hook = B24Hook;
exports.B24LangList = B24LangList;
exports.B24LocaleMap = B24LocaleMap;
exports.B24OAuth = B24OAuth;
exports.B24PullClientManager = PullClient;
exports.BatchRefV3 = BatchRefV3;
exports.Browser = Browser;
exports.CatalogProductImageType = CatalogProductImageType;
exports.CatalogProductType = CatalogProductType;
exports.CatalogRoundingRuleType = CatalogRoundingRuleType;
exports.CloseReasons = CloseReasons;
exports.ConnectionType = ConnectionType;
exports.ConsolaAdapter = ConsolaAdapter;
exports.ConsoleHandler = ConsoleHandler;
exports.ConsoleV2Handler = ConsoleV2Handler;
exports.DataType = DataType;
exports.DialogManager = DialogManager;
exports.EnumAppStatus = EnumAppStatus;
exports.EnumBitrix24Edition = EnumBitrix24Edition;
exports.EnumBizprocBaseType = EnumBizprocBaseType;
exports.EnumBizprocDocumentType = EnumBizprocDocumentType;
exports.EnumCrmEntityType = EnumCrmEntityType;
exports.EnumCrmEntityTypeId = EnumCrmEntityTypeId;
exports.EnumCrmEntityTypeShort = EnumCrmEntityTypeShort;
exports.Environment = Environment;
exports.FilterV3 = FilterV3;
exports.HttpV2 = HttpV2;
exports.HttpV3 = HttpV3;
exports.JsonFormatter = JsonFormatter;
exports.LineFormatter = LineFormatter;
exports.ListRpcError = ListRpcError;
exports.LoadDataType = LoadDataType;
exports.LogLevel = LogLevel;
exports.Logger = Logger;
exports.LoggerBrowser = LoggerBrowser;
exports.LoggerFactory = LoggerFactory;
exports.LoggerType = LoggerType;
exports.LsKeys = LsKeys;
exports.MemoryHandler = MemoryHandler;
exports.MessageCommands = MessageCommands;
exports.MessageManager = MessageManager;
exports.NullLogger = NullLogger;
exports.OperatingLimiter = OperatingLimiter;
exports.OptionsManager = OptionsManager$1;
exports.ParamsFactory = ParamsFactory;
exports.ParentManager = ParentManager;
exports.PlacementManager = PlacementManager;
exports.ProductRowDiscountTypeId = ProductRowDiscountTypeId;
exports.PullStatus = PullStatus;
exports.RateLimiter = RateLimiter;
exports.RefreshTokenError = RefreshTokenError;
exports.RestrictionManager = RestrictionManager;
exports.Result = Result;
exports.RpcMethod = RpcMethod;
exports.SdkError = SdkError;
exports.SenderType = SenderType;
exports.ServerMode = ServerMode;
exports.SliderManager = SliderManager;
exports.StatusDescriptions = StatusDescriptions;
exports.StreamHandler = StreamHandler;
exports.SubscriptionType = SubscriptionType;
exports.SystemCommands = SystemCommands;
exports.TelegramFormatter = TelegramFormatter;
exports.TelegramHandler = TelegramHandler;
exports.Text = Text;
exports.Type = Type;
exports.TypeOption = TypeOption;
exports.TypeSpecificUrl = TypeSpecificUrl;
exports.WinstonAdapter = WinstonAdapter;
exports.convertBizprocDocumentTypeToCrmEntityTypeId = convertBizprocDocumentTypeToCrmEntityTypeId;
exports.getDocumentId = getDocumentId;
exports.getDocumentType = getDocumentType;
exports.getDocumentTypeForFilter = getDocumentTypeForFilter;
exports.getEnumCrmEntityTypeShort = getEnumCrmEntityTypeShort;
exports.getEnumValue = getEnumValue;
exports.getEnvironment = getEnvironment;
exports.initializeB24Frame = initializeB24Frame;
exports.isArrayOfArray = isArrayOfArray;
exports.memoryUsageProcessor = memoryUsageProcessor;
exports.omit = omit;
exports.pick = pick;
exports.pidProcessor = pidProcessor;
exports.useB24Helper = useB24Helper;
exports.useFormatter = useFormatter;
exports.versionManager = versionManager;
}));
//# sourceMappingURL=index.js.map